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

Data Integrity bbs-2023 Cryptosuite #550

Merged
merged 34 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c78c1da
Add bbs2023 suite.
timothee-haudebourg Jun 3, 2024
2ed5b10
BBS transformation algorithm done.
timothee-haudebourg Jun 5, 2024
834da2b
Complete base proof generation.
timothee-haudebourg Jun 7, 2024
0ced82f
Tested base transformation.
timothee-haudebourg Jun 10, 2024
92beba1
Proof deserialization.
timothee-haudebourg Jun 10, 2024
cf741a6
Implement derived proof verification.
timothee-haudebourg Jun 12, 2024
3d72775
Testing bbs-2023 deriving/verification
timothee-haudebourg Jun 12, 2024
bf6a6a0
Successful bbs-2023 verification.
timothee-haudebourg Jun 13, 2024
ac9da0f
Cleanup code.
timothee-haudebourg Jun 13, 2024
a71015c
Feature gate.
timothee-haudebourg Jun 13, 2024
5890307
Factorize tests, ensure JSON canonicalization.
timothee-haudebourg Jun 13, 2024
9a2a8c5
Fix formatting & clippy warnings.
timothee-haudebourg Jun 24, 2024
9f3871c
Fix tests.
timothee-haudebourg Jun 27, 2024
1231a75
Fix redundant imports.
timothee-haudebourg Jun 27, 2024
fcd7339
Fix non-exhaustive pattern in multikey.
timothee-haudebourg Jun 27, 2024
80857a9
Upgrade `uuid`to 1.9
timothee-haudebourg Jul 3, 2024
224a54c
Fix multicodec imports.
timothee-haudebourg Jul 3, 2024
892ed01
Remove some unused files.
timothee-haudebourg Jul 3, 2024
28adfb3
Remove duplicate `serde_json` dev dependency.
timothee-haudebourg Jul 5, 2024
a155b72
Fix formatting.
timothee-haudebourg Jul 5, 2024
8d754aa
Lazy `Multikey` decoding.
timothee-haudebourg Jul 5, 2024
8fdf904
A few renamings.
timothee-haudebourg Jul 5, 2024
8ddd4d6
Add `SelectiveCryptographicSuite` trait, providing a nice interface t…
timothee-haudebourg Jul 8, 2024
ec9b763
Add `Bbs2023` variant to `AnySuite`.
timothee-haudebourg Jul 9, 2024
e8dfe7d
Fix feature gates.
timothee-haudebourg Jul 9, 2024
73cbd44
Fix imports & feature gates.
timothee-haudebourg Jul 9, 2024
74db767
Upgrade `json-ld` to version 0.21
timothee-haudebourg Jul 9, 2024
932bbf8
Remove feature gates on `Multikey`.
timothee-haudebourg Jul 9, 2024
38a1062
Enable `ssi-jwk/bbs` with `ssi-verification-methods-core/bbs`.
timothee-haudebourg Jul 9, 2024
46a4bbf
Rename `verification-methods/bls12-381` feature into `bbs`.
timothee-haudebourg Jul 9, 2024
d6c3972
Fix more feature gates.
timothee-haudebourg Jul 9, 2024
00b720e
Add to_jwk for Bls multikeys
sbihel Jul 9, 2024
cd6b5b0
Revert manual JWK conversion
sbihel Jul 9, 2024
3aaa2b4
Upgrade `json-ld` to 0.21.1
timothee-haudebourg Jul 10, 2024
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
12 changes: 10 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ ssi-ucan = { path = "./crates/ucan", version = "0.2", default-features = false }
ssi-zcap-ld = { path = "./crates/zcap-ld", version = "0.2", default-features = false }
ssi-ssh = { path = "./crates/ssh", version = "0.2", default-features = false }
ssi-status = { path = "./crates/status", version = "0.1", default-features = false }
ssi-bbs = { path = "./crates/bbs", version = "0.1", default-features = false }

