Skip to content

Commit a6e713a

Browse files
authored
fix(avm)!: missing input len column into poseidon2 hash start row is (#19971)
Linear issue: [AVM-213](https://linear.app/aztec-labs/issue/AVM-213/missing-input-len-column-into-poseidon2-hash-start-row-is-not-sound)
1 parent 4d838c2 commit a6e713a

File tree

55 files changed

+677
-481
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+677
-481
lines changed

barretenberg/cpp/pil/vm2/bytecode/address_derivation.pil

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,19 @@ namespace address_derivation;
3939
pol commit partial_address_domain_separator;
4040
sel * (partial_address_domain_separator - constants.DOM_SEP__PARTIAL_ADDRESS) = 0;
4141

42-
// TODO: We need these temporarily while we dont allow for aliases in the lookup tuple
42+
// Lookup constant support: Can be removed when we support constants in lookups.
4343
pol commit const_two;
4444
sel * (const_two - 2) = 0;
4545
pol commit const_three;
4646
sel * (const_three - 3) = 0;
4747
pol commit const_four;
4848
sel * (const_four - 4) = 0;
49-
pol commit const_five;
50-
sel * (const_five - 5) = 0;
49+
pol commit const_thirteen;
50+
sel * (const_thirteen - 13) = 0;
5151

5252
#[SALTED_INITIALIZATION_HASH_POSEIDON2_0]
53-
sel { partial_address_domain_separator, salt, init_hash, salted_init_hash, const_two }
54-
in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output, poseidon2_hash.num_perm_rounds_rem };
53+
sel { partial_address_domain_separator, salt, init_hash, salted_init_hash, const_four }
54+
in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output, poseidon2_hash.input_len };
5555

5656
#[SALTED_INITIALIZATION_HASH_POSEIDON2_1]
5757
sel { deployer_addr, precomputed.zero, precomputed.zero, salted_init_hash }
@@ -63,8 +63,8 @@ namespace address_derivation;
6363
pol commit partial_address;
6464

6565
#[PARTIAL_ADDRESS_POSEIDON2]
66-
sel { sel /* =1 */, partial_address_domain_separator, class_id, salted_init_hash, partial_address }
67-
in poseidon2_hash.end { poseidon2_hash.start, poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };
66+
sel { partial_address_domain_separator, class_id, salted_init_hash, partial_address, const_three }
67+
in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output, poseidon2_hash.input_len };
6868

6969

7070
// Hash the public keys
@@ -78,8 +78,8 @@ namespace address_derivation;
7878
// Remove all the 0s for is_infinite when removed from public_keys.nr
7979
// https://github.com/AztecProtocol/aztec-packages/issues/7529
8080
#[PUBLIC_KEYS_HASH_POSEIDON2_0]
81-
sel { public_keys_hash_domain_separator, nullifier_key_x, nullifier_key_y, public_keys_hash, const_five }
82-
in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output, poseidon2_hash.num_perm_rounds_rem };
81+
sel { public_keys_hash_domain_separator, nullifier_key_x, nullifier_key_y, public_keys_hash, const_thirteen }
82+
in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output, poseidon2_hash.input_len };
8383

8484
#[PUBLIC_KEYS_HASH_POSEIDON2_1]
8585
sel { precomputed.zero, incoming_viewing_key_x, incoming_viewing_key_y, public_keys_hash, const_four }
@@ -107,8 +107,8 @@ namespace address_derivation;
107107
sel * (preaddress_domain_separator - constants.DOM_SEP__CONTRACT_ADDRESS_V1) = 0;
108108

109109
#[PREADDRESS_POSEIDON2]
110-
sel { sel /* =1 */, preaddress_domain_separator, public_keys_hash, partial_address, preaddress }
111-
in poseidon2_hash.end { poseidon2_hash.start, poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };
110+
sel { preaddress_domain_separator, public_keys_hash, partial_address, preaddress, const_three }
111+
in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output, poseidon2_hash.input_len };
112112

113113

114114
// Derive preaddress public key

barretenberg/cpp/pil/vm2/bytecode/class_id_derivation.pil

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ namespace class_id_derivation;
2323
// TODO: We need these temporarily while we dont allow for aliases in the lookup tuple.
2424
pol commit gen_index_contract_class_id;
2525
sel * (gen_index_contract_class_id - constants.DOM_SEP__CONTRACT_CLASS_ID) = 0;
26-
pol commit const_two;
27-
sel * (const_two - 2) = 0;
26+
pol commit const_four;
27+
sel * (const_four - 4) = 0;
2828

