decaf377/fields/fq/u64/
wrapper.rs

1use ark_ed_on_bls12_377::Fq as ArkworksFq;
2use ark_ff::{biginteger::BigInt, Field, PrimeField};
3use ark_serialize::CanonicalSerialize;
4use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
5
6use super::super::{N_64, N_8};
7
8const N: usize = N_64;
9
10#[derive(Copy, Clone)]
11pub struct Fq(ArkworksFq);
12
13impl PartialEq for Fq {
14    fn eq(&self, other: &Self) -> bool {
15        match (self.is_sentinel(), other.is_sentinel()) {
16            (true, true) => true,
17            (true, false) => false,
18            (false, true) => false,
19            (false, false) => self.0 == other.0,
20        }
21    }
22}
23
24impl Eq for Fq {}
25
26impl zeroize::Zeroize for Fq {
27    fn zeroize(&mut self) {
28        self.0 .0.zeroize()
29    }
30}
31
32impl Fq {
33    pub(crate) fn from_le_limbs(limbs: [u64; N_64]) -> Fq {
34        let mut bytes = [0u8; N_8];
35        for i in 0..N_64 {
36            let this_byte = limbs[i].to_le_bytes();
37            for j in 0..8 {
38                bytes[8 * i + j] = this_byte[j];
39            }
40        }
41
42        Self::from_raw_bytes(&bytes)
43    }
44
45    pub(crate) fn from_raw_bytes(bytes: &[u8; N_8]) -> Fq {
46        Self(ArkworksFq::from_le_bytes_mod_order(bytes))
47    }
48
49    pub(crate) fn to_le_limbs(&self) -> [u64; N_64] {
50        debug_assert!(!self.is_sentinel());
51
52        let le_bytes = self.to_bytes_le();
53        let mut out = [0u64; N_64];
54        for i in 0..N_64 {
55            out[i] = u64::from_le_bytes([
56                le_bytes[8 * i],
57                le_bytes[8 * i + 1],
58                le_bytes[8 * i + 2],
59                le_bytes[8 * i + 3],
60                le_bytes[8 * i + 4],
61                le_bytes[8 * i + 5],
62                le_bytes[8 * i + 6],
63                le_bytes[8 * i + 7],
64            ]);
65        }
66        out
67    }
68
69    pub fn to_bytes_le(&self) -> [u8; N_8] {
70        debug_assert!(!self.is_sentinel());
71
72        let mut bytes = [0u8; 32];
73        self.0
74            .serialize_compressed(&mut bytes[..])
75            .expect("serialization into array should be infallible");
76        bytes
77    }
78
79    /// Instantiate a constant field element from its montgomery limbs.
80    ///
81    /// This should only be used if you are familiar with the internals of the library.
82    pub const fn from_montgomery_limbs(limbs: [u64; N]) -> Fq {
83        // The Arkworks `Fp::new_unchecked` method does not perform montgomery reduction.
84        Self(ArkworksFq::new_unchecked(BigInt::new(limbs)))
85    }
86
87    pub const ZERO: Self = Self(ArkworksFq::new(BigInt::new([0; N])));
88    pub const ONE: Self = Self(ArkworksFq::new(BigInt::one()));
89
90    /// A sentinel value which exists only to not be equal to any other field element.
91    ///
92    /// Operations involving this element are undefined.
93    pub const SENTINEL: Self = Self::from_montgomery_limbs([u64::MAX; N_64]);
94
95    fn is_sentinel(&self) -> bool {
96        self.0 .0 == Self::SENTINEL.0 .0
97    }
98
99    pub fn square(&self) -> Fq {
100        debug_assert!(!self.is_sentinel());
101        Fq(self.0.square())
102    }
103
104    pub fn inverse(&self) -> Option<Fq> {
105        debug_assert!(!self.is_sentinel());
106
107        if self == &Fq::ZERO {
108            return None;
109        }
110
111        Some(Fq(self.0.inverse()?))
112    }
113
114    pub fn add(self, other: &Fq) -> Fq {
115        debug_assert!(!self.is_sentinel() && !other.is_sentinel());
116        Fq(self.0 + other.0)
117    }
118
119    pub fn sub(self, other: &Fq) -> Fq {
120        debug_assert!(!self.is_sentinel() && !other.is_sentinel());
121        Fq(self.0 - other.0)
122    }
123
124    pub fn mul(self, other: &Fq) -> Fq {
125        debug_assert!(!self.is_sentinel() && !other.is_sentinel());
126        Fq(self.0 * other.0)
127    }
128
129    pub fn neg(self) -> Fq {
130        debug_assert!(!self.is_sentinel());
131        Fq(-self.0)
132    }
133}
134
135impl ConditionallySelectable for Fq {
136    fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
137        let mut out = [0u64; 4];
138        let a_limbs = a.0 .0 .0;
139        let b_limbs = b.0 .0 .0;
140        for i in 0..4 {
141            out[i] = u64::conditional_select(&a_limbs[i], &b_limbs[i], choice);
142        }
143        let bigint = BigInt::new(out);
144        Self(ArkworksFq::new(bigint))
145    }
146}
147
148impl ConstantTimeEq for Fq {
149    fn ct_eq(&self, other: &Fq) -> Choice {
150        let self_limbs = self.0 .0 .0;
151        let other_limbs = other.0 .0 .0;
152        let mut is_equal = true;
153        for i in 0..4 {
154            is_equal &= self_limbs[i] == other_limbs[i];
155        }
156        Choice::from(is_equal as u8)
157    }
158}