use core::convert::TryFrom;
use core::fmt;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
use crate::util::{adc, mac, sbb};
#[derive(Copy, Clone)]
pub struct Fp([u64; 6]);
impl fmt::Debug for Fp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let tmp = self.to_bytes();
write!(f, "0x")?;
for &b in tmp.iter() {
write!(f, "{:02x}", b)?;
}
Ok(())
}
}
impl Default for Fp {
fn default() -> Self {
Fp::zero()
}
}
impl ConstantTimeEq for Fp {
fn ct_eq(&self, other: &Self) -> Choice {
self.0[0].ct_eq(&other.0[0])
& self.0[1].ct_eq(&other.0[1])
& self.0[2].ct_eq(&other.0[2])
& self.0[3].ct_eq(&other.0[3])
& self.0[4].ct_eq(&other.0[4])
& self.0[5].ct_eq(&other.0[5])
}
}
impl Eq for Fp {}
impl PartialEq for Fp {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).unwrap_u8() == 1
}
}
impl ConditionallySelectable for Fp {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fp([
u64::conditional_select(&a.0[0], &b.0[0], choice),
u64::conditional_select(&a.0[1], &b.0[1], choice),
u64::conditional_select(&a.0[2], &b.0[2], choice),
u64::conditional_select(&a.0[3], &b.0[3], choice),
u64::conditional_select(&a.0[4], &b.0[4], choice),
u64::conditional_select(&a.0[5], &b.0[5], choice),
])
}
}
const MODULUS: [u64; 6] = [
0xb9feffffffffaaab,
0x1eabfffeb153ffff,
0x6730d2a0f6b0f624,
0x64774b84f38512bf,
0x4b1ba7b6434bacd7,
0x1a0111ea397fe69a,
];
const INV: u64 = 0x89f3fffcfffcfffd;
const R: Fp = Fp([
0x760900000002fffd,
0xebf4000bc40c0002,
0x5f48985753c758ba,
0x77ce585370525745,
0x5c071a97a256ec6d,
0x15f65ec3fa80e493,
]);
const R2: Fp = Fp([
0xf4df1f341c341746,
0xa76e6a609d104f1,
0x8de5476c4c95b6d5,
0x67eb88a9939d83c0,
0x9a793e85b519952d,
0x11988fe592cae3aa,
]);
impl<'a> Neg for &'a Fp {
type Output = Fp;
#[inline]
fn neg(self) -> Fp {
self.neg()
}
}
impl Neg for Fp {
type Output = Fp;
#[inline]
fn neg(self) -> Fp {
-&self
}
}
impl<'a, 'b> Sub<&'b Fp> for &'a Fp {
type Output = Fp;
#[inline]
fn sub(self, rhs: &'b Fp) -> Fp {
self.sub(rhs)
}
}
impl<'a, 'b> Add<&'b Fp> for &'a Fp {
type Output = Fp;
#[inline]
fn add(self, rhs: &'b Fp) -> Fp {
self.add(rhs)
}
}
impl<'a, 'b> Mul<&'b Fp> for &'a Fp {
type Output = Fp;
#[inline]
fn mul(self, rhs: &'b Fp) -> Fp {
self.mul(rhs)
}
}
impl_binops_additive!(Fp, Fp);
impl_binops_multiplicative!(Fp, Fp);
impl Fp {
#[inline]
pub const fn zero() -> Fp {
Fp([0, 0, 0, 0, 0, 0])
}
#[inline]
pub const fn one() -> Fp {
R
}
pub fn is_zero(&self) -> Choice {
self.ct_eq(&Fp::zero())
}
pub fn from_bytes(bytes: &[u8; 48]) -> CtOption<Fp> {
let mut tmp = Fp([0, 0, 0, 0, 0, 0]);
tmp.0[5] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[0..8]).unwrap());
tmp.0[4] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[8..16]).unwrap());
tmp.0[3] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[16..24]).unwrap());
tmp.0[2] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[24..32]).unwrap());
tmp.0[1] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[32..40]).unwrap());
tmp.0[0] = u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[40..48]).unwrap());
let (_, borrow) = sbb(tmp.0[0], MODULUS[0], 0);
let (_, borrow) = sbb(tmp.0[1], MODULUS[1], borrow);
let (_, borrow) = sbb(tmp.0[2], MODULUS[2], borrow);
let (_, borrow) = sbb(tmp.0[3], MODULUS[3], borrow);
let (_, borrow) = sbb(tmp.0[4], MODULUS[4], borrow);
let (_, borrow) = sbb(tmp.0[5], MODULUS[5], borrow);
let is_some = (borrow as u8) & 1;
tmp *= &R2;
CtOption::new(tmp, Choice::from(is_some))
}
pub fn to_bytes(&self) -> [u8; 48] {
let tmp = Fp::montgomery_reduce(
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], 0, 0, 0, 0, 0, 0,
);
let mut res = [0; 48];
res[0..8].copy_from_slice(&tmp.0[5].to_be_bytes());
res[8..16].copy_from_slice(&tmp.0[4].to_be_bytes());
res[16..24].copy_from_slice(&tmp.0[3].to_be_bytes());
res[24..32].copy_from_slice(&tmp.0[2].to_be_bytes());
res[32..40].copy_from_slice(&tmp.0[1].to_be_bytes());
res[40..48].copy_from_slice(&tmp.0[0].to_be_bytes());
res
}
pub fn lexicographically_largest(&self) -> Choice {
let tmp = Fp::montgomery_reduce(
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], 0, 0, 0, 0, 0, 0,
);
let (_, borrow) = sbb(tmp.0[0], 0xdcff7fffffffd556, 0);
let (_, borrow) = sbb(tmp.0[1], 0x0f55ffff58a9ffff, borrow);
let (_, borrow) = sbb(tmp.0[2], 0xb39869507b587b12, borrow);
let (_, borrow) = sbb(tmp.0[3], 0xb23ba5c279c2895f, borrow);
let (_, borrow) = sbb(tmp.0[4], 0x258dd3db21a5d66b, borrow);
let (_, borrow) = sbb(tmp.0[5], 0x0d0088f51cbff34d, borrow);
!Choice::from((borrow as u8) & 1)
}
pub const fn from_raw_unchecked(v: [u64; 6]) -> Fp {
Fp(v)
}
pub fn pow_vartime(&self, by: &[u64; 6]) -> Self {
let mut res = Self::one();
for e in by.iter().rev() {
for i in (0..64).rev() {
res = res.square();
if ((*e >> i) & 1) == 1 {
res *= self;
}
}
}
res
}
#[inline]
pub fn sqrt(&self) -> CtOption<Self> {
let sqrt = self.pow_vartime(&[
0xee7fbfffffffeaab,
0x7aaffffac54ffff,
0xd9cc34a83dac3d89,
0xd91dd2e13ce144af,
0x92c6e9ed90d2eb35,
0x680447a8e5ff9a6,
]);
CtOption::new(sqrt, sqrt.square().ct_eq(self))
}
#[inline]
pub fn invert(&self) -> CtOption<Self> {
let t = self.pow_vartime(&[
0xb9feffffffffaaa9,
0x1eabfffeb153ffff,
0x6730d2a0f6b0f624,
0x64774b84f38512bf,
0x4b1ba7b6434bacd7,
0x1a0111ea397fe69a,
]);
CtOption::new(t, !self.is_zero())
}
#[inline]
const fn subtract_p(&self) -> Fp {
let (r0, borrow) = sbb(self.0[0], MODULUS[0], 0);
let (r1, borrow) = sbb(self.0[1], MODULUS[1], borrow);
let (r2, borrow) = sbb(self.0[2], MODULUS[2], borrow);
let (r3, borrow) = sbb(self.0[3], MODULUS[3], borrow);
let (r4, borrow) = sbb(self.0[4], MODULUS[4], borrow);
let (r5, borrow) = sbb(self.0[5], MODULUS[5], borrow);
let r0 = (self.0[0] & borrow) | (r0 & !borrow);
let r1 = (self.0[1] & borrow) | (r1 & !borrow);
let r2 = (self.0[2] & borrow) | (r2 & !borrow);
let r3 = (self.0[3] & borrow) | (r3 & !borrow);
let r4 = (self.0[4] & borrow) | (r4 & !borrow);
let r5 = (self.0[5] & borrow) | (r5 & !borrow);
Fp([r0, r1, r2, r3, r4, r5])
}
#[inline]
pub const fn add(&self, rhs: &Fp) -> Fp {
let (d0, carry) = adc(self.0[0], rhs.0[0], 0);
let (d1, carry) = adc(self.0[1], rhs.0[1], carry);
let (d2, carry) = adc(self.0[2], rhs.0[2], carry);
let (d3, carry) = adc(self.0[3], rhs.0[3], carry);
let (d4, carry) = adc(self.0[4], rhs.0[4], carry);
let (d5, _) = adc(self.0[5], rhs.0[5], carry);
(&Fp([d0, d1, d2, d3, d4, d5])).subtract_p()
}
#[inline]
pub const fn neg(&self) -> Fp {
let (d0, borrow) = sbb(MODULUS[0], self.0[0], 0);
let (d1, borrow) = sbb(MODULUS[1], self.0[1], borrow);
let (d2, borrow) = sbb(MODULUS[2], self.0[2], borrow);
let (d3, borrow) = sbb(MODULUS[3], self.0[3], borrow);
let (d4, borrow) = sbb(MODULUS[4], self.0[4], borrow);
let (d5, _) = sbb(MODULUS[5], self.0[5], borrow);
let mask = (((self.0[0] | self.0[1] | self.0[2] | self.0[3] | self.0[4] | self.0[5]) == 0)
as u64)
.wrapping_sub(1);
Fp([
d0 & mask,
d1 & mask,
d2 & mask,
d3 & mask,
d4 & mask,
d5 & mask,
])
}
#[inline]
pub const fn sub(&self, rhs: &Fp) -> Fp {
(&rhs.neg()).add(self)
}
#[inline(always)]
const fn montgomery_reduce(
t0: u64,
t1: u64,
t2: u64,
t3: u64,
t4: u64,
t5: u64,
t6: u64,
t7: u64,
t8: u64,
t9: u64,
t10: u64,
t11: u64,
) -> Self {
let k = t0.wrapping_mul(INV);
let (_, carry) = mac(t0, k, MODULUS[0], 0);
let (r1, carry) = mac(t1, k, MODULUS[1], carry);
let (r2, carry) = mac(t2, k, MODULUS[2], carry);
let (r3, carry) = mac(t3, k, MODULUS[3], carry);
let (r4, carry) = mac(t4, k, MODULUS[4], carry);
let (r5, carry) = mac(t5, k, MODULUS[5], carry);
let (r6, r7) = adc(t6, 0, carry);
let k = r1.wrapping_mul(INV);
let (_, carry) = mac(r1, k, MODULUS[0], 0);
let (r2, carry) = mac(r2, k, MODULUS[1], carry);
let (r3, carry) = mac(r3, k, MODULUS[2], carry);
let (r4, carry) = mac(r4, k, MODULUS[3], carry);
let (r5, carry) = mac(r5, k, MODULUS[4], carry);
let (r6, carry) = mac(r6, k, MODULUS[5], carry);
let (r7, r8) = adc(t7, r7, carry);
let k = r2.wrapping_mul(INV);
let (_, carry) = mac(r2, k, MODULUS[0], 0);
let (r3, carry) = mac(r3, k, MODULUS[1], carry);
let (r4, carry) = mac(r4, k, MODULUS[2], carry);
let (r5, carry) = mac(r5, k, MODULUS[3], carry);
let (r6, carry) = mac(r6, k, MODULUS[4], carry);
let (r7, carry) = mac(r7, k, MODULUS[5], carry);
let (r8, r9) = adc(t8, r8, carry);
let k = r3.wrapping_mul(INV);
let (_, carry) = mac(r3, k, MODULUS[0], 0);
let (r4, carry) = mac(r4, k, MODULUS[1], carry);
let (r5, carry) = mac(r5, k, MODULUS[2], carry);
let (r6, carry) = mac(r6, k, MODULUS[3], carry);
let (r7, carry) = mac(r7, k, MODULUS[4], carry);
let (r8, carry) = mac(r8, k, MODULUS[5], carry);
let (r9, r10) = adc(t9, r9, carry);
let k = r4.wrapping_mul(INV);
let (_, carry) = mac(r4, k, MODULUS[0], 0);
let (r5, carry) = mac(r5, k, MODULUS[1], carry);
let (r6, carry) = mac(r6, k, MODULUS[2], carry);
let (r7, carry) = mac(r7, k, MODULUS[3], carry);
let (r8, carry) = mac(r8, k, MODULUS[4], carry);
let (r9, carry) = mac(r9, k, MODULUS[5], carry);
let (r10, r11) = adc(t10, r10, carry);
let k = r5.wrapping_mul(INV);
let (_, carry) = mac(r5, k, MODULUS[0], 0);
let (r6, carry) = mac(r6, k, MODULUS[1], carry);
let (r7, carry) = mac(r7, k, MODULUS[2], carry);
let (r8, carry) = mac(r8, k, MODULUS[3], carry);
let (r9, carry) = mac(r9, k, MODULUS[4], carry);
let (r10, carry) = mac(r10, k, MODULUS[5], carry);
let (r11, _) = adc(t11, r11, carry);
(&Fp([r6, r7, r8, r9, r10, r11])).subtract_p()
}
#[inline]
pub const fn mul(&self, rhs: &Fp) -> Fp {
let (t0, carry) = mac(0, self.0[0], rhs.0[0], 0);
let (t1, carry) = mac(0, self.0[0], rhs.0[1], carry);
let (t2, carry) = mac(0, self.0[0], rhs.0[2], carry);
let (t3, carry) = mac(0, self.0[0], rhs.0[3], carry);
let (t4, carry) = mac(0, self.0[0], rhs.0[4], carry);
let (t5, t6) = mac(0, self.0[0], rhs.0[5], carry);
let (t1, carry) = mac(t1, self.0[1], rhs.0[0], 0);
let (t2, carry) = mac(t2, self.0[1], rhs.0[1], carry);
let (t3, carry) = mac(t3, self.0[1], rhs.0[2], carry);
let (t4, carry) = mac(t4, self.0[1], rhs.0[3], carry);
let (t5, carry) = mac(t5, self.0[1], rhs.0[4], carry);
let (t6, t7) = mac(t6, self.0[1], rhs.0[5], carry);
let (t2, carry) = mac(t2, self.0[2], rhs.0[0], 0);
let (t3, carry) = mac(t3, self.0[2], rhs.0[1], carry);
let (t4, carry) = mac(t4, self.0[2], rhs.0[2], carry);
let (t5, carry) = mac(t5, self.0[2], rhs.0[3], carry);
let (t6, carry) = mac(t6, self.0[2], rhs.0[4], carry);
let (t7, t8) = mac(t7, self.0[2], rhs.0[5], carry);
let (t3, carry) = mac(t3, self.0[3], rhs.0[0], 0);
let (t4, carry) = mac(t4, self.0[3], rhs.0[1], carry);
let (t5, carry) = mac(t5, self.0[3], rhs.0[2], carry);
let (t6, carry) = mac(t6, self.0[3], rhs.0[3], carry);
let (t7, carry) = mac(t7, self.0[3], rhs.0[4], carry);
let (t8, t9) = mac(t8, self.0[3], rhs.0[5], carry);
let (t4, carry) = mac(t4, self.0[4], rhs.0[0], 0);
let (t5, carry) = mac(t5, self.0[4], rhs.0[1], carry);
let (t6, carry) = mac(t6, self.0[4], rhs.0[2], carry);
let (t7, carry) = mac(t7, self.0[4], rhs.0[3], carry);
let (t8, carry) = mac(t8, self.0[4], rhs.0[4], carry);
let (t9, t10) = mac(t9, self.0[4], rhs.0[5], carry);
let (t5, carry) = mac(t5, self.0[5], rhs.0[0], 0);
let (t6, carry) = mac(t6, self.0[5], rhs.0[1], carry);
let (t7, carry) = mac(t7, self.0[5], rhs.0[2], carry);
let (t8, carry) = mac(t8, self.0[5], rhs.0[3], carry);
let (t9, carry) = mac(t9, self.0[5], rhs.0[4], carry);
let (t10, t11) = mac(t10, self.0[5], rhs.0[5], carry);
Self::montgomery_reduce(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)
}
#[inline]
pub const fn square(&self) -> Self {
let (t1, carry) = mac(0, self.0[0], self.0[1], 0);
let (t2, carry) = mac(0, self.0[0], self.0[2], carry);
let (t3, carry) = mac(0, self.0[0], self.0[3], carry);
let (t4, carry) = mac(0, self.0[0], self.0[4], carry);
let (t5, t6) = mac(0, self.0[0], self.0[5], carry);
let (t3, carry) = mac(t3, self.0[1], self.0[2], 0);
let (t4, carry) = mac(t4, self.0[1], self.0[3], carry);
let (t5, carry) = mac(t5, self.0[1], self.0[4], carry);
let (t6, t7) = mac(t6, self.0[1], self.0[5], carry);
let (t5, carry) = mac(t5, self.0[2], self.0[3], 0);
let (t6, carry) = mac(t6, self.0[2], self.0[4], carry);
let (t7, t8) = mac(t7, self.0[2], self.0[5], carry);
let (t7, carry) = mac(t7, self.0[3], self.0[4], 0);
let (t8, t9) = mac(t8, self.0[3], self.0[5], carry);
let (t9, t10) = mac(t9, self.0[4], self.0[5], 0);
let t11 = t10 >> 63;
let t10 = (t10 << 1) | (t9 >> 63);
let t9 = (t9 << 1) | (t8 >> 63);
let t8 = (t8 << 1) | (t7 >> 63);
let t7 = (t7 << 1) | (t6 >> 63);
let t6 = (t6 << 1) | (t5 >> 63);
let t5 = (t5 << 1) | (t4 >> 63);
let t4 = (t4 << 1) | (t3 >> 63);
let t3 = (t3 << 1) | (t2 >> 63);
let t2 = (t2 << 1) | (t1 >> 63);
let t1 = t1 << 1;
let (t0, carry) = mac(0, self.0[0], self.0[0], 0);
let (t1, carry) = adc(t1, 0, carry);
let (t2, carry) = mac(t2, self.0[1], self.0[1], carry);
let (t3, carry) = adc(t3, 0, carry);
let (t4, carry) = mac(t4, self.0[2], self.0[2], carry);
let (t5, carry) = adc(t5, 0, carry);
let (t6, carry) = mac(t6, self.0[3], self.0[3], carry);
let (t7, carry) = adc(t7, 0, carry);
let (t8, carry) = mac(t8, self.0[4], self.0[4], carry);
let (t9, carry) = adc(t9, 0, carry);
let (t10, carry) = mac(t10, self.0[5], self.0[5], carry);
let (t11, _) = adc(t11, 0, carry);
Self::montgomery_reduce(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)
}
}
#[test]
fn test_conditional_selection() {
let a = Fp([1, 2, 3, 4, 5, 6]);
let b = Fp([7, 8, 9, 10, 11, 12]);
assert_eq!(
ConditionallySelectable::conditional_select(&a, &b, Choice::from(0u8)),
a
);
assert_eq!(
ConditionallySelectable::conditional_select(&a, &b, Choice::from(1u8)),
b
);
}
#[test]
fn test_equality() {
fn is_equal(a: &Fp, b: &Fp) -> bool {
let eq = a == b;
let ct_eq = a.ct_eq(&b);
assert_eq!(eq, ct_eq.unwrap_u8() == 1);
eq
}
assert!(is_equal(&Fp([1, 2, 3, 4, 5, 6]), &Fp([1, 2, 3, 4, 5, 6])));
assert!(!is_equal(&Fp([7, 2, 3, 4, 5, 6]), &Fp([1, 2, 3, 4, 5, 6])));
assert!(!is_equal(&Fp([1, 7, 3, 4, 5, 6]), &Fp([1, 2, 3, 4, 5, 6])));
assert!(!is_equal(&Fp([1, 2, 7, 4, 5, 6]), &Fp([1, 2, 3, 4, 5, 6])));
assert!(!is_equal(&Fp([1, 2, 3, 7, 5, 6]), &Fp([1, 2, 3, 4, 5, 6])));
assert!(!is_equal(&Fp([1, 2, 3, 4, 7, 6]), &Fp([1, 2, 3, 4, 5, 6])));
assert!(!is_equal(&Fp([1, 2, 3, 4, 5, 7]), &Fp([1, 2, 3, 4, 5, 6])));
}
#[test]
fn test_squaring() {
let a = Fp([
0xd215d2768e83191b,
0x5085d80f8fb28261,
0xce9a032ddf393a56,
0x3e9c4fff2ca0c4bb,
0x6436b6f7f4d95dfb,
0x10606628ad4a4d90,
]);
let b = Fp([
0x33d9c42a3cb3e235,
0xdad11a094c4cd455,
0xa2f144bd729aaeba,
0xd4150932be9ffeac,
0xe27bc7c47d44ee50,
0x14b6a78d3ec7a560,
]);
assert_eq!(a.square(), b);
}
#[test]
fn test_multiplication() {
let a = Fp([
0x397a38320170cd4,
0x734c1b2c9e761d30,
0x5ed255ad9a48beb5,
0x95a3c6b22a7fcfc,
0x2294ce75d4e26a27,
0x13338bd870011ebb,
]);
let b = Fp([
0xb9c3c7c5b1196af7,
0x2580e2086ce335c1,
0xf49aed3d8a57ef42,
0x41f281e49846e878,
0xe0762346c38452ce,
0x652e89326e57dc0,
]);
let c = Fp([
0xf96ef3d711ab5355,
0xe8d459ea00f148dd,
0x53f7354a5f00fa78,
0x9e34a4f3125c5f83,
0x3fbe0c47ca74c19e,
0x1b06a8bbd4adfe4,
]);
assert_eq!(a * b, c);
}
#[test]
fn test_addition() {
let a = Fp([
0x5360bb5978678032,
0x7dd275ae799e128e,
0x5c5b5071ce4f4dcf,
0xcdb21f93078dbb3e,
0xc32365c5e73f474a,
0x115a2a5489babe5b,
]);
let b = Fp([
0x9fd287733d23dda0,
0xb16bf2af738b3554,
0x3e57a75bd3cc6d1d,
0x900bc0bd627fd6d6,
0xd319a080efb245fe,
0x15fdcaa4e4bb2091,
]);
let c = Fp([
0x393442ccb58bb327,
0x1092685f3bd547e3,
0x3382252cab6ac4c9,
0xf94694cb76887f55,
0x4b215e9093a5e071,
0xd56e30f34f5f853,
]);
assert_eq!(a + b, c);
}
#[test]
fn test_subtraction() {
let a = Fp([
0x5360bb5978678032,
0x7dd275ae799e128e,
0x5c5b5071ce4f4dcf,
0xcdb21f93078dbb3e,
0xc32365c5e73f474a,
0x115a2a5489babe5b,
]);
let b = Fp([
0x9fd287733d23dda0,
0xb16bf2af738b3554,
0x3e57a75bd3cc6d1d,
0x900bc0bd627fd6d6,
0xd319a080efb245fe,
0x15fdcaa4e4bb2091,
]);
let c = Fp([
0x6d8d33e63b434d3d,
0xeb1282fdb766dd39,
0x85347bb6f133d6d5,
0xa21daa5a9892f727,
0x3b256cfb3ad8ae23,
0x155d7199de7f8464,
]);
assert_eq!(a - b, c);
}
#[test]
fn test_negation() {
let a = Fp([
0x5360bb5978678032,
0x7dd275ae799e128e,
0x5c5b5071ce4f4dcf,
0xcdb21f93078dbb3e,
0xc32365c5e73f474a,
0x115a2a5489babe5b,
]);
let b = Fp([
0x669e44a687982a79,
0xa0d98a5037b5ed71,
0xad5822f2861a854,
0x96c52bf1ebf75781,
0x87f841f05c0c658c,
0x8a6e795afc5283e,
]);
assert_eq!(-a, b);
}
#[test]
fn test_debug() {
assert_eq!(
format!(
"{:?}",
Fp([0x5360bb5978678032, 0x7dd275ae799e128e, 0x5c5b5071ce4f4dcf, 0xcdb21f93078dbb3e, 0xc32365c5e73f474a, 0x115a2a5489babe5b])
),
"0x104bf052ad3bc99bcb176c24a06a6c3aad4eaf2308fc4d282e106c84a757d061052630515305e59bdddf8111bfdeb704"
);
}
#[test]
fn test_from_bytes() {
let mut a = Fp([
0xdc906d9be3f95dc8,
0x8755caf7459691a1,
0xcff1a7f4e9583ab3,
0x9b43821f849e2284,
0xf57554f3a2974f3f,
0x85dbea84ed47f79,
]);
for _ in 0..100 {
a = a.square();
let tmp = a.to_bytes();
let b = Fp::from_bytes(&tmp).unwrap();
assert_eq!(a, b);
}
assert_eq!(
-Fp::one(),
Fp::from_bytes(&[
26, 1, 17, 234, 57, 127, 230, 154, 75, 27, 167, 182, 67, 75, 172, 215, 100, 119, 75,
132, 243, 133, 18, 191, 103, 48, 210, 160, 246, 176, 246, 36, 30, 171, 255, 254, 177,
83, 255, 255, 185, 254, 255, 255, 255, 255, 170, 170
])
.unwrap()
);
assert!(
Fp::from_bytes(&[
27, 1, 17, 234, 57, 127, 230, 154, 75, 27, 167, 182, 67, 75, 172, 215, 100, 119, 75,
132, 243, 133, 18, 191, 103, 48, 210, 160, 246, 176, 246, 36, 30, 171, 255, 254, 177,
83, 255, 255, 185, 254, 255, 255, 255, 255, 170, 170
])
.is_none()
.unwrap_u8()
== 1
);
assert!(Fp::from_bytes(&[0xff; 48]).is_none().unwrap_u8() == 1);
}
#[test]
fn test_sqrt() {
let a = Fp::from_raw_unchecked([
0xaa270000000cfff3,
0x53cc0032fc34000a,
0x478fe97a6b0a807f,
0xb1d37ebee6ba24d7,
0x8ec9733bbf78ab2f,
0x9d645513d83de7e,
]);
assert_eq!(
-a.sqrt().unwrap(),
Fp::from_raw_unchecked([
0x321300000006554f,
0xb93c0018d6c40005,
0x57605e0db0ddbb51,
0x8b256521ed1f9bcb,
0x6cf28d7901622c03,
0x11ebab9dbb81e28c
])
);
}
#[test]
fn test_inversion() {
let a = Fp([
0x43b43a5078ac2076,
0x1ce0763046f8962b,
0x724a5276486d735c,
0x6f05c2a6282d48fd,
0x2095bd5bb4ca9331,
0x3b35b3894b0f7da,
]);
let b = Fp([
0x69ecd7040952148f,
0x985ccc2022190f55,
0xe19bba36a9ad2f41,
0x19bb16c95219dbd8,
0x14dcacfdfb478693,
0x115ff58afff9a8e1,
]);
assert_eq!(a.invert().unwrap(), b);
assert!(Fp::zero().invert().is_none().unwrap_u8() == 1);
}
#[test]
fn test_lexicographic_largest() {
assert!(!bool::from(Fp::zero().lexicographically_largest()));
assert!(!bool::from(Fp::one().lexicographically_largest()));
assert!(!bool::from(
Fp::from_raw_unchecked([
0xa1fafffffffe5557,
0x995bfff976a3fffe,
0x3f41d24d174ceb4,
0xf6547998c1995dbd,
0x778a468f507a6034,
0x20559931f7f8103
])
.lexicographically_largest()
));
assert!(bool::from(
Fp::from_raw_unchecked([
0x1804000000015554,
0x855000053ab00001,
0x633cb57c253c276f,
0x6e22d1ec31ebb502,
0xd3916126f2d14ca2,
0x17fbb8571a006596
])
.lexicographically_largest()
));
assert!(bool::from(
Fp::from_raw_unchecked([
0x43f5fffffffcaaae,
0x32b7fff2ed47fffd,
0x7e83a49a2e99d69,
0xeca8f3318332bb7a,
0xef148d1ea0f4c069,
0x40ab3263eff0206
])
.lexicographically_largest()
));
}