Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ Verify the Noir Proof:
cargo run --release --bin noir-r1cs verify ./noir-proof-scheme.nps ./noir-proof.np
```

Generate inputs for Gnark circuit:

```sh
cargo run --release --bin noir-r1cs generate-gnark-inputs ./noir-proof-scheme.nps ./noir-proof.np
```

Recursively verify in a Gnark proof (reads the proof from `../ProveKit/prover/proof`):

```sh
Expand Down
63 changes: 63 additions & 0 deletions noir-r1cs/src/cli/cmd/generate_gnark_inputs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use {
crate::Command,
anyhow::{Context, Result},
argh::FromArgs,
ark_serialize::CanonicalSerialize,
noir_r1cs::{
create_io_pattern, read, write_gnark_parameters_to_file, NoirProof, NoirProofScheme,
},
std::{fs::File, io::Write, path::PathBuf},
tracing::{info, instrument},
};

/// Generate input compatible with gnark.
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "generate-gnark-inputs")]
pub struct Args {
/// path to the compiled Noir program
#[argh(positional)]
scheme_path: PathBuf,

/// path to the proof file
#[argh(positional)]
proof_path: PathBuf,
}

impl Command for Args {
#[instrument(skip_all)]
fn run(&self) -> Result<()> {
// Read the scheme
let scheme: NoirProofScheme =
read(&self.scheme_path).context("while reading Noir proof scheme")?;
let (constraints, witnesses) = scheme.size();
info!(constraints, witnesses, "Read Noir proof scheme");

// Read the proof
let proof: NoirProof = read(&self.proof_path).context("while reading proof")?;

write_gnark_parameters_to_file(
&scheme.whir.whir_config,
&proof.whir_r1cs_proof.transcript,
&create_io_pattern(scheme.whir.m_0, &scheme.whir.whir_config),
proof.whir_r1cs_proof.whir_query_answer_sums,
scheme.whir.m_0,
scheme.whir.m,
);

let mut file = File::create("./prover/proof").unwrap();
let mut proof_bytes = vec![];
proof
.whir_r1cs_proof
.whir_proof
.serialize_compressed(&mut proof_bytes)
.unwrap();
file.write_all(&proof_bytes)
.expect("Writing proof bytes to a file failed");

let json = serde_json::to_string_pretty(&scheme.r1cs).unwrap(); // Or `to_string` for compact
let mut file = File::create("r1cs.json")?;
file.write_all(json.as_bytes())?;

Ok(())
}
}
3 changes: 3 additions & 0 deletions noir-r1cs/src/cli/cmd/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod circuit_stats;
mod generate_gnark_inputs;
mod prepare;
mod prove;
mod verify;
Expand All @@ -23,6 +24,7 @@ enum Commands {
Prove(prove::Args),
CircuitStats(circuit_stats::Args),
Verify(verify::Args),
GenerateGnarkInputs(generate_gnark_inputs::Args),
}

