[keys] Less convoluted entropy generation

Since const generics aren't in rust yet you have to find some awkward
workarounds. This improves the workaround for specifying entropy length.
This commit is contained in:
LLFourn 2020-09-30 08:17:49 +10:00
parent eae15563d8
commit 490c88934e
2 changed files with 16 additions and 23 deletions

View File

@ -77,14 +77,14 @@ impl<Ctx: ScriptContext> DerivableKey<Ctx> for Mnemonic {
} }
impl<Ctx: ScriptContext> GeneratableKey<Ctx> for Mnemonic { impl<Ctx: ScriptContext> GeneratableKey<Ctx> for Mnemonic {
const ENTROPY_LENGTH: usize = 32; type Entropy = [u8; 32];
type Options = (MnemonicType, Language); type Options = (MnemonicType, Language);
type Error = Option<bip39::ErrorKind>; type Error = Option<bip39::ErrorKind>;
fn generate_with_entropy<E: AsRef<[u8]>>( fn generate_with_entropy(
(mnemonic_type, language): Self::Options, (mnemonic_type, language): Self::Options,
entropy: E, entropy: Self::Entropy,
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> { ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
let entropy = &entropy.as_ref()[..(mnemonic_type.entropy_bits() / 8)]; let entropy = &entropy.as_ref()[..(mnemonic_type.entropy_bits() / 8)];
let mnemonic = Mnemonic::from_entropy(entropy, language).map_err(|e| e.downcast().ok())?; let mnemonic = Mnemonic::from_entropy(entropy, language).map_err(|e| e.downcast().ok())?;

View File

@ -370,8 +370,8 @@ where
/// This trait is particularly useful when combined with [`DerivableKey`]: if `Self` /// This trait is particularly useful when combined with [`DerivableKey`]: if `Self`
/// implements it, the returned [`GeneratedKey`] will also implement it. /// implements it, the returned [`GeneratedKey`] will also implement it.
pub trait GeneratableKey<Ctx: ScriptContext>: Sized { pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
/// Lenght in bytes of the required entropy /// Type specifying the amount of entropy required e.g. [u8;32]
const ENTROPY_LENGTH: usize; type Entropy: AsMut<[u8]> + Default;
/// Extra options required by the `generate_with_entropy` /// Extra options required by the `generate_with_entropy`
type Options; type Options;
@ -379,37 +379,32 @@ pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
type Error: std::fmt::Debug; type Error: std::fmt::Debug;
/// Generate a key given the extra options and the entropy /// Generate a key given the extra options and the entropy
fn generate_with_entropy<E: AsRef<[u8]>>( fn generate_with_entropy(
options: Self::Options, options: Self::Options,
entropy: E, entropy: Self::Entropy,
) -> Result<GeneratedKey<Self, Ctx>, Self::Error>; ) -> Result<GeneratedKey<Self, Ctx>, Self::Error>;
/// Generate a key given the options with a random entropy /// Generate a key given the options with a random entropy
fn generate(options: Self::Options) -> Result<GeneratedKey<Self, Ctx>, Self::Error> { fn generate(options: Self::Options) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
let mut entropy = Vec::<u8>::with_capacity(Self::ENTROPY_LENGTH); let mut entropy = Self::Entropy::default();
for _ in 0..Self::ENTROPY_LENGTH { thread_rng().fill(entropy.as_mut());
entropy.push(0x00); Self::generate_with_entropy(options, entropy)
}
thread_rng().fill(&mut entropy[..Self::ENTROPY_LENGTH]);
Self::generate_with_entropy(options, &entropy)
} }
} }
impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::ExtendedPrivKey { impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::ExtendedPrivKey {
const ENTROPY_LENGTH: usize = 32; type Entropy = [u8; 32];
type Options = (); type Options = ();
type Error = bip32::Error; type Error = bip32::Error;
fn generate_with_entropy<E: AsRef<[u8]>>( fn generate_with_entropy(
_: Self::Options, _: Self::Options,
entropy: E, entropy: Self::Entropy,
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> { ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
// pick a random network here, but say that we support all of them // pick a arbitrary network here, but say that we support all of them
let xprv = bip32::ExtendedPrivKey::new_master(Network::Bitcoin, entropy.as_ref())?; let xprv = bip32::ExtendedPrivKey::new_master(Network::Bitcoin, entropy.as_ref())?;
Ok(GeneratedKey::new(xprv, any_network())) Ok(GeneratedKey::new(xprv, any_network()))
} }
@ -567,14 +562,12 @@ pub mod test {
use super::*; use super::*;
pub fn get_test_entropy() -> Vec<u8> { const test_entropy: [u8; 32] = [0xAA; 32];
[0xAA; 32].to_vec()
}
#[test] #[test]
fn test_keys_generate_xprv() { fn test_keys_generate_xprv() {
let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> = let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> =
bip32::ExtendedPrivKey::generate_with_entropy((), get_test_entropy()).unwrap(); bip32::ExtendedPrivKey::generate_with_entropy((), test_entropy).unwrap();
assert_eq!(generated_xprv.valid_networks, any_network()); assert_eq!(generated_xprv.valid_networks, any_network());
assert_eq!(generated_xprv.to_string(), "xprv9s21ZrQH143K4Xr1cJyqTvuL2FWR8eicgY9boWqMBv8MDVUZ65AXHnzBrK1nyomu6wdcabRgmGTaAKawvhAno1V5FowGpTLVx3jxzE5uk3Q"); assert_eq!(generated_xprv.to_string(), "xprv9s21ZrQH143K4Xr1cJyqTvuL2FWR8eicgY9boWqMBv8MDVUZ65AXHnzBrK1nyomu6wdcabRgmGTaAKawvhAno1V5FowGpTLVx3jxzE5uk3Q");