Skip to content

Commit

Permalink
feat: plain zk prover and zk verifier working
Browse files Browse the repository at this point in the history
  • Loading branch information
florin5f committed Feb 14, 2025
1 parent 2cc64ec commit 01ccd2a
Show file tree
Hide file tree
Showing 37 changed files with 1,482 additions and 111 deletions.
2 changes: 1 addition & 1 deletion co-noir/co-builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ num-traits.workspace = true
serde.workspace = true
thiserror.workspace = true
tracing.workspace = true
rand.workspace = true

[dev-dependencies]
rand.workspace = true
13 changes: 13 additions & 0 deletions co-noir/co-builder/src/honk_curve.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use ark_ec::pairing::Pairing;
use ark_ff::{One, PrimeField};
use num_bigint::BigUint;
use std::str::FromStr;

// Des describes the PrimeField used for the Transcript
pub trait HonkCurve<Des: PrimeField>: Pairing {
const NUM_BASEFIELD_ELEMENTS: usize;
const NUM_SCALARFIELD_ELEMENTS: usize;
const SUBGROUP_SIZE: usize;

fn g1_affine_from_xy(x: Self::BaseField, y: Self::BaseField) -> Self::G1Affine;
fn g1_affine_to_xy(p: &Self::G1Affine) -> (Self::BaseField, Self::BaseField);
Expand All @@ -21,11 +23,14 @@ pub trait HonkCurve<Des: PrimeField>: Pairing {

// For the elliptic curve relation
fn get_curve_b() -> Self::ScalarField;

fn get_subgroup_generator() -> Self::ScalarField;
}

impl HonkCurve<ark_bn254::Fr> for ark_bn254::Bn254 {
const NUM_BASEFIELD_ELEMENTS: usize = 2;
const NUM_SCALARFIELD_ELEMENTS: usize = 1;
const SUBGROUP_SIZE: usize = 256;

fn g1_affine_from_xy(x: ark_bn254::Fq, y: ark_bn254::Fq) -> ark_bn254::G1Affine {
ark_bn254::G1Affine::new(x, y)
Expand Down Expand Up @@ -62,6 +67,14 @@ impl HonkCurve<ark_bn254::Fr> for ark_bn254::Bn254 {
// We are getting grumpkin::b, which is -17
-ark_bn254::Fr::from(17)
}

fn get_subgroup_generator() -> Self::ScalarField {
ark_bn254::Fr::from_str(
"3478517300119284901893091970156912948790432420133812234316178878452092729974",
)
.map_err(|_| eyre::eyre!("Failed to parse subgroup generator"))
.unwrap()
}
}

const NUM_LIMB_BITS: u32 = 68;
Expand Down
102 changes: 101 additions & 1 deletion co-noir/co-builder/src/polynomials/polynomial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use ark_ff::PrimeField;
use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, Polynomial as _};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use num_traits::Zero;

use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::ops::{AddAssign, Index, IndexMut, SubAssign};
use std::ops::{AddAssign, Index, IndexMut, MulAssign, SubAssign};

#[derive(Clone, Debug, Default)]
pub struct Polynomial<F> {
Expand Down Expand Up @@ -203,6 +204,63 @@ impl<F: PrimeField> Polynomial<F> {
let poly = DensePolynomial::from_coefficients_slice(&self.coefficients);
poly.evaluate(&point)
}
pub fn random(size: usize) -> Self {
let mut rng = rand::thread_rng();
let coefficients = (0..size).map(|_| F::rand(&mut rng)).collect();
Self { coefficients }
}

pub fn evaluate_mle(&self, evaluation_points: &[F]) -> F {
if self.coefficients.is_empty() {
return F::zero();
}

let n = evaluation_points.len();
let dim = (self.coefficients.len() - 1)
.next_power_of_two()
.trailing_zeros() as usize; // Round up to next power of 2

// To simplify handling of edge cases, we assume that the index space is always a power of 2
assert_eq!(self.coefficients.len(), 1 << n);

// We first fold over dim rounds l = 0,...,dim-1.
// in round l, n_l is the size of the buffer containing the Polynomial partially evaluated
// at u₀,..., u_l.
// In round 0, this is half the size of dim
let mut n_l = 1 << (dim - 1);
let mut tmp = vec![F::zero(); n_l];

// Note below: i * 2 + 1 + offset might equal virtual_size. This used to subtlely be handled by extra capacity
// padding (and there used to be no assert time checks, which this constant helps with).
for (i, val) in tmp.iter_mut().enumerate().take(n_l) {
*val = self.coefficients[i * 2]
+ evaluation_points[0] * (self.coefficients[i * 2 + 1] - self.coefficients[i * 2]);
}

// partially evaluate the dim-1 remaining points
for (l, val) in evaluation_points.iter().enumerate().take(dim).skip(1) {
n_l = 1 << (dim - l - 1);

for i in 0..n_l {
tmp[i] = tmp[i * 2] + *val * (tmp[i * 2 + 1] - tmp[i * 2]);
}
}
// for l in 1..dim {
// n_l = 1 << (dim - l - 1);
// u_l = evaluation_points[l];
// for i in 0..n_l {
// tmp[i] = tmp[i * 2] + u_l * (tmp[i * 2 + 1] - tmp[i * 2]);
// }
// }
let mut result = tmp[0];

// We handle the "trivial" dimensions which are full of zeros.
for &point in &evaluation_points[dim..n] {
result *= F::one() - point;
}

result
}
}

impl<F> Index<usize> for Polynomial<F> {
Expand Down Expand Up @@ -242,3 +300,45 @@ impl<F: PrimeField> SubAssign<&[F]> for Polynomial<F> {
}
}
}

