grin/keychain/src/view_key.rs
Quentin Le Sceller cf2a65242d
Rename Floonet to Testnet (#3431)
* Rename Floonet to Testnet

* Fix test

* Rename test and docker
2020-10-07 09:36:02 -04:00

195 lines
5.4 KiB
Rust

use crate::blake2::blake2b::blake2b;
use byteorder::{BigEndian, ByteOrder};
//use crate::sha2::{Digest, Sha256};
use super::extkey_bip32::{
BIP32Hasher, ChainCode, ChildNumber, Error as BIP32Error, ExtendedPrivKey, ExtendedPubKey,
Fingerprint,
};
use super::types::{Error, Keychain};
use crate::util::secp::constants::GENERATOR_PUB_J_RAW;
use crate::util::secp::ffi;
use crate::util::secp::key::{PublicKey, SecretKey};
use crate::util::secp::Secp256k1;
use crate::SwitchCommitmentType;
/*const VERSION_TEST_NS: [u8;4] = [0x03, 0x27, 0x3E, 0x4B];
const VERSION_TEST: [u8;4] = [0x03, 0x27, 0x3E, 0x4B];
const VERSION_MAIN_NS: [u8;4] = [0x03, 0x3C, 0x08, 0xDF];
const VERSION_MAIN: [u8;4] = [0x03, 0x3C, 0x08, 0xDF];*/
/// Key that can be used to scan the chain for owned outputs
/// This is a public key, meaning it cannot be used to spend those outputs
/// At the moment only depth 0 keys can be used
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct ViewKey {
/// Whether this view key is meant for testnet or not
pub is_test: bool,
/// How many derivations this key is from the master (which is 0)
pub depth: u8,
/// Fingerprint of the parent key
parent_fingerprint: Fingerprint,
/// Child number of the key used to derive from parent (0 for master)
pub child_number: ChildNumber,
/// Public key
public_key: PublicKey,
/// Switch public key, required to view outputs that use switch commitment
switch_public_key: Option<PublicKey>,
/// Chain code
chain_code: ChainCode,
/// Hash used to generate rewind nonce
pub rewind_hash: Vec<u8>,
}
impl ViewKey {
pub fn create<K, H>(
keychain: &K,
ext_key: ExtendedPrivKey,
hasher: &mut H,
is_test: bool,
) -> Result<Self, Error>
where
K: Keychain,
H: BIP32Hasher,
{
let secp = keychain.secp();
let ExtendedPubKey {
network: _,
depth,
parent_fingerprint,
child_number,
public_key,
chain_code,
} = ExtendedPubKey::from_private(secp, &ext_key, hasher);
let mut switch_public_key = PublicKey(ffi::PublicKey(GENERATOR_PUB_J_RAW));
switch_public_key.mul_assign(secp, &ext_key.secret_key)?;
let switch_public_key = Some(switch_public_key);
let rewind_hash = Self::rewind_hash(secp, keychain.public_root_key());
Ok(Self {
is_test,
depth,
parent_fingerprint,
child_number,
public_key,
switch_public_key,
chain_code,
rewind_hash,
})
}
fn rewind_hash(secp: &Secp256k1, public_root_key: PublicKey) -> Vec<u8> {
let ser = public_root_key.serialize_vec(secp, true);
blake2b(32, &[], &ser[..]).as_bytes().to_vec()
}
fn ckd_pub_tweak<H>(
&self,
secp: &Secp256k1,
hasher: &mut H,
i: ChildNumber,
) -> Result<(SecretKey, ChainCode), Error>
where
H: BIP32Hasher,
{
match i {
ChildNumber::Hardened { .. } => Err(BIP32Error::CannotDeriveFromHardenedKey.into()),
ChildNumber::Normal { index: n } => {
hasher.init_sha512(&self.chain_code[..]);
hasher.append_sha512(&self.public_key.serialize_vec(secp, true)[..]);
let mut be_n = [0; 4];
BigEndian::write_u32(&mut be_n, n);
hasher.append_sha512(&be_n);
let result = hasher.result_sha512();
let secret_key = SecretKey::from_slice(secp, &result[..32])?;
let chain_code = ChainCode::from(&result[32..]);
Ok((secret_key, chain_code))
}
}
}
pub fn ckd_pub<H>(
&self,
secp: &Secp256k1,
hasher: &mut H,
i: ChildNumber,
) -> Result<Self, Error>
where
H: BIP32Hasher,
{
let (secret_key, chain_code) = self.ckd_pub_tweak(secp, hasher, i)?;
let mut public_key = self.public_key;
public_key.add_exp_assign(secp, &secret_key)?;
let switch_public_key = match &self.switch_public_key {
Some(p) => {
let mut j = PublicKey(ffi::PublicKey(GENERATOR_PUB_J_RAW));
j.mul_assign(secp, &secret_key)?;
Some(PublicKey::from_combination(secp, vec![p, &j])?)
}
None => None,
};
Ok(Self {
is_test: self.is_test,
depth: self.depth + 1,
parent_fingerprint: self.fingerprint(secp, hasher),
child_number: i,
public_key,
switch_public_key,
chain_code,
rewind_hash: self.rewind_hash.clone(),
})
}
pub fn commit(
&self,
secp: &Secp256k1,
amount: u64,
switch: SwitchCommitmentType,
) -> Result<PublicKey, Error> {
let value_key = secp.commit_value(amount)?.to_pubkey(secp)?;
let pub_key = PublicKey::from_combination(secp, vec![&self.public_key, &value_key])?;
match switch {
SwitchCommitmentType::None => Ok(pub_key),
SwitchCommitmentType::Regular => {
// TODO: replace this whole block by a libsecp function
/*let switch_pub = self.switch_public_key.ok_or(Error::SwitchCommitment)?;
let switch_ser: Vec<u8> = switch_pub.serialize_vec(secp, true)[..].to_vec();
let mut commit_ser: Vec<u8> = pub_key.serialize_vec(secp, true)[..].to_vec();
commit_ser[0] += 6; // This only works sometimes
let mut hasher = Sha256::new();
hasher.input(&commit_ser);
hasher.input(&switch_ser);
let blind = SecretKey::from_slice(secp, &hasher.result()[..])?;
let mut pub_key = pub_key;
pub_key.add_exp_assign(secp, &blind)?;
Ok(pub_key)*/
Err(Error::SwitchCommitment)
}
}
}
fn identifier<H>(&self, secp: &Secp256k1, hasher: &mut H) -> [u8; 20]
where
H: BIP32Hasher,
{
let sha2_res = hasher.sha_256(&self.public_key.serialize_vec(secp, true)[..]);
hasher.ripemd_160(&sha2_res)
}
fn fingerprint<H>(&self, secp: &Secp256k1, hasher: &mut H) -> Fingerprint
where
H: BIP32Hasher,
{
Fingerprint::from(&self.identifier(secp, hasher)[0..4])
}
}