Skip to content

Commit

Permalink
feat: added bls12_381 backend to bls crate
Browse files Browse the repository at this point in the history
  • Loading branch information
shreyas-londhe committed Dec 25, 2024
1 parent 7742ed2 commit 09fd47e
Show file tree
Hide file tree
Showing 14 changed files with 762 additions and 9 deletions.
26 changes: 26 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ base64 = '0.22'
bincode = '1'
bit_field = '0.10'
bitvec = '1'
bls12_381 = { git = "https://github.com/zkcrypto/bls12_381.git" }
blst = { version = '0.3', features = ['portable'] }
bstr = '1'
build-time = '0.1'
Expand Down Expand Up @@ -323,6 +324,7 @@ enum-map = '2'
enumset = '1'
env_logger = '0.11'
ethereum-types = '0.14'
ff = "0.13.0"
fixed-hash = '0.8.0'
fnv = '1'
fs-err = { version = '2', features = ['tokio'] }
Expand Down
15 changes: 13 additions & 2 deletions bls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,34 @@ authors = ["Grandine <info@grandine.io>"]

[features]
default = ["blst"]
blst = ["dep:blst"]
blst = [
"dep:blst",
"dep:itertools"
]
bls12_381 = [
"dep:bls12_381",
"dep:ff",
"dep:sha2",
]

[lints]
workspace = true

[dependencies]
blst = { workspace = true, optional = true }
bls12_381 = { workspace = true, optional = true, features = ["default", "experimental"] }
derivative = { workspace = true }
derive_more = { workspace = true }
ff = { workspace = true, optional = true }
fixed-hash = { workspace = true }
hex = { workspace = true }
impl-serde = { workspace = true }
itertools = { workspace = true }
itertools = { workspace = true, optional = true }
once_cell = { workspace = true }
rand = { workspace = true }
serde = { workspace = true }
serde_utils = { workspace = true }
sha2 = { workspace = true, optional = true }
ssz = { workspace = true }
static_assertions = { workspace = true }
thiserror = { workspace = true }
Expand Down
110 changes: 110 additions & 0 deletions bls/src/backends/bls12_381/cached_public_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use derivative::Derivative;
use once_cell::race::OnceBox;
use serde::{Deserialize, Serialize};
use ssz::{ReadError, Size, SszHash, SszRead, SszReadDefault as _, SszSize, SszWrite, H256};

use super::{public_key::PublicKey, public_key_bytes::PublicKeyBytes};
use crate::{error::Error, traits::CachedPublicKey as CachedPublicKeyTrait};

#[derive(Default, Debug, Derivative, Deserialize, Serialize)]
#[derivative(PartialEq, Eq)]
#[serde(transparent)]
pub struct CachedPublicKey {
bytes: PublicKeyBytes,
#[derivative(PartialEq = "ignore")]
#[serde(skip)]
decompressed: OnceBox<PublicKey>,
}

impl Clone for CachedPublicKey {
fn clone(&self) -> Self {
let Self {
bytes,
ref decompressed,
} = *self;
match decompressed.get().copied() {
Some(public_key) => Self::new(bytes, public_key),
None => bytes.into(),
}
}
}

impl From<PublicKeyBytes> for CachedPublicKey {
#[inline]
fn from(bytes: PublicKeyBytes) -> Self {
Self {
bytes,
decompressed: OnceBox::new(),
}
}
}

impl From<PublicKey> for CachedPublicKey {
#[inline]
fn from(public_key: PublicKey) -> Self {
Self::new(public_key.into(), public_key)
}
}

impl SszSize for CachedPublicKey {
const SIZE: Size = PublicKeyBytes::SIZE;
}

impl<C> SszRead<C> for CachedPublicKey {
#[inline]
fn from_ssz_unchecked(_context: &C, bytes: &[u8]) -> Result<Self, ReadError> {
Ok(Self {
bytes: PublicKeyBytes::from_ssz_default(bytes)?,
decompressed: OnceBox::new(),
})
}
}

impl SszWrite for CachedPublicKey {
#[inline]
fn write_fixed(&self, bytes: &mut [u8]) {
self.bytes.write_fixed(bytes);
}
}

impl SszHash for CachedPublicKey {
type PackingFactor = <PublicKeyBytes as SszHash>::PackingFactor;

#[inline]
fn hash_tree_root(&self) -> H256 {
self.bytes.hash_tree_root()
}
}

