1use crate::{
2 key::{ed25519_extended, SharedSecret},
3 memsec::Scrubbed as _,
4};
5use cryptoxide::{
6 curve25519::{Ge, Scalar},
7 hmac::Hmac,
8 mac::Mac,
9 sha2::Sha512,
10};
11use packtool::Packed;
12use rand_core::{CryptoRng, RngCore};
13use std::{
14 convert::TryFrom,
15 fmt::{self, Debug, Display, Formatter},
16 ops::Deref,
17 str::FromStr,
18};
19use thiserror::Error;
20
21#[derive(Packed, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)]
22pub struct ChainCode(
23 #[packed(accessor = false)] [u8; Self::SIZE],
25);
26
27#[derive(Clone, Eq, PartialEq, Hash)]
28pub struct SecretKey {
29 key: ed25519_extended::SecretKey,
30 chain_code: ChainCode,
31}
32
33#[derive(Packed, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
34pub struct PublicKey {
35 #[packed(accessor = "public_key")]
36 key: ed25519_extended::PublicKey,
37 #[packed(accessor = false)]
39 chain_code: ChainCode,
40}
41
42pub use crate::key::ed25519::Signature;
43
44impl ChainCode {
45 pub const SIZE: usize = 32;
46
47 #[inline(always)]
49 const fn zero() -> Self {
50 Self([0; Self::SIZE])
51 }
52
53 fn new<Rng>(mut rng: Rng) -> Self
56 where
57 Rng: RngCore + CryptoRng,
58 {
59 let mut s = Self::zero();
60 rng.fill_bytes(&mut s.0);
61 s
62 }
63}
64
65impl SecretKey {
66 pub const SIZE: usize = ed25519_extended::SecretKey::SIZE + ChainCode::SIZE;
67
68 pub fn new<Rng>(mut rng: Rng) -> Self
71 where
72 Rng: RngCore + CryptoRng,
73 {
74 let mut key = ed25519_extended::SecretKey::new(&mut rng);
75 let chain_code = ChainCode::new(rng);
76
77 key.clear_3rd_highest_bit();
78
79 let s = Self { key, chain_code };
80
81 debug_assert!(
82 s.key.is_3rd_highest_bit_clear(),
83 "checking we properly set the bit tweaks for the extended Ed25519 BIP32"
84 );
85
86 s
87 }
88
89 #[inline]
90 pub fn is_3rd_highest_bit_clear(&self) -> bool {
91 self.key.is_3rd_highest_bit_clear()
92 }
93
94 pub fn public_key(&self) -> PublicKey {
101 let key = self.key.public_key();
102 let chain_code = self.chain_code;
103
104 PublicKey { key, chain_code }
105 }
106
107 pub fn chain(&self) -> &ChainCode {
108 &self.chain_code
109 }
110
111 pub fn key(&self) -> &ed25519_extended::SecretKey {
117 &self.key
118 }
119
120 pub fn into_key(self) -> ed25519_extended::SecretKey {
121 self.key
122 }
123
124 pub fn exchange<P>(&self, public_key: &P) -> SharedSecret
128 where
129 P: AsRef<ed25519_extended::PublicKey>,
130 {
131 self.key.exchange(public_key.as_ref())
132 }
133
134 pub fn sign<T: AsRef<[u8]>>(&self, msg: T) -> Signature {
139 self.key.sign(msg)
140 }
141
142 pub fn derive<P>(&self, path: P) -> Self
143 where
144 P: AsRef<[u8]>,
145 {
146 let e_key = &self.key.leak_as_ref()[0..64];
147 let kl = &e_key[0..32];
148 let kr = &e_key[32..64];
149 let chaincode = self.chain_code.as_ref();
150
151 let mut z_mac = Hmac::new(Sha512::new(), chaincode);
152 let mut i_mac = Hmac::new(Sha512::new(), chaincode);
153 let pk = self.public_key();
154 let pk = pk.key().as_ref();
155 z_mac.input(&[0x2]);
156 z_mac.input(pk);
157 z_mac.input(path.as_ref());
158 i_mac.input(&[0x3]);
159 i_mac.input(pk);
160 i_mac.input(path.as_ref());
161
162 let mut z_out = [0u8; 64];
163 z_mac.raw_result(&mut z_out);
164 let zl = &z_out[0..32];
165 let zr = &z_out[32..64];
166
167 let mut left = add_28_mul8(kl, zl);
169 let mut right = add_256bits(kr.try_into().unwrap(), zr.try_into().unwrap());
171
172 let mut i_out = [0u8; 64];
173 i_mac.raw_result(&mut i_out);
174 let cc = &i_out[32..];
175
176 let mut out = [0u8; Self::SIZE];
177 out[0..32].clone_from_slice(&left);
178 out[32..64].clone_from_slice(&right);
179 out[64..96].clone_from_slice(cc);
180
181 i_mac.reset();
182 z_mac.reset();
183
184 z_out.scrub();
185 left.scrub();
186 right.scrub();
187
188 Self::try_from(out).unwrap()
189 }
190}
191
192impl PublicKey {
193 pub const SIZE: usize = ed25519_extended::PublicKey::SIZE + ChainCode::SIZE;
194
195 pub fn from_parts(key: ed25519_extended::PublicKey, chain_code: ChainCode) -> Self {
196 Self { key, chain_code }
197 }
198
199 pub fn key(&self) -> &ed25519_extended::PublicKey {
200 &self.key
201 }
202
203 pub fn into_key(self) -> ed25519_extended::PublicKey {
204 self.key
205 }
206
207 pub fn chain_code(&self) -> &ChainCode {
208 &self.chain_code
209 }
210
211 pub fn derive<P>(&self, path: P) -> Option<Self>
212 where
213 P: AsRef<[u8]>,
214 {
215 let pk = self.key().bytes();
216 let chaincode = self.chain_code().as_ref();
217
218 let mut z_mac = Hmac::new(Sha512::new(), chaincode);
219 let mut i_mac = Hmac::new(Sha512::new(), chaincode);
220 z_mac.input(&[0x2]);
221 z_mac.input(pk);
222 z_mac.input(path.as_ref());
223 i_mac.input(&[0x3]);
224 i_mac.input(pk);
225 i_mac.input(path.as_ref());
226
227 let mut z_out = [0u8; 64];
228 z_mac.raw_result(&mut z_out);
229 let zl = &z_out[0..32];
230 let _zr = &z_out[32..64];
231
232 let left = point_plus(pk, &point_of_trunc28_mul8(zl.try_into().unwrap()))?;
234
235 let mut i_out = [0u8; 64];
236 i_mac.raw_result(&mut i_out);
237 let cc = &i_out[32..];
238
239 let mut out = [0u8; Self::SIZE];
240 out[..ed25519_extended::PublicKey::SIZE].copy_from_slice(&left);
241 out[ed25519_extended::PublicKey::SIZE..].copy_from_slice(cc);
242
243 i_mac.reset();
244 z_mac.reset();
245
246 Some(Self::from(out))
247 }
248}
249
250fn point_of_trunc28_mul8(sk: &[u8; 32]) -> [u8; 32] {
253 let copy = add_28_mul8(&[0u8; 32], sk);
254 let scalar = Scalar::from_bytes(©);
255 let a = Ge::scalarmult_base(&scalar);
256 a.to_bytes()
257}
258
259fn point_plus(p1: &[u8; 32], p2: &[u8; 32]) -> Option<[u8; 32]> {
260 let a = Ge::from_bytes(p1)?;
261 let b = Ge::from_bytes(p2)?;
262 let r = &a + &b.to_cached();
263 let mut r = r.to_partial().to_bytes();
264 r[31] ^= 0x80;
265 Some(r)
266}
267
268fn add_28_mul8(x: &[u8], y: &[u8]) -> [u8; 32] {
269 assert!(x.len() == 32);
270 assert!(y.len() == 32);
271
272 let mut carry: u16 = 0;
273 let mut out = [0u8; 32];
274
275 for i in 0..28 {
276 let r = x[i] as u16 + ((y[i] as u16) << 3) + carry;
277 out[i] = (r & 0xff) as u8;
278 carry = r >> 8;
279 }
280 for i in 28..32 {
281 let r = x[i] as u16 + carry;
282 out[i] = (r & 0xff) as u8;
283 carry = r >> 8;
284 }
285 out
286}
287
288fn add_256bits(x: &[u8; 32], y: &[u8; 32]) -> [u8; 32] {
289 let mut carry: u16 = 0;
290 let mut out = [0u8; 32];
291 for i in 0..32 {
292 let r = (x[i] as u16) + (y[i] as u16) + carry;
293 out[i] = r as u8;
294 carry = r >> 8;
295 }
296 out
297}
298
299impl Deref for PublicKey {
302 type Target = ed25519_extended::PublicKey;
303 fn deref(&self) -> &Self::Target {
304 self.key()
305 }
306}
307
308impl Debug for ChainCode {
311 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
312 f.debug_tuple("ChainCode")
313 .field(&hex::encode(&self.0))
314 .finish()
315 }
316}
317
318impl Debug for SecretKey {
319 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
320 f.debug_struct("SecretKey<Ed25519BIP32>")
321 .field("key", &self.key)
322 .field("chain_code", &self.chain_code)
323 .finish()
324 }
325}
326
327impl Debug for PublicKey {
328 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
329 f.debug_struct("PublicKey<Ed25519BIP32>")
330 .field("key", &self.key)
331 .field("chain_code", &self.chain_code)
332 .finish()
333 }
334}
335
336impl Display for ChainCode {
337 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
338 Display::fmt(&hex::encode(&self.0), f)
339 }
340}
341
342impl Display for PublicKey {
343 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
344 write!(f, "{}", self.key())?;
345 write!(f, "{}", self.chain_code())
346 }
347}
348
349impl From<[u8; Self::SIZE]> for ChainCode {
352 fn from(bytes: [u8; Self::SIZE]) -> Self {
353 Self(bytes)
354 }
355}
356
357impl From<[u8; Self::SIZE]> for PublicKey {
358 fn from(bytes: [u8; Self::SIZE]) -> Self {
359 let mut key = [0; ed25519_extended::PublicKey::SIZE];
360 let mut chain_code = [0; ChainCode::SIZE];
361 key.copy_from_slice(&bytes[..ed25519_extended::PublicKey::SIZE]);
362 chain_code.copy_from_slice(&bytes[ed25519_extended::PublicKey::SIZE..]);
363 Self {
364 key: ed25519_extended::PublicKey::from(key),
365 chain_code: ChainCode::from(chain_code),
366 }
367 }
368}
369
370#[derive(Debug, Error)]
371pub enum ChainCodeError {
372 #[error("Invalid size, expecting {}", ChainCode::SIZE)]
373 InvalidSize,
374}
375
376impl<'a> TryFrom<&'a [u8]> for ChainCode {
377 type Error = ChainCodeError;
378
379 fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
380 if bytes.len() != Self::SIZE {
381 return Err(Self::Error::InvalidSize);
382 }
383 let mut chain_code = ChainCode::zero();
384 chain_code.0.copy_from_slice(bytes);
385 Ok(chain_code)
386 }
387}
388
389#[derive(Debug, Error)]
390pub enum PublicKeyError {
391 #[error("Invalid size, expecting {}", PublicKey::SIZE)]
392 InvalidSize,
393 #[error("Invalid verify key")]
394 InvalidPublicKey(
395 #[from]
396 #[source]
397 ed25519_extended::PublicKeyError,
398 ),
399 #[error("Invalid chain code")]
400 InvalidChainCode(
401 #[from]
402 #[source]
403 ChainCodeError,
404 ),
405}
406
407impl<'a> TryFrom<&'a [u8]> for PublicKey {
408 type Error = PublicKeyError;
409
410 fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
411 if bytes.len() != Self::SIZE {
412 return Err(Self::Error::InvalidSize);
413 }
414
415 let key =
416 ed25519_extended::PublicKey::try_from(&bytes[..ed25519_extended::PublicKey::SIZE])?;
417 let chain_code = ChainCode::try_from(&bytes[ed25519_extended::PublicKey::SIZE..])?;
418
419 Ok(Self { key, chain_code })
420 }
421}
422
423#[derive(Debug, Error)]
424pub enum SecretKeyError {
425 #[error("Invalid size, expecting {}", SecretKey::SIZE)]
426 InvalidSize,
427 #[error("Invalid chain code")]
428 InvalidChainCode(
429 #[from]
430 #[source]
431 ChainCodeError,
432 ),
433 #[error("Invalid structure")]
434 InvalidStructure,
435 #[error("Invalid hexadecimal string")]
436 InvalidHexadecimal(
437 #[source]
438 #[from]
439 hex::FromHexError,
440 ),
441}
442
443impl TryFrom<[u8; Self::SIZE]> for SecretKey {
444 type Error = SecretKeyError;
445
446 fn try_from(bytes: [u8; Self::SIZE]) -> Result<Self, Self::Error> {
447 Self::try_from(&bytes[..])
448 }
449}
450
451impl<'a> TryFrom<&'a [u8]> for SecretKey {
452 type Error = SecretKeyError;
453 fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
454 if bytes.len() != Self::SIZE {
455 return Err(Self::Error::InvalidSize);
456 }
457
458 match ed25519_extended::SecretKey::try_from(&bytes[..ed25519_extended::SecretKey::SIZE]) {
459 Ok(key) => {
460 let chain_code = ChainCode::try_from(&bytes[ed25519_extended::SecretKey::SIZE..])?;
465 Ok(Self { key, chain_code })
466 }
467 Err(ed25519_extended::SecretKeyError::InvalidSize) => {
468 unreachable!("The Size({}) is already checked, expecting an extended key of {} and a chain code of {}", SecretKey::SIZE, ed25519_extended::SecretKey::SIZE, ChainCode::SIZE)
469 }
470 Err(ed25519_extended::SecretKeyError::InvalidStructure) => {
471 Err(Self::Error::InvalidStructure)
472 }
473 }
474 }
475}
476
477impl FromStr for SecretKey {
478 type Err = SecretKeyError;
479 fn from_str(s: &str) -> Result<Self, Self::Err> {
480 let mut r = [0; Self::SIZE];
481 hex::decode_to_slice(s, &mut r)?;
482
483 let sk = Self::try_from(&r[..])?;
484
485 r.scrub();
486
487 Ok(sk)
488 }
489}
490
491impl FromStr for PublicKey {
492 type Err = hex::FromHexError;
493 fn from_str(s: &str) -> Result<Self, Self::Err> {
494 let mut r = [0; Self::SIZE];
495 hex::decode_to_slice(s, &mut r)?;
496 Ok(Self::from(r))
497 }
498}
499
500impl FromStr for ChainCode {
501 type Err = hex::FromHexError;
502 fn from_str(s: &str) -> Result<Self, Self::Err> {
503 let mut r = [0; Self::SIZE];
504 hex::decode_to_slice(s, &mut r)?;
505 Ok(Self::from(r))
506 }
507}
508
509impl AsRef<[u8]> for ChainCode {
512 fn as_ref(&self) -> &[u8] {
513 &self.0
514 }
515}
516
517impl AsRef<ed25519_extended::PublicKey> for PublicKey {
518 fn as_ref(&self) -> &ed25519_extended::PublicKey {
519 self.key()
520 }
521}
522
523#[cfg(test)]
524mod tests {
525 use super::*;
526 use quickcheck::{Arbitrary, Gen, TestResult};
527
528 impl Arbitrary for ChainCode {
529 fn arbitrary(g: &mut Gen) -> Self {
530 let mut s = Self::zero();
531 s.0.iter_mut().for_each(|byte| {
532 *byte = u8::arbitrary(g);
533 });
534 s
535 }
536 }
537
538 impl Arbitrary for PublicKey {
539 fn arbitrary(g: &mut Gen) -> Self {
540 SecretKey::arbitrary(g).public_key()
541 }
542 }
543
544 impl Arbitrary for SecretKey {
545 fn arbitrary(g: &mut Gen) -> Self {
546 let key = ed25519_extended::SecretKey::arbitrary(g);
547 let chain_code = ChainCode::arbitrary(g);
548
549 Self { key, chain_code }
557 }
558 }
559
560 #[quickcheck]
561 fn verify_exchange_works(alice: SecretKey, bob: SecretKey) -> bool {
562 let alice_pk = alice.public_key();
563 let bob_pk = bob.public_key();
564
565 alice.exchange(&bob_pk) == bob.exchange(&alice_pk)
566 }
567
568 #[quickcheck]
569 fn signing_verify_works(signing_key: SecretKey, message: Vec<u8>) -> bool {
570 let public_key = signing_key.public_key();
571 let signature = signing_key.sign(&message);
572
573 public_key.verify(message, &signature)
574 }
575
576 #[quickcheck]
577 fn signing_key_try_from_correct_size(signing_key: SecretKey) -> TestResult {
578 let mut bytes = signing_key.key.leak_as_ref().to_vec();
579 bytes.extend(&signing_key.chain_code.0);
580 match SecretKey::try_from(bytes.as_slice()) {
581 Ok(_) => TestResult::passed(),
582 Err(SecretKeyError::InvalidSize) => {
583 TestResult::error("was expecting the test to pass, not an invalid size")
584 }
585 Err(SecretKeyError::InvalidChainCode(ChainCodeError::InvalidSize)) => {
586 unreachable!("The total size of the key is already being checked")
587 }
588 Err(SecretKeyError::InvalidStructure) => {
589 TestResult::error("was expecting the test to pass, not an invalid structure")
590 }
591 Err(SecretKeyError::InvalidHexadecimal(_)) => {
592 unreachable!("We should not see an hexadecimal error at all in this test")
593 }
594 }
595 }
596
597 #[quickcheck]
598 fn signing_key_try_from_incorrect_size(bytes: Vec<u8>) -> TestResult {
599 if bytes.len() == SecretKey::SIZE {
600 return TestResult::discard();
601 }
602 match SecretKey::try_from(bytes.as_slice()) {
603 Ok(_) => TestResult::error(
604 "Expecting to fail with invalid size instead of having a valid value",
605 ),
606 Err(SecretKeyError::InvalidSize) => TestResult::passed(),
607 Err(SecretKeyError::InvalidChainCode(ChainCodeError::InvalidSize)) => {
608 unreachable!("The total size of the key is already being checked")
609 }
610 Err(SecretKeyError::InvalidStructure) => {
611 TestResult::error("was expecting an invalid size error, not an invalid structure")
612 }
613 Err(SecretKeyError::InvalidHexadecimal(_)) => {
614 unreachable!("We should not see an hexadecimal error at all in this test")
615 }
616 }
617 }
618
619 #[quickcheck]
620 fn public_key_try_from_correct_size(public_key: PublicKey) -> TestResult {
621 let mut bytes = public_key.key.as_ref().to_vec();
622 bytes.extend(&public_key.chain_code.0);
623 match PublicKey::try_from(bytes.as_slice()) {
624 Ok(_) => TestResult::passed(),
625 Err(PublicKeyError::InvalidSize) => {
626 TestResult::error("was expecting the test to pass, not an invalid size")
627 }
628 Err(PublicKeyError::InvalidPublicKey(
629 ed25519_extended::PublicKeyError::InvalidSize,
630 )) => unreachable!("The total size of the key is already being checked"),
631 Err(PublicKeyError::InvalidChainCode(ChainCodeError::InvalidSize)) => {
632 unreachable!("The total size of the key is already being checked")
633 }
634 }
635 }
636
637 #[quickcheck]
638 fn public_key_try_from_incorrect_size(bytes: Vec<u8>) -> TestResult {
639 if bytes.len() == PublicKey::SIZE {
640 return TestResult::discard();
641 }
642 match PublicKey::try_from(bytes.as_slice()) {
643 Ok(_) => TestResult::error(
644 "Expecting to fail with invalid size instead of having a valid value",
645 ),
646 Err(PublicKeyError::InvalidSize) => TestResult::passed(),
647 Err(PublicKeyError::InvalidPublicKey(
648 ed25519_extended::PublicKeyError::InvalidSize,
649 )) => unreachable!("The total size of the key is already being checked"),
650 Err(PublicKeyError::InvalidChainCode(ChainCodeError::InvalidSize)) => {
651 unreachable!("The total size of the key is already being checked")
652 }
653 }
654 }
655
656 #[quickcheck]
657 fn chain_code_try_from_correct_size(chain_code: ChainCode) -> TestResult {
658 match ChainCode::try_from(chain_code.0.as_ref()) {
659 Ok(_) => TestResult::passed(),
660 Err(ChainCodeError::InvalidSize) => {
661 TestResult::error("was expecting the test to pass, not an invalid size")
662 }
663 }
664 }
665
666 #[quickcheck]
667 fn chain_code_try_from_incorrect_size(bytes: Vec<u8>) -> TestResult {
668 if bytes.len() == ChainCode::SIZE {
669 return TestResult::discard();
670 }
671 match ChainCode::try_from(bytes.as_slice()) {
672 Ok(_) => TestResult::error(
673 "Expecting to fail with invalid size instead of having a valid value",
674 ),
675 Err(ChainCodeError::InvalidSize) => TestResult::passed(),
676 }
677 }
678
679 #[quickcheck]
680 fn public_key_from_str(public_key: PublicKey) -> TestResult {
681 let mut bytes = public_key.key.as_ref().to_vec();
682 bytes.extend(&public_key.chain_code.0);
683 let s = hex::encode(bytes);
684
685 match s.parse::<PublicKey>() {
686 Ok(decoded) => {
687 if decoded == public_key {
688 TestResult::passed()
689 } else {
690 TestResult::error("the decoded key is not equal")
691 }
692 }
693 Err(error) => TestResult::error(error.to_string()),
694 }
695 }
696
697 #[quickcheck]
698 fn chain_code_from_str(chain_code: ChainCode) -> TestResult {
699 let s = hex::encode(&chain_code);
700
701 match s.parse::<ChainCode>() {
702 Ok(decoded) => {
703 if decoded == chain_code {
704 TestResult::passed()
705 } else {
706 TestResult::error("the decoded chain_code is not equal")
707 }
708 }
709 Err(error) => TestResult::error(error.to_string()),
710 }
711 }
712
713 #[quickcheck]
714 fn derivation_from_signing_and_public_key(root_key: SecretKey, path: Vec<u8>) -> TestResult {
715 let root_public_key = root_key.public_key();
716
717 let d1 = root_key.derive(&path);
718 let d2 = root_public_key.derive(path).unwrap();
719
720 TestResult::from_bool(Some(d1.public_key()) == Some(d2))
721 }
722
723 #[quickcheck]
724 fn different_derivation_from_signing_key(
725 root_key: SecretKey,
726 path1: Vec<u8>,
727 path2: Vec<u8>,
728 ) -> TestResult {
729 if path1 == path2 {
730 return TestResult::discard();
731 }
732
733 let dp1 = root_key.derive(&path1);
734 let dp2 = root_key.derive(&path2);
735
736 TestResult::from_bool(dp1 != dp2)
737 }
738
739 #[quickcheck]
740 fn different_derivation_from_public_key(
741 root_key: PublicKey,
742 path1: Vec<u8>,
743 path2: Vec<u8>,
744 ) -> TestResult {
745 if path1 == path2 {
746 return TestResult::discard();
747 }
748
749 let dp1 = root_key.derive(&path1).unwrap();
750 let dp2 = root_key.derive(&path2).unwrap();
751
752 dbg!(hex::encode(&path2));
753 dbg!(hex::encode(&path1));
754 dbg!(&dp1);
755 dbg!(&dp2);
756 TestResult::from_bool(dp1 != dp2)
757 }
758}