From 07d7c5f307ca9e3aef7e78467b58154a4684972c Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:27:00 +0100 Subject: [PATCH 01/21] Changing SignatureScheme into Curve --- crates/contract-interface/src/lib.rs | 2 +- crates/contract-interface/src/types/state.rs | 10 +- crates/contract/src/dto_mapping.rs | 16 +- crates/contract/src/errors.rs | 6 +- crates/contract/src/lib.rs | 93 +++++----- crates/contract/src/primitives/domain.rs | 161 +++++++++--------- crates/contract/src/primitives/test_utils.rs | 30 ++-- crates/contract/src/state.rs | 9 +- crates/contract/src/state/initializing.rs | 10 +- crates/contract/src/state/resharing.rs | 8 +- crates/contract/src/state/running.rs | 34 ++-- crates/contract/src/utils.rs | 8 +- .../tests/inprocess/attestation_submission.rs | 6 +- crates/contract/tests/sandbox/common.rs | 35 ++-- .../tests/sandbox/foreign_chain_policy.rs | 10 +- .../tests/sandbox/participants_gas.rs | 4 +- crates/contract/tests/sandbox/sign.rs | 18 +- crates/contract/tests/sandbox/tee.rs | 32 ++-- .../sandbox/tee_cleanup_after_resharing.rs | 6 +- .../update_votes_cleanup_after_resharing.rs | 10 +- .../sandbox/upgrade_from_current_contract.rs | 20 +-- .../sandbox/upgrade_to_current_contract.rs | 6 +- crates/contract/tests/sandbox/user_views.rs | 11 +- crates/contract/tests/sandbox/utils/consts.rs | 12 +- .../contract/tests/sandbox/utils/interface.rs | 14 +- .../tests/sandbox/utils/shared_key_utils.rs | 12 +- crates/contract/tests/sandbox/vote.rs | 37 ++-- crates/devnet/src/contracts.rs | 24 +-- crates/devnet/src/loadtest.rs | 10 +- crates/devnet/src/mpc.rs | 6 +- crates/node/src/coordinator.rs | 14 +- crates/node/src/key_events.rs | 41 ++--- crates/node/src/mpc_client.rs | 93 +++++----- crates/node/src/tests.rs | 18 +- crates/node/src/tests/basic_cluster.rs | 8 +- .../src/tests/changing_participant_details.rs | 4 +- crates/node/src/tests/faulty.rs | 6 +- crates/node/src/tests/multidomain.rs | 38 ++--- crates/node/src/tests/onboarding.rs | 4 +- crates/node/src/tests/resharing.rs | 32 ++-- 40 files changed, 430 insertions(+), 488 deletions(-) diff --git a/crates/contract-interface/src/lib.rs b/crates/contract-interface/src/lib.rs index 1090a55a1..a2b5a8f40 100644 --- a/crates/contract-interface/src/lib.rs +++ b/crates/contract-interface/src/lib.rs @@ -14,7 +14,7 @@ pub mod types { pub use primitives::{AccountId, CkdAppId, DomainId, Tweak}; pub use sign::*; pub use state::{ - AddDomainsVotes, AttemptId, AuthenticatedAccountId, AuthenticatedParticipantId, + AddDomainsVotes, AttemptId, AuthenticatedAccountId, AuthenticatedParticipantId, Curve, DomainConfig, DomainPurpose, DomainRegistry, EpochId, InitializingContractState, KeyEvent, KeyEventId, KeyEventInstance, KeyForDomain, Keyset, ProtocolContractState, ResharingContractState, RunningContractState, SignatureScheme, Threshold, diff --git a/crates/contract-interface/src/types/state.rs b/crates/contract-interface/src/types/state.rs index 70a4ba474..75a26ba93 100644 --- a/crates/contract-interface/src/types/state.rs +++ b/crates/contract-interface/src/types/state.rs @@ -133,7 +133,7 @@ pub struct AuthenticatedAccountId(pub AccountId); // Domain Types // ============================================================================= -/// Supported signature schemes. +/// Elliptic curve used by a domain. #[derive( Clone, Copy, @@ -152,7 +152,7 @@ pub struct AuthenticatedAccountId(pub AccountId); all(feature = "abi", not(target_arch = "wasm32")), derive(schemars::JsonSchema) )] -pub enum SignatureScheme { +pub enum Curve { Secp256k1, Ed25519, Bls12381, @@ -160,6 +160,9 @@ pub enum SignatureScheme { V2Secp256k1, } +/// Backwards-compatible type alias. +pub type SignatureScheme = Curve; + /// The purpose that a domain serves. #[derive( Clone, @@ -198,7 +201,8 @@ pub enum DomainPurpose { )] pub struct DomainConfig { pub id: DomainId, - pub scheme: SignatureScheme, + #[serde(alias = "scheme")] + pub curve: Curve, /// `None` when reading state from an old contract that predates domain purposes. #[serde(default, skip_serializing_if = "Option::is_none")] pub purpose: Option, diff --git a/crates/contract/src/dto_mapping.rs b/crates/contract/src/dto_mapping.rs index 044ad8aa8..6c1b588e4 100644 --- a/crates/contract/src/dto_mapping.rs +++ b/crates/contract/src/dto_mapping.rs @@ -19,7 +19,7 @@ use crate::{ crypto_shared::types::PublicKeyExtended, errors::{ConversionError, Error}, primitives::{ - domain::{AddDomainsVotes, DomainConfig, DomainId, DomainRegistry, SignatureScheme}, + domain::{AddDomainsVotes, Curve, DomainConfig, DomainId, DomainRegistry}, key_state::{ AttemptId, AuthenticatedAccountId, AuthenticatedParticipantId, EpochId, KeyEventId, KeyForDomain, Keyset, @@ -511,13 +511,13 @@ impl IntoInterfaceType for &AuthenticatedAccountId // --- Domain types --- -impl IntoInterfaceType for SignatureScheme { - fn into_dto_type(self) -> dtos::SignatureScheme { +impl IntoInterfaceType for Curve { + fn into_dto_type(self) -> dtos::Curve { match self { - SignatureScheme::Secp256k1 => dtos::SignatureScheme::Secp256k1, - SignatureScheme::Ed25519 => dtos::SignatureScheme::Ed25519, - SignatureScheme::Bls12381 => dtos::SignatureScheme::Bls12381, - SignatureScheme::V2Secp256k1 => dtos::SignatureScheme::V2Secp256k1, + Curve::Secp256k1 => dtos::Curve::Secp256k1, + Curve::Ed25519 => dtos::Curve::Ed25519, + Curve::Bls12381 => dtos::Curve::Bls12381, + Curve::V2Secp256k1 => dtos::Curve::V2Secp256k1, } } } @@ -526,7 +526,7 @@ impl IntoInterfaceType for &DomainConfig { fn into_dto_type(self) -> dtos::DomainConfig { dtos::DomainConfig { id: self.id.into_dto_type(), - scheme: self.scheme.into_dto_type(), + curve: self.curve.into_dto_type(), purpose: Some(self.purpose), } } diff --git a/crates/contract/src/errors.rs b/crates/contract/src/errors.rs index 05083d470..bfec0c00a 100644 --- a/crates/contract/src/errors.rs +++ b/crates/contract/src/errors.rs @@ -200,9 +200,9 @@ pub enum DomainError { InvalidDomains, #[error("Domains from keyset do not match the provided domains")] DomainsMismatch, - #[error("Invalid scheme-purpose combination: scheme {scheme:?} is not compatible with purpose {purpose:?}")] - InvalidSchemePurposeCombination { - scheme: crate::primitives::domain::SignatureScheme, + #[error("Invalid curve-purpose combination: curve {curve:?} is not compatible with purpose {purpose:?}")] + InvalidCurvePurposeCombination { + curve: crate::primitives::domain::Curve, purpose: crate::primitives::domain::DomainPurpose, }, } diff --git a/crates/contract/src/lib.rs b/crates/contract/src/lib.rs index 32b1104d6..f60fd9bef 100644 --- a/crates/contract/src/lib.rs +++ b/crates/contract/src/lib.rs @@ -66,7 +66,7 @@ use near_sdk::{ }; use node_migrations::{BackupServiceInfo, DestinationNodeInfo, NodeMigrations}; use primitives::{ - domain::{DomainConfig, DomainId, DomainPurpose, DomainRegistry, SignatureScheme}, + domain::{Curve, DomainConfig, DomainId, DomainPurpose, DomainRegistry}, key_state::{AuthenticatedAccountId, AuthenticatedParticipantId, EpochId, KeyEventId, Keyset}, signature::{SignRequest, SignRequestArgs, SignatureRequest, YieldIndex}, thresholds::{Threshold, ThresholdParameters}, @@ -254,17 +254,17 @@ impl MpcContract { // ensure the signer sent a valid signature request // It's important we fail here because the MPC nodes will fail in an identical way. // This allows users to get the error message - match domain_config.scheme { - SignatureScheme::Secp256k1 | SignatureScheme::V2Secp256k1 => { + match domain_config.curve { + Curve::Secp256k1 | Curve::V2Secp256k1 => { let hash = *request.payload.as_ecdsa().expect("Payload is not Ecdsa"); k256::Scalar::from_repr(hash.into()) .into_option() .expect("Ecdsa payload cannot be converted to Scalar"); } - SignatureScheme::Ed25519 => { + Curve::Ed25519 => { request.payload.as_eddsa().expect("Payload is not EdDSA"); } - SignatureScheme::Bls12381 => { + Curve::Bls12381 => { env::panic_str(&InvalidParameters::InvalidDomainId.message("Selected domain is used for Bls12381, which is not compatible with this function").to_string(),); } } @@ -400,9 +400,9 @@ impl MpcContract { /// within a secure enclave. The signature_scheme parameter specifies which protocol /// we're querying the latest version for. The default is Secp256k1. The default is **NOT** /// to query across all protocols. - pub fn latest_key_version(&self, signature_scheme: Option) -> u32 { + pub fn latest_key_version(&self, signature_scheme: Option) -> u32 { self.protocol_state - .most_recent_domain_for_protocol(signature_scheme.unwrap_or_default()) + .most_recent_domain_for_curve(signature_scheme.unwrap_or_default()) .unwrap() .0 as u32 } @@ -2061,10 +2061,10 @@ mod tests { use crate::primitives::participants::{ParticipantId, ParticipantInfo}; use crate::primitives::test_utils::{ bogus_ed25519_near_public_key, bogus_ed25519_public_key, gen_account_id, gen_participant, - NUM_PROTOCOLS, + NUM_CURVES, }; use crate::primitives::{ - domain::{infer_purpose_from_scheme, DomainConfig, DomainId, SignatureScheme}, + domain::{infer_purpose_from_curve, Curve, DomainConfig, DomainId}, participants::Participants, signature::{Payload, Tweak}, test_utils::gen_participants, @@ -2166,19 +2166,19 @@ mod tests { } pub fn make_public_key_for_domain( - domain_scheme: SignatureScheme, + domain_curve: Curve, rng: &mut impl CryptoRngCore, ) -> (dtos::PublicKey, SharedSecretKey) { - match domain_scheme { - SignatureScheme::Secp256k1 | SignatureScheme::V2Secp256k1 => { + match domain_curve { + Curve::Secp256k1 | Curve::V2Secp256k1 => { let (pk, sk) = new_secp256k1(rng); (pk.into(), SharedSecretKey::Secp256k1(sk)) } - SignatureScheme::Ed25519 => { + Curve::Ed25519 => { let (pk, sk) = new_ed25519(rng); (pk.into(), SharedSecretKey::Ed25519(sk)) } - SignatureScheme::Bls12381 => { + Curve::Bls12381 => { let (pk, sk) = new_bls12381g2(rng); (pk.into(), SharedSecretKey::Bls12381(sk)) } @@ -2186,14 +2186,14 @@ mod tests { } fn basic_setup( - scheme: SignatureScheme, + curve: Curve, rng: &mut impl CryptoRngCore, ) -> (VMContext, MpcContract, SharedSecretKey) { - basic_setup_with_purpose(scheme, infer_purpose_from_scheme(scheme), rng) + basic_setup_with_purpose(curve, infer_purpose_from_curve(curve), rng) } fn basic_setup_with_purpose( - scheme: SignatureScheme, + curve: Curve, purpose: DomainPurpose, rng: &mut impl CryptoRngCore, ) -> (VMContext, MpcContract, SharedSecretKey) { @@ -2207,11 +2207,11 @@ mod tests { let domain_id = DomainId::default(); let domains = vec![DomainConfig { id: domain_id, - scheme, + curve, purpose, }]; let epoch_id = EpochId::new(0); - let (pk, sk) = make_public_key_for_domain(scheme, rng); + let (pk, sk) = make_public_key_for_domain(curve, rng); let key_for_domain = KeyForDomain { domain_id, key: pk.try_into().unwrap(), @@ -2268,8 +2268,7 @@ mod tests { } fn test_signature_common(success: bool, legacy_v1_api: bool) { - let (context, mut contract, secret_key) = - basic_setup(SignatureScheme::Secp256k1, &mut OsRng); + let (context, mut contract, secret_key) = basic_setup(Curve::Secp256k1, &mut OsRng); let SharedSecretKey::Secp256k1(secret_key) = secret_key else { unreachable!(); }; @@ -2356,7 +2355,7 @@ mod tests { #[test] fn test_signature_timeout() { - let (context, mut contract, _) = basic_setup(SignatureScheme::Secp256k1, &mut OsRng); + let (context, mut contract, _) = basic_setup(Curve::Secp256k1, &mut OsRng); let payload = Payload::from_legacy_ecdsa([0u8; 32]); let key_path = "m/44'\''/60'\''/0'\''/0/0".to_string(); @@ -2385,8 +2384,7 @@ mod tests { #[test] fn respond_ckd__should_succeed_when_response_is_valid_and_request_exists() { - let (context, mut contract, _secret_key) = - basic_setup(SignatureScheme::Bls12381, &mut OsRng); + let (context, mut contract, _secret_key) = basic_setup(Curve::Bls12381, &mut OsRng); let app_public_key: dtos::Bls12381G1PublicKey = "bls12381g1:6KtVVcAAGacrjNGePN8bp3KV6fYGrw1rFsyc7cVJCqR16Zc2ZFg3HX3hSZxSfv1oH6" .parse() @@ -2426,8 +2424,7 @@ mod tests { #[test] fn test_ckd_timeout() { - let (context, mut contract, _secret_key) = - basic_setup(SignatureScheme::Bls12381, &mut OsRng); + let (context, mut contract, _secret_key) = basic_setup(Curve::Bls12381, &mut OsRng); let app_public_key: dtos::Bls12381G1PublicKey = "bls12381g1:6KtVVcAAGacrjNGePN8bp3KV6fYGrw1rFsyc7cVJCqR16Zc2ZFg3HX3hSZxSfv1oH6" .parse() @@ -2458,11 +2455,8 @@ mod tests { fn respond_verify_foreign_tx__should_succeed_when_response_is_valid_and_request_exists() { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); - let (_context, mut contract, secret_key) = basic_setup_with_purpose( - SignatureScheme::Secp256k1, - DomainPurpose::ForeignTx, - &mut rng, - ); + let (_context, mut contract, secret_key) = + basic_setup_with_purpose(Curve::Secp256k1, DomainPurpose::ForeignTx, &mut rng); contract.foreign_chain_policy = bitcoin_foreign_chain_policy(); let SharedSecretKey::Secp256k1(secret_key) = secret_key else { unreachable!(); @@ -2529,11 +2523,8 @@ mod tests { fn test_verify_foreign_tx_timeout() { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); - let (_context, mut contract, _secret_key) = basic_setup_with_purpose( - SignatureScheme::Secp256k1, - DomainPurpose::ForeignTx, - &mut rng, - ); + let (_context, mut contract, _secret_key) = + basic_setup_with_purpose(Curve::Secp256k1, DomainPurpose::ForeignTx, &mut rng); contract.foreign_chain_policy = bitcoin_foreign_chain_policy(); let request_args = VerifyForeignTransactionRequestArgs { domain_id: DomainId::default().0.into(), @@ -2570,7 +2561,7 @@ mod tests { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); let (_context, mut contract, _sk) = - basic_setup_with_purpose(SignatureScheme::Secp256k1, purpose, &mut rng); + basic_setup_with_purpose(Curve::Secp256k1, purpose, &mut rng); // When contract.sign(SignRequestArgs { @@ -2591,7 +2582,7 @@ mod tests { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); let (_context, mut contract, _sk) = - basic_setup_with_purpose(SignatureScheme::Secp256k1, purpose, &mut rng); + basic_setup_with_purpose(Curve::Secp256k1, purpose, &mut rng); // When contract.verify_foreign_transaction(VerifyForeignTransactionRequestArgs { @@ -2610,11 +2601,8 @@ mod tests { fn verify_foreign_tx__should_reject_chain_not_in_policy() { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); - let (_context, mut contract, _sk) = basic_setup_with_purpose( - SignatureScheme::Secp256k1, - DomainPurpose::ForeignTx, - &mut rng, - ); + let (_context, mut contract, _sk) = + basic_setup_with_purpose(Curve::Secp256k1, DomainPurpose::ForeignTx, &mut rng); // Policy has Solana but not Bitcoin contract.foreign_chain_policy = dtos::ForeignChainPolicy { chains: BTreeMap::from([( @@ -2645,7 +2633,7 @@ mod tests { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); let (_context, mut contract, _sk) = - basic_setup_with_purpose(SignatureScheme::Secp256k1, purpose, &mut rng); + basic_setup_with_purpose(Curve::Secp256k1, purpose, &mut rng); // When contract.request_app_private_key(CKDRequestArgs { @@ -2893,8 +2881,7 @@ mod tests { #[test] fn test_respond_ckd_fails_for_attested_non_participant() { // --- Step 1: Setup standard contract with Bls domain and threshold=2 --- - let (context, mut contract, _secret_key) = - basic_setup(SignatureScheme::Bls12381, &mut OsRng); + let (context, mut contract, _secret_key) = basic_setup(Curve::Bls12381, &mut OsRng); // Submit valid attestations for all participants (so contract is in Running state) // 2. Extract participants list (we have 4 by default) @@ -3023,7 +3010,7 @@ mod tests { } const NUM_GENERATED_DOMAINS: usize = 1; - const NUM_DOMAINS: usize = 2 * NUM_PROTOCOLS; + const NUM_DOMAINS: usize = 2 * NUM_CURVES; #[test] fn test_start_node_migration_failure_not_participant() { let running_state = ProtocolContractState::Running(gen_running_state(NUM_DOMAINS)); @@ -3941,7 +3928,7 @@ mod tests { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); let (_context, mut contract, _sk) = - basic_setup_with_purpose(SignatureScheme::Secp256k1, DomainPurpose::Sign, &mut rng); + basic_setup_with_purpose(Curve::Secp256k1, DomainPurpose::Sign, &mut rng); assert_eq!(contract.metrics.sign_with_v1_payload_count, 0); assert_eq!(contract.metrics.sign_with_v2_payload_count, 0); @@ -3963,7 +3950,7 @@ mod tests { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); let (_context, mut contract, _sk) = - basic_setup_with_purpose(SignatureScheme::Secp256k1, DomainPurpose::Sign, &mut rng); + basic_setup_with_purpose(Curve::Secp256k1, DomainPurpose::Sign, &mut rng); assert_eq!(contract.metrics.sign_with_v1_payload_count, 0); assert_eq!(contract.metrics.sign_with_v2_payload_count, 0); @@ -3985,7 +3972,7 @@ mod tests { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); let (_context, mut contract, _sk) = - basic_setup_with_purpose(SignatureScheme::Secp256k1, DomainPurpose::Sign, &mut rng); + basic_setup_with_purpose(Curve::Secp256k1, DomainPurpose::Sign, &mut rng); // When — two v1 calls and one v2 call contract.sign(SignRequestArgs { @@ -4078,10 +4065,10 @@ mod tests { let domain_id = DomainId::default(); let domains = vec![DomainConfig { id: domain_id, - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }]; - let (pk, _) = make_public_key_for_domain(SignatureScheme::Secp256k1, &mut OsRng); + let (pk, _) = make_public_key_for_domain(Curve::Secp256k1, &mut OsRng); let key_for_domain = KeyForDomain { domain_id, key: pk.try_into().unwrap(), @@ -4183,7 +4170,7 @@ mod tests { Hash32, near_sdk::PublicKey, ) { - let (_context, contract, _secret_key) = basic_setup(SignatureScheme::Bls12381, &mut OsRng); + let (_context, contract, _secret_key) = basic_setup(Curve::Bls12381, &mut OsRng); let participant_account_ids: Vec<_> = contract .protocol_state diff --git a/crates/contract/src/primitives/domain.rs b/crates/contract/src/primitives/domain.rs index c742b38f8..476b61ffd 100644 --- a/crates/contract/src/primitives/domain.rs +++ b/crates/contract/src/primitives/domain.rs @@ -33,61 +33,61 @@ impl Display for DomainId { } } -/// Uniquely identifies a specific request algorithm. -/// More protocols may be added in the future. When adding new protocols, both Borsh +/// Elliptic curve used by a domain. +/// More curves may be added in the future. When adding new curves, both Borsh /// *and* JSON serialization must be kept compatible. #[near(serializers=[borsh, json])] #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SignatureScheme { +pub enum Curve { Secp256k1, Ed25519, Bls12381, V2Secp256k1, // Robust ECDSA } -impl Default for SignatureScheme { +impl Default for Curve { fn default() -> Self { Self::Secp256k1 } } -/// Infer a default purpose from the signature scheme. +/// Infer a default purpose from the curve. /// Used during migration from old state that lacks the `purpose` field. -pub fn infer_purpose_from_scheme(scheme: SignatureScheme) -> DomainPurpose { - match scheme { - SignatureScheme::Bls12381 => DomainPurpose::CKD, +pub fn infer_purpose_from_curve(curve: Curve) -> DomainPurpose { + match curve { + Curve::Bls12381 => DomainPurpose::CKD, _ => DomainPurpose::Sign, } } -/// Returns whether the given scheme is valid for the given purpose. -pub fn is_valid_scheme_for_purpose(purpose: DomainPurpose, scheme: SignatureScheme) -> bool { +/// Returns whether the given curve is valid for the given purpose. +pub fn is_valid_curve_for_purpose(purpose: DomainPurpose, curve: Curve) -> bool { matches!( - (purpose, scheme), - (DomainPurpose::Sign, SignatureScheme::Secp256k1) - | (DomainPurpose::Sign, SignatureScheme::V2Secp256k1) - | (DomainPurpose::Sign, SignatureScheme::Ed25519) - | (DomainPurpose::ForeignTx, SignatureScheme::Secp256k1) - | (DomainPurpose::CKD, SignatureScheme::Bls12381) + (purpose, curve), + (DomainPurpose::Sign, Curve::Secp256k1) + | (DomainPurpose::Sign, Curve::V2Secp256k1) + | (DomainPurpose::Sign, Curve::Ed25519) + | (DomainPurpose::ForeignTx, Curve::Secp256k1) + | (DomainPurpose::CKD, Curve::Bls12381) ) } -/// Describes the configuration of a domain: the domain ID and the protocol it uses. +/// Describes the configuration of a domain: the domain ID and the curve it uses. #[near(serializers=[borsh, json])] #[serde(from = "DomainConfigCompat")] #[derive(Debug, Clone, PartialEq, Eq)] pub struct DomainConfig { pub id: DomainId, - pub scheme: SignatureScheme, + pub curve: Curve, pub purpose: DomainPurpose, } /// JSON-only compatibility helper: -/// old 3.4.x state omitted `purpose`, so we infer it from `scheme` when absent. +/// old 3.4.x state omitted `purpose`, so we infer it from `curve` when absent. #[derive(serde::Deserialize)] struct DomainConfigCompat { id: DomainId, - scheme: SignatureScheme, + curve: Curve, #[serde(default)] purpose: Option, } @@ -96,10 +96,10 @@ impl From for DomainConfig { fn from(value: DomainConfigCompat) -> Self { Self { id: value.id, - scheme: value.scheme, + curve: value.curve, purpose: value .purpose - .unwrap_or_else(|| infer_purpose_from_scheme(value.scheme)), + .unwrap_or_else(|| infer_purpose_from_curve(value.curve)), } } } @@ -122,16 +122,16 @@ impl DomainRegistry { /// Migration from legacy: creates a DomainRegistry with a single ecdsa key. pub fn new_single_ecdsa_key_from_legacy() -> Self { let mut registry = Self::default(); - registry.add_domain(SignatureScheme::Secp256k1, DomainPurpose::Sign); + registry.add_domain(Curve::Secp256k1, DomainPurpose::Sign); registry } /// Add a single domain with the given protocol and purpose, returning the DomainId of the /// added domain. - fn add_domain(&mut self, scheme: SignatureScheme, purpose: DomainPurpose) -> DomainId { + fn add_domain(&mut self, curve: Curve, purpose: DomainPurpose) -> DomainId { let domain = DomainConfig { id: DomainId(self.next_domain_id), - scheme, + curve, purpose, }; self.next_domain_id += 1; @@ -145,7 +145,7 @@ impl DomainRegistry { pub fn add_domains(&self, domains: Vec) -> Result { let mut new_registry = self.clone(); for domain in domains { - let new_domain_id = new_registry.add_domain(domain.scheme, domain.purpose); + let new_domain_id = new_registry.add_domain(domain.curve, domain.purpose); if new_domain_id != domain.id { return Err(DomainError::NewDomainIdsNotContiguous { expected_id: new_domain_id, @@ -174,11 +174,11 @@ impl DomainRegistry { /// Returns the most recently added domain for the given protocol, /// or None if no such domain exists. - pub fn most_recent_domain_for_protocol(&self, scheme: SignatureScheme) -> Option { + pub fn most_recent_domain_for_curve(&self, curve: Curve) -> Option { self.domains .iter() .rev() - .find(|domain| domain.scheme == scheme) + .find(|domain| domain.curve == curve) .map(|domain| domain.id) } @@ -264,8 +264,8 @@ impl AddDomainsVotes { #[cfg(test)] pub mod tests { use super::{ - infer_purpose_from_scheme, is_valid_scheme_for_purpose, AddDomainsVotes, DomainConfig, - DomainId, DomainPurpose, DomainRegistry, Participants, SignatureScheme, + infer_purpose_from_curve, is_valid_curve_for_purpose, AddDomainsVotes, Curve, DomainConfig, + DomainId, DomainPurpose, DomainRegistry, Participants, }; use crate::primitives::key_state::AuthenticatedParticipantId; use crate::primitives::test_utils::{gen_participant, gen_participants}; @@ -279,12 +279,12 @@ pub mod tests { let domains1 = vec![ DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }, DomainConfig { id: DomainId(1), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }, ]; @@ -294,12 +294,12 @@ pub mod tests { let domains2 = vec![ DomainConfig { id: DomainId(2), - scheme: SignatureScheme::Bls12381, + curve: Curve::Bls12381, purpose: DomainPurpose::CKD, }, DomainConfig { id: DomainId(3), - scheme: SignatureScheme::V2Secp256k1, + curve: Curve::V2Secp256k1, purpose: DomainPurpose::Sign, }, ]; @@ -310,7 +310,7 @@ pub mod tests { // This fails because the domain ID does not start from next_domain_id. let domains3 = vec![DomainConfig { id: DomainId(5), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }]; let _ = new_registry.add_domains(domains3).unwrap_err(); @@ -319,12 +319,12 @@ pub mod tests { let domains4 = vec![ DomainConfig { id: DomainId(5), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }, DomainConfig { id: DomainId(4), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }, ]; @@ -336,22 +336,22 @@ pub mod tests { let expected = vec![ DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }, DomainConfig { id: DomainId(2), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }, DomainConfig { id: DomainId(3), - scheme: SignatureScheme::Bls12381, + curve: Curve::Bls12381, purpose: DomainPurpose::CKD, }, DomainConfig { id: DomainId(4), - scheme: SignatureScheme::V2Secp256k1, + curve: Curve::V2Secp256k1, purpose: DomainPurpose::Sign, }, ]; @@ -370,22 +370,22 @@ pub mod tests { } #[test] - fn test_most_recent_domain_for_signature_scheme() { + fn test_most_recent_domain_for_curve() { let registry = DomainRegistry::from_raw_validated( vec![ DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }, DomainConfig { id: DomainId(2), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }, DomainConfig { id: DomainId(3), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }, ], @@ -393,11 +393,11 @@ pub mod tests { ) .unwrap(); assert_eq!( - registry.most_recent_domain_for_protocol(SignatureScheme::Secp256k1), + registry.most_recent_domain_for_curve(Curve::Secp256k1), Some(DomainId(3)) ); assert_eq!( - registry.most_recent_domain_for_protocol(SignatureScheme::Ed25519), + registry.most_recent_domain_for_curve(Curve::Ed25519), Some(DomainId(2)) ); } @@ -406,71 +406,64 @@ pub mod tests { fn test_serialization_format() { let domain_config = DomainConfig { id: DomainId(3), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }; let json = serde_json::to_string(&domain_config).unwrap(); - assert_eq!(json, r#"{"id":3,"scheme":"Secp256k1","purpose":"Sign"}"#); + assert_eq!(json, r#"{"id":3,"curve":"Secp256k1","purpose":"Sign"}"#); let domain_config: DomainConfig = serde_json::from_str(&json).unwrap(); assert_eq!(domain_config.id, DomainId(3)); - assert_eq!(domain_config.scheme, SignatureScheme::Secp256k1); + assert_eq!(domain_config.curve, Curve::Secp256k1); assert_eq!(domain_config.purpose, DomainPurpose::Sign); } #[rstest] #[case( - r#"{"id":0,"scheme":"Secp256k1"}"#, - SignatureScheme::Secp256k1, + r#"{"id":0,"curve":"Secp256k1"}"#, + Curve::Secp256k1, DomainPurpose::Sign )] - #[case( - r#"{"id":1,"scheme":"Bls12381"}"#, - SignatureScheme::Bls12381, - DomainPurpose::CKD - )] + #[case(r#"{"id":1,"curve":"Bls12381"}"#, Curve::Bls12381, DomainPurpose::CKD)] fn test_deserialization_without_purpose( #[case] json: &str, - #[case] expected_scheme: SignatureScheme, + #[case] expected_curve: Curve, #[case] expected_purpose: DomainPurpose, ) { // Simulates JSON from a 3.4.1 contract that lacks the `purpose` field. let config: DomainConfig = serde_json::from_str(json).unwrap(); - assert_eq!(config.scheme, expected_scheme); + assert_eq!(config.curve, expected_curve); assert_eq!(config.purpose, expected_purpose); } #[rstest] - #[case(SignatureScheme::Secp256k1, DomainPurpose::Sign)] - #[case(SignatureScheme::Ed25519, DomainPurpose::Sign)] - #[case(SignatureScheme::V2Secp256k1, DomainPurpose::Sign)] - #[case(SignatureScheme::Bls12381, DomainPurpose::CKD)] - fn test_infer_purpose_from_scheme( - #[case] scheme: SignatureScheme, - #[case] expected: DomainPurpose, - ) { - assert_eq!(infer_purpose_from_scheme(scheme), expected); + #[case(Curve::Secp256k1, DomainPurpose::Sign)] + #[case(Curve::Ed25519, DomainPurpose::Sign)] + #[case(Curve::V2Secp256k1, DomainPurpose::Sign)] + #[case(Curve::Bls12381, DomainPurpose::CKD)] + fn test_infer_purpose_from_curve(#[case] curve: Curve, #[case] expected: DomainPurpose) { + assert_eq!(infer_purpose_from_curve(curve), expected); } #[rstest] // Valid combinations - #[case(DomainPurpose::Sign, SignatureScheme::Secp256k1, true)] - #[case(DomainPurpose::Sign, SignatureScheme::V2Secp256k1, true)] - #[case(DomainPurpose::Sign, SignatureScheme::Ed25519, true)] - #[case(DomainPurpose::ForeignTx, SignatureScheme::Secp256k1, true)] - #[case(DomainPurpose::CKD, SignatureScheme::Bls12381, true)] + #[case(DomainPurpose::Sign, Curve::Secp256k1, true)] + #[case(DomainPurpose::Sign, Curve::V2Secp256k1, true)] + #[case(DomainPurpose::Sign, Curve::Ed25519, true)] + #[case(DomainPurpose::ForeignTx, Curve::Secp256k1, true)] + #[case(DomainPurpose::CKD, Curve::Bls12381, true)] // Invalid combinations - #[case(DomainPurpose::Sign, SignatureScheme::Bls12381, false)] - #[case(DomainPurpose::ForeignTx, SignatureScheme::Ed25519, false)] - #[case(DomainPurpose::ForeignTx, SignatureScheme::Bls12381, false)] - #[case(DomainPurpose::ForeignTx, SignatureScheme::V2Secp256k1, false)] - #[case(DomainPurpose::CKD, SignatureScheme::Secp256k1, false)] - fn test_valid_scheme_purpose_combinations( + #[case(DomainPurpose::Sign, Curve::Bls12381, false)] + #[case(DomainPurpose::ForeignTx, Curve::Ed25519, false)] + #[case(DomainPurpose::ForeignTx, Curve::Bls12381, false)] + #[case(DomainPurpose::ForeignTx, Curve::V2Secp256k1, false)] + #[case(DomainPurpose::CKD, Curve::Secp256k1, false)] + fn test_valid_curve_purpose_combinations( #[case] purpose: DomainPurpose, - #[case] scheme: SignatureScheme, + #[case] curve: Curve, #[case] expected: bool, ) { - assert_eq!(is_valid_scheme_for_purpose(purpose, scheme), expected); + assert_eq!(is_valid_curve_for_purpose(purpose, curve), expected); } fn setup_participants(n: usize) -> (Participants, Vec) { @@ -494,7 +487,7 @@ pub mod tests { fn sample_proposal() -> Vec { vec![DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }] } @@ -572,12 +565,12 @@ pub mod tests { let (participants, auth_ids) = setup_participants(3); let proposal_a = vec![DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }]; let proposal_b = vec![DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }]; let mut votes = AddDomainsVotes::default(); diff --git a/crates/contract/src/primitives/test_utils.rs b/crates/contract/src/primitives/test_utils.rs index b79a5abe2..5ac224600 100644 --- a/crates/contract/src/primitives/test_utils.rs +++ b/crates/contract/src/primitives/test_utils.rs @@ -1,6 +1,4 @@ -use super::domain::{ - infer_purpose_from_scheme, DomainConfig, DomainId, DomainRegistry, SignatureScheme, -}; +use super::domain::{infer_purpose_from_curve, Curve, DomainConfig, DomainId, DomainRegistry}; use crate::{ crypto_shared::types::{serializable::SerializableEdwardsPoint, PublicKeyExtended}, primitives::{ @@ -13,23 +11,23 @@ use near_account_id::AccountId; use rand::{distributions::Uniform, Rng}; use std::collections::BTreeMap; -const ALL_PROTOCOLS: [SignatureScheme; 4] = [ - SignatureScheme::Secp256k1, - SignatureScheme::Ed25519, - SignatureScheme::Bls12381, - SignatureScheme::V2Secp256k1, +const ALL_CURVES: [Curve; 4] = [ + Curve::Secp256k1, + Curve::Ed25519, + Curve::Bls12381, + Curve::V2Secp256k1, ]; -pub const NUM_PROTOCOLS: usize = ALL_PROTOCOLS.len(); +pub const NUM_CURVES: usize = ALL_CURVES.len(); -/// Generates a valid DomainRegistry with various signature schemes, with num_domains total. +/// Generates a valid DomainRegistry with various curves, with num_domains total. pub fn gen_domain_registry(num_domains: usize) -> DomainRegistry { let mut domains = Vec::new(); for i in 0..num_domains { - let scheme = ALL_PROTOCOLS[i % ALL_PROTOCOLS.len()]; + let curve = ALL_CURVES[i % ALL_CURVES.len()]; domains.push(DomainConfig { id: DomainId(i as u64 * 2), - scheme, - purpose: infer_purpose_from_scheme(scheme), + curve, + purpose: infer_purpose_from_curve(curve), }); } DomainRegistry::from_raw_validated(domains, num_domains as u64 * 2).unwrap() @@ -39,11 +37,11 @@ pub fn gen_domain_registry(num_domains: usize) -> DomainRegistry { pub fn gen_domains_to_add(registry: &DomainRegistry, num_domains: usize) -> Vec { let mut new_domains = Vec::new(); for i in 0..num_domains { - let scheme = ALL_PROTOCOLS[i % ALL_PROTOCOLS.len()]; + let curve = ALL_CURVES[i % ALL_CURVES.len()]; new_domains.push(DomainConfig { id: DomainId(registry.next_domain_id() + i as u64), - scheme, - purpose: infer_purpose_from_scheme(scheme), + curve, + purpose: infer_purpose_from_curve(curve), }); } new_domains diff --git a/crates/contract/src/state.rs b/crates/contract/src/state.rs index efc42e2ad..dfbe24164 100644 --- a/crates/contract/src/state.rs +++ b/crates/contract/src/state.rs @@ -8,7 +8,7 @@ pub mod test_utils; use crate::crypto_shared::types::PublicKeyExtended; use crate::errors::{DomainError, Error, InvalidState}; use crate::primitives::{ - domain::{DomainConfig, DomainId, DomainRegistry, SignatureScheme}, + domain::{Curve, DomainConfig, DomainId, DomainRegistry}, key_state::{AuthenticatedParticipantId, EpochId, KeyEventId}, participants::Participants, thresholds::{Threshold, ThresholdParameters}, @@ -168,12 +168,9 @@ impl ProtocolContractState { .map(|x| x.map(ProtocolContractState::Running)) } - pub fn most_recent_domain_for_protocol( - &self, - signature_scheme: SignatureScheme, - ) -> Result { + pub fn most_recent_domain_for_curve(&self, curve: Curve) -> Result { self.domain_registry()? - .most_recent_domain_for_protocol(signature_scheme) + .most_recent_domain_for_curve(curve) .ok_or_else(|| DomainError::NoSuchDomain.into()) } diff --git a/crates/contract/src/state/initializing.rs b/crates/contract/src/state/initializing.rs index ed461f015..4d2f8a2d3 100644 --- a/crates/contract/src/state/initializing.rs +++ b/crates/contract/src/state/initializing.rs @@ -155,7 +155,7 @@ pub mod tests { use crate::primitives::domain::{AddDomainsVotes, DomainId}; use crate::primitives::key_state::{AttemptId, KeyEventId}; use crate::primitives::test_utils::{ - bogus_ed25519_public_key_extended, gen_account_id, NUM_PROTOCOLS, + bogus_ed25519_public_key_extended, gen_account_id, NUM_CURVES, }; use crate::primitives::votes::ThresholdParametersVotes; use crate::state::key_event::tests::find_leader; @@ -320,9 +320,9 @@ pub mod tests { #[case(3, 0)] #[case(3, 1)] #[case(3, 2)] - #[case(NUM_PROTOCOLS, 0)] - #[case(NUM_PROTOCOLS, 1)] - #[case(NUM_PROTOCOLS, 2)] + #[case(NUM_CURVES, 0)] + #[case(NUM_CURVES, 1)] + #[case(NUM_CURVES, 2)] fn test_initializing_contract_state( #[case] domains: usize, #[case] num_already_generated: usize, @@ -332,7 +332,7 @@ pub mod tests { #[test] fn test_cancel_key_generation() { - let (mut env, mut state) = gen_initializing_state(NUM_PROTOCOLS, 2); + let (mut env, mut state) = gen_initializing_state(NUM_CURVES, 2); // Vote for domain #2. let leader = find_leader(&state.generating_key); diff --git a/crates/contract/src/state/resharing.rs b/crates/contract/src/state/resharing.rs index c7c6e162c..e057bc74d 100644 --- a/crates/contract/src/state/resharing.rs +++ b/crates/contract/src/state/resharing.rs @@ -193,7 +193,7 @@ impl ResharingContractState { } #[cfg(test)] pub mod tests { - use crate::primitives::test_utils::NUM_PROTOCOLS; + use crate::primitives::test_utils::NUM_CURVES; use crate::state::{key_event::tests::find_leader, running::RunningContractState}; use crate::{ primitives::{ @@ -346,15 +346,15 @@ pub mod tests { #[case(1)] #[case(2)] #[case(3)] - #[case(NUM_PROTOCOLS)] - #[case(2*NUM_PROTOCOLS)] + #[case(NUM_CURVES)] + #[case(2*NUM_CURVES)] fn test_resharing_contract_state(#[case] num_domains: usize) { test_resharing_contract_state_for(num_domains); } #[test] fn test_resharing_reproposal() { - let (mut env, mut state) = gen_resharing_state(NUM_PROTOCOLS); + let (mut env, mut state) = gen_resharing_state(NUM_CURVES); // Vote for first domain's key. let leader = find_leader(&state.resharing_key); diff --git a/crates/contract/src/state/running.rs b/crates/contract/src/state/running.rs index 2233b0ddb..bab33b327 100644 --- a/crates/contract/src/state/running.rs +++ b/crates/contract/src/state/running.rs @@ -167,12 +167,10 @@ impl RunningContractState { return Err(DomainError::AddDomainsMustAddAtLeastOneDomain.into()); } for domain in &domains { - if !crate::primitives::domain::is_valid_scheme_for_purpose( - domain.purpose, - domain.scheme, - ) { - return Err(DomainError::InvalidSchemePurposeCombination { - scheme: domain.scheme, + if !crate::primitives::domain::is_valid_curve_for_purpose(domain.purpose, domain.curve) + { + return Err(DomainError::InvalidCurvePurposeCombination { + curve: domain.curve, purpose: domain.purpose, } .into()); @@ -211,9 +209,9 @@ pub mod running_tests { use rstest::rstest; use crate::primitives::domain::{ - AddDomainsVotes, DomainConfig, DomainId, DomainPurpose, SignatureScheme, + AddDomainsVotes, Curve, DomainConfig, DomainId, DomainPurpose, }; - use crate::primitives::test_utils::{gen_threshold_params, NUM_PROTOCOLS}; + use crate::primitives::test_utils::{gen_threshold_params, NUM_CURVES}; use crate::state::key_event::tests::Environment; use crate::state::test_utils::gen_valid_params_proposal; use crate::{ @@ -342,18 +340,18 @@ pub mod running_tests { #[case(1)] #[case(2)] #[case(3)] - #[case(NUM_PROTOCOLS)] - #[case(2*NUM_PROTOCOLS)] + #[case(NUM_CURVES)] + #[case(2*NUM_CURVES)] fn test_running(#[case] n: usize) { test_running_for(n); } #[rstest] - #[case(SignatureScheme::Bls12381, DomainPurpose::Sign)] - #[case(SignatureScheme::Ed25519, DomainPurpose::ForeignTx)] - #[case(SignatureScheme::Secp256k1, DomainPurpose::CKD)] - fn vote_add_domains__should_reject_invalid_scheme_purpose( - #[case] scheme: SignatureScheme, + #[case(Curve::Bls12381, DomainPurpose::Sign)] + #[case(Curve::Ed25519, DomainPurpose::ForeignTx)] + #[case(Curve::Secp256k1, DomainPurpose::CKD)] + fn vote_add_domains__should_reject_invalid_curve_purpose( + #[case] curve: Curve, #[case] purpose: DomainPurpose, ) { // Given @@ -364,7 +362,7 @@ pub mod running_tests { let invalid_domain = vec![DomainConfig { id: DomainId(next_id), - scheme, + curve, purpose, }]; @@ -374,8 +372,8 @@ pub mod running_tests { // Then assert!( err.to_string() - .contains("Invalid scheme-purpose combination"), - "Expected InvalidSchemePurposeCombination, got: {err}" + .contains("Invalid curve-purpose combination"), + "Expected InvalidCurvePurposeCombination, got: {err}" ); } } diff --git a/crates/contract/src/utils.rs b/crates/contract/src/utils.rs index 4e4eea592..b51d19630 100644 --- a/crates/contract/src/utils.rs +++ b/crates/contract/src/utils.rs @@ -29,7 +29,7 @@ pub fn protocol_state_to_string(contract_state: &ProtocolContractState) -> Strin output.push_str(&format!(" Epoch: {}\n", state.generating_key.epoch_id())); output.push_str(" Domains:\n"); for (i, domain) in state.domains.domains().iter().enumerate() { - output.push_str(&format!(" Domain {}: {:?}, ", domain.id, domain.scheme)); + output.push_str(&format!(" Domain {}: {:?}, ", domain.id, domain.curve)); #[allow(clippy::comparison_chain)] if i < state.generated_keys.len() { output.push_str(&format!( @@ -73,7 +73,7 @@ pub fn protocol_state_to_string(contract_state: &ProtocolContractState) -> Strin { output.push_str(&format!( " Domain {}: {:?}, key from attempt {}\n", - domain.id, domain.scheme, key.attempt + domain.id, domain.curve, key.attempt )); } output.push_str(" Parameters:\n"); @@ -96,9 +96,7 @@ pub fn protocol_state_to_string(contract_state: &ProtocolContractState) -> Strin { output.push_str(&format!( " Domain {}: {:?}, original key from attempt {}, ", - domain.id, - domain.scheme, - state.previous_running_state.keyset.domains[i].attempt + domain.id, domain.curve, state.previous_running_state.keyset.domains[i].attempt )); #[allow(clippy::comparison_chain)] diff --git a/crates/contract/tests/inprocess/attestation_submission.rs b/crates/contract/tests/inprocess/attestation_submission.rs index 130936283..b8d6b25a6 100644 --- a/crates/contract/tests/inprocess/attestation_submission.rs +++ b/crates/contract/tests/inprocess/attestation_submission.rs @@ -2,7 +2,7 @@ use contract_interface::types::{Attestation, InitConfig, MockAttestation, Protoc use mpc_contract::{ crypto_shared::types::PublicKeyExtended, primitives::{ - domain::{DomainConfig, DomainId, DomainPurpose, SignatureScheme}, + domain::{Curve, DomainConfig, DomainId, DomainPurpose}, key_state::{AttemptId, EpochId, KeyForDomain, Keyset}, participants::{ParticipantId, ParticipantInfo}, test_utils::{bogus_ed25519_near_public_key, gen_participants}, @@ -101,7 +101,7 @@ impl TestSetupBuilder { let domains = vec![DomainConfig { id: DomainId::default(), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }]; @@ -148,7 +148,7 @@ impl TestSetupBuilder { .contract .vote_add_domains(vec![DomainConfig { id: DomainId(1), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }]) .unwrap(); diff --git a/crates/contract/tests/sandbox/common.rs b/crates/contract/tests/sandbox/common.rs index 17963b2d9..62b94d12d 100644 --- a/crates/contract/tests/sandbox/common.rs +++ b/crates/contract/tests/sandbox/common.rs @@ -13,9 +13,7 @@ use dtos::ProtocolContractState; use mpc_contract::{ crypto_shared::types::PublicKeyExtended, primitives::{ - domain::{ - infer_purpose_from_scheme, DomainConfig, DomainId, DomainPurpose, SignatureScheme, - }, + domain::{infer_purpose_from_curve, Curve, DomainConfig, DomainId, DomainPurpose}, key_state::{AttemptId, EpochId, KeyForDomain, Keyset}, participants::{ParticipantInfo, Participants}, test_utils::bogus_ed25519_near_public_key, @@ -204,25 +202,25 @@ pub async fn init_with_candidates( .enumerate() .map(|(i, pk)| { let domain_id = DomainId((i as u64) * 2); - let scheme = match pk { - dtos::PublicKey::Ed25519(_) => SignatureScheme::Ed25519, - dtos::PublicKey::Secp256k1(_) => SignatureScheme::Secp256k1, - dtos::PublicKey::Bls12381(_) => SignatureScheme::Bls12381, + let curve = match pk { + dtos::PublicKey::Ed25519(_) => Curve::Ed25519, + dtos::PublicKey::Secp256k1(_) => Curve::Secp256k1, + dtos::PublicKey::Bls12381(_) => Curve::Bls12381, }; let key: PublicKeyExtended = pk.try_into().unwrap(); - let purpose = infer_purpose_from_scheme(scheme); + let purpose = infer_purpose_from_curve(curve); ret_domains.push(DomainPublicKey { public_key: key.clone(), config: DomainConfig { id: domain_id, - scheme, + curve, purpose, }, }); ( DomainConfig { id: domain_id, - scheme, + curve, purpose, }, KeyForDomain { @@ -262,13 +260,10 @@ pub struct SandboxTestSetup { pub keys: Vec, } -pub async fn init_env( - schemes: &[SignatureScheme], - number_of_participants: usize, -) -> SandboxTestSetup { - let (public_keys, secret_keys): (Vec<_>, Vec<_>) = schemes +pub async fn init_env(curves: &[Curve], number_of_participants: usize) -> SandboxTestSetup { + let (public_keys, secret_keys): (Vec<_>, Vec<_>) = curves .iter() - .map(|scheme| make_key_for_domain(*scheme)) + .map(|curve| make_key_for_domain(*curve)) .collect(); let (worker, contract, mpc_signer_accounts, domains) = init_with_candidates(public_keys, None, number_of_participants).await; @@ -467,7 +462,7 @@ pub async fn call_contract_key_generation( start_keygen_instance(contract, accounts, key_event_id) .await .unwrap(); - let (public_key, shared_secret_key) = make_key_for_domain(domain.scheme); + let (public_key, shared_secret_key) = make_key_for_domain(domain.curve); domain_keys.push(DomainKey { domain_config: domain.clone(), @@ -534,17 +529,17 @@ pub async fn execute_key_generation_and_add_random_state( let domains_to_add = [ DomainConfig { id: 0.into(), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }, DomainConfig { id: 1.into(), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }, DomainConfig { id: 2.into(), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }, ]; diff --git a/crates/contract/tests/sandbox/foreign_chain_policy.rs b/crates/contract/tests/sandbox/foreign_chain_policy.rs index 84f29a401..c6191745b 100644 --- a/crates/contract/tests/sandbox/foreign_chain_policy.rs +++ b/crates/contract/tests/sandbox/foreign_chain_policy.rs @@ -1,7 +1,7 @@ #![allow(non_snake_case)] use crate::sandbox::common::{init_env, SandboxTestSetup}; -use crate::sandbox::utils::consts::{ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN}; +use crate::sandbox::utils::consts::{ALL_CURVES, PARTICIPANT_LEN}; use assert_matches::assert_matches; use contract_interface::method_names::{ GET_FOREIGN_CHAIN_POLICY_PROPOSALS, VOTE_FOREIGN_CHAIN_POLICY, @@ -15,7 +15,7 @@ async fn vote_foreign_chain_policy__should_reject_empty_rpc_providers() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; // When: a participant votes with a policy containing an empty RPC providers set let transaction_result = mpc_signer_accounts[0] @@ -47,7 +47,7 @@ async fn vote_foreign_chain_policy_accepts_valid_policy() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; // When: a participant votes with a valid policy containing non-empty RPC providers let transaction_result = mpc_signer_accounts[0] @@ -79,7 +79,7 @@ async fn vote_foreign_chain_policy_deduplicates_duplicate_rpc_providers() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; // When: a participant votes with a policy containing duplicate RPC providers let transaction_result = mpc_signer_accounts[0] @@ -132,7 +132,7 @@ async fn vote_foreign_chain_policy_deduplicates_duplicate_chain_keys() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; // When: a participant votes with a policy containing duplicate chain keys. // The json! macro cannot represent duplicate object keys, so we use raw JSON bytes. diff --git a/crates/contract/tests/sandbox/participants_gas.rs b/crates/contract/tests/sandbox/participants_gas.rs index 1ca3972e1..f7e02280f 100644 --- a/crates/contract/tests/sandbox/participants_gas.rs +++ b/crates/contract/tests/sandbox/participants_gas.rs @@ -17,7 +17,7 @@ use crate::sandbox::{ use mpc_contract::{ crypto_shared::types::PublicKeyExtended, primitives::{ - domain::{DomainConfig, DomainId, DomainPurpose, SignatureScheme}, + domain::{Curve, DomainConfig, DomainId, DomainPurpose}, key_state::{AttemptId, EpochId, KeyForDomain, Keyset}, }, }; @@ -273,7 +273,7 @@ async fn setup_test_env_with_state(n_participants: usize, running_state: bool) - let domain_id = DomainId(0); let domain = DomainConfig { id: domain_id, - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }; let (dto_pk, _) = new_secp256k1(); diff --git a/crates/contract/tests/sandbox/sign.rs b/crates/contract/tests/sandbox/sign.rs index 36e97d290..af37e4884 100644 --- a/crates/contract/tests/sandbox/sign.rs +++ b/crates/contract/tests/sandbox/sign.rs @@ -1,7 +1,7 @@ use crate::sandbox::{ common::{candidates, create_account_given_id, init, init_env, SandboxTestSetup}, utils::{ - consts::{ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN}, + consts::{ALL_CURVES, PARTICIPANT_LEN}, shared_key_utils::SharedSecretKey, sign_utils::{ gen_secp_256k1_sign_test, submit_signature_response, verify_timeout, DomainResponseTest, @@ -13,7 +13,7 @@ use contract_interface::method_names; use mpc_contract::{ errors, primitives::{ - domain::SignatureScheme, + domain::Curve, participants::Participants, thresholds::{Threshold, ThresholdParameters}, }, @@ -34,7 +34,7 @@ async fn test_contract_request_all_schemes() -> anyhow::Result<()> { contract, mpc_signer_accounts, keys, - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let attested_account = &mpc_signer_accounts[0]; let account_ids: [AccountId; 5] = [ @@ -72,7 +72,7 @@ async fn test_contract_request_duplicate_requests_all_schemes() -> anyhow::Resul contract, mpc_signer_accounts, keys, - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let attested_account = &mpc_signer_accounts[0]; for key in &keys { @@ -118,7 +118,7 @@ async fn test_contract_request_timeout_all_schemes() -> anyhow::Result<()> { contract, keys, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; for key in &keys { let alice = worker.dev_create_account().await.unwrap(); @@ -141,7 +141,7 @@ async fn test_contract_success_refund_all_schemes() -> anyhow::Result<()> { contract, mpc_signer_accounts, keys, - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let mut rng = rand::rngs::StdRng::from_seed([1u8; 32]); let attested_account = &mpc_signer_accounts[0]; @@ -181,7 +181,7 @@ async fn test_contract_fail_refund_all_schemes() -> anyhow::Result<()> { contract, keys, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let mut rng = rand::rngs::StdRng::from_seed([2u8; 32]); let alice = worker.dev_create_account().await?; let balance = alice.view_account().await?.balance; @@ -219,7 +219,7 @@ async fn test_contract_request_deposits_all_schemes() -> anyhow::Result<()> { mpc_signer_accounts, keys, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let mut rng = rand::rngs::StdRng::from_seed([1u8; 32]); let attested_account = &mpc_signer_accounts[0]; let predecessor_id = contract.id(); @@ -277,7 +277,7 @@ async fn test_sign_v1_compatibility() -> anyhow::Result<()> { mpc_signer_accounts, keys, .. - } = init_env(&[SignatureScheme::Secp256k1], PARTICIPANT_LEN).await; + } = init_env(&[Curve::Secp256k1], PARTICIPANT_LEN).await; let mut rng = rand::rngs::StdRng::from_seed([1u8; 32]); let key = &keys[0]; const LEGACY_KEY_VERSION: u64 = 0; // this is the first cait-sith domain in the contract diff --git a/crates/contract/tests/sandbox/tee.rs b/crates/contract/tests/sandbox/tee.rs index 8908519a5..39a62a05b 100644 --- a/crates/contract/tests/sandbox/tee.rs +++ b/crates/contract/tests/sandbox/tee.rs @@ -1,7 +1,7 @@ use crate::sandbox::{ common::{gen_accounts, init_env, submit_tee_attestations, SandboxTestSetup}, utils::{ - consts::{ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN}, + consts::{ALL_CURVES, PARTICIPANT_LEN}, interface::IntoContractType, mpc_contract::{ assert_running_return_participants, assert_running_return_threshold, @@ -16,9 +16,7 @@ use contract_interface::method_names; use contract_interface::types::{self as dtos, Attestation, MockAttestation}; use mpc_contract::{ errors::InvalidState, - primitives::{ - domain::SignatureScheme, participants::Participants, test_utils::bogus_ed25519_public_key, - }, + primitives::{domain::Curve, participants::Participants, test_utils::bogus_ed25519_public_key}, }; use mpc_primitives::hash::{LauncherDockerComposeHash, MpcDockerImageHash}; use near_workspaces::Contract; @@ -33,7 +31,7 @@ async fn test_vote_code_hash_basic_threshold_and_stability() -> Result<()> { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let threshold = assert_running_return_threshold(&contract).await; let allowed_mpc_image_digest = image_digest(); @@ -82,7 +80,7 @@ async fn test_vote_code_hash_approved_hashes_persist_after_vote_changes() -> Res contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let threshold = assert_running_return_threshold(&contract).await; // This is necessary for some parts of the test below assert!((threshold.0 as usize) < mpc_signer_accounts.len()); @@ -148,7 +146,7 @@ async fn test_vote_code_hash_approved_hashes_persist_after_vote_changes() -> Res async fn test_vote_code_hash_doesnt_accept_account_id_not_in_participant_list() -> Result<()> { let SandboxTestSetup { worker, contract, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let random_account = &gen_accounts(&worker, 1).await.0[0]; let allowed_mpc_image_digest = image_digest(); @@ -174,7 +172,7 @@ async fn test_vote_code_hash_accepts_allowed_mpc_image_digest_hex_parameter() -> contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let allowed_mpc_image_digest = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; @@ -236,7 +234,7 @@ async fn test_submit_participant_info_succeeds_with_mock_attestation() -> Result contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let mock_attestation = Attestation::Mock(MockAttestation::Valid); let tls_key = p2p_tls_key().into(); let success = submit_participant_info( @@ -257,7 +255,7 @@ async fn test_submit_participant_info_succeeds_with_mock_attestation() -> Result async fn test_clean_tee_status_denies_external_account_access() -> Result<()> { let SandboxTestSetup { worker, contract, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; // Create a new account that's not the contract let external_account = worker.dev_create_account().await?; @@ -294,7 +292,7 @@ async fn test_clean_tee_status_succeeds_when_contract_calls_itself() -> Result<( contract, mut mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let participant_uids = { let p: Participants = @@ -345,7 +343,7 @@ async fn new_hash_and_previous_hashes_under_grace_period_pass_attestation_verifi contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let threshold = assert_running_return_threshold(&contract).await; let hash_1 = [1; 32]; let hash_2 = [2; 32]; @@ -401,7 +399,7 @@ async fn get_attestation_returns_none_when_tls_key_is_not_associated_with_an_att contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let participant_account_1 = &mpc_signer_accounts[0]; let tls_key_1 = bogus_ed25519_public_key(); @@ -434,7 +432,7 @@ async fn get_attestation_returns_some_when_tls_key_associated_with_an_attestatio contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let participant_account_1 = &mpc_signer_accounts[0]; let tls_key_1 = bogus_ed25519_public_key(); @@ -500,7 +498,7 @@ async fn get_attestation_overwrites_when_same_tls_key_is_reused() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let participant_account = &mpc_signer_accounts[0]; let tls_key = bogus_ed25519_public_key(); @@ -561,7 +559,7 @@ async fn test_function_allowed_launcher_compose_hashes() -> anyhow::Result<()> { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let allowed_mpc_image_digest = image_digest(); @@ -605,7 +603,7 @@ async fn test_verify_tee_expired_attestation_triggers_resharing() -> Result<()> contract, mpc_signer_accounts, .. - } = init_env(&[SignatureScheme::Secp256k1], PARTICIPANT_COUNT).await; + } = init_env(&[Curve::Secp256k1], PARTICIPANT_COUNT).await; let initial_participants = assert_running_return_participants(&contract).await?; assert_eq!(initial_participants.participants.len(), PARTICIPANT_COUNT); diff --git a/crates/contract/tests/sandbox/tee_cleanup_after_resharing.rs b/crates/contract/tests/sandbox/tee_cleanup_after_resharing.rs index 7cc64affe..b40bf7204 100644 --- a/crates/contract/tests/sandbox/tee_cleanup_after_resharing.rs +++ b/crates/contract/tests/sandbox/tee_cleanup_after_resharing.rs @@ -14,8 +14,8 @@ use anyhow::Result; use contract_interface::types::{self as dtos, Attestation, MockAttestation}; use mpc_contract::{ primitives::{ - domain::SignatureScheme, participants::Participants, - test_utils::bogus_ed25519_near_public_key, thresholds::ThresholdParameters, + domain::Curve, participants::Participants, test_utils::bogus_ed25519_near_public_key, + thresholds::ThresholdParameters, }, tee::tee_state::NodeId, }; @@ -36,7 +36,7 @@ async fn test_tee_cleanup_after_full_resharing_flow() -> Result<()> { contract, mpc_signer_accounts, .. - } = init_env(&[SignatureScheme::Secp256k1], PARTICIPANT_LEN).await; + } = init_env(&[Curve::Secp256k1], PARTICIPANT_LEN).await; // extract initial participants: let initial_participants = assert_running_return_participants(&contract).await?; diff --git a/crates/contract/tests/sandbox/update_votes_cleanup_after_resharing.rs b/crates/contract/tests/sandbox/update_votes_cleanup_after_resharing.rs index 286484e06..425c1edf4 100644 --- a/crates/contract/tests/sandbox/update_votes_cleanup_after_resharing.rs +++ b/crates/contract/tests/sandbox/update_votes_cleanup_after_resharing.rs @@ -16,9 +16,7 @@ use anyhow::Result; use contract_interface::method_names; use contract_interface::types as dtos; use mpc_contract::{ - primitives::{ - domain::SignatureScheme, participants::Participants, thresholds::ThresholdParameters, - }, + primitives::{domain::Curve, participants::Participants, thresholds::ThresholdParameters}, update::{ProposeUpdateArgs, UpdateId}, }; use near_account_id::AccountId; @@ -35,7 +33,7 @@ async fn update_votes_from_kicked_out_participants_are_cleared_after_resharing() contract, mpc_signer_accounts, .. - } = init_env(&[SignatureScheme::Secp256k1], PARTICIPANT_LEN).await; + } = init_env(&[Curve::Secp256k1], PARTICIPANT_LEN).await; let initial_participants = assert_running_return_participants(&contract).await?; let threshold = assert_running_return_threshold(&contract).await; @@ -151,7 +149,7 @@ async fn add_domain_votes_from_kicked_out_participants_are_cleared_after_reshari contract, mpc_signer_accounts, .. - } = init_env(&[SignatureScheme::Secp256k1], PARTICIPANT_LEN).await; + } = init_env(&[Curve::Secp256k1], PARTICIPANT_LEN).await; let initial_participants = assert_running_return_participants(&contract).await?; let threshold = assert_running_return_threshold(&contract).await; @@ -165,7 +163,7 @@ async fn add_domain_votes_from_kicked_out_participants_are_cleared_after_reshari }; let domains_to_add = vec![dtos::DomainConfig { id: dtos::DomainId(next_domain_id), - scheme: dtos::SignatureScheme::Ed25519, + curve: dtos::Curve::Ed25519, purpose: Some(dtos::DomainPurpose::Sign), }]; execute_async_transactions( diff --git a/crates/contract/tests/sandbox/upgrade_from_current_contract.rs b/crates/contract/tests/sandbox/upgrade_from_current_contract.rs index 4cf33d553..63417c45d 100644 --- a/crates/contract/tests/sandbox/upgrade_from_current_contract.rs +++ b/crates/contract/tests/sandbox/upgrade_from_current_contract.rs @@ -5,7 +5,7 @@ use crate::sandbox::{ }, utils::{ consts::{ - ALL_SIGNATURE_SCHEMES, CURRENT_CONTRACT_DEPLOY_DEPOSIT, GAS_FOR_VOTE_BEFORE_THRESHOLD, + ALL_CURVES, CURRENT_CONTRACT_DEPLOY_DEPOSIT, GAS_FOR_VOTE_BEFORE_THRESHOLD, GAS_FOR_VOTE_UPDATE, MAX_GAS_FOR_THRESHOLD_VOTE, PARTICIPANT_LEN, }, contract_build::{current_contract, migration_contract}, @@ -49,7 +49,7 @@ async fn test_propose_contract_max_size_upload() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; dbg!(contract.id()); // check that we can propose an update with the maximum contract size. @@ -77,7 +77,7 @@ async fn test_propose_update_config() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let threshold = assert_running_return_threshold(&contract).await; dbg!(contract.id()); @@ -183,7 +183,7 @@ async fn test_propose_update_contract() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; propose_and_vote_contract_binary(&mpc_signer_accounts, &contract, current_contract()).await; } @@ -193,7 +193,7 @@ async fn test_invalid_contract_deploy() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; dbg!(contract.id()); const CONTRACT_DEPLOY: NearToken = NearToken::from_near(1); @@ -233,7 +233,7 @@ async fn test_propose_update_contract_many() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; dbg!(contract.id()); const PROPOSAL_COUNT: usize = 2; @@ -291,7 +291,7 @@ async fn test_vote_update_gas_before_threshold() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let execution = mpc_signer_accounts[0] .call(contract.id(), method_names::PROPOSE_UPDATE) @@ -365,7 +365,7 @@ async fn test_propose_incorrect_updates() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; dbg!(contract.id()); let dummy_config = contract_interface::types::InitConfig::default(); @@ -404,7 +404,7 @@ async fn many_sequential_updates() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, number_of_participants).await; + } = init_env(ALL_CURVES, number_of_participants).await; dbg!(contract.id()); let number_of_updates = 3; for _ in 0..number_of_updates { @@ -427,7 +427,7 @@ async fn only_one_vote_from_participant() { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, number_of_participants).await; + } = init_env(ALL_CURVES, number_of_participants).await; dbg!(contract.id()); let execution = mpc_signer_accounts[0] diff --git a/crates/contract/tests/sandbox/upgrade_to_current_contract.rs b/crates/contract/tests/sandbox/upgrade_to_current_contract.rs index 3dce69a7d..0453a2b9b 100644 --- a/crates/contract/tests/sandbox/upgrade_to_current_contract.rs +++ b/crates/contract/tests/sandbox/upgrade_to_current_contract.rs @@ -16,7 +16,7 @@ use contract_interface::types::ProtocolContractState; use mpc_contract::{ crypto_shared::CKDResponse, primitives::{ - domain::{DomainConfig, DomainPurpose, SignatureScheme}, + domain::{Curve, DomainConfig, DomainPurpose}, key_state::{EpochId, Keyset}, participants::Participants, thresholds::{Threshold, ThresholdParameters}, @@ -350,12 +350,12 @@ async fn upgrade_allows_new_request_types( let domains_to_add = [ DomainConfig { id: first_available_domain_id.into(), - scheme: SignatureScheme::Bls12381, + curve: Curve::Bls12381, purpose: DomainPurpose::CKD, }, DomainConfig { id: (first_available_domain_id + 1).into(), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }, ]; diff --git a/crates/contract/tests/sandbox/user_views.rs b/crates/contract/tests/sandbox/user_views.rs index 10fe71ea0..2bbcba322 100644 --- a/crates/contract/tests/sandbox/user_views.rs +++ b/crates/contract/tests/sandbox/user_views.rs @@ -1,5 +1,5 @@ use contract_interface::method_names; -use mpc_contract::primitives::domain::SignatureScheme; +use mpc_contract::primitives::domain::Curve; use near_sdk::{CurveType, PublicKey}; use serde_json::json; use std::str::FromStr; @@ -11,8 +11,7 @@ use crate::sandbox::{ #[tokio::test] async fn test_key_version() -> anyhow::Result<()> { - let SandboxTestSetup { contract, .. } = - init_env(&[SignatureScheme::Secp256k1], PARTICIPANT_LEN).await; + let SandboxTestSetup { contract, .. } = init_env(&[Curve::Secp256k1], PARTICIPANT_LEN).await; let version: u32 = contract .view(method_names::LATEST_KEY_VERSION) @@ -27,8 +26,7 @@ async fn test_key_version() -> anyhow::Result<()> { #[tokio::test] async fn test_public_key() -> anyhow::Result<()> { - let SandboxTestSetup { contract, .. } = - init_env(&[SignatureScheme::Secp256k1], PARTICIPANT_LEN).await; + let SandboxTestSetup { contract, .. } = init_env(&[Curve::Secp256k1], PARTICIPANT_LEN).await; let key: String = contract .view(method_names::PUBLIC_KEY) @@ -45,8 +43,7 @@ async fn test_public_key() -> anyhow::Result<()> { #[tokio::test] async fn test_derived_public_key() -> anyhow::Result<()> { - let SandboxTestSetup { contract, .. } = - init_env(&[SignatureScheme::Secp256k1], PARTICIPANT_LEN).await; + let SandboxTestSetup { contract, .. } = init_env(&[Curve::Secp256k1], PARTICIPANT_LEN).await; let key: String = contract .view(method_names::DERIVED_PUBLIC_KEY) diff --git a/crates/contract/tests/sandbox/utils/consts.rs b/crates/contract/tests/sandbox/utils/consts.rs index f25633780..5b2978841 100644 --- a/crates/contract/tests/sandbox/utils/consts.rs +++ b/crates/contract/tests/sandbox/utils/consts.rs @@ -1,15 +1,15 @@ use std::time::Duration; -use mpc_contract::primitives::domain::SignatureScheme; +use mpc_contract::primitives::domain::Curve; use near_sdk::{Gas, NearToken}; /* --- Protocol defaults --- */ pub const PARTICIPANT_LEN: usize = 10; -pub const ALL_SIGNATURE_SCHEMES: &[SignatureScheme; 4] = &[ - SignatureScheme::Secp256k1, - SignatureScheme::Ed25519, - SignatureScheme::Bls12381, - SignatureScheme::V2Secp256k1, +pub const ALL_CURVES: &[Curve; 4] = &[ + Curve::Secp256k1, + Curve::Ed25519, + Curve::Bls12381, + Curve::V2Secp256k1, ]; /* --- Gas constants --- */ diff --git a/crates/contract/tests/sandbox/utils/interface.rs b/crates/contract/tests/sandbox/utils/interface.rs index 48f607bcc..f4ecd8fe6 100644 --- a/crates/contract/tests/sandbox/utils/interface.rs +++ b/crates/contract/tests/sandbox/utils/interface.rs @@ -3,7 +3,7 @@ // needed anymore use contract_interface::types::{self as dtos}; use mpc_contract::primitives::{ - domain::SignatureScheme, + domain::Curve, participants::{ParticipantInfo, Participants}, }; @@ -15,13 +15,13 @@ pub(crate) trait IntoContractType { fn into_contract_type(self) -> ContractType; } -impl IntoInterfaceType for SignatureScheme { - fn into_interface_type(self) -> dtos::SignatureScheme { +impl IntoInterfaceType for Curve { + fn into_interface_type(self) -> dtos::Curve { match self { - SignatureScheme::Secp256k1 => dtos::SignatureScheme::Secp256k1, - SignatureScheme::Ed25519 => dtos::SignatureScheme::Ed25519, - SignatureScheme::Bls12381 => dtos::SignatureScheme::Bls12381, - SignatureScheme::V2Secp256k1 => dtos::SignatureScheme::V2Secp256k1, + Curve::Secp256k1 => dtos::Curve::Secp256k1, + Curve::Ed25519 => dtos::Curve::Ed25519, + Curve::Bls12381 => dtos::Curve::Bls12381, + Curve::V2Secp256k1 => dtos::Curve::V2Secp256k1, } } } diff --git a/crates/contract/tests/sandbox/utils/shared_key_utils.rs b/crates/contract/tests/sandbox/utils/shared_key_utils.rs index b60be9d59..e024430ec 100644 --- a/crates/contract/tests/sandbox/utils/shared_key_utils.rs +++ b/crates/contract/tests/sandbox/utils/shared_key_utils.rs @@ -3,7 +3,7 @@ use k256::elliptic_curve::{Field as _, Group as _, PrimeField as _}; use mpc_contract::{ crypto_shared::types::PublicKeyExtended, primitives::{ - domain::{DomainConfig, DomainId, SignatureScheme}, + domain::{Curve, DomainConfig, DomainId}, signature::Tweak, }, }; @@ -57,17 +57,17 @@ pub fn new_secp256k1() -> (dtos::PublicKey, ts_ecdsa::KeygenOutput) { (pk, keygen_output) } -pub fn make_key_for_domain(domain_scheme: SignatureScheme) -> (dtos::PublicKey, SharedSecretKey) { - match domain_scheme { - SignatureScheme::Secp256k1 | SignatureScheme::V2Secp256k1 => { +pub fn make_key_for_domain(domain_curve: Curve) -> (dtos::PublicKey, SharedSecretKey) { + match domain_curve { + Curve::Secp256k1 | Curve::V2Secp256k1 => { let (pk, sk) = new_secp256k1(); (pk, SharedSecretKey::Secp256k1(sk)) } - SignatureScheme::Ed25519 => { + Curve::Ed25519 => { let (pk, sk) = new_ed25519(); (pk, SharedSecretKey::Ed25519(sk)) } - SignatureScheme::Bls12381 => { + Curve::Bls12381 => { let (pk, sk) = new_bls12381(); (pk, SharedSecretKey::Bls12381(sk)) } diff --git a/crates/contract/tests/sandbox/vote.rs b/crates/contract/tests/sandbox/vote.rs index 84d496fd7..178bbf8f7 100644 --- a/crates/contract/tests/sandbox/vote.rs +++ b/crates/contract/tests/sandbox/vote.rs @@ -5,7 +5,7 @@ use crate::sandbox::{ SandboxTestSetup, }, utils::{ - consts::{ALL_SIGNATURE_SCHEMES, GAS_FOR_VOTE_CANCEL_KEYGEN, PARTICIPANT_LEN}, + consts::{ALL_CURVES, GAS_FOR_VOTE_CANCEL_KEYGEN, PARTICIPANT_LEN}, initializing_utils::{start_keygen_instance, vote_add_domains, vote_public_key}, interface::{IntoContractType, IntoInterfaceType}, mpc_contract::get_state, @@ -19,7 +19,7 @@ use dtos::{AttemptId, KeyEventId, ProtocolContractState, RunningContractState}; use mpc_contract::{ errors::InvalidParameters, primitives::{ - domain::{infer_purpose_from_scheme, DomainConfig, DomainPurpose, SignatureScheme}, + domain::{infer_purpose_from_curve, Curve, DomainConfig, DomainPurpose}, thresholds::{Threshold, ThresholdParameters}, }, }; @@ -33,14 +33,14 @@ async fn test_keygen() -> anyhow::Result<()> { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let init_state = get_state(&contract).await; let ProtocolContractState::Running(ref init_running) = init_state else { panic!("expected running state"); }; let epoch_id = init_running.keyset.epoch_id; let domain_id = init_running.domains.next_domain_id; - let scheme = SignatureScheme::Ed25519; + let curve = Curve::Ed25519; // vote to add the domain and verify we enter initializing state vote_add_domains( @@ -48,7 +48,7 @@ async fn test_keygen() -> anyhow::Result<()> { &mpc_signer_accounts, &[DomainConfig { id: domain_id.into(), - scheme, + curve, purpose: DomainPurpose::Sign, }], ) @@ -61,7 +61,7 @@ async fn test_keygen() -> anyhow::Result<()> { assert_eq!(init.domains.next_domain_id, domain_id + 1); let expected_domain = dtos::DomainConfig { id: dtos::DomainId(domain_id), - scheme: scheme.into_interface_type(), + curve: curve.into_interface_type(), purpose: Some(dtos::DomainPurpose::Sign), }; let found = init @@ -111,10 +111,7 @@ async fn test_keygen() -> anyhow::Result<()> { found_key, near_sdk::PublicKey::try_from(public_key.clone()).unwrap() ); - assert_eq!( - running.domains.domains.len(), - ALL_SIGNATURE_SCHEMES.len() + 1 - ); + assert_eq!(running.domains.domains.len(), ALL_CURVES.len() + 1); // assert that the epoch id did not change assert_eq!(running.keyset.epoch_id, epoch_id); @@ -137,14 +134,14 @@ async fn test_cancel_keygen() -> anyhow::Result<()> { contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let init_state = get_state(&contract).await; let ProtocolContractState::Running(ref init_running) = init_state else { panic!("expected running state"); }; let epoch_id: u64 = init_running.keyset.epoch_id.0; let mut next_domain_id: u64 = init_running.domains.next_domain_id; - for scheme in ALL_SIGNATURE_SCHEMES { + for curve in ALL_CURVES { let threshold = init_running.parameters.threshold.0 as usize; // vote to start key generation @@ -153,8 +150,8 @@ async fn test_cancel_keygen() -> anyhow::Result<()> { &mpc_signer_accounts, &[DomainConfig { id: next_domain_id.into(), - scheme: *scheme, - purpose: infer_purpose_from_scheme(*scheme), + curve: *curve, + purpose: infer_purpose_from_curve(*curve), }], ) .await @@ -165,13 +162,13 @@ async fn test_cancel_keygen() -> anyhow::Result<()> { panic!("expected initializing state"); }; assert_eq!(init.domains.next_domain_id, next_domain_id + 1); - let expected_purpose = match scheme { - SignatureScheme::Bls12381 => dtos::DomainPurpose::CKD, + let expected_purpose = match curve { + Curve::Bls12381 => dtos::DomainPurpose::CKD, _ => dtos::DomainPurpose::Sign, }; let expected_domain = dtos::DomainConfig { id: dtos::DomainId(next_domain_id), - scheme: (*scheme).into_interface_type(), + curve: (*curve).into_interface_type(), purpose: Some(expected_purpose), }; let found = init @@ -206,7 +203,7 @@ async fn test_cancel_keygen() -> anyhow::Result<()> { .all(|k| k.domain_id.0 != next_domain_id), "No key should be registered for the cancelled domain" ); - assert_eq!(running.domains.domains.len(), ALL_SIGNATURE_SCHEMES.len()); + assert_eq!(running.domains.domains.len(), ALL_CURVES.len()); // verify that the contract's `public_key` view method fails for the cancelled domain let public_key_result = contract @@ -324,7 +321,7 @@ async fn setup_resharing_state( contract, mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, number_of_participants).await; + } = init_env(ALL_CURVES, number_of_participants).await; let state: ProtocolContractState = get_state(&contract).await; let ProtocolContractState::Running(initial_running_state) = state else { @@ -755,7 +752,7 @@ async fn vote_new_parameters_errors_if_new_participant_is_missing_valid_attestat contract, mut mpc_signer_accounts, .. - } = init_env(ALL_SIGNATURE_SCHEMES, PARTICIPANT_LEN).await; + } = init_env(ALL_CURVES, PARTICIPANT_LEN).await; let state = get_state(&contract).await; let ProtocolContractState::Running(ref running_state) = state else { diff --git a/crates/devnet/src/contracts.rs b/crates/devnet/src/contracts.rs index 509de749e..a32720812 100644 --- a/crates/devnet/src/contracts.rs +++ b/crates/devnet/src/contracts.rs @@ -6,7 +6,7 @@ use contract_interface::{ }; use mpc_contract::primitives::{ ckd::CKDRequestArgs, - domain::{DomainConfig, SignatureScheme}, + domain::{Curve, DomainConfig}, signature::{Bytes, Payload, SignRequestArgs}, }; use near_account_id::AccountId; @@ -53,14 +53,14 @@ pub fn make_actions(call: ContractActionCall) -> ActionCall { let mut eddsa_calls_by_domain = BTreeMap::new(); let mut ckd_calls_by_domain = BTreeMap::new(); for (domain, prot_calls) in args.calls_by_domain { - match domain.scheme { - SignatureScheme::Secp256k1 | SignatureScheme::V2Secp256k1 => { + match domain.curve { + Curve::Secp256k1 | Curve::V2Secp256k1 => { ecdsa_calls_by_domain.insert(domain.id.0, prot_calls); } - SignatureScheme::Ed25519 => { + Curve::Ed25519 => { eddsa_calls_by_domain.insert(domain.id.0, prot_calls); } - SignatureScheme::Bls12381 => { + Curve::Bls12381 => { ckd_calls_by_domain.insert(domain.id.0, prot_calls); } } @@ -90,7 +90,7 @@ pub fn make_actions(call: ContractActionCall) -> ActionCall { request: SignRequestArgs { domain_id: Some(args.domain_config.id), path: "".to_string(), - payload_v2: Some(make_payload(args.domain_config.scheme)), + payload_v2: Some(make_payload(args.domain_config.curve)), ..Default::default() }, }) @@ -165,12 +165,12 @@ struct ParallelSignArgsV2 { seed: u64, } -fn make_payload(scheme: SignatureScheme) -> Payload { - match scheme { - SignatureScheme::Secp256k1 | SignatureScheme::V2Secp256k1 => { +fn make_payload(curve: Curve) -> Payload { + match curve { + Curve::Secp256k1 | Curve::V2Secp256k1 => { Payload::Ecdsa(Bytes::new(rand::random::<[u8; 32]>().to_vec()).unwrap()) } - SignatureScheme::Ed25519 => { + Curve::Ed25519 => { let len = rand::random_range( EDDSA_PAYLOAD_SIZE_LOWER_BOUND_BYTES..=EDDSA_PAYLOAD_SIZE_UPPER_BOUND_BYTES, ); @@ -178,8 +178,8 @@ fn make_payload(scheme: SignatureScheme) -> Payload { rand::rng().fill_bytes(&mut payload); Payload::Eddsa(Bytes::new(payload).unwrap()) } - SignatureScheme::Bls12381 => { - unreachable!("make_payload should not be called with `Bls12381` scheme") + Curve::Bls12381 => { + unreachable!("make_payload should not be called with `Bls12381` curve") } } } diff --git a/crates/devnet/src/loadtest.rs b/crates/devnet/src/loadtest.rs index 1e234c94d..9f45140ae 100644 --- a/crates/devnet/src/loadtest.rs +++ b/crates/devnet/src/loadtest.rs @@ -13,7 +13,7 @@ use crate::types::{LoadtestSetup, NearAccount, ParsedConfig}; use anyhow::anyhow; use futures::future::BoxFuture; use futures::FutureExt; -use mpc_contract::primitives::domain::{DomainConfig, DomainId, SignatureScheme}; +use mpc_contract::primitives::domain::{Curve, DomainConfig, DomainId}; use near_jsonrpc_client::methods::send_tx; use near_jsonrpc_client::methods::tx::{RpcTransactionResponse, TransactionInfo}; use near_jsonrpc_client::methods::EXPERIMENTAL_tx_status::RpcTransactionStatusRequest; @@ -281,16 +281,14 @@ impl RunLoadtestCmd { let domain_config = contract_state .get_domain_config(DomainId(domain_id)) .expect("require valid domain id"); - match domain_config.scheme { - SignatureScheme::Bls12381 => { + match domain_config.curve { + Curve::Bls12381 => { ContractActionCall::Ckd(crate::contracts::RequestActionCallArgs { mpc_contract: mpc_account, domain_config, }) } - SignatureScheme::Ed25519 - | SignatureScheme::Secp256k1 - | SignatureScheme::V2Secp256k1 => { + Curve::Ed25519 | Curve::Secp256k1 | Curve::V2Secp256k1 => { ContractActionCall::Sign(crate::contracts::RequestActionCallArgs { mpc_contract: mpc_account, domain_config, diff --git a/crates/devnet/src/mpc.rs b/crates/devnet/src/mpc.rs index 2e1eecebd..ecafbdd36 100644 --- a/crates/devnet/src/mpc.rs +++ b/crates/devnet/src/mpc.rs @@ -21,7 +21,7 @@ use ed25519_dalek::{SigningKey, VerifyingKey}; use mpc_contract::tee::proposal::MpcDockerImageHash; use mpc_contract::{ primitives::{ - domain::{infer_purpose_from_scheme, DomainConfig, DomainId, SignatureScheme}, + domain::{infer_purpose_from_scheme, Curve, DomainConfig, DomainId}, key_state::EpochId, participants::{ParticipantInfo, Participants}, thresholds::{Threshold, ThresholdParameters}, @@ -578,7 +578,7 @@ impl MpcVoteAddDomainsCmd { "Going to vote_add_domains MPC network {} for signature schemes {:?}", name, self.schemes ); - let schemes: Vec = self + let schemes: Vec = self .schemes .iter() .map(|scheme| { @@ -615,7 +615,7 @@ impl MpcVoteAddDomainsCmd { for scheme in &schemes { proposal.push(DomainConfig { id: DomainId(next_domain), - scheme: *scheme, + curve: *scheme, purpose: infer_purpose_from_scheme(*scheme), }); next_domain += 1; diff --git a/crates/node/src/coordinator.rs b/crates/node/src/coordinator.rs index d15515b9e..e409adb57 100644 --- a/crates/node/src/coordinator.rs +++ b/crates/node/src/coordinator.rs @@ -33,7 +33,7 @@ use anyhow::Context; use contract_interface::types as dtos; use futures::future::BoxFuture; use futures::FutureExt; -use mpc_contract::primitives::domain::{DomainId, SignatureScheme}; +use mpc_contract::primitives::domain::{Curve, DomainId}; use mpc_contract::primitives::key_state::EpochId; use near_time::Clock; use std::collections::HashMap; @@ -537,26 +537,26 @@ where DomainId, confidential_key_derivation::KeygenOutput, > = HashMap::new(); - let mut domain_to_scheme: HashMap = HashMap::new(); + let mut domain_to_curve: HashMap = HashMap::new(); for keyshare in keyshares { let domain_id = keyshare.key_id.domain_id; match keyshare.data { KeyshareData::Secp256k1(data) => { ecdsa_keyshares.insert(keyshare.key_id.domain_id, data); - domain_to_scheme.insert(domain_id, SignatureScheme::Secp256k1); + domain_to_curve.insert(domain_id, Curve::Secp256k1); } KeyshareData::Ed25519(data) => { eddsa_keyshares.insert(keyshare.key_id.domain_id, data); - domain_to_scheme.insert(domain_id, SignatureScheme::Ed25519); + domain_to_curve.insert(domain_id, Curve::Ed25519); } KeyshareData::Bls12381(data) => { ckd_keyshares.insert(keyshare.key_id.domain_id, data); - domain_to_scheme.insert(domain_id, SignatureScheme::Bls12381); + domain_to_curve.insert(domain_id, Curve::Bls12381); } KeyshareData::V2Secp256k1(data) => { robust_ecdsa_keyshares.insert(keyshare.key_id.domain_id, data); - domain_to_scheme.insert(domain_id, SignatureScheme::V2Secp256k1); + domain_to_curve.insert(domain_id, Curve::V2Secp256k1); } } } @@ -619,7 +619,7 @@ where eddsa_signature_provider, ckd_provider, verify_foreign_tx_provider, - domain_to_scheme, + domain_to_curve, )); mpc_client diff --git a/crates/node/src/key_events.rs b/crates/node/src/key_events.rs index 84dda0d4c..9c31795e8 100644 --- a/crates/node/src/key_events.rs +++ b/crates/node/src/key_events.rs @@ -21,7 +21,7 @@ use crate::{ }, }; use contract_interface::types as dtos; -use mpc_contract::primitives::domain::{DomainConfig, SignatureScheme}; +use mpc_contract::primitives::domain::{Curve, DomainConfig}; use mpc_contract::primitives::key_state::{KeyEventId, KeyForDomain, Keyset}; use std::sync::Arc; use std::time::Duration; @@ -58,8 +58,8 @@ pub async fn keygen_computation_inner( key_id ); - let (keyshare, public_key) = match domain.scheme { - SignatureScheme::Secp256k1 => { + let (keyshare, public_key) = match domain.curve { + Curve::Secp256k1 => { let keyshare = EcdsaSignatureProvider::run_key_generation_client(threshold, channel).await?; let public_key = dtos::PublicKey::Secp256k1(dtos::Secp256k1PublicKey::try_from( @@ -67,7 +67,7 @@ pub async fn keygen_computation_inner( )?); (KeyshareData::Secp256k1(keyshare), public_key) } - SignatureScheme::V2Secp256k1 => { + Curve::V2Secp256k1 => { let keyshare = RobustEcdsaSignatureProvider::run_key_generation_client(threshold, channel).await?; let public_key = dtos::PublicKey::Secp256k1(dtos::Secp256k1PublicKey::try_from( @@ -75,7 +75,7 @@ pub async fn keygen_computation_inner( )?); (KeyshareData::V2Secp256k1(keyshare), public_key) } - SignatureScheme::Ed25519 => { + Curve::Ed25519 => { let keyshare = EddsaSignatureProvider::run_key_generation_client(threshold, channel).await?; let public_key = dtos::PublicKey::Ed25519(dtos::Ed25519PublicKey::from( @@ -83,7 +83,7 @@ pub async fn keygen_computation_inner( )); (KeyshareData::Ed25519(keyshare), public_key) } - SignatureScheme::Bls12381 => { + Curve::Bls12381 => { let keyshare = CKDProvider::run_key_generation_client(threshold, channel).await?; let public_key = dtos::PublicKey::Bls12381(dtos::Bls12381G2PublicKey::from( &keyshare.public_key.to_element(), @@ -210,11 +210,8 @@ async fn resharing_computation_inner( let public_key = dtos::PublicKey::from(previous_public_key.clone()); - let keyshare_data = match (public_key, domain.scheme) { - ( - contract_interface::types::PublicKey::Secp256k1(inner_public_key), - SignatureScheme::Secp256k1, - ) => { + let keyshare_data = match (public_key, domain.curve) { + (contract_interface::types::PublicKey::Secp256k1(inner_public_key), Curve::Secp256k1) => { let pk = k256::PublicKey::try_from(&inner_public_key)?; let public_key = frost_secp256k1::VerifyingKey::new(pk.to_projective()); let my_share = existing_keyshare @@ -233,10 +230,7 @@ async fn resharing_computation_inner( .await?; KeyshareData::Secp256k1(res) } - ( - contract_interface::types::PublicKey::Secp256k1(inner_public_key), - SignatureScheme::V2Secp256k1, - ) => { + (contract_interface::types::PublicKey::Secp256k1(inner_public_key), Curve::V2Secp256k1) => { let pk = k256::PublicKey::try_from(&inner_public_key)?; let public_key = frost_secp256k1::VerifyingKey::new(pk.to_projective()); let my_share = existing_keyshare @@ -255,10 +249,7 @@ async fn resharing_computation_inner( .await?; KeyshareData::V2Secp256k1(res) } - ( - contract_interface::types::PublicKey::Ed25519(inner_public_key), - SignatureScheme::Ed25519, - ) => { + (contract_interface::types::PublicKey::Ed25519(inner_public_key), Curve::Ed25519) => { let public_key = frost_ed25519::VerifyingKey::deserialize(inner_public_key.as_ref())?; let my_share = existing_keyshare .map(|keyshare| match keyshare.data { @@ -276,7 +267,7 @@ async fn resharing_computation_inner( .await?; KeyshareData::Ed25519(res) } - (dtos::PublicKey::Bls12381(inner_public_key), SignatureScheme::Bls12381) => { + (dtos::PublicKey::Bls12381(inner_public_key), Curve::Bls12381) => { let public_key = ckd::VerifyingKey::new(ckd::ElementG2::try_from(&inner_public_key)?); let my_share = existing_keyshare .map(|keyshare| match keyshare.data { @@ -294,11 +285,11 @@ async fn resharing_computation_inner( .await?; KeyshareData::Bls12381(res) } - (public_key, scheme) => { + (public_key, curve) => { return Err(anyhow::anyhow!( "Unexpected pair of ({:?}, {:?})", public_key, - scheme + curve )); } }; @@ -721,9 +712,7 @@ mod tests { use crate::indexer::participants::{ContractKeyEventInstance, KeyEventIdComparisonResult}; use crate::indexer::tx_sender::{TransactionProcessorError, TransactionStatus}; use crate::keyshare::KeyStorageConfig; - use mpc_contract::primitives::domain::{ - DomainConfig, DomainId, DomainPurpose, SignatureScheme, - }; + use mpc_contract::primitives::domain::{Curve, DomainConfig, DomainId, DomainPurpose}; use mpc_contract::primitives::key_state::{AttemptId, EpochId, KeyEventId}; use std::collections::BTreeSet; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -882,7 +871,7 @@ mod tests { id: key_event_id, domain: DomainConfig { id: key_event_id.domain_id, - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }, started, diff --git a/crates/node/src/mpc_client.rs b/crates/node/src/mpc_client.rs index 880a141b6..447e67667 100644 --- a/crates/node/src/mpc_client.rs +++ b/crates/node/src/mpc_client.rs @@ -27,7 +27,7 @@ use crate::types::{CKDRequest, VerifyForeignTxRequest}; use crate::web::{DebugRequest, DebugRequestKind}; use mpc_contract::crypto_shared::{derive_tweak, CKDResponse}; -use mpc_contract::primitives::domain::{DomainId, SignatureScheme}; +use mpc_contract::primitives::domain::{Curve, DomainId}; use near_time::Clock; use std::collections::HashMap; use std::sync::Arc; @@ -56,7 +56,7 @@ pub struct MpcClient { eddsa_signature_provider: Arc, ckd_provider: Arc, verify_foreign_tx_provider: Arc>, - domain_to_scheme: HashMap, + domain_to_curve: HashMap, } impl MpcClient @@ -75,7 +75,7 @@ where eddsa_signature_provider: Arc, ckd_provider: Arc, verify_foreign_tx_provider: Arc>, - domain_to_scheme: HashMap, + domain_to_curve: HashMap, ) -> Self { Self { config, @@ -88,7 +88,7 @@ where eddsa_signature_provider, ckd_provider, verify_foreign_tx_provider, - domain_to_scheme, + domain_to_curve, } } @@ -385,10 +385,10 @@ where .inc(); let response = match this - .domain_to_scheme + .domain_to_curve .get(&signature_attempt.request.domain) { - Some(SignatureScheme::Secp256k1) => { + Some(Curve::Secp256k1) => { let (signature, public_key) = timeout( Duration::from_secs(this.config.signature.timeout_sec), this.ecdsa_signature_provider @@ -405,7 +405,7 @@ where Ok(response) } - Some(SignatureScheme::Ed25519) => { + Some(Curve::Ed25519) => { let (signature, _) = timeout( Duration::from_secs(this.config.signature.timeout_sec), this.eddsa_signature_provider @@ -421,11 +421,11 @@ where Ok(response) } - Some(SignatureScheme::Bls12381) => Err(anyhow::anyhow!( + Some(Curve::Bls12381) => Err(anyhow::anyhow!( "Incorrect protocol for domain: {:?}", signature_attempt.request.domain.clone() )), - Some(SignatureScheme::V2Secp256k1) => { + Some(Curve::V2Secp256k1) => { let (signature, public_key) = timeout( Duration::from_secs(this.config.signature.timeout_sec), this.robust_ecdsa_signature_provider @@ -500,39 +500,40 @@ where ]) .inc(); - let response = - match this.domain_to_scheme.get(&ckd_attempt.request.domain_id) - { - Some(SignatureScheme::Bls12381) => { - let response = timeout( - Duration::from_secs(this.config.ckd.timeout_sec), - this.ckd_provider - .clone() - .make_signature(ckd_attempt.request.id), - ) - .await??; - - let response = ChainCKDRespondArgs::new_ckd( - &ckd_attempt.request, - &CKDResponse { - big_y: (&response.0 .0).into(), - big_c: (&response.0 .1).into(), - }, - )?; + let response = match this + .domain_to_curve + .get(&ckd_attempt.request.domain_id) + { + Some(Curve::Bls12381) => { + let response = timeout( + Duration::from_secs(this.config.ckd.timeout_sec), + this.ckd_provider + .clone() + .make_signature(ckd_attempt.request.id), + ) + .await??; + + let response = ChainCKDRespondArgs::new_ckd( + &ckd_attempt.request, + &CKDResponse { + big_y: (&response.0 .0).into(), + big_c: (&response.0 .1).into(), + }, + )?; - Ok(response) - } - Some(SignatureScheme::Secp256k1) - | Some(SignatureScheme::V2Secp256k1) - | Some(SignatureScheme::Ed25519) => Err(anyhow::anyhow!( - "Signature scheme is not allowed for domain: {:?}", - ckd_attempt.request.domain_id.clone() - )), - None => Err(anyhow::anyhow!( - "Signature scheme is not found for domain: {:?}", - ckd_attempt.request.domain_id.clone() - )), - }?; + Ok(response) + } + Some(Curve::Secp256k1) + | Some(Curve::V2Secp256k1) + | Some(Curve::Ed25519) => Err(anyhow::anyhow!( + "Signature scheme is not allowed for domain: {:?}", + ckd_attempt.request.domain_id.clone() + )), + None => Err(anyhow::anyhow!( + "Signature scheme is not found for domain: {:?}", + ckd_attempt.request.domain_id.clone() + )), + }?; metrics::MPC_NUM_CKD_COMPUTATIONS_LED .with_label_values(&[ @@ -591,10 +592,10 @@ where .inc(); let response = match this - .domain_to_scheme + .domain_to_curve .get(&verify_foreign_tx_attempt.request.domain_id) { - Some(SignatureScheme::Secp256k1) => { + Some(Curve::Secp256k1) => { let response = timeout( Duration::from_secs(this.config.signature.timeout_sec), this.verify_foreign_tx_provider.clone().make_signature( @@ -614,9 +615,9 @@ where Ok(response) } - Some(SignatureScheme::Bls12381) - | Some(SignatureScheme::V2Secp256k1) - | Some(SignatureScheme::Ed25519) => Err(anyhow::anyhow!( + Some(Curve::Bls12381) + | Some(Curve::V2Secp256k1) + | Some(Curve::Ed25519) => Err(anyhow::anyhow!( "Signature scheme is not allowed for domain: {:?}", verify_foreign_tx_attempt.request.domain_id.clone() )), diff --git a/crates/node/src/tests.rs b/crates/node/src/tests.rs index 063d359c9..f14d51797 100644 --- a/crates/node/src/tests.rs +++ b/crates/node/src/tests.rs @@ -33,7 +33,7 @@ use crate::tests::common::MockTransactionSender; use crate::tracking::{self, start_root_task, AutoAbortTask}; use crate::web::{start_web_server, static_web_data}; use assert_matches::assert_matches; -use mpc_contract::primitives::domain::{DomainConfig, SignatureScheme}; +use mpc_contract::primitives::domain::{Curve, DomainConfig}; use mpc_contract::primitives::signature::{Bytes, Payload}; use near_account_id::AccountId; use near_indexer_primitives::types::Finality; @@ -272,13 +272,13 @@ pub async fn request_signature_and_await_response( domain: &DomainConfig, timeout_sec: std::time::Duration, ) -> Option { - let payload = match domain.scheme { - SignatureScheme::Secp256k1 | SignatureScheme::V2Secp256k1 => { + let payload = match domain.curve { + Curve::Secp256k1 | Curve::V2Secp256k1 => { let mut payload = [0; 32]; rand::thread_rng().fill_bytes(payload.as_mut()); Payload::Ecdsa(Bytes::new(payload.to_vec()).unwrap()) } - SignatureScheme::Ed25519 => { + Curve::Ed25519 => { let len = rand::thread_rng().gen_range( EDDSA_PAYLOAD_SIZE_LOWER_BOUND_BYTES..EDDSA_PAYLOAD_SIZE_UPPER_BOUND_BYTES, ); @@ -286,7 +286,7 @@ pub async fn request_signature_and_await_response( rand::thread_rng().fill_bytes(payload.as_mut()); Payload::Eddsa(Bytes::new(payload.to_vec()).unwrap()) } - SignatureScheme::Bls12381 => unreachable!(), + Curve::Bls12381 => unreachable!(), }; let request = SignatureRequestFromChain { entropy: rand::random(), @@ -354,8 +354,8 @@ pub async fn request_ckd_and_await_response( timeout_sec: std::time::Duration, ) -> Option { assert_matches!( - domain.scheme, - SignatureScheme::Bls12381, + domain.curve, + Curve::Bls12381, "`request_ckd_and_await_response` must be called with a compatible domain", ); let request = CKDRequestFromChain { @@ -440,8 +440,8 @@ pub async fn request_verify_foreign_tx_and_await_response( timeout_sec: std::time::Duration, ) -> Option { assert_matches!( - domain.scheme, - SignatureScheme::Secp256k1, + domain.curve, + Curve::Secp256k1, "`request_ckd_and_await_response` must be called with a compatible domain", ); let request = VerifyForeignTxRequestFromChain { diff --git a/crates/node/src/tests/basic_cluster.rs b/crates/node/src/tests/basic_cluster.rs index ea702aac7..3d0fee184 100644 --- a/crates/node/src/tests/basic_cluster.rs +++ b/crates/node/src/tests/basic_cluster.rs @@ -5,7 +5,7 @@ use crate::tests::{ DEFAULT_BLOCK_TIME, DEFAULT_MAX_PROTOCOL_WAIT_TIME, DEFAULT_MAX_SIGNATURE_WAIT_TIME, }; use crate::tracking::AutoAbortTask; -use mpc_contract::primitives::domain::{DomainConfig, DomainId, DomainPurpose, SignatureScheme}; +use mpc_contract::primitives::domain::{Curve, DomainConfig, DomainId, DomainPurpose}; use near_time::Clock; // Make a cluster of four nodes, test that we can generate keyshares @@ -31,19 +31,19 @@ async fn test_basic_cluster() { let signature_domain_ecdsa = DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }; let signature_domain_eddsa = DomainConfig { id: DomainId(1), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }; let ckd_domain = DomainConfig { id: DomainId(2), - scheme: SignatureScheme::Bls12381, + curve: Curve::Bls12381, purpose: DomainPurpose::CKD, }; diff --git a/crates/node/src/tests/changing_participant_details.rs b/crates/node/src/tests/changing_participant_details.rs index 42913d99a..954f65731 100644 --- a/crates/node/src/tests/changing_participant_details.rs +++ b/crates/node/src/tests/changing_participant_details.rs @@ -7,7 +7,7 @@ use crate::tests::{ }; use crate::tests::{make_key_storage_config, DEFAULT_BLOCK_TIME}; use crate::tracking::AutoAbortTask; -use mpc_contract::primitives::domain::{DomainConfig, DomainId, DomainPurpose, SignatureScheme}; +use mpc_contract::primitives::domain::{Curve, DomainConfig, DomainId, DomainPurpose}; use mpc_contract::state::ProtocolContractState; use near_time::Clock; @@ -48,7 +48,7 @@ async fn test_changing_participant_set_test_keyshare_import() { let domain = DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }; diff --git a/crates/node/src/tests/faulty.rs b/crates/node/src/tests/faulty.rs index a884b1d88..8e0447443 100644 --- a/crates/node/src/tests/faulty.rs +++ b/crates/node/src/tests/faulty.rs @@ -5,7 +5,7 @@ use crate::tests::{ DEFAULT_MAX_PROTOCOL_WAIT_TIME, DEFAULT_MAX_SIGNATURE_WAIT_TIME, }; use crate::tracking::AutoAbortTask; -use mpc_contract::primitives::domain::{DomainConfig, DomainId, DomainPurpose, SignatureScheme}; +use mpc_contract::primitives::domain::{Curve, DomainConfig, DomainId, DomainPurpose}; use near_account_id::AccountId; use near_time::Clock; use rand::Rng; @@ -36,7 +36,7 @@ async fn test_faulty_cluster() { let domain = DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }; @@ -171,7 +171,7 @@ async fn test_indexer_stuck() { let domain = DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }; diff --git a/crates/node/src/tests/multidomain.rs b/crates/node/src/tests/multidomain.rs index b28cf48b5..51ae83036 100644 --- a/crates/node/src/tests/multidomain.rs +++ b/crates/node/src/tests/multidomain.rs @@ -5,7 +5,7 @@ use crate::tests::{ DEFAULT_MAX_PROTOCOL_WAIT_TIME, DEFAULT_MAX_SIGNATURE_WAIT_TIME, }; use crate::tracking::AutoAbortTask; -use mpc_contract::primitives::domain::{DomainConfig, DomainId, DomainPurpose, SignatureScheme}; +use mpc_contract::primitives::domain::{Curve, DomainConfig, DomainId, DomainPurpose}; use near_time::Clock; // Make a cluster of four nodes, test that we can generate keyshares @@ -35,17 +35,17 @@ async fn test_basic_multidomain() { let mut domains = vec![ DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }, DomainConfig { id: DomainId(1), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }, DomainConfig { id: DomainId(2), - scheme: SignatureScheme::Bls12381, + curve: Curve::Bls12381, purpose: DomainPurpose::CKD, }, ]; @@ -73,10 +73,8 @@ async fn test_basic_multidomain() { tracing::info!("requesting signature"); for domain in &domains { - match domain.scheme { - SignatureScheme::Secp256k1 - | SignatureScheme::Ed25519 - | SignatureScheme::V2Secp256k1 => { + match domain.curve { + Curve::Secp256k1 | Curve::Ed25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), @@ -86,7 +84,7 @@ async fn test_basic_multidomain() { .await .is_some()); } - SignatureScheme::Bls12381 => { + Curve::Bls12381 => { assert!(request_ckd_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), @@ -101,17 +99,17 @@ async fn test_basic_multidomain() { let new_domains = vec![ DomainConfig { id: DomainId(3), - scheme: SignatureScheme::Ed25519, + curve: Curve::Ed25519, purpose: DomainPurpose::Sign, }, DomainConfig { id: DomainId(4), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }, DomainConfig { id: DomainId(5), - scheme: SignatureScheme::Bls12381, + curve: Curve::Bls12381, purpose: DomainPurpose::CKD, }, ]; @@ -140,10 +138,8 @@ async fn test_basic_multidomain() { .expect("must not exceed timeout"); for domain in &domains { - match domain.scheme { - SignatureScheme::Secp256k1 - | SignatureScheme::Ed25519 - | SignatureScheme::V2Secp256k1 => { + match domain.curve { + Curve::Secp256k1 | Curve::Ed25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), @@ -153,7 +149,7 @@ async fn test_basic_multidomain() { .await .is_some()); } - SignatureScheme::Bls12381 => { + Curve::Bls12381 => { assert!(request_ckd_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), @@ -189,10 +185,8 @@ async fn test_basic_multidomain() { .expect("must not exceed timeout"); for domain in &domains { - match domain.scheme { - SignatureScheme::Secp256k1 - | SignatureScheme::Ed25519 - | SignatureScheme::V2Secp256k1 => { + match domain.curve { + Curve::Secp256k1 | Curve::Ed25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), @@ -202,7 +196,7 @@ async fn test_basic_multidomain() { .await .is_some()); } - SignatureScheme::Bls12381 => { + Curve::Bls12381 => { assert!(request_ckd_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), diff --git a/crates/node/src/tests/onboarding.rs b/crates/node/src/tests/onboarding.rs index 2cc31a3bc..4759c2a17 100644 --- a/crates/node/src/tests/onboarding.rs +++ b/crates/node/src/tests/onboarding.rs @@ -17,7 +17,7 @@ use crate::tracking::AutoAbortTask; use contract_interface::types::Ed25519PublicKey; use ed25519_dalek::{SigningKey, VerifyingKey}; use mpc_contract::node_migrations::{BackupServiceInfo, DestinationNodeInfo}; -use mpc_contract::primitives::domain::{DomainConfig, DomainId, DomainPurpose, SignatureScheme}; +use mpc_contract::primitives::domain::{Curve, DomainConfig, DomainId, DomainPurpose}; use mpc_contract::state::ProtocolContractState; use near_time::Clock; use rand::rngs::OsRng; @@ -103,7 +103,7 @@ async fn test_onboarding() { let domain = DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }; diff --git a/crates/node/src/tests/resharing.rs b/crates/node/src/tests/resharing.rs index 8308106eb..4f9f1d28e 100644 --- a/crates/node/src/tests/resharing.rs +++ b/crates/node/src/tests/resharing.rs @@ -7,7 +7,7 @@ use crate::tests::{ }; use crate::tracking::AutoAbortTask; use mpc_contract::primitives::domain::{ - infer_purpose_from_scheme, DomainConfig, DomainId, DomainPurpose, SignatureScheme, + infer_purpose_from_curve, Curve, DomainConfig, DomainId, DomainPurpose, }; use near_time::Clock; use rstest::rstest; @@ -19,14 +19,14 @@ use super::DEFAULT_BLOCK_TIME; #[tokio::test] #[test_log::test] #[rstest] -#[case(0, SignatureScheme::Secp256k1, 3)] -#[case(1, SignatureScheme::Ed25519, 3)] -#[case(2, SignatureScheme::Bls12381, 3)] +#[case(0, Curve::Secp256k1, 3)] +#[case(1, Curve::Ed25519, 3)] +#[case(2, Curve::Bls12381, 3)] // TODO(#1946): re-enable once it is no longer flaky -// #[case(3, SignatureScheme::V2Secp256k1, 5)] +// #[case(3, Curve::V2Secp256k1, 5)] async fn test_key_resharing_simple( #[case] case: u16, - #[case] scheme: SignatureScheme, + #[case] curve: Curve, #[case] threshold: usize, ) { let num_participants: usize = threshold + 1; @@ -50,8 +50,8 @@ async fn test_key_resharing_simple( let domain = DomainConfig { id: DomainId(0), - scheme, - purpose: infer_purpose_from_scheme(scheme), + curve, + purpose: infer_purpose_from_curve(curve), }; { @@ -76,8 +76,8 @@ async fn test_key_resharing_simple( .expect("must not exceed timeout"); // Sanity check. - match domain.scheme { - SignatureScheme::Secp256k1 | SignatureScheme::Ed25519 | SignatureScheme::V2Secp256k1 => { + match domain.curve { + Curve::Secp256k1 | Curve::Ed25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, "user1", @@ -87,7 +87,7 @@ async fn test_key_resharing_simple( .await .is_some()); } - SignatureScheme::Bls12381 => { + Curve::Bls12381 => { assert!(request_ckd_and_await_response( &mut setup.indexer, "user1", @@ -120,8 +120,8 @@ async fn test_key_resharing_simple( .await .expect("Timeout waiting for resharing to complete"); - match domain.scheme { - SignatureScheme::Secp256k1 | SignatureScheme::Ed25519 | SignatureScheme::V2Secp256k1 => { + match domain.curve { + Curve::Secp256k1 | Curve::Ed25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, "user1", @@ -131,7 +131,7 @@ async fn test_key_resharing_simple( .await .is_some()); } - SignatureScheme::Bls12381 => { + Curve::Bls12381 => { assert!(request_ckd_and_await_response( &mut setup.indexer, "user1", @@ -172,7 +172,7 @@ async fn test_key_resharing_multistage() { let domain = DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }; @@ -377,7 +377,7 @@ async fn test_signature_requests_in_resharing_are_processed() { let domain = DomainConfig { id: DomainId(0), - scheme: SignatureScheme::Secp256k1, + curve: Curve::Secp256k1, purpose: DomainPurpose::Sign, }; From 756501ec68233bf50b3049725169e17291339528 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:32:44 +0100 Subject: [PATCH 02/21] infer-purpose-from-curve --- crates/devnet/src/mpc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/devnet/src/mpc.rs b/crates/devnet/src/mpc.rs index ecafbdd36..c3ccd6c71 100644 --- a/crates/devnet/src/mpc.rs +++ b/crates/devnet/src/mpc.rs @@ -21,7 +21,7 @@ use ed25519_dalek::{SigningKey, VerifyingKey}; use mpc_contract::tee::proposal::MpcDockerImageHash; use mpc_contract::{ primitives::{ - domain::{infer_purpose_from_scheme, Curve, DomainConfig, DomainId}, + domain::{infer_purpose_from_curve, Curve, DomainConfig, DomainId}, key_state::EpochId, participants::{ParticipantInfo, Participants}, thresholds::{Threshold, ThresholdParameters}, @@ -616,7 +616,7 @@ impl MpcVoteAddDomainsCmd { proposal.push(DomainConfig { id: DomainId(next_domain), curve: *scheme, - purpose: infer_purpose_from_scheme(*scheme), + purpose: infer_purpose_from_curve(*scheme), }); next_domain += 1; } From 09204d85fa844f7fd51ca1e445bd81bc467c8a73 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:34:02 +0100 Subject: [PATCH 03/21] Compatibility with serde --- crates/contract/src/primitives/domain.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/contract/src/primitives/domain.rs b/crates/contract/src/primitives/domain.rs index 476b61ffd..7132538a9 100644 --- a/crates/contract/src/primitives/domain.rs +++ b/crates/contract/src/primitives/domain.rs @@ -87,6 +87,7 @@ pub struct DomainConfig { #[derive(serde::Deserialize)] struct DomainConfigCompat { id: DomainId, + #[serde(alias = "scheme")] curve: Curve, #[serde(default)] purpose: Option, From 27ebb7535b164569cb51e4f5b17f92acfa16cbb7 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:44:11 +0100 Subject: [PATCH 04/21] rename instead of alias for backwards compat --- crates/contract-interface/src/types/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/contract-interface/src/types/state.rs b/crates/contract-interface/src/types/state.rs index 75a26ba93..d92309507 100644 --- a/crates/contract-interface/src/types/state.rs +++ b/crates/contract-interface/src/types/state.rs @@ -201,7 +201,7 @@ pub enum DomainPurpose { )] pub struct DomainConfig { pub id: DomainId, - #[serde(alias = "scheme")] + #[serde(rename = "scheme")] pub curve: Curve, /// `None` when reading state from an old contract that predates domain purposes. #[serde(default, skip_serializing_if = "Option::is_none")] From 3f1fabeb506c0a77aba0ee85cb58b8e894f7b291 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:44:48 +0100 Subject: [PATCH 05/21] Verifying alias still works --- crates/contract/src/primitives/domain.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/contract/src/primitives/domain.rs b/crates/contract/src/primitives/domain.rs index 7132538a9..f79684af5 100644 --- a/crates/contract/src/primitives/domain.rs +++ b/crates/contract/src/primitives/domain.rs @@ -426,6 +426,12 @@ pub mod tests { DomainPurpose::Sign )] #[case(r#"{"id":1,"curve":"Bls12381"}"#, Curve::Bls12381, DomainPurpose::CKD)] + // Old JSON used "scheme" as the key — verify the alias still works. + #[case( + r#"{"id":0,"scheme":"Secp256k1"}"#, + Curve::Secp256k1, + DomainPurpose::Sign + )] fn test_deserialization_without_purpose( #[case] json: &str, #[case] expected_curve: Curve, From 665dd0d8b9ab45ae9feb04bc2951522f4f69e0b6 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 13:09:03 +0100 Subject: [PATCH 06/21] No changes on the contract interface after speaking to Kevin --- crates/contract/src/dto_mapping.rs | 14 +- .../abi__abi_has_not_changed.snap.new | 3709 +++++++++++++++++ 2 files changed, 3716 insertions(+), 7 deletions(-) create mode 100644 crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new diff --git a/crates/contract/src/dto_mapping.rs b/crates/contract/src/dto_mapping.rs index 6c1b588e4..afde3a1eb 100644 --- a/crates/contract/src/dto_mapping.rs +++ b/crates/contract/src/dto_mapping.rs @@ -511,13 +511,13 @@ impl IntoInterfaceType for &AuthenticatedAccountId // --- Domain types --- -impl IntoInterfaceType for Curve { - fn into_dto_type(self) -> dtos::Curve { +impl IntoInterfaceType for Curve { + fn into_dto_type(self) -> dtos::SignatureScheme { match self { - Curve::Secp256k1 => dtos::Curve::Secp256k1, - Curve::Ed25519 => dtos::Curve::Ed25519, - Curve::Bls12381 => dtos::Curve::Bls12381, - Curve::V2Secp256k1 => dtos::Curve::V2Secp256k1, + Curve::Secp256k1 => dtos::SignatureScheme::Secp256k1, + Curve::Ed25519 => dtos::SignatureScheme::Ed25519, + Curve::Bls12381 => dtos::SignatureScheme::Bls12381, + Curve::V2Secp256k1 => dtos::SignatureScheme::V2Secp256k1, } } } @@ -526,7 +526,7 @@ impl IntoInterfaceType for &DomainConfig { fn into_dto_type(self) -> dtos::DomainConfig { dtos::DomainConfig { id: self.id.into_dto_type(), - curve: self.curve.into_dto_type(), + scheme: self.curve.into_dto_type(), purpose: Some(self.purpose), } } diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new new file mode 100644 index 000000000..58aaeb8d7 --- /dev/null +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new @@ -0,0 +1,3709 @@ +--- +source: crates/contract/tests/abi.rs +assertion_line: 49 +expression: abi +--- +{ + "schema_version": "0.4.0", + "metadata": { + "name": "mpc-contract", + "version": "3.6.0", + "build": { + "compiler": "rustc 1.86.0", + "builder": "[CARGO_NEAR_BUILD_VERSION]" + }, + "wasm_hash": "[WASM_HASH]" + }, + "body": { + "functions": [ + { + "name": "allowed_docker_image_hashes", + "doc": " Returns all allowed code hashes in order from most recent to least recent allowed code hashes. The first element is the most recent allowed code hash.", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + } + } + } + }, + { + "name": "allowed_launcher_compose_hashes", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + } + } + } + }, + { + "name": "clean_tee_status", + "doc": " Private endpoint to clean up TEE information for non-participants after resharing.\n This can only be called by the contract itself via a promise.", + "kind": "call", + "modifiers": [ + "private" + ], + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "cleanup_orphaned_node_migrations", + "kind": "call", + "modifiers": [ + "private" + ], + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "conclude_node_migration", + "doc": " Finalizes a node migration for the calling account.\n\n This method can only be called while the protocol is in a `Running` state\n and by an existing participant. On success, the participant’s information is\n updated to the new destination node.\n\n # Errors\n Returns the following errors:\n - `InvalidState::ProtocolStateNotRunning`: if protocol is not in `Running` state\n - `InvalidState::NotParticipant`: if caller is not a current participant\n - `NodeMigrationError::KeysetMismatch`: if provided keyset does not match the expected keyset\n - `NodeMigrationError::MigrationNotFound`: if no migration record exists for the caller\n - `NodeMigrationError::AccountPublicKeyMismatch`: if caller’s public key does not match the expected destination node\n - `InvalidParameters::InvalidTeeRemoteAttestation`: if destination node’s TEE quote is invalid", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "keyset", + "type_schema": { + "$ref": "#/definitions/Keyset" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "config", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/Config" + } + } + }, + { + "name": "contract_source_metadata", + "kind": "view" + }, + { + "name": "derived_public_key", + "doc": " This is the derived public key of the caller given path and predecessor\n if predecessor is not provided, it will be the caller of the contract.\n\n The domain parameter specifies which domain we're deriving the public key for;\n the default is the first domain.", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "path", + "type_schema": { + "type": "string" + } + }, + { + "name": "predecessor", + "type_schema": { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": [ + "string", + "null" + ] + } + }, + { + "name": "domain_id", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/DomainId" + }, + { + "type": "null" + } + ] + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PublicKey" + } + } + }, + { + "name": "fail_on_timeout", + "kind": "view", + "modifiers": [ + "private" + ] + }, + { + "name": "get_attestation", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "tls_public_key", + "type_schema": { + "$ref": "#/definitions/Ed25519PublicKey" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/VerifiedAttestation" + }, + { + "type": "null" + } + ] + } + } + }, + { + "name": "get_foreign_chain_policy", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/ForeignChainPolicy" + } + } + }, + { + "name": "get_foreign_chain_policy_proposals", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/ForeignChainPolicyVotes" + } + } + }, + { + "name": "get_pending_ckd_request", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/CKDRequest" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/YieldIndex" + }, + { + "type": "null" + } + ] + } + } + }, + { + "name": "get_pending_request", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/SignatureRequest" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/YieldIndex" + }, + { + "type": "null" + } + ] + } + } + }, + { + "name": "get_pending_verify_foreign_tx_request", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionRequest" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/YieldIndex" + }, + { + "type": "null" + } + ] + } + } + }, + { + "name": "get_tee_accounts", + "doc": " Returns all accounts that have TEE attestations stored in the contract.\n Note: This includes both current protocol participants and accounts that may have\n submitted TEE information but are not currently part of the active participant set.", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/NodeId" + } + } + } + }, + { + "name": "init", + "kind": "call", + "modifiers": [ + "init" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "parameters", + "type_schema": { + "$ref": "#/definitions/ThresholdParameters" + } + }, + { + "name": "init_config", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/InitConfig" + }, + { + "type": "null" + } + ] + } + } + ] + } + }, + { + "name": "init_running", + "kind": "call", + "modifiers": [ + "init", + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "domains", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/DomainConfig" + } + } + }, + { + "name": "next_domain_id", + "type_schema": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + { + "name": "keyset", + "type_schema": { + "$ref": "#/definitions/Keyset" + } + }, + { + "name": "parameters", + "type_schema": { + "$ref": "#/definitions/ThresholdParameters" + } + }, + { + "name": "init_config", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/InitConfig" + }, + { + "type": "null" + } + ] + } + } + ] + } + }, + { + "name": "latest_key_version", + "doc": " Key versions refer new versions of the root key that we may choose to generate on cohort\n changes. Older key versions will always work but newer key versions were never held by\n older signers. Newer key versions may also add new security features, like only existing\n within a secure enclave. The signature_scheme parameter specifies which protocol\n we're querying the latest version for. The default is Secp256k1. The default is **NOT**\n to query across all protocols.", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "signature_scheme", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/Curve" + }, + { + "type": "null" + } + ] + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + }, + { + "name": "metrics", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/Metrics" + } + } + }, + { + "name": "migrate", + "doc": " This will be called internally by the contract to migrate the state when a new contract\n is deployed. This function should be changed every time state is changed to do the proper\n migrate flow.\n\n If nothing is changed, then this function will just return the current state. If it fails\n to read the state, then it will return an error.", + "kind": "call", + "modifiers": [ + "init", + "private" + ] + }, + { + "name": "migration_info", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": [ + { + "anyOf": [ + { + "$ref": "#/definitions/BackupServiceInfo" + }, + { + "type": "null" + } + ] + }, + { + "anyOf": [ + { + "$ref": "#/definitions/DestinationNodeInfo" + }, + { + "type": "null" + } + ] + } + ], + "maxItems": 2, + "minItems": 2 + } + } + } + }, + { + "name": "propose_update", + "doc": " Propose update to either code or config, but not both of them at the same time.", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "borsh", + "args": [ + { + "name": "args", + "type_schema": { + "declaration": "ProposeUpdateArgs", + "definitions": { + "()": { + "Primitive": 0 + }, + "Config": { + "Struct": [ + [ + "key_event_timeout_blocks", + "u64" + ], + [ + "tee_upgrade_deadline_duration_seconds", + "u64" + ], + [ + "contract_upgrade_deposit_tera_gas", + "u64" + ], + [ + "sign_call_gas_attachment_requirement_tera_gas", + "u64" + ], + [ + "ckd_call_gas_attachment_requirement_tera_gas", + "u64" + ], + [ + "return_signature_and_clean_state_on_success_call_tera_gas", + "u64" + ], + [ + "return_ck_and_clean_state_on_success_call_tera_gas", + "u64" + ], + [ + "fail_on_timeout_tera_gas", + "u64" + ], + [ + "clean_tee_status_tera_gas", + "u64" + ], + [ + "cleanup_orphaned_node_migrations_tera_gas", + "u64" + ], + [ + "remove_non_participant_update_votes_tera_gas", + "u64" + ] + ] + }, + "Option": { + "Enum": { + "tag_width": 1, + "variants": [ + [ + 0, + "None", + "()" + ], + [ + 1, + "Some", + "Config" + ] + ] + } + }, + "Option>": { + "Enum": { + "tag_width": 1, + "variants": [ + [ + 0, + "None", + "()" + ], + [ + 1, + "Some", + "Vec" + ] + ] + } + }, + "ProposeUpdateArgs": { + "Struct": [ + [ + "code", + "Option>" + ], + [ + "config", + "Option" + ] + ] + }, + "Vec": { + "Sequence": { + "length_width": 4, + "length_range": { + "start": 0, + "end": 4294967295 + }, + "elements": "u8" + } + }, + "u64": { + "Primitive": 8 + }, + "u8": { + "Primitive": 1 + } + } + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/UpdateId" + } + } + }, + { + "name": "proposed_updates", + "doc": " returns all proposed updates", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/ProposedUpdates" + } + } + }, + { + "name": "public_key", + "doc": " This is the root public key combined from all the public keys of the participants.\n The domain parameter specifies which domain we're querying the public key for;\n the default is the first domain.", + "kind": "view", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "domain_id", + "type_schema": { + "anyOf": [ + { + "$ref": "#/definitions/DomainId" + }, + { + "type": "null" + } + ] + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PublicKey" + } + } + }, + { + "name": "register_backup_service", + "doc": " Registers or updates the backup service information for the caller account.\n\n The caller (`signer_account_id`) must be an existing or prospective participant.\n Otherwise, the transaction will fail.\n\n # Notes\n - A deposit requirement may be added in the future.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "backup_service_info", + "type_schema": { + "$ref": "#/definitions/BackupServiceInfo" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "remove_non_participant_update_votes", + "doc": " Cleans update votes from non-participants after resharing.\n Can be called by any participant or triggered automatically via promise.", + "kind": "call", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "remove_update_vote", + "doc": " Removes an update vote by the caller\n panics if the contract is not in a running state or if the caller is not a participant", + "kind": "call" + }, + { + "name": "request_app_private_key", + "doc": " To avoid overloading the network with too many requests,\n we ask for a small deposit for each ckd request.", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/CKDRequestArgs" + } + } + ] + } + }, + { + "name": "respond", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/SignatureRequest" + } + }, + { + "name": "response", + "type_schema": { + "$ref": "#/definitions/SignatureResponse" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "respond_ckd", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/CKDRequest" + } + }, + { + "name": "response", + "type_schema": { + "$ref": "#/definitions/CKDResponse" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "respond_verify_foreign_tx", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionRequest" + } + }, + { + "name": "response", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionResponse" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "return_ck_and_clean_state_on_success", + "doc": " Upon success, removes the confidential key request from state and returns it.\n If the ckd request times out, removes the ckd request from state and panics to fail the\n original transaction", + "kind": "call", + "modifiers": [ + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/CKDRequest" + } + } + ] + }, + "callbacks": [ + { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/CKDResponse" + } + } + ], + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PromiseOrValueCKDResponse" + } + } + }, + { + "name": "return_signature_and_clean_state_on_success", + "doc": " Upon success, removes the signature from state and returns it.\n If the signature request times out, removes the signature request from state and panics to\n fail the original transaction", + "kind": "call", + "modifiers": [ + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/SignatureRequest" + } + } + ] + }, + "callbacks": [ + { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/SignatureResponse" + } + } + ], + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PromiseOrValueSignatureResponse" + } + } + }, + { + "name": "return_verify_foreign_tx_and_clean_state_on_success", + "doc": " Upon success, removes the verify foreign tx request from state and returns it.\n If the verify foreign tx request times out, removes the verify foreign tx request from state and panics to fail the\n original transaction", + "kind": "call", + "modifiers": [ + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionRequest" + } + } + ] + }, + "callbacks": [ + { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionResponse" + } + } + ], + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/PromiseOrValueVerifyForeignTransactionResponse" + } + } + }, + { + "name": "sign", + "doc": " `key_version` must be less than or equal to the value at `latest_key_version`\n To avoid overloading the network with too many requests,\n we ask for a small deposit for each signature request.", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/SignRequestArgs" + } + } + ] + } + }, + { + "name": "start_keygen_instance", + "doc": " Starts a new attempt to generate a key for the current domain.\n This only succeeds if the signer is the leader (the participant with the lowest ID).", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "key_event_id", + "type_schema": { + "$ref": "#/definitions/KeyEventId" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "start_node_migration", + "doc": " Sets the destination node for the calling account.\n\n This function can only be called while the protocol is in a `Running` state.\n The signer must be a current participant of the current epoch, otherwise an error is returned.\n On success, the provided [`DestinationNodeInfo`] is stored in the contract state\n under the signer’s account ID.\n\n # Errors\n - [`InvalidState::ProtocolStateNotRunning`] if the protocol is not in the `Running` state. \n - [`InvalidState::NotParticipant`] if the signer is not a current participant.\n # Note:\n - might require a deposit", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "destination_node_info", + "type_schema": { + "$ref": "#/definitions/DestinationNodeInfo" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "start_reshare_instance", + "doc": " Starts a new attempt to reshare the key for the current domain.\n This only succeeds if the signer is the leader (the participant with the lowest ID).", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "key_event_id", + "type_schema": { + "$ref": "#/definitions/KeyEventId" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "state", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "$ref": "#/definitions/ProtocolContractState" + } + } + }, + { + "name": "submit_participant_info", + "doc": " (Prospective) Participants can submit their tee participant information through this\n endpoint.", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "proposed_participant_attestation", + "type_schema": { + "$ref": "#/definitions/Attestation" + } + }, + { + "name": "tls_public_key", + "type_schema": { + "$ref": "#/definitions/Ed25519PublicKey" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "update_config", + "kind": "call", + "modifiers": [ + "private" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "config", + "type_schema": { + "$ref": "#/definitions/Config" + } + } + ] + } + }, + { + "name": "verify_foreign_transaction", + "doc": " Submit a verification + signing request for a foreign chain transaction.\n MPC nodes will verify the transaction on the foreign chain before signing.\n The signed payload is derived from the transaction ID (hash of tx_id).", + "kind": "call", + "modifiers": [ + "payable" + ], + "params": { + "serialization_type": "json", + "args": [ + { + "name": "request", + "type_schema": { + "$ref": "#/definitions/VerifyForeignTransactionRequestArgs" + } + } + ] + } + }, + { + "name": "verify_tee", + "doc": " Verifies if all current participants have an accepted TEE state.\n Automatically enters a resharing, in case one or more participants do not have an accepted\n TEE state.\n Returns `false` and stops the contract from accepting new signature requests or responses,\n in case less than `threshold` participants run in an accepted TEE State.", + "kind": "call", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "boolean" + } + } + }, + { + "name": "version", + "kind": "view", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "string" + } + } + }, + { + "name": "vote_abort_key_event_instance", + "doc": " Casts a vote to abort the current key event instance. If succesful, the contract aborts the\n instance and a new instance with the next attempt_id can be started.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "key_event_id", + "type_schema": { + "$ref": "#/definitions/KeyEventId" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_add_domains", + "doc": " Propose adding a new set of domains for the MPC network.\n If a threshold number of votes are reached on the exact same proposal, this will transition\n the contract into the Initializing state to generate keys for the new domains.\n\n The specified list of domains must have increasing and contiguous IDs, and the first ID\n must be the same as the `next_domain_id` returned by state().", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "domains", + "type_schema": { + "type": "array", + "items": { + "$ref": "#/definitions/DomainConfig" + } + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_cancel_keygen", + "doc": " Casts a vote to cancel key generation. Any keys that have already been generated\n are kept and we transition into Running state; remaining domains are permanently deleted.\n Deleted domain IDs cannot be reused again in future calls to vote_add_domains.\n\n A next_domain_id that matches that in the state's domains struct must be passed in. This is\n to prevent stale requests from accidentally cancelling a future key generation state.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "next_domain_id", + "type_schema": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_cancel_resharing", + "doc": " Casts a vote to cancel the current key resharing. If a threshold number of unique\n votes are collected to cancel the resharing, the contract state will revert back to the\n previous running state.\n\n - This method is idempotent, meaning a single account can not make more than one vote.\n - Only nodes from the previous running state are allowed to vote.\n\n Return value:\n - [Ok] if the vote was successfully collected.\n - [Err] if:\n - The signer is not a participant in the previous running state.\n - The contract is not in a resharing state.", + "kind": "call", + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_code_hash", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "code_hash", + "type_schema": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_foreign_chain_policy", + "doc": " Propose a new foreign chain policy.\n If all current participants vote for the exact same policy, it is applied.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "policy", + "type_schema": { + "$ref": "#/definitions/ForeignChainPolicy" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_new_parameters", + "doc": " Propose a new set of parameters (participants and threshold) for the MPC network.\n If a threshold number of votes are reached on the exact same proposal, this will transition\n the contract into the Resharing state.\n\n The epoch_id must be equal to 1 plus the current epoch ID (if Running) or prospective epoch\n ID (if Resharing). Otherwise the vote is ignored. This is to prevent late transactions from\n accidentally voting on outdated proposals.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "prospective_epoch_id", + "type_schema": { + "$ref": "#/definitions/EpochId" + } + }, + { + "name": "proposal", + "type_schema": { + "$ref": "#/definitions/ThresholdParameters" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_pk", + "doc": " Casts a vote for `public_key` for the attempt identified by `key_event_id`.\n\n The effect of this method is either:\n - Returns error (which aborts with no changes), if there is no active key generation\n attempt (including if the attempt timed out), if the signer is not a participant, or if\n the key_event_id corresponds to a different domain, different epoch, or different attempt\n from the current key generation attempt.\n - Returns Ok(()), with one of the following changes:\n - A vote has been collected but we don't have enough votes yet.\n - This vote is for a public key that disagrees from an earlier voted public key, causing\n the attempt to abort; another call to `start` is then necessary.\n - Everyone has now voted for the same public key; the state transitions into generating a\n key for the next domain.\n - Same as the last case, except that all domains have a generated key now, and the state\n transitions into Running with the newly generated keys.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "key_event_id", + "type_schema": { + "$ref": "#/definitions/KeyEventId" + } + }, + { + "name": "public_key", + "type_schema": { + "$ref": "#/definitions/PublicKey" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_reshared", + "doc": " Casts a vote for the successful resharing of the attempt identified by `key_event_id`.\n\n The effect of this method is either:\n - Returns error (which aborts with no changes), if there is no active key resharing attempt\n (including if the attempt timed out), if the signer is not a participant, or if the\n key_event_id corresponds to a different domain, different epoch, or different attempt\n from the current key resharing attempt.\n - Returns Ok(()), with one of the following changes:\n - A vote has been collected but we don't have enough votes yet.\n - Everyone has now voted; the state transitions into resharing the key for the next\n domain.\n - Same as the last case, except that all domains' keys have been reshared now, and the\n state transitions into Running with the newly reshared keys.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "key_event_id", + "type_schema": { + "$ref": "#/definitions/KeyEventId" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "null" + } + } + }, + { + "name": "vote_update", + "doc": " Vote for a proposed update given the [`UpdateId`] of the update.\n\n Returns `Ok(true)` if the amount of voters surpassed the threshold and the update was\n executed. Returns `Ok(false)` if the amount of voters did not surpass the threshold.\n Returns [`Error`] if the update was not found or if the voter is not a participant\n in the protocol.", + "kind": "call", + "params": { + "serialization_type": "json", + "args": [ + { + "name": "id", + "type_schema": { + "$ref": "#/definitions/UpdateId" + } + } + ] + }, + "result": { + "serialization_type": "json", + "type_schema": { + "type": "boolean" + } + } + } + ], + "root_schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "String", + "type": "string", + "definitions": { + "AccountId": { + "description": "A Near AccountId", + "type": "string" + }, + "AddDomainsVotes": { + "description": "Votes for adding new domains.", + "type": "object", + "required": [ + "proposal_by_account" + ], + "properties": { + "proposal_by_account": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/DomainConfig2" + } + } + } + } + }, + "AttemptId": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "AttemptId2": { + "description": "Attempt identifier within a key event.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "Attestation": { + "oneOf": [ + { + "type": "object", + "required": [ + "Dstack" + ], + "properties": { + "Dstack": { + "$ref": "#/definitions/DstackAttestation" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Mock" + ], + "properties": { + "Mock": { + "$ref": "#/definitions/MockAttestation" + } + }, + "additionalProperties": false + } + ] + }, + "AuthenticatedAccountId": { + "description": "An account ID that has been authenticated (i.e., the caller is this account).", + "allOf": [ + { + "$ref": "#/definitions/AccountId" + } + ] + }, + "AuthenticatedParticipantId": { + "description": "A participant ID that has been authenticated (i.e., the caller is this participant).", + "allOf": [ + { + "$ref": "#/definitions/ParticipantId2" + } + ] + }, + "BackupServiceInfo": { + "type": "object", + "required": [ + "public_key" + ], + "properties": { + "public_key": { + "$ref": "#/definitions/Ed25519PublicKey" + } + } + }, + "BitcoinExtractor": { + "type": "string", + "enum": [ + "BlockHash" + ] + }, + "BitcoinRpcRequest": { + "type": "object", + "required": [ + "confirmations", + "extractors", + "tx_id" + ], + "properties": { + "confirmations": { + "$ref": "#/definitions/BlockConfirmations" + }, + "extractors": { + "type": "array", + "items": { + "$ref": "#/definitions/BitcoinExtractor" + } + }, + "tx_id": { + "$ref": "#/definitions/BitcoinTxId" + } + } + }, + "BitcoinTxId": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "BlockConfirmations": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "Bls12381G1PublicKey": { + "type": "string" + }, + "Bls12381G2PublicKey": { + "type": "string" + }, + "CKDRequest": { + "type": "object", + "required": [ + "app_id", + "app_public_key", + "domain_id" + ], + "properties": { + "app_id": { + "$ref": "#/definitions/CkdAppId" + }, + "app_public_key": { + "description": "The app ephemeral public key", + "allOf": [ + { + "$ref": "#/definitions/Bls12381G1PublicKey" + } + ] + }, + "domain_id": { + "$ref": "#/definitions/DomainId" + } + } + }, + "CKDRequestArgs": { + "type": "object", + "required": [ + "app_public_key", + "derivation_path", + "domain_id" + ], + "properties": { + "app_public_key": { + "$ref": "#/definitions/Bls12381G1PublicKey" + }, + "derivation_path": { + "type": "string" + }, + "domain_id": { + "$ref": "#/definitions/DomainId" + } + } + }, + "CKDResponse": { + "type": "object", + "required": [ + "big_c", + "big_y" + ], + "properties": { + "big_c": { + "$ref": "#/definitions/Bls12381G1PublicKey" + }, + "big_y": { + "$ref": "#/definitions/Bls12381G1PublicKey" + } + } + }, + "CkdAppId": { + "description": "AppId for CKD", + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + }, + "Collateral": { + "type": "object", + "required": [ + "pck_crl", + "pck_crl_issuer_chain", + "qe_identity", + "qe_identity_issuer_chain", + "qe_identity_signature", + "root_ca_crl", + "tcb_info", + "tcb_info_issuer_chain", + "tcb_info_signature" + ], + "properties": { + "pck_certificate_chain": { + "type": [ + "string", + "null" + ] + }, + "pck_crl": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "pck_crl_issuer_chain": { + "type": "string" + }, + "qe_identity": { + "type": "string" + }, + "qe_identity_issuer_chain": { + "type": "string" + }, + "qe_identity_signature": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "root_ca_crl": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "tcb_info": { + "type": "string" + }, + "tcb_info_issuer_chain": { + "type": "string" + }, + "tcb_info_signature": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + } + } + }, + "Config": { + "description": "Configuration parameters of the contract.", + "type": "object", + "required": [ + "ckd_call_gas_attachment_requirement_tera_gas", + "clean_tee_status_tera_gas", + "cleanup_orphaned_node_migrations_tera_gas", + "contract_upgrade_deposit_tera_gas", + "fail_on_timeout_tera_gas", + "key_event_timeout_blocks", + "remove_non_participant_update_votes_tera_gas", + "return_ck_and_clean_state_on_success_call_tera_gas", + "return_signature_and_clean_state_on_success_call_tera_gas", + "sign_call_gas_attachment_requirement_tera_gas", + "tee_upgrade_deadline_duration_seconds" + ], + "properties": { + "ckd_call_gas_attachment_requirement_tera_gas": { + "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "clean_tee_status_tera_gas": { + "description": "Prepaid gas for a `clean_tee_status` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "cleanup_orphaned_node_migrations_tera_gas": { + "description": "Prepaid gas for a `cleanup_orphaned_node_migrations` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "contract_upgrade_deposit_tera_gas": { + "description": "Amount of gas to deposit for contract and config updates.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "fail_on_timeout_tera_gas": { + "description": "Prepaid gas for a `fail_on_timeout` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "key_event_timeout_blocks": { + "description": "If a key event attempt has not successfully completed within this many blocks, it is considered failed.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "remove_non_participant_update_votes_tera_gas": { + "description": "Prepaid gas for a `remove_non_participant_update_votes` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "return_ck_and_clean_state_on_success_call_tera_gas": { + "description": "Prepaid gas for a `return_ck_and_clean_state_on_success` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "return_signature_and_clean_state_on_success_call_tera_gas": { + "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "sign_call_gas_attachment_requirement_tera_gas": { + "description": "Gas required for a sign request.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "tee_upgrade_deadline_duration_seconds": { + "description": "The grace period duration for expiry of old mpc image hashes once a new one is added.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "Curve": { + "description": "Elliptic curve used by a domain. More curves may be added in the future. When adding new curves, both Borsh *and* JSON serialization must be kept compatible.", + "type": "string", + "enum": [ + "Secp256k1", + "Ed25519", + "Bls12381", + "V2Secp256k1" + ] + }, + "Curve2": { + "description": "Elliptic curve used by a domain.", + "oneOf": [ + { + "type": "string", + "enum": [ + "Secp256k1", + "Ed25519", + "Bls12381" + ] + }, + { + "description": "Robust ECDSA variant.", + "type": "string", + "enum": [ + "V2Secp256k1" + ] + } + ] + }, + "DestinationNodeInfo": { + "type": "object", + "required": [ + "destination_node_info", + "signer_account_pk" + ], + "properties": { + "destination_node_info": { + "$ref": "#/definitions/ParticipantInfo" + }, + "signer_account_pk": { + "description": "the public key used by the node to sign transactions to the contract this key is different from the TLS key called `sign_pk` and stored in `ParticipantInfo`.", + "type": "string" + } + } + }, + "DomainConfig": { + "description": "Describes the configuration of a domain: the domain ID and the curve it uses.", + "type": "object", + "required": [ + "curve", + "id", + "purpose" + ], + "properties": { + "curve": { + "$ref": "#/definitions/Curve" + }, + "id": { + "$ref": "#/definitions/DomainId" + }, + "purpose": { + "$ref": "#/definitions/DomainPurpose" + } + } + }, + "DomainConfig2": { + "description": "Configuration for a signature domain.", + "type": "object", + "required": [ + "id", + "scheme" + ], + "properties": { + "id": { + "$ref": "#/definitions/DomainId2" + }, + "purpose": { + "description": "`None` when reading state from an old contract that predates domain purposes.", + "anyOf": [ + { + "$ref": "#/definitions/DomainPurpose" + }, + { + "type": "null" + } + ] + }, + "scheme": { + "$ref": "#/definitions/Curve2" + } + } + }, + "DomainId": { + "description": "Each domain corresponds to a specific root key in a specific signature scheme. There may be multiple domains per signature scheme. The domain ID uniquely identifies a domain.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "DomainId2": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "DomainPurpose": { + "description": "The purpose that a domain serves.", + "oneOf": [ + { + "description": "Domain is used by `sign()`.", + "type": "string", + "enum": [ + "Sign" + ] + }, + { + "description": "Domain is used by `verify_foreign_transaction()`.", + "type": "string", + "enum": [ + "ForeignTx" + ] + }, + { + "description": "Domain is used by `request_app_private_key()` (Confidential Key Derivation).", + "type": "string", + "enum": [ + "CKD" + ] + } + ] + }, + "DomainRegistry": { + "description": "Registry of all signature domains.", + "type": "object", + "required": [ + "domains", + "next_domain_id" + ], + "properties": { + "domains": { + "type": "array", + "items": { + "$ref": "#/definitions/DomainConfig2" + } + }, + "next_domain_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "DstackAttestation": { + "type": "object", + "required": [ + "collateral", + "quote", + "tcb_info" + ], + "properties": { + "collateral": { + "$ref": "#/definitions/Collateral" + }, + "quote": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "tcb_info": { + "$ref": "#/definitions/TcbInfo" + } + } + }, + "Ed25519PublicKey": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + }, + "Ed25519Signature": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + }, + "EpochId": { + "description": "An EpochId uniquely identifies a ThresholdParameters (but not vice-versa). Every time we change the ThresholdParameters (participants and threshold), we increment EpochId. Locally on each node, each keyshare is uniquely identified by the tuple (EpochId, DomainId, AttemptId).", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "EpochId2": { + "description": "Epoch identifier for key generation/resharing cycles.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "EventLog": { + "description": "Represents an event log entry in the system", + "type": "object", + "required": [ + "digest", + "event", + "event_payload", + "event_type", + "imr" + ], + "properties": { + "digest": { + "description": "The cryptographic digest of the event", + "type": "string" + }, + "event": { + "description": "The type of event as a string", + "type": "string" + }, + "event_payload": { + "description": "The payload data associated with the event", + "type": "string" + }, + "event_type": { + "description": "The type of event being logged", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "imr": { + "description": "The index of the IMR (Integrity Measurement Register)", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + }, + "EvmExtractor": { + "oneOf": [ + { + "type": "string", + "enum": [ + "BlockHash" + ] + }, + { + "type": "object", + "required": [ + "Log" + ], + "properties": { + "Log": { + "type": "object", + "required": [ + "log_index" + ], + "properties": { + "log_index": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + } + ] + }, + "EvmFinality": { + "type": "string", + "enum": [ + "Latest", + "Safe", + "Finalized" + ] + }, + "EvmRpcRequest": { + "type": "object", + "required": [ + "extractors", + "finality", + "tx_id" + ], + "properties": { + "extractors": { + "type": "array", + "items": { + "$ref": "#/definitions/EvmExtractor" + } + }, + "finality": { + "$ref": "#/definitions/EvmFinality" + }, + "tx_id": { + "$ref": "#/definitions/EvmTxId" + } + } + }, + "EvmTxId": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "ForeignChainPolicy": { + "type": "object", + "required": [ + "chains" + ], + "properties": { + "chains": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/NonEmptyBTreeSet_RpcProvider" + } + } + } + }, + "ForeignChainPolicyVotes": { + "type": "object", + "required": [ + "proposal_by_account" + ], + "properties": { + "proposal_by_account": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ForeignChainPolicy" + } + } + } + }, + "ForeignChainRpcRequest": { + "oneOf": [ + { + "type": "object", + "required": [ + "Abstract" + ], + "properties": { + "Abstract": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Ethereum" + ], + "properties": { + "Ethereum": { + "$ref": "#/definitions/EvmRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Solana" + ], + "properties": { + "Solana": { + "$ref": "#/definitions/SolanaRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Bitcoin" + ], + "properties": { + "Bitcoin": { + "$ref": "#/definitions/BitcoinRpcRequest" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Starknet" + ], + "properties": { + "Starknet": { + "$ref": "#/definitions/StarknetRpcRequest" + } + }, + "additionalProperties": false + } + ] + }, + "Hash256": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "InitConfig": { + "description": "The initial configuration parameters for when initializing the contract. All fields are optional, as the contract can fill in defaults for any missing fields.", + "type": "object", + "properties": { + "ckd_call_gas_attachment_requirement_tera_gas": { + "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "clean_tee_status_tera_gas": { + "description": "Prepaid gas for a `clean_tee_status` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "cleanup_orphaned_node_migrations_tera_gas": { + "description": "Prepaid gas for a `cleanup_orphaned_node_migrations` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "contract_upgrade_deposit_tera_gas": { + "description": "Amount of gas to deposit for contract and config updates.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "fail_on_timeout_tera_gas": { + "description": "Prepaid gas for a `fail_on_timeout` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "key_event_timeout_blocks": { + "description": "If a key event attempt has not successfully completed within this many blocks, it is considered failed.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "remove_non_participant_update_votes_tera_gas": { + "description": "Prepaid gas for a `remove_non_participant_update_votes` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "return_ck_and_clean_state_on_success_call_tera_gas": { + "description": "Prepaid gas for a `return_ck_and_clean_state_on_success` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "return_signature_and_clean_state_on_success_call_tera_gas": { + "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "sign_call_gas_attachment_requirement_tera_gas": { + "description": "Gas required for a sign request.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "tee_upgrade_deadline_duration_seconds": { + "description": "The grace period duration for expiry of old mpc image hashes once a new one is added.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + } + } + }, + "InitializingContractState": { + "description": "State when the contract is generating keys for new domains.", + "type": "object", + "required": [ + "cancel_votes", + "domains", + "epoch_id", + "generated_keys", + "generating_key" + ], + "properties": { + "cancel_votes": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedParticipantId" + }, + "uniqueItems": true + }, + "domains": { + "$ref": "#/definitions/DomainRegistry" + }, + "epoch_id": { + "$ref": "#/definitions/EpochId2" + }, + "generated_keys": { + "type": "array", + "items": { + "$ref": "#/definitions/KeyForDomain2" + } + }, + "generating_key": { + "$ref": "#/definitions/KeyEvent" + } + } + }, + "K256AffinePoint": { + "description": "AffinePoint on the Secp256k1 curve", + "type": "object", + "required": [ + "affine_point" + ], + "properties": { + "affine_point": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + } + } + }, + "K256Scalar": { + "type": "object", + "required": [ + "scalar" + ], + "properties": { + "scalar": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + } + } + }, + "KeyEvent": { + "description": "Key generation or resharing event state.", + "type": "object", + "required": [ + "domain", + "epoch_id", + "next_attempt_id", + "parameters" + ], + "properties": { + "domain": { + "$ref": "#/definitions/DomainConfig2" + }, + "epoch_id": { + "$ref": "#/definitions/EpochId2" + }, + "instance": { + "anyOf": [ + { + "$ref": "#/definitions/KeyEventInstance" + }, + { + "type": "null" + } + ] + }, + "next_attempt_id": { + "$ref": "#/definitions/AttemptId2" + }, + "parameters": { + "$ref": "#/definitions/ThresholdParameters2" + } + } + }, + "KeyEventId": { + "description": "A unique identifier for a key event (generation or resharing): `epoch_id`: identifies the ThresholdParameters that this key is intended to function in. `domain_id`: the domain this key is intended for. `attempt_id`: identifies a particular attempt for this key event, in case multiple attempts yielded partially valid results. This is incremented for each attempt within the same epoch and domain.", + "type": "object", + "required": [ + "attempt_id", + "domain_id", + "epoch_id" + ], + "properties": { + "attempt_id": { + "$ref": "#/definitions/AttemptId" + }, + "domain_id": { + "$ref": "#/definitions/DomainId" + }, + "epoch_id": { + "$ref": "#/definitions/EpochId" + } + } + }, + "KeyEventInstance": { + "description": "State of a key generation/resharing instance.", + "type": "object", + "required": [ + "attempt_id", + "completed", + "expires_on", + "started_in" + ], + "properties": { + "attempt_id": { + "$ref": "#/definitions/AttemptId2" + }, + "completed": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedParticipantId" + }, + "uniqueItems": true + }, + "expires_on": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "public_key": { + "anyOf": [ + { + "$ref": "#/definitions/PublicKeyExtended2" + }, + { + "type": "null" + } + ] + }, + "started_in": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "KeyForDomain": { + "description": "The identification of a specific distributed key, based on which a node would know exactly what keyshare it has corresponds to this distributed key. (A distributed key refers to a specific set of keyshares that nodes have which can be pieced together to form the secret key.)", + "type": "object", + "required": [ + "attempt", + "domain_id", + "key" + ], + "properties": { + "attempt": { + "description": "The attempt ID that generated (initially or as a result of resharing) this distributed key. Nodes may have made multiple attempts to generate the distributed key, and this uniquely identifies which one should ultimately be used.", + "allOf": [ + { + "$ref": "#/definitions/AttemptId" + } + ] + }, + "domain_id": { + "description": "Identifies the domain this key is intended for.", + "allOf": [ + { + "$ref": "#/definitions/DomainId" + } + ] + }, + "key": { + "description": "Identifies the public key. Although technically redundant given that we have the AttemptId, we keep it here in the contract so that it can be verified against and queried.", + "allOf": [ + { + "$ref": "#/definitions/PublicKeyExtended" + } + ] + } + } + }, + "KeyForDomain2": { + "description": "A public key for a specific domain.", + "type": "object", + "required": [ + "attempt", + "domain_id", + "key" + ], + "properties": { + "attempt": { + "$ref": "#/definitions/AttemptId2" + }, + "domain_id": { + "$ref": "#/definitions/DomainId2" + }, + "key": { + "$ref": "#/definitions/PublicKeyExtended2" + } + } + }, + "Keyset": { + "description": "Represents a key for every domain in a specific epoch.", + "type": "object", + "required": [ + "domains", + "epoch_id" + ], + "properties": { + "domains": { + "type": "array", + "items": { + "$ref": "#/definitions/KeyForDomain" + } + }, + "epoch_id": { + "$ref": "#/definitions/EpochId" + } + } + }, + "Keyset2": { + "description": "Set of keys for the current epoch.", + "type": "object", + "required": [ + "domains", + "epoch_id" + ], + "properties": { + "domains": { + "type": "array", + "items": { + "$ref": "#/definitions/KeyForDomain2" + } + }, + "epoch_id": { + "$ref": "#/definitions/EpochId2" + } + } + }, + "Metrics": { + "type": "object", + "required": [ + "sign_with_v1_payload_count", + "sign_with_v2_payload_count" + ], + "properties": { + "sign_with_v1_payload_count": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "sign_with_v2_payload_count": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "MockAttestation": { + "oneOf": [ + { + "description": "Always pass validation", + "type": "string", + "enum": [ + "Valid" + ] + }, + { + "description": "Always fails validation", + "type": "string", + "enum": [ + "Invalid" + ] + }, + { + "description": "Pass validation depending on the set constraints", + "type": "object", + "required": [ + "WithConstraints" + ], + "properties": { + "WithConstraints": { + "type": "object", + "properties": { + "expiry_timestamp_seconds": { + "description": "Unix time stamp for when this attestation expires.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "launcher_docker_compose_hash": { + "default": null, + "type": [ + "string", + "null" + ], + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "mpc_docker_image_hash": { + "default": null, + "type": [ + "string", + "null" + ], + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "NodeId": { + "type": "object", + "required": [ + "account_id", + "tls_public_key" + ], + "properties": { + "account_id": { + "description": "Operator account", + "type": "string" + }, + "account_public_key": { + "type": [ + "string", + "null" + ] + }, + "tls_public_key": { + "description": "TLS public key, MUST BE of type Ed25519", + "type": "string" + } + } + }, + "NonEmptyBTreeSet_RpcProvider": { + "type": "array", + "items": { + "$ref": "#/definitions/RpcProvider" + }, + "minItems": 1, + "uniqueItems": true + }, + "ParticipantId": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "ParticipantId2": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "ParticipantInfo": { + "type": "object", + "required": [ + "sign_pk", + "url" + ], + "properties": { + "sign_pk": { + "description": "The public key used for verifying messages.", + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "ParticipantInfo2": { + "type": "object", + "required": [ + "sign_pk", + "url" + ], + "properties": { + "sign_pk": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "Participants": { + "type": "object", + "required": [ + "next_id", + "participants" + ], + "properties": { + "next_id": { + "$ref": "#/definitions/ParticipantId" + }, + "participants": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", + "type": "string" + }, + { + "$ref": "#/definitions/ParticipantId" + }, + { + "$ref": "#/definitions/ParticipantInfo" + } + ], + "maxItems": 3, + "minItems": 3 + } + } + } + }, + "Participants2": { + "description": "DTO representation of the contract-internal `Participants` type.\n\nIt decouples the JSON wire format (used in view methods like `state()` via [`ThresholdParameters`](crate::types::state::ThresholdParameters)) from the internal `Participants` representation, allowing internal changes (e.g., migrating to [`BTreeMap`](std::collections::BTreeMap) in [#1861](https://github.com/near/mpc/pull/1861)) without breaking the public API.", + "type": "object", + "required": [ + "next_id", + "participants" + ], + "properties": { + "next_id": { + "$ref": "#/definitions/ParticipantId2" + }, + "participants": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "$ref": "#/definitions/AccountId" + }, + { + "$ref": "#/definitions/ParticipantId2" + }, + { + "$ref": "#/definitions/ParticipantInfo2" + } + ], + "maxItems": 3, + "minItems": 3 + } + } + } + }, + "Payload": { + "description": "A signature payload; the right payload must be passed in for the curve. The json encoding for this payload converts the bytes to hex string.", + "oneOf": [ + { + "type": "object", + "required": [ + "Ecdsa" + ], + "properties": { + "Ecdsa": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Eddsa" + ], + "properties": { + "Eddsa": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + }, + "additionalProperties": false + } + ] + }, + "PromiseOrValueCKDResponse": { + "type": "object", + "required": [ + "big_c", + "big_y" + ], + "properties": { + "big_c": { + "$ref": "#/definitions/Bls12381G1PublicKey" + }, + "big_y": { + "$ref": "#/definitions/Bls12381G1PublicKey" + } + } + }, + "PromiseOrValueSignatureResponse": { + "oneOf": [ + { + "type": "object", + "required": [ + "big_r", + "recovery_id", + "s", + "scheme" + ], + "properties": { + "big_r": { + "$ref": "#/definitions/K256AffinePoint" + }, + "recovery_id": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "s": { + "$ref": "#/definitions/K256Scalar" + }, + "scheme": { + "type": "string", + "enum": [ + "Secp256k1" + ] + } + } + }, + { + "type": "object", + "required": [ + "scheme", + "signature" + ], + "properties": { + "scheme": { + "type": "string", + "enum": [ + "Ed25519" + ] + }, + "signature": { + "$ref": "#/definitions/Ed25519Signature" + } + } + } + ] + }, + "PromiseOrValueVerifyForeignTransactionResponse": { + "type": "object", + "required": [ + "payload_hash", + "signature" + ], + "properties": { + "payload_hash": { + "$ref": "#/definitions/Hash256" + }, + "signature": { + "$ref": "#/definitions/SignatureResponse" + } + } + }, + "ProposedUpdates": { + "type": "object", + "required": [ + "updates", + "votes" + ], + "properties": { + "updates": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/UpdateHash" + } + }, + "votes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "ProtocolContractState": { + "description": "The main protocol contract state enum.", + "oneOf": [ + { + "type": "string", + "enum": [ + "NotInitialized" + ] + }, + { + "type": "object", + "required": [ + "Initializing" + ], + "properties": { + "Initializing": { + "$ref": "#/definitions/InitializingContractState" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Running" + ], + "properties": { + "Running": { + "$ref": "#/definitions/RunningContractState" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Resharing" + ], + "properties": { + "Resharing": { + "$ref": "#/definitions/ResharingContractState" + } + }, + "additionalProperties": false + } + ] + }, + "PublicKey": { + "oneOf": [ + { + "type": "object", + "required": [ + "Secp256k1" + ], + "properties": { + "Secp256k1": { + "$ref": "#/definitions/Secp256k1PublicKey" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Ed25519" + ], + "properties": { + "Ed25519": { + "$ref": "#/definitions/Ed25519PublicKey" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Bls12381" + ], + "properties": { + "Bls12381": { + "$ref": "#/definitions/Bls12381G2PublicKey" + } + }, + "additionalProperties": false + } + ] + }, + "PublicKeyExtended": { + "oneOf": [ + { + "type": "object", + "required": [ + "Secp256k1" + ], + "properties": { + "Secp256k1": { + "type": "object", + "required": [ + "near_public_key" + ], + "properties": { + "near_public_key": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Ed25519" + ], + "properties": { + "Ed25519": { + "type": "object", + "required": [ + "edwards_point", + "near_public_key_compressed" + ], + "properties": { + "edwards_point": { + "description": "Decompressed Edwards point used for curve arithmetic operations.", + "allOf": [ + { + "$ref": "#/definitions/SerializableEdwardsPoint" + } + ] + }, + "near_public_key_compressed": { + "description": "Serialized compressed Edwards-y point.", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Bls12381" + ], + "properties": { + "Bls12381": { + "type": "object", + "required": [ + "public_key" + ], + "properties": { + "public_key": { + "$ref": "#/definitions/PublicKey" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "PublicKeyExtended2": { + "description": "Extended public key representation for different signature schemes.", + "oneOf": [ + { + "description": "Secp256k1 public key (ECDSA).", + "type": "object", + "required": [ + "Secp256k1" + ], + "properties": { + "Secp256k1": { + "type": "object", + "required": [ + "near_public_key" + ], + "properties": { + "near_public_key": { + "description": "The public key in NEAR SDK format (string representation).", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Ed25519 public key.", + "type": "object", + "required": [ + "Ed25519" + ], + "properties": { + "Ed25519": { + "type": "object", + "required": [ + "edwards_point", + "near_public_key_compressed" + ], + "properties": { + "edwards_point": { + "description": "The Edwards point (32 bytes).", + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + }, + "near_public_key_compressed": { + "description": "The compressed public key in NEAR SDK format.", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "BLS12-381 public key.", + "type": "object", + "required": [ + "Bls12381" + ], + "properties": { + "Bls12381": { + "type": "object", + "required": [ + "public_key" + ], + "properties": { + "public_key": { + "description": "The public key.", + "allOf": [ + { + "$ref": "#/definitions/PublicKey" + } + ] + } + } + } + }, + "additionalProperties": false + } + ] + }, + "ResharingContractState": { + "description": "State when the contract is resharing keys to new participants.", + "type": "object", + "required": [ + "cancellation_requests", + "previous_running_state", + "reshared_keys", + "resharing_key" + ], + "properties": { + "cancellation_requests": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthenticatedAccountId" + }, + "uniqueItems": true + }, + "previous_running_state": { + "$ref": "#/definitions/RunningContractState" + }, + "reshared_keys": { + "type": "array", + "items": { + "$ref": "#/definitions/KeyForDomain2" + } + }, + "resharing_key": { + "$ref": "#/definitions/KeyEvent" + } + } + }, + "RpcProvider": { + "type": "object", + "required": [ + "rpc_url" + ], + "properties": { + "rpc_url": { + "type": "string" + } + } + }, + "RunningContractState": { + "description": "State when the contract is ready for signature operations.", + "type": "object", + "required": [ + "add_domains_votes", + "domains", + "keyset", + "parameters", + "parameters_votes" + ], + "properties": { + "add_domains_votes": { + "$ref": "#/definitions/AddDomainsVotes" + }, + "domains": { + "$ref": "#/definitions/DomainRegistry" + }, + "keyset": { + "$ref": "#/definitions/Keyset2" + }, + "parameters": { + "$ref": "#/definitions/ThresholdParameters2" + }, + "parameters_votes": { + "$ref": "#/definitions/ThresholdParametersVotes" + }, + "previously_cancelled_resharing_epoch_id": { + "anyOf": [ + { + "$ref": "#/definitions/EpochId2" + }, + { + "type": "null" + } + ] + } + } + }, + "Secp256k1PublicKey": { + "type": "string" + }, + "SerializableEdwardsPoint": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + }, + "SignRequestArgs": { + "type": "object", + "required": [ + "path" + ], + "properties": { + "domain_id": { + "anyOf": [ + { + "$ref": "#/definitions/DomainId" + }, + { + "type": "null" + } + ] + }, + "key_version": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 + }, + "path": { + "type": "string" + }, + "payload": { + "type": [ + "array", + "null" + ], + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + }, + "payload_v2": { + "anyOf": [ + { + "$ref": "#/definitions/Payload" + }, + { + "type": "null" + } + ] + } + } + }, + "SignatureRequest": { + "type": "object", + "required": [ + "domain_id", + "payload", + "tweak" + ], + "properties": { + "domain_id": { + "$ref": "#/definitions/DomainId" + }, + "payload": { + "$ref": "#/definitions/Payload" + }, + "tweak": { + "$ref": "#/definitions/Tweak" + } + } + }, + "SignatureResponse": { + "oneOf": [ + { + "type": "object", + "required": [ + "big_r", + "recovery_id", + "s", + "scheme" + ], + "properties": { + "big_r": { + "$ref": "#/definitions/K256AffinePoint" + }, + "recovery_id": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "s": { + "$ref": "#/definitions/K256Scalar" + }, + "scheme": { + "type": "string", + "enum": [ + "Secp256k1" + ] + } + } + }, + { + "type": "object", + "required": [ + "scheme", + "signature" + ], + "properties": { + "scheme": { + "type": "string", + "enum": [ + "Ed25519" + ] + }, + "signature": { + "$ref": "#/definitions/Ed25519Signature" + } + } + } + ] + }, + "SolanaExtractor": { + "oneOf": [ + { + "type": "object", + "required": [ + "SolanaProgramIdIndex" + ], + "properties": { + "SolanaProgramIdIndex": { + "type": "object", + "required": [ + "ix_index" + ], + "properties": { + "ix_index": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "SolanaDataHash" + ], + "properties": { + "SolanaDataHash": { + "type": "object", + "required": [ + "ix_index" + ], + "properties": { + "ix_index": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + } + ] + }, + "SolanaFinality": { + "type": "string", + "enum": [ + "Processed", + "Confirmed", + "Finalized" + ] + }, + "SolanaRpcRequest": { + "type": "object", + "required": [ + "extractors", + "finality", + "tx_id" + ], + "properties": { + "extractors": { + "type": "array", + "items": { + "$ref": "#/definitions/SolanaExtractor" + } + }, + "finality": { + "$ref": "#/definitions/SolanaFinality" + }, + "tx_id": { + "$ref": "#/definitions/SolanaTxId" + } + } + }, + "SolanaTxId": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + }, + "StarknetExtractor": { + "oneOf": [ + { + "type": "string", + "enum": [ + "BlockHash" + ] + }, + { + "type": "object", + "required": [ + "Log" + ], + "properties": { + "Log": { + "type": "object", + "required": [ + "log_index" + ], + "properties": { + "log_index": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + } + ] + }, + "StarknetFelt": { + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "StarknetFinality": { + "type": "string", + "enum": [ + "AcceptedOnL2", + "AcceptedOnL1" + ] + }, + "StarknetRpcRequest": { + "type": "object", + "required": [ + "extractors", + "finality", + "tx_id" + ], + "properties": { + "extractors": { + "type": "array", + "items": { + "$ref": "#/definitions/StarknetExtractor" + } + }, + "finality": { + "$ref": "#/definitions/StarknetFinality" + }, + "tx_id": { + "$ref": "#/definitions/StarknetTxId" + } + } + }, + "StarknetTxId": { + "$ref": "#/definitions/StarknetFelt" + }, + "TcbInfo": { + "description": "Trusted Computing Base information structure", + "type": "object", + "required": [ + "app_compose", + "compose_hash", + "device_id", + "event_log", + "mrtd", + "rtmr0", + "rtmr1", + "rtmr2", + "rtmr3" + ], + "properties": { + "app_compose": { + "description": "The app compose", + "type": "string" + }, + "compose_hash": { + "description": "The hash of the compose configuration", + "type": "string" + }, + "device_id": { + "description": "The device identifier", + "type": "string" + }, + "event_log": { + "description": "The event log entries", + "type": "array", + "items": { + "$ref": "#/definitions/EventLog" + } + }, + "mrtd": { + "description": "The measurement root of trust", + "type": "string" + }, + "os_image_hash": { + "description": "The hash of the OS image. This is empty if the OS image is not measured by KMS.", + "default": "", + "type": "string" + }, + "rtmr0": { + "description": "The value of RTMR0 (Runtime Measurement Register 0)", + "type": "string" + }, + "rtmr1": { + "description": "The value of RTMR1 (Runtime Measurement Register 1)", + "type": "string" + }, + "rtmr2": { + "description": "The value of RTMR2 (Runtime Measurement Register 2)", + "type": "string" + }, + "rtmr3": { + "description": "The value of RTMR3 (Runtime Measurement Register 3)", + "type": "string" + } + } + }, + "Threshold": { + "description": "Stores the cryptographic threshold for a distributed key. ``` use mpc_contract::primitives::thresholds::Threshold; let dt = Threshold::new(8); assert!(dt.value() == 8); ```", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "Threshold2": { + "description": "Threshold value for distributed key operations.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "ThresholdParameters": { + "description": "Stores information about the threshold key parameters: - owners of key shares - cryptographic threshold", + "type": "object", + "required": [ + "participants", + "threshold" + ], + "properties": { + "participants": { + "$ref": "#/definitions/Participants" + }, + "threshold": { + "$ref": "#/definitions/Threshold" + } + } + }, + "ThresholdParameters2": { + "description": "Threshold parameters for distributed key operations.", + "type": "object", + "required": [ + "participants", + "threshold" + ], + "properties": { + "participants": { + "$ref": "#/definitions/Participants2" + }, + "threshold": { + "$ref": "#/definitions/Threshold2" + } + } + }, + "ThresholdParametersVotes": { + "description": "Votes for threshold parameter changes.", + "type": "object", + "required": [ + "proposal_by_account" + ], + "properties": { + "proposal_by_account": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ThresholdParameters2" + } + } + } + }, + "Tweak": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + }, + "UpdateHash": { + "description": "An update hash", + "oneOf": [ + { + "type": "object", + "required": [ + "Code" + ], + "properties": { + "Code": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Config" + ], + "properties": { + "Config": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + } + }, + "additionalProperties": false + } + ] + }, + "UpdateId": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "VerifiedAttestation": { + "oneOf": [ + { + "type": "object", + "required": [ + "Dstack" + ], + "properties": { + "Dstack": { + "$ref": "#/definitions/VerifiedDstackAttestation" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Mock" + ], + "properties": { + "Mock": { + "$ref": "#/definitions/MockAttestation" + } + }, + "additionalProperties": false + } + ] + }, + "VerifiedDstackAttestation": { + "type": "object", + "required": [ + "expiry_timestamp_seconds", + "launcher_compose_hash", + "mpc_image_hash" + ], + "properties": { + "expiry_timestamp_seconds": { + "description": "Unix time stamp for when this attestation expires.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "launcher_compose_hash": { + "description": "The digest of the launcher compose file running.", + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + }, + "mpc_image_hash": { + "description": "The digest of the MPC image running.", + "type": "string", + "pattern": "^(?:[0-9A-Fa-f]{2})*$" + } + } + }, + "VerifyForeignTransactionRequest": { + "type": "object", + "required": [ + "domain_id", + "payload_version", + "request" + ], + "properties": { + "domain_id": { + "$ref": "#/definitions/DomainId2" + }, + "payload_version": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "request": { + "$ref": "#/definitions/ForeignChainRpcRequest" + } + } + }, + "VerifyForeignTransactionRequestArgs": { + "type": "object", + "required": [ + "domain_id", + "payload_version", + "request" + ], + "properties": { + "domain_id": { + "$ref": "#/definitions/DomainId2" + }, + "payload_version": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "request": { + "$ref": "#/definitions/ForeignChainRpcRequest" + } + } + }, + "VerifyForeignTransactionResponse": { + "type": "object", + "required": [ + "payload_hash", + "signature" + ], + "properties": { + "payload_hash": { + "$ref": "#/definitions/Hash256" + }, + "signature": { + "$ref": "#/definitions/SignatureResponse" + } + } + }, + "YieldIndex": { + "description": "The index into calling the YieldResume feature of NEAR. This will allow to resume a yield call after the contract has been called back via this index.", + "type": "object", + "required": [ + "data_id" + ], + "properties": { + "data_id": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "maxItems": 32, + "minItems": 32 + } + } + } + } + } + } +} From a1784ae6dd0c0257d47b8916ccbd1b12de7ac27d Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 13:19:05 +0100 Subject: [PATCH 07/21] More revert --- crates/contract-interface/src/lib.rs | 2 +- crates/contract-interface/src/types/state.rs | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/crates/contract-interface/src/lib.rs b/crates/contract-interface/src/lib.rs index a2b5a8f40..1090a55a1 100644 --- a/crates/contract-interface/src/lib.rs +++ b/crates/contract-interface/src/lib.rs @@ -14,7 +14,7 @@ pub mod types { pub use primitives::{AccountId, CkdAppId, DomainId, Tweak}; pub use sign::*; pub use state::{ - AddDomainsVotes, AttemptId, AuthenticatedAccountId, AuthenticatedParticipantId, Curve, + AddDomainsVotes, AttemptId, AuthenticatedAccountId, AuthenticatedParticipantId, DomainConfig, DomainPurpose, DomainRegistry, EpochId, InitializingContractState, KeyEvent, KeyEventId, KeyEventInstance, KeyForDomain, Keyset, ProtocolContractState, ResharingContractState, RunningContractState, SignatureScheme, Threshold, diff --git a/crates/contract-interface/src/types/state.rs b/crates/contract-interface/src/types/state.rs index d92309507..70a4ba474 100644 --- a/crates/contract-interface/src/types/state.rs +++ b/crates/contract-interface/src/types/state.rs @@ -133,7 +133,7 @@ pub struct AuthenticatedAccountId(pub AccountId); // Domain Types // ============================================================================= -/// Elliptic curve used by a domain. +/// Supported signature schemes. #[derive( Clone, Copy, @@ -152,7 +152,7 @@ pub struct AuthenticatedAccountId(pub AccountId); all(feature = "abi", not(target_arch = "wasm32")), derive(schemars::JsonSchema) )] -pub enum Curve { +pub enum SignatureScheme { Secp256k1, Ed25519, Bls12381, @@ -160,9 +160,6 @@ pub enum Curve { V2Secp256k1, } -/// Backwards-compatible type alias. -pub type SignatureScheme = Curve; - /// The purpose that a domain serves. #[derive( Clone, @@ -201,8 +198,7 @@ pub enum DomainPurpose { )] pub struct DomainConfig { pub id: DomainId, - #[serde(rename = "scheme")] - pub curve: Curve, + pub scheme: SignatureScheme, /// `None` when reading state from an old contract that predates domain purposes. #[serde(default, skip_serializing_if = "Option::is_none")] pub purpose: Option, From 5ee59c6763705980e5a639e6250363717bf01636 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 13:26:37 +0100 Subject: [PATCH 08/21] Reverting all the SignatureScheme types in dto and interface --- crates/contract/src/lib.rs | 2 +- .../sandbox/update_votes_cleanup_after_resharing.rs | 2 +- crates/contract/tests/sandbox/utils/interface.rs | 12 ++++++------ crates/contract/tests/sandbox/vote.rs | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/contract/src/lib.rs b/crates/contract/src/lib.rs index f60fd9bef..c8daadf02 100644 --- a/crates/contract/src/lib.rs +++ b/crates/contract/src/lib.rs @@ -2578,7 +2578,7 @@ mod tests { #[should_panic( expected = "verify_foreign_transaction() requires a domain with purpose ForeignTx" )] - fn verify_foreign_tx__should_reject_non_foreign_tx_domain(#[case] purpose: DomainPurpose) { + fn verify_foreign_tx_should_reject_non_foreign_tx_domain(#[case] purpose: DomainPurpose) { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); let (_context, mut contract, _sk) = diff --git a/crates/contract/tests/sandbox/update_votes_cleanup_after_resharing.rs b/crates/contract/tests/sandbox/update_votes_cleanup_after_resharing.rs index 425c1edf4..c483b324d 100644 --- a/crates/contract/tests/sandbox/update_votes_cleanup_after_resharing.rs +++ b/crates/contract/tests/sandbox/update_votes_cleanup_after_resharing.rs @@ -163,7 +163,7 @@ async fn add_domain_votes_from_kicked_out_participants_are_cleared_after_reshari }; let domains_to_add = vec![dtos::DomainConfig { id: dtos::DomainId(next_domain_id), - curve: dtos::Curve::Ed25519, + scheme: dtos::SignatureScheme::Ed25519, purpose: Some(dtos::DomainPurpose::Sign), }]; execute_async_transactions( diff --git a/crates/contract/tests/sandbox/utils/interface.rs b/crates/contract/tests/sandbox/utils/interface.rs index f4ecd8fe6..58ad9e8c6 100644 --- a/crates/contract/tests/sandbox/utils/interface.rs +++ b/crates/contract/tests/sandbox/utils/interface.rs @@ -15,13 +15,13 @@ pub(crate) trait IntoContractType { fn into_contract_type(self) -> ContractType; } -impl IntoInterfaceType for Curve { - fn into_interface_type(self) -> dtos::Curve { +impl IntoInterfaceType for Curve { + fn into_interface_type(self) -> dtos::SignatureScheme { match self { - Curve::Secp256k1 => dtos::Curve::Secp256k1, - Curve::Ed25519 => dtos::Curve::Ed25519, - Curve::Bls12381 => dtos::Curve::Bls12381, - Curve::V2Secp256k1 => dtos::Curve::V2Secp256k1, + Curve::Secp256k1 => dtos::SignatureScheme::Secp256k1, + Curve::Ed25519 => dtos::SignatureScheme::Ed25519, + Curve::Bls12381 => dtos::SignatureScheme::Bls12381, + Curve::V2Secp256k1 => dtos::SignatureScheme::V2Secp256k1, } } } diff --git a/crates/contract/tests/sandbox/vote.rs b/crates/contract/tests/sandbox/vote.rs index 178bbf8f7..22525796e 100644 --- a/crates/contract/tests/sandbox/vote.rs +++ b/crates/contract/tests/sandbox/vote.rs @@ -61,7 +61,7 @@ async fn test_keygen() -> anyhow::Result<()> { assert_eq!(init.domains.next_domain_id, domain_id + 1); let expected_domain = dtos::DomainConfig { id: dtos::DomainId(domain_id), - curve: curve.into_interface_type(), + scheme: curve.into_interface_type(), purpose: Some(dtos::DomainPurpose::Sign), }; let found = init @@ -168,7 +168,7 @@ async fn test_cancel_keygen() -> anyhow::Result<()> { }; let expected_domain = dtos::DomainConfig { id: dtos::DomainId(next_domain_id), - curve: (*curve).into_interface_type(), + scheme: (*curve).into_interface_type(), purpose: Some(expected_purpose), }; let found = init From cdfd46eddc2880d987b866f5a67a15d70cf8ce62 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 13:30:08 +0100 Subject: [PATCH 09/21] verify_foreign_tx__should_reject_non_foreign_tx_domain --- crates/contract/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/contract/src/lib.rs b/crates/contract/src/lib.rs index c8daadf02..f60fd9bef 100644 --- a/crates/contract/src/lib.rs +++ b/crates/contract/src/lib.rs @@ -2578,7 +2578,7 @@ mod tests { #[should_panic( expected = "verify_foreign_transaction() requires a domain with purpose ForeignTx" )] - fn verify_foreign_tx_should_reject_non_foreign_tx_domain(#[case] purpose: DomainPurpose) { + fn verify_foreign_tx__should_reject_non_foreign_tx_domain(#[case] purpose: DomainPurpose) { // Given let mut rng = rand::rngs::StdRng::from_seed([42u8; 32]); let (_context, mut contract, _sk) = From e255ece7ac2b1caf616df2e5d881daded37216cf Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 13:38:28 +0100 Subject: [PATCH 10/21] No abi_has_not_changed file --- .../abi__abi_has_not_changed.snap.new | 3709 ----------------- 1 file changed, 3709 deletions(-) delete mode 100644 crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new deleted file mode 100644 index 58aaeb8d7..000000000 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap.new +++ /dev/null @@ -1,3709 +0,0 @@ ---- -source: crates/contract/tests/abi.rs -assertion_line: 49 -expression: abi ---- -{ - "schema_version": "0.4.0", - "metadata": { - "name": "mpc-contract", - "version": "3.6.0", - "build": { - "compiler": "rustc 1.86.0", - "builder": "[CARGO_NEAR_BUILD_VERSION]" - }, - "wasm_hash": "[WASM_HASH]" - }, - "body": { - "functions": [ - { - "name": "allowed_docker_image_hashes", - "doc": " Returns all allowed code hashes in order from most recent to least recent allowed code hashes. The first element is the most recent allowed code hash.", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "array", - "items": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - } - } - } - }, - { - "name": "allowed_launcher_compose_hashes", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "array", - "items": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - } - } - } - }, - { - "name": "clean_tee_status", - "doc": " Private endpoint to clean up TEE information for non-participants after resharing.\n This can only be called by the contract itself via a promise.", - "kind": "call", - "modifiers": [ - "private" - ], - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "cleanup_orphaned_node_migrations", - "kind": "call", - "modifiers": [ - "private" - ], - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "conclude_node_migration", - "doc": " Finalizes a node migration for the calling account.\n\n This method can only be called while the protocol is in a `Running` state\n and by an existing participant. On success, the participant’s information is\n updated to the new destination node.\n\n # Errors\n Returns the following errors:\n - `InvalidState::ProtocolStateNotRunning`: if protocol is not in `Running` state\n - `InvalidState::NotParticipant`: if caller is not a current participant\n - `NodeMigrationError::KeysetMismatch`: if provided keyset does not match the expected keyset\n - `NodeMigrationError::MigrationNotFound`: if no migration record exists for the caller\n - `NodeMigrationError::AccountPublicKeyMismatch`: if caller’s public key does not match the expected destination node\n - `InvalidParameters::InvalidTeeRemoteAttestation`: if destination node’s TEE quote is invalid", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "keyset", - "type_schema": { - "$ref": "#/definitions/Keyset" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "config", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/Config" - } - } - }, - { - "name": "contract_source_metadata", - "kind": "view" - }, - { - "name": "derived_public_key", - "doc": " This is the derived public key of the caller given path and predecessor\n if predecessor is not provided, it will be the caller of the contract.\n\n The domain parameter specifies which domain we're deriving the public key for;\n the default is the first domain.", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "path", - "type_schema": { - "type": "string" - } - }, - { - "name": "predecessor", - "type_schema": { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": [ - "string", - "null" - ] - } - }, - { - "name": "domain_id", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/DomainId" - }, - { - "type": "null" - } - ] - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PublicKey" - } - } - }, - { - "name": "fail_on_timeout", - "kind": "view", - "modifiers": [ - "private" - ] - }, - { - "name": "get_attestation", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "tls_public_key", - "type_schema": { - "$ref": "#/definitions/Ed25519PublicKey" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/VerifiedAttestation" - }, - { - "type": "null" - } - ] - } - } - }, - { - "name": "get_foreign_chain_policy", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/ForeignChainPolicy" - } - } - }, - { - "name": "get_foreign_chain_policy_proposals", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/ForeignChainPolicyVotes" - } - } - }, - { - "name": "get_pending_ckd_request", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/CKDRequest" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/YieldIndex" - }, - { - "type": "null" - } - ] - } - } - }, - { - "name": "get_pending_request", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/SignatureRequest" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/YieldIndex" - }, - { - "type": "null" - } - ] - } - } - }, - { - "name": "get_pending_verify_foreign_tx_request", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionRequest" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/YieldIndex" - }, - { - "type": "null" - } - ] - } - } - }, - { - "name": "get_tee_accounts", - "doc": " Returns all accounts that have TEE attestations stored in the contract.\n Note: This includes both current protocol participants and accounts that may have\n submitted TEE information but are not currently part of the active participant set.", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/NodeId" - } - } - } - }, - { - "name": "init", - "kind": "call", - "modifiers": [ - "init" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "parameters", - "type_schema": { - "$ref": "#/definitions/ThresholdParameters" - } - }, - { - "name": "init_config", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/InitConfig" - }, - { - "type": "null" - } - ] - } - } - ] - } - }, - { - "name": "init_running", - "kind": "call", - "modifiers": [ - "init", - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "domains", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/DomainConfig" - } - } - }, - { - "name": "next_domain_id", - "type_schema": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - { - "name": "keyset", - "type_schema": { - "$ref": "#/definitions/Keyset" - } - }, - { - "name": "parameters", - "type_schema": { - "$ref": "#/definitions/ThresholdParameters" - } - }, - { - "name": "init_config", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/InitConfig" - }, - { - "type": "null" - } - ] - } - } - ] - } - }, - { - "name": "latest_key_version", - "doc": " Key versions refer new versions of the root key that we may choose to generate on cohort\n changes. Older key versions will always work but newer key versions were never held by\n older signers. Newer key versions may also add new security features, like only existing\n within a secure enclave. The signature_scheme parameter specifies which protocol\n we're querying the latest version for. The default is Secp256k1. The default is **NOT**\n to query across all protocols.", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "signature_scheme", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/Curve" - }, - { - "type": "null" - } - ] - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - }, - { - "name": "metrics", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/Metrics" - } - } - }, - { - "name": "migrate", - "doc": " This will be called internally by the contract to migrate the state when a new contract\n is deployed. This function should be changed every time state is changed to do the proper\n migrate flow.\n\n If nothing is changed, then this function will just return the current state. If it fails\n to read the state, then it will return an error.", - "kind": "call", - "modifiers": [ - "init", - "private" - ] - }, - { - "name": "migration_info", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": [ - { - "anyOf": [ - { - "$ref": "#/definitions/BackupServiceInfo" - }, - { - "type": "null" - } - ] - }, - { - "anyOf": [ - { - "$ref": "#/definitions/DestinationNodeInfo" - }, - { - "type": "null" - } - ] - } - ], - "maxItems": 2, - "minItems": 2 - } - } - } - }, - { - "name": "propose_update", - "doc": " Propose update to either code or config, but not both of them at the same time.", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "borsh", - "args": [ - { - "name": "args", - "type_schema": { - "declaration": "ProposeUpdateArgs", - "definitions": { - "()": { - "Primitive": 0 - }, - "Config": { - "Struct": [ - [ - "key_event_timeout_blocks", - "u64" - ], - [ - "tee_upgrade_deadline_duration_seconds", - "u64" - ], - [ - "contract_upgrade_deposit_tera_gas", - "u64" - ], - [ - "sign_call_gas_attachment_requirement_tera_gas", - "u64" - ], - [ - "ckd_call_gas_attachment_requirement_tera_gas", - "u64" - ], - [ - "return_signature_and_clean_state_on_success_call_tera_gas", - "u64" - ], - [ - "return_ck_and_clean_state_on_success_call_tera_gas", - "u64" - ], - [ - "fail_on_timeout_tera_gas", - "u64" - ], - [ - "clean_tee_status_tera_gas", - "u64" - ], - [ - "cleanup_orphaned_node_migrations_tera_gas", - "u64" - ], - [ - "remove_non_participant_update_votes_tera_gas", - "u64" - ] - ] - }, - "Option": { - "Enum": { - "tag_width": 1, - "variants": [ - [ - 0, - "None", - "()" - ], - [ - 1, - "Some", - "Config" - ] - ] - } - }, - "Option>": { - "Enum": { - "tag_width": 1, - "variants": [ - [ - 0, - "None", - "()" - ], - [ - 1, - "Some", - "Vec" - ] - ] - } - }, - "ProposeUpdateArgs": { - "Struct": [ - [ - "code", - "Option>" - ], - [ - "config", - "Option" - ] - ] - }, - "Vec": { - "Sequence": { - "length_width": 4, - "length_range": { - "start": 0, - "end": 4294967295 - }, - "elements": "u8" - } - }, - "u64": { - "Primitive": 8 - }, - "u8": { - "Primitive": 1 - } - } - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/UpdateId" - } - } - }, - { - "name": "proposed_updates", - "doc": " returns all proposed updates", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/ProposedUpdates" - } - } - }, - { - "name": "public_key", - "doc": " This is the root public key combined from all the public keys of the participants.\n The domain parameter specifies which domain we're querying the public key for;\n the default is the first domain.", - "kind": "view", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "domain_id", - "type_schema": { - "anyOf": [ - { - "$ref": "#/definitions/DomainId" - }, - { - "type": "null" - } - ] - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PublicKey" - } - } - }, - { - "name": "register_backup_service", - "doc": " Registers or updates the backup service information for the caller account.\n\n The caller (`signer_account_id`) must be an existing or prospective participant.\n Otherwise, the transaction will fail.\n\n # Notes\n - A deposit requirement may be added in the future.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "backup_service_info", - "type_schema": { - "$ref": "#/definitions/BackupServiceInfo" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "remove_non_participant_update_votes", - "doc": " Cleans update votes from non-participants after resharing.\n Can be called by any participant or triggered automatically via promise.", - "kind": "call", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "remove_update_vote", - "doc": " Removes an update vote by the caller\n panics if the contract is not in a running state or if the caller is not a participant", - "kind": "call" - }, - { - "name": "request_app_private_key", - "doc": " To avoid overloading the network with too many requests,\n we ask for a small deposit for each ckd request.", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/CKDRequestArgs" - } - } - ] - } - }, - { - "name": "respond", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/SignatureRequest" - } - }, - { - "name": "response", - "type_schema": { - "$ref": "#/definitions/SignatureResponse" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "respond_ckd", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/CKDRequest" - } - }, - { - "name": "response", - "type_schema": { - "$ref": "#/definitions/CKDResponse" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "respond_verify_foreign_tx", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionRequest" - } - }, - { - "name": "response", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionResponse" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "return_ck_and_clean_state_on_success", - "doc": " Upon success, removes the confidential key request from state and returns it.\n If the ckd request times out, removes the ckd request from state and panics to fail the\n original transaction", - "kind": "call", - "modifiers": [ - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/CKDRequest" - } - } - ] - }, - "callbacks": [ - { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/CKDResponse" - } - } - ], - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PromiseOrValueCKDResponse" - } - } - }, - { - "name": "return_signature_and_clean_state_on_success", - "doc": " Upon success, removes the signature from state and returns it.\n If the signature request times out, removes the signature request from state and panics to\n fail the original transaction", - "kind": "call", - "modifiers": [ - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/SignatureRequest" - } - } - ] - }, - "callbacks": [ - { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/SignatureResponse" - } - } - ], - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PromiseOrValueSignatureResponse" - } - } - }, - { - "name": "return_verify_foreign_tx_and_clean_state_on_success", - "doc": " Upon success, removes the verify foreign tx request from state and returns it.\n If the verify foreign tx request times out, removes the verify foreign tx request from state and panics to fail the\n original transaction", - "kind": "call", - "modifiers": [ - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionRequest" - } - } - ] - }, - "callbacks": [ - { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionResponse" - } - } - ], - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/PromiseOrValueVerifyForeignTransactionResponse" - } - } - }, - { - "name": "sign", - "doc": " `key_version` must be less than or equal to the value at `latest_key_version`\n To avoid overloading the network with too many requests,\n we ask for a small deposit for each signature request.", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/SignRequestArgs" - } - } - ] - } - }, - { - "name": "start_keygen_instance", - "doc": " Starts a new attempt to generate a key for the current domain.\n This only succeeds if the signer is the leader (the participant with the lowest ID).", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "key_event_id", - "type_schema": { - "$ref": "#/definitions/KeyEventId" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "start_node_migration", - "doc": " Sets the destination node for the calling account.\n\n This function can only be called while the protocol is in a `Running` state.\n The signer must be a current participant of the current epoch, otherwise an error is returned.\n On success, the provided [`DestinationNodeInfo`] is stored in the contract state\n under the signer’s account ID.\n\n # Errors\n - [`InvalidState::ProtocolStateNotRunning`] if the protocol is not in the `Running` state. \n - [`InvalidState::NotParticipant`] if the signer is not a current participant.\n # Note:\n - might require a deposit", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "destination_node_info", - "type_schema": { - "$ref": "#/definitions/DestinationNodeInfo" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "start_reshare_instance", - "doc": " Starts a new attempt to reshare the key for the current domain.\n This only succeeds if the signer is the leader (the participant with the lowest ID).", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "key_event_id", - "type_schema": { - "$ref": "#/definitions/KeyEventId" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "state", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "$ref": "#/definitions/ProtocolContractState" - } - } - }, - { - "name": "submit_participant_info", - "doc": " (Prospective) Participants can submit their tee participant information through this\n endpoint.", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "proposed_participant_attestation", - "type_schema": { - "$ref": "#/definitions/Attestation" - } - }, - { - "name": "tls_public_key", - "type_schema": { - "$ref": "#/definitions/Ed25519PublicKey" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "update_config", - "kind": "call", - "modifiers": [ - "private" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "config", - "type_schema": { - "$ref": "#/definitions/Config" - } - } - ] - } - }, - { - "name": "verify_foreign_transaction", - "doc": " Submit a verification + signing request for a foreign chain transaction.\n MPC nodes will verify the transaction on the foreign chain before signing.\n The signed payload is derived from the transaction ID (hash of tx_id).", - "kind": "call", - "modifiers": [ - "payable" - ], - "params": { - "serialization_type": "json", - "args": [ - { - "name": "request", - "type_schema": { - "$ref": "#/definitions/VerifyForeignTransactionRequestArgs" - } - } - ] - } - }, - { - "name": "verify_tee", - "doc": " Verifies if all current participants have an accepted TEE state.\n Automatically enters a resharing, in case one or more participants do not have an accepted\n TEE state.\n Returns `false` and stops the contract from accepting new signature requests or responses,\n in case less than `threshold` participants run in an accepted TEE State.", - "kind": "call", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "boolean" - } - } - }, - { - "name": "version", - "kind": "view", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "string" - } - } - }, - { - "name": "vote_abort_key_event_instance", - "doc": " Casts a vote to abort the current key event instance. If succesful, the contract aborts the\n instance and a new instance with the next attempt_id can be started.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "key_event_id", - "type_schema": { - "$ref": "#/definitions/KeyEventId" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_add_domains", - "doc": " Propose adding a new set of domains for the MPC network.\n If a threshold number of votes are reached on the exact same proposal, this will transition\n the contract into the Initializing state to generate keys for the new domains.\n\n The specified list of domains must have increasing and contiguous IDs, and the first ID\n must be the same as the `next_domain_id` returned by state().", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "domains", - "type_schema": { - "type": "array", - "items": { - "$ref": "#/definitions/DomainConfig" - } - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_cancel_keygen", - "doc": " Casts a vote to cancel key generation. Any keys that have already been generated\n are kept and we transition into Running state; remaining domains are permanently deleted.\n Deleted domain IDs cannot be reused again in future calls to vote_add_domains.\n\n A next_domain_id that matches that in the state's domains struct must be passed in. This is\n to prevent stale requests from accidentally cancelling a future key generation state.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "next_domain_id", - "type_schema": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_cancel_resharing", - "doc": " Casts a vote to cancel the current key resharing. If a threshold number of unique\n votes are collected to cancel the resharing, the contract state will revert back to the\n previous running state.\n\n - This method is idempotent, meaning a single account can not make more than one vote.\n - Only nodes from the previous running state are allowed to vote.\n\n Return value:\n - [Ok] if the vote was successfully collected.\n - [Err] if:\n - The signer is not a participant in the previous running state.\n - The contract is not in a resharing state.", - "kind": "call", - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_code_hash", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "code_hash", - "type_schema": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_foreign_chain_policy", - "doc": " Propose a new foreign chain policy.\n If all current participants vote for the exact same policy, it is applied.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "policy", - "type_schema": { - "$ref": "#/definitions/ForeignChainPolicy" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_new_parameters", - "doc": " Propose a new set of parameters (participants and threshold) for the MPC network.\n If a threshold number of votes are reached on the exact same proposal, this will transition\n the contract into the Resharing state.\n\n The epoch_id must be equal to 1 plus the current epoch ID (if Running) or prospective epoch\n ID (if Resharing). Otherwise the vote is ignored. This is to prevent late transactions from\n accidentally voting on outdated proposals.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "prospective_epoch_id", - "type_schema": { - "$ref": "#/definitions/EpochId" - } - }, - { - "name": "proposal", - "type_schema": { - "$ref": "#/definitions/ThresholdParameters" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_pk", - "doc": " Casts a vote for `public_key` for the attempt identified by `key_event_id`.\n\n The effect of this method is either:\n - Returns error (which aborts with no changes), if there is no active key generation\n attempt (including if the attempt timed out), if the signer is not a participant, or if\n the key_event_id corresponds to a different domain, different epoch, or different attempt\n from the current key generation attempt.\n - Returns Ok(()), with one of the following changes:\n - A vote has been collected but we don't have enough votes yet.\n - This vote is for a public key that disagrees from an earlier voted public key, causing\n the attempt to abort; another call to `start` is then necessary.\n - Everyone has now voted for the same public key; the state transitions into generating a\n key for the next domain.\n - Same as the last case, except that all domains have a generated key now, and the state\n transitions into Running with the newly generated keys.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "key_event_id", - "type_schema": { - "$ref": "#/definitions/KeyEventId" - } - }, - { - "name": "public_key", - "type_schema": { - "$ref": "#/definitions/PublicKey" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_reshared", - "doc": " Casts a vote for the successful resharing of the attempt identified by `key_event_id`.\n\n The effect of this method is either:\n - Returns error (which aborts with no changes), if there is no active key resharing attempt\n (including if the attempt timed out), if the signer is not a participant, or if the\n key_event_id corresponds to a different domain, different epoch, or different attempt\n from the current key resharing attempt.\n - Returns Ok(()), with one of the following changes:\n - A vote has been collected but we don't have enough votes yet.\n - Everyone has now voted; the state transitions into resharing the key for the next\n domain.\n - Same as the last case, except that all domains' keys have been reshared now, and the\n state transitions into Running with the newly reshared keys.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "key_event_id", - "type_schema": { - "$ref": "#/definitions/KeyEventId" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "null" - } - } - }, - { - "name": "vote_update", - "doc": " Vote for a proposed update given the [`UpdateId`] of the update.\n\n Returns `Ok(true)` if the amount of voters surpassed the threshold and the update was\n executed. Returns `Ok(false)` if the amount of voters did not surpass the threshold.\n Returns [`Error`] if the update was not found or if the voter is not a participant\n in the protocol.", - "kind": "call", - "params": { - "serialization_type": "json", - "args": [ - { - "name": "id", - "type_schema": { - "$ref": "#/definitions/UpdateId" - } - } - ] - }, - "result": { - "serialization_type": "json", - "type_schema": { - "type": "boolean" - } - } - } - ], - "root_schema": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "String", - "type": "string", - "definitions": { - "AccountId": { - "description": "A Near AccountId", - "type": "string" - }, - "AddDomainsVotes": { - "description": "Votes for adding new domains.", - "type": "object", - "required": [ - "proposal_by_account" - ], - "properties": { - "proposal_by_account": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "$ref": "#/definitions/DomainConfig2" - } - } - } - } - }, - "AttemptId": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "AttemptId2": { - "description": "Attempt identifier within a key event.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "Attestation": { - "oneOf": [ - { - "type": "object", - "required": [ - "Dstack" - ], - "properties": { - "Dstack": { - "$ref": "#/definitions/DstackAttestation" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Mock" - ], - "properties": { - "Mock": { - "$ref": "#/definitions/MockAttestation" - } - }, - "additionalProperties": false - } - ] - }, - "AuthenticatedAccountId": { - "description": "An account ID that has been authenticated (i.e., the caller is this account).", - "allOf": [ - { - "$ref": "#/definitions/AccountId" - } - ] - }, - "AuthenticatedParticipantId": { - "description": "A participant ID that has been authenticated (i.e., the caller is this participant).", - "allOf": [ - { - "$ref": "#/definitions/ParticipantId2" - } - ] - }, - "BackupServiceInfo": { - "type": "object", - "required": [ - "public_key" - ], - "properties": { - "public_key": { - "$ref": "#/definitions/Ed25519PublicKey" - } - } - }, - "BitcoinExtractor": { - "type": "string", - "enum": [ - "BlockHash" - ] - }, - "BitcoinRpcRequest": { - "type": "object", - "required": [ - "confirmations", - "extractors", - "tx_id" - ], - "properties": { - "confirmations": { - "$ref": "#/definitions/BlockConfirmations" - }, - "extractors": { - "type": "array", - "items": { - "$ref": "#/definitions/BitcoinExtractor" - } - }, - "tx_id": { - "$ref": "#/definitions/BitcoinTxId" - } - } - }, - "BitcoinTxId": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "BlockConfirmations": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "Bls12381G1PublicKey": { - "type": "string" - }, - "Bls12381G2PublicKey": { - "type": "string" - }, - "CKDRequest": { - "type": "object", - "required": [ - "app_id", - "app_public_key", - "domain_id" - ], - "properties": { - "app_id": { - "$ref": "#/definitions/CkdAppId" - }, - "app_public_key": { - "description": "The app ephemeral public key", - "allOf": [ - { - "$ref": "#/definitions/Bls12381G1PublicKey" - } - ] - }, - "domain_id": { - "$ref": "#/definitions/DomainId" - } - } - }, - "CKDRequestArgs": { - "type": "object", - "required": [ - "app_public_key", - "derivation_path", - "domain_id" - ], - "properties": { - "app_public_key": { - "$ref": "#/definitions/Bls12381G1PublicKey" - }, - "derivation_path": { - "type": "string" - }, - "domain_id": { - "$ref": "#/definitions/DomainId" - } - } - }, - "CKDResponse": { - "type": "object", - "required": [ - "big_c", - "big_y" - ], - "properties": { - "big_c": { - "$ref": "#/definitions/Bls12381G1PublicKey" - }, - "big_y": { - "$ref": "#/definitions/Bls12381G1PublicKey" - } - } - }, - "CkdAppId": { - "description": "AppId for CKD", - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - }, - "Collateral": { - "type": "object", - "required": [ - "pck_crl", - "pck_crl_issuer_chain", - "qe_identity", - "qe_identity_issuer_chain", - "qe_identity_signature", - "root_ca_crl", - "tcb_info", - "tcb_info_issuer_chain", - "tcb_info_signature" - ], - "properties": { - "pck_certificate_chain": { - "type": [ - "string", - "null" - ] - }, - "pck_crl": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "pck_crl_issuer_chain": { - "type": "string" - }, - "qe_identity": { - "type": "string" - }, - "qe_identity_issuer_chain": { - "type": "string" - }, - "qe_identity_signature": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "root_ca_crl": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "tcb_info": { - "type": "string" - }, - "tcb_info_issuer_chain": { - "type": "string" - }, - "tcb_info_signature": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - } - } - }, - "Config": { - "description": "Configuration parameters of the contract.", - "type": "object", - "required": [ - "ckd_call_gas_attachment_requirement_tera_gas", - "clean_tee_status_tera_gas", - "cleanup_orphaned_node_migrations_tera_gas", - "contract_upgrade_deposit_tera_gas", - "fail_on_timeout_tera_gas", - "key_event_timeout_blocks", - "remove_non_participant_update_votes_tera_gas", - "return_ck_and_clean_state_on_success_call_tera_gas", - "return_signature_and_clean_state_on_success_call_tera_gas", - "sign_call_gas_attachment_requirement_tera_gas", - "tee_upgrade_deadline_duration_seconds" - ], - "properties": { - "ckd_call_gas_attachment_requirement_tera_gas": { - "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "clean_tee_status_tera_gas": { - "description": "Prepaid gas for a `clean_tee_status` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "cleanup_orphaned_node_migrations_tera_gas": { - "description": "Prepaid gas for a `cleanup_orphaned_node_migrations` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "contract_upgrade_deposit_tera_gas": { - "description": "Amount of gas to deposit for contract and config updates.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "fail_on_timeout_tera_gas": { - "description": "Prepaid gas for a `fail_on_timeout` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "key_event_timeout_blocks": { - "description": "If a key event attempt has not successfully completed within this many blocks, it is considered failed.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "remove_non_participant_update_votes_tera_gas": { - "description": "Prepaid gas for a `remove_non_participant_update_votes` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "return_ck_and_clean_state_on_success_call_tera_gas": { - "description": "Prepaid gas for a `return_ck_and_clean_state_on_success` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "return_signature_and_clean_state_on_success_call_tera_gas": { - "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "sign_call_gas_attachment_requirement_tera_gas": { - "description": "Gas required for a sign request.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "tee_upgrade_deadline_duration_seconds": { - "description": "The grace period duration for expiry of old mpc image hashes once a new one is added.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "Curve": { - "description": "Elliptic curve used by a domain. More curves may be added in the future. When adding new curves, both Borsh *and* JSON serialization must be kept compatible.", - "type": "string", - "enum": [ - "Secp256k1", - "Ed25519", - "Bls12381", - "V2Secp256k1" - ] - }, - "Curve2": { - "description": "Elliptic curve used by a domain.", - "oneOf": [ - { - "type": "string", - "enum": [ - "Secp256k1", - "Ed25519", - "Bls12381" - ] - }, - { - "description": "Robust ECDSA variant.", - "type": "string", - "enum": [ - "V2Secp256k1" - ] - } - ] - }, - "DestinationNodeInfo": { - "type": "object", - "required": [ - "destination_node_info", - "signer_account_pk" - ], - "properties": { - "destination_node_info": { - "$ref": "#/definitions/ParticipantInfo" - }, - "signer_account_pk": { - "description": "the public key used by the node to sign transactions to the contract this key is different from the TLS key called `sign_pk` and stored in `ParticipantInfo`.", - "type": "string" - } - } - }, - "DomainConfig": { - "description": "Describes the configuration of a domain: the domain ID and the curve it uses.", - "type": "object", - "required": [ - "curve", - "id", - "purpose" - ], - "properties": { - "curve": { - "$ref": "#/definitions/Curve" - }, - "id": { - "$ref": "#/definitions/DomainId" - }, - "purpose": { - "$ref": "#/definitions/DomainPurpose" - } - } - }, - "DomainConfig2": { - "description": "Configuration for a signature domain.", - "type": "object", - "required": [ - "id", - "scheme" - ], - "properties": { - "id": { - "$ref": "#/definitions/DomainId2" - }, - "purpose": { - "description": "`None` when reading state from an old contract that predates domain purposes.", - "anyOf": [ - { - "$ref": "#/definitions/DomainPurpose" - }, - { - "type": "null" - } - ] - }, - "scheme": { - "$ref": "#/definitions/Curve2" - } - } - }, - "DomainId": { - "description": "Each domain corresponds to a specific root key in a specific signature scheme. There may be multiple domains per signature scheme. The domain ID uniquely identifies a domain.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "DomainId2": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "DomainPurpose": { - "description": "The purpose that a domain serves.", - "oneOf": [ - { - "description": "Domain is used by `sign()`.", - "type": "string", - "enum": [ - "Sign" - ] - }, - { - "description": "Domain is used by `verify_foreign_transaction()`.", - "type": "string", - "enum": [ - "ForeignTx" - ] - }, - { - "description": "Domain is used by `request_app_private_key()` (Confidential Key Derivation).", - "type": "string", - "enum": [ - "CKD" - ] - } - ] - }, - "DomainRegistry": { - "description": "Registry of all signature domains.", - "type": "object", - "required": [ - "domains", - "next_domain_id" - ], - "properties": { - "domains": { - "type": "array", - "items": { - "$ref": "#/definitions/DomainConfig2" - } - }, - "next_domain_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "DstackAttestation": { - "type": "object", - "required": [ - "collateral", - "quote", - "tcb_info" - ], - "properties": { - "collateral": { - "$ref": "#/definitions/Collateral" - }, - "quote": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "tcb_info": { - "$ref": "#/definitions/TcbInfo" - } - } - }, - "Ed25519PublicKey": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - }, - "Ed25519Signature": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - } - }, - "EpochId": { - "description": "An EpochId uniquely identifies a ThresholdParameters (but not vice-versa). Every time we change the ThresholdParameters (participants and threshold), we increment EpochId. Locally on each node, each keyshare is uniquely identified by the tuple (EpochId, DomainId, AttemptId).", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "EpochId2": { - "description": "Epoch identifier for key generation/resharing cycles.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "EventLog": { - "description": "Represents an event log entry in the system", - "type": "object", - "required": [ - "digest", - "event", - "event_payload", - "event_type", - "imr" - ], - "properties": { - "digest": { - "description": "The cryptographic digest of the event", - "type": "string" - }, - "event": { - "description": "The type of event as a string", - "type": "string" - }, - "event_payload": { - "description": "The payload data associated with the event", - "type": "string" - }, - "event_type": { - "description": "The type of event being logged", - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "imr": { - "description": "The index of the IMR (Integrity Measurement Register)", - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - }, - "EvmExtractor": { - "oneOf": [ - { - "type": "string", - "enum": [ - "BlockHash" - ] - }, - { - "type": "object", - "required": [ - "Log" - ], - "properties": { - "Log": { - "type": "object", - "required": [ - "log_index" - ], - "properties": { - "log_index": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - } - ] - }, - "EvmFinality": { - "type": "string", - "enum": [ - "Latest", - "Safe", - "Finalized" - ] - }, - "EvmRpcRequest": { - "type": "object", - "required": [ - "extractors", - "finality", - "tx_id" - ], - "properties": { - "extractors": { - "type": "array", - "items": { - "$ref": "#/definitions/EvmExtractor" - } - }, - "finality": { - "$ref": "#/definitions/EvmFinality" - }, - "tx_id": { - "$ref": "#/definitions/EvmTxId" - } - } - }, - "EvmTxId": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "ForeignChainPolicy": { - "type": "object", - "required": [ - "chains" - ], - "properties": { - "chains": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/NonEmptyBTreeSet_RpcProvider" - } - } - } - }, - "ForeignChainPolicyVotes": { - "type": "object", - "required": [ - "proposal_by_account" - ], - "properties": { - "proposal_by_account": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/ForeignChainPolicy" - } - } - } - }, - "ForeignChainRpcRequest": { - "oneOf": [ - { - "type": "object", - "required": [ - "Abstract" - ], - "properties": { - "Abstract": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Ethereum" - ], - "properties": { - "Ethereum": { - "$ref": "#/definitions/EvmRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Solana" - ], - "properties": { - "Solana": { - "$ref": "#/definitions/SolanaRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Bitcoin" - ], - "properties": { - "Bitcoin": { - "$ref": "#/definitions/BitcoinRpcRequest" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Starknet" - ], - "properties": { - "Starknet": { - "$ref": "#/definitions/StarknetRpcRequest" - } - }, - "additionalProperties": false - } - ] - }, - "Hash256": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "InitConfig": { - "description": "The initial configuration parameters for when initializing the contract. All fields are optional, as the contract can fill in defaults for any missing fields.", - "type": "object", - "properties": { - "ckd_call_gas_attachment_requirement_tera_gas": { - "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "clean_tee_status_tera_gas": { - "description": "Prepaid gas for a `clean_tee_status` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "cleanup_orphaned_node_migrations_tera_gas": { - "description": "Prepaid gas for a `cleanup_orphaned_node_migrations` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "contract_upgrade_deposit_tera_gas": { - "description": "Amount of gas to deposit for contract and config updates.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "fail_on_timeout_tera_gas": { - "description": "Prepaid gas for a `fail_on_timeout` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "key_event_timeout_blocks": { - "description": "If a key event attempt has not successfully completed within this many blocks, it is considered failed.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "remove_non_participant_update_votes_tera_gas": { - "description": "Prepaid gas for a `remove_non_participant_update_votes` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "return_ck_and_clean_state_on_success_call_tera_gas": { - "description": "Prepaid gas for a `return_ck_and_clean_state_on_success` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "return_signature_and_clean_state_on_success_call_tera_gas": { - "description": "Prepaid gas for a `return_signature_and_clean_state_on_success` call.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "sign_call_gas_attachment_requirement_tera_gas": { - "description": "Gas required for a sign request.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "tee_upgrade_deadline_duration_seconds": { - "description": "The grace period duration for expiry of old mpc image hashes once a new one is added.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - } - } - }, - "InitializingContractState": { - "description": "State when the contract is generating keys for new domains.", - "type": "object", - "required": [ - "cancel_votes", - "domains", - "epoch_id", - "generated_keys", - "generating_key" - ], - "properties": { - "cancel_votes": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedParticipantId" - }, - "uniqueItems": true - }, - "domains": { - "$ref": "#/definitions/DomainRegistry" - }, - "epoch_id": { - "$ref": "#/definitions/EpochId2" - }, - "generated_keys": { - "type": "array", - "items": { - "$ref": "#/definitions/KeyForDomain2" - } - }, - "generating_key": { - "$ref": "#/definitions/KeyEvent" - } - } - }, - "K256AffinePoint": { - "description": "AffinePoint on the Secp256k1 curve", - "type": "object", - "required": [ - "affine_point" - ], - "properties": { - "affine_point": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - } - } - }, - "K256Scalar": { - "type": "object", - "required": [ - "scalar" - ], - "properties": { - "scalar": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - } - } - }, - "KeyEvent": { - "description": "Key generation or resharing event state.", - "type": "object", - "required": [ - "domain", - "epoch_id", - "next_attempt_id", - "parameters" - ], - "properties": { - "domain": { - "$ref": "#/definitions/DomainConfig2" - }, - "epoch_id": { - "$ref": "#/definitions/EpochId2" - }, - "instance": { - "anyOf": [ - { - "$ref": "#/definitions/KeyEventInstance" - }, - { - "type": "null" - } - ] - }, - "next_attempt_id": { - "$ref": "#/definitions/AttemptId2" - }, - "parameters": { - "$ref": "#/definitions/ThresholdParameters2" - } - } - }, - "KeyEventId": { - "description": "A unique identifier for a key event (generation or resharing): `epoch_id`: identifies the ThresholdParameters that this key is intended to function in. `domain_id`: the domain this key is intended for. `attempt_id`: identifies a particular attempt for this key event, in case multiple attempts yielded partially valid results. This is incremented for each attempt within the same epoch and domain.", - "type": "object", - "required": [ - "attempt_id", - "domain_id", - "epoch_id" - ], - "properties": { - "attempt_id": { - "$ref": "#/definitions/AttemptId" - }, - "domain_id": { - "$ref": "#/definitions/DomainId" - }, - "epoch_id": { - "$ref": "#/definitions/EpochId" - } - } - }, - "KeyEventInstance": { - "description": "State of a key generation/resharing instance.", - "type": "object", - "required": [ - "attempt_id", - "completed", - "expires_on", - "started_in" - ], - "properties": { - "attempt_id": { - "$ref": "#/definitions/AttemptId2" - }, - "completed": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedParticipantId" - }, - "uniqueItems": true - }, - "expires_on": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "public_key": { - "anyOf": [ - { - "$ref": "#/definitions/PublicKeyExtended2" - }, - { - "type": "null" - } - ] - }, - "started_in": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "KeyForDomain": { - "description": "The identification of a specific distributed key, based on which a node would know exactly what keyshare it has corresponds to this distributed key. (A distributed key refers to a specific set of keyshares that nodes have which can be pieced together to form the secret key.)", - "type": "object", - "required": [ - "attempt", - "domain_id", - "key" - ], - "properties": { - "attempt": { - "description": "The attempt ID that generated (initially or as a result of resharing) this distributed key. Nodes may have made multiple attempts to generate the distributed key, and this uniquely identifies which one should ultimately be used.", - "allOf": [ - { - "$ref": "#/definitions/AttemptId" - } - ] - }, - "domain_id": { - "description": "Identifies the domain this key is intended for.", - "allOf": [ - { - "$ref": "#/definitions/DomainId" - } - ] - }, - "key": { - "description": "Identifies the public key. Although technically redundant given that we have the AttemptId, we keep it here in the contract so that it can be verified against and queried.", - "allOf": [ - { - "$ref": "#/definitions/PublicKeyExtended" - } - ] - } - } - }, - "KeyForDomain2": { - "description": "A public key for a specific domain.", - "type": "object", - "required": [ - "attempt", - "domain_id", - "key" - ], - "properties": { - "attempt": { - "$ref": "#/definitions/AttemptId2" - }, - "domain_id": { - "$ref": "#/definitions/DomainId2" - }, - "key": { - "$ref": "#/definitions/PublicKeyExtended2" - } - } - }, - "Keyset": { - "description": "Represents a key for every domain in a specific epoch.", - "type": "object", - "required": [ - "domains", - "epoch_id" - ], - "properties": { - "domains": { - "type": "array", - "items": { - "$ref": "#/definitions/KeyForDomain" - } - }, - "epoch_id": { - "$ref": "#/definitions/EpochId" - } - } - }, - "Keyset2": { - "description": "Set of keys for the current epoch.", - "type": "object", - "required": [ - "domains", - "epoch_id" - ], - "properties": { - "domains": { - "type": "array", - "items": { - "$ref": "#/definitions/KeyForDomain2" - } - }, - "epoch_id": { - "$ref": "#/definitions/EpochId2" - } - } - }, - "Metrics": { - "type": "object", - "required": [ - "sign_with_v1_payload_count", - "sign_with_v2_payload_count" - ], - "properties": { - "sign_with_v1_payload_count": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "sign_with_v2_payload_count": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "MockAttestation": { - "oneOf": [ - { - "description": "Always pass validation", - "type": "string", - "enum": [ - "Valid" - ] - }, - { - "description": "Always fails validation", - "type": "string", - "enum": [ - "Invalid" - ] - }, - { - "description": "Pass validation depending on the set constraints", - "type": "object", - "required": [ - "WithConstraints" - ], - "properties": { - "WithConstraints": { - "type": "object", - "properties": { - "expiry_timestamp_seconds": { - "description": "Unix time stamp for when this attestation expires.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "launcher_docker_compose_hash": { - "default": null, - "type": [ - "string", - "null" - ], - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "mpc_docker_image_hash": { - "default": null, - "type": [ - "string", - "null" - ], - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "NodeId": { - "type": "object", - "required": [ - "account_id", - "tls_public_key" - ], - "properties": { - "account_id": { - "description": "Operator account", - "type": "string" - }, - "account_public_key": { - "type": [ - "string", - "null" - ] - }, - "tls_public_key": { - "description": "TLS public key, MUST BE of type Ed25519", - "type": "string" - } - } - }, - "NonEmptyBTreeSet_RpcProvider": { - "type": "array", - "items": { - "$ref": "#/definitions/RpcProvider" - }, - "minItems": 1, - "uniqueItems": true - }, - "ParticipantId": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "ParticipantId2": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "ParticipantInfo": { - "type": "object", - "required": [ - "sign_pk", - "url" - ], - "properties": { - "sign_pk": { - "description": "The public key used for verifying messages.", - "type": "string" - }, - "url": { - "type": "string" - } - } - }, - "ParticipantInfo2": { - "type": "object", - "required": [ - "sign_pk", - "url" - ], - "properties": { - "sign_pk": { - "type": "string" - }, - "url": { - "type": "string" - } - } - }, - "Participants": { - "type": "object", - "required": [ - "next_id", - "participants" - ], - "properties": { - "next_id": { - "$ref": "#/definitions/ParticipantId" - }, - "participants": { - "type": "array", - "items": { - "type": "array", - "items": [ - { - "description": "NEAR Account Identifier.\n\nThis is a unique, syntactically valid, human-readable account identifier on the NEAR network.\n\n[See the crate-level docs for information about validation.](index.html#account-id-rules)\n\nAlso see [Error kind precedence](AccountId#error-kind-precedence).\n\n## Examples\n\n``` use near_account_id::AccountId;\n\nlet alice: AccountId = \"alice.near\".parse().unwrap();\n\nassert!(\"ƒelicia.near\".parse::().is_err()); // (ƒ is not f) ```", - "type": "string" - }, - { - "$ref": "#/definitions/ParticipantId" - }, - { - "$ref": "#/definitions/ParticipantInfo" - } - ], - "maxItems": 3, - "minItems": 3 - } - } - } - }, - "Participants2": { - "description": "DTO representation of the contract-internal `Participants` type.\n\nIt decouples the JSON wire format (used in view methods like `state()` via [`ThresholdParameters`](crate::types::state::ThresholdParameters)) from the internal `Participants` representation, allowing internal changes (e.g., migrating to [`BTreeMap`](std::collections::BTreeMap) in [#1861](https://github.com/near/mpc/pull/1861)) without breaking the public API.", - "type": "object", - "required": [ - "next_id", - "participants" - ], - "properties": { - "next_id": { - "$ref": "#/definitions/ParticipantId2" - }, - "participants": { - "type": "array", - "items": { - "type": "array", - "items": [ - { - "$ref": "#/definitions/AccountId" - }, - { - "$ref": "#/definitions/ParticipantId2" - }, - { - "$ref": "#/definitions/ParticipantInfo2" - } - ], - "maxItems": 3, - "minItems": 3 - } - } - } - }, - "Payload": { - "description": "A signature payload; the right payload must be passed in for the curve. The json encoding for this payload converts the bytes to hex string.", - "oneOf": [ - { - "type": "object", - "required": [ - "Ecdsa" - ], - "properties": { - "Ecdsa": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Eddsa" - ], - "properties": { - "Eddsa": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - } - } - }, - "additionalProperties": false - } - ] - }, - "PromiseOrValueCKDResponse": { - "type": "object", - "required": [ - "big_c", - "big_y" - ], - "properties": { - "big_c": { - "$ref": "#/definitions/Bls12381G1PublicKey" - }, - "big_y": { - "$ref": "#/definitions/Bls12381G1PublicKey" - } - } - }, - "PromiseOrValueSignatureResponse": { - "oneOf": [ - { - "type": "object", - "required": [ - "big_r", - "recovery_id", - "s", - "scheme" - ], - "properties": { - "big_r": { - "$ref": "#/definitions/K256AffinePoint" - }, - "recovery_id": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "s": { - "$ref": "#/definitions/K256Scalar" - }, - "scheme": { - "type": "string", - "enum": [ - "Secp256k1" - ] - } - } - }, - { - "type": "object", - "required": [ - "scheme", - "signature" - ], - "properties": { - "scheme": { - "type": "string", - "enum": [ - "Ed25519" - ] - }, - "signature": { - "$ref": "#/definitions/Ed25519Signature" - } - } - } - ] - }, - "PromiseOrValueVerifyForeignTransactionResponse": { - "type": "object", - "required": [ - "payload_hash", - "signature" - ], - "properties": { - "payload_hash": { - "$ref": "#/definitions/Hash256" - }, - "signature": { - "$ref": "#/definitions/SignatureResponse" - } - } - }, - "ProposedUpdates": { - "type": "object", - "required": [ - "updates", - "votes" - ], - "properties": { - "updates": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/UpdateHash" - } - }, - "votes": { - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "ProtocolContractState": { - "description": "The main protocol contract state enum.", - "oneOf": [ - { - "type": "string", - "enum": [ - "NotInitialized" - ] - }, - { - "type": "object", - "required": [ - "Initializing" - ], - "properties": { - "Initializing": { - "$ref": "#/definitions/InitializingContractState" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Running" - ], - "properties": { - "Running": { - "$ref": "#/definitions/RunningContractState" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Resharing" - ], - "properties": { - "Resharing": { - "$ref": "#/definitions/ResharingContractState" - } - }, - "additionalProperties": false - } - ] - }, - "PublicKey": { - "oneOf": [ - { - "type": "object", - "required": [ - "Secp256k1" - ], - "properties": { - "Secp256k1": { - "$ref": "#/definitions/Secp256k1PublicKey" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Ed25519" - ], - "properties": { - "Ed25519": { - "$ref": "#/definitions/Ed25519PublicKey" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Bls12381" - ], - "properties": { - "Bls12381": { - "$ref": "#/definitions/Bls12381G2PublicKey" - } - }, - "additionalProperties": false - } - ] - }, - "PublicKeyExtended": { - "oneOf": [ - { - "type": "object", - "required": [ - "Secp256k1" - ], - "properties": { - "Secp256k1": { - "type": "object", - "required": [ - "near_public_key" - ], - "properties": { - "near_public_key": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Ed25519" - ], - "properties": { - "Ed25519": { - "type": "object", - "required": [ - "edwards_point", - "near_public_key_compressed" - ], - "properties": { - "edwards_point": { - "description": "Decompressed Edwards point used for curve arithmetic operations.", - "allOf": [ - { - "$ref": "#/definitions/SerializableEdwardsPoint" - } - ] - }, - "near_public_key_compressed": { - "description": "Serialized compressed Edwards-y point.", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Bls12381" - ], - "properties": { - "Bls12381": { - "type": "object", - "required": [ - "public_key" - ], - "properties": { - "public_key": { - "$ref": "#/definitions/PublicKey" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "PublicKeyExtended2": { - "description": "Extended public key representation for different signature schemes.", - "oneOf": [ - { - "description": "Secp256k1 public key (ECDSA).", - "type": "object", - "required": [ - "Secp256k1" - ], - "properties": { - "Secp256k1": { - "type": "object", - "required": [ - "near_public_key" - ], - "properties": { - "near_public_key": { - "description": "The public key in NEAR SDK format (string representation).", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Ed25519 public key.", - "type": "object", - "required": [ - "Ed25519" - ], - "properties": { - "Ed25519": { - "type": "object", - "required": [ - "edwards_point", - "near_public_key_compressed" - ], - "properties": { - "edwards_point": { - "description": "The Edwards point (32 bytes).", - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - }, - "near_public_key_compressed": { - "description": "The compressed public key in NEAR SDK format.", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "BLS12-381 public key.", - "type": "object", - "required": [ - "Bls12381" - ], - "properties": { - "Bls12381": { - "type": "object", - "required": [ - "public_key" - ], - "properties": { - "public_key": { - "description": "The public key.", - "allOf": [ - { - "$ref": "#/definitions/PublicKey" - } - ] - } - } - } - }, - "additionalProperties": false - } - ] - }, - "ResharingContractState": { - "description": "State when the contract is resharing keys to new participants.", - "type": "object", - "required": [ - "cancellation_requests", - "previous_running_state", - "reshared_keys", - "resharing_key" - ], - "properties": { - "cancellation_requests": { - "type": "array", - "items": { - "$ref": "#/definitions/AuthenticatedAccountId" - }, - "uniqueItems": true - }, - "previous_running_state": { - "$ref": "#/definitions/RunningContractState" - }, - "reshared_keys": { - "type": "array", - "items": { - "$ref": "#/definitions/KeyForDomain2" - } - }, - "resharing_key": { - "$ref": "#/definitions/KeyEvent" - } - } - }, - "RpcProvider": { - "type": "object", - "required": [ - "rpc_url" - ], - "properties": { - "rpc_url": { - "type": "string" - } - } - }, - "RunningContractState": { - "description": "State when the contract is ready for signature operations.", - "type": "object", - "required": [ - "add_domains_votes", - "domains", - "keyset", - "parameters", - "parameters_votes" - ], - "properties": { - "add_domains_votes": { - "$ref": "#/definitions/AddDomainsVotes" - }, - "domains": { - "$ref": "#/definitions/DomainRegistry" - }, - "keyset": { - "$ref": "#/definitions/Keyset2" - }, - "parameters": { - "$ref": "#/definitions/ThresholdParameters2" - }, - "parameters_votes": { - "$ref": "#/definitions/ThresholdParametersVotes" - }, - "previously_cancelled_resharing_epoch_id": { - "anyOf": [ - { - "$ref": "#/definitions/EpochId2" - }, - { - "type": "null" - } - ] - } - } - }, - "Secp256k1PublicKey": { - "type": "string" - }, - "SerializableEdwardsPoint": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - }, - "SignRequestArgs": { - "type": "object", - "required": [ - "path" - ], - "properties": { - "domain_id": { - "anyOf": [ - { - "$ref": "#/definitions/DomainId" - }, - { - "type": "null" - } - ] - }, - "key_version": { - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - }, - "path": { - "type": "string" - }, - "payload": { - "type": [ - "array", - "null" - ], - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - }, - "payload_v2": { - "anyOf": [ - { - "$ref": "#/definitions/Payload" - }, - { - "type": "null" - } - ] - } - } - }, - "SignatureRequest": { - "type": "object", - "required": [ - "domain_id", - "payload", - "tweak" - ], - "properties": { - "domain_id": { - "$ref": "#/definitions/DomainId" - }, - "payload": { - "$ref": "#/definitions/Payload" - }, - "tweak": { - "$ref": "#/definitions/Tweak" - } - } - }, - "SignatureResponse": { - "oneOf": [ - { - "type": "object", - "required": [ - "big_r", - "recovery_id", - "s", - "scheme" - ], - "properties": { - "big_r": { - "$ref": "#/definitions/K256AffinePoint" - }, - "recovery_id": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "s": { - "$ref": "#/definitions/K256Scalar" - }, - "scheme": { - "type": "string", - "enum": [ - "Secp256k1" - ] - } - } - }, - { - "type": "object", - "required": [ - "scheme", - "signature" - ], - "properties": { - "scheme": { - "type": "string", - "enum": [ - "Ed25519" - ] - }, - "signature": { - "$ref": "#/definitions/Ed25519Signature" - } - } - } - ] - }, - "SolanaExtractor": { - "oneOf": [ - { - "type": "object", - "required": [ - "SolanaProgramIdIndex" - ], - "properties": { - "SolanaProgramIdIndex": { - "type": "object", - "required": [ - "ix_index" - ], - "properties": { - "ix_index": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "SolanaDataHash" - ], - "properties": { - "SolanaDataHash": { - "type": "object", - "required": [ - "ix_index" - ], - "properties": { - "ix_index": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - } - ] - }, - "SolanaFinality": { - "type": "string", - "enum": [ - "Processed", - "Confirmed", - "Finalized" - ] - }, - "SolanaRpcRequest": { - "type": "object", - "required": [ - "extractors", - "finality", - "tx_id" - ], - "properties": { - "extractors": { - "type": "array", - "items": { - "$ref": "#/definitions/SolanaExtractor" - } - }, - "finality": { - "$ref": "#/definitions/SolanaFinality" - }, - "tx_id": { - "$ref": "#/definitions/SolanaTxId" - } - } - }, - "SolanaTxId": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - } - }, - "StarknetExtractor": { - "oneOf": [ - { - "type": "string", - "enum": [ - "BlockHash" - ] - }, - { - "type": "object", - "required": [ - "Log" - ], - "properties": { - "Log": { - "type": "object", - "required": [ - "log_index" - ], - "properties": { - "log_index": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - } - ] - }, - "StarknetFelt": { - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "StarknetFinality": { - "type": "string", - "enum": [ - "AcceptedOnL2", - "AcceptedOnL1" - ] - }, - "StarknetRpcRequest": { - "type": "object", - "required": [ - "extractors", - "finality", - "tx_id" - ], - "properties": { - "extractors": { - "type": "array", - "items": { - "$ref": "#/definitions/StarknetExtractor" - } - }, - "finality": { - "$ref": "#/definitions/StarknetFinality" - }, - "tx_id": { - "$ref": "#/definitions/StarknetTxId" - } - } - }, - "StarknetTxId": { - "$ref": "#/definitions/StarknetFelt" - }, - "TcbInfo": { - "description": "Trusted Computing Base information structure", - "type": "object", - "required": [ - "app_compose", - "compose_hash", - "device_id", - "event_log", - "mrtd", - "rtmr0", - "rtmr1", - "rtmr2", - "rtmr3" - ], - "properties": { - "app_compose": { - "description": "The app compose", - "type": "string" - }, - "compose_hash": { - "description": "The hash of the compose configuration", - "type": "string" - }, - "device_id": { - "description": "The device identifier", - "type": "string" - }, - "event_log": { - "description": "The event log entries", - "type": "array", - "items": { - "$ref": "#/definitions/EventLog" - } - }, - "mrtd": { - "description": "The measurement root of trust", - "type": "string" - }, - "os_image_hash": { - "description": "The hash of the OS image. This is empty if the OS image is not measured by KMS.", - "default": "", - "type": "string" - }, - "rtmr0": { - "description": "The value of RTMR0 (Runtime Measurement Register 0)", - "type": "string" - }, - "rtmr1": { - "description": "The value of RTMR1 (Runtime Measurement Register 1)", - "type": "string" - }, - "rtmr2": { - "description": "The value of RTMR2 (Runtime Measurement Register 2)", - "type": "string" - }, - "rtmr3": { - "description": "The value of RTMR3 (Runtime Measurement Register 3)", - "type": "string" - } - } - }, - "Threshold": { - "description": "Stores the cryptographic threshold for a distributed key. ``` use mpc_contract::primitives::thresholds::Threshold; let dt = Threshold::new(8); assert!(dt.value() == 8); ```", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "Threshold2": { - "description": "Threshold value for distributed key operations.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "ThresholdParameters": { - "description": "Stores information about the threshold key parameters: - owners of key shares - cryptographic threshold", - "type": "object", - "required": [ - "participants", - "threshold" - ], - "properties": { - "participants": { - "$ref": "#/definitions/Participants" - }, - "threshold": { - "$ref": "#/definitions/Threshold" - } - } - }, - "ThresholdParameters2": { - "description": "Threshold parameters for distributed key operations.", - "type": "object", - "required": [ - "participants", - "threshold" - ], - "properties": { - "participants": { - "$ref": "#/definitions/Participants2" - }, - "threshold": { - "$ref": "#/definitions/Threshold2" - } - } - }, - "ThresholdParametersVotes": { - "description": "Votes for threshold parameter changes.", - "type": "object", - "required": [ - "proposal_by_account" - ], - "properties": { - "proposal_by_account": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/ThresholdParameters2" - } - } - } - }, - "Tweak": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - }, - "UpdateHash": { - "description": "An update hash", - "oneOf": [ - { - "type": "object", - "required": [ - "Code" - ], - "properties": { - "Code": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Config" - ], - "properties": { - "Config": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - } - }, - "additionalProperties": false - } - ] - }, - "UpdateId": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "VerifiedAttestation": { - "oneOf": [ - { - "type": "object", - "required": [ - "Dstack" - ], - "properties": { - "Dstack": { - "$ref": "#/definitions/VerifiedDstackAttestation" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Mock" - ], - "properties": { - "Mock": { - "$ref": "#/definitions/MockAttestation" - } - }, - "additionalProperties": false - } - ] - }, - "VerifiedDstackAttestation": { - "type": "object", - "required": [ - "expiry_timestamp_seconds", - "launcher_compose_hash", - "mpc_image_hash" - ], - "properties": { - "expiry_timestamp_seconds": { - "description": "Unix time stamp for when this attestation expires.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "launcher_compose_hash": { - "description": "The digest of the launcher compose file running.", - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - }, - "mpc_image_hash": { - "description": "The digest of the MPC image running.", - "type": "string", - "pattern": "^(?:[0-9A-Fa-f]{2})*$" - } - } - }, - "VerifyForeignTransactionRequest": { - "type": "object", - "required": [ - "domain_id", - "payload_version", - "request" - ], - "properties": { - "domain_id": { - "$ref": "#/definitions/DomainId2" - }, - "payload_version": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "request": { - "$ref": "#/definitions/ForeignChainRpcRequest" - } - } - }, - "VerifyForeignTransactionRequestArgs": { - "type": "object", - "required": [ - "domain_id", - "payload_version", - "request" - ], - "properties": { - "domain_id": { - "$ref": "#/definitions/DomainId2" - }, - "payload_version": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "request": { - "$ref": "#/definitions/ForeignChainRpcRequest" - } - } - }, - "VerifyForeignTransactionResponse": { - "type": "object", - "required": [ - "payload_hash", - "signature" - ], - "properties": { - "payload_hash": { - "$ref": "#/definitions/Hash256" - }, - "signature": { - "$ref": "#/definitions/SignatureResponse" - } - } - }, - "YieldIndex": { - "description": "The index into calling the YieldResume feature of NEAR. This will allow to resume a yield call after the contract has been called back via this index.", - "type": "object", - "required": [ - "data_id" - ], - "properties": { - "data_id": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "maxItems": 32, - "minItems": 32 - } - } - } - } - } - } -} From 5469dfbb72d036897b7f849ae7ea945ecc8e4e12 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:04:16 +0100 Subject: [PATCH 11/21] Snap file changing --- .../snapshots/abi__abi_has_not_changed.snap | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index c5124def7..5c195c8c9 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -415,7 +415,7 @@ expression: abi "type_schema": { "anyOf": [ { - "$ref": "#/definitions/SignatureScheme" + "$ref": "#/definitions/Curve" }, { "type": "null" @@ -1667,6 +1667,16 @@ expression: abi } } }, + "Curve": { + "description": "Elliptic curve used by a domain. More curves may be added in the future. When adding new curves, both Borsh *and* JSON serialization must be kept compatible.", + "type": "string", + "enum": [ + "Secp256k1", + "Ed25519", + "Bls12381", + "V2Secp256k1" + ] + }, "DestinationNodeInfo": { "type": "object", "required": [ @@ -1684,22 +1694,22 @@ expression: abi } }, "DomainConfig": { - "description": "Describes the configuration of a domain: the domain ID and the protocol it uses.", + "description": "Describes the configuration of a domain: the domain ID and the curve it uses.", "type": "object", "required": [ + "curve", "id", - "purpose", - "scheme" + "purpose" ], "properties": { + "curve": { + "$ref": "#/definitions/Curve" + }, "id": { "$ref": "#/definitions/DomainId" }, "purpose": { "$ref": "#/definitions/DomainPurpose" - }, - "scheme": { - "$ref": "#/definitions/SignatureScheme" } } }, @@ -1726,7 +1736,7 @@ expression: abi ] }, "scheme": { - "$ref": "#/definitions/SignatureScheme2" + "$ref": "#/definitions/SignatureScheme" } } }, @@ -3211,16 +3221,6 @@ expression: abi ] }, "SignatureScheme": { - "description": "Uniquely identifies a specific request algorithm. More protocols may be added in the future. When adding new protocols, both Borsh *and* JSON serialization must be kept compatible.", - "type": "string", - "enum": [ - "Secp256k1", - "Ed25519", - "Bls12381", - "V2Secp256k1" - ] - }, - "SignatureScheme2": { "description": "Supported signature schemes.", "oneOf": [ { From f3246543cac4eb9487ee9a4ee45f04d53a68d0de Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:51:42 +0100 Subject: [PATCH 12/21] missing one curve --- crates/contract/src/primitives/domain.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/contract/src/primitives/domain.rs b/crates/contract/src/primitives/domain.rs index f79684af5..a6700a191 100644 --- a/crates/contract/src/primitives/domain.rs +++ b/crates/contract/src/primitives/domain.rs @@ -78,6 +78,7 @@ pub fn is_valid_curve_for_purpose(purpose: DomainPurpose, curve: Curve) -> bool #[derive(Debug, Clone, PartialEq, Eq)] pub struct DomainConfig { pub id: DomainId, + #[serde(rename = "scheme")] pub curve: Curve, pub purpose: DomainPurpose, } @@ -411,7 +412,7 @@ pub mod tests { purpose: DomainPurpose::Sign, }; let json = serde_json::to_string(&domain_config).unwrap(); - assert_eq!(json, r#"{"id":3,"curve":"Secp256k1","purpose":"Sign"}"#); + assert_eq!(json, r#"{"id":3,"scheme":"Secp256k1","purpose":"Sign"}"#); let domain_config: DomainConfig = serde_json::from_str(&json).unwrap(); assert_eq!(domain_config.id, DomainId(3)); From dfb56743ff6345b9361a2cfda88ebc3e6c344e17 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:59:56 +0100 Subject: [PATCH 13/21] Snap changes --- .../tests/snapshots/abi__abi_has_not_changed.snap | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index 5c195c8c9..4c5353eba 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -1697,19 +1697,19 @@ expression: abi "description": "Describes the configuration of a domain: the domain ID and the curve it uses.", "type": "object", "required": [ - "curve", "id", - "purpose" + "purpose", + "scheme" ], "properties": { - "curve": { - "$ref": "#/definitions/Curve" - }, "id": { "$ref": "#/definitions/DomainId" }, "purpose": { "$ref": "#/definitions/DomainPurpose" + }, + "scheme": { + "$ref": "#/definitions/Curve" } } }, From a99a4454b0b997b9c9508a71aaed375bf4d847d6 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:09:45 +0100 Subject: [PATCH 14/21] Renaming ed25519 to Curve25519 --- crates/contract/src/dto_mapping.rs | 2 +- crates/contract/src/lib.rs | 4 ++-- crates/contract/src/primitives/domain.rs | 21 ++++++++++--------- crates/contract/src/primitives/test_utils.rs | 2 +- crates/contract/src/state/running.rs | 2 +- .../tests/inprocess/attestation_submission.rs | 2 +- crates/contract/tests/sandbox/common.rs | 6 +++--- .../sandbox/upgrade_to_current_contract.rs | 2 +- crates/contract/tests/sandbox/utils/consts.rs | 2 +- .../contract/tests/sandbox/utils/interface.rs | 2 +- .../tests/sandbox/utils/shared_key_utils.rs | 2 +- crates/contract/tests/sandbox/vote.rs | 2 +- crates/devnet/src/contracts.rs | 4 ++-- crates/devnet/src/loadtest.rs | 2 +- crates/node/src/coordinator.rs | 2 +- crates/node/src/key_events.rs | 4 ++-- crates/node/src/mpc_client.rs | 6 +++--- crates/node/src/tests.rs | 2 +- crates/node/src/tests/basic_cluster.rs | 2 +- crates/node/src/tests/multidomain.rs | 10 ++++----- crates/node/src/tests/resharing.rs | 6 +++--- 21 files changed, 44 insertions(+), 43 deletions(-) diff --git a/crates/contract/src/dto_mapping.rs b/crates/contract/src/dto_mapping.rs index afde3a1eb..d25dc3d04 100644 --- a/crates/contract/src/dto_mapping.rs +++ b/crates/contract/src/dto_mapping.rs @@ -515,7 +515,7 @@ impl IntoInterfaceType for Curve { fn into_dto_type(self) -> dtos::SignatureScheme { match self { Curve::Secp256k1 => dtos::SignatureScheme::Secp256k1, - Curve::Ed25519 => dtos::SignatureScheme::Ed25519, + Curve::Curve25519 => dtos::SignatureScheme::Ed25519, Curve::Bls12381 => dtos::SignatureScheme::Bls12381, Curve::V2Secp256k1 => dtos::SignatureScheme::V2Secp256k1, } diff --git a/crates/contract/src/lib.rs b/crates/contract/src/lib.rs index f60fd9bef..ceb2580d6 100644 --- a/crates/contract/src/lib.rs +++ b/crates/contract/src/lib.rs @@ -261,7 +261,7 @@ impl MpcContract { .into_option() .expect("Ecdsa payload cannot be converted to Scalar"); } - Curve::Ed25519 => { + Curve::Curve25519 => { request.payload.as_eddsa().expect("Payload is not EdDSA"); } Curve::Bls12381 => { @@ -2174,7 +2174,7 @@ mod tests { let (pk, sk) = new_secp256k1(rng); (pk.into(), SharedSecretKey::Secp256k1(sk)) } - Curve::Ed25519 => { + Curve::Curve25519 => { let (pk, sk) = new_ed25519(rng); (pk.into(), SharedSecretKey::Ed25519(sk)) } diff --git a/crates/contract/src/primitives/domain.rs b/crates/contract/src/primitives/domain.rs index a6700a191..2804b7123 100644 --- a/crates/contract/src/primitives/domain.rs +++ b/crates/contract/src/primitives/domain.rs @@ -40,7 +40,8 @@ impl Display for DomainId { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Curve { Secp256k1, - Ed25519, + #[serde(alias = "Ed25519")] + Curve25519, Bls12381, V2Secp256k1, // Robust ECDSA } @@ -66,7 +67,7 @@ pub fn is_valid_curve_for_purpose(purpose: DomainPurpose, curve: Curve) -> bool (purpose, curve), (DomainPurpose::Sign, Curve::Secp256k1) | (DomainPurpose::Sign, Curve::V2Secp256k1) - | (DomainPurpose::Sign, Curve::Ed25519) + | (DomainPurpose::Sign, Curve::Curve25519) | (DomainPurpose::ForeignTx, Curve::Secp256k1) | (DomainPurpose::CKD, Curve::Bls12381) ) @@ -286,7 +287,7 @@ pub mod tests { }, DomainConfig { id: DomainId(1), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }, ]; @@ -343,7 +344,7 @@ pub mod tests { }, DomainConfig { id: DomainId(2), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }, DomainConfig { @@ -382,7 +383,7 @@ pub mod tests { }, DomainConfig { id: DomainId(2), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }, DomainConfig { @@ -399,7 +400,7 @@ pub mod tests { Some(DomainId(3)) ); assert_eq!( - registry.most_recent_domain_for_curve(Curve::Ed25519), + registry.most_recent_domain_for_curve(Curve::Curve25519), Some(DomainId(2)) ); } @@ -446,7 +447,7 @@ pub mod tests { #[rstest] #[case(Curve::Secp256k1, DomainPurpose::Sign)] - #[case(Curve::Ed25519, DomainPurpose::Sign)] + #[case(Curve::Curve25519, DomainPurpose::Sign)] #[case(Curve::V2Secp256k1, DomainPurpose::Sign)] #[case(Curve::Bls12381, DomainPurpose::CKD)] fn test_infer_purpose_from_curve(#[case] curve: Curve, #[case] expected: DomainPurpose) { @@ -457,12 +458,12 @@ pub mod tests { // Valid combinations #[case(DomainPurpose::Sign, Curve::Secp256k1, true)] #[case(DomainPurpose::Sign, Curve::V2Secp256k1, true)] - #[case(DomainPurpose::Sign, Curve::Ed25519, true)] + #[case(DomainPurpose::Sign, Curve::Curve25519, true)] #[case(DomainPurpose::ForeignTx, Curve::Secp256k1, true)] #[case(DomainPurpose::CKD, Curve::Bls12381, true)] // Invalid combinations #[case(DomainPurpose::Sign, Curve::Bls12381, false)] - #[case(DomainPurpose::ForeignTx, Curve::Ed25519, false)] + #[case(DomainPurpose::ForeignTx, Curve::Curve25519, false)] #[case(DomainPurpose::ForeignTx, Curve::Bls12381, false)] #[case(DomainPurpose::ForeignTx, Curve::V2Secp256k1, false)] #[case(DomainPurpose::CKD, Curve::Secp256k1, false)] @@ -578,7 +579,7 @@ pub mod tests { }]; let proposal_b = vec![DomainConfig { id: DomainId(0), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }]; let mut votes = AddDomainsVotes::default(); diff --git a/crates/contract/src/primitives/test_utils.rs b/crates/contract/src/primitives/test_utils.rs index 5ac224600..92dbc34cc 100644 --- a/crates/contract/src/primitives/test_utils.rs +++ b/crates/contract/src/primitives/test_utils.rs @@ -13,7 +13,7 @@ use std::collections::BTreeMap; const ALL_CURVES: [Curve; 4] = [ Curve::Secp256k1, - Curve::Ed25519, + Curve::Curve25519, Curve::Bls12381, Curve::V2Secp256k1, ]; diff --git a/crates/contract/src/state/running.rs b/crates/contract/src/state/running.rs index bab33b327..dffef643a 100644 --- a/crates/contract/src/state/running.rs +++ b/crates/contract/src/state/running.rs @@ -348,7 +348,7 @@ pub mod running_tests { #[rstest] #[case(Curve::Bls12381, DomainPurpose::Sign)] - #[case(Curve::Ed25519, DomainPurpose::ForeignTx)] + #[case(Curve::Curve25519, DomainPurpose::ForeignTx)] #[case(Curve::Secp256k1, DomainPurpose::CKD)] fn vote_add_domains__should_reject_invalid_curve_purpose( #[case] curve: Curve, diff --git a/crates/contract/tests/inprocess/attestation_submission.rs b/crates/contract/tests/inprocess/attestation_submission.rs index b8d6b25a6..8c73ba760 100644 --- a/crates/contract/tests/inprocess/attestation_submission.rs +++ b/crates/contract/tests/inprocess/attestation_submission.rs @@ -148,7 +148,7 @@ impl TestSetupBuilder { .contract .vote_add_domains(vec![DomainConfig { id: DomainId(1), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }]) .unwrap(); diff --git a/crates/contract/tests/sandbox/common.rs b/crates/contract/tests/sandbox/common.rs index 62b94d12d..0032c7a0e 100644 --- a/crates/contract/tests/sandbox/common.rs +++ b/crates/contract/tests/sandbox/common.rs @@ -203,7 +203,7 @@ pub async fn init_with_candidates( .map(|(i, pk)| { let domain_id = DomainId((i as u64) * 2); let curve = match pk { - dtos::PublicKey::Ed25519(_) => Curve::Ed25519, + dtos::PublicKey::Ed25519(_) => Curve::Curve25519, dtos::PublicKey::Secp256k1(_) => Curve::Secp256k1, dtos::PublicKey::Bls12381(_) => Curve::Bls12381, }; @@ -529,7 +529,7 @@ pub async fn execute_key_generation_and_add_random_state( let domains_to_add = [ DomainConfig { id: 0.into(), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }, DomainConfig { @@ -539,7 +539,7 @@ pub async fn execute_key_generation_and_add_random_state( }, DomainConfig { id: 2.into(), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }, ]; diff --git a/crates/contract/tests/sandbox/upgrade_to_current_contract.rs b/crates/contract/tests/sandbox/upgrade_to_current_contract.rs index 0453a2b9b..1a1205127 100644 --- a/crates/contract/tests/sandbox/upgrade_to_current_contract.rs +++ b/crates/contract/tests/sandbox/upgrade_to_current_contract.rs @@ -355,7 +355,7 @@ async fn upgrade_allows_new_request_types( }, DomainConfig { id: (first_available_domain_id + 1).into(), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }, ]; diff --git a/crates/contract/tests/sandbox/utils/consts.rs b/crates/contract/tests/sandbox/utils/consts.rs index 5b2978841..6413203a0 100644 --- a/crates/contract/tests/sandbox/utils/consts.rs +++ b/crates/contract/tests/sandbox/utils/consts.rs @@ -7,7 +7,7 @@ use near_sdk::{Gas, NearToken}; pub const PARTICIPANT_LEN: usize = 10; pub const ALL_CURVES: &[Curve; 4] = &[ Curve::Secp256k1, - Curve::Ed25519, + Curve::Curve25519, Curve::Bls12381, Curve::V2Secp256k1, ]; diff --git a/crates/contract/tests/sandbox/utils/interface.rs b/crates/contract/tests/sandbox/utils/interface.rs index 58ad9e8c6..f5f084e32 100644 --- a/crates/contract/tests/sandbox/utils/interface.rs +++ b/crates/contract/tests/sandbox/utils/interface.rs @@ -19,7 +19,7 @@ impl IntoInterfaceType for Curve { fn into_interface_type(self) -> dtos::SignatureScheme { match self { Curve::Secp256k1 => dtos::SignatureScheme::Secp256k1, - Curve::Ed25519 => dtos::SignatureScheme::Ed25519, + Curve::Curve25519 => dtos::SignatureScheme::Ed25519, Curve::Bls12381 => dtos::SignatureScheme::Bls12381, Curve::V2Secp256k1 => dtos::SignatureScheme::V2Secp256k1, } diff --git a/crates/contract/tests/sandbox/utils/shared_key_utils.rs b/crates/contract/tests/sandbox/utils/shared_key_utils.rs index e024430ec..40ef7e3b8 100644 --- a/crates/contract/tests/sandbox/utils/shared_key_utils.rs +++ b/crates/contract/tests/sandbox/utils/shared_key_utils.rs @@ -63,7 +63,7 @@ pub fn make_key_for_domain(domain_curve: Curve) -> (dtos::PublicKey, SharedSecre let (pk, sk) = new_secp256k1(); (pk, SharedSecretKey::Secp256k1(sk)) } - Curve::Ed25519 => { + Curve::Curve25519 => { let (pk, sk) = new_ed25519(); (pk, SharedSecretKey::Ed25519(sk)) } diff --git a/crates/contract/tests/sandbox/vote.rs b/crates/contract/tests/sandbox/vote.rs index 22525796e..95cbf8879 100644 --- a/crates/contract/tests/sandbox/vote.rs +++ b/crates/contract/tests/sandbox/vote.rs @@ -40,7 +40,7 @@ async fn test_keygen() -> anyhow::Result<()> { }; let epoch_id = init_running.keyset.epoch_id; let domain_id = init_running.domains.next_domain_id; - let curve = Curve::Ed25519; + let curve = Curve::Curve25519; // vote to add the domain and verify we enter initializing state vote_add_domains( diff --git a/crates/devnet/src/contracts.rs b/crates/devnet/src/contracts.rs index a32720812..ea48c0edc 100644 --- a/crates/devnet/src/contracts.rs +++ b/crates/devnet/src/contracts.rs @@ -57,7 +57,7 @@ pub fn make_actions(call: ContractActionCall) -> ActionCall { Curve::Secp256k1 | Curve::V2Secp256k1 => { ecdsa_calls_by_domain.insert(domain.id.0, prot_calls); } - Curve::Ed25519 => { + Curve::Curve25519 => { eddsa_calls_by_domain.insert(domain.id.0, prot_calls); } Curve::Bls12381 => { @@ -170,7 +170,7 @@ fn make_payload(curve: Curve) -> Payload { Curve::Secp256k1 | Curve::V2Secp256k1 => { Payload::Ecdsa(Bytes::new(rand::random::<[u8; 32]>().to_vec()).unwrap()) } - Curve::Ed25519 => { + Curve::Curve25519 => { let len = rand::random_range( EDDSA_PAYLOAD_SIZE_LOWER_BOUND_BYTES..=EDDSA_PAYLOAD_SIZE_UPPER_BOUND_BYTES, ); diff --git a/crates/devnet/src/loadtest.rs b/crates/devnet/src/loadtest.rs index 9f45140ae..b5f470507 100644 --- a/crates/devnet/src/loadtest.rs +++ b/crates/devnet/src/loadtest.rs @@ -288,7 +288,7 @@ impl RunLoadtestCmd { domain_config, }) } - Curve::Ed25519 | Curve::Secp256k1 | Curve::V2Secp256k1 => { + Curve::Curve25519 | Curve::Secp256k1 | Curve::V2Secp256k1 => { ContractActionCall::Sign(crate::contracts::RequestActionCallArgs { mpc_contract: mpc_account, domain_config, diff --git a/crates/node/src/coordinator.rs b/crates/node/src/coordinator.rs index e409adb57..1d57bf26b 100644 --- a/crates/node/src/coordinator.rs +++ b/crates/node/src/coordinator.rs @@ -548,7 +548,7 @@ where } KeyshareData::Ed25519(data) => { eddsa_keyshares.insert(keyshare.key_id.domain_id, data); - domain_to_curve.insert(domain_id, Curve::Ed25519); + domain_to_curve.insert(domain_id, Curve::Curve25519); } KeyshareData::Bls12381(data) => { ckd_keyshares.insert(keyshare.key_id.domain_id, data); diff --git a/crates/node/src/key_events.rs b/crates/node/src/key_events.rs index 9c31795e8..0ba4d1560 100644 --- a/crates/node/src/key_events.rs +++ b/crates/node/src/key_events.rs @@ -75,7 +75,7 @@ pub async fn keygen_computation_inner( )?); (KeyshareData::V2Secp256k1(keyshare), public_key) } - Curve::Ed25519 => { + Curve::Curve25519 => { let keyshare = EddsaSignatureProvider::run_key_generation_client(threshold, channel).await?; let public_key = dtos::PublicKey::Ed25519(dtos::Ed25519PublicKey::from( @@ -249,7 +249,7 @@ async fn resharing_computation_inner( .await?; KeyshareData::V2Secp256k1(res) } - (contract_interface::types::PublicKey::Ed25519(inner_public_key), Curve::Ed25519) => { + (contract_interface::types::PublicKey::Ed25519(inner_public_key), Curve::Curve25519) => { let public_key = frost_ed25519::VerifyingKey::deserialize(inner_public_key.as_ref())?; let my_share = existing_keyshare .map(|keyshare| match keyshare.data { diff --git a/crates/node/src/mpc_client.rs b/crates/node/src/mpc_client.rs index 447e67667..e5d6da939 100644 --- a/crates/node/src/mpc_client.rs +++ b/crates/node/src/mpc_client.rs @@ -405,7 +405,7 @@ where Ok(response) } - Some(Curve::Ed25519) => { + Some(Curve::Curve25519) => { let (signature, _) = timeout( Duration::from_secs(this.config.signature.timeout_sec), this.eddsa_signature_provider @@ -525,7 +525,7 @@ where } Some(Curve::Secp256k1) | Some(Curve::V2Secp256k1) - | Some(Curve::Ed25519) => Err(anyhow::anyhow!( + | Some(Curve::Curve25519) => Err(anyhow::anyhow!( "Signature scheme is not allowed for domain: {:?}", ckd_attempt.request.domain_id.clone() )), @@ -617,7 +617,7 @@ where } Some(Curve::Bls12381) | Some(Curve::V2Secp256k1) - | Some(Curve::Ed25519) => Err(anyhow::anyhow!( + | Some(Curve::Curve25519) => Err(anyhow::anyhow!( "Signature scheme is not allowed for domain: {:?}", verify_foreign_tx_attempt.request.domain_id.clone() )), diff --git a/crates/node/src/tests.rs b/crates/node/src/tests.rs index f14d51797..844127b91 100644 --- a/crates/node/src/tests.rs +++ b/crates/node/src/tests.rs @@ -278,7 +278,7 @@ pub async fn request_signature_and_await_response( rand::thread_rng().fill_bytes(payload.as_mut()); Payload::Ecdsa(Bytes::new(payload.to_vec()).unwrap()) } - Curve::Ed25519 => { + Curve::Curve25519 => { let len = rand::thread_rng().gen_range( EDDSA_PAYLOAD_SIZE_LOWER_BOUND_BYTES..EDDSA_PAYLOAD_SIZE_UPPER_BOUND_BYTES, ); diff --git a/crates/node/src/tests/basic_cluster.rs b/crates/node/src/tests/basic_cluster.rs index 3d0fee184..3a33e9f82 100644 --- a/crates/node/src/tests/basic_cluster.rs +++ b/crates/node/src/tests/basic_cluster.rs @@ -37,7 +37,7 @@ async fn test_basic_cluster() { let signature_domain_eddsa = DomainConfig { id: DomainId(1), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }; diff --git a/crates/node/src/tests/multidomain.rs b/crates/node/src/tests/multidomain.rs index 51ae83036..7214632d5 100644 --- a/crates/node/src/tests/multidomain.rs +++ b/crates/node/src/tests/multidomain.rs @@ -40,7 +40,7 @@ async fn test_basic_multidomain() { }, DomainConfig { id: DomainId(1), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }, DomainConfig { @@ -74,7 +74,7 @@ async fn test_basic_multidomain() { tracing::info!("requesting signature"); for domain in &domains { match domain.curve { - Curve::Secp256k1 | Curve::Ed25519 | Curve::V2Secp256k1 => { + Curve::Secp256k1 | Curve::Curve25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), @@ -99,7 +99,7 @@ async fn test_basic_multidomain() { let new_domains = vec![ DomainConfig { id: DomainId(3), - curve: Curve::Ed25519, + curve: Curve::Curve25519, purpose: DomainPurpose::Sign, }, DomainConfig { @@ -139,7 +139,7 @@ async fn test_basic_multidomain() { for domain in &domains { match domain.curve { - Curve::Secp256k1 | Curve::Ed25519 | Curve::V2Secp256k1 => { + Curve::Secp256k1 | Curve::Curve25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), @@ -186,7 +186,7 @@ async fn test_basic_multidomain() { for domain in &domains { match domain.curve { - Curve::Secp256k1 | Curve::Ed25519 | Curve::V2Secp256k1 => { + Curve::Secp256k1 | Curve::Curve25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), diff --git a/crates/node/src/tests/resharing.rs b/crates/node/src/tests/resharing.rs index 4f9f1d28e..3f0fcfe32 100644 --- a/crates/node/src/tests/resharing.rs +++ b/crates/node/src/tests/resharing.rs @@ -20,7 +20,7 @@ use super::DEFAULT_BLOCK_TIME; #[test_log::test] #[rstest] #[case(0, Curve::Secp256k1, 3)] -#[case(1, Curve::Ed25519, 3)] +#[case(1, Curve::Curve25519, 3)] #[case(2, Curve::Bls12381, 3)] // TODO(#1946): re-enable once it is no longer flaky // #[case(3, Curve::V2Secp256k1, 5)] @@ -77,7 +77,7 @@ async fn test_key_resharing_simple( // Sanity check. match domain.curve { - Curve::Secp256k1 | Curve::Ed25519 | Curve::V2Secp256k1 => { + Curve::Secp256k1 | Curve::Curve25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, "user1", @@ -121,7 +121,7 @@ async fn test_key_resharing_simple( .expect("Timeout waiting for resharing to complete"); match domain.curve { - Curve::Secp256k1 | Curve::Ed25519 | Curve::V2Secp256k1 => { + Curve::Secp256k1 | Curve::Curve25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, "user1", From 0ac4bd65b5c10cf0881a31953130a27c2d53f038 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:27:41 +0100 Subject: [PATCH 15/21] Edwards25519 --- crates/contract/src/dto_mapping.rs | 2 +- crates/contract/src/lib.rs | 4 ++-- crates/contract/src/primitives/domain.rs | 20 +++++++++---------- crates/contract/src/primitives/test_utils.rs | 2 +- crates/contract/src/state/running.rs | 2 +- .../tests/inprocess/attestation_submission.rs | 2 +- crates/contract/tests/sandbox/common.rs | 6 +++--- .../sandbox/upgrade_to_current_contract.rs | 2 +- crates/contract/tests/sandbox/utils/consts.rs | 2 +- .../contract/tests/sandbox/utils/interface.rs | 2 +- .../tests/sandbox/utils/shared_key_utils.rs | 2 +- crates/contract/tests/sandbox/vote.rs | 2 +- crates/devnet/src/contracts.rs | 4 ++-- crates/devnet/src/loadtest.rs | 2 +- crates/node/src/coordinator.rs | 2 +- crates/node/src/key_events.rs | 4 ++-- crates/node/src/mpc_client.rs | 6 +++--- crates/node/src/tests.rs | 2 +- crates/node/src/tests/basic_cluster.rs | 2 +- crates/node/src/tests/multidomain.rs | 10 +++++----- crates/node/src/tests/resharing.rs | 6 +++--- crates/threshold-signatures/README.md | 4 ++-- crates/threshold-signatures/docs/dkg.md | 2 +- .../docs/eddsa/signing.md | 2 +- .../threshold-signatures/src/crypto/README.md | 2 +- 25 files changed, 48 insertions(+), 48 deletions(-) diff --git a/crates/contract/src/dto_mapping.rs b/crates/contract/src/dto_mapping.rs index d25dc3d04..9377604a1 100644 --- a/crates/contract/src/dto_mapping.rs +++ b/crates/contract/src/dto_mapping.rs @@ -515,7 +515,7 @@ impl IntoInterfaceType for Curve { fn into_dto_type(self) -> dtos::SignatureScheme { match self { Curve::Secp256k1 => dtos::SignatureScheme::Secp256k1, - Curve::Curve25519 => dtos::SignatureScheme::Ed25519, + Curve::Edwards25519 => dtos::SignatureScheme::Ed25519, Curve::Bls12381 => dtos::SignatureScheme::Bls12381, Curve::V2Secp256k1 => dtos::SignatureScheme::V2Secp256k1, } diff --git a/crates/contract/src/lib.rs b/crates/contract/src/lib.rs index ceb2580d6..6d92a84ab 100644 --- a/crates/contract/src/lib.rs +++ b/crates/contract/src/lib.rs @@ -261,7 +261,7 @@ impl MpcContract { .into_option() .expect("Ecdsa payload cannot be converted to Scalar"); } - Curve::Curve25519 => { + Curve::Edwards25519 => { request.payload.as_eddsa().expect("Payload is not EdDSA"); } Curve::Bls12381 => { @@ -2174,7 +2174,7 @@ mod tests { let (pk, sk) = new_secp256k1(rng); (pk.into(), SharedSecretKey::Secp256k1(sk)) } - Curve::Curve25519 => { + Curve::Edwards25519 => { let (pk, sk) = new_ed25519(rng); (pk.into(), SharedSecretKey::Ed25519(sk)) } diff --git a/crates/contract/src/primitives/domain.rs b/crates/contract/src/primitives/domain.rs index 2804b7123..add88a59d 100644 --- a/crates/contract/src/primitives/domain.rs +++ b/crates/contract/src/primitives/domain.rs @@ -41,7 +41,7 @@ impl Display for DomainId { pub enum Curve { Secp256k1, #[serde(alias = "Ed25519")] - Curve25519, + Edwards25519, Bls12381, V2Secp256k1, // Robust ECDSA } @@ -67,7 +67,7 @@ pub fn is_valid_curve_for_purpose(purpose: DomainPurpose, curve: Curve) -> bool (purpose, curve), (DomainPurpose::Sign, Curve::Secp256k1) | (DomainPurpose::Sign, Curve::V2Secp256k1) - | (DomainPurpose::Sign, Curve::Curve25519) + | (DomainPurpose::Sign, Curve::Edwards25519) | (DomainPurpose::ForeignTx, Curve::Secp256k1) | (DomainPurpose::CKD, Curve::Bls12381) ) @@ -287,7 +287,7 @@ pub mod tests { }, DomainConfig { id: DomainId(1), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }, ]; @@ -344,7 +344,7 @@ pub mod tests { }, DomainConfig { id: DomainId(2), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }, DomainConfig { @@ -383,7 +383,7 @@ pub mod tests { }, DomainConfig { id: DomainId(2), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }, DomainConfig { @@ -400,7 +400,7 @@ pub mod tests { Some(DomainId(3)) ); assert_eq!( - registry.most_recent_domain_for_curve(Curve::Curve25519), + registry.most_recent_domain_for_curve(Curve::Edwards25519), Some(DomainId(2)) ); } @@ -447,7 +447,7 @@ pub mod tests { #[rstest] #[case(Curve::Secp256k1, DomainPurpose::Sign)] - #[case(Curve::Curve25519, DomainPurpose::Sign)] + #[case(Curve::Edwards25519, DomainPurpose::Sign)] #[case(Curve::V2Secp256k1, DomainPurpose::Sign)] #[case(Curve::Bls12381, DomainPurpose::CKD)] fn test_infer_purpose_from_curve(#[case] curve: Curve, #[case] expected: DomainPurpose) { @@ -458,12 +458,12 @@ pub mod tests { // Valid combinations #[case(DomainPurpose::Sign, Curve::Secp256k1, true)] #[case(DomainPurpose::Sign, Curve::V2Secp256k1, true)] - #[case(DomainPurpose::Sign, Curve::Curve25519, true)] + #[case(DomainPurpose::Sign, Curve::Edwards25519, true)] #[case(DomainPurpose::ForeignTx, Curve::Secp256k1, true)] #[case(DomainPurpose::CKD, Curve::Bls12381, true)] // Invalid combinations #[case(DomainPurpose::Sign, Curve::Bls12381, false)] - #[case(DomainPurpose::ForeignTx, Curve::Curve25519, false)] + #[case(DomainPurpose::ForeignTx, Curve::Edwards25519, false)] #[case(DomainPurpose::ForeignTx, Curve::Bls12381, false)] #[case(DomainPurpose::ForeignTx, Curve::V2Secp256k1, false)] #[case(DomainPurpose::CKD, Curve::Secp256k1, false)] @@ -579,7 +579,7 @@ pub mod tests { }]; let proposal_b = vec![DomainConfig { id: DomainId(0), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }]; let mut votes = AddDomainsVotes::default(); diff --git a/crates/contract/src/primitives/test_utils.rs b/crates/contract/src/primitives/test_utils.rs index 92dbc34cc..8a5615755 100644 --- a/crates/contract/src/primitives/test_utils.rs +++ b/crates/contract/src/primitives/test_utils.rs @@ -13,7 +13,7 @@ use std::collections::BTreeMap; const ALL_CURVES: [Curve; 4] = [ Curve::Secp256k1, - Curve::Curve25519, + Curve::Edwards25519, Curve::Bls12381, Curve::V2Secp256k1, ]; diff --git a/crates/contract/src/state/running.rs b/crates/contract/src/state/running.rs index dffef643a..b0d3c8c08 100644 --- a/crates/contract/src/state/running.rs +++ b/crates/contract/src/state/running.rs @@ -348,7 +348,7 @@ pub mod running_tests { #[rstest] #[case(Curve::Bls12381, DomainPurpose::Sign)] - #[case(Curve::Curve25519, DomainPurpose::ForeignTx)] + #[case(Curve::Edwards25519, DomainPurpose::ForeignTx)] #[case(Curve::Secp256k1, DomainPurpose::CKD)] fn vote_add_domains__should_reject_invalid_curve_purpose( #[case] curve: Curve, diff --git a/crates/contract/tests/inprocess/attestation_submission.rs b/crates/contract/tests/inprocess/attestation_submission.rs index 8c73ba760..9a5365a1f 100644 --- a/crates/contract/tests/inprocess/attestation_submission.rs +++ b/crates/contract/tests/inprocess/attestation_submission.rs @@ -148,7 +148,7 @@ impl TestSetupBuilder { .contract .vote_add_domains(vec![DomainConfig { id: DomainId(1), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }]) .unwrap(); diff --git a/crates/contract/tests/sandbox/common.rs b/crates/contract/tests/sandbox/common.rs index 0032c7a0e..60120e286 100644 --- a/crates/contract/tests/sandbox/common.rs +++ b/crates/contract/tests/sandbox/common.rs @@ -203,7 +203,7 @@ pub async fn init_with_candidates( .map(|(i, pk)| { let domain_id = DomainId((i as u64) * 2); let curve = match pk { - dtos::PublicKey::Ed25519(_) => Curve::Curve25519, + dtos::PublicKey::Ed25519(_) => Curve::Edwards25519, dtos::PublicKey::Secp256k1(_) => Curve::Secp256k1, dtos::PublicKey::Bls12381(_) => Curve::Bls12381, }; @@ -529,7 +529,7 @@ pub async fn execute_key_generation_and_add_random_state( let domains_to_add = [ DomainConfig { id: 0.into(), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }, DomainConfig { @@ -539,7 +539,7 @@ pub async fn execute_key_generation_and_add_random_state( }, DomainConfig { id: 2.into(), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }, ]; diff --git a/crates/contract/tests/sandbox/upgrade_to_current_contract.rs b/crates/contract/tests/sandbox/upgrade_to_current_contract.rs index 1a1205127..ab747d26f 100644 --- a/crates/contract/tests/sandbox/upgrade_to_current_contract.rs +++ b/crates/contract/tests/sandbox/upgrade_to_current_contract.rs @@ -355,7 +355,7 @@ async fn upgrade_allows_new_request_types( }, DomainConfig { id: (first_available_domain_id + 1).into(), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }, ]; diff --git a/crates/contract/tests/sandbox/utils/consts.rs b/crates/contract/tests/sandbox/utils/consts.rs index 6413203a0..f209ec106 100644 --- a/crates/contract/tests/sandbox/utils/consts.rs +++ b/crates/contract/tests/sandbox/utils/consts.rs @@ -7,7 +7,7 @@ use near_sdk::{Gas, NearToken}; pub const PARTICIPANT_LEN: usize = 10; pub const ALL_CURVES: &[Curve; 4] = &[ Curve::Secp256k1, - Curve::Curve25519, + Curve::Edwards25519, Curve::Bls12381, Curve::V2Secp256k1, ]; diff --git a/crates/contract/tests/sandbox/utils/interface.rs b/crates/contract/tests/sandbox/utils/interface.rs index f5f084e32..c17a224e1 100644 --- a/crates/contract/tests/sandbox/utils/interface.rs +++ b/crates/contract/tests/sandbox/utils/interface.rs @@ -19,7 +19,7 @@ impl IntoInterfaceType for Curve { fn into_interface_type(self) -> dtos::SignatureScheme { match self { Curve::Secp256k1 => dtos::SignatureScheme::Secp256k1, - Curve::Curve25519 => dtos::SignatureScheme::Ed25519, + Curve::Edwards25519 => dtos::SignatureScheme::Ed25519, Curve::Bls12381 => dtos::SignatureScheme::Bls12381, Curve::V2Secp256k1 => dtos::SignatureScheme::V2Secp256k1, } diff --git a/crates/contract/tests/sandbox/utils/shared_key_utils.rs b/crates/contract/tests/sandbox/utils/shared_key_utils.rs index 40ef7e3b8..194819760 100644 --- a/crates/contract/tests/sandbox/utils/shared_key_utils.rs +++ b/crates/contract/tests/sandbox/utils/shared_key_utils.rs @@ -63,7 +63,7 @@ pub fn make_key_for_domain(domain_curve: Curve) -> (dtos::PublicKey, SharedSecre let (pk, sk) = new_secp256k1(); (pk, SharedSecretKey::Secp256k1(sk)) } - Curve::Curve25519 => { + Curve::Edwards25519 => { let (pk, sk) = new_ed25519(); (pk, SharedSecretKey::Ed25519(sk)) } diff --git a/crates/contract/tests/sandbox/vote.rs b/crates/contract/tests/sandbox/vote.rs index 95cbf8879..fd2109d15 100644 --- a/crates/contract/tests/sandbox/vote.rs +++ b/crates/contract/tests/sandbox/vote.rs @@ -40,7 +40,7 @@ async fn test_keygen() -> anyhow::Result<()> { }; let epoch_id = init_running.keyset.epoch_id; let domain_id = init_running.domains.next_domain_id; - let curve = Curve::Curve25519; + let curve = Curve::Edwards25519; // vote to add the domain and verify we enter initializing state vote_add_domains( diff --git a/crates/devnet/src/contracts.rs b/crates/devnet/src/contracts.rs index ea48c0edc..0dedea5ae 100644 --- a/crates/devnet/src/contracts.rs +++ b/crates/devnet/src/contracts.rs @@ -57,7 +57,7 @@ pub fn make_actions(call: ContractActionCall) -> ActionCall { Curve::Secp256k1 | Curve::V2Secp256k1 => { ecdsa_calls_by_domain.insert(domain.id.0, prot_calls); } - Curve::Curve25519 => { + Curve::Edwards25519 => { eddsa_calls_by_domain.insert(domain.id.0, prot_calls); } Curve::Bls12381 => { @@ -170,7 +170,7 @@ fn make_payload(curve: Curve) -> Payload { Curve::Secp256k1 | Curve::V2Secp256k1 => { Payload::Ecdsa(Bytes::new(rand::random::<[u8; 32]>().to_vec()).unwrap()) } - Curve::Curve25519 => { + Curve::Edwards25519 => { let len = rand::random_range( EDDSA_PAYLOAD_SIZE_LOWER_BOUND_BYTES..=EDDSA_PAYLOAD_SIZE_UPPER_BOUND_BYTES, ); diff --git a/crates/devnet/src/loadtest.rs b/crates/devnet/src/loadtest.rs index b5f470507..08c3233f6 100644 --- a/crates/devnet/src/loadtest.rs +++ b/crates/devnet/src/loadtest.rs @@ -288,7 +288,7 @@ impl RunLoadtestCmd { domain_config, }) } - Curve::Curve25519 | Curve::Secp256k1 | Curve::V2Secp256k1 => { + Curve::Edwards25519 | Curve::Secp256k1 | Curve::V2Secp256k1 => { ContractActionCall::Sign(crate::contracts::RequestActionCallArgs { mpc_contract: mpc_account, domain_config, diff --git a/crates/node/src/coordinator.rs b/crates/node/src/coordinator.rs index 1d57bf26b..b34522be9 100644 --- a/crates/node/src/coordinator.rs +++ b/crates/node/src/coordinator.rs @@ -548,7 +548,7 @@ where } KeyshareData::Ed25519(data) => { eddsa_keyshares.insert(keyshare.key_id.domain_id, data); - domain_to_curve.insert(domain_id, Curve::Curve25519); + domain_to_curve.insert(domain_id, Curve::Edwards25519); } KeyshareData::Bls12381(data) => { ckd_keyshares.insert(keyshare.key_id.domain_id, data); diff --git a/crates/node/src/key_events.rs b/crates/node/src/key_events.rs index 0ba4d1560..fa4f0bd10 100644 --- a/crates/node/src/key_events.rs +++ b/crates/node/src/key_events.rs @@ -75,7 +75,7 @@ pub async fn keygen_computation_inner( )?); (KeyshareData::V2Secp256k1(keyshare), public_key) } - Curve::Curve25519 => { + Curve::Edwards25519 => { let keyshare = EddsaSignatureProvider::run_key_generation_client(threshold, channel).await?; let public_key = dtos::PublicKey::Ed25519(dtos::Ed25519PublicKey::from( @@ -249,7 +249,7 @@ async fn resharing_computation_inner( .await?; KeyshareData::V2Secp256k1(res) } - (contract_interface::types::PublicKey::Ed25519(inner_public_key), Curve::Curve25519) => { + (contract_interface::types::PublicKey::Ed25519(inner_public_key), Curve::Edwards25519) => { let public_key = frost_ed25519::VerifyingKey::deserialize(inner_public_key.as_ref())?; let my_share = existing_keyshare .map(|keyshare| match keyshare.data { diff --git a/crates/node/src/mpc_client.rs b/crates/node/src/mpc_client.rs index e5d6da939..a38f7f919 100644 --- a/crates/node/src/mpc_client.rs +++ b/crates/node/src/mpc_client.rs @@ -405,7 +405,7 @@ where Ok(response) } - Some(Curve::Curve25519) => { + Some(Curve::Edwards25519) => { let (signature, _) = timeout( Duration::from_secs(this.config.signature.timeout_sec), this.eddsa_signature_provider @@ -525,7 +525,7 @@ where } Some(Curve::Secp256k1) | Some(Curve::V2Secp256k1) - | Some(Curve::Curve25519) => Err(anyhow::anyhow!( + | Some(Curve::Edwards25519) => Err(anyhow::anyhow!( "Signature scheme is not allowed for domain: {:?}", ckd_attempt.request.domain_id.clone() )), @@ -617,7 +617,7 @@ where } Some(Curve::Bls12381) | Some(Curve::V2Secp256k1) - | Some(Curve::Curve25519) => Err(anyhow::anyhow!( + | Some(Curve::Edwards25519) => Err(anyhow::anyhow!( "Signature scheme is not allowed for domain: {:?}", verify_foreign_tx_attempt.request.domain_id.clone() )), diff --git a/crates/node/src/tests.rs b/crates/node/src/tests.rs index 844127b91..36bbfbd85 100644 --- a/crates/node/src/tests.rs +++ b/crates/node/src/tests.rs @@ -278,7 +278,7 @@ pub async fn request_signature_and_await_response( rand::thread_rng().fill_bytes(payload.as_mut()); Payload::Ecdsa(Bytes::new(payload.to_vec()).unwrap()) } - Curve::Curve25519 => { + Curve::Edwards25519 => { let len = rand::thread_rng().gen_range( EDDSA_PAYLOAD_SIZE_LOWER_BOUND_BYTES..EDDSA_PAYLOAD_SIZE_UPPER_BOUND_BYTES, ); diff --git a/crates/node/src/tests/basic_cluster.rs b/crates/node/src/tests/basic_cluster.rs index 3a33e9f82..e0471254a 100644 --- a/crates/node/src/tests/basic_cluster.rs +++ b/crates/node/src/tests/basic_cluster.rs @@ -37,7 +37,7 @@ async fn test_basic_cluster() { let signature_domain_eddsa = DomainConfig { id: DomainId(1), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }; diff --git a/crates/node/src/tests/multidomain.rs b/crates/node/src/tests/multidomain.rs index 7214632d5..10bc12b81 100644 --- a/crates/node/src/tests/multidomain.rs +++ b/crates/node/src/tests/multidomain.rs @@ -40,7 +40,7 @@ async fn test_basic_multidomain() { }, DomainConfig { id: DomainId(1), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }, DomainConfig { @@ -74,7 +74,7 @@ async fn test_basic_multidomain() { tracing::info!("requesting signature"); for domain in &domains { match domain.curve { - Curve::Secp256k1 | Curve::Curve25519 | Curve::V2Secp256k1 => { + Curve::Secp256k1 | Curve::Edwards25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), @@ -99,7 +99,7 @@ async fn test_basic_multidomain() { let new_domains = vec![ DomainConfig { id: DomainId(3), - curve: Curve::Curve25519, + curve: Curve::Edwards25519, purpose: DomainPurpose::Sign, }, DomainConfig { @@ -139,7 +139,7 @@ async fn test_basic_multidomain() { for domain in &domains { match domain.curve { - Curve::Secp256k1 | Curve::Curve25519 | Curve::V2Secp256k1 => { + Curve::Secp256k1 | Curve::Edwards25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), @@ -186,7 +186,7 @@ async fn test_basic_multidomain() { for domain in &domains { match domain.curve { - Curve::Secp256k1 | Curve::Curve25519 | Curve::V2Secp256k1 => { + Curve::Secp256k1 | Curve::Edwards25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, &format!("user{}", domain.id.0), diff --git a/crates/node/src/tests/resharing.rs b/crates/node/src/tests/resharing.rs index 3f0fcfe32..e360d9284 100644 --- a/crates/node/src/tests/resharing.rs +++ b/crates/node/src/tests/resharing.rs @@ -20,7 +20,7 @@ use super::DEFAULT_BLOCK_TIME; #[test_log::test] #[rstest] #[case(0, Curve::Secp256k1, 3)] -#[case(1, Curve::Curve25519, 3)] +#[case(1, Curve::Edwards25519, 3)] #[case(2, Curve::Bls12381, 3)] // TODO(#1946): re-enable once it is no longer flaky // #[case(3, Curve::V2Secp256k1, 5)] @@ -77,7 +77,7 @@ async fn test_key_resharing_simple( // Sanity check. match domain.curve { - Curve::Secp256k1 | Curve::Curve25519 | Curve::V2Secp256k1 => { + Curve::Secp256k1 | Curve::Edwards25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, "user1", @@ -121,7 +121,7 @@ async fn test_key_resharing_simple( .expect("Timeout waiting for resharing to complete"); match domain.curve { - Curve::Secp256k1 | Curve::Curve25519 | Curve::V2Secp256k1 => { + Curve::Secp256k1 | Curve::Edwards25519 | Curve::V2Secp256k1 => { assert!(request_signature_and_await_response( &mut setup.indexer, "user1", diff --git a/crates/threshold-signatures/README.md b/crates/threshold-signatures/README.md index bdd98d3cf..3bcd944ff 100644 --- a/crates/threshold-signatures/README.md +++ b/crates/threshold-signatures/README.md @@ -15,7 +15,7 @@ however is implemented from scratch and follows The EdDSA implementation is mainly a wrapper of the [Frost](https://github.com/ZcashFoundation/frost) signing functions instantiated -with Curve25519. +with Edwards25519. The Confidential Key Derivation (CKD) code implements a threshold protocol to generate deterministic keys in a confidential manner. The scheme is based on @@ -99,7 +99,7 @@ More details can be found in ### Threshold EdDSA Functionalities The threshold EdDSA scheme is implemented over curve -Curve25519. We refer to such scheme as Ed25519. +Edwards25519. We refer to such scheme as Ed25519. The following functionalities are provided: 1) **Distributed Key Generation (DKG)**: Same as in ECDSA. diff --git a/crates/threshold-signatures/docs/dkg.md b/crates/threshold-signatures/docs/dkg.md index 78dd51722..25c1478d4 100644 --- a/crates/threshold-signatures/docs/dkg.md +++ b/crates/threshold-signatures/docs/dkg.md @@ -7,7 +7,7 @@ a stronger notion of security than the one promised by plain PedPop. PedPop+ is a five-and-a-half-rounds protocol and makes use in three of its rounds of a reliable broadcast channel. A reliable broadcast is a three-round protocol, implying that the effective total number of PedPop+ rounds is eleven and a half. The broadcast channel is implemented in `src/protocol/echo_broadcast.rs`. -The implemented DKG serves as a generic one that can be used with multiple different underlying elliptic curves. We thus use it with `Secp256k1` for ECDSA schemes, `Curve25519` for EdDSA scheme, and `BLS12-381` for the confidential key derivation functionality. +The implemented DKG serves as a generic one that can be used with multiple different underlying elliptic curves. We thus use it with `Secp256k1` for ECDSA schemes, `Edwards25519` for EdDSA scheme, and `BLS12-381` for the confidential key derivation functionality. ## Keygen, Reshare and Refresh diff --git a/crates/threshold-signatures/docs/eddsa/signing.md b/crates/threshold-signatures/docs/eddsa/signing.md index 434a49ec5..d8e8d073b 100644 --- a/crates/threshold-signatures/docs/eddsa/signing.md +++ b/crates/threshold-signatures/docs/eddsa/signing.md @@ -3,7 +3,7 @@ This document specifies the distributed EdDSA signing protocol called FROST. The implementation is heavily inspired by the Zcash Foundation [implementation](https://github.com/ZcashFoundation/frost) which builds the -scheme on top of Curve25519. The implementation thus generates signatures +scheme on top of Edwards25519. The implementation thus generates signatures that can be checked by any Ed25519 verifier. We implement the two round FROST protocol without the extra round responsible of detecting which party deviated from the protocol. diff --git a/crates/threshold-signatures/src/crypto/README.md b/crates/threshold-signatures/src/crypto/README.md index 7f92dd7f3..9081022b0 100644 --- a/crates/threshold-signatures/src/crypto/README.md +++ b/crates/threshold-signatures/src/crypto/README.md @@ -11,7 +11,7 @@ Defines the library's [`Ciphersuite`](ciphersuite.rs) trait, which extends `fros | Type | Curve | Byte Order | |------|-------|------------| | `Secp256K1Sha256` | Secp256k1 | Big-endian | -| `Ed25519Sha512` | Curve25519 | Little-endian | +| `Ed25519Sha512` | Edwards25519 | Little-endian | | `JubjubBlake2b512` | JubJub | Little-endian | | `BLS12381SHA256` | BLS12-381 (G2) | Little-endian | From b346820e25d2476984614d73f998e6fd16ad7ea5 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:39:58 +0100 Subject: [PATCH 16/21] Snap changed --- crates/contract/tests/snapshots/abi__abi_has_not_changed.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index 4c5353eba..f9cf72766 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -1672,7 +1672,7 @@ expression: abi "type": "string", "enum": [ "Secp256k1", - "Ed25519", + "Edwards25519", "Bls12381", "V2Secp256k1" ] From 20e149cdfe341eaa27db4f3d8575c4fad280fc82 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Thu, 12 Mar 2026 12:45:09 +0100 Subject: [PATCH 17/21] alias to rename --- crates/contract/src/primitives/domain.rs | 2 +- crates/contract/tests/snapshots/abi__abi_has_not_changed.snap | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/contract/src/primitives/domain.rs b/crates/contract/src/primitives/domain.rs index add88a59d..d7fc47b18 100644 --- a/crates/contract/src/primitives/domain.rs +++ b/crates/contract/src/primitives/domain.rs @@ -40,7 +40,7 @@ impl Display for DomainId { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Curve { Secp256k1, - #[serde(alias = "Ed25519")] + #[serde(rename = "Ed25519")] Edwards25519, Bls12381, V2Secp256k1, // Robust ECDSA diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index f9cf72766..4c5353eba 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -1672,7 +1672,7 @@ expression: abi "type": "string", "enum": [ "Secp256k1", - "Edwards25519", + "Ed25519", "Bls12381", "V2Secp256k1" ] From e52f8df55dd651929e0a3e387cf6c47bc7584764 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Tue, 24 Mar 2026 10:05:01 +0100 Subject: [PATCH 18/21] Missing one conflicted file --- crates/node/src/tests.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/node/src/tests.rs b/crates/node/src/tests.rs index b57f120fa..32d1181ef 100644 --- a/crates/node/src/tests.rs +++ b/crates/node/src/tests.rs @@ -280,11 +280,7 @@ pub async fn request_signature_and_await_response( rand::thread_rng().fill_bytes(payload.as_mut()); Payload::Ecdsa(Bytes::new(payload.to_vec()).unwrap()) } -<<<<<<< HEAD Curve::Edwards25519 => { -======= - Curve::Ed25519 => { ->>>>>>> origin/main let len = rand::thread_rng().gen_range( EDDSA_PAYLOAD_SIZE_LOWER_BOUND_BYTES..EDDSA_PAYLOAD_SIZE_UPPER_BOUND_BYTES, ); From d31df0caa2d51a619d89c81371ba2382e09ace3d Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Tue, 24 Mar 2026 10:09:08 +0100 Subject: [PATCH 19/21] Fixed: missing one Ed25519 --- crates/node/src/key_events.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/node/src/key_events.rs b/crates/node/src/key_events.rs index 3b8198c15..30a21fb2c 100644 --- a/crates/node/src/key_events.rs +++ b/crates/node/src/key_events.rs @@ -257,7 +257,7 @@ async fn resharing_computation_inner( } ( near_mpc_contract_interface::types::PublicKey::Ed25519(inner_public_key), - Curve::Ed25519, + Curve::Edwards25519, ) => { let public_key = frost_ed25519::VerifyingKey::deserialize(inner_public_key.as_ref())?; let my_share = existing_keyshare From e25ce47c378ead1e1935b9e86094004ed692919d Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Tue, 24 Mar 2026 10:30:39 +0100 Subject: [PATCH 20/21] update borsh --- crates/contract/tests/snapshots/abi__abi_has_not_changed.snap | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap index 343b1eb9f..142b2bcf0 100644 --- a/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap +++ b/crates/contract/tests/snapshots/abi__abi_has_not_changed.snap @@ -1901,8 +1901,6 @@ expression: abi } } }, -<<<<<<< HEAD -======= "ContractExpectedMeasurements": { "description": "On-chain representation of expected TDX measurements. Mirrors [`mpc_attestation::attestation::ExpectedMeasurements`] with contract-compatible serialization (hex strings in JSON, borsh for storage).", "type": "object", @@ -1931,7 +1929,6 @@ expression: abi } } }, ->>>>>>> origin/main "Curve": { "description": "Elliptic curve used by a domain. More curves may be added in the future. When adding new curves, both Borsh *and* JSON serialization must be kept compatible.", "type": "string", From b9268725f9382de98437681609e12b30c9516855 Mon Sep 17 00:00:00 2001 From: SimonRastikian <43679791+SimonRastikian@users.noreply.github.com> Date: Tue, 24 Mar 2026 10:45:25 +0100 Subject: [PATCH 21/21] borsh test --- ...t__tests__mpc_contract_borsh_schema_has_not_changed.snap | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/contract/src/snapshots/mpc_contract__tests__mpc_contract_borsh_schema_has_not_changed.snap b/crates/contract/src/snapshots/mpc_contract__tests__mpc_contract_borsh_schema_has_not_changed.snap index 08c9a7797..810001587 100644 --- a/crates/contract/src/snapshots/mpc_contract__tests__mpc_contract_borsh_schema_has_not_changed.snap +++ b/crates/contract/src/snapshots/mpc_contract__tests__mpc_contract_borsh_schema_has_not_changed.snap @@ -301,8 +301,8 @@ BorshSchemaContainer { ), ( 1, - "Ed25519", - "Curve__Ed25519", + "Edwards25519", + "Curve__Edwards25519", ), ( 2, @@ -319,7 +319,7 @@ BorshSchemaContainer { "Curve__Bls12381": Struct { fields: Empty, }, - "Curve__Ed25519": Struct { + "Curve__Edwards25519": Struct { fields: Empty, }, "Curve__Secp256k1": Struct {