Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement CurveExt for G1Projective #4

Merged
merged 20 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ optional = true
version = "0.13"
default-features = false

[dependencies.pasta_curves]
version = "0.5"
default-features = false
optional = true

[dependencies.group]
version = "0.13"
default-features = false
Expand Down Expand Up @@ -68,7 +73,7 @@ default = ["groups", "pairings", "alloc", "bits"]
bits = ["ff/bits"]
groups = ["group"]
pairings = ["groups", "pairing"]
alloc = ["group/alloc"]
alloc = ["group/alloc", "pasta_curves/alloc"]
experimental = ["digest"]
nightly = ["subtle/nightly"]
basefield = []
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[toolchain]
channel = "1.61.0"
channel = "1.66.0"
components = [ "clippy", "rustfmt" ]
198 changes: 192 additions & 6 deletions src/fp.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
//! This module provides an implementation of the BLS12-381 base field `GF(p)`
//! where `p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab`

#![allow(clippy::needless_borrow)]
use core::cmp::Ordering;
use core::fmt;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use ff::{Field, PrimeField, WithSmallOrderMulGroup};
use rand_core::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

Expand Down Expand Up @@ -54,6 +57,27 @@ impl PartialEq for Fp {
}
}

impl Ord for Fp {
fn cmp(&self, other: &Self) -> Ordering {
let left = self.to_repr().0;
let right = other.to_repr().0;
left.iter()
.zip(right.iter())
.rev()
.find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) {
Ordering::Equal => None,
res => Some(res),
})
.unwrap_or(Ordering::Equal)
}
}

