Files shuffling

This commit is contained in:
wborgeaud 2022-07-13 18:48:25 +02:00
parent f053932791
commit c8c3cc9a8f
9 changed files with 1326 additions and 174 deletions

View File

@ -22,6 +22,10 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/curve_mul.asm"),
include_str!("asm/curve_add.asm"),
include_str!("asm/moddiv.asm"),
// include_str!("asm/secp256k1/curve_mul.asm"),
// include_str!("asm/secp256k1/curve_add.asm"),
// include_str!("asm/secp256k1/moddiv.asm"),
include_str!("asm/ecrecover.asm"),
include_str!("asm/storage_read.asm"),
include_str!("asm/storage_write.asm"),
];
@ -32,14 +36,7 @@ pub(crate) fn combined_kernel() -> Kernel {
#[cfg(test)]
mod tests {
use std::str::FromStr;
use anyhow::Result;
use ethereum_types::U256;
use rand::{thread_rng, Rng};
use crate::cpu::kernel::aggregator::combined_kernel;
use crate::cpu::kernel::interpreter::run;
#[test]
fn make_kernel() {
@ -47,171 +44,4 @@ mod tests {
let kernel = combined_kernel();
println!("Kernel size: {} bytes", kernel.code.len());
}
fn u256ify<'a>(hexes: impl IntoIterator<Item = &'a str>) -> Result<Vec<U256>> {
Ok(hexes
.into_iter()
.map(U256::from_str)
.collect::<Result<Vec<_>, _>>()?)
}
#[test]
fn test_exp() -> Result<()> {
// Make sure we can parse and assemble the entire kernel.
let kernel = combined_kernel();
let exp = kernel.global_labels["exp"];
let mut rng = thread_rng();
let a = U256([0; 4].map(|_| rng.gen()));
let b = U256([0; 4].map(|_| rng.gen()));
// Random input
let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, a];
let stack_with_kernel = run(&kernel.code, exp, initial_stack);
let initial_stack = vec![b, a];
let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP
let stack_with_opcode = run(&code, 0, initial_stack);
assert_eq!(stack_with_kernel, stack_with_opcode);
// 0 base
let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, U256::zero()];
let stack_with_kernel = run(&kernel.code, exp, initial_stack);
let initial_stack = vec![b, U256::zero()];
let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP
let stack_with_opcode = run(&code, 0, initial_stack);
assert_eq!(stack_with_kernel, stack_with_opcode);
// 0 exponent
let initial_stack = vec![U256::from_str("0xdeadbeef")?, U256::zero(), a];
let stack_with_kernel = run(&kernel.code, exp, initial_stack);
let initial_stack = vec![U256::zero(), a];
let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP
let stack_with_opcode = run(&code, 0, initial_stack);
assert_eq!(stack_with_kernel, stack_with_opcode);
Ok(())
}
#[test]
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"];
let ec_double = kernel.global_labels["ec_double"];
let ec_mul = kernel.global_labels["ec_mul"];
let identity = ("0x0", "0x0");
let invalid = ("0x0", "0x3"); // Not on curve
let point0 = (
"0x1feee7ec986e198890cb83be8b8ba09ee953b3f149db6d9bfdaa5c308a33e58d",
"0x2051cc9a9edd46231604fd88f351e95ec72a285be93e289ac59cb48561efb2c6",
);
let point1 = (
"0x15b64d0a5f329fb672029298be8050f444626e6de11903caffa74b388075be1b",
"0x2d9e07340bd5cd7b70687b98f2500ff930a89a30d7b6a3e04b1b4d345319d234",
);
// point2 = point0 + point1
let point2 = (
"0x18659c0e0a8fedcb8747cf463fc7cfa05f667d84e771d0a9521fc1a550688f0c",
"0x283ed10b42703e187e7a808aeb45c6b457bc4cc7d704e53b3348a1e3b0bfa55b",
);
// point3 = 2 * point0
let point3 = (
"0x17da2b7b1a01c8dfdf0f5a6415833c7d755d219aa7e2c4cd0ac83d87d0ca4217",
"0xc9ace9de14aac8114541b50c19320eb40f0eeac3621526d9e34dbcf4c3a6c0f",
);
let s = "0xabb2a34c0e7956cfe6cef9ddb7e810c45ea19a6ebadd79c21959af09f5ba480a";
// point4 = s * point0
let point4 = (
"0xe519344959cc17021fe98878f947f5c1b1675325533a620c1684cfa6367e6c0",
"0x7496a7575b0b6a821e19ce780ecc3e0b156e605327798693defeb9f265b7a6f",
);
// Standard addition #1
let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point1.1, point1.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point2.1, point2.0])?);
// Standard addition #2
let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, point0.1, point0.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point2.1, point2.0])?);
// Standard doubling #1
let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point0.1, point0.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point3.1, point3.0])?);
// Standard doubling #2
let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0])?;
let stack = run(&kernel.code, ec_double, initial_stack);
assert_eq!(stack, u256ify([point3.1, point3.0])?);
// Standard doubling #3
let initial_stack = u256ify(["0xdeadbeef", "0x2", point0.1, point0.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, u256ify([point3.1, point3.0])?);
// Addition with identity #1
let initial_stack = u256ify(["0xdeadbeef", identity.1, identity.0, point1.1, point1.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point1.1, point1.0])?);
// Addition with identity #2
let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, identity.1, identity.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point1.1, point1.0])?);
// Addition with identity #3
let initial_stack =
u256ify(["0xdeadbeef", identity.1, identity.0, identity.1, identity.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([identity.1, identity.0])?);
// Addition with invalid point(s) #1
let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, invalid.1, invalid.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, vec![U256::MAX, U256::MAX]);
// Addition with invalid point(s) #2
let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, point0.1, point0.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, vec![U256::MAX, U256::MAX]);
// Addition with invalid point(s) #3
let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, identity.1, identity.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, vec![U256::MAX, U256::MAX]);
// Addition with invalid point(s) #4
let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, invalid.1, invalid.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, vec![U256::MAX, U256::MAX]);
// Scalar multiplication #1
let initial_stack = u256ify(["0xdeadbeef", s, point0.1, point0.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, u256ify([point4.1, point4.0])?);
// Scalar multiplication #2
let initial_stack = u256ify(["0xdeadbeef", "0x0", point0.1, point0.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, u256ify([identity.1, identity.0])?);
// Scalar multiplication #3
let initial_stack = u256ify(["0xdeadbeef", "0x1", point0.1, point0.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, u256ify([point0.1, point0.0])?);
// Scalar multiplication #4
let initial_stack = u256ify(["0xdeadbeef", s, identity.1, identity.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, u256ify([identity.1, identity.0])?);
// Scalar multiplication #5
let initial_stack = u256ify(["0xdeadbeef", s, invalid.1, invalid.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, vec![U256::MAX, U256::MAX]);
// Multiple calls
let ec_mul_hex = format!("0x{:x}", ec_mul);
let initial_stack = u256ify([
"0xdeadbeef",
s,
&ec_mul_hex,
identity.1,
identity.0,
point0.1,
point0.0,
])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point4.1, point4.0])?);
Ok(())
}
}

