Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
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
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions fastcrypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ elliptic-curve = { version = "0.13.2", features = ["hash2curve"] }
rsa = { version = "0.8.2", features = ["sha2"] }
static_assertions = "1.1.0"
ark-secp256r1 = "0.4.0"
ark-bn254 = "0.4.0"
ark-ec = "0.4.1"
ark-ff = "0.4.1"
ark-serialize = "0.4.1"
Expand Down
81 changes: 81 additions & 0 deletions fastcrypto/src/groups/bn254/g1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::ops::{Div, Mul};

use crate::error::{FastCryptoError, FastCryptoResult};
use crate::groups::bn254::Scalar;
use crate::groups::bn254::{G1Element, G1_ELEMENT_BYTE_LENGTH};
use crate::groups::{FromTrustedByteArray, GroupElement, Scalar as ScalarType};
use crate::serde_helpers::ToFromByteArray;
use crate::serialize_deserialize_with_to_from_byte_array;
use ark_bn254::{G1Affine, G1Projective};
use ark_ec::{AffineRepr, Group};
use ark_ff::Zero;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use serde::{de, Deserialize};

impl GroupElement for G1Element {
type ScalarType = Scalar;

fn zero() -> Self {
G1Element(G1Projective::zero())
}

fn generator() -> Self {
G1Element(G1Projective::generator())
}
}

impl Div<Scalar> for G1Element {
type Output = FastCryptoResult<Self>;

fn div(self, rhs: Scalar) -> Self::Output {
let inverse = rhs.inverse()?;
Ok(self.mul(inverse))
}
}

impl Mul<Scalar> for G1Element {
type Output = Self;

fn mul(self, rhs: Scalar) -> Self::Output {
Self(self.0.mul(rhs.0))
}
}

impl ToFromByteArray<G1_ELEMENT_BYTE_LENGTH> for G1Element {
fn from_byte_array(bytes: &[u8; G1_ELEMENT_BYTE_LENGTH]) -> Result<Self, FastCryptoError> {
let point = G1Affine::deserialize_compressed(bytes.as_slice())
.map_err(|_| FastCryptoError::InvalidInput)?;

// Arkworks only checks the infinity flag, but we require all-zeros to have unique serialization
if point.is_zero()
&& bytes[0..G1_ELEMENT_BYTE_LENGTH - 1]
.iter()
.any(|x| !x.is_zero())
{
return Err(FastCryptoError::InvalidInput);
}

Ok(Self(G1Projective::from(point)))
}

fn to_byte_array(&self) -> [u8; G1_ELEMENT_BYTE_LENGTH] {
let mut bytes = [0u8; G1_ELEMENT_BYTE_LENGTH];
self.0
.serialize_compressed(bytes.as_mut_slice())
.expect("Never fails");
bytes
}
}

impl FromTrustedByteArray<G1_ELEMENT_BYTE_LENGTH> for G1Element {
fn from_trusted_byte_array(bytes: &[u8; G1_ELEMENT_BYTE_LENGTH]) -> FastCryptoResult<Self> {
G1Projective::deserialize_compressed_unchecked(bytes.as_slice())
.map_err(|_| FastCryptoError::InvalidInput)
.map(G1Element)
}
}

serialize_deserialize_with_to_from_byte_array!(G1Element);
80 changes: 80 additions & 0 deletions fastcrypto/src/groups/bn254/g2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::error::{FastCryptoError, FastCryptoResult};
use crate::groups::bn254::G2Element;
use crate::groups::bn254::{Scalar, G2_ELEMENT_BYTE_LENGTH};
use crate::groups::{FromTrustedByteArray, GroupElement, Scalar as ScalarType};
use crate::serde_helpers::ToFromByteArray;
use crate::serialize_deserialize_with_to_from_byte_array;
use ark_bn254::{G2Affine, G2Projective};
use ark_ec::{AffineRepr, Group};
use ark_ff::Zero;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use serde::{de, Deserialize};
use std::ops::{Div, Mul};

impl GroupElement for G2Element {
type ScalarType = Scalar;

fn zero() -> Self {
G2Element(G2Projective::zero())
}

fn generator() -> Self {
G2Element(G2Projective::generator())
}
}

impl Div<Scalar> for G2Element {
type Output = FastCryptoResult<Self>;

fn div(self, rhs: Scalar) -> Self::Output {
let inverse = rhs.inverse()?;
Ok(self.mul(inverse))
}
}

impl Mul<Scalar> for G2Element {
type Output = Self;

fn mul(self, rhs: Scalar) -> Self::Output {
Self(self.0.mul(rhs.0))
}
}

impl ToFromByteArray<G2_ELEMENT_BYTE_LENGTH> for G2Element {
fn from_byte_array(bytes: &[u8; G2_ELEMENT_BYTE_LENGTH]) -> Result<Self, FastCryptoError> {
let point = G2Affine::deserialize_compressed(bytes.as_slice())
.map_err(|_| FastCryptoError::InvalidInput)?;

// Arkworks only checks the infinty flag, but we require all-zeros to have unique serialization
if point.is_zero()
&& bytes[0..G2_ELEMENT_BYTE_LENGTH - 1]
.iter()
.any(|x| !x.is_zero())
{
return Err(FastCryptoError::InvalidInput);
}

Ok(Self(G2Projective::from(point)))
}

fn to_byte_array(&self) -> [u8; G2_ELEMENT_BYTE_LENGTH] {
let mut bytes = [0u8; G2_ELEMENT_BYTE_LENGTH];
self.0
.serialize_compressed(bytes.as_mut_slice())
.expect("Never fails");
bytes
}
}

