1use std::{borrow::BorrowMut, marker::PhantomData};
15
16use binius_compute::{Allocator, GlobalAllocator};
17use binius_core::word::Word;
18use binius_field::{Field, PackedField};
19use binius_hash_prover::{BinaryMerkleTree, ParallelHashSuite};
20use binius_iop::merkle_tree::MerkleTreeScheme;
21use binius_ip_prover::channel::{IPProverChannel, WordIPProverChannel};
22use binius_math::FieldSlice;
23use binius_transcript::{ProverTranscript, fiat_shamir::Challenger};
24use binius_utils::{SerializeBytes, checked_arithmetics::checked_log_2};
25use digest::Output;
26
27use crate::{
28 channel::grinding::GrindingProverChannel,
29 merkle_tree::{MerkleTreeProver, prover::BinaryMerkleTreeProver},
30};
31
32pub trait MerkleIPProverChannel<F: Field>: WordIPProverChannel<F> {
37 type Commitment;
39
40 fn send_merkle_commitment<P: PackedField<Scalar = F>>(
50 &mut self,
51 data: FieldSlice<'_, P>,
52 leaf_size: usize,
53 ) -> Self::Commitment;
54
55 fn send_openings<P: PackedField<Scalar = F>>(
64 &mut self,
65 commitment: &Self::Commitment,
66 data: FieldSlice<'_, P>,
67 indices: &[Self::Word],
68 );
69
70 fn send_committed_vector<P: PackedField<Scalar = F>>(
76 &mut self,
77 commitment: &Self::Commitment,
78 data: FieldSlice<'_, P>,
79 );
80}
81
82pub struct ProverMerkleTranscriptChannel<
88 T,
89 Challenger_,
90 F,
91 H: ParallelHashSuite,
92 A: Allocator = GlobalAllocator,
93> {
94 transcript: T,
95 merkle_prover: BinaryMerkleTreeProver<F, H, A>,
96 _challenger_marker: PhantomData<Challenger_>,
97}
98
99impl<T, Challenger_, F, H: ParallelHashSuite> ProverMerkleTranscriptChannel<T, Challenger_, F, H> {
100 pub fn new(transcript: T) -> Self {
102 Self::with_merkle_prover(transcript, BinaryMerkleTreeProver::new())
103 }
104}
105
106impl<T, Challenger_, F, H: ParallelHashSuite, A: Allocator>
107 ProverMerkleTranscriptChannel<T, Challenger_, F, H, A>
108{
109 pub const fn with_merkle_prover(
113 transcript: T,
114 merkle_prover: BinaryMerkleTreeProver<F, H, A>,
115 ) -> Self {
116 Self {
117 transcript,
118 merkle_prover,
119 _challenger_marker: PhantomData,
120 }
121 }
122
123 pub fn into_transcript(self) -> T {
125 self.transcript
126 }
127}
128
129pub struct ProverMerkleCommitment<Committed> {
132 committed: Committed,
133 depth: usize,
134 log_leaf_size: usize,
135}
136
137impl<Committed> ProverMerkleCommitment<Committed> {
138 pub const fn new(committed: Committed, depth: usize, log_leaf_size: usize) -> Self {
146 Self {
147 committed,
148 depth,
149 log_leaf_size,
150 }
151 }
152}
153
154impl<F, T, Challenger_, H, A> IPProverChannel<F>
155 for ProverMerkleTranscriptChannel<T, Challenger_, F, H, A>
156where
157 F: Field,
158 T: BorrowMut<ProverTranscript<Challenger_>>,
159 Challenger_: Challenger,
160 H: ParallelHashSuite,
161 A: Allocator,
162{
163 fn send_one(&mut self, elem: F) {
164 self.transcript.borrow_mut().send_one(elem);
165 }
166
167 fn send_many(&mut self, elems: &[F]) {
168 self.transcript.borrow_mut().send_many(elems);
169 }
170
171 fn observe_one(&mut self, val: F) {
172 self.transcript.borrow_mut().observe_one(val);
173 }
174
175 fn observe_many(&mut self, vals: &[F]) {
176 self.transcript.borrow_mut().observe_many(vals);
177 }
178
179 fn sample(&mut self) -> F {
180 IPProverChannel::sample(self.transcript.borrow_mut())
181 }
182}
183
184impl<F, T, Challenger_, H, A> WordIPProverChannel<F>
185 for ProverMerkleTranscriptChannel<T, Challenger_, F, H, A>
186where
187 F: Field,
188 T: BorrowMut<ProverTranscript<Challenger_>>,
189 Challenger_: Challenger,
190 H: ParallelHashSuite,
191 A: Allocator,
192{
193 type Word = Word;
194
195 fn observe_words(&mut self, words: &[Word]) {
196 WordIPProverChannel::<F>::observe_words(self.transcript.borrow_mut(), words);
197 }
198
199 fn sample_bits(&mut self, bits: usize) -> Word {
200 WordIPProverChannel::<F>::sample_bits(self.transcript.borrow_mut(), bits)
201 }
202}
203
204impl<T, Challenger_, F, H: ParallelHashSuite, A: Allocator> GrindingProverChannel
205 for ProverMerkleTranscriptChannel<T, Challenger_, F, H, A>
206where
207 T: BorrowMut<ProverTranscript<Challenger_>>,
208 Challenger_: Challenger + Clone,
209{
210 fn grind(&mut self, bits: usize) -> u64 {
211 if bits == 0 {
213 return 0;
214 }
215 self.transcript.borrow_mut().grind(bits)
216 }
217}
218
219impl<F, T, Challenger_, H, A> MerkleIPProverChannel<F>
220 for ProverMerkleTranscriptChannel<T, Challenger_, F, H, A>
221where
222 F: Field,
223 T: BorrowMut<ProverTranscript<Challenger_>>,
224 Challenger_: Challenger,
225 H: ParallelHashSuite,
226 A: Allocator,
227 Output<H::LeafHash>: SerializeBytes,
228{
229 type Commitment = ProverMerkleCommitment<BinaryMerkleTree<Output<H::LeafHash>, A>>;
230
231 fn send_merkle_commitment<P: PackedField<Scalar = F>>(
232 &mut self,
233 data: FieldSlice<'_, P>,
234 leaf_size: usize,
235 ) -> Self::Commitment {
236 assert!(leaf_size.is_power_of_two(), "precondition: leaf_size must be a power of two");
237 let log_leaf_size = checked_log_2(leaf_size);
238 let (commitment, committed) = self.merkle_prover.commit_field_buffer(data, log_leaf_size);
239 self.transcript
240 .borrow_mut()
241 .message()
242 .write(&commitment.root);
243 ProverMerkleCommitment::new(committed, commitment.depth, log_leaf_size)
244 }
245
246 fn send_openings<P: PackedField<Scalar = F>>(
247 &mut self,
248 commitment: &Self::Commitment,
249 data: FieldSlice<'_, P>,
250 indices: &[Word],
251 ) {
252 let tree_depth = commitment.depth;
253 debug_assert_eq!(tree_depth, data.log_len() - commitment.log_leaf_size);
254 let indices = indices
255 .iter()
256 .map(|index| index.as_u64() as usize)
257 .collect::<Vec<_>>();
258 assert!(indices.iter().all(|&index| index < 1 << tree_depth)); let scheme = self.merkle_prover.scheme();
263 let layer_depth = scheme.optimal_verify_layer(indices.len(), tree_depth);
264 let layer = self.merkle_prover.layer(&commitment.committed, layer_depth);
265 let mut advice = self.transcript.borrow_mut().decommitment();
266 advice.write_slice(layer);
267 for &index in &indices {
268 let leaf = data.chunk(commitment.log_leaf_size, index);
269 advice.write_scalar_iter(leaf.iter_scalars());
270 self.merkle_prover.prove_opening(
271 &commitment.committed,
272 layer_depth,
273 index,
274 &mut advice,
275 );
276 }
277 }
278
279 fn send_committed_vector<P: PackedField<Scalar = F>>(
280 &mut self,
281 commitment: &Self::Commitment,
282 data: FieldSlice<'_, P>,
283 ) {
284 debug_assert_eq!(commitment.depth, data.log_len() - commitment.log_leaf_size);
285
286 let mut advice = self.transcript.borrow_mut().decommitment();
289 advice.write_scalar_iter(data.iter_scalars());
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use binius_core::word::Word;
296 use binius_field::{Ghash128b as B128, PackedGhash2x128b};
297 use binius_hash::{StdDigest, StdHashSuite};
298 use binius_iop::{
299 channel::grinding::GrindingVerifierChannel,
300 merkle_channel::{MerkleIPVerifierChannel, VerifierMerkleTranscriptChannel},
301 };
302 use binius_ip::channel::{IPVerifierChannel, WordIPVerifierChannel};
303 use binius_math::{FieldBuffer, test_utils::random_scalars};
304 use binius_transcript::{
305 Error as TranscriptError, ProverTranscript, fiat_shamir::HasherChallenger,
306 };
307 use rand::prelude::*;
308
309 use super::{
310 GrindingProverChannel, IPProverChannel, MerkleIPProverChannel, ProverMerkleCommitment,
311 ProverMerkleTranscriptChannel,
312 };
313 use crate::merkle_tree::{MerkleTreeProver, prover::BinaryMerkleTreeProver};
314
315 type StdChallenger = HasherChallenger<StdDigest>;
316 type P = PackedGhash2x128b;
317 type VerifierChannel<T> = VerifierMerkleTranscriptChannel<T, StdChallenger, B128, StdHashSuite>;
318 type ProverChannel<T> = ProverMerkleTranscriptChannel<T, StdChallenger, B128, StdHashSuite>;
319
320 const LOG_LEN: usize = 8;
321 const LOG_LEAF_SIZE: usize = 2;
322 const LEAF_SIZE: usize = 1 << LOG_LEAF_SIZE;
323 const DEPTH: usize = LOG_LEN - LOG_LEAF_SIZE;
324 const N_QUERIES: usize = 5;
325
326 fn sample_indices<Channel: MerkleIPProverChannel<B128>>(
327 channel: &mut Channel,
328 ) -> Vec<Channel::Word> {
329 (0..N_QUERIES).map(|_| channel.sample_bits(DEPTH)).collect()
330 }
331
332 #[test]
333 fn test_merkle_channel_roundtrip() {
334 let mut rng = StdRng::seed_from_u64(0);
335
336 let scalars = random_scalars::<B128>(&mut rng, 1 << LOG_LEN);
337 let data = FieldBuffer::<P, _>::from_values(&scalars);
338
339 let mut prover_channel =
341 ProverChannel::new(ProverTranscript::new(StdChallenger::default()));
342 let commitment = prover_channel.send_merkle_commitment(data.as_view(), LEAF_SIZE);
343 let indices = sample_indices(&mut prover_channel);
344 prover_channel.send_openings(&commitment, data.as_view(), &indices);
345 prover_channel.send_committed_vector(&commitment, data.as_view());
346
347 let transcript = prover_channel.into_transcript().into_verifier();
349 let mut verifier_channel = VerifierChannel::new(transcript);
350 let commitment = verifier_channel
351 .recv_merkle_commitment(LEAF_SIZE, DEPTH)
352 .unwrap();
353 let verifier_indices = (0..N_QUERIES)
354 .map(|_| verifier_channel.sample_bits(DEPTH))
355 .collect::<Vec<_>>();
356 assert_eq!(verifier_indices, indices);
357
358 let values = verifier_channel
359 .recv_openings(&commitment, &indices)
360 .unwrap();
361 assert_eq!(values.len(), N_QUERIES * LEAF_SIZE);
362 for (chunk, index) in values.chunks(LEAF_SIZE).zip(&indices) {
363 let index = index.as_u64() as usize;
364 assert_eq!(chunk, &scalars[index * LEAF_SIZE..(index + 1) * LEAF_SIZE]);
365 }
366
367 let vector = verifier_channel.recv_committed_vector(&commitment).unwrap();
368 assert_eq!(vector, scalars);
369
370 verifier_channel.into_transcript().finalize().unwrap();
371 }
372
373 #[test]
374 fn a_commitment_rebuilt_after_it_was_sent_opens_like_the_original() {
375 let mut rng = StdRng::seed_from_u64(0);
382 let scalars = random_scalars::<B128>(&mut rng, 1 << LOG_LEN);
383 let data = FieldBuffer::<P, _>::from_values(&scalars);
384 let rebuild = || {
385 let (commitment, tree) = BinaryMerkleTreeProver::<B128, StdHashSuite>::new()
386 .commit_field_buffer(data.as_view(), LOG_LEAF_SIZE);
387 (commitment.root, ProverMerkleCommitment::new(tree, commitment.depth, LOG_LEAF_SIZE))
388 };
389
390 let open_through = |rebuilt: bool| {
391 let mut prover_channel =
392 ProverChannel::new(ProverTranscript::new(StdChallenger::default()));
393 let sent = prover_channel.send_merkle_commitment(data.as_view(), LEAF_SIZE);
394 let commitment = if rebuilt {
395 drop(sent);
396 rebuild().1
397 } else {
398 sent
399 };
400 let indices = sample_indices(&mut prover_channel);
401 prover_channel.send_openings(&commitment, data.as_view(), &indices);
402 prover_channel.into_transcript().finalize()
403 };
404 assert_eq!(open_through(true), open_through(false));
405
406 let mut prover_channel =
407 ProverChannel::new(ProverTranscript::new(StdChallenger::default()));
408 prover_channel.send_merkle_commitment(data.as_view(), LEAF_SIZE);
409 let transcript = prover_channel.into_transcript().into_verifier();
410 let mut verifier_channel = VerifierChannel::new(transcript);
411 let received = verifier_channel
412 .recv_merkle_commitment(LEAF_SIZE, DEPTH)
413 .unwrap();
414 assert_eq!(received.commitment.root, rebuild().0);
415 }
416
417 #[test]
418 fn a_grind_round_trips_and_zero_bits_is_not_a_grind() {
419 const BITS: usize = 4;
426
427 let mut prover_channel =
428 ProverChannel::new(ProverTranscript::new(StdChallenger::default()));
429 prover_channel.grind(BITS);
430 let challenge = IPProverChannel::<B128>::sample(&mut prover_channel);
431
432 let mut transcript = ProverChannel::into_transcript(prover_channel).into_verifier();
433 {
434 let mut verifier_channel = VerifierChannel::new(&mut transcript);
435 verifier_channel.verify_grind(BITS).unwrap();
436 assert_eq!(IPVerifierChannel::<B128>::sample(&mut verifier_channel), challenge);
438 }
439 transcript.finalize().unwrap();
440
441 let write = |bits: Option<usize>| {
444 let mut channel = ProverChannel::new(ProverTranscript::new(StdChallenger::default()));
445 if let Some(bits) = bits {
446 channel.grind(bits);
447 }
448 let challenge = IPProverChannel::<B128>::sample(&mut channel);
449 (ProverChannel::into_transcript(channel).finalize(), challenge)
450 };
451 assert_eq!(write(Some(0)), write(None));
452 }
453
454 #[test]
455 fn a_grind_checked_at_the_wrong_difficulty_is_rejected() {
456 let mut prover_channel =
462 ProverChannel::new(ProverTranscript::new(StdChallenger::default()));
463 prover_channel.grind(4);
464
465 let mut transcript = ProverChannel::into_transcript(prover_channel).into_verifier();
466 let mut verifier_channel = VerifierChannel::new(&mut transcript);
467 let err = verifier_channel
468 .verify_grind(24)
469 .expect_err("four bits of work cannot satisfy a twenty-four bit demand");
470 let TranscriptError::InsufficientWork { bits, sampled } = err else {
471 panic!("expected unmet proof of work, got {err}")
472 };
473 assert_eq!(bits, 24);
474 assert_ne!(sampled, 0);
475 }
476
477 #[test]
478 fn test_merkle_channel_borrowed_transcript() {
479 let mut rng = StdRng::seed_from_u64(0);
480
481 let scalars = random_scalars::<B128>(&mut rng, 1 << LOG_LEN);
482 let data = FieldBuffer::<P, _>::from_values(&scalars);
483
484 let mut prover_transcript = ProverTranscript::new(StdChallenger::default());
485 {
486 let mut prover_channel = ProverChannel::new(&mut prover_transcript);
487 let commitment = prover_channel.send_merkle_commitment(data.as_view(), LEAF_SIZE);
488 let indices = sample_indices(&mut prover_channel);
489 prover_channel.send_openings(&commitment, data.as_view(), &indices);
490 }
491
492 let mut verifier_transcript = prover_transcript.into_verifier();
493 {
494 let mut verifier_channel = VerifierChannel::new(&mut verifier_transcript);
495 let commitment = verifier_channel
496 .recv_merkle_commitment(LEAF_SIZE, DEPTH)
497 .unwrap();
498 let indices = (0..N_QUERIES)
499 .map(|_| verifier_channel.sample_bits(DEPTH))
500 .collect::<Vec<_>>();
501 let values = verifier_channel
502 .recv_openings(&commitment, &indices)
503 .unwrap();
504 for (chunk, index) in values.chunks(LEAF_SIZE).zip(&indices) {
505 let index = index.as_u64() as usize;
506 assert_eq!(chunk, &scalars[index * LEAF_SIZE..(index + 1) * LEAF_SIZE]);
507 }
508 }
509 verifier_transcript.finalize().unwrap();
510 }
511
512 #[test]
513 fn test_merkle_channel_rejects_openings_at_wrong_index() {
514 let mut rng = StdRng::seed_from_u64(0);
515
516 let scalars = random_scalars::<B128>(&mut rng, 1 << LOG_LEN);
517 let data = FieldBuffer::<P, _>::from_values(&scalars);
518
519 let mut prover_channel =
520 ProverChannel::new(ProverTranscript::new(StdChallenger::default()));
521 let commitment = prover_channel.send_merkle_commitment(data.as_view(), LEAF_SIZE);
522 let indices = sample_indices(&mut prover_channel);
523 prover_channel.send_openings(&commitment, data.as_view(), &indices);
524
525 let transcript = prover_channel.into_transcript().into_verifier();
526 let mut verifier_channel = VerifierChannel::new(transcript);
527 let commitment = verifier_channel
528 .recv_merkle_commitment(LEAF_SIZE, DEPTH)
529 .unwrap();
530 let _ = (0..N_QUERIES)
531 .map(|_| verifier_channel.sample_bits(DEPTH))
532 .collect::<Vec<_>>();
533
534 let wrong_indices = indices
536 .iter()
537 .map(|&index| index ^ Word::ONE)
538 .collect::<Vec<_>>();
539 assert!(
540 verifier_channel
541 .recv_openings(&commitment, &wrong_indices)
542 .is_err()
543 );
544
545 let _ = verifier_channel.into_transcript();
547 }
548
549 #[test]
550 fn test_merkle_channel_rejects_wrong_root() {
551 let mut rng = StdRng::seed_from_u64(0);
552
553 let scalars = random_scalars::<B128>(&mut rng, 1 << LOG_LEN);
554 let data = FieldBuffer::<P, _>::from_values(&scalars);
555 let other_scalars = random_scalars::<B128>(&mut rng, 1 << LOG_LEN);
556 let other_data = FieldBuffer::<P, _>::from_values(&other_scalars);
557
558 let mut prover_channel =
560 ProverChannel::new(ProverTranscript::new(StdChallenger::default()));
561 let commitment = prover_channel.send_merkle_commitment(data.as_view(), LEAF_SIZE);
562 let other_commitment =
563 prover_channel.send_merkle_commitment(other_data.as_view(), LEAF_SIZE);
564 let indices = sample_indices(&mut prover_channel);
565 prover_channel.send_openings(&other_commitment, other_data.as_view(), &indices);
566 let _ = commitment;
567
568 let transcript = prover_channel.into_transcript().into_verifier();
569 let mut verifier_channel = VerifierChannel::new(transcript);
570 let commitment = verifier_channel
571 .recv_merkle_commitment(LEAF_SIZE, DEPTH)
572 .unwrap();
573 let _other_commitment = verifier_channel
574 .recv_merkle_commitment(LEAF_SIZE, DEPTH)
575 .unwrap();
576 let indices = (0..N_QUERIES)
577 .map(|_| verifier_channel.sample_bits(DEPTH))
578 .collect::<Vec<_>>();
579
580 assert!(
583 verifier_channel
584 .recv_openings(&commitment, &indices)
585 .is_err()
586 );
587
588 let _ = verifier_channel.into_transcript();
589 }
590}