secret.rs
1 use std::fmt::Debug; 2 use std::io::{Read, Write}; 3 4 use fedimint_core::config::FederationId; 5 use fedimint_core::core::ModuleInstanceId; 6 use fedimint_core::encoding::{Decodable, DecodeError, Encodable}; 7 use fedimint_derive_secret::{ChildId, DerivableSecret}; 8 use rand::{CryptoRng, Rng, RngCore}; 9 10 const TYPE_MODULE: ChildId = ChildId(0); 11 const TYPE_BACKUP: ChildId = ChildId(1); 12 13 pub trait DeriveableSecretClientExt { 14 fn derive_module_secret(&self, module_instance_id: ModuleInstanceId) -> DerivableSecret; 15 fn derive_backup_secret(&self) -> DerivableSecret; 16 } 17 18 impl DeriveableSecretClientExt for DerivableSecret { 19 fn derive_module_secret(&self, module_instance_id: ModuleInstanceId) -> DerivableSecret { 20 assert_eq!(self.level(), 0); 21 self.child_key(TYPE_MODULE) 22 .child_key(ChildId(module_instance_id as u64)) 23 } 24 25 fn derive_backup_secret(&self) -> DerivableSecret { 26 assert_eq!(self.level(), 0); 27 self.child_key(TYPE_BACKUP) 28 } 29 } 30 31 /// Trait defining a way to generate, serialize and deserialize a root secret. 32 /// It defines a `Encoding` associated type which represents a specific 33 /// representation of a secret (e.g. a bip39, slip39, CODEX32, … struct) and 34 /// then defines the methods necessary for the client to interact with it. 35 /// 36 /// We use a strategy pattern (i.e. implementing the trait on a zero sized type 37 /// with the actual secret struct as an associated type instead of implementing 38 /// the necessary functions directly on the secret struct) to allow external 39 /// implementations on third-party types without wrapping them in newtypes. 40 pub trait RootSecretStrategy: Debug { 41 /// Type representing the secret 42 type Encoding: Clone; 43 44 /// Conversion function from the external encoding to the internal one 45 fn to_root_secret(secret: &Self::Encoding) -> DerivableSecret; 46 47 /// Serialization function for the external encoding 48 fn consensus_encode( 49 secret: &Self::Encoding, 50 writer: &mut impl std::io::Write, 51 ) -> std::io::Result<usize>; 52 53 /// Deserialization function for the external encoding 54 fn consensus_decode(reader: &mut impl std::io::Read) -> Result<Self::Encoding, DecodeError>; 55 56 /// Random generation function for the external secret type 57 fn random<R>(rng: &mut R) -> Self::Encoding 58 where 59 R: rand::RngCore + rand::CryptoRng; 60 } 61 62 /// Just uses 64 random bytes and derives the secret from them 63 #[derive(Debug)] 64 pub struct PlainRootSecretStrategy; 65 66 impl RootSecretStrategy for PlainRootSecretStrategy { 67 type Encoding = [u8; 64]; 68 69 fn to_root_secret(secret: &Self::Encoding) -> DerivableSecret { 70 const FEDIMINT_CLIENT_NONCE: &[u8] = b"Fedimint Client Salt"; 71 DerivableSecret::new_root(secret.as_ref(), FEDIMINT_CLIENT_NONCE) 72 } 73 74 fn consensus_encode( 75 secret: &Self::Encoding, 76 writer: &mut impl Write, 77 ) -> std::io::Result<usize> { 78 secret.consensus_encode(writer) 79 } 80 81 fn consensus_decode(reader: &mut impl Read) -> Result<Self::Encoding, DecodeError> { 82 Self::Encoding::consensus_decode(reader, &Default::default()) 83 } 84 85 fn random<R>(rng: &mut R) -> Self::Encoding 86 where 87 R: RngCore + CryptoRng, 88 { 89 let mut secret = [0u8; 64]; 90 rng.fill(&mut secret); 91 secret 92 } 93 } 94 95 /// Convenience function to derive fedimint-client root secret 96 /// using the default (0) wallet number, given a global root secret 97 /// that's managed externally by a consumer of fedimint-client. 98 /// 99 /// See docs/secret_derivation.md 100 /// 101 /// `global_root_secret/<key-type=per-federation=0>/<federation-id>/ 102 /// <wallet-number=0>/<key-type=fedimint-client=0>` 103 pub fn get_default_client_secret( 104 global_root_secret: &DerivableSecret, 105 federation_id: &FederationId, 106 ) -> DerivableSecret { 107 let multi_federation_root_secret = global_root_secret.child_key(ChildId(0)); 108 let federation_root_secret = multi_federation_root_secret.federation_key(federation_id); 109 let federation_wallet_root_secret = federation_root_secret.child_key(ChildId(0)); // wallet-number=0 110 federation_wallet_root_secret.child_key(ChildId(0)) // key-type=fedimint-client=0 111 }