Skip to main content

p384/arithmetic/
scalar.rs

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