2929
// Since the inputs to poseidon2 have to be chunks of 3, we need two lookups if we want to do this in a single row
3030
#[CLASS_ID_POSEIDON2_0]
31-
sel { gen_index_contract_class_id, artifact_hash, private_functions_root, class_id, const_two }
32-
in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output, poseidon2_hash.num_perm_rounds_rem };
31+
sel { gen_index_contract_class_id, artifact_hash, private_functions_root, class_id, const_four }
32+
in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output, poseidon2_hash.input_len };
3333

3434
#[CLASS_ID_POSEIDON2_1]
3535
sel { public_bytecode_commitment, precomputed.zero, precomputed.zero, class_id }

barretenberg/cpp/pil/vm2/bytecode/update_check.pil

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace update_check;
4141
pol commit timestamp;
4242

4343
// Get timestamp from public inputs
44-
// TODO: Remove this as a column when we can lookup with constants
44+
// Lookup constant support: Can be removed when we support constants in lookups.
4545
pol commit timestamp_pi_offset;
4646
timestamp_pi_offset = sel * constants.AVM_PUBLIC_INPUTS_GLOBAL_VARIABLES_TIMESTAMP_ROW_IDX;
4747
#[TIMESTAMP_FROM_PUBLIC_INPUTS]
@@ -54,20 +54,27 @@ namespace update_check;
5454
// ======== DELAYED PUBLIC MUTABLE HASH READ ========
5555

5656
pol commit update_hash;
57-
// TODO: Remove this as a column when we can lookup with constants
57+
// Lookup constant support: Can be removed when we support constants in lookups.
5858
pol commit updated_class_ids_slot;
5959
sel * (constants.UPDATED_CLASS_IDS_SLOT - updated_class_ids_slot) = 0;
60+
pol commit const_two;
61+
sel * (const_two - 2) = 0;
6062

6163
pol commit delayed_public_mutable_slot;
6264

6365
#[DELAYED_PUBLIC_MUTABLE_SLOT_POSEIDON2]
64-
sel { sel /* =1 */, updated_class_ids_slot, address, precomputed.zero, delayed_public_mutable_slot }
65-
in poseidon2_hash.end { poseidon2_hash.start, poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };
66+
sel {
67+
updated_class_ids_slot, address, precomputed.zero,
68+
delayed_public_mutable_slot, const_two
69+
} in poseidon2_hash.start {
70+
poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2,
71+
poseidon2_hash.output, poseidon2_hash.input_len
72+
};
6673

6774
pol commit delayed_public_mutable_hash_slot;
6875
sel * (delayed_public_mutable_slot + constants.UPDATES_DELAYED_PUBLIC_MUTABLE_VALUES_LEN - delayed_public_mutable_hash_slot) = 0;
6976

70-
// TODO: Remove this as a column when we can lookup with constants
77+
// Lookup constant support: Can be removed when we support constants in lookups.
7178
pol commit deployer_protocol_contract_address;
7279
sel * (constants.CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS - deployer_protocol_contract_address) = 0;
7380

@@ -103,9 +110,18 @@ namespace update_check;
103110
pol commit update_preimage_pre_class_id;
104111
pol commit update_preimage_post_class_id;
105112

113+
// Lookup constant support: Can be removed when we support constants in lookups.
114+
pol commit const_three;
115+
sel * (const_three - 3) = 0;
116+
106117
#[UPDATE_HASH_POSEIDON2]
107-
hash_not_zero { sel /* =1 */, update_preimage_metadata, update_preimage_pre_class_id, update_preimage_post_class_id, update_hash }
108-
in poseidon2_hash.end { poseidon2_hash.start, poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };
118+
hash_not_zero {
119+
update_preimage_metadata, update_preimage_pre_class_id, update_preimage_post_class_id,
120+
update_hash, const_three
121+
} in poseidon2_hash.start {
122+
poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2,
123+
poseidon2_hash.output, poseidon2_hash.input_len
124+
};
109125

110126
// ======== TIMESTAMP OF CHANGE READ ========
111127

