Skip to content

Commit

Permalink
Legendre trait now uses accelerated Jacobi (#102)
Browse files Browse the repository at this point in the history
legendre trait now uses accelerated jacobi
  • Loading branch information
mratsim authored Nov 24, 2023
1 parent d59aaa0 commit 2e7f8eb
Show file tree
Hide file tree
Showing 18 changed files with 82 additions and 135 deletions.
5 changes: 1 addition & 4 deletions benches/bn256_field.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use halo2curves::{bn256::*, ff::Field, legendre::Legendre};
use halo2curves::{bn256::*, ff::Field, ff_ext::Legendre};
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;

Expand Down Expand Up @@ -45,9 +45,6 @@ pub fn bench_bn256_field(c: &mut Criterion) {
group.bench_function("bn256_fq_legendre", |bencher| {
bencher.iter(|| black_box(&a).legendre())
});
group.bench_function("bn256_fq_jacobi", |bencher| {
bencher.iter(|| black_box(&a).jacobi())
});
}

criterion_group!(benches, bench_bn256_field);
Expand Down
9 changes: 5 additions & 4 deletions src/bn256/fq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::bn256::assembly::field_arithmetic_asm;
use crate::{arithmetic::macx, field_arithmetic, field_specific};

use crate::arithmetic::{adc, mac, sbb};
use crate::extend_field_legendre;
use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
use crate::{
field_bits, field_common, impl_add_binop_specify_output, impl_binops_additive,
Expand Down Expand Up @@ -160,7 +161,7 @@ impl Fq {
}
}

prime_field_legendre!(Fq);
extend_field_legendre!(Fq);

impl ff::Field for Fq {
const ZERO: Self = Self::zero();
Expand Down Expand Up @@ -284,7 +285,7 @@ impl WithSmallOrderMulGroup<3> for Fq {
#[cfg(test)]
mod test {
use super::*;
use crate::legendre::Legendre;
use crate::ff_ext::Legendre;
use ff::Field;
use rand_core::OsRng;

Expand All @@ -297,7 +298,7 @@ mod test {
let a = Fq::random(OsRng);
let mut b = a;
b = b.square();
assert_eq!(b.legendre(), Fq::ONE);
assert_eq!(b.legendre(), 1);

let b = b.sqrt().unwrap();
let mut negb = b;
Expand All @@ -310,7 +311,7 @@ mod test {
for _ in 0..10000 {
let mut b = c;
b = b.square();
assert_eq!(b.legendre(), Fq::ONE);
assert_eq!(b.legendre(), 1);

b = b.sqrt().unwrap();

Expand Down
48 changes: 20 additions & 28 deletions src/bn256/fq2.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::fq::{Fq, NEGATIVE_ONE};
use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
use crate::legendre::Legendre;
use crate::ff_ext::Legendre;
use core::convert::TryInto;
use core::ops::{Add, Mul, Neg, Sub};
use rand::RngCore;
Expand Down Expand Up @@ -125,30 +125,6 @@ impl_binops_additive!(Fq2, Fq2);
impl_binops_multiplicative!(Fq2, Fq2);
impl_sum_prod!(Fq2);

impl Legendre for Fq2 {
type BasePrimeField = Fq;

#[inline]
fn legendre_exp() -> &'static [u64] {
lazy_static::lazy_static! {
// (p-1) / 2
static ref LEGENDRE_EXP: Vec<u64> =
(num_bigint::BigUint::from_bytes_le((-<Fq as ff::Field>::ONE).to_repr().as_ref())/2usize).to_u64_digits();
}
&LEGENDRE_EXP
}

/// Norm of Fq2 as extension field in i over Fq
#[inline]
fn norm(&self) -> Self::BasePrimeField {
let mut t0 = self.c0;
let mut t1 = self.c1;
t0 = t0.square();
t1 = t1.square();
t1 + t0
}
}

impl Fq2 {
#[inline]
pub const fn zero() -> Fq2 {
Expand Down Expand Up @@ -317,6 +293,22 @@ impl Fq2 {
tmp
})
}

/// Norm of Fq2 as extension field in i over Fq
#[inline]
fn norm(&self) -> Fq {
let mut t0 = self.c0;
let mut t1 = self.c1;
t0 = t0.square();
t1 = t1.square();
t1 + t0
}
}

impl Legendre for Fq2 {
fn legendre(&self) -> i64 {
self.norm().legendre()
}
}

impl Field for Fq2 {
Expand Down Expand Up @@ -679,7 +671,7 @@ pub fn test_sqrt() {

for _ in 0..10000 {
let a = Fq2::random(&mut rng);
if a.legendre() == -Fq::ONE {
if a.legendre() == -1 {
assert!(bool::from(a.sqrt().is_none()));
}
}
Expand All @@ -688,7 +680,7 @@ pub fn test_sqrt() {
let a = Fq2::random(&mut rng);
let mut b = a;
b.square_assign();
assert_eq!(b.legendre(), Fq::ONE);
assert_eq!(b.legendre(), 1);

let b = b.sqrt().unwrap();
let mut negb = b;
Expand All @@ -701,7 +693,7 @@ pub fn test_sqrt() {
for _ in 0..10000 {
let mut b = c;
b.square_assign();
assert_eq!(b.legendre(), Fq::ONE);
assert_eq!(b.legendre(), 1);

b = b.sqrt().unwrap();

Expand Down
3 changes: 2 additions & 1 deletion src/bn256/fr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub use table::FR_TABLE;
use crate::impl_from_u64;

use crate::arithmetic::{adc, mac, sbb};
use crate::extend_field_legendre;
use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
use crate::{
field_bits, field_common, impl_add_binop_specify_output, impl_binops_additive,
Expand Down Expand Up @@ -165,7 +166,7 @@ field_common!(
R3
);
impl_sum_prod!(Fr);
prime_field_legendre!(Fr);
extend_field_legendre!(Fr);

#[cfg(not(feature = "bn256-table"))]
impl_from_u64!(Fr, R2);
Expand Down
35 changes: 9 additions & 26 deletions src/derive/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ macro_rules! field_common {
) => {
/// Bernstein-Yang modular multiplicative inverter created for the modulus equal to
/// the characteristic of the field to invert positive integers in the Montgomery form.
const BYINVERTOR: $crate::ff_inverse::BYInverter<6> =
$crate::ff_inverse::BYInverter::<6>::new(&$modulus.0, &$r2.0);
const BYINVERTOR: $crate::ff_ext::inverse::BYInverter<6> =
$crate::ff_ext::inverse::BYInverter::<6>::new(&$modulus.0, &$r2.0);

impl $field {
/// Returns zero, the additive identity.
Expand All @@ -44,6 +44,7 @@ macro_rules! field_common {

/// Returns the multiplicative inverse of the
/// element. If it is zero, the method fails.
#[inline(always)]
pub fn invert(&self) -> CtOption<Self> {
if let Some(inverse) = BYINVERTOR.invert(&self.0) {
CtOption::new(Self(inverse), Choice::from(1))
Expand All @@ -52,10 +53,14 @@ macro_rules! field_common {
}
}

// Returns the Legendre symbol, where the numerator and denominator
// Returns the Jacobi symbol, where the numerator and denominator
// are the element and the characteristic of the field, respectively.
// The Jacobi symbol is applicable to odd moduli
// while the Legendre symbol is applicable to prime moduli.
// They are equivalent for prime moduli.
#[inline(always)]
pub fn jacobi(&self) -> i64 {
$crate::ff_jacobi::jacobi::<5>(&self.0, &$modulus.0)
$crate::ff_ext::jacobi::jacobi::<5>(&self.0, &$modulus.0)
}

fn from_u512(limbs: [u64; 8]) -> $field {
Expand Down Expand Up @@ -359,28 +364,6 @@ macro_rules! field_common {
Ok(())
}
}

#[test]
fn test_jacobi() {
use rand::SeedableRng;
use $crate::ff::Field;
use $crate::legendre::Legendre;
let mut rng = rand_xorshift::XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..100000 {
let e = $field::random(&mut rng);
assert_eq!(
e.legendre(),
match e.jacobi() {
1 => $field::ONE,
-1 => -$field::ONE,
_ => $field::ZERO,
}
);
}
}
};
}

Expand Down
File renamed without changes.
File renamed without changes.
32 changes: 32 additions & 0 deletions src/ff_ext/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
pub mod inverse;
pub mod jacobi;
use subtle::{Choice, ConstantTimeEq};

pub trait Legendre {
fn legendre(&self) -> i64;

#[inline(always)]
fn ct_quadratic_non_residue(&self) -> Choice {
self.legendre().ct_eq(&-1)
}

#[inline(always)]
fn ct_quadratic_residue(&self) -> Choice {
// The legendre symbol returns 0 for 0
// and 1 for quadratic residues,
// we consider 0 a square hence quadratic residue.
self.legendre().ct_ne(&-1)
}
}

#[macro_export]
macro_rules! extend_field_legendre {
($field:ident ) => {
impl $crate::ff_ext::Legendre for $field {
#[inline(always)]
fn legendre(&self) -> i64 {
self.jacobi()
}
}
};
}
2 changes: 1 addition & 1 deletion src/hash_to_curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use pasta_curves::arithmetic::CurveExt;
use static_assertions::const_assert;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

use crate::legendre::Legendre;
use crate::ff_ext::Legendre;

/// Hashes over a message and writes the output to all of `buf`.
/// Modified from https://github.com/zcash/pasta_curves/blob/7e3fc6a4919f6462a32b79dd226cb2587b7961eb/src/hashtocurve.rs#L11.
Expand Down
50 changes: 0 additions & 50 deletions src/legendre.rs

This file was deleted.

5 changes: 1 addition & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
mod arithmetic;
mod ff_inverse;
mod ff_jacobi;
pub mod ff_ext;
pub mod fft;
pub mod hash_to_curve;
pub mod msm;
pub mod multicore;
#[macro_use]
pub mod legendre;
pub mod serde;

pub mod bn256;
Expand Down
9 changes: 0 additions & 9 deletions src/pasta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ const ENDO_PARAMS_EP: EndoParameters = EndoParameters {
endo!(Eq, Fp, ENDO_PARAMS_EQ);
endo!(Ep, Fq, ENDO_PARAMS_EP);

prime_field_legendre!(Fp);
prime_field_legendre!(Fq);

#[test]
fn test_endo() {
use ff::Field;
Expand Down Expand Up @@ -74,9 +71,3 @@ fn test_endo() {
}
}
}

#[test]
fn test_quadratic_residue() {
crate::tests::field::random_quadratic_residue_test::<Fp>();
crate::tests::field::random_quadratic_residue_test::<Fq>();
}
3 changes: 2 additions & 1 deletion src/secp256k1/fp.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::arithmetic::{adc, mac, macx, sbb};
use crate::extend_field_legendre;
use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
use crate::{
field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output,
Expand Down Expand Up @@ -287,7 +288,7 @@ impl WithSmallOrderMulGroup<3> for Fp {
const ZETA: Self = ZETA;
}

prime_field_legendre!(Fp);
extend_field_legendre!(Fp);

#[cfg(test)]
mod test {
Expand Down
3 changes: 2 additions & 1 deletion src/secp256k1/fq.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::arithmetic::{adc, mac, macx, sbb};
use crate::extend_field_legendre;
use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
use crate::{
field_arithmetic, field_bits, field_common, field_specific, impl_add_binop_specify_output,
Expand Down Expand Up @@ -294,7 +295,7 @@ impl WithSmallOrderMulGroup<3> for Fq {
const ZETA: Self = ZETA;
}

prime_field_legendre!(Fq);
extend_field_legendre!(Fq);

#[cfg(test)]
mod test {
Expand Down
Loading

0 comments on commit 2e7f8eb

Please sign in to comment.