diff --git a/rs/consensus/src/idkg/payload_builder.rs b/rs/consensus/src/idkg/payload_builder.rs index 6533be27c52..acaba039846 100644 --- a/rs/consensus/src/idkg/payload_builder.rs +++ b/rs/consensus/src/idkg/payload_builder.rs @@ -1082,6 +1082,7 @@ mod tests { signature: vec![2; 32], }) } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }, ); @@ -1924,6 +1925,7 @@ mod tests { &mut rng, )) } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; payload_0.available_pre_signatures.insert( payload_0.uid_generator.next_pre_signature_id(), diff --git a/rs/consensus/src/idkg/payload_builder/pre_signatures.rs b/rs/consensus/src/idkg/payload_builder/pre_signatures.rs index 2f6c7c26ca4..d7ff721c97b 100644 --- a/rs/consensus/src/idkg/payload_builder/pre_signatures.rs +++ b/rs/consensus/src/idkg/payload_builder/pre_signatures.rs @@ -359,6 +359,12 @@ fn make_new_pre_signatures_if_needed_helper( let Some(pre_signatures_to_create) = chain_key_config .key_configs .iter() + .filter(|key_config| { + matches!( + &key_config.key_id, + MasterPublicKeyId::Ecdsa(_) | MasterPublicKeyId::Schnorr(_) + ) + }) .find(|key_config| &key_config.key_id == key_id) .map(|key_config| key_config.pre_signatures_to_create_in_advance as usize) else { @@ -370,7 +376,7 @@ fn make_new_pre_signatures_if_needed_helper( } for _ in 0..(pre_signatures_to_create - unassigned_pre_signatures) { - let pre_signature = match key_id { + match key_id { MasterPublicKeyId::Ecdsa(ecdsa_key_id) => { let kappa_config = new_random_unmasked_config( key_id, @@ -380,11 +386,12 @@ fn make_new_pre_signatures_if_needed_helper( ); let lambda_config = new_random_config(key_id, subnet_nodes, registry_version, uid_generator); - PreSignatureInCreation::Ecdsa(QuadrupleInCreation::new( + let pre_signature = PreSignatureInCreation::Ecdsa(QuadrupleInCreation::new( ecdsa_key_id.clone(), kappa_config, lambda_config, - )) + )); + new_pre_signatures.insert(uid_generator.next_pre_signature_id(), pre_signature); } MasterPublicKeyId::Schnorr(schnorr_key_id) => { let blinder_config = new_random_unmasked_config( @@ -393,13 +400,16 @@ fn make_new_pre_signatures_if_needed_helper( registry_version, uid_generator, ); - PreSignatureInCreation::Schnorr(TranscriptInCreation::new( + let pre_signature = PreSignatureInCreation::Schnorr(TranscriptInCreation::new( schnorr_key_id.clone(), blinder_config, - )) + )); + new_pre_signatures.insert(uid_generator.next_pre_signature_id(), pre_signature); + } + MasterPublicKeyId::VetKd(_vetkd_key_id) => { + // vetKD does not have pre-signatures } }; - new_pre_signatures.insert(uid_generator.next_pre_signature_id(), pre_signature); } new_pre_signatures @@ -495,6 +505,7 @@ pub(super) mod test_utils { blinder_config_ref, )) } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; let configs = pre_signature .iter_transcript_configs_in_creation() @@ -709,6 +720,7 @@ pub(super) mod tests { let expected_transcript_ids = match key_id { MasterPublicKeyId::Ecdsa(_) => 2 * expected_pre_signatures_in_creation, MasterPublicKeyId::Schnorr(_) => expected_pre_signatures_in_creation, + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; assert_eq!(transcript_ids.len(), expected_transcript_ids); assert_eq!( diff --git a/rs/consensus/src/idkg/payload_builder/signatures.rs b/rs/consensus/src/idkg/payload_builder/signatures.rs index 9a7ae273e57..a29665fc80b 100644 --- a/rs/consensus/src/idkg/payload_builder/signatures.rs +++ b/rs/consensus/src/idkg/payload_builder/signatures.rs @@ -311,6 +311,7 @@ mod tests { signature: vec![i as u8; 32], }) } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }, ); } diff --git a/rs/consensus/src/idkg/payload_verifier.rs b/rs/consensus/src/idkg/payload_verifier.rs index 07c3703daa3..5ae723a6d2d 100644 --- a/rs/consensus/src/idkg/payload_verifier.rs +++ b/rs/consensus/src/idkg/payload_verifier.rs @@ -1043,6 +1043,7 @@ mod test { MasterPublicKeyId::Schnorr(_) => { SignWithSchnorrReply { signature: vec![] }.encode() } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }), )); @@ -1076,6 +1077,7 @@ mod test { fake_schnorr_master_public_key_id(SchnorrAlgorithm::Ed25519) } MasterPublicKeyId::Schnorr(_) => fake_ecdsa_master_public_key_id(), + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; // Add a pre-signature for the "wrong_key_id" insert_test_sig_inputs( diff --git a/rs/consensus/src/idkg/signer.rs b/rs/consensus/src/idkg/signer.rs index c3b983c386e..6f946dd23ae 100644 --- a/rs/consensus/src/idkg/signer.rs +++ b/rs/consensus/src/idkg/signer.rs @@ -1101,6 +1101,7 @@ mod tests { fake_schnorr_master_public_key_id(SchnorrAlgorithm::Ed25519) } MasterPublicKeyId::Schnorr(_) => fake_ecdsa_master_public_key_id(), + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; // Set up the signature requests @@ -1288,6 +1289,7 @@ mod tests { let expected_complaints_count = match key_id { MasterPublicKeyId::Ecdsa(_) => requested_signatures_count * 5, MasterPublicKeyId::Schnorr(_) => requested_signatures_count * 2, + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; let complaints = transcript_loader.returned_complaints(); assert_eq!(change_set.len(), complaints.len()); @@ -1368,6 +1370,7 @@ mod tests { ThresholdSigInputs::Schnorr(inputs), ) } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; let crypto = env .nodes @@ -1548,6 +1551,7 @@ mod tests { fake_schnorr_master_public_key_id(SchnorrAlgorithm::Ed25519) } MasterPublicKeyId::Schnorr(_) => fake_ecdsa_master_public_key_id(), + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; let message = create_signature_share(&key_id_wrong_scheme, NODE_2, id_2.clone()); let msg_id_2 = message.message_id(); diff --git a/rs/consensus/src/idkg/test_utils.rs b/rs/consensus/src/idkg/test_utils.rs index f4ee4903b57..65a849dd644 100644 --- a/rs/consensus/src/idkg/test_utils.rs +++ b/rs/consensus/src/idkg/test_utils.rs @@ -97,6 +97,7 @@ fn fake_signature_request_args(key_id: MasterPublicKeyId) -> ThresholdArguments key_id, message: Arc::new(vec![1; 48]), }), + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), } } @@ -1152,6 +1153,7 @@ pub(crate) fn create_sig_inputs_with_args( MasterPublicKeyId::Schnorr(key_id) => { create_schnorr_sig_inputs_with_args(caller, receivers, key_unmasked, height, key_id) } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), } } @@ -1356,6 +1358,7 @@ pub(crate) fn create_signature_share_with_nonce( sig_share_raw: vec![nonce], }, }), + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), } } @@ -1617,6 +1620,7 @@ pub(crate) fn key_id_with_name(key_id: &MasterPublicKeyId, name: &str) -> Master match key_id { MasterPublicKeyId::Ecdsa(ref mut key_id) => key_id.name = name.into(), MasterPublicKeyId::Schnorr(ref mut key_id) => key_id.name = name.into(), + MasterPublicKeyId::VetKd(ref mut key_id) => key_id.name = name.into(), } key_id } diff --git a/rs/consensus/src/idkg/utils.rs b/rs/consensus/src/idkg/utils.rs index e67bd98b415..ef765e9b8de 100644 --- a/rs/consensus/src/idkg/utils.rs +++ b/rs/consensus/src/idkg/utils.rs @@ -8,7 +8,7 @@ use ic_interfaces::consensus_pool::ConsensusBlockChain; use ic_interfaces::idkg::{IDkgChangeAction, IDkgChangeSet, IDkgPool}; use ic_interfaces_registry::RegistryClient; use ic_logger::{warn, ReplicaLogger}; -use ic_management_canister_types::{EcdsaCurve, MasterPublicKeyId, SchnorrAlgorithm}; +use ic_management_canister_types::{EcdsaCurve, MasterPublicKeyId, SchnorrAlgorithm, VetKdCurve}; use ic_protobuf::registry::subnet::v1 as pb; use ic_registry_client_helpers::subnet::SubnetRegistry; use ic_registry_subnet_features::ChainKeyConfig; @@ -443,6 +443,9 @@ pub(crate) fn algorithm_for_key_id(key_id: &MasterPublicKeyId) -> AlgorithmId { SchnorrAlgorithm::Bip340Secp256k1 => AlgorithmId::ThresholdSchnorrBip340, SchnorrAlgorithm::Ed25519 => AlgorithmId::ThresholdEd25519, }, + MasterPublicKeyId::VetKd(vetkd_key_id) => match vetkd_key_id.curve { + VetKdCurve::Bls12_381_G2 => AlgorithmId::Placeholder, + }, } } diff --git a/rs/consensus/utils/src/lib.rs b/rs/consensus/utils/src/lib.rs index e23e05e63a5..721de192dd3 100644 --- a/rs/consensus/utils/src/lib.rs +++ b/rs/consensus/utils/src/lib.rs @@ -860,6 +860,7 @@ mod tests { MasterPublicKeyId::Schnorr(key_id) => { PreSignatureRef::Schnorr(fake_schnorr_transcript(id, key_id.clone())) } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), } } @@ -880,6 +881,7 @@ mod tests { key_id: key_id.clone(), }) } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }, derivation_path: vec![], pseudo_random_id: [0; 32], diff --git a/rs/execution_environment/src/scheduler/threshold_signatures.rs b/rs/execution_environment/src/scheduler/threshold_signatures.rs index 35c7b7c4972..7b819994277 100644 --- a/rs/execution_environment/src/scheduler/threshold_signatures.rs +++ b/rs/execution_environment/src/scheduler/threshold_signatures.rs @@ -140,6 +140,7 @@ mod tests { key_id: key_id.clone(), message: Arc::new(vec![1; 64]), }), + MasterPublicKeyId::VetKd(_) => panic!("vetKD does not have pre-signatures"), }; let context = SignWithThresholdContext { request: RequestBuilder::new().build(), diff --git a/rs/protobuf/def/registry/crypto/v1/crypto.proto b/rs/protobuf/def/registry/crypto/v1/crypto.proto index 5d9821ee253..02ed9df91f2 100644 --- a/rs/protobuf/def/registry/crypto/v1/crypto.proto +++ b/rs/protobuf/def/registry/crypto/v1/crypto.proto @@ -80,9 +80,20 @@ message SchnorrKeyId { string name = 2; } +enum VetKdCurve { + VET_KD_CURVE_UNSPECIFIED = 0; + VET_KD_CURVE_BLS12_381_G2 = 1; +} + +message VetKdKeyId { + VetKdCurve curve = 1; + string name = 2; +} + message MasterPublicKeyId { oneof key_id { EcdsaKeyId ecdsa = 1; SchnorrKeyId schnorr = 2; + VetKdKeyId vetkd = 3; } } diff --git a/rs/protobuf/src/gen/crypto/registry.crypto.v1.rs b/rs/protobuf/src/gen/crypto/registry.crypto.v1.rs index 28a372a000c..c69d66bbe64 100644 --- a/rs/protobuf/src/gen/crypto/registry.crypto.v1.rs +++ b/rs/protobuf/src/gen/crypto/registry.crypto.v1.rs @@ -49,8 +49,15 @@ pub struct SchnorrKeyId { pub name: ::prost::alloc::string::String, } #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct VetKdKeyId { + #[prost(enumeration = "VetKdCurve", tag = "1")] + pub curve: i32, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] pub struct MasterPublicKeyId { - #[prost(oneof = "master_public_key_id::KeyId", tags = "1, 2")] + #[prost(oneof = "master_public_key_id::KeyId", tags = "1, 2, 3")] pub key_id: ::core::option::Option, } /// Nested message and enum types in `MasterPublicKeyId`. @@ -61,6 +68,8 @@ pub mod master_public_key_id { Ecdsa(super::EcdsaKeyId), #[prost(message, tag = "2")] Schnorr(super::SchnorrKeyId), + #[prost(message, tag = "3")] + Vetkd(super::VetKdKeyId), } } /// An algorithm ID. This is used to specify the signature algorithm associated with a public key. @@ -237,3 +246,41 @@ impl SchnorrAlgorithm { } } } +#[derive( + serde::Serialize, + serde::Deserialize, + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration, +)] +#[repr(i32)] +pub enum VetKdCurve { + Unspecified = 0, + Bls12381G2 = 1, +} +impl VetKdCurve { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unspecified => "VET_KD_CURVE_UNSPECIFIED", + Self::Bls12381G2 => "VET_KD_CURVE_BLS12_381_G2", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VET_KD_CURVE_UNSPECIFIED" => Some(Self::Unspecified), + "VET_KD_CURVE_BLS12_381_G2" => Some(Self::Bls12381G2), + _ => None, + } + } +} diff --git a/rs/protobuf/src/gen/registry/registry.crypto.v1.rs b/rs/protobuf/src/gen/registry/registry.crypto.v1.rs index 112cc14aaba..1df6d48effd 100644 --- a/rs/protobuf/src/gen/registry/registry.crypto.v1.rs +++ b/rs/protobuf/src/gen/registry/registry.crypto.v1.rs @@ -71,8 +71,15 @@ pub struct SchnorrKeyId { pub name: ::prost::alloc::string::String, } #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct VetKdKeyId { + #[prost(enumeration = "VetKdCurve", tag = "1")] + pub curve: i32, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] pub struct MasterPublicKeyId { - #[prost(oneof = "master_public_key_id::KeyId", tags = "1, 2")] + #[prost(oneof = "master_public_key_id::KeyId", tags = "1, 2, 3")] pub key_id: ::core::option::Option, } /// Nested message and enum types in `MasterPublicKeyId`. @@ -83,6 +90,8 @@ pub mod master_public_key_id { Ecdsa(super::EcdsaKeyId), #[prost(message, tag = "2")] Schnorr(super::SchnorrKeyId), + #[prost(message, tag = "3")] + Vetkd(super::VetKdKeyId), } } /// An algorithm ID. This is used to specify the signature algorithm associated with a public key. @@ -260,3 +269,41 @@ impl SchnorrAlgorithm { } } } +#[derive( + serde::Serialize, + serde::Deserialize, + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration, +)] +#[repr(i32)] +pub enum VetKdCurve { + Unspecified = 0, + Bls12381G2 = 1, +} +impl VetKdCurve { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unspecified => "VET_KD_CURVE_UNSPECIFIED", + Self::Bls12381G2 => "VET_KD_CURVE_BLS12_381_G2", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VET_KD_CURVE_UNSPECIFIED" => Some(Self::Unspecified), + "VET_KD_CURVE_BLS12_381_G2" => Some(Self::Bls12381G2), + _ => None, + } + } +} diff --git a/rs/protobuf/src/gen/state/registry.crypto.v1.rs b/rs/protobuf/src/gen/state/registry.crypto.v1.rs index 3c38ea93200..9f0c609fbb7 100644 --- a/rs/protobuf/src/gen/state/registry.crypto.v1.rs +++ b/rs/protobuf/src/gen/state/registry.crypto.v1.rs @@ -49,8 +49,15 @@ pub struct SchnorrKeyId { pub name: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, ::prost::Message)] +pub struct VetKdKeyId { + #[prost(enumeration = "VetKdCurve", tag = "1")] + pub curve: i32, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] pub struct MasterPublicKeyId { - #[prost(oneof = "master_public_key_id::KeyId", tags = "1, 2")] + #[prost(oneof = "master_public_key_id::KeyId", tags = "1, 2, 3")] pub key_id: ::core::option::Option, } /// Nested message and enum types in `MasterPublicKeyId`. @@ -61,6 +68,8 @@ pub mod master_public_key_id { Ecdsa(super::EcdsaKeyId), #[prost(message, tag = "2")] Schnorr(super::SchnorrKeyId), + #[prost(message, tag = "3")] + Vetkd(super::VetKdKeyId), } } /// An algorithm ID. This is used to specify the signature algorithm associated with a public key. @@ -201,3 +210,29 @@ impl SchnorrAlgorithm { } } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum VetKdCurve { + Unspecified = 0, + Bls12381G2 = 1, +} +impl VetKdCurve { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unspecified => "VET_KD_CURVE_UNSPECIFIED", + Self::Bls12381G2 => "VET_KD_CURVE_BLS12_381_G2", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VET_KD_CURVE_UNSPECIFIED" => Some(Self::Unspecified), + "VET_KD_CURVE_BLS12_381_G2" => Some(Self::Bls12381G2), + _ => None, + } + } +} diff --git a/rs/protobuf/src/gen/types/registry.crypto.v1.rs b/rs/protobuf/src/gen/types/registry.crypto.v1.rs index 3c38ea93200..9f0c609fbb7 100644 --- a/rs/protobuf/src/gen/types/registry.crypto.v1.rs +++ b/rs/protobuf/src/gen/types/registry.crypto.v1.rs @@ -49,8 +49,15 @@ pub struct SchnorrKeyId { pub name: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, ::prost::Message)] +pub struct VetKdKeyId { + #[prost(enumeration = "VetKdCurve", tag = "1")] + pub curve: i32, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] pub struct MasterPublicKeyId { - #[prost(oneof = "master_public_key_id::KeyId", tags = "1, 2")] + #[prost(oneof = "master_public_key_id::KeyId", tags = "1, 2, 3")] pub key_id: ::core::option::Option, } /// Nested message and enum types in `MasterPublicKeyId`. @@ -61,6 +68,8 @@ pub mod master_public_key_id { Ecdsa(super::EcdsaKeyId), #[prost(message, tag = "2")] Schnorr(super::SchnorrKeyId), + #[prost(message, tag = "3")] + Vetkd(super::VetKdKeyId), } } /// An algorithm ID. This is used to specify the signature algorithm associated with a public key. @@ -201,3 +210,29 @@ impl SchnorrAlgorithm { } } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum VetKdCurve { + Unspecified = 0, + Bls12381G2 = 1, +} +impl VetKdCurve { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unspecified => "VET_KD_CURVE_UNSPECIFIED", + Self::Bls12381G2 => "VET_KD_CURVE_BLS12_381_G2", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VET_KD_CURVE_UNSPECIFIED" => Some(Self::Unspecified), + "VET_KD_CURVE_BLS12_381_G2" => Some(Self::Bls12381G2), + _ => None, + } + } +} diff --git a/rs/registry/canister/canister/registry.did b/rs/registry/canister/canister/registry.did index 18fd5111049..987abff684c 100644 --- a/rs/registry/canister/canister/registry.did +++ b/rs/registry/canister/canister/registry.did @@ -132,12 +132,16 @@ type KeyConfig = record { max_queue_size : opt nat32; }; -type MasterPublicKeyId = variant { Schnorr : SchnorrKeyId; Ecdsa : EcdsaKeyId }; +type MasterPublicKeyId = variant { Schnorr : SchnorrKeyId; Ecdsa : EcdsaKeyId; VetKd : VetKdKeyId }; type SchnorrKeyId = record { algorithm : SchnorrAlgorithm; name : text }; type SchnorrAlgorithm = variant { ed25519; bip340secp256k1 }; +type VetKdKeyId = record { curve: VetKdCurve; name: text }; + +type VetKdCurve = variant { bls12_381_g2 }; + type EcdsaConfig = record { quadruples_to_create_in_advance : nat32; max_queue_size : opt nat32; diff --git a/rs/registry/canister/tests/common/test_helpers.rs b/rs/registry/canister/tests/common/test_helpers.rs index 5e8e06a1721..e218267817d 100644 --- a/rs/registry/canister/tests/common/test_helpers.rs +++ b/rs/registry/canister/tests/common/test_helpers.rs @@ -346,6 +346,9 @@ pub async fn wait_for_chain_key_setup( MasterPublicKeyId::Schnorr(key_id) => { wait_for_schnorr_setup(runtime, calling_canister, key_id).await; } + MasterPublicKeyId::VetKd(_key_id) => { + todo!("CRP-2632 Extend registry canister tests") + } } } diff --git a/rs/state_machine_tests/src/lib.rs b/rs/state_machine_tests/src/lib.rs index f15d2f81a11..ed78766e276 100644 --- a/rs/state_machine_tests/src/lib.rs +++ b/rs/state_machine_tests/src/lib.rs @@ -1763,6 +1763,9 @@ impl StateMachine { (public_key, private_key) } }, + MasterPublicKeyId::VetKd(_vetkd_key_id) => { + todo!("CRP-2629: Support vetKD in state machine tests") + } }; idkg_subnet_secret_keys.insert(key_id.clone(), private_key); diff --git a/rs/test_utilities/execution_environment/src/lib.rs b/rs/test_utilities/execution_environment/src/lib.rs index a721fd2638c..ffc6ae15d35 100644 --- a/rs/test_utilities/execution_environment/src/lib.rs +++ b/rs/test_utilities/execution_environment/src/lib.rs @@ -2149,6 +2149,13 @@ impl ExecutionTestBuilder { public_key: b"cdcdcdcd".to_vec(), }, ), + MasterPublicKeyId::VetKd(_) => ( + key_id, + MasterPublicKey { + algorithm_id: AlgorithmId::ThresBls12_381, + public_key: b"efefefef".to_vec(), + }, + ), }) .collect(); diff --git a/rs/tests/consensus/tecdsa/tecdsa_signature_fails_without_cycles_test.rs b/rs/tests/consensus/tecdsa/tecdsa_signature_fails_without_cycles_test.rs index 7a7cc95469e..9869d7d3626 100644 --- a/rs/tests/consensus/tecdsa/tecdsa_signature_fails_without_cycles_test.rs +++ b/rs/tests/consensus/tecdsa/tecdsa_signature_fails_without_cycles_test.rs @@ -67,6 +67,7 @@ fn test(env: TestEnv) { let method_name = match key_id { MasterPublicKeyId::Ecdsa(_) => "sign_with_ecdsa", MasterPublicKeyId::Schnorr(_) => "sign_with_schnorr", + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; assert_eq!( error, diff --git a/rs/tests/consensus/tecdsa/tecdsa_signature_life_cycle_test.rs b/rs/tests/consensus/tecdsa/tecdsa_signature_life_cycle_test.rs index 76ad01d89da..676ad647ebe 100644 --- a/rs/tests/consensus/tecdsa/tecdsa_signature_life_cycle_test.rs +++ b/rs/tests/consensus/tecdsa/tecdsa_signature_life_cycle_test.rs @@ -215,6 +215,7 @@ fn test(env: TestEnv) { let method_name = match key_id { MasterPublicKeyId::Ecdsa(_) => "sign_with_ecdsa", MasterPublicKeyId::Schnorr(_) => "sign_with_schnorr", + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; if let Err(sig_err) = sig_result { assert_eq!( diff --git a/rs/tests/consensus/tecdsa/utils/src/lib.rs b/rs/tests/consensus/tecdsa/utils/src/lib.rs index 56d574fc1ae..1b4f02d2e33 100644 --- a/rs/tests/consensus/tecdsa/utils/src/lib.rs +++ b/rs/tests/consensus/tecdsa/utils/src/lib.rs @@ -301,6 +301,7 @@ pub async fn get_public_key_with_retries( MasterPublicKeyId::Schnorr(key_id) => { get_schnorr_public_key_with_retries(key_id, msg_can, logger, retries).await } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), } } @@ -507,6 +508,7 @@ pub async fn get_signature_with_logger( MasterPublicKeyId::Schnorr(key_id) => { get_schnorr_signature_with_logger(message, cycles, key_id, msg_can, logger).await } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), } } @@ -809,6 +811,7 @@ pub fn verify_signature(key_id: &MasterPublicKeyId, msg: &[u8], pk: &[u8], sig: SchnorrAlgorithm::Bip340Secp256k1 => verify_bip340_signature(pk, sig, msg), SchnorrAlgorithm::Ed25519 => verify_ed25519_signature(pk, sig, msg), }, + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; assert!(res); } @@ -837,6 +840,7 @@ impl ChainSignatureRequest { MasterPublicKeyId::Schnorr(schnorr_key_id) => { Self::schnorr_params(schnorr_key_id, schnorr_message_size) } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }; let payload = Encode!(¶ms).unwrap(); @@ -901,6 +905,7 @@ impl Request for ChainSignatureRequest { MasterPublicKeyId::Schnorr(_) => { SignWithChainKeyReply::Schnorr(SignWithSchnorrReply::decode(raw_response)?) } + MasterPublicKeyId::VetKd(_) => panic!("not applicable to vetKD"), }) } } diff --git a/rs/types/management_canister_types/src/lib.rs b/rs/types/management_canister_types/src/lib.rs index 633b73dd35c..1f10ff1e989 100644 --- a/rs/types/management_canister_types/src/lib.rs +++ b/rs/types/management_canister_types/src/lib.rs @@ -2251,6 +2251,129 @@ impl FromStr for SchnorrKeyId { } } +/// Types of curves that can be used for threshold key derivation (vetKD). +/// ```text +/// (variant { bls12_381_g2; }) +/// ``` +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + Debug, + CandidType, + Deserialize, + EnumIter, + Serialize, +)] +pub enum VetKdCurve { + #[serde(rename = "bls12_381_g2")] + #[allow(non_camel_case_types)] + Bls12_381_G2, +} + +impl From<&VetKdCurve> for pb_registry_crypto::VetKdCurve { + fn from(item: &VetKdCurve) -> Self { + match item { + VetKdCurve::Bls12_381_G2 => pb_registry_crypto::VetKdCurve::Bls12381G2, + } + } +} + +impl TryFrom for VetKdCurve { + type Error = ProxyDecodeError; + + fn try_from(item: pb_registry_crypto::VetKdCurve) -> Result { + match item { + pb_registry_crypto::VetKdCurve::Bls12381G2 => Ok(VetKdCurve::Bls12_381_G2), + pb_registry_crypto::VetKdCurve::Unspecified => Err(ProxyDecodeError::ValueOutOfRange { + typ: "VetKdCurve", + err: format!("Unable to convert {:?} to a VetKdCurve", item), + }), + } + } +} + +impl std::fmt::Display for VetKdCurve { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl FromStr for VetKdCurve { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "bls12_381_g2" => Ok(Self::Bls12_381_G2), + _ => Err(format!("{} is not a recognized vetKD curve", s)), + } + } +} + +/// Unique identifier for a key that can be used for threshold key derivation +/// (vetKD). The name is just an identifier, but it may be used to convey +/// some information about the key (e.g. that the key is meant to be used for +/// testing purposes). +/// ```text +/// (record { curve: vetkd_curve; name: text}) +/// ``` +#[derive( + Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, CandidType, Deserialize, Serialize, +)] +pub struct VetKdKeyId { + pub curve: VetKdCurve, + pub name: String, +} + +impl From<&VetKdKeyId> for pb_registry_crypto::VetKdKeyId { + fn from(item: &VetKdKeyId) -> Self { + Self { + curve: pb_registry_crypto::VetKdCurve::from(&item.curve) as i32, + name: item.name.clone(), + } + } +} + +impl TryFrom for VetKdKeyId { + type Error = ProxyDecodeError; + fn try_from(item: pb_registry_crypto::VetKdKeyId) -> Result { + Ok(Self { + curve: VetKdCurve::try_from( + pb_registry_crypto::VetKdCurve::try_from(item.curve).map_err(|_| { + ProxyDecodeError::ValueOutOfRange { + typ: "VetKdKeyId", + err: format!("Unable to convert {} to a VetKdCurve", item.curve), + } + })?, + )?, + name: item.name, + }) + } +} + +impl std::fmt::Display for VetKdKeyId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.curve, self.name) + } +} + +impl FromStr for VetKdKeyId { + type Err = String; + fn from_str(s: &str) -> Result { + let (curve, name) = s + .split_once(':') + .ok_or_else(|| format!("vetKD key id {} does not contain a ':'", s))?; + Ok(VetKdKeyId { + curve: curve.parse::()?, + name: name.to_string(), + }) + } +} + /// Unique identifier for a key that can be used for one of the signature schemes /// supported on the IC. /// ```text @@ -2262,6 +2385,7 @@ impl FromStr for SchnorrKeyId { pub enum MasterPublicKeyId { Ecdsa(EcdsaKeyId), Schnorr(SchnorrKeyId), + VetKd(VetKdKeyId), } impl From<&MasterPublicKeyId> for pb_registry_crypto::MasterPublicKeyId { @@ -2270,6 +2394,7 @@ impl From<&MasterPublicKeyId> for pb_registry_crypto::MasterPublicKeyId { let key_id_pb = match item { MasterPublicKeyId::Schnorr(schnorr_key_id) => KeyId::Schnorr(schnorr_key_id.into()), MasterPublicKeyId::Ecdsa(ecdsa_key_id) => KeyId::Ecdsa(ecdsa_key_id.into()), + MasterPublicKeyId::VetKd(vetkd_key_id) => KeyId::Vetkd(vetkd_key_id.into()), }; Self { key_id: Some(key_id_pb), @@ -2289,6 +2414,7 @@ impl TryFrom for MasterPublicKeyId { MasterPublicKeyId::Schnorr(schnorr_key_id.try_into()?) } KeyId::Ecdsa(ecdsa_key_id) => MasterPublicKeyId::Ecdsa(ecdsa_key_id.try_into()?), + KeyId::Vetkd(vetkd_key_id) => MasterPublicKeyId::VetKd(vetkd_key_id.try_into()?), }; Ok(master_public_key_id) } @@ -2305,6 +2431,10 @@ impl std::fmt::Display for MasterPublicKeyId { write!(f, "schnorr:")?; schnorr_key_id.fmt(f) } + Self::VetKd(vetkd_key_id) => { + write!(f, "vetkd:")?; + vetkd_key_id.fmt(f) + } } } } @@ -2318,6 +2448,7 @@ impl FromStr for MasterPublicKeyId { match scheme.to_lowercase().as_str() { "ecdsa" => Ok(Self::Ecdsa(EcdsaKeyId::from_str(key_id)?)), "schnorr" => Ok(Self::Schnorr(SchnorrKeyId::from_str(key_id)?)), + "vetkd" => Ok(Self::VetKd(VetKdKeyId::from_str(key_id)?)), _ => Err(format!( "Scheme {} in master public key id {} is not supported.", scheme, s @@ -3346,6 +3477,26 @@ mod tests { } } + #[test] + fn vetkd_curve_round_trip() { + for curve in VetKdCurve::iter() { + assert_eq!(format!("{}", curve).parse::().unwrap(), curve); + } + } + + #[test] + fn vetkd_key_id_round_trip() { + for curve in VetKdCurve::iter() { + for name in ["bls12_381_g2", "", "other_key", "other key", "other:key"] { + let key = VetKdKeyId { + curve, + name: name.to_string(), + }; + assert_eq!(format!("{}", key).parse::().unwrap(), key); + } + } + } + #[test] fn master_public_key_id_round_trip() { for algorithm in SchnorrAlgorithm::iter() { @@ -3373,6 +3524,19 @@ mod tests { ); } } + + for curve in VetKdCurve::iter() { + for name in ["bls12_381_g2", "", "other_key", "other key", "other:key"] { + let key = MasterPublicKeyId::VetKd(VetKdKeyId { + curve, + name: name.to_string(), + }); + assert_eq!( + format!("{}", key).parse::().unwrap(), + key + ); + } + } } #[test]