mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-10 17:53:06 +00:00
206 lines
6.4 KiB
NASM
206 lines
6.4 KiB
NASM
// ecrecover precompile.
|
|
global ecrecover:
|
|
JUMPDEST
|
|
// stack: hash, v, r, s, retdest
|
|
|
|
// Check if inputs are valid.
|
|
%ecrecover_input_check
|
|
// stack: isValid(v,r,s), hash, v, r, s, retdest
|
|
|
|
// Lift r to an elliptic curve point if possible.
|
|
SWAP2
|
|
// stack: v, hash, isValid(v,r,s), r, s, retdest
|
|
DUP4
|
|
// stack: r, v, hash, isValid(v,r,s), r, s, retdest
|
|
|
|
// Compute v-27 which gives the parity of the y-coordinate of the lifted point.
|
|
SWAP1
|
|
// stack: v, r, hash, isValid(v,r,s), r, s, retdest
|
|
PUSH 27
|
|
// stack: 27, v, r, hash, isValid(v,r,s), r, s, retdest
|
|
SWAP1
|
|
// stack: v, 27, r, hash, isValid(v,r,s), r, s, retdest
|
|
SUB
|
|
// stack: v - 27, r, hash, isValid(v,r,s), r, s, retdest
|
|
SWAP1
|
|
// stack: r, v - 27, hash, isValid(v,r,s), r, s, retdest
|
|
%secp_lift_x
|
|
// stack: y, sqrtOk, hash, isValid(v,r,s), r, s, retdest
|
|
|
|
// If inputs are invalid or lifting fails, abort.
|
|
SWAP3
|
|
// stack: isValid(v,r,s), sqrtOk, hash, y, r, s, retdest
|
|
AND
|
|
// stack: isValid(v,r,s) & sqrtOk, hash, y, r, s, retdest
|
|
%jumpi(ecrecover_valid_input)
|
|
// stack: hash, y, r, s, retdest
|
|
%pop4
|
|
// stack: retdest
|
|
%ecrecover_invalid_input
|
|
|
|
// ecrecover precompile.
|
|
// Assumption: Inputs are valid.
|
|
// Pseudo-code:
|
|
// let P = lift_x(r, recovery_id);
|
|
// let r_inv = r.inverse();
|
|
// let u1 = s * r_inv;
|
|
// let u2 = -hash * r_inv;
|
|
// return u1*P + u2*GENERATOR;
|
|
ecrecover_valid_input:
|
|
JUMPDEST
|
|
// stack: hash, y, r, s, retdest
|
|
|
|
// Compute u1 = s * r^(-1)
|
|
SWAP1
|
|
// stack: y, hash, r, s, retdest
|
|
DUP3
|
|
// stack: r, y, hash, x, s, retdest (r=x)
|
|
%inverse_secp_scalar
|
|
// stack: r^(-1), y, hash, x, s, retdest
|
|
DUP1
|
|
// stack: r^(-1), r^(-1), y, hash, x, s, retdest
|
|
SWAP5
|
|
// stack: s, r^(-1), y, hash, x, r^(-1), retdest
|
|
%mulmodn_secp_scalar
|
|
// stack: u1, y, hash, x, r^(-1), retdest
|
|
|
|
|
|
// Compute (X,Y) = u1 * (x,y)
|
|
PUSH ecrecover_with_first_point
|
|
// stack: ecrecover_with_first_point, u1, y, hash, x, r^(-1), retdest
|
|
SWAP1
|
|
// stack: u1, ecrecover_with_first_point, y, hash, x, r^(-1), retdest
|
|
SWAP2
|
|
// stack: y, ecrecover_with_first_point, u1, hash, x, r^(-1), retdest
|
|
SWAP1
|
|
// stack: ecrecover_with_first_point, y, u1, hash, x, r^(-1), retdest
|
|
SWAP3
|
|
// stack: hash, y, u1, ecrecover_with_first_point, x, r^(-1), retdest
|
|
SWAP4
|
|
// stack: x, y, u1, ecrecover_with_first_point, hash, r^(-1), retdest
|
|
%jump(ec_mul_valid_point_secp)
|
|
|
|
// ecrecover precompile.
|
|
// Assumption: (X,Y) = u1 * P. Result is (X,Y) + u2*GENERATOR
|
|
ecrecover_with_first_point:
|
|
JUMPDEST
|
|
// stack: X, Y, hash, r^(-1), retdest
|
|
%secp_scalar
|
|
// stack: p, X, Y, hash, r^(-1), retdest
|
|
SWAP1
|
|
// stack: X, p, Y, hash, r^(-1), retdest
|
|
SWAP4
|
|
// stack: r^(-1), p, Y, hash, X, retdest
|
|
SWAP2
|
|
// stack: Y, p, r^(-1), hash, X, retdest
|
|
SWAP3
|
|
// stack: hash, p, r^(-1), Y, X, retdest
|
|
|
|
// Compute u2 = -hash * r^(-1)
|
|
MOD
|
|
// stack: hash%p, r^(-1), Y, X, retdest
|
|
%secp_scalar
|
|
// stack: p, hash%p, r^(-1), Y, X, retdest
|
|
SUB
|
|
// stack: -hash, r^(-1), Y, X, retdest
|
|
%mulmodn_secp_scalar
|
|
// stack: u2, Y, X, retdest
|
|
|
|
// Compute u2 * GENERATOR and chain the call to `ec_mul` with a call to `ec_add` to compute PUBKEY = (X,Y) + u2 * GENERATOR,
|
|
// and a call to `final_hashing` to get the final result `SHA3(PUBKEY)[-20:]`.
|
|
PUSH final_hashing
|
|
// stack: final_hashing, u2, Y, X, retdest
|
|
SWAP3
|
|
// stack: X, u2, Y, final_hashing, retdest
|
|
PUSH ec_add_valid_points_secp
|
|
// stack: ec_add_valid_points_secp, X, u2, Y, final_hashing, retdest
|
|
SWAP1
|
|
// stack: X, ec_add_valid_points_secp, u2, Y, final_hashing, retdest
|
|
PUSH 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 // x-coordinate of generator
|
|
// stack: Gx, X, ec_add_valid_points_secp, u2, Y, final_hashing, retdest
|
|
SWAP1
|
|
// stack: X, Gx, ec_add_valid_points_secp, u2, Y, final_hashing, retdest
|
|
PUSH 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 // y-coordinate of generator
|
|
// stack: Gy, X, Gx, ec_add_valid_points_secp, u2, Y, final_hashing, retdest
|
|
SWAP1
|
|
// stack: X, Gy, Gx, ec_add_valid_points_secp, u2, Y, final_hashing, retdest
|
|
SWAP4
|
|
// stack: u2, Gy, Gx, ec_add_valid_points_secp, X, Y, final_hashing, retdest
|
|
SWAP2
|
|
// stack: Gx, Gy, u2, ec_add_valid_points_secp, X, Y, final_hashing, retdest
|
|
%jump(ec_mul_valid_point_secp)
|
|
|
|
// TODO
|
|
final_hashing:
|
|
JUMPDEST
|
|
PUSH 0xdeadbeef
|
|
JUMP
|
|
|
|
// Check if v, r, and s are in correct form.
|
|
// Returns r < N & r!=0 & s < N & s!=0 & (v==28 || v==27).
|
|
%macro ecrecover_input_check
|
|
// stack: hash, v, r, s, retdest
|
|
DUP2
|
|
// stack: v, hash, v, r, s, retdest
|
|
PUSH 27
|
|
// stack: 27, v, hash, v, r, s, retdest
|
|
EQ
|
|
// stack: v==27, hash, v, r, s, retdest
|
|
DUP3
|
|
// stack: v, v==27, hash, v, r, s, retdest
|
|
PUSH 28
|
|
// stack: 28, v, v==27, hash, v, r, s, retdest
|
|
EQ
|
|
// stack: v==28, v==27, hash, v, r, s, retdest
|
|
OR
|
|
// stack: (v==28 || v==27), hash, v, r, s, retdest
|
|
DUP5
|
|
// stack: s, (v==28 || v==27), hash, v, r, s, retdest
|
|
%secp_is_out_of_bounds
|
|
// stack: (s >= N || s==0), (v==28 || v==27), hash, v, r, s, retdest
|
|
DUP5
|
|
// stack: r, (s >= N || s==0), (v==28 || v==27), hash, v, r, s, retdest
|
|
%secp_is_out_of_bounds
|
|
// stack: (r >= N || r==0), (s >= N || s==0), (v==28 || v==27), hash, v, r, s, retdest
|
|
OR
|
|
// stack: (r >= N || r==0 || s >= N || s==0), (v==28 || v==27), hash, v, r, s, retdest
|
|
ISZERO
|
|
// stack: (r < N & r!=0 & s < N & s!=0), (v==28 || v==27), hash, v, r, s, retdest
|
|
AND
|
|
// stack: r < N & r!=0 & s < N & s!=0 & (v==28 || v==27), hash, v, r, s, retdest
|
|
%endmacro
|
|
|
|
%macro secp_is_out_of_bounds
|
|
// stack: x
|
|
DUP1
|
|
// stack: x, x
|
|
ISZERO
|
|
// stack: x==0, x
|
|
SWAP1
|
|
// stack: x, x==0
|
|
%secp_scalar
|
|
// stack: N, x, x==0
|
|
SWAP1
|
|
// stack: x, N, x==0
|
|
LT
|
|
// stack: x < N, x==0
|
|
ISZERO
|
|
// stack: x >= N, x==0
|
|
OR
|
|
// stack: x >= N || x==0
|
|
%endmacro
|
|
|
|
%macro secp_scalar
|
|
PUSH 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
|
|
%endmacro
|
|
|
|
// Return u256::MAX which is used to indicate the input was invalid.
|
|
%macro ecrecover_invalid_input
|
|
// stack: retdest
|
|
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
// stack: u256::MAX, retdest
|
|
SWAP1
|
|
// stack: retdest, u256::MAX
|
|
JUMP
|
|
%endmacro
|