Skip to content
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
params_for_recursive_verifier
params
artifacts/
spartan_vm_debug/

# Don't ignore benchmarking artifacts
!tooling/provekit-bench/benches/*
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ ark-ff = { version = "0.5", features = ["asm", "std"] }
ark-poly = "0.5"
ark-serialize = "0.5"
ark-std = { version = "0.5", features = ["std"] }
spartan-vm = { path = "../spartan-vm" }
spongefish = { git = "https://github.com/arkworks-rs/spongefish", features = [
"arkworks-algebra",
], rev = "ecb4f08373ed930175585c856517efdb1851fb47" }
Expand Down
7 changes: 7 additions & 0 deletions noir-examples/many_poseidons/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "basic"
type = "bin"
authors = [""]

[dependencies]
poseidon = { tag = "v0.1.1", git = "https://github.com/noir-lang/poseidon" }
2 changes: 2 additions & 0 deletions noir-examples/many_poseidons/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
input = "2"
out = "1851489996817039498840903388622400291095679538238885635067493836951352608371"
8 changes: 8 additions & 0 deletions noir-examples/many_poseidons/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use poseidon::poseidon::bn254;

fn main(mut input: Field, out: pub Field) {
for i in 0..10 {
input = bn254::hash_1([input]);
}
assert_eq(input, out);
}
7 changes: 7 additions & 0 deletions noir-examples/power/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "basic"
type = "bin"
authors = [""]
compiler_version = ">=0.22.0"

[dependencies]
2 changes: 2 additions & 0 deletions noir-examples/power/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x = "1"
y = "1"
8 changes: 8 additions & 0 deletions noir-examples/power/prove.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
nargo compile
nargo check
nargo execute my-witness
bb prove -b ./target/power.json -w ./target/my-witness.gz -o ./target/proof
echo "✅ Proof generated at ./target/proof"
bb write_vk -b ./target/power.json -o ./target/vk
bb verify -k ./target/vk -p ./target/proof
echo "✅ Verified the proof at ./target/proof"
7 changes: 7 additions & 0 deletions noir-examples/power/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main(mut x: Field, y: pub Field) {
let mut r = 1;
for i in 0..10 {
r *= x;
}
assert(r == y);
}
6 changes: 6 additions & 0 deletions noir-examples/rangechecks/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "basic"
type = "bin"
authors = [""]

[dependencies]
1 change: 1 addition & 0 deletions noir-examples/rangechecks/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x = "0"
7 changes: 7 additions & 0 deletions noir-examples/rangechecks/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main(x: Field) {
for i in 0..10000 {
let r = x + i as Field;
r.assert_max_bit_size::<32>();
}
}

1 change: 1 addition & 0 deletions provekit/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ repository.workspace = true
[dependencies]
# Workspace crates
skyscraper.workspace = true
spartan-vm.workspace = true

# Noir language
acir.workspace = true
Expand Down
65 changes: 56 additions & 9 deletions provekit/common/src/interner.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,48 @@
use {
crate::{utils::serde_ark, FieldElement},
serde::{Deserialize, Serialize},
ark_ff::PrimeField,
serde::{Deserialize, Deserializer, Serialize},
std::collections::HashMap,
};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
type FieldKey = [u64; 4];

#[inline(always)]
fn field_to_key(value: FieldElement) -> FieldKey {
value.into_bigint().0
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Interner {
#[serde(with = "serde_ark")]
values: Vec<FieldElement>,
values: Vec<FieldElement>,
#[serde(skip)]
index_map: HashMap<FieldKey, usize>,
}

impl<'de> Deserialize<'de> for Interner {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct InternerData {
#[serde(with = "serde_ark")]
values: Vec<FieldElement>,
}

let data = InternerData::deserialize(deserializer)?;

let mut index_map = HashMap::with_capacity(data.values.len());
for (index, &value) in data.values.iter().enumerate() {
index_map.insert(field_to_key(value), index);
}

Ok(Self {
values: data.values,
index_map,
})
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
Expand All @@ -19,24 +55,35 @@ impl Default for Interner {
}

impl Interner {
pub const fn new() -> Self {
Self { values: Vec::new() }
pub fn new() -> Self {
Self {
values: Vec::new(),
index_map: HashMap::new(),
}
}

/// Interning is slow in favour of faster lookups.
pub fn intern(&mut self, value: FieldElement) -> InternedFieldElement {
// Deduplicate
if let Some(index) = self.values.iter().position(|v| *v == value) {
let key = field_to_key(value);

if let Some(&index) = self.index_map.get(&key) {
return InternedFieldElement(index);
}

// Insert
let index = self.values.len();
self.values.push(value);
self.index_map.insert(key, index);
InternedFieldElement(index)
}

pub fn get(&self, el: InternedFieldElement) -> Option<FieldElement> {
self.values.get(el.0).copied()
}

pub fn rebuild_index_map(&mut self) {
self.index_map.clear();
self.index_map.reserve(self.values.len());
for (index, &value) in self.values.iter().enumerate() {
self.index_map.insert(field_to_key(value), index);
}
}
}
8 changes: 3 additions & 5 deletions provekit/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,15 @@ mod verifier;
mod whir_r1cs;
pub mod witness;

use crate::{
interner::{InternedFieldElement, Interner},
sparse_matrix::{HydratedSparseMatrix, SparseMatrix},
};
use crate::sparse_matrix::{HydratedSparseMatrix, SparseMatrix};
pub use {
acir::FieldElement as NoirElement,
interner::{InternedFieldElement, Interner},
noir_proof_scheme::{NoirProof, NoirProofScheme},
prover::Prover,
r1cs::R1CS,
spartan_vm::compiler::Field as FieldElement,
verifier::Verifier,
whir::crypto::fields::Field256 as FieldElement,
whir_r1cs::{IOPattern, WhirConfig, WhirR1CSProof, WhirR1CSScheme},
};

Expand Down
19 changes: 10 additions & 9 deletions provekit/common/src/noir_proof_scheme.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
use {
crate::{
whir_r1cs::{WhirR1CSProof, WhirR1CSScheme},
witness::{LayeredWitnessBuilders, NoirWitnessGenerator},
NoirElement, R1CS,
R1CS,
},
acir::circuit::Program,
serde::{Deserialize, Serialize},
spartan_vm::compiled_artifacts::CompiledArtifacts,
};

/// A scheme for proving a Noir program.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NoirProofScheme {
pub program: Program<NoirElement>,
pub r1cs: R1CS,
pub layered_witness_builders: LayeredWitnessBuilders,
pub witness_generator: NoirWitnessGenerator,
pub whir_for_witness: WhirR1CSScheme,
pub whir_for_witness: WhirR1CSScheme,
pub artifacts: CompiledArtifacts,
/// R1CS in the format expected by the recursive verifier (Go/gnark)
pub r1cs: R1CS,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
Expand All @@ -26,6 +24,9 @@ pub struct NoirProof {
impl NoirProofScheme {
#[must_use]
pub const fn size(&self) -> (usize, usize) {
(self.r1cs.num_constraints(), self.r1cs.num_witnesses())
(
self.artifacts.r1cs.constraints.len(),
self.artifacts.r1cs.witness_layout.algebraic_size,
)
}
}
30 changes: 12 additions & 18 deletions provekit/common/src/prover.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,30 @@
use {
crate::{
noir_proof_scheme::NoirProofScheme,
whir_r1cs::WhirR1CSScheme,
witness::{LayeredWitnessBuilders, NoirWitnessGenerator},
NoirElement, R1CS,
},
acir::circuit::Program,
crate::{noir_proof_scheme::NoirProofScheme, whir_r1cs::WhirR1CSScheme, R1CS},
serde::{Deserialize, Serialize},
spartan_vm::CompiledArtifacts,
};

/// A prover for a Noir Proof Scheme
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Prover {
pub program: Program<NoirElement>,
pub r1cs: R1CS,
pub layered_witness_builders: LayeredWitnessBuilders,
pub witness_generator: NoirWitnessGenerator,
pub whir_for_witness: WhirR1CSScheme,
pub whir_for_witness: WhirR1CSScheme,
pub artifacts: CompiledArtifacts,
pub r1cs: R1CS,
}

impl Prover {
pub fn from_noir_proof_scheme(noir_proof_scheme: NoirProofScheme) -> Self {
Self {
program: noir_proof_scheme.program,
r1cs: noir_proof_scheme.r1cs,
layered_witness_builders: noir_proof_scheme.layered_witness_builders,
witness_generator: noir_proof_scheme.witness_generator,
whir_for_witness: noir_proof_scheme.whir_for_witness,
whir_for_witness: noir_proof_scheme.whir_for_witness,
artifacts: noir_proof_scheme.artifacts,
r1cs: noir_proof_scheme.r1cs,
}
}

pub const fn size(&self) -> (usize, usize) {
(self.r1cs.num_constraints(), self.r1cs.num_witnesses())
(
self.artifacts.r1cs.constraints.len(),
self.artifacts.r1cs.witness_layout.algebraic_size,
)
}
}
26 changes: 25 additions & 1 deletion provekit/common/src/r1cs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use {
crate::{FieldElement, HydratedSparseMatrix, Interner, SparseMatrix},
crate::{FieldElement, HydratedSparseMatrix, InternedFieldElement, Interner, SparseMatrix},
serde::{Deserialize, Serialize},
};

Expand Down Expand Up @@ -101,4 +101,28 @@ impl R1CS {
);
}
}

pub fn reserve_constraints(&mut self, num_constraints: usize, total_entries: usize) {
let entries_per_matrix = total_entries / 3 + 1;
self.a.reserve(num_constraints, entries_per_matrix);
self.b.reserve(num_constraints, entries_per_matrix);
self.c.reserve(num_constraints, entries_per_matrix);
}

#[inline]
pub fn push_constraint(
&mut self,
a: impl Iterator<Item = (u32, InternedFieldElement)>,
b: impl Iterator<Item = (u32, InternedFieldElement)>,
c: impl Iterator<Item = (u32, InternedFieldElement)>,
) {
self.a.push_row(a);
self.b.push_row(b);
self.c.push_row(c);
}

#[inline]
pub fn intern(&mut self, value: FieldElement) -> InternedFieldElement {
self.interner.intern(value)
}
}
17 changes: 17 additions & 0 deletions provekit/common/src/sparse_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,23 @@ impl SparseMatrix {
self.new_row_indices.resize(rows, self.values.len() as u32);
}

pub fn reserve(&mut self, additional_rows: usize, additional_entries: usize) {
self.new_row_indices.reserve(additional_rows);
self.col_indices.reserve(additional_entries);
self.values.reserve(additional_entries);
}

#[inline]
pub fn push_row(&mut self, entries: impl Iterator<Item = (u32, InternedFieldElement)>) {
self.new_row_indices.push(self.values.len() as u32);
self.num_rows += 1;
for (col, value) in entries {
debug_assert!((col as usize) < self.num_cols, "column index out of bounds");
self.col_indices.push(col);
self.values.push(value);
}
}

/// Set the value at the given row and column.
pub fn set(&mut self, row: usize, col: usize, value: InternedFieldElement) {
assert!(row < self.num_rows, "row index out of bounds");
Expand Down
Loading
Loading