-
-
Save anonymous/8ad5a5766ba754e57fd5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
# | |
# WARNING! | |
# | |
# TO,OOO,OOO dirty | |
# | |
# YOURE CANT UNSEE IT! | |
# | |
use strict; | |
use warnings; | |
use Math::BigInt; | |
use Crypt::RIPEMD160; | |
use Digest::SHA qw(sha256_hex); | |
# Private key exponent | |
# Gives right result: 0284196c3028cbe20c29d0d1c1d5c24a09bd3f028bbc2d1c76dde0816a28365c | |
# Gives wrong result: 835c6975aa65f95cb55616ace8c8bede83b010f7191c0a6d385be1c95992870d | |
my $k = "0284196c3028cbe20c29d0d1c1d5c24a09bd3f028bbc2d1c76dde0816a28365c"; | |
# Base58 func was taken from http://lenschulwitz.com/b58/base58perl.txt | |
my @b58 = qw{ | |
1 2 3 4 5 6 7 8 9 | |
A B C D E F G H J K L M N P Q R S T U V W X Y Z | |
a b c d e f g h i j k m n o p q r s t u v w x y z | |
}; | |
my %b58 = map { $b58[$_] => $_ } 0 .. 57; | |
my %reverseb58 = reverse %b58; | |
sub base58 { | |
my @binary_address_to_encode = @{$_[0]}; | |
die "Subroutine base58 needs binary decimal array to encode!\n" unless @binary_address_to_encode; | |
my $base58_encoded_array_size = 2 * scalar @binary_address_to_encode; | |
my @base58_encoded_address; | |
my $leading_zeroes = length $1 if join('', @binary_address_to_encode) =~ /^(0*)/; | |
for my $dec_char ( @binary_address_to_encode ) { | |
for (my $encoded_character_index = $base58_encoded_array_size; $encoded_character_index--; ) { | |
$dec_char += 256 * ($base58_encoded_address[$encoded_character_index] // 0); | |
$base58_encoded_address[$encoded_character_index] = $dec_char % 58; | |
$dec_char /= 58; | |
} | |
} | |
my $encoded_address_with_leading_1s = join('', map { $reverseb58{$_} } @base58_encoded_address); | |
if ($encoded_address_with_leading_1s =~ /(1{$leading_zeroes}[^1].*)/){ | |
return $1; | |
} | |
elsif ($encoded_address_with_leading_1s =~ /(1{$leading_zeroes})/){ | |
return $1; | |
} | |
else{ | |
die "Unexpected error in subroutine base58!\n"; | |
} | |
} | |
sub encodebase58fromhex { | |
my $hex_binary_address = $_[0]; | |
die "Subroutine encodebase58fromhex needs binary address represented with hex characters as input!" unless (defined $hex_binary_address and length $hex_binary_address != 0); | |
die "Cannot Encode! Invalid Hexadecimal Character(s)!\n" unless $hex_binary_address =~ /^[a-f0-9]*$/i; | |
my @binary_address_to_encode = $hex_binary_address =~ /../g; | |
for( 0 .. scalar(@binary_address_to_encode)-1 ){ | |
$binary_address_to_encode[$_] = hex($binary_address_to_encode[$_]); | |
} | |
my $std_bitcoin_address = base58(\@binary_address_to_encode); | |
return $std_bitcoin_address; | |
} | |
# Ok, here we go | |
&processKey("0x$k"); | |
sub processKey() { | |
my $k = shift; | |
my %p = getPubKeyPoints($k); | |
my ($pkh, $pkhs, $pkhr, $pkhrd, $pkhrde, $pkhrdeh1, $pkhrdeh2, $pkhrdeh2c, $pkhrdec, $pkb); | |
my ($pkch, $pkchs, $pkchr, $pkchrd, $pkchrde, $pkchrdeh1, $pkchrdeh2, $pkchrdeh2c, $pkchrdec, $pkcb); | |
$p{"x"} = substr($p{"x"}, 2, length($p{"x"}) - 2); | |
$p{"y"} = substr($p{"y"}, 2, length($p{"y"}) - 2); | |
while(length($p{'x'}) < 64) { | |
$p{'x'} = '0' . $p{'x'}; | |
} | |
while(length($p{'y'}) < 64) { | |
$p{'x'} = '0' . $p{'x'}; | |
} | |
if ((Math::BigInt->new("0x" . $p{"x"})->is_even())) { | |
$pkch = "02" . $p{"x"}; | |
} else { | |
$pkch = "03" . $p{"x"}; | |
} | |
print "X: " . $p{"x"} . "\n"; | |
print "Y: " . $p{"y"} . "\n"; | |
$pkh = "04" . $p{"x"} . $p{"y"}; | |
print "pkh = $pkh\n"; | |
print "pkch = $pkch\n"; | |
$pkhs = sha256_hex(pack('H*', $pkh)); | |
$pkhr = new Crypt::RIPEMD160; | |
$pkhr->add(pack('H*', $pkhs)); | |
$pkhrd = $pkhr->hexdigest(); | |
$pkhrd =~ s/\s//g; | |
$pkhrde = '00' . $pkhrd; | |
$pkhrdeh1 = sha256_hex(pack('H*', $pkhrde)); | |
$pkhrdeh2 = sha256_hex(pack('H*', $pkhrdeh1)); | |
$pkhrdeh2c = substr($pkhrdeh2, 0, 8); | |
$pkhrdec = $pkhrde . $pkhrdeh2c; | |
$pkb = encodebase58fromhex($pkhrdec); | |
print "Uncompressed: $pkb\n"; | |
$pkchs = sha256_hex(pack('H*', $pkch)); | |
$pkchr = new Crypt::RIPEMD160; | |
$pkchr->add(pack('H*', $pkchs)); | |
$pkchrd = $pkchr->hexdigest(); | |
$pkchrd =~ s/\s//g; | |
$pkchrde = '00' . $pkchrd; | |
$pkchrdeh1 = sha256_hex(pack('H*', $pkchrde)); | |
$pkchrdeh2 = sha256_hex(pack('H*', $pkchrdeh1)); | |
$pkchrdeh2c = substr($pkchrdeh2, 0, 8); | |
$pkchrdec = $pkchrde . $pkchrdeh2c; | |
$pkcb = encodebase58fromhex($pkchrdec); | |
print "Compressed: $pkcb\n"; | |
} | |
sub getPubKeyPoints() { | |
my $k = Math::BigInt->new(shift); | |
my $a = Math::BigInt->new("0x0"); | |
my $b = Math::BigInt->new("0x7"); | |
my $p = Math::BigInt->new("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"); | |
my $n = Math::BigInt->new("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); | |
my %g = ( | |
"x" => Math::BigInt->new("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"), | |
"y" => Math::BigInt->new("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"), | |
); | |
my %pubkey = mulPoint(\%g, $k, $a, $b, $p); | |
$pubkey{"x"} = Math::BigInt->new($pubkey{"x"})->as_hex(); | |
$pubkey{"y"} = Math::BigInt->new($pubkey{"y"})->as_hex(); | |
# ==== | |
$pubkey{"x"} = substr($pubkey{"x"}, 2, length($pubkey{"x"}) - 2); | |
$pubkey{"y"} = substr($pubkey{"y"}, 2, length($pubkey{"y"}) - 2); | |
while(length($pubkey{'x'}) < 64) { | |
$pubkey{'x'} = '00' . $pubkey{'x'}; | |
} | |
while(length($pubkey{'y'}) < 64) { | |
$pubkey{'x'} = '00' . $pubkey{'x'}; | |
} | |
# ==== | |
$pubkey{"x"} = Math::BigInt->new("0x" . $pubkey{"x"})->as_hex(); | |
$pubkey{"y"} = Math::BigInt->new("0x" . $pubkey{"y"})->as_hex(); | |
return %pubkey; | |
} | |
sub mulPoint { | |
my %g = %{shift()}; | |
my $k = shift; | |
my $a = shift; | |
my $b = shift; | |
my $p = shift; | |
my $kb = $k->copy()->as_bin(); | |
$kb = substr($kb, 2, length($kb) - 2); | |
my $kbl = length($kb); | |
my %lastpoint = %g; | |
my %dpt = (); | |
my $i = 1; | |
for ($i = 1; $i < $kbl; $i ++) { | |
if (substr($kb, $i, 1) eq 1) { | |
%dpt = doublePoint(\%lastpoint, $a, $p); | |
%lastpoint = addPoints(\%dpt, \%g, $a, $p); | |
} else { | |
%lastpoint = doublePoint(\%lastpoint, $a, $p); | |
} | |
} | |
return %lastpoint; | |
} | |
sub addPoints { | |
my %pt1 = %{shift()}; | |
my %pt2 = %{shift()}; | |
my $a = shift; | |
my $p = shift; | |
my $pt1x = $pt1{"x"}; | |
my $pt1y = $pt1{"y"}; | |
my $pt2x = $pt2{"x"}; | |
my $pt2y = $pt2{"y"}; | |
my $number2 = Math::BigInt->new(2); | |
my $number3 = Math::BigInt->new(3); | |
if (($pt1x->bcmp($pt2x)) eq 0 && ($pt1y->bcmp($pt2y)) eq 0) { | |
return doublePoint(\%pt1, $a, $p); | |
} | |
my $gcd_sub = $pt1x->copy()->bsub($pt2x); | |
my @gcd_arr = ($gcd_sub, $p); | |
my $gcd = Math::BigInt::bgcd(@gcd_arr); | |
if ($gcd != 1) { | |
print "Possibly INFINITY there, does not know what to do with that\n"; | |
exit; | |
} | |
my $pt_sub1 = $pt1x->copy()->bsub($pt2x); | |
my $pt_inv = $pt_sub1->copy->bmodinv($p); | |
my $pt_sub2 = $pt1y->copy()->bsub($pt2y); | |
my $pt_mul = $pt_sub2->copy()->bmul($pt_inv); | |
my $slope = $pt_mul->copy()->bmod($p); | |
my %nPt = (); | |
my $nPtx_pow = $slope->copy()->bpow($number2); | |
my $nPtx_sub1 = $nPtx_pow->copy()->bsub($pt1x); | |
my $nPtx_sub2 = $nPtx_sub1->copy()->bsub($pt2x); | |
my $nPtx_mod = $nPtx_sub2->copy()->bmod($p); | |
$nPt{"x"} = $nPtx_mod; | |
my $nPty_sub1 = $pt1x->copy()->bsub($nPtx_mod); | |
my $nPty_mul = $slope->copy()->bmul($nPty_sub1); | |
my $nPty_sub2 = $nPty_mul->copy()->bsub($pt1y); | |
my $nPty_mod = $nPty_sub2->copy()->bmod($p); | |
$nPt{"y"} = $nPty_mod; | |
return %nPt; | |
} | |
sub doublePoint { | |
my %pt = %{shift()}; | |
my $a = shift; | |
my $p = shift; | |
my $ptx = $pt{"x"}; | |
my $pty = $pt{"y"}; | |
my $number2 = Math::BigInt->new(2); | |
my $number3 = Math::BigInt->new(3); | |
my $pt_ymul = $pty->copy()->bmul($number2); | |
my $pt_ymod = $pt_ymul->copy()->bmod($p); | |
my $pt_yinv = $pt_ymod->copy()->bmodinv($p); | |
my $pt_xpow = $ptx->copy()->bpow($number2); | |
my $pt_xmul = $pt_xpow->copy()->bmul($number3); | |
my $pt_xadd = $pt_xmul->copy()->badd($a); | |
my $pt_xymul = $pt_yinv->copy()->bmul($pt_xadd); | |
my $slope = $pt_xymul->copy()->bmod($p); | |
my %nPt = (); | |
my $nPtx_pow = $slope->copy()->bpow($number2); | |
my $nPtx_sub1 = $nPtx_pow->copy()->bsub($ptx); | |
my $nPtx_sub2 = $nPtx_sub1->copy()->bsub($ptx); | |
my $nPtx_mod = $nPtx_sub2->copy()->bmod($p); | |
$nPt{"x"} = $nPtx_mod; | |
my $nPty_sub1 = $ptx->copy()->bsub($nPtx_mod); | |
my $nPty_mul = $slope->copy()->bmul($nPty_sub1); | |
my $nPty_sub2 = $nPty_mul->copy()->bsub($pty); | |
my $nPty_mod = $nPty_sub2->copy()->bmod($p); | |
$nPt{"y"} = $nPty_mod; | |
return %nPt; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment