From 9ec9774410c8fec0267d6c0ab72676c85f3d8137 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Tue, 14 Mar 2023 17:29:38 -0700 Subject: [PATCH 01/15] run_ops --- evm/src/bls381_arithmetic.rs | 60 +++++++++++----------- evm/src/cpu/kernel/interpreter.rs | 85 +++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 30 deletions(-) diff --git a/evm/src/bls381_arithmetic.rs b/evm/src/bls381_arithmetic.rs index bf886e1c..4a9daedd 100644 --- a/evm/src/bls381_arithmetic.rs +++ b/evm/src/bls381_arithmetic.rs @@ -31,77 +31,77 @@ pub const BLS_BASE: U512 = U512([ ]); #[derive(Debug, Copy, Clone, PartialEq)] -pub struct Fp { +pub struct Fp381 { pub val: U512, } -impl Fp { - pub fn new(val: usize) -> Fp { - Fp { +impl Fp381 { + pub fn new(val: usize) -> Fp381 { + Fp381 { val: U512::from(val), } } } -// impl Distribution for Standard { -// fn sample(&self, rng: &mut R) -> Fp { +// impl Distribution for Standard { +// fn sample(&self, rng: &mut R) -> Fp381 { // let xs = rng.gen::<[u64; 8]>(); -// Fp { +// Fp381 { // val: U512(xs) % BLS_BASE, // } // } // } -impl Add for Fp { +impl Add for Fp381 { type Output = Self; fn add(self, other: Self) -> Self { - Fp { + Fp381 { val: (self.val + other.val) % BLS_BASE, } } } -impl Neg for Fp { +impl Neg for Fp381 { type Output = Self; fn neg(self) -> Self::Output { - Fp { + Fp381 { val: (BLS_BASE - self.val) % BLS_BASE, } } } -impl Sub for Fp { +impl Sub for Fp381 { type Output = Self; fn sub(self, other: Self) -> Self { - Fp { + Fp381 { val: (BLS_BASE + self.val - other.val) % BLS_BASE, } } } -impl Fp { - fn lsh_128(self) -> Fp { +impl Fp381 { + fn lsh_128(self) -> Fp381 { let b128: U512 = U512([0, 0, 1, 0, 0, 0, 0, 0]); // since BLS_BASE < 2^384, multiplying by 2^128 doesn't overflow the U512 - Fp { + Fp381 { val: self.val.saturating_mul(b128) % BLS_BASE, } } - fn lsh_256(self) -> Fp { + fn lsh_256(self) -> Fp381 { self.lsh_128().lsh_128() } - fn lsh_512(self) -> Fp { + fn lsh_512(self) -> Fp381 { self.lsh_256().lsh_256() } } #[allow(clippy::suspicious_arithmetic_impl)] -impl Mul for Fp { +impl Mul for Fp381 { type Output = Self; fn mul(self, other: Self) -> Self { @@ -110,16 +110,16 @@ impl Mul for Fp { let (x1, x0) = self.val.div_mod(b256); let (y1, y0) = other.val.div_mod(b256); - let z00 = Fp { + let z00 = Fp381 { val: x0.saturating_mul(y0) % BLS_BASE, }; - let z01 = Fp { + let z01 = Fp381 { val: x0.saturating_mul(y1), }; - let z10 = Fp { + let z10 = Fp381 { val: x1.saturating_mul(y0), }; - let z11 = Fp { + let z11 = Fp381 { val: x1.saturating_mul(y1), }; @@ -127,16 +127,16 @@ impl Mul for Fp { } } -impl FieldExt for Fp { - const ZERO: Self = Fp { val: U512::zero() }; - const UNIT: Self = Fp { val: U512::one() }; - fn inv(self) -> Fp { +impl FieldExt for Fp381 { + const ZERO: Self = Fp381 { val: U512::zero() }; + const UNIT: Self = Fp381 { val: U512::one() }; + fn inv(self) -> Fp381 { exp_fp(self, BLS_BASE - 2) } } #[allow(clippy::suspicious_arithmetic_impl)] -impl Div for Fp { +impl Div for Fp381 { type Output = Self; fn div(self, rhs: Self) -> Self::Output { @@ -144,9 +144,9 @@ impl Div for Fp { } } -fn exp_fp(x: Fp, e: U512) -> Fp { +fn exp_fp(x: Fp381, e: U512) -> Fp381 { let mut current = x; - let mut product = Fp { val: U512::one() }; + let mut product = Fp381 { val: U512::one() }; for j in 0..512 { if e.bit(j) { diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 52876c97..42e67424 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -8,6 +8,7 @@ use ethereum_types::{U256, U512}; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; +use crate::bls381_arithmetic::{Fp381, BLS_BASE}; use crate::bn254_arithmetic::BN_BASE; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::context_metadata::ContextMetadata; @@ -438,6 +439,90 @@ impl<'a> Interpreter<'a> { self.push((x + (BN_BASE - y)) % BN_BASE); } + #[allow(dead_code)] + fn run_addfp381_lo(&mut self) { + let x1 = self.pop(); + let x0 = self.pop(); + let y1 = self.pop(); + let y0 = self.pop(); + + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = (x + y) % BLS_BASE; + + self.push(U256(z.0[0..4].try_into().unwrap())); + } + + #[allow(dead_code)] + fn run_addfp381_hi(&mut self) { + let x1 = self.pop(); + let x0 = self.pop(); + let y1 = self.pop(); + let y0 = self.pop(); + + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = (x + y) % BLS_BASE; + + self.push(U256(z.0[4..].try_into().unwrap())); + } + + #[allow(dead_code)] + fn run_mulfp254_lo(&mut self) { + let x1 = self.pop(); + let x0 = self.pop(); + let y1 = self.pop(); + let y0 = self.pop(); + + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = (Fp381 {val: x} * Fp381 {val: y}).val; + + self.push(U256(z.0[0..4].try_into().unwrap())); + } + + #[allow(dead_code)] + fn run_mulfp254_hi(&mut self) { + let x1 = self.pop(); + let x0 = self.pop(); + let y1 = self.pop(); + let y0 = self.pop(); + + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = (Fp381 {val: x} * Fp381 {val: y}).val; + + self.push(U256(z.0[4..].try_into().unwrap())); + } + + #[allow(dead_code)] + fn run_subfp381_lo(&mut self) { + let x1 = self.pop(); + let x0 = self.pop(); + let y1 = self.pop(); + let y0 = self.pop(); + + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = (BLS_BASE + x - y) % BLS_BASE; + + self.push(U256(z.0[0..4].try_into().unwrap())); + } + + #[allow(dead_code)] + fn run_subfp381_hi(&mut self) { + let x1 = self.pop(); + let x0 = self.pop(); + let y1 = self.pop(); + let y0 = self.pop(); + + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = (BLS_BASE + x - y) % BLS_BASE; + + self.push(U256(z.0[4..].try_into().unwrap())); + } + fn run_div(&mut self) { let x = self.pop(); let y = self.pop(); From a8956b9408c43f7f80438065d793f0f03572e260 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Tue, 14 Mar 2023 17:31:55 -0700 Subject: [PATCH 02/15] flip limbs --- evm/src/cpu/kernel/interpreter.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 42e67424..92a2e2ec 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -450,7 +450,7 @@ impl<'a> Interpreter<'a> { let y = U512::from(y0) + (U512::from(y1) << 256); let z = (x + y) % BLS_BASE; - self.push(U256(z.0[0..4].try_into().unwrap())); + self.push(U256(z.0[4..].try_into().unwrap())); } #[allow(dead_code)] @@ -464,7 +464,7 @@ impl<'a> Interpreter<'a> { let y = U512::from(y0) + (U512::from(y1) << 256); let z = (x + y) % BLS_BASE; - self.push(U256(z.0[4..].try_into().unwrap())); + self.push(U256(z.0[..4].try_into().unwrap())); } #[allow(dead_code)] @@ -476,9 +476,9 @@ impl<'a> Interpreter<'a> { let x = U512::from(x0) + (U512::from(x1) << 256); let y = U512::from(y0) + (U512::from(y1) << 256); - let z = (Fp381 {val: x} * Fp381 {val: y}).val; + let z = (Fp381 { val: x } * Fp381 { val: y }).val; - self.push(U256(z.0[0..4].try_into().unwrap())); + self.push(U256(z.0[4..].try_into().unwrap())); } #[allow(dead_code)] @@ -490,9 +490,9 @@ impl<'a> Interpreter<'a> { let x = U512::from(x0) + (U512::from(x1) << 256); let y = U512::from(y0) + (U512::from(y1) << 256); - let z = (Fp381 {val: x} * Fp381 {val: y}).val; + let z = (Fp381 { val: x } * Fp381 { val: y }).val; - self.push(U256(z.0[4..].try_into().unwrap())); + self.push(U256(z.0[..4].try_into().unwrap())); } #[allow(dead_code)] @@ -506,7 +506,7 @@ impl<'a> Interpreter<'a> { let y = U512::from(y0) + (U512::from(y1) << 256); let z = (BLS_BASE + x - y) % BLS_BASE; - self.push(U256(z.0[0..4].try_into().unwrap())); + self.push(U256(z.0[4..].try_into().unwrap())); } #[allow(dead_code)] @@ -520,7 +520,7 @@ impl<'a> Interpreter<'a> { let y = U512::from(y0) + (U512::from(y1) << 256); let z = (BLS_BASE + x - y) % BLS_BASE; - self.push(U256(z.0[4..].try_into().unwrap())); + self.push(U256(z.0[..4].try_into().unwrap())); } fn run_div(&mut self) { From 459d2929643f8f0d18ca30254e51c713b09f6be2 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Wed, 15 Mar 2023 19:34:33 -0700 Subject: [PATCH 03/15] folder --- evm/src/cpu/kernel/asm/curve/bls381/util.asm | 0 evm/src/cpu/kernel/interpreter.rs | 45 ++------------------ 2 files changed, 3 insertions(+), 42 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/curve/bls381/util.asm diff --git a/evm/src/cpu/kernel/asm/curve/bls381/util.asm b/evm/src/cpu/kernel/asm/curve/bls381/util.asm new file mode 100644 index 00000000..e69de29b diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 92a2e2ec..ecd0e3bc 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -440,7 +440,7 @@ impl<'a> Interpreter<'a> { } #[allow(dead_code)] - fn run_addfp381_lo(&mut self) { + fn run_addfp381(&mut self) { let x1 = self.pop(); let x0 = self.pop(); let y1 = self.pop(); @@ -451,24 +451,11 @@ impl<'a> Interpreter<'a> { let z = (x + y) % BLS_BASE; self.push(U256(z.0[4..].try_into().unwrap())); - } - - #[allow(dead_code)] - fn run_addfp381_hi(&mut self) { - let x1 = self.pop(); - let x0 = self.pop(); - let y1 = self.pop(); - let y0 = self.pop(); - - let x = U512::from(x0) + (U512::from(x1) << 256); - let y = U512::from(y0) + (U512::from(y1) << 256); - let z = (x + y) % BLS_BASE; - self.push(U256(z.0[..4].try_into().unwrap())); } #[allow(dead_code)] - fn run_mulfp254_lo(&mut self) { + fn run_mulfp381(&mut self) { let x1 = self.pop(); let x0 = self.pop(); let y1 = self.pop(); @@ -479,24 +466,11 @@ impl<'a> Interpreter<'a> { let z = (Fp381 { val: x } * Fp381 { val: y }).val; self.push(U256(z.0[4..].try_into().unwrap())); - } - - #[allow(dead_code)] - fn run_mulfp254_hi(&mut self) { - let x1 = self.pop(); - let x0 = self.pop(); - let y1 = self.pop(); - let y0 = self.pop(); - - let x = U512::from(x0) + (U512::from(x1) << 256); - let y = U512::from(y0) + (U512::from(y1) << 256); - let z = (Fp381 { val: x } * Fp381 { val: y }).val; - self.push(U256(z.0[..4].try_into().unwrap())); } #[allow(dead_code)] - fn run_subfp381_lo(&mut self) { + fn run_subfp381(&mut self) { let x1 = self.pop(); let x0 = self.pop(); let y1 = self.pop(); @@ -507,19 +481,6 @@ impl<'a> Interpreter<'a> { let z = (BLS_BASE + x - y) % BLS_BASE; self.push(U256(z.0[4..].try_into().unwrap())); - } - - #[allow(dead_code)] - fn run_subfp381_hi(&mut self) { - let x1 = self.pop(); - let x0 = self.pop(); - let y1 = self.pop(); - let y0 = self.pop(); - - let x = U512::from(x0) + (U512::from(x1) << 256); - let y = U512::from(y0) + (U512::from(y1) << 256); - let z = (BLS_BASE + x - y) % BLS_BASE; - self.push(U256(z.0[..4].try_into().unwrap())); } From b847d16e13913717efa2f3a29de84c906c541420 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Tue, 21 Mar 2023 19:25:28 -0700 Subject: [PATCH 04/15] redundancy --- evm/src/bls381_arithmetic.rs | 605 ----------------------------------- 1 file changed, 605 deletions(-) delete mode 100644 evm/src/bls381_arithmetic.rs diff --git a/evm/src/bls381_arithmetic.rs b/evm/src/bls381_arithmetic.rs deleted file mode 100644 index 4a9daedd..00000000 --- a/evm/src/bls381_arithmetic.rs +++ /dev/null @@ -1,605 +0,0 @@ -use std::ops::{Add, Div, Mul, Neg, Sub}; - -use ethereum_types::U512; - -// use rand::distributions::{Distribution, Standard}; -// use rand::Rng; - -pub trait FieldExt: - Sized - + Copy - + std::ops::Add - + std::ops::Neg - + std::ops::Sub - + std::ops::Mul - + std::ops::Div -{ - const ZERO: Self; - const UNIT: Self; - fn inv(self) -> Self; -} - -pub const BLS_BASE: U512 = U512([ - 0xb9feffffffffaaab, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - 0x0, - 0x0, -]); - -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Fp381 { - pub val: U512, -} - -impl Fp381 { - pub fn new(val: usize) -> Fp381 { - Fp381 { - val: U512::from(val), - } - } -} - -// impl Distribution for Standard { -// fn sample(&self, rng: &mut R) -> Fp381 { -// let xs = rng.gen::<[u64; 8]>(); -// Fp381 { -// val: U512(xs) % BLS_BASE, -// } -// } -// } - -impl Add for Fp381 { - type Output = Self; - - fn add(self, other: Self) -> Self { - Fp381 { - val: (self.val + other.val) % BLS_BASE, - } - } -} - -impl Neg for Fp381 { - type Output = Self; - - fn neg(self) -> Self::Output { - Fp381 { - val: (BLS_BASE - self.val) % BLS_BASE, - } - } -} - -impl Sub for Fp381 { - type Output = Self; - - fn sub(self, other: Self) -> Self { - Fp381 { - val: (BLS_BASE + self.val - other.val) % BLS_BASE, - } - } -} - -impl Fp381 { - fn lsh_128(self) -> Fp381 { - let b128: U512 = U512([0, 0, 1, 0, 0, 0, 0, 0]); - // since BLS_BASE < 2^384, multiplying by 2^128 doesn't overflow the U512 - Fp381 { - val: self.val.saturating_mul(b128) % BLS_BASE, - } - } - - fn lsh_256(self) -> Fp381 { - self.lsh_128().lsh_128() - } - - fn lsh_512(self) -> Fp381 { - self.lsh_256().lsh_256() - } -} - -#[allow(clippy::suspicious_arithmetic_impl)] -impl Mul for Fp381 { - type Output = Self; - - fn mul(self, other: Self) -> Self { - let b256: U512 = U512([0, 0, 0, 0, 1, 0, 0, 0]); - // x1, y1 are at most (q-1) // 2^256 < 2^125 - let (x1, x0) = self.val.div_mod(b256); - let (y1, y0) = other.val.div_mod(b256); - - let z00 = Fp381 { - val: x0.saturating_mul(y0) % BLS_BASE, - }; - let z01 = Fp381 { - val: x0.saturating_mul(y1), - }; - let z10 = Fp381 { - val: x1.saturating_mul(y0), - }; - let z11 = Fp381 { - val: x1.saturating_mul(y1), - }; - - z00 + (z01 + z10).lsh_256() + z11.lsh_512() - } -} - -impl FieldExt for Fp381 { - const ZERO: Self = Fp381 { val: U512::zero() }; - const UNIT: Self = Fp381 { val: U512::one() }; - fn inv(self) -> Fp381 { - exp_fp(self, BLS_BASE - 2) - } -} - -#[allow(clippy::suspicious_arithmetic_impl)] -impl Div for Fp381 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - self * rhs.inv() - } -} - -fn exp_fp(x: Fp381, e: U512) -> Fp381 { - let mut current = x; - let mut product = Fp381 { val: U512::one() }; - - for j in 0..512 { - if e.bit(j) { - product = product * current; - } - current = current * current; - } - product -} - -/// The degree 2 field extension Fp2 is given by adjoining i, the square root of -1, to Fp -/// The arithmetic in this extension is standard complex arithmetic -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Fp2 -where - T: FieldExt, -{ - pub re: T, - pub im: T, -} - -// impl> Distribution> for Standard { -// fn sample(&self, rng: &mut R) -> Fp2 { -// let (re, im) = rng.gen::<(T, T)>(); -// Fp2 { re, im } -// } -// } - -impl Add for Fp2 { - type Output = Self; - - fn add(self, other: Self) -> Self { - Fp2 { - re: self.re + other.re, - im: self.im + other.im, - } - } -} - -impl Neg for Fp2 { - type Output = Self; - - fn neg(self) -> Self::Output { - Fp2 { - re: -self.re, - im: -self.im, - } - } -} - -impl Sub for Fp2 { - type Output = Self; - - fn sub(self, other: Self) -> Self { - Fp2 { - re: self.re - other.re, - im: self.im - other.im, - } - } -} - -impl Mul for Fp2 { - type Output = Self; - - fn mul(self, other: Self) -> Self { - Fp2 { - re: self.re * other.re - self.im * other.im, - im: self.re * other.im + self.im * other.re, - } - } -} - -impl Fp2 { - /// This function scalar multiplies an Fp2 by an Fp - pub fn scale(self, x: T) -> Self { - Fp2 { - re: x * self.re, - im: x * self.im, - } - } - - /// Return the complex conjugate z' of z: Fp2 - /// This also happens to be the frobenius map - /// z -> z^p - /// since p == 3 mod 4 and hence - /// i^p = i^(4k) * i^3 = 1*(-i) = -i - fn conj(self) -> Self { - Fp2 { - re: self.re, - im: -self.im, - } - } - - // Return the magnitude squared of a complex number - fn norm_sq(self) -> T { - self.re * self.re + self.im * self.im - } -} - -impl FieldExt for Fp2 { - const ZERO: Fp2 = Fp2 { - re: T::ZERO, - im: T::ZERO, - }; - - const UNIT: Fp2 = Fp2 { - re: T::UNIT, - im: T::ZERO, - }; - /// The inverse of z is given by z'/||z||^2 since ||z||^2 = zz' - fn inv(self) -> Fp2 { - let norm_sq = self.norm_sq(); - self.conj().scale(norm_sq.inv()) - } -} - -#[allow(clippy::suspicious_arithmetic_impl)] -impl Div for Fp2 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - self * rhs.inv() - } -} - -pub trait Adj { - fn mul_adj(self) -> Self; -} - -/// Helper function which multiplies by the Fp2 element -/// whose cube root we will adjoin in the next extension -impl Adj for Fp2 { - fn mul_adj(self) -> Self { - Fp2 { - re: self.re - self.im, - im: self.re + self.im, - } - } -} - -/// The degree 3 field extension Fp6 over Fp2 is given by adjoining t, where t^3 = 1 + i -/// Fp6 has basis 1, t, t^2 over Fp2 -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Fp6 -where - T: FieldExt, -{ - pub t0: Fp2, - pub t1: Fp2, - pub t2: Fp2, -} - -// impl> Distribution> for Standard { -// fn sample(&self, rng: &mut R) -> Fp6 { -// let (t0, t1, t2) = rng.gen::<(Fp2, Fp2, Fp2)>(); -// Fp6 { t0, t1, t2 } -// } -// } - -impl Add for Fp6 { - type Output = Self; - - fn add(self, other: Self) -> Self { - Fp6 { - t0: self.t0 + other.t0, - t1: self.t1 + other.t1, - t2: self.t2 + other.t2, - } - } -} - -impl Neg for Fp6 { - type Output = Self; - - fn neg(self) -> Self::Output { - Fp6 { - t0: -self.t0, - t1: -self.t1, - t2: -self.t2, - } - } -} - -impl Sub for Fp6 { - type Output = Self; - - fn sub(self, other: Self) -> Self { - Fp6 { - t0: self.t0 - other.t0, - t1: self.t1 - other.t1, - t2: self.t2 - other.t2, - } - } -} - -impl Mul for Fp6 { - type Output = Self; - - fn mul(self, other: Self) -> Self { - Fp6 { - t0: self.t0 * other.t0 + (self.t1 * other.t2 + self.t2 * other.t1).mul_adj(), - t1: self.t0 * other.t1 + self.t1 * other.t0 + (self.t2 * other.t2).mul_adj(), - t2: self.t0 * other.t2 + self.t1 * other.t1 + self.t2 * other.t0, - } - } -} - -impl Fp6 { - // This function scalar multiplies an Fp6 by an Fp2 - fn scale(self, x: Fp2) -> Fp6 { - Fp6 { - t0: x * self.t0, - t1: x * self.t1, - t2: x * self.t2, - } - } -} - -impl Fp6 { - /// This function multiplies an Fp6 element by t, and hence shifts the bases, - /// where the t^2 coefficient picks up a factor of 1+i as the 1 coefficient of the output - fn sh(self) -> Fp6 { - Fp6 { - t0: self.t2.mul_adj(), - t1: self.t0, - t2: self.t1, - } - } -} - -impl Fp6 { - const FROB_T: [[Fp2; 6]; 2] = [[Fp2::::ZERO; 6]; 2]; - const FROB_Z: [Fp2; 12] = [Fp2::::ZERO; 12]; -} - -impl Fp6 { - /// The nth frobenius endomorphism of a p^q field is given by mapping - /// x to x^(p^n) - /// which sends a + bt + ct^2: Fp6 to - /// a^(p^n) + b^(p^n) * t^(p^n) + c^(p^n) * t^(2p^n) - /// The Fp2 coefficients are determined by the comment in the conj method, - /// while the values of - /// t^(p^n) and t^(2p^n) - /// are precomputed in the constant arrays FROB_T1 and FROB_T2 - pub fn frob(self, n: usize) -> Fp6 { - let n = n % 6; - let frob_t1 = Fp6::::FROB_T[0][n]; - let frob_t2 = Fp6::::FROB_T[1][n]; - - if n % 2 != 0 { - Fp6 { - t0: self.t0.conj(), - t1: frob_t1 * self.t1.conj(), - t2: frob_t2 * self.t2.conj(), - } - } else { - Fp6 { - t0: self.t0, - t1: frob_t1 * self.t1, - t2: frob_t2 * self.t2, - } - } - } -} - -impl FieldExt for Fp6 { - const ZERO: Fp6 = Fp6 { - t0: Fp2::::ZERO, - t1: Fp2::::ZERO, - t2: Fp2::::ZERO, - }; - - const UNIT: Fp6 = Fp6 { - t0: Fp2::::UNIT, - t1: Fp2::::ZERO, - t2: Fp2::::ZERO, - }; - - /// Let x_n = x^(p^n) and note that - /// x_0 = x^(p^0) = x^1 = x - /// (x_n)_m = (x^(p^n))^(p^m) = x^(p^n * p^m) = x^(p^(n+m)) = x_{n+m} - /// By Galois Theory, given x: Fp6, the product - /// phi = x_0 * x_1 * x_2 * x_3 * x_4 * x_5 - /// lands in Fp, and hence the inverse of x is given by - /// (x_1 * x_2 * x_3 * x_4 * x_5) / phi - /// We can save compute by rearranging the numerator: - /// (x_1 * x_3) * x_5 * (x_1 * x_3)_1 - /// By Galois theory, the following are in Fp2 and are complex conjugates - /// x_1 * x_3 * x_5, x_0 * x_2 * x_4 - /// and therefore - /// phi = ||x_1 * x_3 * x_5||^2 - /// and hence the inverse is given by - /// ([x_1 * x_3] * x_5) * [x_1 * x_3]_1 / ||[x_1 * x_3] * x_5||^2 - fn inv(self) -> Fp6 { - let prod_13 = self.frob(1) * self.frob(3); - let prod_135 = (prod_13 * self.frob(5)).t0; - let phi = prod_135.norm_sq(); - let prod_odds_over_phi = prod_135.scale(phi.inv()); - let prod_24 = prod_13.frob(1); - prod_24.scale(prod_odds_over_phi) - } -} - -#[allow(clippy::suspicious_arithmetic_impl)] -impl Div for Fp6 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - self * rhs.inv() - } -} - -/// The degree 2 field extension Fp12 over Fp6 is given by adjoining z, where z^2 = t. -/// It thus has basis 1, z over Fp6 -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Fp12 -where - T: FieldExt, -{ - pub z0: Fp6, - pub z1: Fp6, -} - -impl FieldExt for Fp12 { - const ZERO: Fp12 = Fp12 { - z0: Fp6::::ZERO, - z1: Fp6::::ZERO, - }; - - const UNIT: Fp12 = Fp12 { - z0: Fp6::::UNIT, - z1: Fp6::::ZERO, - }; - - /// By Galois Theory, given x: Fp12, the product - /// phi = Prod_{i=0}^11 x_i - /// lands in Fp, and hence the inverse of x is given by - /// (Prod_{i=1}^11 x_i) / phi - /// The 6th Frob map is nontrivial but leaves Fp6 fixed and hence must be the conjugate: - /// x_6 = (a + bz)_6 = a - bz = x.conj() - /// Letting prod_17 = x_1 * x_7, the remaining factors in the numerator can be expresed as: - /// [(prod_17) * (prod_17)_2] * (prod_17)_4 * [(prod_17) * (prod_17)_2]_1 - /// By Galois theory, both the following are in Fp2 and are complex conjugates - /// prod_odds, prod_evens - /// Thus phi = ||prod_odds||^2, and hence the inverse is given by - /// prod_odds * prod_evens_except_six * x.conj() / ||prod_odds||^2 - fn inv(self) -> Fp12 { - let prod_17 = (self.frob(1) * self.frob(7)).z0; - let prod_1379 = prod_17 * prod_17.frob(2); - let prod_odds = (prod_1379 * prod_17.frob(4)).t0; - let phi = prod_odds.norm_sq(); - let prod_odds_over_phi = prod_odds.scale(phi.inv()); - let prod_evens_except_six = prod_1379.frob(1); - let prod_except_six = prod_evens_except_six.scale(prod_odds_over_phi); - self.conj().scale(prod_except_six) - } -} - -// impl> Distribution> for Standard { -// fn sample(&self, rng: &mut R) -> Fp12 { -// let (z0, z1) = rng.gen::<(Fp6, Fp6)>(); -// Fp12 { z0, z1 } -// } -// } - -impl Add for Fp12 { - type Output = Self; - - fn add(self, other: Self) -> Self { - Fp12 { - z0: self.z0 + other.z0, - z1: self.z1 + other.z1, - } - } -} - -impl Neg for Fp12 { - type Output = Self; - - fn neg(self) -> Self::Output { - Fp12 { - z0: -self.z0, - z1: -self.z1, - } - } -} - -impl Sub for Fp12 { - type Output = Self; - - fn sub(self, other: Self) -> Self { - Fp12 { - z0: self.z0 - other.z0, - z1: self.z1 - other.z1, - } - } -} - -impl Mul for Fp12 { - type Output = Self; - - fn mul(self, other: Self) -> Self { - let h0 = self.z0 * other.z0; - let h1 = self.z1 * other.z1; - let h01 = (self.z0 + self.z1) * (other.z0 + other.z1); - Fp12 { - z0: h0 + h1.sh(), - z1: h01 - (h0 + h1), - } - } -} - -impl Fp12 { - // This function scalar multiplies an Fp12 by an Fp6 - fn scale(self, x: Fp6) -> Fp12 { - Fp12 { - z0: x * self.z0, - z1: x * self.z1, - } - } - - fn conj(self) -> Fp12 { - Fp12 { - z0: self.z0, - z1: -self.z1, - } - } -} - -impl Fp12 { - /// The nth frobenius endomorphism of a p^q field is given by mapping - /// x to x^(p^n) - /// which sends a + bz: Fp12 to - /// a^(p^n) + b^(p^n) * z^(p^n) - /// where the values of z^(p^n) are precomputed in the constant array FROB_Z - pub fn frob(self, n: usize) -> Fp12 { - let n = n % 12; - Fp12 { - z0: self.z0.frob(n), - z1: self.z1.frob(n).scale(Fp6::::FROB_Z[n]), - } - } -} - -#[allow(clippy::suspicious_arithmetic_impl)] -impl Div for Fp12 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - self * rhs.inv() - } -} - -// trait Stack { -// fn on_stack(self) -> Vec; -// } From 1437affcfd51a08e0d1ca671d7d597d32994ec0d Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Tue, 21 Mar 2023 19:26:06 -0700 Subject: [PATCH 05/15] fmt --- evm/src/cpu/kernel/interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index dedb84da..408671ba 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -8,11 +8,11 @@ use ethereum_types::{U256, U512}; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; -use crate::extension_tower::BN_BASE; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::context_metadata::ContextMetadata; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; use crate::cpu::kernel::constants::txn_fields::NormalizedTxnField; +use crate::extension_tower::BN_BASE; use crate::generation::prover_input::ProverInputFn; use crate::generation::state::GenerationState; use crate::generation::GenerationInputs; From 9ea0ebd78f407376e26c8f467459e03e472b78f1 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Tue, 21 Mar 2023 21:10:01 -0700 Subject: [PATCH 06/15] skeleton --- evm/src/cpu/kernel/asm/curve/bls381/util.asm | 41 ++++++++++ evm/src/extension_tower.rs | 8 ++ evm/src/generation/prover_input.rs | 79 +++++++++++++++++++- 3 files changed, 125 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/asm/curve/bls381/util.asm b/evm/src/cpu/kernel/asm/curve/bls381/util.asm index e69de29b..5f39d68a 100644 --- a/evm/src/cpu/kernel/asm/curve/bls381/util.asm +++ b/evm/src/cpu/kernel/asm/curve/bls381/util.asm @@ -0,0 +1,41 @@ +%macro add_fp381 + // stack: x0, x1, y0, y1 + PROVER_INPUT(sf::bls381_base::add_hi) + // stack: z1, x0, x1, y0, y1 + SWAP4 + // stack: y1, x0, x1, y0, z1 + PROVER_INPUT(sf::bls381_base::add_lo) + // stack: z0, y1, x0, x1, y0, z1 + SWAP4 + // stack: y0, y1, x0, x1, z0, z1 + %pop4 + // stack: z0, z1 +%endmacro + +%macro mul_fp381 + // stack: x0, x1, y0, y1 + PROVER_INPUT(sf::bls381_base::mul_hi) + // stack: z1, x0, x1, y0, y1 + SWAP4 + // stack: y1, x0, x1, y0, z1 + PROVER_INPUT(sf::bls381_base::mul_lo) + // stack: z0, y1, x0, x1, y0, z1 + SWAP4 + // stack: y0, y1, x0, x1, z0, z1 + %pop4 + // stack: z0, z1 +%endmacro + +%macro sub_fp381 + // stack: x0, x1, y0, y1 + PROVER_INPUT(sf::bls381_base::sub_hi) + // stack: z1, x0, x1, y0, y1 + SWAP4 + // stack: y1, x0, x1, y0, z1 + PROVER_INPUT(sf::bls381_base::sub_lo) + // stack: z0, y1, x0, x1, y0, z1 + SWAP4 + // stack: y0, y1, x0, x1, z0, z1 + %pop4 + // stack: z0, z1 +%endmacro diff --git a/evm/src/extension_tower.rs b/evm/src/extension_tower.rs index 00e396b4..f72b16ac 100644 --- a/evm/src/extension_tower.rs +++ b/evm/src/extension_tower.rs @@ -137,6 +137,14 @@ impl BLS381 { val: U512::from(val), } } + + pub fn lo(self) -> U256 { + U256(self.val.0[..4].try_into().unwrap()) + } + + pub fn hi(self) -> U256 { + U256(self.val.0[4..].try_into().unwrap()) + } } impl Distribution for Standard { diff --git a/evm/src/generation/prover_input.rs b/evm/src/generation/prover_input.rs index 7f62acda..69e2f63d 100644 --- a/evm/src/generation/prover_input.rs +++ b/evm/src/generation/prover_input.rs @@ -2,12 +2,12 @@ use std::mem::transmute; use std::str::FromStr; use anyhow::{bail, Error}; -use ethereum_types::{BigEndianHash, H256, U256}; +use ethereum_types::{BigEndianHash, H256, U256, U512}; use plonky2::field::types::Field; -use crate::extension_tower::{FieldExt, Fp12, BN254}; +use crate::extension_tower::{FieldExt, Fp12, BLS381, BN254}; use crate::generation::prover_input::EvmField::{ - Bn254Base, Bn254Scalar, Secp256k1Base, Secp256k1Scalar, + Bls381Base, Bls381Scalar, Bn254Base, Bn254Scalar, Secp256k1Base, Secp256k1Scalar, }; use crate::generation::prover_input::FieldOp::{Inverse, Sqrt}; use crate::generation::state::GenerationState; @@ -30,6 +30,7 @@ impl GenerationState { match input_fn.0[0].as_str() { "end_of_txns" => self.run_end_of_txns(), "ff" => self.run_ff(input_fn), + "sf" => self.run_sf(input_fn), "ffe" => self.run_ffe(input_fn), "mpt" => self.run_mpt(), "rlp" => self.run_rlp(), @@ -56,6 +57,24 @@ impl GenerationState { field.op(op, x) } + /// Special finite field operations. + fn run_sf(&self, input_fn: &ProverInputFn) -> U256 { + let field = EvmField::from_str(input_fn.0[1].as_str()).unwrap(); + let op = FieldOp::from_str(input_fn.0[2].as_str()).unwrap(); + let ptr = stack_peek(self, 11 - n).expect("Empty stack").as_usize(); + let xs: [U256; 4] = match field { + Bn254Base => { + let mut xs: [U256; 4] = [U256::zero(); 4]; + for i in 0..4 { + xs[i] = kernel_peek(self, BnPairing, ptr + i); + } + xs + } + _ => todo!(), + }; + field.op(op, xs) + } + /// Finite field extension operations. fn run_ffe(&self, input_fn: &ProverInputFn) -> U256 { let field = EvmField::from_str(input_fn.0[1].as_str()).unwrap(); @@ -126,6 +145,8 @@ impl GenerationState { } enum EvmField { + Bls381Base, + Bls381Scalar, Bn254Base, Bn254Scalar, Secp256k1Base, @@ -142,6 +163,8 @@ impl FromStr for EvmField { fn from_str(s: &str) -> Result { Ok(match s { + "bls381_base" => Bls381Base, + "bls381_scalar" => Bls381Scalar, "bn254_base" => Bn254Base, "bn254_scalar" => Bn254Scalar, "secp256k1_base" => Secp256k1Base, @@ -166,6 +189,8 @@ impl FromStr for FieldOp { impl EvmField { fn order(&self) -> U256 { match self { + EvmField::Bls381Base => todo!(), + EvmField::Bls381Scalar => todo!(), EvmField::Bn254Base => { U256::from_str("0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47") .unwrap() @@ -206,6 +231,54 @@ impl EvmField { modexp(x, q, n) } + fn add_lo(&self, inputs: [U256; 4]) -> U256 { + let [y1, x0, x1, y0] = inputs; + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = BLS381 { val: x } + BLS381 { val: y }; + z.lo() + } + + fn add_hi(&self, inputs: [U256; 4]) -> U256 { + let [x0, x1, y0, y1] = inputs; + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = BLS381 { val: x } + BLS381 { val: y }; + z.hi() + } + + fn mul_lo(&self, inputs: [U256; 4]) -> U256 { + let [y1, x0, x1, y0] = inputs; + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = BLS381 { val: x } * BLS381 { val: y }; + z.lo() + } + + fn mul_hi(&self, inputs: [U256; 4]) -> U256 { + let [x0, x1, y0, y1] = inputs; + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = BLS381 { val: x } * BLS381 { val: y }; + z.hi() + } + + fn sub_lo(&self, inputs: [U256; 4]) -> U256 { + let [y1, x0, x1, y0] = inputs; + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = BLS381 { val: x } - BLS381 { val: y }; + z.lo() + } + + fn sub_hi(&self, inputs: [U256; 4]) -> U256 { + let [x0, x1, y0, y1] = inputs; + let x = U512::from(x0) + (U512::from(x1) << 256); + let y = U512::from(y0) + (U512::from(y1) << 256); + let z = BLS381 { val: x } - BLS381 { val: y }; + z.hi() + } + fn field_extension_inverse(&self, n: usize, f: [U256; 12]) -> U256 { let f: Fp12 = unsafe { transmute(f) }; let f_inv: [U256; 12] = unsafe { transmute(f.inv()) }; From 392c29f41216eee628a467f58dd5194a8c1fce76 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Tue, 21 Mar 2023 21:16:19 -0700 Subject: [PATCH 07/15] compiles --- evm/src/generation/prover_input.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/evm/src/generation/prover_input.rs b/evm/src/generation/prover_input.rs index 69e2f63d..e25d11b4 100644 --- a/evm/src/generation/prover_input.rs +++ b/evm/src/generation/prover_input.rs @@ -60,19 +60,25 @@ impl GenerationState { /// Special finite field operations. fn run_sf(&self, input_fn: &ProverInputFn) -> U256 { let field = EvmField::from_str(input_fn.0[1].as_str()).unwrap(); - let op = FieldOp::from_str(input_fn.0[2].as_str()).unwrap(); - let ptr = stack_peek(self, 11 - n).expect("Empty stack").as_usize(); - let xs: [U256; 4] = match field { + let inputs: [U256; 4] = match field { Bn254Base => { - let mut xs: [U256; 4] = [U256::zero(); 4]; + let mut inputs: [U256; 4] = [U256::zero(); 4]; for i in 0..4 { - xs[i] = kernel_peek(self, BnPairing, ptr + i); + inputs[i] = stack_peek(self, i).expect("Empty stack"); } - xs + inputs } _ => todo!(), }; - field.op(op, xs) + match input_fn.0[2].as_str() { + "add_lo" => field.add_lo(inputs), + "add_hi" => field.add_hi(inputs), + "mul_lo" => field.mul_lo(inputs), + "mul_hi" => field.mul_hi(inputs), + "sub_lo" => field.sub_lo(inputs), + "sub_hi" => field.sub_hi(inputs), + _ => todo!(), + } } /// Finite field extension operations. From 0e8f6a2f681e94edfc6d520b062812659724c6ee Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Tue, 21 Mar 2023 21:17:46 -0700 Subject: [PATCH 08/15] test skeleton --- evm/src/cpu/kernel/asm/curve/bls381/util.asm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/evm/src/cpu/kernel/asm/curve/bls381/util.asm b/evm/src/cpu/kernel/asm/curve/bls381/util.asm index 5f39d68a..96136914 100644 --- a/evm/src/cpu/kernel/asm/curve/bls381/util.asm +++ b/evm/src/cpu/kernel/asm/curve/bls381/util.asm @@ -39,3 +39,15 @@ %pop4 // stack: z0, z1 %endmacro + +global test_add_fp381: + %add_fp381 + %jump(0xdeadbeef) + +global test_mul_fp381: + %add_fp381 + %jump(0xdeadbeef) + +global test_sub_fp381: + %add_fp381 + %jump(0xdeadbeef) From 373062b2a36b8099d722c42a31eda993d99997ba Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Tue, 21 Mar 2023 21:22:08 -0700 Subject: [PATCH 09/15] on stack --- evm/src/extension_tower.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/evm/src/extension_tower.rs b/evm/src/extension_tower.rs index f72b16ac..a71e2892 100644 --- a/evm/src/extension_tower.rs +++ b/evm/src/extension_tower.rs @@ -1186,6 +1186,12 @@ pub trait Stack { fn on_stack(self) -> Vec; } +impl Stack for BLS381 { + fn on_stack(self) -> Vec { + vec![self.lo(), self.hi()] + } +} + impl Stack for Fp6 { fn on_stack(self) -> Vec { let f: [U256; 6] = unsafe { transmute(self) }; From 84a0bcf893da4a2d041aae90b0de326145ff9b1e Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Tue, 21 Mar 2023 21:28:15 -0700 Subject: [PATCH 10/15] cleanup --- evm/src/extension_tower.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/evm/src/extension_tower.rs b/evm/src/extension_tower.rs index a71e2892..4b52c414 100644 --- a/evm/src/extension_tower.rs +++ b/evm/src/extension_tower.rs @@ -210,10 +210,10 @@ impl Mul for BLS381 { fn mul(self, other: Self) -> Self { // x1, y1 are at most ((q-1) // 2^256) < 2^125 - let x0 = U512(self.val.0[..4].try_into().unwrap()); - let x1 = U512(self.val.0[4..].try_into().unwrap()); - let y0 = U512(other.val.0[..4].try_into().unwrap()); - let y1 = U512(other.val.0[4..].try_into().unwrap()); + let x0 = U512::from(self.lo()); + let x1 = U512::from(self.hi()); + let y0 = U512::from(other.lo()); + let y1 = U512::from(other.hi()); let z00 = BLS381 { val: x0.saturating_mul(y0) % BLS_BASE, From 1627a9a0d33bddd5086450e67e5e268e84d106c0 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Wed, 22 Mar 2023 09:55:35 -0700 Subject: [PATCH 11/15] tests pass --- evm/src/cpu/kernel/aggregator.rs | 1 + evm/src/cpu/kernel/asm/curve/bls381/util.asm | 4 +- evm/src/cpu/kernel/tests/bls381.rs | 48 ++++++++++++++++++++ evm/src/cpu/kernel/tests/mod.rs | 1 + evm/src/generation/prover_input.rs | 2 +- 5 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 evm/src/cpu/kernel/tests/bls381.rs diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 89f11467..595edfa7 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -35,6 +35,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/core/terminate.asm"), include_str!("asm/core/transfer.asm"), include_str!("asm/core/util.asm"), + include_str!("asm/curve/bls381/util.asm"), include_str!("asm/curve/bn254/curve_arithmetic/constants.asm"), include_str!("asm/curve/bn254/curve_arithmetic/curve_add.asm"), include_str!("asm/curve/bn254/curve_arithmetic/curve_mul.asm"), diff --git a/evm/src/cpu/kernel/asm/curve/bls381/util.asm b/evm/src/cpu/kernel/asm/curve/bls381/util.asm index 96136914..a4e846cb 100644 --- a/evm/src/cpu/kernel/asm/curve/bls381/util.asm +++ b/evm/src/cpu/kernel/asm/curve/bls381/util.asm @@ -45,9 +45,9 @@ global test_add_fp381: %jump(0xdeadbeef) global test_mul_fp381: - %add_fp381 + %mul_fp381 %jump(0xdeadbeef) global test_sub_fp381: - %add_fp381 + %sub_fp381 %jump(0xdeadbeef) diff --git a/evm/src/cpu/kernel/tests/bls381.rs b/evm/src/cpu/kernel/tests/bls381.rs new file mode 100644 index 00000000..0a35ebbb --- /dev/null +++ b/evm/src/cpu/kernel/tests/bls381.rs @@ -0,0 +1,48 @@ +use anyhow::Result; +use ethereum_types::{U256, U512}; +use rand::Rng; + +use crate::cpu::kernel::interpreter::{ + run_interpreter_with_memory, Interpreter, InterpreterMemoryInitialization, +}; +use crate::extension_tower::{Stack, BLS381}; +use crate::memory::segments::Segment::KernelGeneral; + +fn extract_stack(interpreter: Interpreter<'static>) -> Vec { + interpreter + .stack() + .iter() + .rev() + .cloned() + .collect::>() +} + +fn combine_u256s(hi: U256, lo: U256) -> U512 { + U512::from(lo) + (U512::from(hi) << 256) +} + +#[test] +fn test_bls_ops() -> Result<()> { + let mut rng = rand::thread_rng(); + let x: BLS381 = rng.gen::(); + let y: BLS381 = rng.gen::(); + + let mut stack = x.on_stack(); + stack.extend(y.on_stack()); + + let setup = InterpreterMemoryInitialization { + label: "test_mul_fp381".to_string(), + stack, + segment: KernelGeneral, + memory: vec![], + }; + let interpreter = run_interpreter_with_memory(setup).unwrap(); + let output = extract_stack(interpreter); + println!("{:#?}", output); + let output_512 = combine_u256s(output[1], output[0]); + let expected = x * y; + + assert_eq!(expected.val, output_512); + + Ok(()) +} diff --git a/evm/src/cpu/kernel/tests/mod.rs b/evm/src/cpu/kernel/tests/mod.rs index 061cd57d..68695e2f 100644 --- a/evm/src/cpu/kernel/tests/mod.rs +++ b/evm/src/cpu/kernel/tests/mod.rs @@ -1,6 +1,7 @@ mod account_code; mod balance; mod bignum; +mod bls381; mod bn254; mod core; mod ecc; diff --git a/evm/src/generation/prover_input.rs b/evm/src/generation/prover_input.rs index e25d11b4..74321562 100644 --- a/evm/src/generation/prover_input.rs +++ b/evm/src/generation/prover_input.rs @@ -61,7 +61,7 @@ impl GenerationState { fn run_sf(&self, input_fn: &ProverInputFn) -> U256 { let field = EvmField::from_str(input_fn.0[1].as_str()).unwrap(); let inputs: [U256; 4] = match field { - Bn254Base => { + Bls381Base => { let mut inputs: [U256; 4] = [U256::zero(); 4]; for i in 0..4 { inputs[i] = stack_peek(self, i).expect("Empty stack"); From 1f3e3de77c3cf9b965a32061beb153a07b6a4da9 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Wed, 22 Mar 2023 10:16:02 -0700 Subject: [PATCH 12/15] clean and generalize --- evm/src/cpu/kernel/tests/bls381.rs | 46 +++++++++++++----------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bls381.rs b/evm/src/cpu/kernel/tests/bls381.rs index 0a35ebbb..6d412849 100644 --- a/evm/src/cpu/kernel/tests/bls381.rs +++ b/evm/src/cpu/kernel/tests/bls381.rs @@ -8,17 +8,20 @@ use crate::cpu::kernel::interpreter::{ use crate::extension_tower::{Stack, BLS381}; use crate::memory::segments::Segment::KernelGeneral; -fn extract_stack(interpreter: Interpreter<'static>) -> Vec { - interpreter - .stack() - .iter() - .rev() - .cloned() - .collect::>() -} - -fn combine_u256s(hi: U256, lo: U256) -> U512 { - U512::from(lo) + (U512::from(hi) << 256) +fn run_and_return_bls(label: String, x: BLS381, y: BLS381) -> BLS381 { + let mut stack = x.on_stack(); + stack.extend(y.on_stack()); + let setup = InterpreterMemoryInitialization { + label, + stack, + segment: KernelGeneral, + memory: vec![], + }; + let interpreter = run_interpreter_with_memory(setup).unwrap(); + let output = interpreter.stack(); + BLS381 { + val: U512::from(output[1]) + (U512::from(output[0]) << 256), + } } #[test] @@ -27,22 +30,13 @@ fn test_bls_ops() -> Result<()> { let x: BLS381 = rng.gen::(); let y: BLS381 = rng.gen::(); - let mut stack = x.on_stack(); - stack.extend(y.on_stack()); + let output_add = run_and_return_bls("test_add_fp381".to_string(), x, y); + let output_mul = run_and_return_bls("test_mul_fp381".to_string(), x, y); + let output_sub = run_and_return_bls("test_sub_fp381".to_string(), x, y); - let setup = InterpreterMemoryInitialization { - label: "test_mul_fp381".to_string(), - stack, - segment: KernelGeneral, - memory: vec![], - }; - let interpreter = run_interpreter_with_memory(setup).unwrap(); - let output = extract_stack(interpreter); - println!("{:#?}", output); - let output_512 = combine_u256s(output[1], output[0]); - let expected = x * y; - - assert_eq!(expected.val, output_512); + assert_eq!(output_add, x + y); + assert_eq!(output_mul, x * y); + assert_eq!(output_sub, x - y); Ok(()) } From 74afec70ed340ac64b74b2ca16ef32e85b501bcd Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Wed, 22 Mar 2023 11:56:58 -0700 Subject: [PATCH 13/15] remove imports --- evm/src/cpu/kernel/tests/bls381.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/tests/bls381.rs b/evm/src/cpu/kernel/tests/bls381.rs index 6d412849..2986537f 100644 --- a/evm/src/cpu/kernel/tests/bls381.rs +++ b/evm/src/cpu/kernel/tests/bls381.rs @@ -1,9 +1,9 @@ use anyhow::Result; -use ethereum_types::{U256, U512}; +use ethereum_types::{U512}; use rand::Rng; use crate::cpu::kernel::interpreter::{ - run_interpreter_with_memory, Interpreter, InterpreterMemoryInitialization, + run_interpreter_with_memory, InterpreterMemoryInitialization, }; use crate::extension_tower::{Stack, BLS381}; use crate::memory::segments::Segment::KernelGeneral; From c8d2769c289c9aeeb3fcf1f9517a08a5257d37c4 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Wed, 22 Mar 2023 11:58:51 -0700 Subject: [PATCH 14/15] fmt --- evm/src/cpu/kernel/tests/bls381.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/tests/bls381.rs b/evm/src/cpu/kernel/tests/bls381.rs index 2986537f..afd22a14 100644 --- a/evm/src/cpu/kernel/tests/bls381.rs +++ b/evm/src/cpu/kernel/tests/bls381.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use ethereum_types::{U512}; +use ethereum_types::U512; use rand::Rng; use crate::cpu::kernel::interpreter::{ From cf5a4edc8b73f5e311b5985a71fa6a4165dae869 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Mon, 27 Mar 2023 18:20:22 -0700 Subject: [PATCH 15/15] prover input minor improvements --- evm/src/generation/prover_input.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/evm/src/generation/prover_input.rs b/evm/src/generation/prover_input.rs index 74321562..ea834164 100644 --- a/evm/src/generation/prover_input.rs +++ b/evm/src/generation/prover_input.rs @@ -61,13 +61,9 @@ impl GenerationState { fn run_sf(&self, input_fn: &ProverInputFn) -> U256 { let field = EvmField::from_str(input_fn.0[1].as_str()).unwrap(); let inputs: [U256; 4] = match field { - Bls381Base => { - let mut inputs: [U256; 4] = [U256::zero(); 4]; - for i in 0..4 { - inputs[i] = stack_peek(self, i).expect("Empty stack"); - } - inputs - } + Bls381Base => std::array::from_fn(|i| { + stack_peek(self, i).expect("Insufficient number of items on stack") + }), _ => todo!(), }; match input_fn.0[2].as_str() { @@ -91,16 +87,12 @@ impl GenerationState { .unwrap() .parse::() .unwrap(); - let ptr = stack_peek(self, 11 - n).expect("Empty stack").as_usize(); + let ptr = stack_peek(self, 11 - n) + .expect("Insufficient number of items on stack") + .as_usize(); let f: [U256; 12] = match field { - Bn254Base => { - let mut f: [U256; 12] = [U256::zero(); 12]; - for i in 0..12 { - f[i] = kernel_peek(self, BnPairing, ptr + i); - } - f - } + Bn254Base => std::array::from_fn(|i| kernel_peek(self, BnPairing, ptr + i)), _ => todo!(), }; field.field_extension_inverse(n, f)