View File

View File

@ -0,0 +1,340 @@
// #define N 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 // Secp256k1 scalar field order
// Secp256k1 elliptic curve addition.
// Uses the standard affine addition formula.
global ec_add_secp:
JUMPDEST
// stack: x0, y0, x1, y1, retdest
// Check if points are valid Secp256k1 points.
DUP2
// stack: y0, x0, y0, x1, y1, retdest
DUP2
// stack: x0, y0, x0, y0, x1, y1, retdest
%ec_check_secp
// 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_secp
// 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_secp)
// stack: x0, y0, x1, y1, retdest
// Otherwise return
%pop4
// stack: retdest
%ec_invalid_input
// Secp256k1 elliptic curve addition.
// Assumption: (x0,y0) and (x1,y1) are valid points.
global ec_add_valid_points_secp:
JUMPDEST
// stack: x0, y0, x1, y1, retdest
// Check if the first point is the identity.
DUP2
// stack: y0, x0, y0, x1, y1, retdest
DUP2
// 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)
// stack: x0, y0, x1, y1, retdest
// Check if the first 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)
// stack: x0, y0, x1, y1, retdest
// Check if both points have the same x-coordinate.
DUP3
// stack: x1, x0, y0, x1, y1, retdest
DUP2
// stack: x0, x1, x0, y0, x1, y1, retdest
EQ
// stack: x0 == x1, x0, y0, x1, y1, retdest
%jumpi(ec_add_equal_first_coord)
// stack: x0, y0, x1, y1, retdest
// Otherwise, we can use the standard formula.
// Compute lambda = (y0 - y1)/(x0 - x1)
DUP4
// stack: y1, x0, y0, x1, y1, retdest
DUP3
// stack: y0, y1, x0, y0, x1, y1, retdest
%submod
// stack: y0 - y1, x0, y0, x1, y1, retdest
DUP4
// stack: x1, y0 - y1, x0, y0, x1, y1, retdest
DUP3
// stack: x0, x1, y0 - y1, x0, y0, x1, y1, retdest
%submod
// stack: x0 - x1, y0 - y1, x0, y0, x1, y1, retdest
%moddiv_secp
// stack: lambda, x0, y0, x1, y1, retdest
%jump(ec_add_valid_points_with_lambda)
// Secp256k1 elliptic curve addition.
// Assumption: (x0,y0) == (0,0)
ec_add_first_zero:
JUMPDEST
// stack: x0, y0, x1, y1, retdest
// Just return (x1,y1)
%pop2
// stack: x1, y1, retdest
SWAP1
// stack: y1, x1, retdest
SWAP2
// stack: retdest, x1, y1
JUMP
// Secp256k1 elliptic curve addition.
// Assumption: (x1,y1) == (0,0)
ec_add_snd_zero:
JUMPDEST
// stack: x0, y0, x1, y1, retdest
// Just return (x1,y1)
SWAP2
// stack: x1, y0, x0, y1, retdest
POP
// stack: y0, x0, y1, retdest
SWAP2
// stack: y1, x0, y0, retdest
POP
// stack: x0, y0, retdest
SWAP1
// stack: y0, x0, retdest
SWAP2
// stack: retdest, x0, y0
JUMP
// Secp256k1 elliptic curve addition.
// Assumption: lambda = (y0 - y1)/(x0 - x1)
ec_add_valid_points_with_lambda:
JUMPDEST
// stack: lambda, x0, y0, x1, y1, retdest
// Compute x2 = lambda^2 - x1 - x0
DUP2
// stack: x0, lambda, x0, y0, x1, y1, retdest
DUP5
// stack: x1, x0, lambda, x0, y0, x1, y1, retdest
%secp_base
// stack: N, x1, x0, lambda, x0, y0, x1, y1, retdest
DUP4
// stack: lambda, N, x1, x0, lambda, x0, y0, x1, y1, retdest
DUP1
// stack: lambda, lambda, N, x1, x0, lambda, x0, y0, x1, y1, retdest
MULMOD
// stack: lambda^2, x1, x0, lambda, x0, y0, x1, y1, retdest
%submod
// stack: lambda^2 - x1, x0, lambda, x0, y0, x1, y1, retdest
%submod
// stack: x2, lambda, x0, y0, x1, y1, retdest
// Compute y2 = lambda*(x1 - x2) - y1
%secp_base
// stack: N, x2, lambda, x0, y0, x1, y1, retdest
DUP2
// stack: x2, N, x2, lambda, x0, y0, x1, y1, retdest
DUP7
// stack: x1, x2, N, x2, lambda, x0, y0, x1, y1, retdest
%submod
// stack: x1 - x2, N, x2, lambda, x0, y0, x1, y1, retdest
DUP4
// stack: lambda, x1 - x2, N, x2, lambda, x0, y0, x1, y1, retdest
MULMOD
// stack: lambda * (x1 - x2), x2, lambda, x0, y0, x1, y1, retdest
DUP7
// stack: y1, lambda * (x1 - x2), x2, lambda, x0, y0, x1, y1, retdest
SWAP1
// stack: lambda * (x1 - x2), y1, x2, lambda, x0, y0, x1, y1, retdest
%submod
// stack: y2, x2, lambda, x0, y0, x1, y1, retdest
// Return x2,y2
SWAP5
// stack: x1, x2, lambda, x0, y0, y2, y1, retdest
POP
// stack: x2, lambda, x0, y0, y2, y1, retdest
SWAP5
// stack: y1, lambda, x0, y0, y2, x2, retdest
%pop4
// stack: y2, x2, retdest
SWAP2
// stack: retdest, x2, y2
JUMP
// Secp256k1 elliptic curve addition.
// Assumption: (x0,y0) and (x1,y1) are valid points and x0 == x1
ec_add_equal_first_coord:
JUMPDEST
// stack: x0, y0, x1, y1, retdest with x0 == x1
// Check if the points are equal
DUP2
// stack: y0, x0, y0, x1, y1, retdest
DUP5
// stack: y1, y0, x0, y0, x1, y1, retdest
EQ
// stack: y1 == y0, x0, y0, x1, y1, retdest
%jumpi(ec_add_equal_points)
// stack: x0, y0, x1, y1, retdest
// Otherwise, one is the negation of the other so we can return (0,0).
%pop4
// stack: retdest
PUSH 0
// stack: 0, retdest
PUSH 0
// stack: 0, 0, retdest
SWAP2
// stack: retdest, 0, 0
JUMP
// Secp256k1 elliptic curve addition.
// Assumption: x0 == x1 and y0 == y1
// Standard doubling formula.
ec_add_equal_points:
JUMPDEST
// stack: x0, y0, x1, y1, retdest
// Compute lambda = 3/2 * x0^2 / y0
%secp_base
// stack: N, x0, y0, x1, y1, retdest
%secp_base
// stack: N, N, x0, y0, x1, y1, retdest
DUP3
// stack: x0, N, N, x0, y0, x1, y1, retdest
DUP1
// stack: x0, x0, N, N, x0, y0, x1, y1, retdest
MULMOD
// stack: x0^2, N, x0, y0, x1, y1, retdest with
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffe19 // 3/2 in the base field
// stack: 3/2, x0^2, N, x0, y0, x1, y1, retdest
MULMOD
// stack: 3/2 * x0^2, x0, y0, x1, y1, retdest
DUP3
// stack: y0, 3/2 * x0^2, x0, y0, x1, y1, retdest
%moddiv_secp
// stack: lambda, x0, y0, x1, y1, retdest
%jump(ec_add_valid_points_with_lambda)
// BN254 elliptic curve doubling.
// Assumption: (x0,y0) is a valid point.
// Standard doubling formula.
global ec_double_secp:
JUMPDEST
// stack: x0, y0, retdest
DUP2
// stack: y0, x0, y0, retdest
DUP2
// stack: x0, y0, x0, y0, retdest
%jump(ec_add_equal_points)
// Push the order of the Secp256k1 scalar field.
%macro secp_base
PUSH 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
%endmacro
// Assumption: x, y < N and 2N < 2^256.
// Note: Doesn't hold for Secp256k1 base field.
%macro submod_secp
// stack: x, y
SWAP1
// stack: y, x
DUP2
// stack: x, y, x
SUB
// stack: x - y, x
DUP1
// stack: x - y, x - y, x
SWAP2
// stack: x, x - y, x - y
LT
// stack: x < x - y, x - y
%secp_base
// stack: N, x < x - y, x - y
MUL
// stack: N * (x < x - y), x - y
ADD
// (x-y) % N
%endmacro
// 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
// stack: x, y
%secp_base
// stack: N, x, y
DUP2
// stack: x, N, x, y
LT
// stack: x < N, x, y
%secp_base
// stack: N, x < N, x, y
DUP4
// stack: y, N, x < N, x, y
LT
// stack: y < N, x < N, x, y
AND
// stack: (y < N) & (x < N), x, y
SWAP2
// stack: y, x, (y < N) & (x < N), x
SWAP1
// stack: x, y, (y < N) & (x < N)
%secp_base
// stack: N, x, y, b
%secp_base
// stack: N, N, x, y, b
DUP3
// stack: x, N, N, x, y, b
%secp_base
// stack: N, x, N, N, x, y, b
DUP2
// stack: x, N, x, N, N, x, y, b
DUP1
// stack: x, x, N, x, N, N, x, y, b
MULMOD
// stack: x^2 % N, x, N, N, x, y, b
MULMOD
// stack: x^3 % N, N, x, y, b
PUSH 3
// stack: 3, x^3 % N, N, x, y, b
ADDMOD
// stack: (x^3 + 3) % N, x, y, b
DUP3
// stack: y, (x^3 + 3) % N, x, y, b
%secp_base
// stack: N, y, (x^3 + 3) % N, x, y, b
SWAP1
// stack: y, N, (x^3 + 3) % N, x, y, b
DUP1
// stack: y, y, N, (x^3 + 3) % N, x, y, b
MULMOD
// stack: y^2 % N, (x^3 + 3) % N, x, y, b
EQ
// stack: y^2 % N == (x^3 + 3) % N, x, y, b
SWAP2
// stack: y, x, y^2 % N == (x^3 + 3) % N, b
%ec_isidentity
// stack: (x,y)==(0,0), y^2 % N == (x^3 + 3) % N, b
SWAP2
// stack: b, y^2 % N == (x^3 + 3) % N, (x,y)==(0,0)
AND
// stack: y^2 % N == (x^3 + 3) % N & (x < N) & (y < N), (x,y)==(0,0)
OR
// stack: y^2 % N == (x^3 + 3) % N & (x < N) & (y < N) || (x,y)==(0,0)
%endmacro

