diff --git a/key_protocol/Cargo.toml b/key_protocol/Cargo.toml index 5ce7e97c..022f3ccd 100644 --- a/key_protocol/Cargo.toml +++ b/key_protocol/Cargo.toml @@ -8,8 +8,6 @@ license = { workspace = true } workspace = true [dependencies] -secp256k1 = "0.31.1" - nssa.workspace = true nssa_core.workspace = true common.workspace = true diff --git a/key_protocol/src/key_management/key_tree/keys_private.rs b/key_protocol/src/key_management/key_tree/keys_private.rs index 0b20a310..ee812d36 100644 --- a/key_protocol/src/key_management/key_tree/keys_private.rs +++ b/key_protocol/src/key_management/key_tree/keys_private.rs @@ -137,13 +137,13 @@ impl<'a> From<&'a mut ChildKeysPrivate> for &'a mut (KeyChain, nssa::Account) { #[cfg(test)] mod tests { - use nssa_core::NullifierSecretKey; + use nssa_core::{NullifierPublicKey, NullifierSecretKey}; use super::*; use crate::key_management::{self, secret_holders::ViewingSecretKey}; #[test] - fn master_key_generation() { + fn test_master_key_generation() { let seed: [u8; 64] = [ 252, 56, 204, 83, 232, 123, 209, 188, 187, 167, 39, 213, 71, 39, 58, 65, 125, 134, 255, 49, 43, 108, 92, 53, 173, 164, 94, 142, 150, 74, 21, 163, 43, 144, 226, 87, 199, 18, @@ -153,7 +153,7 @@ mod tests { let keys = ChildKeysPrivate::root(seed); - let expected_ssk = key_management::secret_holders::SecretSpendingKey([ + let expected_ssk: SecretSpendingKey = key_management::secret_holders::SecretSpendingKey([ 246, 79, 26, 124, 135, 95, 52, 51, 201, 27, 48, 194, 2, 144, 51, 219, 245, 128, 139, 222, 42, 195, 105, 33, 115, 97, 186, 0, 97, 14, 218, 191, ]); @@ -168,7 +168,7 @@ mod tests { 34, 234, 19, 222, 2, 22, 12, 163, 252, 88, 11, 0, 163, ]; - let expected_npk = nssa_core::NullifierPublicKey([ + let expected_npk: NullifierPublicKey = nssa_core::NullifierPublicKey([ 7, 123, 125, 191, 233, 183, 201, 4, 20, 214, 155, 210, 45, 234, 27, 240, 194, 111, 97, 247, 155, 113, 122, 246, 192, 0, 70, 61, 76, 71, 70, 2, ]); @@ -191,7 +191,7 @@ mod tests { } #[test] - fn child_keys_generation() { + fn test_child_keys_generation() { let seed: [u8; 64] = [ 252, 56, 204, 83, 232, 123, 209, 188, 187, 167, 39, 213, 71, 39, 58, 65, 125, 134, 255, 49, 43, 108, 92, 53, 173, 164, 94, 142, 150, 74, 21, 163, 43, 144, 226, 87, 199, 18, diff --git a/key_protocol/src/key_management/key_tree/keys_public.rs b/key_protocol/src/key_management/key_tree/keys_public.rs index 73ed7bee..74caabf3 100644 --- a/key_protocol/src/key_management/key_tree/keys_public.rs +++ b/key_protocol/src/key_management/key_tree/keys_public.rs @@ -1,4 +1,4 @@ -use secp256k1::Scalar; +use k256::elliptic_curve::{PrimeField as _, sec1::ToEncodedPoint as _}; use serde::{Deserialize, Serialize}; use crate::key_management::key_tree::traits::KeyNode; @@ -13,7 +13,6 @@ pub struct ChildKeysPublic { } impl ChildKeysPublic { - #[expect(clippy::big_endian_bytes, reason = "BIP-032 uses big endian")] fn compute_hash_value(&self, cci: u32) -> [u8; 64] { let mut hash_input = vec![]; @@ -21,10 +20,10 @@ impl ChildKeysPublic { // Non-harden. // BIP-032 compatibility requires 1-byte header from the public_key; // Not stored in `self.cpk.value()`. - let sk = secp256k1::SecretKey::from_byte_array(*self.csk.value()) + let sk = k256::SecretKey::from_bytes(self.csk.value().into()) .expect("32 bytes, within curve order"); - let pk = secp256k1::PublicKey::from_secret_key(&secp256k1::Secp256k1::new(), &sk); - hash_input.extend_from_slice(&secp256k1::PublicKey::serialize(&pk)); + let pk = sk.public_key(); + hash_input.extend_from_slice(&pk.to_encoded_point(true).as_bytes()); } else { // Harden. hash_input.extend_from_slice(&[0_u8]); @@ -41,7 +40,12 @@ impl KeyNode for ChildKeysPublic { fn root(seed: [u8; 64]) -> Self { let hash_value = hmac_sha512::HMAC::mac(seed, "LEE_master_pub"); - let csk = nssa::PrivateKey::try_new(*hash_value.first_chunk::<32>().unwrap()).unwrap(); + let csk = nssa::PrivateKey::try_new( + *hash_value + .first_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get first 32"), + ) + .unwrap(); let ccc = *hash_value.last_chunk::<32>().unwrap(); let cpk = nssa::PublicKey::new_from_private_key(&csk); @@ -56,26 +60,20 @@ impl KeyNode for ChildKeysPublic { fn nth_child(&self, cci: u32) -> Self { let hash_value = self.compute_hash_value(cci); - let csk = secp256k1::SecretKey::from_byte_array( - *hash_value - .first_chunk::<32>() - .expect("hash_value is 64 bytes, must be safe to get first 32"), - ) - .unwrap(); - let csk = nssa::PrivateKey::try_new({ - let scalar = Scalar::from_be_bytes(*self.csk.value()).unwrap(); + let hash_value = hash_value + .first_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get first 32"); - csk.add_tweak(&scalar) - .expect("Expect a valid Scalar") - .secret_bytes() + let value_1 = + k256::Scalar::from_repr((*hash_value).into()).expect("Expect a valid k256 scalar"); + let value_2 = k256::Scalar::from_repr((*self.csk.value()).into()) + .expect("Expect a valid k256 scalar"); + + let sum = value_1.add(&value_2); + sum.to_bytes().into() }) - .unwrap(); - - assert!( - secp256k1::constants::CURVE_ORDER >= *csk.value(), - "Secret key cannot exceed curve order" - ); + .expect("Expect a valid private key"); let ccc = *hash_value .last_chunk::<32>() @@ -121,7 +119,7 @@ mod tests { use super::*; #[test] - fn master_keys_generation() { + fn test_master_keys_generation() { let seed = [ 88, 189, 37, 237, 199, 125, 151, 226, 69, 153, 165, 113, 191, 69, 188, 221, 9, 34, 173, 134, 61, 109, 34, 103, 121, 39, 237, 14, 107, 194, 24, 194, 191, 14, 237, 185, 12, 87, @@ -153,7 +151,7 @@ mod tests { } #[test] - fn harden_child_keys_generation() { + fn test_harden_child_keys_generation() { let seed = [ 88, 189, 37, 237, 199, 125, 151, 226, 69, 153, 165, 113, 191, 69, 188, 221, 9, 34, 173, 134, 61, 109, 34, 103, 121, 39, 237, 14, 107, 194, 24, 194, 191, 14, 237, 185, 12, 87, @@ -187,7 +185,7 @@ mod tests { } #[test] - fn nonharden_child_keys_generation() { + fn test_nonharden_child_keys_generation() { let seed = [ 88, 189, 37, 237, 199, 125, 151, 226, 69, 153, 165, 113, 191, 69, 188, 221, 9, 34, 173, 134, 61, 109, 34, 103, 121, 39, 237, 14, 107, 194, 24, 194, 191, 14, 237, 185, 12, 87, @@ -221,7 +219,7 @@ mod tests { } #[test] - fn edge_case_child_keys_generation_2_power_31() { + fn test_edge_case_child_keys_generation_2_power_31() { let seed = [ 88, 189, 37, 237, 199, 125, 151, 226, 69, 153, 165, 113, 191, 69, 188, 221, 9, 34, 173, 134, 61, 109, 34, 103, 121, 39, 237, 14, 107, 194, 24, 194, 191, 14, 237, 185, 12, 87, diff --git a/nssa/Cargo.toml b/nssa/Cargo.toml index ceebaa2e..07f5fe53 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -19,7 +19,7 @@ sha2.workspace = true rand.workspace = true borsh.workspace = true hex.workspace = true -secp256k1 = "0.31.1" +k256.workspace = true risc0-binfmt = "3.0.2" log.workspace = true diff --git a/nssa/src/error.rs b/nssa/src/error.rs index 3576b366..60ca603c 100644 --- a/nssa/src/error.rs +++ b/nssa/src/error.rs @@ -29,7 +29,10 @@ pub enum NssaError { Io(#[from] io::Error), #[error("Invalid Public Key")] - InvalidPublicKey(#[source] secp256k1::Error), + InvalidPublicKey(#[source] k256::schnorr::Error), + + #[error("Invalid hex for public key")] + InvalidHexPublicKey(hex::FromHexError), #[error("Risc0 error: {0}")] ProgramWriteInputFailed(String), diff --git a/nssa/src/signature/mod.rs b/nssa/src/signature/mod.rs index 9dfd47b3..3a594da6 100644 --- a/nssa/src/signature/mod.rs +++ b/nssa/src/signature/mod.rs @@ -49,21 +49,28 @@ impl Signature { aux_random: [u8; 32], ) -> Self { let value = { - let secp = secp256k1::Secp256k1::new(); - let secret_key = secp256k1::SecretKey::from_byte_array(*key.value()).unwrap(); - let keypair = secp256k1::Keypair::from_secret_key(&secp, &secret_key); - let signature = secp.sign_schnorr_with_aux_rand(message, &keypair, &aux_random); - signature.to_byte_array() + let signing_key = k256::schnorr::SigningKey::from_bytes(key.value()) + .expect("Expect valid signing key"); + signing_key + .sign_raw(message, &aux_random) + .expect("Expect to produce a valid signature") + .to_bytes() }; + Self { value } } #[must_use] pub fn is_valid_for(&self, bytes: &[u8], public_key: &PublicKey) -> bool { - let pk = secp256k1::XOnlyPublicKey::from_byte_array(*public_key.value()).unwrap(); - let secp = secp256k1::Secp256k1::new(); - let sig = secp256k1::schnorr::Signature::from_byte_array(self.value); - secp.verify_schnorr(&sig, bytes, &pk).is_ok() + let Ok(pk) = k256::schnorr::VerifyingKey::from_bytes(public_key.value()) else { + return false; + }; + + let Ok(sig) = k256::schnorr::Signature::try_from(self.value.as_slice()) else { + return false; + }; + + pk.verify_raw(bytes, &sig).is_ok() } } diff --git a/nssa/src/signature/private_key.rs b/nssa/src/signature/private_key.rs index e73e0e4f..1bfecf80 100644 --- a/nssa/src/signature/private_key.rs +++ b/nssa/src/signature/private_key.rs @@ -45,7 +45,7 @@ impl PrivateKey { } fn is_valid_key(value: [u8; 32]) -> bool { - secp256k1::SecretKey::from_byte_array(value).is_ok() + k256::SecretKey::from_bytes(&value.into()).is_ok() } pub fn try_new(value: [u8; 32]) -> Result { diff --git a/nssa/src/signature/public_key.rs b/nssa/src/signature/public_key.rs index ee0f5dbc..ebec6b62 100644 --- a/nssa/src/signature/public_key.rs +++ b/nssa/src/signature/public_key.rs @@ -1,6 +1,7 @@ use std::str::FromStr; use borsh::{BorshDeserialize, BorshSerialize}; +use k256::elliptic_curve::sec1::ToEncodedPoint as _; use nssa_core::account::AccountId; use serde_with::{DeserializeFromStr, SerializeDisplay}; use sha2::{Digest as _, Sha256}; @@ -27,8 +28,7 @@ impl FromStr for PublicKey { fn from_str(s: &str) -> Result { let mut bytes = [0_u8; 32]; - hex::decode_to_slice(s, &mut bytes) - .map_err(|_err| NssaError::InvalidPublicKey(secp256k1::Error::InvalidPublicKey))?; + hex::decode_to_slice(s, &mut bytes).map_err(NssaError::InvalidHexPublicKey)?; Self::try_new(bytes) } } @@ -46,19 +46,24 @@ impl PublicKey { #[must_use] pub fn new_from_private_key(key: &PrivateKey) -> Self { let value = { - let secret_key = secp256k1::SecretKey::from_byte_array(*key.value()).unwrap(); - let public_key = - secp256k1::PublicKey::from_secret_key(&secp256k1::Secp256k1::new(), &secret_key); - let (x_only, _) = public_key.x_only_public_key(); - x_only.serialize() + let secret_key = k256::SecretKey::from_bytes(&(*key.value()).into()) + .expect("Expect a valid private key"); + + let encoded = secret_key.public_key().to_encoded_point(false); + let x_only = encoded + .x() + .expect("Expect k256 point to have a x-coordinate"); + + *x_only.first_chunk().expect("x_only is exactly 32 bytes") }; Self(value) } pub fn try_new(value: [u8; 32]) -> Result { - // Check point is valid - let _ = secp256k1::XOnlyPublicKey::from_byte_array(value) - .map_err(NssaError::InvalidPublicKey)?; + // Check point is a valid x-only public key + let _ = + k256::schnorr::VerifyingKey::from_bytes(&value).map_err(NssaError::InvalidPublicKey)?; + Ok(Self(value)) }