@@ -114,10 +130,10 @@ namespace update_check;
114130
pol commit timestamp_of_change;
115131
pol commit update_hi_metadata;
116132
pol TWO_POW_32 = 2**32;
117-
// TODO: Remove this as a column when we can lookup with constants
133+
// Lookup constant support: Can be removed when we support constants in lookups.
118134
pol commit update_hi_metadata_bit_size;
119135
hash_not_zero * (constants.UPDATES_DELAYED_PUBLIC_MUTABLE_METADATA_BIT_SIZE - constants.TIMESTAMP_OF_CHANGE_BIT_SIZE - update_hi_metadata_bit_size) = 0;
120-
// TODO: Remove this as a column when we can lookup with constants
136+
// Lookup constant support: Can be removed when we support constants in lookups.
121137
pol commit timestamp_of_change_bit_size; // 32
122138
hash_not_zero * (constants.TIMESTAMP_OF_CHANGE_BIT_SIZE - timestamp_of_change_bit_size) = 0;
123139

barretenberg/cpp/pil/vm2/poseidon2_hash.pil

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,26 @@ include "precomputed.pil";
44
/** Performs the poseidon2 full hash
55
* === Usage Tips ===
66
* - SINGLE ROW: To constrain the result of a poseidon hash over a single row (i.e. 3 or fewer inputs), lookup the inputs,
7-
* output, end (= 1), and start (= 1). This trace constrains that when start = end = 1, we have a single row.
7+
* output, input_len and use destination selector start (= 1). The caller will pass 1,2, or 3 for input_len. This follows
8+
* from the below constraints that `num_perm_rounds_rem == 1` and `end ==1`.
89
*
910
* Example (nullifier_check.pil):
10-
* should_silo { sel, siloing_separator, address, nullifier, siloed_nullifier }
11-
* in poseidon2_hash.end { poseidon2_hash.start, poseidon2_hash.input_0, poseidon2_hash.input_1,
12-
* poseidon2_hash.input_2, poseidon2_hash.output };
11+
* should_silo { siloing_separator, address, nullifier, siloed_nullifier, const_three }
12+
* in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1,
13+
* poseidon2_hash.input_2, poseidon2_hash.output, poseidon2_hash.input_len };
1314
*
1415
* - MULTIPLE ROWS:
1516
* - Lookup the inputs and output values for each row.
1617
* - Use num_perm_rounds_rem against the decrementing counter to ensure that each round is
1718
* computed in the correct order (at end = 1, num_perm_rounds_rem is constrained to be 1 => can equivalently
18-
* lookup the end selector for the final row).
19-
* - Over multiple rows, lookup the start selector at the expected first row to ensure no extra rows are prepended.
20-
* Note that input_len is only constrained at the start row, so it cannot be relied on for intermediate rows.
21-
* Pass also `num_perm_rounds_rem` explicitly at the start row. // TODO(AVM-213): Require `input_len` explicitly
22-
* // at the start row.
19+
* lookup the end selector for the final row). This can be omitted at the `start==1` row.
20+
* - Lookup the start selector at the expected first row to ensure no extra rows are prepended.
21+
* Pass `input_len` in the lookup at the start row, so that the IV is correctly computed.
2322
*
2423
* Example (address_derivation.pil):
2524
* // First row (removed prefix poseidon2_hash.** in destination tuple for presentation purposes)
26-
* sel { public_keys_hash_domain_separator, nullifier_key_x, nullifier_key_y, public_keys_hash, const_five }
27-
* in poseidon2_hash.start { input_0, input_1, input_2, output, num_perm_rounds_rem };
25+
* sel { public_keys_hash_domain_separator, nullifier_key_x, nullifier_key_y, public_keys_hash, const_thirteen }
26+
* in poseidon2_hash.start { input_0, input_1, input_2, output, ipnut_len };
2827
*
2928
* sel { precomputed.zero, incoming_viewing_key_x, incoming_viewing_key_y, public_keys_hash, const_four }
3029
* in poseidon2_hash.sel { input_0, input_1, input_2, output, num_perm_rounds_rem };
@@ -72,12 +71,27 @@ namespace poseidon2_hash;
7271
#[skippable_if]
7372
sel = 0;
7473

75-
// If the current row is not active, then there are no more active rows after that.
76-
// Note that sel cannot be activated in the first row as sel' is defined.
77-
// As a consequence, if a row is activated (sel == 1) somewhere in this sub-trace, then
78-
// the activated rows start from the second row and are contiguous.
74+
// == Multi-row Computation Selectors ==
75+
// We follow the recipe documented in:
76+
// https://hackmd.io/moq6viBpRJeLpWrHAogCZw?view#Contiguous-Multi-Rows-Computation-Trace
77+
78+
// Start of a poseidon2 computation
79+
pol commit start; // @boolean
80+
start * (1 - start) = 0;
81+
// The last row of hashing for the given input
82+
pol commit end; // @boolean
83+
end * (1 - end) = 0;
84+
85+
pol LATCH_CONDITION = end + precomputed.first_row;
86+
87+
#[SEL_ON_START_OR_END]
88+
(start + end) * (1 - sel) = 0;
89+
7990
#[TRACE_CONTINUITY]
80-
(1 - precomputed.first_row) * (1 - sel) * sel' = 0;
91+
(1 - LATCH_CONDITION) * (sel - sel') = 0;
92+
93+
#[START_AFTER_LATCH]
94+
sel' * (start' - LATCH_CONDITION) = 0;
8195

8296
// === Input Values ===
8397
// Unpadded Length of the inputs to be hashed
@@ -97,25 +111,6 @@ namespace poseidon2_hash;
97111
// The latch condition (see below for definition) will be on at the first_row (customary pil relations) or when num_perm_rounds_rem - 1 = 0
98112
(1 - LATCH_CONDITION) * (output' - output) = 0;
99113

100-
// === Control Flow within Subtrace ===
101-
// Start of a poseidon2 computation
102-
pol commit start; // @boolean
103-
start * (1 - start) = 0;
104-
// When we end a poseidon, the next row must naturally have a start
105-
sel' * (start' - LATCH_CONDITION) = 0;
106-
107-
// The last row of hashing for the given input
108-
pol commit end; // @boolean
109-
end * (1 - end) = 0;
110-
111-
// Selector must be 1 in end row
112-
#[SELECTOR_ON_START_OR_END]
113-
(start + end) * (1 - sel) = 0;
114-
115-
// Our latch condition can either be the designated end of the computation or the first row
116-
// The previous relation ensures they cannot both be 1
117-
pol LATCH_CONDITION = end + precomputed.first_row;
118-
119114
// === Permutation/Round Counting ===
120115
// We use the padded length to calculate the num of rounds to perform
121116
pol commit num_perm_rounds_rem;
@@ -144,6 +139,8 @@ namespace poseidon2_hash;
144139
// This cannot happen because to satisfy the current subtrace constraints, the attacker must decrement `num_perm_rounds_rem`
145140
// to `1` which would require ca. 2^250 rows. This implies that we will never reach legitimate `num_perm_rounds_rem` values
146141
// and that `end == 1` cannot be satisfied for this multi-row invocation.
142+
// If we cannot reach `end == 1`, then we cannot satisfy the constraint #[TRACE_CONTINUITY] on the
143+
// last row of the trace.
147144

148145
//=== Output Chaining ===
149146
// The permutation input values are represented by a_0, a_1, a_2, a_3

barretenberg/cpp/pil/vm2/trees/merkle_check.pil

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,19 +198,27 @@ namespace merkle_check;
198198
pol commit read_output_hash;
199199
pol commit write_output_hash;
200200

201+
// Lookup constant support: Can be removed when we support constants in lookups.
202+
pol commit const_two;
203+
sel * (const_two - 2) = 0;
204+
201205
// Lookup to the full poseidon2 gadget
202206
#[MERKLE_POSEIDON2_READ]
203207
sel {
204-
read_left_node, read_right_node, /*input_2=*/ precomputed.zero, /*start=1=*/ sel, read_output_hash
205-
} in poseidon2_hash.end {
206-
poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.start, poseidon2_hash.output
208+
read_left_node, read_right_node, /*input_2=*/ precomputed.zero,
209+
read_output_hash, const_two
210+
} in poseidon2_hash.start {
211+
poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2,
212+
poseidon2_hash.output, poseidon2_hash.input_len
207213
};
208214

