Skip to content

Commit 16afaa3

Browse files
committed
feat : updated challange indices logic for clear abstraction
1 parent 1b2529c commit 16afaa3

2 files changed

Lines changed: 73 additions & 36 deletions

File tree

benches/zook_vs_whir.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ use whir::{
3333
parameters::ProtocolParameters,
3434
protocols::{
3535
params::{
36-
DecodingRegime, FoldingFactor, KneeWeight, Mode, PowBudget, ProtocolConfig,
37-
RateSchedule, SecuritySpec, TuningSpec,
36+
DecodingRegime, FoldingFactor, Mode, PowBudget, ProtocolConfig, RateSchedule,
37+
SecuritySpec, TuningSpec,
3838
},
3939
whir as whir_non_zk,
4040
},
@@ -370,21 +370,15 @@ fn main() {
370370
Err(e) => eprintln!(" zook_standard_stepping failed: {e}"),
371371
}
372372

373-
eprintln!("[2^{log_size}] zook_zk_adaptive ...");
374-
match bench_zook(
375-
log_size,
376-
Mode::ZeroKnowledge,
377-
RateSchedule::Adaptive {
378-
knee_weight: KneeWeight::DEFAULT,
379-
},
380-
) {
373+
eprintln!("[2^{log_size}] zook_zk_stepping ...");
374+
match bench_zook(log_size, Mode::ZeroKnowledge, RateSchedule::Stepping) {
381375
Ok(s) => {
382376
let pb = s.proof_bytes;
383377
record_cell(
384378
&mut csv,
385379
log_size,
386380
size,
387-
"zook_zk_adaptive",
381+
"zook_zk_stepping",
388382
"commit",
389383
&s.commit,
390384
pb,
@@ -393,7 +387,7 @@ fn main() {
393387
&mut csv,
394388
log_size,
395389
size,
396-
"zook_zk_adaptive",
390+
"zook_zk_stepping",
397391
"prove",
398392
&s.prove,
399393
pb,
@@ -402,7 +396,7 @@ fn main() {
402396
&mut csv,
403397
log_size,
404398
size,
405-
"zook_zk_adaptive",
399+
"zook_zk_stepping",
406400
"verify",
407401
&s.verify,
408402
pb,

src/protocols/challenge_indices.rs

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,10 @@ where
2121
return if deduplicate { vec![0] } else { vec![0; count] };
2222
}
2323

24-
// Size the entropy chunk so `2^(8·size_bytes) ≥ next_pow2(num_leaves)`.
25-
// For pow2 `num_leaves`, the entropy space is an exact multiple of
26-
// `num_leaves` and rejection never triggers — bit-identical to the
27-
// pre-rejection implementation. For non-pow2 `num_leaves`, rejection
28-
// sampling eliminates the modular bias of a plain `% num_leaves`.
29-
let bits_needed = num_leaves.next_power_of_two().ilog2() as usize;
30-
let size_bytes = bits_needed.div_ceil(8);
31-
32-
// Largest multiple of `num_leaves` below `2^(8·size_bytes)`. u128
33-
// accommodates `size_bytes ≤ 16` without shift overflow on 64-bit hosts.
34-
let entropy_space: u128 = 1u128 << (8 * size_bytes);
35-
let num_leaves_u = num_leaves as u128;
36-
let threshold: u128 = (entropy_space / num_leaves_u) * num_leaves_u;
37-
24+
let domain = IndexDomain::new(num_leaves);
3825
let mut indices = Vec::with_capacity(count);
39-
while indices.len() < count {
40-
let mut candidate: u128 = 0;
41-
for _ in 0..size_bytes {
42-
candidate = (candidate << 8) | u128::from(transcript.verifier_message::<u8>());
43-
}
44-
if candidate < threshold {
45-
indices.push((candidate % num_leaves_u) as usize);
46-
}
47-
// else: candidate falls in the biased tail — reject and redraw.
26+
for _ in 0..count {
27+
indices.push(domain.sample(transcript));
4828
}
4929

5030
if deduplicate {
@@ -54,6 +34,69 @@ where
5434
indices
5535
}
5636

37+
/// Rejection-sampling domain for transcript-derived row indices.
38+
///
39+
/// For power-of-two domains, `entropy_space` is an exact multiple of
40+
/// `num_leaves`, so rejection never triggers and sampling is bit-identical to
41+
/// the legacy `% num_leaves` implementation. For non-power-of-two domains,
42+
/// candidates in the biased tail are rejected and redrawn.
43+
#[derive(Clone, Copy, Debug)]
44+
struct IndexDomain {
45+
num_leaves: usize,
46+
size_bytes: usize,
47+
threshold: u128,
48+
}
49+
50+
impl IndexDomain {
51+
fn new(num_leaves: usize) -> Self {
52+
debug_assert!(num_leaves > 1);
53+
let bits_needed = ceil_log2(num_leaves);
54+
let size_bytes = bits_needed.div_ceil(8);
55+
let entropy_bits = 8 * size_bytes;
56+
debug_assert!(entropy_bits < u128::BITS as usize);
57+
58+
let entropy_space = 1u128 << entropy_bits;
59+
let num_leaves_u = num_leaves as u128;
60+
let threshold = (entropy_space / num_leaves_u) * num_leaves_u;
61+
62+
Self {
63+
num_leaves,
64+
size_bytes,
65+
threshold,
66+
}
67+
}
68+
69+
fn sample<T>(&self, transcript: &mut T) -> usize
70+
where
71+
T: VerifierMessage,
72+
u8: Decoding<[T::U]>,
73+
{
74+
loop {
75+
let candidate = self.draw_candidate(transcript);
76+
if candidate < self.threshold {
77+
return (candidate % self.num_leaves as u128) as usize;
78+
}
79+
}
80+
}
81+
82+
fn draw_candidate<T>(&self, transcript: &mut T) -> u128
83+
where
84+
T: VerifierMessage,
85+
u8: Decoding<[T::U]>,
86+
{
87+
let mut candidate = 0u128;
88+
for _ in 0..self.size_bytes {
89+
candidate = (candidate << 8) | u128::from(transcript.verifier_message::<u8>());
90+
}
91+
candidate
92+
}
93+
}
94+
95+
fn ceil_log2(n: usize) -> usize {
96+
debug_assert!(n > 1);
97+
usize::BITS as usize - (n - 1).leading_zeros() as usize
98+
}
99+
57100
#[cfg(test)]
58101
mod tests {
59102
use super::*;

0 commit comments

Comments
 (0)