Repository navigation
Expand file tree
/
Copy pathBitcoinMath.pm
More file actions
105 lines (90 loc) · 2.53 KB
/
Copy pathBitcoinMath.pm
File metadata and controls
105 lines (90 loc) · 2.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package BitcoinMath;
use strict;
use warnings;
use Crypt::Digest qw(digest_data digest_data_hex);
our @base58 = ('1' .. '9', 'A' .. 'H', 'J' .. 'N', 'P' .. 'Z', 'a' .. 'k', 'm' .. 'z');
sub reverse_map {
my @ret;
for (my $i = 0; $i < @base58; ++$i) {
$ret[ord($base58[$i])] = $i;
}
@ret;
}
our @decBase58 = reverse_map;
sub big_zero {use bigint; 0}
sub decodeBase58 {
my $base58 = $_[0];
my $return = big_zero;
for (my $i = 0; $i < length($base58); $i++) {
my $sym = ord(substr($base58, $i, 1));
$return *= 58;
$return += $decBase58[$sym];
}
$return = lc substr($return->as_hex, 2);
for (my $i = 0; $i < length($base58) && substr($base58, $i, 1) eq "1"; $i++) {
$return = "00" . $return;
}
if (length($return) % 2 != 0) {
$return = "0" . $return;
}
return $return;
}
sub encodeBase58 {
my $orighex = $_[0];
die "encodeBase58: uneven number of hex characters" if length($orighex) % 2 != 0;
my $hex = big_zero;
for (my $i = 0; $i < length($orighex); ++$i) {
$hex = $hex * 16 + hex(substr($orighex, $i, 1));
}
my $return = "";
for (; $hex > 0; $hex /= 58) {
$return .= $base58[$hex % 58];
}
$return = reverse($return);
for (my $i = 0; $i < length($orighex) && substr($orighex, $i, 2) eq "00"; $i += 2) {
$return = "1" . $return;
}
return $return;
}
sub checksum {
return lc unpack 'H8', digest_data("SHA256", digest_data("SHA256", pack 'H*', $_[0]));
}
sub checkBitcoinAddress {
local $_ = shift;
die 'wrong format' unless /^[@base58]{34,}$/x;
$_ = decodeBase58 $_;
my $checksum = checksum sprintf '%042s', substr $_, 0, -8;
die 'wrong checksum' unless m{$checksum$};
}
sub hash160ToAddress {
my ($hash, $version) = ($_[0], (sprintf '%02x', $_[1] || 0));
local $_ = sprintf '%34s', map encodeBase58($_ . checksum($_)), $version . $hash;
tr/ /1/;
return $_;
}
sub hash160 {
my $data = pack("H*", $_[0]);
return lc(digest_data_hex("RIPEMD160", digest_data("SHA256", $data)));
}
sub addressToHash160 {
my $addr = decodeBase58($_[0]);
$addr = substr($addr, 2, length($addr) - 10);
return $addr;
}
sub pubKeyToAddress {
return hash160ToAddress(hash160($_[0]));
}
sub generateKeyAddressPair {
my $mode;
my %sd;
for (`openssl ecparam -genkey -name secp256k1 -noout |openssl ec -text 2>/dev/null`) {
chomp;
if (/^priv:/) {$mode = "priv"; next}
elsif (/^pub:/) {$mode = "pub"; next}
elsif (/^\S/) {$mode = ""}
if ($mode) {s/[\s:]//g; $sd{$mode} .= uc $_}
}
$sd{priv} = '80' . $sd{priv} if $sd{priv} !~ s/^00/80/;
return (encodeBase58($sd{priv} . checksum($sd{priv})), pubKeyToAddress($sd{pub}));
}
1;