Skip to content

Commit 93afdf3

Browse files
Adopt a CSR Representation for Sparse Matrices (Arecibo backport) (#232)
* CSR Representation for Sparse Matrices (#38) * add csr feature * remove feature remove conversions * cleanup * avoid iter() and go row-by-row * cleanup and apply suggestions * add R1CSShape padding test * add more suggestions * refactor: Refactor sparse namespace and SparseMatrix visibility - Modifies the visibility of `sparse` module from public to private - Makes `SparseMatrix` class within `sparse` module public - Updates `SparseMatrix` import across several files to accommodate visibility changes * fix: define matrix inputs in idiomatic Nova style * chore: Refactor dependencies for r1cs module - Shifted `proptest` and `rand` dependencies to dev-dependencies in `Cargo.toml` - Introduced testing flag for `util` module under `r1cs` --------- Co-authored-by: Hanting Zhang <[email protected]>
1 parent 9165211 commit 93afdf3

10 files changed

Lines changed: 475 additions & 119 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@ getrandom = { version = "0.2.0", default-features = false, features = ["js"] }
4545

4646
[dev-dependencies]
4747
criterion = { version = "0.4", features = ["html_reports"] }
48-
rand = "0.8.4"
4948
flate2 = "1.0"
5049
hex = "0.4.3"
5150
pprof = { version = "0.11" }
5251
cfg-if = "1.0.0"
5352
sha2 = "0.10.7"
5453
proptest = "1.2.0"
54+
rand = "0.8.5"
5555

5656
[[bench]]
5757
name = "recursive-snark"

examples/minroot.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,13 @@ where
129129
}
130130
}
131131

