diff --git a/bindings/wasm/src/storage/jwk_storage_bbs_plus_ext.rs b/bindings/wasm/src/storage/jwk_storage_bbs_plus_ext.rs index fb2c5a322e..c6d57444a0 100644 --- a/bindings/wasm/src/storage/jwk_storage_bbs_plus_ext.rs +++ b/bindings/wasm/src/storage/jwk_storage_bbs_plus_ext.rs @@ -9,6 +9,11 @@ use super::WasmJwkGenOutput; use super::WasmJwkStorage; use super::WasmProofUpdateCtx; +use identity_iota::storage::bls::encode_bls_jwk; +use identity_iota::storage::bls::expand_bls_jwk; +use identity_iota::storage::bls::generate_bbs_keypair; +use identity_iota::storage::bls::sign_bbs; +use identity_iota::storage::bls::update_bbs_signature; use identity_iota::storage::JwkGenOutput; use identity_iota::storage::JwkStorage; use identity_iota::storage::JwkStorageBbsPlusExt; @@ -18,169 +23,10 @@ use identity_iota::storage::KeyStorageErrorKind; use identity_iota::storage::KeyStorageResult; use identity_iota::storage::KeyType; use identity_iota::storage::ProofUpdateCtx; -use identity_iota::verification::jwk::BlsCurve; use identity_iota::verification::jwk::Jwk; -use identity_iota::verification::jwk::JwkParamsEc; -use identity_iota::verification::jwu; use jsonprooftoken::jpa::algs::ProofAlgorithm; use wasm_bindgen::prelude::*; -use zkryptium::bbsplus::ciphersuites::BbsCiphersuite; -use zkryptium::bbsplus::ciphersuites::Bls12381Sha256; -use zkryptium::bbsplus::ciphersuites::Bls12381Shake256; -use zkryptium::bbsplus::keys::BBSplusPublicKey; -use zkryptium::bbsplus::keys::BBSplusSecretKey; use zkryptium::bbsplus::signature::BBSplusSignature; -use zkryptium::keys::pair::KeyPair; -use zkryptium::schemes::algorithms::BBSplus; -use zkryptium::schemes::algorithms::BbsBls12381Sha256; -use zkryptium::schemes::algorithms::BbsBls12381Shake256; -use zkryptium::schemes::generics::Signature; - -fn generate_bbs_keypair() -> Result<(BBSplusSecretKey, BBSplusPublicKey), KeyStorageError> { - 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(); - Ok((sk, pk)) -} - -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) -} - -fn expand_bls_jwk(jwk: &Jwk) -> Result<(BBSplusSecretKey, BBSplusPublicKey), KeyStorageError> { - 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("invalid BBS+ secret key".to_owned()) - })?; - - 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("invalid BBS+ public key".to_owned()) - })?; - - Ok((sk, pk)) -} - -fn update_bbs_signature( - sig: &[u8; 80], - sk: &BBSplusSecretKey, - update_ctx: &ProofUpdateCtx, -) -> Result<[u8; 80], KeyStorageError> -where - A: BbsCiphersuite, -{ - let sig = Signature::>::from_bytes(sig) - .map_err(|e| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(e))?; - let ProofUpdateCtx { - old_start_validity_timeframe, - new_start_validity_timeframe, - old_end_validity_timeframe, - new_end_validity_timeframe, - index_start_validity_timeframe, - index_end_validity_timeframe, - number_of_signed_messages, - } = update_ctx; - let half_updated = sig - .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") - })?; - half_updated - .update_signature( - sk, - old_end_validity_timeframe, - new_end_validity_timeframe, - *index_end_validity_timeframe, - *number_of_signed_messages, - ) - .map(|sig| sig.to_bytes()) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature update failed")) -} - -fn decode_sk_jwt(jwk: &Jwk) -> Result { - let params = jwk.try_ec_params().map_err(|_| KeyStorageErrorKind::Unspecified)?; - BBSplusSecretKey::from_bytes( - ¶ms - .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_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("key not valid")) -} #[wasm_bindgen(js_class = JwkStorage)] impl WasmJwkStorage { @@ -235,20 +81,9 @@ impl WasmJwkStorage { #[async_trait::async_trait(?Send)] impl JwkStorageBbsPlusExt for WasmJwkStorage { async fn generate_bbs(&self, _key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult { - let (sk, pk) = match alg { - ProofAlgorithm::BLS12381_SHA256 => generate_bbs_keypair::(), - ProofAlgorithm::BLS12381_SHAKE256 => generate_bbs_keypair::(), - other => Err( - KeyStorageError::new(KeyStorageErrorKind::KeyAlgorithmMismatch) - .with_custom_message(format!("cannot validate proof with {}", other)), - ), - }?; + let (sk, pk) = generate_bbs_keypair(alg)?; - let mut jwk = encode_bls_jwk(&sk, &pk); - jwk.set_alg(alg.to_string()); - jwk.set_kid(jwk.thumbprint_sha256_b64()); - - let public_jwk = jwk.to_public().expect("kty != oct"); + let (jwk, public_jwk) = encode_bls_jwk(&sk, &pk, alg); let kid = ::insert(self, jwk).await?; Ok(JwkGenOutput::new(kid, public_jwk)) @@ -267,48 +102,12 @@ impl JwkStorageBbsPlusExt for WasmJwkStorage { let alg = public_key .alg() .ok_or(KeyStorageErrorKind::UnsupportedProofAlgorithm) - .and_then(|alg_str| ProofAlgorithm::from_str(alg_str).map_err(|_| KeyStorageErrorKind::UnsupportedProofAlgorithm)) - .map_err(KeyStorageError::new)?; - - if matches!(alg, ProofAlgorithm::BLS12381_SHA256 | ProofAlgorithm::BLS12381_SHAKE256) { - let ec_params = public_key.try_ec_params().map_err(|err| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("expected a Jwk with EC params in order to sign with {alg}")) - .with_source(err) + .and_then(|alg_str| { + ProofAlgorithm::from_str(alg_str).map_err(|_| KeyStorageErrorKind::UnsupportedProofAlgorithm) })?; - if ec_params.crv != BlsCurve::BLS12381G2.to_string() { - return Err( - KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!( - "expected Jwk with EC {} crv in order to generate the proof with {alg}", - BlsCurve::BLS12381G2 - )), - ); - } - } else { - return Err( - KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm) - .with_custom_message(format!("{alg} is not supported")), - ); - } + let (sk, pk) = expand_bls_jwk(&private_jwk)?; - 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(|bytes| bytes.to_vec()) - .map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("signature failed".to_owned()) - }) + sign_bbs(alg, data, &sk.expect("jwk was private"), &pk, header) } async fn update_signature( &self, @@ -321,37 +120,14 @@ impl JwkStorageBbsPlusExt for WasmJwkStorage { let alg = public_key .alg() .ok_or(KeyStorageErrorKind::UnsupportedProofAlgorithm) - .and_then(|alg_str| ProofAlgorithm::from_str(alg_str).map_err(|_| KeyStorageErrorKind::UnsupportedProofAlgorithm)) - .map_err(KeyStorageError::new)?; - - if matches!(alg, ProofAlgorithm::BLS12381_SHA256 | ProofAlgorithm::BLS12381_SHAKE256) { - let ec_params = public_key.try_ec_params().map_err(|err| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("expected a Jwk with EC params in order to sign with {alg}")) - .with_source(err) + .and_then(|alg_str| { + ProofAlgorithm::from_str(alg_str).map_err(|_| KeyStorageErrorKind::UnsupportedProofAlgorithm) })?; - if ec_params.crv != BlsCurve::BLS12381G2.to_string() { - return Err( - KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!( - "expected Jwk with EC {} crv in order to generate the proof with {alg}", - BlsCurve::BLS12381G2 - )), - ); - } - } else { - return Err( - KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm) - .with_custom_message(format!("{alg} is not supported")), - ); - } + let Some(private_jwk) = WasmJwkStorage::_get_key(self, key_id.as_str()).map(Jwk::from) else { return Err(KeyStorageError::new(KeyStorageErrorKind::KeyNotFound)); }; - let sk = decode_sk_jwt(&private_jwk)?; - match alg { - ProofAlgorithm::BLS12381_SHA256 => update_bbs_signature::(signature, &sk, &ctx), - ProofAlgorithm::BLS12381_SHAKE256 => update_bbs_signature::(signature, &sk, &ctx), - _ => unreachable!(), - } + let sk = expand_bls_jwk(&private_jwk)?.0.expect("jwk is private"); + update_bbs_signature(alg, signature, &sk, &ctx) } } diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 843bf10cff..31e6191978 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -9,7 +9,7 @@ publish = false anyhow = "1.0.62" identity_eddsa_verifier = { path = "../identity_eddsa_verifier", default-features = false } identity_iota = { path = "../identity_iota", default-features = false, features = ["iota-client", "client", "memstore", "domain-linkage", "revocation-bitmap", "status-list-2021", "jpt-bbs-plus"] } -identity_stronghold = { path = "../identity_stronghold", default-features = false } +identity_stronghold = { path = "../identity_stronghold", default-features = false, features = ["bbs-plus"] } iota-sdk = { version = "1.0", default-features = false, features = ["tls", "client", "stronghold"] } json-proof-token.workspace = true primitive-types = "0.12.1" diff --git a/identity_iota/src/lib.rs b/identity_iota/src/lib.rs index 24a20359eb..bd067bd13b 100644 --- a/identity_iota/src/lib.rs +++ b/identity_iota/src/lib.rs @@ -105,7 +105,21 @@ pub mod verification { pub mod storage { //! Storage traits. - pub use identity_storage::*; + /// KeyIdStorage types and functionalities. + pub mod key_id_storage { + pub use identity_storage::key_id_storage::*; + } + /// KeyStorage types and functionalities. + pub mod key_storage { + pub use identity_storage::key_storage::public_modules::*; + } + /// Storage types and functionalities. + pub mod storage { + pub use identity_storage::storage::*; + } + pub use identity_storage::key_id_storage::*; + pub use identity_storage::key_storage::*; + pub use identity_storage::storage::*; } #[cfg(feature = "sd-jwt")] diff --git a/identity_storage/Cargo.toml b/identity_storage/Cargo.toml index e8bc5ec654..9e07433f74 100644 --- a/identity_storage/Cargo.toml +++ b/identity_storage/Cargo.toml @@ -29,6 +29,7 @@ thiserror.workspace = true tokio = { version = "1.29.0", default-features = false, features = ["macros", "sync"], optional = true } zkryptium = { workspace = true, optional = true } json-proof-token = { workspace = true, optional = true } +anyhow = "1.0.82" [dev-dependencies] identity_credential = { version = "=1.1.1", path = "../identity_credential", features = ["revocation-bitmap"] } diff --git a/identity_storage/src/key_storage/bls.rs b/identity_storage/src/key_storage/bls.rs index bf92959694..7cb6cee2de 100644 --- a/identity_storage/src/key_storage/bls.rs +++ b/identity_storage/src/key_storage/bls.rs @@ -1,87 +1,190 @@ +use anyhow::Context; use identity_verification::jose::jwk::Jwk; use identity_verification::jose::jwu; use identity_verification::jwk::BlsCurve; use identity_verification::jwk::JwkParamsEc; +use jsonprooftoken::jpa::algs::ProofAlgorithm; +use zkryptium::bbsplus::ciphersuites::BbsCiphersuite; +use zkryptium::bbsplus::ciphersuites::Bls12381Sha256; +use zkryptium::bbsplus::ciphersuites::Bls12381Shake256; use zkryptium::bbsplus::keys::BBSplusPublicKey; use zkryptium::bbsplus::keys::BBSplusSecretKey; +use zkryptium::keys::pair::KeyPair; +use zkryptium::schemes::algorithms::BBSplus; +use zkryptium::schemes::generics::Signature; use crate::key_storage::KeyStorageError; use crate::key_storage::KeyStorageErrorKind; use crate::key_storage::KeyStorageResult; +use crate::ProofUpdateCtx; -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())), - ); +fn random_bbs_keypair() -> Result<(BBSplusSecretKey, BBSplusPublicKey), zkryptium::errors::Error> +where + S: BbsCiphersuite, +{ + let key_pair = KeyPair::>::random()?; + Ok((key_pair.private_key().clone(), key_pair.public_key().clone())) +} + +/// Generates a new BBS+ keypair using either `BLS12381-SHA256` or `BLS12381-SHAKE256`. +pub fn generate_bbs_keypair(alg: ProofAlgorithm) -> KeyStorageResult<(BBSplusSecretKey, BBSplusPublicKey)> { + match alg { + ProofAlgorithm::BLS12381_SHA256 => random_bbs_keypair::(), + ProofAlgorithm::BLS12381_SHAKE256 => random_bbs_keypair::(), + _ => return Err(KeyStorageErrorKind::UnsupportedProofAlgorithm.into()), } + .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(err)) +} + +/// Encodes a private BBS+ key into JWK. +pub fn encode_bls_jwk( + private_key: &BBSplusSecretKey, + public_key: &BBSplusPublicKey, + alg: ProofAlgorithm, +) -> (Jwk, 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 params = JwkParamsEc { + x, + y, + d: Some(d), + crv: BlsCurve::BLS12381G2.name().to_owned(), + }; + + let mut jwk = Jwk::from_params(params); + + jwk.set_alg(alg.to_string()); + jwk.set_kid(jwk.thumbprint_sha256_b64()); + let public_jwk = jwk.to_public().expect("kty != oct"); + + (jwk, public_jwk) +} + +/// Attempts to decode JWK into a BBS+ keypair. +pub fn expand_bls_jwk(jwk: &Jwk) -> KeyStorageResult<(Option, BBSplusPublicKey)> { + // Check the provided JWK represents a BLS12381G2 key. + let params = jwk + .try_ec_params() + .ok() + .filter(|params| params.try_bls_curve().is_ok_and(|curve| curve == BlsCurve::BLS12381G2)) + .context(format!("not a {} curve key", BlsCurve::BLS12381G2)) + .map_err(|e| KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType).with_source(e))?; - let sk: BBSplusSecretKey = params + let sk = 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("invalid BBS+ secret key".to_owned()) - })?; - - 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("invalid BBS+ public key".to_owned()) + .map(|d| { + jwu::decode_b64(d) + .context("`d` parameter is not base64 encoded") + .and_then(|bytes| BBSplusSecretKey::from_bytes(&bytes).context("invalid key size")) + }) + .transpose() + .map_err(|e| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(e))?; + + let x = jwu::decode_b64(¶ms.x) + .context("`x` parameter is not base64 encoded") + .and_then(|bytes| bytes.try_into().ok().context("invalid coordinate size")) + .map_err(|e| KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType).with_source(e))?; + let y = jwu::decode_b64(¶ms.y) + .context("`y` parameter is not base64 encoded") + .and_then(|bytes| bytes.try_into().ok().context("invalid coordinate size")) + .map_err(|e| KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType).with_source(e))?; + + let pk = BBSplusPublicKey::from_coordinates(&x, &y).map_err(|e| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_source(e) + .with_custom_message("invalid BBS+ public key".to_owned()) })?; 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); +fn _sign_bbs( + data: &[Vec], + sk: &BBSplusSecretKey, + pk: &BBSplusPublicKey, + header: &[u8], +) -> Result, zkryptium::errors::Error> +where + S: BbsCiphersuite, +{ + Signature::>::sign(Some(data), &sk, &pk, Some(header)).map(|s| s.to_bytes().to_vec()) +} - 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) +/// Signs data and header using the given keys. +pub fn sign_bbs( + alg: ProofAlgorithm, + data: &[Vec], + sk: &BBSplusSecretKey, + pk: &BBSplusPublicKey, + header: &[u8], +) -> KeyStorageResult> { + match alg { + ProofAlgorithm::BLS12381_SHA256 => _sign_bbs::(data, sk, pk, header), + ProofAlgorithm::BLS12381_SHAKE256 => _sign_bbs::(data, sk, pk, header), + _ => return Err(KeyStorageErrorKind::UnsupportedProofAlgorithm.into()), + } + .map_err(|e| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_source(e) + .with_custom_message("signature failed".to_owned()) + }) +} + +fn _update_bbs_signature( + sig: &[u8; 80], + sk: &BBSplusSecretKey, + update_ctx: &ProofUpdateCtx, +) -> Result<[u8; 80], zkryptium::errors::Error> +where + S: BbsCiphersuite, +{ + let sig = Signature::>::from_bytes(sig)?; + let ProofUpdateCtx { + old_start_validity_timeframe, + new_start_validity_timeframe, + old_end_validity_timeframe, + new_end_validity_timeframe, + index_start_validity_timeframe, + index_end_validity_timeframe, + number_of_signed_messages, + } = update_ctx; + let half_updated = sig.update_signature( + sk, + old_start_validity_timeframe, + new_start_validity_timeframe, + *index_start_validity_timeframe, + *number_of_signed_messages, + )?; + half_updated + .update_signature( + sk, + old_end_validity_timeframe, + new_end_validity_timeframe, + *index_end_validity_timeframe, + *number_of_signed_messages, + ) + .map(|sig| sig.to_bytes()) +} + +/// Updates BBS+ signature's timeframe data. +pub fn update_bbs_signature( + alg: ProofAlgorithm, + sig: &[u8; 80], + sk: &BBSplusSecretKey, + update_ctx: &ProofUpdateCtx, +) -> Result<[u8; 80], KeyStorageError> { + match alg { + ProofAlgorithm::BLS12381_SHA256 => _update_bbs_signature::(sig, sk, update_ctx), + ProofAlgorithm::BLS12381_SHAKE256 => _update_bbs_signature::(sig, sk, update_ctx), + _ => return Err(KeyStorageErrorKind::UnsupportedProofAlgorithm.into()), + } + .map_err(|e| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("signature failed") + .with_source(e) + }) } diff --git a/identity_storage/src/key_storage/memstore.rs b/identity_storage/src/key_storage/memstore.rs index 815cb35741..d9a65ae818 100644 --- a/identity_storage/src/key_storage/memstore.rs +++ b/identity_storage/src/key_storage/memstore.rs @@ -206,8 +206,8 @@ impl JwkMemStore { impl MemStoreKeyType { const fn name(&self) -> &'static str { match self { - MemStoreKeyType::Ed25519 => "Ed25519", - MemStoreKeyType::BLS12381G2 => "BLS12381G2", + MemStoreKeyType::Ed25519 => JwkMemStore::ED25519_KEY_TYPE_STR, + MemStoreKeyType::BLS12381G2 => JwkMemStore::BLS12381G2_KEY_TYPE_STR, } } } @@ -307,6 +307,9 @@ mod bbs_plus_impl { use crate::key_storage::bls::encode_bls_jwk; use crate::key_storage::bls::expand_bls_jwk; + use crate::key_storage::bls::generate_bbs_keypair; + use crate::key_storage::bls::sign_bbs; + use crate::key_storage::bls::update_bbs_signature; use crate::JwkGenOutput; use crate::JwkMemStore; use crate::JwkStorageBbsPlusExt; @@ -319,77 +322,27 @@ mod bbs_plus_impl { use async_trait::async_trait; use identity_verification::jwk::BlsCurve; use identity_verification::jwk::Jwk; - use identity_verification::jwu; use jsonprooftoken::jpa::algs::ProofAlgorithm; - 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::random_key_id; - use super::MemStoreKeyType; - - /// 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}`")), - ), - } - } /// JwkStorageBbsPlusExt implementation for JwkMemStore #[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))] #[cfg_attr(feature = "send-sync-storage", async_trait)] impl JwkStorageBbsPlusExt for JwkMemStore { async fn generate_bbs(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult { - let key_type: MemStoreKeyType = MemStoreKeyType::try_from(&key_type)?; - - 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(); + if key_type != JwkMemStore::BLS12381G2_KEY_TYPE { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("unsupported key type {key_type}")), + ); + } - 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"); + let (private_key, public_key) = generate_bbs_keypair(alg)?; + let (jwk, public_jwk) = encode_bls_jwk(&private_key, &public_key, alg); + let kid: KeyId = random_key_id(); let mut jwk_store = self.jwk_store.write().await; jwk_store.insert(kid.clone(), jwk); @@ -408,61 +361,25 @@ mod bbs_plus_impl { // Extract the required alg from the given public key let alg = public_key .alg() - .ok_or(KeyStorageErrorKind::UnsupportedProofAlgorithm) - .and_then(|alg_str| { - ProofAlgorithm::from_str(alg_str).map_err(|_| KeyStorageErrorKind::UnsupportedProofAlgorithm) - })?; - - match alg { - ProofAlgorithm::BLS12381_SHA256 | ProofAlgorithm::BLS12381_SHAKE256 => { - let ec_params = public_key.try_ec_params().map_err(|err| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("expected a Jwk with EC params in order to sign with {alg}")) - .with_source(err) - })?; - if ec_params.crv != BlsCurve::BLS12381G2.to_string() { - return Err( - KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!( - "expected Jwk with EC {} crv in order to generate the proof with {alg}", - BlsCurve::BLS12381G2 - )), - ); - } - } - other => { - return Err( - KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm) - .with_custom_message(format!("{other} is not supported")), - ); - } + .and_then(|alg_str| ProofAlgorithm::from_str(alg_str).ok()) + .ok_or(KeyStorageErrorKind::UnsupportedProofAlgorithm)?; + + // Check the provided JWK represents a BLS12381G2 key. + if !public_key + .try_ec_params() + .is_ok_and(|ec| ec.crv == BlsCurve::BLS12381G2.to_string()) + { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("expected a key from the {} curve", BlsCurve::BLS12381G2)), + ); } - // Obtain the corresponding private key and sign `data`. - let jwk: &Jwk = jwk_store - .get(key_id) - .ok_or_else(|| KeyStorageError::new(KeyStorageErrorKind::KeyNotFound))?; - + // Obtain the corresponding private key. + let jwk: &Jwk = jwk_store.get(key_id).ok_or(KeyStorageErrorKind::KeyNotFound)?; 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) - .with_custom_message(format!("{other} is not supported")), - ); - } - } - .map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("signature failed".to_owned()) - })?; - - Ok(signature.to_vec()) + sign_bbs(alg, data, &sk.expect("jwk is private"), &pk, header) } async fn update_signature( @@ -474,16 +391,6 @@ mod bbs_plus_impl { ) -> KeyStorageResult<[u8; BBSplusSignature::BYTES]> { let jwk_store = self.jwk_store.read().await; - let ProofUpdateCtx { - old_start_validity_timeframe, - new_start_validity_timeframe, - old_end_validity_timeframe, - new_end_validity_timeframe, - index_start_validity_timeframe, - index_end_validity_timeframe, - number_of_signed_messages, - } = ctx; - // Extract the required alg from the given public key let alg = public_key .alg() @@ -492,122 +399,23 @@ mod bbs_plus_impl { ProofAlgorithm::from_str(alg_str).map_err(|_| KeyStorageErrorKind::UnsupportedProofAlgorithm) })?; - match alg { - ProofAlgorithm::BLS12381_SHA256 | ProofAlgorithm::BLS12381_SHAKE256 => { - let ec_params = public_key.try_ec_params().map_err(|err| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("expected a Jwk with EC params in order to sign with {alg}")) - .with_source(err) - })?; - if ec_params.crv != BlsCurve::BLS12381G2.to_string() { - return Err( - KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!( - "expected Jwk with EC {} crv in order to generate the proof with {alg}", - BlsCurve::BLS12381G2 - )), - ); - } - } - other => { - return Err( - KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm) - .with_custom_message(format!("{other} is not supported")), - ); - } + // Check the provided JWK represents a BLS12381G2 key. + if !public_key + .try_ec_params() + .is_ok_and(|ec| ec.crv == BlsCurve::BLS12381G2.to_string()) + { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("expected a key from the {} curve", BlsCurve::BLS12381G2)), + ); } - // Obtain the corresponding private key and sign `data`. - let jwk: &Jwk = jwk_store - .get(key_id) - .ok_or_else(|| KeyStorageError::new(KeyStorageErrorKind::KeyNotFound))?; - - let params = jwk.try_ec_params().map_err(|_| KeyStorageErrorKind::Unspecified)?; - - let sk = BBSplusSecretKey::from_bytes( - ¶ms - .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_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("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") - })?; - - 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() - } - 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") - })?; - - 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() - } - other => { - return Err( - KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm) - .with_custom_message(format!("{other} is not supported")), - ); - } - }; + // Obtain the corresponding private key. + let jwk = jwk_store.get(key_id).ok_or(KeyStorageErrorKind::KeyNotFound)?; + let sk = expand_bls_jwk(jwk)?.0.expect("jwk is private"); - Ok(new_proof) + // Update the signature. + update_bbs_signature(alg, signature, &sk, &ctx) } } } diff --git a/identity_storage/src/key_storage/mod.rs b/identity_storage/src/key_storage/mod.rs index 72047e70c6..f54f9d5233 100644 --- a/identity_storage/src/key_storage/mod.rs +++ b/identity_storage/src/key_storage/mod.rs @@ -6,8 +6,9 @@ //! This module provides the [`JwkStorage`] trait that //! abstracts over storages that store JSON Web Keys. -#[cfg(all(feature = "memstore", feature = "jpt-bbs-plus"))] -mod bls; +#[cfg(feature = "jpt-bbs-plus")] +/// BLS12381 utils. +pub mod bls; #[cfg(feature = "memstore")] mod ed25519; mod jwk_gen_output; @@ -23,12 +24,17 @@ mod memstore; #[cfg(test)] pub(crate) mod tests; -pub use jwk_gen_output::*; -pub use jwk_storage::*; -#[cfg(feature = "jpt-bbs-plus")] -pub use jwk_storage_bbs_plus_ext::*; -pub use key_id::*; -pub use key_storage_error::*; -pub use key_type::*; -#[cfg(feature = "memstore")] -pub use memstore::*; +/// All modules that should be made available to end-users. +pub mod public_modules { + pub use super::jwk_gen_output::*; + pub use super::jwk_storage::*; + #[cfg(feature = "jpt-bbs-plus")] + pub use super::jwk_storage_bbs_plus_ext::*; + pub use super::key_id::*; + pub use super::key_storage_error::*; + pub use super::key_type::*; + #[cfg(feature = "memstore")] + pub use super::memstore::*; +} + +pub use public_modules::*; diff --git a/identity_storage/src/lib.rs b/identity_storage/src/lib.rs index da1b0b66f4..643e1e7444 100644 --- a/identity_storage/src/lib.rs +++ b/identity_storage/src/lib.rs @@ -19,5 +19,5 @@ pub mod key_storage; pub mod storage; pub use key_id_storage::*; -pub use key_storage::*; +pub use key_storage::public_modules::*; pub use storage::*; diff --git a/identity_stronghold/src/stronghold_jwk_storage_ext.rs b/identity_stronghold/src/stronghold_jwk_storage_ext.rs index 730226452a..b27be8f4cb 100644 --- a/identity_stronghold/src/stronghold_jwk_storage_ext.rs +++ b/identity_stronghold/src/stronghold_jwk_storage_ext.rs @@ -3,8 +3,8 @@ //! Wrapper around [`StrongholdSecretManager`](StrongholdSecretManager). -use anyhow::Context; use async_trait::async_trait; +use identity_storage::key_storage::bls::*; use identity_storage::key_storage::JwkStorage; use identity_storage::JwkGenOutput; use identity_storage::JwkStorageBbsPlusExt; @@ -14,10 +14,7 @@ use identity_storage::KeyStorageErrorKind; use identity_storage::KeyStorageResult; use identity_storage::KeyType; use identity_storage::ProofUpdateCtx; -use identity_verification::jwk::BlsCurve; use identity_verification::jwk::Jwk; -use identity_verification::jwk::JwkParamsEc; -use identity_verification::jwu; use iota_stronghold::procedures::FatalProcedureError; use iota_stronghold::procedures::Products; use iota_stronghold::procedures::Runner as _; @@ -25,13 +22,8 @@ use iota_stronghold::Location; use jsonprooftoken::jpa::algs::ProofAlgorithm; use std::str::FromStr; use zeroize::Zeroizing; -use zkryptium::bbsplus::keys::BBSplusPublicKey; 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 crate::stronghold_key_type::*; use crate::utils::*; @@ -60,12 +52,8 @@ impl JwkStorageBbsPlusExt for StrongholdStorage { ); let jwk = client .exec_proc([], &target_key_location, |_| { - let (sk, pk) = generate_bbs_plus_key_pair(alg).map_err(|e| FatalProcedureError::from(e.to_string()))?; - let mut jwk = encode_bls_jwk(&sk, &pk); - jwk.set_alg(alg.to_string()); - jwk.set_kid(jwk.thumbprint_sha256_b64()); - // Safety: jkw.kty can only be "ec". - let public_jwk = jwk.to_public().expect("should only panic if kty == oct"); + let (sk, pk) = generate_bbs_keypair(alg).map_err(|e| FatalProcedureError::from(e.to_string()))?; + let public_jwk = encode_bls_jwk(&sk, &pk, alg).1; Ok(Products { output: public_jwk, @@ -101,34 +89,14 @@ impl JwkStorageBbsPlusExt for StrongholdStorage { ProofAlgorithm::from_str(alg_str).map_err(|_| KeyStorageErrorKind::UnsupportedProofAlgorithm) })?; - if matches!(alg, ProofAlgorithm::BLS12381_SHA256 | ProofAlgorithm::BLS12381_SHAKE256) { - let ec_params = public_key.try_ec_params().map_err(|err| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("expected a Jwk with EC params in order to sign with {alg}")) - .with_source(err) - })?; - if ec_params.crv != BlsCurve::BLS12381G2.to_string() { - return Err( - KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!( - "expected Jwk with EC {} crv in order to generate the proof with {alg}", - BlsCurve::BLS12381G2 - )), - ); - } - } else { - return Err( - KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm) - .with_custom_message(format!("{alg} is not supported")), - ); - } - // Check `key_id` exists in store. if !self.exists(key_id).await? { return Err(KeyStorageError::new(KeyStorageErrorKind::KeyNotFound)); } - let pk = jwk_to_bbs_plus_pk(public_key) - .map_err(|e| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(e))?; + let pk = expand_bls_jwk(public_key) + .map_err(|e| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(e))? + .1; let sk_location = Location::Generic { vault_path: IDENTITY_VAULT_PATH.as_bytes().to_vec(), @@ -138,18 +106,7 @@ impl JwkStorageBbsPlusExt for StrongholdStorage { client .get_guards([sk_location], |[sk]| { let sk = BBSplusSecretKey::from_bytes(&sk.borrow()).map_err(|e| FatalProcedureError::from(e.to_string()))?; - let signature_result = 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()) - } - // Safety: Already checked it's either of the two handled variants - _ => unreachable!(), - } - .map_err(|e| FatalProcedureError::from(e.to_string()))?; - Ok(signature_result) + sign_bbs(alg, data, &sk, &pk, header).map_err(|e| FatalProcedureError::from(e.to_string())) }) .map(|sig| sig.to_vec()) .map_err(|e| { @@ -169,16 +126,6 @@ impl JwkStorageBbsPlusExt for StrongholdStorage { let stronghold = self.get_stronghold().await; let client = get_client(&stronghold)?; - let ProofUpdateCtx { - old_start_validity_timeframe, - new_start_validity_timeframe, - old_end_validity_timeframe, - new_end_validity_timeframe, - index_start_validity_timeframe, - index_end_validity_timeframe, - number_of_signed_messages, - } = ctx; - // Extract the required alg from the given public key let alg = public_key .alg() @@ -187,27 +134,6 @@ impl JwkStorageBbsPlusExt for StrongholdStorage { ProofAlgorithm::from_str(alg_str).map_err(|_| KeyStorageErrorKind::UnsupportedProofAlgorithm) })?; - if matches!(alg, ProofAlgorithm::BLS12381_SHA256 | ProofAlgorithm::BLS12381_SHAKE256) { - let ec_params = public_key.try_ec_params().map_err(|err| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message(format!("expected a Jwk with EC params in order to sign with {alg}")) - .with_source(err) - })?; - if ec_params.crv != BlsCurve::BLS12381G2.to_string() { - return Err( - KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!( - "expected Jwk with EC {} crv in order to generate the proof with {alg}", - BlsCurve::BLS12381G2 - )), - ); - } - } else { - return Err( - KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm) - .with_custom_message(format!("{alg} is not supported")), - ); - } - // Check `key_id` exists in store. if !self.exists(key_id).await? { return Err(KeyStorageError::new(KeyStorageErrorKind::KeyNotFound)); @@ -221,51 +147,7 @@ impl JwkStorageBbsPlusExt for StrongholdStorage { client .get_guards([sk_location], |[sk]| { let sk = BBSplusSecretKey::from_bytes(&sk.borrow()).map_err(|e| FatalProcedureError::from(e.to_string()))?; - match alg { - ProofAlgorithm::BLS12381_SHA256 => Signature::::from_bytes(signature) - .and_then(|sig| { - sig.update_signature( - &sk, - &old_start_validity_timeframe, - &new_start_validity_timeframe, - index_start_validity_timeframe, - number_of_signed_messages, - ) - }) - .and_then(|sig| { - sig.update_signature( - &sk, - &old_end_validity_timeframe, - &new_end_validity_timeframe, - index_end_validity_timeframe, - number_of_signed_messages, - ) - }) - .map_err(|e| FatalProcedureError::from(e.to_string())) - .map(|sig| sig.to_bytes()), - ProofAlgorithm::BLS12381_SHAKE256 => Signature::::from_bytes(signature) - .and_then(|sig| { - sig.update_signature( - &sk, - &old_start_validity_timeframe, - &new_start_validity_timeframe, - index_start_validity_timeframe, - number_of_signed_messages, - ) - }) - .and_then(|sig| { - sig.update_signature( - &sk, - &old_end_validity_timeframe, - &new_end_validity_timeframe, - index_end_validity_timeframe, - number_of_signed_messages, - ) - }) - .map_err(|e| FatalProcedureError::from(e.to_string())) - .map(|sig| sig.to_bytes()), - _ => unreachable!(), - } + update_bbs_signature(alg, signature, &sk, &ctx).map_err(|e| FatalProcedureError::from(e.to_string())) }) .map_err(|e| { KeyStorageError::new(KeyStorageErrorKind::Unspecified) @@ -274,57 +156,3 @@ impl JwkStorageBbsPlusExt for StrongholdStorage { }) } } - -fn jwk_to_bbs_plus_pk(jwk: &Jwk) -> anyhow::Result { - // Safety: only called after checking `jwk`. - let params = jwk.try_ec_params().unwrap(); - let x = jwu::decode_b64(params.x.as_bytes())? - .try_into() - .map_err(|_| anyhow::anyhow!("Invalid coordinate length"))?; - let y = jwu::decode_b64(params.y.as_bytes())? - .try_into() - .map_err(|_| anyhow::anyhow!("Invalid coordinate length"))?; - - BBSplusPublicKey::from_coordinates(&x, &y).context("Failed to create BBS+ public key with the given coordinates") -} - -fn generate_bbs_plus_key_pair(alg: ProofAlgorithm) -> KeyStorageResult<(BBSplusSecretKey, BBSplusPublicKey)> { - 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(); - - Ok((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(); - - Ok((sk, pk)) - } - other => Err( - KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm).with_custom_message(format!( - "`{other}` is not supported with key type `{}`", - StrongholdKeyType::BLS12381G2 - )), - ), - } -} - -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) -}