Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add the BBS Interface abstraction #165

Open
wants to merge 3 commits into
base: vasilis/parameterize-proof-procedures
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 3 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ pub(crate) mod util;

// Common serialization utils.
pub(crate) mod serialization;

/// Common interface parameters
pub(crate) mod interface;
4 changes: 2 additions & 2 deletions src/common/ciphersuite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ impl CipherSuiteId {
pub(crate) fn as_octets(&self) -> &[u8] {
match &self {
CipherSuiteId::BbsBls12381G1XmdSha256 => {
b"BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_H2G_HM2S_"
b"BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_"
}
CipherSuiteId::BbsBls12381G1XofShake256 => {
b"BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_H2G_HM2S_"
b"BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_"
}
CipherSuiteId::BlsSigBls12381G2XmdSha256Nul => {
b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_"
Expand Down
76 changes: 5 additions & 71 deletions src/common/hash_param/h2s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,90 +5,24 @@ use crate::{
Error,
};

use super::{
constant::{
DEFAULT_DST_SUFFIX_H2S,
DEFAULT_DST_SUFFIX_MESSAGE_TO_SCALAR,
MAX_DST_SIZE,
MAX_MESSAGE_SIZE,
XOF_NO_OF_BYTES,
},
ExpandMessageParameter,
};
use super::{constant::XOF_NO_OF_BYTES, ExpandMessageParameter};

pub(crate) trait HashToScalarParameter: ExpandMessageParameter {
/// Default domain separation tag for `hash_to_scalar` operation.
fn default_hash_to_scalar_dst() -> Vec<u8> {
[Self::ID.as_octets(), DEFAULT_DST_SUFFIX_H2S.as_bytes()].concat()
}

/// Default domain separation tag to be used in [MapMessageToScalarAsHash](https://identity.foundation/bbs-signature/draft-bbs-signatures.html#name-mapmessagetoscalarashash).
fn default_map_message_to_scalar_as_hash_dst() -> Vec<u8> {
[
Self::ID.as_octets(),
DEFAULT_DST_SUFFIX_MESSAGE_TO_SCALAR.as_bytes(),
]
.concat()
}

/// Hash arbitrary data to `n` number of scalars as specified in BBS
/// specification.
fn hash_to_scalar(
msg_octets: &[u8],
dst: Option<&[u8]>,
) -> Result<Scalar, Error> {
let default_hash_to_scalar_dst = Self::default_hash_to_scalar_dst();
let dst_octets = dst.unwrap_or(&default_hash_to_scalar_dst);

if !dst_octets.is_ascii() {
fn hash_to_scalar(msg_octets: &[u8], dst: &[u8]) -> Result<Scalar, Error> {
if !dst.is_ascii() {
return Err(Error::BadParams {
cause: "non-ascii dst".to_owned(),
});
}
let mut expander = Self::Expander::init_expand(
msg_octets,
dst_octets,
XOF_NO_OF_BYTES,
);
let mut expander =
Self::Expander::init_expand(msg_octets, dst, XOF_NO_OF_BYTES);

let mut buf = [0u8; 64];
expander.read_into(&mut buf[16..]);
let out_scalar = Scalar::from_wide_bytes_be_mod_r(&buf);

Ok(out_scalar)
}

/// Hash arbitrary data to a scalar as specified in [3.3.9.1 Hash to scalar](https://identity.foundation/bbs-signature/draft-bbs-signatures.html#name-mapmessagetoscalarashash).
fn map_message_to_scalar_as_hash(
message: &[u8],
dst: Option<&[u8]>,
) -> Result<Scalar, Error> {
let default_map_message_to_scalar_as_hash_dst =
Self::default_map_message_to_scalar_as_hash_dst();
let dst = dst.unwrap_or(&default_map_message_to_scalar_as_hash_dst);

if !dst.is_ascii() {
return Err(Error::BadParams {
cause: "non-ascii dst".to_owned(),
});
}

// If len(dst) > 2^8 - 1 or len(msg) > 2^64 - 1, abort
if message.len() as u64 > MAX_MESSAGE_SIZE {
return Err(Error::MessageIsTooLarge);
}
if dst.len() > MAX_DST_SIZE as usize {
return Err(Error::DstIsTooLarge);
}

// hash_to_scalar(message || dst_prime, 1)
Self::hash_to_scalar(message, Some(dst))
}

/// Hash the input octets to scalar values representing the e component of a
/// BBS signature.
fn hash_to_e(input_octets: &[u8]) -> Result<Scalar, Error> {
let e = Self::hash_to_scalar(input_octets, None)?;
Ok(e)
}
}
17 changes: 17 additions & 0 deletions src/common/interface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use core::fmt::Debug;

pub(crate) trait InterfaceParameter: Debug + Clone {
const ID: InterfaceId;
}

pub(crate) enum InterfaceId {
BbsH2gHm2s,
}

impl InterfaceId {
pub(crate) fn as_octets(&self) -> &[u8] {
match &self {
InterfaceId::BbsH2gHm2s => b"H2G_HM2S_",
}
}
}
9 changes: 9 additions & 0 deletions src/schemes/bbs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,12 @@ pub(crate) mod core;

/// BBS ciphersuites abstraction over core implementation.
pub mod ciphersuites;

/// BBS Interface abstraction over ciphersuites, defining how messages are
/// mapped to scalars, how generators are created and how core interfaces are
/// used.
pub mod interface;

/// Calculating the generators, that form part of the BBS Signature
/// public parameters.
pub mod generator;
9 changes: 5 additions & 4 deletions src/schemes/bbs/api/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,23 @@ use crate::{
memory_cached_generator::MemoryCachedGenerators,
Generators,
},
interface::BbsInterfaceParameter,
},
Error,
};

pub(crate) fn create_generators<C>(
pub(crate) fn create_generators<I>(
count: usize,
private_holder_binding: Option<bool>,
) -> Result<Vec<Vec<u8>>, Error>
where
C: BbsCiphersuiteParameters,
I: BbsInterfaceParameter,
{
let mut result = Vec::new();
let generators =
MemoryCachedGenerators::<C>::new(count - 2, private_holder_binding)?;
MemoryCachedGenerators::<I>::new(count - 2, private_holder_binding)?;

result.push(C::p1()?.to_affine().to_compressed().to_vec());
result.push(I::Ciphersuite::p1()?.to_affine().to_compressed().to_vec());
result.push(generators.Q.to_affine().to_compressed().to_vec());
result.extend(
generators
Expand Down
40 changes: 20 additions & 20 deletions src/schemes/bbs/api/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use super::{
};
use crate::{
bbs::{
ciphersuites::BbsCiphersuiteParameters,
core::{
generator::memory_cached_generator::MemoryCachedGenerators,
types::ProofMessage,
},
interface::BbsInterfaceParameter,
},
error::Error,
schemes::bbs::core::{
Expand All @@ -34,38 +34,38 @@ pub fn get_proof_size(num_undisclosed_messages: usize) -> usize {
}

// helper function for parsing a BBS Proof Generation Request
fn _parse_request_helper<T, C>(
fn _parse_request_helper<T, I>(
request: &BbsProofGenRequest<'_, T>,
) -> Result<
(
PublicKey,
Signature,
MemoryCachedGenerators<C>,
MemoryCachedGenerators<I>,
Vec<ProofMessage>,
),
Error,
>
where
T: AsRef<[u8]>,
C: BbsCiphersuiteParameters,
I: BbsInterfaceParameter,
{
// Parse public key from request
let pk = PublicKey::from_octets(request.public_key)?;

let (digested_messages, proof_messages) =
digest_proof_messages::<_, C>(request.messages)?;
digest_proof_messages::<_, I>(request.messages)?;

// Derive generators
let generators =
MemoryCachedGenerators::<C>::new(digested_messages.len(), None)?;
MemoryCachedGenerators::<I>::new(digested_messages.len(), None)?;

// Parse signature from request
let signature = Signature::from_octets(request.signature)?;

let verify_signature = request.verify_signature.unwrap_or(true);
if verify_signature {
// Verify the signature to check the messages supplied are valid
if !(signature.verify::<_, _, _, C>(
if !(signature.verify::<_, _, _, I>(
&pk,
request.header.as_ref(),
&generators,
Expand All @@ -79,18 +79,18 @@ where
}

// Generate a BBS signature proof of knowledge.
pub(crate) fn proof_gen<T, C>(
pub(crate) fn proof_gen<T, I>(
request: &BbsProofGenRequest<'_, T>,
) -> Result<Vec<u8>, Error>
where
T: AsRef<[u8]>,
C: BbsCiphersuiteParameters,
I: BbsInterfaceParameter,
{
let (pk, signature, generators, proof_messages) =
_parse_request_helper::<T, C>(request)?;
_parse_request_helper::<T, I>(request)?;

// Generate the proof
let proof = Proof::new::<_, _, C>(
let proof = Proof::new::<_, _, I>(
&pk,
&signature,
request.header.as_ref(),
Expand All @@ -103,12 +103,12 @@ where
}

// Verify a BBS signature proof of knowledge.
pub(crate) fn proof_verify<T, C>(
pub(crate) fn proof_verify<T, I>(
request: &BbsProofVerifyRequest<'_, T>,
) -> Result<bool, Error>
where
T: AsRef<[u8]>,
C: BbsCiphersuiteParameters,
I: BbsInterfaceParameter,
{
// Parse public key from request
let public_key = PublicKey::from_octets(request.public_key)?;
Expand All @@ -124,13 +124,13 @@ where

// Digest the revealed proof messages
let messages: BTreeMap<usize, Message> =
digest_revealed_proof_messages::<_, C>(messages, total_message_count)?;
digest_revealed_proof_messages::<_, I>(messages, total_message_count)?;

// Derive generators
let generators =
MemoryCachedGenerators::<C>::new(total_message_count, None)?;
MemoryCachedGenerators::<I>::new(total_message_count, None)?;

proof.verify::<_, _, C>(
proof.verify::<_, _, I>(
&public_key,
request.header.as_ref(),
request.presentation_header.as_ref(),
Expand All @@ -141,20 +141,20 @@ where

// Generate a BBS signature proof of knowledge with a given rng.
#[cfg(feature = "__private_bbs_fixtures_generator_api")]
pub(crate) fn proof_gen_with_rng<T, R, C>(
pub(crate) fn proof_gen_with_rng<T, R, I>(
request: &BbsProofGenRequest<'_, T>,
rng: R,
) -> Result<Vec<u8>, Error>
where
T: AsRef<[u8]>,
R: RngCore + CryptoRng,
C: BbsCiphersuiteParameters,
I: BbsInterfaceParameter,
{
let (pk, signature, generators, proof_messages) =
_parse_request_helper::<T, C>(request)?;
_parse_request_helper::<T, I>(request)?;

// Generate the proof
let proof = Proof::new_with_rng::<_, _, _, C>(
let proof = Proof::new_with_rng::<_, _, _, I>(
&pk,
&signature,
request.header.as_ref(),
Expand Down
26 changes: 12 additions & 14 deletions src/schemes/bbs/api/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,25 @@ use super::{
};
use crate::{
bbs::{
ciphersuites::{
bls12_381::BBS_BLS12381G1_SIGNATURE_LENGTH,
BbsCiphersuiteParameters,
},
ciphersuites::bls12_381::BBS_BLS12381G1_SIGNATURE_LENGTH,
core::{
generator::memory_cached_generator::MemoryCachedGenerators,
key_pair::{PublicKey, SecretKey},
signature::Signature,
types::Message,
},
interface::BbsInterfaceParameter,
},
error::Error,
};

// Create a BBS signature.
pub(crate) fn sign<T, C>(
pub(crate) fn sign<T, I>(
request: &BbsSignRequest<'_, T>,
) -> Result<[u8; BBS_BLS12381G1_SIGNATURE_LENGTH], Error>
where
T: AsRef<[u8]>,
C: BbsCiphersuiteParameters,
I: BbsInterfaceParameter,
{
// Parse the secret key
let sk = SecretKey::from_bytes(request.secret_key)?;
Expand All @@ -33,13 +31,13 @@ where
let pk = PublicKey::from_octets(request.public_key)?;

// Digest the supplied messages
let messages: Vec<Message> = digest_messages::<_, C>(request.messages)?;
let messages: Vec<Message> = digest_messages::<_, I>(request.messages)?;

// Derive generators
let generators = MemoryCachedGenerators::<C>::new(messages.len(), None)?;
let generators = MemoryCachedGenerators::<I>::new(messages.len(), None)?;

// Produce the signature and return
Signature::new::<_, _, _, C>(
Signature::new::<_, _, _, I>(
&sk,
&pk,
request.header.as_ref(),
Expand All @@ -50,26 +48,26 @@ where
}

// Verify a BBS signature.
pub(crate) fn verify<T, C>(
pub(crate) fn verify<T, I>(
request: &BbsVerifyRequest<'_, T>,
) -> Result<bool, Error>
where
T: AsRef<[u8]>,
C: BbsCiphersuiteParameters,
I: BbsInterfaceParameter,
{
// Parse public key from request
let pk = PublicKey::from_octets(request.public_key)?;

// Digest the supplied messages
let messages: Vec<Message> = digest_messages::<_, C>(request.messages)?;
let messages: Vec<Message> = digest_messages::<_, I>(request.messages)?;

// Derive generators
let generators = MemoryCachedGenerators::<C>::new(messages.len(), None)?;
let generators = MemoryCachedGenerators::<I>::new(messages.len(), None)?;

// Parse signature from request
let signature = Signature::from_octets(request.signature)?;

signature.verify::<_, _, _, C>(
signature.verify::<_, _, _, I>(
&pk,
request.header.as_ref(),
&generators,
Expand Down
Loading