Skip to content

Commit

Permalink
feat: Add builder for ultrahonk and fix prover
Browse files Browse the repository at this point in the history
  • Loading branch information
rw0x0 authored and dkales committed Oct 3, 2024
1 parent 9f2911f commit 929dd1d
Show file tree
Hide file tree
Showing 38 changed files with 5,174 additions and 663 deletions.
3 changes: 3 additions & 0 deletions co-noir/ultrahonk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ license.workspace = true
rust-version.workspace = true

[dependencies]
acir.workspace = true
ark-ec.workspace = true
ark-ff.workspace = true
ark-serialize.workspace = true
Expand All @@ -18,8 +19,10 @@ byteorder.workspace = true
eyre.workspace = true
itertools.workspace = true
lazy_static = "1.5"
noirc-artifacts.workspace = true
num-bigint.workspace = true
num-traits.workspace = true
serde_json.workspace = true
tracing.workspace = true
thiserror.workspace = true
rand.workspace = true
Binary file removed co-noir/ultrahonk/example/poseidon/poseidon.gz
Binary file not shown.
1 change: 0 additions & 1 deletion co-noir/ultrahonk/example/poseidon/poseidon.json

This file was deleted.

11 changes: 6 additions & 5 deletions co-noir/ultrahonk/src/decider/barycentric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ impl Barycentric {
) -> Vec<F> {
let mut res = Vec::with_capacity(domain_size);

for (i, r) in res.iter_mut().enumerate() {
*r = F::one();
for i in 0..domain_size {
let mut r = F::one();
for j in 0..domain_size {
if j != i {
*r *= big_domain[i] - big_domain[j];
r *= big_domain[i] - big_domain[j];
}
}
res.push(r);
}
res
}
Expand All @@ -52,12 +53,12 @@ impl Barycentric {
assert_eq!(big_domain_size, std::cmp::max(domain_size, num_evals));

let res_size = domain_size * num_evals;
let mut res = Vec::with_capacity(res_size);
let mut res = vec![F::zero(); res_size]; // default init to 0 since below does not init all elements

for k in domain_size..num_evals {
for j in 0..domain_size {
let inv = lagrange_denominators[j] * (big_domain[k] - big_domain[j]);
res.push(inv);
res[k * domain_size + j] = inv;
}
}

Expand Down
65 changes: 59 additions & 6 deletions co-noir/ultrahonk/src/decider/polynomial.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,43 @@
use std::ops::{AddAssign, Index, IndexMut};

use ark_ff::PrimeField;
use std::ops::{AddAssign, Index, IndexMut};

#[derive(Clone, Debug, Default)]
pub struct Polynomial<F: PrimeField> {
pub(crate) coefficients: Vec<F>,
}

pub struct ShiftedPoly<'a, F: PrimeField> {
pub(crate) coefficients: &'a [F],
zero: F, // TODO is there are better solution
}

impl<'a, F: PrimeField> ShiftedPoly<'a, F> {
pub(crate) fn to_vec(&self) -> Vec<F> {
let mut res = Vec::with_capacity(self.coefficients.len() + 1);
for c in self.coefficients.iter() {
res.push(*c);
}
res.push(self.zero);
res
}

pub fn as_ref(&self) -> &[F] {
self.coefficients
}
}

impl<'a, F: PrimeField> Index<usize> for ShiftedPoly<'a, F> {
type Output = F;

fn index(&self, index: usize) -> &Self::Output {
if index == self.coefficients.len() {
&self.zero
} else {
&self.coefficients[index]
}
}
}

impl<F: PrimeField> Polynomial<F> {
pub fn new(coefficients: Vec<F>) -> Self {
Self { coefficients }
Expand All @@ -22,6 +53,10 @@ impl<F: PrimeField> Polynomial<F> {
self.coefficients.iter()
}

pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut F> {
self.coefficients.iter_mut()
}

pub fn len(&self) -> usize {
self.coefficients.len()
}
Expand All @@ -38,6 +73,22 @@ impl<F: PrimeField> Polynomial<F> {
len
}

pub fn as_ref(&self) -> &[F] {
&self.coefficients
}

pub fn as_mut(&mut self) -> &mut [F] {
&mut self.coefficients
}

pub fn resize(&mut self, size: usize, value: F) {
self.coefficients.resize(size, value);
}

pub fn into_vec(self) -> Vec<F> {
self.coefficients
}

/**
* @brief Divides p(X) by (X-r) in-place.
*/
Expand Down Expand Up @@ -102,11 +153,13 @@ impl<F: PrimeField> Polynomial<F> {
}

// Can only shift by 1
pub(crate) fn shifted(&self) -> &[F] {
pub(crate) fn shifted(&self) -> ShiftedPoly<F> {
assert!(!self.coefficients.is_empty());
assert!(self.coefficients[0].is_zero());
assert!(self.coefficients.last().unwrap().is_zero());
&self.coefficients[1..]
ShiftedPoly {
coefficients: &self.coefficients[1..],
zero: F::zero(),
}
}
}

Expand All @@ -128,7 +181,7 @@ impl<F: PrimeField> AddAssign<&[F]> for Polynomial<F> {
fn add_assign(&mut self, rhs: &[F]) {
if rhs.len() > self.coefficients.len() {
panic!("Polynomial too large, this should not have happened");
self.coefficients.resize(rhs.len(), F::zero());
// self.coefficients.resize(rhs.len(), F::zero());
}
for (l, r) in self.coefficients.iter_mut().zip(rhs.iter()) {
*l += *r;
Expand Down
24 changes: 13 additions & 11 deletions co-noir/ultrahonk/src/decider/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
honk_curve::HonkCurve,
prover::HonkProofResult,
transcript::{TranscriptFieldType, TranscriptType},
types::{HonkProof, ProvingKey},
types::{HonkProof, ProverCrs},
};
use std::marker::PhantomData;

Expand All @@ -23,14 +23,14 @@ impl<P: HonkCurve<TranscriptFieldType>> Decider<P> {
fn compute_opening_proof(
opening_claim: ZeroMorphOpeningClaim<P::ScalarField>,
transcript: &mut TranscriptType,
proving_key: &ProvingKey<P>,
crs: &ProverCrs<P>,
) -> HonkProofResult<()> {
let mut quotient = opening_claim.polynomial;
let pair = opening_claim.opening_pair;
quotient[0] -= pair.evaluation;
// Computes the coefficients for the quotient polynomial q(X) = (p(X) - v) / (X - r) through an FFT
quotient.factor_roots(&pair.challenge);
let quotient_commitment = crate::commit(&quotient.coefficients, &proving_key.crs)?;
let quotient_commitment = crate::commit(&quotient.coefficients, crs)?;
// TODO(#479): for now we compute the KZG commitment directly to unify the KZG and IPA interfaces but in the
// future we might need to adjust this to use the incoming alternative to work queue (i.e. variation of
// pthreads) or even the work queue itself
Expand All @@ -46,10 +46,10 @@ impl<P: HonkCurve<TranscriptFieldType>> Decider<P> {
fn execute_relation_check_rounds(
&self,
transcript: &mut TranscriptType,
proving_key: &ProvingKey<P>,
circuit_size: u32,
) -> SumcheckOutput<P::ScalarField> {
// This is just Sumcheck.prove
self.sumcheck_prove(transcript, proving_key)
self.sumcheck_prove(transcript, circuit_size)
}

/**
Expand All @@ -61,27 +61,29 @@ impl<P: HonkCurve<TranscriptFieldType>> Decider<P> {
fn execute_pcs_rounds(
&mut self,
transcript: &mut TranscriptType,
proving_key: &ProvingKey<P>,
circuit_size: u32,
crs: &ProverCrs<P>,
sumcheck_output: SumcheckOutput<P::ScalarField>,
) -> HonkProofResult<()> {
let prover_opening_claim =
self.zeromorph_prove(transcript, proving_key, sumcheck_output)?;
Self::compute_opening_proof(prover_opening_claim, transcript, proving_key)
self.zeromorph_prove(transcript, circuit_size, crs, sumcheck_output)?;
Self::compute_opening_proof(prover_opening_claim, transcript, crs)
}

pub fn prove(
mut self,
proving_key: &ProvingKey<P>,
circuit_size: u32,
crs: &ProverCrs<P>,
mut transcript: TranscriptType,
) -> HonkProofResult<HonkProof<TranscriptFieldType>> {
tracing::trace!("Decider prove");

// Run sumcheck subprotocol.
let sumcheck_output = self.execute_relation_check_rounds(&mut transcript, proving_key);
let sumcheck_output = self.execute_relation_check_rounds(&mut transcript, circuit_size);

// Fiat-Shamir: rho, y, x, z
// Execute Zeromorph multilinear PCS
self.execute_pcs_rounds(&mut transcript, proving_key, sumcheck_output)?;
self.execute_pcs_rounds(&mut transcript, circuit_size, crs, sumcheck_output)?;

Ok(transcript.get_proof())
}
Expand Down
36 changes: 18 additions & 18 deletions co-noir/ultrahonk/src/decider/relations/auxiliary_relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl<F: PrimeField> Relation<F> for AuxiliaryRelation {

fn skip(input: &ProverUnivariates<F>) -> bool {
<Self as Relation<F>>::check_skippable();
input.polys.precomputed.q_aux().is_zero()
input.precomputed.q_aux().is_zero()
}

/**
Expand Down Expand Up @@ -152,23 +152,23 @@ impl<F: PrimeField> Relation<F> for AuxiliaryRelation {
let eta_two = &relation_parameters.eta_2;
let eta_three = &relation_parameters.eta_3;

let w_1 = input.polys.witness.w_l();
let w_2 = input.polys.witness.w_r();
let w_3 = input.polys.witness.w_o();
let w_4 = input.memory.w_4();
let w_1_shift = input.polys.shifted_witness.w_l();
let w_2_shift = input.polys.shifted_witness.w_r();
let w_3_shift = input.polys.shifted_witness.w_o();
let w_4_shift = input.polys.shifted_witness.w_4();

let q_1 = input.polys.precomputed.q_l();
let q_2 = input.polys.precomputed.q_r();
let q_3 = input.polys.precomputed.q_o();
let q_4 = input.polys.precomputed.q_4();
let q_m = input.polys.precomputed.q_m();
let q_c = input.polys.precomputed.q_c();
let q_arith = input.polys.precomputed.q_arith();
let q_aux = input.polys.precomputed.q_aux();
let w_1 = input.witness.w_l();
let w_2 = input.witness.w_r();
let w_3 = input.witness.w_o();
let w_4 = input.witness.w_4();
let w_1_shift = input.shifted_witness.w_l();
let w_2_shift = input.shifted_witness.w_r();
let w_3_shift = input.shifted_witness.w_o();
let w_4_shift = input.shifted_witness.w_4();

let q_1 = input.precomputed.q_l();
let q_2 = input.precomputed.q_r();
let q_3 = input.precomputed.q_o();
let q_4 = input.precomputed.q_4();
let q_m = input.precomputed.q_m();
let q_c = input.precomputed.q_c();
let q_arith = input.precomputed.q_arith();
let q_aux = input.precomputed.q_aux();

let limb_size = F::from(BigUint::one() << 68);
let sublimb_shift = F::from(1u64 << 14);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl<F: PrimeField> Relation<F> for DeltaRangeConstraintRelation {

fn skip(input: &ProverUnivariates<F>) -> bool {
<Self as Relation<F>>::check_skippable();
input.polys.precomputed.q_delta_range().is_zero()
input.precomputed.q_delta_range().is_zero()
}

/**
Expand All @@ -97,12 +97,12 @@ impl<F: PrimeField> Relation<F> for DeltaRangeConstraintRelation {
) {
tracing::trace!("Accumulate DeltaRangeConstraintRelation");

let w_1 = input.polys.witness.w_l();
let w_2 = input.polys.witness.w_r();
let w_3 = input.polys.witness.w_o();
let w_4 = input.memory.w_4();
let w_1_shift = input.polys.shifted_witness.w_l();
let q_delta_range = input.polys.precomputed.q_delta_range();
let w_1 = input.witness.w_l();
let w_2 = input.witness.w_r();
let w_3 = input.witness.w_o();
let w_4 = input.witness.w_4();
let w_1_shift = input.shifted_witness.w_l();
let q_delta_range = input.precomputed.q_delta_range();
let minus_one = -F::one();
let minus_two = -F::from(2u64);

Expand Down
22 changes: 11 additions & 11 deletions co-noir/ultrahonk/src/decider/relations/elliptic_relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl EllipticRelation {
if !Self::SKIPPABLE {
panic!("Cannot skip this relation");
}
input.polys.precomputed.q_elliptic().is_zero()
input.precomputed.q_elliptic().is_zero()
}

/**
Expand All @@ -76,17 +76,17 @@ impl EllipticRelation {
// replace old addition relations with these ones and
// remove endomorphism coefficient in ecc add gate(not used))

let x_1 = input.polys.witness.w_r();
let y_1 = input.polys.witness.w_o();
let x_1 = input.witness.w_r();
let y_1 = input.witness.w_o();

let x_2 = input.polys.shifted_witness.w_l();
let y_2 = input.polys.shifted_witness.w_4();
let x_3 = input.polys.shifted_witness.w_o();
let y_3 = input.polys.shifted_witness.w_r();
let x_2 = input.shifted_witness.w_l();
let y_2 = input.shifted_witness.w_4();
let y_3 = input.shifted_witness.w_o();
let x_3 = input.shifted_witness.w_r();

let q_sign = input.polys.precomputed.q_l();
let q_elliptic = input.polys.precomputed.q_elliptic();
let q_is_double = input.polys.precomputed.q_m();
let q_sign = input.precomputed.q_l();
let q_elliptic = input.precomputed.q_elliptic();
let q_is_double = input.precomputed.q_m();

// Contribution (1) point addition, x-coordinate check
// q_elliptic * (x3 + x2 + x1)(x2 - x1)(x2 - x1) - y2^2 - y1^2 + 2(y2y1)*q_sign = 0
Expand Down Expand Up @@ -117,7 +117,7 @@ impl EllipticRelation {
// (x3 + x1 + x1) (4y1*y1) - 9 * x1 * x1 * x1 * x1 = 0
// N.B. we're using the equivalence x1*x1*x1 === y1*y1 - curve_b to reduce degree by 1

let curve_b = P::get_curve_b_as_scalarfield(); // here we need the extra constraint on the Curve
let curve_b = P::get_curve_b(); // here we need the extra constraint on the Curve
let x1_mul_3 = x_1.to_owned() + x_1 + x_1;
let x_pow_4_mul_3 = (y1_sqr.to_owned() - &curve_b) * &x1_mul_3;
let mut y1_sqr_mul_4 = y1_sqr.double();
Expand Down
Loading

0 comments on commit 929dd1d

Please sign in to comment.