mwc_keychain/
view_key.rs

1// Copyright 2019 The Grin Developers
2// Copyright 2024 The MWC Developers
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::blake2::blake2b::blake2b;
17use byteorder::{BigEndian, ByteOrder};
18//use crate::sha2::{Digest, Sha256};
19use 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/*const VERSION_FLOO_NS: [u8;4] = [0x03, 0x27, 0x3E, 0x4B];
31const VERSION_FLOO: [u8;4]    = [0x03, 0x27, 0x3E, 0x4B];
32const VERSION_MAIN_NS: [u8;4] = [0x03, 0x3C, 0x08, 0xDF];
33const VERSION_MAIN: [u8;4]    = [0x03, 0x3C, 0x08, 0xDF];*/
34
35/// Key that can be used to scan the chain for owned outputs
36/// This is a public key, meaning it cannot be used to spend those outputs
37/// At the moment only depth 0 keys can be used
38#[derive(Clone, PartialEq, Eq, Debug)]
39pub struct ViewKey {
40	/// Whether this view key is meant for floonet or not
41	pub is_floo: bool,
42	/// How many derivations this key is from the master (which is 0)
43	pub depth: u8,
44	/// Fingerprint of the parent key
45	parent_fingerprint: Fingerprint,
46	/// Child number of the key used to derive from parent (0 for master)
47	pub child_number: ChildNumber,
48	/// Public key
49	public_key: PublicKey,
50	/// Switch public key, required to view outputs that use switch commitment
51	switch_public_key: Option<PublicKey>,
52	/// Chain code
53	chain_code: ChainCode,
54	/// Hash used to generate rewind nonce
55	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				// TODO: replace this whole block by a libsecp function
177				/*let switch_pub = self.switch_public_key.ok_or(Error::SwitchCommitment)?;
178				let switch_ser: Vec<u8> = switch_pub.serialize_vec(secp, true)[..].to_vec();
179
180				let mut commit_ser: Vec<u8> = pub_key.serialize_vec(secp, true)[..].to_vec();
181				commit_ser[0] += 6; // This only works sometimes
182
183				let mut hasher = Sha256::new();
184				hasher.input(&commit_ser);
185				hasher.input(&switch_ser);
186				let blind = SecretKey::from_slice(secp, &hasher.result()[..])?;
187				let mut pub_key = pub_key;
188				pub_key.add_exp_assign(secp, &blind)?;
189
190				Ok(pub_key)*/
191				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}