binius_field/
linear_transformation.rsuse crate::{packed::PackedBinaryField, BinaryField, BinaryField1b, ExtensionField};
use rand::RngCore;
use std::ops::Deref;
pub trait Transformation<Input, Output> {
fn transform(&self, data: &Input) -> Output;
}
#[derive(Debug, Clone)]
pub struct FieldLinearTransformation<OF: BinaryField, Data: Deref<Target = [OF]> = &'static [OF]> {
bases: Data,
}
impl<OF: BinaryField> FieldLinearTransformation<OF, &'static [OF]> {
pub const fn new_const(bases: &'static [OF]) -> Self {
assert!(bases.len() == OF::DEGREE);
Self { bases }
}
}
impl<OF: BinaryField, Data: Deref<Target = [OF]>> FieldLinearTransformation<OF, Data> {
pub fn new(bases: Data) -> Self {
debug_assert_eq!(bases.deref().len(), OF::DEGREE);
Self { bases }
}
pub fn bases(&self) -> &[OF] {
&self.bases
}
}
impl<IF: BinaryField, OF: BinaryField, Data: Deref<Target = [OF]>> Transformation<IF, OF>
for FieldLinearTransformation<OF, Data>
{
fn transform(&self, data: &IF) -> OF {
assert_eq!(IF::DEGREE, OF::DEGREE);
ExtensionField::<BinaryField1b>::iter_bases(data)
.zip(self.bases.iter())
.fold(OF::ZERO, |acc, (scalar, &basis_elem)| acc + basis_elem * scalar)
}
}
impl<OF: BinaryField> FieldLinearTransformation<OF, Vec<OF>> {
pub fn random(mut rng: impl RngCore) -> Self {
Self {
bases: (0..OF::DEGREE).map(|_| OF::random(&mut rng)).collect(),
}
}
}
#[allow(private_bounds)]
pub trait PackedTransformationFactory<OP>: PackedBinaryField
where
OP: PackedBinaryField,
{
type PackedTransformation<Data: Deref<Target = [OP::Scalar]>>: Transformation<Self, OP>;
fn make_packed_transformation<Data: Deref<Target = [OP::Scalar]>>(
transformation: FieldLinearTransformation<OP::Scalar, Data>,
) -> Self::PackedTransformation<Data>;
}