Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -1,4 +1,8 @@
Write a program that takes a [[wp:bitcoin|bitcoin address]] as argument, and checks whether or not this address is valid.
{{omit from|Brlcad}}
{{omit from|GUISS}}
Write a program that takes a [[wp:bitcoin|bitcoin address]] as argument,
and checks whether or not this address is valid.
A bitcoin address uses a base58 encoding, which uses an alphabet of the characters 0 .. 9, A ..Z, a .. z, but without the four characters 0, O, I and l.
@ -17,6 +21,8 @@ Here is an example of a bitcoin address:
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i
It does not belong to anyone. It is part of the test suite of the bitcoin software. You can change a few characters in this string and check that it will fail the test.
It does not belong to anyone.
It is part of the test suite of the bitcoin software.
You can change a few characters in this string and check that it will fail the test.
''extra credit'': allow your code to deal with [http://bitcoin.stackexchange.com/questions/3059/what-is-a-compressed-bitcoin-key compressed keys]

View file

@ -0,0 +1,3 @@
---
category:
- Checksums

View file

@ -1,26 +1,26 @@
import std.stdio, std.algorithm, std.array, std.string, sha_256;
import std.stdio, std.algorithm, std.array, std.string, sha_256_2;
struct A25 {
// Type for a 25 ubyte (not base58 encoded) bitcoin address.
ubyte[25] enc;
ubyte bitcoinVersion() const pure nothrow {
ubyte bitcoinVersion() const pure nothrow @safe @nogc {
return enc[0];
}
ubyte[4] embeddedChecksum() const pure nothrow {
ubyte[4] embeddedChecksum() return const pure nothrow @safe @nogc {
return enc[$ - 4 .. $];
}
/** Computes a double sha256 hash of the first 21 bytes of
the address. Returns the full 32 ubyte sha256 hash. */
ubyte[32] doubleSHA256() const pure nothrow {
ubyte[32] doubleSHA256() const pure nothrow @nogc {
return SHA256.digest(SHA256.digest(enc[0 .. 21]));
}
/** Returns a four ubyte checksum computed from the first 21
bytes of the address. */
ubyte[4] computeChecksum() const pure nothrow {
ubyte[4] computeChecksum() const pure nothrow @nogc {
return doubleSHA256[0 .. 4];
}
@ -28,7 +28,7 @@ struct A25 {
receiver. Errors are returned if the argument is not valid base58
or if the decoded value does not fit in the 25 ubyte address.
The address is not otherwise checked for validity. */
string set58(in ubyte[] s) pure nothrow {
string set58(in ubyte[] s) pure nothrow @safe @nogc {
static immutable digits =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
.representation;
@ -60,7 +60,7 @@ if it can be decoded into a 25 ubyte address, the Version number is 0,
and the checksum validates. Return value ok will be true for valid
addresses. If ok is false, the address is invalid and the error value
may indicate why. */
string isValidA58(in ubyte[] a58) pure nothrow {
string isValidA58(in ubyte[] a58) pure nothrow @nogc {
A25 a;
immutable err = a.set58(a58);
if (!err.empty)

View file

@ -18,7 +18,7 @@ sub unbase58(Str $str) {
}
sub check-bitcoin-address($addr) {
use Digest;
use Digest::SHA;
my @byte = unbase58 $addr;
!!! 'wrong checksum' unless @byte[21..24] ~~
sha256(sha256 Buf.new: @byte[0..20]).subbuf(0, 4).list;

View file

@ -8,22 +8,25 @@ my %b58 = map { $b58[$_] => $_ } 0 .. 57;
sub unbase58 {
use integer;
my @out;
for my $c ( map { $b58{$_} } shift =~ /./g ) {
my $azeroes = length($1) if $_[0] =~ /^(1*)/;
for my $c ( map { $b58{$_} } $_[0] =~ /./g ) {
for (my $j = 25; $j--; ) {
$c += 58 * ($out[$j] // 0);
$out[$j] = $c % 256;
$c /= 256;
}
}
my $bzeroes = length($1) if join('', @out) =~ /^(0*)/;
die "not a 25 byte address\n" if $bzeroes != $azeroes;
return @out;
}
sub check_bitcoin_address {
# does nothing if the address is valid
# Does nothing if address is valid
# dies otherwise
use Digest::SHA qw(sha256);
my @byte = unbase58 shift;
die "wrong checksum" unless
join('', map { chr } @byte[21..24]) eq
die "wrong checksum\n" unless
(pack 'C*', @byte[21..24]) eq
substr sha256(sha256 pack 'C*', @byte[0..20]), 0, 4;
}

View file

@ -0,0 +1,43 @@
(setq *Alphabet
(chop "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"))
# if returns NIL then adress is already invalid
(de base58 (Str)
(let N 0
(for L (chop Str)
(setq N
(+
(* N 58)
(index L *Alphabet)
-1 ) ) )
N )
)
(de sha256 (Lst)
(native "libcrypto.so" "SHA256"
'(B . 32)
(cons
NIL
(32)
(native "libcrypto.so" "SHA256" '(B . 32)
(cons NIL (32) Lst) (length Lst) '(NIL (32))) )
32
'(NIL (32)) ) )
(de bytes25 (N)
(flip
(make
(do 25
(link (% N 256))
(setq N (/ N 256)) ) ) ) )
(de valid (Str)
(and
(base58 Str)
(bytes25 @)
(=
(head 4 (sha256 (head 21 @)))
(tail 4 @) ) ) )
(bye)

View file

@ -0,0 +1,16 @@
# Validate Bitcoin address
#
# Nigel_Galloway
# October 13th., 2014
require 'digest/sha2'
def convert g
i,e = '',[]
(0...g.length/2).each{|n| e[n] = g[n+=n]+g[n+1]; i+='H2'}
e.pack(i)
end
N = [0,1,2,3,4,5,6,7,8,nil,nil,nil,nil,nil,nil,nil,9,10,11,12,13,14,15,16,nil,17,18,19,20,21,nil,22,23,24,25,26,27,28,29,30,31,32,nil,nil,nil,nil,nil,nil,33,34,35,36,37,38,39,40,41,42,43,nil,44,45,46,47,48,49,50,51,52,53,54,55,56,57]
A = '1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62x'
g = A.bytes.inject(0){|g,n| g*58+N[n-49]}.to_s(16) # A small and interesting piece of code to do the decoding of base58-encoded data.
n = g.slice!(0..-9)
(n.length...42).each{n.insert(0,'0')}
puts "I think the checksum should be #{g}\nI calculate that it is #{Digest::SHA256.hexdigest(Digest::SHA256.digest(convert(n)))[0,8]}"