binius_field/
linear_transformation.rs1use std::marker::PhantomData;
4
5use rand::RngCore;
6
7use crate::{packed::PackedBinaryField, BinaryField, BinaryField1b, ExtensionField};
8
9pub trait Transformation<Input, Output>: Sync {
11 fn transform(&self, data: &Input) -> Output;
12}
13
14#[derive(Debug, Clone)]
20pub struct FieldLinearTransformation<OF: BinaryField, Data: AsRef<[OF]> + Sync = &'static [OF]> {
21 bases: Data,
22 _pd: PhantomData<OF>,
23}
24
25impl<OF: BinaryField> FieldLinearTransformation<OF, &'static [OF]> {
26 pub const fn new_const(bases: &'static [OF]) -> Self {
27 assert!(bases.len() == OF::DEGREE);
28
29 Self {
30 bases,
31 _pd: PhantomData,
32 }
33 }
34}
35
36impl<OF: BinaryField, Data: AsRef<[OF]> + Sync> FieldLinearTransformation<OF, Data> {
37 pub fn new(bases: Data) -> Self {
38 debug_assert_eq!(bases.as_ref().len(), OF::DEGREE);
39
40 Self {
41 bases,
42 _pd: PhantomData,
43 }
44 }
45
46 pub fn bases(&self) -> &[OF] {
47 self.bases.as_ref()
48 }
49}
50
51impl<IF: BinaryField, OF: BinaryField, Data: AsRef<[OF]> + Sync> Transformation<IF, OF>
52 for FieldLinearTransformation<OF, Data>
53{
54 fn transform(&self, data: &IF) -> OF {
55 assert_eq!(IF::DEGREE, OF::DEGREE);
56
57 ExtensionField::<BinaryField1b>::iter_bases(data)
58 .zip(self.bases.as_ref().iter())
59 .fold(OF::ZERO, |acc, (scalar, &basis_elem)| acc + basis_elem * scalar)
60 }
61}
62
63impl<OF: BinaryField> FieldLinearTransformation<OF, Vec<OF>> {
64 pub fn random(mut rng: impl RngCore) -> Self {
65 Self {
66 bases: (0..OF::DEGREE).map(|_| OF::random(&mut rng)).collect(),
67 _pd: PhantomData,
68 }
69 }
70}
71
72#[allow(private_bounds)]
75pub trait PackedTransformationFactory<OP>: PackedBinaryField
76where
77 OP: PackedBinaryField,
78{
79 type PackedTransformation<Data: AsRef<[OP::Scalar]> + Sync>: Transformation<Self, OP>;
80
81 fn make_packed_transformation<Data: AsRef<[OP::Scalar]> + Sync>(
82 transformation: FieldLinearTransformation<OP::Scalar, Data>,
83 ) -> Self::PackedTransformation<Data>;
84}