View File

@ -0,0 +1,788 @@
/// Division modulo 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f, the Secp256k1 base field order
/// To replace with more efficient method using non-determinism later.
// Returns y * (x^-1) where the inverse is taken modulo N
%macro moddiv_secp
// stack: x, y
%inverse
// stack: x^-1, y
%mulmodn
%endmacro
%macro mulmodn_secp
// stack: x, y
%secp_base
// stack: N, x, y
SWAP2
// stack: y, x, N
MULMOD
%endmacro
%macro squaremodn_secp
// stack: x
DUP1
// stack: x, x
%mulmodn_secp
%endmacro
// Computes the inverse modulo N using x^-1 = x^(N-2) mod N and square-and-multiply modular exponentiation.
%macro inverse
DUP1
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
%squaremodn
%squaremodn
%squaremodn
%squaremodn
DUP2
%mulmodn
%squaremodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
%squaremodn
DUP2
%mulmodn
SWAP1
// stack: x, x^-1
POP
// stack: x^-1
%endmacro

View File

@ -6,6 +6,8 @@ mod parser;
#[cfg(test)]
mod interpreter;
#[cfg(test)]
mod tests;
use assembler::assemble;
use parser::parse;

View File

@ -0,0 +1,134 @@
#[cfg(test)]
mod bn {
use anyhow::Result;
use ethereum_types::U256;
use crate::cpu::kernel::aggregator::combined_kernel;
use crate::cpu::kernel::interpreter::run;
use crate::cpu::kernel::tests::u256ify;
#[test]
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"];
let ec_double = kernel.global_labels["ec_double"];
let ec_mul = kernel.global_labels["ec_mul"];
let identity = ("0x0", "0x0");
let invalid = ("0x0", "0x3"); // Not on curve
let point0 = (
"0x1feee7ec986e198890cb83be8b8ba09ee953b3f149db6d9bfdaa5c308a33e58d",
"0x2051cc9a9edd46231604fd88f351e95ec72a285be93e289ac59cb48561efb2c6",
);
let point1 = (
"0x15b64d0a5f329fb672029298be8050f444626e6de11903caffa74b388075be1b",
"0x2d9e07340bd5cd7b70687b98f2500ff930a89a30d7b6a3e04b1b4d345319d234",
);
// point2 = point0 + point1
let point2 = (
"0x18659c0e0a8fedcb8747cf463fc7cfa05f667d84e771d0a9521fc1a550688f0c",
"0x283ed10b42703e187e7a808aeb45c6b457bc4cc7d704e53b3348a1e3b0bfa55b",
);
// point3 = 2 * point0
let point3 = (
"0x17da2b7b1a01c8dfdf0f5a6415833c7d755d219aa7e2c4cd0ac83d87d0ca4217",
"0xc9ace9de14aac8114541b50c19320eb40f0eeac3621526d9e34dbcf4c3a6c0f",
);
let s = "0xabb2a34c0e7956cfe6cef9ddb7e810c45ea19a6ebadd79c21959af09f5ba480a";
// point4 = s * point0
let point4 = (
"0xe519344959cc17021fe98878f947f5c1b1675325533a620c1684cfa6367e6c0",
"0x7496a7575b0b6a821e19ce780ecc3e0b156e605327798693defeb9f265b7a6f",
);
// Standard addition #1
let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point1.1, point1.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point2.1, point2.0])?);
// Standard addition #2
let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, point0.1, point0.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point2.1, point2.0])?);
// Standard doubling #1
let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, point0.1, point0.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point3.1, point3.0])?);
// Standard doubling #2
let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0])?;
let stack = run(&kernel.code, ec_double, initial_stack);
assert_eq!(stack, u256ify([point3.1, point3.0])?);
// Standard doubling #3
let initial_stack = u256ify(["0xdeadbeef", "0x2", point0.1, point0.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, u256ify([point3.1, point3.0])?);
// Addition with identity #1
let initial_stack = u256ify(["0xdeadbeef", identity.1, identity.0, point1.1, point1.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point1.1, point1.0])?);
// Addition with identity #2
let initial_stack = u256ify(["0xdeadbeef", point1.1, point1.0, identity.1, identity.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point1.1, point1.0])?);
// Addition with identity #3
let initial_stack =
u256ify(["0xdeadbeef", identity.1, identity.0, identity.1, identity.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([identity.1, identity.0])?);
// Addition with invalid point(s) #1
let initial_stack = u256ify(["0xdeadbeef", point0.1, point0.0, invalid.1, invalid.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, vec![U256::MAX, U256::MAX]);
// Addition with invalid point(s) #2
let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, point0.1, point0.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, vec![U256::MAX, U256::MAX]);
// Addition with invalid point(s) #3
let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, identity.1, identity.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, vec![U256::MAX, U256::MAX]);
// Addition with invalid point(s) #4
let initial_stack = u256ify(["0xdeadbeef", invalid.1, invalid.0, invalid.1, invalid.0])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, vec![U256::MAX, U256::MAX]);
// Scalar multiplication #1
let initial_stack = u256ify(["0xdeadbeef", s, point0.1, point0.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, u256ify([point4.1, point4.0])?);
// Scalar multiplication #2
let initial_stack = u256ify(["0xdeadbeef", "0x0", point0.1, point0.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, u256ify([identity.1, identity.0])?);
// Scalar multiplication #3
let initial_stack = u256ify(["0xdeadbeef", "0x1", point0.1, point0.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, u256ify([point0.1, point0.0])?);
// Scalar multiplication #4
let initial_stack = u256ify(["0xdeadbeef", s, identity.1, identity.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, u256ify([identity.1, identity.0])?);
// Scalar multiplication #5
let initial_stack = u256ify(["0xdeadbeef", s, invalid.1, invalid.0])?;
let stack = run(&kernel.code, ec_mul, initial_stack);
assert_eq!(stack, vec![U256::MAX, U256::MAX]);
// Multiple calls
let ec_mul_hex = format!("0x{:x}", ec_mul);
let initial_stack = u256ify([
"0xdeadbeef",
s,
&ec_mul_hex,
identity.1,
identity.0,
point0.1,
point0.0,
])?;
let stack = run(&kernel.code, ec_add, initial_stack);
assert_eq!(stack, u256ify([point4.1, point4.0])?);
Ok(())
}
}

View File

@ -0,0 +1,44 @@
use std::str::FromStr;
use anyhow::Result;
use ethereum_types::U256;
use rand::{thread_rng, Rng};
use crate::cpu::kernel::aggregator::combined_kernel;
use crate::cpu::kernel::interpreter::run;
#[test]
fn test_exp() -> Result<()> {
// Make sure we can parse and assemble the entire kernel.
let kernel = combined_kernel();
let exp = kernel.global_labels["exp"];
let mut rng = thread_rng();
let a = U256([0; 4].map(|_| rng.gen()));
let b = U256([0; 4].map(|_| rng.gen()));
// Random input
let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, a];
let stack_with_kernel = run(&kernel.code, exp, initial_stack);
let initial_stack = vec![b, a];
let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP
let stack_with_opcode = run(&code, 0, initial_stack);
assert_eq!(stack_with_kernel, stack_with_opcode);
// 0 base
let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, U256::zero()];
let stack_with_kernel = run(&kernel.code, exp, initial_stack);
let initial_stack = vec![b, U256::zero()];
let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP
let stack_with_opcode = run(&code, 0, initial_stack);
assert_eq!(stack_with_kernel, stack_with_opcode);
// 0 exponent
let initial_stack = vec![U256::from_str("0xdeadbeef")?, U256::zero(), a];
let stack_with_kernel = run(&kernel.code, exp, initial_stack);
let initial_stack = vec![U256::zero(), a];
let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP
let stack_with_opcode = run(&code, 0, initial_stack);
assert_eq!(stack_with_kernel, stack_with_opcode);
Ok(())
}

View File

@ -0,0 +1,14 @@
mod curve_ops;
mod exp;
use std::str::FromStr;
use anyhow::Result;
use ethereum_types::U256;
pub(crate) fn u256ify<'a>(hexes: impl IntoIterator<Item = &'a str>) -> Result<Vec<U256>> {
Ok(hexes
.into_iter()
.map(U256::from_str)
.collect::<Result<Vec<_>, _>>()?)
}