Skip to content

Commit 2b7d2c3

Browse files
authored
feat(avm)!: Derive is_infinite flag from point coordinates (#22564)
### Update Will also close [Foundation AVM Issue 13](https://linear.app/aztec-foundation/issue/AVM-13/enforce-canonical-point-at-infinity-representation) Note that this is currently being used as a base for removing the flag from AVM's point representation ([Foundation AVM Issue 14](https://linear.app/aztec-foundation/issue/AVM-14/remove-is-inf-flag-from-avm-ec-point-representation)): - ~#22745 (in merge train) - #23342 (ACIR changes from #23155 for removing `inf`) - #22564 <-- here - #22921 ✅ - #22795 ✅ - #22945 ✅ - #23031 ✅ **Everything in this branch has been reviewed**, see above PRs for individual work ⬆️ ### [OLD] Overview Will close [AVM-248](https://linear.app/aztec-labs/issue/AVM-248/enforce-canonical-point-at-infinity-representation) As a kind of stopgap before removing the `is_infinite` flag completely from the AVM ([AVM-266](https://linear.app/aztec-labs/issue/AVM-266/remove-is-inf-flag-from-ec-point-representation)), we now follow Noir behaviour more closely by deriving `is_inf` from coordinates inside the circuits ( `(x, y) == (0, 0) ? is_inf == true`). This replaces previous logic remapping points to (0, 0) from `is_inf`. This method relies on the on curve check (for `(0, 0) ==> is_inf `) and some new relations enforcing coordinates (for `is_inf ==> (0, 0)`) rather than (more expensive) error handling. However this does mean that the former will fail with an on curve error whereas the latter will simply fail a relation.
2 parents 88226ee + 0ddd0d0 commit 2b7d2c3

47 files changed

Lines changed: 559 additions & 930 deletions

Some content is hidden

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

avm-transpiler/src/procedures/msm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
pub(crate) const MSM_ASSEMBLY: &str = "
22
; We are passed three pointers and one usize.
3-
; d0 points to the points. Points are represented by (x: Field, y: Field). The point at infinity is (0, 0).
3+
; d0 points to the points. Points are represented by (x: Field, y: Field).
44
; d1 points to the scalars. Scalars are represented by (lo: Field, hi: Field) both range checked to 128 bits.
55
; d2 contains the number of points.
66
; d3 points to the result. The result is a point.
77
ADD d3, /*the reserved register 'one_usize'*/ $2, d4; Compute the pointer to the result y.
8-
; Initialize the msm result: point at infinity (0, 0)
8+
; Initialize the msm result: point at infinity
99
SET i3, 0 ff
1010
SET i4, 0 ff
1111
; Loop globals

avm-transpiler/src/transpile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1285,7 +1285,7 @@ fn handle_black_box_function(
12851285
result,
12861286
} => avm_instrs.push(AvmInstruction {
12871287
opcode: AvmOpcode::ECADD,
1288-
// The result (SIXTH operand) is indirect (addressing mode).
1288+
// The result (FOURTH operand) is indirect (addressing mode).
12891289
addressing_mode: Some(
12901290
AddressingModeBuilder::default()
12911291
.direct_operand(p1_x_offset)

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ include "../scalar_mul.pil";
3030
* as an independent 'destination' trace which is purely responsible for address
3131
* computation.
3232
* This means we assume all public keys are not the point at infinity, and so use
33-
* precomputed.zero to represent each key's is_infinity flag (see TODO(#7529)).
33+
* precomputed.zero to represent each key's is_infinity flag (see TODO(#7529) and PR #22462).
3434
*
3535
* USAGE: To enforce that an address is correctly derived from all preimage members
3636
* (adapted from #[ADDRESS_DERIVATION] in contract_instance_retrieval.pil):
@@ -184,7 +184,9 @@ namespace address_derivation;
184184
// 3. Computation of public keys hash
185185
pol commit public_keys_hash;
186186

187-
// TODO(#7529): Remove all the 0s for is_infinity when removed from public_keys.nr
187+
// TODO(#AVM-266): Remove infinity flags from point representation. Note that we may still need to use
188+
// precomputed.zero in the hash preimages until address derivation removes them:
189+
// TODO(#7529)/TODO(F-553): Remove all the 0s for is_infinity when removed from public_keys.nr
188190
// https://github.com/AztecProtocol/aztec-packages/issues/7529
189191
// TODO(#14031): Compress keys in public_keys_hash
190192
// https://github.com/AztecProtocol/aztec-packages/issues/14031
@@ -312,11 +314,11 @@ namespace address_derivation;
312314
sel {
313315
preaddress_public_key_x, preaddress_public_key_y, precomputed.zero,
314316
incoming_viewing_key_x, incoming_viewing_key_y, precomputed.zero,
315-
address, address_y, precomputed.zero
317+
address, address_y
316318
} in ecc.sel {
317319
ecc.p_x, ecc.p_y, ecc.p_is_inf,
318320
ecc.q_x, ecc.q_y, ecc.q_is_inf,
319-
ecc.r_x, ecc.r_y, ecc.r_is_inf
321+
ecc.r_x, ecc.r_y
320322
};
321323

322324
// Note: We can safely assume the address point is not infinity since that would imply either

barretenberg/cpp/pil/vm2/ecc.pil

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,32 @@
22
/**
33
* This subtrace supports point addition over the Grumpkin curve.
44
* Given two points, P & Q, this trace computes R = P + Q.
5-
* PRECONDITIONS: The only assumption here is that the inputs P & Q are points on the Grumpkin curve (note that the Point at Infinity = (0, 0) is considered on the curve):
6-
* Grumpkin Curve Eqn in SW form: Y^2 = X^3 − 17.
5+
* PRECONDITIONS: This trace assumes that the inputs P & Q are points on the Grumpkin curve and infinity points are correctly
6+
* flagged with p_is_inf and/or q_is_inf (note that the Point at Infinity = (0, 0) is considered on the curve):
7+
* Grumpkin Curve Eqn in SW form: Y^2 = X^3 − 17.
78
* Note: Grumpkin forms a 2-cycle with BN254, i.e the base field of one is the scalar field of the other and vice-versa.
89
*
910
* USAGE: This is a non-memory aware subtrace used to constrain point addition as defined above. Each point can be looked up
1011
* by coordinates (lookup as defined in ecc_mem.pil):
1112
* #[INPUT_OUTPUT_ECC_ADD]
1213
* sel_should_exec {
13-
* p_x_n, p_y_n, p_is_inf, // Point P
14-
* q_x_n, q_y_n, q_is_inf, // Point Q
15-
* res_x, res_y, res_is_inf // Point R
14+
* p_x_n, p_y_n, // Point P
15+
* p_is_inf, // P == O
16+
* q_x_n, q_y_n, // Point Q
17+
* q_is_inf, // Q == O
18+
* res_x, res_y // Point R
1619
* } in ecc.sel {
17-
* ecc.p_x, ecc.p_y, ecc.p_is_inf, // Point P
18-
* ecc.q_x, ecc.q_y, ecc.q_is_inf, // Point Q
19-
* ecc.r_x, ecc.r_y, ecc.r_is_inf // Point R
20+
* ecc.p_x, ecc.p_y, // Point P
21+
* ecc.p_is_inf, // P == O
22+
* ecc.q_x, ecc.q_y,, // Point Q
23+
* ecc.q_is_inf, // Q == O
24+
* ecc.r_x, ecc.r_y // Point R
2025
* };
2126
*
27+
* NOTE: For now, the calling trace MUST constrain that p_is_inf, q_is_inf above are correct. This is so if we have a calling
28+
* trace in which we know inf would never be an input we can simply use precomputed.zero and avoid wasting gates on deriving is_inf.
29+
* This follows the same logic for points being on the curve.
30+
*
2231
* TRACE SHAPE: 1 single row per computation (P + Q = R).
2332
*
2433
* INTERACTIONS: This subtrace is looked up by:
@@ -37,11 +46,11 @@ namespace ecc;
3746
// We perform point addition over our Short Weierstrass (SW) curve with 3 cases outlined in the last section ('Assign Result').
3847
// The notation will be as follows:
3948
// P + Q = R where:
40-
// P = (p_x, p_y, p_is_inf), Q = (q_x, q_y, q_is_inf), R = (r_x, r_y, r_is_inf),
49+
// P = (p_x, p_y), Q = (q_x, q_y), R = (r_x, r_y),
4150
// where the coordinates satisfy:
4251
// y^2 = x^3 - 17 (unless is_inf is true).
4352
// The point at infinity, O, does not have valid coordinates (a property of SW curves). We represent it as:
44-
// O = (0, 0, true).
53+
// O = (0, 0).
4554
// Note: this is NOT enforced here for inputs, see ecc_mem.pil for example of constraining.
4655
//
4756

@@ -70,20 +79,20 @@ namespace ecc;
7079
// Point P in affine form
7180
pol commit p_x;
7281
pol commit p_y;
82+
// Must be constrained by the calling trace:
7383
pol commit p_is_inf; // @boolean
7484
p_is_inf * (1 - p_is_inf) = 0;
7585

7686
// Point Q in affine form
7787
pol commit q_x;
7888
pol commit q_y;
89+
// Must be constrained by the calling trace:
7990
pol commit q_is_inf; // @boolean
8091
q_is_inf * (1 - q_is_inf) = 0;
8192

8293
// Resulting Point R in affine form
8394
pol commit r_x;
8495
pol commit r_y;
85-
pol commit r_is_inf; // @boolean
86-
r_is_inf * (1 - r_is_inf) = 0;
8796

8897
// Check x coordinates, i.e. p_x == q_x
8998
pol commit x_match; // @boolean
@@ -147,9 +156,9 @@ namespace ecc;
147156
// If P != Q where x_match, this implies p_y == -q_y <==> P == -Q (INVERSE_PRED == true):
148157
// R := O
149158
// If P == O:
150-
// R := Q (r_x := q_x, r_y := q_y, r_is_inf = q_is_inf)
159+
// R := Q (r_x := q_x, r_y := q_y)
151160
// Vice versa, if Q == O:
152-
// R := P (r_x := p_x, r_y := p_y, r_is_inf = p_is_inf)
161+
// R := P (r_x := p_x, r_y := p_y)
153162
//
154163

155164
pol INVERSE_PRED = x_match * (1 - y_match);
@@ -182,6 +191,4 @@ namespace ecc;
182191
sel * (r_x - (EITHER_INF * (p_is_inf * q_x + q_is_inf * p_x)) - result_infinity * INFINITY_X - use_computed_result * COMPUTED_R_X) = 0;
183192
#[OUTPUT_Y_COORD]
184193
sel * (r_y - (EITHER_INF * (p_is_inf * q_y + q_is_inf * p_y)) - result_infinity * INFINITY_Y - use_computed_result * COMPUTED_R_Y) = 0;
185-
#[OUTPUT_INF_FLAG]
186-
sel * (r_is_inf - result_infinity) = 0;
187194

0 commit comments

Comments
 (0)