Skip to content

Commit

Permalink
fix!: Adapt co-noir binary to handle public noir inputs correctly (#216)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: co-noir now stores shared inputs in a different format (`BTreeMap<String, Rep3AcvmType<ark_bn254::Fr>>` instead of `BTreeMap<String, Rep3PrimeFieldShare<ark_bn254::Fr>>`)
  • Loading branch information
rw0x0 authored and 0xThemis committed Oct 15, 2024
1 parent 9dbaa75 commit bed3996
Show file tree
Hide file tree
Showing 16 changed files with 165 additions and 37 deletions.
19 changes: 16 additions & 3 deletions co-noir/co-acvm/src/mpc/rep3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use mpc_core::{
Rep3PrimeFieldShare,
},
};
use serde::{Deserialize, Serialize};

use super::plain::PlainAcvmSolver;
use super::NoirWitnessExtensionProtocol;
Expand Down Expand Up @@ -40,10 +41,22 @@ impl<F: PrimeField, N: Rep3Network> Rep3AcvmSolver<F, N> {

// TODO maybe we want to merge that with the Rep3VmType?? Atm we do not need
// binary shares so maybe it is ok..
#[derive(Clone)]
#[derive(Clone, Serialize, Deserialize)]
pub enum Rep3AcvmType<F: PrimeField> {
Public(F),
Shared(ArithmeticShare<F>),
Public(
#[serde(
serialize_with = "mpc_core::ark_se",
deserialize_with = "mpc_core::ark_de"
)]
F,
),
Shared(
#[serde(
serialize_with = "mpc_core::ark_se",
deserialize_with = "mpc_core::ark_de"
)]
ArithmeticShare<F>,
),
}

impl<F: PrimeField> std::fmt::Debug for Rep3AcvmType<F> {
Expand Down
24 changes: 17 additions & 7 deletions co-noir/co-acvm/src/solver.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use acir::{
acir_field::GenericFieldElement,
circuit::{Circuit, ExpressionWidth, Opcode},
circuit::{Circuit, ExpressionWidth, Opcode, Program},
native_types::{WitnessMap, WitnessStack},
FieldElement,
};
Expand All @@ -9,6 +9,7 @@ use intmap::IntMap;
use mpc_core::{lut::LookupTableProvider, protocols::rep3::network::Rep3Network};
use noirc_abi::{input_parser::Format, Abi, MAIN_RETURN_NAME};
use noirc_artifacts::program::ProgramArtifact;
use partial_abi::PublicMarker;
use std::{collections::BTreeMap, io, path::PathBuf};

use crate::mpc::{plain::PlainAcvmSolver, rep3::Rep3AcvmSolver, NoirWitnessExtensionProtocol};
Expand Down Expand Up @@ -72,6 +73,8 @@ impl<T> CoSolver<T, ark_bn254::Fr>
where
T: NoirWitnessExtensionProtocol<ark_bn254::Fr>,
{
const DEFAULT_FUNCTION_INDEX: usize = 0;

pub fn read_abi_bn254_fieldelement<P>(
path: P,
abi: &Abi,
Expand All @@ -96,7 +99,8 @@ where
pub fn partially_read_abi_bn254_fieldelement<P>(
path: P,
abi: &Abi,
) -> eyre::Result<BTreeMap<String, FieldElement>>
program: &Program<FieldElement>,
) -> eyre::Result<BTreeMap<String, PublicMarker<FieldElement>>>
where
PathBuf: From<P>,
{
Expand All @@ -111,7 +115,12 @@ where
// do we want to keep it like that? Seems not necessary but maybe
// we need it for proving/verifying
let encoded = abi_.encode(&input_map, return_value.clone())?;
Ok(Self::create_string_map(&abi_, encoded)?)
Ok(Self::create_string_map(
abi,
&abi_,
encoded,
&program.functions[Self::DEFAULT_FUNCTION_INDEX].public_parameters,
)?)
}
}

Expand All @@ -137,7 +146,8 @@ where
{
let mut witness_map =
vec![WitnessMap::default(); compiled_program.bytecode.functions.len()];
witness_map[0] = Self::read_abi_bn254(prover_path, &compiled_program.abi)?;
witness_map[Self::DEFAULT_FUNCTION_INDEX] =
Self::read_abi_bn254(prover_path, &compiled_program.abi)?;
Ok(Self {
driver,
abi: compiled_program.abi,
Expand All @@ -149,7 +159,7 @@ where
.map(|function| acvm::compiler::transform(function, CO_EXPRESSION_WIDTH).0)
.collect::<Vec<_>>(),
witness_map,
function_index: 0,
function_index: Self::DEFAULT_FUNCTION_INDEX,
memory_access: IntMap::new(),
})
}
Expand All @@ -161,7 +171,7 @@ where
) -> eyre::Result<Self> {
let mut witness_map =
vec![WitnessMap::default(); compiled_program.bytecode.functions.len()];
witness_map[0] = witness;
witness_map[Self::DEFAULT_FUNCTION_INDEX] = witness;
Ok(Self {
driver,
abi: compiled_program.abi,
Expand All @@ -173,7 +183,7 @@ where
.map(|function| acvm::compiler::transform(function, CO_EXPRESSION_WIDTH).0)
.collect::<Vec<_>>(),
witness_map,
function_index: 0,
function_index: Self::DEFAULT_FUNCTION_INDEX,
memory_access: IntMap::new(),
})
}
Expand Down
55 changes: 46 additions & 9 deletions co-noir/co-acvm/src/solver/partial_abi.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::CoSolver;
use crate::mpc::NoirWitnessExtensionProtocol;
use acir::{native_types::WitnessMap, FieldElement};
use acir::{circuit::PublicInputs, native_types::WitnessMap, FieldElement};
use eyre::eyre;
use noirc_abi::Abi;
use serde::{Deserialize, Serialize};
Expand All @@ -24,6 +24,11 @@ enum TomlTypes {
Table(BTreeMap<String, TomlTypes>),
}

