Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
JwkStorageBbsPlusExt impl refactor for Stronghold, MemStore, WasmStore
Browse files Browse the repository at this point in the history
UMR1352 committed Apr 25, 2024
1 parent ae8e022 commit 4a152d0
Showing 9 changed files with 270 additions and 734 deletions.
256 changes: 16 additions & 240 deletions bindings/wasm/src/storage/jwk_storage_bbs_plus_ext.rs
Original file line number Diff line number Diff line change
@@ -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<A: BbsCiphersuite>() -> Result<(BBSplusSecretKey, BBSplusPublicKey), KeyStorageError> {
let keypair = KeyPair::<BBSplus<A>>::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(&params.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(&params.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<A>(
sig: &[u8; 80],
sk: &BBSplusSecretKey,
update_ctx: &ProofUpdateCtx,
) -> Result<[u8; 80], KeyStorageError>
where
A: BbsCiphersuite,
{
let sig = Signature::<BBSplus<A>>::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<BBSplusSecretKey, KeyStorageError> {
let params = jwk.try_ec_params().map_err(|_| KeyStorageErrorKind::Unspecified)?;
BBSplusSecretKey::from_bytes(
&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_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<JwkGenOutput> {
let (sk, pk) = match alg {
ProofAlgorithm::BLS12381_SHA256 => generate_bbs_keypair::<Bls12381Sha256>(),
ProofAlgorithm::BLS12381_SHAKE256 => generate_bbs_keypair::<Bls12381Shake256>(),
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 = <Self as JwkStorage>::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::<BbsBls12381Sha256>::sign(Some(data), &sk, &pk, Some(header)).map(|s| s.to_bytes())
}
ProofAlgorithm::BLS12381_SHAKE256 => {
Signature::<BbsBls12381Shake256>::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::<Bls12381Sha256>(signature, &sk, &ctx),
ProofAlgorithm::BLS12381_SHAKE256 => update_bbs_signature::<Bls12381Shake256>(signature, &sk, &ctx),
_ => unreachable!(),
}
let sk = expand_bls_jwk(&private_jwk)?.0.expect("jwk is private");
update_bbs_signature(alg, signature, &sk, &ctx)
}
}
2 changes: 1 addition & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
16 changes: 15 additions & 1 deletion identity_iota/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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")]
1 change: 1 addition & 0 deletions identity_storage/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"] }
233 changes: 168 additions & 65 deletions identity_storage/src/key_storage/bls.rs
Original file line number Diff line number Diff line change
@@ -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<S>() -> Result<(BBSplusSecretKey, BBSplusPublicKey), zkryptium::errors::Error>
where
S: BbsCiphersuite,
{
let key_pair = KeyPair::<BBSplus<S>>::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::<Bls12381Sha256>(),
ProofAlgorithm::BLS12381_SHAKE256 => random_bbs_keypair::<Bls12381Shake256>(),
_ => 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<BBSplusSecretKey>, 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(&params.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(&params.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(&params.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(&params.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<S>(
data: &[Vec<u8>],
sk: &BBSplusSecretKey,
pk: &BBSplusPublicKey,
header: &[u8],
) -> Result<Vec<u8>, zkryptium::errors::Error>
where
S: BbsCiphersuite,
{
Signature::<BBSplus<S>>::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<u8>],
sk: &BBSplusSecretKey,
pk: &BBSplusPublicKey,
header: &[u8],
) -> KeyStorageResult<Vec<u8>> {
match alg {
ProofAlgorithm::BLS12381_SHA256 => _sign_bbs::<Bls12381Sha256>(data, sk, pk, header),
ProofAlgorithm::BLS12381_SHAKE256 => _sign_bbs::<Bls12381Shake256>(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<S>(
sig: &[u8; 80],
sk: &BBSplusSecretKey,
update_ctx: &ProofUpdateCtx,
) -> Result<[u8; 80], zkryptium::errors::Error>
where
S: BbsCiphersuite,
{
let sig = Signature::<BBSplus<S>>::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::<Bls12381Sha256>(sig, sk, update_ctx),
ProofAlgorithm::BLS12381_SHAKE256 => _update_bbs_signature::<Bls12381Shake256>(sig, sk, update_ctx),
_ => return Err(KeyStorageErrorKind::UnsupportedProofAlgorithm.into()),
}
.map_err(|e| {
KeyStorageError::new(KeyStorageErrorKind::Unspecified)
.with_custom_message("signature failed")
.with_source(e)
})
}
278 changes: 43 additions & 235 deletions identity_storage/src/key_storage/memstore.rs
Original file line number Diff line number Diff line change
@@ -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<JwkGenOutput> {
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::<BbsBls12381Sha256>::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::<BbsBls12381Shake256>::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::<BbsBls12381Sha256>::sign(Some(data), &sk, &pk, Some(header)).map(|s| s.to_bytes())
}
ProofAlgorithm::BLS12381_SHAKE256 => {
Signature::<BbsBls12381Shake256>::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(
&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_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::<BbsBls12381Sha256>::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::<BbsBls12381Shake256>::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)
}
}
}
28 changes: 17 additions & 11 deletions identity_storage/src/key_storage/mod.rs
Original file line number Diff line number Diff line change
@@ -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::*;
2 changes: 1 addition & 1 deletion identity_storage/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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::*;
188 changes: 8 additions & 180 deletions identity_stronghold/src/stronghold_jwk_storage_ext.rs
Original file line number Diff line number Diff line change
@@ -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,24 +14,16 @@ 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 _;
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::<BbsBls12381Sha256>::sign(Some(data), &sk, &pk, Some(header)).map(|s| s.to_bytes())
}
ProofAlgorithm::BLS12381_SHAKE256 => {
Signature::<BbsBls12381Shake256>::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::<BbsBls12381Sha256>::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::<BbsBls12381Shake256>::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<BBSplusPublicKey> {
// 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::<BbsBls12381Sha256>::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::<BbsBls12381Shake256>::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)
}

0 comments on commit 4a152d0

Please sign in to comment.