diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index 5c3430503..d17bc3d4a 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -1057,7 +1057,7 @@ mod test { ).unwrap(); let short_id = input.short_id(&block_hash); - assert_eq!(short_id, ShortId::from_hex("102864956811").unwrap()); + assert_eq!(short_id, ShortId::from_hex("3e1262905b7a").unwrap()); // now generate the short_id for a *very* similar output (single feature flag different) // and check it generates a different short_id @@ -1072,6 +1072,6 @@ mod test { ).unwrap(); let short_id = input.short_id(&block_hash); - assert_eq!(short_id, ShortId::from_hex("b8c189165df1").unwrap()); + assert_eq!(short_id, ShortId::from_hex("90653c1c870a").unwrap()); } } diff --git a/keychain/src/extkey.rs b/keychain/src/extkey.rs index c8972af3c..11ba48b3b 100644 --- a/keychain/src/extkey.rs +++ b/keychain/src/extkey.rs @@ -126,12 +126,20 @@ impl Identifier { Identifier(identifier) } - pub fn from_key_id(secp: &Secp256k1, pubkey: &PublicKey) -> Identifier { + pub fn from_pubkey(secp: &Secp256k1, pubkey: &PublicKey) -> Identifier { let bytes = pubkey.serialize_vec(secp, true); let identifier = blake2b(IDENTIFIER_SIZE, &[], &bytes[..]); Identifier::from_bytes(&identifier.as_bytes()) } + /// Return the identifier of the secret key + /// which is the blake2b (10 byte) digest of the PublicKey + /// corresponding to the secret key provided. + fn from_secret_key(secp: &Secp256k1, key: &SecretKey) -> Result { + let key_id = PublicKey::from_secret_key(secp, key)?; + Ok(Identifier::from_pubkey(secp, &key_id)) + } + fn from_hex(hex: &str) -> Result { let bytes = util::from_hex(hex.to_string()).unwrap(); Ok(Identifier::from_bytes(&bytes)) @@ -162,6 +170,20 @@ impl fmt::Display for Identifier { } } +#[derive(Debug, Clone)] +pub struct ChildKey { + /// Child number of the key (n derivations) + pub n_child: u32, + /// Root key id + pub root_key_id: Identifier, + /// Key id + pub key_id: Identifier, + /// The private key + pub key: SecretKey, + /// The key used for generating the associated switch_commit_hash + pub switch_key: [u8; 32], +} + /// An ExtendedKey is a secret key which can be used to derive new /// secret keys to blind the commitment of a transaction output. /// To be usable, a secret key should have an amount assigned to it, @@ -169,20 +191,20 @@ impl fmt::Display for Identifier { /// given. #[derive(Debug, Clone)] pub struct ExtendedKey { - /// Depth of the extended key - pub depth: u8, - /// Child number of the key + /// Child number of the extended key pub n_child: u32, - /// Root key identifier + /// Root key id pub root_key_id: Identifier, - /// Actual private key + /// Key id + pub key_id: Identifier, + /// The secret key pub key: SecretKey, - /// Code of the derivation chain - pub chaincode: [u8; 32], - /// The bytes of the key used for generating the associated switch_commit_hash + /// The chain code for the key derivation chain + pub chain_code: [u8; 32], + /// The key used for generating the associated switch_commit_hash pub switch_key: [u8; 32], - /// Code of the derivation chain for the switch_commit_hash key - pub switch_chaincode: [u8; 32], + /// The chain code for the switch key derivation chain + pub switch_chain_code: [u8; 32], } impl ExtendedKey { @@ -196,14 +218,15 @@ impl ExtendedKey { let derived = blake2b(64, b"Grin/MW Seed", seed); let slice = derived.as_bytes(); - // TODO Error handling let key = SecretKey::from_slice(&secp, &slice[0..32]) - .expect("Error generating from seed"); + .expect("Error deriving key (from_slice)"); - let mut chaincode: [u8; 32] = Default::default(); - (&mut chaincode).copy_from_slice(&slice[32..64]); + let mut chain_code: [u8; 32] = Default::default(); + (&mut chain_code).copy_from_slice(&slice[32..64]); - // Now derive the switch_key and switch_chaincode in a similar fashion + let key_id = Identifier::from_secret_key(secp, &key)?; + + // Now derive the switch_key and switch_chain_code in a similar fashion // but using a different key to ensure there is nothing linking // the secret key and the switch commit hash key for any extended key // we subsequently derive @@ -212,75 +235,67 @@ impl ExtendedKey { let mut switch_key: [u8; 32] = Default::default(); (&mut switch_key).copy_from_slice(&switch_slice[0..32]); - let mut switch_chaincode: [u8; 32] = Default::default(); - (&mut switch_chaincode).copy_from_slice(&switch_slice[32..64]); - let mut ext_key = ExtendedKey { - depth: 0, - root_key_id: Identifier::zero(), + let mut switch_chain_code: [u8; 32] = Default::default(); + (&mut switch_chain_code).copy_from_slice(&switch_slice[32..64]); + + let ext_key = ExtendedKey { n_child: 0, - key, - chaincode, - switch_key, - switch_chaincode, - }; + root_key_id: key_id.clone(), + key_id: key_id.clone(), - ext_key.root_key_id = ext_key.identifier(secp)?; + // key and extended chain code for the key itself + key, + chain_code, + + // key and extended chain code for the key for hashed switch commitments + switch_key, + switch_chain_code, + }; Ok(ext_key) } - /// Return the identifier of the key - /// which is the blake2b (10 byte) digest of the PublicKey - // corresponding to the underlying SecretKey - pub fn identifier(&self, secp: &Secp256k1) -> Result { - let key_id = PublicKey::from_secret_key(secp, &self.key)?; - Ok(Identifier::from_key_id(secp, &key_id)) - } - - /// Derive an extended key from an extended key - pub fn derive(&self, secp: &Secp256k1, n: u32) -> Result { + /// Derive a child key from this extended key + pub fn derive(&self, secp: &Secp256k1, n: u32) -> Result { let mut n_bytes: [u8; 4] = [0; 4]; BigEndian::write_u32(&mut n_bytes, n); let mut seed = self.key[..].to_vec(); seed.extend_from_slice(&n_bytes); - let derived = blake2b(64, &self.chaincode[..], &seed[..]); - let slice = derived.as_bytes(); + // only need a 32 byte digest here as we only need the bytes for the key itself + // we do not need additional bytes for a derived (and unused) chain code + let derived = blake2b(32, &self.chain_code[..], &seed[..]); - let mut key = SecretKey::from_slice(&secp, &slice[0..32]) - .expect("Error deriving key"); + let mut key = SecretKey::from_slice(&secp, &derived.as_bytes()[..]) + .expect("Error deriving key (from_slice)"); key.add_assign(secp, &self.key) - .expect("Error deriving key"); + .expect("Error deriving key (add_assign)"); - let mut chaincode: [u8; 32] = Default::default(); - (&mut chaincode).copy_from_slice(&slice[32..64]); + let key_id = Identifier::from_secret_key(secp, &key)?; - // Now derive the switch_key and switch_chaincode in a similar fashion let mut switch_seed = self.switch_key[..].to_vec(); switch_seed.extend_from_slice(&n_bytes); - let switch_derived = blake2b(64, &self.switch_chaincode[..], &switch_seed[..]); - let switch_slice = switch_derived.as_bytes(); + + // only need a 32 byte digest here as we only need the bytes for the key itself + // we do not need additional bytes for a derived (and unused) chain code + let switch_derived = blake2b(32, &self.switch_chain_code[..], &switch_seed[..]); + let mut switch_key: [u8; 32] = Default::default(); - (&mut switch_key).copy_from_slice(&switch_slice[0..32]); - let mut switch_chaincode: [u8; 32] = Default::default(); - (&mut switch_chaincode).copy_from_slice(&switch_slice[32..64]); + (&mut switch_key).copy_from_slice(&switch_derived.as_bytes()[..]); - // TODO check if key != 0 ? - - Ok(ExtendedKey { - depth: self.depth + 1, - root_key_id: self.identifier(&secp)?, + Ok(ChildKey { n_child: n, + root_key_id: self.root_key_id.clone(), + key_id, key, - chaincode, switch_key, - switch_chaincode, }) } } + #[cfg(test)] mod test { use serde_json; @@ -321,22 +336,20 @@ mod test { let extk = ExtendedKey::from_seed(&s, &seed.as_slice()).unwrap(); let sec = from_hex("2878a92133b0a7c2fbfb0bd4520ed2e55ea3fa2913200f05c30077d30b193480"); let secret_key = SecretKey::from_slice(&s, sec.as_slice()).unwrap(); - let chaincode = + let chain_code = from_hex("3ad40dd836c5ce25dfcbdee5044d92cf6b65bd5475717fa7a56dd4a032cca7c0"); let identifier = from_hex("6f7c1a053ca54592e783"); - let depth = 0; let n_child = 0; assert_eq!(extk.key, secret_key); assert_eq!( - extk.identifier(&s).unwrap(), + extk.key_id, Identifier::from_bytes(identifier.as_slice()) ); assert_eq!( extk.root_key_id, Identifier::from_bytes(identifier.as_slice()) ); - assert_eq!(extk.chaincode, chaincode.as_slice()); - assert_eq!(extk.depth, depth); + assert_eq!(extk.chain_code, chain_code.as_slice()); assert_eq!(extk.n_child, n_child); } @@ -346,25 +359,20 @@ mod test { let seed = from_hex("000102030405060708090a0b0c0d0e0f"); let extk = ExtendedKey::from_seed(&s, &seed.as_slice()).unwrap(); let derived = extk.derive(&s, 0).unwrap(); - let sec = from_hex("2676a3ab2ded7c79cbd0bd26d448698de5da5af8e809080d3cacfa2ee31a9aa7"); + let sec = from_hex("55f1a2b67ec58933bf954fdc721327afe486e8989af923c3ae298e45a84ef597"); let secret_key = SecretKey::from_slice(&s, sec.as_slice()).unwrap(); - let chaincode = - from_hex("9bc90b148f4c9478205d6ca72c58bbda2902be1e5082de05d56339a74a5314a3"); let root_key_id = from_hex("6f7c1a053ca54592e783"); - let identifier = from_hex("5f2ec8ee00e8bca002fa"); - let depth = 1; + let identifier = from_hex("8fa188b56cefe66be154"); let n_child = 0; assert_eq!(derived.key, secret_key); assert_eq!( - derived.identifier(&s).unwrap(), + derived.key_id, Identifier::from_bytes(identifier.as_slice()) ); assert_eq!( derived.root_key_id, Identifier::from_bytes(root_key_id.as_slice()) ); - assert_eq!(derived.chaincode, chaincode.as_slice()); - assert_eq!(derived.depth, depth); assert_eq!(derived.n_child, n_child); } } diff --git a/keychain/src/keychain.rs b/keychain/src/keychain.rs index ed7232934..075bd16c3 100644 --- a/keychain/src/keychain.rs +++ b/keychain/src/keychain.rs @@ -106,9 +106,8 @@ impl Keychain { } pub fn derive_key_id(&self, derivation: u32) -> Result { - let extkey = self.extkey.derive(&self.secp, derivation)?; - let key_id = extkey.identifier(&self.secp)?; - Ok(key_id) + let child_key = self.extkey.derive(&self.secp, derivation)?; + Ok(child_key.key_id) } fn derived_key(&self, key_id: &Identifier) -> Result { @@ -118,11 +117,11 @@ impl Keychain { return Ok(*key); } - let extkey = self.derived_extended_key(key_id)?; - Ok(extkey.key) + let child_key = self.derived_child_key(key_id)?; + Ok(child_key.key) } - fn derived_extended_key(&self, key_id: &Identifier) -> Result { + fn derived_child_key(&self, key_id: &Identifier) -> Result { trace!(LOGGER, "Derived Key by key_id: {}", key_id); // then check the derivation cache to see if we have previously derived this key @@ -142,22 +141,27 @@ impl Keychain { { let mut cache = self.key_derivation_cache.write().unwrap(); for i in 1..100_000 { - let extkey = self.extkey.derive(&self.secp, i)?; - let extkey_id = extkey.identifier(&self.secp)?; + let child_key = self.extkey.derive(&self.secp, i)?; + // let child_key_id = extkey.identifier(&self.secp)?; - if !cache.contains_key(&extkey_id) { - trace!(LOGGER, "... Derived Key (cache miss) key_id: {}, derivation: {}", extkey_id, extkey.n_child); - cache.insert(extkey_id.clone(), extkey.n_child); + if !cache.contains_key(&child_key.key_id) { + trace!( + LOGGER, + "... Derived Key (cache miss) key_id: {}, derivation: {}", + child_key.key_id, + child_key.n_child, + ); + cache.insert(child_key.key_id.clone(), child_key.n_child); } - if extkey_id == *key_id { - return Ok(extkey); + if child_key.key_id == *key_id { + return Ok(child_key); } } } Err(Error::KeyDerivation( - format!("cannot find extkey for {:?}", key_id), + format!("failed to derive child_key for {:?}", key_id), )) } @@ -165,10 +169,10 @@ impl Keychain { fn derived_key_from_index( &self, derivation: u32, - ) -> Result { + ) -> Result { trace!(LOGGER, "Derived Key (fast) by derivation: {}", derivation); - let extkey = self.extkey.derive(&self.secp, derivation)?; - return Ok(extkey) + let child_key = self.extkey.derive(&self.secp, derivation)?; + return Ok(child_key) } pub fn commit(&self, amount: u64, key_id: &Identifier) -> Result { @@ -182,8 +186,8 @@ impl Keychain { amount: u64, derivation: u32, ) -> Result { - let extkey = self.derived_key_from_index(derivation)?; - let commit = self.secp.commit(amount, extkey.key)?; + let child_key = self.derived_key_from_index(derivation)?; + let commit = self.secp.commit(amount, child_key.key)?; Ok(commit) } @@ -210,8 +214,8 @@ impl Keychain { return Ok(key); } - let extkey = self.derived_extended_key(key_id)?; - Ok(extkey.switch_key) + let child_key = self.derived_child_key(key_id)?; + Ok(child_key.switch_key) } pub fn range_proof(