From 323ba36869126520c294b6c8acacfa9877cde5c7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 27 Dec 2013 22:32:55 +0100 Subject: [PATCH] Updated rlp encoding. (requires verification!) --- rlp.go | 91 +++++++++++++++++++++++++++++++++++++++++++---------- rlp_test.go | 20 ++++++++++++ 2 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 rlp_test.go diff --git a/rlp.go b/rlp.go index 2c722cf7a..cce839095 100644 --- a/rlp.go +++ b/rlp.go @@ -6,29 +6,51 @@ import ( "math" ) -func EncodeSlice(slice []interface{}) []byte { - var buff bytes.Buffer +func BinaryLength(n uint64) uint64 { + if n == 0 { return 0 } - for _, val := range slice { - switch t := val.(type) { - case []interface{}, []string: - buff.Write(Encode(t)) - } + return 1 + BinaryLength(n / 256) +} + +func ToBinarySlice(n uint64, length uint64) []uint64 { + if length == 0 { + length = BinaryLength(n) } - return buff.Bytes() + if n == 0 { return make([]uint64, 1) } + + slice := ToBinarySlice(n / 256, 0) + slice = append(slice, n % 256) + + return slice +} + +func ToBin(n uint64, length uint64) string { + var buf bytes.Buffer + for _, val := range ToBinarySlice(n, length) { + buf.WriteString(string(val)) + } + + return buf.String() +} + +func FromBin(data []byte) uint64 { + if len(data) == 0 { return 0 } + + return FromBin(data[:len(data)-1]) * 256 + uint64(data[len(data)-1]) +} + +func Decode(data []byte, pos int) { + char := int(data[pos]) + switch { + case char < 24: + } } func Encode(object interface{}) []byte { var buff bytes.Buffer switch t := object.(type) { - case string: - if len(t) < 56 { - buff.WriteString(string(len(t) + 64) + t) - } else { - - } case uint32, uint64: var num uint64 if _num, ok := t.(uint64); ok { @@ -40,12 +62,49 @@ func Encode(object interface{}) []byte { if num >= 0 && num < 24 { buff.WriteString(string(num)) } else if num <= uint64(math.Pow(2, 256)) { + b := ToBin(num, 0) + buff.WriteString(string(len(b) + 23) + b) + } else { + b := ToBin(num, 0) + b2 := ToBin(uint64(len(b)), 0) + buff.WriteString(string(len(b2) + 55) + b2 + b) } + + case string: + if len(t) < 56 { + buff.WriteString(string(len(t) + 64) + t) + } else { + b2 := ToBin(uint64(len(t)), 0) + buff.WriteString(string(len(b2) + 119) + b2 + t) + } + case []byte: // Cast the byte slice to a string buff.Write(Encode(string(t))) - case []interface{}: - buff.Write(EncodeSlice(t)) + + case []interface{}, []string: + // Inline function for writing the slice header + WriteSliceHeader := func(length int) { + if length < 56 { + buff.WriteString(string(length + 128)) + } else { + b2 := ToBin(uint64(length), 0) + buff.WriteString(string(len(b2) + 183) + b2) + } + } + + // FIXME How can I do this "better"? + if interSlice, ok := t.([]interface{}); ok { + WriteSliceHeader(len(interSlice)) + for _, val := range interSlice { + buff.Write(Encode(val)) + } + } else if stringSlice, ok := t.([]string); ok { + WriteSliceHeader(len(stringSlice)) + for _, val := range stringSlice { + buff.Write(Encode(val)) + } + } } return buff.Bytes() diff --git a/rlp_test.go b/rlp_test.go new file mode 100644 index 000000000..922b70978 --- /dev/null +++ b/rlp_test.go @@ -0,0 +1,20 @@ +package main + +import ( + "testing" + "fmt" +) + +func TestEncode(t *testing.T) { + strRes := "Cdog" + str := string(Encode("dog")) + if str != strRes { + t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str)) + } + + sliceRes := "\u0083CdogCgodCcat" + slice := string(Encode([]string{"dog", "god", "cat"})) + if slice != sliceRes { + t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice)) + } +}