Skip to content

Commit 7bef69a

Browse files
authored
Merge pull request #128 from dfinity/icrc-3
2 parents ad8358a + 65ed86d commit 7bef69a

File tree

3 files changed

+560
-0
lines changed

3 files changed

+560
-0
lines changed

standards/ICRC-3/HASHINGVALUES.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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+
```

standards/ICRC-3/ICRC-3.did

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
type Value = variant {
2+
Blob : blob;
3+
Text : text;
4+
Nat : nat;
5+
Int : int;
6+
Array : vec Value;
7+
Map : vec record { text; Value };
8+
};
9+
10+
type GetArchivesArgs = record {
11+
// The last archive seen by the client.
12+
// The Ledger will return archives coming
13+
// after this one if set, otherwise it
14+
// will return the first archives.
15+
from : opt principal;
16+
};
17+
18+
type GetArchivesResult = vec record {
19+
// The id of the archive
20+
canister_id : principal;
21+
22+
// The first block in the archive
23+
start : nat;
24+
25+
// The last block in the archive
26+
end : nat;
27+
};
28+
29+
type GetBlocksArgs = vec record { start : nat; length : nat };
30+
31+
type GetBlocksResult = record {
32+
// Total number of blocks in the
33+
// block log
34+
log_length : nat;
35+
36+
blocks : vec record { id : nat; block: Value };
37+
38+
archived_blocks : vec record {
39+
args : GetBlocksArgs;
40+
callback : func (GetBlocksArgs) -> (GetBlocksResult) query;
41+
};
42+
};
43+
44+
type DataCertificate = record {
45+
// See https://internetcomputer.org/docs/current/references/ic-interface-spec#certification
46+
certificate : blob;
47+
48+
// CBOR encoded hash_tree
49+
hash_tree : blob;
50+
};
51+
52+
service : {
53+
icrc3_get_archives : (GetArchivesArgs) -> (GetArchivesResult) query;
54+
icrc3_get_tip_certificate : () -> (opt DataCertificate) query;
55+
icrc3_get_blocks : (GetBlocksArgs) -> (GetBlocksResult) query;
56+
icrc3_supported_block_types : () -> (vec record { block_type : text; url : text }) query;
57+
};

0 commit comments

Comments
 (0)