1use crate::{FieldBytes, NistP384, ORDER_HEX, U384};
14use elliptic_curve::{
15 Curve as _,
16 bigint::{ArrayEncoding, Limb, cpubits},
17 ff::PrimeField,
18 ops::{Reduce, ReduceNonZero},
19 scalar::{FromUintUnchecked, IsHigh},
20 subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption},
21};
22
23cpubits! {
24 32 => {
25 #[cfg(p384_backend = "fiat")]
26 use fiat_crypto::p384_scalar_32::*;
27 }
28 64 => {
29 #[cfg(p384_backend = "fiat")]
30 use fiat_crypto::p384_scalar_64::*;
31 }
32}
33
34#[cfg(feature = "serde")]
35use {
36 elliptic_curve::ScalarValue,
37 serdect::serde::{Deserialize, Serialize, de, ser},
38};
39
40#[cfg(doc)]
41use core::ops::{Add, Mul, Neg, Sub};
42
43primefield::monty_field_params! {
44 name: ScalarParams,
45 modulus: ORDER_HEX,
46 uint: U384,
47 byte_order: primefield::ByteOrder::BigEndian,
48 multiplicative_generator: 2,
49 doc: "Montgomery parameters for the NIST P-384 scalar modulus `n`."
50}
51
52primefield::monty_field_element! {
53 name: Scalar,
54 params: ScalarParams,
55 uint: U384,
56 doc: "Element in the NIST P-384 scalar field modulo `n`."
57}
58
59#[cfg(not(p384_backend = "fiat"))]
60primefield::monty_field_arithmetic! {
61 name: Scalar,
62 params: ScalarParams,
63 uint: U384
64}
65
66#[cfg(p384_backend = "fiat")]
67primefield::fiat_monty_field_arithmetic! {
68 name: Scalar,
69 params: ScalarParams,
70 uint: U384,
71 non_mont: fiat_p384_scalar_non_montgomery_domain_field_element,
72 mont: fiat_p384_scalar_montgomery_domain_field_element,
73 from_mont: fiat_p384_scalar_from_montgomery,
74 to_mont: fiat_p384_scalar_to_montgomery,
75 add: fiat_p384_scalar_add,
76 sub: fiat_p384_scalar_sub,
77 mul: fiat_p384_scalar_mul,
78 neg: fiat_p384_scalar_opp,
79 square: fiat_p384_scalar_square,
80 divstep_precomp: fiat_p384_scalar_divstep_precomp,
81 divstep: fiat_p384_scalar_divstep,
82 msat: fiat_p384_scalar_msat,
83 selectnz: fiat_p384_scalar_selectznz
84}
85
86elliptic_curve::scalar_impls!(NistP384, Scalar);
87
88impl AsRef<Scalar> for Scalar {
89 fn as_ref(&self) -> &Scalar {
90 self
91 }
92}
93
94impl FromUintUnchecked for Scalar {
95 type Uint = U384;
96
97 fn from_uint_unchecked(uint: Self::Uint) -> Self {
98 Self::from_uint_unchecked(uint)
99 }
100}
101
102impl IsHigh for Scalar {
103 fn is_high(&self) -> Choice {
104 const MODULUS_SHR1: U384 = NistP384::ORDER.as_ref().shr_vartime(1);
105 self.to_canonical().ct_gt(&MODULUS_SHR1)
106 }
107}
108
109impl Reduce<U384> for Scalar {
110 fn reduce(w: &U384) -> Self {
111 let (r, underflow) = w.borrowing_sub(&NistP384::ORDER, Limb::ZERO);
112 let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
113 Self::from_uint_unchecked(U384::conditional_select(w, &r, !underflow))
114 }
115}
116
117impl Reduce<FieldBytes> for Scalar {
118 #[inline]
119 fn reduce(bytes: &FieldBytes) -> Self {
120 Self::reduce(&U384::from_be_byte_array(*bytes))
121 }
122}
123
124impl ReduceNonZero<U384> for Scalar {
125 fn reduce_nonzero(w: &U384) -> Self {
126 const ORDER_MINUS_ONE: U384 = NistP384::ORDER.as_ref().wrapping_sub(&U384::ONE);
127 let (r, underflow) = w.borrowing_sub(&ORDER_MINUS_ONE, Limb::ZERO);
128 let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
129 Self::from_uint_unchecked(
130 U384::conditional_select(w, &r, !underflow).wrapping_add(&U384::ONE),
131 )
132 }
133}
134
135impl ReduceNonZero<FieldBytes> for Scalar {
136 #[inline]
137 fn reduce_nonzero(bytes: &FieldBytes) -> Self {
138 Self::reduce_nonzero(&U384::from_be_byte_array(*bytes))
139 }
140}
141
142#[cfg(feature = "serde")]
143impl Serialize for Scalar {
144 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
145 where
146 S: ser::Serializer,
147 {
148 ScalarValue::from(self).serialize(serializer)
149 }
150}
151
152#[cfg(feature = "serde")]
153impl<'de> Deserialize<'de> for Scalar {
154 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
155 where
156 D: de::Deserializer<'de>,
157 {
158 Ok(ScalarValue::deserialize(deserializer)?.into())
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::{Scalar, U384};
165 #[cfg(p384_backend = "fiat")]
166 use super::{
167 ScalarParams, fiat_p384_scalar_montgomery_domain_field_element, fiat_p384_scalar_msat,
168 fiat_p384_scalar_non_montgomery_domain_field_element, fiat_p384_scalar_to_montgomery,
169 };
170 use crate::{FieldBytes, NistP384, NonZeroScalar};
171 use elliptic_curve::{Curve, array::Array, ff::PrimeField, ops::ReduceNonZero};
172 use proptest::{prelude::any, prop_compose};
173
174 primefield::test_primefield!(Scalar, U384);
175
176 #[cfg(p384_backend = "fiat")]
177 primefield::test_fiat_monty_field_arithmetic!(
178 name: Scalar,
179 params: ScalarParams,
180 uint: U384,
181 non_mont: fiat_p384_scalar_non_montgomery_domain_field_element,
182 mont: fiat_p384_scalar_montgomery_domain_field_element,
183 to_mont: fiat_p384_scalar_to_montgomery,
184 msat: fiat_p384_scalar_msat
185 );
186
187 #[test]
188 fn from_to_bytes_roundtrip() {
189 let k: u64 = 42;
190 let mut bytes = FieldBytes::default();
191 bytes[40..].copy_from_slice(k.to_be_bytes().as_ref());
192
193 let scalar = Scalar::from_repr(bytes).unwrap();
194 assert_eq!(bytes, scalar.to_bytes());
195 }
196
197 #[test]
199 fn multiply() {
200 let one = Scalar::ONE;
201 let two = one + one;
202 let three = two + one;
203 let six = three + three;
204 assert_eq!(six, two * three);
205
206 let minus_two = -two;
207 let minus_three = -three;
208 assert_eq!(two, -minus_two);
209
210 assert_eq!(minus_three * minus_two, minus_two * minus_three);
211 assert_eq!(six, minus_two * minus_three);
212 }
213
214 #[test]
215 fn reduce_nonzero() {
216 assert_eq!(
217 Scalar::reduce_nonzero(&Array::default()).to_canonical(),
218 U384::ONE
219 );
220 assert_eq!(
221 Scalar::reduce_nonzero(&U384::ONE).to_canonical(),
222 U384::from_u8(2)
223 );
224 assert_eq!(
225 Scalar::reduce_nonzero(&U384::from_u8(2)).to_canonical(),
226 U384::from_u8(3),
227 );
228
229 assert_eq!(
230 Scalar::reduce_nonzero(NistP384::ORDER.as_ref()).to_canonical(),
231 U384::from_u8(2),
232 );
233 assert_eq!(
234 Scalar::reduce_nonzero(&NistP384::ORDER.wrapping_sub(&U384::from_u8(1))).to_canonical(),
235 U384::ONE,
236 );
237 assert_eq!(
238 Scalar::reduce_nonzero(&NistP384::ORDER.wrapping_sub(&U384::from_u8(2))).to_canonical(),
239 NistP384::ORDER.wrapping_sub(&U384::ONE),
240 );
241 assert_eq!(
242 Scalar::reduce_nonzero(&NistP384::ORDER.wrapping_sub(&U384::from_u8(3))).to_canonical(),
243 NistP384::ORDER.wrapping_sub(&U384::from_u8(2)),
244 );
245
246 assert_eq!(
247 Scalar::reduce_nonzero(&NistP384::ORDER.wrapping_add(&U384::ONE)).to_canonical(),
248 U384::from_u8(3),
249 );
250 assert_eq!(
251 Scalar::reduce_nonzero(&NistP384::ORDER.wrapping_add(&U384::from_u8(2))).to_canonical(),
252 U384::from_u8(4),
253 );
254 }
255
256 prop_compose! {
257 fn non_zero_scalar()(bytes in any::<[u8; 48]>()) -> NonZeroScalar {
258 NonZeroScalar::reduce_nonzero(&FieldBytes::from(bytes))
259 }
260 }
261}