Just another update
This commit is contained in:
parent
a25938f123
commit
00a190b0a6
6591 changed files with 94363 additions and 23227 deletions
|
|
@ -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]
|
||||
|
|
|
|||
3
Task/Bitcoin-address-validation/00META.yaml
Normal file
3
Task/Bitcoin-address-validation/00META.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
category:
|
||||
- Checksums
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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]}"
|
||||
Loading…
Add table
Add a link
Reference in a new issue