Skip to content

Commit

Permalink
Implement XPRV application of BIP85, change WIF to return private key
Browse files Browse the repository at this point in the history
  • Loading branch information
bbrtj committed Jul 27, 2024
1 parent a231056 commit de61248
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 10 deletions.
58 changes: 50 additions & 8 deletions lib/Bitcoin/Crypto/BIP85.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use List::Util qw(all);
use Crypt::Mac::HMAC qw(hmac);
use Crypt::Digest::SHAKE;

use Bitcoin::Crypto qw(btc_prv);
use Bitcoin::Crypto qw(btc_prv btc_extprv);
use Bitcoin::Crypto::Types -types;
use Bitcoin::Crypto::Util qw(mnemonic_from_entropy);
use Bitcoin::Crypto::Exception;
Expand Down Expand Up @@ -100,7 +100,7 @@ sub derive_mnemonic
return mnemonic_from_entropy($entropy, $args->{language});
}

signature_for derive_wif => (
signature_for derive_prv => (
method => Object,
named => [
index => PositiveOrZeroInt,
Expand All @@ -109,14 +109,36 @@ signature_for derive_wif => (
bless => !!0,
);

sub derive_wif
sub derive_prv
{
my ($self, $args) = @_;

my $spec_path = "m/83696968'/2'/$args->{index}'";

my $entropy = $self->derive_entropy($spec_path, 32);
return btc_prv->from_serialized($entropy)->to_wif;
return btc_prv->from_serialized($entropy);
}

signature_for derive_extprv => (
method => Object,
named => [
index => PositiveOrZeroInt,
{default => 0},
],
bless => !!0,
);

sub derive_extprv
{
my ($self, $args) = @_;

my $spec_path = "m/83696968'/32'/$args->{index}'";

my $entropy = $self->derive_entropy($spec_path);
return btc_extprv->new(
key_instance => substr($entropy, 32, 32),
chain_code => substr($entropy, 0, 32),
);
}

1;
Expand Down Expand Up @@ -152,7 +174,9 @@ It currently implements the following applications from the BIP85 spec:
=item * C<BIP39>: L</derive_mnemonic>
=item * C<HD-Seed WIF>: L</derive_wif>
=item * C<HD-Seed WIF>: L</derive_prv>
=item * C<XPRV>: L</derive_extprv>
=back
Expand Down Expand Up @@ -211,11 +235,29 @@ The generation index. Must be a non-negative integer. Default: C<0>
=back
=head3 derive_wif
=head3 derive_prv
$mnemonic = $object->derive_mnemonic(%args)
$mnemonic = $object->derive_prv(%args)
Derives private key from the master key. The key can immediately be
serialized using C<< ->to_wif >> to match BIP85 spec for this
application. C<%args> can be any combination of:
=over
=item * C<index>
The generation index. Must be a non-negative integer. Default: C<0>
=back
=head3 derive_extprv
$mnemonic = $object->derive_extprv(%args)
Derives wif from the master key. C<%args> can be any combination of:
Derives an extended private key from the master key. The key can immediately be
serialized using C<< ->to_serialized >> to match BIP85 spec for this
application. C<%args> can be any combination of:
=over
Expand Down
21 changes: 19 additions & 2 deletions t/BIP85.t
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use Bitcoin::Crypto::BIP85;
use Bitcoin::Crypto qw(btc_extprv);
use Bitcoin::Crypto::Util qw(to_format);

# Data from https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki
# extra data generated by https://iancoleman.io/bip39/

subtest 'should derive_entropy' => sub {
my $bip85 = Bitcoin::Crypto::BIP85->new(
key => btc_extprv->from_serialized(
Expand Down Expand Up @@ -65,8 +68,22 @@ subtest 'should derive a wif according to HD-Seed WIF application of BIP85' => s
),
);

is $bip85->derive_wif, 'Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp', 'wif ok';
is $bip85->derive_wif(index => 1), 'L45nghBsnmqaGj9Vy64FCw9AyJNi6K4LUFP4r41tYHmQLEyXUkYP', 'wif index 1 ok';
is $bip85->derive_prv->to_wif, 'Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp', 'wif ok';
is $bip85->derive_prv(index => 1)->to_wif, 'L45nghBsnmqaGj9Vy64FCw9AyJNi6K4LUFP4r41tYHmQLEyXUkYP', 'wif index 1 ok';
};

subtest 'should derive an extprv according to XPRV application of BIP85' => sub {
my $bip85 = Bitcoin::Crypto::BIP85->new(
key => btc_extprv->from_serialized(
[
base58 =>
'xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb'
]
),
);

is to_format [base58 => $bip85->derive_extprv->to_serialized], 'xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UGXMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX', 'xprv ok';
is to_format [base58 => $bip85->derive_extprv(index => 1)->to_serialized], 'xprv9s21ZrQH143K38mDZkjswdWQv6DWyjWiejciPywBBZsCnZ9Vg3WCWnhkPW3rKsPT6u3MnhDn52huxjBjFES1xCzEtxTSAfQTapE7CXcbQ4b', 'xprv index 1 ok';
};

done_testing;
Expand Down

0 comments on commit de61248

Please sign in to comment.