# Verifiable Claims
ssi-claims-core = { path = "./crates/claims/core", version = "0.1", default-features = false }
Expand All @@ -48,6 +49,7 @@ ssi-jwt = { path = "./crates/claims/crates/jwt", version = "0.2", default-featur
ssi-sd-jwt = { path = "./crates/claims/crates/sd-jwt", version = "0.2", default-features = false }
ssi-vc = { path = "./crates/claims/crates/vc", version = "0.3", default-features = false }
ssi-data-integrity-core = { path = "./crates/claims/crates/data-integrity/core", version = "0.1", default-features = false }
ssi-di-sd-primitives = { path = "./crates/claims/crates/data-integrity/sd-primitives", version = "0.1", default-features = false }
ssi-data-integrity-suites = { path = "./crates/claims/crates/data-integrity/suites", version = "0.1", default-features = false }
ssi-data-integrity = { path = "./crates/claims/crates/data-integrity", version = "0.1", default-features = false }
ssi-claims = { path = "./crates/claims", version = "0.1", default-features = false }
Expand All @@ -64,6 +66,7 @@ did-web = { path = "./crates/dids/methods/web", version = "0.3", default-feature
ssi-dids = { path = "./crates/dids", version = "0.2", default-features = false }

# crypto
digest = "0.10"
k256 = "0.13.1"
p256 = "0.13.2"
p384 = "0.13.0"
Expand All @@ -72,6 +75,7 @@ blake2 = "0.10"
sha2 = "0.10.0"
sha3 = "0.10.8"
rsa = "0.6"
zkryptium = "0.2.2" # BBS

# other common dependencies
log = "0.4.21"
Expand Down Expand Up @@ -100,8 +104,11 @@ futures = "0.3.28"
linked-data = "0.1.2"
rand = "0.8"
rand_chacha = "0.3.1"
getrandom = "0.2"
contextual = "0.1.6"
lazy_static = "1.4.0"
indexmap = "2.0.0"
uuid = "1.9"

[features]
default = ["w3c", "rsa", "ed25519", "secp256k1", "secp256r1", "ripemd-160", "eip712"]
Expand Down Expand Up @@ -192,7 +199,7 @@ ethereum = ["ssi-claims/ethereum", "ssi-jwk/eip", "ssi-dids/eip"]
ripemd-160 = ["ssi-jwk/ripemd-160", "ssi-dids/ripemd-160"]

## Enable bbs.
bbs = ["ssi-crypto/bbs"]
bbs = ["ssi-crypto/bbs", "ssi-claims/bbs", "ssi-bbs"]

## Use the Ring crate for crypto operations
ring = ["ssi-jwk/ring", "ssi-jws/ring", "ssi-crypto/ring"]
Expand Down Expand Up @@ -224,12 +231,13 @@ ssi-ucan.workspace = true
ssi-zcap-ld.workspace = true
ssi-multicodec.workspace = true
ssi-ssh.workspace = true
ssi-bbs = { workspace = true, optional = true }
xsd-types.workspace = true # public reexport
document-features = "0.2"

[dev-dependencies]
async-std = { workspace = true, features = ["attributes"] }
uuid = { version = "0.8", features = ["v4", "serde"] }
uuid = { workspace = true, features = ["v4", "serde"] }
iref.workspace = true
static-iref.workspace = true
serde = { workspace = true, features = ["derive"] }
Expand Down
15 changes: 15 additions & 0 deletions crates/bbs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "ssi-bbs"
sbihel marked this conversation as resolved.
Show resolved Hide resolved
version = "0.1.0"
edition = "2021"
authors = ["Spruce Systems, Inc."]
license = "Apache-2.0"
description = "The BBS Signature Scheme implementation for SSI"
repository = "https://github.com/spruceid/ssi/"
documentation = "https://docs.rs/ssi-bbs/"

[dependencies]
ssi-crypto.workspace = true
ssi-claims-core.workspace = true
zkryptium = "0.2.2"
rand.workspace = true
112 changes: 112 additions & 0 deletions crates/bbs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use ssi_claims_core::{InvalidProof, MessageSignatureError, ProofValidationError, ProofValidity};
use ssi_crypto::algorithm::BbsParameters;
pub use zkryptium::{
bbsplus::keys::{BBSplusPublicKey, BBSplusSecretKey},
errors::Error,
};
use zkryptium::{
bbsplus::{
ciphersuites::{BbsCiphersuite, Bls12381Sha256},
commitment::BlindFactor,
},
keys::pair::KeyPair,
schemes::{
algorithms::BBSplus,
generics::{BlindSignature, Signature},
},
};

pub use ssi_crypto::algorithm::Bbs;

#[derive(Debug)]
pub struct ProofGenFailed;

pub fn proof_gen(
pk: &BBSplusPublicKey,
signature: &[u8],
header: &[u8],
ph: Option<&[u8]>,
messages: &[Vec<u8>],
disclosed_indexes: &[usize],
) -> Result<Vec<u8>, ProofGenFailed> {
Ok(
zkryptium::schemes::generics::PoKSignature::<BBSplus<Bls12381Sha256>>::proof_gen(
pk,
signature,
Some(header),
ph,
Some(messages),
Some(disclosed_indexes),
)
.map_err(|_| ProofGenFailed)?
.to_bytes(),
)
}

pub fn proof_verify(
pk: &BBSplusPublicKey,
signature: &[u8],
header: &[u8],
ph: Option<&[u8]>,
disclosed_messages: &[Vec<u8>],
disclosed_indexes: &[usize],
) -> Result<ProofValidity, ProofValidationError> {
let signature =
zkryptium::schemes::generics::PoKSignature::<BBSplus<Bls12381Sha256>>::from_bytes(
signature,
)
.map_err(|_| ProofValidationError::InvalidSignature)?;

Ok(signature
.proof_verify(
pk,
Some(disclosed_messages),
Some(disclosed_indexes),
Some(header),
ph,
)
.map_err(|_| InvalidProof::Signature))
}

pub fn sign(
params: BbsParameters,
sk: &BBSplusSecretKey,
pk: &BBSplusPublicKey,
messages: &[Vec<u8>],
) -> Result<Vec<u8>, MessageSignatureError> {
match params {
BbsParameters::Baseline { header } => {
Ok(
Signature::<BBSplus<Bls12381Sha256>>::sign(Some(messages), sk, pk, Some(&header))
.map_err(MessageSignatureError::signature_failed)?
.to_bytes()
.to_vec(),
)
}
BbsParameters::Blind {
header,
commitment_with_proof,
signer_blind,
} => {
let signer_blind = signer_blind.map(|b| BlindFactor::from_bytes(&b).unwrap());
Ok(BlindSignature::<BBSplus<Bls12381Sha256>>::blind_sign(
sk,
pk,
commitment_with_proof.as_deref(),
Some(&header),
Some(messages),
signer_blind.as_ref(),
)
.map_err(MessageSignatureError::signature_failed)?
.to_bytes()
.to_vec())
}
}
}

pub fn generate_secret_key(rng: &mut impl rand::RngCore) -> BBSplusSecretKey {
let mut key_material = [0; Bls12381Sha256::IKM_LEN];
rng.fill_bytes(&mut key_material);
let pair = KeyPair::<BBSplus<Bls12381Sha256>>::generate(&key_material, None, None).unwrap();
pair.into_parts().0
}
3 changes: 3 additions & 0 deletions crates/claims/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ solana = ["ssi-data-integrity/solana", "ssi-verification-methods/solana"]
# Enables `EthereumPersonalSignature2021`
ethereum = ["ssi-jws/eip", "ssi-data-integrity/ethereum"]

# Enables `Bbs2023`
bbs = ["ssi-data-integrity/bbs"]

[dependencies]
ssi-core.workspace = true
ssi-crypto.workspace = true
Expand Down
1 change: 1 addition & 0 deletions crates/claims/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ linked-data = ["dep:linked-data"]

[dependencies]
ssi-core.workspace = true
ssi-crypto.workspace = true
educe.workspace = true
thiserror.workspace = true
chrono.workspace = true
Expand Down
75 changes: 75 additions & 0 deletions crates/claims/core/src/signature.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::fmt;

use ssi_crypto::algorithm::{AlgorithmError, UnsupportedAlgorithm};
use ssi_eip712::Eip712TypesLoaderProvider;
use ssi_json_ld::JsonLdLoaderProvider;

Expand All @@ -26,6 +27,9 @@ pub enum SignatureError {
#[error("claims: {0}")]
Claims(String),

#[error("missing required option `{0}`")]
MissingRequiredOption(String),

#[error("missing signer")]
MissingSigner,

Expand All @@ -43,6 +47,10 @@ impl SignatureError {
pub fn other(e: impl fmt::Display) -> Self {
Self::Other(e.to_string())
}

pub fn missing_required_option(name: &str) -> Self {
Self::MissingRequiredOption(name.to_string())
}
}

impl From<std::convert::Infallible> for SignatureError {
Expand All @@ -51,6 +59,73 @@ impl From<std::convert::Infallible> for SignatureError {
}
}

#[derive(Debug, thiserror::Error)]
pub enum MessageSignatureError {
#[error("0")]
SignatureFailed(String),

#[error("invalid signature client query")]
InvalidQuery,

#[error("invalid signer response")]
InvalidResponse,

#[error("invalid public key")]
InvalidPublicKey,

#[error("invalid secret key")]
InvalidSecretKey,

#[error("missing signature algorithm")]
MissingAlgorithm,

#[error("unsupported signature algorithm `{0}`")]
UnsupportedAlgorithm(String),

#[error("unsupported verification method `{0}`")]
UnsupportedVerificationMethod(String),

/// Signature algorithm does not support multi-message signing.
#[error("too many messages")]
TooManyMessages,

/// Signature algorithm requires at least one message.
#[error("missing message")]
MissingMessage,
}

impl MessageSignatureError {
pub fn signature_failed(e: impl ToString) -> Self {
Self::SignatureFailed(e.to_string())
}
}

impl From<MessageSignatureError> for SignatureError {
fn from(value: MessageSignatureError) -> Self {
match value {
MessageSignatureError::MissingAlgorithm => Self::MissingAlgorithm,
MessageSignatureError::UnsupportedAlgorithm(name) => Self::UnsupportedAlgorithm(name),
MessageSignatureError::InvalidSecretKey => Self::InvalidSecretKey,
other => Self::other(other),
}
}
}

impl From<AlgorithmError> for MessageSignatureError {
fn from(value: AlgorithmError) -> Self {
match value {
AlgorithmError::Missing => Self::MissingAlgorithm,
AlgorithmError::Unsupported(a) => Self::UnsupportedAlgorithm(a.to_string()),
}
}
}

impl From<UnsupportedAlgorithm> for MessageSignatureError {
fn from(value: UnsupportedAlgorithm) -> Self {
Self::UnsupportedAlgorithm(value.0.to_string())
}
}

/// Signature environment.
///
/// This is a common environment implementation expected to work with most
Expand Down
13 changes: 13 additions & 0 deletions crates/claims/core/src/verification/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,19 @@ pub enum Invalid {
Proof(#[from] InvalidProof),
}

/// Arbitrary resource provider.
pub trait ResourceProvider<T> {
/// Returns a reference to the resource of type `T`.
fn get_resource(&self) -> &T;
}

/// Anything can return the unit resource.
impl<T> ResourceProvider<()> for T {
fn get_resource(&self) -> &() {
&()
}
}

/// Type that provides a public key resolver.
pub trait ResolverProvider {
/// Public key resolver.
Expand Down
5 changes: 5 additions & 0 deletions crates/claims/crates/data-integrity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ solana = ["ssi-data-integrity-suites/solana"]
## - `Eip712Signature2021` (requires `eip712`)
ethereum = ["ssi-data-integrity-suites/ethereum"]

## BBS cryptographic suites.
bbs = ["ssi-bbs", "ssi-data-integrity-suites/bbs"]

[dependencies]
ssi-data-integrity-core.workspace = true
ssi-data-integrity-suites.workspace = true
Expand All @@ -106,6 +109,8 @@ ssi-json-ld.workspace = true
ssi-verification-methods.workspace = true
ssi-eip712.workspace = true
ssi-claims-core.workspace = true
ssi-di-sd-primitives.workspace = true
ssi-bbs = { workspace = true, optional = true }
iref.workspace = true
rdf-types.workspace = true
linked-data.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/claims/crates/data-integrity/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ futures.workspace = true
self_cell = "1.0.1"
contextual.workspace = true
multibase.workspace = true
digest = "0.10"
digest.workspace = true

[package.metadata.docs.rs]
all-features = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use ssi_rdf::{AnyLdEnvironment, LdEnvironment};

use crate::{
hashing::ConcatOutputSize,
suite::standard::{self, HashingAlgorithm, TransformationAlgorithm, TransformationError},
suite::{
standard::{self, HashingAlgorithm, TransformationAlgorithm, TransformationError},
TransformationOptions,
},
CryptographicSuite, ProofConfigurationRef, SerializeCryptographicSuite,
StandardCryptographicSuite,
};
Expand Down Expand Up @@ -36,6 +39,7 @@ where
context: &C,
data: &T,
proof_configuration: ProofConfigurationRef<'_, S>,
_transformation_options: TransformationOptions<S>,
) -> Result<Self::Output, TransformationError> {
let mut ld = LdEnvironment::default();

Expand Down
Loading