Skip to main content

cashweb_bitcoin/
bip32.rs

1//! This module contains the [`ExtendedPublicKey`] and [`ExtendedPrivateKey`] structs which allow
2//! interaction with [`Hierarchical Deterministic Wallets`].
3//!
4//! [`Hierarchical Deterministic Wallets`]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
5
6use std::convert::TryInto;
7
8use ring::hmac::{sign as hmac, Key as HmacKey, HMAC_SHA512};
9pub use secp256k1::{Error as SecpError, PublicKey, Secp256k1, SecretKey as PrivateKey};
10use thiserror::Error;
11
12/// Error associated with child number construction.
13#[derive(Debug, Error)]
14#[error("index error: {0}")]
15pub struct IndexError(u32);
16
17/// Public key to public key derivation can not be performed for a hardened key.
18#[derive(Debug, Error)]
19#[error("hardened derivation error")]
20pub struct HardenedDeriveError;
21
22/// Represents a child number.
23#[derive(Clone, Copy, Debug)]
24pub enum ChildNumber {
25    /// A "normal" child number is within range [0, 2^31 - 1]
26    Normal(u32),
27    /// A "hardened" child number is within range [0, 2^31 - 1]
28    Hardened(u32),
29}
30
31/// Error associated with the derivation of a [`ExtendedPublicKey`].
32#[derive(Debug, Error)]
33pub enum DeriveError {
34    /// Public key to public key derivation can not be performed for a hardened key.
35    #[error("hardened derivation error")]
36    HardenedDeriveError,
37    /// Invalid Tweak.
38    #[error(transparent)]
39    InvalidTweak(SecpError),
40}
41
42impl ChildNumber {
43    /// Create a [`ChildNumber::Normal`] from an index, returns an error if the index is not within
44    /// [0, 2^31).
45    pub fn from_normal_index(index: u32) -> Result<Self, IndexError> {
46        if index & (1 << 31) == 0 {
47            Ok(ChildNumber::Normal(index))
48        } else {
49            Err(IndexError(index))
50        }
51    }
52
53    /// Create a [`ChildNumber::Hardened`] from an index, returns an error if the index is not within
54    /// [0, 2^31).
55    pub fn from_hardened_index(index: u32) -> Result<Self, IndexError> {
56        if index & (1 << 31) == 0 {
57            Ok(ChildNumber::Hardened(index))
58        } else {
59            Err(IndexError(index))
60        }
61    }
62}
63
64impl From<u32> for ChildNumber {
65    fn from(number: u32) -> Self {
66        if number & (1 << 31) != 0 {
67            ChildNumber::Hardened(number ^ (1 << 31))
68        } else {
69            ChildNumber::Normal(number)
70        }
71    }
72}
73
74/// A wrapper around [`PublicKey`] to allow [`Hierarchical Deterministic Wallets`] public key derivation.
75///
76/// [`Hierarchical Deterministic Wallets`]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
77#[derive(Debug, Copy, Clone, PartialEq, Eq)]
78pub struct ExtendedPublicKey {
79    public_key: PublicKey,
80    chain_code: [u8; 32],
81}
82
83impl ExtendedPublicKey {
84    /// Construct a new master public key.
85    pub fn new_master(public_key: PublicKey, chain_code: [u8; 32]) -> Self {
86        Self {
87            public_key,
88            chain_code,
89        }
90    }
91
92    /// Get the underlying [`PublicKey`].
93    pub fn get_public_key(&self) -> &PublicKey {
94        &self.public_key
95    }
96
97    /// Convert into the underlying [`PublicKey`].
98    pub fn into_public_key(self) -> PublicKey {
99        self.public_key
100    }
101
102    /// Convert into the [`PublicKey`] and chain code.
103    pub fn as_parts(&self) -> (PublicKey, [u8; 32]) {
104        (self.public_key, self.chain_code)
105    }
106
107    /// Convert into the [`PublicKey`] and chain code.
108    pub fn into_parts(self) -> (PublicKey, [u8; 32]) {
109        (self.public_key, self.chain_code)
110    }
111
112    /// Attempts to derive an [`ExtendedPublicKey`] from a path.
113    ///
114    /// The `path` must consist of an iterable collection of [`ChildNumber`]s.
115    pub fn derive_public_path<C: secp256k1::Verification, P>(
116        &self,
117        secp: &Secp256k1<C>,
118        path: &P,
119    ) -> Result<ExtendedPublicKey, DeriveError>
120    where
121        for<'a> &'a P: IntoIterator<Item = &'a ChildNumber>,
122    {
123        let mut path_iter = path.into_iter();
124        let mut public_key = if let Some(num) = path_iter.next() {
125            self.derive_public_child(secp, *num)?
126        } else {
127            return Ok(*self);
128        };
129        for num in path_iter {
130            public_key = public_key.derive_public_child(secp, *num)?
131        }
132        Ok(public_key)
133    }
134
135    /// Derive the child [`ExtendedPublicKey`] from a [`ChildNumber`].
136    pub fn derive_public_child<C: secp256k1::Verification>(
137        &self,
138        secp: &Secp256k1<C>,
139        child_number: ChildNumber,
140    ) -> Result<ExtendedPublicKey, DeriveError> {
141        let index = match child_number {
142            ChildNumber::Hardened(_) => return Err(DeriveError::HardenedDeriveError),
143            ChildNumber::Normal(index) => index,
144        };
145        let key = HmacKey::new(HMAC_SHA512, &self.chain_code);
146        let data = [&self.public_key.serialize()[..], &index.to_be_bytes()[..]].concat();
147        let hmac_result = hmac(&key, &data);
148
149        let private_key = PrivateKey::from_slice(&hmac_result.as_ref()[..32]).unwrap(); // This is safe
150        let chain_code: [u8; 32] = hmac_result.as_ref()[32..].try_into().unwrap(); // This is safe
151        let mut public_key = self.public_key;
152        public_key
153            .add_exp_assign(secp, &private_key[..])
154            .map_err(DeriveError::InvalidTweak)?;
155
156        Ok(ExtendedPublicKey {
157            public_key,
158            chain_code,
159        })
160    }
161}
162
163/// A wrapper around [`PrivateKey`] to allow [`Hierarchical Deterministic Wallets`] public key derivation.
164///
165/// [`Hierarchical Deterministic Wallets`]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
166#[derive(Debug, Copy, Clone, PartialEq, Eq)]
167pub struct ExtendedPrivateKey {
168    private_key: PrivateKey,
169    chain_code: [u8; 32],
170}
171
172impl ExtendedPrivateKey {
173    /// Construct a new master private key.
174    pub fn new_master(private_key: PrivateKey, chain_code: [u8; 32]) -> Self {
175        ExtendedPrivateKey {
176            private_key,
177            chain_code,
178        }
179    }
180
181    /// Get the underlying [`PrivateKey`].
182    pub fn get_private_key(&self) -> &PrivateKey {
183        &self.private_key
184    }
185
186    /// Convert into the underlying [`PrivateKey`].
187    pub fn into_private_key(self) -> PrivateKey {
188        self.private_key
189    }
190
191    /// Convert into the [`PrivateKey`] and chain code.
192    pub fn into_parts(self) -> (PrivateKey, [u8; 32]) {
193        (self.private_key, self.chain_code)
194    }
195
196    /// Derive an child [`ExtendedPrivateKey`] from a path.
197    ///
198    /// The `path` must consist of an iterable collection of [`ChildNumber`]s.
199    pub fn derive_private_path<C: secp256k1::Signing, P>(
200        &self,
201        secp: &Secp256k1<C>,
202        path: &P,
203    ) -> ExtendedPrivateKey
204    where
205        for<'a> &'a P: IntoIterator<Item = &'a ChildNumber>,
206    {
207        let mut path_iter = path.into_iter();
208        let mut private_key = if let Some(num) = path_iter.next() {
209            self.derive_private_child(secp, *num)
210        } else {
211            return *self;
212        };
213        for num in path_iter {
214            private_key = private_key.derive_private_child(secp, *num);
215        }
216        private_key
217    }
218
219    /// Derive child [`ExtendedPrivateKey`].
220    pub fn derive_private_child<C: secp256k1::Signing>(
221        &self,
222        secp: &Secp256k1<C>,
223        child_number: ChildNumber,
224    ) -> ExtendedPrivateKey {
225        // Calculate HMAC
226        let key = HmacKey::new(HMAC_SHA512, &self.chain_code);
227        let hmac_result = match child_number {
228            ChildNumber::Normal(index) => {
229                // Non-hardened key: compute public data and use that
230                let raw_public_key =
231                    PublicKey::from_secret_key(secp, &self.private_key).serialize();
232                let data = [&raw_public_key[..], &index.to_be_bytes()].concat();
233                hmac(&key, &data)
234            }
235            ChildNumber::Hardened(index) => {
236                // Hardened key: use only secret data to prevent public derivation
237                let data = [&[0], &self.private_key[..], &index.to_be_bytes()].concat();
238                hmac(&key, &data)
239            }
240        };
241
242        // Construct new private key
243        let mut private_key = PrivateKey::from_slice(&hmac_result.as_ref()[..32]).unwrap(); // This is safe
244        private_key.add_assign(&self.private_key[..]).unwrap(); // This is safe
245
246        // Construct new extended private key
247        let chain_code = hmac_result.as_ref()[32..].try_into().unwrap(); // This is safe
248        ExtendedPrivateKey {
249            private_key,
250            chain_code,
251        }
252    }
253}
254
255#[cfg(test)]
256mod tests {
257    use super::*;
258    use rand::thread_rng;
259    use secp256k1::Secp256k1;
260
261    #[test]
262    fn child_derivation() {
263        let secp = Secp256k1::new();
264        let mut rng = thread_rng();
265        let private_key = PrivateKey::new(&mut rng);
266        let public_key = PublicKey::from_secret_key(&secp, &private_key);
267        let hd_private_key = ExtendedPrivateKey::new_master(private_key, [0; 32]);
268        let hd_public_key = ExtendedPublicKey::new_master(public_key, [0; 32]);
269
270        let new_hd_private_key =
271            hd_private_key.derive_private_child(&secp, ChildNumber::Normal(32));
272        let new_hd_public_key = hd_public_key
273            .derive_public_child(&secp, ChildNumber::Normal(32))
274            .unwrap();
275
276        assert_eq!(
277            PublicKey::from_secret_key(&secp, &new_hd_private_key.into_private_key()),
278            new_hd_public_key.into_public_key()
279        );
280    }
281
282    #[test]
283    fn child_derivation_normal_path_a() {
284        let secp = Secp256k1::new();
285        let mut rng = thread_rng();
286
287        let path = [ChildNumber::Normal(32), ChildNumber::Normal(4)];
288
289        let private_key = PrivateKey::new(&mut rng);
290        let public_key = PublicKey::from_secret_key(&secp, &private_key);
291        let hd_private_key = ExtendedPrivateKey::new_master(private_key, [0; 32]);
292        let hd_public_key = ExtendedPublicKey::new_master(public_key, [0; 32]);
293
294        let new_hd_private_key = hd_private_key.derive_private_path(&secp, &path);
295        let new_hd_public_key = hd_public_key.derive_public_path(&secp, &path).unwrap();
296
297        assert_eq!(
298            PublicKey::from_secret_key(&secp, &new_hd_private_key.into_private_key()),
299            new_hd_public_key.into_public_key()
300        );
301    }
302
303    #[test]
304    fn child_derivation_normal_path_b() {
305        let secp = Secp256k1::new();
306        let mut rng = thread_rng();
307
308        let path = [
309            ChildNumber::Normal(32),
310            ChildNumber::Normal(4),
311            ChildNumber::Normal(54),
312        ];
313
314        let private_key = PrivateKey::new(&mut rng);
315        let hd_private_key = ExtendedPrivateKey::new_master(private_key, [0; 32]);
316
317        let hd_private_key_a = hd_private_key.derive_private_path(&secp, &path);
318        let hd_private_key_b = hd_private_key
319            .derive_private_child(&secp, path[0])
320            .derive_private_child(&secp, path[1])
321            .derive_private_child(&secp, path[2]);
322
323        assert_eq!(hd_private_key_a, hd_private_key_b);
324    }
325}