impl PartialOrd for Fp {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl ConditionallySelectable for Fp {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fp([
Expand All @@ -67,6 +91,12 @@ impl ConditionallySelectable for Fp {
}
}

impl From<u64> for Fp {
fn from(value: u64) -> Self {
Self([value, 0, 0, 0, 0, 0])
CPerezz marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// p = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787
const MODULUS: [u64; 6] = [
0xb9fe_ffff_ffff_aaab,
Expand Down Expand Up @@ -110,6 +140,63 @@ const R3: Fp = Fp([
0x0aa6_3460_9175_5d4d,
]);

/// Fp(1/2)
const TWO_INV: Fp = Fp([
0xdcff7fffffffd556,
0x0f55ffff58a9ffff,
0xb39869507b587b12,
0xb23ba5c279c2895f,
0x258dd3db21a5d66b,
0xd0088f51cbff34d,
]);
CPerezz marked this conversation as resolved.
Show resolved Hide resolved

/// Generator of the field.
const GENERATOR: Fp = Fp([0x0, 0x0, 0x0, 0x0, 0x0, 0x2]);
CPerezz marked this conversation as resolved.
Show resolved Hide resolved

/// Primitive root of unity
const ROOT_OF_UNITY: Fp = Fp([
0x8527e005bf87356d,
0xd867814cd448c6d3,
0xae5a5b133eddd420,
0x356f43ccc999120f,
0xc4296fb7e96da4d6,
0x1938c01908424cd8,
]);
CPerezz marked this conversation as resolved.
Show resolved Hide resolved

/// Inverse of the primitive root of unity.
const ROOT_OF_UNITY_INV: Fp = Fp([
0xded7a779aa2898c8,
0x53f260542172180b,
0xf05b58c2034dddd6,
0x4a7cdeacf037ae72,
0x7aa8223a111aeea8,
0x5046e6d0c9ac33e,
]);
CPerezz marked this conversation as resolved.
Show resolved Hide resolved

/// DELTA
const DELTA: Fp = Fp([
0xca172967c7a255d7,
0xa5d11a97b6038a99,
0x19e243df219f0178,
0x74bc071476d308b7,
0x73a18c6550d55c00,
0x1536fbfcdcf7f2f5,
]);
CPerezz marked this conversation as resolved.
Show resolved Hide resolved

/// ZETA
// sage: modulus = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
// sage: GF(modulus).primitive_element() ^ ((modulus - 1) // 3)
// 793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350
// 5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe
const ZETA: Fp = Fp([
0x2e01fffffffefffe,
0xde17d813620a0002,
0xddb3a93be6f89688,
0xba69c6076a0f77ea,
0x5f19672fdf76ce51,
0x0000000000000000,
]);
CPerezz marked this conversation as resolved.
Show resolved Hide resolved

impl<'a> Neg for &'a Fp {
type Output = Fp;

Expand Down Expand Up @@ -158,6 +245,110 @@ impl<'a, 'b> Mul<&'b Fp> for &'a Fp {
impl_binops_additive!(Fp, Fp);
impl_binops_multiplicative!(Fp, Fp);

impl<T> core::iter::Sum<T> for Fp
where
T: core::borrow::Borrow<Fp>,
{
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = T>,
{
iter.fold(Self::zero(), |acc, item| acc + item.borrow())
}
}

impl<T> core::iter::Product<T> for Fp
where
T: core::borrow::Borrow<Fp>,
{
fn product<I>(iter: I) -> Self
where
I: Iterator<Item = T>,
{
iter.fold(Self::one(), |acc, item| acc * item.borrow())
}
}

impl Field for Fp {
const ZERO: Self = Fp::zero();
const ONE: Self = Fp::one();

fn random(rng: impl RngCore) -> Self {
Self::random(rng)
}

fn square(&self) -> Self {
self.square()
}

fn double(&self) -> Self {
self.add(self)
}

fn invert(&self) -> CtOption<Self> {
self.invert()
}

fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
ff::helpers::sqrt_ratio_generic(num, div)
}

fn sqrt(&self) -> CtOption<Self> {
self.sqrt()
}
}

#[derive(Debug, Clone, Copy)]
pub struct ReprFp(pub(crate) [u8; 48]);

impl AsMut<[u8]> for ReprFp {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..]
}
}

impl AsRef<[u8]> for ReprFp {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}

impl Default for ReprFp {
fn default() -> Self {
Self([0u8; 48])
}
}

impl PrimeField for Fp {
type Repr = ReprFp;

fn from_repr(r: Self::Repr) -> CtOption<Self> {
Self::from_bytes(&r.0)
han0110 marked this conversation as resolved.
Show resolved Hide resolved
}

fn to_repr(&self) -> Self::Repr {
ReprFp(self.to_bytes())
}

fn is_odd(&self) -> Choice {
Choice::from(self.to_bytes()[0] & 1)
}

const MODULUS: &'static str = "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab";
const NUM_BITS: u32 = 381;
const CAPACITY: u32 = Self::NUM_BITS - 1;
const TWO_INV: Self = TWO_INV;
const MULTIPLICATIVE_GENERATOR: Self = GENERATOR;
const S: u32 = 32;
CPerezz marked this conversation as resolved.
Show resolved Hide resolved
const ROOT_OF_UNITY: Self = ROOT_OF_UNITY;
const ROOT_OF_UNITY_INV: Self = ROOT_OF_UNITY_INV;
const DELTA: Self = DELTA;
}

impl WithSmallOrderMulGroup<3> for Fp {
const ZETA: Self = ZETA;
}

impl Fp {
/// Returns zero, the additive identity.
#[inline]
Expand All @@ -171,11 +362,6 @@ impl Fp {
R
}

/// Checks if a value is equal to zero in constant time.
pub fn is_zero(&self) -> Choice {
self.ct_eq(&Fp::zero())
}

/// Attempts to convert a big-endian byte representation of
/// a scalar into an `Fp`, failing if the input is not canonical.
pub fn from_bytes(bytes: &[u8; 48]) -> CtOption<Fp> {
Expand Down Expand Up @@ -395,7 +581,7 @@ impl Fp {

// Attempt to subtract the modulus, to ensure the value
// is smaller than the modulus.
(&Fp([d0, d1, d2, d3, d4, d5])).subtract_p()
(Fp([d0, d1, d2, d3, d4, d5])).subtract_p()
}

#[inline]
Expand Down
2 changes: 2 additions & 0 deletions src/fp2.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! This module implements arithmetic over the quadratic extension field Fp2.

#![allow(clippy::needless_borrow)]
use core::fmt;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use ff::Field;
use rand_core::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

Expand Down
Loading
Loading