Skip to content

Commit a9195b1

Browse files
failing test
1 parent a3367da commit a9195b1

File tree

4 files changed

+216
-129
lines changed

4 files changed

+216
-129
lines changed

src/nova/batch.rs

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ where
2222
rom: Vec<usize>,
2323
}
2424

25+
impl<E1> EpochCircuitSequence<E1>
26+
where
27+
E1: CurveCycleEquipped,
28+
{
29+
pub fn new(operations: Vec<(usize, EpochCircuit<E1::Scalar>)>) -> Self {
30+
let rom = operations.iter().map(|(op, _)| *op).collect();
31+
let circuits = operations.into_iter().map(|(_, circuit)| circuit).collect();
32+
33+
Self { circuits, rom }
34+
}
35+
}
36+
2537
impl<E1> arecibo::supernova::NonUniformCircuit<E1> for EpochCircuitSequence<E1>
2638
where
2739
E1: CurveCycleEquipped,
@@ -52,6 +64,16 @@ enum EpochCircuit<F: PrimeField> {
5264
Update(UpdateCircuit<F>),
5365
}
5466

67+
impl<F: PrimeField> EpochCircuit<F> {
68+
pub fn new_insert(insertion_proof: InsertProof, rom_size: usize) -> Self {
69+
Self::Insert(InsertCircuit::new(insertion_proof, rom_size))
70+
}
71+
72+
pub fn new_update(update_proof: UpdateProof, rom_size: usize) -> Self {
73+
Self::Update(UpdateCircuit::new(update_proof, rom_size))
74+
}
75+
}
76+
5577
impl<F: PrimeField> StepCircuit<F> for EpochCircuit<F> {
5678
fn arity(&self) -> usize {
5779
match self {
@@ -85,3 +107,168 @@ impl<F: PrimeField> StepCircuit<F> for EpochCircuit<F> {
85107
}
86108
}
87109
}
110+
111+
#[cfg(test)]
112+
mod tests {
113+
use super::*;
114+
use crate::common::Hashchain;
115+
use crate::nova::utils::Digest as NovaDigest;
116+
use crate::tree::*;
117+
use arecibo::provider::{PallasEngine, VestaEngine};
118+
use arecibo::supernova::{PublicParams, RecursiveSNARK, TrivialTestCircuit};
119+
use arecibo::traits::snark::default_ck_hint;
120+
use ff::Field;
121+
use jmt::mock::MockTreeStore;
122+
use jmt::KeyHash;
123+
use rand::{rngs::StdRng, Rng, SeedableRng};
124+
use std::sync::Arc;
125+
126+
use std::collections::HashSet;
127+
128+
struct TestTreeState {
129+
pub tree: KeyDirectoryTree<MockTreeStore>,
130+
inserted_keys: HashSet<KeyHash>,
131+
}
132+
133+
impl TestTreeState {
134+
fn new() -> Self {
135+
let store = Arc::new(MockTreeStore::default());
136+
let tree = KeyDirectoryTree::new(store);
137+
Self {
138+
tree,
139+
inserted_keys: HashSet::new(),
140+
}
141+
}
142+
}
143+
144+
fn create_random_insert(state: &mut TestTreeState, rng: &mut StdRng) -> InsertProof {
145+
loop {
146+
let random_string: String = (0..10)
147+
.map(|_| rng.sample(rand::distributions::Alphanumeric) as char)
148+
.collect();
149+
let hc = Hashchain::new(random_string);
150+
let key = hc.get_keyhash();
151+
152+
if !state.inserted_keys.contains(&key) {
153+
let proof = state.tree.insert(key, hc).expect("Insert should succeed");
154+
state.inserted_keys.insert(key);
155+
return proof;
156+
}
157+
}
158+
}
159+
160+
fn create_random_update(state: &mut TestTreeState, rng: &mut StdRng) -> UpdateProof {
161+
if state.inserted_keys.is_empty() {
162+
panic!("No keys have been inserted yet. Cannot perform update.");
163+
}
164+
165+
let key = *state
166+
.inserted_keys
167+
.iter()
168+
.nth(rng.gen_range(0..state.inserted_keys.len()))
169+
.unwrap();
170+
let mut hc = state.tree.get(key).unwrap().unwrap();
171+
172+
let random_string: String = (0..10)
173+
.map(|_| rng.sample(rand::distributions::Alphanumeric) as char)
174+
.collect();
175+
hc.add(random_string)
176+
.expect("Adding to hashchain should succeed");
177+
178+
state.tree.update(key, hc).expect("Update should succeed")
179+
}
180+
181+
#[test]
182+
fn test_recursive_epoch_circuit_proof() {
183+
type E1 = PallasEngine;
184+
type E2 = VestaEngine;
185+
186+
let mut state = TestTreeState::new();
187+
let mut rng = StdRng::from_entropy();
188+
189+
let operations = vec![
190+
(
191+
0,
192+
EpochCircuit::new_insert(create_random_insert(&mut state, &mut rng), 4),
193+
),
194+
(
195+
1,
196+
EpochCircuit::new_update(create_random_update(&mut state, &mut rng), 4),
197+
),
198+
(
199+
0,
200+
EpochCircuit::new_insert(create_random_insert(&mut state, &mut rng), 4),
201+
),
202+
(
203+
1,
204+
EpochCircuit::new_update(create_random_update(&mut state, &mut rng), 4),
205+
),
206+
];
207+
let circuit_sequence = EpochCircuitSequence::<E1>::new(operations);
208+
let secondary_circuit = TrivialSecondaryCircuit::<<E2 as Engine>::Scalar>::default();
209+
210+
let pp = PublicParams::setup(&circuit_sequence, &*default_ck_hint(), &*default_ck_hint());
211+
212+
let initial_commitment: <E1 as Engine>::Scalar =
213+
NovaDigest::new(state.tree.get_commitment().unwrap())
214+
.to_scalar()
215+
.unwrap();
216+
let mut z0_primary = vec![initial_commitment]; // Initial root
217+
z0_primary.push(<E1 as Engine>::Scalar::ZERO); // Initial ROM index
218+
z0_primary.extend(
219+
circuit_sequence
220+
.rom
221+
.iter()
222+
.map(|&x| <E1 as Engine>::Scalar::from(x as u64)),
223+
);
224+
let z0_secondary = vec![<<Dual<E1> as Engine>::Scalar>::ONE];
225+
226+
// Initialize RecursiveSNARK
227+
let mut recursive_snark = RecursiveSNARK::<E1>::new(
228+
&pp,
229+
&circuit_sequence,
230+
&circuit_sequence.circuits[0],
231+
&secondary_circuit,
232+
&z0_primary,
233+
&z0_secondary,
234+
)
235+
.unwrap();
236+
237+
// Prove steps
238+
for circuit in &circuit_sequence.circuits {
239+
recursive_snark
240+
.prove_step(&pp, circuit, &secondary_circuit)
241+
.unwrap();
242+
243+
// Verify after each step
244+
recursive_snark
245+
.verify(&pp, &z0_primary, &z0_secondary)
246+
.unwrap();
247+
}
248+
249+
// Final verification
250+
assert!(recursive_snark
251+
.verify(&pp, &z0_primary, &z0_secondary)
252+
.is_ok());
253+
254+
// Additional assertions
255+
let zi_primary = &recursive_snark.zi_primary();
256+
257+
println!("Final primary state: {:?}", zi_primary);
258+
259+
assert_eq!(
260+
zi_primary.len(),
261+
z0_primary.len(),
262+
"Primary state vector length should remain constant"
263+
);
264+
265+
let final_commitment: <E1 as Engine>::Scalar =
266+
NovaDigest::new(state.tree.get_commitment().unwrap())
267+
.to_scalar()
268+
.unwrap();
269+
assert_eq!(
270+
zi_primary[0], final_commitment,
271+
"Final commitment should match the tree state"
272+
);
273+
}
274+
}

src/nova/insert.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ pub struct InsertCircuit<F> {
1212
_phantom: std::marker::PhantomData<F>,
1313
}
1414

15+
impl<F: PrimeField> InsertCircuit<F> {
16+
pub fn new(insertion_proof: InsertProof, rom_size: usize) -> Self {
17+
Self {
18+
insertion_proof,
19+
rom_size,
20+
_phantom: std::marker::PhantomData,
21+
}
22+
}
23+
}
24+
1525
impl<F> StepCircuit<F> for InsertCircuit<F>
1626
where
1727
F: PrimeField,
@@ -44,12 +54,12 @@ where
4454
pc,
4555
)?;
4656

