Skip to content

Commit

Permalink
init impl of bls signature
Browse files Browse the repository at this point in the history
  • Loading branch information
zhenfeizhang committed Apr 19, 2022
1 parent 09892eb commit b164ffb
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 65 deletions.
2 changes: 1 addition & 1 deletion primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ark-std = { version = "0.3.0", default-features = false }
ark-ec = { version = "0.3.0", default-features = false }
ark-serialize = { version = "0.3.0", default-features = false }
ark-bls12-381 = { version = "0.3.0", default-features = false, features = ["curve"] }
ark-bls12-377 = { git = "https://github.com/arkworks-rs/curves", default-features = false, features = ["curve"], rev = "677b4ae751a274037880ede86e9b6f30f62635af" }


# jellyfish
Expand Down Expand Up @@ -45,7 +46,6 @@ ark-ed-on-bls12-377 = { git = "https://github.com/arkworks-rs/curves", default-f
ark-ed-on-bls12-381 = { version = "0.3.0", default-features = false }
ark-ed-on-bls12-381-bandersnatch = { git = "https://github.com/arkworks-rs/curves", default-features = false, rev = "677b4ae751a274037880ede86e9b6f30f62635af" }
ark-ed-on-bn254 = { version = "0.3.0", default-features = false }
ark-bls12-377 = { git = "https://github.com/arkworks-rs/curves", default-features = false, features = ["curve"], rev = "677b4ae751a274037880ede86e9b6f30f62635af" }
ark-bn254 = { version = "0.3.0", default-features = false, features = ["curve"] }
ark-bw6-761 = { git = "https://github.com/arkworks-rs/curves", default-features = false, rev = "677b4ae751a274037880ede86e9b6f30f62635af" }

Expand Down
2 changes: 1 addition & 1 deletion primitives/src/circuit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ pub mod commitment;
pub mod elgamal;
pub mod merkle_tree;
pub mod prf;
pub mod schnorr_dsa;
pub mod signature;
10 changes: 10 additions & 0 deletions primitives/src/circuit/signature/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) 2022 Espresso Systems (espressosys.com)
// This file is part of the Jellyfish library.

// You should have received a copy of the MIT License
// along with the Jellyfish library. If not, see <https://mit-license.org/>.

//! Circuit implementation of a signature schemes.
//! Currently this module only implements Schnorr signature scheme over EC.
pub mod schnorr;
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,8 @@ where

