Optimize ecMul precompile (scalar multiplication on BN254) (#852)

* windowed mul

* Working

* Window of 4 bits

* Fix

* Comments

* Unroll loop

* Unroll loop

* remove global

* Minor

* Minor

* Implement `CALLVALUE, CALLDATALOAD, CALLDATASIZE, CALLDATACOPY` in interpreter

* Minor

* Doesn't work

* Minor

* Minor

* wnaf msm

* Working hardcoded values: 28657 opcodes

* Working wnaf

* Small wnaf optim

* Precompute works

* Working together

* Bump to 129 bits

* Working glv decomposition

* Working MSM with GLV

* Almost working

* Working

* ECC test folder

* Working with real sig data

* Fix tests + Clippy

* Minor

* Cleaning

* Comments

* Cleaning

* Smaller glv test file

* Print opcode count at the end of interpreter run

* More constants

* Add z3 proof that the GLV scalars are 129-bit or less

* Minor change to z3 proof

* Move files and renaming fns

* Testing

* Fix BN GLV

* BN precompute table

* Working precompute

* Working bn tests

* Working

* Minor

* Minor

* Use MULFP254

* Minor

* Merge conflicts

* Remove unused asm file

* ECC fns renaming (#874)

* PR feedback
This commit is contained in:
wborgeaud 2023-02-13 20:11:32 +01:00 committed by GitHub
parent 3332fbb483
commit ac40bd5f5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1566 additions and 156 deletions

View File

@ -27,6 +27,9 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/curve/bn254/curve_add.asm"),
include_str!("asm/curve/bn254/curve_mul.asm"),
include_str!("asm/curve/bn254/moddiv.asm"),
include_str!("asm/curve/bn254/glv.asm"),
include_str!("asm/curve/bn254/msm.asm"),
include_str!("asm/curve/bn254/precomputation.asm"),
include_str!("asm/curve/common.asm"),
include_str!("asm/curve/secp256k1/curve_add.asm"),
include_str!("asm/curve/secp256k1/ecrecover.asm"),
@ -35,6 +38,7 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/curve/secp256k1/moddiv.asm"),
include_str!("asm/curve/secp256k1/glv.asm"),
include_str!("asm/curve/secp256k1/precomputation.asm"),
include_str!("asm/curve/wnaf.asm"),
include_str!("asm/exp.asm"),
include_str!("asm/fields/fp6_macros.asm"),
include_str!("asm/fields/fp6_mul.asm"),

View File

@ -2,7 +2,7 @@
// BN254 elliptic curve addition.
// Uses the standard affine addition formula.
global ec_add:
global bn_add:
// Uncomment for test inputs.
// PUSH 0xdeadbeef
// PUSH 2
@ -16,27 +16,27 @@ global ec_add:
// stack: y0, x0, y0, x1, y1, retdest
DUP2
// stack: x0, y0, x0, y0, x1, y1, retdest
%ec_check
%bn_check
// stack: isValid(x0, y0), x0, y0, x1, y1, retdest
DUP5
// stack: x1, isValid(x0, y0), x0, y0, x1, y1, retdest
DUP5
// stack: x1, y1, isValid(x0, y0), x0, y0, x1, y1, retdest
%ec_check
%bn_check
// stack: isValid(x1, y1), isValid(x0, y0), x0, y0, x1, y1, retdest
AND
// stack: isValid(x1, y1) & isValid(x0, y0), x0, y0, x1, y1, retdest
%jumpi(ec_add_valid_points)
%jumpi(bn_add_valid_points)
// stack: x0, y0, x1, y1, retdest
// Otherwise return
%pop4
// stack: retdest
%ec_invalid_input
%bn_invalid_input
// BN254 elliptic curve addition.
// Assumption: (x0,y0) and (x1,y1) are valid points.
global ec_add_valid_points:
global bn_add_valid_points:
// stack: x0, y0, x1, y1, retdest
// Check if the first point is the identity.
@ -46,17 +46,17 @@ global ec_add_valid_points:
// stack: x0, y0, x0, y0, x1, y1, retdest
%ec_isidentity
// stack: (x0,y0)==(0,0), x0, y0, x1, y1, retdest
%jumpi(ec_add_first_zero)
%jumpi(bn_add_first_zero)
// stack: x0, y0, x1, y1, retdest
// Check if the first point is the identity.
// Check if the second point is the identity.
DUP4
// stack: y1, x0, y0, x1, y1, retdest
DUP4
// stack: x1, y1, x0, y0, x1, y1, retdest
%ec_isidentity
// stack: (x1,y1)==(0,0), x0, y0, x1, y1, retdest
%jumpi(ec_add_snd_zero)
%jumpi(bn_add_snd_zero)
// stack: x0, y0, x1, y1, retdest
// Check if both points have the same x-coordinate.
@ -66,7 +66,7 @@ global ec_add_valid_points:
// stack: x0, x1, x0, y0, x1, y1, retdest
EQ
// stack: x0 == x1, x0, y0, x1, y1, retdest
%jumpi(ec_add_equal_first_coord)
%jumpi(bn_add_equal_first_coord)
// stack: x0, y0, x1, y1, retdest
// Otherwise, we can use the standard formula.
@ -85,11 +85,11 @@ global ec_add_valid_points:
// stack: x0 - x1, y0 - y1, x0, y0, x1, y1, retdest
%moddiv
// stack: lambda, x0, y0, x1, y1, retdest
%jump(ec_add_valid_points_with_lambda)
%jump(bn_add_valid_points_with_lambda)
// BN254 elliptic curve addition.
// Assumption: (x0,y0) == (0,0)
ec_add_first_zero:
bn_add_first_zero:
// stack: x0, y0, x1, y1, retdest
// Just return (x1,y1)
%stack (x0, y0, x1, y1, retdest) -> (retdest, x1, y1)
@ -97,7 +97,7 @@ ec_add_first_zero:
// BN254 elliptic curve addition.
// Assumption: (x1,y1) == (0,0)
ec_add_snd_zero:
bn_add_snd_zero:
// stack: x0, y0, x1, y1, retdest
// Just return (x0,y0)
@ -106,7 +106,7 @@ ec_add_snd_zero:
// BN254 elliptic curve addition.
// Assumption: lambda = (y0 - y1)/(x0 - x1)
ec_add_valid_points_with_lambda:
bn_add_valid_points_with_lambda:
// stack: lambda, x0, y0, x1, y1, retdest
// Compute x2 = lambda^2 - x1 - x0
@ -153,7 +153,7 @@ ec_add_valid_points_with_lambda:
// BN254 elliptic curve addition.
// Assumption: (x0,y0) and (x1,y1) are valid points and x0 == x1
ec_add_equal_first_coord:
bn_add_equal_first_coord:
// stack: x0, y0, x1, y1, retdest with x0 == x1
// Check if the points are equal
@ -163,7 +163,7 @@ ec_add_equal_first_coord:
// stack: y1, y0, x0, y0, x1, y1, retdest
EQ
// stack: y1 == y0, x0, y0, x1, y1, retdest
%jumpi(ec_add_equal_points)
%jumpi(bn_add_equal_points)
// stack: x0, y0, x1, y1, retdest
// Otherwise, one is the negation of the other so we can return (0,0).
@ -181,7 +181,7 @@ ec_add_equal_first_coord:
// BN254 elliptic curve addition.
// Assumption: x0 == x1 and y0 == y1
// Standard doubling formula.
ec_add_equal_points:
bn_add_equal_points:
// stack: x0, y0, x1, y1, retdest
// Compute lambda = 3/2 * x0^2 / y0
@ -203,18 +203,19 @@ ec_add_equal_points:
// stack: y0, 3/2 * x0^2, x0, y0, x1, y1, retdest
%moddiv
// stack: lambda, x0, y0, x1, y1, retdest
%jump(ec_add_valid_points_with_lambda)
%jump(bn_add_valid_points_with_lambda)
// BN254 elliptic curve doubling.
// Assumption: (x0,y0) is a valid point.
// Standard doubling formula.
global ec_double:
// stack: x0, y0, retdest
DUP2
// stack: y0, x0, y0, retdest
DUP2
// stack: x0, y0, x0, y0, retdest
%jump(ec_add_equal_points)
global bn_double:
// stack: x, y, retdest
DUP2 DUP2 %ec_isidentity
// stack: (x,y)==(0,0), x, y, retdest
%jumpi(ec_double_retself)
DUP2 DUP2
// stack: x, y, x, y, retdest
%jump(bn_add_equal_points)
// Push the order of the BN254 base field.
%macro bn_base
@ -241,7 +242,7 @@ global ec_double:
// Check if (x,y) is a valid curve point.
// Puts y^2 % N == (x^3 + 3) % N & (x < N) & (y < N) || (x,y)==(0,0) on top of the stack.
%macro ec_check
%macro bn_check
// stack: x, y
%bn_base
// stack: N, x, y
@ -291,17 +292,8 @@ global ec_double:
// stack: y^2 % N == (x^3 + 3) % N & (x < N) & (y < N) || (x,y)==(0,0)
%endmacro
// Check if (x,y)==(0,0)
%macro ec_isidentity
// stack: x, y
OR
// stack: x | y
ISZERO
// stack: (x,y) == (0,0)
%endmacro
// Return (u256::MAX, u256::MAX) which is used to indicate the input was invalid.
%macro ec_invalid_input
%macro bn_invalid_input
// stack: retdest
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// stack: u256::MAX, retdest

View File

@ -1,11 +1,6 @@
// BN254 elliptic curve scalar multiplication.
// Recursive implementation, same algorithm as in `exp.asm`.
global ec_mul:
// Uncomment for test inputs.
// PUSH 0xdeadbeef
// PUSH 0xd
// PUSH 2
// PUSH 1
// Uses GLV, wNAF with w=5, and a MSM algorithm.
global bn_mul:
// stack: x, y, s, retdest
DUP2
// stack: y, x, y, s, retdest
@ -19,77 +14,28 @@ global ec_mul:
// stack: y, x, y, s, retdest
DUP2
// stack: x, y, x, y, s, retdest
%ec_check
%bn_check
// stack: isValid(x, y), x, y, s, retdest
%jumpi(ec_mul_valid_point)
%jumpi(bn_mul_valid_point)
// stack: x, y, s, retdest
%pop3
%ec_invalid_input
%bn_invalid_input
// Same algorithm as in `exp.asm`
ec_mul_valid_point:
// stack: x, y, s, retdest
DUP3
// stack: s, x, y, s, retdest
%jumpi(step_case)
// stack: x, y, s, retdest
%jump(ret_zero_ec_mul)
step_case:
// stack: x, y, s, retdest
PUSH recursion_return
// stack: recursion_return, x, y, s, retdest
PUSH 2
// stack: 2, recursion_return, x, y, s, retdest
DUP5
// stack: s, 2, recursion_return, x, y, s, retdest
DIV
// stack: s / 2, recursion_return, x, y, s, retdest
PUSH step_case_contd
// stack: step_case_contd, s / 2, recursion_return, x, y, s, retdest
DUP5
// stack: y, step_case_contd, s / 2, recursion_return, x, y, s, retdest
DUP5
// stack: x, y, step_case_contd, s / 2, recursion_return, x, y, s, retdest
%jump(ec_double)
// Assumption: 2(x,y) = (x',y')
step_case_contd:
// stack: x', y', s / 2, recursion_return, x, y, s, retdest
%jump(ec_mul_valid_point)
recursion_return:
// stack: x', y', x, y, s, retdest
SWAP4
// stack: s, y', x, y, x', retdest
PUSH 1
// stack: 1, s, y', x, y, x', retdest
AND
// stack: s & 1, y', x, y, x', retdest
SWAP1
// stack: y', s & 1, x, y, x', retdest
SWAP2
// stack: x, s & 1, y', y, x', retdest
SWAP3
// stack: y, s & 1, y', x, x', retdest
SWAP4
// stack: x', s & 1, y', x, y, retdest
SWAP1
// stack: s & 1, x', y', x, y, retdest
%jumpi(odd_scalar)
// stack: x', y', x, y, retdest
SWAP3
// stack: y, y', x, x', retdest
POP
// stack: y', x, x', retdest
SWAP1
// stack: x, y', x', retdest
POP
// stack: y', x', retdest
SWAP2
// stack: retdest, x', y'
bn_mul_valid_point:
%stack (x, y, s, retdest) -> (s, bn_mul_after_glv, x, y, bn_msm, bn_mul_end, retdest)
%jump(bn_glv_decompose)
bn_mul_after_glv:
// stack: bneg, a, b, x, y, bn_msm, bn_mul_end, retdest
// Store bneg at this (otherwise unused) location. Will be used later in the MSM.
%mstore_kernel(@SEGMENT_KERNEL_BN_TABLE_Q, @BN_BNEG_LOC)
// stack: a, b, x, y, bn_msm, bn_mul_end, retdest
PUSH bn_mul_after_a SWAP1 PUSH @SEGMENT_KERNEL_BN_WNAF_A PUSH @BN_SCALAR %jump(wnaf)
bn_mul_after_a:
// stack: b, x, y, bn_msm, bn_mul_end, retdest
PUSH bn_mul_after_b SWAP1 PUSH @SEGMENT_KERNEL_BN_WNAF_B PUSH @BN_SCALAR %jump(wnaf)
bn_mul_after_b:
// stack: x, y, bn_msm, bn_mul_end, retdest
%jump(bn_precompute_table)
bn_mul_end:
%stack (Ax, Ay, retdest) -> (retdest, Ax, Ay)
JUMP
odd_scalar:
// stack: x', y', x, y, retdest
%jump(ec_add_valid_points)

View File

@ -0,0 +1,97 @@
// Inspired by https://github.com/AztecProtocol/weierstrudel/blob/master/huff_modules/endomorphism.huff
// See also Sage code in evm/src/cpu/kernel/tests/ecc/bn_glv_test_data
// Given scalar `k ∈ Bn254::ScalarField`, return `u, k1, k2` with `k1,k2 < 2^127` and such that
// `k = k1 - s*k2` if `u==0` otherwise `k = k1 + s*k2`, where `s` is the scalar value representing the endomorphism.
// In the comments below, N means @BN_SCALAR
//
// Z3 proof that the resulting `k1, k2` satisfy `k1>0`, `k1 < 2^127` and `|k2| < 2^127`.
// ```python
// from z3 import Solver, Int, Or, unsat
// q = 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001
// glv_s = 0xB3C4D79D41A917585BFC41088D8DAAA78B17EA66B99C90DD
//
// b2 = 0x89D3256894D213E3
// b1 = -0x6F4D8248EEB859FC8211BBEB7D4F1128
//
// g1 = 0x24CCEF014A773D2CF7A7BD9D4391EB18D
// g2 = 0x2D91D232EC7E0B3D7
// k = Int("k")
// c1 = Int("c1")
// c2 = Int("c2")
// s = Solver()
//
// c2p = -c2
// s.add(k < q)
// s.add(0 < k)
// s.add(c1 * (2**256) <= g2 * k)
// s.add((c1 + 1) * (2**256) > g2 * k)
// s.add(c2p * (2**256) <= g1 * k)
// s.add((c2p + 1) * (2**256) > g1 * k)
//
// q1 = c1 * b1
// q2 = c2 * b2
//
// k2 = q2 - q1
// k2L = (glv_s * k2) % q
// k1 = k - k2L
// k2 = -k2
//
// s.add(Or((k2 >= 2**127), (-k2 >= 2**127), (k1 >= 2**127), (k1 < 0)))
//
// assert s.check() == unsat
// ```
global bn_glv_decompose:
// stack: k, retdest
PUSH @BN_SCALAR DUP1 DUP1
// Compute c2 which is the top 256 bits of k*g1. Use asm from https://medium.com/wicketh/mathemagic-full-multiply-27650fec525d.
PUSH @U256_MAX
// stack: -1, N, N, N, k, retdest
PUSH @BN_GLV_MINUS_G1 DUP6
// stack: k, g1, -1, N, N, N, k, retdest
MULMOD
// stack: (k * g1 % -1), N, N, N, k, retdest
PUSH @BN_GLV_MINUS_G1 DUP6
// stack: k, g1, (k * g1 % -1), N, N, N, k, retdest
MUL
// stack: bottom = (k * g1), (k * g1 % -1), N, N, N, k, retdest
DUP1 DUP3
// stack: (k * g1 % -1), bottom, bottom, (k * g1 % -1), N, N, N, k, retdest
LT SWAP2 SUB SUB
// stack: c2, N, N, N, k, retdest
PUSH @BN_GLV_B2 MULMOD
// stack: q2=c2*b2, N, N, k, retdest
// Use the same trick to compute c1 = top 256 bits of g2*k.
PUSH @BN_SCALAR PUSH @U256_MAX
PUSH @BN_GLV_G2 DUP7 MULMOD
PUSH @BN_GLV_G2 DUP7 MUL
DUP1 DUP3 LT
SWAP2 SUB SUB
// stack: c1, N, q2, N, N, k, retdest
PUSH @BN_GLV_B1 MULMOD
// stack: q1, q2, N, N, k, retdest
// We compute k2 = q1 + q2 - N, but we check for underflow and return N-q1-q2 instead if there is one,
// along with a flag `underflow` set to 1 if there is an underflow, 0 otherwise.
ADD %sub_check_underflow
// stack: k2, underflow, N, k, retdest
SWAP3 PUSH @BN_SCALAR DUP5 PUSH @BN_GLV_S
// stack: s, k2, N, k, underflow, N, k2, retdest
MULMOD
// stack: s*k2, k, underflow, N, k2, retdest
// Need to return `k + s*k2` if no underflow occur, otherwise return `k - s*k2` which is done in the `underflowed` fn.
SWAP2 DUP1 %jumpi(underflowed)
%stack (underflow, k, x, N, k2) -> (k, x, N, k2, underflow)
ADDMOD
%stack (k1, k2, underflow, retdest) -> (retdest, underflow, k1, k2)
JUMP
underflowed:
// stack: underflow, k, s*k2, N, k2
// Compute (k-s*k2)%N. TODO: Use SUBMOD here when ready
%stack (u, k, x, N, k2) -> (N, x, k, N, k2, u)
SUB ADDMOD
%stack (k1, k2, underflow, retdest) -> (retdest, underflow, k1, k2)
JUMP

View File

@ -0,0 +1,73 @@
// Computes the multiplication `a*G` using a standard MSM with the GLV decomposition of `a`.
// see there for a detailed description.
global bn_msm:
// stack: retdest
PUSH 0 PUSH 0 PUSH 0
global bn_msm_loop:
// stack: accx, accy, i, retdest
DUP3 %bn_mload_wnaf_a
// stack: w, accx, accy, i, retdest
DUP1 %jumpi(bn_msm_loop_add_a_nonzero)
POP
msm_loop_add_b:
//stack: accx, accy, i, retdest
DUP3 %bn_mload_wnaf_b
// stack: w, accx, accy, i, retdest
DUP1 %jumpi(bn_msm_loop_add_b_nonzero)
POP
msm_loop_contd:
%stack (accx, accy, i, retdest) -> (i, i, accx, accy, retdest)
// TODO: the GLV scalars for the BN curve are 127-bit, so could use 127 here. But this would require modifying `wnaf.asm`. Not sure it's worth it...
%eq_const(129) %jumpi(msm_end)
%increment
//stack: i+1, accx, accy, retdest
%stack (i, accx, accy, retdest) -> (accx, accy, bn_msm_loop, i, retdest)
%jump(bn_double)
msm_end:
%stack (i, accx, accy, retdest) -> (retdest, accx, accy)
JUMP
bn_msm_loop_add_a_nonzero:
%stack (w, accx, accy, i, retdest) -> (w, accx, accy, msm_loop_add_b, i, retdest)
%bn_mload_point_a
// stack: px, py, accx, accy, msm_loop_add_b, i, retdest
%jump(bn_add_valid_points)
bn_msm_loop_add_b_nonzero:
%stack (w, accx, accy, i, retdest) -> (w, accx, accy, msm_loop_contd, i, retdest)
%bn_mload_point_b
// stack: px, py, accx, accy, msm_loop_contd, i, retdest
%jump(bn_add_valid_points)
%macro bn_mload_wnaf_a
// stack: i
%mload_kernel(@SEGMENT_KERNEL_BN_WNAF_A)
%endmacro
%macro bn_mload_wnaf_b
// stack: i
%mload_kernel(@SEGMENT_KERNEL_BN_WNAF_B)
%endmacro
%macro bn_mload_point_a
// stack: w
DUP1
%mload_kernel(@SEGMENT_KERNEL_BN_TABLE_Q)
//stack: Gy, w
SWAP1 %decrement %mload_kernel(@SEGMENT_KERNEL_BN_TABLE_Q)
//stack: Gx, Gy
%endmacro
%macro bn_mload_point_b
// stack: w
DUP1
%mload_kernel(@SEGMENT_KERNEL_BN_TABLE_Q)
PUSH @BN_BNEG_LOC %mload_kernel(@SEGMENT_KERNEL_BN_TABLE_Q)
%stack (bneg, Gy, w) -> (@BN_BASE, Gy, bneg, bneg, Gy, w)
SUB SWAP1 ISZERO MUL SWAP2 MUL ADD
SWAP1 %decrement %mload_kernel(@SEGMENT_KERNEL_BN_TABLE_Q)
//stack: Gx, Gy
PUSH @BN_GLV_BETA
MULFP254
%endmacro

View File

@ -0,0 +1,35 @@
// Precompute a table of multiples of the BN254 point `Q = (Qx, Qy)`.
// Let `(Qxi, Qyi) = i * Q`, then store in the `SEGMENT_KERNEL_BN_TABLE_Q` segment of memory the values
// `i-1 => Qxi`, `i => Qyi if i < 16 else -Qy(32-i)` for `i in range(1, 32, 2)`.
global bn_precompute_table:
// stack: Qx, Qy, retdest
PUSH precompute_table_contd DUP3 DUP3
%jump(bn_double)
precompute_table_contd:
// stack: Qx2, Qy2, Qx, Qy, retdest
PUSH 1
bn_precompute_table_loop:
// stack i, Qx2, Qy2, Qx, Qy, retdest
PUSH 1 DUP2 SUB
%stack (im, i, Qx2, Qy2, Qx, Qy, retdest) -> (i, Qy, im, Qx, i, Qx2, Qy2, Qx, Qy, retdest)
%mstore_kernel(@SEGMENT_KERNEL_BN_TABLE_Q) %mstore_kernel(@SEGMENT_KERNEL_BN_TABLE_Q)
// stack: i, Qx2, Qy2, Qx, Qy, retdest
DUP1 PUSH 32 SUB PUSH 1 DUP2 SUB
// stack: 31-i, 32-i, i, Qx2, Qy2, Qx, Qy, retdest
DUP7 PUSH @BN_BASE SUB
// TODO: Could maybe avoid storing Qx a second time here, not sure if it would be more efficient.
%stack (Qyy, iii, ii, i, Qx2, Qy2, Qx, Qy, retdest) -> (iii, Qx, ii, Qyy, i, Qx2, Qy2, Qx, Qy, retdest)
%mstore_kernel(@SEGMENT_KERNEL_BN_TABLE_Q) %mstore_kernel(@SEGMENT_KERNEL_BN_TABLE_Q)
// stack: i, Qx2, Qy2, Qx, Qy, retdest
PUSH 2 ADD
// stack: i+2, Qx2, Qy2, Qx, Qy, retdest
DUP1 PUSH 16 LT %jumpi(precompute_table_end)
%stack (i, Qx2, Qy2, Qx, Qy, retdest) -> (Qx, Qy, Qx2, Qy2, precompute_table_loop_contd, i, Qx2, Qy2, retdest)
%jump(bn_add_valid_points)
precompute_table_loop_contd:
%stack (Qx, Qy, i, Qx2, Qy2, retdest) -> (i, Qx2, Qy2, Qx, Qy, retdest)
%jump(bn_precompute_table_loop)
precompute_table_end:
// stack: i, Qx2, Qy2, Qx, Qy, retdest
%pop5 JUMP

View File

@ -9,3 +9,17 @@ global ret_zero_ec_mul:
SWAP2
// stack: retdest, 0, 0
JUMP
global ec_double_retself:
%stack (x, y, retdest) -> (retdest, x, y)
JUMP
// Check if (x,y)==(0,0)
%macro ec_isidentity
// stack: x, y
OR
// stack: x | y
ISZERO
// stack: (x,y) == (0,0)
%endmacro

View File

@ -2,7 +2,7 @@
// Secp256k1 elliptic curve addition.
// Assumption: (x0,y0) and (x1,y1) are valid points.
global ec_add_valid_points_secp:
global secp_add_valid_points:
// stack: x0, y0, x1, y1, retdest
// Check if the first point is the identity.
@ -12,7 +12,7 @@ global ec_add_valid_points_secp:
// stack: x0, y0, x0, y0, x1, y1, retdest
%ec_isidentity
// stack: (x0,y0)==(0,0), x0, y0, x1, y1, retdest
%jumpi(ec_add_first_zero)
%jumpi(secp_add_first_zero)
// stack: x0, y0, x1, y1, retdest
// Check if the second point is the identity.
@ -22,7 +22,7 @@ global ec_add_valid_points_secp:
// stack: x1, y1, x0, y0, x1, y1, retdest
%ec_isidentity
// stack: (x1,y1)==(0,0), x0, y0, x1, y1, retdest
%jumpi(ec_add_snd_zero)
%jumpi(secp_add_snd_zero)
// stack: x0, y0, x1, y1, retdest
// Check if both points have the same x-coordinate.
@ -32,9 +32,9 @@ global ec_add_valid_points_secp:
// stack: x0, x1, x0, y0, x1, y1, retdest
EQ
// stack: x0 == x1, x0, y0, x1, y1, retdest
%jumpi(ec_add_equal_first_coord)
%jumpi(secp_add_equal_first_coord)
// Standard affine addition formula.
global ec_add_valid_points_no_edge_case_secp:
global secp_add_valid_points_no_edge_case:
// stack: x0, y0, x1, y1, retdest
// Compute lambda = (y0 - y1)/(x0 - x1)
DUP4
@ -51,11 +51,11 @@ global ec_add_valid_points_no_edge_case_secp:
// stack: x0 - x1, y0 - y1, x0, y0, x1, y1, retdest
%moddiv_secp_base
// stack: lambda, x0, y0, x1, y1, retdest
%jump(ec_add_valid_points_with_lambda)
%jump(secp_add_valid_points_with_lambda)
// Secp256k1 elliptic curve addition.
// Assumption: (x0,y0) == (0,0)
ec_add_first_zero:
secp_add_first_zero:
// stack: x0, y0, x1, y1, retdest
// Just return (x1,y1)
@ -69,7 +69,7 @@ ec_add_first_zero:
// Secp256k1 elliptic curve addition.
// Assumption: (x1,y1) == (0,0)
ec_add_snd_zero:
secp_add_snd_zero:
// stack: x0, y0, x1, y1, retdest
// Just return (x1,y1)
@ -89,7 +89,7 @@ ec_add_snd_zero:
// Secp256k1 elliptic curve addition.
// Assumption: lambda = (y0 - y1)/(x0 - x1)
ec_add_valid_points_with_lambda:
secp_add_valid_points_with_lambda:
// stack: lambda, x0, y0, x1, y1, retdest
// Compute x2 = lambda^2 - x1 - x0
@ -145,7 +145,7 @@ ec_add_valid_points_with_lambda:
// Secp256k1 elliptic curve addition.
// Assumption: (x0,y0) and (x1,y1) are valid points and x0 == x1
ec_add_equal_first_coord:
secp_add_equal_first_coord:
// stack: x0, y0, x1, y1, retdest with x0 == x1
// Check if the points are equal
@ -155,7 +155,7 @@ ec_add_equal_first_coord:
// stack: y1, y0, x0, y0, x1, y1, retdest
EQ
// stack: y1 == y0, x0, y0, x1, y1, retdest
%jumpi(ec_add_equal_points)
%jumpi(secp_add_equal_points)
// stack: x0, y0, x1, y1, retdest
// Otherwise, one is the negation of the other so we can return (0,0).
@ -173,7 +173,7 @@ ec_add_equal_first_coord:
// Secp256k1 elliptic curve addition.
// Assumption: x0 == x1 and y0 == y1
// Standard doubling formula.
ec_add_equal_points:
secp_add_equal_points:
// Compute lambda = 3/2 * x0^2 / y0
%stack (x0, y0, x1, y1, retdest) -> (x0, x0, @SECP_BASE, @SECP_BASE, x0, y0, x1, y1, retdest)
MULMOD
@ -181,16 +181,16 @@ ec_add_equal_points:
MULMOD
DUP3
%moddiv_secp_base
%jump(ec_add_valid_points_with_lambda)
%jump(secp_add_valid_points_with_lambda)
// Secp256k1 elliptic curve doubling.
// Assumption: (x,y) is a valid point.
// Standard doubling formula.
global ec_double_secp:
global secp_double:
// stack: x, y, retdest
DUP2 DUP2 %ec_isidentity
// stack: (x,y)==(0,0), x, y, retdest
%jumpi(retself)
%jumpi(ec_double_retself)
// Compute lambda = 3/2 * x0^2 / y0
%stack (x, y, retdest) -> (x, x, @SECP_BASE, @SECP_BASE, x, y, retdest)
@ -200,11 +200,7 @@ global ec_double_secp:
DUP3
%moddiv_secp_base
%stack (lambda, x, y, retdest) -> (lambda, x, y, x, y, retdest)
%jump(ec_add_valid_points_with_lambda)
retself:
%stack (x, y, retdest) -> (retdest, x, y)
JUMP
%jump(secp_add_valid_points_with_lambda)
// Push the order of the Secp256k1 scalar field.
%macro secp_base
@ -221,7 +217,7 @@ retself:
// Check if (x,y) is a valid curve point.
// Puts y^2 % N == (x^3 + 3) % N & (x < N) & (y < N) || (x,y)==(0,0) on top of the stack.
%macro ec_check_secp
%macro secp_check
// stack: x, y
%secp_base
// stack: N, x, y

View File

@ -64,13 +64,13 @@ ecrecover_valid_input:
// return msm_with_precomputation([a0, a1, b0, b1], [G, phi(G), Q, phi(Q)]) -- phi is the Secp endomorphism.
ecdsa_msm_with_glv:
%stack (a, b, Qx, Qy, retdest) -> (a, ecdsa_after_glv_a, b, Qx, Qy, retdest)
%jump(glv_decompose)
%jump(secp_glv_decompose)
ecdsa_after_glv_a:
%stack (a1neg, a0, a1, b, Qx, Qy, retdest) -> (b, ecdsa_after_glv_b, a1neg, a0, a1, Qx, Qy, retdest)
%jump(glv_decompose)
%jump(secp_glv_decompose)
ecdsa_after_glv_b:
%stack (b1neg, b0, b1, a1neg, a0, a1, Qx, Qy, retdest) -> (a1neg, b1neg, Qx, Qy, ecdsa_after_precompute, a0, a1, b0, b1, retdest)
%jump(precompute_table)
%jump(secp_precompute_table)
ecdsa_after_precompute:
// stack: a0, a1, b0, b1, retdest
PUSH 0 PUSH 0 PUSH 129 // 129 is the bit length of the GLV exponents
@ -91,11 +91,11 @@ ecdsa_after_precompute_loop:
SWAP1 %mul_const(2)
%mload_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
%stack (Px, Py, i, accx, accy, a0, a1, b0, b1, retdest) -> (Px, Py, accx, accy, ecdsa_after_precompute_loop_contd, i, a0, a1, b0, b1, retdest)
%jump(ec_add_valid_points_secp)
%jump(secp_add_valid_points)
ecdsa_after_precompute_loop_contd:
%stack (accx, accy, i, a0, a1, b0, b1, retdest) -> (i, accx, accy, ecdsa_after_precompute_loop_contd2, i, a0, a1, b0, b1, retdest)
ISZERO %jumpi(ecdsa_after_precompute_loop_end)
%jump(ec_double_secp)
%jump(secp_double)
ecdsa_after_precompute_loop_contd2:
%stack (accx, accy, i, a0, a1, b0, b1, retdest) -> (i, accx, accy, a0, a1, b0, b1, retdest)
%decrement %jump(ecdsa_after_precompute_loop)

View File

@ -1,5 +1,5 @@
// Inspired by https://github.com/AztecProtocol/weierstrudel/blob/master/huff_modules/endomorphism.huff
// See also Sage code in evm/src/cpu/kernel/tests/ecc/glv_test_data
// See also Sage code in evm/src/cpu/kernel/tests/ecc/secp_glv_test_data
// Given scalar `k ∈ Secp256k1::ScalarField`, return `u, k1, k2` with `k1,k2 < 2^129` and such that
// `k = k1 - s*k2` if `u==0` otherwise `k = k1 + s*k2`, where `s` is the scalar value representing the endomorphism.
// In the comments below, N means @SECP_SCALAR
@ -36,7 +36,7 @@
// s.add(Or((k2 >= 2**129), (-k2 >= 2**129), (k1 >= 2**129), (k1 < 0)))
// assert s.check() == unsat
// ```
global glv_decompose:
global secp_glv_decompose:
// stack: k, retdest
PUSH @SECP_SCALAR DUP1 DUP1
// Compute c2 which is the top 256 bits of k*g1. Use asm from https://medium.com/wicketh/mathemagic-full-multiply-27650fec525d.

View File

@ -1,6 +1,6 @@
// Initial stack: Gneg, Qneg, Qx, Qy, retdest
// Compute a*G ± b*phi(G) + c*Q ± d*phi(Q) for a,b,c,d in {0,1}^4 and store its x-coordinate at location `2*(8a+4b+2c+d)` and its y-coordinate at location `2*(8a+4b+2c+d)+1` in the SEGMENT_KERNEL_ECDSA_TABLE segment.
global precompute_table:
global secp_precompute_table:
// First store G, ± phi(G), G ± phi(G)
// Use Gneg for the ±, e.g., ±phi(G) is computed as `Gneg * (-phi(G)) + (1-Gneg)*phi(G)` (note only the y-coordinate needs to be filtered).
// stack: Gneg, Qneg, Qx, Qy, retdest
@ -30,7 +30,7 @@ global precompute_table:
DUP5 PUSH @SECP_BASE SUB MUL ADD
%stack (selectQy, betaQx, Qx, Qy, retdest) -> (2, betaQx, 3, selectQy, betaQx, selectQy, Qx, Qy, precompute_table_contd, retdest)
%mstore_kernel(@SEGMENT_KERNEL_ECDSA_TABLE) %mstore_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
%jump(ec_add_valid_points_no_edge_case_secp)
%jump(secp_add_valid_points_no_edge_case)
precompute_table_contd:
%stack (x, y, retdest) -> (6, x, 7, y, retdest)
%mstore_kernel(@SEGMENT_KERNEL_ECDSA_TABLE) %mstore_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
@ -46,7 +46,7 @@ precompute_table_loop:
PUSH 9 %mload_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
PUSH 8 %mload_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
// stack: Gx, Gy, x, y, precompute_table_loop_contd, x, y, i, retdest
%jump(ec_add_valid_points_secp)
%jump(secp_add_valid_points)
precompute_table_loop_contd:
%stack (Rx, Ry, x, y, i, retdest) -> (i, 8, Rx, i, 9, Ry, x, y, i, retdest)
ADD %mstore_kernel(@SEGMENT_KERNEL_ECDSA_TABLE) ADD %mstore_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
@ -54,14 +54,14 @@ precompute_table_loop_contd:
PUSH 17 %mload_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
PUSH 16 %mload_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
%stack (Gx, Gy, x, y, x, y, i, retdest) -> (Gx, Gy, x, y, precompute_table_loop_contd2, x, y, i, retdest)
%jump(ec_add_valid_points_secp)
%jump(secp_add_valid_points)
precompute_table_loop_contd2:
%stack (Rx, Ry, x, y, i, retdest) -> (i, 16, Rx, i, 17, Ry, x, y, i, retdest)
ADD %mstore_kernel(@SEGMENT_KERNEL_ECDSA_TABLE) ADD %mstore_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
PUSH 25 %mload_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
PUSH 24 %mload_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)
%stack (Gx, Gy, x, y, i, retdest) -> (Gx, Gy, x, y, precompute_table_loop_contd3, i, retdest)
%jump(ec_add_valid_points_secp)
%jump(secp_add_valid_points)
precompute_table_loop_contd3:
%stack (Rx, Ry, i, retdest) -> (i, 24, Rx, i, 25, Ry, i, retdest)
ADD %mstore_kernel(@SEGMENT_KERNEL_ECDSA_TABLE) ADD %mstore_kernel(@SEGMENT_KERNEL_ECDSA_TABLE)

View File

@ -0,0 +1,69 @@
// wNAF expansion with w=5.
// Stores the reversed expansion of the given scalar in memory at the given segment and offsets 0..130.
// Should be called with scalars of bit length <= 129, which is the case when using GLV.
// Pseudo-code:
// def wnaf(n):
// ans = [0 for _ in range(130)]
// o = 0
// while n != 0:
// i = n.trailing_zero_bits()
// o += i
// n >>= i
// m = n & 31
// ans[o] = m
// if m > 16:
// ne += 32
// ne -= m
// return ans
global wnaf:
// stack: N, segment, n, retdest (N is the size of the group in which the mul is taking place)
DUP3 MOD ISZERO %jumpi(wnaf_zero_scalar)
PUSH 0
wnaf_loop:
%stack (o, segment, n, retdest) -> (n, wnaf_loop_contd, o, segment, retdest)
%jump(trailing_zeros)
wnaf_loop_contd:
%stack (n, i, o, segment, retdest) -> (o, i, n, segment, retdest)
ADD
%stack (o, n, segment, retdest) -> (n, segment, o, retdest)
DUP1 %and_const(31) SWAP1
PUSH 16 DUP3 GT
// stack: m>16, n, m, segment, o, retdest
%mul_const(32) ADD
// stack: n, m, segment, o, retdest
DUP2 SWAP1 SUB
%stack (n, m, segment, o, retdest) -> (129, o, m, o, segment, n, retdest)
SUB
%stack (i, m, o, segment, n, retdest) -> (0, segment, i, m, o, segment, n, retdest)
MSTORE_GENERAL
// stack: o, segment, n, retdest
DUP3 ISZERO %jumpi(wnaf_end)
// stack: o, segment, n, retdest
%jump(wnaf_loop)
wnaf_end:
// stack: o, segment, n, retdest
%pop3 JUMP
wnaf_zero_scalar:
// stack: segment, n, retdest
%pop2 JUMP
// Number of trailing zeros computed with a simple loop and returning the scalar without its lsb zeros.
trailing_zeros:
// stack: x, retdest
PUSH 0
trailing_zeros_loop:
// stack: count, x, retdest
PUSH 1 DUP3 AND
// stack: x&1, count, x, retdest
%jumpi(trailing_zeros_end)
// stack: count, x, retdest
%increment SWAP1 PUSH 1 SHR SWAP1
// stack: count, x>>1, retdest
%jump(trailing_zeros_loop)
trailing_zeros_end:
%stack (count, x, retdest) -> (retdest, x, count)
JUMP

View File

@ -63,7 +63,7 @@ const HASH_CONSTANTS: [(&str, [u8; 32]); 2] = [
),
];
const EC_CONSTANTS: [(&str, [u8; 32]); 10] = [
const EC_CONSTANTS: [(&str, [u8; 32]); 18] = [
(
"U256_MAX",
hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
@ -72,6 +72,39 @@ const EC_CONSTANTS: [(&str, [u8; 32]); 10] = [
"BN_BASE",
hex!("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"),
),
(
"BN_SCALAR",
hex!("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"),
),
(
"BN_GLV_BETA",
hex!("000000000000000059e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe"),
),
(
"BN_GLV_S",
hex!("0000000000000000b3c4d79d41a917585bfc41088d8daaa78b17ea66b99c90dd"),
),
(
"BN_GLV_MINUS_G1",
hex!("000000000000000000000000000000024ccef014a773d2cf7a7bd9d4391eb18d"),
),
(
"BN_GLV_G2",
hex!("000000000000000000000000000000000000000000000002d91d232ec7e0b3d7"),
),
(
"BN_GLV_B1",
hex!("30644e72e131a029b85045b68181585cb8e665ff8b011694c1d039a872b0eed9"),
),
(
"BN_GLV_B2",
hex!("00000000000000000000000000000000000000000000000089d3256894d213e3"),
),
(
"BN_BNEG_LOC",
// This just needs to be large enough to not interfere with anything else in SEGMENT_KERNEL_BN_TABLE_Q.
hex!("0000000000000000000000000000000000000000000000000000000000001337"),
),
(
"SECP_BASE",
hex!("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),

File diff suppressed because it is too large Load Diff

View File

@ -4,15 +4,16 @@ mod bn {
use ethereum_types::U256;
use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::interpreter::run_interpreter;
use crate::cpu::kernel::interpreter::{run_interpreter, Interpreter};
use crate::cpu::kernel::tests::u256ify;
use crate::memory::segments::Segment;
#[test]
fn test_ec_ops() -> Result<()> {
// Make sure we can parse and assemble the entire kernel.
let ec_add = KERNEL.global_labels["ec_add"];
let ec_double = KERNEL.global_labels["ec_double"];
let ec_mul = KERNEL.global_labels["ec_mul"];
let ec_add = KERNEL.global_labels["bn_add"];
let ec_double = KERNEL.global_labels["bn_double"];
let ec_mul = KERNEL.global_labels["bn_mul"];
let identity = ("0x0", "0x0");
let invalid = ("0x0", "0x3"); // Not on curve
let point0 = (
@ -130,11 +131,100 @@ mod bn {
Ok(())
}
#[test]
fn test_glv_verify_data() -> Result<()> {
let glv = KERNEL.global_labels["bn_glv_decompose"];
let f = include_str!("bn_glv_test_data");
for line in f.lines().filter(|s| !s.starts_with("//")) {
let mut line = line
.split_whitespace()
.map(|s| U256::from_str_radix(s, 10).unwrap())
.collect::<Vec<_>>();
let k = line.remove(0);
line.reverse();
let mut initial_stack = u256ify(["0xdeadbeef"])?;
initial_stack.push(k);
let mut int = Interpreter::new(&KERNEL.code, glv, initial_stack, &KERNEL.prover_inputs);
int.run()?;
assert_eq!(line, int.stack());
}
Ok(())
}
#[test]
fn test_precomputation() -> Result<()> {
let precompute = KERNEL.global_labels["bn_precompute_table"];
let initial_stack = u256ify([
"0xdeadbeef",
"0x10d7cf0621b6e42c1dbb421f5ef5e1936ca6a87b38198d1935be31e28821d171",
"0x11b7d55f16aaac07de9a0ed8ac2e8023570dbaa78571fc95e553c4b3ba627689",
])?;
let mut int = Interpreter::new(
&KERNEL.code,
precompute,
initial_stack,
&KERNEL.prover_inputs,
);
int.run()?;
let mut computed_table = Vec::new();
for i in 0..32 {
computed_table.push(
int.generation_state
.memory
.mload_general(0, Segment::BnTableQ, i),
);
}
let table = u256ify([
"0x11b7d55f16aaac07de9a0ed8ac2e8023570dbaa78571fc95e553c4b3ba627689",
"0x10d7cf0621b6e42c1dbb421f5ef5e1936ca6a87b38198d1935be31e28821d171",
"0x1565e5587d8566239c23219bc0e1d1d267d19100c3869d0c55b1e3ea4532304e",
"0x19fd9b572558479df062632562113e4d9a3eb655698ee3be9a5350ed23e690ee",
"0x19469e55e27021c0af1310ad266cdf1d9eef6942c80afe9c7b517acf16a2a3e1",
"0x226ec29db9339d7ffb1bc3260f1ca008b804f78553d316c37203118466bb5f5a",
"0x10a16b4786bd1717a031a1948010593173d36ab35535641c9fe41802d639b435",
"0x294fe34d7ec9024c96cfde58311b9ee394ff9f8735d882005fcf0d28709b459d",
"0x300f58e61d4ab1872f6b5fad517c6df1b23468fcfa81154786ec230cb0df6d20",
"0x12ff1d200127d2ba7a0171cadbe0f729fc5acbe95565cc57f07c9fa42c001390",
"0x1045a28c9a35a17b63da593c0137ac08a1fda78430b71755941d3dc501b35272",
"0x2a3f4d91b58179451ec177f599d7eaf79e2555f169fd3e5d2af314600fad299",
"0x21de5680f03b262f53d3252d5ca71bbc5f2c9ff5483fb63abaea1ee7e9cede1d",
"0x144249d3fc4c82327845a38ea51181acb374ab30a1e7ea0f13bc8a8b04d96411",
"0x2ba4ce4289de377397878c1195e21a1d573b02d9463f5c454ec50bdf11aee512",
"0x259a447b42bab48e07388baece550607bc0a8a88e1ea224eba94c6bed08e470e",
"0x2ba4ce4289de377397878c1195e21a1d573b02d9463f5c454ec50bdf11aee512",
"0xaca09f79e76eb9bb117ba07b32c5255db76e0088687a83e818bc55807eeb639",
"0x21de5680f03b262f53d3252d5ca71bbc5f2c9ff5483fb63abaea1ee7e9cede1d",
"0x1c22049ee4e51df7400aa227dc6fd6b0e40cbf60c689e07e2864018bd3a39936",
"0x1045a28c9a35a17b63da593c0137ac08a1fda78430b71755941d3dc501b35272",
"0x2dc05999c5d9889566642e3727e3d9ae1d9f153251d1f6a769715ad0d7822aae",
"0x300f58e61d4ab1872f6b5fad517c6df1b23468fcfa81154786ec230cb0df6d20",
"0x1d653152e009cd6f3e4ed3eba5a061339b269ea8130bfe354ba3ec72ac7ce9b7",
"0x10a16b4786bd1717a031a1948010593173d36ab35535641c9fe41802d639b435",
"0x7146b2562689ddd2180675e5065b97a0281cb0a3299488cdc517eee67e1b7aa",
"0x19469e55e27021c0af1310ad266cdf1d9eef6942c80afe9c7b517acf16a2a3e1",
"0xdf58bd527fe02a9bd3482907264b854df7c730c149eb3c9ca1d7a9271c19ded",
"0x1565e5587d8566239c23219bc0e1d1d267d19100c3869d0c55b1e3ea4532304e",
"0x1666b31bbbd9588bc7ede2911f701a0ffd42b43bfee2e6cea1cd3b29b4966c59",
"0x11b7d55f16aaac07de9a0ed8ac2e8023570dbaa78571fc95e553c4b3ba627689",
"0x1f8c7f6cbf7abbfd9a950397228b76ca2adac21630583d7406625a34505b2bd6",
])?;
assert_eq!(computed_table, table);
Ok(())
}
}
#[cfg(test)]
mod secp {
use anyhow::Result;
use ethereum_types::U256;
@ -146,8 +236,8 @@ mod secp {
fn test_ec_ops() -> Result<()> {
// Make sure we can parse and assemble the entire kernel.
let kernel = combined_kernel();
let ec_add = kernel.global_labels["ec_add_valid_points_secp"];
let ec_double = kernel.global_labels["ec_double_secp"];
let ec_add = kernel.global_labels["secp_add_valid_points"];
let ec_double = kernel.global_labels["secp_double"];
let identity = ("0x0", "0x0");
let point0 = (
"0xc82ccceebd739e646631b7270ed8c33e96c4940b19db91eaf67da6ec92d109b",
@ -207,9 +297,9 @@ mod secp {
#[test]
fn test_glv_verify_data() -> Result<()> {
let glv = KERNEL.global_labels["glv_decompose"];
let glv = KERNEL.global_labels["secp_glv_decompose"];
let f = include_str!("glv_test_data");
let f = include_str!("secp_glv_test_data");
for line in f.lines().filter(|s| !s.starts_with("//")) {
let mut line = line
.split_whitespace()

View File

@ -40,10 +40,13 @@ pub(crate) enum Segment {
ShiftTable = 16,
JumpdestBits = 17,
EcdsaTable = 18,
BnWnafA = 19,
BnWnafB = 20,
BnTableQ = 21,
}
impl Segment {
pub(crate) const COUNT: usize = 19;
pub(crate) const COUNT: usize = 22;
pub(crate) fn all() -> [Self; Self::COUNT] {
[
@ -66,6 +69,9 @@ impl Segment {
Self::ShiftTable,
Self::JumpdestBits,
Self::EcdsaTable,
Self::BnWnafA,
Self::BnWnafB,
Self::BnTableQ,
]
}
@ -91,6 +97,9 @@ impl Segment {
Segment::ShiftTable => "SEGMENT_SHIFT_TABLE",
Segment::JumpdestBits => "SEGMENT_JUMPDEST_BITS",
Segment::EcdsaTable => "SEGMENT_KERNEL_ECDSA_TABLE",
Segment::BnWnafA => "SEGMENT_KERNEL_BN_WNAF_A",
Segment::BnWnafB => "SEGMENT_KERNEL_BN_WNAF_B",
Segment::BnTableQ => "SEGMENT_KERNEL_BN_TABLE_Q",
}
}
@ -116,6 +125,9 @@ impl Segment {
Segment::ShiftTable => 256,
Segment::JumpdestBits => 1,
Segment::EcdsaTable => 256,
Segment::BnWnafA => 8,
Segment::BnWnafB => 8,
Segment::BnTableQ => 256,
}
}
}