Skip to content

Commit

Permalink
Merge branch 'lambdaclass:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
mdvillagra authored Sep 7, 2023
2 parents 6f32048 + 0465d89 commit 9c2d333
Show file tree
Hide file tree
Showing 31 changed files with 183 additions and 158 deletions.
68 changes: 2 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ Right now Plonk prover is in this repo, you can find the others here:
## Main crates

- [Math](https://github.com/lambdaclass/lambdaworks/tree/main/math)
- [Crypto primitives](https://github.com/lambdaclass/lambdaworks/crypto)
- [Plonk Prover](https://github.com/lambdaclass/lambdaworks/provers/plonk)
- [Crypto primitives](https://github.com/lambdaclass/lambdaworks/tree/main/crypto)
- [Plonk Prover](https://github.com/lambdaclass/lambdaworks/tree/main/provers/plonk)

### Crypto
- [Elliptic curves](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve)
Expand Down Expand Up @@ -120,70 +120,6 @@ make benchmark BENCH=field

You can check the generated HTML report in `target/criterion/reports/index.html`

# Lambdaworks Plonk Prover
A fast implementation of the [Plonk](https://eprint.iacr.org/2019/953) zk-protocol written in Rust. This is part of the [Lambdaworks](https://github.com/lambdaclass/lambdaworks) zero-knowledge framework. It includes a high-level API to seamlessly build your own circuits.

<div>

[![Telegram Chat][tg-badge]][tg-url]

[tg-badge]: https://img.shields.io/static/v1?color=green&logo=telegram&label=chat&style=flat&message=join
[tg-url]: https://t.me/+98Whlzql7Hs0MDZh

</div>

This prover is still in development and may contain bugs. It is not intended to be used in production yet.

## Building a circuit
The following code creates a circuit with two public inputs `x`, `y` and asserts `x * e = y`:

```rust
let system = &mut ConstraintSystem::<FrField>::new();
let x = system.new_public_input();
let y = system.new_public_input();
let e = system.new_variable();

let z = system.mul(&x, &e);
system.assert_eq(&y, &z);;
```

## Generating a proof
### Setup
A setup is needed in order to generate a proof for a new circuit. The following code generates a verifying key that will be used by both the prover and the verifier:

```rust
let common = CommonPreprocessedInput::from_constraint_system(&system, &ORDER_R_MINUS_1_ROOT_UNITY);
let srs = test_srs(common.n);
let kzg = KZG::new(srs); // The commitment scheme for plonk.
let verifying_key = setup(&common, &kzg);
```

### Prover
First, we fix values for `x` and `e` and solve the constraint system:
```rust
let inputs = HashMap::from([(x, FieldElement::from(4)), (e, FieldElement::from(3))]);
let assignments = system.solve(inputs).unwrap();
```

Finally, we call the prover:
```rust
let witness = Witness::new(assignments, &system);
let public_inputs = system.public_input_values(&assignments);
let prover = Prover::new(kzg.clone(), TestRandomFieldGenerator {});
let proof = prover.prove(&witness, &public_inputs, &common, &verifying_key);
```

## Verifying a proof
Just call the verifier:

```rust
let verifier = Verifier::new(kzg);
assert!(verifier.verify(&proof, &public_inputs, &common, &verifying_key));
```

# More info
You can find more info in the [documentation](https://lambdaclass.github.io/lambdaworks_plonk_prover/).

## 📚 References

The following links, repos and projects have been important in the development of this library and we want to thank and acknowledge them.
Expand Down
2 changes: 1 addition & 1 deletion benches/benches/invert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|b| {
b.iter(|| {
for elem in lambdaworks_vec.iter() {
black_box(black_box(&elem).inv());
black_box(black_box(&elem).inv().unwrap());
}
});
},
Expand Down
4 changes: 2 additions & 2 deletions fuzz/no_gpu_fuzz/fuzz_targets/field_from_hex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ fuzz_target!(|values: (String, String)| {
assert_eq!(&b - &b, zero, "Inverse add b failed");

if a != zero {
assert_eq!(&a * a.inv(), one, "Inverse mul a failed");
assert_eq!(&a * a.inv().unwrap(), one, "Inverse mul a failed");
}
if b != zero {
assert_eq!(&b * b.inv(), one, "Inverse mul b failed");
assert_eq!(&b * b.inv().unwrap(), one, "Inverse mul b failed");
}
}
});
Expand Down
4 changes: 2 additions & 2 deletions fuzz/no_gpu_fuzz/fuzz_targets/field_from_raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ fuzz_target!(|values: (u64, u64)| {
assert_eq!(&b - &b, zero, "Inverse add b failed");

if a != zero {
assert_eq!(&a * a.inv(), one, "Inverse mul a failed");
assert_eq!(&a * a.inv().unwrap(), one, "Inverse mul a failed");
}
if b != zero {
assert_eq!(&b * b.inv(), one, "Inverse mul b failed");
assert_eq!(&b * b.inv().unwrap(), one, "Inverse mul b failed");
}


Expand Down
4 changes: 2 additions & 2 deletions fuzz/no_gpu_fuzz/fuzz_targets/field_fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ fuzz_target!(|values: (u64, u64)| {
assert_eq!(&b - &b, zero, "Inverse add b failed");

if a != zero {
assert_eq!(&a * a.inv(), one, "Inverse mul a failed");
assert_eq!(&a * a.inv().unwrap(), one, "Inverse mul a failed");
}
if b != zero {
assert_eq!(&b * b.inv(), one, "Inverse mul b failed");
assert_eq!(&b * b.inv().unwrap(), one, "Inverse mul b failed");
}


Expand Down
2 changes: 1 addition & 1 deletion math/benches/criterion_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn starkfield_ops_benchmarks(c: &mut Criterion) {
});

group.bench_with_input("inv", &x, |bench, x| {
bench.iter(|| x.inv());
bench.iter(|| x.inv().unwrap());
});

group.bench_with_input("div", &(x, y), |bench, (x, y)| {
Expand Down
2 changes: 1 addition & 1 deletion math/src/elliptic_curve/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl<E: IsEllipticCurve> ProjectivePoint<E> {
pub fn to_affine(&self) -> Self {
let [x, y, z] = self.coordinates();
assert_ne!(z, &FieldElement::zero());
let inv_z = z.inv();
let inv_z = z.inv().unwrap();
ProjectivePoint::new([x * &inv_z, y * inv_z, FieldElement::one()])
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::unsigned_integer::element::U384;
use crate::{
field::{
element::FieldElement,
errors::FieldError,
extensions::{
cubic::{CubicExtensionField, HasCubicNonResidue},
quadratic::{HasQuadraticNonResidue, QuadraticExtensionField},
Expand Down Expand Up @@ -65,14 +66,14 @@ impl IsField for Degree2ExtensionField {

/// Returns the multiplicative inverse of `a`
/// This uses the equality `(a0 + a1 * t) * (a0 - a1 * t) = a0.pow(2) - a1.pow(2) * Q::residue()`
fn inv(a: &Self::BaseType) -> Self::BaseType {
let inv_norm = (a[0].pow(2_u64) + a[1].pow(2_u64)).inv();
[&a[0] * &inv_norm, -&a[1] * inv_norm]
fn inv(a: &Self::BaseType) -> Result<Self::BaseType, FieldError> {
let inv_norm = (a[0].pow(2_u64) + a[1].pow(2_u64)).inv()?;
Ok([&a[0] * &inv_norm, -&a[1] * inv_norm])
}

/// Returns the division of `a` and `b`
fn div(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType {
Self::mul(a, &Self::inv(b))
Self::mul(a, &Self::inv(b).unwrap())
}

/// Returns a boolean indicating whether `a` and `b` are equal component wise.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ fn miller(
add_accumulate_line(&mut r, q, p, &mut f);
}
}
f.inv()
f.inv().unwrap()
}

/// Auxiliary function for the final exponentiation of the ate pairing.
Expand Down Expand Up @@ -205,7 +205,7 @@ fn final_exponentiation(
) -> FieldElement<Degree12ExtensionField> {
const PHI_DIVIDED_BY_R: UnsignedInteger<20> = UnsignedInteger::from_hex_unchecked("f686b3d807d01c0bd38c3195c899ed3cde88eeb996ca394506632528d6a9a2f230063cf081517f68f7764c28b6f8ae5a72bce8d63cb9f827eca0ba621315b2076995003fc77a17988f8761bdc51dc2378b9039096d1b767f17fcbde783765915c97f36c6f18212ed0b283ed237db421d160aeb6a1e79983774940996754c8c71a2629b0dea236905ce937335d5b68fa9912aae208ccf1e516c3f438e3ba79");

let f1 = base.conjugate() * base.inv();
let f1 = base.conjugate() * base.inv().unwrap();
let f2 = frobenius_square(&f1) * f1;
f2.pow(PHI_DIVIDED_BY_R)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub fn sqrt_qfe(
match gamma {
LegendreSymbol::One => {
let two = BLS12381FieldElement::from(2u64);
let two_inv = two.inv();
let two_inv = two.inv().unwrap();
// calculate the square root of alpha
let (y_sqrt1, y_sqrt2) = alpha.sqrt()?;
let mut delta = (a.clone() + y_sqrt1) * two_inv.clone();
Expand All @@ -59,7 +59,7 @@ pub fn sqrt_qfe(
};
let (x_sqrt_1, x_sqrt_2) = delta.sqrt()?;
let x_0 = select_sqrt_value_from_third_bit(x_sqrt_1, x_sqrt_2, third_bit);
let x_1 = b * (two * x_0.clone()).inv();
let x_1 = b * (two * x_0.clone()).inv().unwrap();
Some(BLS12381TwistCurveFieldElement::new([x_0, x_1]))
}
LegendreSymbol::MinusOne => None,
Expand Down
2 changes: 1 addition & 1 deletion math/src/fft/cpu/roots_of_unity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub fn get_powers_of_primitive_root<F: IsFFTField>(

let root = match config {
RootsConfig::Natural | RootsConfig::BitReverse => F::get_primitive_root_of_unity(n)?,
_ => F::get_primitive_root_of_unity(n)?.inv(),
_ => F::get_primitive_root_of_unity(n)?.inv().unwrap(),
};
let up_to = match config {
RootsConfig::Natural | RootsConfig::NaturalInversed => count,
Expand Down
3 changes: 3 additions & 0 deletions math/src/fft/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ impl From<FieldError> for FFTError {
FieldError::DivisionByZero => {
panic!("Can't divide by zero during FFT");
}
FieldError::InvZeroError => {
panic!("Can't calculate inverse of zero during FFT");
}
FieldError::RootOfUnityError(order) => FFTError::RootOfUnityError(order),
}
}
Expand Down
2 changes: 1 addition & 1 deletion math/src/fft/gpu/cuda/polynomial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ where

let coeffs = fft(fft_evals, &twiddles, &state)?;

let scale_factor = FieldElement::from(fft_evals.len() as u64).inv();
let scale_factor = FieldElement::from(fft_evals.len() as u64).inv().unwrap();
Ok(Polynomial::new(&coeffs).scale_coeffs(&scale_factor))
}

Expand Down
2 changes: 1 addition & 1 deletion math/src/fft/gpu/metal/polynomial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ where

let coeffs = fft(fft_evals, &twiddles, &metal_state)?;

let scale_factor = FieldElement::from(fft_evals.len() as u64).inv();
let scale_factor = FieldElement::from(fft_evals.len() as u64).inv().unwrap();
Ok(Polynomial::new(&coeffs).scale_coeffs(&scale_factor))
}
4 changes: 2 additions & 2 deletions math/src/fft/polynomial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ impl<F: IsFFTField> FFTPoly<F> for Polynomial<FieldElement<F>> {
offset: &FieldElement<F>,
) -> Result<Polynomial<FieldElement<F>>, FFTError> {
let scaled = Polynomial::interpolate_fft(fft_evals)?;
Ok(scaled.scale(&offset.inv()))
Ok(scaled.scale(&offset.inv().unwrap()))
}
}

Expand Down Expand Up @@ -182,7 +182,7 @@ where

let coeffs = ops::fft(fft_evals, &twiddles)?;

let scale_factor = FieldElement::from(fft_evals.len() as u64).inv();
let scale_factor = FieldElement::from(fft_evals.len() as u64).inv().unwrap();
Ok(Polynomial::new(&coeffs).scale_coeffs(&scale_factor))
}

Expand Down
17 changes: 9 additions & 8 deletions math/src/field/element.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::errors::CreationError;
use crate::field::errors::FieldError;
use crate::field::traits::IsField;
use crate::unsigned_integer::element::UnsignedInteger;
use crate::unsigned_integer::montgomery::MontgomeryAlgorithms;
Expand Down Expand Up @@ -29,23 +30,24 @@ pub struct FieldElement<F: IsField> {
#[cfg(feature = "std")]
impl<F: IsField> FieldElement<F> {
// Source: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse#Multiple_inverses
pub fn inplace_batch_inverse(numbers: &mut [Self]) {
pub fn inplace_batch_inverse(numbers: &mut [Self]) -> Result<(), FieldError> {
if numbers.is_empty() {
return;
return Ok(());
}
let count = numbers.len();
let mut prod_prefix = Vec::with_capacity(count);
prod_prefix.push(numbers[0].clone());
for i in 1..count {
prod_prefix.push(&prod_prefix[i - 1] * &numbers[i]);
}
let mut bi_inv = prod_prefix[count - 1].inv();
let mut bi_inv = prod_prefix[count - 1].inv()?;
for i in (1..count).rev() {
let ai_inv = &bi_inv * &prod_prefix[i - 1];
bi_inv = &bi_inv * &numbers[i];
numbers[i] = ai_inv;
}
numbers[0] = bi_inv;
Ok(())
}
}

Expand Down Expand Up @@ -367,10 +369,9 @@ where

/// Returns the multiplicative inverse of `self`
#[inline(always)]
pub fn inv(&self) -> Self {
Self {
value: F::inv(&self.value),
}
pub fn inv(&self) -> Result<Self, FieldError> {
let value = F::inv(&self.value)?;
Ok(Self { value })
}

/// Returns the square of `self`
Expand Down Expand Up @@ -694,7 +695,7 @@ mod tests {
fn test_inplace_batch_inverse_returns_inverses(vec in field_vec(10)) {
let input: Vec<_> = vec.into_iter().filter(|x| x != &FieldElement::<Stark252PrimeField>::zero()).collect();
let mut inverses = input.clone();
FieldElement::inplace_batch_inverse(&mut inverses);
FieldElement::inplace_batch_inverse(&mut inverses).unwrap();

for (i, x) in inverses.into_iter().enumerate() {
prop_assert_eq!(x * input[i], FieldElement::<Stark252PrimeField>::one());
Expand Down
2 changes: 2 additions & 0 deletions math/src/field/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ pub enum FieldError {
DivisionByZero,
/// Returns order of the calculated root of unity
RootOfUnityError(u64),
/// Can't calculate inverse of zero
InvZeroError,
}
17 changes: 10 additions & 7 deletions math/src/field/extensions/cubic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::field::element::FieldElement;
use crate::field::errors::FieldError;
use crate::field::traits::IsField;
use core::fmt::Debug;
use core::marker::PhantomData;
Expand Down Expand Up @@ -70,27 +71,29 @@ where
}

/// Returns the multiplicative inverse of `a`
fn inv(a: &[FieldElement<Q::BaseField>; 3]) -> [FieldElement<Q::BaseField>; 3] {
fn inv(
a: &[FieldElement<Q::BaseField>; 3],
) -> Result<[FieldElement<Q::BaseField>; 3], FieldError> {
let three = FieldElement::from(3_u64);

let d = a[0].pow(3_u64)
+ a[1].pow(3_u64) * Q::residue()
+ a[2].pow(3_u64) * Q::residue().pow(2_u64)
- three * &a[0] * &a[1] * &a[2] * Q::residue();
let inv = d.inv();
[
let inv = d.inv()?;
Ok([
(a[0].pow(2_u64) - &a[1] * &a[2] * Q::residue()) * &inv,
(-&a[0] * &a[1] + a[2].pow(2_u64) * Q::residue()) * &inv,
(-&a[0] * &a[2] + a[1].pow(2_u64)) * &inv,
]
])
}

/// Returns the division of `a` and `b`
fn div(
a: &[FieldElement<Q::BaseField>; 3],
b: &[FieldElement<Q::BaseField>; 3],
) -> [FieldElement<Q::BaseField>; 3] {
Self::mul(a, &Self::inv(b))
Self::mul(a, &Self::inv(b).unwrap())
}

/// Returns a boolean indicating whether `a` and `b` are equal component wise.
Expand Down Expand Up @@ -241,13 +244,13 @@ mod tests {
fn test_inv() {
let a = FEE::new([FE::new(12), FE::new(5), FE::new(3)]);
let expected_result = FEE::new([FE::new(2), FE::new(2), FE::new(3)]);
assert_eq!(a.inv(), expected_result);
assert_eq!(a.inv().unwrap(), expected_result);
}

#[test]
fn test_inv_1() {
let a = FEE::new([FE::new(1), FE::new(0), FE::new(1)]);
let expected_result = FEE::new([FE::new(8), FE::new(3), FE::new(5)]);
assert_eq!(a.inv(), expected_result);
assert_eq!(a.inv().unwrap(), expected_result);
}
}
Loading

0 comments on commit 9c2d333

Please sign in to comment.