Skip to content

Commit

Permalink
feat: Make builder generic for both shares and plain, add shared prov…
Browse files Browse the repository at this point in the history
…ing key and start with MPC prover (#193)
  • Loading branch information
rw0x0 committed Sep 26, 2024
1 parent ee932bf commit 54867af
Show file tree
Hide file tree
Showing 50 changed files with 1,479 additions and 784 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"co-circom/co-plonk",
"co-noir/co-acvm",
"co-noir/ultrahonk",
"co-noir/co-ultrahonk",
"mpc-core",
"mpc-net",
"tests",
Expand Down Expand Up @@ -85,6 +86,7 @@ tokio = { version = "1.34.0", features = [
toml = "0.8.13"
tracing = { version = "0.1.40" }
tracing-subscriber = "0.3"
ultrahonk = { version = "0.1.0", path = "co-noir/ultrahonk" }

# This profile can be used for CI in pull requests.
[profile.ci-dev]
Expand Down
2 changes: 0 additions & 2 deletions co-noir/co-acvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ intmap.workspace = true
mpc-core.workspace = true
noirc-abi.workspace = true
noirc-artifacts.workspace = true
num-bigint.workspace = true
num-traits.workspace = true
thiserror.workspace = true
tracing.workspace = true

Expand Down
19 changes: 19 additions & 0 deletions co-noir/co-ultrahonk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "co-ultrahonk"
version = "0.1.0"
publish.workspace = true
authors.workspace = true
edition.workspace = true
repository.workspace = true
homepage.workspace = true
license.workspace = true
rust-version.workspace = true

[dependencies]
ark-ec.workspace = true
ark-ff.workspace = true
ark-bn254.workspace = true
eyre.workspace = true
mpc-core.workspace = true
tracing.workspace = true
ultrahonk.workspace = true
19 changes: 19 additions & 0 deletions co-noir/co-ultrahonk/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pub(crate) mod parse;
pub mod prelude;
pub(crate) mod prover;
pub(crate) mod types;

use ark_ec::pairing::Pairing;
use mpc_core::protocols::plain::PlainDriver;
use parse::builder_variable::SharedBuilderVariable;

impl<P: Pairing> SharedBuilderVariable<PlainDriver<P::ScalarField>, P> {
pub fn promote_public_witness_vector(
witness: Vec<P::ScalarField>,
) -> Vec<SharedBuilderVariable<PlainDriver<P::ScalarField>, P>> {
witness
.into_iter()
.map(SharedBuilderVariable::Public)
.collect()
}
}
92 changes: 92 additions & 0 deletions co-noir/co-ultrahonk/src/parse/builder_variable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use ark_ec::pairing::Pairing;
use mpc_core::traits::PrimeFieldMpcProtocol;
use std::fmt::Debug;
use ultrahonk::prelude::UltraCircuitVariable;

pub enum SharedBuilderVariable<T, P>
where
P: Pairing,
T: PrimeFieldMpcProtocol<P::ScalarField>,
{
Public(P::ScalarField),
Shared(T::FieldShare),
}

impl<T, P> SharedBuilderVariable<T, P>
where
P: Pairing,
T: PrimeFieldMpcProtocol<P::ScalarField>,
{
pub fn get_as_shared(&self, driver: &T) -> T::FieldShare {
match self {
SharedBuilderVariable::Public(value) => driver.promote_to_trivial_share(*value),
SharedBuilderVariable::Shared(value) => value.to_owned(),
}
}
}

impl<T, P> Clone for SharedBuilderVariable<T, P>
where
P: Pairing,
T: PrimeFieldMpcProtocol<P::ScalarField>,
{
fn clone(&self) -> Self {
match self {
SharedBuilderVariable::Public(value) => Self::Public(*value),
SharedBuilderVariable::Shared(value) => Self::Shared(value.clone()),
}
}
}

impl<T, P> PartialEq for SharedBuilderVariable<T, P>
where
P: Pairing,
T: PrimeFieldMpcProtocol<P::ScalarField>,
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(SharedBuilderVariable::Public(a), SharedBuilderVariable::Public(b)) => a == b,
(SharedBuilderVariable::Shared(a), SharedBuilderVariable::Shared(b)) => a == b,
_ => false,
}
}
}

impl<T, P> Debug for SharedBuilderVariable<T, P>
where
P: Pairing,
T: PrimeFieldMpcProtocol<P::ScalarField>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SharedBuilderVariable::Public(value) => write!(f, "Public({:?})", value),
SharedBuilderVariable::Shared(value) => write!(f, "Shared({:?})", value),
}
}
}

impl<T, P> UltraCircuitVariable<P::ScalarField> for SharedBuilderVariable<T, P>
where
P: Pairing,
T: PrimeFieldMpcProtocol<P::ScalarField>,
{
type Shared = T::FieldShare;

fn from_public(value: P::ScalarField) -> Self {
Self::Public(value)
}

fn is_public(&self) -> bool {
match self {
SharedBuilderVariable::Public(_) => true,
SharedBuilderVariable::Shared(_) => false,
}
}

fn public_into_field(self) -> P::ScalarField {
match self {
SharedBuilderVariable::Public(val) => val,
SharedBuilderVariable::Shared(_) => panic!("Expected public value"),
}
}
}
14 changes: 14 additions & 0 deletions co-noir/co-ultrahonk/src/parse/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
pub(crate) mod builder_variable;
pub(crate) mod proving_key;
pub(crate) mod types;

