ssz: switch to little-endian

https://github.com/ethereum/eth2.0-specs/pull/139
This commit is contained in:
Jacek Sieka 2019-01-22 11:56:01 -06:00
parent a9c026b957
commit 523a990adc
No known key found for this signature in database
GPG Key ID: 6299FEB3EB6FA465
2 changed files with 24 additions and 24 deletions

View File

@ -20,20 +20,20 @@ from milagro_crypto import getRaw, fromRaw
# toBytesSSZ convert simple fixed-length types to their SSZ wire representation
func toBytesSSZ(x: SomeInteger): array[sizeof(x), byte] =
## Convert directly to bytes the size of the int. (e.g. ``uint16 = 2 bytes``)
## All integers are serialized as **big endian**.
## All integers are serialized as **little endian**.
when x.sizeof == 8: bigEndian64(result.addr, x.unsafeAddr)
elif x.sizeof == 4: bigEndian32(result.addr, x.unsafeAddr)
elif x.sizeof == 2: bigEndian16(result.addr, x.unsafeAddr)
when x.sizeof == 8: littleEndian64(result.addr, x.unsafeAddr)
elif x.sizeof == 4: littleEndian32(result.addr, x.unsafeAddr)
elif x.sizeof == 2: littleEndian16(result.addr, x.unsafeAddr)
elif x.sizeof == 1: copyMem(result.addr, x.unsafeAddr, sizeof(result))
else: {.fatal: "Unsupported type serialization: " & $(type(x)).name.}
func toBytesSSZ(x: Uint24): array[3, byte] =
## Integers are all encoded as bigendian and not padded
## Integers are all encoded as little endian and not padded
let v = x.uint32
result[2] = byte(v and 0xff)
result[0] = byte(v and 0xff)
result[1] = byte((v shr 8) and 0xff)
result[0] = byte((v shr 16) and 0xff)
result[2] = byte((v shr 16) and 0xff)
func toBytesSSZ(x: bool): array[1, byte] =
[if x: 1'u8 else: 0'u8]
@ -74,7 +74,7 @@ func sszLen(v: seq | array): int =
# there's enough data in the buffer
func fromBytesSSZUnsafe(T: typedesc[SomeInteger], data: pointer): T =
## Convert directly to bytes the size of the int. (e.g. ``uint16 = 2 bytes``)
## All integers are serialized as **big endian**.
## All integers are serialized as **little endian**.
## TODO: Assumes data points to a sufficiently large buffer
# TODO: any better way to get a suitably aligned buffer in nim???
@ -83,9 +83,9 @@ func fromBytesSSZUnsafe(T: typedesc[SomeInteger], data: pointer): T =
var alignedBuf = cast[ptr byte](tmp.addr)
copyMem(alignedBuf, data, result.sizeof)
when result.sizeof == 8: bigEndian64(result.addr, alignedBuf)
elif result.sizeof == 4: bigEndian32(result.addr, alignedBuf)
elif result.sizeof == 2: bigEndian16(result.addr, alignedBuf)
when result.sizeof == 8: littleEndian64(result.addr, alignedBuf)
elif result.sizeof == 4: littleEndian32(result.addr, alignedBuf)
elif result.sizeof == 2: littleEndian16(result.addr, alignedBuf)
elif result.sizeof == 1: copyMem(result.addr, alignedBuf, sizeof(result))
else: {.fatal: "Unsupported type deserialization: " & $(type(result)).name.}
@ -95,12 +95,12 @@ func fromBytesSSZUnsafe(T: typedesc[bool], data: pointer): T =
fromBytesSSZUnsafe(uint8, data) != 0
func fromBytesSSZUnsafe(T: typedesc[Uint24], data: pointer): T =
## Integers are all encoded as bigendian and not padded
## Integers are all encoded as littleendian and not padded
var tmp: uint32
let p = cast[ptr UncheckedArray[byte]](data)
tmp = tmp or uint32(p[2])
tmp = tmp or uint32(p[0])
tmp = tmp or uint32(p[1]) shl 8
tmp = tmp or uint32(p[0]) shl 16
tmp = tmp or uint32(p[2]) shl 16
result = tmp.Uint24
func fromBytesSSZUnsafe(T: typedesc[EthAddress], data: pointer): T =
@ -212,7 +212,7 @@ func serialize[T: not enum](dest: var seq[byte], src: T) =
# Write size (we only know it once we've serialized the object!)
var objLen = dest.len() - lenPos - 4
bigEndian32(dest[lenPos].addr, objLen.addr)
littleEndian32(dest[lenPos].addr, objLen.addr)
# ################### Core functions ###################################
@ -262,12 +262,12 @@ func merkleHash[T](lst: openArray[T]): array[32, byte]
func hash_tree_root*(x: SomeInteger | bool): array[sizeof(x), byte] =
## Convert directly to bytes the size of the int. (e.g. ``uint16 = 2 bytes``)
## All integers are serialized as **big endian**.
## All integers are serialized as **little endian**.
toBytesSSZ(x)
func hash_tree_root*(x: Uint24): array[3, byte] =
## Convert directly to bytes the size of the int. (e.g. ``uint16 = 2 bytes``)
## All integers are serialized as **big endian**.
## All integers are serialized as **little endian**.
toBytesSSZ(x)
func hash_tree_root*(x: EthAddress): array[sizeof(x), byte] =
@ -333,7 +333,7 @@ func merkleHash[T](lst: openArray[T]): array[32, byte] =
# Store length of list (to compensate for non-bijectiveness of padding)
var dataLen: array[32, byte]
var lstLen = uint64(len(lst))
bigEndian64(dataLen[32-8].addr, lstLen.addr)
littleEndian64(dataLen[32-8].addr, lstLen.addr)
# Divide into chunks
var chunkz: seq[seq[byte]]

View File

@ -39,14 +39,14 @@ suite "Simple serialization":
)
var expected_ser = @[
byte 0, 0, 0, 67, # length
byte 67, 0, 0, 0, # length
5,
'\xFF'.ord, '\xFF'.ord, '\xFF'.ord, '\xFD'.ord,
0xFD, 0xFF, 0xFF, 0xFF,
]
expected_ser &= EthAddress.filled(byte 35)
expected_ser &= MDigest[256].filled(byte 35).data
expected_ser &= [byte 0, 0, 0, 3, 'c'.ord, 'o'.ord, 'w'.ord]
expected_ser &= [byte 0, 0, 79]
expected_ser &= [byte 3, 0, 0, 0, 'c'.ord, 'o'.ord, 'w'.ord]
expected_ser &= [byte 79, 0, 0]
test "Object deserialization":
let deser = expected_ser.deserialize(Foo).get()
@ -119,5 +119,5 @@ suite "Tree hashing":
check: hash_tree_root(bb).len > 0
test "Hash integer":
check: hash_tree_root(0x01'u32) == [0'u8, 0, 0, 1] # big endian!
check: hash_tree_root(Uint24(0x01)) == [0'u8, 0, 1] # big endian!
check: hash_tree_root(0x01'u32) == [1'u8, 0, 0, 0] # little endian!
check: hash_tree_root(Uint24(0x01)) == [1'u8, 0, 0] # little endian!