pub enum PublicMarker<F> {
Public(F),
Private(F),
}

impl<T> CoSolver<T, ark_bn254::Fr>
where
T: NoirWitnessExtensionProtocol<ark_bn254::Fr>,
Expand Down Expand Up @@ -56,21 +61,49 @@ where
}

pub(crate) fn create_string_map(
abi: &Abi,
original_abi: &Abi,
partial_abi: &Abi,
witness: WitnessMap<FieldElement>,
) -> eyre::Result<BTreeMap<String, FieldElement>> {
public_parameters: &PublicInputs,
) -> eyre::Result<BTreeMap<String, PublicMarker<FieldElement>>> {
let mut res_map = BTreeMap::new();
let mut wit_iter = witness.into_iter();

for param in abi.parameters.iter() {
let mut orig_params = original_abi.parameters.iter();
let mut offset = 0;

for param in partial_abi.parameters.iter() {
let arg_name = &param.name;
let typ_field_len = param.typ.field_count();

// Calculate real witness offset for the public parameter marker
loop {
let next = orig_params
.next()
.ok_or(eyre!("Corrupted Witness: Too few witnesses"))?;

if &next.name == arg_name {
break;
}
offset += next.typ.field_count();
}

for i in 0..typ_field_len {
let name = format!("{}[{}]", arg_name, i);
let name = if typ_field_len == 1 {
arg_name.to_owned()
} else {
format!("{}[{}]", arg_name, i)
};

let (_, el) = wit_iter
.next()
.ok_or(eyre!("Corrupted Witness: Too little witnesses"))?;
res_map.insert(name, el);
.ok_or(eyre!("Corrupted Witness: Too few witnesses"))?;
if public_parameters.contains((offset) as usize) {
res_map.insert(name, PublicMarker::Public(el));
} else {
res_map.insert(name, PublicMarker::Private(el));
}
offset += 1;
}
}
if wit_iter.next().is_some() {
Expand All @@ -95,10 +128,14 @@ where
let arg_name = &params.name;
let typ_field_len = params.typ.field_count();
for i in 0..typ_field_len {
let should_name = format!("{}[{}]", arg_name, i);
let should_name = if typ_field_len == 1 {
arg_name.to_owned()
} else {
format!("{}[{}]", arg_name, i)
};
let el = witness
.get(&should_name)
.ok_or(eyre!("Corrupted Witness: Missing witness"))?;
.ok_or(eyre!("Corrupted Witness: Missing witness: {}", should_name))?;

result.insert(index.into(), O::from(el.to_owned()));
index += 1;
Expand Down
20 changes: 20 additions & 0 deletions co-noir/co-noir/examples/run_full_add3.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# split input into shares
cargo run --release --bin co-noir -- split-input --circuit test_vectors/add3/add3.json --input test_vectors/add3/Alice.toml --protocol REP3 --out-dir test_vectors/add3
cargo run --release --bin co-noir -- split-input --circuit test_vectors/add3/add3.json --input test_vectors/add3/Bob.toml --protocol REP3 --out-dir test_vectors/add3
cargo run --release --bin co-noir -- split-input --circuit test_vectors/add3/add3.json --input test_vectors/add3/Davina.toml --protocol REP3 --out-dir test_vectors/add3
# merge inputs into single input file
cargo run --release --bin co-noir -- merge-input-shares --inputs test_vectors/add3/Alice.toml.0.shared --inputs test_vectors/add3/Bob.toml.0.shared --inputs test_vectors/add3/Davina.toml.0.shared --protocol REP3 --out test_vectors/add3/Prover.toml.0.shared
cargo run --release --bin co-noir -- merge-input-shares --inputs test_vectors/add3/Alice.toml.2.shared --inputs test_vectors/add3/Bob.toml.2.shared --inputs test_vectors/add3/Davina.toml.2.shared --protocol REP3 --out test_vectors/add3/Prover.toml.2.shared
cargo run --release --bin co-noir -- merge-input-shares --inputs test_vectors/add3/Alice.toml.1.shared --inputs test_vectors/add3/Bob.toml.1.shared --inputs test_vectors/add3/Davina.toml.1.shared --protocol REP3 --out test_vectors/add3/Prover.toml.1.shared
# run witness extension in MPC
cargo run --release --bin co-noir -- generate-witness --input test_vectors/add3/Prover.toml.0.shared --circuit test_vectors/add3/add3.json --protocol REP3 --config configs/party1.toml --out test_vectors/add3/add3.gz.0.shared &
cargo run --release --bin co-noir -- generate-witness --input test_vectors/add3/Prover.toml.1.shared --circuit test_vectors/add3/add3.json --protocol REP3 --config configs/party2.toml --out test_vectors/add3/add3.gz.1.shared &
cargo run --release --bin co-noir -- generate-witness --input test_vectors/add3/Prover.toml.2.shared --circuit test_vectors/add3/add3.json --protocol REP3 --config configs/party3.toml --out test_vectors/add3/add3.gz.2.shared
# run proving in MPC
cargo run --release --bin co-noir -- generate-proof --witness test_vectors/add3/add3.gz.0.shared --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --protocol REP3 --config configs/party1.toml --out proof.0.proof --public-input public_input.json &
cargo run --release --bin co-noir -- generate-proof --witness test_vectors/add3/add3.gz.1.shared --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --protocol REP3 --config configs/party2.toml --out proof.1.proof &
cargo run --release --bin co-noir -- generate-proof --witness test_vectors/add3/add3.gz.2.shared --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --protocol REP3 --config configs/party3.toml --out proof.2.proof
# Create verification key
cargo run --release --bin co-noir -- create-vk --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --vk test_vectors/add3/verification_key
# verify proof
cargo run --release --bin co-noir -- verify --proof proof.0.proof --vk test_vectors/add3/verification_key --crs test_vectors/bn254_g2.dat
10 changes: 10 additions & 0 deletions co-noir/co-noir/examples/run_proof_only_add3.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# split input into shares
cargo run --release --bin co-noir -- split-witness --witness test_vectors/add3/add3.gz --circuit test_vectors/add3/add3.json --protocol REP3 --out-dir test_vectors/add3
# run proving in MPC
cargo run --release --bin co-noir -- generate-proof --witness test_vectors/add3/add3.gz.0.shared --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --protocol REP3 --config configs/party1.toml --out proof.0.proof --public-input public_input.json &
cargo run --release --bin co-noir -- generate-proof --witness test_vectors/add3/add3.gz.1.shared --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --protocol REP3 --config configs/party2.toml --out proof.1.proof &
cargo run --release --bin co-noir -- generate-proof --witness test_vectors/add3/add3.gz.2.shared --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --protocol REP3 --config configs/party3.toml --out proof.2.proof
# Create verification key
cargo run --release --bin co-noir -- create-vk --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --vk test_vectors/add3/verification_key
# verify proof
cargo run --release --bin co-noir -- verify --proof proof.0.proof --vk test_vectors/add3/verification_key --crs test_vectors/bn254_g2.dat
10 changes: 10 additions & 0 deletions co-noir/co-noir/examples/run_proof_only_add3_shamir.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# split input into shares
cargo run --release --bin co-noir -- split-witness --witness test_vectors/add3/add3.gz --circuit test_vectors/add3/add3.json --protocol SHAMIR --out-dir test_vectors/add3
# run proving in MPC
cargo run --release --bin co-noir -- generate-proof --witness test_vectors/add3/add3.gz.0.shared --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --protocol SHAMIR --config configs/party1.toml --out proof.0.proof --public-input public_input.json &
cargo run --release --bin co-noir -- generate-proof --witness test_vectors/add3/add3.gz.1.shared --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --protocol SHAMIR --config configs/party2.toml --out proof.1.proof &
cargo run --release --bin co-noir -- generate-proof --witness test_vectors/add3/add3.gz.2.shared --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --protocol SHAMIR --config configs/party3.toml --out proof.2.proof
# Create verification key
cargo run --release --bin co-noir -- create-vk --circuit test_vectors/add3/add3.json --crs test_vectors/bn254_g1.dat --vk test_vectors/add3/verification_key
# verify proof
cargo run --release --bin co-noir -- verify --proof proof.0.proof --vk test_vectors/add3/verification_key --crs test_vectors/bn254_g2.dat
1 change: 1 addition & 0 deletions co-noir/co-noir/examples/test_vectors/add3/Alice.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x = "1"
1 change: 1 addition & 0 deletions co-noir/co-noir/examples/test_vectors/add3/Bob.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
y = "2"
1 change: 1 addition & 0 deletions co-noir/co-noir/examples/test_vectors/add3/Davina.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
z = "3"
7 changes: 7 additions & 0 deletions co-noir/co-noir/examples/test_vectors/add3/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "simple_add"
type = "bin"
authors = [""]
compiler_version = ">=0.33.0"

[dependencies]
Binary file added co-noir/co-noir/examples/test_vectors/add3/add3.gz
Binary file not shown.
1 change: 1 addition & 0 deletions co-noir/co-noir/examples/test_vectors/add3/add3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"noir_version":"0.33.0+325dac54efb6f99201de9fdeb0a507d45189607d","hash":3433527208697688045,"abi":{"parameters":[{"name":"x","type":{"kind":"field"},"visibility":"private"},{"name":"y","type":{"kind":"field"},"visibility":"public"},{"name":"z","type":{"kind":"field"},"visibility":"public"}],"return_type":{"abi_type":{"kind":"field"},"visibility":"public"},"error_types":{}},"bytecode":"H4sIAAAAAAAA/62RSwqAMAxE+/FASZPYZOdVLNb7H0HRCgXd2QdhIIEHYby7ied492ZqubQkmJlrThUJV0hWVIClzIqKorIlJarKmq1YBkOmirsY7XAz0uUHukLngn9gHOe6fnw66PsJ3S50t+g+OAApYh7N5QEAAA==","debug_symbols":"TclRCoAgDADQu+y7E3SViJimMZAtSoMYu7uCfvj5eApncOU6iKO8sG4KSTxmEm5SW+DDh9ClMBgL+2nzf/ex3So=","file_map":{},"names":["main"]}
9 changes: 9 additions & 0 deletions co-noir/co-noir/examples/test_vectors/add3/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fn main(x: Field, y: pub Field, z: pub Field) -> pub Field {
x + y + z
}

#[test]
fn test_main() {
let addition = main(1, 2, 3);
assert(addition == 6);
}
14 changes: 6 additions & 8 deletions co-noir/co-noir/src/bin/co-noir.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use ark_bn254::Bn254;
use ark_ff::Zero;
use clap::{Parser, Subcommand};
use co_acvm::solver::Rep3CoSolver;
use co_acvm::{solver::Rep3CoSolver, Rep3AcvmType};
use co_noir::{
convert_witness_to_vec_rep3, file_utils, share_input_rep3, share_rep3, share_shamir,
translate_witness_share_rep3, CreateVKCli, CreateVKConfig, GenerateProofCli,
Expand All @@ -22,10 +22,7 @@ use co_ultrahonk::{
use color_eyre::eyre::{eyre, Context, ContextCompat};
use mpc_core::protocols::{
bridges::network::RepToShamirNetwork,
rep3::{
network::{IoContext, Rep3MpcNet, Rep3Network},
Rep3PrimeFieldShare,
},
rep3::network::{IoContext, Rep3MpcNet, Rep3Network},
shamir::{
network::{ShamirMpcNet, ShamirNetwork},
ShamirPreprocessing, ShamirProtocol,
Expand Down Expand Up @@ -240,6 +237,7 @@ fn run_split_input(config: SplitInputConfig) -> color_eyre::Result<ExitCode> {
let inputs = Rep3CoSolver::<_, Rep3MpcNet>::partially_read_abi_bn254_fieldelement(
&input,
&compiled_program.abi,
&compiled_program.bytecode,
)?;

// create input shares
Expand All @@ -258,7 +256,7 @@ fn run_split_input(config: SplitInputConfig) -> color_eyre::Result<ExitCode> {
for (i, share) in shares.iter().enumerate() {
let path = out_dir.join(format!("{}.{}.shared", base_name, i));
let out_file = BufWriter::new(File::create(&path).context("while creating output file")?);
bincode::serialize_into(out_file, share).context("while serializing witness share")?;
bincode::serialize_into(out_file, share).context("while serializing input share")?;
tracing::info!("Wrote input share {} to file {}", i, path.display());
}

Expand Down Expand Up @@ -292,7 +290,7 @@ fn run_merge_input_shares(config: MergeInputSharesConfig) -> color_eyre::Result<
// parse input shares
let input_share_file =
BufReader::new(File::open(input).context("while opening input share file")?);
let input_share: BTreeMap<String, Rep3PrimeFieldShare<ark_bn254::Fr>> =
let input_share: BTreeMap<String, Rep3AcvmType<ark_bn254::Fr>> =
bincode::deserialize_from(input_share_file)
.context("while deserializing input share")?;
color_eyre::Result::<_>::Ok(input_share)
Expand Down Expand Up @@ -343,7 +341,7 @@ fn run_generate_witness(config: GenerateWitnessConfig) -> color_eyre::Result<Exi
// parse input shares
let input_share_file =
BufReader::new(File::open(&input).context("while opening input share file")?);
let input_share: BTreeMap<String, Rep3PrimeFieldShare<ark_bn254::Fr>> =
let input_share: BTreeMap<String, Rep3AcvmType<ark_bn254::Fr>> =
bincode::deserialize_from(input_share_file).context("while deserializing input share")?;
let input_share = translate_witness_share_rep3(input_share, &compiled_program.abi)?;

Expand Down
28 changes: 19 additions & 9 deletions co-noir/co-noir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use acir::{
use ark_ec::pairing::Pairing;
use ark_ff::Zero;
use clap::{Args, ValueEnum};
use co_acvm::{solver::Rep3CoSolver, Rep3AcvmType};
use co_acvm::{
solver::{partial_abi::PublicMarker, Rep3CoSolver},
Rep3AcvmType,
};
use co_ultrahonk::prelude::{
Rep3UltraHonkDriver, ShamirUltraHonkDriver, SharedBuilderVariable, UltraCircuitVariable,
};
Expand All @@ -18,7 +21,6 @@ use mpc_core::protocols::{
rep3::{
self,
network::{Rep3MpcNet, Rep3Network},
Rep3PrimeFieldShare,
},
shamir::{self, network::ShamirNetwork},
};
Expand Down Expand Up @@ -481,23 +483,31 @@ pub fn share_shamir<P: Pairing, N: ShamirNetwork, R: Rng + CryptoRng>(
}

pub fn share_input_rep3<P: Pairing, N: Rep3Network, R: Rng + CryptoRng>(
initial_witness: BTreeMap<String, GenericFieldElement<P::ScalarField>>,
initial_witness: BTreeMap<String, PublicMarker<GenericFieldElement<P::ScalarField>>>,
rng: &mut R,
) -> [BTreeMap<String, Rep3PrimeFieldShare<P::ScalarField>>; 3] {
) -> [BTreeMap<String, Rep3AcvmType<P::ScalarField>>; 3] {
let mut witnesses = array::from_fn(|_| BTreeMap::default());
for (witness, v) in initial_witness.into_iter() {
let v = v.into_repr();
let shares = rep3::share_field_element(v, rng);
for (w, share) in witnesses.iter_mut().zip(shares) {
w.insert(witness.to_owned(), share);
match v {
PublicMarker::Public(v) => {
for w in witnesses.iter_mut() {
w.insert(witness.to_owned(), Rep3AcvmType::Public(v.into_repr()));
}
}
PublicMarker::Private(v) => {
let shares = rep3::share_field_element(v.into_repr(), rng);
for (w, share) in witnesses.iter_mut().zip(shares) {
w.insert(witness.clone(), Rep3AcvmType::Shared(share));
}
}
}
}

witnesses
}

pub fn translate_witness_share_rep3(
witness: BTreeMap<String, Rep3PrimeFieldShare<ark_bn254::Fr>>,
witness: BTreeMap<String, Rep3AcvmType<ark_bn254::Fr>>,
abi: &Abi,
) -> color_eyre::Result<WitnessMap<Rep3AcvmType<ark_bn254::Fr>>> {
Rep3CoSolver::<ark_bn254::Fr, Rep3MpcNet>::witness_map_from_string_map(witness, abi)
Expand Down
Loading

0 comments on commit bed3996

Please sign in to comment.