mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-11-14 10:07:04 +00:00
Merge branch 'develop'
This commit is contained in:
@@ -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)]
|
||||
|
||||
Reference in New Issue
Block a user