impl Command for Args {
Expand All @@ -38,6 +40,7 @@ impl Command for Commands {
Commands::Prove(args) => args.run(),
Commands::CircuitStats(args) => args.run(),
Commands::Verify(args) => args.run(),
Commands::GenerateGnarkInputs(args) => args.run(),
}
}
}
10 changes: 5 additions & 5 deletions noir-r1cs/src/gnark_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub struct GnarkConfig {
#[instrument(skip_all)]
pub fn gnark_parameters(
whir_params: &WhirConfig,
merlin: &ProverState<SkyscraperSponge, FieldElement>,
transcript: &[u8],
io: &IOPattern,
sums: [FieldElement; 3],
m_0: usize,
Expand Down Expand Up @@ -89,8 +89,8 @@ pub fn gnark_parameters(
whir_params.starting_domain.backing_domain.group_gen()
),
io_pattern: String::from_utf8(io.as_bytes().to_vec()).unwrap(),
transcript: merlin.narg_string().to_vec(),
transcript_len: merlin.narg_string().to_vec().len(),
transcript: transcript.to_vec(),
transcript_len: transcript.to_vec().len(),
statement_evaluations: vec![
sums[0].to_string(),
sums[1].to_string(),
Expand All @@ -103,13 +103,13 @@ pub fn gnark_parameters(
#[instrument(skip_all)]
pub fn write_gnark_parameters_to_file(
whir_params: &WhirConfig,
merlin: &ProverState<SkyscraperSponge, FieldElement>,
transcript: &[u8],
io: &IOPattern,
sums: [FieldElement; 3],
m_0: usize,
m: usize,
) {
let gnark_config = gnark_parameters(whir_params, merlin, io, sums, m_0, m);
let gnark_config = gnark_parameters(whir_params, transcript, io, sums, m_0, m);
println!("round config {:?}", whir_params.round_parameters);
let mut file_params = File::create("./prover/params").unwrap();
file_params
Expand Down
4 changes: 3 additions & 1 deletion noir-r1cs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ mod whir_r1cs;
pub use {
crate::{
file::{read, write, FileFormat},
noir_proof_scheme::NoirProofScheme,
noir_proof_scheme::{NoirProof, NoirProofScheme},
noir_to_r1cs::noir_to_r1cs,
r1cs::R1CS,
utils::human,
},
acir::FieldElement as NoirElement,
gnark_config::write_gnark_parameters_to_file,
whir::crypto::fields::Field256 as FieldElement,
whir_r1cs::create_io_pattern,
};
use {
crate::{
Expand Down
8 changes: 4 additions & 4 deletions noir-r1cs/src/noir_proof_scheme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ use {
/// A scheme for proving a Noir program.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NoirProofScheme {
r1cs: R1CS,
witness_generator: NoirWitnessGenerator,
whir: WhirR1CSScheme,
pub r1cs: R1CS,
pub witness_generator: NoirWitnessGenerator,
pub whir: WhirR1CSScheme,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NoirProof {
whir_r1cs_proof: WhirR1CSProof,
pub whir_r1cs_proof: WhirR1CSProof,
}

impl NoirProofScheme {
Expand Down
50 changes: 28 additions & 22 deletions noir-r1cs/src/whir_r1cs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ use {
domainsep::WhirDomainSeparator,
parameters::WhirConfig as GenericWhirConfig,
prover::Prover,
statement::{Statement, StatementVerifier as GenericStatementVerifier, VerifierWeights, Weights},
statement::{
Statement, StatementVerifier as GenericStatementVerifier, VerifierWeights, Weights,
},
verifier::Verifier,
WhirProof as GenericWhirProof,
},
Expand All @@ -49,26 +51,26 @@ pub type StatementVerifier = GenericStatementVerifier<FieldElement>;

#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct WhirR1CSScheme {
m: usize,
m_0: usize,
whir_config: WhirConfig,
pub m: usize,
pub m_0: usize,
pub whir_config: WhirConfig,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct WhirR1CSProof {
#[serde(with = "serde_hex")]
transcript: Vec<u8>,
pub transcript: Vec<u8>,

whir_proof: WhirProof,
pub whir_proof: WhirProof,

// TODO: Derive from transcript
#[serde(with = "serde_ark")]
whir_query_answer_sums: [FieldElement; 3],
pub whir_query_answer_sums: [FieldElement; 3],
}

struct DataFromSumcheckVerifier {
r: Vec<FieldElement>,
alpha: Vec<FieldElement>,
r: Vec<FieldElement>,
alpha: Vec<FieldElement>,
last_sumcheck_val: FieldElement,
}

Expand Down Expand Up @@ -131,8 +133,7 @@ impl WhirR1CSScheme {

// First round of sumcheck to reduce R1CS to a batch weighted evaluation of the
// witness
let (merlin, alpha) =
run_sumcheck_prover(r1cs, &witness, merlin, self.m_0);
let (merlin, alpha) = run_sumcheck_prover(r1cs, &witness, merlin, self.m_0);

// Compute weights from R1CS instance
let alphas = calculate_external_row_of_r1cs_matrices(&alpha, r1cs);
Expand All @@ -157,17 +158,16 @@ impl WhirR1CSScheme {
let io = create_io_pattern(self.m_0, &self.whir_config);
let mut arthur = io.to_verifier_state(&proof.transcript);


// Compute statement verifier
let mut statement_verifier = StatementVerifier::from_statement(&Statement::<FieldElement>::new(self.m));
let mut statement_verifier =
StatementVerifier::from_statement(&Statement::<FieldElement>::new(self.m));
for claimed_sum in &proof.whir_query_answer_sums {
statement_verifier.add_constraint(
VerifierWeights::linear(self.m, None),
claimed_sum.clone(),
);
}
statement_verifier
.add_constraint(VerifierWeights::linear(self.m, None), claimed_sum.clone());
}

let data_from_sumcheck_verifier = run_sumcheck_verifier(&mut arthur, self.m_0).context("while verifying sumcheck")?;
let data_from_sumcheck_verifier =
run_sumcheck_verifier(&mut arthur, self.m_0).context("while verifying sumcheck")?;
run_whir_pcs_verifier(
&mut arthur,
&self.whir_config,
Expand All @@ -181,7 +181,10 @@ impl WhirR1CSScheme {
data_from_sumcheck_verifier.last_sumcheck_val
== (proof.whir_query_answer_sums[0] * proof.whir_query_answer_sums[1]
- proof.whir_query_answer_sums[2])
* calculate_eq(&data_from_sumcheck_verifier.r, &data_from_sumcheck_verifier.alpha),
* calculate_eq(
&data_from_sumcheck_verifier.r,
&data_from_sumcheck_verifier.alpha
),
"last sumcheck value does not match"
);

Expand Down Expand Up @@ -359,10 +362,13 @@ pub fn run_sumcheck_verifier(
saved_val_for_sumcheck_equality_assertion = eval_qubic_poly(&hhat_i, &alpha_i[0]);
}

Ok(DataFromSumcheckVerifier{r, alpha, last_sumcheck_val: saved_val_for_sumcheck_equality_assertion})
Ok(DataFromSumcheckVerifier {
r,
alpha,
last_sumcheck_val: saved_val_for_sumcheck_equality_assertion,
})
}


#[instrument(skip_all)]
pub fn run_whir_pcs_verifier(
arthur: &mut VerifierState<SkyscraperSponge, FieldElement>,
Expand Down
Loading