1cpubits::cpubits! {
23 16 | 32 => {
24 #[path = "field_element/mul32.rs"]
25 mod mul;
26 }
27 64 => {
28 #[path = "field_element/mul64.rs"]
29 mod mul;
30 }
31}
32
33mod mulx;
34
35use crate::{BLOCK_SIZE, Block};
36use core::{
37 fmt::{self, Debug},
38 num::Wrapping,
39 ops::{Add, BitAnd, BitOr, BitXor, Mul, MulAssign, Shl},
40};
41
42#[cfg(feature = "zeroize")]
43use zeroize::Zeroize;
44
45#[derive(Clone, Copy, Default)]
57#[cfg_attr(test, derive(Eq, PartialEq))]
58#[repr(align(16))] pub struct FieldElement([u8; BLOCK_SIZE]);
60
61impl FieldElement {
62 #[inline]
66 #[must_use]
67 pub fn reverse(mut self) -> Self {
68 self.0.reverse();
69 self
70 }
71}
72
73impl Debug for FieldElement {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 write!(f, "FieldElement(")?;
76 for byte in self.0 {
77 write!(f, "{:02x}", byte)?;
78 }
79 write!(f, ")")
80 }
81}
82
83impl From<Block> for FieldElement {
84 #[inline]
85 fn from(block: Block) -> Self {
86 Self(block.into())
87 }
88}
89
90impl From<&Block> for FieldElement {
91 #[inline]
92 fn from(block: &Block) -> Self {
93 Self::from(*block)
94 }
95}
96
97impl From<FieldElement> for Block {
98 #[inline]
99 fn from(fe: FieldElement) -> Self {
100 fe.0.into()
101 }
102}
103
104impl From<&FieldElement> for Block {
105 #[inline]
106 fn from(fe: &FieldElement) -> Self {
107 Self::from(*fe)
108 }
109}
110
111impl From<[u8; BLOCK_SIZE]> for FieldElement {
112 #[inline]
113 fn from(bytes: [u8; BLOCK_SIZE]) -> Self {
114 Self(bytes)
115 }
116}
117
118impl From<FieldElement> for [u8; BLOCK_SIZE] {
119 #[inline]
120 fn from(fe: FieldElement) -> [u8; BLOCK_SIZE] {
121 fe.0
122 }
123}
124
125impl From<u128> for FieldElement {
126 #[inline]
127 fn from(x: u128) -> Self {
128 Self(x.to_le_bytes())
129 }
130}
131
132impl From<FieldElement> for u128 {
133 #[inline]
134 fn from(fe: FieldElement) -> Self {
135 u128::from_le_bytes(fe.0)
136 }
137}
138
139impl Add for FieldElement {
140 type Output = Self;
141
142 #[inline]
146 fn add(self, rhs: Self) -> Self::Output {
147 (u128::from(self) ^ u128::from(rhs)).into()
148 }
149}
150
151impl Mul for FieldElement {
152 type Output = Self;
153
154 #[inline]
156 fn mul(self, rhs: Self) -> Self {
157 self.karatsuba_mul(rhs).mont_reduce()
158 }
159}
160
161impl MulAssign for FieldElement {
162 #[inline]
163 fn mul_assign(&mut self, rhs: Self) {
164 *self = *self * rhs;
165 }
166}
167
168#[cfg(feature = "zeroize")]
169impl Zeroize for FieldElement {
170 fn zeroize(&mut self) {
171 self.0.zeroize();
172 }
173}
174
175#[inline]
184fn bmul<T>(x: T, y: T, m0: T) -> T
185where
186 T: BitAnd<Output = T> + BitOr<Output = T> + Copy + Shl<u32, Output = T>,
187 Wrapping<T>: BitXor<Output = Wrapping<T>> + Mul<Output = Wrapping<T>>,
188{
189 let m1 = m0 << 1;
190 let m2 = m1 << 1;
191 let m3 = m2 << 1;
192
193 let x0 = Wrapping(x & m0);
194 let x1 = Wrapping(x & m1);
195 let x2 = Wrapping(x & m2);
196 let x3 = Wrapping(x & m3);
197
198 let y0 = Wrapping(y & m0);
199 let y1 = Wrapping(y & m1);
200 let y2 = Wrapping(y & m2);
201 let y3 = Wrapping(y & m3);
202
203 let z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);
204 let z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);
205 let z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);
206 let z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);
207
208 (z0.0 & m0) | (z1.0 & m1) | (z2.0 & m2) | (z3.0 & m3)
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214 use hex_literal::hex;
215
216 const A: [u8; 16] = hex!("66e94bd4ef8a2c3b884cfa59ca342b2e");
217 const B: [u8; 16] = hex!("ff000000000000000000000000000000");
218
219 #[test]
220 fn fe_add() {
221 let a = FieldElement::from(A);
222 let b = FieldElement::from(B);
223
224 let expected = FieldElement::from(hex!("99e94bd4ef8a2c3b884cfa59ca342b2e"));
225 assert_eq!(a + b, expected);
226 assert_eq!(b + a, expected);
227 }
228
229 #[test]
230 fn fe_mul() {
231 let a = FieldElement::from(A);
232 let b = FieldElement::from(B);
233
234 let expected = FieldElement::from(hex!("ebe563401e7e91ea3ad6426b8140c394"));
235 assert_eq!(a * b, expected);
236 assert_eq!(b * a, expected);
237 }
238}