1#![allow(clippy::from_over_into)]
5
6use alloc::vec::Vec;
7use core::convert::TryFrom;
8use core::fmt;
9
10use zeroize::{Zeroize, ZeroizeOnDrop};
11
12use crate::macs::hmac::HMAC_SHA512;
13
14mod hazmat {
25 use super::Segment;
26
27 pub trait Sealed {}
29 pub trait Derivable: Sealed {
31 fn is_key_valid(key_bytes: &[u8; 33]) -> bool;
32 fn to_key(key_bytes: &[u8; 33]) -> Self;
33 fn add_key(key_bytes: &mut [u8; 33], parent_key: &[u8; 33]) -> bool;
34 }
35 pub trait IsSecretKey: Derivable {
37 const SEEDKEY: &'static [u8];
38 type PublicKey;
40 }
41 pub trait IsPublicKey: Derivable {
43 type SecretKey: IsSecretKey;
45 }
46 pub trait ToPublic: IsSecretKey {
50 fn to_public(sk_bytes: &[u8; 33]) -> [u8; 33];
51 }
52 pub trait WithSegment<S: Segment>: Sealed {
54 fn calc_data(key_bytes: &[u8; 33], segment: S) -> [u8; 33];
55 }
56 pub trait ToChain<C> {
58 type Chain;
59 fn to_chain(pre_chain: &C) -> Self::Chain;
60 }
61}
62
63pub use hazmat::{Derivable, IsPublicKey, IsSecretKey, ToChain, ToPublic, WithSegment};
64
65#[cfg(feature = "ed25519")]
66pub mod ed25519 {
67 use super::{hazmat::*, Hardened};
68 use crate::signatures::ed25519;
69
70 impl Sealed for ed25519::SecretKey {}
71
72 impl Derivable for ed25519::SecretKey {
73 fn is_key_valid(key_bytes: &[u8; 33]) -> bool {
74 key_bytes[0] == 0
75 }
76 fn to_key(key_bytes: &[u8; 33]) -> Self {
77 debug_assert_eq!(0, key_bytes[0]);
78 let sk_bytes: &[u8; 32] = unsafe { &*(key_bytes[1..].as_ptr() as *const [u8; 32]) };
79 ed25519::SecretKey::from_bytes(sk_bytes)
80 }
81 fn add_key(_key_bytes: &mut [u8; 33], _parent_key: &[u8; 33]) -> bool {
82 true
83 }
84 }
85
86 impl IsSecretKey for ed25519::SecretKey {
87 const SEEDKEY: &'static [u8] = b"ed25519 seed";
88 type PublicKey = ed25519::PublicKey;
89 }
90
91 impl WithSegment<Hardened> for ed25519::SecretKey {
92 fn calc_data(key_bytes: &[u8; 33], _segment: Hardened) -> [u8; 33] {
93 *key_bytes
94 }
95 }
96}
97
98#[cfg(feature = "secp256k1")]
99pub mod secp256k1 {
100 use super::{hazmat::*, Hardened, NonHardened, Segment};
101 use crate::signatures::secp256k1_ecdsa;
102
103 impl Sealed for secp256k1_ecdsa::SecretKey {}
104
105 impl Derivable for secp256k1_ecdsa::SecretKey {
106 fn is_key_valid(key_bytes: &[u8; 33]) -> bool {
107 debug_assert_eq!(0, key_bytes[0]);
108 let sk_bytes: &[u8; 32] = unsafe { &*(key_bytes[1..].as_ptr() as *const [u8; 32]) };
109 k256::SecretKey::from_bytes(sk_bytes.into()).is_ok()
110 }
111 fn to_key(key_bytes: &[u8; 33]) -> Self {
112 debug_assert_eq!(0, key_bytes[0]);
113 let sk_bytes: &[u8; 32] = unsafe { &*(key_bytes[1..].as_ptr() as *const [u8; 32]) };
114 secp256k1_ecdsa::SecretKey::try_from_bytes(sk_bytes).expect("valid extended secret key")
115 }
116 fn add_key(key_bytes: &mut [u8; 33], parent_key: &[u8; 33]) -> bool {
117 debug_assert_eq!(0, parent_key[0]);
118 debug_assert_eq!(0, key_bytes[0]);
119 let sk_bytes: &[u8; 32] = unsafe { &*(key_bytes[1..].as_ptr() as *const [u8; 32]) };
120
121 if let Ok(sk_delta) = k256::SecretKey::from_bytes(sk_bytes.into()) {
122 let sk =
123 k256::SecretKey::from_bytes((&parent_key[1..]).into()).expect("valid Secp256k1 parent secret key");
124
125 let scalar_delta = sk_delta.to_nonzero_scalar();
126 let mut scalar = *sk.to_nonzero_scalar().as_ref();
127 scalar += scalar_delta.as_ref();
128
129 if scalar.is_zero().into() {
130 false
131 } else {
132 key_bytes[1..].copy_from_slice(&scalar.to_bytes());
133 true
134 }
135 } else {
136 false
137 }
138 }
139 }
140
141 impl IsSecretKey for secp256k1_ecdsa::SecretKey {
142 const SEEDKEY: &'static [u8] = b"Bitcoin seed";
143 type PublicKey = secp256k1_ecdsa::PublicKey;
144 }
145
146 impl ToPublic for secp256k1_ecdsa::SecretKey {
147 fn to_public(key_bytes: &[u8; 33]) -> [u8; 33] {
148 use k256::elliptic_curve::sec1::ToEncodedPoint;
149 debug_assert_eq!(0, key_bytes[0]);
150 let sk_bytes: &[u8; 32] = unsafe { &*(key_bytes[1..].as_ptr() as *const [u8; 32]) };
151 let sk = k256::SecretKey::from_bytes(sk_bytes.into()).expect("valid Secp256k1 parent secret key");
152 let pk = sk.public_key();
153 let mut pk_bytes = [0_u8; 33];
154 pk_bytes.copy_from_slice(pk.to_encoded_point(true).as_bytes());
155 pk_bytes
156 }
157 }
158
159 impl WithSegment<Hardened> for secp256k1_ecdsa::SecretKey {
160 fn calc_data(key_bytes: &[u8; 33], _segment: Hardened) -> [u8; 33] {
161 *key_bytes
162 }
163 }
164
165 impl WithSegment<NonHardened> for secp256k1_ecdsa::SecretKey {
166 fn calc_data(key_bytes: &[u8; 33], _segment: NonHardened) -> [u8; 33] {
167 Self::to_public(key_bytes)
168 }
169 }
170
171 impl WithSegment<u32> for secp256k1_ecdsa::SecretKey {
172 fn calc_data(key_bytes: &[u8; 33], segment: u32) -> [u8; 33] {
173 if segment.is_hardened() {
174 Self::calc_data(key_bytes, Hardened(segment))
175 } else {
176 Self::calc_data(key_bytes, NonHardened(segment))
177 }
178 }
179 }
180
181 impl Sealed for secp256k1_ecdsa::PublicKey {}
182
183 impl Derivable for secp256k1_ecdsa::PublicKey {
184 fn is_key_valid(key_bytes: &[u8; 33]) -> bool {
185 (key_bytes[0] == 2 || key_bytes[0] == 3) && k256::PublicKey::from_sec1_bytes(key_bytes).is_ok()
186 }
187 fn to_key(key_bytes: &[u8; 33]) -> Self {
188 secp256k1_ecdsa::PublicKey::try_from_bytes(key_bytes)
189 .expect("valid extended public key")
191 }
192 fn add_key(key_bytes: &mut [u8; 33], parent_key: &[u8; 33]) -> bool {
193 use k256::{
194 elliptic_curve::{group::prime::PrimeCurveAffine, sec1::ToEncodedPoint},
195 AffinePoint, ProjectivePoint,
196 };
197 debug_assert_eq!(0, key_bytes[0]);
198 let sk_bytes: &[u8; 32] = unsafe { &*(key_bytes[1..].as_ptr() as *const [u8; 32]) };
199
200 if let Ok(sk_delta) = k256::SecretKey::from_bytes(sk_bytes.into()) {
201 let pk_delta = sk_delta.public_key();
202 let pk_parent =
203 k256::PublicKey::from_sec1_bytes(parent_key).expect("valid Secp256k1 parent public key");
204
205 let mut point: ProjectivePoint = pk_parent.as_affine().into();
206 point += pk_delta.as_affine();
207 let point_sum: AffinePoint = point.into();
208
209 if point_sum.is_identity().into() {
210 false
211 } else {
212 key_bytes.copy_from_slice(point_sum.to_encoded_point(true).as_bytes());
213 true
214 }
215 } else {
216 false
217 }
218 }
219 }
220
221 impl IsPublicKey for secp256k1_ecdsa::PublicKey {
222 type SecretKey = secp256k1_ecdsa::SecretKey;
223 }
224
225 impl WithSegment<NonHardened> for secp256k1_ecdsa::PublicKey {
226 fn calc_data(key_bytes: &[u8; 33], _segment: NonHardened) -> [u8; 33] {
227 *key_bytes
228 }
229 }
230}
231
232#[derive(Zeroize, ZeroizeOnDrop)]
242pub struct Seed(Vec<u8>);
243
244impl Seed {
245 pub fn from_bytes(bs: &[u8]) -> Self {
246 Self(bs.to_vec())
247 }
248
249 pub fn to_master_key<K: hazmat::IsSecretKey>(&self) -> Slip10<K> {
250 Slip10::from_seed(self)
251 }
252
253 pub fn derive<K, I>(&self, chain: I) -> Slip10<K>
254 where
255 K: hazmat::IsSecretKey + hazmat::WithSegment<<I as Iterator>::Item>,
256 I: Iterator,
257 <I as Iterator>::Item: Segment,
258 {
259 self.to_master_key().derive(chain)
260 }
261}
262
263impl fmt::Debug for Seed {
264 #[inline]
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 "<slip10::Seed>".fmt(f)
267 }
268}
269
270impl AsRef<[u8]> for Seed {
271 fn as_ref(&self) -> &[u8] {
272 &self.0
273 }
274}
275
276#[cfg(feature = "bip39")]
277impl From<super::bip39::Seed> for Seed {
278 fn from(seed: super::bip39::Seed) -> Self {
279 Self::from_bytes(seed.as_ref())
280 }
281}
282
283pub type ChainCode = [u8; 32];
285
286#[derive(ZeroizeOnDrop)]
290pub struct Slip10<K> {
291 key: core::marker::PhantomData<K>,
292 ext: [u8; 65],
293}
294
295impl<K> Clone for Slip10<K> {
296 fn clone(&self) -> Self {
297 Self {
298 key: core::marker::PhantomData,
299 ext: self.ext,
300 }
301 }
302}
303
304impl<K> fmt::Debug for Slip10<K> {
305 #[inline]
306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307 write!(f, "<slip10::Slip10<{}>>", core::any::type_name::<K>())
308 }
309}
310
311impl<K> Zeroize for Slip10<K> {
312 fn zeroize(&mut self) {
313 self.ext.zeroize()
314 }
315}
316
317impl<K: hazmat::IsSecretKey> Slip10<K> {
318 pub fn from_seed<S: AsRef<[u8]>>(seed: &S) -> Self {
319 let mut key = Self::new();
320 HMAC_SHA512(seed.as_ref(), K::SEEDKEY, key.ext_mut());
321 while !key.is_key_valid() {
322 let mut tmp = [0_u8; 64];
323 tmp.copy_from_slice(&key.ext[1..]);
324 HMAC_SHA512(&tmp, K::SEEDKEY, key.ext_mut());
325 tmp.zeroize();
326 }
327 key
328 }
329
330 pub fn secret_key(&self) -> K {
331 self.key()
332 }
333
334 pub fn to_extended_public_key(&self) -> Slip10<K::PublicKey>
335 where
336 K::PublicKey: hazmat::IsPublicKey<SecretKey = K>,
337 K: hazmat::ToPublic,
338 {
339 Slip10::from_extended_secret_key(self)
340 }
341}
342
343impl<K: hazmat::IsSecretKey> From<&Seed> for Slip10<K> {
344 fn from(seed: &Seed) -> Self {
345 Self::from_seed(seed)
346 }
347}
348
349impl<K> Slip10<K>
350where
351 K: hazmat::IsPublicKey,
352 K::SecretKey: hazmat::ToPublic,
353{
354 pub fn from_extended_secret_key(esk: &Slip10<K::SecretKey>) -> Self {
355 let mut k = Self::new();
356 k.ext[..33].copy_from_slice(&<K::SecretKey as hazmat::ToPublic>::to_public(esk.key_bytes()));
357 k.ext[33..].copy_from_slice(esk.chain_code());
358 k
359 }
360}
361
362impl<K> From<&Slip10<K::SecretKey>> for Slip10<K>
363where
364 K: hazmat::IsPublicKey,
365 K::SecretKey: hazmat::ToPublic,
366{
367 fn from(esk: &Slip10<K::SecretKey>) -> Self {
368 Self::from_extended_secret_key(esk)
369 }
370}
371
372impl<K: hazmat::IsPublicKey> Slip10<K> {
373 pub fn public_key(&self) -> K {
374 self.key()
375 }
376}
377
378impl<K> Slip10<K> {
379 pub(crate) fn new() -> Self {
380 Self {
381 key: core::marker::PhantomData,
382 ext: [0_u8; 65],
383 }
384 }
385}
386
387impl<K> Slip10<K> {
388 pub fn extended_bytes(&self) -> &[u8; 65] {
389 &self.ext
390 }
391
392 pub fn chain_code(&self) -> &[u8; 32] {
393 unsafe { &*(self.ext[33..].as_ptr() as *const [u8; 32]) }
394 }
395}
396
397impl<K: hazmat::Derivable> Slip10<K> {
398 fn key(&self) -> K {
399 K::to_key(self.key_bytes())
400 }
401
402 pub fn try_from_extended_bytes(ext_bytes: &[u8; 65]) -> crate::Result<Self> {
403 let key_bytes: &[u8; 33] = unsafe { &*(ext_bytes[..33].as_ptr() as *const [u8; 33]) };
404 if K::is_key_valid(key_bytes) {
405 Ok(Self {
406 key: core::marker::PhantomData,
407 ext: *ext_bytes,
408 })
409 } else {
410 Err(crate::Error::InvalidArgumentError {
411 alg: "SLIP10",
412 expected: "valid extended key bytes",
413 })
414 }
415 }
416
417 pub fn derive<I>(&self, chain: I) -> Self
418 where
419 K: hazmat::WithSegment<<I as Iterator>::Item>,
420 I: Iterator,
421 <I as Iterator>::Item: Segment,
422 {
423 chain.fold(self.clone(), |key, segment| key.child_key(segment))
424 }
425
426 fn ext_mut(&mut self) -> &mut [u8; 64] {
427 unsafe { &mut *(self.ext[1..].as_mut_ptr() as *mut [u8; 64]) }
428 }
429
430 fn key_bytes(&self) -> &[u8; 33] {
431 unsafe { &*(self.ext[..33].as_ptr() as *const [u8; 33]) }
432 }
433
434 fn key_bytes_mut(&mut self) -> &mut [u8; 33] {
435 unsafe { &mut *(self.ext[..33].as_mut_ptr() as *mut [u8; 33]) }
436 }
437
438 fn add_key(&mut self, parent_key: &[u8; 33]) -> bool {
439 K::add_key(self.key_bytes_mut(), parent_key)
440 }
441
442 fn is_key_valid(&self) -> bool {
443 K::is_key_valid(self.key_bytes())
444 }
445
446 fn calc_data<S>(&self, segment: S) -> [u8; 33]
447 where
448 S: Segment,
449 K: hazmat::WithSegment<S>,
450 {
451 K::calc_data(self.key_bytes(), segment)
452 }
453
454 pub fn child_key<S>(&self, segment: S) -> Self
455 where
456 S: Segment,
457 K: hazmat::WithSegment<S>,
458 {
459 let mut data = [0u8; 33 + 4];
460 data[..33].copy_from_slice(&self.calc_data(segment));
461 data[33..].copy_from_slice(&segment.ser32());
462
463 let mut key = Self::new();
464 HMAC_SHA512(&data, self.chain_code(), key.ext_mut());
465 while !key.add_key(self.key_bytes()) {
466 data[0] = 1;
467 data[1..1 + 32].copy_from_slice(key.key_bytes());
468 HMAC_SHA512(&data, self.chain_code(), key.ext_mut());
469 }
470
471 data.zeroize();
472 key
473 }
474
475 pub fn children<I>(&self, child_segments: I) -> Children<K, I>
476 where
477 K: hazmat::WithSegment<<I as IntoIterator>::Item>,
478 I: Iterator,
479 <I as Iterator>::Item: Segment,
480 {
481 Children {
482 mk: self.clone(),
483 child_segments,
484 }
485 }
486}
487
488pub struct Children<K, I> {
489 mk: Slip10<K>,
490 child_segments: I,
491}
492
493impl<K, I> Iterator for Children<K, I>
494where
495 K: hazmat::Derivable + hazmat::WithSegment<<I as IntoIterator>::Item>,
496 I: Iterator,
497 <I as Iterator>::Item: Segment,
498{
499 type Item = Slip10<K>;
500 fn next(&mut self) -> Option<Slip10<K>> {
501 self.child_segments.next().map(|segment| self.mk.child_key(segment))
502 }
503}
504
505impl<K, I> core::iter::FusedIterator for Children<K, I>
506where
507 K: hazmat::Derivable + hazmat::WithSegment<<I as IntoIterator>::Item>,
508 I: core::iter::FusedIterator,
509 <I as Iterator>::Item: Segment,
510{
511}
512
513impl<K, I> core::iter::ExactSizeIterator for Children<K, I>
514where
515 K: hazmat::Derivable + hazmat::WithSegment<<I as IntoIterator>::Item>,
516 I: core::iter::ExactSizeIterator,
517 <I as Iterator>::Item: Segment,
518{
519 fn len(&self) -> usize {
520 self.child_segments.len()
521 }
522}
523
524impl<K: hazmat::Derivable> TryFrom<&[u8; 65]> for Slip10<K> {
525 type Error = crate::Error;
526 fn try_from(ext_bytes: &[u8; 65]) -> crate::Result<Self> {
527 Self::try_from_extended_bytes(ext_bytes)
528 }
529}
530
531pub trait Segment: Copy + Into<u32> {
533 fn is_hardened(self) -> bool;
534 fn ser32(self) -> [u8; 4] {
535 self.into().to_be_bytes()
536 }
537 fn harden(self) -> Hardened;
538 fn unharden(self) -> NonHardened;
539}
540
541#[derive(Clone, Copy, Debug, Eq, PartialEq)]
544#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
545pub enum SegmentHardeningError {
546 Hardened,
548 NonHardened,
550}
551
552impl From<SegmentHardeningError> for crate::Error {
553 fn from(inner: SegmentHardeningError) -> Self {
554 crate::Error::Slip10Error(inner)
555 }
556}
557
558pub const HARDEN_MASK: u32 = 1 << 31;
559
560impl Segment for u32 {
562 fn is_hardened(self) -> bool {
563 self & HARDEN_MASK != 0
564 }
565 fn harden(self) -> Hardened {
566 Hardened(self | HARDEN_MASK)
567 }
568 fn unharden(self) -> NonHardened {
569 NonHardened(self & !HARDEN_MASK)
570 }
571}
572
573#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
575#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
576#[repr(transparent)]
577pub struct Hardened(u32);
578
579impl From<Hardened> for u32 {
580 fn from(segment: Hardened) -> u32 {
581 segment.0
582 }
583}
584
585impl TryFrom<u32> for Hardened {
586 type Error = SegmentHardeningError;
587 fn try_from(segment: u32) -> Result<Self, SegmentHardeningError> {
588 if segment.is_hardened() {
589 Ok(Hardened(segment))
590 } else {
591 Err(SegmentHardeningError::NonHardened)
592 }
593 }
594}
595
596impl Segment for Hardened {
597 fn is_hardened(self) -> bool {
598 true
599 }
600 fn harden(self) -> Hardened {
601 self
602 }
603 fn unharden(self) -> NonHardened {
604 NonHardened(self.0 ^ HARDEN_MASK)
605 }
606}
607
608#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
610#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
611#[repr(transparent)]
612pub struct NonHardened(u32);
613
614impl From<NonHardened> for u32 {
615 fn from(segment: NonHardened) -> u32 {
616 segment.0
617 }
618}
619
620impl TryFrom<u32> for NonHardened {
621 type Error = SegmentHardeningError;
622 fn try_from(segment: u32) -> Result<Self, SegmentHardeningError> {
623 if !segment.is_hardened() {
624 Ok(NonHardened(segment))
625 } else {
626 Err(SegmentHardeningError::Hardened)
627 }
628 }
629}
630
631impl Segment for NonHardened {
632 fn is_hardened(self) -> bool {
633 false
634 }
635 fn harden(self) -> Hardened {
636 Hardened(self.0 ^ HARDEN_MASK)
637 }
638 fn unharden(self) -> NonHardened {
639 self
640 }
641}