From 1c8a9917aa9b21e70233681e5b62f49dd41277e3 Mon Sep 17 00:00:00 2001 From: Jules de Smit Date: Tue, 29 Nov 2022 20:33:16 -0500 Subject: [PATCH] Add GLV code, endomorphism still fails --- src/arithmetic.rs | 33 +++++++++++++++ src/curve.rs | 105 ++++++++++++++++++++++++++++++++++++++++++---- src/fq.rs | 1 + 3 files changed, 131 insertions(+), 8 deletions(-) diff --git a/src/arithmetic.rs b/src/arithmetic.rs index ea8bb8b..f79a54f 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -73,3 +73,36 @@ pub(crate) const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) { let ret = (a as u128) + ((b as u128) * (c as u128)) + (carry as u128); (ret as u64, (ret >> 64) as u64) } + +/// Compute a + (b * c), returning the result and the new carry over. +#[inline(always)] +pub(crate) const fn macx(a: u64, b: u64, c: u64) -> (u64, u64) { + let res = (a as u128) + ((b as u128) * (c as u128)); + (res as u64, (res >> 64) as u64) +} + +/// Compute a * b, returning the result. +#[inline(always)] +pub(crate) fn mul_512(a: [u64; 4], b: [u64; 4]) -> [u64; 8] { + let (r0, carry) = macx(0, a[0], b[0]); + let (r1, carry) = macx(carry, a[0], b[1]); + let (r2, carry) = macx(carry, a[0], b[2]); + let (r3, carry_out) = macx(carry, a[0], b[3]); + + let (r1, carry) = macx(r1, a[1], b[0]); + let (r2, carry) = mac(r2, a[1], b[1], carry); + let (r3, carry) = mac(r3, a[1], b[2], carry); + let (r4, carry_out) = mac(carry_out, a[1], b[3], carry); + + let (r2, carry) = macx(r2, a[2], b[0]); + let (r3, carry) = mac(r3, a[2], b[1], carry); + let (r4, carry) = mac(r4, a[2], b[2], carry); + let (r5, carry_out) = mac(carry_out, a[2], b[3], carry); + + let (r3, carry) = macx(r3, a[3], b[0]); + let (r4, carry) = mac(r4, a[3], b[1], carry); + let (r5, carry) = mac(r5, a[3], b[2], carry); + let (r6, carry_out) = mac(carry_out, a[3], b[3], carry); + + [r0, r1, r2, r3, r4, r5, r6, carry_out] +} diff --git a/src/curve.rs b/src/curve.rs index ccfec11..a423288 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -1,3 +1,4 @@ +use crate::arithmetic::mul_512; use crate::Fq; use crate::Fr; use core::cmp; @@ -7,7 +8,7 @@ use core::ops::{Add, Mul, Neg, Sub}; use ff::{Field, PrimeField}; use group::Curve; use group::{prime::PrimeCurveAffine, Group as _, GroupEncoding}; -use halo2curves::{Coordinates, CurveAffine, CurveAffineExt, CurveExt, Group}; +use halo2curves::{Coordinates, CurveAffine, CurveAffineExt, CurveExt, FieldExt, Group}; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; @@ -30,12 +31,6 @@ new_curve_impl!( "grumpkin_g1", ); -impl G1 { - fn endomorphism_base(&self) -> Self { - unimplemented!(); - } -} - impl CurveAffineExt for G1Affine { batch_add!(); } @@ -70,12 +65,106 @@ impl group::cofactor::CofactorGroup for G1 { } } +const ENDO_G1: [u64; 4] = [ + 0x7a7bd9d4391eb18du64, + 0x4ccef014a773d2cfu64, + 0x0000000000000002u64, + 0u64, +]; +const ENDO_G2: [u64; 4] = [0xd91d232ec7e0b3d7u64, 0x0000000000000002u64, 0u64, 0u64]; +const ENDO_MINUS_B1: [u64; 4] = [0x8211bbeb7d4f1128u64, 0x6f4d8248eeb859fcu64, 0u64, 0u64]; +const ENDO_B2: [u64; 4] = [0x89d3256894d213e3u64, 0u64, 0u64, 0u64]; +const ENDO_BETA: Fr = Fr::from_raw([ + 0xe4bd44e5607cfd48, + 0xc28f069fbb966e3d, + 0x5e6dd9e7e0acccb0, + 0x30644e72e131a029, +]); + +trait CurveEndo: CurveExt { + fn endomorphism_base(&self) -> Self; + fn endomorphism_scalars(k: &Self::ScalarExt) -> (u128, u128); +} + +impl CurveEndo for G1 { + fn endomorphism_base(&self) -> Self { + Self { + x: self.x * Self::Base::ZETA, + y: -self.y, + z: self.z, + } + } + + fn endomorphism_scalars(k: &Self::ScalarExt) -> (u128, u128) { + #[cfg(feature = "asm")] + let input = Fr::montgomery_reduce(&[k.0[0], k.0[1], k.0[2], k.0[3], 0, 0, 0, 0]).0; + + #[cfg(not(feature = "asm"))] + let input = Fr::montgomery_reduce(k.0[0], k.0[1], k.0[2], k.0[3], 0, 0, 0, 0).0; + + let c1_512 = mul_512(ENDO_G2, input); + let c2_512 = mul_512(ENDO_G1, input); + + let c1_hi = [c1_512[4], c1_512[5], c1_512[6], c1_512[7]]; + let c2_hi = [c2_512[4], c2_512[5], c2_512[6], c2_512[7]]; + + let q1_512 = mul_512(c1_hi, ENDO_MINUS_B1); + let q2_512 = mul_512(c2_hi, ENDO_B2); + + let q1_lo = Self::ScalarExt::from_raw([q1_512[0], q1_512[1], q1_512[2], q1_512[3]]); + let q2_lo = Self::ScalarExt::from_raw([q2_512[0], q2_512[1], q2_512[2], q2_512[3]]); + + let k1 = q2_lo - q1_lo; + let k2 = (k1 * ENDO_BETA) + k; + + (k2.get_lower_128(), k1.get_lower_128()) + } +} + #[cfg(test)] mod tests { - use crate::G1; + use crate::{ + curve::{CurveEndo, ENDO_BETA}, + Fr, G1Affine, G1, + }; + use ff::Field; + use halo2curves::CurveExt; + use rand_core::OsRng; #[test] fn test_curve() { crate::tests::curve::curve_tests::(); } + + #[test] + fn test_endo_consistency() { + let g = G1::generator(); + assert_eq!(g * (-ENDO_BETA), g.endo()); + } + + #[test] + fn test_endomorphism() { + use halo2curves::FieldExt; + + let scalar = Fr::random(OsRng); + let point = G1Affine::random(OsRng); + + let expected = point * scalar; + + let (part1, part2) = G1::endomorphism_scalars(&scalar); + + let k1 = Fr::from_u128(part1); + let k2 = Fr::from_u128(part2); + + let t1 = point * k1; + let base = G1::endomorphism_base(&point.into()); + + let t2 = base * k2; + let result = t1 + t2; + + let res_affine: G1Affine = result.into(); + let exp_affine: G1Affine = expected.into(); + + assert_eq!(res_affine, exp_affine); + } } diff --git a/src/fq.rs b/src/fq.rs index 28aad4c..53136b5 100644 --- a/src/fq.rs +++ b/src/fq.rs @@ -88,6 +88,7 @@ const ROOT_OF_UNITY: Fq = Fq::from_raw([ 0x03ddb9f5166d18b7, ]); +// Unused constant for base field const ROOT_OF_UNITY_INV: Fq = Fq::zero(); // Unused constant for base field