ed25519_bip32/
key.rs

1use std::fmt;
2
3use cryptoxide::constant_time::CtEqual;
4use cryptoxide::ed25519;
5use cryptoxide::ed25519::signature_extended;
6use cryptoxide::hashing::sha2::Sha512;
7
8use std::convert::{TryFrom, TryInto};
9use std::error::Error;
10use std::hash::{Hash, Hasher};
11
12use super::derivation::{self, DerivationError, DerivationIndex, DerivationScheme};
13use super::hex;
14use super::securemem;
15use super::signature::Signature;
16
17/// Extended Private key size in bytes
18pub const XPRV_SIZE: usize = 96;
19pub const EXTENDED_SECRET_KEY_SIZE: usize = 64;
20
21/// Extended Public key size in bytes
22pub const XPUB_SIZE: usize = 64;
23pub const PUBLIC_KEY_SIZE: usize = 32;
24pub const CHAIN_CODE_SIZE: usize = 32;
25
26/// Possible errors during conversion from bytes
27///
28/// HighestBitsInvalid and LowestBitsInvalid are errors
29/// reported linked to the shape of a normal extended ed25519 key.
30///
31#[derive(Debug, PartialEq, Eq)]
32pub enum PrivateKeyError {
33    LengthInvalid(usize),
34    HighestBitsInvalid,
35    LowestBitsInvalid,
36}
37
38/// Possible errors during conversion from bytes
39#[derive(Debug)]
40pub enum PublicKeyError {
41    LengthInvalid(usize),
42}
43
44/// HDWallet extended private key
45///
46/// Effectively this is an ed25519 extended secret key (64 bytes) followed by a chain code (32 bytes).
47///
48pub struct XPrv([u8; XPRV_SIZE]);
49impl XPrv {
50    /// takes the given raw bytes and perform some modifications to normalize
51    /// to a valid Ed25519 extended key, but it does also force
52    /// the 3rd highest bit to be cleared too.
53    pub fn normalize_bytes_force3rd(mut bytes: [u8; XPRV_SIZE]) -> Self {
54        bytes[0] &= 0b1111_1000;
55        bytes[31] &= 0b0001_1111;
56        bytes[31] |= 0b0100_0000;
57
58        Self::from_bytes(bytes)
59    }
60
61    /// Takes the given raw bytes and perform some modifications to normalize
62    /// to a valid Ed25519 extended key. It doesn't touch the 3rd highest bit
63    /// as expected in the ed25519-bip32 paper.
64    pub fn normalize_bytes_ed25519(mut bytes: [u8; XPRV_SIZE]) -> Self {
65        bytes[0] &= 0b1111_1000;
66        bytes[31] &= 0b0011_1111;
67        bytes[31] |= 0b0100_0000;
68
69        Self::from_bytes(bytes)
70    }
71
72    /// Check if the 3rd highest bit is clear as expected from the paper
73    pub fn is_3rd_highest_bit_clear(&self) -> bool {
74        (self.0[31] & 0b0010_0000) == 0
75    }
76
77    /// Clear the 3rd highest bit as expected from the paper setting
78    pub fn clear_3rd_highest_bit(mut self) -> Self {
79        self.0[31] &= 0b1101_1111;
80        self
81    }
82
83    /// Takes a non-extended Ed25519 secret key and hash through SHA512 it in the same way the standard
84    /// Ed25519 signature system make extended key, but *also* force clear the 3rd highest bit of the key
85    /// instead of returning an error
86    pub fn from_nonextended_force(bytes: &[u8; 32], chain_code: &[u8; CHAIN_CODE_SIZE]) -> Self {
87        let mut extended_out = [0u8; XPRV_SIZE];
88        extended_out[0..64].copy_from_slice(&Sha512::new().update(bytes).finalize());
89        extended_out[64..96].clone_from_slice(chain_code);
90        Self::normalize_bytes_force3rd(extended_out)
91    }
92
93    /// Takes a non-extended Ed25519 secret key and hash through SHA512 it in the same way the standard
94    /// Ed25519 signature system make extended key. If the 3rd highest bit is set, then return an error
95    ///
96    /// bip32-ed25519 paper:
97    ///
98    /// > "2) We admit only those ~k such that the third highest bit of the last byte of kL is zero."
99    pub fn from_nonextended_noforce(
100        bytes: &[u8; 32],
101        chain_code: &[u8; CHAIN_CODE_SIZE],
102    ) -> Result<Self, ()> {
103        let mut extended_out = [0u8; XPRV_SIZE];
104        extended_out[0..64].copy_from_slice(&Sha512::new().update(bytes).finalize());
105        extended_out[64..96].clone_from_slice(chain_code);
106        let xprv = Self::normalize_bytes_ed25519(extended_out);
107        if xprv.is_3rd_highest_bit_clear() {
108            Ok(xprv)
109        } else {
110            Err(())
111        }
112    }
113
114    /// create a `XPrv` by its components (a 64 bytes extended secret key, and a 32 bytes chain code)
115    ///
116    /// No verification is done on the extended secret key
117    pub fn from_extended_and_chaincode(
118        sk: &[u8; EXTENDED_SECRET_KEY_SIZE],
119        chain_code: &[u8; CHAIN_CODE_SIZE],
120    ) -> Self {
121        let mut buf = [0u8; XPRV_SIZE];
122        buf[0..64].copy_from_slice(sk);
123        buf[64..96].copy_from_slice(chain_code);
124        Self::from_bytes(buf)
125    }
126
127    // Create a XPrv from the given bytes.
128    //
129    // This function does not perform any validity check and should not be used outside
130    // of this crate.
131    pub(crate) fn from_bytes(bytes: [u8; XPRV_SIZE]) -> Self {
132        XPrv(bytes)
133    }
134
135    /// Create a `XPrv` by taking ownership of the given array
136    ///
137    /// This function may returns an error if it does not have the expected
138    /// format.
139    ///
140    /// This function allow the 3rd highest bit to not be clear (to handle potential derived valid xprv),
141    /// but self.is_3rd_highest_bit_clear() can be called to check if the 3rd highest bit
142    /// is assumed to be clear or not.
143    pub fn from_bytes_verified(bytes: [u8; XPRV_SIZE]) -> Result<Self, PrivateKeyError> {
144        let scalar = &bytes[0..32];
145        let last = scalar[31];
146        let first = scalar[0];
147
148        if (last & 0b1100_0000) != 0b0100_0000 {
149            return Err(PrivateKeyError::HighestBitsInvalid);
150        }
151        if (first & 0b0000_0111) != 0b0000_0000 {
152            return Err(PrivateKeyError::LowestBitsInvalid);
153        }
154
155        Ok(XPrv(bytes))
156    }
157
158    pub fn from_slice_verified(bytes: &[u8]) -> Result<Self, PrivateKeyError> {
159        if bytes.len() != XPRV_SIZE {
160            return Err(PrivateKeyError::LengthInvalid(bytes.len()));
161        }
162
163        let mut buf = [0u8; XPRV_SIZE];
164        buf[..].clone_from_slice(bytes);
165        XPrv::from_bytes_verified(buf)
166    }
167
168    /// Create a `XPrv` from the given slice. This slice must be of size `XPRV_SIZE`
169    /// otherwise it will return `Err`.
170    ///
171    fn from_slice(bytes: &[u8]) -> Result<Self, PrivateKeyError> {
172        if bytes.len() != XPRV_SIZE {
173            return Err(PrivateKeyError::LengthInvalid(bytes.len()));
174        }
175        let mut buf = [0u8; XPRV_SIZE];
176        buf[..].clone_from_slice(bytes);
177        Ok(XPrv::from_bytes(buf))
178    }
179
180    /// Get the associated `XPub`
181    ///
182    pub fn public(&self) -> XPub {
183        let pk = mk_public_key(self.extended_secret_key_bytes());
184        let mut out = [0u8; XPUB_SIZE];
185        out[0..32].clone_from_slice(&pk);
186        out[32..64].clone_from_slice(&self.as_ref()[64..]);
187        XPub::from_bytes(out)
188    }
189
190    /// sign the given message with the `XPrv`.
191    ///
192    pub fn sign<T>(&self, message: &[u8]) -> Signature<T> {
193        let extended_key = <&[u8; 64]>::try_from(&self.0[0..64]).unwrap();
194        Signature::from_bytes(signature_extended(message, extended_key))
195    }
196
197    /// verify a given signature
198    ///
199    pub fn verify<T>(&self, message: &[u8], signature: &Signature<T>) -> bool {
200        let xpub = self.public();
201        xpub.verify(message, signature)
202    }
203
204    pub fn derive(&self, scheme: DerivationScheme, index: DerivationIndex) -> Self {
205        derivation::private(self, index, scheme)
206    }
207
208    pub fn get_extended_mut(&self, out: &mut [u8; EXTENDED_SECRET_KEY_SIZE]) {
209        out.clone_from_slice(self.extended_secret_key_slice())
210    }
211
212    pub fn extended_secret_key_bytes(&self) -> &[u8; 64] {
213        self.0[0..EXTENDED_SECRET_KEY_SIZE].try_into().unwrap()
214    }
215
216    pub fn extended_secret_key_slice(&self) -> &[u8] {
217        &self.0[0..EXTENDED_SECRET_KEY_SIZE]
218    }
219
220    pub fn chain_code(&self) -> &[u8; CHAIN_CODE_SIZE] {
221        self.0[64..96].try_into().unwrap()
222    }
223
224    pub fn chain_code_slice(&self) -> &[u8] {
225        &self.0[64..96]
226    }
227
228    pub fn extended_secret_key(&self) -> [u8; EXTENDED_SECRET_KEY_SIZE] {
229        let mut buf = [0u8; EXTENDED_SECRET_KEY_SIZE];
230        buf.copy_from_slice(self.extended_secret_key_slice());
231        buf
232    }
233}
234impl PartialEq for XPrv {
235    fn eq(&self, rhs: &XPrv) -> bool {
236        self.0.ct_eq(&rhs.0).into()
237    }
238}
239impl Eq for XPrv {}
240impl Clone for XPrv {
241    fn clone(&self) -> Self {
242        Self::from_slice(self.as_ref()).expect("it is already a safely constructed XPrv")
243    }
244}
245impl fmt::Debug for XPrv {
246    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
247        write!(f, "{}", hex::encode(self.as_ref()))
248    }
249}
250impl fmt::Display for XPrv {
251    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252        write!(f, "{}", hex::encode(self.as_ref()))
253    }
254}
255impl AsRef<[u8]> for XPrv {
256    fn as_ref(&self) -> &[u8] {
257        &self.0
258    }
259}
260impl From<XPrv> for [u8; XPRV_SIZE] {
261    fn from(v: XPrv) -> [u8; XPRV_SIZE] {
262        v.0
263    }
264}
265impl Drop for XPrv {
266    fn drop(&mut self) {
267        securemem::zero(&mut self.0);
268    }
269}
270
271/// Extended Public Key (Point + ChainCode)
272#[derive(Clone, Copy)]
273pub struct XPub([u8; XPUB_SIZE]);
274impl XPub {
275    /// create a `XPub` by taking ownership of the given array
276    pub fn from_bytes(bytes: [u8; XPUB_SIZE]) -> Self {
277        XPub(bytes)
278    }
279
280    /// create a `XPub` by its components (a 32 bytes public key, and a 32 bytes chain code)
281    pub fn from_pk_and_chaincode(
282        pk: &[u8; PUBLIC_KEY_SIZE],
283        chain_code: &[u8; CHAIN_CODE_SIZE],
284    ) -> Self {
285        let mut buf = [0u8; XPUB_SIZE];
286        buf[0..32].copy_from_slice(pk);
287        buf[32..64].copy_from_slice(chain_code);
288        Self::from_bytes(buf)
289    }
290
291    /// create a `XPub` from the given slice. This slice must be of size `XPUB_SIZE`
292    /// otherwise it will return `Option::None`.
293    ///
294    pub fn from_slice(bytes: &[u8]) -> Result<Self, PublicKeyError> {
295        if bytes.len() != XPUB_SIZE {
296            return Err(PublicKeyError::LengthInvalid(bytes.len()));
297        }
298        let mut buf = [0u8; XPUB_SIZE];
299        buf[..].clone_from_slice(bytes);
300        Ok(Self::from_bytes(buf))
301    }
302
303    /// verify a signature
304    ///
305    pub fn verify<T>(&self, message: &[u8], signature: &Signature<T>) -> bool {
306        ed25519::verify(
307            message,
308            &self.0[0..32].try_into().unwrap(),
309            signature.to_bytes(),
310        )
311    }
312
313    pub fn derive(
314        &self,
315        scheme: DerivationScheme,
316        index: DerivationIndex,
317    ) -> Result<Self, DerivationError> {
318        derivation::public(self, index, scheme)
319    }
320
321    pub fn get_without_chaincode(&self, out: &mut [u8; 32]) {
322        out.clone_from_slice(&self.0[0..32])
323    }
324
325    pub fn public_key_bytes(&self) -> &[u8; 32] {
326        <&[u8; 32]>::try_from(&self.0[0..32]).unwrap()
327    }
328
329    pub fn public_key_slice(&self) -> &[u8] {
330        &self.0[0..32]
331    }
332
333    pub fn chain_code_slice(&self) -> &[u8] {
334        &self.0[32..64]
335    }
336
337    pub fn public_key(&self) -> [u8; PUBLIC_KEY_SIZE] {
338        let mut buf = [0u8; PUBLIC_KEY_SIZE];
339        buf.copy_from_slice(self.public_key_slice());
340        buf
341    }
342
343    pub fn chain_code(&self) -> &[u8; CHAIN_CODE_SIZE] {
344        (&self.0[32..64]).try_into().unwrap()
345    }
346}
347impl PartialEq for XPub {
348    fn eq(&self, rhs: &XPub) -> bool {
349        self.0.ct_eq(&rhs.0).into()
350    }
351}
352impl Eq for XPub {}
353impl Hash for XPub {
354    fn hash<H: Hasher>(&self, state: &mut H) {
355        state.write(&self.0)
356    }
357}
358impl fmt::Display for XPub {
359    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
360        write!(f, "{}", hex::encode(self.as_ref()))
361    }
362}
363impl fmt::Debug for XPub {
364    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
365        write!(f, "{}", hex::encode(self.as_ref()))
366    }
367}
368impl AsRef<[u8]> for XPub {
369    fn as_ref(&self) -> &[u8] {
370        &self.0
371    }
372}
373impl From<XPub> for [u8; XPUB_SIZE] {
374    fn from(v: XPub) -> [u8; XPUB_SIZE] {
375        v.0
376    }
377}
378
379impl fmt::Display for PublicKeyError {
380    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
381        match self {
382            PublicKeyError::LengthInvalid(length) => write!(
383                f,
384                "Invalid public key length, expected {} but received {}",
385                XPUB_SIZE, length
386            ),
387        }
388    }
389}
390impl Error for PublicKeyError {}
391
392impl fmt::Display for PrivateKeyError {
393    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394        match self {
395            PrivateKeyError::LengthInvalid(length) => write!(
396                f,
397                "Invalid private key length, expected {} but received {}",
398                XPRV_SIZE, length
399            ),
400            PrivateKeyError::HighestBitsInvalid => f.write_str("Invalid highest bits"),
401            PrivateKeyError::LowestBitsInvalid => f.write_str("Invalid lowest bits"),
402        }
403    }
404}
405impl Error for PrivateKeyError {}
406
407pub(crate) fn mk_xprv(out: &mut [u8; XPRV_SIZE], kl: &[u8], kr: &[u8], cc: &[u8]) {
408    assert!(kl.len() == 32);
409    assert!(kr.len() == 32);
410    assert!(cc.len() == CHAIN_CODE_SIZE);
411
412    out[0..32].clone_from_slice(kl);
413    out[32..64].clone_from_slice(kr);
414    out[64..96].clone_from_slice(cc);
415}
416
417pub(crate) fn mk_xpub(out: &mut [u8; XPUB_SIZE], pk: &[u8], cc: &[u8]) {
418    assert!(pk.len() == 32);
419    assert!(cc.len() == CHAIN_CODE_SIZE);
420
421    out[0..32].clone_from_slice(pk);
422    out[32..64].clone_from_slice(cc);
423}
424
425pub fn mk_public_key(extended_secret: &[u8; 64]) -> [u8; PUBLIC_KEY_SIZE] {
426    ed25519::extended_to_public(extended_secret)
427}