sp1_recursion_compiler/ir/
poseidon.rsuse p3_field::AbstractField;
use sp1_recursion_core::runtime::{DIGEST_SIZE, HASH_RATE, PERMUTATION_WIDTH};
use super::{Array, Builder, Config, DslIr, Ext, Felt, Usize, Var};
impl<C: Config> Builder<C> {
    pub fn poseidon2_permute(&mut self, array: &Array<C, Felt<C::F>>) -> Array<C, Felt<C::F>> {
        let output = match array {
            Array::Fixed(values) => {
                assert_eq!(values.len(), PERMUTATION_WIDTH);
                self.array::<Felt<C::F>>(Usize::Const(PERMUTATION_WIDTH))
            }
            Array::Dyn(_, len) => self.array::<Felt<C::F>>(*len),
        };
        self.push_op(DslIr::Poseidon2PermuteBabyBear(Box::new((output.clone(), array.clone()))));
        output
    }
    pub fn poseidon2_permute_mut(&mut self, array: &Array<C, Felt<C::F>>) {
        self.push_op(DslIr::Poseidon2PermuteBabyBear(Box::new((array.clone(), array.clone()))));
    }
    pub fn poseidon2_absorb(
        &mut self,
        p2_hash_and_absorb_num: Var<C::N>,
        input: &Array<C, Felt<C::F>>,
    ) {
        self.push_op(DslIr::Poseidon2AbsorbBabyBear(p2_hash_and_absorb_num, input.clone()));
    }
    pub fn poseidon2_finalize_mut(
        &mut self,
        p2_hash_num: Var<C::N>,
        output: &Array<C, Felt<C::F>>,
    ) {
        self.push_op(DslIr::Poseidon2FinalizeBabyBear(p2_hash_num, output.clone()));
    }
    pub fn poseidon2_compress(
        &mut self,
        left: &Array<C, Felt<C::F>>,
        right: &Array<C, Felt<C::F>>,
    ) -> Array<C, Felt<C::F>> {
        let mut input = self.dyn_array(PERMUTATION_WIDTH);
        for i in 0..DIGEST_SIZE {
            let a = self.get(left, i);
            let b = self.get(right, i);
            self.set(&mut input, i, a);
            self.set(&mut input, i + DIGEST_SIZE, b);
        }
        self.poseidon2_permute_mut(&input);
        input
    }
    pub fn poseidon2_compress_x(
        &mut self,
        result: &mut Array<C, Felt<C::F>>,
        left: &Array<C, Felt<C::F>>,
        right: &Array<C, Felt<C::F>>,
    ) {
        self.push_op(DslIr::Poseidon2CompressBabyBear(Box::new((
            result.clone(),
            left.clone(),
            right.clone(),
        ))));
    }
    pub fn poseidon2_hash(&mut self, array: &Array<C, Felt<C::F>>) -> Array<C, Felt<C::F>> {
        let mut state: Array<C, Felt<C::F>> = self.dyn_array(PERMUTATION_WIDTH);
        let break_flag: Var<_> = self.eval(C::N::zero());
        let last_index: Usize<_> = self.eval(array.len() - 1);
        self.range(0, array.len()).step_by(HASH_RATE).for_each(|i, builder| {
            builder.if_eq(break_flag, C::N::one()).then(|builder| {
                builder.break_loop();
            });
            builder.range(0, HASH_RATE).for_each(|j, builder| {
                let index: Var<_> = builder.eval(i + j);
                let element = builder.get(array, index);
                builder.set_value(&mut state, j, element);
                builder.if_eq(index, last_index).then(|builder| {
                    builder.assign(break_flag, C::N::one());
                    builder.break_loop();
                });
            });
            builder.poseidon2_permute_mut(&state);
        });
        state.truncate(self, Usize::Const(DIGEST_SIZE));
        state
    }
    pub fn poseidon2_hash_x(
        &mut self,
        array: &Array<C, Array<C, Felt<C::F>>>,
    ) -> Array<C, Felt<C::F>> {
        self.cycle_tracker("poseidon2-hash");
        let p2_hash_num = self.p2_hash_num;
        let two_power_12: Var<_> = self.eval(C::N::from_canonical_u32(1 << 12));
        self.range(0, array.len()).for_each(|i, builder| {
            let subarray = builder.get(array, i);
            let p2_hash_and_absorb_num: Var<_> = builder.eval(p2_hash_num * two_power_12 + i);
            builder.poseidon2_absorb(p2_hash_and_absorb_num, &subarray);
        });
        let output: Array<C, Felt<C::F>> = self.dyn_array(DIGEST_SIZE);
        self.poseidon2_finalize_mut(self.p2_hash_num, &output);
        self.assign(self.p2_hash_num, self.p2_hash_num + C::N::one());
        self.cycle_tracker("poseidon2-hash");
        output
    }
    pub fn poseidon2_hash_ext(
        &mut self,
        array: &Array<C, Array<C, Ext<C::F, C::EF>>>,
    ) -> Array<C, Felt<C::F>> {
        self.cycle_tracker("poseidon2-hash-ext");
        let mut state: Array<C, Felt<C::F>> = self.dyn_array(PERMUTATION_WIDTH);
        let idx: Var<_> = self.eval(C::N::zero());
        self.range(0, array.len()).for_each(|i, builder| {
            let subarray = builder.get(array, i);
            builder.range(0, subarray.len()).for_each(|j, builder| {
                let element = builder.get(&subarray, j);
                let felts = builder.ext2felt(element);
                for i in 0..4 {
                    let felt = builder.get(&felts, i);
                    builder.set_value(&mut state, idx, felt);
                    builder.assign(idx, idx + C::N::one());
                    builder.if_eq(idx, C::N::from_canonical_usize(HASH_RATE)).then(|builder| {
                        builder.poseidon2_permute_mut(&state);
                        builder.assign(idx, C::N::zero());
                    });
                }
            });
        });
        self.if_ne(idx, C::N::zero()).then(|builder| {
            builder.poseidon2_permute_mut(&state);
        });
        state.truncate(self, Usize::Const(DIGEST_SIZE));
        self.cycle_tracker("poseidon2-hash-ext");
        state
    }
}