impl FromTrustedByteArray<G2_ELEMENT_BYTE_LENGTH> for G2Element {
fn from_trusted_byte_array(bytes: &[u8; G2_ELEMENT_BYTE_LENGTH]) -> FastCryptoResult<Self> {
G2Projective::deserialize_compressed_unchecked(bytes.as_slice())
.map_err(|_| FastCryptoError::InvalidInput)
.map(G2Element)
}
}

serialize_deserialize_with_to_from_byte_array!(G2Element);
80 changes: 80 additions & 0 deletions fastcrypto/src/groups/bn254/gt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::error::{FastCryptoError, FastCryptoResult};
use crate::groups::bn254::G2Element;
use crate::groups::bn254::{G1Element, GTElement};
use crate::groups::bn254::{Scalar, GT_ELEMENT_BYTE_LENGTH};
use crate::groups::{FromTrustedByteArray, GroupElement, Pairing, Scalar as ScalarType};
use crate::serde_helpers::ToFromByteArray;
use crate::serialize_deserialize_with_to_from_byte_array;
use ark_bn254::Bn254;
use ark_ec::pairing::PairingOutput;
use ark_ff::Zero;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use once_cell::sync::OnceCell;
use serde::{de, Deserialize};
use std::ops::{Div, Mul};

#[allow(clippy::suspicious_arithmetic_impl)]
impl Div<Scalar> for GTElement {
type Output = FastCryptoResult<GTElement>;

fn div(self, rhs: Scalar) -> Self::Output {
let inverse = rhs.inverse()?;
Ok(self * inverse)
}
}

impl Mul<Scalar> for GTElement {
type Output = GTElement;

fn mul(self, rhs: Scalar) -> Self::Output {
Self(self.0.mul(rhs.0))
}
}

impl GroupElement for GTElement {
type ScalarType = Scalar;

fn zero() -> Self {
GTElement(PairingOutput::zero())
}

fn generator() -> Self {
static G: OnceCell<PairingOutput<Bn254>> = OnceCell::new();
Self(*G.get_or_init(Self::compute_generator))
}
}

impl GTElement {
fn compute_generator() -> PairingOutput<Bn254> {
G1Element::generator().pairing(&G2Element::generator()).0
}
}

impl FromTrustedByteArray<GT_ELEMENT_BYTE_LENGTH> for GTElement {
fn from_trusted_byte_array(bytes: &[u8; GT_ELEMENT_BYTE_LENGTH]) -> FastCryptoResult<Self> {
PairingOutput::<Bn254>::deserialize_compressed_unchecked(bytes.as_ref())
.map_err(|_| FastCryptoError::InvalidInput)
.map(GTElement)
}
}

impl ToFromByteArray<GT_ELEMENT_BYTE_LENGTH> for GTElement {
fn from_byte_array(bytes: &[u8; GT_ELEMENT_BYTE_LENGTH]) -> Result<Self, FastCryptoError> {
PairingOutput::<Bn254>::deserialize_compressed(bytes.as_ref())
.map_err(|_| FastCryptoError::InvalidInput)
.map(GTElement)
}

fn to_byte_array(&self) -> [u8; GT_ELEMENT_BYTE_LENGTH] {
let mut bytes = [0u8; GT_ELEMENT_BYTE_LENGTH];
self.0
.serialize_compressed(bytes.as_mut_slice())
.expect("Never fails");
bytes
}
}

serialize_deserialize_with_to_from_byte_array!(GTElement);
56 changes: 56 additions & 0 deletions fastcrypto/src/groups/bn254/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::groups::{GroupElement, Pairing};
use ark_bn254::{Bn254, Fr, G1Projective, G2Projective};
use ark_ec::pairing::{Pairing as ArkworksPairing, PairingOutput};
use derive_more::{Add, Neg, Sub};
use fastcrypto_derive::GroupOpsExtend;

mod g1;
mod g2;
mod gt;
mod scalar;

#[cfg(test)]
mod tests;

/// The byte length of a compressed element of G1.
pub const G1_ELEMENT_BYTE_LENGTH: usize = 32;

/// The byte length of a compressed element of G2.
pub const G2_ELEMENT_BYTE_LENGTH: usize = 64;

/// The byte length of a compressed element of GT.
pub const GT_ELEMENT_BYTE_LENGTH: usize = 384;

/// The byte length of a scalar.
pub const SCALAR_LENGTH: usize = 32;

/// Elements of the group G1 in BN254.
#[derive(Clone, Copy, Eq, PartialEq, Debug, Add, Sub, Neg, GroupOpsExtend)]
#[repr(transparent)]
pub struct G1Element(G1Projective);

/// Elements of the group G2 in BN254.
#[derive(Clone, Copy, Eq, PartialEq, Debug, Add, Sub, Neg, GroupOpsExtend)]
#[repr(transparent)]
pub struct G2Element(G2Projective);

/// Elements of the subgroup GT of F_q^{12} in BN254. Note that it is written in additive notation here.
#[derive(Clone, Copy, Eq, PartialEq, Debug, Add, Sub, Neg, GroupOpsExtend)]
pub struct GTElement(PairingOutput<Bn254>);

/// This represents a scalar modulo r = 21888242871839275222246405745257275088548364400416034343698204186575808495617
/// which is the order of the groups G1, G2 and GT. Note that r is a 254 bit prime.
#[derive(Clone, Copy, Eq, PartialEq, Debug, Add, Sub, Neg, GroupOpsExtend)]
pub struct Scalar(Fr);

impl Pairing for G1Element {
type Other = G2Element;
type Output = GTElement;

fn pairing(&self, other: &Self::Other) -> <Self as Pairing>::Output {
GTElement(Bn254::pairing(self.0, other.0))
}
}
Loading
Loading