use ark_ec::pairing::Pairing;
use builder_variable::SharedBuilderVariable;
use mpc_core::protocols::{plain::PlainDriver, rep3::Rep3Protocol};
use ultrahonk::prelude::GenericUltraCircuitBuilder;

pub type CoUltraCircuitBuilder<T, P> = GenericUltraCircuitBuilder<P, SharedBuilderVariable<T, P>>;

pub type PlainCoBuilder<P> = CoUltraCircuitBuilder<PlainDriver<<P as Pairing>::ScalarField>, P>;
pub type Rep3CoBuilder<P, N> =
CoUltraCircuitBuilder<Rep3Protocol<<P as Pairing>::ScalarField, N>, P>;
134 changes: 134 additions & 0 deletions co-noir/co-ultrahonk/src/parse/proving_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use super::CoUltraCircuitBuilder;
use crate::parse::types::TraceData;
use crate::types::Polynomials;
use crate::types::ProverWitnessEntities;
use crate::types::ProvingKey;
use ark_ec::pairing::Pairing;
use ark_ff::One;
use eyre::Result;
use mpc_core::traits::PrimeFieldMpcProtocol;
use std::marker::PhantomData;
use ultrahonk::prelude::ProverCrs;
use ultrahonk::prelude::ProvingKey as PlainProvingKey;
use ultrahonk::prelude::UltraCircuitVariable;

impl<T, P: Pairing> ProvingKey<T, P>
where
T: PrimeFieldMpcProtocol<P::ScalarField>,
{
const PUBLIC_INPUT_WIRE_INDEX: usize =
ProverWitnessEntities::<T::FieldShare, P::ScalarField>::W_R;

// We ignore the TraceStructure for now (it is None in barretenberg for UltraHonk)
pub fn create(driver: &T, mut circuit: CoUltraCircuitBuilder<T, P>, crs: ProverCrs<P>) -> Self {
tracing::info!("ProvingKey create");
circuit.add_gates_to_ensure_all_polys_are_non_zero();
circuit.finalize_circuit();

let dyadic_circuit_size = circuit.compute_dyadic_size();
let mut proving_key = Self::new(dyadic_circuit_size, circuit.public_inputs.len(), crs);
// Construct and add to proving key the wire, selector and copy constraint polynomials
proving_key.populate_trace(driver, &mut circuit, false);

// First and last lagrange polynomials (in the full circuit size)
proving_key.polynomials.precomputed.lagrange_first_mut()[0] = P::ScalarField::one();
proving_key.polynomials.precomputed.lagrange_last_mut()[dyadic_circuit_size - 1] =
P::ScalarField::one();

PlainProvingKey::construct_lookup_table_polynomials(
proving_key
.polynomials
.precomputed
.get_table_polynomials_mut(),
&circuit,
dyadic_circuit_size,
0,
);
PlainProvingKey::construct_lookup_read_counts(
proving_key
.polynomials
.witness
.lookup_read_counts_and_tags_mut()
.try_into()
.unwrap(),
&mut circuit,
dyadic_circuit_size,
);

// Construct the public inputs array
let block = circuit.blocks.get_pub_inputs();
assert!(block.is_pub_inputs);
for var_idx in block.wires[Self::PUBLIC_INPUT_WIRE_INDEX]
.iter()
.take(proving_key.num_public_inputs as usize)
.cloned()
{
let var = circuit.get_variable(var_idx as usize);
proving_key.public_inputs.push(var.public_into_field());
}

// TODO the following elements are not part of the proving key so far
// Set the recursive proof indices
// proving_key.recursive_proof_public_input_indices =
// circuit.recursive_proof_public_input_indices;
// proving_key.contains_recursive_proof = circuit.contains_recursive_proof;

proving_key
}

pub fn get_prover_crs(
circuit: &CoUltraCircuitBuilder<T, P>,
path_g1: &str,
) -> Result<ProverCrs<P>> {
PlainProvingKey::get_prover_crs(circuit, path_g1)
}

fn new(circuit_size: usize, num_public_inputs: usize, crs: ProverCrs<P>) -> Self {
tracing::info!("ProvingKey new");
let polynomials = Polynomials::new(circuit_size);

Self {
crs,
circuit_size: circuit_size as u32,
public_inputs: Vec::with_capacity(num_public_inputs),
num_public_inputs: num_public_inputs as u32,
pub_inputs_offset: 0,
polynomials,
memory_read_records: Vec::new(),
memory_write_records: Vec::new(),
phantom: PhantomData,
}
}

fn populate_trace(
&mut self,
driver: &T,
builder: &mut CoUltraCircuitBuilder<T, P>,
is_strucutred: bool,
) {
tracing::info!("Populating trace");

let mut trace_data = TraceData::new(builder, self);
trace_data.construct_trace_data(driver, builder, is_strucutred);

let ram_rom_offset = trace_data.ram_rom_offset;
let copy_cycles = trace_data.copy_cycles;
self.pub_inputs_offset = trace_data.pub_inputs_offset;

PlainProvingKey::add_memory_records_to_proving_key(
ram_rom_offset,
builder,
&mut self.memory_read_records,
&mut self.memory_write_records,
);

// Compute the permutation argument polynomials (sigma/id) and add them to proving key
PlainProvingKey::compute_permutation_argument_polynomials(
&mut self.polynomials.precomputed,
builder,
copy_cycles,
self.circuit_size as usize,
self.pub_inputs_offset as usize,
);
}
}
Loading

0 comments on commit 54867af

Please sign in to comment.