Business-Bitcoin
view release on metacpan or search on metacpan
lib/Business/Bitcoin/Request.pm view on Meta::CPAN
my $curve = Math::EllipticCurve::Prime->from_name('secp256k1');
my $xpubdata = Math::BigInt->new(_decode58($xpub))->as_hex;
$xpubdata =~ /.(.{8})(..)(.{8})(.{8})(.{64})(.{66})(.*)/;
my ($ver, $depth, $fp, $i, $c, $Kc) = ($1, $2, $3, $4, $5, $6);
my $K = Math::EllipticCurve::Prime::Point->from_hex(_decompress($Kc));
if ($bizbtc->path eq 'electrum') {
# m/0
my ($Ki, $ci) = _CKDpub($K, $c, 0);
# m/0/$index
my ($Ki2, $ci2) = _CKDpub($Ki, $ci, $index);
return _address(_compress($Ki2));
}
else {
my ($Ki, $ci) = _CKDpub($K, $c, $index);
return _address(_compress($Ki));
}
}
sub _CKDpub {
my ($K, $c, $i) = @_;
my $curve = Math::EllipticCurve::Prime->from_name('secp256k1');
my $data = pack('H*', _compress($K)) . pack ('L>', $i);
my $hmac = hmac_sha512_hex($data, pack('H*', $c)); $hmac =~ /(.{64})(.{64})/;
my ($Il, $ci) = ($1, $2);
my $Ki = $curve->g->multiply(Math::BigInt->from_hex($Il))->add($K);
return ($Ki, $ci);
}
sub _address {
my $sha256 = sha256(pack('H*', shift));
my $id = '00' . Crypt::RIPEMD160->hexhash($sha256); $id =~ s/\s//g;
my $checksum = substr(sha256_hex(sha256(pack('H*', $id))), 0, 8);
my $address = _encode58(Math::BigInt->from_hex($id . $checksum));
my $leadingones;
while ($id =~ /^(00)/) { $leadingones .= '1'; $id =~ s/^00//; }
return $leadingones . $address;
}
sub _decompress {
my $Kc = shift; $Kc =~ /^(..)(.*)/;
my $i = $1; my $K = '04' . '0' x (64 - length($2)) . $2; my $x = Math::BigInt->from_hex($2);
my $curve = Math::EllipticCurve::Prime->from_name('secp256k1');
my ($p, $a, $b) = ($curve->p, $curve->a, $curve->b);
my $y = ($x->bmodpow(3,$p)+$a*$x+$b)->bmodpow(($p+1)/4,$p);
$y = $p - $y if $i%2 ne $y%2;
my $yhex = $y->as_hex; $yhex =~ s/^0x//;
$K .= '0' x (64 - length($yhex)) . $yhex;
return $K;
}
sub _compress {
my $K = shift;
my $Kc = $K->x->as_hex; $Kc =~ s/^0x//;
$Kc = '0' x (64 - length($Kc)) . $Kc;
$Kc = ($K->y % 2 ? '03' : '02') . $Kc;
}
sub _decode58 {
my $todecode = shift;
$todecode =~ tr/A-HJ-NP-Za-km-z/a-km-zA-HJ-NP-Z/;
my $decoded = decode_base58($todecode);
}
sub _encode58 {
my $encoded = encode_base58(shift);
$encoded =~ tr/a-km-zA-HJ-NP-Z/A-HJ-NP-Za-km-z/;
return $encoded;
}
sub AUTOLOAD {
my $self = shift; (my $auto = $AUTOLOAD) =~ s/.*:://;
return if $auto eq 'DESTROY';
if ($auto =~ /^(confirmations|processed|status|amount|reference|error)$/x and defined $_[0]) {
$self->{"\u$auto"} = shift;
}
if ($auto =~ /^(reqid|amount|address|reference|version|created|confirmations|processed|status|error)$/x) {
return $self->{"\u$auto"};
}
if ($auto =~ /^(db|id)$/x) {
return $self->{"\U$auto"};
}
die "Could not AUTOLOAD method $auto.";
}
1; # End of Business::Bitcoin::Request
=head1 NAME
Business::Bitcoin::Request - Bitcoin payment request
=head1 VERSION
$Revision: 1.051 $
$Date: Tue Oct 16 22:26:58 PDT 2018 $
=head1 SYNOPSIS
Business::Bitcoin::Request objects represent Bitcoin payment requests
generated by Business::Bitcoin.
use Business::Bitcoin;
my $bizbtc = new Business::Bitcoin (DB => '/tmp/bizbtc.db',
XPUB => 'xpub...');
my $request = $bizbtc->request(Amount => 4200);
print ($request->verify ? "Verified\n" : "Verification failed\n");
=head1 METHODS
=head2 new
Not intended to be called directly. Business::Bitcoin::Request objects
should be created by calling the request method on a Business::Bitcoin
object.
=head2 commit
Commit the Request object to the requests database. Only the
'processed' and 'status' fields are updated in the database.
( run in 1.147 second using v1.01-cache-2.11-cpan-40ba7b3775d )