Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions bellman/src/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
})
}
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion bellman/src/gadgets/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
},
)?;
Expand Down
18 changes: 16 additions & 2 deletions bellman/src/groth16/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there should be an impl From<Option<T>> for CtOption<T> in subtle...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes it too easy to slip out of constant-time-ness, which could lead to subtle bugs. I'm rather partial to the fact that if you want to leave that domain, it needs to be noisy. It would definitely be nice to have it be easier than it currently is; it should be possible to do that while still being noisy.

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();

Expand Down
99 changes: 45 additions & 54 deletions bellman/src/groth16/tests/dummy_engine.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use ff::{
Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine,
SqrtField,
};
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use pairing::{Engine, PairingCurveAffine};

Expand All @@ -10,13 +7,25 @@ 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, ConstantTimeEq, 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 ConstantTimeEq for Fr {
fn ct_eq(&self, other: &Fr) -> Choice {
(self.0).0.ct_eq(&(other.0).0)
}
}

impl fmt::Display for Fr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", (self.0).0)
Expand Down Expand Up @@ -159,11 +168,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))
}
}

Expand All @@ -173,57 +182,39 @@ impl Field for Fr {
}

impl SqrtField for Fr {
fn legendre(&self) -> LegendreSymbol {
// s = self^((r - 1) // 2)
let s = self.pow([32256]);
if s == <Fr as Field>::zero() {
LegendreSymbol::Zero
} else if s == <Fr as Field>::one() {
LegendreSymbol::QuadraticResidue
} else {
LegendreSymbol::QuadraticNonResidue
}
}

fn sqrt(&self) -> Option<Self> {
fn sqrt(&self) -> CtOption<Self> {
// Tonelli-Shank's algorithm for q mod 16 = 1
// https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
match self.legendre() {
LegendreSymbol::Zero => Some(*self),
LegendreSymbol::QuadraticNonResidue => None,
LegendreSymbol::QuadraticResidue => {
let mut c = Fr::root_of_unity();
// r = self^((t + 1) // 2)
let mut r = self.pow([32]);
// t = self^t
let mut t = self.pow([63]);
let mut m = Fr::S;

while t != <Fr as Field>::one() {
let mut i = 1;
{
let mut t2i = t.square();
loop {
if t2i == <Fr as Field>::one() {
break;
}
t2i = t2i.square();
i += 1;
}
let mut c = Fr::root_of_unity();
// r = self^((t + 1) // 2)
let mut r = self.pow([32]);
// t = self^t
let mut t = self.pow([63]);
let mut m = Fr::S;

while t != <Fr as Field>::one() {
let mut i = 1;
{
let mut t2i = t.square();
loop {
if t2i == <Fr as Field>::one() {
break;
}

for _ in 0..(m - i - 1) {
c = c.square();
}
MulAssign::mul_assign(&mut r, &c);
c = c.square();
MulAssign::mul_assign(&mut t, &c);
m = i;
t2i = t2i.square();
i += 1;
}
}

Some(r)
for _ in 0..(m - i - 1) {
c = c.square();
}
MulAssign::mul_assign(&mut r, &c);
c = c.square();
MulAssign::mul_assign(&mut t, &c);
m = i;
}

CtOption::new(r, (r * r).ct_eq(self))
}
}

Expand Down Expand Up @@ -382,8 +373,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))
}
}

Expand Down
4 changes: 2 additions & 2 deletions bellman/src/groth16/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading