|
| 1 | +## Representation independent hashing |
| 2 | + |
| 3 | +The following pseudocode specifies how to calculate the (representation independent) hash of an element of the Value type. Some test vectors to check compliance of an implementation with this specification follow. |
| 4 | + |
| 5 | +``` |
| 6 | +type Value = variant { |
| 7 | + Blob : blob, |
| 8 | + Text : text, |
| 9 | + Nat : nat, |
| 10 | + Int : int, |
| 11 | + Array : vec Value, |
| 12 | + Map : vec (text, Value) |
| 13 | +}; |
| 14 | +
|
| 15 | +Function hash_value(value) |
| 16 | + Initialize hasher as a new instance of SHA256 |
| 17 | +
|
| 18 | + Match value with |
| 19 | + Nat: |
| 20 | + Return SHA256_hash(LEB128_encode(value)) |
| 21 | + Int: |
| 22 | + Return SHA256_hash(SLEB128_encode(value)) |
| 23 | + Text: |
| 24 | + Return SHA256_hash(UTF8_encode(value)) |
| 25 | + Blob: |
| 26 | + Return SHA256_hash(value) |
| 27 | + Array: |
| 28 | + For each element in value |
| 29 | + Update hasher with hash_value(element) |
| 30 | + Return hasher.finalize() |
| 31 | + Map: |
| 32 | + Initialize hashes as empty list |
| 33 | + For each (key, val) in value |
| 34 | + Add (SHA256_hash(UTF8_encode(key)), hash_value(val)) to hashes |
| 35 | + Sort hashes in lexicographical order |
| 36 | + For each (key_hash, val_hash) in hashes |
| 37 | + Update hasher with key_hash |
| 38 | + Update hasher with val_hash |
| 39 | + Return hasher.finalize() |
| 40 | + Else: |
| 41 | + Return error "unsupported value type" |
| 42 | +End Function |
| 43 | +
|
| 44 | +Function LEB128_encode(nat_input) |
| 45 | + Convert nat_input to LEB128 byte encoding |
| 46 | +End Function |
| 47 | +
|
| 48 | +Function SLEB128_encode(integer_input) |
| 49 | + Convert integer_input to SLEB128 byte encoding |
| 50 | +End Function |
| 51 | +
|
| 52 | +Function UTF8_encode(text) |
| 53 | + Convert text to UTF-8 byte array and return it |
| 54 | +End Function |
| 55 | +
|
| 56 | +Function SHA256_hash(data) |
| 57 | + Initialize a new SHA256 hasher |
| 58 | + Update hasher with data |
| 59 | + Return hasher.finalize() |
| 60 | +End Function |
| 61 | +
|
| 62 | +``` |
| 63 | + |
| 64 | +## Test vectors |
| 65 | + |
| 66 | + |
| 67 | +```ignorelang |
| 68 | +input: Nat(42) |
| 69 | +expected output: 684888c0ebb17f374298b65ee2807526c066094c701bcc7ebbe1c1095f494fc1 |
| 70 | +``` |
| 71 | + |
| 72 | +```ignorelang |
| 73 | +input: Int(-42) |
| 74 | +expected output: de5a6f78116eca62d7fc5ce159d23ae6b889b365a1739ad2cf36f925a140d0cc |
| 75 | +``` |
| 76 | + |
| 77 | + |
| 78 | +```ignorelang |
| 79 | +input: Text("Hello, World!"), |
| 80 | +expected output: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f |
| 81 | +``` |
| 82 | + |
| 83 | +```ignorelang |
| 84 | +input: Blob(b'\x01\x02\x03\x04') |
| 85 | +expected output: 9f64a747e1b97f131fabb6b447296c9b6f0201e79fb3c5356e6c77e89b6a806a |
| 86 | +``` |
| 87 | + |
| 88 | +```ignorelang |
| 89 | +input: Array([Nat(3), Text("foo"), Blob(b'\x05\x06')]) |
| 90 | +expected output: 514a04011caa503990d446b7dec5d79e19c221ae607fb08b2848c67734d468d6 |
| 91 | +``` |
| 92 | + |
| 93 | +```ignorelang |
| 94 | +input: Map([("from", Blob(b'\x00\xab\xcd\xef\x00\x12\x34\x00\x56\x78\x9a\x00\xbc\xde\xf0\x00\x01\x23\x45\x67\x89\x00\xab\xcd\xef\x01')), |
| 95 | + ("to", Blob(b'\x00\xab\x0d\xef\x00\x12\x34\x00\x56\x78\x9a\x00\xbc\xde\xf0\x00\x01\x23\x45\x67\x89\x00\xab\xcd\xef\x01')), |
| 96 | + ("amount", Nat(42)), |
| 97 | + ("created_at", Nat(1699218263)), |
| 98 | + ("memo", Nat(0)) |
| 99 | + ]) |
| 100 | +
|
| 101 | +expected output: c56ece650e1de4269c5bdeff7875949e3e2033f85b2d193c2ff4f7f78bdcfc75 |
| 102 | +``` |
0 commit comments