From e93235d07e606f8849f032a653623f95e1ed0747 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 22 Jul 2022 18:26:15 +0200 Subject: [PATCH 01/14] Modify `inverse` asm --- evm/src/cpu/kernel/asm/moddiv.asm | 491 ++---------------------------- 1 file changed, 17 insertions(+), 474 deletions(-) diff --git a/evm/src/cpu/kernel/asm/moddiv.asm b/evm/src/cpu/kernel/asm/moddiv.asm index 891897e5..3340faa9 100644 --- a/evm/src/cpu/kernel/asm/moddiv.asm +++ b/evm/src/cpu/kernel/asm/moddiv.asm @@ -11,7 +11,7 @@ %macro mulmodn // stack: x, y - PUSH 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + %bn_base // stack: N, x, y SWAP2 // stack: y, x, N @@ -25,480 +25,23 @@ %mulmodn %endmacro -// Computes the inverse modulo N using x^-1 = x^(N-2) mod N and square-and-multiply modular exponentiation. +// Computes the inverse modulo N by providing it non-deterministically. %macro inverse - DUP1 - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - %squaremodn - %squaremodn - DUP2 - %mulmodn - %squaremodn - %squaremodn - DUP2 - %mulmodn + // stack: x + PROVER_INPUT + // stack: x^-1, x + %bn_base + // stack: N, x^-1, x + DUP3 + // stack: x, N, x^-1, x + DUP3 + // stack: x^-1, x, N, x^-1, x + MULMOD + // stack: x^-1 * x, x^-1, x + PUSH 1 + // stack: 1, x^-1 * x, x^-1, x + %assert_eq + // stack: x^-1, x SWAP1 // stack: x, x^-1 POP From 0afe98525b8e54b6cbdae7fc1ebcbc319a62a0e9 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 22 Jul 2022 19:25:06 +0200 Subject: [PATCH 02/14] Minor --- evm/src/cpu/kernel/asm/moddiv.asm | 8 ++------ evm/src/cpu/kernel/evm_asm.pest | 2 ++ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/evm/src/cpu/kernel/asm/moddiv.asm b/evm/src/cpu/kernel/asm/moddiv.asm index 3340faa9..630dcc54 100644 --- a/evm/src/cpu/kernel/asm/moddiv.asm +++ b/evm/src/cpu/kernel/asm/moddiv.asm @@ -28,13 +28,9 @@ // Computes the inverse modulo N by providing it non-deterministically. %macro inverse // stack: x - PROVER_INPUT + PROVER_INPUT(ff::bn254_base::inverse) // stack: x^-1, x - %bn_base - // stack: N, x^-1, x - DUP3 - // stack: x, N, x^-1, x - DUP3 + %stack (inv, x) -> (inv, x, @BN_BASE, inv, x) // stack: x^-1, x, N, x^-1, x MULMOD // stack: x^-1 * x, x^-1, x diff --git a/evm/src/cpu/kernel/evm_asm.pest b/evm/src/cpu/kernel/evm_asm.pest index 78938b64..943e8dae 100644 --- a/evm/src/cpu/kernel/evm_asm.pest +++ b/evm/src/cpu/kernel/evm_asm.pest @@ -29,6 +29,8 @@ local_label = { identifier ~ ":" } bytes_item = { ^"BYTES " ~ literal ~ ("," ~ literal)* } push_instruction = { ^"PUSH " ~ push_target } push_target = { literal | identifier | variable | constant } +prover_input_instruction = { ^"PROVER_INPUT " ~ "(" ~ prover_input_fn ~ ")" } // TODO: Can also support extra arguments. +prover_input_fn = { identifier ~ ("::" ~ identifier)*} nullary_instruction = { identifier } file = { SOI ~ item* ~ silent_eoi } From ec97f8497fd736a3aca622ac4316b600e8ad394a Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 23 Jul 2022 11:16:45 +0200 Subject: [PATCH 03/14] Modify parser --- evm/src/cpu/kernel/assembler.rs | 30 ++++++++++++++++++++++++++---- evm/src/cpu/kernel/ast.rs | 4 ++++ evm/src/cpu/kernel/evm_asm.pest | 4 ++-- evm/src/cpu/kernel/mod.rs | 1 + evm/src/cpu/kernel/parser.rs | 9 +++++++++ evm/src/cpu/kernel/prover_input.rs | 8 ++++++++ 6 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 evm/src/cpu/kernel/prover_input.rs diff --git a/evm/src/cpu/kernel/assembler.rs b/evm/src/cpu/kernel/assembler.rs index 4dbc46ca..334220fd 100644 --- a/evm/src/cpu/kernel/assembler.rs +++ b/evm/src/cpu/kernel/assembler.rs @@ -7,6 +7,7 @@ use log::debug; use super::ast::PushTarget; use crate::cpu::kernel::ast::{Literal, StackReplacement}; use crate::cpu::kernel::keccak_util::hash_kernel; +use crate::cpu::kernel::prover_input::ProverInputFn; use crate::cpu::kernel::stack_manipulation::expand_stack_manipulation; use crate::cpu::kernel::{ ast::{File, Item}, @@ -27,15 +28,22 @@ pub struct Kernel { pub(crate) code_hash: [u32; 8], pub(crate) global_labels: HashMap, + + pub(crate) prover_inputs: HashMap, } impl Kernel { - fn new(code: Vec, global_labels: HashMap) -> Self { + fn new( + code: Vec, + global_labels: HashMap, + prover_inputs: HashMap, + ) -> Self { let code_hash = hash_kernel(&code); Self { code, code_hash, global_labels, + prover_inputs, } } } @@ -57,6 +65,7 @@ impl Macro { pub(crate) fn assemble(files: Vec, constants: HashMap) -> Kernel { let macros = find_macros(&files); let mut global_labels = HashMap::new(); + let mut prover_inputs = HashMap::new(); let mut offset = 0; let mut expanded_files = Vec::with_capacity(files.len()); let mut local_labels = Vec::with_capacity(files.len()); @@ -65,7 +74,12 @@ pub(crate) fn assemble(files: Vec, constants: HashMap) -> Ke let expanded_file = expand_repeats(expanded_file); let expanded_file = inline_constants(expanded_file, &constants); let expanded_file = expand_stack_manipulation(expanded_file); - local_labels.push(find_labels(&expanded_file, &mut offset, &mut global_labels)); + local_labels.push(find_labels( + &expanded_file, + &mut offset, + &mut global_labels, + &mut prover_inputs, + )); expanded_files.push(expanded_file); } let mut code = vec![]; @@ -76,7 +90,7 @@ pub(crate) fn assemble(files: Vec, constants: HashMap) -> Ke debug!("Assembled file size: {} bytes", file_len); } assert_eq!(code.len(), offset, "Code length doesn't match offset."); - Kernel::new(code, global_labels) + Kernel::new(code, global_labels, prover_inputs) } fn find_macros(files: &[File]) -> HashMap { @@ -217,6 +231,7 @@ fn find_labels( body: &[Item], offset: &mut usize, global_labels: &mut HashMap, + prover_inputs: &mut HashMap, ) -> HashMap { // Discover the offset of each label in this file. let mut local_labels = HashMap::::new(); @@ -237,6 +252,10 @@ fn find_labels( assert!(old.is_none(), "Duplicate local label: {}", label); } Item::Push(target) => *offset += 1 + push_target_size(target) as usize, + Item::ProverInput(prover_input_fn) => { + prover_inputs.insert(*offset, prover_input_fn.clone()); + *offset += 1; + } Item::StandardOp(_) => *offset += 1, Item::Bytes(bytes) => *offset += bytes.len(), } @@ -283,6 +302,9 @@ fn assemble_file( code.push(get_push_opcode(target_bytes.len() as u8)); code.extend(target_bytes); } + Item::ProverInput(_) => { + code.push(get_opcode("PROVER_INPUT")); + } Item::StandardOp(opcode) => { code.push(get_opcode(&opcode)); } @@ -357,7 +379,7 @@ mod tests { expected_global_labels.insert("function_1".to_string(), 0); expected_global_labels.insert("function_2".to_string(), 3); - let expected_kernel = Kernel::new(expected_code, expected_global_labels); + let expected_kernel = Kernel::new(expected_code, expected_global_labels, HashMap::new()); let program = vec![file_1, file_2]; assert_eq!(assemble(program, HashMap::new()), expected_kernel); diff --git a/evm/src/cpu/kernel/ast.rs b/evm/src/cpu/kernel/ast.rs index 92728104..9580d9c6 100644 --- a/evm/src/cpu/kernel/ast.rs +++ b/evm/src/cpu/kernel/ast.rs @@ -1,6 +1,8 @@ use ethereum_types::U256; use plonky2_util::ceil_div_usize; +use crate::cpu::kernel::prover_input::ProverInputFn; + #[derive(Debug)] pub(crate) struct File { pub(crate) body: Vec, @@ -25,6 +27,8 @@ pub(crate) enum Item { LocalLabelDeclaration(String), /// A `PUSH` operation. Push(PushTarget), + /// A `ProverInput` operation. + ProverInput(ProverInputFn), /// Any opcode besides a PUSH opcode. StandardOp(String), /// Literal hex data; should contain an even number of hex chars. diff --git a/evm/src/cpu/kernel/evm_asm.pest b/evm/src/cpu/kernel/evm_asm.pest index 943e8dae..b0033391 100644 --- a/evm/src/cpu/kernel/evm_asm.pest +++ b/evm/src/cpu/kernel/evm_asm.pest @@ -15,7 +15,7 @@ literal = { literal_hex | literal_decimal } variable = ${ "$" ~ identifier } constant = ${ "@" ~ identifier } -item = { macro_def | macro_call | repeat | stack | global_label | local_label | bytes_item | push_instruction | nullary_instruction } +item = { macro_def | macro_call | repeat | stack | global_label | local_label | bytes_item | push_instruction | prover_input_instruction | nullary_instruction } macro_def = { ^"%macro" ~ identifier ~ paramlist? ~ item* ~ ^"%endmacro" } macro_call = ${ "%" ~ !(^"macro" | ^"endmacro" | ^"rep" | ^"endrep" | ^"stack") ~ identifier ~ macro_arglist? } repeat = { ^"%rep" ~ literal ~ item* ~ ^"%endrep" } @@ -29,7 +29,7 @@ local_label = { identifier ~ ":" } bytes_item = { ^"BYTES " ~ literal ~ ("," ~ literal)* } push_instruction = { ^"PUSH " ~ push_target } push_target = { literal | identifier | variable | constant } -prover_input_instruction = { ^"PROVER_INPUT " ~ "(" ~ prover_input_fn ~ ")" } // TODO: Can also support extra arguments. +prover_input_instruction = { ^"PROVER_INPUT" ~ "(" ~ prover_input_fn ~ ")" } // TODO: Could also support extra arguments. prover_input_fn = { identifier ~ ("::" ~ identifier)*} nullary_instruction = { identifier } diff --git a/evm/src/cpu/kernel/mod.rs b/evm/src/cpu/kernel/mod.rs index 1f13a042..a79e17e9 100644 --- a/evm/src/cpu/kernel/mod.rs +++ b/evm/src/cpu/kernel/mod.rs @@ -4,6 +4,7 @@ mod ast; pub(crate) mod keccak_util; mod opcodes; mod parser; +mod prover_input; mod stack_manipulation; #[cfg(test)] diff --git a/evm/src/cpu/kernel/parser.rs b/evm/src/cpu/kernel/parser.rs index aa84ee05..f7acc96c 100644 --- a/evm/src/cpu/kernel/parser.rs +++ b/evm/src/cpu/kernel/parser.rs @@ -33,6 +33,15 @@ fn parse_item(item: Pair) -> Item { } Rule::bytes_item => Item::Bytes(item.into_inner().map(parse_literal).collect()), Rule::push_instruction => Item::Push(parse_push_target(item.into_inner().next().unwrap())), + Rule::prover_input_instruction => Item::ProverInput( + item.into_inner() + .next() + .unwrap() + .into_inner() + .map(|x| x.as_str().into()) + .collect::>() + .into(), + ), Rule::nullary_instruction => Item::StandardOp(item.as_str().into()), _ => panic!("Unexpected {:?}", item.as_rule()), } diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs new file mode 100644 index 00000000..1251f7d2 --- /dev/null +++ b/evm/src/cpu/kernel/prover_input.rs @@ -0,0 +1,8 @@ +#[derive(PartialEq, Eq, Debug, Clone)] +pub(crate) struct ProverInputFn(Vec); + +impl From> for ProverInputFn { + fn from(v: Vec) -> Self { + Self(v) + } +} From 0c539795fab75f218a35647577087865f17a03e1 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 23 Jul 2022 11:47:10 +0200 Subject: [PATCH 04/14] Implement prover input fns --- evm/src/cpu/kernel/prover_input.rs | 104 +++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs index 1251f7d2..79a8483d 100644 --- a/evm/src/cpu/kernel/prover_input.rs +++ b/evm/src/cpu/kernel/prover_input.rs @@ -1,3 +1,12 @@ +use std::str::FromStr; + +use ethereum_types::U256; + +use crate::cpu::kernel::prover_input::Field::{ + Bn254Base, Bn254Scalar, Secp256k1Base, Secp256k1Scalar, +}; +use crate::cpu::kernel::prover_input::FieldOp::{Inverse, Sqrt}; + #[derive(PartialEq, Eq, Debug, Clone)] pub(crate) struct ProverInputFn(Vec); @@ -6,3 +15,98 @@ impl From> for ProverInputFn { Self(v) } } + +impl ProverInputFn { + pub(crate) fn run(&self, mut stack: Vec) -> U256 { + match self.0[0].as_str() { + "ff" => self.run_ff(stack), + "storage" => todo!(), + _ => panic!("Unrecognized prover input function."), + } + } + + fn run_ff(&self, mut stack: Vec) -> U256 { + let field = Field::from_str(self.0[1].as_str()).unwrap(); + let op = FieldOp::from_str(self.0[2].as_str()).unwrap(); + let x = stack.pop().expect("Empty stack"); + field.op(op, x) + } +} + +enum Field { + Bn254Base, + Bn254Scalar, + Secp256k1Base, + Secp256k1Scalar, +} + +enum FieldOp { + Inverse, + Sqrt, +} + +impl FromStr for Field { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "bn254_base" => Bn254Base, + "bn254_scalar" => Bn254Scalar, + "secp256k1_base" => Secp256k1Base, + "secp256k1_scalar" => Secp256k1Scalar, + _ => panic!("Unrecognized field."), + }) + } +} + +impl FromStr for FieldOp { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "inverse" => Inverse, + "sqrt" => Sqrt, + _ => panic!("Unrecognized field operation."), + }) + } +} + +impl Field { + fn order(&self) -> U256 { + match self { + Field::Bn254Base => { + U256::from_str("0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47") + .unwrap() + } + Field::Bn254Scalar => todo!(), + Field::Secp256k1Base => todo!(), + Field::Secp256k1Scalar => todo!(), + } + } + + fn op(&self, op: FieldOp, x: U256) -> U256 { + match op { + FieldOp::Inverse => self.inverse(x), + FieldOp::Sqrt => todo!(), + } + } + + fn inverse(&self, x: U256) -> U256 { + let n = self.order(); + assert!(x < n); + modexp(x, n - 2, n) + } +} + +fn modexp(x: U256, e: U256, n: U256) -> U256 { + let mut current = x; + let mut product = U256::one(); + + for j in 0..256 { + if !(e >> j & U256::one()).is_zero() { + product = U256::try_from(product.full_mul(current) % n).unwrap(); + } + current = U256::try_from(current.full_mul(current) % n).unwrap(); + } + product +} From 19e6725cfae3c0f0debea414c01d8aa48fa1eab3 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 23 Jul 2022 11:56:52 +0200 Subject: [PATCH 05/14] Working --- evm/src/cpu/kernel/interpreter.rs | 46 ++++++++--------- evm/src/cpu/kernel/prover_input.rs | 2 +- evm/src/cpu/kernel/tests/curve_ops.rs | 74 ++++++++++++++++----------- evm/src/cpu/kernel/tests/ecrecover.rs | 16 +++++- evm/src/cpu/kernel/tests/exp.rs | 12 ++--- 5 files changed, 86 insertions(+), 64 deletions(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index f2fb276a..c9d52cff 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -1,7 +1,11 @@ +use std::collections::HashMap; + use anyhow::{anyhow, bail}; use ethereum_types::{BigEndianHash, U256, U512}; use keccak_hash::keccak; +use crate::cpu::kernel::prover_input::ProverInputFn; + /// Halt interpreter execution whenever a jump to this offset is done. const HALT_OFFSET: usize = 0xdeadbeef; @@ -55,29 +59,16 @@ pub(crate) struct Interpreter<'a> { offset: usize, pub(crate) stack: Vec, pub(crate) memory: EvmMemory, - /// Non-deterministic prover inputs, stored backwards so that popping the last item gives the - /// next prover input. - prover_inputs: Vec, + prover_inputs: &'a HashMap, running: bool, } -pub(crate) fn run( - code: &[u8], +pub(crate) fn run<'a>( + code: &'a [u8], initial_offset: usize, initial_stack: Vec, -) -> anyhow::Result { - run_with_input(code, initial_offset, initial_stack, vec![]) -} - -pub(crate) fn run_with_input( - code: &[u8], - initial_offset: usize, - initial_stack: Vec, - mut prover_inputs: Vec, -) -> anyhow::Result { - // Prover inputs are stored backwards, so that popping the last item gives the next input. - prover_inputs.reverse(); - + prover_inputs: &'a HashMap, +) -> anyhow::Result> { let mut interpreter = Interpreter { code, jumpdests: find_jumpdests(code), @@ -337,11 +328,12 @@ impl<'a> Interpreter<'a> { } fn run_prover_input(&mut self) -> anyhow::Result<()> { - let input = self + let prover_input_fn = self .prover_inputs - .pop() - .ok_or_else(|| anyhow!("Out of prover inputs"))?; - self.stack.push(input); + .get(&(self.offset - 1)) + .ok_or_else(|| anyhow!("Offset not in prover inputs."))?; + let output = prover_input_fn.run(self.stack.clone()); + self.stack.push(output); Ok(()) } @@ -424,6 +416,8 @@ fn find_jumpdests(code: &[u8]) -> Vec { #[cfg(test)] mod tests { + use std::collections::HashMap; + use hex_literal::hex; use crate::cpu::kernel::interpreter::{run, Interpreter}; @@ -433,7 +427,10 @@ mod tests { let code = vec![ 0x60, 0x1, 0x60, 0x2, 0x1, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56, ]; // PUSH1, 1, PUSH1, 2, ADD, PUSH4 deadbeef, JUMP - assert_eq!(run(&code, 0, vec![])?.stack, vec![0x3.into()]); + assert_eq!( + run(&code, 0, vec![], &HashMap::new())?.stack, + vec![0x3.into()], + ); Ok(()) } @@ -456,7 +453,8 @@ mod tests { 0x60, 0xff, 0x60, 0x0, 0x52, 0x60, 0, 0x51, 0x60, 0x1, 0x51, 0x60, 0x42, 0x60, 0x27, 0x53, ]; - let run = run(&code, 0, vec![])?; + let pis = HashMap::new(); + let run = run(&code, 0, vec![], &pis)?; let Interpreter { stack, memory, .. } = run; assert_eq!(stack, vec![0xff.into(), 0xff00.into()]); assert_eq!(&memory.memory, &hex!("00000000000000000000000000000000000000000000000000000000000000ff0000000000000042000000000000000000000000000000000000000000000000")); diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs index 79a8483d..c9cb8821 100644 --- a/evm/src/cpu/kernel/prover_input.rs +++ b/evm/src/cpu/kernel/prover_input.rs @@ -17,7 +17,7 @@ impl From> for ProverInputFn { } impl ProverInputFn { - pub(crate) fn run(&self, mut stack: Vec) -> U256 { + pub(crate) fn run(&self, stack: Vec) -> U256 { match self.0[0].as_str() { "ff" => self.run_ff(stack), "storage" => todo!(), diff --git a/evm/src/cpu/kernel/tests/curve_ops.rs b/evm/src/cpu/kernel/tests/curve_ops.rs index 6d8c6696..72e4169b 100644 --- a/evm/src/cpu/kernel/tests/curve_ops.rs +++ b/evm/src/cpu/kernel/tests/curve_ops.rs @@ -43,76 +43,82 @@ mod bn { // 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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run( + &kernel.code, + ec_double, + initial_stack, + &kernel.prover_inputs, + )? + .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)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Multiple calls @@ -126,7 +132,7 @@ mod bn { point0.1, point0.0, ])?; - let stack = run(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); Ok(()) @@ -176,55 +182,61 @@ mod secp { // 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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run( + &kernel.code, + ec_double, + initial_stack, + &kernel.prover_inputs, + )? + .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)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #1 let initial_stack = u256ify(["0xdeadbeef", s, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Multiple calls @@ -238,7 +250,7 @@ mod secp { point0.1, point0.0, ])?; - let stack = run(&kernel.code, ec_add, initial_stack)?.stack; + let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); Ok(()) diff --git a/evm/src/cpu/kernel/tests/ecrecover.rs b/evm/src/cpu/kernel/tests/ecrecover.rs index 78bdea3e..790a4a2c 100644 --- a/evm/src/cpu/kernel/tests/ecrecover.rs +++ b/evm/src/cpu/kernel/tests/ecrecover.rs @@ -18,7 +18,13 @@ fn test_valid_ecrecover( ) -> Result<()> { let ecrecover = kernel.global_labels["ecrecover"]; let initial_stack = u256ify(["0xdeadbeef", s, r, v, hash])?; - let stack = run(&kernel.code, ecrecover, initial_stack)?.stack; + let stack = run( + &kernel.code, + ecrecover, + initial_stack, + &kernel.prover_inputs, + )? + .stack; assert_eq!(stack[0], U256::from_str(expected).unwrap()); Ok(()) @@ -27,7 +33,13 @@ fn test_valid_ecrecover( fn test_invalid_ecrecover(hash: &str, v: &str, r: &str, s: &str, kernel: &Kernel) -> Result<()> { let ecrecover = kernel.global_labels["ecrecover"]; let initial_stack = u256ify(["0xdeadbeef", s, r, v, hash])?; - let stack = run(&kernel.code, ecrecover, initial_stack)?.stack; + let stack = run( + &kernel.code, + ecrecover, + initial_stack, + &kernel.prover_inputs, + )? + .stack; assert_eq!(stack, vec![U256::MAX]); Ok(()) diff --git a/evm/src/cpu/kernel/tests/exp.rs b/evm/src/cpu/kernel/tests/exp.rs index 25c88623..0858c37c 100644 --- a/evm/src/cpu/kernel/tests/exp.rs +++ b/evm/src/cpu/kernel/tests/exp.rs @@ -18,26 +18,26 @@ fn test_exp() -> Result<()> { // Random input let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, a]; - let stack_with_kernel = run(&kernel.code, exp, initial_stack)?.stack; + let stack_with_kernel = run(&kernel.code, exp, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack_with_opcode = run(&code, 0, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack_with_kernel = run(&kernel.code, exp, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack_with_opcode = run(&code, 0, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack_with_kernel = run(&kernel.code, exp, initial_stack, &kernel.prover_inputs)?.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)?.stack; + let stack_with_opcode = run(&code, 0, initial_stack, &kernel.prover_inputs)?.stack; assert_eq!(stack_with_kernel, stack_with_opcode); Ok(()) From cafae8b818d0a7ec53f81be8536d89b97f18a948 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 23 Jul 2022 12:36:03 +0200 Subject: [PATCH 06/14] Add `run_with_kernel` fn --- evm/src/cpu/kernel/asm/moddiv.asm | 2 +- evm/src/cpu/kernel/interpreter.rs | 18 ++++++- evm/src/cpu/kernel/mod.rs | 3 +- evm/src/cpu/kernel/prover_input.rs | 2 +- evm/src/cpu/kernel/tests/curve_ops.rs | 76 +++++++++++---------------- 5 files changed, 51 insertions(+), 50 deletions(-) diff --git a/evm/src/cpu/kernel/asm/moddiv.asm b/evm/src/cpu/kernel/asm/moddiv.asm index 630dcc54..2b76d054 100644 --- a/evm/src/cpu/kernel/asm/moddiv.asm +++ b/evm/src/cpu/kernel/asm/moddiv.asm @@ -25,7 +25,7 @@ %mulmodn %endmacro -// Computes the inverse modulo N by providing it non-deterministically. +// Non-deterministically provide the inverse modulo N. %macro inverse // stack: x PROVER_INPUT(ff::bn254_base::inverse) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index c9d52cff..b5f44103 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -4,6 +4,7 @@ use anyhow::{anyhow, bail}; use ethereum_types::{BigEndianHash, U256, U512}; use keccak_hash::keccak; +use crate::cpu::kernel::assembler::Kernel; use crate::cpu::kernel::prover_input::ProverInputFn; /// Halt interpreter execution whenever a jump to this offset is done. @@ -53,7 +54,7 @@ impl EvmMemory { } } -pub(crate) struct Interpreter<'a> { +pub struct Interpreter<'a> { code: &'a [u8], jumpdests: Vec, offset: usize, @@ -63,7 +64,20 @@ pub(crate) struct Interpreter<'a> { running: bool, } -pub(crate) fn run<'a>( +pub fn run_with_kernel( + kernel: &Kernel, + initial_offset: usize, + initial_stack: Vec, +) -> anyhow::Result { + run( + &kernel.code, + initial_offset, + initial_stack, + &kernel.prover_inputs, + ) +} + +pub fn run<'a>( code: &'a [u8], initial_offset: usize, initial_stack: Vec, diff --git a/evm/src/cpu/kernel/mod.rs b/evm/src/cpu/kernel/mod.rs index a79e17e9..67a22fc1 100644 --- a/evm/src/cpu/kernel/mod.rs +++ b/evm/src/cpu/kernel/mod.rs @@ -1,14 +1,13 @@ pub mod aggregator; pub mod assembler; mod ast; +pub mod interpreter; pub(crate) mod keccak_util; mod opcodes; mod parser; mod prover_input; mod stack_manipulation; -#[cfg(test)] -mod interpreter; #[cfg(test)] mod tests; diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs index c9cb8821..5f3ecd42 100644 --- a/evm/src/cpu/kernel/prover_input.rs +++ b/evm/src/cpu/kernel/prover_input.rs @@ -8,7 +8,7 @@ use crate::cpu::kernel::prover_input::Field::{ use crate::cpu::kernel::prover_input::FieldOp::{Inverse, Sqrt}; #[derive(PartialEq, Eq, Debug, Clone)] -pub(crate) struct ProverInputFn(Vec); +pub struct ProverInputFn(Vec); impl From> for ProverInputFn { fn from(v: Vec) -> Self { diff --git a/evm/src/cpu/kernel/tests/curve_ops.rs b/evm/src/cpu/kernel/tests/curve_ops.rs index 72e4169b..44609f21 100644 --- a/evm/src/cpu/kernel/tests/curve_ops.rs +++ b/evm/src/cpu/kernel/tests/curve_ops.rs @@ -4,7 +4,7 @@ mod bn { use ethereum_types::U256; use crate::cpu::kernel::aggregator::combined_kernel; - use crate::cpu::kernel::interpreter::run; + use crate::cpu::kernel::interpreter::run_with_kernel; use crate::cpu::kernel::tests::u256ify; #[test] @@ -43,82 +43,76 @@ mod bn { // 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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, - &kernel.prover_inputs, - )? - .stack; + let stack = run_with_kernel(&kernel, ec_double, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.stack; assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Multiple calls @@ -132,7 +126,7 @@ mod bn { point0.1, point0.0, ])?; - let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); Ok(()) @@ -144,7 +138,7 @@ mod secp { use anyhow::Result; use crate::cpu::kernel::aggregator::combined_kernel; - use crate::cpu::kernel::interpreter::run; + use crate::cpu::kernel::interpreter::{run, run_with_kernel}; use crate::cpu::kernel::tests::u256ify; #[test] @@ -182,7 +176,7 @@ mod secp { // 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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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])?; @@ -191,52 +185,46 @@ mod secp { // 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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, - &kernel.prover_inputs, - )? - .stack; + let stack = run_with_kernel(&kernel, ec_double, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Scalar multiplication #1 let initial_stack = u256ify(["0xdeadbeef", s, point0.1, point0.0])?; - let stack = run(&kernel.code, ec_mul, initial_stack, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.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, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_mul, initial_stack)?.stack; assert_eq!(stack, u256ify([identity.1, identity.0])?); // Multiple calls @@ -250,7 +238,7 @@ mod secp { point0.1, point0.0, ])?; - let stack = run(&kernel.code, ec_add, initial_stack, &kernel.prover_inputs)?.stack; + let stack = run_with_kernel(&kernel, ec_add, initial_stack)?.stack; assert_eq!(stack, u256ify([point4.1, point4.0])?); Ok(()) From 9dacbe0ff61b17aefdcaa496635b92adaac282be Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 23 Jul 2022 12:52:45 +0200 Subject: [PATCH 07/14] Comments --- evm/src/cpu/kernel/assembler.rs | 1 + evm/src/cpu/kernel/evm_asm.pest | 2 +- evm/src/cpu/kernel/prover_input.rs | 11 ++++++++++- evm/src/cpu/kernel/tests/ecrecover.rs | 18 +++--------------- evm/src/cpu/kernel/tests/exp.rs | 8 ++++---- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/evm/src/cpu/kernel/assembler.rs b/evm/src/cpu/kernel/assembler.rs index 334220fd..6d2b0ff2 100644 --- a/evm/src/cpu/kernel/assembler.rs +++ b/evm/src/cpu/kernel/assembler.rs @@ -29,6 +29,7 @@ pub struct Kernel { pub(crate) global_labels: HashMap, + /// Map from `PROVER_INPUT` offsets to their corresponding `ProverInputFn`. pub(crate) prover_inputs: HashMap, } diff --git a/evm/src/cpu/kernel/evm_asm.pest b/evm/src/cpu/kernel/evm_asm.pest index b0033391..0703798e 100644 --- a/evm/src/cpu/kernel/evm_asm.pest +++ b/evm/src/cpu/kernel/evm_asm.pest @@ -29,7 +29,7 @@ local_label = { identifier ~ ":" } bytes_item = { ^"BYTES " ~ literal ~ ("," ~ literal)* } push_instruction = { ^"PUSH " ~ push_target } push_target = { literal | identifier | variable | constant } -prover_input_instruction = { ^"PROVER_INPUT" ~ "(" ~ prover_input_fn ~ ")" } // TODO: Could also support extra arguments. +prover_input_instruction = { ^"PROVER_INPUT" ~ "(" ~ prover_input_fn ~ ")" } prover_input_fn = { identifier ~ ("::" ~ identifier)*} nullary_instruction = { identifier } diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs index 5f3ecd42..733cbef7 100644 --- a/evm/src/cpu/kernel/prover_input.rs +++ b/evm/src/cpu/kernel/prover_input.rs @@ -7,6 +7,8 @@ use crate::cpu::kernel::prover_input::Field::{ }; use crate::cpu::kernel::prover_input::FieldOp::{Inverse, Sqrt}; +/// Prover input function represented as a scoped function name. +/// Example: `PROVER_INPUT(ff::bn254_base::inverse)` is represented as `ProverInputFn([ff, bn254_base, inverse])`. #[derive(PartialEq, Eq, Debug, Clone)] pub struct ProverInputFn(Vec); @@ -17,20 +19,27 @@ impl From> for ProverInputFn { } impl ProverInputFn { + /// Run the function on the stack. pub(crate) fn run(&self, stack: Vec) -> U256 { match self.0[0].as_str() { "ff" => self.run_ff(stack), - "storage" => todo!(), + "mpt" => todo!(), _ => panic!("Unrecognized prover input function."), } } + // Finite field operations. fn run_ff(&self, mut stack: Vec) -> U256 { let field = Field::from_str(self.0[1].as_str()).unwrap(); let op = FieldOp::from_str(self.0[2].as_str()).unwrap(); let x = stack.pop().expect("Empty stack"); field.op(op, x) } + + // MPT operations. + fn run_mpt(&self, mut stack: Vec) -> U256 { + todo!() + } } enum Field { diff --git a/evm/src/cpu/kernel/tests/ecrecover.rs b/evm/src/cpu/kernel/tests/ecrecover.rs index 790a4a2c..b105cf47 100644 --- a/evm/src/cpu/kernel/tests/ecrecover.rs +++ b/evm/src/cpu/kernel/tests/ecrecover.rs @@ -5,7 +5,7 @@ use ethereum_types::U256; use crate::cpu::kernel::aggregator::combined_kernel; use crate::cpu::kernel::assembler::Kernel; -use crate::cpu::kernel::interpreter::run; +use crate::cpu::kernel::interpreter::run_with_kernel; use crate::cpu::kernel::tests::u256ify; fn test_valid_ecrecover( @@ -18,13 +18,7 @@ fn test_valid_ecrecover( ) -> Result<()> { let ecrecover = kernel.global_labels["ecrecover"]; let initial_stack = u256ify(["0xdeadbeef", s, r, v, hash])?; - let stack = run( - &kernel.code, - ecrecover, - initial_stack, - &kernel.prover_inputs, - )? - .stack; + let stack = run_with_kernel(kernel, ecrecover, initial_stack)?.stack; assert_eq!(stack[0], U256::from_str(expected).unwrap()); Ok(()) @@ -33,13 +27,7 @@ fn test_valid_ecrecover( fn test_invalid_ecrecover(hash: &str, v: &str, r: &str, s: &str, kernel: &Kernel) -> Result<()> { let ecrecover = kernel.global_labels["ecrecover"]; let initial_stack = u256ify(["0xdeadbeef", s, r, v, hash])?; - let stack = run( - &kernel.code, - ecrecover, - initial_stack, - &kernel.prover_inputs, - )? - .stack; + let stack = run_with_kernel(kernel, ecrecover, initial_stack)?.stack; assert_eq!(stack, vec![U256::MAX]); Ok(()) diff --git a/evm/src/cpu/kernel/tests/exp.rs b/evm/src/cpu/kernel/tests/exp.rs index 0858c37c..049fd23a 100644 --- a/evm/src/cpu/kernel/tests/exp.rs +++ b/evm/src/cpu/kernel/tests/exp.rs @@ -5,7 +5,7 @@ use ethereum_types::U256; use rand::{thread_rng, Rng}; use crate::cpu::kernel::aggregator::combined_kernel; -use crate::cpu::kernel::interpreter::run; +use crate::cpu::kernel::interpreter::{run, run_with_kernel}; #[test] fn test_exp() -> Result<()> { @@ -18,7 +18,7 @@ fn test_exp() -> Result<()> { // Random input let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, a]; - let stack_with_kernel = run(&kernel.code, exp, initial_stack, &kernel.prover_inputs)?.stack; + let stack_with_kernel = run_with_kernel(&kernel, exp, initial_stack)?.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, &kernel.prover_inputs)?.stack; @@ -26,7 +26,7 @@ fn test_exp() -> Result<()> { // 0 base let initial_stack = vec![U256::from_str("0xdeadbeef")?, b, U256::zero()]; - let stack_with_kernel = run(&kernel.code, exp, initial_stack, &kernel.prover_inputs)?.stack; + let stack_with_kernel = run_with_kernel(&kernel, exp, initial_stack)?.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, &kernel.prover_inputs)?.stack; @@ -34,7 +34,7 @@ fn test_exp() -> Result<()> { // 0 exponent let initial_stack = vec![U256::from_str("0xdeadbeef")?, U256::zero(), a]; - let stack_with_kernel = run(&kernel.code, exp, initial_stack, &kernel.prover_inputs)?.stack; + let stack_with_kernel = run_with_kernel(&kernel, exp, initial_stack)?.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, &kernel.prover_inputs)?.stack; From 1e02fd0236cf68ffd1418b54bea05f0393444692 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 23 Jul 2022 12:58:29 +0200 Subject: [PATCH 08/14] Oh Clippy... --- evm/src/cpu/kernel/prover_input.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs index 733cbef7..21645340 100644 --- a/evm/src/cpu/kernel/prover_input.rs +++ b/evm/src/cpu/kernel/prover_input.rs @@ -37,7 +37,8 @@ impl ProverInputFn { } // MPT operations. - fn run_mpt(&self, mut stack: Vec) -> U256 { + #[allow(dead_code)] + fn run_mpt(&self, _stack: Vec) -> U256 { todo!() } } From 927cad3acd7dd9aa282a6f98f4c55dda213e33c2 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 23 Jul 2022 13:03:43 +0200 Subject: [PATCH 09/14] Collect prover inputs --- evm/src/cpu/kernel/interpreter.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index b5f44103..e179d713 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -60,7 +60,8 @@ pub struct Interpreter<'a> { offset: usize, pub(crate) stack: Vec, pub(crate) memory: EvmMemory, - prover_inputs: &'a HashMap, + prover_inputs_map: &'a HashMap, + prover_inputs: Vec, running: bool, } @@ -89,7 +90,8 @@ pub fn run<'a>( offset: initial_offset, stack: initial_stack, memory: EvmMemory::default(), - prover_inputs, + prover_inputs_map: prover_inputs, + prover_inputs: Vec::new(), running: true, }; @@ -343,11 +345,12 @@ impl<'a> Interpreter<'a> { fn run_prover_input(&mut self) -> anyhow::Result<()> { let prover_input_fn = self - .prover_inputs + .prover_inputs_map .get(&(self.offset - 1)) .ok_or_else(|| anyhow!("Offset not in prover inputs."))?; let output = prover_input_fn.run(self.stack.clone()); self.stack.push(output); + self.prover_inputs.push(output); Ok(()) } From ce23d4377a5202f67c25ff2313ed03f495603311 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 27 Jul 2022 11:27:04 +0200 Subject: [PATCH 10/14] Minor --- evm/src/cpu/kernel/interpreter.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index ebd4b949..0634b864 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -36,7 +36,7 @@ impl InterpreterMemory { } // TODO: Remove `code` and `stack` fields as they are contained in `memory`. -pub(crate) struct Interpreter<'a> { +pub struct Interpreter<'a> { code: &'a [u8], jumpdests: Vec, offset: usize, @@ -468,8 +468,6 @@ fn find_jumpdests(code: &[u8]) -> Vec { mod tests { use std::collections::HashMap; - use hex_literal::hex; - use crate::cpu::kernel::interpreter::{run, Interpreter}; use crate::memory::segments::Segment; From 805321584193f18dbc2411e92327f00696389edc Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 27 Jul 2022 16:49:26 +0200 Subject: [PATCH 11/14] Inverse for other fields --- evm/src/cpu/kernel/aggregator.rs | 24 +- .../cpu/kernel/asm/secp256k1/curve_mul.asm | 4 + .../kernel/asm/secp256k1/inverse_scalar.asm | 659 +-------------- evm/src/cpu/kernel/asm/secp256k1/moddiv.asm | 765 +----------------- evm/src/cpu/kernel/prover_input.rs | 10 +- 5 files changed, 54 insertions(+), 1408 deletions(-) diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 1f8ba0da..114a3d83 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -14,14 +14,26 @@ use crate::memory::segments::Segment; pub static KERNEL: Lazy = Lazy::new(combined_kernel); +const EC_CONSTANTS: [(&str, [u8; 32]); 3] = [ + ( + "BN_BASE", + hex!("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"), + ), + ( + "SECP_BASE", + hex!("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"), + ), + ( + "SECP_SCALAR", + hex!("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), + ), +]; + pub fn evm_constants() -> HashMap { let mut c = HashMap::new(); - c.insert( - "BN_BASE".into(), - U256::from_big_endian(&hex!( - "30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47" - )), - ); + for (name, value) in EC_CONSTANTS { + c.insert(name.into(), U256::from_big_endian(&value)); + } for segment in Segment::all() { c.insert(segment.var_name().into(), (segment as u32).into()); } diff --git a/evm/src/cpu/kernel/asm/secp256k1/curve_mul.asm b/evm/src/cpu/kernel/asm/secp256k1/curve_mul.asm index 7ad2dd71..f0825e88 100644 --- a/evm/src/cpu/kernel/asm/secp256k1/curve_mul.asm +++ b/evm/src/cpu/kernel/asm/secp256k1/curve_mul.asm @@ -2,6 +2,10 @@ global ec_mul_valid_point_secp: JUMPDEST // stack: x, y, s, retdest + %stack (x,y) -> (x,y,x,y) + %ec_isidentity + // stack: (x,y)==(0,0), x, y, s, retdest + %jumpi(ret_zero_ec_mul) DUP3 // stack: s, x, y, s, retdest %jumpi(step_case) diff --git a/evm/src/cpu/kernel/asm/secp256k1/inverse_scalar.asm b/evm/src/cpu/kernel/asm/secp256k1/inverse_scalar.asm index ce0af757..7b859b4f 100644 --- a/evm/src/cpu/kernel/asm/secp256k1/inverse_scalar.asm +++ b/evm/src/cpu/kernel/asm/secp256k1/inverse_scalar.asm @@ -17,654 +17,19 @@ %mulmodn_secp_scalar %endmacro -// Computes the inverse modulo N using x^-1 = x^(N-2) mod N and square-and-multiply modular exponentiation. +// Non-deterministically provide the inverse modulo N. %macro inverse_secp_scalar - DUP1 - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar - %squaremodn_secp_scalar - DUP2 - %mulmodn_secp_scalar + // stack: x + PROVER_INPUT(ff::secp256k1_scalar::inverse) + // stack: x^-1, x + %stack (inv, x) -> (inv, x, @SECP_SCALAR, inv, x) + // stack: x^-1, x, N, x^-1, x + MULMOD + // stack: x^-1 * x, x^-1, x + PUSH 1 + // stack: 1, x^-1 * x, x^-1, x + %assert_eq + // stack: x^-1, x SWAP1 // stack: x, x^-1 POP diff --git a/evm/src/cpu/kernel/asm/secp256k1/moddiv.asm b/evm/src/cpu/kernel/asm/secp256k1/moddiv.asm index 941fa33a..fd077b11 100644 --- a/evm/src/cpu/kernel/asm/secp256k1/moddiv.asm +++ b/evm/src/cpu/kernel/asm/secp256k1/moddiv.asm @@ -25,760 +25,19 @@ %mulmodn_secp_base %endmacro -// Computes the inverse modulo N using x^-1 = x^(N-2) mod N and square-and-multiply modular exponentiation. +// Non-deterministically provide the inverse modulo N. %macro inverse_secp_base - DUP1 - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base + // stack: x + PROVER_INPUT(ff::secp256k1_base::inverse) + // stack: x^-1, x + %stack (inv, x) -> (inv, x, @SECP_BASE, inv, x) + // stack: x^-1, x, N, x^-1, x + MULMOD + // stack: x^-1 * x, x^-1, x + PUSH 1 + // stack: 1, x^-1 * x, x^-1, x + %assert_eq + // stack: x^-1, x SWAP1 // stack: x, x^-1 POP diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs index 21645340..ac83257a 100644 --- a/evm/src/cpu/kernel/prover_input.rs +++ b/evm/src/cpu/kernel/prover_input.rs @@ -89,8 +89,14 @@ impl Field { .unwrap() } Field::Bn254Scalar => todo!(), - Field::Secp256k1Base => todo!(), - Field::Secp256k1Scalar => todo!(), + Field::Secp256k1Base => { + U256::from_str("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f") + .unwrap() + } + Field::Secp256k1Scalar => { + U256::from_str("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") + .unwrap() + } } } From bb2ee9d543809c14c51c16cc8ee5f2c28c845892 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 27 Jul 2022 17:06:16 +0200 Subject: [PATCH 12/14] Implement sqrt --- evm/src/cpu/kernel/asm/secp256k1/lift_x.asm | 756 +------------------- evm/src/cpu/kernel/prover_input.rs | 13 +- 2 files changed, 17 insertions(+), 752 deletions(-) diff --git a/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm b/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm index cd392b61..4bef700e 100644 --- a/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm +++ b/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm @@ -60,759 +60,13 @@ ADDMOD %endmacro -// Returns a square root of x if one exists, otherwise an undefined value. -// Computed as x^(q+1)/4, with q the Secp base field order. -// To replace with more efficient method using non-determinism later. +// Non-deterministically provide the square root modulo N. %macro sqrt_secp_base // stack: x - DUP1 - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - DUP2 - %mulmodn_secp_base - %squaremodn_secp_base - %squaremodn_secp_base + PROVER_INPUT(ff::secp256k1_base::sqrt) + // stack: √x, x SWAP1 - // stack: x, x^-1 + // stack: x, √x POP - // stack: x^-1 + // stack: √x %endmacro \ No newline at end of file diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs index ac83257a..b27eb561 100644 --- a/evm/src/cpu/kernel/prover_input.rs +++ b/evm/src/cpu/kernel/prover_input.rs @@ -103,7 +103,7 @@ impl Field { fn op(&self, op: FieldOp, x: U256) -> U256 { match op { FieldOp::Inverse => self.inverse(x), - FieldOp::Sqrt => todo!(), + FieldOp::Sqrt => self.sqrt(x), } } @@ -112,6 +112,17 @@ impl Field { assert!(x < n); modexp(x, n - 2, n) } + + fn sqrt(&self, x: U256) -> U256 { + let n = self.order(); + assert!(x < n); + let (q, r) = (n + 1).div_mod(4.into()); + assert!( + r.is_zero(), + "Only naive sqrt implementation for now. If needed implement Tonelli-Shanks." + ); + modexp(x, q, n) + } } fn modexp(x: U256, e: U256, n: U256) -> U256 { From 87640d7e98683f7b6ec92e09d0564c43765c3522 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 28 Jul 2022 10:35:53 +0200 Subject: [PATCH 13/14] PR feedback --- evm/src/cpu/kernel/aggregator.rs | 1 + evm/src/cpu/kernel/asm/moddiv.asm | 14 ++++---------- .../cpu/kernel/asm/secp256k1/inverse_scalar.asm | 14 ++++---------- evm/src/cpu/kernel/asm/secp256k1/lift_x.asm | 5 +++-- evm/src/cpu/kernel/asm/secp256k1/moddiv.asm | 14 ++++---------- evm/src/cpu/kernel/interpreter.rs | 2 +- evm/src/cpu/kernel/mod.rs | 5 +++-- evm/src/cpu/kernel/prover_input.rs | 8 ++++---- 8 files changed, 24 insertions(+), 39 deletions(-) diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 114a3d83..81be7f96 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -90,5 +90,6 @@ mod tests { // Make sure we can parse and assemble the entire kernel. let kernel = combined_kernel(); debug!("Total kernel size: {} bytes", kernel.code.len()); + dbg!("Total kernel size: {} bytes", kernel.code.len()); } } diff --git a/evm/src/cpu/kernel/asm/moddiv.asm b/evm/src/cpu/kernel/asm/moddiv.asm index 2b76d054..780473b9 100644 --- a/evm/src/cpu/kernel/asm/moddiv.asm +++ b/evm/src/cpu/kernel/asm/moddiv.asm @@ -30,16 +30,10 @@ // stack: x PROVER_INPUT(ff::bn254_base::inverse) // stack: x^-1, x - %stack (inv, x) -> (inv, x, @BN_BASE, inv, x) - // stack: x^-1, x, N, x^-1, x + %stack (inv, x) -> (inv, x, @BN_BASE, inv) + // stack: x^-1, x, N, x^-1 MULMOD - // stack: x^-1 * x, x^-1, x - PUSH 1 - // stack: 1, x^-1 * x, x^-1, x - %assert_eq - // stack: x^-1, x - SWAP1 - // stack: x, x^-1 - POP + // stack: x^-1 * x, x^-1 + %assert_eq_const(1) // stack: x^-1 %endmacro diff --git a/evm/src/cpu/kernel/asm/secp256k1/inverse_scalar.asm b/evm/src/cpu/kernel/asm/secp256k1/inverse_scalar.asm index 7b859b4f..6e1563e2 100644 --- a/evm/src/cpu/kernel/asm/secp256k1/inverse_scalar.asm +++ b/evm/src/cpu/kernel/asm/secp256k1/inverse_scalar.asm @@ -22,16 +22,10 @@ // stack: x PROVER_INPUT(ff::secp256k1_scalar::inverse) // stack: x^-1, x - %stack (inv, x) -> (inv, x, @SECP_SCALAR, inv, x) - // stack: x^-1, x, N, x^-1, x + %stack (inv, x) -> (inv, x, @SECP_SCALAR, inv) + // stack: x^-1, x, N, x^-1 MULMOD - // stack: x^-1 * x, x^-1, x - PUSH 1 - // stack: 1, x^-1 * x, x^-1, x - %assert_eq - // stack: x^-1, x - SWAP1 - // stack: x, x^-1 - POP + // stack: x^-1 * x, x^-1 + %assert_eq_const(1) // stack: x^-1 %endmacro diff --git a/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm b/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm index 4bef700e..dc765518 100644 --- a/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm +++ b/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm @@ -10,7 +10,7 @@ // stack: x^3+7, x, parity DUP1 // stack: x^3+7, x^3+7, parity - %sqrt_secp_base + %sqrt_secp_base_unsafe // stack: y, x^3+7, x, parity SWAP1 // stack: x^3+7, y, parity @@ -61,7 +61,8 @@ %endmacro // Non-deterministically provide the square root modulo N. -%macro sqrt_secp_base +// Note: The square root is not checked and the macro doesn't not panic if `x` is not a square. +%macro sqrt_secp_base_unsafe // stack: x PROVER_INPUT(ff::secp256k1_base::sqrt) // stack: √x, x diff --git a/evm/src/cpu/kernel/asm/secp256k1/moddiv.asm b/evm/src/cpu/kernel/asm/secp256k1/moddiv.asm index fd077b11..d878dc14 100644 --- a/evm/src/cpu/kernel/asm/secp256k1/moddiv.asm +++ b/evm/src/cpu/kernel/asm/secp256k1/moddiv.asm @@ -30,16 +30,10 @@ // stack: x PROVER_INPUT(ff::secp256k1_base::inverse) // stack: x^-1, x - %stack (inv, x) -> (inv, x, @SECP_BASE, inv, x) - // stack: x^-1, x, N, x^-1, x + %stack (inv, x) -> (inv, x, @SECP_BASE, inv) + // stack: x^-1, x, N, x^-1 MULMOD - // stack: x^-1 * x, x^-1, x - PUSH 1 - // stack: 1, x^-1 * x, x^-1, x - %assert_eq - // stack: x^-1, x - SWAP1 - // stack: x, x^-1 - POP + // stack: x^-1 * x, x^-1 + %assert_eq_const(1) // stack: x^-1 %endmacro diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 0634b864..61272c24 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -336,7 +336,7 @@ impl<'a> Interpreter<'a> { .prover_inputs_map .get(&(self.offset - 1)) .ok_or_else(|| anyhow!("Offset not in prover inputs."))?; - let output = prover_input_fn.run(self.stack.clone()); + let output = prover_input_fn.run(&self.stack); self.stack.push(output); self.prover_inputs.push(output); Ok(()) diff --git a/evm/src/cpu/kernel/mod.rs b/evm/src/cpu/kernel/mod.rs index d146884a..5b9b1b4a 100644 --- a/evm/src/cpu/kernel/mod.rs +++ b/evm/src/cpu/kernel/mod.rs @@ -1,14 +1,15 @@ pub mod aggregator; pub mod assembler; mod ast; -pub mod interpreter; pub(crate) mod keccak_util; mod opcodes; mod parser; -mod prover_input; +pub mod prover_input; mod stack_manipulation; mod txn_fields; +#[cfg(test)] +mod interpreter; #[cfg(test)] mod tests; diff --git a/evm/src/cpu/kernel/prover_input.rs b/evm/src/cpu/kernel/prover_input.rs index b27eb561..38e1914e 100644 --- a/evm/src/cpu/kernel/prover_input.rs +++ b/evm/src/cpu/kernel/prover_input.rs @@ -20,7 +20,7 @@ impl From> for ProverInputFn { impl ProverInputFn { /// Run the function on the stack. - pub(crate) fn run(&self, stack: Vec) -> U256 { + pub fn run(&self, stack: &[U256]) -> U256 { match self.0[0].as_str() { "ff" => self.run_ff(stack), "mpt" => todo!(), @@ -29,10 +29,10 @@ impl ProverInputFn { } // Finite field operations. - fn run_ff(&self, mut stack: Vec) -> U256 { + fn run_ff(&self, stack: &[U256]) -> U256 { let field = Field::from_str(self.0[1].as_str()).unwrap(); let op = FieldOp::from_str(self.0[2].as_str()).unwrap(); - let x = stack.pop().expect("Empty stack"); + let x = *stack.last().expect("Empty stack"); field.op(op, x) } @@ -130,7 +130,7 @@ fn modexp(x: U256, e: U256, n: U256) -> U256 { let mut product = U256::one(); for j in 0..256 { - if !(e >> j & U256::one()).is_zero() { + if e.bit(j) { product = U256::try_from(product.full_mul(current) % n).unwrap(); } current = U256::try_from(current.full_mul(current) % n).unwrap(); From eb96216278fadc4f06d425a048abcaf1ba18b09b Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 29 Jul 2022 11:32:55 +0200 Subject: [PATCH 14/14] Typo --- evm/src/cpu/kernel/asm/secp256k1/lift_x.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm b/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm index dc765518..77e484be 100644 --- a/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm +++ b/evm/src/cpu/kernel/asm/secp256k1/lift_x.asm @@ -61,7 +61,7 @@ %endmacro // Non-deterministically provide the square root modulo N. -// Note: The square root is not checked and the macro doesn't not panic if `x` is not a square. +// Note: The square root is not checked and the macro doesn't panic if `x` is not a square. %macro sqrt_secp_base_unsafe // stack: x PROVER_INPUT(ff::secp256k1_base::sqrt)