209215
#[MERKLE_POSEIDON2_WRITE]
210216
write {
211-
write_left_node, write_right_node, /*input_2=*/ precomputed.zero, /*start=1=*/ write, write_output_hash
212-
} in poseidon2_hash.end {
213-
poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.start, poseidon2_hash.output
217+
write_left_node, write_right_node, /*input_2=*/ precomputed.zero,
218+
write_output_hash, const_two
219+
} in poseidon2_hash.start {
220+
poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2,
221+
poseidon2_hash.output, poseidon2_hash.input_len
214222
};
215223

216224
// If we are not done, this row's output_hash is the next row's node

barretenberg/cpp/pil/vm2/trees/note_hash_tree_check.pil

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,20 @@ namespace note_hash_tree_check;
7878
#[PASSTHROUGH_SILOING]
7979
sel * (1 - should_silo) * (note_hash - siloed_note_hash) = 0;
8080

81-
// TODO: We need this temporarily while we do not allow for aliases in the lookup tuple
81+
// Lookup constant support: Can be removed when we support constants in lookups.
8282
pol commit siloing_separator;
8383
sel * (constants.DOM_SEP__SILOED_NOTE_HASH - siloing_separator) = 0;
84+
pol commit const_three;
85+
sel * (const_three - 3) = 0;
8486

