use boojum::{
cs::traits::cs::ConstraintSystem,
ethereum_types::U256,
field::SmallField,
gadgets::{traits::selectable::Selectable, u256::UInt256},
};
const U256_MAX_BITS: usize = 256;
const U512_MAX_BITS: usize = 512;
const U256_MAX_LIMBS: usize = 8;
const U512_MAX_LIMBS: usize = 16;
const MAX_BINARY_SEARCH_ITERATIONS: usize = 33;
pub fn modexp_32_32_32<F, CS>(
cs: &mut CS,
base: &UInt256<F>,
exponent: &UInt256<F>,
modulus: &UInt256<F>,
) -> UInt256<F>
where
F: SmallField,
CS: ConstraintSystem<F>,
{
let mut a = UInt256::allocated_constant(cs, U256::one());
let binary_expansion = exponent
.to_le_bytes(cs)
.into_iter()
.map(|x| x.into_num().spread_into_bits::<CS, 8>(cs))
.flatten()
.collect::<Vec<_>>();
let mod_is_zero = modulus.is_zero(cs);
for e in binary_expansion.into_iter().rev() {
let a_squared = a.modmul(cs, &a, modulus);
let a_base = a_squared.modmul(cs, base, modulus);
a = UInt256::conditionally_select(cs, e, &a_base, &a_squared);
}
let res = a.mask_negated(cs, mod_is_zero);
res
}