Skip to content

Commit

Permalink
SignatureScheme trait bounds (#148)
Browse files Browse the repository at this point in the history
* WIP


revert unnecessary changes

* fix a comment on serialization

* Add trait bounds for `SignatureScheme`'s verification key and signature

* Fix rust doc formatting for CanoninicalBytes

* move constants from bls.rs to constants.rs

* Add a Zeroize bound on `SigningKey`

* map errors

* Remove `Deref` impl for BLS structs

instead use the inner reference with `<data>.0`

* Replace tags with updated definitions from espresso common

* Add de/ser bounds on `SigningKey`

* add bounds on SignatureScheme associated types

bounds for `Debug + Clone + Send + Sync`

* Add Eq, PartialEq bounds on SignatureScheme types

* Revert "Remove `Deref` impl for BLS structs"

This reverts commit 7149b1a.

* pin espresso-common to 0.4
  • Loading branch information
tessico authored Dec 7, 2022
1 parent da89241 commit 6a718c3
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 20 deletions.
2 changes: 1 addition & 1 deletion plonk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ derivative = { version = "2", features = ["use_core"] }
displaydoc = { version = "0.2.3", default-features = false }
downcast-rs = { version = "1.2.0", default-features = false }
dyn-clone = "^1.0"
espresso-systems-common = { git = "https://github.com/espressosystems/espresso-systems-common", branch = "main" }
espresso-systems-common = { git = "https://github.com/espressosystems/espresso-systems-common", tag = "0.4.0" }
hashbrown = "0.12.3"
itertools = { version = "0.10.1", default-features = false }
jf-primitives = { path = "../primitives", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ crypto_box = "0.8.1"
derivative = { version = "2", features = ["use_core"] }
digest = { version = "0.10.1", default-features = false, features = ["alloc"] }
displaydoc = { version = "0.2.3", default-features = false }
espresso-systems-common = { git = "https://github.com/espressosystems/espresso-systems-common", branch = "main" }
espresso-systems-common = { git = "https://github.com/espressosystems/espresso-systems-common", tag = "0.4.0" }
generic-array = { version = "^0.14", default-features = false }
itertools = { version = "0.10.1", default-features = false, features = [ "use_alloc" ] }
jf-relation = { path = "../relation", default-features = false }
Expand Down
7 changes: 7 additions & 0 deletions primitives/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ pub const CS_ID_SCHNORR: &str = "SCHNORR_WITH_RESCUE_HASH_v01";

/// ciphersuite identifier for BLS signature
pub const CS_ID_BLS_SIG_NAIVE: &str = "BLS_SIG_WITH_NAIVE_HtG_v01";

/// Size in bytes of a secret key in our BLS signature scheme.
pub const BLS_SIG_KEY_SIZE: usize = 32;
/// Size in bytes of a signature in our BLS signature scheme.
pub const BLS_SIG_SIGNATURE_SIZE: usize = 96;
/// Size in bytes of a verification key in our BLS signature scheme.
pub const BLS_SIG_VERKEY_SIZE: usize = 192;
178 changes: 171 additions & 7 deletions primitives/src/signatures/bls.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,151 @@
//! BLS Signature Scheme
use super::SignatureScheme;
use crate::{constants::CS_ID_BLS_SIG_NAIVE, errors::PrimitivesError};
use crate::{
constants::{
BLS_SIG_KEY_SIZE, BLS_SIG_SIGNATURE_SIZE, BLS_SIG_VERKEY_SIZE, CS_ID_BLS_SIG_NAIVE,
},
errors::PrimitivesError,
};

use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError};
use ark_std::{
convert::TryInto,
format,
rand::{CryptoRng, RngCore},
};

use blst::{min_sig::*, BLST_ERROR};
use blst::BLST_ERROR;
use espresso_systems_common::jellyfish::tag;
use tagged_base64::tagged;

pub use blst::min_sig::{
PublicKey as BLSVerKey, SecretKey as BLSSignKey, Signature as BLSSignature,
};
pub use blst::min_sig::{PublicKey, SecretKey, Signature};
use zeroize::Zeroize;

/// Newtype wrapper for a BLS Signing Key.
#[tagged(tag::BLS_SIGNING_KEY)]
#[derive(Clone, Debug, Zeroize)]
pub struct BLSSignKey(SecretKey);

impl core::ops::Deref for BLSSignKey {
type Target = SecretKey;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl CanonicalSerialize for BLSSignKey {
fn serialized_size(&self) -> usize {
BLS_SIG_KEY_SIZE
}

fn serialize<W: ark_serialize::Write>(&self, writer: W) -> Result<(), SerializationError> {
let bytes = &self.0.serialize();
CanonicalSerialize::serialize(bytes.as_ref(), writer)
}
}

impl CanonicalDeserialize for BLSSignKey {
fn deserialize<R: ark_serialize::Read>(mut reader: R) -> Result<Self, SerializationError> {
let len = <usize as ark_serialize::CanonicalDeserialize>::deserialize(&mut reader)?;
if len != BLS_SIG_KEY_SIZE {
return Err(SerializationError::InvalidData);
}

let mut key = [0u8; BLS_SIG_KEY_SIZE];
reader.read_exact(&mut key)?;
SecretKey::deserialize(&key)
.map(Self)
.map_err(|_| SerializationError::InvalidData)
}
}

impl PartialEq for BLSSignKey {
fn eq(&self, other: &Self) -> bool {
self.0.serialize() == other.0.serialize()
}
}

impl Eq for BLSSignKey {}

/// Newtype wrapper for a BLS Signature.
#[tagged(tag::BLS_SIG)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BLSSignature(Signature);

impl core::ops::Deref for BLSSignature {
type Target = Signature;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl CanonicalSerialize for BLSSignature {
fn serialized_size(&self) -> usize {
BLS_SIG_SIGNATURE_SIZE
}

fn serialize<W: ark_serialize::Write>(&self, writer: W) -> Result<(), SerializationError> {
let bytes = &self.0.serialize();
CanonicalSerialize::serialize(bytes.as_ref(), writer)
}
}

impl CanonicalDeserialize for BLSSignature {
fn deserialize<R: ark_serialize::Read>(mut reader: R) -> Result<Self, SerializationError> {
let len = <usize as ark_serialize::CanonicalDeserialize>::deserialize(&mut reader)?;
if len != BLS_SIG_SIGNATURE_SIZE {
return Err(SerializationError::InvalidData);
}

let mut sig = [0u8; BLS_SIG_SIGNATURE_SIZE];
reader.read_exact(&mut sig)?;
Signature::deserialize(&sig)
.map(Self)
.map_err(|_| SerializationError::InvalidData)
}
}

/// Newtype wrapper for a BLS Verification Key.
#[tagged(tag::BLS_VER_KEY)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BLSVerKey(PublicKey);

impl core::ops::Deref for BLSVerKey {
type Target = PublicKey;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl CanonicalSerialize for BLSVerKey {
fn serialized_size(&self) -> usize {
BLS_SIG_VERKEY_SIZE
}

fn serialize<W: ark_serialize::Write>(&self, writer: W) -> Result<(), SerializationError> {
let bytes = &self.0.serialize();
CanonicalSerialize::serialize(bytes.as_ref(), writer)
}
}

impl CanonicalDeserialize for BLSVerKey {
fn deserialize<R: ark_serialize::Read>(mut reader: R) -> Result<Self, SerializationError> {
let len = <usize as ark_serialize::CanonicalDeserialize>::deserialize(&mut reader)?;
if len != BLS_SIG_VERKEY_SIZE {
return Err(SerializationError::InvalidData);
}

let mut key = [0u8; BLS_SIG_VERKEY_SIZE];
reader.read_exact(&mut key)?;
PublicKey::deserialize(&key)
.map(Self)
.map_err(|_| SerializationError::InvalidData)
}
}

/// BLS signature scheme. Imports blst library.
pub struct BLSSignatureScheme;
Expand Down Expand Up @@ -55,7 +188,7 @@ impl SignatureScheme for BLSSignatureScheme {
Err(e) => return Err(PrimitivesError::InternalError(format!("{:?}", e))),
};
let vk = sk.sk_to_pk();
Ok((sk, vk))
Ok((BLSSignKey(sk), BLSVerKey(vk)))
}

/// Sign a message
Expand All @@ -65,7 +198,11 @@ impl SignatureScheme for BLSSignatureScheme {
msg: M,
_prng: &mut R,
) -> Result<Self::Signature, PrimitivesError> {
Ok(sk.sign(msg.as_ref(), Self::CS_ID.as_bytes(), &[]))
Ok(BLSSignature(sk.sign(
msg.as_ref(),
Self::CS_ID.as_bytes(),
&[],
)))
}

/// Verify a signature.
Expand All @@ -84,6 +221,8 @@ impl SignatureScheme for BLSSignatureScheme {

#[cfg(test)]
mod test {
use ark_std::{test_rng, vec::Vec};

use super::*;
use crate::signatures::tests::{failed_verification, sign_and_verify};

Expand All @@ -94,4 +233,29 @@ mod test {
sign_and_verify::<BLSSignatureScheme>(message.as_ref());
failed_verification::<BLSSignatureScheme>(message.as_ref(), message_bad.as_ref());
}

#[test]
fn test_bls_sig_serde() {
let rng = &mut test_rng();
let parameters = BLSSignatureScheme::param_gen(Some(rng)).unwrap();
let (sk, vk) = BLSSignatureScheme::key_gen(&parameters, rng).unwrap();

// serde for Verification Key
let mut keypair_bytes = Vec::new();
vk.serialize(&mut keypair_bytes).unwrap();
let keypair_de = BLSVerKey::deserialize(&keypair_bytes[..]).unwrap();
assert_eq!(vk, keypair_de);
// wrong byte length
assert!(BLSVerKey::deserialize(&keypair_bytes[1..]).is_err());

// serde for Signature
let message = "this is a test message";
let sig = BLSSignatureScheme::sign(&parameters, &sk, message.as_bytes(), rng).unwrap();
let mut sig_bytes = Vec::new();
sig.serialize(&mut sig_bytes).unwrap();
let sig_de = BLSSignature::deserialize(&sig_bytes[..]).unwrap();
assert_eq!(sig, sig_de);
// wrong byte length
assert!(BLSSignature::deserialize(&sig_bytes[1..]).is_err());
}
}
34 changes: 29 additions & 5 deletions primitives/src/signatures/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ use ark_std::rand::{CryptoRng, RngCore};
pub mod bls;
pub mod schnorr;
pub use bls::BLSSignatureScheme;
use core::fmt::Debug;
pub use schnorr::SchnorrSignatureScheme;

use serde::{Deserialize, Serialize};
use zeroize::Zeroize;
/// 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 All @@ -17,19 +19,41 @@ pub trait SignatureScheme {
const CS_ID: &'static str;

/// Signing key.
type SigningKey;
type SigningKey: Debug
+ Clone
+ Send
+ Sync
+ Zeroize
+ for<'a> Deserialize<'a>
+ Serialize
+ PartialEq
+ Eq;

/// Verification key
type VerificationKey;
type VerificationKey: Debug
+ Clone
+ Send
+ Sync
+ for<'a> Deserialize<'a>
+ Serialize
+ PartialEq
+ Eq;

/// Public Parameter
type PublicParameter;

/// Signature
type Signature;
type Signature: Debug
+ Clone
+ Send
+ Sync
+ for<'a> Deserialize<'a>
+ Serialize
+ PartialEq
+ Eq;

/// A message is &\[MessageUnit\]
type MessageUnit;
type MessageUnit: Debug + Clone + Send + Sync;

/// generate public parameters from RNG.
/// If the RNG is not presented, use the default group generator.
Expand Down
7 changes: 4 additions & 3 deletions primitives/src/signatures/schnorr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ where
// =====================================================
// Signing key
// =====================================================
#[tagged(tag::SCHNORR_SIGNING_KEY)]
#[derive(
Clone, Hash, Default, Zeroize, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize, Debug,
)]
Expand All @@ -127,7 +128,7 @@ impl<F: PrimeField> SignKey<F> {

/// Signature public verification key
// derive zeroize here so that keypair can be zeroized
#[tagged(tag::SCHNORRVERKEY)]
#[tagged(tag::SCHNORR_VER_KEY)]
#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)]
#[derivative(
Debug(bound = "P: Parameters"),
Expand Down Expand Up @@ -196,7 +197,7 @@ impl<P: Parameters> VerKey<P> {

/// Signature secret key pair used to sign messages
// make sure sk can be zeroized
#[tagged(tag::SIGNKEYPAIR)]
#[tagged(tag::SCHNORR_KEY_PAIR)]
#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)]
#[derivative(
Debug(bound = "P: Parameters"),
Expand All @@ -217,7 +218,7 @@ where
// =====================================================

/// The signature of Schnorr signature scheme
#[tagged(tag::SIG)]
#[tagged(tag::SCHNORR_SIG)]
#[derive(CanonicalSerialize, CanonicalDeserialize, Derivative)]
#[derivative(
Debug(bound = "P: Parameters"),
Expand Down
6 changes: 3 additions & 3 deletions utilities/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
use ark_std::vec::Vec;
use serde::{Deserialize, Serialize};

/// A helper for converting CanonicalSerde bytes to standard Serde bytes.
/// use this struct as intermediate target instead of directly deriving
/// serde::Serialize/Deserialize to avoid implementation of Visitors.
/// A helper for converting ark_serialize::CanonicalSerialize bytes to standard
/// Serde bytes. Use this struct as intermediate target instead of directly
/// deriving serde::Serialize/Deserialize to avoid implementation of Visitors.
#[derive(Serialize, Deserialize)]
pub struct CanonicalBytes(pub Vec<u8>);

Expand Down

0 comments on commit 6a718c3

Please sign in to comment.