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 pseudonyms #166

Open
wants to merge 3 commits into
base: vasilis/bbs-interface
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
2 changes: 2 additions & 0 deletions src/common/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ pub(crate) trait InterfaceParameter: Debug + Clone {

pub(crate) enum InterfaceId {
BbsH2gHm2s,
BbsH2gHm2sNym,
}

impl InterfaceId {
pub(crate) fn as_octets(&self) -> &[u8] {
match &self {
InterfaceId::BbsH2gHm2s => b"H2G_HM2S_",
InterfaceId::BbsH2gHm2sNym => b"H2G_HM2S_PSEUDONYM_",
}
}
}
2 changes: 1 addition & 1 deletion src/curves/bls12_381.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub use blstrs::*;
pub(crate) const OCTET_SCALAR_LENGTH: usize = 32;

/// Number of bytes to store an element of G1 in affine and compressed form.
pub(crate) const OCTET_POINT_G1_LENGTH: usize = 48;
pub const OCTET_POINT_G1_LENGTH: usize = 48;

/// Number of bytes to store an element of G2 in affine and compressed form.
pub(crate) const OCTET_POINT_G2_LENGTH: usize = 96;
6 changes: 6 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ pub enum Error {
/// Public key is not valid.
InvalidPublicKey,

/// Pseudonym is not valid
InvalidPseudonym,

/// Signature is malformed.
MalformedSignature {
/// Detailed cause.
Expand Down Expand Up @@ -126,6 +129,9 @@ impl core::fmt::Debug for Error {
Error::InvalidPublicKey => {
write!(f, "public key is invalid.")
}
Error::InvalidPseudonym => {
write!(f, "pseudonym is invalid")
}
Error::MalformedSignature { ref cause } => {
write!(f, "signature is malformed: cause: {cause}")
}
Expand Down
3 changes: 3 additions & 0 deletions src/schemes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ pub mod bbs_bound;

/// The BLS signature scheme
pub mod bls;

/// The BBS signature scheme using per verifier linkable pseudonyms.
pub mod pseudonym;
2 changes: 1 addition & 1 deletion src/schemes/bbs/api/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ where
}

/// Digests a set of supplied proof messages
pub(super) fn digest_proof_messages<T, I>(
pub(crate) fn digest_proof_messages<T, I>(
messages: Option<&[BbsProofGenRevealMessageRequest<T>]>,
) -> Result<(Vec<Message>, Vec<ProofMessage>), Error>
where
Expand Down
57 changes: 35 additions & 22 deletions src/schemes/bbs/core/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,26 @@ macro_rules! slicer {
};
}

#[derive(Default)]
pub(crate) struct RandomScalars {
pub r1: Scalar,
pub r2_tilde: Scalar,
pub z_tilde: Scalar,
pub m_tilde_scalars: Vec<Scalar>,
}

impl Default for RandomScalars {
fn default() -> Self {
Self {
r1: Default::default(),
r2_tilde: Default::default(),
z_tilde: Default::default(),
m_tilde_scalars: Vec::new() as Vec<Scalar>,
}
}
}

impl RandomScalars {
fn insert_m_tilde(&mut self, m_tilde: Scalar) {
pub fn insert_m_tilde(&mut self, m_tilde: Scalar) {
self.m_tilde_scalars.push(m_tilde);
}

Expand Down Expand Up @@ -144,21 +154,6 @@ impl Proof {
G: Generators,
I: BbsInterfaceParameter,
{
// Input parameter checks
// Error out if there is no `header` and not any `ProofMessage`
if header.is_none() && messages.is_empty() {
return Err(Error::BadParams {
cause: "nothing to prove".to_owned(),
});
}
// Error out if length of messages and generators are not equal
if messages.len() != generators.message_generators_length() {
return Err(Error::MessageGeneratorsLengthMismatch {
generators: generators.message_generators_length(),
messages: messages.len(),
});
}

// (r1, r2, r3, m~_j1, ..., m~_jU) = calculate_random_scalars(3+U)
let mut random_scalars = RandomScalars {
r1: create_random_scalar(&mut rng)?,
Expand Down Expand Up @@ -206,8 +201,12 @@ impl Proof {
)?;

// calculate the challenge
let c =
compute_challenge::<_, I>(&init_result, &disclosed_messages, ph)?;
let c = compute_challenge::<_, I>(
&init_result,
&disclosed_messages,
ph,
None,
)?;

// finalize the proof
Self::proof_finalize(
Expand Down Expand Up @@ -253,7 +252,8 @@ impl Proof {
// cv_for_hash = encode_for_hash(cv_array)
// if cv_for_hash is INVALID, return INVALID
// cv = hash_to_scalar(cv_for_hash, 1)
let cv = compute_challenge::<_, I>(&init_res, disclosed_messages, ph)?;
let cv =
compute_challenge::<_, I>(&init_res, disclosed_messages, ph, None)?;

// Check the selective disclosure proof
// if c != cv, return INVALID
Expand Down Expand Up @@ -301,6 +301,19 @@ impl Proof {
let total_no_of_messages = message_scalars.len();

// Check input sizes.
// Error out if there is no `header` and not any `ProofMessage`
if header.is_none() && message_scalars.is_empty() {
return Err(Error::BadParams {
cause: "nothing to prove".to_owned(),
});
}
// Error out if length of messages and generators are not equal
if total_no_of_messages != generators.message_generators_length() {
return Err(Error::MessageGeneratorsLengthMismatch {
generators: generators.message_generators_length(),
messages: total_no_of_messages,
});
}
// Number of message generators == number of messages is checked in
// compute_domain. Checking that all the indexes are in the [0,
// length(messages)) range is done before get_message_generator
Expand All @@ -315,7 +328,7 @@ impl Proof {

// Checking that number of undisclosed messages (/indexes) <= number of
// messages
if undisclosed_indexes.len() > message_scalars.len() {
if undisclosed_indexes.len() > total_no_of_messages {
return Err(Error::BadParams {
cause: format!(
"Not disclosed messages number is invalid. Maximum \
Expand All @@ -330,7 +343,7 @@ impl Proof {
let domain = compute_domain::<_, _, I>(
PK,
header,
message_scalars.len(),
total_no_of_messages,
generators,
)?;

Expand Down
8 changes: 8 additions & 0 deletions src/schemes/bbs/core/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,11 @@ pub(crate) struct ProofInitResult {
pub T: G1Projective,
pub domain: Scalar,
}

/// Result of commit correctness proof
/// generation initialization.
pub(crate) struct CommitProofInitResult {
pub commit: G1Projective,
pub commit_base: G1Projective,
pub blind_commit: G1Projective,
}
10 changes: 9 additions & 1 deletion src/schemes/bbs/core/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use super::{
generator::Generators,
key_pair::PublicKey,
types::{Challenge, Message, ProofInitResult},
types::{Challenge, CommitProofInitResult, Message, ProofInitResult},
};
use crate::{
bbs::{
Expand Down Expand Up @@ -125,6 +125,7 @@ pub(crate) fn compute_challenge<T, I>(
proof_init_res: &ProofInitResult,
disclosed_messages: &BTreeMap<usize, Message>,
ph: Option<T>,
commit_init_res: Option<CommitProofInitResult>,
) -> Result<Challenge, Error>
where
T: AsRef<[u8]>,
Expand All @@ -139,6 +140,13 @@ where
data_to_hash.extend(point_to_octets_g1(&proof_init_res.B_bar).as_ref());
data_to_hash.extend(point_to_octets_g1(&proof_init_res.T));

// Add the commit proof init result elements if supplied
if let Some(commit_init) = commit_init_res {
data_to_hash.extend(point_to_octets_g1(&commit_init.commit));
data_to_hash.extend(point_to_octets_g1(&commit_init.commit_base));
data_to_hash.extend(point_to_octets_g1(&commit_init.blind_commit));
};

data_to_hash.extend(i2osp(
disclosed_messages.len() as u64,
NON_NEGATIVE_INTEGER_ENCODING_LENGTH,
Expand Down
5 changes: 5 additions & 0 deletions src/schemes/bbs/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,9 @@ pub(crate) trait BbsInterfaceParameter: InterfaceParameter {
[&Self::api_id(), DEFAULT_DST_SUFFIX_H2S.as_bytes()].concat();
Self::Ciphersuite::hash_to_scalar(data_to_hash, &e_dst)
}

// Hash to curve function, using the Interface's identifier as a dst
fn hash_to_curve(message: &[u8]) -> Result<G1Projective, Error> {
Self::Ciphersuite::hash_to_curve(message, &Self::api_id())
}
}
6 changes: 6 additions & 0 deletions src/schemes/pseudonym.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// Interface for using the BBS operations with a pseudonym.
pub mod api;
/// Ciphersuite abstraction over the defined api. Each ciphersuite includes
/// concrete instantiations of the api operations.
pub mod ciphersuites;
pub(crate) mod core;
5 changes: 5 additions & 0 deletions src/schemes/pseudonym/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// Types for Signature and Proof generation and verification requests.
pub mod dtos;
pub(crate) mod proof;
pub(crate) mod pseudonym;
pub(crate) mod signature;
150 changes: 150 additions & 0 deletions src/schemes/pseudonym/api/dtos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
use crate::bbs::{
api::dtos::BbsProofGenRevealMessageRequest,
ciphersuites::bls12_381::{
BBS_BLS12381G1_PUBLIC_KEY_LENGTH,
BBS_BLS12381G1_SECRET_KEY_LENGTH,
BBS_BLS12381G1_SIGNATURE_LENGTH,
},
};

use crate::curves::bls12_381::OCTET_POINT_G1_LENGTH;

/// Sign request for a BBS signature with a Pseudonym.
#[derive(Clone, Debug)]
pub struct BbsSignRequest<'a, T: AsRef<[u8]> + Default> {
/// Secret key
pub secret_key: &'a [u8; BBS_BLS12381G1_SECRET_KEY_LENGTH],
/// Public key
pub public_key: &'a [u8; BBS_BLS12381G1_PUBLIC_KEY_LENGTH],
/// Prover unique identifier
pub prover_id: T,
/// Header containing context and application specific information
pub header: Option<T>,
/// Vector of messages to sign
pub messages: Option<&'a [T]>,
}

impl<'a, T: AsRef<[u8]> + Default> Default for BbsSignRequest<'a, T> {
fn default() -> Self {
Self {
secret_key: &[0u8; BBS_BLS12381G1_SECRET_KEY_LENGTH],
public_key: &[0u8; BBS_BLS12381G1_PUBLIC_KEY_LENGTH],
prover_id: Default::default(),
header: Default::default(),
messages: Default::default(),
}
}
}

/// Verify request for a BBS signature.
#[derive(Clone, Debug)]
pub struct BbsVerifyRequest<'a, T: AsRef<[u8]> + Default> {
/// Public key
pub public_key: &'a [u8; BBS_BLS12381G1_PUBLIC_KEY_LENGTH],
/// Prover unique identifier
pub prover_id: T,
/// Header containing context and application specific information
pub header: Option<T>,
/// Vector of messages to verify against a signature
pub messages: Option<&'a [T]>,
/// Signature to verify
pub signature: &'a [u8; BBS_BLS12381G1_SIGNATURE_LENGTH],
}

impl<'a, T: AsRef<[u8]> + Default> Default for BbsVerifyRequest<'a, T> {
fn default() -> Self {
Self {
public_key: &[0u8; BBS_BLS12381G1_PUBLIC_KEY_LENGTH],
prover_id: Default::default(),
header: Default::default(),
messages: Default::default(),
signature: &[0u8; BBS_BLS12381G1_SIGNATURE_LENGTH],
}
}
}

/// Derive proof request for computing a signature proof of knowledge for a
/// supplied BBS signature.
#[derive(Clone, Debug)]
pub struct BbsProofGenRequest<'a, T: AsRef<[u8]> + Default> {
/// Public key associated to the BBS signature
pub public_key: &'a [u8; BBS_BLS12381G1_PUBLIC_KEY_LENGTH],
/// The Prover's unique identifier
pub prover_id: T,
/// The Verifier's unique Identifier
pub verifier_id: T,
/// Point of G1 used by a Verifier to link multiple proof presentations
/// by the same Prover.
pub pseudonym: &'a [u8; OCTET_POINT_G1_LENGTH],
/// Header containing context and application specific information
pub header: Option<T>,
/// Vector of messages protected by the signature, including a flag
/// indicating which to reveal in the derived proof
pub messages: Option<&'a [BbsProofGenRevealMessageRequest<T>]>,
/// Signature to derive the signature proof of knowledge from
pub signature: &'a [u8; BBS_BLS12381G1_SIGNATURE_LENGTH],
/// Presentation header to be bound to the signature proof of knowledge
pub presentation_header: Option<T>,
/// Flag which indicates if the signature verification should be done
/// before actual proof computation.
pub verify_signature: Option<bool>,
}

impl<'a, T: AsRef<[u8]> + Default> Default for BbsProofGenRequest<'a, T> {
fn default() -> Self {
Self {
public_key: &[0u8; BBS_BLS12381G1_PUBLIC_KEY_LENGTH],
prover_id: Default::default(),
verifier_id: Default::default(),
pseudonym: &[0u8; OCTET_POINT_G1_LENGTH],
header: Default::default(),
messages: Default::default(),
signature: &[0u8; BBS_BLS12381G1_SIGNATURE_LENGTH],
presentation_header: Default::default(),
verify_signature: None,
}
}
}

/// Verify proof request for verifying a supplied signature proof of knowledge.
#[derive(Clone, Debug)]
pub struct BbsProofVerifyRequest<'a, T: AsRef<[u8]> + Default> {
/// Public key associated to the signature proof of knowledge (who signed
/// the original BBS signature the proof is derived from)
pub public_key: &'a [u8; BBS_BLS12381G1_PUBLIC_KEY_LENGTH],
/// The Verifier's unique Identifier
pub verifier_id: T,
/// Point of G1 used by a Verifier to link multiple proof presentations
/// by the same Prover.
pub pseudonym: &'a [u8; OCTET_POINT_G1_LENGTH],
/// Header containing context and application specific information
pub header: Option<T>,
/// Presentation header associated to the signature proof of knowledge
pub presentation_header: Option<T>,
/// Proof to verify
pub proof: &'a [u8],
/// Revealed messages to validate against the signature proof of knowledge
pub messages: Option<&'a [(usize, T)]>,
}

impl<'a, T: AsRef<[u8]> + Default> Default for BbsProofVerifyRequest<'a, T> {
fn default() -> Self {
Self {
public_key: &[0u8; BBS_BLS12381G1_PUBLIC_KEY_LENGTH],
verifier_id: Default::default(),
pseudonym: &[0u8; OCTET_POINT_G1_LENGTH],
header: Default::default(),
messages: Default::default(),
presentation_header: Default::default(),
proof: &[0u8; 0],
}
}
}

/// Generate a pseudonym request
pub struct BbsPseudonymGenRequest<T: AsRef<[u8]>> {
/// The Verifier's unique Identifier
pub verifier_id: T,
/// The Prover's unique identifier
pub prover_id: T,
}
Loading