prio/field/
field255.rs

1// Copyright (c) 2023 ISRG
2// SPDX-License-Identifier: MPL-2.0
3
4//! Finite field arithmetic for `GF(2^255 - 19)`.
5
6use crate::{
7    codec::{CodecError, Decode, Encode},
8    field::{FieldElement, FieldElementVisitor, FieldError},
9};
10use fiat_crypto::curve25519_64::{
11    fiat_25519_add, fiat_25519_carry, fiat_25519_carry_mul, fiat_25519_from_bytes,
12    fiat_25519_loose_field_element, fiat_25519_opp, fiat_25519_relax, fiat_25519_selectznz,
13    fiat_25519_sub, fiat_25519_tight_field_element, fiat_25519_to_bytes,
14};
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16use std::{
17    convert::TryFrom,
18    fmt::{self, Debug, Display, Formatter},
19    io::{Cursor, Read},
20    marker::PhantomData,
21    mem::size_of,
22    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
23};
24use subtle::{
25    Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
26};
27
28// `python3 -c "print(', '.join(hex(x) for x in (2**255-19).to_bytes(32, 'little')))"`
29const MODULUS_LITTLE_ENDIAN: [u8; 32] = [
30    0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
31    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
32];
33
34/// `GF(2^255 - 19)`, a 255-bit field.
35#[derive(Clone, Copy)]
36#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
37pub struct Field255(fiat_25519_tight_field_element);
38
39impl Field255 {
40    /// Attempts to instantiate a `Field255` from the first `Self::ENCODED_SIZE` bytes in the
41    /// provided slice.
42    ///
43    /// # Errors
44    ///
45    /// An error is returned if the provided slice is not long enough to encode a field element or
46    /// if the decoded value is greater than the field prime.
47    fn try_from_bytes(bytes: &[u8], mask_top_bit: bool) -> Result<Self, FieldError> {
48        if Self::ENCODED_SIZE > bytes.len() {
49            return Err(FieldError::ShortRead);
50        }
51
52        let mut value = [0u8; Self::ENCODED_SIZE];
53        value.copy_from_slice(&bytes[..Self::ENCODED_SIZE]);
54
55        if mask_top_bit {
56            value[31] &= 0b0111_1111;
57        }
58
59        // Walk through the bytes of the provided value from most significant to least,
60        // and identify whether the first byte that differs from the field's modulus is less than
61        // the corresponding byte or greater than the corresponding byte, in constant time. (Or
62        // whether the provided value is equal to the field modulus.)
63        let mut less_than_modulus = Choice::from(0u8);
64        let mut greater_than_modulus = Choice::from(0u8);
65        for (value_byte, modulus_byte) in value.iter().rev().zip(MODULUS_LITTLE_ENDIAN.iter().rev())
66        {
67            less_than_modulus |= value_byte.ct_lt(modulus_byte) & !greater_than_modulus;
68            greater_than_modulus |= value_byte.ct_gt(modulus_byte) & !less_than_modulus;
69        }
70
71        if bool::from(!less_than_modulus) {
72            return Err(FieldError::ModulusOverflow);
73        }
74
75        let mut output = fiat_25519_tight_field_element([0; 5]);
76        fiat_25519_from_bytes(&mut output, &value);
77
78        Ok(Field255(output))
79    }
80}
81
82impl ConstantTimeEq for Field255 {
83    fn ct_eq(&self, rhs: &Self) -> Choice {
84        // The internal representation used by fiat-crypto is not 1-1 with the field, so it is
85        // necessary to compare field elements via their canonical encodings.
86
87        let mut self_encoded = [0; 32];
88        fiat_25519_to_bytes(&mut self_encoded, &self.0);
89        let mut rhs_encoded = [0; 32];
90        fiat_25519_to_bytes(&mut rhs_encoded, &rhs.0);
91
92        self_encoded.ct_eq(&rhs_encoded)
93    }
94}
95
96impl ConditionallySelectable for Field255 {
97    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
98        let mut output = [0; 5];
99        fiat_25519_selectznz(&mut output, choice.unwrap_u8(), &(a.0).0, &(b.0).0);
100        Field255(fiat_25519_tight_field_element(output))
101    }
102}
103
104impl PartialEq for Field255 {
105    fn eq(&self, rhs: &Self) -> bool {
106        self.ct_eq(rhs).into()
107    }
108}
109
110impl Eq for Field255 {}
111
112impl Add for Field255 {
113    type Output = Field255;
114
115    fn add(self, rhs: Self) -> Field255 {
116        let mut loose_output = fiat_25519_loose_field_element([0; 5]);
117        fiat_25519_add(&mut loose_output, &self.0, &rhs.0);
118        let mut output = fiat_25519_tight_field_element([0; 5]);
119        fiat_25519_carry(&mut output, &loose_output);
120        Field255(output)
121    }
122}
123
124impl AddAssign for Field255 {
125    fn add_assign(&mut self, rhs: Self) {
126        let mut loose_output = fiat_25519_loose_field_element([0; 5]);
127        fiat_25519_add(&mut loose_output, &self.0, &rhs.0);
128        fiat_25519_carry(&mut self.0, &loose_output);
129    }
130}
131
132impl Sub for Field255 {
133    type Output = Field255;
134
135    fn sub(self, rhs: Self) -> Field255 {
136        let mut loose_output = fiat_25519_loose_field_element([0; 5]);
137        fiat_25519_sub(&mut loose_output, &self.0, &rhs.0);
138        let mut output = fiat_25519_tight_field_element([0; 5]);
139        fiat_25519_carry(&mut output, &loose_output);
140        Field255(output)
141    }
142}
143
144impl SubAssign for Field255 {
145    fn sub_assign(&mut self, rhs: Self) {
146        let mut loose_output = fiat_25519_loose_field_element([0; 5]);
147        fiat_25519_sub(&mut loose_output, &self.0, &rhs.0);
148        fiat_25519_carry(&mut self.0, &loose_output);
149    }
150}
151
152impl Mul for Field255 {
153    type Output = Field255;
154
155    fn mul(self, rhs: Self) -> Field255 {
156        let mut self_relaxed = fiat_25519_loose_field_element([0; 5]);
157        fiat_25519_relax(&mut self_relaxed, &self.0);
158        let mut rhs_relaxed = fiat_25519_loose_field_element([0; 5]);
159        fiat_25519_relax(&mut rhs_relaxed, &rhs.0);
160        let mut output = fiat_25519_tight_field_element([0; 5]);
161        fiat_25519_carry_mul(&mut output, &self_relaxed, &rhs_relaxed);
162        Field255(output)
163    }
164}
165
166impl MulAssign for Field255 {
167    fn mul_assign(&mut self, rhs: Self) {
168        let mut self_relaxed = fiat_25519_loose_field_element([0; 5]);
169        fiat_25519_relax(&mut self_relaxed, &self.0);
170        let mut rhs_relaxed = fiat_25519_loose_field_element([0; 5]);
171        fiat_25519_relax(&mut rhs_relaxed, &rhs.0);
172        fiat_25519_carry_mul(&mut self.0, &self_relaxed, &rhs_relaxed);
173    }
174}
175
176impl Div for Field255 {
177    type Output = Field255;
178
179    fn div(self, _rhs: Self) -> Self::Output {
180        unimplemented!("Div is not implemented for Field255 because it's not needed yet")
181    }
182}
183
184impl DivAssign for Field255 {
185    fn div_assign(&mut self, _rhs: Self) {
186        unimplemented!("DivAssign is not implemented for Field255 because it's not needed yet")
187    }
188}
189
190impl Neg for Field255 {
191    type Output = Field255;
192
193    fn neg(self) -> Field255 {
194        -&self
195    }
196}
197
198impl<'a> Neg for &'a Field255 {
199    type Output = Field255;
200
201    fn neg(self) -> Field255 {
202        let mut loose_output = fiat_25519_loose_field_element([0; 5]);
203        fiat_25519_opp(&mut loose_output, &self.0);
204        let mut output = fiat_25519_tight_field_element([0; 5]);
205        fiat_25519_carry(&mut output, &loose_output);
206        Field255(output)
207    }
208}
209
210impl From<u64> for Field255 {
211    fn from(value: u64) -> Self {
212        let input_bytes = value.to_le_bytes();
213        let mut field_bytes = [0u8; Self::ENCODED_SIZE];
214        field_bytes[..input_bytes.len()].copy_from_slice(&input_bytes);
215        Self::try_from_bytes(&field_bytes, false).unwrap()
216    }
217}
218
219impl<'a> TryFrom<&'a [u8]> for Field255 {
220    type Error = FieldError;
221
222    fn try_from(bytes: &[u8]) -> Result<Self, FieldError> {
223        Self::try_from_bytes(bytes, false)
224    }
225}
226
227impl From<Field255> for [u8; Field255::ENCODED_SIZE] {
228    fn from(element: Field255) -> Self {
229        let mut array = [0; Field255::ENCODED_SIZE];
230        fiat_25519_to_bytes(&mut array, &element.0);
231        array
232    }
233}
234
235impl From<Field255> for Vec<u8> {
236    fn from(elem: Field255) -> Vec<u8> {
237        <[u8; Field255::ENCODED_SIZE]>::from(elem).to_vec()
238    }
239}
240
241impl Display for Field255 {
242    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
243        let encoded: [u8; Self::ENCODED_SIZE] = (*self).into();
244        write!(f, "0x")?;
245        for byte in encoded {
246            write!(f, "{byte:02x}")?;
247        }
248        Ok(())
249    }
250}
251
252impl Debug for Field255 {
253    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
254        <Self as Display>::fmt(self, f)
255    }
256}
257
258impl Serialize for Field255 {
259    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
260        let bytes: [u8; Self::ENCODED_SIZE] = (*self).into();
261        serializer.serialize_bytes(&bytes)
262    }
263}
264
265impl<'de> Deserialize<'de> for Field255 {
266    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Field255, D::Error> {
267        deserializer.deserialize_bytes(FieldElementVisitor {
268            phantom: PhantomData,
269        })
270    }
271}
272
273impl Encode for Field255 {
274    fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
275        bytes.extend_from_slice(&<[u8; Self::ENCODED_SIZE]>::from(*self));
276        Ok(())
277    }
278
279    fn encoded_len(&self) -> Option<usize> {
280        Some(Self::ENCODED_SIZE)
281    }
282}
283
284impl Decode for Field255 {
285    fn decode(bytes: &mut Cursor<&[u8]>) -> Result<Self, CodecError> {
286        let mut value = [0u8; Self::ENCODED_SIZE];
287        bytes.read_exact(&mut value)?;
288        Field255::try_from_bytes(&value, false).map_err(|e| {
289            CodecError::Other(Box::new(e) as Box<dyn std::error::Error + 'static + Send + Sync>)
290        })
291    }
292}
293
294impl FieldElement for Field255 {
295    const ENCODED_SIZE: usize = 32;
296
297    fn inv(&self) -> Self {
298        unimplemented!("Field255::inv() is not implemented because it's not needed yet")
299    }
300
301    fn try_from_random(bytes: &[u8]) -> Result<Self, FieldError> {
302        Field255::try_from_bytes(bytes, true)
303    }
304
305    fn zero() -> Self {
306        Field255(fiat_25519_tight_field_element([0, 0, 0, 0, 0]))
307    }
308
309    fn one() -> Self {
310        Field255(fiat_25519_tight_field_element([1, 0, 0, 0, 0]))
311    }
312}
313
314impl Default for Field255 {
315    fn default() -> Self {
316        Field255::zero()
317    }
318}
319
320impl TryFrom<Field255> for u64 {
321    type Error = FieldError;
322
323    fn try_from(elem: Field255) -> Result<u64, FieldError> {
324        const PREFIX_LEN: usize = size_of::<u64>();
325        let mut le_bytes = [0; 32];
326
327        fiat_25519_to_bytes(&mut le_bytes, &elem.0);
328        if !bool::from(le_bytes[PREFIX_LEN..].ct_eq(&[0_u8; 32 - PREFIX_LEN])) {
329            return Err(FieldError::IntegerTryFrom);
330        }
331
332        Ok(u64::from_le_bytes(
333            le_bytes[..PREFIX_LEN].try_into().unwrap(),
334        ))
335    }
336}
337
338#[cfg(test)]
339mod tests {
340    use super::{Field255, MODULUS_LITTLE_ENDIAN};
341    use crate::{
342        codec::Encode,
343        field::{
344            test_utils::{field_element_test_common, TestFieldElementWithInteger},
345            FieldElement, FieldError, Integer,
346        },
347    };
348    use assert_matches::assert_matches;
349    use fiat_crypto::curve25519_64::{
350        fiat_25519_from_bytes, fiat_25519_tight_field_element, fiat_25519_to_bytes,
351    };
352    use num_bigint::BigUint;
353    use once_cell::sync::Lazy;
354    use std::convert::{TryFrom, TryInto};
355
356    static MODULUS: Lazy<BigUint> = Lazy::new(|| BigUint::from_bytes_le(&MODULUS_LITTLE_ENDIAN));
357
358    impl From<BigUint> for Field255 {
359        fn from(value: BigUint) -> Self {
360            let le_bytes_vec = (value % &*MODULUS).to_bytes_le();
361
362            let mut le_bytes_array = [0u8; 32];
363            le_bytes_array[..le_bytes_vec.len()].copy_from_slice(&le_bytes_vec);
364
365            let mut output = fiat_25519_tight_field_element([0; 5]);
366            fiat_25519_from_bytes(&mut output, &le_bytes_array);
367            Field255(output)
368        }
369    }
370
371    impl From<Field255> for BigUint {
372        fn from(value: Field255) -> Self {
373            let mut le_bytes = [0u8; 32];
374            fiat_25519_to_bytes(&mut le_bytes, &value.0);
375            BigUint::from_bytes_le(&le_bytes)
376        }
377    }
378
379    impl Integer for BigUint {
380        type TryFromUsizeError = <Self as TryFrom<usize>>::Error;
381
382        type TryIntoU64Error = <Self as TryInto<u64>>::Error;
383
384        fn zero() -> Self {
385            Self::new(Vec::new())
386        }
387
388        fn one() -> Self {
389            Self::new(Vec::from([1]))
390        }
391    }
392
393    impl TestFieldElementWithInteger for Field255 {
394        type TestInteger = BigUint;
395        type IntegerTryFromError = <Self::TestInteger as TryFrom<usize>>::Error;
396        type TryIntoU64Error = <Self::TestInteger as TryInto<u64>>::Error;
397
398        fn modulus() -> Self::TestInteger {
399            MODULUS.clone()
400        }
401    }
402
403    #[test]
404    fn check_modulus() {
405        let modulus = Field255::modulus();
406        let element = Field255::from(modulus);
407        // Note that these two objects represent the same field element, they encode to the same
408        // canonical value (32 zero bytes), but they do not have the same internal representation.
409        assert_eq!(element, Field255::zero());
410    }
411
412    #[test]
413    fn check_identities() {
414        let zero_bytes: [u8; 32] = Field255::zero().into();
415        assert_eq!(zero_bytes, [0; 32]);
416        let one_bytes: [u8; 32] = Field255::one().into();
417        assert_eq!(
418            one_bytes,
419            [
420                1, 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,
421                0, 0, 0, 0
422            ]
423        );
424    }
425
426    #[test]
427    fn encode_endianness() {
428        let mut one_encoded = Vec::new();
429        Field255::one().encode(&mut one_encoded).unwrap();
430        assert_eq!(
431            one_encoded,
432            [
433                1, 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,
434                0, 0, 0, 0
435            ]
436        );
437    }
438
439    #[test]
440    fn test_field255() {
441        field_element_test_common::<Field255>();
442    }
443
444    #[test]
445    fn try_from_bytes() {
446        assert_matches!(
447            Field255::try_from_bytes(
448                &[
449                    0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
450                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
451                    0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
452                ],
453                false,
454            ),
455            Err(FieldError::ModulusOverflow)
456        );
457        assert_matches!(
458            Field255::try_from_bytes(
459                &[
460                    0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
461                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
462                    0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
463                ],
464                false,
465            ),
466            Ok(_)
467        );
468        assert_matches!(
469            Field255::try_from_bytes(
470                &[
471                    0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
472                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
473                    0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
474                ],
475                true,
476            ),
477            Ok(element) => assert_eq!(element + Field255::one(), Field255::zero())
478        );
479        assert_matches!(
480            Field255::try_from_bytes(
481                &[
482                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484                    0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
485                ],
486                false
487            ),
488            Err(FieldError::ModulusOverflow)
489        );
490        assert_matches!(
491            Field255::try_from_bytes(
492                &[
493                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
494                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
495                    0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
496                ],
497                true
498            ),
499            Ok(element) => assert_eq!(element, Field255::zero())
500        );
501    }
502
503    #[test]
504    fn u64_conversion() {
505        assert_eq!(Field255::from(0u64), Field255::zero());
506        assert_eq!(Field255::from(1u64), Field255::one());
507
508        let max_bytes: [u8; 32] = Field255::from(u64::MAX).into();
509        assert_eq!(
510            max_bytes,
511            [
512                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
513                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
514                0x00, 0x00, 0x00, 0x00
515            ]
516        );
517
518        let want: u64 = 0xffffffffffffffff;
519        assert_eq!(u64::try_from(Field255::from(want)).unwrap(), want);
520
521        let want: u64 = 0x7000000000000001;
522        assert_eq!(u64::try_from(Field255::from(want)).unwrap(), want);
523
524        let want: u64 = 0x1234123412341234;
525        assert_eq!(u64::try_from(Field255::from(want)).unwrap(), want);
526
527        assert!(u64::try_from(Field255::try_from_bytes(&[1; 32], false).unwrap()).is_err());
528        assert!(u64::try_from(Field255::try_from_bytes(&[2; 32], false).unwrap()).is_err());
529    }
530
531    #[test]
532    fn formatting() {
533        assert_eq!(
534            format!("{}", Field255::zero()),
535            "0x0000000000000000000000000000000000000000000000000000000000000000"
536        );
537        assert_eq!(
538            format!("{}", Field255::one()),
539            "0x0100000000000000000000000000000000000000000000000000000000000000"
540        );
541        assert_eq!(
542            format!("{}", -Field255::one()),
543            "0xecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"
544        );
545        assert_eq!(
546            format!("{:?}", Field255::zero()),
547            "0x0000000000000000000000000000000000000000000000000000000000000000"
548        );
549        assert_eq!(
550            format!("{:?}", Field255::one()),
551            "0x0100000000000000000000000000000000000000000000000000000000000000"
552        );
553    }
554}