diff --git a/chain-signatures/contract/src/lib.rs b/chain-signatures/contract/src/lib.rs index 9c923556..a37c797a 100644 --- a/chain-signatures/contract/src/lib.rs +++ b/chain-signatures/contract/src/lib.rs @@ -11,7 +11,7 @@ use errors::{ use k256::elliptic_curve::sec1::ToEncodedPoint; use k256::Scalar; use mpc_crypto::{ - derive_epsilon, derive_key, kdf::check_ec_signature, near_public_key_to_affine_point, + derive_epsilon_near, derive_key, kdf::check_ec_signature, near_public_key_to_affine_point, types::SignatureResponse, ScalarExt as _, }; use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; @@ -207,7 +207,7 @@ impl VersionedMpcContract { predecessor: Option, ) -> Result { let predecessor = predecessor.unwrap_or_else(env::predecessor_account_id); - let epsilon = derive_epsilon(&predecessor, &path); + let epsilon = derive_epsilon_near(&predecessor, &path); let derived_public_key = derive_key(near_public_key_to_affine_point(self.public_key()?), epsilon); let encoded_point = derived_public_key.to_encoded_point(false); diff --git a/chain-signatures/contract/src/primitives.rs b/chain-signatures/contract/src/primitives.rs index 05ada2b1..a16f569e 100644 --- a/chain-signatures/contract/src/primitives.rs +++ b/chain-signatures/contract/src/primitives.rs @@ -1,5 +1,5 @@ use k256::Scalar; -use mpc_crypto::{derive_epsilon, SerializableScalar}; +use mpc_crypto::{derive_epsilon_near, SerializableScalar}; use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; use near_sdk::serde::{Deserialize, Serialize}; use near_sdk::{AccountId, BorshStorageKey, CryptoHash, NearToken, PublicKey}; @@ -42,7 +42,7 @@ pub struct ContractSignatureRequest { impl SignatureRequest { pub fn new(payload_hash: Scalar, predecessor_id: &AccountId, path: &str) -> Self { - let epsilon = derive_epsilon(predecessor_id, path); + let epsilon = derive_epsilon_near(predecessor_id, path); let epsilon = SerializableScalar { scalar: epsilon }; let payload_hash = SerializableScalar { scalar: payload_hash, diff --git a/chain-signatures/contract/tests/common.rs b/chain-signatures/contract/tests/common.rs index 2a32b898..58165850 100644 --- a/chain-signatures/contract/tests/common.rs +++ b/chain-signatures/contract/tests/common.rs @@ -13,7 +13,7 @@ use mpc_contract::primitives::{ use mpc_contract::update::UpdateId; use mpc_crypto::kdf::{check_ec_signature, derive_secret_key}; use mpc_crypto::{ - derive_epsilon, derive_key, ScalarExt as _, SerializableAffinePoint, SerializableScalar, + derive_epsilon_near, derive_key, ScalarExt as _, SerializableAffinePoint, SerializableScalar, SignatureResponse, }; use near_workspaces::network::Sandbox; @@ -161,7 +161,7 @@ pub async fn create_response( let (digest, scalar_hash, payload_hash) = process_message(msg).await; let pk = sk.public_key(); - let epsilon = derive_epsilon(predecessor_id, path); + let epsilon = derive_epsilon_near(predecessor_id, path); let derived_sk = derive_secret_key(sk, epsilon); let derived_pk = derive_key(pk.into(), epsilon); let signing_key = k256::ecdsa::SigningKey::from(&derived_sk); diff --git a/chain-signatures/crypto/src/kdf.rs b/chain-signatures/crypto/src/kdf.rs index 5089e320..96ab0cc5 100644 --- a/chain-signatures/crypto/src/kdf.rs +++ b/chain-signatures/crypto/src/kdf.rs @@ -9,10 +9,11 @@ use near_account_id::AccountId; use sha3::{Digest, Keccak256, Sha3_256}; // Constant prefix that ensures epsilon derivation values are used specifically for -// near-mpc-recovery with key derivation protocol vX.Y.Z. -const EPSILON_DERIVATION_PREFIX: &str = "near-mpc-recovery v0.1.0 epsilon derivation:"; +// Sig.Network with key derivation protocol vX.Y.Z. +const EPSILON_DERIVATION_PREFIX: &str = "sig.network v1.0.0 epsilon derivation"; -pub fn derive_epsilon(predecessor_id: &AccountId, path: &str) -> Scalar { +const CHAIN_ID_NEAR: &str = "0x18d"; +pub fn derive_epsilon_near(predecessor_id: &AccountId, path: &str) -> Scalar { // TODO: Use a key derivation library instead of doing this manually. // https://crates.io/crates/hkdf might be a good option? // @@ -21,16 +22,22 @@ pub fn derive_epsilon(predecessor_id: &AccountId, path: &str) -> Scalar { // indicate the end of the account id in derivation path. // Do not reuse this hash function on anything that isn't an account // ID or it'll be vunerable to Hash Melleability/extention attacks. - let derivation_path = format!("{EPSILON_DERIVATION_PREFIX}{},{}", predecessor_id, path); + let derivation_path = format!( + "{EPSILON_DERIVATION_PREFIX},{CHAIN_ID_NEAR},{},{}", + predecessor_id, path + ); let mut hasher = Sha3_256::new(); hasher.update(derivation_path); let hash: [u8; 32] = hasher.finalize().into(); Scalar::from_non_biased(hash) } -const EPSILON_DERIVATION_PREFIX_ETH: &str = "near-mpc-recovery v0.2.0 epsilon derivation:"; +const CHAIN_ID_ETHEREUM: &str = "0x1"; pub fn derive_epsilon_eth(requester: String, path: &str) -> Scalar { - let derivation_path = format!("{EPSILON_DERIVATION_PREFIX_ETH}{},{}", requester, path); + let derivation_path = format!( + "{EPSILON_DERIVATION_PREFIX},{CHAIN_ID_ETHEREUM},{},{}", + requester, path + ); let mut hasher = Keccak256::new(); hasher.update(derivation_path); let hash: [u8; 32] = hasher.finalize().into(); diff --git a/chain-signatures/crypto/src/lib.rs b/chain-signatures/crypto/src/lib.rs index 763cba83..536dfa62 100644 --- a/chain-signatures/crypto/src/lib.rs +++ b/chain-signatures/crypto/src/lib.rs @@ -3,7 +3,7 @@ pub mod types; use k256::elliptic_curve::sec1::FromEncodedPoint; use k256::EncodedPoint; -pub use kdf::{derive_epsilon, derive_key, x_coordinate}; +pub use kdf::{derive_epsilon_near, derive_key, x_coordinate}; pub use types::{ PublicKey, ScalarExt, SerializableAffinePoint, SerializableScalar, SignatureResponse, }; diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index b88c2202..d5ae3793 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -2,7 +2,7 @@ use crate::protocol::Chain::NEAR; use crate::protocol::{Chain, SignRequest}; use crate::storage::app_data_storage::AppDataStorage; use k256::Scalar; -use mpc_crypto::{derive_epsilon, ScalarExt}; +use mpc_crypto::{derive_epsilon_near, ScalarExt}; use near_account_id::AccountId; use near_lake_framework::{Lake, LakeBuilder, LakeContext}; use near_lake_primitives::actions::ActionMetaDataExt; @@ -233,7 +233,8 @@ async fn handle_block( ); continue; }; - let epsilon = derive_epsilon(&action.predecessor_id(), &arguments.request.path); + let epsilon = + derive_epsilon_near(&action.predecessor_id(), &arguments.request.path); tracing::info!( receipt_id = %receipt_id, caller_id = receipt.predecessor_id().to_string(), diff --git a/integration-tests/src/actions/mod.rs b/integration-tests/src/actions/mod.rs index e5767b8b..3234a8e8 100644 --- a/integration-tests/src/actions/mod.rs +++ b/integration-tests/src/actions/mod.rs @@ -15,7 +15,7 @@ use k256::{AffinePoint, EncodedPoint, Scalar, Secp256k1}; use mpc_contract::errors::SignError; use mpc_contract::primitives::SignRequest; use mpc_crypto::ScalarExt; -use mpc_crypto::{derive_epsilon, derive_key}; +use mpc_crypto::{derive_epsilon_near, derive_key}; use near_crypto::InMemorySigner; use near_fetch::ops::AsyncTransactionStatus; use near_fetch::ops::Function; @@ -110,7 +110,7 @@ pub async fn validate_signature( ) -> anyhow::Result<()> { let mpc_point = EncodedPoint::from_bytes(mpc_pk_bytes).unwrap(); let mpc_pk = AffinePoint::from_encoded_point(&mpc_point).unwrap(); - let epsilon = derive_epsilon(account_id, "test"); + let epsilon = derive_epsilon_near(account_id, "test"); let user_pk = derive_key(mpc_pk, epsilon); signature .verify( @@ -290,7 +290,7 @@ mod tests { use k256::elliptic_curve::point::AffineCoordinates; use k256::elliptic_curve::ProjectivePoint; use k256::{AffinePoint, EncodedPoint, Scalar}; - use mpc_crypto::{derive_epsilon, derive_key, ScalarExt as _}; + use mpc_crypto::{derive_epsilon_near, derive_key, ScalarExt as _}; use super::{public_key_to_address, recover, x_coordinate}; @@ -300,12 +300,12 @@ mod tests { fn signatures_havent_changed() { const CHAIN_ID_ETH: u64 = 31337; - let big_r = "03f13a99141ce0a4043a7c02afdec6d52f25c6b3de01967acc5cf4a3fa43801589"; - let s = "39e5631fcc06ffccf8469a3cdcdce0651ebafd998a4280ebbf5dc24a749c98fb"; - let mpc_key = "04b5695a882aeaf36bf3933e21911b5cbcceae7fd7cb424f3ea221c7e8d390aad4ad2c1a427faec960f22a5442739c0a04fd64ab7ce4c93980417bd3d1d8bc04ea"; - let account_id = "dev-20240719125040-80075249096169.test.near"; + let big_r = "029b1b94bf4511b1a25986ba858cfa0fbdd5e4077c02e1d1102a194389b1f72df7"; + let s = "25f3494bb7e7b3349a4b4d939d3e5ae1787a0863e4f698fb8ed2d3e11c195035"; + let mpc_key = "045b4fa179e005361fd858f8a6f896d7afc23a53d3f95d6566a88cde954e7b2f1cb77c554705c35d4ffced67aeafbcda46d9d89d6f200c3a3d109f92872863b3dc"; + let account_id = "dev-20250212213501-93636560094065.test.near"; let payload_hash: [u8; 32] = - hex::decode("49f32740939bfdcbd8d1786075df7aca384381ec203975c3a6c1fd80acddcd4c") + hex::decode("835b9f469b36126284df2e06ecab9482cf495413ab9275faaafb2d40d79cf7bb") .unwrap() .try_into() .unwrap(); @@ -318,7 +318,7 @@ mod tests { let mpc_pk = AffinePoint::from_encoded_point(&mpc_pk).unwrap(); let account_id = account_id.parse().unwrap(); - let derivation_epsilon: k256::Scalar = derive_epsilon(&account_id, "test"); + let derivation_epsilon: k256::Scalar = derive_epsilon_near(&account_id, "test"); let user_pk: AffinePoint = derive_key(mpc_pk, derivation_epsilon); let user_pk_y_parity = match user_pk.y_is_odd().unwrap_u8() { 0 => secp256k1::Parity::Even, @@ -455,7 +455,7 @@ mod tests { ) -> Result<(), &'static str> { // let z: Scalar = Scalar::reduce_bytes(z); let z = - ::Uint>>::reduce_bytes(z); + ::Uint>>::reduce_bytes(z); let (r, s) = sig.split_scalars(); let s_inv = *s.invert_vartime(); let u1 = z * s_inv; @@ -476,9 +476,9 @@ mod tests { // println!("------------- verify_prehashed[end] -------------"); let reduced = - ::Uint>>::reduce_bytes( - &x, - ); + ::Uint>>::reduce_bytes( + &x, + ); //println!("reduced {reduced:#?}"); diff --git a/integration-tests/src/actions/sign.rs b/integration-tests/src/actions/sign.rs index 97782bea..ea603f51 100644 --- a/integration-tests/src/actions/sign.rs +++ b/integration-tests/src/actions/sign.rs @@ -6,7 +6,8 @@ use k256::{Scalar, Secp256k1}; use mpc_contract::errors; use mpc_contract::primitives::{SignRequest, SignatureRequest}; use mpc_crypto::{ - derive_epsilon, ScalarExt as _, SerializableAffinePoint, SerializableScalar, SignatureResponse, + derive_epsilon_near, ScalarExt as _, SerializableAffinePoint, SerializableScalar, + SignatureResponse, }; use near_crypto::InMemorySigner; use near_fetch::ops::AsyncTransactionStatus; @@ -162,11 +163,12 @@ impl SignAction<'_> { mpc_pk_bytes.extend_from_slice(&state.public_key.as_bytes()[1..]); // Useful for populating the "signatures_havent_changed" test's hardcoded values - // dbg!( + // tracing::warn!( + // "ref_string: big_r={}, s={}, mpc_pk_bytes={}, payload_hash={}, account_id={}", // hex::encode(signature.big_r.to_encoded_point(true).to_bytes()), // hex::encode(signature.s.to_bytes()), // hex::encode(&mpc_pk_bytes), - // hex::encode(&payload_hash), + // hex::encode(payload_hash), // account.id(), // ); actions::validate_signature(account.id(), &mpc_pk_bytes, payload_hash, &signature).await?; @@ -238,7 +240,7 @@ impl SignAction<'_> { public_key: rogue.secret_key().public_key().clone().into(), secret_key: rogue.secret_key().to_string().parse()?, }; - let epsilon = derive_epsilon(predecessor, &self.path); + let epsilon = derive_epsilon_near(predecessor, &self.path); let request = SignatureRequest { payload_hash: Scalar::from_bytes(payload_hash).unwrap().into(), diff --git a/integration-tests/tests/cases/mod.rs b/integration-tests/tests/cases/mod.rs index 4b08c5be..5a261ad0 100644 --- a/integration-tests/tests/cases/mod.rs +++ b/integration-tests/tests/cases/mod.rs @@ -11,7 +11,7 @@ use k256::elliptic_curve::point::AffineCoordinates; use k256::Secp256k1; use mpc_contract::config::Config; use mpc_contract::update::ProposeUpdateArgs; -use mpc_crypto::{self, derive_epsilon, derive_key, x_coordinate, ScalarExt}; +use mpc_crypto::{self, derive_epsilon_near, derive_key, x_coordinate, ScalarExt}; use mpc_node::kdf::into_eth_sig; use mpc_node::protocol::presignature::{Presignature, PresignatureId, PresignatureManager}; use mpc_node::protocol::triple::{Triple, TripleManager}; @@ -102,7 +102,7 @@ async fn test_key_derivation() -> anyhow::Result<()> { nodes.wait().signable().await?; let outcome = nodes.sign().path(hd_path).await?; - let derivation_epsilon = derive_epsilon(outcome.account.id(), hd_path); + let derivation_epsilon = derive_epsilon_near(outcome.account.id(), hd_path); let user_pk = derive_key(mpc_pk, derivation_epsilon); let multichain_sig = into_eth_sig( &user_pk,