From 05788a997df9b1f338d72405b5168c87779ef072 Mon Sep 17 00:00:00 2001 From: Dmitry Vagner Date: Tue, 14 Mar 2023 15:16:24 -0700 Subject: [PATCH] compiles --- evm/src/bls381_arithmetic.rs | 263 ++++++++++++++++++++--------------- 1 file changed, 151 insertions(+), 112 deletions(-) diff --git a/evm/src/bls381_arithmetic.rs b/evm/src/bls381_arithmetic.rs index d2e2cac3..bf886e1c 100644 --- a/evm/src/bls381_arithmetic.rs +++ b/evm/src/bls381_arithmetic.rs @@ -1,11 +1,13 @@ use std::ops::{Add, Div, Mul, Neg, Sub}; -use ethereum_types::{U512}; +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 @@ -158,12 +160,14 @@ fn exp_fp(x: Fp, e: U512) -> Fp { /// 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 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)>(); @@ -182,7 +186,7 @@ impl Add for Fp2 { } } -impl Neg for Fp2 { +impl Neg for Fp2 { type Output = Self; fn neg(self) -> Self::Output { @@ -193,7 +197,7 @@ impl Neg for Fp2 { } } -impl Sub for Fp2 { +impl Sub for Fp2 { type Output = Self; fn sub(self, other: Self) -> Self { @@ -204,9 +208,7 @@ impl Sub for Fp2 { } } -impl Mul - for Fp2 -{ +impl Mul for Fp2 { type Output = Self; fn mul(self, other: Self) -> Self { @@ -270,13 +272,13 @@ impl Div for Fp2 { } } -trait Adj { +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 { +impl Adj for Fp2 { fn mul_adj(self) -> Self { Fp2 { re: self.re - self.im, @@ -288,14 +290,15 @@ impl Adj for Fp2 { /// 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 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)>(); @@ -374,12 +377,12 @@ impl Fp6 { } } -pub trait Frob { - const FROB_T: Self; - const FROB_Z: Self; +impl Fp6 { + const FROB_T: [[Fp2; 6]; 2] = [[Fp2::::ZERO; 6]; 2]; + const FROB_Z: [Fp2; 12] = [Fp2::::ZERO; 12]; } -impl Fp6 { +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 @@ -390,8 +393,8 @@ impl Fp6 { /// 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 = Self::FROB_T[0][n]; - let frob_t2 = Self::FROB_T[1][n]; + let frob_t1 = Fp6::::FROB_T[0][n]; + let frob_t2 = Fp6::::FROB_T[1][n]; if n % 2 != 0 { Fp6 { @@ -409,7 +412,7 @@ impl Fp6 { } } -impl FieldExt for Fp6 { +impl FieldExt for Fp6 { const ZERO: Fp6 = Fp6 { t0: Fp2::::ZERO, t1: Fp2::::ZERO, @@ -456,110 +459,146 @@ impl Div for Fp6 { } } -// /// 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 { -// pub z0: Fp6, -// pub z1: Fp6, -// } +/// 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 Unital for Fp12 { -// const ZERO: Fp12 = Fp12 { -// z0: Fp6::::ZERO, -// z1: Fp6::::ZERO, -// }; +impl FieldExt for Fp12 { + const ZERO: Fp12 = Fp12 { + z0: Fp6::::ZERO, + z1: Fp6::::ZERO, + }; -// const UNIT: Fp12 = Fp12 { -// z0: Fp6::::UNIT, -// z1: Fp6::::ZERO, -// }; -// } + const UNIT: Fp12 = Fp12 { + z0: Fp6::::UNIT, + z1: Fp6::::ZERO, + }; -// // impl> Distribution> for Standard { -// // fn sample(&self, rng: &mut R) -> Fp12 { -// // let (z0, z1) = rng.gen::<(Fp6, Fp6)>(); -// // Fp12 { z0, z1 } -// // } -// // } + /// 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 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> Distribution> for Standard { +// fn sample(&self, rng: &mut R) -> Fp12 { +// let (z0, z1) = rng.gen::<(Fp6, Fp6)>(); +// Fp12 { z0, z1 } // } // } -// 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, -// } -// } +impl Add for Fp12 { + type Output = Self; -// fn conj(self) -> Fp12 { -// Fp12 { -// z0: self.z0, -// z1: -self.z1, -// } -// } -// } + fn add(self, other: Self) -> Self { + Fp12 { + z0: self.z0 + other.z0, + z1: self.z1 + other.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(Self::FROB_Z[n]), -// } -// } +impl Neg for Fp12 { + type Output = Self; -// /// 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 -// pub 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) -// } -// } + fn neg(self) -> Self::Output { + Fp12 { + z0: -self.z0, + z1: -self.z1, + } + } +} -// #[allow(clippy::suspicious_arithmetic_impl)] -// impl> Div for Fp12 { -// type Output = Self; +impl Sub for Fp12 { + type Output = Self; -// fn div(self, rhs: Self) -> Self::Output { -// self * rhs.inv() -// } -// } + 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;