Skip to content

Commit c32970e

Browse files
authored
air: poseidon columns (#13)
* air: poseidon columns * fmt
1 parent 3d9f1f0 commit c32970e

File tree

5 files changed

+154
-1
lines changed

5 files changed

+154
-1
lines changed

crates/leanVm/src/air/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod constant;
22
pub mod dot_product;
3+
pub mod poseidon;
34
pub mod vm;

crates/leanVm/src/air/poseidon.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use p3_field::PrimeCharacteristicRing;
2+
3+
use crate::{
4+
constant::F,
5+
poseidon2::{generate_trace_poseidon_16, generate_trace_poseidon_24},
6+
utils::pad_to_power_of_two,
7+
witness::poseidon::{WitnessPoseidon16, WitnessPoseidon24},
8+
};
9+
10+
/// Build Poseidon Columns
11+
///
12+
/// This function generates the execution traces for both Poseidon16 and Poseidon24 operations.
13+
///
14+
/// ## Arguments
15+
/// * `poseidons_16`: A slice of `WitnessPoseidon16` structs.
16+
/// * `poseidons_24`: A slice of `WitnessPoseidon24` structs.
17+
///
18+
/// ## Returns
19+
/// A tuple containing two items:
20+
/// 1. A `Vec<Vec<F>>` for the Poseidon16 trace, where each inner vector is a column.
21+
/// 2. A `Vec<Vec<F>>` for the Poseidon24 trace, where each inner vector is a column.
22+
pub fn build_poseidon_columns(
23+
poseidons_16: &[WitnessPoseidon16],
24+
poseidons_24: &[WitnessPoseidon24],
25+
) -> (Vec<Vec<F>>, Vec<Vec<F>>) {
26+
// Poseidon16 Trace Generation
27+
//
28+
// Extract the `input` state from each Poseidon16 witness.
29+
let poseidon_16_data = poseidons_16.iter().map(|w| w.input).collect::<Vec<_>>();
30+
// Generate the full execution trace for all Poseidon16 operations.
31+
// This returns a `RowMajorMatrix`.
32+
let witness_matrix_poseidon_16 = generate_trace_poseidon_16(poseidon_16_data);
33+
34+
// Poseidon24 Trace Generation
35+
//
36+
// Extract the `input` state from each Poseidon24 witness.
37+
let poseidon_24_data = poseidons_24.iter().map(|w| w.input).collect::<Vec<_>>();
38+
// Generate the full execution trace for all Poseidon24 operations.
39+
let witness_matrix_poseidon_24 = generate_trace_poseidon_24(poseidon_24_data);
40+
41+
// Column Extraction
42+
//
43+
// To get the columns of a row-major matrix, we first transpose it.
44+
let transposed_16 = witness_matrix_poseidon_16.transpose();
45+
// After transposing, the rows of the new matrix are the columns of the original.
46+
// We can then iterate over the row slices of the transposed matrix and collect them.
47+
let cols_16 = transposed_16.row_slices().map(<[F]>::to_vec).collect();
48+
49+
// Repeat the same process for the Poseidon24 trace.
50+
let transposed_24 = witness_matrix_poseidon_24.transpose();
51+
let cols_24 = transposed_24.row_slices().map(<[F]>::to_vec).collect();
52+
53+
// Return the two sets of columns.
54+
(cols_16, cols_24)
55+
}
56+
57+
/// All Poseidon16 Indexes
58+
///
59+
/// This function collects all memory addresses used by the Poseidon16 precompile,
60+
/// flattens them into a single vector, and pads it to the next power of two.
61+
///
62+
/// ## Arguments
63+
/// * `poseidons_16`: A slice of `WitnessPoseidon16` structs.
64+
///
65+
/// ## Returns
66+
/// A padded `Vec<F>` containing the concatenated offsets of `addr_input_a`, `addr_input_b`, and `addr_output`.
67+
#[must_use]
68+
pub fn all_poseidon_16_indexes(poseidons_16: &[WitnessPoseidon16]) -> Vec<F> {
69+
// Collect all the indices into a single vector.
70+
let all_indices: Vec<F> = poseidons_16
71+
.iter()
72+
.map(|p| F::from_usize(p.addr_input_a.offset))
73+
.chain(
74+
poseidons_16
75+
.iter()
76+
.map(|p| F::from_usize(p.addr_input_b.offset)),
77+
)
78+
.chain(
79+
poseidons_16
80+
.iter()
81+
.map(|p| F::from_usize(p.addr_output.offset)),
82+
)
83+
.collect();
84+
85+
// Pad the final vector with zeros to the next power of two.
86+
pad_to_power_of_two(&all_indices)
87+
}
88+
89+
/// All Poseidon24 Indexes
90+
///
91+
/// This function collects all memory addresses used by the Poseidon24 precompile,
92+
/// flattens them into a single vector, and pads it to the next power of two.
93+
///
94+
/// ## Arguments
95+
/// * `poseidons_24`: A slice of `WitnessPoseidon24` structs.
96+
///
97+
/// ## Returns
98+
/// A padded `Vec<F>` containing the concatenated and individually padded offsets of
99+
/// `addr_input_a`, `addr_input_b`, and `addr_output`.
100+
#[must_use]
101+
pub fn all_poseidon_24_indexes(poseidons_24: &[WitnessPoseidon24]) -> Vec<F> {
102+
// Extract and pad the offsets for `addr_input_a`.
103+
let indices_a = pad_to_power_of_two(
104+
&poseidons_24
105+
.iter()
106+
.map(|p| F::from_usize(p.addr_input_a.offset))
107+
.collect::<Vec<_>>(),
108+
);
109+
// Extract and pad the offsets for `addr_input_b`.
110+
let indices_b = pad_to_power_of_two(
111+
&poseidons_24
112+
.iter()
113+
.map(|p| F::from_usize(p.addr_input_b.offset))
114+
.collect::<Vec<_>>(),
115+
);
116+
// Extract and pad the offsets for `addr_output`.
117+
let indices_c = pad_to_power_of_two(
118+
&poseidons_24
119+
.iter()
120+
.map(|p| F::from_usize(p.addr_output.offset))
121+
.collect::<Vec<_>>(),
122+
);
123+
124+
// Concatenate the three padded vectors into a single flat vector.
125+
[indices_a, indices_b, indices_c].concat()
126+
}

crates/leanVm/src/lang/simple_expr.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ impl SimpleExpr {
3535
matches!(self, Self::Constant(_))
3636
}
3737

38-
#[must_use] pub fn simplify_if_const(&self) -> Self {
38+
#[must_use]
39+
pub fn simplify_if_const(&self) -> Self {
3940
if let Self::Constant(constant) = self {
4041
return constant.try_naive_simplification().into();
4142
}

crates/leanVm/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ pub mod memory;
1010
pub mod parser;
1111
pub mod poseidon2;
1212
pub mod trace;
13+
pub mod utils;
1314
pub mod witness;

crates/leanVm/src/utils.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use p3_field::PrimeCharacteristicRing;
2+
3+
use crate::constant::F;
4+
5+
/// # Pad to Power of Two
6+
///
7+
/// A utility function that pads a slice of field elements with zeros to the next
8+
/// power-of-two length.
9+
///
10+
/// ## Arguments
11+
/// * `data`: A slice of field elements.
12+
///
13+
/// ## Returns
14+
/// A new `Vec<F>` containing the original data, padded with zeros.
15+
pub(crate) fn pad_to_power_of_two(data: &[F]) -> Vec<F> {
16+
// Calculate the next power-of-two length.
17+
let next_power_of_two = data.len().next_power_of_two();
18+
// Create a new vector from the input slice.
19+
let mut padded = data.to_vec();
20+
// Resize the vector to the target length, filling with zeros.
21+
padded.resize(next_power_of_two, F::ZERO);
22+
// Return the padded vector.
23+
padded
24+
}

0 commit comments

Comments
 (0)