1#![allow(clippy::assign_op_pattern, clippy::op_ref)]
4
5use elliptic_curve::{bigint::cpubits, ops::BatchInvert};
6
7cpubits! {
8 32 => {
9 #[path = "field/field32.rs"]
10 mod field_impl;
11 }
12 64 => {
13 #[path = "field/field64.rs"]
14 mod field_impl;
15 }
16}
17
18use core::ops::Mul;
19use elliptic_curve::{
20 bigint::U256,
21 ff::PrimeField,
22 subtle::{Choice, ConstantTimeEq, CtOption},
23};
24
25#[cfg(doc)]
26use {
27 core::ops::{Add, Neg, Sub},
28 elliptic_curve::{
29 ff::{self, Field},
30 subtle::ConditionallySelectable,
31 },
32};
33
34const MODULUS_HEX: &str = "ffffffff00000001000000000000000000000000ffffffffffffffffffffffff";
36
37primefield::monty_field_params!(
38 name: FieldParams,
39 modulus: MODULUS_HEX,
40 uint: U256,
41 byte_order: primefield::ByteOrder::BigEndian,
42 multiplicative_generator: 6,
43 doc: "Montgomery parameters for the NIST P-256 field modulus: p = 2^{224}(2^{32} − 1) + 2^{192} + 2^{96} − 1."
44);
45
46primefield::monty_field_element!(
47 name: FieldElement,
48 params: FieldParams,
49 uint: U256,
50 doc: "Element in the finite field modulo p = 2^{224}(2^{32} − 1) + 2^{192} + 2^{96} − 1."
51);
52
53impl FieldElement {
54 pub(crate) const fn from_uint_unchecked(w: U256) -> Self {
60 Self::multiply(
61 &Self::from_montgomery(w),
62 &Self::from_montgomery(*FieldParams::PARAMS.r2()),
63 )
64 }
65
66 pub const fn add(&self, rhs: &Self) -> Self {
68 Self::from_montgomery(field_impl::add(
69 self.0.as_montgomery(),
70 rhs.0.as_montgomery(),
71 ))
72 }
73
74 pub const fn double(&self) -> Self {
76 self.add(self)
77 }
78
79 pub const fn sub(&self, rhs: &Self) -> Self {
81 Self::from_montgomery(field_impl::sub(
82 self.0.as_montgomery(),
83 rhs.0.as_montgomery(),
84 ))
85 }
86
87 pub const fn neg(&self) -> Self {
89 Self::sub(&Self::ZERO, self)
90 }
91
92 #[inline]
94 pub(crate) const fn to_canonical(self) -> U256 {
95 field_impl::to_canonical(self.0.as_montgomery())
96 }
97
98 pub const fn multiply(&self, rhs: &Self) -> Self {
100 let (lo, hi): (U256, U256) = self.0.as_montgomery().widening_mul(rhs.0.as_montgomery());
101 Self::from_montgomery(field_impl::montgomery_reduce(&lo, &hi))
102 }
103
104 pub const fn square(&self) -> Self {
106 self.multiply(self)
108 }
109
110 pub fn invert(&self) -> CtOption<Self> {
112 self.0.invert().map(Self)
113 }
114
115 pub fn invert_vartime(&self) -> CtOption<Self> {
117 self.0.invert_vartime().map(Self)
118 }
119
120 pub fn sqrt(&self) -> CtOption<Self> {
122 let t11 = self.mul(&self.square());
131 let t1111 = t11.mul(&t11.sqn(2));
132 let t11111111 = t1111.mul(t1111.sqn(4));
133 let x16 = t11111111.sqn(8).mul(t11111111);
134 let sqrt = x16
135 .sqn(16)
136 .mul(x16)
137 .sqn(32)
138 .mul(self)
139 .sqn(96)
140 .mul(self)
141 .sqn(94);
142
143 CtOption::new(
144 sqrt,
145 (&sqrt * &sqrt).ct_eq(self), )
147 }
148
149 const fn sqn(&self, n: usize) -> Self {
151 Self(self.0.sqn_vartime(n))
152 }
153
154 #[inline]
156 pub(crate) const fn from_montgomery(uint: U256) -> Self {
157 Self(primefield::MontyFieldElement::<
158 FieldParams,
159 { FieldParams::LIMBS },
160 >::from_montgomery(uint))
161 }
162}
163
164impl BatchInvert for FieldElement {}
165
166#[cfg(test)]
167mod tests {
168 use super::{FieldElement, FieldParams, cpubits};
169 use crate::{FieldBytes, U256, test_vectors::field::DBL_TEST_VECTORS};
170 use elliptic_curve::{array::Array, bigint::modular::ConstMontyParams};
171
172 cpubits! {
173 64 => { use proptest::{num::u64::ANY, prelude::*}; }
174 }
175
176 primefield::test_primefield!(FieldElement, U256);
177
178 #[test]
182 fn r2() {
183 let expected_r2 =
184 U256::from_be_hex("00000004fffffffdfffffffffffffffefffffffbffffffff0000000000000003");
185 assert_eq!(FieldParams::PARAMS.r2(), &expected_r2);
186 }
187
188 #[test]
189 fn from_bytes() {
190 assert_eq!(
191 FieldElement::from_bytes(&FieldBytes::default()).unwrap(),
192 FieldElement::ZERO
193 );
194 assert_eq!(
195 FieldElement::from_bytes(&Array([
196 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
197 0, 0, 0, 1
198 ]))
199 .unwrap(),
200 FieldElement::ONE
201 );
202 assert!(bool::from(
203 FieldElement::from_bytes(&Array([0xff; 32])).is_none()
204 ));
205 }
206
207 #[test]
208 fn to_bytes() {
209 assert_eq!(FieldElement::ZERO.to_bytes(), FieldBytes::default());
210 assert_eq!(
211 FieldElement::ONE.to_bytes(),
212 [
213 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
214 0, 0, 0, 1
215 ]
216 );
217 }
218
219 #[test]
220 fn repeated_add() {
221 let mut r = FieldElement::ONE;
222 for item in DBL_TEST_VECTORS {
223 assert_eq!(r.to_bytes().as_slice(), item);
224 r = r + &r;
225 }
226 }
227
228 #[test]
229 fn repeated_double() {
230 let mut r = FieldElement::ONE;
231 for item in DBL_TEST_VECTORS {
232 assert_eq!(r.to_bytes().as_slice(), item);
233 r = r.double();
234 }
235 }
236
237 #[test]
238 fn repeated_mul() {
239 let mut r = FieldElement::ONE;
240 let two = r + &r;
241 for item in DBL_TEST_VECTORS {
242 assert_eq!(r.to_bytes().as_slice(), item);
243 r = r * &two;
244 }
245 }
246
247 #[test]
248 fn negation() {
249 let two = FieldElement::ONE.double();
250 let neg_two = -two;
251 assert_eq!(two + &neg_two, FieldElement::ZERO);
252 assert_eq!(-neg_two, two);
253 }
254
255 #[test]
256 fn pow_vartime() {
257 let one = FieldElement::ONE;
258 let two = one + &one;
259 let four = two.square();
260 assert_eq!(two.pow_vartime(&U256::from_u64(2)), four);
261 }
262
263 cpubits! {
264 64 => {
265 proptest! {
266 #[test]
269 fn add_then_sub(
270 a0 in ANY,
271 a1 in ANY,
272 a2 in ANY,
273 b0 in ANY,
274 b1 in ANY,
275 b2 in ANY,
276 ) {
277 let a = FieldElement::from_montgomery(U256::from_words([a0, a1, a2, 0]));
278 let b = FieldElement::from_montgomery(U256::from_words([b0, b1, b2, 0]));
279 assert_eq!(a.add(&b).sub(&a), b);
280 }
281 }
282 }
283 }
284}