Skip to content

Commit 9eb24f9

Browse files
Add export preprocessed roots dev util.
1 parent 976b9a1 commit 9eb24f9

File tree

7 files changed

+139
-59
lines changed

7 files changed

+139
-59
lines changed

stwo_cairo_prover/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

stwo_cairo_prover/crates/dev_utils/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ edition.workspace = true
77
name = "extract_mem_trace"
88
required-features = ["stwo-cairo-adapter/extract-mem-trace"]
99

10+
[[bin]]
11+
name = "export_preprocessed_roots"
12+
1013
[dependencies]
1114
anyhow.workspace = true
1215
cairo-air.workspace = true
@@ -25,6 +28,7 @@ log.workspace = true
2528
regex = "1.11.1"
2629
num-bigint = "0.4.6"
2730
bincode = "1.3.3"
31+
itertools.workspace = true
2832

2933
serde_json.workspace = true
3034
cairo-vm.workspace = true
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use clap::{Parser, ValueEnum};
2+
use dev_utils::preprocessed_roots::{export_preprocessed_roots, HashSelection};
3+
4+
#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)]
5+
enum HashArg {
6+
Blake,
7+
Poseidon,
8+
Both,
9+
}
10+
11+
impl From<HashArg> for HashSelection {
12+
fn from(value: HashArg) -> Self {
13+
match value {
14+
HashArg::Blake => HashSelection::Blake,
15+
HashArg::Poseidon => HashSelection::Poseidon,
16+
HashArg::Both => HashSelection::Both,
17+
}
18+
}
19+
}
20+
21+
/// Export preprocessed commitment roots for Cairo preprocessed traces.
22+
///
23+
/// Computes the commitment roots for Blake2s and/or Poseidon252 Merkle channels for all
24+
/// log blowup factors in the range 1..=max.
25+
///
26+
/// Performance note: This computation is slow. It is strongly recommended to run with
27+
/// release optimizations:
28+
///
29+
/// cargo run --release --bin export_preprocessed_roots -- [OPTIONS]
30+
///
31+
/// Examples:
32+
/// # Compute both sets of roots up to the default max (2)
33+
/// cargo run --release --bin export_preprocessed_roots
34+
///
35+
/// # Compute only Blake roots up to 4
36+
/// cargo run --release --bin export_preprocessed_roots -- -m 4 --hash blake
37+
#[derive(Parser, Debug)]
38+
#[command(name = "export_preprocessed_roots")]
39+
struct Args {
40+
/// Maximum log blowup factor (inclusive), computes for 1..=max
41+
#[arg(short = 'm', long = "max-log-blowup-factor", default_value_t = 2)]
42+
max_log_blowup_factor: u32,
43+
44+
/// Hash function to compute roots for: blake, poseidon, or both
45+
#[arg(long = "hash", value_enum, default_value_t = HashArg::Both)]
46+
hash: HashArg,
47+
}
48+
49+
fn main() {
50+
let args = Args::parse();
51+
export_preprocessed_roots(args.max_log_blowup_factor, args.hash.into());
52+
}
53+
54+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pub mod utils;
2+
pub mod preprocessed_roots;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use cairo_air::PreProcessedTraceVariant;
2+
use itertools::Itertools;
3+
use stwo::core::channel::MerkleChannel;
4+
use stwo::core::vcs::blake2_merkle::Blake2sMerkleChannel;
5+
use stwo::core::vcs::poseidon252_merkle::Poseidon252MerkleChannel;
6+
use stwo::core::vcs::MerkleHasher;
7+
use stwo::prover::backend::BackendForChannel;
8+
use stwo_cairo_prover::witness::preprocessed_trace::generate_preprocessed_commitment_root;
9+
10+
#[derive(Clone, Copy, Debug)]
11+
pub enum HashSelection {
12+
Blake,
13+
Poseidon,
14+
Both,
15+
}
16+
17+
fn get_preprocessed_roots<MC: MerkleChannel>(
18+
max_log_blowup_factor: u32,
19+
preprocessed_trace: PreProcessedTraceVariant,
20+
) -> Vec<<MC::H as MerkleHasher>::Hash>
21+
where
22+
stwo::prover::backend::simd::SimdBackend: BackendForChannel<MC>,
23+
{
24+
(1..=max_log_blowup_factor)
25+
.map(|i| generate_preprocessed_commitment_root::<MC>(i, preprocessed_trace))
26+
.collect_vec()
27+
}
28+
29+
pub fn export_preprocessed_roots(max_log_blowup_factor: u32, selection: HashSelection) {
30+
match selection {
31+
HashSelection::Blake => {
32+
let roots = get_preprocessed_roots::<Blake2sMerkleChannel>(
33+
max_log_blowup_factor,
34+
PreProcessedTraceVariant::Canonical,
35+
);
36+
roots.iter().enumerate().for_each(|(i, root)| {
37+
let root_bytes = root.0;
38+
let u32s_hex = root_bytes
39+
.as_slice()
40+
.chunks_exact(4)
41+
.map(|bytes| {
42+
let arr: [u8; 4] = bytes.try_into().expect("chunk size");
43+
format!("{:#010x}", u32::from_le_bytes(arr))
44+
})
45+
.collect_vec()
46+
.join(", ");
47+
println!("log_blowup_factor: {}, blake root: [{}]", i + 1, u32s_hex);
48+
});
49+
}
50+
HashSelection::Poseidon => {
51+
println!("Starting Poseidon roots");
52+
get_preprocessed_roots::<Poseidon252MerkleChannel>(
53+
max_log_blowup_factor,
54+
PreProcessedTraceVariant::CanonicalWithoutPedersen,
55+
)
56+
.into_iter()
57+
.enumerate()
58+
.for_each(|(i, root)| {
59+
println!(
60+
"log_blowup_factor: {}, poseidon root: [{:#010x}]",
61+
i + 1,
62+
root
63+
);
64+
});
65+
}
66+
HashSelection::Both => {
67+
export_preprocessed_roots(max_log_blowup_factor, HashSelection::Blake);
68+
export_preprocessed_roots(max_log_blowup_factor, HashSelection::Poseidon);
69+
}
70+
}
71+
}
72+
73+

