Skip to content

Commit

Permalink
fix: add G2 subgroup check for ECPAIRING (#268)
Browse files Browse the repository at this point in the history
* Rewrite file and misc

* Add addition on the twist

* Couple tweaks

* Tweak

* Final tweaks

* Reduce overhead and add tests

* Add forgotten file

* Cleanup

* Minor

* Add comment as per review
  • Loading branch information
Nashtare authored Jun 10, 2024
1 parent 4ab700e commit 428ac1b
Show file tree
Hide file tree
Showing 14 changed files with 663 additions and 17 deletions.
5 changes: 4 additions & 1 deletion evm_arithmetization/src/cpu/kernel/aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/curve/bn254/curve_arithmetic/msm.asm"),
include_str!("asm/curve/bn254/curve_arithmetic/pairing.asm"),
include_str!("asm/curve/bn254/curve_arithmetic/precomputation.asm"),
include_str!("asm/curve/bn254/curve_arithmetic/twisted_curve.asm"),
include_str!("asm/curve/bn254/curve_arithmetic/twisted_curve_add.asm"),
include_str!("asm/curve/bn254/curve_arithmetic/twisted_curve_checks.asm"),
include_str!("asm/curve/bn254/curve_arithmetic/twisted_curve_endomorphism.asm"),
include_str!("asm/curve/bn254/curve_arithmetic/twisted_curve_mul.asm"),
include_str!("asm/curve/bn254/field_arithmetic/degree_6_mul.asm"),
include_str!("asm/curve/bn254/field_arithmetic/degree_12_mul.asm"),
include_str!("asm/curve/bn254/field_arithmetic/frobenius.asm"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ global bn_add:
%bn_check
// stack: isValid(x0, y0), x0, y0, x1, y1, retdest
DUP5
// stack: x1, isValid(x0, y0), x0, y0, x1, y1, retdest
// stack: y1, isValid(x0, y0), x0, y0, x1, y1, retdest
DUP5
// stack: x1, y1, isValid(x0, y0), x0, y0, x1, y1, retdest
%bn_check
// stack: isValid(x1, y1), isValid(x0, y0), x0, y0, x1, y1, retdest
AND
MUL // Cheaper than AND
// stack: isValid(x1, y1) & isValid(x0, y0), x0, y0, x1, y1, retdest
%jumpi(bn_add_valid_points)
// stack: x0, y0, x1, y1, retdest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,16 @@ bn254_input_check:
// stack: inp_j', inp_j, j, k, inp
%load_fp254_4
// stack: Q_j, inp_j, j, k, inp
%dup_bn_g2
// stack: Q_j, Q_j, inp_j, j, k, inp
%bn_check_twisted
// stack: valid?, inp_j, j, k, inp
ISZERO
// stack: valid_1?, Q_j, inp_j, j, k, inp
%stack (b, Q: 4) -> (Q, b)
%bn_check_twisted_subgroup
ISZERO
// stack: valid_2?, valid_1?, inp_j, j, k, inp
ADD // Cheaper than OR
%jumpi(bn_pairing_invalid_input)
// stack: inp_j, j, k, inp
POP
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// Elliptic curve addition on the twist of BN254 curve.
// Assumption: (X0,Y0) is a valid point.
// Uses the standard affine addition formula.
global bn_twisted_add:
// stack: X0: 2, Y0: 2, X1: 2, Y1: 2, retdest

// Check if the first point is the identity.
%dup_fp254_2_2
// stack: Y0, X0, Y0, X1, Y1, retdest
%dup_fp254_2_2
// stack: X0, Y0, X0, Y0, X1, Y1, retdest
%bn_check_twisted_ident
// stack: (X0,Y0)==(0,0), X0, Y0, X1, Y1, retdest
%jumpi(bn_twisted_add_fst_zero)
// stack: X0, Y0, X1, Y1, retdest

// Check if the second point is the identity.
%dup_fp254_2_6
// stack: Y1, X0, Y0, X1, Y1, retdest
%dup_fp254_2_6
// stack: X1, Y1, X0, Y0, X1, Y1, retdest
%bn_check_twisted_ident
// stack: (X1,Y1)==(0,0), X0, Y0, X1, Y1, retdest
%jumpi(bn_twisted_add_snd_zero)
// stack: X0, Y0, X1, Y1, retdest

// Check if both points have the same X-coordinate.
%dup_fp254_2_4
// stack: X1, X0, Y0, X1, Y1, retdest
%dup_fp254_2_2
// stack: X0, X1, X0, Y0, X1, Y1, retdest
%eq_fp254_2
// stack: X0 == X1, X0, Y0, X1, Y1, retdest
%jumpi(bn_twisted_add_equal_first_coord)
// stack: X0, Y0, X1, Y1, retdest

// Otherwise, we can use the standard formula.
// Compute lambda = (Y0 - Y1)/(X0 - X1)
%dup_fp254_2_6
// stack: Y1, X0, Y0, X1, Y1, retdest
%dup_fp254_2_4
// stack: Y0, Y1, X0, Y0, X1, Y1, retdest
%sub_fp254_2
// stack: Y0 - Y1, X0, Y0, X1, Y1, retdest
%dup_fp254_2_6
// stack: X1, Y0 - Y1, X0, Y0, X1, Y1, retdest
%dup_fp254_2_4
// stack: X0, X1, Y0 - Y1, X0, Y0, X1, Y1, retdest
%sub_fp254_2
// stack: X0 - X1, Y0 - Y1, X0, Y0, X1, Y1, retdest
%divr_fp254_2
// stack: lambda, X0, Y0, X1, Y1, retdest
%jump(bn_twisted_add_valid_points_with_lambda)

// BN254 twisted elliptic curve addition.
// Assumption: (X0,Y0) == (0,0)
bn_twisted_add_fst_zero:
// stack: X0: 2, Y0: 2, X1: 2, Y1: 2, retdest
// Just return (X1, Y1)
%stack (X0: 2, Y0: 2, X1: 2, Y1: 2, retdest) -> (retdest, X1, Y1)
JUMP

// BN254 twisted elliptic curve addition.
// Assumption: (X1,Y1) == (0,0)
bn_twisted_add_snd_zero:
// stack: X0: 2, Y0: 2, X1: 2, Y1: 2, retdest

// Just return (X0,Y0)
%stack (X0: 2, Y0: 2, X1: 2, Y1: 2, retdest) -> (retdest, X0, Y0)
JUMP

// BN254 twisted elliptic curve addition.
// Assumption: lambda = (Y0 - Y1)/(X0 - X1)
bn_twisted_add_valid_points_with_lambda:
// stack: lambda: 2, X0: 2, Y0: 2, X1: 2, Y1: 2, retdest

// Compute X2 = lambda^2 - X1 - X0
%dup_fp254_2_2
// stack: X0, lambda, X0, Y0, X1, Y1, retdest
%dup_fp254_2_8
// stack: X1, X0, lambda, X0, Y0, X1, Y1, retdest
%dup_fp254_2_4
// stack: lambda, X1, X0, lambda, X0, Y0, X1, Y1, retdest
%dup_fp254_2_0
// stack: lambda, lambda, X1, X0, lambda, X0, Y0, X1, Y1, retdest
%mul_fp254_2
// stack: lambda^2, X1, X0, lambda, X0, Y0, X1, Y1, retdest
%sub_fp254_2
// stack: lambda^2 - X1, X0, lambda, X0, Y0, X1, Y1, retdest
%sub_fp254_2
// stack: X2, lambda, X0, Y0, X1, Y1, retdest

// Compute Y2 = lambda*(X1 - X2) - Y1
%dup_fp254_2_0
// stack: X2, X2, lambda, X0, Y0, X1, Y1, retdest
%dup_fp254_2_10
// stack: X1, X2, X2, lambda, X0, Y0, X1, Y1, retdest
%sub_fp254_2
// stack: X1 - X2, X2, lambda, X0, Y0, X1, Y1, retdest
%dup_fp254_2_4
// stack: lambda, X1 - X2, X2, lambda, X0, Y0, X1, Y1, retdest
%mul_fp254_2
// stack: lambda * (X1 - X2), X2, lambda, X0, Y0, X1, Y1, retdest
%dup_fp254_2_12
// stack: Y1, lambda * (X1 - X2), X2, lambda, X0, Y0, X1, Y1, retdest
%stack (Y1: 2, T: 2) -> (T, Y1)
// stack: lambda * (X1 - X2), Y1, X2, lambda, X0, Y0, X1, Y1, retdest
%sub_fp254_2
// stack: Y2, X2, lambda, X0, Y0, X1, Y1, retdest

// Return X2, Y2
%stack (Y2: 2, X2: 2, lambda: 2, X0: 2, Y0: 2, X1: 2, Y1: 2, retdest) -> (retdest, X2, Y2)
JUMP

// BN254 twisted elliptic curve addition.
// Assumption: (X0,Y0) and (X1,Y1) are valid points and X0 == X1
bn_twisted_add_equal_first_coord:
// stack: X0, Y0, X1, Y1, retdest with X0 == X1

// Check if the points are equal
%dup_fp254_2_2
// stack: Y0, X0, Y0, X1, Y1, retdest
%dup_fp254_2_8
// stack: Y1, Y0, X0, Y0, X1, Y1, retdest
%eq_fp254_2
// stack: Y1 == Y0, X0, Y0, X1, Y1, retdest
%jumpi(bn_twisted_add_equal_points)
// stack: X0, Y0, X1, Y1, retdest

// Otherwise, one is the negation of the other so we can return the identity.
%stack (garbage: 8, retdest) -> (retdest, 0, 0, 0, 0)
// stack: retdest, X=0, Y=0
JUMP


// BN254 twisted elliptic curve addition.
// Assumption: X0 == X1 and Y0 == Y1
// Standard doubling formula.
bn_twisted_add_equal_points:
// stack: X0, Y0, X1, Y1, retdest

// Compute lambda = 3/2 * X0^2 / Y0
%dup_fp254_2_0
// stack: X0, X0, Y0, X1, Y1, retdest
%dup_fp254_2_0
// stack: X0, X0, X0, Y0, X1, Y1, retdest
%mul_fp254_2
// stack: X0^2, X0, Y0, X1, Y1, retdest
PUSH 0X183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea5 // 3/2 in the base field
// stack: 3/2, X0^2, X0, Y0, X1, Y1, retdest
%scale_fp254_2
// stack: 3/2 * X0^2, X0, Y0, X1, Y1, retdest
%dup_fp254_2_4
// stack: Y0, 3/2 * X0^2, X0, Y0, X1, Y1, retdest
%divr_fp254_2
// stack: lambda, X0, Y0, X1, Y1, retdest
%jump(bn_twisted_add_valid_points_with_lambda)

// BN254 twisted elliptic curve doubling.
// Assumption: (X0,Y0) is a valid point.
// Standard doubling formula.
global bn_twisted_double:
// stack: X, Y, retdest
%dup_bn_g2
// stack: X, Y, X, Y, retdest
%bn_check_twisted_ident
// stack: (X,Y)==(0,0), X, Y, retdest
%jumpi(ec_twisted_double_retself)
%dup_bn_g2
// stack: X, Y, X, Y, retdest
%jump(bn_twisted_add_equal_points)

// Convenience macro to call bn_twisted_add and return where we left off.
%macro bn_twisted_add
%stack (X0: 2, Y0: 2, X1: 2, Y1: 2) -> (X0, Y0, X1, Y1, %%after)
%jump(bn_twisted_add)
%%after:
%endmacro

%macro bn_twisted_sub
// stack: X0: 2, Y0: 2, X1: 2, Y1: 2
%swap_fp254_2_4
// stack: Y1, Y0, X1, X0
PUSH 0 PUSH 0
%sub_fp254_2
// stack: -Y1, Y0, X1, X0
%stack (Y1: 2, Y0: 2, X1: 2, X0: 2) -> (X0, Y0, X1, Y1, %%after)
%jump(bn_twisted_add)
%%after:
%endmacro

// Convenience macro to call bn_twisted_double and return where we left off.
%macro bn_twisted_double
%stack (X: 2, Y: 2) -> (X, Y, %%after)
%jump(bn_twisted_double)
%%after:
%endmacro
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,52 @@
MUL // Cheaper than AND
MUL // Cheaper than AND
%endmacro

/// The `ECPAIRING` precompile requires checking that G2
/// inputs are on the correct prime-order subgroup.
/// This macro performs this check, based on the algorithm
/// detailed in <https://eprint.iacr.org/2022/348.pdf>.
%macro bn_check_twisted_subgroup
// stack: Q = (X, Y)
%dup_bn_g2
// stack: Q, Q
%bn_twisted_mul_by_z
// stack: zQ, Q
%dup_bn_g2
// stack: zQ, zQ, Q
%swap_bn_g2_2
// stack: Q, zQ, zQ
%bn_twisted_add
// stack: [z+1]Q, zQ
%swap_bn_g2
// stack: zQ, [z+1]Q
%bn_endomorphism
// stack: phi(zQ), [z+1]Q
%dup_bn_g2
// stack: phi(zQ), phi(zQ), [z+1]Q
%bn_endomorphism
// stack: phi^2(zQ), phi(zQ), [z+1]Q
%dup_bn_g2
// stack: phi^2(zQ), phi^2(zQ), phi(zQ), [z+1]Q
%bn_endomorphism
// stack: phi^3(zQ), phi^2(zQ), phi(zQ), [z+1]Q
%bn_twisted_double
// stack: phi^3([2z]Q), phi^2(zQ), phi(zQ), [z+1]Q
%bn_twisted_sub
// stack: phi^3([2z]Q) - phi^2(zQ), phi(zQ), [z+1]Q
%bn_twisted_sub
// stack: phi^3([2z]Q) - phi^2(zQ) - phi(zQ), [z+1]Q
%bn_twisted_sub
// stack: phi^3([2z]Q) - phi^2(zQ) - phi(zQ) - [z+1]Q
%bn_check_twisted_ident
// stack: is_ident
%endmacro

// Return [(u256::MAX, u256::MAX), (u256::MAX, u256::MAX)] which is used to indicate the input was invalid.
%macro bn_twisted_invalid_input
// stack: retdest
PUSH @U256_MAX
// stack: u256::MAX, retdest
%stack (max, retdest) -> (retdest, max, max, max, max)
JUMP
%endmacro
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Implementation of the BN254 twist endomorphism.

/// Frobenius map over BN254 quadratic extension.
%macro frob_fp254_2
// stack: X = (x, x_)
%conj_fp254_2
// stack: frob(X)
%endmacro

%macro bn_endomorphism
// stack: X: 2, Y: 2
%frob_fp254_2
// stack: X', Y
%swap_fp254_2
// stack: Y, X'
%frob_fp254_2
// stack: Y', X'
PUSH @BN_ENDO_Y_COORD_IM
PUSH @BN_ENDO_Y_COORD_RE
%mul_fp254_2
// stack: φ_y.Y', X'
%swap_fp254_2
// stack: X', φ_y.Y'
PUSH @BN_ENDO_X_COORD_IM
PUSH @BN_ENDO_X_COORD_RE
%mul_fp254_2
// stack: φ_x.X', φ_y.Y'
%endmacro
Loading

0 comments on commit 428ac1b

Please sign in to comment.