openvm_poseidon2_air/
babybear.rs1use std::array::from_fn;
2
3use lazy_static::lazy_static;
4use openvm_stark_backend::p3_field::{
5 integers::QuotientMap, PrimeCharacteristicRing, PrimeField32,
6};
7use openvm_stark_sdk::p3_baby_bear::BabyBear;
8use zkhash::{
9 ark_ff::PrimeField as _, fields::babybear::FpBabyBear as HorizenBabyBear,
10 poseidon2::poseidon2_instance_babybear::RC16,
11};
12
13use super::{
14 Poseidon2Constants, BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS, BABY_BEAR_POSEIDON2_PARTIAL_ROUNDS,
15 POSEIDON2_WIDTH,
16};
17
18pub(crate) fn horizen_to_p3_babybear(horizen_babybear: HorizenBabyBear) -> BabyBear {
19 BabyBear::from_u64(horizen_babybear.into_bigint().0[0])
20}
21
22pub(crate) fn horizen_round_consts() -> Poseidon2Constants<BabyBear> {
23 let p3_rc16: Vec<Vec<BabyBear>> = RC16
24 .iter()
25 .map(|round| {
26 round
27 .iter()
28 .map(|babybear| horizen_to_p3_babybear(*babybear))
29 .collect()
30 })
31 .collect();
32 let p_end = BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS + BABY_BEAR_POSEIDON2_PARTIAL_ROUNDS;
33
34 let beginning_full_round_constants: [[BabyBear; POSEIDON2_WIDTH];
35 BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS] = from_fn(|i| p3_rc16[i].clone().try_into().unwrap());
36 let partial_round_constants: [BabyBear; BABY_BEAR_POSEIDON2_PARTIAL_ROUNDS] =
37 from_fn(|i| p3_rc16[i + BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS][0]);
38 let ending_full_round_constants: [[BabyBear; POSEIDON2_WIDTH];
39 BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS] =
40 from_fn(|i| p3_rc16[i + p_end].clone().try_into().unwrap());
41
42 Poseidon2Constants {
43 beginning_full_round_constants,
44 partial_round_constants,
45 ending_full_round_constants,
46 }
47}
48
49lazy_static! {
50 pub static ref BABYBEAR_BEGIN_EXT_CONSTS: [[BabyBear; POSEIDON2_WIDTH]; BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS] =
51 horizen_round_consts().beginning_full_round_constants;
52 pub static ref BABYBEAR_PARTIAL_CONSTS: [BabyBear; BABY_BEAR_POSEIDON2_PARTIAL_ROUNDS] =
53 horizen_round_consts().partial_round_constants;
54 pub static ref BABYBEAR_END_EXT_CONSTS: [[BabyBear; POSEIDON2_WIDTH]; BABY_BEAR_POSEIDON2_HALF_FULL_ROUNDS] =
55 horizen_round_consts().ending_full_round_constants;
56}
57
58pub const INTERNAL_DIAG_MONTY_16: [BabyBear; 16] = BabyBear::new_array([
62 BabyBear::ORDER_U32 - 2,
63 1,
64 2,
65 (BabyBear::ORDER_U32 + 1) >> 1,
66 3,
67 4,
68 (BabyBear::ORDER_U32 - 1) >> 1,
69 BabyBear::ORDER_U32 - 3,
70 BabyBear::ORDER_U32 - 4,
71 BabyBear::ORDER_U32 - ((BabyBear::ORDER_U32 - 1) >> 8),
72 BabyBear::ORDER_U32 - ((BabyBear::ORDER_U32 - 1) >> 2),
73 BabyBear::ORDER_U32 - ((BabyBear::ORDER_U32 - 1) >> 3),
74 BabyBear::ORDER_U32 - 15,
75 (BabyBear::ORDER_U32 - 1) >> 8,
76 (BabyBear::ORDER_U32 - 1) >> 4,
77 15,
78]);
79
80pub(crate) fn babybear_internal_linear_layer<R: PrimeCharacteristicRing>(
81 state: &mut [R; POSEIDON2_WIDTH],
82 diag_m1_matrix: &[BabyBear; POSEIDON2_WIDTH],
83) {
84 let sum: R = state.iter().cloned().sum();
85 for (val, &diag_elem) in state.iter_mut().zip(diag_m1_matrix.iter()) {
86 let diag_sub = R::PrimeSubfield::from_int(diag_elem.as_canonical_u32());
87 let diag_r = R::from_prime_subfield(diag_sub);
88 *val = sum.clone() + diag_r * val.clone();
89 }
90}