Skip to content

Commit

Permalink
SOT 164: Add Parser (#15)
Browse files Browse the repository at this point in the history
* add expectation

* Testing

* Commit

* Update parser.rs

* Update parser.rs

* add expectation

* Update parser.rs

* Update parser.rs

* parser

* fix

* Update parser.rs

* Update parser.rs

* Update parser.rs

* temp

* update

* Optimize code

* Update parser.rs

* Change position map shuffling algorithm

* Update parser.rs

* Fix parser: add constant gate support

* Fix parser: add integer larger than 9 power support

* Refactor: Major code improvement from plonk_ckb

Change into no_std format
Separate KzgScheme, Srs, CPI generation for other usage e.g: on chain verification

---------

Co-authored-by: Harry Nguyen <sonntuet1997@gmail.com>
Co-authored-by: Steve Nguyen <33181397+zk-steve@users.noreply.github.com>
  • Loading branch information
3 people authored Jul 18, 2024
1 parent 58e1026 commit c6d2ee1
Show file tree
Hide file tree
Showing 18 changed files with 1,835 additions and 506 deletions.
2 changes: 1 addition & 1 deletion kzg/src/srs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::types::{G1Point, G2Point};
///
/// The `Srs` struct represents the structured reference string used in the KZG scheme,
/// containing precomputed values necessary for commitment and verification.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct Srs {
/// Points in G1, each equals to generator point multiplied by the secret's powers.
g1_points: Vec<G1Point>,
Expand Down
4 changes: 2 additions & 2 deletions plonk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ ark-poly = "0.4.2"
ark-ec = "0.4.2"
ark-bls12-381 = "0.4.0"
ark-serialize = "0.4.2"
ark-std = "0.4.0"
rand = "0.8.5"
ark-std = { version = "0.4.0", default-features = false }
sha2 = "0.10"
kzg = { path = "../kzg" }
clap = { version = "4.5.4", features = ["derive"] }

[dependencies.digest]
version = "0.10"
Expand Down
96 changes: 49 additions & 47 deletions plonk/examples/example.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use ark_bls12_381::Fr;
use sha2::Sha256;

use kzg::srs::Srs;
use plonk::circuit::Circuit;
use plonk::prover;
use plonk::verifier;
Expand All @@ -9,55 +10,56 @@ fn main() {
// Function: xy + 3x^2 + xyz = 11

// init a new circuit
let compile_circuit = Circuit::default()
.add_multiplication_gate(
(0, 1, Fr::from(1)),
(1, 0, Fr::from(2)),
(0, 3, Fr::from(2)),
Fr::from(0),
)
.add_multiplication_gate(
(1, 1, Fr::from(1)),
(0, 0, Fr::from(1)),
(0, 2, Fr::from(1)),
Fr::from(0),
)
.add_multiplication_gate(
(2, 1, Fr::from(1)),
(2, 6, Fr::from(3)),
(1, 3, Fr::from(3)),
Fr::from(0),
)
.add_addition_gate(
(0, 4, Fr::from(2)),
(2, 2, Fr::from(3)),
(0, 5, Fr::from(5)),
Fr::from(0),
)
.add_multiplication_gate(
(2, 0, Fr::from(2)),
(1, 4, Fr::from(3)),
(1, 5, Fr::from(6)),
Fr::from(0),
)
.add_addition_gate(
(2, 3, Fr::from(5)),
(2, 4, Fr::from(6)),
(2, 5, Fr::from(11)),
Fr::from(0),
)
.add_constant_gate(
(0, 6, Fr::from(3)),
(1, 6, Fr::from(0)),
(1, 2, Fr::from(3)),
Fr::from(0),
)
.compile()
.unwrap();
let mut circuit = Circuit::default();
circuit.add_multiplication_gate(
(0, 1, Fr::from(1)),
(1, 0, Fr::from(2)),
(0, 3, Fr::from(2)),
Fr::from(0),
);
circuit.add_multiplication_gate(
(1, 1, Fr::from(1)),
(0, 0, Fr::from(1)),
(0, 2, Fr::from(1)),
Fr::from(0),
);
circuit.add_multiplication_gate(
(2, 1, Fr::from(1)),
(2, 6, Fr::from(3)),
(1, 3, Fr::from(3)),
Fr::from(0),
);
circuit.add_addition_gate(
(0, 4, Fr::from(2)),
(2, 2, Fr::from(3)),
(0, 5, Fr::from(5)),
Fr::from(0),
);
circuit.add_multiplication_gate(
(2, 0, Fr::from(2)),
(1, 4, Fr::from(3)),
(1, 5, Fr::from(6)),
Fr::from(0),
);
circuit.add_addition_gate(
(2, 3, Fr::from(5)),
(2, 4, Fr::from(6)),
(2, 5, Fr::from(11)),
Fr::from(0),
);
circuit.add_constant_gate(
(0, 6, Fr::from(3)),
(1, 6, Fr::from(0)),
(1, 2, Fr::from(3)),
Fr::from(0),
);

let compiled_circuit = circuit.compile().unwrap();

// generate proof
let proof = prover::generate_proof::<Sha256>(&compile_circuit);
let srs = Srs::new(compiled_circuit.size);
let proof = prover::generate_proof::<Sha256>(&compiled_circuit, srs.clone());

// verify proof
assert!(verifier::verify::<Sha256>(&compile_circuit, proof).is_ok());
assert!(verifier::verify::<Sha256>(&compiled_circuit, srs, proof).is_ok());
}
41 changes: 25 additions & 16 deletions plonk/plonk.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
# PLONK implementation

## Overview

This is an implementation of PLONK. You all can use this one as a library.

## Details
This implementation closely follows the specifications outlined in the
[PLONK paper](https://eprint.iacr.org/2019/953.pdf). We have implemented all the relevant rounds
for both proof generation and verification. For detailed code, please

This implementation closely follows the specifications outlined in the
[PLONK paper](https://eprint.iacr.org/2019/953.pdf). We have implemented all the relevant rounds
for both proof generation and verification. For detailed code, please
refer to the `prover.rs`and `verifier.rs` files located in the `src`
directory.
directory.

### What we use ?
We utilize the Bls12-381 curve for KZG commitment in this implementation. To learn more about this

We utilize the Bls12-381 curve for KZG commitment in this implementation. To learn more about this
curve, please refer to [this resource](https://github.com/sota-zk-lab/zkp-documents/blob/main/terms/bls12-381.md),
and for further insights into KZG commitment, you can explore
and for further insights into KZG commitment, you can explore
[our documentation](https://github.com/sota-zk-lab/zkp-documents/blob/main/terms/polynomial-commitment/100_kate_commitment.md).

All the dependencies utilized in this project are sourced from the `ark` (or `arkworks`) crates. For more information, please visit [arkworks.rs](https://arkworks.rs/).
All the dependencies utilized in this project are sourced from the `ark` (or `arkworks`) crates. For more information,
please visit [arkworks.rs](https://arkworks.rs/).

### Set up

Expand All @@ -30,19 +34,21 @@ Before proceeding, it's advisable to review the documentation on how to utilize
```
cargo run --example plonk-example
```
The above code will run the `main` function in `example.rs` files located in the `examples`
The above code will run the `main` function in `example.rs` files located in the `examples`
directory, which is the example usage of this library.
### Gates
> [!NOTE]
> For now, we have not implemented a transformation function to convert plain equations
> into circuits automatically. So, we're adding gates manually. We will endeavor to create
> this function as soon as possible. If you're interested in contributing to this project
> For now, we have not implemented a transformation function to convert plain equations
> into circuits automatically. So, we're adding gates manually. We will endeavor to create
> this function as soon as possible. If you're interested in contributing to this project
> in any capacity, feel free to raise the issue or create a pull request.
Let's take equation: `x^2 + y^2 = z^2` with `x = 3, y = 4, z = 5` as an example.
Prior to circuit generation, it's essential to parse it into smaller equations:
```
- x * x = m
- y * y = n
Expand All @@ -55,38 +61,41 @@ Consider each equation above as a gate. Here is the table of gates:
![gate_explanation_01.PNG](attachments/gate_explanation_01.png)
In the first equations, both the left and right parts of the left side are `x`, which means
they are the same. So, in the first gate, the values of `a` and `b` must be equal. It holds
they are the same. So, in the first gate, the values of `a` and `b` must be equal. It holds
true for the other gates as well. We denote this with colorful lines in the picture.
We store the value of each wire in gates in a 2-D vector, where the first dimension is either `0`, `1` or `2`,
corresponding to `a`, `b` or `c` respectively. Then, instead of storing each wire with its actual position
corresponding to `a`, `b` or `c` respectively. Then, instead of storing each wire with its actual position
(e.g., wire `a` in gate `0` is `(0, 0)`, wire `c` in gate `3` is `(2, 3)`), we store it with its copied position.
In the example above, wire `a` in gate `0` is a copy of wire `b` in gate `0`, so we store `(1, 0)` for wire `a`
and `(0, 0)` for wire `b`. Similarly, wire `c` in gate `0` is a copy of wire `a` in gate `3`, so we store `(0, 3)`
In the example above, wire `a` in gate `0` is a copy of wire `b` in gate `0`, so we store `(1, 0)` for wire `a`
and `(0, 0)` for wire `b`. Similarly, wire `c` in gate `0` is a copy of wire `a` in gate `3`, so we store `(0, 3)`
for wire `c` and `(2,0)` for wire `a`. The following picture shows the full positions:
![gate_explanation_02.PNG](attachments/gate_explanation_02.png)
Now, you can create any circuit on your own and run PLONK on it.
> [!TIP]
> If you are not familiar with the workings of PLONK, I recommend reading our slide
> If you are not familiar with the workings of PLONK, I recommend reading our slide
> [here](https://github.com/sota-zk-lab/zkp-documents/blob/main/presentations/plonk_implementation.pptx)
### Run
This library comes with some unit and integration tests. Run these tests with this command:
```
cargo test
```
You can view each round in generating proof step and verifying step does by:
```
cargo test -- --nocapture
```
## References
[Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of Knowledge](https://eprint.iacr.org/2019/953.pdf)<br/>
Ariel Gabizon, Zachary J. Williamson, Oana Ciobotaru
Expand Down
55 changes: 29 additions & 26 deletions plonk/src/challenge.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::marker::PhantomData;

use ark_bls12_381::Fr;
use ark_ff::UniformRand;
use ark_ff::{UniformRand, Zero};
use ark_serialize::{CanonicalSerialize, Write};
use rand::rngs::StdRng;
use rand::SeedableRng;
use ark_std::rand::rngs::StdRng;
use ark_std::rand::SeedableRng;
use sha2::Digest;

use kzg::commitment::KzgCommitment;
Expand All @@ -17,27 +17,26 @@ pub struct ChallengeGenerator<T: Digest + Default> {
data: Option<Vec<u8>>,
generated: bool,

#[allow(dead_code)]
/// Phantom data for annotation purposes.
// Phantom data for annotation purposes.
_phantom_data: PhantomData<T>,
}

impl<T: Digest + Default> ChallengeGenerator<T> {
/// Creates a new `ChallengeGenerator` instance from a list of commitments.
/// Creates a new `ChallengeGenerator` from a slice of KZG commitments.
///
/// # Parameters
/// # Arguments
///
/// - `kzg_commitment`: A slice containing the commitments.
/// * `kzg_commitments` - A slice of KZG commitments used to initialize the generator.
///
/// # Returns
///
/// A new `ChallengeGenerator` instance.
pub fn from_commitment(kzg_commitment: &[KzgCommitment]) -> Self {
let mut challenge_parse = Self::default();
for commitment in kzg_commitment {
challenge_parse.feed(commitment);
/// A `ChallengeGenerator` initialized with the provided commitments.
pub fn from_commitments(kzg_commitments: &[KzgCommitment]) -> Self {
let mut challenge_generator = Self::default();
for commitment in kzg_commitments {
challenge_generator.feed(commitment);
}
challenge_parse
challenge_generator
}
}

Expand All @@ -63,9 +62,11 @@ impl<T: Digest + Default> ChallengeGenerator<T> {
panic!("I'm hungry! Feed me something first");
}
self.generated = true;
let mut seed: [u8; 8] = Default::default();
seed.copy_from_slice(&self.data.clone().unwrap_or_default()[0..8]);
let seed = u64::from_le_bytes(seed);
let seed = self
.data
.clone()
.map(|data| u64::from_le_bytes(data[..8].try_into().unwrap()))
.expect("No data to generate seed from");
StdRng::seed_from_u64(seed)
}

Expand All @@ -80,8 +81,11 @@ impl<T: Digest + Default> ChallengeGenerator<T> {
/// An array of generated challenges.
pub fn generate_challenges<const N: usize>(&mut self) -> [Fr; N] {
let mut rng = self.generate_rng_with_seed();
let points = [0; N];
points.map(|_| Fr::rand(&mut rng))
let mut points = [Fr::zero(); N];
for point in &mut points {
*point = Fr::rand(&mut rng);
}
points
}
}

Expand All @@ -92,7 +96,7 @@ struct HashMarshaller<'a, H: Digest>(&'a mut H);
impl<'a, H: Digest> Write for HashMarshaller<'a, H> {
#[inline]
fn write(&mut self, buf: &[u8]) -> ark_std::io::Result<usize> {
Digest::update(self.0, buf);
self.0.update(buf);
Ok(buf.len())
}

Expand All @@ -104,10 +108,9 @@ impl<'a, H: Digest> Write for HashMarshaller<'a, H> {

#[cfg(test)]
mod tests {
use std::ops::Mul;

use ark_ec::{AffineRepr, CurveGroup};
use sha2::Sha256;
use std::ops::Mul;

use crate::types::G1Point;

Expand All @@ -119,16 +122,16 @@ mod tests {
let commitment2 = KzgCommitment(G1Point::generator().mul(Fr::from(2)).into_affine());
let commitments1: [KzgCommitment; 2] = [commitment1.clone(), commitment2.clone()];
let [a, aa, aaa] =
ChallengeGenerator::<Sha256>::from_commitment(&commitments1).generate_challenges();
ChallengeGenerator::<Sha256>::from_commitments(&commitments1).generate_challenges();

let commitments2: [KzgCommitment; 1] = [commitment2.clone()];
let [b] =
ChallengeGenerator::<Sha256>::from_commitment(&commitments2).generate_challenges();
ChallengeGenerator::<Sha256>::from_commitments(&commitments2).generate_challenges();
assert_ne!(a, b, "should be different");

let commitments3: [KzgCommitment; 2] = [commitment1.clone(), commitment2.clone()];
let [c, cc, ccc] =
ChallengeGenerator::<Sha256>::from_commitment(&commitments3).generate_challenges();
ChallengeGenerator::<Sha256>::from_commitments(&commitments3).generate_challenges();
assert_eq!(a, c, "should be equal");
assert_eq!(aa, cc, "should be equal");
assert_eq!(aaa, ccc, "should be equal");
Expand All @@ -139,7 +142,7 @@ mod tests {
fn safe_guard() {
let commitment1 = KzgCommitment(G1Point::generator().mul(Fr::from(1)).into_affine());
let commitments1: [KzgCommitment; 1] = [commitment1.clone()];
let mut generator = ChallengeGenerator::<Sha256>::from_commitment(&commitments1);
let mut generator = ChallengeGenerator::<Sha256>::from_commitments(&commitments1);
let [_a, _aa, _aaa] = generator.generate_challenges();
let [_a, _aa, _aaa] = generator.generate_challenges();
}
Expand Down
Loading

0 comments on commit c6d2ee1

Please sign in to comment.