sp1_hypercube/operations/poseidon2/
trace.rs1use std::borrow::Borrow;
4
5use slop_algebra::PrimeField32;
6use slop_koala_bear::{
7 KoalaBear_BEGIN_EXT_CONSTS, KoalaBear_END_EXT_CONSTS, KoalaBear_PARTIAL_CONSTS,
8};
9
10use super::{
11 air::{external_linear_layer, external_linear_layer_mut, internal_linear_layer_mut},
12 permutation::permutation_mut,
13 Poseidon2Operation, NUM_EXTERNAL_ROUNDS, NUM_INTERNAL_ROUNDS, NUM_POSEIDON2_OPERATION_COLUMNS,
14 WIDTH,
15};
16
17pub fn populate_perm_deg3<F: PrimeField32>(
19 input: [F; WIDTH],
20 expected_output: Option<[F; WIDTH]>,
21) -> Poseidon2Operation<F> {
22 let mut row: Vec<F> = vec![F::zero(); NUM_POSEIDON2_OPERATION_COLUMNS];
23 populate_perm::<F, 3>(input, expected_output, row.as_mut_slice());
24 let op: &Poseidon2Operation<F> = row.as_slice().borrow();
25 *op
26}
27
28pub fn populate_perm<F: PrimeField32, const DEGREE: usize>(
30 input: [F; WIDTH],
31 expected_output: Option<[F; WIDTH]>,
32 input_row: &mut [F],
33) {
34 {
35 let permutation = permutation_mut::<F, DEGREE>(input_row);
36
37 let (external_rounds_state, internal_rounds_state, internal_rounds_s0, output_state) =
38 permutation.get_cols_mut();
39
40 external_rounds_state[0] = input;
41
42 for r in 0..NUM_EXTERNAL_ROUNDS / 2 {
44 let next_state = populate_external_round::<F, DEGREE>(external_rounds_state, r);
45 if r == NUM_EXTERNAL_ROUNDS / 2 - 1 {
46 *internal_rounds_state = next_state;
47 } else {
48 external_rounds_state[r + 1] = next_state;
49 }
50 }
51
52 external_rounds_state[NUM_EXTERNAL_ROUNDS / 2] =
54 populate_internal_rounds(internal_rounds_state, internal_rounds_s0);
55
56 for r in NUM_EXTERNAL_ROUNDS / 2..NUM_EXTERNAL_ROUNDS {
58 let next_state = populate_external_round::<F, DEGREE>(external_rounds_state, r);
59 if r == NUM_EXTERNAL_ROUNDS - 1 {
60 for i in 0..WIDTH {
61 output_state[i] = next_state[i];
62 if let Some(expected_output) = expected_output {
63 assert_eq!(expected_output[i], next_state[i]);
64 }
65 }
66 } else {
67 external_rounds_state[r + 1] = next_state;
68 }
69 }
70 }
71}
72
73pub fn populate_external_round<F: PrimeField32, const DEGREE: usize>(
75 external_rounds_state: &[[F; WIDTH]],
76 r: usize,
77) -> [F; WIDTH] {
78 let mut state = {
79 let round_state: &[F; WIDTH] = if r == 0 {
81 &external_linear_layer(&external_rounds_state[r])
82 } else {
83 &external_rounds_state[r]
84 };
85
86 let mut add_rc = *round_state;
92 for i in 0..WIDTH {
93 add_rc[i] += if r < NUM_EXTERNAL_ROUNDS / 2 {
94 F::from_canonical_u32(KoalaBear_BEGIN_EXT_CONSTS[r][i].as_canonical_u32())
95 } else {
96 F::from_canonical_u32(
97 KoalaBear_END_EXT_CONSTS[r - NUM_EXTERNAL_ROUNDS / 2][i].as_canonical_u32(),
98 )
99 };
100 }
101
102 let mut sbox_deg_3: [F; 16] = [F::zero(); WIDTH];
107 for i in 0..WIDTH {
108 sbox_deg_3[i] = add_rc[i] * add_rc[i] * add_rc[i];
109 }
110
111 sbox_deg_3
112 };
113
114 external_linear_layer_mut(&mut state);
116 state
117}
118
119pub fn populate_internal_rounds<F: PrimeField32>(
121 internal_rounds_state: &[F; WIDTH],
122 internal_rounds_s0: &mut [F; NUM_INTERNAL_ROUNDS - 1],
123) -> [F; WIDTH] {
124 let mut state: [F; WIDTH] = *internal_rounds_state;
125 for r in 0..NUM_INTERNAL_ROUNDS {
126 let add_rc =
130 state[0] + F::from_canonical_u32(KoalaBear_PARTIAL_CONSTS[r].as_canonical_u32());
131
132 let sbox_deg_3 = add_rc * add_rc * add_rc;
136
137 state[0] = sbox_deg_3;
139 internal_linear_layer_mut(&mut state);
140
141 if r < NUM_INTERNAL_ROUNDS - 1 {
147 internal_rounds_s0[r] = state[0];
148 }
149 }
150
151 state
152}