diff --git a/evm/src/bn254_pairing.rs b/evm/src/bn254_pairing.rs index 138f23e7..25cb649f 100644 --- a/evm/src/bn254_pairing.rs +++ b/evm/src/bn254_pairing.rs @@ -5,32 +5,32 @@ use rand::Rng; use crate::extension_tower::{FieldExt, Fp12, Fp2, Fp6, BN254}; -// The curve consists of pairs (x, y): (BN254, BN254) | y^2 = x^3 + 2 #[derive(Debug, Copy, Clone, PartialEq)] -pub struct Curve { - pub x: BN254, - pub y: BN254, +pub struct Curve +where + T: FieldExt, +{ + pub x: T, + pub y: T, } -// The curve is cyclic with generator (1, 2) -pub const CURVE_GENERATOR: Curve = { - Curve { - x: BN254 { val: U256::one() }, - y: BN254 { - val: U256([2, 0, 0, 0]), - }, +impl Curve { + pub fn unit() -> Self { + Curve { + x: T::UNIT, + y: T::UNIT, + } } -}; +} /// Standard addition formula for elliptic curves, restricted to the cases -/// where neither inputs nor output would ever be the identity O. source: /// https://en.wikipedia.org/wiki/Elliptic_curve#Algebraic_interpretation -impl Add for Curve { +impl Add for Curve { type Output = Self; fn add(self, other: Self) -> Self { let m = if self == other { - BN254::new(3) * self.x * self.x / (BN254::new(2) * self.y) + T::new(3) * self.x * self.x / (T::new(2) * self.y) } else { (other.y - self.y) / (other.x - self.x) }; @@ -42,8 +42,8 @@ impl Add for Curve { } } -impl Neg for Curve { - type Output = Curve; +impl Neg for Curve { + type Output = Curve; fn neg(self) -> Self { Curve { @@ -53,37 +53,48 @@ impl Neg for Curve { } } -impl Mul for Curve { - type Output = Curve; - - fn mul(self, other: i32) -> Self { - let mut result: Curve = self; - if other.is_negative() { - result = -result; - } - let mut multiplier = result; - let mut exp = other.abs() as usize; - while exp > 0 { - if exp % 2 == 1 { - result = result + multiplier; - } - exp >>= 1; - multiplier = multiplier + multiplier; - } - result - } +pub trait CurveGroup { + const GENERATOR: Self; } -// The twisted curve consists of pairs (x, y): (Fp2, Fp2) | y^2 = x^3 + 3/(9 + i) -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct TwistedCurve { - pub x: Fp2, - pub y: Fp2, +/// The BN curve consists of pairs +/// (x, y): (BN254, BN254) | y^2 = x^3 + 2 +// with generator given by (1, 2) +impl CurveGroup for Curve { + const GENERATOR: Curve = Curve { + x: BN254 { val: U256::one() }, + y: BN254 { + val: U256([2, 0, 0, 0]), + }, + }; } -// The twisted curve is cyclic with generator (x, y) as follows -pub const TWISTED_GENERATOR: TwistedCurve = { - TwistedCurve { +// impl Mul for Curve { +// type Output = Curve; + +// fn mul(self, other: i32) -> Self { +// let mut result: Curve = self; +// if other.is_negative() { +// result = -result; +// } +// let mut multiplier = result; +// let mut exp = other.unsigned_abs() as usize; +// while exp > 0 { +// if exp % 2 == 1 { +// result = result + multiplier; +// } +// exp >>= 1; +// multiplier = multiplier + multiplier; +// } +// result +// } +// } + +/// The twisted curve consists of pairs +/// (x, y): (Fp2, Fp2) | y^2 = x^3 + 3/(9 + i) +/// with generator given as follows +impl CurveGroup for Curve> { + const GENERATOR: Curve> = Curve { x: Fp2 { re: BN254 { val: U256([ @@ -120,11 +131,11 @@ pub const TWISTED_GENERATOR: TwistedCurve = { ]), }, }, - } -}; + }; +} // The tate pairing takes a point each from the curve and its twist and outputs an Fp12 element -pub fn tate(p: Curve, q: TwistedCurve) -> Fp12 { +pub fn tate(p: Curve, q: Curve>) -> Fp12 { let miller_output = miller_loop(p, q); final_exponent(miller_output) } @@ -132,7 +143,7 @@ pub fn tate(p: Curve, q: TwistedCurve) -> Fp12 { /// Standard code for miller loop, can be found on page 99 at this url: /// https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf#page=107 /// where EXP is a hardcoding of the array of Booleans that the loop traverses -pub fn miller_loop(p: Curve, q: TwistedCurve) -> Fp12 { +pub fn miller_loop(p: Curve, q: Curve>) -> Fp12 { let mut r = p; let mut acc: Fp12 = Fp12::::UNIT; let mut line: Fp12; @@ -151,14 +162,14 @@ pub fn miller_loop(p: Curve, q: TwistedCurve) -> Fp12 { } /// The sloped line function for doubling a point -pub fn tangent(p: Curve, q: TwistedCurve) -> Fp12 { +pub fn tangent(p: Curve, q: Curve>) -> Fp12 { let cx = -BN254::new(3) * p.x * p.x; let cy = BN254::new(2) * p.y; sparse_embed(p.y * p.y - BN254::new(9), q.x * cx, q.y * cy) } /// The sloped line function for adding two points -pub fn cord(p1: Curve, p2: Curve, q: TwistedCurve) -> Fp12 { +pub fn cord(p1: Curve, p2: Curve, q: Curve>) -> Fp12 { let cx = p2.y - p1.y; let cy = p1.x - p2.x; sparse_embed(p1.y * p2.x - p2.y * p1.x, q.x * cx, q.y * cy) diff --git a/evm/src/cpu/kernel/tests/bn254.rs b/evm/src/cpu/kernel/tests/bn254.rs index d489a8a8..6895e8a4 100644 --- a/evm/src/cpu/kernel/tests/bn254.rs +++ b/evm/src/cpu/kernel/tests/bn254.rs @@ -4,14 +4,12 @@ use anyhow::Result; use ethereum_types::U256; use rand::Rng; -use crate::bn254_pairing::{ - final_exponent, gen_fp12_sparse, miller_loop, CURVE_GENERATOR, TWISTED_GENERATOR, -}; +use crate::bn254_pairing::{final_exponent, gen_fp12_sparse, miller_loop, Curve, CurveGroup}; use crate::cpu::kernel::interpreter::{ run_interpreter_with_memory, Interpreter, InterpreterMemoryInitialization, }; use crate::cpu::kernel::tests::u256ify; -use crate::extension_tower::{FieldExt, Fp12, Fp6, Stack, BN254}; +use crate::extension_tower::{FieldExt, Fp12, Fp2, Fp6, Stack, BN254}; use crate::memory::segments::Segment::BnPairing; fn extract_stack(interpreter: Interpreter<'static>) -> Vec { @@ -204,8 +202,8 @@ fn test_bn_final_exponent() -> Result<()> { } fn pairing_input() -> Vec { - let curve_gen: [U256; 2] = unsafe { transmute(CURVE_GENERATOR) }; - let twisted_gen: [U256; 4] = unsafe { transmute(TWISTED_GENERATOR) }; + let curve_gen: [U256; 2] = unsafe { transmute(Curve::::GENERATOR) }; + let twisted_gen: [U256; 4] = unsafe { transmute(Curve::>::GENERATOR) }; let mut input = curve_gen.to_vec(); input.extend_from_slice(&twisted_gen); input @@ -225,7 +223,7 @@ fn test_bn_miller() -> Result<()> { }; let interpreter = run_interpreter_with_memory(setup).unwrap(); let output: Vec = interpreter.extract_kernel_memory(BnPairing, out..out + 12); - let expected = miller_loop(CURVE_GENERATOR, TWISTED_GENERATOR).on_stack(); + let expected = miller_loop(Curve::::GENERATOR, Curve::>::GENERATOR).on_stack(); assert_eq!(output, expected); diff --git a/evm/src/extension_tower.rs b/evm/src/extension_tower.rs index ddcfe254..1b5bf684 100644 --- a/evm/src/extension_tower.rs +++ b/evm/src/extension_tower.rs @@ -7,6 +7,7 @@ use rand::Rng; pub trait FieldExt: Copy + + std::cmp::PartialEq + std::ops::Add + std::ops::Neg + std::ops::Sub @@ -15,6 +16,7 @@ pub trait FieldExt: { const ZERO: Self; const UNIT: Self; + fn new(val: usize) -> Self; fn inv(self) -> Self; } @@ -30,14 +32,6 @@ pub struct BN254 { pub val: U256, } -impl BN254 { - pub fn new(val: usize) -> BN254 { - BN254 { - val: U256::from(val), - } - } -} - impl Distribution for Standard { fn sample(&self, rng: &mut R) -> BN254 { let xs = rng.gen::<[u64; 4]>(); @@ -91,6 +85,11 @@ impl Mul for BN254 { impl FieldExt for BN254 { const ZERO: Self = BN254 { val: U256::zero() }; const UNIT: Self = BN254 { val: U256::one() }; + fn new(val: usize) -> BN254 { + BN254 { + val: U256::from(val), + } + } fn inv(self) -> BN254 { let exp = BN_BASE - 2; let mut current = self; @@ -131,12 +130,6 @@ pub struct BLS381 { } impl BLS381 { - pub fn new(val: usize) -> BLS381 { - BLS381 { - val: U512::from(val), - } - } - pub fn lo(self) -> U256 { U256(self.val.0[..4].try_into().unwrap()) } @@ -234,6 +227,11 @@ impl Mul for BLS381 { impl FieldExt for BLS381 { const ZERO: Self = BLS381 { val: U512::zero() }; const UNIT: Self = BLS381 { val: U512::one() }; + fn new(val: usize) -> BLS381 { + BLS381 { + val: U512::from(val), + } + } fn inv(self) -> BLS381 { let exp = BLS_BASE - 2; let mut current = self; @@ -365,6 +363,14 @@ impl FieldExt for Fp2 { re: T::UNIT, im: T::ZERO, }; + + fn new(val: usize) -> Fp2 { + Fp2 { + re: T::new(val), + 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(); @@ -974,6 +980,14 @@ where t1: Fp2::::ZERO, t2: Fp2::::ZERO, }; + + fn new(val: usize) -> Fp6 { + Fp6 { + t0: Fp2::::new(val), + t1: Fp2::::ZERO, + t2: Fp2::::ZERO, + } + } /// Let x_n = x^(p^n) and note that /// x_0 = x^(p^0) = x^1 = x @@ -1040,6 +1054,13 @@ where z1: Fp6::::ZERO, }; + fn new(val: usize) -> Fp12 { + Fp12 { + z0: Fp6::::new(val), + z1: Fp6::::ZERO, + } + } + /// By Galois Theory, given x: Fp12, the product /// phi = Prod_{i=0}^11 x_i /// lands in BN254, and hence the inverse of x is given by