App-Bitcoin-PaperWallet

 view release on metacpan or  search on metacpan

bin/paper-wallet  view on Meta::CPAN

=item -a, --auto

Generate entropy automatically using cryptographically-secure pseudorandom
number generator.

=item -o, --stdout

Do not print to file, use standard output instead. The script will not behave
interactively and instead will wait for data on standard input without
prompting anything. Best used with C<--auto> and a single standard input line
for password, or two lines: one for entropy, one for password

=item -f [FILE], --file [FILE]

Specify filename to print to - default is C<wallet.txt>. Has no effect if
C<--stdout> is passed.

=item -w [NUMBER], --words [NUMBER]

A number of words to be generated. Must be 12, 15, 18, 21 or 24. Default 24.

bin/paper-wallet  view on Meta::CPAN

This script will generate a file in your current working directory that
contains Bitcoin wallet details ready to be printed, written down or stored on
a flash drive. This file must not exist already or the script will fail (to
ensure that you don't override your previously generated wallet that you might
have already used).

This is intended to be used as cold storage (Bitcoin wallet which does not have
active connection to the Internet). The generation should best take place while
being offline.

The script will interactively ask for wallet password and entropy (random data
that secures your funds). If you don't have any means to generate random data,
like rolling dice, or you don't know how to properly do so (to ensure large
enough entropy), it is recommended to use the C<--auto> flag, which will use
secure random generators to do it for you. Password can be skipped by hitting
enter, but it is not recommended to do so. Remember that there is no way to
restore your password, so make sure you won't lose it.

After printing, you can cut off the top section (mnemonic seed) and store it
apart from the addresses for safety. You can also write the mnemonic seed down
by hand and only print the addresses part.

=head2 Security

With Bitcoin, information is money. You should be wary (or even paranoid) of
possible dangers during generation of your wallet.

bin/paper-wallet  view on Meta::CPAN

running. Best, use security-focused system like OpenBSD.

=item * Disable Internet connection during generation

If your seed is going to leak, it will do so through the Web. As long as you
have the seed on your computer, avoid being online.

=item * Only store the seed physically

Paper or metal are unhackable. If they are stolen, you can move the funds
elsewhere before they crack your password - as long as you keep the second copy
in a different location.

=item * Don't print the seed, write it down

It is especially true if you have a printer which is connected to your local
network. Regular USB-only printers should be fine, but you never know if they
keep copies of what they printed somewhere. Never ever use printers you have at
work.

=item * Remove the seed from your computer when you're done

bin/paper-wallet  view on Meta::CPAN

knowing:

=over

=item * If you opened a file with a program, it might have saved a draft copy somewhere

=item * Even if you deleted the file, it may still stick around in Trash

=item * Some systems may synchronize contents of a directory with the cloud

=item * If you forget your password, there's no way to recover it

=back

lib/App/Bitcoin/PaperWallet.pm  view on Meta::CPAN

__END__

=head1 NAME

App::Bitcoin::PaperWallet - Generate printable cold storage of bitcoins

=head1 SYNOPSIS

	use App::Bitcoin::PaperWallet;

	my $hash = App::Bitcoin::PaperWallet->generate($entropy, $password, {
		entropy_length => 128,
	});

	my $mnemonic = $hash->{mnemonic};
	my $addresses = $hash->{addresses};

=head1 DESCRIPTION

This module allows you to generate a Hierarchical Deterministic BIP49/84
compilant Bitcoin wallet.

This package contains high level cryptographic operations for doing that. See
L<paper-wallet> for the main script of this distribution.

=head1 FUNCTIONS

=head2 generate

	my $hash = $class->generate($entropy, $password, \%opts);

Not exported, should be used as a class method. Returns a hash containing two
keys: C<mnemonic> (string) and C<addresses> (array reference of strings).

C<$entropy> is meant to be user-defined entropy (string) that will be passed
through sha256 to obtain wallet seed. Can be passed C<undef> explicitly to use
cryptographically secure random number generator instead.

C<$password> is a password that will be used to secure the generated mnemonic.
Passing empty string will disable the password protection. Note that password
does not have to be strong, since it will only secure the mnemonic in case
someone obtained physical access to your mnemonic. Using a hard, long password
increases the possibility you will not be able to claim your bitcoins in the
future.

C<\%opts> can take following values:

=over

=item * C<compat_addresses>

A number of segwit compat (purpose 49) addresses to generate, 1 by default.

lib/App/Bitcoin/PaperWallet.pm  view on Meta::CPAN

=head1 CAVEATS

=over

=item

This module should properly handle unicode in command line, but for in-Perl
usage it is required to pass UTF8-decoded strings to it (like with C<use
utf8;>).

Internally, passwords are handled as-is, while seeds are encoded into UTF8
before passing them to SHA256.

=item

An extra care should be taken when using this module on Windows command line.
Some Windows-specific quirks may not be handled properly. Verify before sending
funds to the wallet.

=back

lib/App/Bitcoin/PaperWallet.pm  view on Meta::CPAN

Versions 1.01 and older generated addresses with invalid derivation paths.
Funds in these wallets won't be visible in most HD wallets, and have to be
swept by revealing their private keys in tools like
L<https://iancoleman.io/bip39/>. Use derivation path C<m/44'/0'/0'/0> and
indexes C<0> throughout C<3> - sweeping these private keys will recover your
funds.

=item

Versions 1.02 and older incorrectly handled unicode. If you generated a wallet
with unicode password in the past, open an issue in the bug tracker.

=back

