Add Legendre symbol for Fq and Fq2.
This commit is contained in:
parent
c4c6e25bc0
commit
1b6cf85251
|
@ -1,4 +1,4 @@
|
||||||
use ::{Field, PrimeField, SqrtField, PrimeFieldRepr, PrimeFieldDecodingError};
|
use ::{Field, LegendreField, PrimeField, SqrtField, PrimeFieldRepr, PrimeFieldDecodingError};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use super::fq2::Fq2;
|
use super::fq2::Fq2;
|
||||||
|
|
||||||
|
@ -832,6 +832,23 @@ impl SqrtField for Fq {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LegendreField for Fq {
|
||||||
|
fn legendre(&self) -> i32 {
|
||||||
|
// (q - 1) / 2 =
|
||||||
|
// 2001204777610833696708894912867952078278441409969503942666029068062015825245418932221343814564507832018947136279893
|
||||||
|
let x = self.pow([0xcff7fffffffd555, 0xf55ffff58a9ffffd,
|
||||||
|
0x39869507b587b120, 0x23ba5c279c2895fb,
|
||||||
|
0x58dd3db21a5d66bb, 0xd0088f51cbff34d2]);
|
||||||
|
if x == Self::one() {
|
||||||
|
1
|
||||||
|
} else if x == Self::zero() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_b_coeff() {
|
fn test_b_coeff() {
|
||||||
assert_eq!(Fq::from_repr(FqRepr::from(4)).unwrap(), B_COEFF);
|
assert_eq!(Fq::from_repr(FqRepr::from(4)).unwrap(), B_COEFF);
|
||||||
|
@ -1779,3 +1796,29 @@ fn test_fq_ordering() {
|
||||||
fn fq_repr_tests() {
|
fn fq_repr_tests() {
|
||||||
::tests::repr::random_repr_tests::<FqRepr>();
|
::tests::repr::random_repr_tests::<FqRepr>();
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_fq_legendre() {
|
||||||
|
assert_eq!(1, Fq::one().legendre());
|
||||||
|
assert_eq!(0, Fq::zero().legendre());
|
||||||
|
|
||||||
|
let e = Fq(FqRepr([0x914577fdcc41112, 0x1a6c20f3392c28e2, 0xd53f75da0c40fd21,
|
||||||
|
0xb747c10d13caf0d0, 0x0de1adc19c24d8d2, 0x2103f924191033d2]));
|
||||||
|
assert_eq!(-1, e.legendre());
|
||||||
|
|
||||||
|
|
||||||
|
// f
|
||||||
|
let e = Fq(FqRepr([0xe51d5292ae8126f, 0x382d60874f48db82, 0xb0dde25abc614254,
|
||||||
|
0x34f4456bd18813df, 0x2c668010247ee04c, 0x44cb8bbdd7c4f1b0]));
|
||||||
|
assert_eq!(-1, e.legendre());
|
||||||
|
|
||||||
|
// f ** 9
|
||||||
|
let e = Fq(FqRepr([0x69fc8eb1b590c712, 0xd73f4fb6fd34042e, 0xb5677ef2ed0eede7,
|
||||||
|
0x367d831c592848c8, 0xb60615cc44e533f5, 0x127da624461b200e]));
|
||||||
|
|
||||||
|
assert_eq!(-1, e.legendre());
|
||||||
|
|
||||||
|
let e = Fq(FqRepr([0x83c7ad9e29b7facc, 0x97b3c8fbdb50cc39, 0x9e2ccd0eb5db5e72,
|
||||||
|
0xc74a00d90e1b247d, 0x90e38ef46c8d7eb7, 0x16882d6aa70bb469]));
|
||||||
|
assert_eq!(1, e.legendre());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use rand::{Rng, Rand};
|
use rand::{Rng, Rand};
|
||||||
use ::{Field, SqrtField};
|
use ::{Field, LegendreField, SqrtField};
|
||||||
use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
|
use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
@ -44,6 +44,17 @@ impl Fq2 {
|
||||||
self.c0.sub_assign(&self.c1);
|
self.c0.sub_assign(&self.c1);
|
||||||
self.c1.add_assign(&t0);
|
self.c1.add_assign(&t0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Norm of Fq2 as extension field in i over Fq
|
||||||
|
pub fn norm(&self) -> Fq {
|
||||||
|
let mut t0 = self.c0;
|
||||||
|
let mut t1 = self.c1;
|
||||||
|
t0.square();
|
||||||
|
t1.square();
|
||||||
|
t1.add_assign(&t0);
|
||||||
|
|
||||||
|
t1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rand for Fq2 {
|
impl Rand for Fq2 {
|
||||||
|
@ -185,6 +196,12 @@ impl SqrtField for Fq2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LegendreField for Fq2 {
|
||||||
|
fn legendre(&self) -> i32 {
|
||||||
|
Fq2::norm(&self).legendre()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_ordering() {
|
fn test_fq2_ordering() {
|
||||||
let mut a = Fq2 {
|
let mut a = Fq2 {
|
||||||
|
@ -412,6 +429,17 @@ fn test_fq2_sqrt() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fq2_legendre() {
|
||||||
|
// i^2 = -1
|
||||||
|
let mut m1 = Fq2::one();
|
||||||
|
m1.negate();
|
||||||
|
assert_eq!(1, m1.legendre());
|
||||||
|
|
||||||
|
m1.mul_by_nonresidue();
|
||||||
|
assert_eq!(-1, m1.legendre());
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use rand::{SeedableRng, XorShiftRng};
|
use rand::{SeedableRng, XorShiftRng};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use ::{Field, PrimeField, SqrtField, PrimeFieldRepr, PrimeFieldDecodingError};
|
use ::{Field, LegendreField, PrimeField, SqrtField, PrimeFieldRepr, PrimeFieldDecodingError};
|
||||||
|
|
||||||
// r = 52435875175126190479447740508185965837690552500527637822603658699938581184513
|
// r = 52435875175126190479447740508185965837690552500527637822603658699938581184513
|
||||||
const MODULUS: FrRepr = FrRepr([0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48]);
|
const MODULUS: FrRepr = FrRepr([0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48]);
|
||||||
|
@ -559,8 +559,7 @@ impl SqrtField for Fr {
|
||||||
return Some(*self);
|
return Some(*self);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if self^((r - 1) // 2) != 1
|
if self.legendre() != 1 {
|
||||||
if self.pow([0x7fffffff80000000, 0xa9ded2017fff2dff, 0x199cec0404d0ec02, 0x39f6d3a994cebea4]) != Self::one() {
|
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let mut c = Fr(ROOT_OF_UNITY);
|
let mut c = Fr(ROOT_OF_UNITY);
|
||||||
|
@ -598,6 +597,19 @@ impl SqrtField for Fr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LegendreField for Fr {
|
||||||
|
fn legendre(&self) -> i32 {
|
||||||
|
// (q - 1) / 2 = 26217937587563095239723870254092982918845276250263818911301829349969290592256
|
||||||
|
let x = self.pow([0x7fffffff80000000, 0xa9ded2017fff2dff, 0x199cec0404d0ec02, 0x39f6d3a994cebea4]);
|
||||||
|
if x == Self::one() {
|
||||||
|
1
|
||||||
|
} else if x == Self::zero() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use rand::{SeedableRng, XorShiftRng, Rand};
|
use rand::{SeedableRng, XorShiftRng, Rand};
|
||||||
|
|
||||||
|
@ -778,6 +790,17 @@ fn test_fr_repr_sub_noborrow() {
|
||||||
assert!(!x.sub_noborrow(&FrRepr([0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48])))
|
assert!(!x.sub_noborrow(&FrRepr([0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48])))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fr_legendre() {
|
||||||
|
assert_eq!(1, Fr::one().legendre());
|
||||||
|
assert_eq!(0, Fr::zero().legendre());
|
||||||
|
|
||||||
|
let e = Fr(FrRepr([0x0dbc5349cd5664da, 0x8ac5b6296e3ae29d, 0x127cb819feceaa3b, 0x3a6b21fb03867191]));
|
||||||
|
assert_eq!(1, e.legendre());
|
||||||
|
let e = Fr(FrRepr([0x96341aefd047c045, 0x9b5f4254500a4d65, 0x1ee08223b68ac240, 0x31d9cd545c0ec7c6]));
|
||||||
|
assert_eq!(-1, e.legendre());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fr_repr_add_nocarry() {
|
fn test_fr_repr_add_nocarry() {
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|
|
@ -332,6 +332,14 @@ pub trait SqrtField: Field
|
||||||
fn sqrt(&self) -> Option<Self>;
|
fn sqrt(&self) -> Option<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This trait represents an element of a field that has a Legendre symbol described for it.
|
||||||
|
pub trait LegendreField: Field
|
||||||
|
{
|
||||||
|
/// Returns the legendre symbol of the field element.
|
||||||
|
fn legendre(&self) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// This trait represents a wrapper around a biginteger which can encode any element of a particular
|
/// This trait represents a wrapper around a biginteger which can encode any element of a particular
|
||||||
/// prime field. It is a smart wrapper around a sequence of `u64` limbs, least-significant digit
|
/// prime field. It is a smart wrapper around a sequence of `u64` limbs, least-significant digit
|
||||||
/// first.
|
/// first.
|
||||||
|
|
Loading…
Reference in New Issue