stwo_cairo_prover/crates/prover/src/witness/preprocessed_trace.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,24 @@ use stwo::prover::poly::circle::PolyOps;
88
use stwo::prover::CommitmentTreeProver;
99

1010
/// Generates the root of the preprocessed trace commitment tree for a given `log_blowup_factor`.
11-
// TODO(Shahars): remove allow.
12-
#[allow(unused)]
1311
pub fn generate_preprocessed_commitment_root<MC: MerkleChannel>(
1412
log_blowup_factor: u32,
1513
preprocessed_trace: PreProcessedTraceVariant,
1614
) -> <<MC as MerkleChannel>::H as MerkleHasher>::Hash
1715
where
1816
SimdBackend: BackendForChannel<MC>,
1917
{
18+
println!("Generating preprocessed trace root for log blowup factor: {}", log_blowup_factor);
2019
let preprocessed_trace = preprocessed_trace.to_preprocessed_trace();
21-
20+
println!("Computing twiddles");
2221
// Precompute twiddles for the commitment scheme.
2322
let max_log_size = preprocessed_trace.log_sizes().into_iter().max().unwrap();
2423
let twiddles = SimdBackend::precompute_twiddles(
2524
CanonicCoset::new(max_log_size + log_blowup_factor)
2625
.circle_domain()
2726
.half_coset,
2827
);
29-
28+
println!("Generating commitment tree");
3029
// Generate the commitment tree.
3130
let polys = SimdBackend::interpolate_columns(preprocessed_trace.gen_trace(), &twiddles);
3231
let commitment_scheme = CommitmentTreeProver::<SimdBackend, MC>::new(

stwo_cairo_prover/crates/prover/src/witness/utils.rs

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
use std::sync::atomic::{AtomicU32, Ordering};
22

33
use cairo_air::air::CairoClaim;
4-
use cairo_air::PreProcessedTraceVariant;
5-
use itertools::Itertools;
64
use num_traits::{One, Zero};
75
use stwo::core::channel::MerkleChannel;
86
use stwo::core::fields::m31::M31;
97
use stwo::core::pcs::{TreeSubspan, TreeVec};
10-
use stwo::core::vcs::blake2_merkle::Blake2sMerkleChannel;
11-
use stwo::core::vcs::poseidon252_merkle::Poseidon252MerkleChannel;
12-
use stwo::core::vcs::MerkleHasher;
8+
139
use stwo::prover::backend::simd::column::BaseColumn;
1410
use stwo::prover::backend::simd::conversion::Pack;
1511
use stwo::prover::backend::simd::m31::{PackedM31, N_LANES};
@@ -19,7 +15,7 @@ use stwo::prover::poly::BitReversedOrder;
1915
use stwo_cairo_common::preprocessed_columns::preprocessed_trace::PreProcessedTrace;
2016
use stwo_constraint_framework::PREPROCESSED_TRACE_IDX;
2117

22-
use crate::witness::preprocessed_trace::generate_preprocessed_commitment_root;
18+
2319

2420
pub fn pack_values<T: Pack>(values: &[T]) -> Vec<T::SimdType> {
2521
values
@@ -130,55 +126,7 @@ pub fn witness_trace_cells(claim: &CairoClaim, pp_trace: &PreProcessedTrace) ->
130126
tree_trace_cells(log_sizes)
131127
}
132128

133-
fn get_preprocessed_roots<MC: MerkleChannel>(
134-
max_log_blowup_factor: u32,
135-
preprocessed_trace: PreProcessedTraceVariant,
136-
) -> Vec<<MC::H as MerkleHasher>::Hash>
137-
where
138-
stwo::prover::backend::simd::SimdBackend: BackendForChannel<MC>,
139-
{
140-
(1..=max_log_blowup_factor)
141-
.map(|i| generate_preprocessed_commitment_root::<MC>(i, preprocessed_trace))
142-
.collect_vec()
143-
}
144-
145-
/// Exports the preprocessed roots for both Blake2s and Poseidon252 channels.
146-
/// Note: This function is very slow and is intended for generating the preprocessed roots when
147-
/// needed.
148-
pub fn export_preprocessed_roots() {
149-
let max_log_blowup_factor = 5;
150-
151-
// Blake2s roots.
152-
let blake_roots = get_preprocessed_roots::<Blake2sMerkleChannel>(
153-
max_log_blowup_factor,
154-
PreProcessedTraceVariant::Canonical,
155-
);
156-
blake_roots.iter().enumerate().for_each(|(i, root)| {
157-
let root_bytes = root.0;
158-
let u32s_hex = root_bytes
159-
.array_chunks::<4>()
160-
.map(|&bytes| format!("{:#010x}", u32::from_le_bytes(bytes)))
161-
.collect_vec()
162-
.join(", ");
163-
164-
println!("log_blowup_factor: {}, blake root: [{}]", i + 1, u32s_hex);
165-
});
166-
167-
// Poseidon252 roots.
168-
get_preprocessed_roots::<Poseidon252MerkleChannel>(
169-
max_log_blowup_factor,
170-
PreProcessedTraceVariant::CanonicalWithoutPedersen,
171-
)
172-
.into_iter()
173-
.enumerate()
174-
.for_each(|(i, root)| {
175-
println!(
176-
"log_blowup_factor: {}, poseidon root: [{:#010x}]",
177-
i + 1,
178-
root
179-
);
180-
});
181-
}
129+
// export_preprocessed_roots moved to `dev_utils` binary.
182130

183131
#[cfg(test)]
184132
mod tests {

0 commit comments

Comments
 (0)