binius_iop_prover/channel/mod.rs
1// Copyright 2026 The Binius Developers
2
3//! Channel abstraction for interactive oracle protocol (IOP) provers.
4
5pub mod grinding;
6pub mod merge;
7pub mod naive;
8
9use binius_compute::Allocator;
10use binius_field::PackedField;
11use binius_iop::channel::OracleSpec;
12use binius_ip_prover::channel::IPProverChannel;
13use binius_math::{FieldSlice, FieldVec, StructuredBuffer};
14
15/// Channel for IOP provers that extends the IP prover channel with oracle operations.
16///
17/// In an IOP, the prover can:
18/// 1. Send field elements to the verifier via `send_*` methods (inherited)
19/// 2. Sample random challenges via `sample` (inherited)
20/// 3. Commit oracles to the verifier
21/// 4. Respond to oracle queries with opening proofs
22///
23/// # Contract
24///
25/// The caller must call `send_oracle()` exactly `remaining_oracle_specs().len()` times before
26/// calling `prove_oracle_relation()`. Each oracle buffer must match the corresponding
27/// specification. Every committed oracle must be handed back to the channel exactly once with
28/// `finalize_oracle()`.
29pub trait IOPProverChannel<P: PackedField, A: Allocator>: IPProverChannel<P::Scalar> {
30 type Oracle: Clone;
31
32 /// Returns the specifications for the remaining oracles to be committed.
33 ///
34 /// This slice shrinks as oracles are committed via `send_oracle()`.
35 fn remaining_oracle_specs(&self) -> &[OracleSpec];
36
37 /// Commits an oracle to the verifier.
38 ///
39 /// # Preconditions
40 ///
41 /// * `remaining_oracle_specs()` must be non-empty.
42 /// * `buffer.log_len()` must match the expected length from the next oracle spec.
43 fn send_oracle(&mut self, buffer: FieldSlice<'_, P>) -> Self::Oracle;
44
45 /// Generates an opening proof for one oracle linear relation.
46 ///
47 /// The relation asserts that `<oracle_poly, transparent> = claim`. An oracle may carry any
48 /// number of relations.
49 ///
50 /// The transparent may be zero outside one aligned block, and say so through its structure. A
51 /// channel that understands the structure skips the zeros; any other materializes it.
52 ///
53 /// The channel owns the transparent multilinear until the opening runs, so it is drawn from
54 /// the caller's allocator `A` — a pooled buffer stays pooled all the way through the opening.
55 ///
56 /// # Preconditions
57 ///
58 /// * `remaining_oracle_specs()` must be empty (all oracles committed).
59 /// * `oracle` must be a valid handle returned by `send_oracle()`.
60 /// * `transparent.log_len()` must match the oracle's message length.
61 /// * The claim must already be bound to the transcript, since the coefficient that batches the
62 /// queued relations is drawn only after the queue closes.
63 fn prove_oracle_relation(
64 &mut self,
65 oracle: Self::Oracle,
66 transparent: StructuredBuffer<P, A::Vec<P>>,
67 claim: P::Scalar,
68 );
69
70 /// Gives ownership of the oracle buffer to the channel.
71 ///
72 /// The [`Self::send_oracle`] method takes a borrowed reference to an oracle buffer and returns
73 /// a handle to it. In order to prove the oracle relations without unnecessarily cloning the
74 /// buffer, some channel implementations require ownership of the buffer.
75 ///
76 /// # Preconditions
77 ///
78 /// * `oracle` must be a valid handle returned by `send_oracle()`, not already finalized.
79 /// * `buffer` must equal the buffer previously committed via `send_oracle()`.
80 fn finalize_oracle(&mut self, oracle: Self::Oracle, buffer: FieldVec<P, A>);
81}