From ac4b5c0daffe612b4fffea04c0751dd377a61683 Mon Sep 17 00:00:00 2001 From: Alberto Solavagione Date: Tue, 19 Mar 2024 16:15:30 +0100 Subject: [PATCH 1/4] update zkryptium/json-proof-token deps and new BLS key representation --- Cargo.toml | 4 +- identity_jose/src/jwk/curve/bls.rs | 36 ++++ identity_jose/src/jwk/curve/mod.rs | 2 + identity_jose/src/jwk/jwk_ext.rs | 44 ++--- .../src/key_storage/jwk_storage.rs | 5 +- identity_storage/src/key_storage/memstore.rs | 154 +++++++----------- .../src/storage/timeframe_revocation_ext.rs | 19 ++- 7 files changed, 127 insertions(+), 137 deletions(-) create mode 100644 identity_jose/src/jwk/curve/bls.rs diff --git a/Cargo.toml b/Cargo.toml index 9dc0983411..e958044495 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,8 +23,8 @@ serde = { version = "1.0", default-features = false, features = ["alloc", "deriv thiserror = { version = "1.0", default-features = false } strum = { version = "0.25", default-features = false, features = ["std", "derive"] } serde_json = { version = "1.0", default-features = false } -json-proof-token = { version = "0.3.3" } -zkryptium = { version = "0.1.9", default-features = false, features = ["bbsplus"] } +json-proof-token = { version = "0.3.4" } +zkryptium = { version = "0.2.0", default-features = false, features = ["bbsplus"] } [workspace.package] authors = ["IOTA Stiftung"] diff --git a/identity_jose/src/jwk/curve/bls.rs b/identity_jose/src/jwk/curve/bls.rs new file mode 100644 index 0000000000..a93e48b3e3 --- /dev/null +++ b/identity_jose/src/jwk/curve/bls.rs @@ -0,0 +1,36 @@ +use core::fmt::Display; +use core::fmt::Formatter; +use core::fmt::Result; + +/// Supported BLS Curves. +/// +/// [More Info](https://datatracker.ietf.org/doc/html/draft-ietf-cose-bls-key-representations-05#name-curve-parameter-registratio) +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub enum BlsCurve { + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 12 with 381-bit p in the subgroup of G1. + BLS12381G1, + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 12 with 381-bit p in the subgroup of G2. + BLS12381G2, + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 48 with 581-bit p in the subgroup of G1. + BLS48581G1, + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 48 with 581-bit p in the subgroup of G2. + BLS48581G2, +} + +impl BlsCurve { + /// Returns the name of the curve as a string slice. + pub const fn name(self) -> &'static str { + match self { + Self::BLS12381G1 => "BLS12381G1", + Self::BLS12381G2 => "BLS12381G2", + Self::BLS48581G1 => "BLS48581G1", + Self::BLS48581G2 => "BLS48581G2", + } + } +} + +impl Display for BlsCurve { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.write_str(self.name()) + } +} \ No newline at end of file diff --git a/identity_jose/src/jwk/curve/mod.rs b/identity_jose/src/jwk/curve/mod.rs index 38a1e3bba7..d333ad879c 100644 --- a/identity_jose/src/jwk/curve/mod.rs +++ b/identity_jose/src/jwk/curve/mod.rs @@ -4,7 +4,9 @@ mod ec; mod ecx; mod ed; +mod bls; pub use self::ec::*; pub use self::ecx::*; pub use self::ed::*; +pub use self::bls::*; \ No newline at end of file diff --git a/identity_jose/src/jwk/jwk_ext.rs b/identity_jose/src/jwk/jwk_ext.rs index 7c6621a5d0..a5b1d47256 100644 --- a/identity_jose/src/jwk/jwk_ext.rs +++ b/identity_jose/src/jwk/jwk_ext.rs @@ -1,14 +1,14 @@ use super::Jwk; use super::JwkOperation; use super::JwkParams; -use super::JwkParamsOkp; +use super::JwkParamsEc; use super::JwkType; use super::JwkUse; use identity_core::common::Url; use jsonprooftoken::jpa::algs::ProofAlgorithm; use jsonprooftoken::jwk::alg_parameters::Algorithm; use jsonprooftoken::jwk::alg_parameters::JwkAlgorithmParameters; -use jsonprooftoken::jwk::alg_parameters::JwkOctetKeyPairParameters; +use jsonprooftoken::jwk::alg_parameters::JwkEllipticCurveKeyParameters; use jsonprooftoken::jwk::curves::EllipticCurveTypes; use jsonprooftoken::jwk::key::Jwk as JwkExt; use jsonprooftoken::jwk::key::KeyOps; @@ -50,23 +50,6 @@ impl From for KeyOps { } } -// impl Into for JwkOperation { -// fn into(self) -> KeyOps { -// match self { -// Self::Sign => KeyOps::Sign, -// Self::Verify => KeyOps::Verify, -// Self::Encrypt => KeyOps::Encrypt, -// Self::Decrypt => KeyOps::Decrypt, -// Self::WrapKey => KeyOps::WrapKey, -// Self::UnwrapKey => KeyOps::UnwrapKey, -// Self::DeriveKey => KeyOps::DeriveKey, -// Self::DeriveBits => KeyOps::DeriveBits, -// Self::ProofGeneration => KeyOps::ProofGeneration, -// Self::ProofVerification => KeyOps::ProofVerification, -// } -// } -// } - impl From for JwkUse { fn from(value: PKUse) -> Self { match value { @@ -87,24 +70,26 @@ impl From for PKUse { } } -impl From for JwkParamsOkp { - fn from(value: JwkOctetKeyPairParameters) -> Self { +impl From for JwkParamsEc { + fn from(value: JwkEllipticCurveKeyParameters) -> Self { Self { crv: value.crv.to_string(), x: value.x, + y: value.y, d: value.d, } } } -impl TryInto for &JwkParamsOkp { +impl TryInto for &JwkParamsEc { type Error = crate::error::Error; - fn try_into(self) -> Result { - Ok(JwkOctetKeyPairParameters { - kty: KeyType::OctetKeyPair, - crv: EllipticCurveTypes::from_str(&self.crv).map_err(|_| Self::Error::KeyError("Invalid crv!"))?, + fn try_into(self) -> Result { + Ok(JwkEllipticCurveKeyParameters { + kty: KeyType::EllipticCurve, + crv: EllipticCurveTypes::from_str(&self.crv).map_err(|_| Self::Error::KeyError("crv not supported!"))?, x: self.x.clone(), + y: self.y.clone(), d: self.d.clone(), }) } @@ -120,7 +105,8 @@ impl TryFrom for Jwk { }; let (kty, params) = match value.key_params { - JwkAlgorithmParameters::OctetKeyPair(p) => (JwkType::Okp, JwkParams::Okp(JwkParamsOkp::from(p))), + JwkAlgorithmParameters::EllipticCurve(p) => (JwkType::Ec, JwkParams::Ec(JwkParamsEc::from(p))), + _ => return Err(Self::Error::KeyError("invalid kty")) }; Ok(Self { @@ -145,7 +131,7 @@ impl TryInto for &Jwk { fn try_into(self) -> Result { let params = match &self.params { - JwkParams::Okp(p) => JwkAlgorithmParameters::OctetKeyPair(p.try_into()?), + JwkParams::Ec(p) => JwkAlgorithmParameters::EllipticCurve(p.try_into()?), _ => return Err(Self::Error::InvalidParam("Parameters not supported!")), }; @@ -170,4 +156,4 @@ impl TryInto for &Jwk { key_params: params, }) } -} +} \ No newline at end of file diff --git a/identity_storage/src/key_storage/jwk_storage.rs b/identity_storage/src/key_storage/jwk_storage.rs index e0e488be03..d74f51b077 100644 --- a/identity_storage/src/key_storage/jwk_storage.rs +++ b/identity_storage/src/key_storage/jwk_storage.rs @@ -11,6 +11,7 @@ use identity_verification::jose::jws::JwsAlgorithm; use jsonprooftoken::jpa::algs::ProofAlgorithm; use jsonprooftoken::jpt::claims::JptClaims; use jsonprooftoken::jwp::header::IssuerProtectedHeader; +use zkryptium::bbsplus::signature::BBSplusSignature; use super::jwk_gen_output::JwkGenOutput; @@ -88,7 +89,7 @@ pub trait JwkStorageExt: JwkStorage { &self, key_id: &KeyId, public_key: &Jwk, - proof: &[u8; 112], + proof: &[u8; BBSplusSignature::BYTES], ctx: ProofUpdateCtx, - ) -> KeyStorageResult<[u8; 112]>; + ) -> KeyStorageResult<[u8; BBSplusSignature::BYTES]>; } diff --git a/identity_storage/src/key_storage/memstore.rs b/identity_storage/src/key_storage/memstore.rs index 4758840da1..b0a8061666 100644 --- a/identity_storage/src/key_storage/memstore.rs +++ b/identity_storage/src/key_storage/memstore.rs @@ -12,11 +12,11 @@ use identity_verification::jose::jwk::EdCurve; use identity_verification::jose::jwk::Jwk; use identity_verification::jose::jwk::JwkType; use identity_verification::jose::jws::JwsAlgorithm; +use identity_verification::jwk::BlsCurve; use identity_verification::jwu; use jsonprooftoken::encoding::SerializationType; use jsonprooftoken::jpa::algs::ProofAlgorithm; use jsonprooftoken::jpt::claims::JptClaims; -use jsonprooftoken::jwk::curves::EllipticCurveTypes; use jsonprooftoken::jwk::key::Jwk as JwkExt; use jsonprooftoken::jwk::types::KeyPairSubtype; use jsonprooftoken::jwp::header::IssuerProtectedHeader; @@ -25,12 +25,11 @@ use rand::distributions::DistString; use shared::Shared; use tokio::sync::RwLockReadGuard; use tokio::sync::RwLockWriteGuard; -use zkryptium::bbsplus::keys::BBSplusPublicKey; use zkryptium::bbsplus::keys::BBSplusSecretKey; -use zkryptium::schemes::algorithms::BBS_BLS12381_SHA256; -use zkryptium::schemes::algorithms::BBS_BLS12381_SHAKE256; +use zkryptium::bbsplus::signature::BBSplusSignature; +use zkryptium::schemes::algorithms::BbsBls12381Sha256; +use zkryptium::schemes::algorithms::BbsBls12381Shake256; use zkryptium::schemes::generics::Signature; -use zkryptium::utils::message::BBSplusMessage; use super::ed25519::encode_jwk; use super::ed25519::expand_secret_jwk; @@ -339,16 +338,16 @@ impl JwkStorageExt for JwkMemStore { match alg { ProofAlgorithm::BLS12381_SHA256 | ProofAlgorithm::BLS12381_SHAKE256 => { - let okp_params = public_key.try_okp_params().map_err(|err| { + let ec_params = public_key.try_ec_params().map_err(|err| { KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("expected a Jwk with Okp params in order to sign with {alg}")) + .with_custom_message(format!("expected a Jwk with EC params in order to sign with {alg}")) .with_source(err) })?; - if okp_params.crv != EllipticCurveTypes::Bls12381G2.to_string() { + if ec_params.crv != BlsCurve::BLS12381G2.to_string() { return Err( KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!( - "expected Jwk with Okp {} crv in order to generate the proof with {alg}", - EllipticCurveTypes::Bls12381G2 + "expected Jwk with EC {} crv in order to generate the proof with {alg}", + BlsCurve::BLS12381G2 )), ); } @@ -384,9 +383,9 @@ impl JwkStorageExt for JwkMemStore { &self, key_id: &KeyId, public_key: &Jwk, - proof: &[u8; 112], + proof: &[u8; BBSplusSignature::BYTES], ctx: ProofUpdateCtx, - ) -> KeyStorageResult<[u8; 112]> { + ) -> KeyStorageResult<[u8; BBSplusSignature::BYTES]> { let jwk_store: RwLockReadGuard<'_, JwkKeyStore> = self.jwk_store.read().await; let ProofUpdateCtx { @@ -409,16 +408,16 @@ impl JwkStorageExt for JwkMemStore { match alg { ProofAlgorithm::BLS12381_SHA256 | ProofAlgorithm::BLS12381_SHAKE256 => { - let okp_params = public_key.try_okp_params().map_err(|err| { + let ec_params = public_key.try_ec_params().map_err(|err| { KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("expected a Jwk with Okp params in order to sign with {alg}")) + .with_custom_message(format!("expected a Jwk with EC params in order to sign with {alg}")) .with_source(err) })?; - if okp_params.crv != EllipticCurveTypes::Bls12381G2.to_string() { + if ec_params.crv != BlsCurve::BLS12381G2.to_string() { return Err( KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!( - "expected Jwk with Okp {} crv in order to generate the proof with {alg}", - EllipticCurveTypes::Bls12381G2 + "expected Jwk with EC {} crv in order to generate the proof with {alg}", + BlsCurve::BLS12381G2 )), ); } @@ -436,13 +435,7 @@ impl JwkStorageExt for JwkMemStore { .get(key_id) .ok_or_else(|| KeyStorageError::new(KeyStorageErrorKind::KeyNotFound))?; - let params = jwk.try_okp_params().map_err(|_| KeyStorageErrorKind::Unspecified)?; - - let pk = BBSplusPublicKey::from_bytes(&jwu::decode_b64(¶ms.x).map_err(|err| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("unable to decode `d` param") - .with_source(err) - })?); + let params = jwk.try_ec_params().map_err(|_| KeyStorageErrorKind::Unspecified)?; let sk = BBSplusSecretKey::from_bytes( ¶ms @@ -458,94 +451,65 @@ impl JwkStorageExt for JwkMemStore { .with_custom_message("unable to decode `d` param") .with_source(err) })?, - ); + ).map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("key not valid") + })?; let new_proof = match alg { ProofAlgorithm::BLS12381_SHA256 => { - let vec_old_start_validity_timeframe = serde_json::to_vec(&old_start_validity_timeframe) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified))?; - let old_start_validity_timeframe = - BBSplusMessage::map_message_to_scalar_as_hash::(&vec_old_start_validity_timeframe, None); - - let vec_new_start_validity_timeframe = serde_json::to_vec(&new_start_validity_timeframe) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified))?; - let new_start_validity_timeframe = - BBSplusMessage::map_message_to_scalar_as_hash::(&vec_new_start_validity_timeframe, None); - - let vec_old_end_validity_timeframe = serde_json::to_vec(&old_end_validity_timeframe) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified))?; - let old_end_validity_timeframe = - BBSplusMessage::map_message_to_scalar_as_hash::(&vec_old_end_validity_timeframe, None); - - let vec_new_end_validity_timeframe = serde_json::to_vec(&new_end_validity_timeframe) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified))?; - let new_end_validity_timeframe = - BBSplusMessage::map_message_to_scalar_as_hash::(&vec_new_end_validity_timeframe, None); - - let proof = Signature::::from_bytes(proof).update_signature( + let proof = Signature::::from_bytes(proof) + .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid"))? + .update_signature( &sk, - &pk, - number_of_signed_messages, &old_start_validity_timeframe, &new_start_validity_timeframe, index_start_validity_timeframe, - ); + number_of_signed_messages, + ).map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("Signature update failed") + })?; proof - .update_signature( - &sk, - &pk, - number_of_signed_messages, - &old_end_validity_timeframe, - &new_end_validity_timeframe, - index_end_validity_timeframe, - ) - .to_bytes() + .update_signature( + &sk, + &old_end_validity_timeframe, + &new_end_validity_timeframe, + index_end_validity_timeframe, + number_of_signed_messages, + ).map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("Signature update failed") + })? + .to_bytes() } ProofAlgorithm::BLS12381_SHAKE256 => { - let vec_old_start_validity_timeframe = serde_json::to_vec(&old_start_validity_timeframe) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified))?; - let old_start_validity_timeframe = BBSplusMessage::map_message_to_scalar_as_hash::( - &vec_old_start_validity_timeframe, - None, - ); - - let vec_new_start_validity_timeframe = serde_json::to_vec(&new_start_validity_timeframe) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified))?; - let new_start_validity_timeframe = BBSplusMessage::map_message_to_scalar_as_hash::( - &vec_new_start_validity_timeframe, - None, - ); - - let vec_old_end_validity_timeframe = serde_json::to_vec(&old_end_validity_timeframe) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified))?; - let old_end_validity_timeframe = - BBSplusMessage::map_message_to_scalar_as_hash::(&vec_old_end_validity_timeframe, None); - - let vec_new_end_validity_timeframe = serde_json::to_vec(&new_end_validity_timeframe) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified))?; - let new_end_validity_timeframe = - BBSplusMessage::map_message_to_scalar_as_hash::(&vec_new_end_validity_timeframe, None); - - let proof = Signature::::from_bytes(proof).update_signature( + let proof = Signature::::from_bytes(proof) + .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid"))? + .update_signature( &sk, - &pk, - number_of_signed_messages, &old_start_validity_timeframe, &new_start_validity_timeframe, index_start_validity_timeframe, - ); + number_of_signed_messages, + ).map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("Signature update failed") + })?; proof - .update_signature( - &sk, - &pk, - number_of_signed_messages, - &old_end_validity_timeframe, - &new_end_validity_timeframe, - index_end_validity_timeframe, - ) - .to_bytes() + .update_signature( + &sk, + &old_end_validity_timeframe, + &new_end_validity_timeframe, + index_end_validity_timeframe, + number_of_signed_messages, + ).map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("Signature update failed") + })? + .to_bytes() } other => { return Err( diff --git a/identity_storage/src/storage/timeframe_revocation_ext.rs b/identity_storage/src/storage/timeframe_revocation_ext.rs index 0d3ed740b7..d03b7d5d8d 100644 --- a/identity_storage/src/storage/timeframe_revocation_ext.rs +++ b/identity_storage/src/storage/timeframe_revocation_ext.rs @@ -16,17 +16,18 @@ use jsonprooftoken::encoding::SerializationType; use jsonprooftoken::jpt::payloads::Payloads; use jsonprooftoken::jwp::issued::JwpIssued; use serde_json::Value; +use zkryptium::bbsplus::signature::BBSplusSignature; /// Contains information needed to update the signature in the RevocationTimeframe2024 revocation mechanism. pub struct ProofUpdateCtx { /// Old `startValidityTimeframe` value - pub old_start_validity_timeframe: String, + pub old_start_validity_timeframe: Vec, /// New `startValidityTimeframe` value to be signed - pub new_start_validity_timeframe: String, + pub new_start_validity_timeframe: Vec, /// Old `endValidityTimeframe` value - pub old_end_validity_timeframe: String, + pub old_end_validity_timeframe: Vec, /// New `endValidityTimeframe` value to be signed - pub new_end_validity_timeframe: String, + pub new_end_validity_timeframe: Vec, /// Index of `startValidityTimeframe` claim inside the array of Claims pub index_start_validity_timeframe: usize, /// Index of `endValidityTimeframe` claim inside the array of Claims @@ -132,15 +133,15 @@ impl TimeframeRevocationExtension for CoreDocument { .map_err(|_| Error::ProofUpdateError("'endValidityTimeframe' value NOT found".to_owned()))? .map_err(|_| Error::ProofUpdateError("'endValidityTimeframe' value NOT a JSON String".to_owned()))?; - let proof: [u8; 112] = proof + let proof: [u8; BBSplusSignature::BYTES] = proof .try_into() .map_err(|_| Error::ProofUpdateError("Invalid bytes length of JWP proof".to_owned()))?; let proof_update_ctx = ProofUpdateCtx { - old_start_validity_timeframe, - new_start_validity_timeframe, - old_end_validity_timeframe, - new_end_validity_timeframe, + old_start_validity_timeframe: serde_json::to_vec(&old_start_validity_timeframe).unwrap(), + new_start_validity_timeframe: serde_json::to_vec(&new_start_validity_timeframe).unwrap(), + old_end_validity_timeframe: serde_json::to_vec(&old_end_validity_timeframe).unwrap(), + new_end_validity_timeframe: serde_json::to_vec(&new_end_validity_timeframe).unwrap(), index_start_validity_timeframe, index_end_validity_timeframe, number_of_signed_messages: payloads.0.len(), From f3fc3b6733fde1978460f573a258c082a4dead7c Mon Sep 17 00:00:00 2001 From: Alberto Solavagione Date: Mon, 25 Mar 2024 10:15:12 +0100 Subject: [PATCH 2/4] minor fix --- identity_jose/src/jwk/jwk_ext.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/identity_jose/src/jwk/jwk_ext.rs b/identity_jose/src/jwk/jwk_ext.rs index a5b1d47256..4b2c3b72fe 100644 --- a/identity_jose/src/jwk/jwk_ext.rs +++ b/identity_jose/src/jwk/jwk_ext.rs @@ -106,7 +106,7 @@ impl TryFrom for Jwk { let (kty, params) = match value.key_params { JwkAlgorithmParameters::EllipticCurve(p) => (JwkType::Ec, JwkParams::Ec(JwkParamsEc::from(p))), - _ => return Err(Self::Error::KeyError("invalid kty")) + _ => unreachable!() }; Ok(Self { From f878bb3a7f8338ba676d362ed9dc4eb9a45823b1 Mon Sep 17 00:00:00 2001 From: Alberto Solavagione Date: Fri, 5 Apr 2024 13:09:15 +0200 Subject: [PATCH 3/4] use zkryptium for crypto operations and JPT for serialization --- Cargo.toml | 4 +- examples/1_advanced/10_zkp_revocation.rs | 2 +- examples/1_advanced/9_zkp.rs | 2 +- .../presentation/jwp_presentation_builder.rs | 2 +- identity_jose/src/jwk/key_params.rs | 13 ++ identity_storage/src/key_storage/bls.rs | 91 +++++++++++ .../src/key_storage/jwk_storage.rs | 19 +-- identity_storage/src/key_storage/memstore.rs | 154 +++++++++++++----- identity_storage/src/key_storage/mod.rs | 2 + .../src/storage/jwp_document_ext.rs | 28 +++- .../src/storage/timeframe_revocation_ext.rs | 2 +- 11 files changed, 254 insertions(+), 65 deletions(-) create mode 100644 identity_storage/src/key_storage/bls.rs diff --git a/Cargo.toml b/Cargo.toml index e958044495..6a6fb06ba6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,8 +23,8 @@ serde = { version = "1.0", default-features = false, features = ["alloc", "deriv thiserror = { version = "1.0", default-features = false } strum = { version = "0.25", default-features = false, features = ["std", "derive"] } serde_json = { version = "1.0", default-features = false } -json-proof-token = { version = "0.3.4" } -zkryptium = { version = "0.2.0", default-features = false, features = ["bbsplus"] } +json-proof-token = { version = "0.3.5" } +zkryptium = { version = "0.2.1", default-features = false, features = ["bbsplus"] } [workspace.package] authors = ["IOTA Stiftung"] diff --git a/examples/1_advanced/10_zkp_revocation.rs b/examples/1_advanced/10_zkp_revocation.rs index 6941f51a16..db30d71d71 100644 --- a/examples/1_advanced/10_zkp_revocation.rs +++ b/examples/1_advanced/10_zkp_revocation.rs @@ -151,7 +151,7 @@ async fn main() -> anyhow::Result<()> { &client, &secret_manager_issuer, &storage_issuer, - JwkMemStore::BLS12381SHA256_KEY_TYPE, + JwkMemStore::BLS12381G2_KEY_TYPE, None, Some(ProofAlgorithm::BLS12381_SHA256), ) diff --git a/examples/1_advanced/9_zkp.rs b/examples/1_advanced/9_zkp.rs index bca63edd94..744395c3cc 100644 --- a/examples/1_advanced/9_zkp.rs +++ b/examples/1_advanced/9_zkp.rs @@ -99,7 +99,7 @@ async fn main() -> anyhow::Result<()> { &client, &secret_manager_issuer, &storage_issuer, - JwkMemStore::BLS12381SHA256_KEY_TYPE, + JwkMemStore::BLS12381G2_KEY_TYPE, ProofAlgorithm::BLS12381_SHA256, ) .await?; diff --git a/identity_credential/src/presentation/jwp_presentation_builder.rs b/identity_credential/src/presentation/jwp_presentation_builder.rs index cb78123578..c1ad0c45a4 100644 --- a/identity_credential/src/presentation/jwp_presentation_builder.rs +++ b/identity_credential/src/presentation/jwp_presentation_builder.rs @@ -85,7 +85,7 @@ impl SelectiveDisclosurePresentation { /// Set Presentation Protected Header. pub fn set_presentation_header(&mut self, ph: PresentationProtectedHeader) { - self.jwp_builder.presentation_protected_header(ph); + self.jwp_builder.set_presentation_protected_header(ph); } /// Get the builder. diff --git a/identity_jose/src/jwk/key_params.rs b/identity_jose/src/jwk/key_params.rs index f60d6d5e66..ba3ca23059 100644 --- a/identity_jose/src/jwk/key_params.rs +++ b/identity_jose/src/jwk/key_params.rs @@ -10,6 +10,8 @@ use crate::jwk::EcxCurve; use crate::jwk::EdCurve; use crate::jwk::JwkType; +use super::BlsCurve; + /// Algorithm-specific parameters for JSON Web Keys. /// /// [More Info](https://tools.ietf.org/html/rfc7518#section-6) @@ -149,6 +151,17 @@ impl JwkParamsEc { _ => Err(Error::KeyError("Ec Curve")), } } + + /// Returns the [`BlsCurve`] if it is of a supported type. + pub fn try_bls_curve(&self) -> Result { + match &*self.crv { + "BLS12381G1" => Ok(BlsCurve::BLS12381G1), + "BLS12381G2" => Ok(BlsCurve::BLS12381G2), + "BLS48581G1" => Ok(BlsCurve::BLS48581G1), + "BLS48581G2" => Ok(BlsCurve::BLS48581G2), + _ => Err(Error::KeyError("BLS Curve")), + } + } } impl From for JwkParams { diff --git a/identity_storage/src/key_storage/bls.rs b/identity_storage/src/key_storage/bls.rs new file mode 100644 index 0000000000..148106578b --- /dev/null +++ b/identity_storage/src/key_storage/bls.rs @@ -0,0 +1,91 @@ + +use identity_verification::jose::jwk::Jwk; +use identity_verification::jose::jwu; +use identity_verification::jwk::BlsCurve; +use identity_verification::jwk::JwkParamsEc; +use zkryptium::bbsplus::keys::BBSplusPublicKey; +use zkryptium::bbsplus::keys::BBSplusSecretKey; + +use crate::key_storage::KeyStorageError; +use crate::key_storage::KeyStorageErrorKind; +use crate::key_storage::KeyStorageResult; + +pub(crate) fn expand_bls_jwk(jwk: &Jwk) -> KeyStorageResult<(BBSplusSecretKey, BBSplusPublicKey)> { + let params: &JwkParamsEc = jwk.try_ec_params().unwrap(); + + if params + .try_bls_curve() + .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType).with_source(err))? + != BlsCurve::BLS12381G2 + { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("expected an {} key", BlsCurve::BLS12381G2.name())), + ); + } + + let sk: BBSplusSecretKey = params + .d + .as_deref() + .map(jwu::decode_b64) + .ok_or_else(|| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("expected Jwk `d` param to be present") + })? + .map(|v| BBSplusSecretKey::from_bytes(&v)) + .map_err(|err| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("unable to decode `d` param") + .with_source(err) + })? + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message(format!("invalid BBS+ secret key")) + })?; + + let x: [u8; BBSplusPublicKey::COORDINATE_LEN] = jwu::decode_b64(¶ms.x) + .map_err(|err| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("unable to decode `x` param") + .with_source(err) + })? + .try_into() + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message(format!("expected key of length {}", BBSplusPublicKey::COORDINATE_LEN)) + })?; + + let y: [u8; BBSplusPublicKey::COORDINATE_LEN] = jwu::decode_b64(¶ms.y) + .map_err(|err| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("unable to decode `y` param") + .with_source(err) + })? + .try_into() + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message(format!("expected key of length {}", BBSplusPublicKey::COORDINATE_LEN)) + })?; + + let pk = BBSplusPublicKey::from_coordinates(&x, &y) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message(format!("invalid BBS+ public key")) + })?; + + Ok((sk, pk)) +} + +#[cfg(any(test, feature = "memstore"))] +pub(crate) fn encode_bls_jwk(private_key: &BBSplusSecretKey, public_key: &BBSplusPublicKey) -> Jwk { + let (x, y) = public_key.to_coordinates(); + let x = jwu::encode_b64(x); + let y = jwu::encode_b64(y); + + let d = jwu::encode_b64(private_key.to_bytes()); + let mut params = JwkParamsEc::new(); + params.x = x; + params.y = y; + params.d = Some(d); + params.crv = BlsCurve::BLS12381G2.name().to_owned(); + Jwk::from_params(params) +} \ No newline at end of file diff --git a/identity_storage/src/key_storage/jwk_storage.rs b/identity_storage/src/key_storage/jwk_storage.rs index d74f51b077..ee1048939d 100644 --- a/identity_storage/src/key_storage/jwk_storage.rs +++ b/identity_storage/src/key_storage/jwk_storage.rs @@ -9,8 +9,6 @@ use async_trait::async_trait; use identity_verification::jose::jwk::Jwk; use identity_verification::jose::jws::JwsAlgorithm; use jsonprooftoken::jpa::algs::ProofAlgorithm; -use jsonprooftoken::jpt::claims::JptClaims; -use jsonprooftoken::jwp::header::IssuerProtectedHeader; use zkryptium::bbsplus::signature::BBSplusSignature; use super::jwk_gen_output::JwkGenOutput; @@ -73,23 +71,18 @@ pub trait JwkStorage: storage_sub_trait::StorageSendSyncMaybe { #[cfg_attr(feature = "send-sync-storage", async_trait)] pub trait JwkStorageExt: JwkStorage { /// Generates a JWK representing a BBS+ signature - async fn generate_bbs_key(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult; + async fn generate_bbs(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult; - /// Generate the JPT representing a JWP in the Issuer form - async fn generate_issuer_proof( - &self, - key_id: &KeyId, - header: IssuerProtectedHeader, - claims: JptClaims, - public_key: &Jwk, - ) -> KeyStorageResult; + /// Sign the provided `data` and `header` using the private key identified by `key_id` according to the requirements of + /// the corresponding `public_key` (see [`Jwk::alg`](Jwk::alg()) etc.). + async fn sign_bbs(&self, key_id: &KeyId, data: &[Vec], header: &[u8], public_key: &Jwk) -> KeyStorageResult>; /// Update proof functionality for timeframe revocation mechanism - async fn update_proof( + async fn update_signature( &self, key_id: &KeyId, public_key: &Jwk, - proof: &[u8; BBSplusSignature::BYTES], + signature: &[u8; BBSplusSignature::BYTES], ctx: ProofUpdateCtx, ) -> KeyStorageResult<[u8; BBSplusSignature::BYTES]>; } diff --git a/identity_storage/src/key_storage/memstore.rs b/identity_storage/src/key_storage/memstore.rs index b0a8061666..2e204bb079 100644 --- a/identity_storage/src/key_storage/memstore.rs +++ b/identity_storage/src/key_storage/memstore.rs @@ -14,23 +14,20 @@ use identity_verification::jose::jwk::JwkType; use identity_verification::jose::jws::JwsAlgorithm; use identity_verification::jwk::BlsCurve; use identity_verification::jwu; -use jsonprooftoken::encoding::SerializationType; use jsonprooftoken::jpa::algs::ProofAlgorithm; -use jsonprooftoken::jpt::claims::JptClaims; -use jsonprooftoken::jwk::key::Jwk as JwkExt; -use jsonprooftoken::jwk::types::KeyPairSubtype; -use jsonprooftoken::jwp::header::IssuerProtectedHeader; -use jsonprooftoken::jwp::issued::JwpIssuedBuilder; use rand::distributions::DistString; use shared::Shared; use tokio::sync::RwLockReadGuard; use tokio::sync::RwLockWriteGuard; use zkryptium::bbsplus::keys::BBSplusSecretKey; use zkryptium::bbsplus::signature::BBSplusSignature; +use zkryptium::keys::pair::KeyPair; use zkryptium::schemes::algorithms::BbsBls12381Sha256; use zkryptium::schemes::algorithms::BbsBls12381Shake256; use zkryptium::schemes::generics::Signature; +use super::bls::encode_bls_jwk; +use super::bls::expand_bls_jwk; use super::ed25519::encode_jwk; use super::ed25519::expand_secret_jwk; use super::jwk_gen_output::JwkGenOutput; @@ -82,6 +79,12 @@ impl JwkStorage for JwkMemStore { let public_key = private_key.public_key(); (private_key, public_key) } + other => { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("{other} is not supported")), + ); + } }; let kid: KeyId = random_key_id(); @@ -199,6 +202,7 @@ impl JwkStorage for JwkMemStore { #[derive(Debug, Copy, Clone)] enum MemStoreKeyType { Ed25519, + BLS12381G2, } impl JwkMemStore { @@ -206,19 +210,17 @@ impl JwkMemStore { /// The Ed25519 key type. pub const ED25519_KEY_TYPE: KeyType = KeyType::from_static_str(Self::ED25519_KEY_TYPE_STR); - const BLS12381SHA256_KEY_TYPE_STR: &'static str = "Bls12381Sha256"; - /// The BLS12381-SHA256 key type - pub const BLS12381SHA256_KEY_TYPE: KeyType = KeyType::from_static_str(Self::BLS12381SHA256_KEY_TYPE_STR); + const BLS12381G2_KEY_TYPE_STR: &'static str = "BLS12381G2"; + /// The BLS12381G2 key type + pub const BLS12381G2_KEY_TYPE: KeyType = KeyType::from_static_str(Self::BLS12381G2_KEY_TYPE_STR); - const BLS12381SHAKE256_KEY_TYPE_STR: &'static str = "Bls12381Shake256"; - /// The BLS12381-SHAKE256 key type - pub const BLS12381SHAKE256_KEY_TYPE: KeyType = KeyType::from_static_str(Self::BLS12381SHAKE256_KEY_TYPE_STR); } impl MemStoreKeyType { const fn name(&self) -> &'static str { match self { MemStoreKeyType::Ed25519 => "Ed25519", + MemStoreKeyType::BLS12381G2 => "BLS12381G2", } } } @@ -235,6 +237,7 @@ impl TryFrom<&KeyType> for MemStoreKeyType { fn try_from(value: &KeyType) -> Result { match value.as_str() { JwkMemStore::ED25519_KEY_TYPE_STR => Ok(MemStoreKeyType::Ed25519), + JwkMemStore::BLS12381G2_KEY_TYPE_STR => Ok(MemStoreKeyType::BLS12381G2), _ => Err(KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)), } } @@ -263,6 +266,24 @@ impl TryFrom<&Jwk> for MemStoreKeyType { ), } } + JwkType::Ec => { + let ec_params = jwk.try_ec_params().map_err(|err| { + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message("expected EC parameters for a JWK with `kty` Ec") + .with_source(err) + })?; + match ec_params.try_bls_curve().map_err(|err| { + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message("only Ed curves are supported for signing") + .with_source(err) + })? { + BlsCurve::BLS12381G2 => Ok(MemStoreKeyType::BLS12381G2), + curve => Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("{curve} not supported")), + ), + } + } other => Err( KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) .with_custom_message(format!("Jwk `kty` {other} not supported")), @@ -293,22 +314,63 @@ fn check_key_alg_compatibility(key_type: MemStoreKeyType, alg: JwsAlgorithm) -> } } +/// Check that the key type can be used with the algorithm. +fn check_key_proof_alg_compatibility(key_type: MemStoreKeyType, alg: ProofAlgorithm) -> KeyStorageResult<()> { + match (key_type, alg) { + (MemStoreKeyType::BLS12381G2, ProofAlgorithm::BLS12381_SHA256) => Ok(()), + (MemStoreKeyType::BLS12381G2, ProofAlgorithm::BLS12381_SHAKE256) => Ok(()), + (key_type, alg) => Err( + KeyStorageError::new(crate::key_storage::KeyStorageErrorKind::KeyAlgorithmMismatch) + .with_custom_message(format!("`cannot use key type `{key_type}` with algorithm `{alg}`")), + ), + } +} + /// JwkStorageExt implementation for JwkMemStore #[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))] #[cfg_attr(feature = "send-sync-storage", async_trait)] impl JwkStorageExt for JwkMemStore { - async fn generate_bbs_key(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult { - let keysubtype = - KeyPairSubtype::from_str(key_type.as_str()).map_err(|_| KeyStorageErrorKind::UnsupportedKeyType)?; + async fn generate_bbs(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult { + let key_type: MemStoreKeyType = MemStoreKeyType::try_from(&key_type)?; - let mut jwk = Jwk::try_from( - JwkExt::generate(keysubtype) - .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::RetryableIOFailure).with_source(err))?, - ) - .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::RetryableIOFailure).with_source(err))?; + check_key_proof_alg_compatibility(key_type, alg)?; + + let (private_key, public_key) = match key_type { + MemStoreKeyType::BLS12381G2 => { + match alg { + ProofAlgorithm::BLS12381_SHA256 => { + let keypair = KeyPair::::random() + .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(err))?; + let sk = keypair.private_key().clone(); + let pk = keypair.public_key().clone(); + (sk, pk) + }, + ProofAlgorithm::BLS12381_SHAKE256 => { + let keypair = KeyPair::::random() + .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(err))?; + let sk = keypair.private_key().clone(); + let pk = keypair.public_key().clone(); + (sk, pk) + }, + other => { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("{other} is not supported")), + ); + } + } + } + other => { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("{other} is not supported")), + ); + } + }; let kid: KeyId = random_key_id(); + let mut jwk: Jwk = encode_bls_jwk(&private_key, &public_key); jwk.set_alg(alg.to_string()); jwk.set_kid(jwk.thumbprint_sha256_b64()); let public_jwk: Jwk = jwk.to_public().expect("should only panic if kty == oct"); @@ -319,13 +381,13 @@ impl JwkStorageExt for JwkMemStore { Ok(JwkGenOutput::new(kid, public_jwk)) } - async fn generate_issuer_proof( + async fn sign_bbs( &self, key_id: &KeyId, - header: IssuerProtectedHeader, - claims: JptClaims, + data: &[Vec], + header: &[u8], public_key: &Jwk, - ) -> KeyStorageResult { + ) -> KeyStorageResult> { let jwk_store: RwLockReadGuard<'_, JwkKeyStore> = self.jwk_store.read().await; // Extract the required alg from the given public key @@ -365,25 +427,37 @@ impl JwkStorageExt for JwkMemStore { .get(key_id) .ok_or_else(|| KeyStorageError::new(KeyStorageErrorKind::KeyNotFound))?; - // Deserialize JSON to JwkExt - let jwk_ext: JwkExt = jwk.try_into().map_err(|_| KeyStorageErrorKind::SerializationError)?; + let (sk, pk) = expand_bls_jwk(jwk)?; - let jwp = JwpIssuedBuilder::new() - .issuer_protected_header(header) - .jpt_claims(claims) - .build(&jwk_ext) - .map_err(|_| KeyStorageErrorKind::Unspecified)? - .encode(SerializationType::COMPACT) - .map_err(|_| KeyStorageErrorKind::Unspecified)?; - - Ok(jwp) + + let signature = match alg { + ProofAlgorithm::BLS12381_SHA256 => { + Signature::::sign(Some(data), &sk, &pk, Some(header)).map(|s| s.to_bytes()) + }, + ProofAlgorithm::BLS12381_SHAKE256 => { + Signature::::sign(Some(data), &sk, &pk, Some(header)).map(|s| s.to_bytes()) + }, + other => { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm) + .with_custom_message(format!("{other} is not supported")), + ); + } + } + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message(format!("signature failed")) + })?; + + Ok(signature.to_vec()) } - async fn update_proof( + + async fn update_signature( &self, key_id: &KeyId, public_key: &Jwk, - proof: &[u8; BBSplusSignature::BYTES], + signature: &[u8; BBSplusSignature::BYTES], ctx: ProofUpdateCtx, ) -> KeyStorageResult<[u8; BBSplusSignature::BYTES]> { let jwk_store: RwLockReadGuard<'_, JwkKeyStore> = self.jwk_store.read().await; @@ -458,7 +532,7 @@ impl JwkStorageExt for JwkMemStore { let new_proof = match alg { ProofAlgorithm::BLS12381_SHA256 => { - let proof = Signature::::from_bytes(proof) + let signature = Signature::::from_bytes(signature) .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid"))? .update_signature( &sk, @@ -471,7 +545,7 @@ impl JwkStorageExt for JwkMemStore { .with_custom_message("Signature update failed") })?; - proof + signature .update_signature( &sk, &old_end_validity_timeframe, @@ -485,7 +559,7 @@ impl JwkStorageExt for JwkMemStore { .to_bytes() } ProofAlgorithm::BLS12381_SHAKE256 => { - let proof = Signature::::from_bytes(proof) + let proof = Signature::::from_bytes(signature) .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid"))? .update_signature( &sk, diff --git a/identity_storage/src/key_storage/mod.rs b/identity_storage/src/key_storage/mod.rs index 70006b0537..b5bcd5b47c 100644 --- a/identity_storage/src/key_storage/mod.rs +++ b/identity_storage/src/key_storage/mod.rs @@ -8,6 +8,8 @@ #[cfg(feature = "memstore")] mod ed25519; +#[cfg(feature = "memstore")] +mod bls; mod jwk_gen_output; mod jwk_storage; mod key_id; diff --git a/identity_storage/src/storage/jwp_document_ext.rs b/identity_storage/src/storage/jwp_document_ext.rs index b99f2f23a2..f69add1ef8 100644 --- a/identity_storage/src/storage/jwp_document_ext.rs +++ b/identity_storage/src/storage/jwp_document_ext.rs @@ -9,6 +9,7 @@ use crate::Storage; use crate::StorageResult; use async_trait::async_trait; use identity_core::common::Object; +use identity_core::convert::ToJson; use identity_credential::credential::Credential; use identity_credential::credential::Jpt; use identity_credential::credential::JwpCredentialOptions; @@ -25,6 +26,7 @@ use jsonprooftoken::jpt::claims::JptClaims; use jsonprooftoken::jwk::key::Jwk; use jsonprooftoken::jwp::header::IssuerProtectedHeader; use jsonprooftoken::jwp::header::PresentationProtectedHeader; +use jsonprooftoken::jwp::issued::JwpIssuedBuilder; use serde::de::DeserializeOwned; use serde::Serialize; @@ -99,7 +101,7 @@ generate_method_for_document_type!( CoreDocument, ProofAlgorithm, JwkStorageExt, - JwkStorageExt::generate_bbs_key, + JwkStorageExt::generate_bbs, generate_method_core_document ); @@ -163,17 +165,31 @@ impl JwpDocumentExt for CoreDocument { .await .map_err(Error::KeyIdStorageError)?; - let jwp = ::generate_issuer_proof( + let jwp_builder = JwpIssuedBuilder::new(issuer_header, jpt_claims.clone()); + + let header = jwp_builder.get_issuer_protected_header() + .map_or_else(|| Err(Error::JwpBuildingError), + |h| h.to_json_vec().map_err(|_| Error::JwpBuildingError))?; + + let data = jwp_builder.get_payloads() + .map_or_else(|| Err(Error::JwpBuildingError), + |p| p.to_bytes().map_err(|_| Error::JwpBuildingError))?; + + let signature = ::sign_bbs( storage.key_storage(), &key_id, - issuer_header, - jpt_claims.clone(), + &data, + &header, jwk, ) .await .map_err(Error::KeyStorageError)?; - Ok(jwp) + jwp_builder.build_with_proof(signature) + .map_err(|_| Error::JwpBuildingError)? + .encode(SerializationType::COMPACT) + .map_err(|err| Error::EncodingError(Box::new(err))) + } async fn create_presented_jwp( @@ -262,7 +278,7 @@ mod iota_document { IotaDocument, ProofAlgorithm, JwkStorageExt, - JwkStorageExt::generate_bbs_key, + JwkStorageExt::generate_bbs, generate_method_iota_document ); diff --git a/identity_storage/src/storage/timeframe_revocation_ext.rs b/identity_storage/src/storage/timeframe_revocation_ext.rs index d03b7d5d8d..7f14dcb1c8 100644 --- a/identity_storage/src/storage/timeframe_revocation_ext.rs +++ b/identity_storage/src/storage/timeframe_revocation_ext.rs @@ -147,7 +147,7 @@ impl TimeframeRevocationExtension for CoreDocument { number_of_signed_messages: payloads.0.len(), }; - let new_proof = ::update_proof(storage.key_storage(), &key_id, jwk, &proof, proof_update_ctx) + let new_proof = ::update_signature(storage.key_storage(), &key_id, jwk, &proof, proof_update_ctx) .await .map_err(Error::KeyStorageError)?; From a1de0865f9973db7c45ab03ddc6c879bfbb1c2c8 Mon Sep 17 00:00:00 2001 From: Alberto Solavagione Date: Fri, 5 Apr 2024 13:37:19 +0200 Subject: [PATCH 4/4] fix format --- identity_jose/src/jwk/curve/bls.rs | 14 +- identity_jose/src/jwk/curve/mod.rs | 4 +- identity_jose/src/jwk/jwk_ext.rs | 4 +- identity_storage/src/key_storage/bls.rs | 18 +-- .../src/key_storage/jwk_storage.rs | 12 +- identity_storage/src/key_storage/memstore.rs | 150 +++++++++--------- identity_storage/src/key_storage/mod.rs | 4 +- .../src/storage/jwp_document_ext.rs | 42 +++-- .../src/storage/timeframe_revocation_ext.rs | 7 +- 9 files changed, 127 insertions(+), 128 deletions(-) diff --git a/identity_jose/src/jwk/curve/bls.rs b/identity_jose/src/jwk/curve/bls.rs index a93e48b3e3..aa241bee21 100644 --- a/identity_jose/src/jwk/curve/bls.rs +++ b/identity_jose/src/jwk/curve/bls.rs @@ -7,13 +7,17 @@ use core::fmt::Result; /// [More Info](https://datatracker.ietf.org/doc/html/draft-ietf-cose-bls-key-representations-05#name-curve-parameter-registratio) #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum BlsCurve { - /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 12 with 381-bit p in the subgroup of G1. + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 12 with 381-bit p in the + /// subgroup of G1. BLS12381G1, - /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 12 with 381-bit p in the subgroup of G2. + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 12 with 381-bit p in the + /// subgroup of G2. BLS12381G2, - /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 48 with 581-bit p in the subgroup of G1. + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 48 with 581-bit p in the + /// subgroup of G1. BLS48581G1, - /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 48 with 581-bit p in the subgroup of G2. + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 48 with 581-bit p in the + /// subgroup of G2. BLS48581G2, } @@ -33,4 +37,4 @@ impl Display for BlsCurve { fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.write_str(self.name()) } -} \ No newline at end of file +} diff --git a/identity_jose/src/jwk/curve/mod.rs b/identity_jose/src/jwk/curve/mod.rs index d333ad879c..8e1627219f 100644 --- a/identity_jose/src/jwk/curve/mod.rs +++ b/identity_jose/src/jwk/curve/mod.rs @@ -1,12 +1,12 @@ // Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +mod bls; mod ec; mod ecx; mod ed; -mod bls; +pub use self::bls::*; pub use self::ec::*; pub use self::ecx::*; pub use self::ed::*; -pub use self::bls::*; \ No newline at end of file diff --git a/identity_jose/src/jwk/jwk_ext.rs b/identity_jose/src/jwk/jwk_ext.rs index 4b2c3b72fe..97f1d8a6f1 100644 --- a/identity_jose/src/jwk/jwk_ext.rs +++ b/identity_jose/src/jwk/jwk_ext.rs @@ -106,7 +106,7 @@ impl TryFrom for Jwk { let (kty, params) = match value.key_params { JwkAlgorithmParameters::EllipticCurve(p) => (JwkType::Ec, JwkParams::Ec(JwkParamsEc::from(p))), - _ => unreachable!() + _ => unreachable!(), }; Ok(Self { @@ -156,4 +156,4 @@ impl TryInto for &Jwk { key_params: params, }) } -} \ No newline at end of file +} diff --git a/identity_storage/src/key_storage/bls.rs b/identity_storage/src/key_storage/bls.rs index 148106578b..11d27f475d 100644 --- a/identity_storage/src/key_storage/bls.rs +++ b/identity_storage/src/key_storage/bls.rs @@ -1,4 +1,3 @@ - use identity_verification::jose::jwk::Jwk; use identity_verification::jose::jwu; use identity_verification::jwk::BlsCurve; @@ -38,11 +37,10 @@ pub(crate) fn expand_bls_jwk(jwk: &Jwk) -> KeyStorageResult<(BBSplusSecretKey, B .with_source(err) })? .map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("invalid BBS+ secret key")) + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!("invalid BBS+ secret key")) })?; - let x: [u8; BBSplusPublicKey::COORDINATE_LEN] = jwu::decode_b64(¶ms.x) + let x: [u8; BBSplusPublicKey::COORDINATE_LEN] = jwu::decode_b64(¶ms.x) .map_err(|err| { KeyStorageError::new(KeyStorageErrorKind::Unspecified) .with_custom_message("unable to decode `x` param") @@ -54,7 +52,7 @@ pub(crate) fn expand_bls_jwk(jwk: &Jwk) -> KeyStorageResult<(BBSplusSecretKey, B .with_custom_message(format!("expected key of length {}", BBSplusPublicKey::COORDINATE_LEN)) })?; - let y: [u8; BBSplusPublicKey::COORDINATE_LEN] = jwu::decode_b64(¶ms.y) + let y: [u8; BBSplusPublicKey::COORDINATE_LEN] = jwu::decode_b64(¶ms.y) .map_err(|err| { KeyStorageError::new(KeyStorageErrorKind::Unspecified) .with_custom_message("unable to decode `y` param") @@ -66,11 +64,9 @@ pub(crate) fn expand_bls_jwk(jwk: &Jwk) -> KeyStorageResult<(BBSplusSecretKey, B .with_custom_message(format!("expected key of length {}", BBSplusPublicKey::COORDINATE_LEN)) })?; - let pk = BBSplusPublicKey::from_coordinates(&x, &y) - .map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("invalid BBS+ public key")) - })?; + let pk = BBSplusPublicKey::from_coordinates(&x, &y).map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!("invalid BBS+ public key")) + })?; Ok((sk, pk)) } @@ -88,4 +84,4 @@ pub(crate) fn encode_bls_jwk(private_key: &BBSplusSecretKey, public_key: &BBSplu params.d = Some(d); params.crv = BlsCurve::BLS12381G2.name().to_owned(); Jwk::from_params(params) -} \ No newline at end of file +} diff --git a/identity_storage/src/key_storage/jwk_storage.rs b/identity_storage/src/key_storage/jwk_storage.rs index ee1048939d..1e0fa4055a 100644 --- a/identity_storage/src/key_storage/jwk_storage.rs +++ b/identity_storage/src/key_storage/jwk_storage.rs @@ -73,9 +73,15 @@ pub trait JwkStorageExt: JwkStorage { /// Generates a JWK representing a BBS+ signature async fn generate_bbs(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult; - /// Sign the provided `data` and `header` using the private key identified by `key_id` according to the requirements of - /// the corresponding `public_key` (see [`Jwk::alg`](Jwk::alg()) etc.). - async fn sign_bbs(&self, key_id: &KeyId, data: &[Vec], header: &[u8], public_key: &Jwk) -> KeyStorageResult>; + /// Sign the provided `data` and `header` using the private key identified by `key_id` according to the requirements + /// of the corresponding `public_key` (see [`Jwk::alg`](Jwk::alg()) etc.). + async fn sign_bbs( + &self, + key_id: &KeyId, + data: &[Vec], + header: &[u8], + public_key: &Jwk, + ) -> KeyStorageResult>; /// Update proof functionality for timeframe revocation mechanism async fn update_signature( diff --git a/identity_storage/src/key_storage/memstore.rs b/identity_storage/src/key_storage/memstore.rs index 2e204bb079..d264144a9a 100644 --- a/identity_storage/src/key_storage/memstore.rs +++ b/identity_storage/src/key_storage/memstore.rs @@ -213,7 +213,6 @@ impl JwkMemStore { const BLS12381G2_KEY_TYPE_STR: &'static str = "BLS12381G2"; /// The BLS12381G2 key type pub const BLS12381G2_KEY_TYPE: KeyType = KeyType::from_static_str(Self::BLS12381G2_KEY_TYPE_STR); - } impl MemStoreKeyType { @@ -336,30 +335,28 @@ impl JwkStorageExt for JwkMemStore { check_key_proof_alg_compatibility(key_type, alg)?; let (private_key, public_key) = match key_type { - MemStoreKeyType::BLS12381G2 => { - match alg { - ProofAlgorithm::BLS12381_SHA256 => { - let keypair = KeyPair::::random() + MemStoreKeyType::BLS12381G2 => match alg { + ProofAlgorithm::BLS12381_SHA256 => { + let keypair = KeyPair::::random() .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(err))?; - let sk = keypair.private_key().clone(); - let pk = keypair.public_key().clone(); - (sk, pk) - }, - ProofAlgorithm::BLS12381_SHAKE256 => { - let keypair = KeyPair::::random() + let sk = keypair.private_key().clone(); + let pk = keypair.public_key().clone(); + (sk, pk) + } + ProofAlgorithm::BLS12381_SHAKE256 => { + let keypair = KeyPair::::random() .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(err))?; - let sk = keypair.private_key().clone(); - let pk = keypair.public_key().clone(); - (sk, pk) - }, - other => { - return Err( - KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) - .with_custom_message(format!("{other} is not supported")), - ); - } + let sk = keypair.private_key().clone(); + let pk = keypair.public_key().clone(); + (sk, pk) } - } + other => { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("{other} is not supported")), + ); + } + }, other => { return Err( KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) @@ -429,14 +426,13 @@ impl JwkStorageExt for JwkMemStore { let (sk, pk) = expand_bls_jwk(jwk)?; - let signature = match alg { ProofAlgorithm::BLS12381_SHA256 => { Signature::::sign(Some(data), &sk, &pk, Some(header)).map(|s| s.to_bytes()) - }, + } ProofAlgorithm::BLS12381_SHAKE256 => { Signature::::sign(Some(data), &sk, &pk, Some(header)).map(|s| s.to_bytes()) - }, + } other => { return Err( KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm) @@ -445,14 +441,12 @@ impl JwkStorageExt for JwkMemStore { } } .map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("signature failed")) + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!("signature failed")) })?; - + Ok(signature.to_vec()) } - async fn update_signature( &self, key_id: &KeyId, @@ -525,65 +519,67 @@ impl JwkStorageExt for JwkMemStore { .with_custom_message("unable to decode `d` param") .with_source(err) })?, - ).map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("key not valid") - })?; + ) + .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("key not valid"))?; let new_proof = match alg { ProofAlgorithm::BLS12381_SHA256 => { let signature = Signature::::from_bytes(signature) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid"))? - .update_signature( - &sk, - &old_start_validity_timeframe, - &new_start_validity_timeframe, - index_start_validity_timeframe, - number_of_signed_messages, - ).map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("Signature update failed") - })?; + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid") + })? + .update_signature( + &sk, + &old_start_validity_timeframe, + &new_start_validity_timeframe, + index_start_validity_timeframe, + number_of_signed_messages, + ) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature update failed") + })?; signature - .update_signature( - &sk, - &old_end_validity_timeframe, - &new_end_validity_timeframe, - index_end_validity_timeframe, - number_of_signed_messages, - ).map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("Signature update failed") - })? - .to_bytes() + .update_signature( + &sk, + &old_end_validity_timeframe, + &new_end_validity_timeframe, + index_end_validity_timeframe, + number_of_signed_messages, + ) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature update failed") + })? + .to_bytes() } ProofAlgorithm::BLS12381_SHAKE256 => { let proof = Signature::::from_bytes(signature) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid"))? - .update_signature( - &sk, - &old_start_validity_timeframe, - &new_start_validity_timeframe, - index_start_validity_timeframe, - number_of_signed_messages, - ).map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("Signature update failed") - })?; + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid") + })? + .update_signature( + &sk, + &old_start_validity_timeframe, + &new_start_validity_timeframe, + index_start_validity_timeframe, + number_of_signed_messages, + ) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature update failed") + })?; proof - .update_signature( - &sk, - &old_end_validity_timeframe, - &new_end_validity_timeframe, - index_end_validity_timeframe, - number_of_signed_messages, - ).map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("Signature update failed") - })? - .to_bytes() + .update_signature( + &sk, + &old_end_validity_timeframe, + &new_end_validity_timeframe, + index_end_validity_timeframe, + number_of_signed_messages, + ) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature update failed") + })? + .to_bytes() } other => { return Err( diff --git a/identity_storage/src/key_storage/mod.rs b/identity_storage/src/key_storage/mod.rs index b5bcd5b47c..5daf049bbc 100644 --- a/identity_storage/src/key_storage/mod.rs +++ b/identity_storage/src/key_storage/mod.rs @@ -6,10 +6,10 @@ //! This module provides the [`JwkStorage`] trait that //! abstracts over storages that store JSON Web Keys. -#[cfg(feature = "memstore")] -mod ed25519; #[cfg(feature = "memstore")] mod bls; +#[cfg(feature = "memstore")] +mod ed25519; mod jwk_gen_output; mod jwk_storage; mod key_id; diff --git a/identity_storage/src/storage/jwp_document_ext.rs b/identity_storage/src/storage/jwp_document_ext.rs index f69add1ef8..5da1608af5 100644 --- a/identity_storage/src/storage/jwp_document_ext.rs +++ b/identity_storage/src/storage/jwp_document_ext.rs @@ -167,29 +167,25 @@ impl JwpDocumentExt for CoreDocument { let jwp_builder = JwpIssuedBuilder::new(issuer_header, jpt_claims.clone()); - let header = jwp_builder.get_issuer_protected_header() - .map_or_else(|| Err(Error::JwpBuildingError), - |h| h.to_json_vec().map_err(|_| Error::JwpBuildingError))?; - - let data = jwp_builder.get_payloads() - .map_or_else(|| Err(Error::JwpBuildingError), - |p| p.to_bytes().map_err(|_| Error::JwpBuildingError))?; - - let signature = ::sign_bbs( - storage.key_storage(), - &key_id, - &data, - &header, - jwk, - ) - .await - .map_err(Error::KeyStorageError)?; - - jwp_builder.build_with_proof(signature) - .map_err(|_| Error::JwpBuildingError)? - .encode(SerializationType::COMPACT) - .map_err(|err| Error::EncodingError(Box::new(err))) - + let header = jwp_builder.get_issuer_protected_header().map_or_else( + || Err(Error::JwpBuildingError), + |h| h.to_json_vec().map_err(|_| Error::JwpBuildingError), + )?; + + let data = jwp_builder.get_payloads().map_or_else( + || Err(Error::JwpBuildingError), + |p| p.to_bytes().map_err(|_| Error::JwpBuildingError), + )?; + + let signature = ::sign_bbs(storage.key_storage(), &key_id, &data, &header, jwk) + .await + .map_err(Error::KeyStorageError)?; + + jwp_builder + .build_with_proof(signature) + .map_err(|_| Error::JwpBuildingError)? + .encode(SerializationType::COMPACT) + .map_err(|err| Error::EncodingError(Box::new(err))) } async fn create_presented_jwp( diff --git a/identity_storage/src/storage/timeframe_revocation_ext.rs b/identity_storage/src/storage/timeframe_revocation_ext.rs index 7f14dcb1c8..766eff7acc 100644 --- a/identity_storage/src/storage/timeframe_revocation_ext.rs +++ b/identity_storage/src/storage/timeframe_revocation_ext.rs @@ -147,9 +147,10 @@ impl TimeframeRevocationExtension for CoreDocument { number_of_signed_messages: payloads.0.len(), }; - let new_proof = ::update_signature(storage.key_storage(), &key_id, jwk, &proof, proof_update_ctx) - .await - .map_err(Error::KeyStorageError)?; + let new_proof = + ::update_signature(storage.key_storage(), &key_id, jwk, &proof, proof_update_ctx) + .await + .map_err(Error::KeyStorageError)?; credential_jwp.set_proof(&new_proof); credential_jwp.set_payloads(payloads);