I'm trying to generate Dogecoin addresses. The generated addresses have the same length as valid Dogecoin addresses generated by RPC-API getnewaddress and the same length, but they do not work. They are not valid.
Here are the steps:
- Public key from secp256k1
- Apply SHA256, then RIPEMD-160 to the result of SHA256
- Add 0x1E (Version for Dogecoin) at the begin of the RIPEMD-160 result
- Apply SHA256 twice to the encrypted pubkey for the checksum hash
- Add first 4 bytes of the checksum hash (8 characters) to the end of the encrypted pub key
- Apply BASE56
That generates a 34 characters address starting with D which looks very authentic, but none of them is valid. Why?
use strict;
use warnings;
use Digest::SHA qw(sha256);
use Crypt::PK::ECC;
use Crypt::RIPEMD160;
use v5.10;
use Bitcoin::Crypto::Base58 qw(
encode_base58
decode_base58
encode_base58check
decode_base58check
);
# Bitcoin Version 0x00
# Dogecoin Version 0x1E
sub append_checksum_and_version {
my ($binstr) = @_;
return (chr(0x1E) . $binstr . substr(sha256(sha256($binstr)), 0, 4));
}
my $pk = Crypt::PK::ECC->new();
$pk->generate_key('secp256k1');
my $public_raw = $pk->export_key_raw('public');
my $encrypted_pubkey = Crypt::RIPEMD160->hash(sha256($public_raw));
say "Private Key: " . unpack "H*", $pk->export_key_raw('private');
say "Dogecoin Address: " . encode_base58(append_checksum_and_version($encrypted_pubkey));
Output:
Dogecoin Address: DGRHFUwqvzh8VBFR1gAhRFVbM476bATZVK Dogecoin Address: DEvMuu6PbQLDQE72aofFzxk5c8AmzRZos9 Dogecoin Address: DM1zqiW5ZPb1MD8hP1sxtBsPkQAofFTRTw
Maybe the checksum calculation is not correct? Even if I use 0x00 instead of 0x1E for Bitcoin. The Bitcoin addresses are not valid either.
CodePudding user response:
It turned out there was a byte missing.
return (chr(0x1E) . $binstr . substr(sha256(sha256($binstr)), 0, 4));
must be replaced to
return (chr(0x1E) . $binstr . substr(sha256(sha256(chr(0x1E) . $binstr)), 0, 4));
The version byte of 0x1E (Dogecoin) or 0x00 (Bitcoin) must be included in the double sha256 calculation for the checksum.
use strict;
use warnings;
use Digest::SHA qw(sha256);
use Crypt::PK::ECC;
use Crypt::RIPEMD160;
use Bitcoin::Crypto::Base58 qw(encode_base58 decode_base58 encode_base58check decode_base58check);
use v5.10;
# Version byte: Bitcoin 0x00, Dogecoin 0x1E
sub cv {
my ($binstr) = @_;
return (chr(0x1E) . $binstr . substr(sha256(sha256(chr(0x1E) . $binstr)), 0, 4));
}
my $pk = Crypt::PK::ECC->new()->generate_key('secp256k1');
my $dogecoin_address = encode_base58(cv(Crypt::RIPEMD160->hash(sha256($pk->export_key_raw('public')))));
say "Dogecoin Address: " . $dogecoin_address;
Gives valid addresses:
Dogecoin Address: DR61RhFNCkswmDx6JjLyVPSoq51gBtxxjK
Dogecoin Address: DFFV4xa9Ph2LUXaKbyxMtViHFhu9e9h88J
Dogecoin Address: DAk4ZbSoWnhpt2exkEevG2j93CVEL7g5Fu
UPDATE:
If you want to generate the wifkey for Dogecoin from pubkey. The version byte for mainnet is 0x9E (Dogecoin) and 0x80 (Bitcoin)
sub toWifKey {
my ($binstr) = @_;
return (chr(0x9E). $binstr . substr(sha256(sha256(chr(0x9E) . $binstr)), 0, 4));
}
my $wifkey = encode_base58(toWifKey($pk->export_key_raw('private')));