Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}
105 changes: 97 additions & 8 deletions src/curve.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::arithmetic::mul_512;
use crate::Fq;
use crate::Fr;
use core::cmp;
Expand All @@ -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};

Expand All @@ -30,12 +31,6 @@ new_curve_impl!(
"grumpkin_g1",
);

impl G1 {
fn endomorphism_base(&self) -> Self {
unimplemented!();
}
}

impl CurveAffineExt for G1Affine {
batch_add!();
}
Expand Down Expand Up @@ -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::<G1>();
}

#[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);
}
}
1 change: 1 addition & 0 deletions src/fq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down