#[cfg(test)]
mod tests {
use crate::{
circuit::schnorr_dsa::*,
signatures::schnorr::{KeyPair, Signature, VerKey},
};
use super::*;
use crate::signatures::schnorr::{KeyPair, Signature, VerKey};
use ark_ed_on_bls12_377::EdwardsParameters as Param377;
use ark_ed_on_bls12_381::EdwardsParameters as Param381;
use ark_ed_on_bls12_381_bandersnatch::EdwardsParameters as Param381b;
Expand Down
6 changes: 5 additions & 1 deletion primitives/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@

//! Constants for curve specific parameters.
pub(crate) const CS_ID_SCHNORR: &[u8; 28] = b"SCHNORR_WITH_RESCUE_HASH_v01";
/// ciphersuite identifier for schnorr signature
pub const CS_ID_SCHNORR: &[u8; 28] = b"SCHNORR_WITH_RESCUE_HASH_v01";

/// ciphersuite identifier for BLS signature
pub const CS_ID_BLS_NAIVE: &[u8; 32] = b"BLS_WITH_NAIVE_HASH_TO_GROUP_v01";
34 changes: 22 additions & 12 deletions primitives/src/hash_to_group/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,20 @@ use sha2::Sha256;
use crate::errors::PrimitivesError;

/// Trait definition and default implementation for hash to group functions.
pub trait HashToGroup: SWModelParameters
where
Self: Sized,
{
/// Hash to Curve point, using sha2-512 function
/// hashing to curve point of `C: ProjectiveCurve`.
// Default implementation implements a naive solution via rejection sampling
pub trait HashToGroup: SWModelParameters + Sized {
/// Hash to Group point, using sha2-512 function
/// hashing to G1 point of `C: ProjectiveCurve`.
// Default implementation implements a naive solution via rejection sampling.
// Slow, and non-constant time.
//
// For specific curves we may want to overload it with a more efficient
// algorithm, such as IETF BLS draft.
fn hash_to_group<B: AsRef<[u8]>>(data: B) -> Result<GroupProjective<Self>, PrimitivesError> {
fn hash_to_group<B: AsRef<[u8]>>(
data: B,
cs_id: B,
) -> Result<GroupProjective<Self>, PrimitivesError> {
let mut hasher = Sha256::new();
hasher.update(data.as_ref());
hasher.update([cs_id.as_ref(), data.as_ref()].concat());
let mut seed = [0u8; 32];
seed.copy_from_slice(hasher.finalize().as_ref());
let mut rng = ChaCha20Rng::from_seed(seed);
Expand All @@ -53,19 +55,27 @@ impl HashToGroup for ark_bls12_381::g1::Parameters {
// <https://github.com/algorand/pairing-plus/blob/7ec2ae03aae4ba2fc5210810211478171ccededf/src/bls12_381/osswu_map/g1.rs#L47>
}

impl HashToGroup for ark_bls12_377::g1::Parameters {
// todo
// overload hash to group with the method in
// <https://github.com/algorand/pairing-plus/blob/7ec2ae03aae4ba2fc5210810211478171ccededf/src/bls12_381/osswu_map/g1.rs#L47>
}

#[cfg(test)]
mod test {
use super::*;
use ark_bls12_381::g1::Parameters;
use ark_std::vec;

#[test]
fn test_hash_to_group() {
test_hash_to_group_helper::<Parameters>();
test_hash_to_group_helper::<ark_bls12_381::g1::Parameters>();
test_hash_to_group_helper::<ark_bls12_377::g1::Parameters>();
}

fn test_hash_to_group_helper<P: HashToGroup>() {
let data = vec![1u8, 2, 3, 4, 5];
let _g1 = P::hash_to_group::<&[u8]>(data.as_ref()).unwrap();
let _g1 =
<P as HashToGroup>::hash_to_group::<&[u8]>(data.as_ref(), "bls signature".as_ref())
.unwrap();
}
}
150 changes: 128 additions & 22 deletions primitives/src/signatures/bls.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,69 @@
//! Placeholder for BLS signature.
use super::SignatureScheme;
use crate::errors::PrimitivesError;
use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve};
use crate::{errors::PrimitivesError, hash_to_group::HashToGroup};
use ark_ec::{
bls12::{Bls12, Bls12Parameters},
short_weierstrass_jacobian::GroupAffine,
AffineCurve, ModelParameters, ProjectiveCurve,
};
use ark_ff::{Fp12, PrimeField};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError, Write};
use ark_std::{
io::Read,
ops::Neg,
rand::{CryptoRng, RngCore},
UniformRand,
string::ToString,
One, UniformRand,
};
use core::marker::PhantomData;
use jf_utils::{multi_pairing, tagged_blob};

/// BLS signature scheme.
/// Optimized for signature size, i.e.: PK in G2 and sig in G1
pub struct BLSSignatureScheme<E: PairingEngine> {
pairing_engine: PhantomData<E>,
pub struct BLSSignatureScheme<P: Bls12Parameters> {
pairing_engine: PhantomData<P>,
}

impl<E: PairingEngine> SignatureScheme for BLSSignatureScheme<E> {
/// BLS public verification key
#[tagged_blob("BLSVERKEY")]
#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)]
#[derivative(Clone(bound = "P: Bls12Parameters"))]
#[derivative(Default(bound = "P: Bls12Parameters"))]
pub struct BLSVerKey<P: Bls12Parameters>(pub(crate) GroupAffine<P::G2Parameters>);

/// Signing key for BLS signature.
#[tagged_blob("BLSSIGNINGKEY")]
#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)]
#[derivative(Clone(bound = "P: Bls12Parameters"))]
#[derivative(Default(bound = "P: Bls12Parameters"))]
pub struct BLSSignKey<P: Bls12Parameters>(
pub(crate) <P::G1Parameters as ModelParameters>::ScalarField,
);

/// Signing key for BLS signature.
#[tagged_blob("BLSSIG")]
#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)]
#[derivative(Clone(bound = "P: Bls12Parameters"))]
#[derivative(Default(bound = "P: Bls12Parameters"))]
pub struct BLSSignature<P: Bls12Parameters>(pub(crate) GroupAffine<P::G1Parameters>);

impl<P> SignatureScheme for BLSSignatureScheme<P>
where
P: Bls12Parameters,
P::G1Parameters: HashToGroup,
{
/// Signing key.
type SigningKey = E::Fr;
type SigningKey = BLSSignKey<P>;

/// Verification key
type VerificationKey = E::G2Affine;
type VerificationKey = BLSVerKey<P>;

/// Public Parameter
type PublicParameter = ();

/// Signature
type Signature = E::G1Affine;
type Signature = BLSSignature<P>;

/// A message is &[MessageUnit]
type MessageUnit = u8;
Expand All @@ -45,32 +82,101 @@ impl<E: PairingEngine> SignatureScheme for BLSSignatureScheme<E> {
_ciphersuite_id: B,
prng: &mut R,
) -> Result<(Self::SigningKey, Self::VerificationKey), PrimitivesError> {
let sk = Self::SigningKey::rand(prng);
let vk = Self::VerificationKey::prime_subgroup_generator()
.mul(sk)
.into_affine();
// todo: absorb ciphersuite_id in prng
let sk = BLSSignKey(<P::G1Parameters as ModelParameters>::ScalarField::rand(
prng,
));
let vk = BLSVerKey(
GroupAffine::<P::G2Parameters>::prime_subgroup_generator()
.mul(sk.0)
.into_affine(),
);
Ok((sk, vk))
}

/// Sample a pair of keys.
fn sign<R: CryptoRng + RngCore, M: AsRef<[Self::MessageUnit]>, B: AsRef<[u8]>>(
_pp: &Self::PublicParameter,
_sk: &Self::SigningKey,
_msg: M,
_ciphersuite_id: B,
sk: &Self::SigningKey,
msg: M,
ciphersuite_id: B,
_prng: &mut R,
) -> Result<Self::Signature, PrimitivesError> {
todo!()
let hm =
<P::G1Parameters as HashToGroup>::hash_to_group(msg.as_ref(), ciphersuite_id.as_ref())?;
Ok(BLSSignature(hm.mul(&sk.0.into_repr()).into_affine()))
}

/// Verify a signature.
fn verify<M: AsRef<[Self::MessageUnit]>, B: AsRef<[u8]>>(
_pp: &Self::PublicParameter,
_vk: &Self::VerificationKey,
_msg: M,
_sig: &Self::Signature,
_ciphersuite_id: B,
vk: &Self::VerificationKey,
msg: M,
sig: &Self::Signature,
ciphersuite_id: B,
) -> Result<(), PrimitivesError> {
todo!()
let hm =
<P::G1Parameters as HashToGroup>::hash_to_group(msg.as_ref(), ciphersuite_id.as_ref())?;

ark_std::println!(
"{:?}",
multi_pairing::<Bls12<P>>(
[hm.into_affine(), sig.0].as_ref(),
[
vk.0,
GroupAffine::<P::G2Parameters>::prime_subgroup_generator(),
]
.as_ref(),
)
);

if multi_pairing::<Bls12<P>>(
[hm.into_affine(), sig.0].as_ref(),
[
vk.0.neg(),
GroupAffine::<P::G2Parameters>::prime_subgroup_generator(),
]
.as_ref(),
) == Fp12::<P::Fp12Params>::one()
{
Ok(())
} else {
Err(PrimitivesError::VerificationError(
"Signature verification error".to_string(),
))
}
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::{
constants::CS_ID_BLS_NAIVE,
signatures::tests::{failed_verification, sign_and_verify},
};
use ark_bls12_377::Parameters as Param377;
use ark_bls12_381::Parameters as Param381;

macro_rules! test_signature {
($curve_param:tt) => {
let message = "this is a test message";
let message_bad = "this is a wrong message";
sign_and_verify::<BLSSignatureScheme<$curve_param>, _>(
message.as_ref(),
CS_ID_BLS_NAIVE,
);
failed_verification::<BLSSignatureScheme<$curve_param>, _>(
message.as_ref(),
message_bad.as_ref(),
CS_ID_BLS_NAIVE,
);
};
}

#[test]
fn test_bls_sig() {
test_signature!(Param377);
test_signature!(Param381);
}
}
33 changes: 33 additions & 0 deletions primitives/src/signatures/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use ark_std::rand::{CryptoRng, RngCore};
pub mod bls;
pub mod schnorr;

pub use bls::BLSSignatureScheme;
pub use schnorr::SchnorrSignatureScheme;

/// Trait definition for a signature scheme.
// A signature scheme is associated with a hash function H that is
// to be used for challenge generation.
Expand Down Expand Up @@ -60,3 +63,33 @@ pub trait SignatureScheme {

/// Trait for aggregatable signatures.
pub trait AggregateableSignatureSchemes<H>: SignatureScheme {}

#[cfg(test)]
mod tests {

use super::*;
use ark_std::test_rng;

pub(crate) fn sign_and_verify<S: SignatureScheme, B: AsRef<[u8]> + Copy>(
message: &[S::MessageUnit],
cs_id: B,
) {
let rng = &mut test_rng();
let parameters = S::param_gen(rng, cs_id).unwrap();
let (sk, pk) = S::key_gen(&parameters, cs_id, rng).unwrap();
let sig = S::sign(&parameters, &sk, &message, cs_id, rng).unwrap();
assert!(S::verify(&parameters, &pk, &message, &sig, cs_id).is_ok());
}

pub(crate) fn failed_verification<S: SignatureScheme, B: AsRef<[u8]> + Copy>(
message: &[S::MessageUnit],
bad_message: &[S::MessageUnit],
cs_id: B,
) {
let rng = &mut test_rng();
let parameters = S::param_gen(rng, cs_id).unwrap();
let (sk, pk) = S::key_gen(&parameters, cs_id, rng).unwrap();
let sig = S::sign(&parameters, &sk, message, cs_id, rng).unwrap();
assert!(!S::verify(&parameters, &pk, bad_message, &sig, cs_id).is_ok());
}
}
Loading

0 comments on commit b164ffb

Please sign in to comment.