Merge branch 'develop'

This commit is contained in:
Jack Grigg
2020-03-14 10:36:58 +13:00
124 changed files with 15961 additions and 2084 deletions

View File

@@ -1,11 +1,12 @@
use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
use ff::{Field, SqrtField};
use rand_core::RngCore;
use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, CtOption};
/// An element of Fq2, represented by c0 + c1 * u.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Fq2 {
pub c0: Fq,
pub c1: Fq,
@@ -46,16 +47,139 @@ impl Fq2 {
/// 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();
let t0 = self.c0.square();
let mut t1 = self.c1.square();
t1.add_assign(&t0);
t1
}
}
impl ConditionallySelectable for Fq2 {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fq2 {
c0: Fq::conditional_select(&a.c0, &b.c0, choice),
c1: Fq::conditional_select(&a.c1, &b.c1, choice),
}
}
}
impl Neg for Fq2 {
type Output = Self;
fn neg(self) -> Self {
Fq2 {
c0: self.c0.neg(),
c1: self.c1.neg(),
}
}
}
impl<'r> Add<&'r Fq2> for Fq2 {
type Output = Self;
fn add(self, other: &Self) -> Self {
Fq2 {
c0: self.c0 + other.c0,
c1: self.c1 + other.c1,
}
}
}
impl Add for Fq2 {
type Output = Self;
fn add(self, other: Self) -> Self {
self.add(&other)
}
}
impl<'r> AddAssign<&'r Fq2> for Fq2 {
fn add_assign(&mut self, other: &'r Self) {
self.c0.add_assign(&other.c0);
self.c1.add_assign(&other.c1);
}
}
impl AddAssign for Fq2 {
fn add_assign(&mut self, other: Self) {
self.add_assign(&other);
}
}
impl<'r> Sub<&'r Fq2> for Fq2 {
type Output = Self;
fn sub(self, other: &Self) -> Self {
Fq2 {
c0: self.c0 - other.c0,
c1: self.c1 - other.c1,
}
}
}
impl Sub for Fq2 {
type Output = Self;
fn sub(self, other: Self) -> Self {
self.sub(&other)
}
}
impl<'r> SubAssign<&'r Fq2> for Fq2 {
fn sub_assign(&mut self, other: &'r Self) {
self.c0.sub_assign(&other.c0);
self.c1.sub_assign(&other.c1);
}
}
impl SubAssign for Fq2 {
fn sub_assign(&mut self, other: Self) {
self.sub_assign(&other);
}
}
impl<'r> Mul<&'r Fq2> for Fq2 {
type Output = Self;
fn mul(self, other: &Self) -> Self {
let mut ret = self;
ret.mul_assign(other);
ret
}
}
impl Mul for Fq2 {
type Output = Self;
fn mul(self, other: Self) -> Self {
self.mul(&other)
}
}
impl<'r> MulAssign<&'r Fq2> for Fq2 {
fn mul_assign(&mut self, other: &Self) {
let mut aa = self.c0;
aa.mul_assign(&other.c0);
let mut bb = self.c1;
bb.mul_assign(&other.c1);
let mut o = other.c0;
o.add_assign(&other.c1);
self.c1.add_assign(&self.c0);
self.c1.mul_assign(&o);
self.c1.sub_assign(&aa);
self.c1.sub_assign(&bb);
self.c0 = aa;
self.c0.sub_assign(&bb);
}
}
impl MulAssign for Fq2 {
fn mul_assign(&mut self, other: Self) {
self.mul_assign(&other);
}
}
impl Field for Fq2 {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
Fq2 {
@@ -82,73 +206,35 @@ impl Field for Fq2 {
self.c0.is_zero() && self.c1.is_zero()
}
fn square(&mut self) {
fn square(&self) -> Self {
let mut ab = self.c0;
ab.mul_assign(&self.c1);
let mut c0c1 = self.c0;
c0c1.add_assign(&self.c1);
let mut c0 = self.c1;
c0.negate();
let mut c0 = self.c1.neg();
c0.add_assign(&self.c0);
c0.mul_assign(&c0c1);
c0.sub_assign(&ab);
self.c1 = ab;
self.c1.add_assign(&ab);
let mut c1 = ab;
c1.add_assign(&ab);
c0.add_assign(&ab);
self.c0 = c0;
Fq2 { c0, c1 }
}
fn double(&mut self) {
self.c0.double();
self.c1.double();
fn double(&self) -> Self {
Fq2 {
c0: self.c0.double(),
c1: self.c1.double(),
}
}
fn negate(&mut self) {
self.c0.negate();
self.c1.negate();
}
fn add_assign(&mut self, other: &Self) {
self.c0.add_assign(&other.c0);
self.c1.add_assign(&other.c1);
}
fn sub_assign(&mut self, other: &Self) {
self.c0.sub_assign(&other.c0);
self.c1.sub_assign(&other.c1);
}
fn mul_assign(&mut self, other: &Self) {
let mut aa = self.c0;
aa.mul_assign(&other.c0);
let mut bb = self.c1;
bb.mul_assign(&other.c1);
let mut o = other.c0;
o.add_assign(&other.c1);
self.c1.add_assign(&self.c0);
self.c1.mul_assign(&o);
self.c1.sub_assign(&aa);
self.c1.sub_assign(&bb);
self.c0 = aa;
self.c0.sub_assign(&bb);
}
fn inverse(&self) -> Option<Self> {
let mut t1 = self.c1;
t1.square();
let mut t0 = self.c0;
t0.square();
fn invert(&self) -> CtOption<Self> {
let t1 = self.c1.square();
let mut t0 = self.c0.square();
t0.add_assign(&t1);
t0.inverse().map(|t| {
let mut tmp = Fq2 {
c0: self.c0,
c1: self.c1,
};
tmp.c0.mul_assign(&t);
tmp.c1.mul_assign(&t);
tmp.c1.negate();
tmp
t0.invert().map(|t| Fq2 {
c0: self.c0.mul(&t),
c1: self.c1.mul(&t).neg(),
})
}
@@ -158,18 +244,16 @@ impl Field for Fq2 {
}
impl SqrtField for Fq2 {
fn legendre(&self) -> ::ff::LegendreSymbol {
self.norm().legendre()
}
fn sqrt(&self) -> Option<Self> {
/// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET!
/// THIS WILL BE REPLACED BY THE bls12_381 CRATE, WHICH IS CONSTANT TIME!
fn sqrt(&self) -> CtOption<Self> {
// Algorithm 9, https://eprint.iacr.org/2012/685.pdf
if self.is_zero() {
Some(Self::zero())
CtOption::new(Self::zero(), Choice::from(1))
} else {
// a1 = self^((q - 3) / 4)
let mut a1 = self.pow([
let mut a1 = self.pow_vartime([
0xee7fbfffffffeaaa,
0x7aaffffac54ffff,
0xd9cc34a83dac3d89,
@@ -177,8 +261,7 @@ impl SqrtField for Fq2 {
0x92c6e9ed90d2eb35,
0x680447a8e5ff9a6,
]);
let mut alpha = a1;
alpha.square();
let mut alpha = a1.square();
alpha.mul_assign(self);
let mut a0 = alpha;
a0.frobenius_map(1);
@@ -190,7 +273,7 @@ impl SqrtField for Fq2 {
};
if a0 == neg1 {
None
CtOption::new(Self::zero(), Choice::from(0))
} else {
a1.mul_assign(self);
@@ -202,7 +285,7 @@ impl SqrtField for Fq2 {
} else {
alpha.add_assign(&Fq2::one());
// alpha = alpha^((q - 1) / 2)
alpha = alpha.pow([
alpha = alpha.pow_vartime([
0xdcff7fffffffd555,
0xf55ffff58a9ffff,
0xb39869507b587b12,
@@ -213,7 +296,7 @@ impl SqrtField for Fq2 {
a1.mul_assign(&alpha);
}
Some(a1)
CtOption::new(a1, Choice::from(1))
}
}
}
@@ -226,7 +309,7 @@ fn test_fq2_ordering() {
c1: Fq::zero(),
};
let mut b = a.clone();
let mut b = a;
assert!(a.cmp(&b) == Ordering::Equal);
b.c0.add_assign(&Fq::one());
@@ -273,34 +356,30 @@ fn test_fq2_squaring() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
let a = Fq2 {
c0: Fq::one(),
c1: Fq::one(),
}; // u + 1
a.square();
assert_eq!(
a,
a.square(),
Fq2 {
c0: Fq::zero(),
c1: Fq::from_repr(FqRepr::from(2)).unwrap(),
}
); // 2u
let mut a = Fq2 {
let a = Fq2 {
c0: Fq::zero(),
c1: Fq::one(),
}; // u
a.square();
assert_eq!(a, {
let mut neg1 = Fq::one();
neg1.negate();
assert_eq!(a.square(), {
Fq2 {
c0: neg1,
c0: Fq::one().neg(),
c1: Fq::zero(),
}
}); // -1
let mut a = Fq2 {
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x9c2c6309bbf8b598,
0x4eef5c946536f602,
@@ -320,9 +399,8 @@ fn test_fq2_squaring() {
]))
.unwrap(),
};
a.square();
assert_eq!(
a,
a.square(),
Fq2 {
c0: Fq::from_repr(FqRepr([
0xf262c28c538bcf68,
@@ -417,11 +495,11 @@ fn test_fq2_mul() {
}
#[test]
fn test_fq2_inverse() {
fn test_fq2_invert() {
use super::fq::FqRepr;
use ff::PrimeField;
assert!(Fq2::zero().inverse().is_none());
assert!(bool::from(Fq2::zero().invert().is_none()));
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -443,7 +521,7 @@ fn test_fq2_inverse() {
]))
.unwrap(),
};
let a = a.inverse().unwrap();
let a = a.invert().unwrap();
assert_eq!(
a,
Fq2 {
@@ -614,7 +692,7 @@ fn test_fq2_negation() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7,
0x11e59ea221a3b6d2,
@@ -633,8 +711,8 @@ fn test_fq2_negation() {
0x12d1137b8a6a837,
]))
.unwrap(),
};
a.negate();
}
.neg();
assert_eq!(
a,
Fq2 {
@@ -665,7 +743,7 @@ fn test_fq2_doubling() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7,
0x11e59ea221a3b6d2,
@@ -685,9 +763,8 @@ fn test_fq2_doubling() {
]))
.unwrap(),
};
a.double();
assert_eq!(
a,
a.double(),
Fq2 {
c0: Fq::from_repr(FqRepr([
0x5a00f006d247ff8e,
@@ -914,19 +991,6 @@ fn test_fq2_sqrt() {
);
}
#[test]
fn test_fq2_legendre() {
use ff::LegendreSymbol::*;
assert_eq!(Zero, Fq2::zero().legendre());
// i^2 = -1
let mut m1 = Fq2::one();
m1.negate();
assert_eq!(QuadraticResidue, m1.legendre());
m1.mul_by_nonresidue();
assert_eq!(QuadraticNonResidue, m1.legendre());
}
#[cfg(test)]
use rand_core::SeedableRng;
#[cfg(test)]