Skip to content

Commit e5a4936

Browse files
authored
feat: absorb OOD evals only once into the transcript (#382)
1 parent 8d3aa88 commit e5a4936

File tree

5 files changed

+59
-58
lines changed

5 files changed

+59
-58
lines changed

air/src/proof/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ mod queries;
2525
pub use queries::Queries;
2626

2727
mod ood_frame;
28-
pub use ood_frame::{OodFrame, QuotientOodFrame, TraceOodFrame};
28+
pub use ood_frame::{merge_ood_evaluations, OodFrame, QuotientOodFrame, TraceOodFrame};
2929

3030
mod security;
3131

air/src/proof/ood_frame.rs

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
use alloc::vec::Vec;
77

8-
use crypto::ElementHasher;
98
use math::FieldElement;
109
use utils::{
1110
ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, SliceReader,
@@ -38,8 +37,7 @@ impl OodFrame {
3837
// UPDATERS
3938
// --------------------------------------------------------------------------------------------
4039

41-
/// Updates the trace state portion of this out-of-domain frame, and returns the hash of the
42-
/// trace states.
40+
/// Updates the trace state portion of this out-of-domain frame.
4341
///
4442
/// The out-of-domain frame is stored as one vector built from the concatenation of values of
4543
/// two vectors, the current row vector and the next row vector. Given the input frame
@@ -58,10 +56,9 @@ impl OodFrame {
5856
///
5957
/// # Panics
6058
/// Panics if evaluation frame has already been set.
61-
pub fn set_trace_states<E, H>(&mut self, trace_ood_frame: &TraceOodFrame<E>) -> H::Digest
59+
pub fn set_trace_states<E>(&mut self, trace_ood_frame: &TraceOodFrame<E>)
6260
where
6361
E: FieldElement,
64-
H: ElementHasher<BaseField = E::BaseField>,
6562
{
6663
assert!(self.trace_states.is_empty(), "trace sates have already been set");
6764

@@ -72,8 +69,6 @@ impl OodFrame {
7269
let frame_size: u8 = 2;
7370
self.trace_states.write_u8(frame_size);
7471
self.trace_states.write_many(&main_and_aux_trace_states);
75-
76-
H::hash_elements(&main_and_aux_trace_states)
7772
}
7873

7974
/// Updates constraints composition polynomials (i.e., quotient polynomials) state portion of
@@ -97,13 +92,9 @@ impl OodFrame {
9792
/// # Panics
9893
/// Panics if:
9994
/// * Constraint evaluations have already been set.
100-
pub fn set_quotient_states<E, H>(
101-
&mut self,
102-
quotients_ood_frame: &QuotientOodFrame<E>,
103-
) -> H::Digest
95+
pub fn set_quotient_states<E>(&mut self, quotients_ood_frame: &QuotientOodFrame<E>)
10496
where
10597
E: FieldElement,
106-
H: ElementHasher<BaseField = E::BaseField>,
10798
{
10899
assert!(self.quotient_states.is_empty(), "constraint evaluations have already been set");
109100

@@ -114,8 +105,6 @@ impl OodFrame {
114105
let frame_size: u8 = 2;
115106
self.quotient_states.write_u8(frame_size);
116107
self.quotient_states.write_many(&quotient_states);
117-
118-
H::hash_elements(&quotient_states)
119108
}
120109

121110
// PARSER
@@ -281,22 +270,14 @@ impl<E: FieldElement> TraceOodFrame<E> {
281270
}
282271
}
283272

284-
/// Hashes the main, auxiliary frames in a manner consistent with
285-
/// [`OodFrame::set_trace_states`], with the purpose of reseeding the public coin.
286-
pub fn hash<H: ElementHasher<BaseField = E::BaseField>>(&self) -> H::Digest {
287-
let trace_states = self.to_trace_states();
288-
289-
H::hash_elements(&trace_states)
290-
}
291-
292273
/// Returns true if an auxiliary frame is present
293274
fn has_aux_frame(&self) -> bool {
294275
self.current_row.len() > self.main_trace_width
295276
}
296277

297278
/// Returns the main/aux frames as a vector of elements described in
298279
/// [`OodFrame::set_trace_states`].
299-
fn to_trace_states(&self) -> Vec<E> {
280+
pub fn to_trace_states(&self) -> Vec<E> {
300281
let mut main_and_aux_frame_states = Vec::new();
301282
main_and_aux_frame_states.extend_from_slice(&self.current_row);
302283
main_and_aux_frame_states.extend_from_slice(&self.next_row);
@@ -335,19 +316,36 @@ impl<E: FieldElement> QuotientOodFrame<E> {
335316
&self.next_row
336317
}
337318

338-
/// Hashes the frame with the purpose of reseeding the public coin.
339-
pub fn hash<H: ElementHasher<BaseField = E::BaseField>>(&self) -> H::Digest {
340-
let trace_states = self.to_trace_states();
341-
342-
H::hash_elements(&trace_states)
343-
}
344-
345319
/// Returns the frame as a vector of elements.
346-
fn to_trace_states(&self) -> Vec<E> {
320+
pub fn to_trace_states(&self) -> Vec<E> {
347321
let mut quotients_frame_states = Vec::new();
348322
quotients_frame_states.extend_from_slice(&self.current_row);
349323
quotients_frame_states.extend_from_slice(&self.next_row);
350324

351325
quotients_frame_states
352326
}
353327
}
328+
329+
// HELPER
330+
// ================================================================================================
331+
332+
/// Given trace and constraints polynomials OOD evaluations, returns the vector containing their
333+
/// concatenation, with the evaluations at `z` grouped together and coming first and followed
334+
/// by the evaluations at `z * g`.
335+
pub fn merge_ood_evaluations<E>(
336+
trace_ood_frame: &TraceOodFrame<E>,
337+
constraints_ood_frame: &QuotientOodFrame<E>,
338+
) -> Vec<E>
339+
where
340+
E: FieldElement,
341+
{
342+
let mut current_row = trace_ood_frame.current_row().to_vec();
343+
current_row.extend_from_slice(constraints_ood_frame.current_row());
344+
let mut next_row = trace_ood_frame.next_row().to_vec();
345+
next_row.extend_from_slice(constraints_ood_frame.next_row());
346+
347+
let mut ood_evals = current_row;
348+
ood_evals.extend_from_slice(&next_row);
349+
350+
ood_evals
351+
}

prover/src/channel.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ use alloc::vec::Vec;
77
use core::marker::PhantomData;
88

99
use air::{
10-
proof::{Commitments, Context, OodFrame, Proof, Queries, QuotientOodFrame, TraceOodFrame},
10+
proof::{
11+
merge_ood_evaluations, Commitments, Context, OodFrame, Proof, Queries, QuotientOodFrame,
12+
TraceOodFrame,
13+
},
1114
Air, ConstraintCompositionCoefficients, DeepCompositionCoefficients,
1215
};
1316
use crypto::{ElementHasher, RandomCoin, VectorCommitment};
@@ -93,19 +96,20 @@ where
9396
self.public_coin.reseed(constraint_root);
9497
}
9598

96-
/// Saves the evaluations of trace polynomials over the out-of-domain evaluation frame. This
97-
/// also reseeds the public coin with the hashes of the evaluation frame states.
98-
pub fn send_ood_trace_states(&mut self, trace_ood_frame: &TraceOodFrame<E>) {
99-
let trace_states_hash = self.ood_frame.set_trace_states::<E, H>(trace_ood_frame);
100-
self.public_coin.reseed(trace_states_hash);
101-
}
102-
103-
/// Saves the evaluations of constraint composition polynomial columns over the out-of-domain
104-
/// evaluation frame. This also reseeds the public coin with the hashes of the evaluation frame
105-
/// states.
106-
pub fn send_ood_constraint_evaluations(&mut self, evaluations: &QuotientOodFrame<E>) {
107-
let quotient_hash = self.ood_frame.set_quotient_states::<E, H>(evaluations);
108-
self.public_coin.reseed(quotient_hash);
99+
/// Saves the evaluations of the trace and constraint composition polynomials over
100+
/// the out-of-domain evaluation frame. This also reseeds the public coin with the hash
101+
/// of all OOD evaluations.
102+
pub fn send_ood_evaluations(
103+
&mut self,
104+
trace_ood_frame: &TraceOodFrame<E>,
105+
constraints_ood_frame: &QuotientOodFrame<E>,
106+
) {
107+
self.ood_frame.set_trace_states::<E>(trace_ood_frame);
108+
self.ood_frame.set_quotient_states::<E>(constraints_ood_frame);
109+
let ood_evals = merge_ood_evaluations(trace_ood_frame, constraints_ood_frame);
110+
let digest = H::hash_elements(&ood_evals);
111+
112+
self.public_coin.reseed(digest);
109113
}
110114

111115
// PUBLIC COIN METHODS

prover/src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,10 +397,8 @@ pub trait Prover {
397397
// evaluate trace and constraint polynomials at the OOD point z and gz, where g is
398398
// the generator of the trace domain. and send the results to the verifier
399399
let ood_trace_states = trace_polys.get_ood_frame(z);
400-
channel.send_ood_trace_states(&ood_trace_states);
401-
402400
let ood_evaluations = composition_poly.get_ood_frame(z);
403-
channel.send_ood_constraint_evaluations(&ood_evaluations);
401+
channel.send_ood_evaluations(&ood_trace_states, &ood_evaluations);
404402

405403
// draw random coefficients to use during DEEP polynomial composition, and use them to
406404
// initialize the DEEP composition polynomial

verifier/src/lib.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extern crate alloc;
3434
use alloc::vec::Vec;
3535
use core::cmp;
3636

37+
use air::proof::merge_ood_evaluations;
3738
pub use air::{
3839
proof::Proof, Air, AirContext, Assertion, BoundaryConstraint, BoundaryConstraintGroup,
3940
ConstraintCompositionCoefficients, ConstraintDivisor, DeepCompositionCoefficients,
@@ -206,8 +207,7 @@ where
206207
// are consistent with the evaluations of composition polynomial columns sent by the prover
207208

208209
// read the out-of-domain trace frames (the main trace frame and auxiliary trace frame, if
209-
// provided) sent by the prover and evaluate constraints over them; also, reseed the public
210-
// coin with the OOD frames received from the prover.
210+
// provided) sent by the prover and evaluate constraints over them.
211211
let ood_trace_frame = channel.read_ood_trace_frame();
212212
let ood_main_trace_frame = ood_trace_frame.main_frame();
213213
let ood_aux_trace_frame = ood_trace_frame.aux_frame();
@@ -219,15 +219,14 @@ where
219219
aux_trace_rand_elements.as_ref(),
220220
z,
221221
);
222-
public_coin.reseed(ood_trace_frame.hash::<H>());
223222

224-
// read evaluations of composition polynomial columns sent by the prover, and reduce them into
225-
// a single value by computing \sum_{i=0}^{m-1}(z^(i * l) * value_i), where value_i is the
223+
// read evaluations of composition polynomial columns sent by the prover, and reduce
224+
// the evaluations at z into a single value by computing
225+
// \sum_{i=0}^{m-1}(z^(i * l) * value_i), where value_i is the
226226
// evaluation of the ith column polynomial H_i(X) at z, l is the trace length and m is
227227
// the number of composition column polynomials. This computes H(z) (i.e.
228228
// the evaluation of the composition polynomial at z) using the fact that
229229
// H(X) = \sum_{i=0}^{m-1} X^{i * l} H_i(X).
230-
// Also, reseed the public coin with the OOD constraint evaluations received from the prover.
231230
let ood_constraint_evaluations = channel.read_ood_constraint_frame();
232231
let ood_constraint_evaluation_2 = ood_constraint_evaluations
233232
.current_row()
@@ -237,14 +236,16 @@ where
237236
result + z.exp_vartime(((i * (air.trace_length())) as u32).into()) * value
238237
});
239238

240-
let ood_constraint_hash = ood_constraint_evaluations.hash::<H>();
241-
public_coin.reseed(ood_constraint_hash);
242-
243239
// finally, make sure the values are the same
244240
if ood_constraint_evaluation_1 != ood_constraint_evaluation_2 {
245241
return Err(VerifierError::InconsistentOodConstraintEvaluations);
246242
}
247243

244+
// reseed the public coin with OOD evaluations
245+
let ood_evals = merge_ood_evaluations(&ood_trace_frame, &ood_constraint_evaluations);
246+
let digest = H::hash_elements(&ood_evals);
247+
public_coin.reseed(digest);
248+
248249
// 4 ----- FRI commitments --------------------------------------------------------------------
249250
// draw coefficients for computing DEEP composition polynomial from the public coin; in the
250251
// interactive version of the protocol, the verifier sends these coefficients to the prover

0 commit comments

Comments
 (0)