binius_field/
linear_transformation.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use std::marker::PhantomData;
4
5use rand::RngCore;
6
7use crate::{packed::PackedBinaryField, BinaryField, BinaryField1b, ExtensionField};
8
9/// Generic transformation trait that is used both for scalars and packed fields
10pub trait Transformation<Input, Output>: Sync {
11	fn transform(&self, data: &Input) -> Output;
12}
13
14/// An $\mathbb{F}_2$-linear transformation on binary fields.
15///
16/// Stores transposed transformation matrix as a collection of field elements. `Data` is a generic
17/// parameter because we want to be able both to have const instances that reference static arrays
18/// and owning vector elements.
19#[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/// This crates represents a type that creates a packed transformation from `Self` to a packed
73/// field based on the scalar field transformation.
74#[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}