132+
/// cargo run --release --example minroot
132133
fn main() {
133134
println!("Nova-based VDF with MinRoot delay function");
134135
println!("=========================================================");
135136

136137
let num_steps = 10;
137-
for num_iters_per_step in [1024, 2048, 4096, 8192, 16384, 32768, 65535] {
138+
for num_iters_per_step in [1024, 2048, 4096, 8192, 16384, 32768, 65536] {
138139
// number of iterations of MinRoot per Nova's recursive step
139140
let circuit_primary = MinRootCircuit {
140141
seq: vec![

src/bellpepper/r1cs.rs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use super::{shape_cs::ShapeCS, solver::SatisfyingAssignment, test_shape_cs::TestShapeCS};
66
use crate::{
77
errors::NovaError,
8-
r1cs::{R1CSInstance, R1CSShape, R1CSWitness, R1CS},
8+
r1cs::{R1CSInstance, R1CSShape, R1CSWitness, SparseMatrix, R1CS},
99
traits::Group,
1010
CommitmentKey,
1111
};
@@ -52,13 +52,12 @@ macro_rules! impl_nova_shape {
5252
G::Scalar: PrimeField,
5353
{
5454
fn r1cs_shape(&self) -> (R1CSShape<G>, CommitmentKey<G>) {
55-
let mut A: Vec<(usize, usize, G::Scalar)> = Vec::new();
56-
let mut B: Vec<(usize, usize, G::Scalar)> = Vec::new();
57-
let mut C: Vec<(usize, usize, G::Scalar)> = Vec::new();
55+
let mut A = SparseMatrix::<G::Scalar>::empty();
56+
let mut B = SparseMatrix::<G::Scalar>::empty();
57+
let mut C = SparseMatrix::<G::Scalar>::empty();
5858

5959
let mut num_cons_added = 0;
6060
let mut X = (&mut A, &mut B, &mut C, &mut num_cons_added);
61-
6261
let num_inputs = self.num_inputs();
6362
let num_constraints = self.num_constraints();
6463
let num_vars = self.num_aux();
@@ -72,15 +71,14 @@ macro_rules! impl_nova_shape {
7271
&constraint.2,
7372
);
7473
}
75-
7674
assert_eq!(num_cons_added, num_constraints);
7775

78-
let S: R1CSShape<G> = {
79-
// Don't count One as an input for shape's purposes.
80-
let res = R1CSShape::new(num_constraints, num_vars, num_inputs - 1, &A, &B, &C);
81-
res.unwrap()
82-
};
76+
A.cols = num_vars + num_inputs;
77+
B.cols = num_vars + num_inputs;
78+
C.cols = num_vars + num_inputs;
8379

80+
// Don't count One as an input for shape's purposes.
81+
let S = R1CSShape::new(num_constraints, num_vars, num_inputs - 1, A, B, C).unwrap();
8482
let ck = R1CS::<G>::commitment_key(&S);
8583

8684
(S, ck)
@@ -94,9 +92,9 @@ impl_nova_shape!(TestShapeCS);
9492

9593
fn add_constraint<S: PrimeField>(
9694
X: &mut (
97-
&mut Vec<(usize, usize, S)>,
98-
&mut Vec<(usize, usize, S)>,
99-
&mut Vec<(usize, usize, S)>,
95+
&mut SparseMatrix<S>,
96+
&mut SparseMatrix<S>,
97+
&mut SparseMatrix<S>,
10098
&mut usize,
10199
),
102100
num_vars: usize,
@@ -106,29 +104,40 @@ fn add_constraint<S: PrimeField>(
106104
) {
107105
let (A, B, C, nn) = X;
108106
let n = **nn;
109-
let one = S::ONE;
107+
assert_eq!(n + 1, A.indptr.len(), "A: invalid shape");
108+
assert_eq!(n + 1, B.indptr.len(), "B: invalid shape");
109+
assert_eq!(n + 1, C.indptr.len(), "C: invalid shape");
110110

111-
let add_constraint_component = |index: Index, coeff, V: &mut Vec<_>| {
111+
let add_constraint_component = |index: Index, coeff: &S, M: &mut SparseMatrix<S>| {
112112
match index {
113113
Index::Input(idx) => {
114114
// Inputs come last, with input 0, reprsenting 'one',
115115
// at position num_vars within the witness vector.
116-
let i = idx + num_vars;
117-
V.push((n, i, one * coeff))
116+
let idx = idx + num_vars;
117+
M.data.push(*coeff);
118+
M.indices.push(idx);
119+
}
120+
Index::Aux(idx) => {
121+
M.data.push(*coeff);
122+
M.indices.push(idx);
118123
}
119-
Index::Aux(idx) => V.push((n, idx, one * coeff)),
120124
}
121125
};
122126

123127
for (index, coeff) in a_lc.iter() {
124128
add_constraint_component(index.0, coeff, A);
125129
}
130+
A.indptr.push(A.indices.len());
131+
126132
for (index, coeff) in b_lc.iter() {
127133
add_constraint_component(index.0, coeff, B)
128134
}
135+
B.indptr.push(B.indices.len());
136+
129137
for (index, coeff) in c_lc.iter() {
130138
add_constraint_component(index.0, coeff, C)
131139
}
140+
C.indptr.push(C.indices.len());
132141

133142
**nn += 1;
134143
}

src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -906,13 +906,13 @@ mod tests {
906906
test_pp_digest_with::<G1, G2, _, _>(
907907
&trivial_circuit1,
908908
&trivial_circuit2,
909-
"fe14a77d74cb8b8bb13105cea9c5b98b621b42c8d61da8f2adce8b9dd0d51b03",
909+
"117ac6f33d66d377346e420f0d8caa09f8f4ec7db0c336dcc65995bf3058bf01",
910910
);
911911

912912
test_pp_digest_with::<G1, G2, _, _>(
913913
&cubic_circuit1,
914914
&trivial_circuit2,
915-
"21ac840e52c75a62823cfdda4ca77aae2f07e4b6f5aa0eba80135492b2fbd003",
915+
"583c9964e180332e63a59450870a72b4cbf663ce0d274ac5bd0d052d4cd92903",
916916
);
917917

918918
let trivial_circuit1_grumpkin = TrivialCircuit::<<bn256::Point as Group>::Scalar>::default();
@@ -922,12 +922,12 @@ mod tests {
922922
test_pp_digest_with::<bn256::Point, grumpkin::Point, _, _>(
923923
&trivial_circuit1_grumpkin,
924924
&trivial_circuit2_grumpkin,
925-
"0b25debdc99cef04b6d113a9a2814de89b3fad239aea90b29f2bdb27d95afa02",
925+
"fb6805b7197f41ae2af71dc0130d4bfd1d28fa63b8221741b597dfbb2e48d603",
926926
);
927927
test_pp_digest_with::<bn256::Point, grumpkin::Point, _, _>(
928928
&cubic_circuit1_grumpkin,
929929
&trivial_circuit2_grumpkin,
930-
"0747f68f8d1c4bac4c3fb82689a1488b5835bbc97d6f6023fbe2760bb0053b00",
930+
"684b2f7151031a79310f6fb553ab1480e290d73731fa34e74c27e004d589f102",
931931
);
932932

933933
let trivial_circuit1_secp = TrivialCircuit::<<secp256k1::Point as Group>::Scalar>::default();
@@ -937,12 +937,12 @@ mod tests {
937937
test_pp_digest_with::<secp256k1::Point, secq256k1::Point, _, _>(
938938
&trivial_circuit1_secp,
939939
&trivial_circuit2_secp,
940-
"0cf0880fa8debe42b7789474f6787062f8118ef251450dd5a7a4b5430f4bb902",
940+
"dbffd48ae0d05f3aeb217e971fbf3b2b7a759668221f6d6cb9032cfa0445aa01",
941941
);
942942
test_pp_digest_with::<secp256k1::Point, secq256k1::Point, _, _>(
943943
&cubic_circuit1_secp,
944944
&trivial_circuit2_secp,
945-
"623a1dd99f3c906e79397f3de0dc1565b35fcb69abf2da51847bc9879a0a6000",
945+
"24e4e8044310e3167196276cc66b4f71b5d0e3e57701dddb17695ae968fba802",
946946
);
947947
}
948948

src/nifs.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ impl<G: Group> NIFS<G> {
113113
#[cfg(test)]
114114
mod tests {
115115
use super::*;
116-
use crate::{r1cs::R1CS, traits::Group};
116+
use crate::{r1cs::SparseMatrix, r1cs::R1CS, traits::Group};
117117
use ::bellpepper_core::{num::AllocatedNum, ConstraintSystem, SynthesisError};
118118
use ff::{Field, PrimeField};
119119
use rand::rngs::OsRng;
@@ -310,8 +310,18 @@ mod tests {
310310
};
311311

312312
// create a shape object
313+
let rows = num_cons;
314+
let num_inputs = num_io + 1;
315+
let cols = num_vars + num_inputs;
313316
let S = {
314-
let res = R1CSShape::new(num_cons, num_vars, num_io, &A, &B, &C);
317+
let res = R1CSShape::new(
318+
num_cons,
319+
num_vars,
320+
num_inputs - 1,
321+
SparseMatrix::new(&A, rows, cols),
322+
SparseMatrix::new(&B, rows, cols),
323+
SparseMatrix::new(&C, rows, cols),
324+
);
315325
assert!(res.is_ok());
316326
res.unwrap()
317327
};

0 commit comments

Comments
 (0)