impl CachedPublicKeyTrait for CachedPublicKey {
type PublicKeyBytes = PublicKeyBytes;
type PublicKey = PublicKey;

fn new(bytes: PublicKeyBytes, public_key: PublicKey) -> Self {
let decompressed = OnceBox::new();
decompressed
.set(Box::new(public_key))
.expect("decompressed is empty because OnceBox::new returns an empty cell");

Self {
bytes,
decompressed,
}
}

#[inline]
fn as_bytes(&self) -> &PublicKeyBytes {
&self.bytes
}

#[inline]
fn to_bytes(&self) -> PublicKeyBytes {
self.bytes
}

#[inline]
fn decompress(&self) -> Result<&PublicKey, Error> {
self.decompressed
.get_or_try_init(|| self.bytes.try_into().map(Box::new))
}
}
7 changes: 7 additions & 0 deletions bls/src/backends/bls12_381/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub mod cached_public_key;
pub mod public_key;
pub mod public_key_bytes;
pub mod secret_key;
pub mod secret_key_bytes;
pub mod signature;
pub mod signature_bytes;
61 changes: 61 additions & 0 deletions bls/src/backends/bls12_381/public_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use bls12_381::{G1Affine, G1Projective};
use derive_more::From;

use crate::{error::Error, traits::PublicKey as PublicKeyTrait};

use super::public_key_bytes::PublicKeyBytes;

#[derive(Clone, Copy, PartialEq, Eq, Debug, From)]
pub struct PublicKey(G1Projective);

impl Default for PublicKey {
#[inline]
fn default() -> Self {
Self(G1Projective::identity())
}
}

impl TryFrom<PublicKeyBytes> for PublicKey {
type Error = Error;

#[inline]
fn try_from(bytes: PublicKeyBytes) -> Result<Self, Self::Error> {
let point: G1Affine = Option::from(G1Affine::from_compressed(bytes.as_ref()))
.ok_or(Error::DecompressionFailed)?;

if !bool::from(point.is_torsion_free()) {
return Err(Error::DecompressionFailed);
}

Ok(Self(point.into()))
}
}

impl PublicKeyTrait for PublicKey {
type PublicKeyBytes = PublicKeyBytes;

fn aggregate_nonempty(public_keys: impl IntoIterator<Item = Self>) -> Result<Self, Error> {
public_keys
.into_iter()
.reduce(Self::aggregate)
.ok_or(Error::NoPublicKeysToAggregate)
}

#[inline]
#[must_use]
fn aggregate(mut self, other: Self) -> Self {
self.aggregate_in_place(other);
self
}

#[inline]
fn aggregate_in_place(&mut self, other: Self) {
self.as_raw().add(other.as_raw());
}
}

impl PublicKey {
pub(crate) const fn as_raw(&self) -> &G1Projective {
&self.0
}
}
68 changes: 68 additions & 0 deletions bls/src/backends/bls12_381/public_key_bytes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use bls12_381::G1Affine;
use derive_more::AsRef;
use fixed_hash::construct_fixed_hash;
use hex::FromHex;
use impl_serde::impl_fixed_hash_serde;
use ssz::{BytesToDepth, MerkleTree, ReadError, Size, SszHash, SszRead, SszSize, SszWrite, H256};
use typenum::{Unsigned as _, U1, U48};

use crate::traits::PublicKeyBytes as PublicKeyBytesTrait;

use super::public_key::PublicKey;

type CompressedSize = U48;

construct_fixed_hash! {
#[derive(AsRef)]
pub struct PublicKeyBytes(CompressedSize::USIZE);
}

impl_fixed_hash_serde!(PublicKeyBytes, CompressedSize::USIZE);

impl From<PublicKey> for PublicKeyBytes {
#[inline]
fn from(public_key: PublicKey) -> Self {
Self(G1Affine::from(public_key.as_raw()).to_compressed())
}
}

impl FromHex for PublicKeyBytes {
type Error = <[u8; CompressedSize::USIZE] as FromHex>::Error;

fn from_hex<T: AsRef<[u8]>>(digits: T) -> Result<Self, Self::Error> {
FromHex::from_hex(digits).map(Self)
}
}

impl SszSize for PublicKeyBytes {
const SIZE: Size = Size::Fixed {
size: CompressedSize::USIZE,
};
}

impl<C> SszRead<C> for PublicKeyBytes {
#[inline]
fn from_ssz_unchecked(_context: &C, bytes: &[u8]) -> Result<Self, ReadError> {
Ok(Self::from_slice(bytes))
}
}

impl SszWrite for PublicKeyBytes {
#[inline]
fn write_fixed(&self, bytes: &mut [u8]) {
bytes.copy_from_slice(self.as_bytes());
}
}

impl SszHash for PublicKeyBytes {
type PackingFactor = U1;

#[inline]
fn hash_tree_root(&self) -> H256 {
MerkleTree::<BytesToDepth<CompressedSize>>::merkleize_bytes(self)
}
}

impl PublicKeyBytesTrait for PublicKeyBytes {
type PublicKey = PublicKey;
}
Loading

0 comments on commit 09fd47e

Please sign in to comment.