Bitcoin/address validation: Difference between revisions

Content added Content deleted
m (minor tidy)
(Update Seed7 example)
Line 1,970: Line 1,970:


=={{header|Seed7}}==
=={{header|Seed7}}==
The Seed7 library [http://seed7.sourceforge.net/libraries/encoding.htm encoding.s7i] defines
the function [http://seed7.sourceforge.net/libraries/encoding.htm#fromBase58(in_string) fromBase58],
which decodes a Base58 encoded string.
The Seed7 library [http://seed7.sourceforge.net/libraries/msgdigest.htm msgdigest.s7i] defines
The Seed7 library [http://seed7.sourceforge.net/libraries/msgdigest.htm msgdigest.s7i] defines
the function [http://seed7.sourceforge.net/libraries/msgdigest.htm#sha256(in_var_string) sha256].
the function [http://seed7.sourceforge.net/libraries/msgdigest.htm#sha256(in_var_string) sha256],
which computes a SHA-256 message digest.
No external library is needed.
No external library is needed.


<lang seed7>$ include "seed7_05.s7i";
<lang seed7>$ include "seed7_05.s7i";
include "msgdigest.s7i";
include "msgdigest.s7i";
include "encoding.s7i";


const func string: unbase58 (in string: stri, inout string: out) is func
const proc: assertBitcoin (in string: stri, in string: expected) is func
result
var string: state is "";
local
local
const string: digits is "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
var string: decoded is "";
var char: ch is ' ';
var string: state is "okay";
var integer: digit is 0;
var integer: index is 0;
begin
begin
if not succeeds(decoded := fromBase58(stri)) then
for ch range stri until state <> "" do
digit := pred(pos(digits, ch));
state := "bad char";
if digit = -1 then
elsif length(decoded) <> 25 then
state := "bad char";
state := "wrong length";
elsif decoded[1] <> '\0;' then
else
for index range 25 downto 1 do
state := "not version 0";
elsif sha256(sha256(decoded[.. 21]))[.. 4] <> decoded[22 ..] then
digit +:= 58 * ord(out[index]);
out @:= [index] char(digit rem 256);
digit := digit div 256;
end for;
if digit <> 0 then
state := "address too long";
end if;
end if;
end for;
end func;

const func string: valid (in string: stri) is func
result
var string: state is "";
local
var string: decoded is "\0;" mult 25;
begin
state := unbase58(stri, decoded);
if state = "" and sha256(sha256(decoded[.. 21]))[.. 4] <> decoded[22 ..] then
state := "bad digest";
state := "bad digest";
end if;
# writeln(stri <& " decoded: " <& hex(decoded));
writeln((stri <& ": ") rpad 37 <& state);
if state <> expected then
writeln(" *** Expected " <& literal(expected) <& " for " <& stri <& ", but got " <& literal(state) <& ".");
end if;
end if;
end func;
end func;


const proc: main is func
const proc: main is func
local
const array string: tests is [] ("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I");
var string: test is "";
var string: state is "";
begin
begin
assertBitcoin("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", "okay");
for test range tests do
assertBitcoin("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", "bad digest");
state := valid(test);
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "okay");
if state = "" then
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j", "bad digest");
writeln(test <& ": okay");
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", "bad digest");
else
assertBitcoin("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "bad digest");
writeln(test <& ": " <& state);
assertBitcoin("oMRDCDfyQhEerkaSmwCfSPqf3MLgBwNvs", "not version 0");
end if;
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz", "wrong length");
end for;
assertBitcoin("1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "bad digest");
assertBitcoin("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", "bad char");
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I", "bad char");
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!", "bad char");
assertBitcoin("1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i", "bad digest");
assertBitcoin("1111111111111111111114oLvT2", "okay");
assertBitcoin("17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j", "okay");
assertBitcoin("1badbadbadbadbadbadbadbadbadbadbad", "wrong length");
assertBitcoin("BZbvjr", "wrong length");
assertBitcoin("i55j", "wrong length");
assertBitcoin("16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", "okay");
end func;</lang>
end func;</lang>


{{out}}
{{out}}
<pre>
<pre>
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9: okay
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9: okay
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9: bad digest
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: okay
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: okay
1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9: bad digest
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j: bad digest
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I: bad char
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X: bad digest
1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: bad digest
oMRDCDfyQhEerkaSmwCfSPqf3MLgBwNvs: not version 0
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz: wrong length
1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: bad digest
1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i: bad char
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I: bad char
1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!: bad char
1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i: bad digest
1111111111111111111114oLvT2: okay
17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j: okay
1badbadbadbadbadbadbadbadbadbadbad: wrong length
BZbvjr: wrong length
i55j: wrong length
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM: okay
</pre>
</pre>