Skip to content

Commit 7999666

Browse files
committed
feat: implement circuit for no results in chunck
1 parent 561baf6 commit 7999666

File tree

2 files changed

+192
-0
lines changed

2 files changed

+192
-0
lines changed

verifiable-db/src/results_tree/extraction/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use public_inputs::PublicInputs;
44
pub(crate) mod child_included_single_path_node;
55
pub(crate) mod full_node;
66
pub(crate) mod no_child_included_single_path_node;
7+
pub(crate) mod no_results_in_chunk;
78
pub(crate) mod partial_node;
89
pub(crate) mod public_inputs;
910
pub(crate) mod record;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
use crate::results_tree::extraction::PublicInputs;
2+
use alloy::primitives::U256;
3+
use mp2_common::{
4+
public_inputs::PublicInputCommon,
5+
serialization::{deserialize, serialize},
6+
types::CBuilder,
7+
u256::CircuitBuilderU256,
8+
utils::{greater_than, ToTargets},
9+
D, F,
10+
};
11+
use plonky2::{
12+
hash::hash_types::{HashOut, HashOutTarget},
13+
iop::{
14+
target::Target,
15+
witness::{PartialWitness, WitnessWrite},
16+
},
17+
plonk::proof::ProofWithPublicInputsTarget,
18+
};
19+
use plonky2_ecgfp5::gadgets::curve::CircuitBuilderEcGFp5;
20+
use recursion_framework::circuit_builder::CircuitLogicWires;
21+
use serde::{Deserialize, Serialize};
22+
use std::iter;
23+
24+
#[derive(Clone, Debug, Serialize, Deserialize)]
25+
pub struct NoResultsInChunkWires {
26+
num_records: Target,
27+
#[serde(serialize_with = "serialize", deserialize_with = "deserialize")]
28+
results_tree_hash: HashOutTarget,
29+
offset_range_min: Target,
30+
offset_range_max: Target,
31+
}
32+
33+
#[derive(Clone, Debug, Serialize, Deserialize)]
34+
pub struct NoResultsInChunkCircuit {
35+
/// Number of records in the results tree
36+
pub(crate) num_records: F,
37+
/// Hash of the results tree
38+
pub(crate) results_tree_hash: HashOut<F>,
39+
/// Minimum offset range bound
40+
pub(crate) offset_range_min: F,
41+
/// Maximum offset range bound
42+
pub(crate) offset_range_max: F,
43+
}
44+
45+
impl NoResultsInChunkCircuit {
46+
pub fn build(b: &mut CBuilder) -> NoResultsInChunkWires {
47+
let zero_u256 = b.zero_u256();
48+
let curve_zero = b.curve_zero();
49+
let one = b.one();
50+
let ttrue = b._true();
51+
52+
let num_records = b.add_virtual_target();
53+
let results_tree_hash = b.add_virtual_hash();
54+
let [offset_range_min, offset_range_max] = b.add_virtual_target_arr();
55+
56+
// Ensure that the query is asking to retrieve results with an offset
57+
// being greater than the overall number of results
58+
let is_greater = greater_than(b, offset_range_min, num_records, 32);
59+
b.connect(is_greater.target, ttrue.target);
60+
61+
// Register the public inputs.
62+
PublicInputs::new(
63+
&results_tree_hash.to_targets(),
64+
&zero_u256.to_targets(),
65+
&zero_u256.to_targets(),
66+
&zero_u256.to_targets(),
67+
&[one; 2],
68+
&[one],
69+
&[num_records],
70+
&[offset_range_min],
71+
&[offset_range_max],
72+
&curve_zero.to_targets(),
73+
)
74+
.register(b);
75+
76+
NoResultsInChunkWires {
77+
num_records,
78+
results_tree_hash,
79+
offset_range_min,
80+
offset_range_max,
81+
}
82+
}
83+
84+
fn assign(&self, pw: &mut PartialWitness<F>, wires: &NoResultsInChunkWires) {
85+
pw.set_target(wires.num_records, self.num_records);
86+
pw.set_hash_target(wires.results_tree_hash, self.results_tree_hash);
87+
pw.set_target(wires.offset_range_min, self.offset_range_min);
88+
pw.set_target(wires.offset_range_max, self.offset_range_max);
89+
}
90+
}
91+
92+
/// Verified proof number = 0
93+
pub(crate) const NUM_VERIFIED_PROOFS: usize = 0;
94+
95+
impl CircuitLogicWires<F, D, NUM_VERIFIED_PROOFS> for NoResultsInChunkWires {
96+
type CircuitBuilderParams = ();
97+
type Inputs = NoResultsInChunkCircuit;
98+
99+
const NUM_PUBLIC_INPUTS: usize = PublicInputs::<F>::total_len();
100+
101+
fn circuit_logic(
102+
builder: &mut CBuilder,
103+
_verified_proofs: [&ProofWithPublicInputsTarget<D>; NUM_VERIFIED_PROOFS],
104+
_builder_parameters: Self::CircuitBuilderParams,
105+
) -> Self {
106+
Self::Inputs::build(builder)
107+
}
108+
109+
fn assign_input(&self, inputs: Self::Inputs, pw: &mut PartialWitness<F>) -> anyhow::Result<()> {
110+
inputs.assign(pw, self);
111+
Ok(())
112+
}
113+
}
114+
115+
#[cfg(test)]
116+
mod tests {
117+
use super::*;
118+
use mp2_common::C;
119+
use mp2_test::{
120+
circuit::{run_circuit, UserCircuit},
121+
utils::gen_random_field_hash,
122+
};
123+
use plonky2::field::types::Field;
124+
use plonky2_ecgfp5::curve::curve::WeierstrassPoint;
125+
use rand::{thread_rng, Rng};
126+
127+
impl UserCircuit<F, D> for NoResultsInChunkCircuit {
128+
type Wires = NoResultsInChunkWires;
129+
130+
fn build(b: &mut CBuilder) -> Self::Wires {
131+
NoResultsInChunkCircuit::build(b)
132+
}
133+
134+
fn prove(&self, pw: &mut PartialWitness<F>, wires: &Self::Wires) {
135+
self.assign(pw, wires);
136+
}
137+
}
138+
139+
#[test]
140+
fn test_no_results_in_chunk_circuit() {
141+
// Construct the witness.
142+
let mut rng = thread_rng();
143+
let num_records = F::from_canonical_u32(rng.gen());
144+
let results_tree_hash = gen_random_field_hash();
145+
let offset_range_min = num_records + F::ONE;
146+
let offset_range_max = offset_range_min + F::from_canonical_u32(rng.gen());
147+
148+
// Construct the circuit.
149+
let test_circuit = NoResultsInChunkCircuit {
150+
num_records,
151+
results_tree_hash,
152+
offset_range_min,
153+
offset_range_max,
154+
};
155+
156+
// Proof for the test circuit.
157+
let proof = run_circuit::<F, D, C, _>(test_circuit);
158+
let pi = PublicInputs::from_slice(&proof.public_inputs);
159+
160+
// Check the public inputs.
161+
// Tree hash
162+
assert_eq!(pi.tree_hash(), results_tree_hash);
163+
164+
// Min value
165+
assert_eq!(pi.min_value(), U256::ZERO);
166+
167+
// Max value
168+
assert_eq!(pi.max_value(), U256::ZERO);
169+
170+
// Primary index value
171+
assert_eq!(pi.primary_index_value(), U256::ZERO);
172+
173+
// Index ids
174+
assert_eq!(pi.index_ids(), [F::ONE; 2]);
175+
176+
// Min counter
177+
assert_eq!(pi.min_counter(), F::ONE);
178+
179+
// Max counter
180+
assert_eq!(pi.max_counter(), num_records);
181+
182+
// Offset range min
183+
assert_eq!(pi.offset_range_min(), offset_range_min);
184+
185+
// Offset range max
186+
assert_eq!(pi.offset_range_max(), offset_range_max);
187+
188+
// Accumulator
189+
assert_eq!(pi.accumulator(), WeierstrassPoint::NEUTRAL);
190+
}
191+
}

0 commit comments

Comments
 (0)