use alloc::{boxed::Box, vec::Vec};
use core::ops::{AddAssign, Mul};
use miden_core::field::PrimeCharacteristicRing;
pub struct Challenges<EF: PrimeCharacteristicRing> {
pub alpha: EF,
pub beta_powers: Box<[EF]>,
pub bus_prefix: Box<[EF]>,
}
impl<EF: PrimeCharacteristicRing> Challenges<EF> {
pub fn new(alpha: EF, beta: EF, max_message_width: usize, num_bus_ids: usize) -> Self {
assert!(max_message_width > 0, "max_message_width must be non-zero");
let mut beta_powers: Vec<EF> = Vec::with_capacity(max_message_width);
beta_powers.push(EF::ONE);
for i in 1..max_message_width {
beta_powers.push(beta_powers[i - 1].clone() * beta.clone());
}
let beta_powers = beta_powers.into_boxed_slice();
let gamma = beta_powers[max_message_width - 1].clone() * beta;
let bus_prefix: Box<[EF]> = (0..num_bus_ids)
.map(|i| alpha.clone() + gamma.clone() * EF::from_u32((i as u32) + 1))
.collect();
Self { alpha, beta_powers, bus_prefix }
}
#[inline(always)]
pub fn encode<BF, const K: usize>(&self, bus: usize, elems: [BF; K]) -> EF
where
EF: Mul<BF, Output = EF> + AddAssign,
{
debug_assert!(
K <= self.beta_powers.len(),
"Message length {K} exceeds beta_powers capacity ({})",
self.beta_powers.len(),
);
debug_assert!(
bus < self.bus_prefix.len(),
"Bus index {bus} exceeds bus_prefix length ({})",
self.bus_prefix.len(),
);
let mut acc = self.bus_prefix[bus].clone();
for (i, elem) in elems.into_iter().enumerate() {
acc += self.beta_powers[i].clone() * elem;
}
acc
}
#[inline(always)]
pub fn inner_product_at<BF: Clone>(&self, offset: usize, elems: &[BF]) -> EF
where
EF: Mul<BF, Output = EF> + AddAssign,
{
debug_assert!(
offset + elems.len() <= self.beta_powers.len(),
"inner_product_at range {}..{} exceeds beta_powers length ({})",
offset,
offset + elems.len(),
self.beta_powers.len(),
);
let mut acc = EF::ZERO;
for (i, elem) in elems.iter().enumerate() {
acc += self.beta_powers[offset + i].clone() * elem.clone();
}
acc
}
#[inline(always)]
pub fn encode_sparse<BF, const K: usize>(
&self,
bus: usize,
layout: [usize; K],
values: [BF; K],
) -> EF
where
EF: Mul<BF, Output = EF> + AddAssign,
{
debug_assert!(
bus < self.bus_prefix.len(),
"Bus index {bus} exceeds bus_prefix length ({})",
self.bus_prefix.len(),
);
let mut acc = self.bus_prefix[bus].clone();
for (idx, value) in layout.into_iter().zip(values) {
debug_assert!(
idx < self.beta_powers.len(),
"encode_sparse index {} exceeds beta_powers length ({})",
idx,
self.beta_powers.len()
);
acc += self.beta_powers[idx].clone() * value;
}
acc
}
}