decaf377/fields/
fp.rs

1use cfg_if::cfg_if;
2use rand_core::CryptoRngCore;
3
4use crate::EncodingError;
5
6#[cfg(feature = "arkworks")]
7pub mod arkworks;
8mod ops;
9mod u32;
10
11// The u64 backend requires arkworks
12#[cfg(feature = "arkworks")]
13mod u64;
14
15cfg_if! {
16    if #[cfg(feature = "arkworks")] {
17        pub type Fp = u64::Fp;
18    } else {
19        pub type Fp = u32::Fp;
20    }
21}
22
23const B: usize = 377;
24const N_8: usize = (B + 7) / 8;
25const N_32: usize = (B + 31) / 32;
26const N_64: usize = (B + 63) / 64;
27
28impl Fp {
29    pub const MODULUS_LIMBS: [u64; N_64] = [
30        9586122913090633729,
31        1660523435060625408,
32        2230234197602682880,
33        1883307231910630287,
34        14284016967150029115,
35        121098312706494698,
36    ];
37
38    pub const MODULUS_MINUS_ONE_DIV_TWO_LIMBS: [u64; N_64] = [
39        4793061456545316864,
40        830261717530312704,
41        10338489135656117248,
42        10165025652810090951,
43        7142008483575014557,
44        60549156353247349,
45    ];
46
47    pub const MODULUS_BIT_SIZE: u32 = 0x179;
48
49    pub const TRACE_LIMBS: [u64; N_64] = [
50        8435453208297608227,
51        9853568280881552429,
52        7479357291536088013,
53        1657802422768920715,
54        16796279350917535980,
55        1720,
56    ];
57
58    pub const TRACE_MINUS_ONE_DIV_TWO_LIMBS: [u64; N_64] = [
59        13441098641003579921,
60        14150156177295552022,
61        12963050682622819814,
62        828901211384460357,
63        8398139675458767990,
64        860,
65    ];
66
67    pub const TWO_ADICITY: u32 = 0x2e;
68
69    pub const QUADRATIC_NON_RESIDUE_TO_TRACE: Self = Self::from_montgomery_limbs([
70        7563926049028936178,
71        2688164645460651601,
72        12112688591437172399,
73        3177973240564633687,
74        14764383749841851163,
75        52487407124055189,
76    ]);
77
78    pub const MULTIPLICATIVE_GENERATOR: Self = Self::from_montgomery_limbs([
79        1580481994230331156,
80        7393753505699199837,
81        15893201093018099506,
82        15064395564155502359,
83        7595513421530309810,
84        112614884009382239,
85    ]);
86
87    pub const TWO_ADIC_ROOT_OF_UNITY: Self = Self::from_montgomery_limbs([
88        16125954451488549662,
89        8217881455460992412,
90        2710394594754331350,
91        15576616684900113046,
92        13256804877427073124,
93        71394035925664393,
94    ]);
95
96    pub const FIELD_SIZE_POWER_OF_TWO: Self = Self::from_montgomery_limbs([
97        13224372171368877346,
98        227991066186625457,
99        2496666625421784173,
100        13825906835078366124,
101        9475172226622360569,
102        30958721782860680,
103    ]);
104
105    pub fn from_le_bytes_mod_order(bytes: &[u8]) -> Self {
106        bytes
107            .chunks(N_8)
108            .map(|x| {
109                let mut padded = [0u8; N_8];
110                padded[..x.len()].copy_from_slice(x);
111                Self::from_raw_bytes(&padded)
112            }) // [X, 2^(384) * X, ...]
113            .rev()
114            .fold(Self::ZERO, |acc, x| {
115                acc * (Self::FIELD_SIZE_POWER_OF_TWO) + x
116            }) // let acc =
117    }
118
119    /// Convert bytes into an Fp element, returning None if these bytes are not already reduced.
120    ///
121    /// This means that values that cannot be produced by encoding a field element will return
122    /// None, enforcing canonical serialization.
123    pub fn from_bytes_checked(bytes: &[u8; N_8]) -> Result<Self, EncodingError> {
124        let reduced = Self::from_raw_bytes(bytes);
125        if reduced.to_bytes_le() == *bytes {
126            Ok(reduced)
127        } else {
128            Err(EncodingError::InvalidEncoding)
129        }
130    }
131
132    pub fn to_bytes(&self) -> [u8; N_8] {
133        self.to_bytes_le()
134    }
135
136    /// Sample a random field element uniformly.
137    pub fn rand<R: CryptoRngCore>(rng: &mut R) -> Self {
138        // Sample wide, reduce
139        let bytes = {
140            let mut out = [0u8; N_8 + 16];
141            rng.fill_bytes(&mut out);
142            out
143        };
144        Self::from_le_bytes_mod_order(&bytes)
145    }
146}
147
148#[cfg(test)]
149mod test {
150    use super::*;
151
152    #[test]
153    fn test_from_bytes_checked() {
154        assert_eq!(Fp::from_bytes_checked(&[0; N_8]), Ok(Fp::ZERO));
155        assert!(Fp::from_bytes_checked(&[0xFF; N_8]).is_err());
156    }
157}