Skip to content

Commit

Permalink
Implement DRNG algorithm from BIP85 and varying size of the entropy
Browse files Browse the repository at this point in the history
  • Loading branch information
bbrtj committed Jul 26, 2024
1 parent 868c47d commit 0aa16e9
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 9 deletions.
34 changes: 29 additions & 5 deletions lib/Bitcoin/Crypto/BIP85.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use Mooish::AttributeBuilder -standard;
use Types::Common -sigs, -types;
use List::Util qw(all);
use Crypt::Mac::HMAC qw(hmac);
use Crypt::Digest::SHAKE;

use Bitcoin::Crypto::Util qw(get_path_info);
use Bitcoin::Crypto::Exception;
Expand All @@ -18,14 +19,28 @@ has param 'key' => (
isa => InstanceOf ['Bitcoin::Crypto::Key::ExtPrivate'],
);

sub _adjust_length
{
my ($self, $bytes, $bytelength) = @_;

if ($bytelength <= length $bytes) {
return substr $bytes, 0, $bytelength;
}
else {
my $shake = Crypt::Digest::SHAKE->new(256);
$shake->add($bytes);
return $shake->done($bytelength);
}
}

signature_for derive_entropy => (
method => Object,
positional => [Str | Object],
positional => [Str | Object, Maybe [PositiveInt], {default => undef}],
);

sub derive_entropy
{
my ($self, $path) = @_;
my ($self, $path, $bytelength) = @_;
my $path_info = get_path_info $path;

Bitcoin::Crypto::Exception::KeyDerive->raise(
Expand All @@ -38,7 +53,10 @@ sub derive_entropy

my $key = $self->key->derive_key($path_info);

my $seed = hmac('SHA512', "bip-entropy-from-k", $key->raw_key('private'));
my $seed = hmac('SHA512', 'bip-entropy-from-k', $key->raw_key('private'));
$seed = $self->_adjust_length($seed, $bytelength)
if $bytelength;

return $seed;
}

Expand Down Expand Up @@ -86,10 +104,16 @@ takes arguments specified in L</Attributes>.
=head3 derive_entropy
$bytestr = $object->derive_entropy($path)
$bytestr = $object->derive_entropy($path, $length = undef)
Returns full C<512> bytes of entropy derived from the master key using
Returns entropy derived from the master key using
C<$path>, which can be a standard string derivation path like
C<m/83696968'/0'/0'> or an instance of L<Bitcoin::Crypto::DerivationPath>. The
derivation path must be fully hardened, as specified in the BIP.
Optional C<$length> is the desired length of the entropy in bytes. If not
provided, full C<64> bytes of entropy will be returned. If provided and less
than C<64>, the entropy will be truncated to the derired length. If greater
than C<64>, the C<DRNG> algorithm defined in BIP85 will be used to stretch the
entropy to this size.
24 changes: 20 additions & 4 deletions t/BIP85.t
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,30 @@ use Bitcoin::Crypto::Util qw(to_format);

subtest 'should derive_entropy' => sub {
my $bip85 = Bitcoin::Crypto::BIP85->new(
key => btc_extprv->from_serialized([base58 => 'xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb']),
key => btc_extprv->from_serialized(
[
base58 =>
'xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb'
]
),
);

is to_format [hex => $bip85->derive_entropy(q{m/83696968'/0'/0'})], 'efecfbccffea313214232d29e71563d941229afb4338c21f9517c41aaa0d16f00b83d2a09ef747e7a64e8e2bd5a14869e693da66ce94ac2da570ab7ee48618f7', 'entropy index 0 derived ok';
is to_format [hex => $bip85->derive_entropy(q{m/83696968'/0'/0'})],
'efecfbccffea313214232d29e71563d941229afb4338c21f9517c41aaa0d16f00b83d2a09ef747e7a64e8e2bd5a14869e693da66ce94ac2da570ab7ee48618f7',
'entropy index 0 derived ok';

is to_format [hex => $bip85->derive_entropy(q{m/83696968'/0'/1'})], '70c6e3e8ebee8dc4c0dbba66076819bb8c09672527c4277ca8729532ad711872218f826919f6b67218adde99018a6df9095ab2b58d803b5b93ec9802085a690e', 'entropy index 1 derived ok';
};
is to_format [hex => $bip85->derive_entropy(q{m/83696968'/0'/0'}, 32)],
'efecfbccffea313214232d29e71563d941229afb4338c21f9517c41aaa0d16f0',
'truncated entropy index 0 ok';

is to_format [hex => $bip85->derive_entropy(q{m/83696968'/0'/0'}, 80)],
'b78b1ee6b345eae6836c2d53d33c64cdaf9a696487be81b03e822dc84b3f1cd883d7559e53d175f243e4c349e822a957bbff9224bc5dde9492ef54e8a439f6bc8c7355b87a925a37ee405a7502991111',
'stretched entropy index 0 ok';

is to_format [hex => $bip85->derive_entropy(q{m/83696968'/0'/1'})],
'70c6e3e8ebee8dc4c0dbba66076819bb8c09672527c4277ca8729532ad711872218f826919f6b67218adde99018a6df9095ab2b58d803b5b93ec9802085a690e',
'entropy index 1 derived ok';
};

done_testing;

0 comments on commit 0aa16e9

Please sign in to comment.