binius_field/arch/portable/
packed_arithmetic.rs1use crate::{
4 PackedField,
5 binary_field::BinaryField,
6 linear_transformation::{FieldLinearTransformation, Transformation},
7 packed::PackedBinaryField,
8 underlier::{UnderlierWithBitOps, WithUnderlier},
9};
10
11pub fn interleave_with_mask<U: UnderlierWithBitOps>(
15 a: U,
16 b: U,
17 log_block_len: usize,
18 even_mask: &[U],
19) -> (U, U) {
20 assert!(log_block_len < even_mask.len());
21
22 let block_len = 1 << log_block_len;
23 let t = ((a >> block_len) ^ b) & even_mask[log_block_len];
24 let c = a ^ t << block_len;
25 let d = b ^ t;
26
27 (c, d)
28}
29
30macro_rules! interleave_mask_even {
32 ($underlier:ty, $tower_level:literal) => {{
33 let scalar_bits = 1 << $tower_level;
34
35 let mut mask: $underlier = (1 << scalar_bits) - 1;
36 let log_width = <$underlier>::LOG_BITS - $tower_level;
37 let mut i = 1;
38 while i < log_width {
39 mask |= mask << (scalar_bits << i);
40 i += 1;
41 }
42
43 mask
44 }};
45}
46
47pub(crate) use interleave_mask_even;
48
49pub struct PackedTransformation<OP> {
58 bases: Vec<OP>,
59}
60
61impl<OP> PackedTransformation<OP>
62where
63 OP: PackedBinaryField,
64{
65 pub fn new<Data: AsRef<[OP::Scalar]> + Sync>(
66 transformation: &FieldLinearTransformation<OP::Scalar, Data>,
67 ) -> Self {
68 Self {
69 bases: transformation
70 .bases()
71 .iter()
72 .map(|base| OP::broadcast(*base))
73 .collect(),
74 }
75 }
76}
77
78fn broadcast_lowest_bit<U: UnderlierWithBitOps>(mut data: U, log_packed_bits: usize) -> U {
80 for i in 0..log_packed_bits {
81 data |= data << (1 << i)
82 }
83
84 data
85}
86
87impl<U, IP, OP, IF, OF> Transformation<IP, OP> for PackedTransformation<OP>
88where
89 IP: PackedField<Scalar = IF> + WithUnderlier<Underlier = U>,
90 OP: PackedField<Scalar = OF> + WithUnderlier<Underlier = U>,
91 IF: BinaryField,
92 OF: BinaryField,
93 U: UnderlierWithBitOps,
94{
95 fn transform(&self, input: &IP) -> OP {
96 let mut result = OP::zero();
97 let ones = OP::one().to_underlier();
98 let mut input = input.to_underlier();
99
100 for base in &self.bases {
101 let base_component = input & ones;
102 let mask = broadcast_lowest_bit(base_component, OF::LOG_DEGREE);
104 result += OP::from_underlier(mask & base.to_underlier());
105 input = input >> 1;
106 }
107
108 result
109 }
110}