=head1 SEE ALSO

L<Bitcoin::Crypto>

=head1 AUTHOR

Bartosz Jarzyna, E<lt>bbrtj.pro@gmail.comE<gt>

t/generate.t  view on Meta::CPAN

use Test2::V0;
use App::Bitcoin::PaperWallet;

subtest 'should generate mnemonic from fixed entropy' => sub {
	my $hash = App::Bitcoin::PaperWallet->generate('silly entropy that should never be used in a real wallet', 'sillypass');

	# seed should be 76f30b114cb9165116a9b0a9e214e3ea4cfa9923adc8154e5d72b12e54b5a20a
	is $hash->{mnemonic}, 'ivory obscure session offer multiply chuckle follow current prepare awful decline stand soul erode modify ribbon best indicate frequent girl torch food market evidence', 'mnemonic ok';

	# those addresses take password into account
	is $hash->{addresses}[0], '3QUyruDJ9oce8KNJELPWAxfcvcvESuGrds', 'compat address ok';
	is $hash->{addresses}[1], 'bc1qm2s2u6rp8u40kwht7fm8nnfgew0vt4t7hftmf9', 'native address 1 ok';
	is $hash->{addresses}[2], 'bc1qngdesm3ljdfyxsskvsxz4034vlyk9cjm7r6k5p', 'native address 2 ok';
	is $hash->{addresses}[3], 'bc1qp67k9ztxp5gycvt3pc8cxm0ssha226sqe338q8', 'native address 3 ok';

	is scalar @{$hash->{addresses}}, 4, 'address count ok';

	# test data generated using https://iancoleman.io/bip39/
};

subtest 'should generate shorter mnemonic from fixed entropy and no compat addresses' => sub {
	my $hash = App::Bitcoin::PaperWallet->generate('silly entropy that should never be used in a real wallet', 'sillypass', {
		compat_addresses => 0,
		entropy_length => 160,
	});

	# seed should be 76f30b114cb9165116a9b0a9e214e3ea4cfa9923
	is $hash->{mnemonic}, 'ivory obscure session offer multiply chuckle follow current prepare awful decline stand soul erode misery', 'mnemonic ok';

	# those addresses take password into account
	is $hash->{addresses}[0], 'bc1qqns5u7ek4dhsg0x3q6dfrsdqqdy5gtgnrzplar', 'native address 1 ok';
	is $hash->{addresses}[1], 'bc1qvpkk52g7fm64l482eln3unf659epqhtpcqt3hm', 'native address 2 ok';
	is $hash->{addresses}[2], 'bc1qyq9sanwvrd300erymsln58myar55fr2cldmcgx', 'native address 3 ok';

	is scalar @{$hash->{addresses}}, 3, 'address count ok';

	# test data generated using https://iancoleman.io/bip39/
};

subtest 'should generate mnemonic from random entropy' => sub {

t/script.t  view on Meta::CPAN

use Test2::V0;
use Test::Script;
use Encode qw(encode);

use constant SCRIPT_PATH => 'bin/paper-wallet';

my $input = encode 'UTF-8', "entropyż\npasswordż\n";
my $expected_seed = 'crush village tuna perfect supply movie pelican believe square neutral lens manual ship observe firm black cram brisk gallery arrest cactus tray marble over';
my $expected_address = '3HfnewBEDykB7gncDz78uzPvAvgrsNyvsy';

subtest 'testing standard output' => sub {
	my $output = "";

	script_runs([SCRIPT_PATH, '-o'], {
		stdin => \$input,
		stdout => \$output,
	}, 'script runs ok');

	like $output, qr/$expected_seed/, 'seed ok';
	like $output, qr/$expected_address/, 'address ok';
};

subtest 'testing auto entropy' => sub {
	my $output = "";

	# first line of $input will be used as password in this scenario
	script_runs([SCRIPT_PATH, '-o', '-a'], {
		stdin => \$input,
		stdout => \$output,
	}, 'script runs ok');

	unlike $output, qr/$expected_seed/, 'seed ok';
	unlike $output, qr/$expected_address/, 'address ok';
};

done_testing;

t/unicode.t  view on Meta::CPAN

use Test2::V0;
use App::Bitcoin::PaperWallet;

my $hash = App::Bitcoin::PaperWallet->generate('another silly entropy that should never be used in a real wallet with ąść', 'ąśćź 1');

# seed should be 6f1a6e66b9c2a706a5f4c16bb0ea34a54577bda27d7a0900be9e8afc952e731e
is $hash->{mnemonic}, 'humor square often inform clerk local oak oblige hill mansion minor enhance first tell measure quantum animal album police bicycle sing now small that', 'mnemonic ok';

# those addresses take password into account
is $hash->{addresses}[0], '3NjcWMUFzw1oEobkFx9ggo2i6QuKaRbTfG', 'compat address ok';
is $hash->{addresses}[1], 'bc1qfm507lwuadw08c98eae862hv2jaesm2gwp8w02', 'native address 1 ok';
is $hash->{addresses}[2], 'bc1ql8kh0gh2gcrhjqu7dnnehlxvphsf5pajucspgr', 'native address 1 ok';
is $hash->{addresses}[3], 'bc1qplyhz7fzx0jledt7533afc6z4d2zk7zg4sjdhq', 'native address 2 ok';

is scalar @{$hash->{addresses}}, 4, 'address count ok';

# test data generated using https://iancoleman.io/bip39/

done_testing;



( run in 0.745 second using v1.01-cache-2.11-cpan-49f99fa48dc )