Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

feat: update representation-independent hash computation #240

Merged
merged 5 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions spec/_attachments/interface-spec-changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* Add a check that a canister receiving an ingress message is Running before the ingress message is marked as Received.
* Increase the maximum number of globals in a canister's WASM.
* Add per-call context performance counter.
* Update the computation of the representation-independent hash for the case of maps with nested maps.

### 0.21.0 (2023-09-18) {#0_21_0}
* Canister cycle balance cannot decrease below the freezing limit after executing `install_code` on the management canister.
Expand Down
31 changes: 21 additions & 10 deletions spec/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -910,27 +910,38 @@ Structured data, such as (recursive) maps, are authenticated by signing a repres

1. For each field that is present in the map (i.e. omitted optional fields are indeed omitted):

- concatenate the hash of the field's name (in ascii-encoding, without terminal `\x00`) and the hash of the value (with the encoding specified below).
- concatenate the hash of the field's name (in ascii-encoding, without terminal `\x00`) and the hash of the value (as specified below).

2. Sort these concatenations from low to high
2. Sort these concatenations from low to high.

3. Concatenate the sorted elements, and hash the result.

The resulting hash of 256 bits (32 bytes) is the representation-independent hash.
The resulting hash of length 256 bits (32 bytes) is the representation-independent hash.

The following encodings of field values as blobs are used
Field values are hashed as follows:

- Binary blobs (`canister_id`, `arg`, `nonce`, `module`) are used as-is.
- Binary blobs (`canister_id`, `arg`, `nonce`, `module`) are hashed as-is.

- Strings (`request_type`, `method_name`) are encoded in UTF-8, without a terminal `\x00`.
- Strings (`request_type`, `method_name`) are hashed by hashing their binary encoding in UTF-8, without a terminal `\x00`.

- Natural numbers (`compute_allocation`, `memory_allocation`, `ingress_expiry`) are encoded using the shortest form [Unsigned LEB128](https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128) encoding. For example, `0` should be encoded as a single zero byte `[0x00]` and `624485` should be encoded as byte sequence `[0xE5, 0x8E, 0x26]`.
- Natural numbers (`compute_allocation`, `memory_allocation`, `ingress_expiry`) are hashed by hashing their binary encoding using the shortest form [Unsigned LEB128](https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128) encoding. For example, `0` should be encoded as a single zero byte `[0x00]` and `624485` should be encoded as byte sequence `[0xE5, 0x8E, 0x26]`.

- Integers are encoded using the shortest form [Signed LEB128](https://en.wikipedia.org/wiki/LEB128#Signed_LEB128) encoding. For example, `0` should be encoded as a single zero byte `[0x00]` and `-123456` should be encoded as byte sequence `[0xC0, 0xBB, 0x78]`.
- Integers are hashed by hashing their encoding using the shortest form [Signed LEB128](https://en.wikipedia.org/wiki/LEB128#Signed_LEB128) encoding. For example, `0` should be encoded as a single zero byte `[0x00]` and `-123456` should be encoded as byte sequence `[0xC0, 0xBB, 0x78]`.

- Arrays (`paths`) are encoded as the concatenation of the hashes of the encodings of the array elements.
- Arrays (`paths`) are hashed by hashing the concatenation of the hashes of the array elements.

- Maps (`sender_delegation`) are encoded by recursively computing the representation-independent hash.
- Maps (`sender_delegation`) are hashed by recursively computing their representation-independent hash.

:::tip

Example calculation (where `H` denotes SHA-256 and `·` denotes blob concatenation) of a representation independent hash
for a map with a nested map in a field value:

hash_of_map({ "reply": { "arg": "DIDL\x00\x00" } })
= H(concat (sort [ H("reply") · hash_of_map({ "arg": "DIDL\x00\x00" }) ]))
= H(concat (sort [ H("reply") · H(concat (sort [ H("arg") · H("DIDL\x00\x00") ])) ]))

:::

### Request ids {#request-id}

Expand Down
Loading