1use crate::blake2::blake2b::blake2b;
17use byteorder::{BigEndian, ByteOrder};
18use super::extkey_bip32::{
20 BIP32Hasher, ChainCode, ChildNumber, Error as BIP32Error, ExtendedPrivKey, ExtendedPubKey,
21 Fingerprint,
22};
23use super::types::{Error, Keychain};
24use crate::util::secp::constants::GENERATOR_PUB_J_RAW;
25use crate::util::secp::ffi;
26use crate::util::secp::key::{PublicKey, SecretKey};
27use crate::util::secp::Secp256k1;
28use crate::SwitchCommitmentType;
29
30#[derive(Clone, PartialEq, Eq, Debug)]
39pub struct ViewKey {
40 pub is_floo: bool,
42 pub depth: u8,
44 parent_fingerprint: Fingerprint,
46 pub child_number: ChildNumber,
48 public_key: PublicKey,
50 switch_public_key: Option<PublicKey>,
52 chain_code: ChainCode,
54 pub rewind_hash: Vec<u8>,
56}
57
58impl ViewKey {
59 pub fn create<K, H>(
60 keychain: &K,
61 ext_key: ExtendedPrivKey,
62 hasher: &mut H,
63 is_floo: bool,
64 ) -> Result<Self, Error>
65 where
66 K: Keychain,
67 H: BIP32Hasher,
68 {
69 let secp = keychain.secp();
70
71 let ExtendedPubKey {
72 network: _,
73 depth,
74 parent_fingerprint,
75 child_number,
76 public_key,
77 chain_code,
78 } = ExtendedPubKey::from_private(secp, &ext_key, hasher);
79
80 let mut switch_public_key = PublicKey(ffi::PublicKey(GENERATOR_PUB_J_RAW));
81 switch_public_key.mul_assign(secp, &ext_key.secret_key)?;
82 let switch_public_key = Some(switch_public_key);
83
84 let rewind_hash = Self::rewind_hash(secp, keychain.public_root_key());
85
86 Ok(Self {
87 is_floo,
88 depth,
89 parent_fingerprint,
90 child_number,
91 public_key,
92 switch_public_key,
93 chain_code,
94 rewind_hash,
95 })
96 }
97
98 pub fn rewind_hash(secp: &Secp256k1, public_root_key: PublicKey) -> Vec<u8> {
99 let ser = public_root_key.serialize_vec(secp, true);
100 blake2b(32, &[], &ser[..]).as_bytes().to_vec()
101 }
102
103 fn ckd_pub_tweak<H>(
104 &self,
105 secp: &Secp256k1,
106 hasher: &mut H,
107 i: ChildNumber,
108 ) -> Result<(SecretKey, ChainCode), Error>
109 where
110 H: BIP32Hasher,
111 {
112 match i {
113 ChildNumber::Hardened { .. } => Err(BIP32Error::CannotDeriveFromHardenedKey.into()),
114 ChildNumber::Normal { index: n } => {
115 hasher.init_sha512(&self.chain_code[..]);
116 hasher.append_sha512(&self.public_key.serialize_vec(secp, true)[..]);
117 let mut be_n = [0; 4];
118 BigEndian::write_u32(&mut be_n, n);
119 hasher.append_sha512(&be_n);
120
121 let result = hasher.result_sha512();
122
123 let secret_key = SecretKey::from_slice(secp, &result[..32])?;
124 let chain_code = ChainCode::from(&result[32..]);
125 Ok((secret_key, chain_code))
126 }
127 }
128 }
129
130 pub fn ckd_pub<H>(
131 &self,
132 secp: &Secp256k1,
133 hasher: &mut H,
134 i: ChildNumber,
135 ) -> Result<Self, Error>
136 where
137 H: BIP32Hasher,
138 {
139 let (secret_key, chain_code) = self.ckd_pub_tweak(secp, hasher, i)?;
140
141 let mut public_key = self.public_key;
142 public_key.add_exp_assign(secp, &secret_key)?;
143
144 let switch_public_key = match &self.switch_public_key {
145 Some(p) => {
146 let mut j = PublicKey(ffi::PublicKey(GENERATOR_PUB_J_RAW));
147 j.mul_assign(secp, &secret_key)?;
148 Some(PublicKey::from_combination(secp, vec![p, &j])?)
149 }
150 None => None,
151 };
152
153 Ok(Self {
154 is_floo: self.is_floo,
155 depth: self.depth + 1,
156 parent_fingerprint: self.fingerprint(secp, hasher),
157 child_number: i,
158 public_key,
159 switch_public_key,
160 chain_code,
161 rewind_hash: self.rewind_hash.clone(),
162 })
163 }
164
165 pub fn commit(
166 &self,
167 secp: &Secp256k1,
168 amount: u64,
169 switch: SwitchCommitmentType,
170 ) -> Result<PublicKey, Error> {
171 let value_key = secp.commit_value(amount)?.to_pubkey(secp)?;
172 let pub_key = PublicKey::from_combination(secp, vec![&self.public_key, &value_key])?;
173 match switch {
174 SwitchCommitmentType::None => Ok(pub_key),
175 SwitchCommitmentType::Regular => {
176 Err(Error::SwitchCommitment)
192 }
193 }
194 }
195
196 fn identifier<H>(&self, secp: &Secp256k1, hasher: &mut H) -> [u8; 20]
197 where
198 H: BIP32Hasher,
199 {
200 let sha2_res = hasher.sha_256(&self.public_key.serialize_vec(secp, true)[..]);
201 hasher.ripemd_160(&sha2_res)
202 }
203
204 fn fingerprint<H>(&self, secp: &Secp256k1, hasher: &mut H) -> Fingerprint
205 where
206 H: BIP32Hasher,
207 {
208 Fingerprint::from(&self.identifier(secp, hasher)[0..4])
209 }
210}