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 Fq = u64::Fq;
18 } else {
19 pub type Fq = u32::Fq;
20 }
21}
22
23const B: usize = 253;
24const N_8: usize = (B + 7) / 8;
25const N_32: usize = (B + 31) / 32;
26const N_64: usize = (B + 63) / 64;
27
28impl Fq {
29 pub const MODULUS_LIMBS: [u64; N_64] = [
30 725501752471715841,
31 6461107452199829505,
32 6968279316240510977,
33 1345280370688173398,
34 ];
35
36 pub const MODULUS_MINUS_ONE_DIV_TWO_LIMBS: [u64; N_64] = [
37 9586122913090633728,
38 12453925762954690560,
39 3484139658120255488,
40 672640185344086699,
41 ];
42
43 pub const MODULUS_BIT_SIZE: u32 = 0xfd;
44
45 pub const TRACE_LIMBS: [u64; N_64] = [
46 17149038877957297187,
47 11113960768935211860,
48 14608890324369326440,
49 9558,
50 ];
51
52 pub const TRACE_MINUS_ONE_DIV_TWO_LIMBS: [u64; N_64] = [
53 8574519438978648593,
54 5556980384467605930,
55 7304445162184663220,
56 4779,
57 ];
58
59 pub const TWO_ADICITY: u32 = 0x2f;
61
62 pub const QUADRATIC_NON_RESIDUE_TO_TRACE: Self = Self::from_montgomery_limbs([
63 4340692304772210610,
64 11102725085307959083,
65 15540458298643990566,
66 944526744080888988,
67 ]);
68
69 pub const MULTIPLICATIVE_GENERATOR: Self = Self::from_montgomery_limbs([
70 2984901390528151251,
71 10561528701063790279,
72 5476750214495080041,
73 898978044469942640,
74 ]);
75
76 pub const TWO_ADIC_ROOT_OF_UNITY: Self = Self::from_montgomery_limbs([
77 12646347781564978760,
78 6783048705277173164,
79 268534165941069093,
80 1121515446318641358,
81 ]);
82
83 pub const FIELD_SIZE_POWER_OF_TWO: Self = Self::from_montgomery_limbs([
84 2726216793283724667,
85 14712177743343147295,
86 12091039717619697043,
87 81024008013859129,
88 ]);
89
90 pub fn from_le_bytes_mod_order(bytes: &[u8]) -> Self {
91 bytes
92 .chunks(N_8)
93 .map(|x| {
94 let mut padded = [0u8; N_8];
95 padded[..x.len()].copy_from_slice(x);
96 Self::from_raw_bytes(&padded)
97 }) .rev()
99 .fold(Self::ZERO, |acc, x| {
100 acc * (Self::FIELD_SIZE_POWER_OF_TWO) + x
101 }) }
103
104 pub fn from_bytes_checked(bytes: &[u8; N_8]) -> Result<Self, EncodingError> {
109 let reduced = Self::from_raw_bytes(bytes);
110 if reduced.to_bytes_le() == *bytes {
111 Ok(reduced)
112 } else {
113 Err(EncodingError::InvalidEncoding)
114 }
115 }
116
117 pub fn to_bytes(&self) -> [u8; N_8] {
118 self.to_bytes_le()
119 }
120
121 pub fn rand<R: CryptoRngCore>(rng: &mut R) -> Self {
123 let bytes = {
125 let mut out = [0u8; N_8 + 16];
126 rng.fill_bytes(&mut out);
127 out
128 };
129 Self::from_le_bytes_mod_order(&bytes)
130 }
131
132 pub fn power<S: AsRef<[u64]>>(&self, exp: S) -> Self {
136 let mut res = Fq::from(1u64);
137 let exp_u64 = exp.as_ref();
138 for _ in 0..exp_u64[0] {
139 res *= self;
140 }
141 res
142 }
143}
144
145#[cfg(test)]
146mod test {
147 use super::*;
148
149 #[test]
150 fn test_from_bytes_checked() {
151 assert_eq!(Fq::from_bytes_checked(&[0; N_8]), Ok(Fq::ZERO));
152 assert!(Fq::from_bytes_checked(&[0xFF; N_8]).is_err());
153 }
154}