Skip to content

Commit

Permalink
Optimize bls precompile by arkworks lib (#993)
Browse files Browse the repository at this point in the history
* Optimize bls precompile by arkworks lib

* Pin bls-test precompose at `address(2017)`

* Fmt

* Update deps

* Add openssl deps in nix

* Remove empty line

* Format and fix compile

* Fix

* Resolve conv

* Fix

* Use rustup on nixos

* Fix

* Disable in the crab and darwinia network

* Add `shell.nix` to .gitigore

* Format

* Format

---------

Co-authored-by: Xavier Lau <[email protected]>
Co-authored-by: bear <[email protected]>
  • Loading branch information
3 people authored and Guantong committed Mar 14, 2023
1 parent 13368e2 commit 26b3b16
Show file tree
Hide file tree
Showing 7 changed files with 355 additions and 38 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
# Package Manager
## cargo
target
# nix
shell.nix
## npm
node_modules

Expand Down
133 changes: 125 additions & 8 deletions Cargo.lock

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

34 changes: 18 additions & 16 deletions precompile/bls12-381/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
[package]
authors.workspace = true
description = "BLS12-381 implementation for EVM pallet."
description = "Arkworks BLS12-381 based precompile for EVM pallet."
edition.workspace = true
name = "darwinia-precompile-bls12-381"
readme = "README.md"
version.workspace = true

[dependencies]
# crates.io
ark-bls12-381 = { version = "0.4.0", default-features = false, features = ["curve"] }
ark-ec = { version = "0.4.1", default-features = false }
ark-ff = { version = "0.4.1", default-features = false }
ark-serialize = { version = "0.4.1", default-features = false, features = ["derive"] }
sha2 = { version = "0.10.6", default-features = false }

# frontier
fp-evm = { workspace = true }
pallet-evm = { workspace = true }
Expand All @@ -18,27 +25,22 @@ precompile-utils = { workspace = true }
sp-std = { workspace = true }

[dev-dependencies]
# crates.io
codec = { package = "parity-scale-codec", workspace = true }
scale-info = { workspace = true }

# moonbeam
precompile-utils = { workspace = true, features = ["testing"] }

# substrate
frame-system = { workspace = true }
pallet-balances = { workspace = true, features = ["std"] }
pallet-timestamp = { workspace = true, features = ["std"] }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
rand = { version = "0.8.5" }
ark-std = { version = "0.4.0" }

[features]
default = ["std"]
std = [
# crates.io
"ark-bls12-381/std",
"ark-serialize/std",
"ark-ec/std",
"ark-ff/std",
"sha2/std",

# frontier
"fp-evm/std",
"pallet-evm/std",
"fp-evm/std",

# moonbeam
"precompile-utils/std",
Expand Down
180 changes: 180 additions & 0 deletions precompile/bls12-381/src/bls/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// This file is part of Darwinia.
//
// Copyright (C) 2018-2023 Darwinia Network
// SPDX-License-Identifier: GPL-3.0
//
// Darwinia is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Darwinia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Darwinia. If not, see <https://www.gnu.org/licenses/>.
//
// Inspired from https://github.com/w3f/apk-proofs/blob/main/bw6/src/bls/mod.rs

// core
use core::{borrow::Borrow, ops::Neg};
// crates.io
use ark_bls12_381::{
g2::Config as G2Config, Bls12_381, G1Affine, G1Projective, G2Affine, G2Projective,
};
use ark_ec::{
hashing::{
curve_maps::wb::WBMap, map_to_curve_hasher::MapToCurveBasedHasher, HashToCurve,
HashToCurveError,
},
models::short_weierstrass::Projective,
pairing::Pairing,
AffineRepr, CurveGroup,
};
use ark_ff::{field_hashers::DefaultFieldHasher, Zero};
use ark_serialize::*;
use sha2::Sha256;
// substrate
use sp_std::prelude::Vec;

/// Domain Separation Tag for signatures on G2
pub const DST_G2: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";

#[derive(Clone, Debug)]
pub struct Signature(G2Projective);
impl From<G2Projective> for Signature {
fn from(sig: G2Projective) -> Signature {
Signature(sig)
}
}
impl AsRef<G2Projective> for Signature {
fn as_ref(&self) -> &G2Projective {
&self.0
}
}
impl Signature {
pub fn from_bytes(bytes: &[u8]) -> Result<Signature, SerializationError> {
let p = G2Affine::deserialize_compressed(bytes)?;
Ok(Self(p.into()))
}

#[allow(dead_code)]
pub fn aggregate<S: Borrow<Signature>>(signatures: impl IntoIterator<Item = S>) -> Signature {
signatures.into_iter().map(|s| s.borrow().0).sum::<G2Projective>().into()
}
}

#[derive(Clone, Debug, Eq, PartialEq, Hash, CanonicalSerialize, CanonicalDeserialize)]
pub struct PublicKey(pub G1Projective);
impl From<G1Projective> for PublicKey {
fn from(pk: G1Projective) -> PublicKey {
PublicKey(pk)
}
}
impl PublicKey {
pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, SerializationError> {
let p = G1Affine::deserialize_compressed(bytes)?;
Ok(Self(p.into()))
}

pub fn aggregate<P: Borrow<PublicKey>>(public_keys: impl IntoIterator<Item = P>) -> PublicKey {
public_keys.into_iter().map(|s| s.borrow().0).sum::<G1Projective>().into()
}

pub fn verify(&self, signature: &Signature, message: &G2Projective) -> bool {
Bls12_381::multi_pairing(
[G1Affine::generator().neg(), self.0.into_affine()],
[signature.as_ref().into_affine(), message.into_affine()],
)
.is_zero()
}
}

pub fn hash_to_curve_g2(message: &[u8]) -> Result<G2Projective, HashToCurveError> {
let wb_to_curve_hasher = MapToCurveBasedHasher::<
Projective<G2Config>,
DefaultFieldHasher<Sha256, 128>,
WBMap<G2Config>,
>::new(DST_G2)?;
Ok(wb_to_curve_hasher.hash(message)?.into())
}

#[cfg(test)]
mod tests {
// crates.io
use rand::Rng;
use ark_std::test_rng;
use ark_bls12_381::Fr;
use ark_ec::Group;
use ark_ff::UniformRand;
// darwinia
use super::*;

#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)]
pub struct SecretKey(Fr);

impl From<Fr> for SecretKey {
fn from(sk: Fr) -> SecretKey {
SecretKey(sk)
}
}

impl From<&SecretKey> for PublicKey {
fn from(sk: &SecretKey) -> PublicKey {
(G1Projective::generator() * sk.as_ref()).into()
}
}

impl AsRef<Fr> for SecretKey {
fn as_ref(&self) -> &Fr {
&self.0
}
}

impl SecretKey {
pub fn new<R: Rng>(rng: &mut R) -> SecretKey {
SecretKey(Fr::rand(rng))
}

pub fn sign(&self, message: &G2Projective) -> Signature {
(*message * self.as_ref()).into()
}
}

#[test]
fn test_apk() {
let rng = &mut test_rng();
let message = G2Projective::rand(rng);

let sks = (0..10).map(|_| SecretKey::new(rng)).collect::<Vec<_>>();
let pks = sks.iter().map(PublicKey::from).collect::<Vec<_>>();
let sigs = sks.iter().map(|sk| sk.sign(&message)).collect::<Vec<_>>();
pks.iter().zip(sigs.iter()).for_each(|(pk, sig)| assert!(pk.verify(sig, &message)));

let apk = PublicKey::aggregate(pks);
let asig = Signature::aggregate(sigs);
assert!(apk.verify(&asig, &message));
}

#[test]
fn test_h2c() {
let message = vec![
58, 137, 108, 164, 181, 219, 16, 43, 157, 253, 71, 82, 139, 6, 34, 10, 145, 189, 18,
70, 29, 204, 134, 121, 60, 226, 213, 145, 244, 30, 164, 248,
];
let e = vec![
178, 18, 44, 225, 215, 170, 68, 228, 52, 151, 40, 113, 171, 202, 76, 203, 156, 112,
105, 249, 147, 210, 132, 79, 69, 117, 109, 151, 35, 71, 117, 21, 119, 179, 181, 81, 92,
22, 22, 88, 190, 243, 147, 248, 3, 210, 87, 98, 0, 84, 201, 248, 182, 249, 99, 59, 86,
60, 71, 244, 250, 189, 134, 232, 18, 82, 72, 76, 83, 155, 46, 113, 128, 107, 49, 67,
174, 100, 244, 181, 33, 174, 14, 151, 112, 62, 141, 100, 173, 191, 103, 178, 205, 17,
237, 147,
];
let p: G2Affine = hash_to_curve_g2(&message).unwrap().into();
let mut c = Vec::new();
p.serialize_compressed(&mut c).unwrap();
assert_eq!(e, c);
}
}
Loading

0 comments on commit 26b3b16

Please sign in to comment.