47-
cs.push_namespace(|| {
48-
format!(
49-
"insert_proof {:?}",
50-
self.insertion_proof.non_membership_proof.root
51-
)
52-
});
57+
// cs.push_namespace(|| {
58+
// format!(
59+
// "insert_proof {:?}",
60+
// self.insertion_proof.non_membership_proof.root
61+
// )
62+
// });
5363

5464
let pre_insertion_scalar = Digest::new(self.insertion_proof.non_membership_proof.root)
5565
.to_scalar()
@@ -74,7 +84,7 @@ where
7484
.verify()
7585
.map_err(|_| SynthesisError::Unsatisfiable)?;
7686

77-
cs.pop_namespace();
87+
// cs.pop_namespace();
7888

7989
// Prepare the next state vector
8090
let mut z_next = vec![new_root];

src/nova/mod.rs

Lines changed: 0 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -2,123 +2,3 @@ pub mod batch;
22
pub mod insert;
33
pub mod update;
44
pub mod utils;
5-
6-
#[cfg(test)]
7-
mod tests {
8-
use crate::common::Hashchain;
9-
use crate::tree::{Hasher, KeyDirectoryTree, SnarkableTree};
10-
use jmt::mock::MockTreeStore;
11-
use jmt::KeyHash;
12-
use std::sync::Arc;
13-
14-
#[test]
15-
fn test_key_directory_tree() {
16-
let store = Arc::new(MockTreeStore::default());
17-
let mut tree = KeyDirectoryTree::new(store);
18-
19-
println!("Initial tree state: {:?}", tree.get_commitment());
20-
21-
// Test insert
22-
let hc1 = Hashchain::new("key_1".into());
23-
let key1 = hc1.get_keyhash();
24-
let insert_proof = tree
25-
.insert(key1, hc1.clone())
26-
.expect("Insert should succeed");
27-
assert!(insert_proof.verify().is_ok());
28-
// tree.write_batch().expect("Write batch should succeed");
29-
30-
println!("After first insert: {:?}", tree.get_commitment());
31-
32-
// Test get after insert
33-
// Test get after insert
34-
let get_result = tree.get(key1).expect("Get should succeed");
35-
println!("Get result after insert: {:?}", get_result);
36-
assert_eq!(get_result.expect("Key should exist"), hc1);
37-
38-
// Test update
39-
let mut hc1_updated = hc1.clone();
40-
hc1_updated
41-
.add("new_value".into())
42-
.expect("Add to hashchain should succeed");
43-
let update_proof = tree
44-
.update(key1, hc1_updated.clone())
45-
.expect("Update should succeed");
46-
assert!(update_proof.verify().is_ok());
47-
// tree.write_batch().expect("Write batch should succeed");
48-
49-
// Test get after update
50-
let get_result_after_update = tree.get(key1).expect("Get should succeed");
51-
assert_eq!(
52-
get_result_after_update.expect("Key should exist"),
53-
hc1_updated
54-
);
55-
56-
// Test insert duplicate key
57-
let insert_duplicate_result = tree.insert(key1, hc1.clone());
58-
assert!(insert_duplicate_result.is_err());
59-
60-
// Test update non-existing key
61-
let non_existing_key = KeyHash::with::<Hasher>(b"non_existing_key");
62-
let update_non_existing_result = tree.update(non_existing_key, hc1.clone());
63-
assert!(update_non_existing_result.is_err());
64-
65-
// Test get non-existing key
66-
let get_non_existing_result = tree.get(non_existing_key).expect("Get should not fail");
67-
assert!(get_non_existing_result.is_err());
68-
if let Err(non_membership_proof) = get_non_existing_result {
69-
assert!(non_membership_proof.verify().is_ok());
70-
}
71-
72-
// Test multiple inserts and updates
73-
let hc2 = Hashchain::new("key_2".into());
74-
let key2 = hc2.get_keyhash();
75-
tree.insert(key2, hc2.clone())
76-
.expect("Insert should succeed");
77-
// tree.write_batch().expect("Write batch should succeed");
78-
79-
let mut hc2_updated = hc2.clone();
80-
hc2_updated
81-
.add("value2".into())
82-
.expect("Add to hashchain should succeed");
83-
tree.update(key2, hc2_updated.clone())
84-
.expect("Update should succeed");
85-
// tree.write_batch().expect("Write batch should succeed");
86-
87-
assert_eq!(tree.get(key2).unwrap().unwrap(), hc2_updated);
88-
89-
// Test root hash changes
90-
let root_before = tree
91-
.get_commitment()
92-
.expect("Get commitment should succeed");
93-
let hc3 = Hashchain::new("key_3".into());
94-
let key3 = hc3.get_keyhash();
95-
tree.insert(key3, hc3).expect("Insert should succeed");
96-
// tree.write_batch().expect("Write batch should succeed");
97-
let root_after = tree
98-
.get_commitment()
99-
.expect("Get commitment should succeed");
100-
101-
assert_ne!(root_before, root_after);
102-
103-
// Test batch writing
104-
let hc4 = Hashchain::new("key_4".into());
105-
let hc5 = Hashchain::new("key_5".into());
106-
let key4 = hc4.get_keyhash();
107-
let key5 = hc5.get_keyhash();
108-
109-
tree.insert(key4, hc4.clone())
110-
.expect("Insert should succeed");
111-
tree.insert(key5, hc5.clone())
112-
.expect("Insert should succeed");
113-
114-
// Before writing the batch
115-
assert!(tree.get(key4).unwrap().is_err());
116-
assert!(tree.get(key5).unwrap().is_err());
117-
118-
// tree.write_batch().expect("Write batch should succeed");
119-
120-
// After writing the batch
121-
assert_eq!(tree.get(key4).unwrap().unwrap(), hc4);
122-
assert_eq!(tree.get(key5).unwrap().unwrap(), hc5);
123-
}
124-
}

0 commit comments

Comments
 (0)