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#[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 }) .rev()
114 .fold(Self::ZERO, |acc, x| {
115 acc * (Self::FIELD_SIZE_POWER_OF_TWO) + x
116 }) }
118
119 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 pub fn rand<R: CryptoRngCore>(rng: &mut R) -> Self {
138 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}