mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-23 08:03:11 +00:00
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.
263 lines
6.3 KiB
Rust
263 lines
6.3 KiB
Rust
use std::convert::TryInto;
|
|
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 = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
|
|
/// = 115792089237316195423570985008687907852837564279074904382605163141518161494337
|
|
/// = 2**256 - 432420386565659656852420866394968145599
|
|
/// ```
|
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
|
pub struct Secp256K1Scalar(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 Secp256K1Scalar {
|
|
fn default() -> Self {
|
|
Self::ZERO
|
|
}
|
|
}
|
|
|
|
impl PartialEq for Secp256K1Scalar {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.to_canonical_biguint() == other.to_canonical_biguint()
|
|
}
|
|
}
|
|
|
|
impl Eq for Secp256K1Scalar {}
|
|
|
|
impl Hash for Secp256K1Scalar {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.to_canonical_biguint().hash(state)
|
|
}
|
|
}
|
|
|
|
impl Display for Secp256K1Scalar {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
Display::fmt(&self.to_canonical_biguint(), f)
|
|
}
|
|
}
|
|
|
|
impl Debug for Secp256K1Scalar {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
Debug::fmt(&self.to_canonical_biguint(), f)
|
|
}
|
|
}
|
|
|
|
impl Field for Secp256K1Scalar {
|
|
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([
|
|
0xBFD25E8CD0364140,
|
|
0xBAAEDCE6AF48A03B,
|
|
0xFFFFFFFFFFFFFFFE,
|
|
0xFFFFFFFFFFFFFFFF,
|
|
]);
|
|
|
|
const TWO_ADICITY: usize = 6;
|
|
const CHARACTERISTIC_TWO_ADICITY: usize = Self::TWO_ADICITY;
|
|
|
|
// Sage: `g = GF(p).multiplicative_generator()`
|
|
const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([7, 0, 0, 0]);
|
|
|
|
// Sage: `g_2 = power_mod(g, (p - 1) // 2^6), p)`
|
|
// 5480320495727936603795231718619559942670027629901634955707709633242980176626
|
|
const POWER_OF_TWO_GENERATOR: Self = Self([
|
|
0x992f4b5402b052f2,
|
|
0x98BDEAB680756045,
|
|
0xDF9879A3FBC483A8,
|
|
0xC1DC060E7A91986,
|
|
]);
|
|
|
|
const BITS: usize = 256;
|
|
|
|
fn order() -> BigUint {
|
|
BigUint::from_slice(&[
|
|
0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 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 Secp256K1Scalar {
|
|
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 Secp256K1Scalar {
|
|
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 Secp256K1Scalar {
|
|
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 Secp256K1Scalar {
|
|
#[inline]
|
|
fn add_assign(&mut self, rhs: Self) {
|
|
*self = *self + rhs;
|
|
}
|
|
}
|
|
|
|
impl Sum for Secp256K1Scalar {
|
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
|
iter.fold(Self::ZERO, |acc, x| acc + x)
|
|
}
|
|
}
|
|
|
|
impl Sub for Secp256K1Scalar {
|
|
type Output = Self;
|
|
|
|
#[inline]
|
|
#[allow(clippy::suspicious_arithmetic_impl)]
|
|
fn sub(self, rhs: Self) -> Self {
|
|
self + -rhs
|
|
}
|
|
}
|
|
|
|
impl SubAssign for Secp256K1Scalar {
|
|
#[inline]
|
|
fn sub_assign(&mut self, rhs: Self) {
|
|
*self = *self - rhs;
|
|
}
|
|
}
|
|
|
|
impl Mul for Secp256K1Scalar {
|
|
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 Secp256K1Scalar {
|
|
#[inline]
|
|
fn mul_assign(&mut self, rhs: Self) {
|
|
*self = *self * rhs;
|
|
}
|
|
}
|
|
|
|
impl Product for Secp256K1Scalar {
|
|
#[inline]
|
|
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
|
|
iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE)
|
|
}
|
|
}
|
|
|
|
impl Div for Secp256K1Scalar {
|
|
type Output = Self;
|
|
|
|
#[allow(clippy::suspicious_arithmetic_impl)]
|
|
fn div(self, rhs: Self) -> Self::Output {
|
|
self * rhs.inverse()
|
|
}
|
|
}
|
|
|
|
impl DivAssign for Secp256K1Scalar {
|
|
fn div_assign(&mut self, rhs: Self) {
|
|
*self = *self / rhs;
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::test_field_arithmetic;
|
|
|
|
test_field_arithmetic!(crate::secp256k1_scalar::Secp256K1Scalar);
|
|
}
|