#![allow(
clippy::should_implement_trait,
clippy::suspicious_op_assign_impl,
clippy::unused_unit,
clippy::unnecessary_cast,
clippy::too_many_arguments,
clippy::identity_op
)]
#[cfg_attr(target_pointer_width = "32", path = "field/p384_32.rs")]
#[cfg_attr(target_pointer_width = "64", path = "field/p384_64.rs")]
mod field_impl;
use self::field_impl::*;
use crate::FieldBytes;
use core::ops::{AddAssign, MulAssign, Neg, SubAssign};
use elliptic_curve::{
bigint::{self, Encoding, Limb, U384},
ff::PrimeField,
subtle::{Choice, ConstantTimeEq, CtOption},
};
pub(crate) const MODULUS: U384 = U384::from_be_hex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff");
#[derive(Clone, Copy, Debug)]
pub struct FieldElement(pub(super) U384);
primeorder::impl_field_element!(
FieldElement,
FieldBytes,
U384,
MODULUS,
fiat_p384_montgomery_domain_field_element,
fiat_p384_from_montgomery,
fiat_p384_to_montgomery,
fiat_p384_add,
fiat_p384_sub,
fiat_p384_mul,
fiat_p384_opp,
fiat_p384_square
);
impl FieldElement {
pub fn from_sec1(bytes: FieldBytes) -> CtOption<Self> {
Self::from_be_bytes(bytes)
}
pub fn to_sec1(self) -> FieldBytes {
self.to_be_bytes()
}
pub fn invert(&self) -> CtOption<Self> {
let ret = impl_field_invert!(
self.to_canonical().to_words(),
Self::ONE.0.to_words(),
Limb::BIT_SIZE,
bigint::nlimbs!(U384::BIT_SIZE),
fiat_p384_mul,
fiat_p384_opp,
fiat_p384_divstep_precomp,
fiat_p384_divstep,
fiat_p384_msat,
fiat_p384_selectznz,
);
CtOption::new(Self(ret.into()), !self.is_zero())
}
pub fn sqrt(&self) -> CtOption<Self> {
let t1 = *self;
let t10 = t1.square();
let t11 = t1 * t10;
let t110 = t11.square();
let t111 = t1 * t110;
let t111000 = t111.sqn(3);
let t111111 = t111 * t111000;
let t1111110 = t111111.square();
let t1111111 = t1 * t1111110;
let x12 = t1111110.sqn(5) * t111111;
let x24 = x12.sqn(12) * x12;
let x31 = x24.sqn(7) * t1111111;
let x32 = x31.square() * t1;
let x63 = x32.sqn(31) * x31;
let x126 = x63.sqn(63) * x63;
let x252 = x126.sqn(126) * x126;
let x255 = x252.sqn(3) * t111;
let x = ((x255.sqn(33) * x32).sqn(64) * t1).sqn(30);
CtOption::new(x, x.square().ct_eq(&t1))
}
fn sqn(&self, n: usize) -> Self {
let mut x = *self;
for _ in 0..n {
x = x.square();
}
x
}
}
impl From<u32> for FieldElement {
fn from(n: u32) -> FieldElement {
Self::from_uint(U384::from(n)).unwrap()
}
}
impl From<u64> for FieldElement {
fn from(n: u64) -> FieldElement {
Self::from_uint(U384::from(n)).unwrap()
}
}
impl From<u128> for FieldElement {
fn from(n: u128) -> FieldElement {
Self::from_uint(U384::from(n)).unwrap()
}
}
impl PrimeField for FieldElement {
type Repr = FieldBytes;
const NUM_BITS: u32 = 384;
const CAPACITY: u32 = 383;
const S: u32 = 1;
fn from_repr(bytes: FieldBytes) -> CtOption<Self> {
Self::from_be_bytes(bytes)
}
fn to_repr(&self) -> FieldBytes {
self.to_be_bytes()
}
fn is_odd(&self) -> Choice {
self.is_odd()
}
fn multiplicative_generator() -> Self {
19u32.into()
}
fn root_of_unity() -> Self {
Self::from_repr(
[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0xff, 0xff, 0xff, 0xfe,
]
.into(),
)
.unwrap()
}
}
#[cfg(test)]
mod tests {
use super::FieldElement;
#[test]
fn invert() {
let one = FieldElement::ONE;
assert_eq!(one.invert().unwrap(), one);
let three = one + &one + &one;
let inv_three = three.invert().unwrap();
assert_eq!(three * &inv_three, one);
let minus_three = -three;
let inv_minus_three = minus_three.invert().unwrap();
assert_eq!(inv_minus_three, -inv_three);
assert_eq!(three * &inv_minus_three, -one);
}
#[test]
fn sqrt() {
let one = FieldElement::ONE;
let two = one + &one;
let four = two.square();
assert_eq!(four.sqrt().unwrap(), two);
}
}