8587
#[SILO_POSEIDON2]
86-
should_silo { sel, siloing_separator, address, note_hash, siloed_note_hash }
87-
in poseidon2_hash.end { poseidon2_hash.start, poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };
88-
88+
should_silo {
89+
siloing_separator, address, note_hash,
90+
siloed_note_hash, const_three
91+
} in poseidon2_hash.start {
92+
poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2,
93+
poseidon2_hash.output, poseidon2_hash.input_len
94+
};
8995

9096
// ====== UNIQUE ======
9197
// If reading we should pass an already unique note hash
@@ -96,7 +102,7 @@ namespace note_hash_tree_check;
96102
#[PASSTHROUGH_UNIQUENESS]
97103
sel * (1 - should_unique) * (siloed_note_hash - unique_note_hash) = 0;
98104

99-
// TODO: We need this temporarily while we do not allow for aliases in the lookup tuple
105+
// Lookup constant support: Can be removed when we support constants in lookups.
100106
pol commit first_nullifier_pi_index;
101107
sel * (constants.AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX - first_nullifier_pi_index) = 0;
102108

@@ -114,21 +120,31 @@ namespace note_hash_tree_check;
114120

115121
pol commit nonce;
116122

117-
// TODO: We need this temporarily while we do not allow for aliases in the lookup tuple
123+
// Lookup constant support: Can be removed when we support constants in lookups.
118124
pol commit nonce_separator;
119125
sel * (constants.DOM_SEP__NOTE_HASH_NONCE - nonce_separator) = 0;
120126

121127
#[NONCE_COMPUTATION_POSEIDON2]
122-
should_unique { sel, nonce_separator, first_nullifier, note_hash_index, nonce }
123-
in poseidon2_hash.end { poseidon2_hash.start, poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };
128+
should_unique {
129+
nonce_separator, first_nullifier, note_hash_index,
130+
nonce, const_three
131+
} in poseidon2_hash.start {
132+
poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2,
133+
poseidon2_hash.output, poseidon2_hash.input_len
134+
};
124135

125-
// TODO: We need this temporarily while we do not allow for aliases in the lookup tuple
136+
// Lookup constant support: Can be removed when we support constants in lookups.
126137
pol commit unique_note_hash_separator;
127138
sel * (constants.DOM_SEP__UNIQUE_NOTE_HASH - unique_note_hash_separator) = 0;
128139

129140
#[UNIQUE_NOTE_HASH_POSEIDON2]
130-
should_unique { sel, unique_note_hash_separator, nonce, siloed_note_hash, unique_note_hash }
131-
in poseidon2_hash.end { poseidon2_hash.start, poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };
141+
should_unique {
142+
unique_note_hash_separator, nonce, siloed_note_hash,
143+
unique_note_hash, const_three
144+
} in poseidon2_hash.start {
145+
poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2,
146+
poseidon2_hash.output, poseidon2_hash.input_len
147+
};
132148

133149
// ====== TREE CHECK ======
134150
pol commit prev_leaf_value;
@@ -142,7 +158,7 @@ namespace note_hash_tree_check;
142158
// If reading, next_leaf_value is unconstrained
143159
write * (unique_note_hash - next_leaf_value) = 0;
144160

145-
// TODO: We need this temporarily while we do not allow for aliases in the lookup tuple
161+
// Lookup constant support: Can be removed when we support constants in lookups.
146162
pol commit note_hash_tree_height;
147163
sel * (constants.NOTE_HASH_TREE_HEIGHT - note_hash_tree_height) = 0;
148164

0 commit comments

Comments
 (0)