Merge 8b061a848adf7a773aa5c0b3a800b8865f0a93a7 into fb083ce91ec10487fc17137a48c47f4322f9c768

This commit is contained in:
jonesmarvin8 2026-03-23 11:14:08 -04:00 committed by GitHub
commit 6b8ab331f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 153 additions and 32 deletions

View File

@ -11,11 +11,11 @@
"channel_id": "0101010101010101010101010101010101010101010101010101010101010101",
"initial_accounts": [
{
"account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r",
"account_id": "jZvdpERLqEkzk6CAz6vDuDJ1wx5aoyFpDa1VFmRvuPX",
"balance": 10000
},
{
"account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2",
"account_id": "3jQfsyRyvVpBfdkZegf8QpjfcDq1M5RAXB4H4eJ4kTtf",
"balance": 20000
}
],

View File

@ -5,6 +5,7 @@ use crate::key_management::key_tree::traits::KeyNode;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ChildKeysPublic {
pub cssk: nssa::PrivateKey,
pub csk: nssa::PrivateKey,
pub cpk: nssa::PublicKey,
pub ccc: [u8; 32],
@ -21,14 +22,14 @@ 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 = secp256k1::SecretKey::from_byte_array(*self.cssk.value())
.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));
} else {
// Harden.
hash_input.extend_from_slice(&[0_u8]);
hash_input.extend_from_slice(self.csk.value());
hash_input.extend_from_slice(self.cssk.value());
}
hash_input.extend_from_slice(&cci.to_be_bytes());
@ -41,11 +42,13 @@ 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 cssk = nssa::PrivateKey::try_new(*hash_value.first_chunk::<32>().unwrap()).unwrap();
let csk = nssa::PrivateKey::tweak(cssk.value()).unwrap();
let ccc = *hash_value.last_chunk::<32>().unwrap();
let cpk = nssa::PublicKey::new_from_private_key(&csk);
Self {
cssk,
csk,
cpk,
ccc,
@ -56,22 +59,22 @@ 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(
let cssk = 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();
csk.add_tweak(&scalar)
let cssk = nssa::PrivateKey::try_new({
cssk.add_tweak(&Scalar::from_be_bytes(*self.cssk.value()).unwrap())
.expect("Expect a valid Scalar")
.secret_bytes()
})
.unwrap();
let csk = nssa::PrivateKey::tweak(cssk.value()).unwrap();
assert!(
secp256k1::constants::CURVE_ORDER >= *csk.value(),
"Secret key cannot exceed curve order"
@ -84,6 +87,7 @@ impl KeyNode for ChildKeysPublic {
let cpk = nssa::PublicKey::new_from_private_key(&csk);
Self {
cssk,
csk,
cpk,
ccc,
@ -135,19 +139,26 @@ mod tests {
13, 146, 126, 232, 239, 113, 9, 194, 219, 190, 48, 187, 155,
];
let expected_csk: PrivateKey = PrivateKey::try_new([
let expected_cssk: PrivateKey = PrivateKey::try_new([
40, 35, 239, 19, 53, 178, 250, 55, 115, 12, 34, 3, 153, 153, 72, 170, 190, 36, 172, 36,
202, 148, 181, 228, 35, 222, 58, 84, 156, 24, 146, 86,
])
.unwrap();
let expected_csk: PrivateKey = PrivateKey::try_new([
207, 4, 246, 223, 104, 72, 19, 85, 14, 122, 194, 82, 32, 163, 60, 57, 8, 25, 209, 91,
254, 107, 76, 238, 31, 68, 236, 192, 154, 78, 105, 118,
])
.unwrap();
let expected_cpk: PublicKey = PublicKey::try_new([
219, 141, 130, 105, 11, 203, 187, 124, 112, 75, 223, 22, 11, 164, 153, 127, 59, 247,
244, 166, 75, 66, 242, 224, 35, 156, 161, 75, 41, 51, 76, 245,
188, 163, 203, 45, 151, 154, 230, 254, 123, 114, 158, 130, 19, 182, 164, 143, 150, 131,
176, 7, 27, 58, 204, 116, 5, 247, 0, 255, 111, 160, 52, 201,
])
.unwrap();
assert!(expected_ccc == keys.ccc);
assert!(expected_cssk == keys.cssk);
assert!(expected_csk == keys.csk);
assert!(expected_cpk == keys.cpk);
}
@ -169,19 +180,26 @@ mod tests {
130, 126, 123, 20, 90, 34, 173, 209, 101, 248, 155, 36,
];
let expected_csk: PrivateKey = PrivateKey::try_new([
let expected_cssk: PrivateKey = PrivateKey::try_new([
9, 65, 33, 228, 25, 82, 219, 117, 91, 217, 11, 223, 144, 85, 246, 26, 123, 216, 107,
213, 33, 52, 188, 22, 198, 246, 71, 46, 245, 174, 16, 47,
])
.unwrap();
let expected_csk: PrivateKey = PrivateKey::try_new([
100, 37, 212, 81, 40, 233, 72, 156, 177, 139, 50, 114, 136, 157, 202, 132, 203, 246,
252, 242, 13, 81, 42, 100, 159, 240, 187, 252, 202, 108, 25, 105,
])
.unwrap();
let expected_cpk: PublicKey = PublicKey::try_new([
142, 143, 238, 159, 105, 165, 224, 252, 108, 62, 53, 209, 176, 219, 249, 38, 90, 241,
201, 81, 194, 146, 236, 5, 83, 152, 238, 243, 138, 16, 229, 15,
210, 59, 119, 137, 21, 153, 82, 22, 195, 82, 12, 16, 80, 156, 125, 199, 19, 173, 46,
224, 213, 144, 165, 126, 70, 129, 171, 141, 77, 212, 108, 233,
])
.unwrap();
assert!(expected_ccc == child_keys.ccc);
assert!(expected_cssk == child_keys.cssk);
assert!(expected_csk == child_keys.csk);
assert!(expected_cpk == child_keys.cpk);
}
@ -203,19 +221,26 @@ mod tests {
16, 28, 79, 80, 232, 216, 101, 145, 19, 101, 220, 217, 141,
];
let expected_csk: PrivateKey = PrivateKey::try_new([
let expected_cssk: PrivateKey = PrivateKey::try_new([
185, 147, 32, 242, 145, 91, 123, 77, 42, 33, 134, 84, 12, 165, 117, 70, 158, 201, 95,
153, 14, 12, 92, 235, 128, 156, 194, 169, 68, 35, 165, 127,
])
.unwrap();
let expected_csk: PrivateKey = PrivateKey::try_new([
215, 157, 181, 165, 200, 92, 8, 103, 239, 104, 39, 41, 150, 199, 17, 205, 77, 179, 188,
27, 168, 216, 198, 12, 94, 11, 72, 131, 148, 44, 166, 128,
])
.unwrap();
let expected_cpk: PublicKey = PublicKey::try_new([
119, 16, 145, 121, 97, 244, 186, 35, 136, 34, 140, 171, 206, 139, 11, 208, 207, 121,
158, 45, 28, 22, 140, 98, 161, 179, 212, 173, 238, 220, 2, 34,
210, 66, 25, 100, 233, 50, 82, 94, 139, 83, 39, 52, 196, 241, 123, 248, 177, 10, 249,
206, 71, 167, 198, 5, 202, 184, 178, 148, 106, 231, 214, 235,
])
.unwrap();
assert!(expected_ccc == child_keys.ccc);
assert!(expected_cssk == child_keys.cssk);
assert!(expected_csk == child_keys.csk);
assert!(expected_cpk == child_keys.cpk);
}
@ -237,19 +262,26 @@ mod tests {
58, 215, 40, 246, 111, 166, 113, 183, 145, 173, 11, 27, 182,
];
let expected_csk: PrivateKey = PrivateKey::try_new([
let expected_cssk: PrivateKey = PrivateKey::try_new([
223, 29, 87, 189, 126, 24, 117, 225, 190, 57, 0, 143, 207, 168, 231, 139, 170, 192, 81,
254, 126, 10, 115, 42, 141, 157, 70, 171, 199, 231, 198, 132,
])
.unwrap();
let expected_csk: PrivateKey = PrivateKey::try_new([
35, 70, 190, 115, 134, 106, 151, 84, 164, 16, 139, 204, 100, 203, 36, 219, 91, 200, 6,
52, 120, 67, 35, 82, 14, 197, 163, 27, 248, 162, 129, 159,
])
.unwrap();
let expected_cpk: PublicKey = PublicKey::try_new([
96, 123, 245, 51, 214, 216, 215, 205, 70, 145, 105, 221, 166, 169, 122, 27, 94, 112,
228, 110, 249, 177, 85, 173, 180, 248, 185, 199, 112, 246, 83, 33,
61, 182, 68, 167, 177, 158, 173, 101, 79, 212, 191, 179, 169, 131, 220, 232, 123, 203,
235, 244, 72, 251, 159, 98, 215, 85, 103, 49, 124, 137, 98, 39,
])
.unwrap();
assert!(expected_ccc == child_keys.ccc);
assert!(expected_cssk == child_keys.cssk);
assert!(expected_csk == child_keys.csk);
assert!(expected_cpk == child_keys.cpk);
}

View File

@ -283,8 +283,8 @@ mod tests {
assert!(tree.key_map.contains_key(&ChainIndex::root()));
assert!(tree.account_id_map.contains_key(&AccountId::new([
172, 82, 222, 249, 164, 16, 148, 184, 219, 56, 92, 145, 203, 220, 251, 89, 214, 178,
38, 30, 108, 202, 251, 241, 148, 200, 125, 185, 93, 227, 189, 247
10, 231, 159, 65, 236, 46, 205, 5, 172, 89, 250, 29, 123, 195, 212, 137, 155, 111, 40,
120, 53, 28, 124, 54, 224, 170, 119, 208, 2, 72, 75, 50
])));
}

View File

@ -1,6 +1,7 @@
use std::str::FromStr;
use rand::{Rng as _, rngs::OsRng};
use risc0_zkvm::sha::{Impl, Sha256 as _};
use serde_with::{DeserializeFromStr, SerializeDisplay};
use crate::error::NssaError;
@ -60,6 +61,28 @@ impl PrivateKey {
pub const fn value(&self) -> &[u8; 32] {
&self.0
}
pub fn tweak(value: &[u8; 32]) -> Result<Self, NssaError> {
assert!(Self::is_valid_key(*value));
let sk = secp256k1::SecretKey::from_byte_array(*value).expect("Expect a valid secret key");
let mut bytes = vec![];
let pk = secp256k1::PublicKey::from_secret_key(&secp256k1::Secp256k1::new(), &sk);
bytes.extend_from_slice(&secp256k1::PublicKey::serialize(&pk));
let hashed: [u8; 32] = Impl::hash_bytes(&bytes)
.as_bytes()
.try_into()
.expect("Sha256 outputs a 32-byte array");
Self::try_new(
sk.add_tweak(
&secp256k1::Scalar::from_be_bytes(hashed).expect("Expect a valid secp256k1 Scalar"),
)
.expect("Expect a valid Scalar")
.secret_bytes(),
)
}
}
#[cfg(test)]

View File

@ -18,11 +18,11 @@
"indexer_rpc_url": "ws://localhost:8779",
"initial_accounts": [
{
"account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r",
"account_id": "jZvdpERLqEkzk6CAz6vDuDJ1wx5aoyFpDa1VFmRvuPX",
"balance": 10000
},
{
"account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2",
"account_id": "3jQfsyRyvVpBfdkZegf8QpjfcDq1M5RAXB4H4eJ4kTtf",
"balance": 20000
}
],

View File

@ -18,11 +18,11 @@
"indexer_rpc_url": "ws://localhost:8779",
"initial_accounts": [
{
"account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r",
"account_id": "jZvdpERLqEkzk6CAz6vDuDJ1wx5aoyFpDa1VFmRvuPX",
"balance": 10000
},
{
"account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2",
"account_id": "3jQfsyRyvVpBfdkZegf8QpjfcDq1M5RAXB4H4eJ4kTtf",
"balance": 20000
}
],

View File

@ -7,14 +7,80 @@
"initial_accounts": [
{
"Public": {
"account_id": "CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r",
"pub_sign_key": "7f273098f25b71e6c005a9519f2678da8d1c7f01f6a27778e2d9948abdf901fb"
"account_id": "jZvdpERLqEkzk6CAz6vDuDJ1wx5aoyFpDa1VFmRvuPX",
"pub_sign_key": [
157,
102,
173,
116,
76,
167,
130,
165,
77,
104,
14,
233,
114,
43,
180,
98,
59,
187,
165,
28,
80,
130,
126,
164,
224,
181,
203,
53,
31,
168,
169,
23
]
}
},
{
"Public": {
"account_id": "2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2",
"pub_sign_key": "f434f8741720014586ae43356d2aec6257da086222f604ddb75d69733b86fc4c"
"account_id": "3jQfsyRyvVpBfdkZegf8QpjfcDq1M5RAXB4H4eJ4kTtf",
"pub_sign_key": [
230,
17,
4,
52,
87,
162,
72,
137,
119,
205,
163,
211,
118,
157,
15,
164,
67,
12,
124,
50,
159,
23,
184,
6,
109,
154,
2,
219,
147,
239,
125,
20
]
}
},
{