impl<F: PrimeField> MulAssign<F> for Polynomial<F> {
fn mul_assign(&mut self, rhs: F) {
for l in self.coefficients.iter_mut() {
*l *= rhs;
}
}
}

pub struct RowDisablingPolynomial<F: PrimeField> {
pub eval_at_0: F,
pub eval_at_1: F,
}

impl<F: PrimeField> Default for RowDisablingPolynomial<F> {
fn default() -> Self {
Self {
eval_at_0: F::one(),
eval_at_1: F::one(),
}
}
}
impl<F: PrimeField> RowDisablingPolynomial<F> {
pub fn update_evaluations(&mut self, round_challenge: F, round_idx: usize) {
if round_idx == 1 {
self.eval_at_0 = F::zero();
}
if round_idx >= 2 {
self.eval_at_1 *= round_challenge;
}
}

pub fn evaluate_at_challenge(multivariate_challenge: &[F], log_circuit_size: usize) -> F {
let mut evaluation_at_multivariate_challenge = F::one();

for val in multivariate_challenge.iter().take(log_circuit_size).skip(2) {
evaluation_at_multivariate_challenge *= val;
}

F::one() - evaluation_at_multivariate_challenge
}
}
2 changes: 1 addition & 1 deletion co-noir/co-builder/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub use crate::honk_curve::HonkCurve;
pub use crate::keys::proving_key::ProvingKey;
pub use crate::keys::verification_key::VerifyingKey;
pub use crate::keys::verification_key::VerifyingKeyBarretenberg;
pub use crate::polynomials::polynomial::Polynomial;
pub use crate::polynomials::polynomial::{Polynomial, RowDisablingPolynomial};
pub use crate::polynomials::polynomial_types::Polynomials;
pub use crate::polynomials::polynomial_types::{
PrecomputedEntities, ProverWitnessEntities, PRECOMPUTED_ENTITIES_SIZE,
Expand Down
4 changes: 3 additions & 1 deletion co-noir/co-noir/examples/co_noir_party0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ fn main() -> Result<()> {
let inputs = co_noir::parse_input(dir.join("poseidon/Prover.toml"), &program_artifact)?;

let recursive = true;
let has_zk = false;

// parse crs
let crs_size = co_noir::compute_circuit_size::<Bn254>(&constraint_system, recursive)?;
Expand Down Expand Up @@ -95,7 +96,8 @@ fn main() -> Result<()> {
let (proof, _) = Rep3CoUltraHonk::<_, _, Poseidon2Sponge>::prove(net, pk, &prover_crs)?;

// verify proof
assert!(UltraHonk::<_, Poseidon2Sponge>::verify(proof, vk).context("while verifying proof")?);
assert!(UltraHonk::<_, Poseidon2Sponge>::verify(proof, vk, has_zk)
.context("while verifying proof")?);

Ok(())
}
4 changes: 3 additions & 1 deletion co-noir/co-noir/examples/co_noir_party1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ fn main() -> Result<()> {
let constraint_system = Utils::get_constraint_system_from_artifact(&program_artifact, true);

let recursive = true;
let has_zk = false;

// parse crs
let crs_size = co_noir::compute_circuit_size::<Bn254>(&constraint_system, recursive)?;
Expand All @@ -87,7 +88,8 @@ fn main() -> Result<()> {
let (proof, _) = Rep3CoUltraHonk::<_, _, Poseidon2Sponge>::prove(net, pk, &prover_crs)?;

// verify proof
assert!(UltraHonk::<_, Poseidon2Sponge>::verify(proof, vk).context("while verifying proof")?);
assert!(UltraHonk::<_, Poseidon2Sponge>::verify(proof, vk, has_zk)
.context("while verifying proof")?);

Ok(())
}
4 changes: 3 additions & 1 deletion co-noir/co-noir/examples/co_noir_party2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ fn main() -> Result<()> {
let constraint_system = Utils::get_constraint_system_from_artifact(&program_artifact, true);

let recursive = true;
let has_zk = false;

// parse crs
let crs_size = co_noir::compute_circuit_size::<Bn254>(&constraint_system, recursive)?;
Expand All @@ -87,7 +88,8 @@ fn main() -> Result<()> {
let (proof, _) = Rep3CoUltraHonk::<_, _, Poseidon2Sponge>::prove(net, pk, &prover_crs)?;

// verify proof
assert!(UltraHonk::<_, Poseidon2Sponge>::verify(proof, vk).context("while verifying proof")?);
assert!(UltraHonk::<_, Poseidon2Sponge>::verify(proof, vk, has_zk)
.context("while verifying proof")?);

Ok(())
}
13 changes: 9 additions & 4 deletions co-noir/co-noir/src/bin/co-noir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,9 @@ pub struct VerifyCli {
#[arg(long)]
#[serde(skip_serializing_if = "::std::option::Option::is_none")]
pub crs: Option<PathBuf>,
/// Verify a ZK proof
#[arg(long)]
pub has_zk: bool,
}

/// Config for `verify`
Expand All @@ -622,6 +625,8 @@ pub struct VerifyConfig {
pub vk: PathBuf,
/// The path to the verifier crs file
pub crs: PathBuf,
/// Verify a ZK proof
pub has_zk: bool,
}

/// Cli arguments for `verify`
Expand Down Expand Up @@ -1683,6 +1688,7 @@ fn run_verify(config: VerifyConfig) -> color_eyre::Result<ExitCode> {
let vk_path: PathBuf = config.vk;
let crs_path = config.crs;
let hasher = config.hasher;
let has_zk = config.has_zk;

// parse proof file
let proof_u8 = std::fs::read(&proof).context("while reading proof file")?;
Expand All @@ -1701,11 +1707,10 @@ fn run_verify(config: VerifyConfig) -> color_eyre::Result<ExitCode> {
tracing::info!("Starting proof verification...");
let start = Instant::now();
let res = match hasher {
TranscriptHash::POSEIDON => {
UltraHonk::<_, Poseidon2Sponge>::verify(proof, vk).context("while verifying proof")?
}
TranscriptHash::POSEIDON => UltraHonk::<_, Poseidon2Sponge>::verify(proof, vk, has_zk)
.context("while verifying proof")?,
TranscriptHash::KECCAK => {
UltraHonk::<_, Keccak256>::verify(proof, vk).context("while verifying proof")?
UltraHonk::<_, Keccak256>::verify(proof, vk, has_zk).context("while verifying proof")?
}
};
let duration_ms = start.elapsed().as_micros() as f64 / 1000.;
Expand Down
9 changes: 6 additions & 3 deletions co-noir/co-noir/src/bin/plaindriver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ fn main() -> color_eyre::Result<ExitCode> {
let circuit_path = config.circuit;
let hasher = config.hasher;
let out_dir = config.out_dir;
let has_zk = false;

// Read circuit
let program_artifact = Utils::get_program_artifact_from_file(&circuit_path)
Expand Down Expand Up @@ -241,9 +242,11 @@ fn main() -> color_eyre::Result<ExitCode> {

// Verify the proof
let is_valid = match hasher {
TranscriptHash::POSEIDON => UltraHonk::<_, Poseidon2Sponge>::verify(proof, verifying_key)
.context("While verifying proof")?,
TranscriptHash::KECCAK => UltraHonk::<_, Keccak256>::verify(proof, verifying_key)
TranscriptHash::POSEIDON => {
UltraHonk::<_, Poseidon2Sponge>::verify(proof, verifying_key, has_zk)
.context("While verifying proof")?
}
TranscriptHash::KECCAK => UltraHonk::<_, Keccak256>::verify(proof, verifying_key, has_zk)
.context("While verifying proof")?,
};

Expand Down
3 changes: 2 additions & 1 deletion co-noir/co-ultrahonk/tests/plaindriver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fn plaindriver_test<H: TranscriptHasher<TranscriptFieldType>>(
) {
const CRS_PATH_G1: &str = "../co-builder/src/crs/bn254_g1.dat";
const CRS_PATH_G2: &str = "../co-builder/src/crs/bn254_g2.dat";
let has_zk = false;

let constraint_system = Utils::get_constraint_system_from_file(circuit_file, true).unwrap();
let witness = Utils::get_witness_from_file(witness_file).unwrap();
Expand Down Expand Up @@ -54,7 +55,7 @@ fn plaindriver_test<H: TranscriptHasher<TranscriptFieldType>>(
let read_proof = HonkProof::from_buffer(&read_proof_u8).unwrap();
assert_eq!(proof, read_proof);

let is_valid = UltraHonk::<_, H>::verify(proof, verifying_key).unwrap();
let is_valid = UltraHonk::<_, H>::verify(proof, verifying_key, has_zk).unwrap();
assert!(is_valid);
}

Expand Down
2 changes: 2 additions & 0 deletions co-noir/ultrahonk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ acir.workspace = true
ark-bn254.workspace = true
ark-ec.workspace = true
ark-ff.workspace = true
ark-poly.workspace = true
co-builder = { version = "0.2.0", path = "../co-builder" }
mpc-core = { version = "0.7.0", path = "../../mpc-core" }
eyre.workspace = true
Expand All @@ -23,6 +24,7 @@ num-bigint.workspace = true
serde_json.workspace = true
sha3 = { workspace = true }
tracing.workspace = true
rand.workspace = true

[dev-dependencies]
rand.workspace = true
2 changes: 1 addition & 1 deletion co-noir/ultrahonk/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ cmake --preset clang16 -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
cmake --build .
```

The prover in this repository, i.e., ``UltraHonk::prove`` in `src/prover.rs`, is compatible with `UltraProver_<UltraFlavor>` in Barretenberg. Similar, the ``Ultrahnok::verify`` verifier in `src/verifier.rs` is compatible with `UltraVerifier_<UltraFlavor>` in Barretenberg.
The prover in this repository, i.e., ``UltraHonk::prove`` in `src/prover.rs`, is compatible with `UltraProver_<UltraFlavor>` in Barretenberg. Similar, the ``UltraHonk::verify`` verifier in `src/verifier.rs` is compatible with `UltraVerifier_<UltraFlavor>` in Barretenberg.

Currently, the circuit builder related code in `src/parse/` is only compatible with basic field arithmetic gates from Noir, stay tuned for more features.

Expand Down
1 change: 1 addition & 0 deletions co-noir/ultrahonk/src/decider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub(crate) mod barycentric;
pub(crate) mod prover;
pub(crate) mod relations;
pub(crate) mod shplemini;
pub(crate) mod small_subgroup_ipa;
pub(crate) mod sumcheck;
pub(crate) mod types;
pub(crate) mod univariate;
Expand Down
Loading

0 comments on commit 01ccd2a

Please sign in to comment.