plonky2/field/src/secp256k1_base.rs
Daniel Lubarov 2fd5fbbe01 Change from_biguint's behavior with extension fields
These appear to be unused for extension fields, so we're free to change the mapping without breaking anything.

As the TODO says, the mapping that's currently implemented doesn't seem natural or useful. It seems more natural to treat the `BigUint` as a base field element, potentially in a non-canonical form.
2022-08-19 09:21:10 -07:00

254 lines
5.9 KiB
Rust

use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::iter::{Product, Sum};
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use itertools::Itertools;
use num::bigint::BigUint;
use num::{Integer, One};
use serde::{Deserialize, Serialize};
use crate::types::{Field, PrimeField};
/// The base field of the secp256k1 elliptic curve.
///
/// Its order is
/// ```ignore
/// P = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1
/// ```
#[derive(Copy, Clone, Serialize, Deserialize)]
pub struct Secp256K1Base(pub [u64; 4]);
fn biguint_from_array(arr: [u64; 4]) -> BigUint {
BigUint::from_slice(&[
arr[0] as u32,
(arr[0] >> 32) as u32,
arr[1] as u32,
(arr[1] >> 32) as u32,
arr[2] as u32,
(arr[2] >> 32) as u32,
arr[3] as u32,
(arr[3] >> 32) as u32,
])
}
impl Default for Secp256K1Base {
fn default() -> Self {
Self::ZERO
}
}
impl PartialEq for Secp256K1Base {
fn eq(&self, other: &Self) -> bool {
self.to_canonical_biguint() == other.to_canonical_biguint()
}
}
impl Eq for Secp256K1Base {}
impl Hash for Secp256K1Base {
fn hash<H: Hasher>(&self, state: &mut H) {
self.to_canonical_biguint().hash(state)
}
}
impl Display for Secp256K1Base {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.to_canonical_biguint(), f)
}
}
impl Debug for Secp256K1Base {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.to_canonical_biguint(), f)
}
}
impl Field for Secp256K1Base {
const ZERO: Self = Self([0; 4]);
const ONE: Self = Self([1, 0, 0, 0]);
const TWO: Self = Self([2, 0, 0, 0]);
const NEG_ONE: Self = Self([
0xFFFFFFFEFFFFFC2E,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF,
]);
const TWO_ADICITY: usize = 1;
const CHARACTERISTIC_TWO_ADICITY: usize = Self::TWO_ADICITY;
// Sage: `g = GF(p).multiplicative_generator()`
const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0]);
// Sage: `g_2 = g^((p - 1) / 2)`
const POWER_OF_TWO_GENERATOR: Self = Self::NEG_ONE;
const BITS: usize = 256;
fn order() -> BigUint {
BigUint::from_slice(&[
0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
0xFFFFFFFF,
])
}
fn characteristic() -> BigUint {
Self::order()
}
fn try_inverse(&self) -> Option<Self> {
if self.is_zero() {
return None;
}
// Fermat's Little Theorem
Some(self.exp_biguint(&(Self::order() - BigUint::one() - BigUint::one())))
}
fn from_noncanonical_biguint(val: BigUint) -> Self {
Self(
val.to_u64_digits()
.into_iter()
.pad_using(4, |_| 0)
.collect::<Vec<_>>()[..]
.try_into()
.expect("error converting to u64 array"),
)
}
#[inline]
fn from_canonical_u64(n: u64) -> Self {
Self([n, 0, 0, 0])
}
#[inline]
fn from_noncanonical_u128(n: u128) -> Self {
Self([n as u64, (n >> 64) as u64, 0, 0])
}
#[inline]
fn from_noncanonical_u96(n: (u64, u32)) -> Self {
Self([n.0, n.1 as u64, 0, 0])
}
#[cfg(feature = "rand")]
fn rand_from_rng<R: rand::Rng>(rng: &mut R) -> Self {
use num::bigint::RandBigInt;
Self::from_noncanonical_biguint(rng.gen_biguint_below(&Self::order()))
}
}
impl PrimeField for Secp256K1Base {
fn to_canonical_biguint(&self) -> BigUint {
let mut result = biguint_from_array(self.0);
if result >= Self::order() {
result -= Self::order();
}
result
}
}
impl Neg for Secp256K1Base {
type Output = Self;
#[inline]
fn neg(self) -> Self {
if self.is_zero() {
Self::ZERO
} else {
Self::from_noncanonical_biguint(Self::order() - self.to_canonical_biguint())
}
}
}
impl Add for Secp256K1Base {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
let mut result = self.to_canonical_biguint() + rhs.to_canonical_biguint();
if result >= Self::order() {
result -= Self::order();
}
Self::from_noncanonical_biguint(result)
}
}
impl AddAssign for Secp256K1Base {
#[inline]
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl Sum for Secp256K1Base {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::ZERO, |acc, x| acc + x)
}
}
impl Sub for Secp256K1Base {
type Output = Self;
#[inline]
#[allow(clippy::suspicious_arithmetic_impl)]
fn sub(self, rhs: Self) -> Self {
self + -rhs
}
}
impl SubAssign for Secp256K1Base {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl Mul for Secp256K1Base {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
Self::from_noncanonical_biguint(
(self.to_canonical_biguint() * rhs.to_canonical_biguint()).mod_floor(&Self::order()),
)
}
}
impl MulAssign for Secp256K1Base {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl Product for Secp256K1Base {
#[inline]
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE)
}
}
impl Div for Secp256K1Base {
type Output = Self;
#[allow(clippy::suspicious_arithmetic_impl)]
fn div(self, rhs: Self) -> Self::Output {
self * rhs.inverse()
}
}
impl DivAssign for Secp256K1Base {
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
#[cfg(test)]
mod tests {
use crate::test_field_arithmetic;
test_field_arithmetic!(crate::secp256k1_base::Secp256K1Base);
}