Skip to content

Commit

Permalink
feat(crypto): CRP-2599 implement VetKdProtocol trait for CryptoCompon…
Browse files Browse the repository at this point in the history
…ent (#3565)

Implements the `VetKdProtocol` trait for the `CryptoComponent`

Smoke tests are added in #3649. They
are split from this PR to make the PR review easier.

---------

Co-authored-by: Jack Lloyd <[email protected]>
  • Loading branch information
fspreiss and randombit authored Jan 31, 2025
1 parent ef59572 commit 15a5164
Show file tree
Hide file tree
Showing 19 changed files with 684 additions and 59 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rs/crypto/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ DEPENDENCIES = [
"//rs/crypto/ed25519",
"//rs/crypto/interfaces/sig_verification",
"//rs/crypto/internal/crypto_lib/basic_sig/ed25519",
"//rs/crypto/internal/crypto_lib/bls12_381/vetkd",
"//rs/crypto/internal/crypto_lib/seed",
"//rs/crypto/internal/crypto_lib/threshold_sig/bls12_381",
"//rs/crypto/internal/crypto_lib/threshold_sig/canister_threshold_sig",
Expand Down
1 change: 1 addition & 0 deletions rs/crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ ic-crypto-internal-logmon = { path = "internal/logmon" }
ic-crypto-internal-seed = { path = "internal/crypto_lib/seed" }
ic-crypto-internal-threshold-sig-bls12381 = { path = "internal/crypto_lib/threshold_sig/bls12_381" }
ic-crypto-internal-threshold-sig-canister-threshold-sig = { path = "internal/crypto_lib/threshold_sig/canister_threshold_sig" }
ic-crypto-internal-bls12-381-vetkd = { path = "internal/crypto_lib/bls12_381/vetkd" }
ic-crypto-internal-types = { path = "internal/crypto_lib/types" }
ic-crypto-standalone-sig-verifier = { path = "standalone-sig-verifier" }
ic-crypto-tls-cert-validation = { path = "node_key_validation/tls_cert_validation" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn vetkd_bench(c: &mut Criterion) {
group.bench_function("EncryptedKeyShare::deserialize", |b| {
b.iter_batched(
|| eks.serialize(),
EncryptedKeyShare::deserialize,
|val| EncryptedKeyShare::deserialize(&val),
BatchSize::SmallInput,
)
});
Expand Down
12 changes: 8 additions & 4 deletions rs/crypto/internal/crypto_lib/bls12_381/vetkd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,10 @@ impl EncryptedKey {
}

/// Deserialize an encrypted key
pub fn deserialize(val: [u8; Self::BYTES]) -> Result<Self, EncryptedKeyDeserializationError> {
pub fn deserialize(val: &[u8]) -> Result<Self, EncryptedKeyDeserializationError> {
if val.len() != Self::BYTES {
return Err(EncryptedKeyDeserializationError::InvalidEncryptedKey);
}
let c2_start = G1Affine::BYTES;
let c3_start = G1Affine::BYTES + G2Affine::BYTES;

Expand Down Expand Up @@ -407,9 +410,10 @@ impl EncryptedKeyShare {
}

/// Deserialize an encrypted key share
pub fn deserialize(
val: [u8; Self::BYTES],
) -> Result<Self, EncryptedKeyShareDeserializationError> {
pub fn deserialize(val: &[u8]) -> Result<Self, EncryptedKeyShareDeserializationError> {
if val.len() != Self::BYTES {
return Err(EncryptedKeyShareDeserializationError::InvalidEncryptedKeyShare);
}
let c2_start = G1Affine::BYTES;
let c3_start = G1Affine::BYTES + G2Affine::BYTES;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ impl<'a> VetkdTestProtocolExecution<'a> {

// check that EKS serialization round trips:
let eks_bytes = eks.serialize();
let eks2 = EncryptedKeyShare::deserialize(eks_bytes).unwrap();
let eks2 = EncryptedKeyShare::deserialize(&eks_bytes).unwrap();
assert_eq!(eks, eks2);

node_info.push((node_idx as u32, node_pk.clone(), eks.clone()));
Expand Down
8 changes: 6 additions & 2 deletions rs/crypto/internal/crypto_service_provider/src/vault/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -974,10 +974,14 @@ pub trait VetKdCspVault {
/// Vault-level error for vetKD key share creation.
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
pub enum VetKdEncryptedKeyShareCreationVaultError {
/// If some arguments are invalid
InvalidArgument(String),
/// If the secret key is missing in the key store of if it has the wrong type
SecretKeyMissingOrWrongType(String),
/// If a transient internal error occurs, e.g., an RPC error communicating with the remote vault
TransientInternalError(String),
/// If the given master public key is invalid
InvalidArgumentMasterPublicKey,
/// If the given encryption public key is invalid
InvalidArgumentEncryptionPublicKey,
}

/// An error returned by failing to generate a public seed from [`CspVault`].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,40 +60,35 @@ impl<R: Rng + CryptoRng, S: SecretKeyStore, C: SecretKeyStore, P: PublicKeyStore
) -> Result<VetKdEncryptedKeyShareContent, VetKdEncryptedKeyShareCreationVaultError> {
let master_public_key =
G2Affine::deserialize(&master_public_key).map_err(|_: PairingInvalidPoint| {
VetKdEncryptedKeyShareCreationVaultError::InvalidArgument(format!(
"invalid master public key: 0x{}",
hex::encode(&master_public_key)
))
VetKdEncryptedKeyShareCreationVaultError::InvalidArgumentMasterPublicKey
})?;

let transport_public_key = TransportPublicKey::deserialize(&encryption_public_key)
.map_err(|e| match e {
TransportPublicKeyDeserializationError::InvalidPublicKey => {
VetKdEncryptedKeyShareCreationVaultError::InvalidArgument(format!(
"invalid encryption public key: 0x{}",
hex::encode(&encryption_public_key)
))
VetKdEncryptedKeyShareCreationVaultError::InvalidArgumentEncryptionPublicKey
}
})?;

let secret_key_from_store = self.sks_read_lock().get(&key_id).ok_or(
VetKdEncryptedKeyShareCreationVaultError::InvalidArgument(format!(
"missing key with ID {key_id:?}",
VetKdEncryptedKeyShareCreationVaultError::SecretKeyMissingOrWrongType(format!(
"missing key with ID {key_id}"
)),
)?;
let secret_bls_scalar = if let CspSecretKey::ThresBls12_381(secret_key_bytes) =
&secret_key_from_store
{
// We use the unchecked deserialization here because it is slighly cheaper, but mainly because
// it cannot fail, and the data is anyway trusted as it comes from the secret key store.
Ok(Scalar::deserialize_unchecked(
secret_key_bytes.inner_secret().expose_secret(),
))
} else {
Err(VetKdEncryptedKeyShareCreationVaultError::InvalidArgument(
format!("wrong secret key type for key with ID {key_id}: expected ThresBls12_381"),
))
}?;
let secret_bls_scalar =
if let CspSecretKey::ThresBls12_381(secret_key_bytes) = &secret_key_from_store {
// We use the unchecked deserialization here because it is slighly cheaper, but mainly because
// it cannot fail, and the data is anyway trusted as it comes from the secret key store.
Ok(Scalar::deserialize_unchecked(
secret_key_bytes.inner_secret().expose_secret(),
))
} else {
Err(
VetKdEncryptedKeyShareCreationVaultError::SecretKeyMissingOrWrongType(format!(
"wrong secret key type for key with ID {key_id}: expected ThresBls12_381"
)),
)
}?;

// Create encrypted key share using our library
let encrypted_key_share = EncryptedKeyShare::create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ fn should_fail_to_create_key_share_with_invalid_master_public_key() {
let result = test_env.create_encrypted_vetkd_key_share();

assert_matches!(
result, Err(VetKdEncryptedKeyShareCreationVaultError::InvalidArgument(error))
if error.contains("invalid master public key")
result,
Err(VetKdEncryptedKeyShareCreationVaultError::InvalidArgumentMasterPublicKey)
);
}

Expand All @@ -79,8 +79,8 @@ fn should_fail_to_create_key_share_with_invalid_encryption_public_key() {
let result = test_env.create_encrypted_vetkd_key_share();

assert_matches!(
result, Err(VetKdEncryptedKeyShareCreationVaultError::InvalidArgument(error))
if error.contains("invalid encryption public key")
result,
Err(VetKdEncryptedKeyShareCreationVaultError::InvalidArgumentEncryptionPublicKey)
);
}

Expand All @@ -94,7 +94,7 @@ fn should_fail_to_create_key_share_if_key_is_missing_in_secret_key_store() {
let result = test_env.create_encrypted_vetkd_key_share();

assert_matches!(
result, Err(VetKdEncryptedKeyShareCreationVaultError::InvalidArgument(error))
result, Err(VetKdEncryptedKeyShareCreationVaultError::SecretKeyMissingOrWrongType(error))
if error.contains("missing key with ID")
);
}
Expand All @@ -111,7 +111,7 @@ fn should_fail_to_create_key_share_if_key_in_secret_key_store_has_wrong_type() {
let result = test_env.create_encrypted_vetkd_key_share();

assert_matches!(
result, Err(VetKdEncryptedKeyShareCreationVaultError::InvalidArgument(error))
result, Err(VetKdEncryptedKeyShareCreationVaultError::SecretKeyMissingOrWrongType(error))
if error.contains("wrong secret key type")
);
}
Expand Down
1 change: 1 addition & 0 deletions rs/crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod common;
mod keygen;
mod sign;
mod tls;
mod vetkd;

use ic_crypto_internal_csp::vault::api::CspVault;
pub use sign::{
Expand Down
6 changes: 3 additions & 3 deletions rs/crypto/src/sign/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use super::*;

use crate::sign::basic_sig::BasicSigVerifierInternal;
use crate::sign::basic_sig::BasicSignerInternal;
use crate::sign::multi_sig::MultiSigVerifierInternal;
use crate::sign::multi_sig::MultiSignerInternal;
use crate::sign::threshold_sig::{ThresholdSigVerifierInternal, ThresholdSignerInternal};
Expand Down Expand Up @@ -37,7 +35,9 @@ use ic_types::{NodeId, RegistryVersion, SubnetId};
use std::collections::{BTreeMap, BTreeSet};
use std::convert::TryFrom;

pub use threshold_sig::ThresholdSigDataStoreImpl;
pub(crate) use basic_sig::{BasicSigVerifierInternal, BasicSignerInternal};
pub(crate) use threshold_sig::lazily_calculated_public_key_from_store;
pub use threshold_sig::{ThresholdSigDataStore, ThresholdSigDataStoreImpl};

mod basic_sig;
mod canister_threshold_sig;
Expand Down
2 changes: 1 addition & 1 deletion rs/crypto/src/sign/threshold_sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ impl ThresholdSigVerifierInternal {
/// Given that both cases indicate that the implementations of DKG and threshold
/// signatures are not aligned and also a caller could not recover from this, we
/// panic.
fn lazily_calculated_public_key_from_store<C: ThresholdSignatureCspClient>(
pub(crate) fn lazily_calculated_public_key_from_store<C: ThresholdSignatureCspClient>(
lockable_threshold_sig_data_store: &LockableThresholdSigDataStore,
threshold_sig_csp_client: &C,
dkg_id: &NiDkgId,
Expand Down
Loading

0 comments on commit 15a5164

Please sign in to comment.