Skip to content

Commit 5d9ff55

Browse files
authored
feat: merge-train/avm (#20492)
BEGIN_COMMIT_OVERRIDE fix(avm)!: to_radix internal audit - first pass (#20455) fix(avm)!: emit public log pre-audit (#20417) END_COMMIT_OVERRIDE
2 parents a7c1dc9 + 5af8a59 commit 5d9ff55

File tree

47 files changed

+6727
-6112
lines changed

Some content is hidden

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

47 files changed

+6727
-6112
lines changed

barretenberg/cpp/pil/vm2/opcodes/emit_public_log.pil

Lines changed: 177 additions & 93 deletions
Large diffs are not rendered by default.
Lines changed: 108 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,55 @@
11
include "precomputed.pil";
22

3-
// Decomposes a field in radixes
4-
// Roughly, what we do is keep track of an accumulator where we reconstruct value using the limbs. We can end when the accumulator is equal to the value (found).
5-
// For overflow protection, we compare the limbs against the p limbs for the given radix. If we reach the last limb (is_unsafe) we assert that we are under p.
6-
// Overflow in the accumulator can only happen in the unsafe limb. After the unsafe limb we have padding limbs, that we assert to be zero. This is used
7-
// because users might want to decompose in more limbs that strictly needed for the radix.
8-
// The following table is non-exhaustive, we do have some extra columns to compute these values.
9-
// +-------+-------+------+--------+------------+------+-------------+----------+------------------+-------+------------+-----------+-------+-----+-----+---------+
10-
// | value | radix | limb | p_limb | limb_index | acc | acc_under_p | exponent | not_padding_limb | found | safe_limbs | is_unsafe | start | end | sel | not_end |
11-
// +-------+-------+------+--------+------------+------+-------------+----------+------------------+-------+------------+-----------+-------+-----+-----+---------+
12-
// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
13-
// | 1337 | 10 | 7 | 7 | 0 | 7 | 0 | 1 | 1 | 0 | 76 | 0 | 1 | 0 | 1 | 1 |
14-
// | 1337 | 10 | 3 | 1 | 1 | 37 | 0 | 10 | 1 | 0 | 76 | 0 | 0 | 0 | 1 | 1 |
15-
// | 1337 | 10 | 3 | 6 | 2 | 337 | 1 | 100 | 1 | 0 | 76 | 0 | 0 | 0 | 1 | 1 |
16-
// | 1337 | 10 | 1 | 5 | 3 | 1337 | 1 | 1000 | 1 | 1 | 76 | 0 | 0 | 0 | 1 | 1 |
17-
// | 1337 | 10 | 0 | 9 | 4 | 1337 | 1 | 10000 | 1 | 1 | 76 | 0 | 0 | 0 | 1 | 1 |
18-
// | 1337 | 10 | 0 | 2 | 76 | 1337 | 1 | 10**76 | 1 | 1 | 76 | 1 | 0 | 0 | 1 | 1 |
19-
// | 1337 | 10 | 0 | 0 | 77 | 1337 | 0 | 0 | 0 | 1 | 76 | 0 | 0 | 1 | 1 | 0 |
20-
// | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
21-
// +-------+-------+------+--------+------------+------+-------------+----------+------------------+-------+------------+-----------+-------+-----+-----+---------+
3+
/*
4+
* Decomposes a field in radixes
5+
* Roughly, what we do is keep track of an accumulator where we reconstruct value using the limbs. We can end when the accumulator is equal to the value (found).
6+
* For overflow protection, we compare the limbs against the p limbs for the given radix. If we reach the last limb (is_unsafe) we assert that we are under p.
7+
* Overflow in the accumulator can only happen in the unsafe limb. After the unsafe limb we have padding limbs, that we assert to be zero. This is used
8+
* because users might want to decompose in more limbs that strictly needed for the radix. We also assert that the decomposition is complete, i.e., that the value
9+
* has been found. In other words, truncation error is not supported in this trace.
10+
*
11+
*
12+
* Usage:
13+
* sel_XX { value, limb_index, radix, limb, value_found
14+
* } in to_radix.sel {
15+
* to_radix.value, to_radix.limb_index, to_radix.radix, to_radix.limb, to_radix.found
16+
* };
17+
*
18+
* Optionally, column `value_found` can be omitted provided that the caller ensures that the decomposition is complete or
19+
* does not care about truncation error.
20+
*
21+
* Preconditions: 'radix' is in range [2, 256]. This trace cannot guarantee correctness if 'radix' is not in this range.
22+
*
23+
* Inputs:
24+
* - value: The value to decompose in little endian.
25+
* - limb_index: The index of the limb to lookup in little endian.
26+
* - radix: The radix to decompose the value in. Must be in range [2, 256].
27+
* Outputs:
28+
* - limb: The limb to lookup in little endian.
29+
* - value_found: Whether the value has been found, i.e., the decomposition is complete with the limbs from index 0 to index `limb_index`.
30+
*
31+
* The following table is non-exhaustive, we do have some extra columns to compute these values.
32+
* +-------+-------+------+--------+------------+------+-------------+----------+------------------+-------+------------+-----------+-------+-----+-----+---------+
33+
* | value | radix | limb | p_limb | limb_index | acc | acc_under_p | power | not_padding_limb | found | safe_limbs | is_unsafe | start | end | sel | NOT_END |
34+
* +-------+-------+------+--------+------------+------+-------------+----------+------------------+-------+------------+-----------+-------+-----+-----+---------+
35+
* | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
36+
* | 1337 | 10 | 7 | 7 | 0 | 7 | 0 | 1 | 1 | 0 | 76 | 0 | 1 | 0 | 1 | 1 |
37+
* | 1337 | 10 | 3 | 1 | 1 | 37 | 0 | 10 | 1 | 0 | 76 | 0 | 0 | 0 | 1 | 1 |
38+
* | 1337 | 10 | 3 | 6 | 2 | 337 | 1 | 100 | 1 | 0 | 76 | 0 | 0 | 0 | 1 | 1 |
39+
* | 1337 | 10 | 1 | 5 | 3 | 1337 | 1 | 1000 | 1 | 1 | 76 | 0 | 0 | 0 | 1 | 1 |
40+
* | 1337 | 10 | 0 | 9 | 4 | 1337 | 1 | 10000 | 1 | 1 | 76 | 0 | 0 | 0 | 1 | 1 |
41+
* .........................................
42+
* | 1337 | 10 | 0 | 2 | 76 | 1337 | 1 | 10**76 | 1 | 1 | 76 | 1 | 0 | 0 | 1 | 1 |
43+
* | 1337 | 10 | 0 | 0 | 77 | 1337 | 1 | 0 | 0 | 1 | 76 | 0 | 0 | 1 | 1 | 0 |
44+
* | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
45+
* +-------+-------+------+--------+------------+------+-------------+----------+------------------+-------+------------+-----------+-------+-----+-----+---------+
46+
*
47+
* Each computation is performed over a contiguous block of rows. The block is determined by the `start` and `end` selectors.
48+
* The number of rows in a computation block is at least the number of limbs for a complete decomposition. Tracegen determines
49+
* the number of "padding" rows for the extra high limbs depending on the need of the subtraces invoking this gadget. Note that
50+
* it does not pose a soundness isssue because this trace ensures that a present row is correct. If a row is not present, then
51+
* we have a completeness issue because the lookup will fail.
52+
*/
2253
namespace to_radix;
2354

2455
#[skippable_if]
@@ -29,73 +60,66 @@ namespace to_radix;
2960

3061
// Inputs to to_radix
3162
pol commit value;
32-
pol commit radix; // Must be 256 >= radix >= 2
63+
pol commit radix; // Must be in range [2, 256] as a precondition.
3364
pol commit limb_index;
3465

3566
// Outputs of to_radix
3667
pol commit limb;
68+
pol commit found;
69+
found * (1 - found) = 0;
3770

38-
39-
// LIFECYCLE
40-
71+
// ==== Multi-row Computation Selectors ====
72+
// See recipe in https://hackmd.io/moq6viBpRJeLpWrHAogCZw?view#Contiguous-Multi-Rows-Computation-Trace
4173
pol commit start;
4274
start * (1 - start) = 0;
43-
4475
pol commit end;
4576
end * (1 - end) = 0;
4677

47-
// end and first_row are NAND
48-
end * precomputed.first_row = 0;
4978
pol LATCH_CONDITION = end + precomputed.first_row;
5079

51-
#[START_AFTER_LATCH]
52-
sel' * (start' - LATCH_CONDITION) = 0;
80+
#[SEL_ON_START_OR_END]
81+
(start + end) * (1 - sel) = 0;
5382

54-
// Selector must be 1 in a start row
55-
#[SELECTOR_ON_START]
56-
start * (1 - sel) = 0;
57-
// Next selector must be current selector unless LATCH_CONDITION
58-
#[SELECTOR_CONSISTENCY]
59-
(sel' - sel) * (1 - LATCH_CONDITION) = 0;
60-
// Selector must be 1 in an end row
61-
end * (1 - sel) = 0;
83+
#[TRACE_CONTINUITY]
84+
(1 - LATCH_CONDITION) * (sel - sel') = 0;
6285

63-
// Commited to reduce the degree of expressions
64-
pol commit not_end;
65-
sel * (1 - end) - not_end = 0;
86+
#[START_AFTER_LATCH]
87+
sel' * (start' - LATCH_CONDITION) = 0;
6688

89+
// `sel * (1 - end) = sel - end * sel` and since `end == 1 ==> sel == 1` we have `end * sel = end`.
90+
pol NOT_END = sel - end;
6791

68-
// EXPONENTIATION
92+
// ===== RADIX POWERS COMPUTATION =====
6993

70-
pol commit exponent;
71-
// We commit not_padding_limb instead of the more natural padding_limb because it's going to be used in a lookup
94+
pol commit power;
95+
// We commit not_padding_limb instead of the more natural padding_limb because it's going to be used as a lookup selector.
7296
pol commit not_padding_limb;
7397
not_padding_limb * (1 - not_padding_limb) = 0;
7498

75-
// exponent starts at 1
76-
start * (exponent - 1) = 0;
77-
// next exponent is current exponent * radix unless it's a padding limb
78-
not_end * not_padding_limb' * (exponent * radix - exponent') = 0;
7999
// not_padding_limb starts at 1
80100
start * (1 - not_padding_limb) = 0;
81-
// next not not_padding_limb is current not_padding_limb unless current limb is unsafe, where it changes to 0
82-
not_end * ((0 - not_padding_limb) * is_unsafe_limb + not_padding_limb - not_padding_limb') = 0;
101+
// next `not_padding_limb` is current `not_padding_limb` unless current limb is unsafe, where it changes to 0
102+
// Note that unsafe_limbs is defined and constrained below.
103+
NOT_END * ((0 - not_padding_limb) * is_unsafe_limb + not_padding_limb - not_padding_limb') = 0;
83104

84-
// Padding limbs have zero exponent
85-
(1 - not_padding_limb) * exponent = 0;
105+
// power starts at 1
106+
start * (power - 1) = 0;
107+
// next power is current power * radix unless it's a padding limb
108+
NOT_END * not_padding_limb' * (power * radix - power') = 0;
86109

110+
// Padding limbs have zero power
111+
(1 - not_padding_limb) * power = 0;
87112

88-
// ACCUMULATION
113+
114+
// ===== ACCUMULATION =====
89115

90116
pol commit acc;
91-
pol commit found;
92-
found * (1 - found) = 0;
93117

94118
// Limb index starts at zero
95119
start * (limb_index - 0) = 0;
96120

97121
// Limb index must increase
98-
not_end * (limb_index + 1 - limb_index') = 0;
122+
NOT_END * (limb_index + 1 - limb_index') = 0;
99123

100124
// Range check limb so we can safely assert that it's less than radix.
101125
#[LIMB_RANGE]
@@ -106,7 +130,7 @@ namespace to_radix;
106130

107131
// Limb should be less than radix
108132
pol commit limb_radix_diff;
109-
sel * (radix - 1 - limb - limb_radix_diff) = 0;
133+
sel * (radix - limb - 1 - limb_radix_diff) = 0;
110134

111135
#[LIMB_LESS_THAN_RADIX_RANGE]
112136
sel { limb_radix_diff }
@@ -117,22 +141,26 @@ namespace to_radix;
117141

118142
// On start, current acc must be equal to limb
119143
start * (acc - limb) = 0;
120-
// Next acc must be current acc + next_exponent*next_limb
121-
not_end * (acc + exponent' * limb' - acc') = 0;
144+
// Next acc must be current acc + next_power*next_limb
145+
NOT_END * (acc + power' * limb' - acc') = 0;
122146

123147
// found is 1 when value - acc = 0
124148
pol REM = value - acc;
125149
pol commit rem_inverse;
126-
sel * (REM * (found * (1 - rem_inverse) + rem_inverse) - 1 + found) = 0;
150+
sel * (REM * (found * (1 - rem_inverse) + rem_inverse) - 1 + found) = 0; // @zero-check
127151

128152
// when found is 1, next limb is 0
129-
not_end * found * limb' = 0;
153+
NOT_END * found * limb' = 0;
154+
155+
// As a consequence, when found is 1, the next acc value must be the same and
156+
// the next found value must be 1 as well. In this way, `found == 1` is propagated
157+
// until the end of the trace.
130158

131159
// We can only enable end when found is one
132160
(1 - found) * end = 0;
133161

134162

135-
// OVERFLOW PROTECTION
163+
// ===== UNSAFE LIMBS COMPUTATION =====
136164

137165
pol commit safe_limbs;
138166

@@ -145,15 +173,13 @@ namespace to_radix;
145173
pol commit is_unsafe_limb;
146174
is_unsafe_limb * (1 - is_unsafe_limb) = 0;
147175

148-
// If is_padding_limb, limb is zero
149-
(1 - not_padding_limb) * limb = 0;
150-
// If is_padding_limb, p_limb is zero
151-
(1 - not_padding_limb) * p_limb = 0;
152-
153-
// is_unsafe_limb is on when and only when limb_index == safe_limbs
154-
pol safety_diff = limb_index - safe_limbs;
176+
// `is_unsafe_limb == 1` iff `limb_index == safe_limbs`
177+
pol SAFETY_DIFF = limb_index - safe_limbs;
155178
pol commit safety_diff_inverse;
156-
sel * (safety_diff * (is_unsafe_limb * (1 - safety_diff_inverse) + safety_diff_inverse) - 1 + is_unsafe_limb) = 0;
179+
// @zero-check
180+
sel * (SAFETY_DIFF * (is_unsafe_limb * (1 - safety_diff_inverse) + safety_diff_inverse) - 1 + is_unsafe_limb) = 0;
181+
182+
// ===== FIELD OVERFLOW PROTECTION =====
157183

158184
// The limb of the modulus p decomposed by radix at this limb_index
159185
pol commit p_limb;
@@ -164,11 +190,16 @@ namespace to_radix;
164190
precomputed.sel_p_decomposition
165191
{ precomputed.p_decomposition_radix, precomputed.p_decomposition_limb_index, precomputed.p_decomposition_limb };
166192

193+
// If is_padding_limb, limb is zero
194+
(1 - not_padding_limb) * limb = 0;
195+
// If is_padding_limb, p_limb is zero
196+
(1 - not_padding_limb) * p_limb = 0;
197+
167198
// We carry wether the accumulator is under p. If we reach the unsafe limb, we need to ensure that this is true.
168199
pol commit acc_under_p;
169200
acc_under_p * (1 - acc_under_p) = 0;
170201

171-
// 1 when lt, 0 when gt or equal
202+
// 1 iff `limb < p_limb`
172203
pol commit limb_lt_p;
173204
limb_lt_p * (1 - limb_lt_p) = 0;
174205

@@ -206,20 +237,20 @@ namespace to_radix;
206237
// acc_under_p is on start is equal to limb_lt_p
207238
start * (acc_under_p - limb_lt_p) = 0;
208239
// acc_under_p' = limb_eq_p' ? acc_under_p : limb_lt_p'
209-
not_end * ((acc_under_p - limb_lt_p') * limb_eq_p' + limb_lt_p' - acc_under_p') = 0;
240+
NOT_END * ((acc_under_p - limb_lt_p') * limb_eq_p' + limb_lt_p' - acc_under_p') = 0;
210241

211242
// On the the unsafe limb, we must be under p
212243
#[OVERFLOW_CHECK]
213244
is_unsafe_limb * (1 - acc_under_p) = 0;
214245

215246

216-
// CONSTANT CONSISTENCY
247+
// ===== CONSTANT CONTINUITY =====
217248

218-
#[CONSTANT_CONSISTENCY_RADIX]
219-
not_end * (radix - radix') = 0;
249+
#[RADIX_CONTINUITY]
250+
NOT_END * (radix - radix') = 0;
220251

221-
#[CONSTANT_CONSISTENCY_VALUE]
222-
not_end * (value - value') = 0;
252+
#[VALUE_CONTINUITY]
253+
NOT_END * (value - value') = 0;
223254

224-
#[CONSTANT_CONSISTENCY_SAFE_LIMBS]
225-
not_end * (safe_limbs - safe_limbs') = 0;
255+
#[SAFE_LIMBS_CONTINUITY]
256+
NOT_END * (safe_limbs - safe_limbs') = 0;

0 commit comments

Comments
 (0)