1609b041b1
* create 2.0.0 branch * fix humansize version * update grin.yml version * PoW HardFork (#2866) * allow version 2 blocks for next 6 months * add cuckarood.rs with working tests * switch cuckaroo to cuckarood at right heights * reorder to reduce conditions * remove _ prefix on used args; fix typo * Make Valid Header Version dependant on ChainType * Rustfmt * Add tests, uncomment header v2 * Rustfmt * Add FLOONET_FIRST_HARD_FORK height and simplify logic * assume floonet stays closer to avg 60s block time * move floonet hf forward by half a day * update version in new block when previous no longer valid * my next commit:-) * micro optimization * Support new Bulletproof rewind scheme (#2848) * Update keychain with new rewind scheme * Refactor: proof builder trait * Update tests, cleanup * rustfmt * Move conversion of SwitchCommitmentType * Add proof build trait to tx builders * Cache hashes in proof builders * Proof builder tests * Add ViewKey struct * Fix some warnings * Zeroize proof builder secrets on drop * Modify mine_block to use wallet V2 API (#2892) * update mine_block to use V2 wallet API * rustfmt * Add version endpoint to node API, rename pool/push (#2897) * add node version API, tweak pool/push parameter * rustfmt * Upate version api call (#2899) * Update version number for next (potential) release * zeroize: Upgrade to v0.9 (#2914) * zeroize: Upgrade to v0.9 * missed Cargo.lock * [PENDING APPROVAL] put phase outs of C32 and beyond on hold (#2714) * put phase outs of C32 and beyond on hold * update tests for phaseouts on hold * Don't wait for p2p-server thread (#2917) Currently p2p.stop() stops and wait for all peers to exit, that's basically all we need. However we also run a TCP listener in this thread which is blocked on `accept` most of the time. We do an attempt to stop it but it would work only if we get an incoming connection during the shutdown, which is a week guarantee. This fix remove joining to p2p-server thread, it stops all peers and makes an attempt to stop the listener. Fixes [#2906] * rustfmt
196 lines
5.4 KiB
Rust
196 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_FLOO_NS: [u8;4] = [0x03, 0x27, 0x3E, 0x4B];
|
|
const VERSION_FLOO: [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 floonet or not
|
|
pub is_floo: 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_floo: 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_floo,
|
|
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.clone();
|
|
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_floo: self.is_floo,
|
|
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])
|
|
}
|
|
}
|