mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-02-01 08:12:14 +00:00
Constant-time field inversion
WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET! The jubjub and bls12_381 crates will replace our constant-time usages, but we NEED to fix ff_derive because other users will expect it to implement the Field trait correctly.
This commit is contained in:
parent
e85a9f309f
commit
40749da9a7
@ -73,11 +73,11 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
|||||||
coeffs,
|
coeffs,
|
||||||
exp,
|
exp,
|
||||||
omega,
|
omega,
|
||||||
omegainv: omega.inverse().unwrap(),
|
omegainv: omega.invert().unwrap(),
|
||||||
geninv: E::Fr::multiplicative_generator().inverse().unwrap(),
|
geninv: E::Fr::multiplicative_generator().invert().unwrap(),
|
||||||
minv: E::Fr::from_str(&format!("{}", m))
|
minv: E::Fr::from_str(&format!("{}", m))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.inverse()
|
.invert()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -141,10 +141,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
|
|||||||
/// evaluation domain, so we must perform division over
|
/// evaluation domain, so we must perform division over
|
||||||
/// a coset.
|
/// a coset.
|
||||||
pub fn divide_by_z_on_coset(&mut self, worker: &Worker) {
|
pub fn divide_by_z_on_coset(&mut self, worker: &Worker) {
|
||||||
let i = self
|
let i = self.z(&E::Fr::multiplicative_generator()).invert().unwrap();
|
||||||
.z(&E::Fr::multiplicative_generator())
|
|
||||||
.inverse()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
worker.scope(self.coeffs.len(), |scope, chunk| {
|
worker.scope(self.coeffs.len(), |scope, chunk| {
|
||||||
for v in self.coeffs.chunks_mut(chunk) {
|
for v in self.coeffs.chunks_mut(chunk) {
|
||||||
|
@ -288,7 +288,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
|
|||||||
if tmp.is_zero() {
|
if tmp.is_zero() {
|
||||||
Err(SynthesisError::DivisionByZero)
|
Err(SynthesisError::DivisionByZero)
|
||||||
} else {
|
} else {
|
||||||
Ok(tmp.inverse().unwrap())
|
Ok(tmp.invert().unwrap())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
@ -215,8 +215,22 @@ where
|
|||||||
assembly.num_inputs + assembly.num_aux
|
assembly.num_inputs + assembly.num_aux
|
||||||
});
|
});
|
||||||
|
|
||||||
let gamma_inverse = gamma.inverse().ok_or(SynthesisError::UnexpectedIdentity)?;
|
let gamma_inverse = {
|
||||||
let delta_inverse = delta.inverse().ok_or(SynthesisError::UnexpectedIdentity)?;
|
let inverse = gamma.invert();
|
||||||
|
if bool::from(inverse.is_some()) {
|
||||||
|
Ok(inverse.unwrap())
|
||||||
|
} else {
|
||||||
|
Err(SynthesisError::UnexpectedIdentity)
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
let delta_inverse = {
|
||||||
|
let inverse = delta.invert();
|
||||||
|
if bool::from(inverse.is_some()) {
|
||||||
|
Ok(inverse.unwrap())
|
||||||
|
} else {
|
||||||
|
Err(SynthesisError::UnexpectedIdentity)
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
let worker = Worker::new();
|
let worker = Worker::new();
|
||||||
|
|
||||||
|
@ -10,13 +10,19 @@ use std::cmp::Ordering;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
use subtle::{Choice, ConditionallySelectable};
|
use subtle::{Choice, ConditionallySelectable, CtOption};
|
||||||
|
|
||||||
const MODULUS_R: Wrapping<u32> = Wrapping(64513);
|
const MODULUS_R: Wrapping<u32> = Wrapping(64513);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Fr(Wrapping<u32>);
|
pub struct Fr(Wrapping<u32>);
|
||||||
|
|
||||||
|
impl Default for Fr {
|
||||||
|
fn default() -> Self {
|
||||||
|
<Fr as Field>::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Fr {
|
impl fmt::Display for Fr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
write!(f, "{}", (self.0).0)
|
write!(f, "{}", (self.0).0)
|
||||||
@ -159,11 +165,11 @@ impl Field for Fr {
|
|||||||
Fr((self.0 << 1) % MODULUS_R)
|
Fr((self.0 << 1) % MODULUS_R)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inverse(&self) -> Option<Self> {
|
fn invert(&self) -> CtOption<Self> {
|
||||||
if <Fr as Field>::is_zero(self) {
|
if <Fr as Field>::is_zero(self) {
|
||||||
None
|
CtOption::new(<Fr as Field>::zero(), Choice::from(0))
|
||||||
} else {
|
} else {
|
||||||
Some(self.pow(&[(MODULUS_R.0 as u64) - 2]))
|
CtOption::new(self.pow(&[(MODULUS_R.0 as u64) - 2]), Choice::from(1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,8 +388,8 @@ impl Engine for DummyEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Perform final exponentiation of the result of a miller loop.
|
/// Perform final exponentiation of the result of a miller loop.
|
||||||
fn final_exponentiation(this: &Self::Fqk) -> Option<Self::Fqk> {
|
fn final_exponentiation(this: &Self::Fqk) -> CtOption<Self::Fqk> {
|
||||||
Some(*this)
|
CtOption::new(*this, Choice::from(1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,8 +156,8 @@ fn test_xordemo() {
|
|||||||
|
|
||||||
// We expect our H query to be 7 elements of the form...
|
// We expect our H query to be 7 elements of the form...
|
||||||
// {tau^i t(tau) / delta}
|
// {tau^i t(tau) / delta}
|
||||||
let delta_inverse = delta.inverse().unwrap();
|
let delta_inverse = delta.invert().unwrap();
|
||||||
let gamma_inverse = gamma.inverse().unwrap();
|
let gamma_inverse = gamma.invert().unwrap();
|
||||||
{
|
{
|
||||||
let mut coeff = delta_inverse;
|
let mut coeff = delta_inverse;
|
||||||
coeff.mul_assign(&t_at_tau);
|
coeff.mul_assign(&t_at_tau);
|
||||||
|
@ -791,6 +791,12 @@ fn prime_field_impl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ::std::default::Default for #name {
|
||||||
|
fn default() -> #name {
|
||||||
|
#name::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ::std::cmp::PartialEq for #name {
|
impl ::std::cmp::PartialEq for #name {
|
||||||
fn eq(&self, other: &#name) -> bool {
|
fn eq(&self, other: &#name) -> bool {
|
||||||
self.0 == other.0
|
self.0 == other.0
|
||||||
@ -1062,9 +1068,11 @@ fn prime_field_impl(
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inverse(&self) -> Option<Self> {
|
/// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET!
|
||||||
|
/// TODO: Make this constant-time.
|
||||||
|
fn invert(&self) -> ::subtle::CtOption<Self> {
|
||||||
if self.is_zero() {
|
if self.is_zero() {
|
||||||
None
|
::subtle::CtOption::new(#name::zero(), ::subtle::Choice::from(0))
|
||||||
} else {
|
} else {
|
||||||
// Guajardo Kumar Paar Pelzl
|
// Guajardo Kumar Paar Pelzl
|
||||||
// Efficient Software-Implementation of Finite Fields with Applications to Cryptography
|
// Efficient Software-Implementation of Finite Fields with Applications to Cryptography
|
||||||
@ -1110,9 +1118,9 @@ fn prime_field_impl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if u == one {
|
if u == one {
|
||||||
Some(b)
|
::subtle::CtOption::new(b, ::subtle::Choice::from(1))
|
||||||
} else {
|
} else {
|
||||||
Some(c)
|
::subtle::CtOption::new(c, ::subtle::Choice::from(1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ use std::error::Error;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
use subtle::ConditionallySelectable;
|
use subtle::{ConditionallySelectable, CtOption};
|
||||||
|
|
||||||
/// This trait represents an element of a field.
|
/// This trait represents an element of a field.
|
||||||
pub trait Field:
|
pub trait Field:
|
||||||
@ -20,6 +20,7 @@ pub trait Field:
|
|||||||
+ Eq
|
+ Eq
|
||||||
+ Copy
|
+ Copy
|
||||||
+ Clone
|
+ Clone
|
||||||
|
+ Default
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ fmt::Debug
|
+ fmt::Debug
|
||||||
@ -60,8 +61,9 @@ pub trait Field:
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
fn double(&self) -> Self;
|
fn double(&self) -> Self;
|
||||||
|
|
||||||
/// Computes the multiplicative inverse of this element, if nonzero.
|
/// Computes the multiplicative inverse of this element,
|
||||||
fn inverse(&self) -> Option<Self>;
|
/// failing if the element is zero.
|
||||||
|
fn invert(&self) -> CtOption<Self>;
|
||||||
|
|
||||||
/// Exponentiates this element by a power of the base prime modulus via
|
/// Exponentiates this element by a power of the base prime modulus via
|
||||||
/// the Frobenius automorphism.
|
/// the Frobenius automorphism.
|
||||||
|
@ -217,7 +217,7 @@ fn bench_fq_square(b: &mut ::test::Bencher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_fq_inverse(b: &mut ::test::Bencher) {
|
fn bench_fq_invert(b: &mut ::test::Bencher) {
|
||||||
const SAMPLES: usize = 1000;
|
const SAMPLES: usize = 1000;
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
@ -230,7 +230,7 @@ fn bench_fq_inverse(b: &mut ::test::Bencher) {
|
|||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
count = (count + 1) % SAMPLES;
|
count = (count + 1) % SAMPLES;
|
||||||
v[count].inverse()
|
v[count].invert()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ fn bench_fq12_squaring(b: &mut ::test::Bencher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_fq12_inverse(b: &mut ::test::Bencher) {
|
fn bench_fq12_invert(b: &mut ::test::Bencher) {
|
||||||
const SAMPLES: usize = 1000;
|
const SAMPLES: usize = 1000;
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
@ -103,7 +103,7 @@ fn bench_fq12_inverse(b: &mut ::test::Bencher) {
|
|||||||
|
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let tmp = v[count].inverse();
|
let tmp = v[count].invert();
|
||||||
count = (count + 1) % SAMPLES;
|
count = (count + 1) % SAMPLES;
|
||||||
tmp
|
tmp
|
||||||
});
|
});
|
||||||
|
@ -91,7 +91,7 @@ fn bench_fq2_squaring(b: &mut ::test::Bencher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_fq2_inverse(b: &mut ::test::Bencher) {
|
fn bench_fq2_invert(b: &mut ::test::Bencher) {
|
||||||
const SAMPLES: usize = 1000;
|
const SAMPLES: usize = 1000;
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
@ -103,7 +103,7 @@ fn bench_fq2_inverse(b: &mut ::test::Bencher) {
|
|||||||
|
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let tmp = v[count].inverse();
|
let tmp = v[count].invert();
|
||||||
count = (count + 1) % SAMPLES;
|
count = (count + 1) % SAMPLES;
|
||||||
tmp
|
tmp
|
||||||
});
|
});
|
||||||
|
@ -217,7 +217,7 @@ fn bench_fr_square(b: &mut ::test::Bencher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_fr_inverse(b: &mut ::test::Bencher) {
|
fn bench_fr_invert(b: &mut ::test::Bencher) {
|
||||||
const SAMPLES: usize = 1000;
|
const SAMPLES: usize = 1000;
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
@ -230,7 +230,7 @@ fn bench_fr_inverse(b: &mut ::test::Bencher) {
|
|||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
count = (count + 1) % SAMPLES;
|
count = (count + 1) % SAMPLES;
|
||||||
v[count].inverse()
|
v[count].invert()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ macro_rules! curve_impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invert `tmp`.
|
// Invert `tmp`.
|
||||||
tmp = tmp.inverse().unwrap(); // Guaranteed to be nonzero.
|
tmp = tmp.invert().unwrap(); // Guaranteed to be nonzero.
|
||||||
|
|
||||||
// Second pass: iterate backwards to compute inverses
|
// Second pass: iterate backwards to compute inverses
|
||||||
for (g, s) in v
|
for (g, s) in v
|
||||||
@ -571,7 +571,7 @@ macro_rules! curve_impl {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Z is nonzero, so it must have an inverse in a field.
|
// Z is nonzero, so it must have an inverse in a field.
|
||||||
let zinv = p.z.inverse().unwrap();
|
let zinv = p.z.invert().unwrap();
|
||||||
let mut zinv_powered = zinv.square();
|
let mut zinv_powered = zinv.square();
|
||||||
|
|
||||||
// X/Z^2
|
// X/Z^2
|
||||||
|
@ -1965,8 +1965,8 @@ fn test_fq_squaring() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fq_inverse() {
|
fn test_fq_invert() {
|
||||||
assert!(Fq::zero().inverse().is_none());
|
assert!(bool::from(Fq::zero().invert().is_none()));
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
@ -1978,7 +1978,7 @@ fn test_fq_inverse() {
|
|||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
// Ensure that a * a^-1 = 1
|
// Ensure that a * a^-1 = 1
|
||||||
let mut a = Fq::random(&mut rng);
|
let mut a = Fq::random(&mut rng);
|
||||||
let ainv = a.inverse().unwrap();
|
let ainv = a.invert().unwrap();
|
||||||
a.mul_assign(&ainv);
|
a.mul_assign(&ainv);
|
||||||
assert_eq!(a, one);
|
assert_eq!(a, one);
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,10 @@ use super::fq6::Fq6;
|
|||||||
use ff::Field;
|
use ff::Field;
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
use subtle::{Choice, ConditionallySelectable};
|
use subtle::{Choice, ConditionallySelectable, CtOption};
|
||||||
|
|
||||||
/// An element of Fq12, represented by c0 + c1 * w.
|
/// An element of Fq12, represented by c0 + c1 * w.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||||
pub struct Fq12 {
|
pub struct Fq12 {
|
||||||
pub c0: Fq6,
|
pub c0: Fq6,
|
||||||
pub c1: Fq6,
|
pub c1: Fq6,
|
||||||
@ -226,13 +226,13 @@ impl Field for Fq12 {
|
|||||||
Fq12 { c0, c1 }
|
Fq12 { c0, c1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inverse(&self) -> Option<Self> {
|
fn invert(&self) -> CtOption<Self> {
|
||||||
let mut c0s = self.c0.square();
|
let mut c0s = self.c0.square();
|
||||||
let mut c1s = self.c1.square();
|
let mut c1s = self.c1.square();
|
||||||
c1s.mul_by_nonresidue();
|
c1s.mul_by_nonresidue();
|
||||||
c0s.sub_assign(&c1s);
|
c0s.sub_assign(&c1s);
|
||||||
|
|
||||||
c0s.inverse().map(|t| Fq12 {
|
c0s.invert().map(|t| Fq12 {
|
||||||
c0: t.mul(&self.c0),
|
c0: t.mul(&self.c0),
|
||||||
c1: t.mul(&self.c1).neg(),
|
c1: t.mul(&self.c1).neg(),
|
||||||
})
|
})
|
||||||
|
@ -3,10 +3,10 @@ use ff::{Field, SqrtField};
|
|||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
use subtle::{Choice, ConditionallySelectable};
|
use subtle::{Choice, ConditionallySelectable, CtOption};
|
||||||
|
|
||||||
/// An element of Fq2, represented by c0 + c1 * u.
|
/// 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 struct Fq2 {
|
||||||
pub c0: Fq,
|
pub c0: Fq,
|
||||||
pub c1: Fq,
|
pub c1: Fq,
|
||||||
@ -228,11 +228,11 @@ impl Field for Fq2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inverse(&self) -> Option<Self> {
|
fn invert(&self) -> CtOption<Self> {
|
||||||
let t1 = self.c1.square();
|
let t1 = self.c1.square();
|
||||||
let mut t0 = self.c0.square();
|
let mut t0 = self.c0.square();
|
||||||
t0.add_assign(&t1);
|
t0.add_assign(&t1);
|
||||||
t0.inverse().map(|t| Fq2 {
|
t0.invert().map(|t| Fq2 {
|
||||||
c0: self.c0.mul(&t),
|
c0: self.c0.mul(&t),
|
||||||
c1: self.c1.mul(&t).neg(),
|
c1: self.c1.mul(&t).neg(),
|
||||||
})
|
})
|
||||||
@ -497,11 +497,11 @@ fn test_fq2_mul() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fq2_inverse() {
|
fn test_fq2_invert() {
|
||||||
use super::fq::FqRepr;
|
use super::fq::FqRepr;
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
assert!(Fq2::zero().inverse().is_none());
|
assert!(bool::from(Fq2::zero().invert().is_none()));
|
||||||
|
|
||||||
let a = Fq2 {
|
let a = Fq2 {
|
||||||
c0: Fq::from_repr(FqRepr([
|
c0: Fq::from_repr(FqRepr([
|
||||||
@ -523,7 +523,7 @@ fn test_fq2_inverse() {
|
|||||||
]))
|
]))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
};
|
};
|
||||||
let a = a.inverse().unwrap();
|
let a = a.invert().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
a,
|
a,
|
||||||
Fq2 {
|
Fq2 {
|
||||||
|
@ -3,10 +3,10 @@ use super::fq2::Fq2;
|
|||||||
use ff::Field;
|
use ff::Field;
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
use subtle::{Choice, ConditionallySelectable};
|
use subtle::{Choice, ConditionallySelectable, CtOption};
|
||||||
|
|
||||||
/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
|
/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||||
pub struct Fq6 {
|
pub struct Fq6 {
|
||||||
pub c0: Fq2,
|
pub c0: Fq2,
|
||||||
pub c1: Fq2,
|
pub c1: Fq2,
|
||||||
@ -345,7 +345,7 @@ impl Field for Fq6 {
|
|||||||
Fq6 { c0, c1, c2 }
|
Fq6 { c0, c1, c2 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inverse(&self) -> Option<Self> {
|
fn invert(&self) -> CtOption<Self> {
|
||||||
let mut c0 = self.c2;
|
let mut c0 = self.c2;
|
||||||
c0.mul_by_nonresidue();
|
c0.mul_by_nonresidue();
|
||||||
c0.mul_assign(&self.c1);
|
c0.mul_assign(&self.c1);
|
||||||
@ -378,21 +378,18 @@ impl Field for Fq6 {
|
|||||||
tmp2.mul_assign(&c0);
|
tmp2.mul_assign(&c0);
|
||||||
tmp1.add_assign(&tmp2);
|
tmp1.add_assign(&tmp2);
|
||||||
|
|
||||||
match tmp1.inverse() {
|
tmp1.invert().map(|t| {
|
||||||
Some(t) => {
|
let mut tmp = Fq6 {
|
||||||
let mut tmp = Fq6 {
|
c0: t,
|
||||||
c0: t,
|
c1: t,
|
||||||
c1: t,
|
c2: t,
|
||||||
c2: t,
|
};
|
||||||
};
|
tmp.c0.mul_assign(&c0);
|
||||||
tmp.c0.mul_assign(&c0);
|
tmp.c1.mul_assign(&c1);
|
||||||
tmp.c1.mul_assign(&c1);
|
tmp.c2.mul_assign(&c2);
|
||||||
tmp.c2.mul_assign(&c2);
|
|
||||||
|
|
||||||
Some(tmp)
|
tmp
|
||||||
}
|
})
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,8 +724,8 @@ fn test_fr_squaring() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fr_inverse() {
|
fn test_fr_invert() {
|
||||||
assert!(Fr::zero().inverse().is_none());
|
assert!(bool::from(Fr::zero().invert().is_none()));
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
@ -737,7 +737,7 @@ fn test_fr_inverse() {
|
|||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
// Ensure that a * a^-1 = 1
|
// Ensure that a * a^-1 = 1
|
||||||
let mut a = Fr::random(&mut rng);
|
let mut a = Fr::random(&mut rng);
|
||||||
let ainv = a.inverse().unwrap();
|
let ainv = a.invert().unwrap();
|
||||||
a.mul_assign(&ainv);
|
a.mul_assign(&ainv);
|
||||||
assert_eq!(a, one);
|
assert_eq!(a, one);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ use super::{Engine, PairingCurveAffine};
|
|||||||
use ff::{BitIterator, Field, ScalarEngine};
|
use ff::{BitIterator, Field, ScalarEngine};
|
||||||
use group::CurveAffine;
|
use group::CurveAffine;
|
||||||
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
||||||
|
use subtle::CtOption;
|
||||||
|
|
||||||
// The BLS parameter x for BLS12-381 is -0xd201000000010000
|
// The BLS parameter x for BLS12-381 is -0xd201000000010000
|
||||||
const BLS_X: u64 = 0xd201000000010000;
|
const BLS_X: u64 = 0xd201000000010000;
|
||||||
@ -111,61 +112,58 @@ impl Engine for Bls12 {
|
|||||||
f
|
f
|
||||||
}
|
}
|
||||||
|
|
||||||
fn final_exponentiation(r: &Fq12) -> Option<Fq12> {
|
fn final_exponentiation(r: &Fq12) -> CtOption<Fq12> {
|
||||||
let mut f1 = *r;
|
let mut f1 = *r;
|
||||||
f1.conjugate();
|
f1.conjugate();
|
||||||
|
|
||||||
match r.inverse() {
|
r.invert().map(|mut f2| {
|
||||||
Some(mut f2) => {
|
let mut r = f1;
|
||||||
let mut r = f1;
|
r.mul_assign(&f2);
|
||||||
r.mul_assign(&f2);
|
f2 = r;
|
||||||
f2 = r;
|
r.frobenius_map(2);
|
||||||
r.frobenius_map(2);
|
r.mul_assign(&f2);
|
||||||
r.mul_assign(&f2);
|
|
||||||
|
|
||||||
fn exp_by_x(f: &mut Fq12, x: u64) {
|
fn exp_by_x(f: &mut Fq12, x: u64) {
|
||||||
*f = f.pow(&[x]);
|
*f = f.pow(&[x]);
|
||||||
if BLS_X_IS_NEGATIVE {
|
if BLS_X_IS_NEGATIVE {
|
||||||
f.conjugate();
|
f.conjugate();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut x = BLS_X;
|
|
||||||
let y0 = r.square();
|
|
||||||
let mut y1 = y0;
|
|
||||||
exp_by_x(&mut y1, x);
|
|
||||||
x >>= 1;
|
|
||||||
let mut y2 = y1;
|
|
||||||
exp_by_x(&mut y2, x);
|
|
||||||
x <<= 1;
|
|
||||||
let mut y3 = r;
|
|
||||||
y3.conjugate();
|
|
||||||
y1.mul_assign(&y3);
|
|
||||||
y1.conjugate();
|
|
||||||
y1.mul_assign(&y2);
|
|
||||||
y2 = y1;
|
|
||||||
exp_by_x(&mut y2, x);
|
|
||||||
y3 = y2;
|
|
||||||
exp_by_x(&mut y3, x);
|
|
||||||
y1.conjugate();
|
|
||||||
y3.mul_assign(&y1);
|
|
||||||
y1.conjugate();
|
|
||||||
y1.frobenius_map(3);
|
|
||||||
y2.frobenius_map(2);
|
|
||||||
y1.mul_assign(&y2);
|
|
||||||
y2 = y3;
|
|
||||||
exp_by_x(&mut y2, x);
|
|
||||||
y2.mul_assign(&y0);
|
|
||||||
y2.mul_assign(&r);
|
|
||||||
y1.mul_assign(&y2);
|
|
||||||
y2 = y3;
|
|
||||||
y2.frobenius_map(1);
|
|
||||||
y1.mul_assign(&y2);
|
|
||||||
|
|
||||||
Some(y1)
|
|
||||||
}
|
}
|
||||||
None => None,
|
|
||||||
}
|
let mut x = BLS_X;
|
||||||
|
let y0 = r.square();
|
||||||
|
let mut y1 = y0;
|
||||||
|
exp_by_x(&mut y1, x);
|
||||||
|
x >>= 1;
|
||||||
|
let mut y2 = y1;
|
||||||
|
exp_by_x(&mut y2, x);
|
||||||
|
x <<= 1;
|
||||||
|
let mut y3 = r;
|
||||||
|
y3.conjugate();
|
||||||
|
y1.mul_assign(&y3);
|
||||||
|
y1.conjugate();
|
||||||
|
y1.mul_assign(&y2);
|
||||||
|
y2 = y1;
|
||||||
|
exp_by_x(&mut y2, x);
|
||||||
|
y3 = y2;
|
||||||
|
exp_by_x(&mut y3, x);
|
||||||
|
y1.conjugate();
|
||||||
|
y3.mul_assign(&y1);
|
||||||
|
y1.conjugate();
|
||||||
|
y1.frobenius_map(3);
|
||||||
|
y2.frobenius_map(2);
|
||||||
|
y1.mul_assign(&y2);
|
||||||
|
y2 = y3;
|
||||||
|
exp_by_x(&mut y2, x);
|
||||||
|
y2.mul_assign(&y0);
|
||||||
|
y2.mul_assign(&r);
|
||||||
|
y1.mul_assign(&y2);
|
||||||
|
y2 = y3;
|
||||||
|
y2.frobenius_map(1);
|
||||||
|
y1.mul_assign(&y2);
|
||||||
|
|
||||||
|
y1
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ pub mod bls12_381;
|
|||||||
|
|
||||||
use ff::{Field, PrimeField, ScalarEngine, SqrtField};
|
use ff::{Field, PrimeField, ScalarEngine, SqrtField};
|
||||||
use group::{CurveAffine, CurveProjective};
|
use group::{CurveAffine, CurveProjective};
|
||||||
|
use subtle::CtOption;
|
||||||
|
|
||||||
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
|
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
|
||||||
/// with well-defined relationships. In particular, the G1/G2 curve groups are
|
/// with well-defined relationships. In particular, the G1/G2 curve groups are
|
||||||
@ -75,7 +76,7 @@ pub trait Engine: ScalarEngine {
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
/// Perform final exponentiation of the result of a miller loop.
|
/// Perform final exponentiation of the result of a miller loop.
|
||||||
fn final_exponentiation(_: &Self::Fqk) -> Option<Self::Fqk>;
|
fn final_exponentiation(_: &Self::Fqk) -> CtOption<Self::Fqk>;
|
||||||
|
|
||||||
/// Performs a complete pairing operation `(p, q)`.
|
/// Performs a complete pairing operation `(p, q)`.
|
||||||
fn pairing<G1, G2>(p: G1, q: G2) -> Self::Fqk
|
fn pairing<G1, G2>(p: G1, q: G2) -> Self::Fqk
|
||||||
|
@ -78,7 +78,7 @@ pub fn random_field_tests<F: Field>() {
|
|||||||
assert!(z.is_zero());
|
assert!(z.is_zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(F::zero().inverse().is_none());
|
assert!(bool::from(F::zero().invert().is_none()));
|
||||||
|
|
||||||
// Multiplication by zero
|
// Multiplication by zero
|
||||||
{
|
{
|
||||||
@ -222,11 +222,11 @@ fn random_squaring_tests<F: Field, R: RngCore>(rng: &mut R) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn random_inversion_tests<F: Field, R: RngCore>(rng: &mut R) {
|
fn random_inversion_tests<F: Field, R: RngCore>(rng: &mut R) {
|
||||||
assert!(F::zero().inverse().is_none());
|
assert!(bool::from(F::zero().invert().is_none()));
|
||||||
|
|
||||||
for _ in 0..10000 {
|
for _ in 0..10000 {
|
||||||
let mut a = F::random(rng);
|
let mut a = F::random(rng);
|
||||||
let b = a.inverse().unwrap(); // probablistically nonzero
|
let b = a.invert().unwrap(); // probablistically nonzero
|
||||||
a.mul_assign(&b);
|
a.mul_assign(&b);
|
||||||
|
|
||||||
assert_eq!(a, F::one());
|
assert_eq!(a, F::one());
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
|
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||||
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
||||||
|
use subtle::{Choice, CtOption};
|
||||||
|
|
||||||
use super::{montgomery, JubjubEngine, JubjubParams, PrimeOrder, Unknown};
|
use super::{montgomery, JubjubEngine, JubjubParams, PrimeOrder, Unknown};
|
||||||
|
|
||||||
@ -90,10 +91,14 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
|||||||
y_repr.as_mut()[3] &= 0x7fffffffffffffff;
|
y_repr.as_mut()[3] &= 0x7fffffffffffffff;
|
||||||
|
|
||||||
match E::Fr::from_repr(y_repr) {
|
match E::Fr::from_repr(y_repr) {
|
||||||
Ok(y) => match Self::get_for_y(y, x_sign, params) {
|
Ok(y) => {
|
||||||
Some(p) => Ok(p),
|
let p = Self::get_for_y(y, x_sign, params);
|
||||||
None => Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")),
|
if bool::from(p.is_some()) {
|
||||||
},
|
Ok(p.unwrap())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve"))
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(_) => Err(io::Error::new(
|
Err(_) => Err(io::Error::new(
|
||||||
io::ErrorKind::InvalidInput,
|
io::ErrorKind::InvalidInput,
|
||||||
"y is not in field",
|
"y is not in field",
|
||||||
@ -101,7 +106,7 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option<Self> {
|
pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> CtOption<Self> {
|
||||||
// Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1)
|
// Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1)
|
||||||
// This is defined for all valid y-coordinates,
|
// This is defined for all valid y-coordinates,
|
||||||
// as dy^2 + 1 = 0 has no solution in Fr.
|
// as dy^2 + 1 = 0 has no solution in Fr.
|
||||||
@ -117,33 +122,30 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
|||||||
// tmp1 = y^2 - 1
|
// tmp1 = y^2 - 1
|
||||||
tmp1.sub_assign(&E::Fr::one());
|
tmp1.sub_assign(&E::Fr::one());
|
||||||
|
|
||||||
match tmp2.inverse() {
|
tmp2.invert().and_then(|tmp2| {
|
||||||
Some(tmp2) => {
|
// tmp1 = (y^2 - 1) / (dy^2 + 1)
|
||||||
// tmp1 = (y^2 - 1) / (dy^2 + 1)
|
tmp1.mul_assign(&tmp2);
|
||||||
tmp1.mul_assign(&tmp2);
|
|
||||||
|
|
||||||
match tmp1.sqrt() {
|
match tmp1.sqrt().map(|mut x| {
|
||||||
Some(mut x) => {
|
if x.into_repr().is_odd() != sign {
|
||||||
if x.into_repr().is_odd() != sign {
|
x = x.neg();
|
||||||
x = x.neg();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut t = x;
|
|
||||||
t.mul_assign(&y);
|
|
||||||
|
|
||||||
Some(Point {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
t,
|
|
||||||
z: E::Fr::one(),
|
|
||||||
_marker: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut t = x;
|
||||||
|
t.mul_assign(&y);
|
||||||
|
|
||||||
|
Point {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
t,
|
||||||
|
z: E::Fr::one(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Some(p) => CtOption::new(p, Choice::from(1)),
|
||||||
|
None => CtOption::new(Point::zero(), Choice::from(0)),
|
||||||
}
|
}
|
||||||
None => None,
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This guarantees the point is in the prime order subgroup
|
/// This guarantees the point is in the prime order subgroup
|
||||||
@ -159,8 +161,9 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
|||||||
let y = E::Fr::random(rng);
|
let y = E::Fr::random(rng);
|
||||||
let sign = rng.next_u32() % 2 != 0;
|
let sign = rng.next_u32() % 2 != 0;
|
||||||
|
|
||||||
if let Some(p) = Self::get_for_y(y, sign, params) {
|
let p = Self::get_for_y(y, sign, params);
|
||||||
return p;
|
if bool::from(p.is_some()) {
|
||||||
|
return p.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,7 +308,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||||||
|
|
||||||
/// Convert to affine coordinates
|
/// Convert to affine coordinates
|
||||||
pub fn to_xy(&self) -> (E::Fr, E::Fr) {
|
pub fn to_xy(&self) -> (E::Fr, E::Fr) {
|
||||||
let zinv = self.z.inverse().unwrap();
|
let zinv = self.z.invert().unwrap();
|
||||||
|
|
||||||
let mut x = self.x;
|
let mut x = self.x;
|
||||||
x.mul_assign(&zinv);
|
x.mul_assign(&zinv);
|
||||||
|
@ -6,7 +6,7 @@ use ff::{
|
|||||||
};
|
};
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||||
use subtle::{Choice, ConditionallySelectable};
|
use subtle::{Choice, ConditionallySelectable, CtOption};
|
||||||
|
|
||||||
use super::ToUniform;
|
use super::ToUniform;
|
||||||
|
|
||||||
@ -258,6 +258,12 @@ impl PrimeFieldRepr for FsRepr {
|
|||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Fs(FsRepr);
|
pub struct Fs(FsRepr);
|
||||||
|
|
||||||
|
impl Default for Fs {
|
||||||
|
fn default() -> Self {
|
||||||
|
Fs::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ::std::fmt::Display for Fs {
|
impl ::std::fmt::Display for Fs {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
write!(f, "Fs({})", self.into_repr())
|
write!(f, "Fs({})", self.into_repr())
|
||||||
@ -526,9 +532,11 @@ impl Field for Fs {
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inverse(&self) -> Option<Self> {
|
/// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET!
|
||||||
|
/// THIS WILL BE REPLACED BY THE jubjub CRATE, WHICH IS CONSTANT TIME!
|
||||||
|
fn invert(&self) -> CtOption<Self> {
|
||||||
if self.is_zero() {
|
if self.is_zero() {
|
||||||
None
|
CtOption::new(Self::zero(), Choice::from(0))
|
||||||
} else {
|
} else {
|
||||||
// Guajardo Kumar Paar Pelzl
|
// Guajardo Kumar Paar Pelzl
|
||||||
// Efficient Software-Implementation of Finite Fields with Applications to Cryptography
|
// Efficient Software-Implementation of Finite Fields with Applications to Cryptography
|
||||||
@ -574,9 +582,9 @@ impl Field for Fs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if u == one {
|
if u == one {
|
||||||
Some(b)
|
CtOption::new(b, Choice::from(1))
|
||||||
} else {
|
} else {
|
||||||
Some(c)
|
CtOption::new(c, Choice::from(1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1454,8 +1462,8 @@ fn test_fr_squaring() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fs_inverse() {
|
fn test_fs_invert() {
|
||||||
assert!(Fs::zero().inverse().is_none());
|
assert!(bool::from(Fs::zero().invert().is_none()));
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([
|
let mut rng = XorShiftRng::from_seed([
|
||||||
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
|
||||||
@ -1467,7 +1475,7 @@ fn test_fs_inverse() {
|
|||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
// Ensure that a * a^-1 = 1
|
// Ensure that a * a^-1 = 1
|
||||||
let mut a = Fs::random(&mut rng);
|
let mut a = Fs::random(&mut rng);
|
||||||
let ainv = a.inverse().unwrap();
|
let ainv = a.invert().unwrap();
|
||||||
a.mul_assign(&ainv);
|
a.mul_assign(&ainv);
|
||||||
assert_eq!(a, one);
|
assert_eq!(a, one);
|
||||||
}
|
}
|
||||||
|
@ -139,11 +139,11 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||||||
{
|
{
|
||||||
let mut tmp = E::Fr::one();
|
let mut tmp = E::Fr::one();
|
||||||
tmp.sub_assign(&y);
|
tmp.sub_assign(&y);
|
||||||
u.mul_assign(&tmp.inverse().unwrap())
|
u.mul_assign(&tmp.invert().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut v = u;
|
let mut v = u;
|
||||||
v.mul_assign(&x.inverse().unwrap());
|
v.mul_assign(&x.invert().unwrap());
|
||||||
|
|
||||||
// Scale it into the correct curve constants
|
// Scale it into the correct curve constants
|
||||||
v.mul_assign(params.scale());
|
v.mul_assign(params.scale());
|
||||||
@ -226,7 +226,8 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
let tmp = self.y.double();
|
let tmp = self.y.double();
|
||||||
delta.mul_assign(&tmp.inverse().expect("y is nonzero so this must be nonzero"));
|
// y is nonzero so this must be nonzero
|
||||||
|
delta.mul_assign(&tmp.invert().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut x3 = delta.square();
|
let mut x3 = delta.square();
|
||||||
@ -272,10 +273,8 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||||||
{
|
{
|
||||||
let mut tmp = other.x;
|
let mut tmp = other.x;
|
||||||
tmp.sub_assign(&self.x);
|
tmp.sub_assign(&self.x);
|
||||||
delta.mul_assign(
|
// self.x != other.x, so this must be nonzero
|
||||||
&tmp.inverse()
|
delta.mul_assign(&tmp.invert().unwrap());
|
||||||
.expect("self.x != other.x, so this must be nonzero"),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut x3 = delta.square();
|
let mut x3 = delta.square();
|
||||||
|
@ -234,7 +234,9 @@ fn test_get_for<E: JubjubEngine>(params: &E::Params) {
|
|||||||
let y = E::Fr::random(rng);
|
let y = E::Fr::random(rng);
|
||||||
let sign = rng.next_u32() % 2 == 1;
|
let sign = rng.next_u32() % 2 == 1;
|
||||||
|
|
||||||
if let Some(mut p) = edwards::Point::<E, _>::get_for_y(y, sign, params) {
|
let p = edwards::Point::<E, _>::get_for_y(y, sign, params);
|
||||||
|
if bool::from(p.is_some()) {
|
||||||
|
let mut p = p.unwrap();
|
||||||
assert!(p.to_xy().0.into_repr().is_odd() == sign);
|
assert!(p.to_xy().0.into_repr().is_odd() == sign);
|
||||||
p = p.negate();
|
p = p.negate();
|
||||||
assert!(edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap() == p);
|
assert!(edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap() == p);
|
||||||
@ -328,7 +330,7 @@ fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
|
|||||||
let mut tmp = *params.edwards_d();
|
let mut tmp = *params.edwards_d();
|
||||||
|
|
||||||
// 1 / d is nonsquare
|
// 1 / d is nonsquare
|
||||||
assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue);
|
assert!(tmp.invert().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||||
|
|
||||||
// tmp = -d
|
// tmp = -d
|
||||||
tmp = tmp.neg();
|
tmp = tmp.neg();
|
||||||
@ -337,7 +339,7 @@ fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
|
|||||||
assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue);
|
assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||||
|
|
||||||
// 1 / -d is nonsquare
|
// 1 / -d is nonsquare
|
||||||
assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue);
|
assert!(tmp.invert().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -358,7 +360,7 @@ fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
|
|||||||
// Check the validity of the scaling factor
|
// Check the validity of the scaling factor
|
||||||
let mut tmp = a;
|
let mut tmp = a;
|
||||||
tmp.sub_assign(¶ms.edwards_d());
|
tmp.sub_assign(¶ms.edwards_d());
|
||||||
tmp = tmp.inverse().unwrap();
|
tmp = tmp.invert().unwrap();
|
||||||
tmp.mul_assign(&E::Fr::from_str("4").unwrap());
|
tmp.mul_assign(&E::Fr::from_str("4").unwrap());
|
||||||
tmp = tmp.sqrt().unwrap();
|
tmp = tmp.sqrt().unwrap();
|
||||||
assert_eq!(&tmp, params.scale());
|
assert_eq!(&tmp, params.scale());
|
||||||
|
@ -344,13 +344,11 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
|
|||||||
let mut t1 = E::Fr::one();
|
let mut t1 = E::Fr::one();
|
||||||
t1.add_assign(c.get_value().get()?);
|
t1.add_assign(c.get_value().get()?);
|
||||||
|
|
||||||
match t1.inverse() {
|
let res = t1.invert().map(|t1| t0 * &t1);
|
||||||
Some(t1) => {
|
if bool::from(res.is_some()) {
|
||||||
t0.mul_assign(&t1);
|
Ok(res.unwrap())
|
||||||
|
} else {
|
||||||
Ok(t0)
|
Err(SynthesisError::DivisionByZero)
|
||||||
}
|
|
||||||
None => Err(SynthesisError::DivisionByZero),
|
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -371,13 +369,11 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
|
|||||||
let mut t1 = E::Fr::one();
|
let mut t1 = E::Fr::one();
|
||||||
t1.sub_assign(c.get_value().get()?);
|
t1.sub_assign(c.get_value().get()?);
|
||||||
|
|
||||||
match t1.inverse() {
|
let res = t1.invert().map(|t1| t0 * &t1);
|
||||||
Some(t1) => {
|
if bool::from(res.is_some()) {
|
||||||
t0.mul_assign(&t1);
|
Ok(res.unwrap())
|
||||||
|
} else {
|
||||||
Ok(t0)
|
Err(SynthesisError::DivisionByZero)
|
||||||
}
|
|
||||||
None => Err(SynthesisError::DivisionByZero),
|
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -451,13 +447,11 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
|
|||||||
let mut t1 = E::Fr::one();
|
let mut t1 = E::Fr::one();
|
||||||
t1.add_assign(c.get_value().get()?);
|
t1.add_assign(c.get_value().get()?);
|
||||||
|
|
||||||
match t1.inverse() {
|
let ret = t1.invert().map(|t1| t0 * &t1);
|
||||||
Some(t1) => {
|
if bool::from(ret.is_some()) {
|
||||||
t0.mul_assign(&t1);
|
Ok(ret.unwrap())
|
||||||
|
} else {
|
||||||
Ok(t0)
|
Err(SynthesisError::DivisionByZero)
|
||||||
}
|
|
||||||
None => Err(SynthesisError::DivisionByZero),
|
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -478,13 +472,11 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
|
|||||||
let mut t1 = E::Fr::one();
|
let mut t1 = E::Fr::one();
|
||||||
t1.sub_assign(c.get_value().get()?);
|
t1.sub_assign(c.get_value().get()?);
|
||||||
|
|
||||||
match t1.inverse() {
|
let ret = t1.invert().map(|t1| t0 * &t1);
|
||||||
Some(t1) => {
|
if bool::from(ret.is_some()) {
|
||||||
t0.mul_assign(&t1);
|
Ok(ret.unwrap())
|
||||||
|
} else {
|
||||||
Ok(t0)
|
Err(SynthesisError::DivisionByZero)
|
||||||
}
|
|
||||||
None => Err(SynthesisError::DivisionByZero),
|
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -521,13 +513,11 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
|
|||||||
let mut t0 = *self.x.get_value().get()?;
|
let mut t0 = *self.x.get_value().get()?;
|
||||||
t0.mul_assign(params.scale());
|
t0.mul_assign(params.scale());
|
||||||
|
|
||||||
match self.y.get_value().get()?.inverse() {
|
let ret = self.y.get_value().get()?.invert().map(|invy| t0 * &invy);
|
||||||
Some(invy) => {
|
if bool::from(ret.is_some()) {
|
||||||
t0.mul_assign(&invy);
|
Ok(ret.unwrap())
|
||||||
|
} else {
|
||||||
Ok(t0)
|
Err(SynthesisError::DivisionByZero)
|
||||||
}
|
|
||||||
None => Err(SynthesisError::DivisionByZero),
|
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -545,13 +535,11 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
|
|||||||
t0.sub_assign(&E::Fr::one());
|
t0.sub_assign(&E::Fr::one());
|
||||||
t1.add_assign(&E::Fr::one());
|
t1.add_assign(&E::Fr::one());
|
||||||
|
|
||||||
match t1.inverse() {
|
let ret = t1.invert().map(|t1| t0 * &t1);
|
||||||
Some(t1) => {
|
if bool::from(ret.is_some()) {
|
||||||
t0.mul_assign(&t1);
|
Ok(ret.unwrap())
|
||||||
|
} else {
|
||||||
Ok(t0)
|
Err(SynthesisError::DivisionByZero)
|
||||||
}
|
|
||||||
None => Err(SynthesisError::DivisionByZero),
|
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -593,12 +581,11 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
|
|||||||
let mut d = *other.x.get_value().get()?;
|
let mut d = *other.x.get_value().get()?;
|
||||||
d.sub_assign(self.x.get_value().get()?);
|
d.sub_assign(self.x.get_value().get()?);
|
||||||
|
|
||||||
match d.inverse() {
|
let ret = d.invert().map(|d| n * &d);
|
||||||
Some(d) => {
|
if bool::from(ret.is_some()) {
|
||||||
n.mul_assign(&d);
|
Ok(ret.unwrap())
|
||||||
Ok(n)
|
} else {
|
||||||
}
|
Err(SynthesisError::DivisionByZero)
|
||||||
None => Err(SynthesisError::DivisionByZero),
|
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user