Crypt-HashCash
view release on metacpan or search on metacpan
bin/hashcash.pl view on Meta::CPAN
$continue = $ProgressDialog->Update($j++, "Unblinding and adding coin " . ($j - $numcoins - 3));
my $coin = $client->unblind_coin($_);
$client->verify_coin($coin) && $stash->addcoins('V',$coin);
}
}
$continue = $ProgressDialog->Update($j);
show();
};
$action{Export} = sub { # Export Coins
my $dialog = Wx::TextEntryDialog->new( $frame, "Amount to export (in Satoshi)", "Export coins from wallet");
my $dialog_height = $dialog->GetSize->GetHeight;
my $fontheight = $frame->GetCharHeight;
if($dialog->ShowModal == wxID_CANCEL) {
return;
};
my $amt = $dialog->GetValue();
return unless $amt and $amt !~ /\D/;
if ($amt % $client->denoms->[0]) {
$dialog = Wx::MessageDialog->new( $frame, "The amount to export should be a multiple of " . $client->denoms->[0],
"Unsupported denomination", wxOK);
if($dialog->ShowModal == wxID_OK) {
return;
}
}
if ($amt > $stash->balance) {
$dialog = Wx::MessageDialog->new( $frame, "Your balance " . $stash->balance . " is lower than $amt", "Not enough cash", wxOK);
if($dialog->ShowModal == wxID_OK) {
return;
}
}
$statusBar->SetStatusText("Export $amt", 0);;
my ($coins, $change) = $stash->getcoins($amt);
if ($change) {
$stash->addcoins('V',@$coins);
$dialog = Wx::MessageDialog->new( $frame, "You don't have exact change to export $amt", "Need change", wxOK);
return if $dialog->ShowModal;
}
return unless $coins;
my $wordlist = 'Common'; $wordlist = uc($lang) if $lang =~ /(es|it|hi|de|gr|zh|ja|ru)/;
my @words = eval 'use Crypt::Diceware words => { wordlist => $wordlist }; words(4);';
$dialog = Wx::TextEntryDialog->new( $frame, "Passphrase (blank for no encryption - NOT RECOMMENDED!)",
"Coin encryption passphrase", join (' ', @words));
$stash->addcoins('V',@$coins), return if $dialog->ShowModal == wxID_CANCEL;
my $passphrase = $dialog->GetValue();
if ($passphrase) {
$dialog = Wx::TextEntryDialog->new( $frame, "Passphrase Confirm", "Coin encryption passphrase");
$stash->addcoins('V',@$coins), return if $dialog->ShowModal == wxID_CANCEL or $dialog->GetValue() ne $passphrase;
}
my $coinexp = _hex($client->keydb->{id}); $coinexp = '0' x (32 - length($coinexp)) . $coinexp;
$coinexp = unpack('H*','[#]' . substr($client->sigscheme, 0, 1)) . $coinexp;
# print STDERR "COINEXP: $coinexp\n";
for (@$coins) {
# $coinexp .= ' ' . $_->as_string;
$coinexp .= $_->as_hex;
}
$coinexp = pack('H*', $coinexp);
if ($passphrase) {
my $cipher = Crypt::CBC->new (-key => $passphrase, -cipher => 'Rijndael', -header => 'salt');
$coinexp = $cipher->encrypt($coinexp);
}
$coinexp = _squish($coinexp);
my ($msg, $qr, $st) = ('Copy coins from below');
my $len = length($coinexp);
if ($len < 7090 ) {
my $qrfh; my $level;
my @version = qw( 0 41 77 127 187 255 322 370 461 552 652 772 883 1022 1101 1250 1408 1548 1725 1903 2061 2232
2409 2620 2812 3057 3283 3517 3669 3909 4158 4417 4686 4965 5253 5529 5836 6153 6479 6743 7089 );
for (1..40) { next if $len > $version[$_]; $version = $_; last; }
my $qrxpm = GD::Barcode::QRcode->new($coinexp, { Version => $version, Ecc => L, ModuleSize => 2 })->barcode;
$qrxpm =~ /^(.*)$/m; my $qrsize = length($1);
$qr = Wx::Bitmap->newFromXPM([ split /\n/, "$qrsize $qrsize 2 1\n0 c #FFFFFF\n1 c #000000\n$qrxpm" ]);
$msg = "\n" x ($qr->GetHeight / $fontheight) . "\n\nScan the QR code or copy coins from below";
}
$dialog = Wx::TextEntryDialog->new( $frame, $msg , 'Export coins', $coinexp);
if (defined $qr) {
my $dialogwidth = $dialog->GetSize->GetWidth;
my $qrheight = $qr->GetHeight; my $width = $qrheight + 20 > $dialogwidth ? $qrheight + 20 : $dialogwidth;
my $adjust = 10 unless $^O eq 'MSWin32' or $^O eq 'darwin';
my $qrpos = ($width-$qrheight)/2 + ($width == 300 ? $adjust : 0);
$dialog->SetSize([$width,$dialog_height+$qrheight+$fontheight+10]);
$dialog->SetMinSize([$width,$dialog_height+$qrheight+$fontheight+10]);
$dialog->SetMaxSize([$width,$dialog_height+$qrheight+$fontheight+10]);
$st = Wx::StaticBitmap->new( $dialog, -1, $qr, [$qrpos,10] );
}
if($dialog->ShowModal == wxID_CANCEL) {
$stash->addcoins('V',@$coins);
}
show();
};
$action{Import} = sub { # Add coins to wallet
my $dialog = Wx::TextEntryDialog->new( $frame, "Paste coins below", "Add coins to wallet");
if($dialog->ShowModal == wxID_CANCEL) {
return;
};
my $coins = $dialog->GetValue();
$coins = _unsquish($coins);
my (@coins, @coinstrs, $sigscheme, $vaultid);
$coins = unpack('H*', $coins);
if ($coins =~ /^5b235d(52|45)/) {
$coins =~ /^5b235d(52|45)([0-9a-f]{32})(.*)$/; ($sigscheme, $vaultid, $coins) = ($1, _dec($2), $3);
my $coinsize = $sigscheme == 52 ? 296 : 170;
while (my $coinstr = substr($coins, 0, $coinsize, '')) { push @coinstrs, $coinstr }
}
else {
$dialog = Wx::TextEntryDialog->new( $frame, "Enter passphrase to decrypt coins", "Add coins to wallet");
if($dialog->ShowModal == wxID_CANCEL) {
return;
}
my $passphrase = $dialog->GetValue();
my $cipher = Crypt::CBC->new (-key => $passphrase, -cipher => 'Rijndael');
my $decrypted = $cipher->decrypt(pack 'H*', $coins); $decrypted =~ s/\s*$//;
return unless $decrypted =~ /^\[\#\](R|E)/;
$decrypted = unpack('H*',$decrypted);
$decrypted =~ /^5b235d(52|45)([0-9a-f]{32})(.*)$/; ($sigscheme, $vaultid, $coins) = ($1, _dec($2), $3);
my $coinsize = ($sigscheme == 52) ? 296 : 170;
while (my $coinstr = substr($coins, 0, $coinsize, '')) { push @coinstrs, $coinstr }
}
unless ($vaultid eq $client->keydb->{id}) {
$dialog = Wx::MessageDialog->new( $frame, "Please switch to the vault with ID\n$vaultid\nto import these coins.", "Add coins to wallet", wxOK);
if($dialog->ShowModal == wxID_OK) {
return;
}
}
for (@coinstrs) {
my $coin = Crypt::HashCash::Coin->from_hex($_);
push @coins, $coin if $coin;
}
if (scalar @coins) {
my $continue = 1; my $max = scalar @coins; my $i = 0;
my $ProgressDialog = Wx::ProgressDialog->new("Adding Coins", "Adding coins to wallet", $max, $frame,
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_ELAPSED_TIME |
wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME);
for my $coin (@coins) {
$ProgressDialog->Update($i++, "Adding coin $i");
$ProgressDialog->Update($i++), next unless $client->verify_coin($coin);
if ($stash->addcoins('U',$coin)) {
$ProgressDialog->Update($i . '.5', "Added coin $i");
}
else {
$ProgressDialog->Update($i, "Coin $i is a duplicate, skipped");
}
}
}
show();
};
$action{Exchange} = sub { # Exchange / verify coins
my $unverified = scalar grep { defined $stash->{$_}->{U} } grep { !/^_/ } keys %$stash;
my ($choice, $i, $j, $continue, $dialog) = (1, 0, 1);
my (@coins, $amt, $numcoins, $denoms, $d);
my ($feecoins, $change, $numchgcoins, $chgdenoms);
if ($unverified) {
$dialog = Wx::SingleChoiceDialog->new( $frame, "Select type of exchange", "Exchange or verify coins",
["Verify all unverified coins", "Make change for a specific amount"]);
return if $dialog->ShowModal == wxID_CANCEL;
$choice = $dialog->GetSelection();
}
my $feefromxchgcoin;
if ($choice == 1) {
$dialog = Wx::TextEntryDialog->new( $frame, "Denomination of coin to get change for", "Exchange coin");
return if $dialog->ShowModal == wxID_CANCEL;
$amt = $dialog->GetValue();
return unless $amt and $amt !~ /\D/ and $amt > 1;
unless ($stash->havedenom($amt)) {
return if Wx::MessageDialog->new( $frame, "Don't have a verified coin of denomination $amt", "Exchange coin", wxOK)->ShowModal;
}
$statusBar->SetStatusText("Exchange $amt", 0);
($denoms, $numcoins) = changecoin($amt);
my $fee = $fee{vf} + $numcoins * $fee{mf} + int($amt * ($fee{mp} + $fee{vp}));
$fee = $fee + ($client->denoms->[0] - ($fee % $client->denoms->[0]));
( run in 1.052 second using v1.01-cache-2.11-cpan-e1769b4cff6 )