view release on metacpan or search on metacpan
examples/address_creation.pl view on Meta::CPAN
use Blockchain::Ethereum::Keystore::Key;
use Blockchain::Ethereum::Keystore::Seed;
# generating a new address
my $key = Blockchain::Ethereum::Keystore::Key->new();
printf "%s\n", $key->address;
# importing private key
$key = Blockchain::Ethereum::Keystore::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
printf "%s\n", $key->address;
# hdwallet
my $wallet = Blockchain::Ethereum::Keystore::Seed->new();
$key = $wallet->derive_key(0);
printf "%s\n", $key->address;
$key = $wallet->derive_key(1);
printf "%s\n", $key->address;
examples/eip1559_tx_signing.pl view on Meta::CPAN
nonce => '0x0',
max_fee_per_gas => '0x1127A5278',
max_priority_fee_per_gas => '0x79000000',
gas_limit => '0x1DE2B9',
value => '0x0',
data => $encoded,
chain_id => '0x1'
);
my $key = Blockchain::Ethereum::Keystore::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
printf("0x%s", unpack "H*", $raw_transaction);
lib/Blockchain/Ethereum/Keystore.pm view on Meta::CPAN
$keyfile->write_to_file("...");
Signing a transaction:
my $transaction = Blockchain::Ethereum::Transaction::EIP1559->new(
...
);
my $keyfile = Blockchain::Ethereum::Keystore::Keyfile->new;
$keyfile->import_file("...");
$keyfile->private_key->sign_transaction($transaction);
Export private key:
my $keyfile = Blockchain::Ethereum::Keystore::Keyfile->new;
$keyfile->import_file("...");
# private key bytes
print $keyfile->private_key->export;
=head1 OVERVIEW
This module provides a collection of Ethereum wallet management utilities.
Core functionalities:
=over 4
=item * Manage Ethereum keyfiles, facilitating import, export, and password change.
lib/Blockchain/Ethereum/Keystore/Key.pm view on Meta::CPAN
use Crypt::Digest::Keccak256 qw(keccak256);
use Crypt::PRNG qw(random_bytes);
use Blockchain::Ethereum::Keystore::Key::PKUtil;
use Blockchain::Ethereum::Keystore::Address;
sub new {
my ($class, %params) = @_;
my $self = bless {}, $class;
if (exists $params{private_key}) {
$self->{private_key} = $params{private_key};
} else {
$self->{private_key} = random_bytes(32);
}
my $importer = Crypt::PK::ECC->new();
$importer->import_key_raw($self->private_key, 'secp256k1');
# Crypt::PK::ECC does not provide support for deterministic keys
$self->{ecc_handler} = bless Crypt::Perl::ECDSA::Parse::private($importer->export_key_der('private')),
'Blockchain::Ethereum::Keystore::Key::PKUtil';
return $self;
}
sub private_key {
return shift->{private_key};
}
sub _ecc_handler {
return shift->{ecc_handler};
}
sub sign_transaction {
my ($self, $transaction) = @_;
croak "transaction must be a reference of Blockchain::Ethereum::Transaction"
lib/Blockchain/Ethereum/Keystore/Key.pm view on Meta::CPAN
my ($x, $y) = Crypt::Perl::ECDSA::Utils::split_G_or_public($self->_ecc_handler->_decompress_public_point);
# address is the hash of the concatenated value of x and y
my $address = substr(keccak256($x . $y), -20);
my $hex_address = unpack("H*", $address);
return Blockchain::Ethereum::Keystore::Address->new(address => "0x$hex_address");
}
sub export {
return shift->private_key;
}
1;
__END__
=pod
=encoding UTF-8
lib/Blockchain/Ethereum/Keystore/Key.pm view on Meta::CPAN
=head1 SYNOPSIS
Generate a new key:
my $key = Blockchain::Ethereum::Key->new;
$key->sign_transaction($transaction); # Blockchain::Ethereum::Transaction
Import existent key:
my $key = Blockchain::Ethereum::Key->new(private_key => $private_key); # private key bytes
$key->sign_transaction($transaction); # Blockchain::Ethereum::Transaction
=head1 OVERVIEW
This is a private key abstraction
If instantiated without a private key, this module uses L<Crypt::PRNG> for the random key generation
=head1 METHODS
lib/Blockchain/Ethereum/Keystore/Key.pm view on Meta::CPAN
Export the L<Blockchain::Ethereum::Keystore::Address> from the imported/generated private key
=over 4
=back
L<Blockchain::Ethereum::Keystore::Address>
=head2 export
Use `private_key` instead this method is deprecated and will be removed.
=over 4
=back
Private key bytes
=head1 AUTHOR
REFECO <refeco@cpan.org>
lib/Blockchain/Ethereum/Keystore/Keyfile.pm view on Meta::CPAN
use Crypt::PRNG;
use Net::SSH::Perl::Cipher;
use Blockchain::Ethereum::Keystore::Key;
use Blockchain::Ethereum::Keystore::Keyfile::KDF;
sub new {
my ($class, %params) = @_;
my $self = bless {}, $class;
for (qw(cipher ciphertext mac version iv kdf id private_key)) {
$self->{$_} = $params{$_} if exists $params{$_};
}
return $self;
}
sub cipher {
shift->{cipher};
}
lib/Blockchain/Ethereum/Keystore/Keyfile.pm view on Meta::CPAN
}
sub kdf {
shift->{kdf};
}
sub id {
shift->{id};
}
sub private_key {
shift->{private_key};
}
sub _json {
return shift->{json} //= JSON::MaybeXS->new(utf8 => 1);
}
sub import_file {
my ($self, $file_path, $password) = @_;
my $content = read_file($file_path);
lib/Blockchain/Ethereum/Keystore/Keyfile.pm view on Meta::CPAN
$self->{kdf} = Blockchain::Ethereum::Keystore::Keyfile::KDF->new(
algorithm => $crypto->{kdf}, #
dklen => $header->{dklen},
n => $header->{n},
p => $header->{p},
r => $header->{r},
c => $header->{c},
prf => $header->{prf},
salt => $header->{salt});
$self->{private_key} = $self->_private_key($password);
return $self;
}
sub change_password {
my ($self, $old_password, $new_password) = @_;
return $self->import_key($self->_private_key($old_password), $new_password);
}
sub _private_key {
my ($self, $password) = @_;
return $self->private_key if $self->private_key;
my $cipher = Net::SSH::Perl::Cipher->new(
$self->cipher, #
$self->kdf->decode($password),
pack("H*", $self->iv));
my $key = $cipher->decrypt(pack("H*", $self->ciphertext));
return Blockchain::Ethereum::Keystore::Key->new(private_key => $key);
}
sub import_key {
my ($self, $key, $password) = @_;
# use the internal method here otherwise would not be availble to get the kdf params
# salt if give will be the same as the response, if not will be auto generated by the library
my ($derived_key, $salt, $N, $r, $p);
($derived_key, $salt, $N, $r, $p) = Crypt::ScryptKDF::_scrypt_extra($password);
$self->kdf->{algorithm} = "scrypt";
lib/Blockchain/Ethereum/Keystore/Keyfile.pm view on Meta::CPAN
my $cipher = Net::SSH::Perl::Cipher->new(
"AES128_CTR", #
$derived_key,
$iv
);
my $encrypted = $cipher->encrypt($key->export);
$self->{ciphertext} = unpack "H*", $encrypted;
$self->{private_key} = $key;
return $self;
}
sub _write_to_object {
my $self = shift;
croak "KDF algorithm and parameters are not set" unless $self->kdf;
my $file = {
lib/Blockchain/Ethereum/Keystore/Keyfile.pm view on Meta::CPAN
=over 4
=item * C<keyfile> - L<Blockchain::Ethereum::Keystore::Key>
=back
self
=head2 write_to_file
Write the imported keyfile/private_key to a keyfile in the file system
=over 4
=item * C<file_path> - file path to save the data
=back
returns 1 upon successfully writing the file or undef if it encountered an error
=head1 AUTHOR
lib/Blockchain/Ethereum/Keystore/Seed.pm view on Meta::CPAN
$change = 0 unless $change;
my $path = Bitcoin::Crypto::BIP44->new(
index => $index,
purpose => $purpose,
coin_type => $coin_type,
account => $account,
change => $change,
);
return Blockchain::Ethereum::Keystore::Key->new(private_key => $self->_hdw_handler->derive_key($path)->get_basic_key->to_serialized);
}
1;
__END__
=pod
=encoding UTF-8
lib/Blockchain/Ethereum/Transaction.pm view on Meta::CPAN
max_priority_fee_per_gas => '0x0',
gas_limit => '0x1DE2B9',
to => '0x3535353535353535353535353535353535353535'
value => Math::BigInt->new('1000000000000000000'),
data => '0x',
chain_id => '0x539'
);
# github.com/refeco/perl-ethereum-keystore
my $key = Blockchain::Ethereum::Keystore::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
print unpack("H*", $raw_transaction);
Supported transaction types:
lib/Blockchain/Ethereum/Transaction/EIP1559.pm view on Meta::CPAN
max_priority_fee_per_gas => '0x0',
gas_limit => '0x1DE2B9',
to => '0x3535353535353535353535353535353535353535'
value => '0xDE0B6B3A7640000',
data => '0x',
chain_id => '0x539'
);
# github.com/refeco/perl-ethereum-keystore
my $key = Blockchain::Ethereum::Keystore::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
=head1 METHODS
=head2 serialize
lib/Blockchain/Ethereum/Transaction/Legacy.pm view on Meta::CPAN
my $transaction = Blockchain::Ethereum::Transaction::Legacy->new(
nonce => '0x9',
gas_price => '0x4A817C800',
gas_limit => '0x5208',
to => '0x3535353535353535353535353535353535353535',
value => '0xDE0B6B3A7640000',
chain_id => '0x1'
# github.com/refeco/perl-ethereum-keystore
my $key = Blockchain::Ethereum::Keystore::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
=head1 METHODS
=head2 serialize
t/Keystore/key.t view on Meta::CPAN
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
use Blockchain::Ethereum::Keystore::Key;
subtest "0x008AeEda4D805471dF9b2A5B0f38A0C3bCBA786b" => sub {
my $private_key = pack "H*", "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d";
my $key = Blockchain::Ethereum::Keystore::Key->new(private_key => $private_key);
is $key->address, '0x008AeEda4D805471dF9b2A5B0f38A0C3bCBA786b';
};
subtest "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F" => sub {
my $private_key = pack "H*", "4646464646464646464646464646464646464646464646464646464646464646";
my $key = Blockchain::Ethereum::Keystore::Key->new(private_key => $private_key);
is $key->address, '0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F';
};
done_testing();
t/Keystore/keyfile.t view on Meta::CPAN
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
use Blockchain::Ethereum::Keystore::Keyfile;
# https://ethereum.org/pt-br/developers/docs/data-structures-and-encoding/web3-secret-storage/#PBKDF2-SHA-256
subtest "v3_pbkdf2_ctr" => sub {
my $private_key = pack "H*", "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d";
my $password = "testpassword";
my $keyfile = Blockchain::Ethereum::Keystore::Keyfile->new;
my $key = $keyfile->import_file("./t/Keystore/resources/pbkdf2_v3.json", $password);
is $key->private_key->export, $private_key;
$key = $keyfile->import_key(Blockchain::Ethereum::Keystore::Key->new(private_key => $private_key), $password);
is $key->private_key->export, $private_key;
};
# https://ethereum.org/pt-br/developers/docs/data-structures-and-encoding/web3-secret-storage/#scrypt
subtest "v3_scrypt_ctr" => sub {
my $private_key = pack "H*", "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d";
my $password = "testpassword";
my $keyfile = Blockchain::Ethereum::Keystore::Keyfile->new;
my $key = $keyfile->import_file("./t/Keystore/resources/scrypt_v3.json", $password);
is $key->private_key->export, $private_key;
$key = $keyfile->import_key(Blockchain::Ethereum::Keystore::Key->new(private_key => $private_key), $password);
is $key->private_key->export, $private_key;
};
done_testing;
t/Transaction/eip1559.t view on Meta::CPAN
nonce => '0x0',
max_fee_per_gas => '0x9',
max_priority_fee_per_gas => '0x0',
gas_limit => '0x1DE2B9',
value => '0x0',
data => $compiled_contract,
chain_id => '0x539'
);
my $key = Blockchain::Ethereum::Keystore::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
is(unpack("H*", $raw_transaction),
'02f901c3820539808009831de2b98080b90170608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b604...
);
t/Transaction/eip1559.t view on Meta::CPAN
nonce => '0x1',
max_fee_per_gas => '0x9',
max_priority_fee_per_gas => '0x0',
gas_limit => '0x5208',
to => '0x3535353535353535353535353535353535353535',
value => '0xDE0B6B3A7640000',
chain_id => '0x539'
);
my $key = Blockchain::Ethereum::Keystore::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
is(unpack("H*", $raw_transaction),
'02f86c820539018009825208943535353535353535353535353535353535353535880de0b6b3a764000080c080a070816c3d026c13a53e98e5dc414398e9dcdf23e440e777114a3e04810e0dfb5da07d732e6b7f847b06d2baed033772d78407da8f4010fa9300df79f2209ba4c7a0'
);
t/Transaction/legacy.t view on Meta::CPAN
my $transaction = Blockchain::Ethereum::Transaction::Legacy->new(
nonce => '0x9',
gas_price => '0x4A817C800',
gas_limit => '0x5208',
to => '0x3535353535353535353535353535353535353535',
value => '0xDE0B6B3A7640000',
chain_id => '0x1'
);
my $key = Blockchain::Ethereum::Keystore::Key->new(
private_key => pack "H*",
'4646464646464646464646464646464646464646464646464646464646464646'
);
$key->sign_transaction($transaction);
my $raw_transaction = $transaction->serialize;
is(unpack("H*", $raw_transaction),
'f86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83'
);