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:
Jack Grigg
2019-05-14 14:18:37 +01:00
parent e85a9f309f
commit 40749da9a7
25 changed files with 243 additions and 221 deletions

View File

@@ -73,11 +73,11 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
coeffs,
exp,
omega,
omegainv: omega.inverse().unwrap(),
geninv: E::Fr::multiplicative_generator().inverse().unwrap(),
omegainv: omega.invert().unwrap(),
geninv: E::Fr::multiplicative_generator().invert().unwrap(),
minv: E::Fr::from_str(&format!("{}", m))
.unwrap()
.inverse()
.invert()
.unwrap(),
})
}
@@ -141,10 +141,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
/// evaluation domain, so we must perform division over
/// a coset.
pub fn divide_by_z_on_coset(&mut self, worker: &Worker) {
let i = self
.z(&E::Fr::multiplicative_generator())
.inverse()
.unwrap();
let i = self.z(&E::Fr::multiplicative_generator()).invert().unwrap();
worker.scope(self.coeffs.len(), |scope, chunk| {
for v in self.coeffs.chunks_mut(chunk) {

View File

@@ -288,7 +288,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
if tmp.is_zero() {
Err(SynthesisError::DivisionByZero)
} else {
Ok(tmp.inverse().unwrap())
Ok(tmp.invert().unwrap())
}
},
)?;

View File

@@ -215,8 +215,22 @@ where
assembly.num_inputs + assembly.num_aux
});
let gamma_inverse = gamma.inverse().ok_or(SynthesisError::UnexpectedIdentity)?;
let delta_inverse = delta.inverse().ok_or(SynthesisError::UnexpectedIdentity)?;
let gamma_inverse = {
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();

View File

@@ -10,13 +10,19 @@ use std::cmp::Ordering;
use std::fmt;
use std::num::Wrapping;
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);
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Fr(Wrapping<u32>);
impl Default for Fr {
fn default() -> Self {
<Fr as Field>::zero()
}
}
impl fmt::Display for Fr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", (self.0).0)
@@ -159,11 +165,11 @@ impl Field for Fr {
Fr((self.0 << 1) % MODULUS_R)
}
fn inverse(&self) -> Option<Self> {
fn invert(&self) -> CtOption<Self> {
if <Fr as Field>::is_zero(self) {
None
CtOption::new(<Fr as Field>::zero(), Choice::from(0))
} 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.
fn final_exponentiation(this: &Self::Fqk) -> Option<Self::Fqk> {
Some(*this)
fn final_exponentiation(this: &Self::Fqk) -> CtOption<Self::Fqk> {
CtOption::new(*this, Choice::from(1))
}
}

View File

@@ -156,8 +156,8 @@ fn test_xordemo() {
// We expect our H query to be 7 elements of the form...
// {tau^i t(tau) / delta}
let delta_inverse = delta.inverse().unwrap();
let gamma_inverse = gamma.inverse().unwrap();
let delta_inverse = delta.invert().unwrap();
let gamma_inverse = gamma.invert().unwrap();
{
let mut coeff = delta_inverse;
coeff.mul_assign(&t_at_tau);