Skip to content

Commit d35fefd

Browse files
slumbersjudson
authored andcommitted
prover: move program columns into preprocessed trace (nexus-xyz#562)
* prover: merge program trace with preprocessed cols to enforce the prover to commit to program trace before generating logup challenges * mix ad into the hasher
1 parent 2609665 commit d35fefd

File tree

6 files changed

+66
-60
lines changed

6 files changed

+66
-60
lines changed

prover/src/column.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ pub enum Column {
537537
// }
538538

539539
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, ColumnsEnum)]
540+
#[column_derive(string_id)]
540541
pub enum ProgramColumn {
541542
/// Program memory content: every Pc in the program memory
542543
#[size = 4]

prover/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub fn verify(proof: Proof, view: &nexus_vm::emulator::View) -> Result<(), Verif
2929
machine::Machine::<machine::BaseComponents>::verify(
3030
proof,
3131
view.get_program_memory(),
32+
view.view_associated_data().as_deref().unwrap_or_default(),
3233
view.get_initial_memory(),
3334
view.get_exit_code(),
3435
view.get_public_output(),

prover/src/machine.rs

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use stwo_prover::{
55
constraint_framework::TraceLocationAllocator,
66
core::{
77
backend::simd::SimdBackend,
8-
channel::Blake2sChannel,
8+
channel::{Blake2sChannel, Channel},
99
fields::qm31::SecureField,
1010
pcs::{CommitmentSchemeProver, CommitmentSchemeVerifier, PcsConfig},
1111
poly::circle::{CanonicCoset, PolyOps},
@@ -14,9 +14,7 @@ use stwo_prover::{
1414
},
1515
};
1616

17-
use super::trace::eval::{
18-
INTERACTION_TRACE_IDX, ORIGINAL_TRACE_IDX, PREPROCESSED_TRACE_IDX, PROGRAM_TRACE_IDX,
19-
};
17+
use super::trace::eval::{INTERACTION_TRACE_IDX, ORIGINAL_TRACE_IDX, PREPROCESSED_TRACE_IDX};
2018
use super::trace::{
2119
program::iter_program_steps, program_trace::ProgramTracesBuilder, sidenote::SideNote,
2220
PreprocessedTraces, TracesBuilder,
@@ -35,7 +33,7 @@ use crate::{
3533
RangeCheckChip, RegisterMemCheckChip, SllChip, SltChip, SltuChip, SraChip, SrlChip,
3634
SubChip, SyscallChip, TimestampChip,
3735
},
38-
column::PreprocessedColumn,
36+
column::{PreprocessedColumn, ProgramColumn},
3937
components::{self, AllLookupElements},
4038
traits::generate_interaction_trace,
4139
};
@@ -112,6 +110,10 @@ impl<C: MachineChip + Sync> Machine<C> {
112110

113111
// Setup protocol.
114112
let prover_channel = &mut Blake2sChannel::default();
113+
for byte in view.view_associated_data().unwrap_or_default() {
114+
prover_channel.mix_u64(byte.into());
115+
}
116+
115117
let mut commitment_scheme =
116118
CommitmentSchemeProver::<SimdBackend, Blake2sMerkleChannel>::new(config, &twiddles);
117119

@@ -142,8 +144,13 @@ impl<C: MachineChip + Sync> Machine<C> {
142144
let finalized_program_trace = program_traces.finalize();
143145

144146
let mut tree_builder = commitment_scheme.tree_builder();
145-
let _preprocessed_trace_location =
146-
tree_builder.extend_evals(preprocessed_trace.clone().into_circle_evaluation());
147+
let _preprocessed_trace_location = tree_builder.extend_evals(
148+
preprocessed_trace
149+
.clone()
150+
.into_circle_evaluation()
151+
.into_iter()
152+
.chain(finalized_program_trace.clone().into_circle_evaluation()),
153+
);
147154
tree_builder.commit(prover_channel);
148155

149156
let mut tree_builder = commitment_scheme.tree_builder();
@@ -165,12 +172,6 @@ impl<C: MachineChip + Sync> Machine<C> {
165172
let _interaction_trace_location = tree_builder.extend_evals(interaction_trace);
166173
tree_builder.commit(prover_channel);
167174

168-
// Fill columns of the program trace.
169-
let mut tree_builder = commitment_scheme.tree_builder();
170-
let _program_trace_location =
171-
tree_builder.extend_evals(finalized_program_trace.into_circle_evaluation());
172-
tree_builder.commit(prover_channel);
173-
174175
let component = MachineComponent::new(
175176
&mut TraceLocationAllocator::default(),
176177
MachineEval::<C>::new(log_size, lookup_elements),
@@ -192,6 +193,7 @@ impl<C: MachineChip + Sync> Machine<C> {
192193
pub fn verify(
193194
proof: Proof,
194195
program_info: &ProgramInfo,
196+
ad: &[u8],
195197
init_memory: &[MemoryInitializationEntry],
196198
exit_code: &[PublicOutputEntry],
197199
output_memory: &[PublicOutputEntry],
@@ -210,12 +212,16 @@ impl<C: MachineChip + Sync> Machine<C> {
210212

211213
let config = PcsConfig::default();
212214
let verifier_channel = &mut Blake2sChannel::default();
215+
for &byte in ad {
216+
verifier_channel.mix_u64(byte.into());
217+
}
218+
213219
let commitment_scheme = &mut CommitmentSchemeVerifier::<Blake2sMerkleChannel>::new(config);
214220

215-
// simulate the prover and compute expected commitment to preprocessed and program traces
221+
// simulate the prover and compute expected commitment to preprocessed trace
216222
{
217223
let config = PcsConfig::default();
218-
let verifier_channel = &mut Blake2sChannel::default();
224+
let verifier_channel = &mut verifier_channel.clone();
219225
let twiddles = SimdBackend::precompute_twiddles(
220226
CanonicCoset::new(
221227
log_size + LOG_CONSTRAINT_DEGREE + config.fri_config.log_blowup_factor,
@@ -228,18 +234,6 @@ impl<C: MachineChip + Sync> Machine<C> {
228234
config, &twiddles,
229235
);
230236
let preprocessed_trace = PreprocessedTraces::new(log_size);
231-
let mut tree_builder = commitment_scheme.tree_builder();
232-
let _preprocessed_trace_location =
233-
tree_builder.extend_evals(preprocessed_trace.into_circle_evaluation());
234-
tree_builder.commit(verifier_channel);
235-
236-
let preprocessed_expected = commitment_scheme.roots()[PREPROCESSED_TRACE_IDX];
237-
let preprocessed = proof.commitments[PREPROCESSED_TRACE_IDX];
238-
if preprocessed_expected != preprocessed {
239-
return Err(VerificationError::InvalidStructure(format!("invalid commitment to preprocessed trace: \
240-
expected {preprocessed_expected}, got {preprocessed}")));
241-
}
242-
243237
let program_trace = ProgramTracesBuilder::new(
244238
log_size,
245239
program_info,
@@ -248,14 +242,21 @@ impl<C: MachineChip + Sync> Machine<C> {
248242
output_memory,
249243
)
250244
.finalize();
245+
251246
let mut tree_builder = commitment_scheme.tree_builder();
252-
tree_builder.extend_evals(program_trace.into_circle_evaluation());
247+
let _preprocessed_trace_location = tree_builder.extend_evals(
248+
preprocessed_trace
249+
.into_circle_evaluation()
250+
.into_iter()
251+
.chain(program_trace.into_circle_evaluation()),
252+
);
253253
tree_builder.commit(verifier_channel);
254-
let program_expected = commitment_scheme.roots()[1];
255-
let program = proof.commitments[PROGRAM_TRACE_IDX];
256-
if program_expected != program {
257-
return Err(VerificationError::InvalidStructure(format!("invalid commitment to program trace: \
258-
expected {program_expected}, got {program}")));
254+
255+
let preprocessed_expected = commitment_scheme.roots()[PREPROCESSED_TRACE_IDX];
256+
let preprocessed = proof.commitments[PREPROCESSED_TRACE_IDX];
257+
if preprocessed_expected != preprocessed {
258+
return Err(VerificationError::InvalidStructure(format!("invalid commitment to preprocessed trace: \
259+
expected {preprocessed_expected}, got {preprocessed}")));
259260
}
260261
}
261262

@@ -270,7 +271,7 @@ impl<C: MachineChip + Sync> Machine<C> {
270271
.map_cols(|_| log_size);
271272
// use the fact that preprocessed columns are only allowed to have [0] mask
272273
sizes[PREPROCESSED_TRACE_IDX] = std::iter::repeat(log_size)
273-
.take(PreprocessedColumn::COLUMNS_NUM)
274+
.take(PreprocessedColumn::COLUMNS_NUM + ProgramColumn::COLUMNS_NUM)
274275
.collect();
275276

276277
for idx in [PREPROCESSED_TRACE_IDX, ORIGINAL_TRACE_IDX] {
@@ -284,10 +285,12 @@ impl<C: MachineChip + Sync> Machine<C> {
284285
MachineEval::<C>::new(log_size, lookup_elements),
285286
claimed_sum,
286287
);
287-
// TODO: prover must commit to the program trace before generating challenges.
288-
for idx in [INTERACTION_TRACE_IDX, PROGRAM_TRACE_IDX] {
289-
commitment_scheme.commit(proof.commitments[idx], &sizes[idx], verifier_channel);
290-
}
288+
289+
commitment_scheme.commit(
290+
proof.commitments[INTERACTION_TRACE_IDX],
291+
&sizes[INTERACTION_TRACE_IDX],
292+
verifier_channel,
293+
);
291294

292295
verify(&[&component], verifier_channel, commitment_scheme, proof)
293296
}
@@ -327,6 +330,7 @@ mod tests {
327330
Machine::<BaseComponents>::verify(
328331
proof,
329332
view.get_program_memory(),
333+
&[],
330334
view.get_initial_memory(),
331335
view.get_exit_code(),
332336
view.get_public_output(),

prover/src/test_utils.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,19 @@ pub(crate) fn commit_traces<'a, C: MachineChip>(
6060
let mut commitment_scheme =
6161
CommitmentSchemeProver::<_, Blake2sMerkleChannel>::new(config, twiddles);
6262
let mut prover_channel = Blake2sChannel::default();
63+
64+
let program_trace =
65+
program_traces.unwrap_or_else(|| ProgramTracesBuilder::dummy(traces.log_size()).finalize());
6366
// Preprocessed trace
6467
let preprocessed_trace = PreprocessedTraces::new(traces.log_size());
6568
let mut tree_builder = commitment_scheme.tree_builder();
66-
let _preprocessed_trace_location =
67-
tree_builder.extend_evals(preprocessed_trace.clone().into_circle_evaluation());
69+
let _preprocessed_trace_location = tree_builder.extend_evals(
70+
preprocessed_trace
71+
.clone()
72+
.into_circle_evaluation()
73+
.into_iter()
74+
.chain(program_trace.clone().into_circle_evaluation()),
75+
);
6876
tree_builder.commit(&mut prover_channel);
6977

7078
// Original trace
@@ -74,23 +82,13 @@ pub(crate) fn commit_traces<'a, C: MachineChip>(
7482
let mut all_elements = AllLookupElements::default();
7583
C::draw_lookup_elements(&mut all_elements, &mut prover_channel);
7684

77-
let program_trace =
78-
program_traces.unwrap_or_else(|| ProgramTracesBuilder::dummy(traces.log_size()).finalize());
79-
8085
// Interaction Trace
8186
let (interaction_trace, claimed_sum) =
8287
generate_interaction_trace::<C>(traces, &preprocessed_trace, &program_trace, &all_elements);
8388
let mut tree_builder = commitment_scheme.tree_builder();
8489
let _interaction_trace_location = tree_builder.extend_evals(interaction_trace.clone());
8590
tree_builder.commit(&mut prover_channel);
8691

87-
// Program Trace
88-
let mut tree_builder = commitment_scheme.tree_builder();
89-
let _program_trace_location =
90-
tree_builder.extend_evals(program_trace.clone().into_circle_evaluation());
91-
tree_builder.commit(&mut prover_channel);
92-
// TODO: make the verifier check the program trace commitment against the expected value
93-
9492
CommittedTraces {
9593
commitment_scheme,
9694
prover_channel,
@@ -123,10 +121,13 @@ pub(crate) fn assert_chip<C: MachineChip>(
123121
} = commit_traces::<C>(config, &twiddles, &finalized_trace, program_trace);
124122

125123
let trace_evals = TreeVec::new(vec![
126-
preprocessed_trace.into_circle_evaluation(),
124+
[
125+
preprocessed_trace.into_circle_evaluation(),
126+
program_trace.into_circle_evaluation(),
127+
]
128+
.concat(),
127129
finalized_trace.into_circle_evaluation(),
128130
interaction_trace,
129-
program_trace.into_circle_evaluation(),
130131
]);
131132
let trace_polys = trace_evals.map(|trace| {
132133
trace

prover/src/trace/eval.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ use crate::column::{
1010
pub use stwo_prover::constraint_framework::{
1111
INTERACTION_TRACE_IDX, ORIGINAL_TRACE_IDX, PREPROCESSED_TRACE_IDX,
1212
};
13-
pub const PROGRAM_TRACE_IDX: usize = 3; // After INTERACTION_TRACE_IDX; the verifier is supposed to know the commitment of the program trace
1413

1514
// Trace evaluation at the current row and the next row.
1615
pub struct TraceEval<E: EvalAtRow> {
1716
evals: Vec<[E::F; 2]>,
1817
preprocessed_evals: Vec<E::F>,
19-
program_evals: Vec<[E::F; 1]>, // only the current row
18+
program_evals: Vec<E::F>, // only the current row
2019
}
2120

2221
impl<E: EvalAtRow> TraceEval<E> {
@@ -25,6 +24,10 @@ impl<E: EvalAtRow> TraceEval<E> {
2524
.iter()
2625
.map(|&id| eval.get_preprocessed_column(PreProcessedColumnId { id: id.to_owned() }))
2726
.collect();
27+
let program_evals = ProgramColumn::STRING_IDS
28+
.iter()
29+
.map(|&id| eval.get_preprocessed_column(PreProcessedColumnId { id: id.to_owned() }))
30+
.collect();
2831
let evals = Column::ALL_VARIANTS
2932
.iter()
3033
.flat_map(|col| std::iter::repeat(col).take(col.size()))
@@ -39,10 +42,6 @@ impl<E: EvalAtRow> TraceEval<E> {
3942
}
4043
})
4144
.collect();
42-
let program_evals =
43-
std::iter::repeat_with(|| eval.next_interaction_mask(PROGRAM_TRACE_IDX, [0]))
44-
.take(ProgramColumn::COLUMNS_NUM)
45-
.collect();
4645
Self {
4746
evals,
4847
preprocessed_evals,
@@ -93,7 +92,7 @@ impl<E: EvalAtRow> TraceEval<E> {
9392
assert_eq!(col.size(), N, "column size mismatch");
9493
let offset = col.offset();
9594

96-
array::from_fn(|i| self.program_evals[offset + i][0].clone())
95+
array::from_fn(|i| self.program_evals[offset + i].clone())
9796
}
9897
}
9998

tests/testing-framework/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ mod test {
203203
fn test_prove_fib() {
204204
let elfs = compile_multi("examples/src/bin/fib", &["-C opt-level=3"], &HOME_PATH);
205205
let (view, execution_trace) =
206-
k_trace(elfs[0].clone(), &[], &[], &[], K).expect("error generating trace");
206+
k_trace(elfs[0].clone(), &[1, 2, 3], &[], &[], K).expect("error generating trace");
207207
let proof = prove(&execution_trace, &view).unwrap();
208208
verify(proof, &view).unwrap();
209209
}

0 commit comments

Comments
 (0)