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};
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    /// Basic tests that multiplication works.
198    #[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}