September Morn Update

This commit is contained in:
Ingy döt Net 2019-09-12 10:33:56 -07:00
parent 4e2d22a71d
commit aac6731f2c
6856 changed files with 141342 additions and 21127 deletions

View file

@ -0,0 +1,75 @@
import algorithm
const SHA256Len = 32
const AddrLen = 25
const AddrMsgLen = 21
const AddrChecksumOffset = 21
const AddrChecksumLen = 4
proc SHA256(d: pointer, n: culong, md: pointer = nil): cstring {.cdecl, dynlib: "libssl.so", importc.}
proc decodeBase58(inStr: string, outArray: var openarray[uint8]) =
let base = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
outArray.fill(0)
for aChar in inStr:
var accum = base.find(aChar)
if accum < 0:
raise newException(ValueError, "Invalid character: " & $aChar)
for outIndex in countDown((AddrLen - 1), 0):
accum += 58 * outArray[outIndex].int
outArray[outIndex] = (accum mod 256).uint8
accum = accum div 256
if accum != 0:
raise newException(ValueError, "Address string too long")
proc verifyChecksum(addrData: openarray[uint8]) : bool =
let doubleHash = SHA256(SHA256(cast[ptr uint8](addrData), AddrMsgLen), SHA256Len)
for ii in 0 ..< AddrChecksumLen:
if doubleHash[ii].uint8 != addrData[AddrChecksumOffset + ii]:
return false
return true
proc main() =
let
testVectors : seq[string] = @[
"3yQ",
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ix",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62ixx",
"17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j",
"1badbadbadbadbadbadbadbadbadbadbad",
"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM",
"1111111111111111111114oLvT2",
"BZbvjr",
]
var
buf: array[AddrLen, uint8]
astr: string
for vector in testVectors:
stdout.write(vector & " : ")
try:
decodeBase58(vector, buf)
if buf[0] != 0:
stdout.write("NG - invalid version number\n")
elif verifyChecksum(buf):
stdout.write("OK\n")
else:
stdout.write("NG - checksum invalid\n")
except:
stdout.write("NG - " & getCurrentExceptionMsg() & "\n")
main()

View file

@ -1,14 +1,12 @@
--
-- demo\rosetta\bitcoin_address_validation.exw
--
string coin_err
include builtins\sha256.e
constant b58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
string charmap = ""
function unbase58(string s)
string out = repeat('\0',25)
if length(charmap)=0 then
function valid(string s, bool expected)
bool res := (expected==false)
if charmap="" then
charmap = repeat('\0',256)
for i=1 to length(b58) do
charmap[b58[i]] = i
@ -16,18 +14,16 @@ string out = repeat('\0',25)
end if
-- not at all sure about this:
-- if length(s)!=34 then
-- coin_err = "bad length"
-- return 0
-- return {res,"bad length"}
-- end if
if s[1]!='1' and s[1]!='3' then
coin_err = "first character is not 1 or 3"
return 0
if not find(s[1],"13") then
return {res,"first character is not 1 or 3"}
end if
string out = repeat('\0',25)
for i=1 to length(s) do
integer c = charmap[s[i]]
if c=0 then
coin_err = "bad char"
return 0
return {res,"bad char"}
end if
c -= 1
for j=25 to 1 by -1 do
@ -36,49 +32,45 @@ string out = repeat('\0',25)
c = floor(c/#100)
end for
if c!=0 then
coin_err = "address too long"
return 0
return {res,"address too long"}
end if
end for
if out[1]!='\0' then
coin_err = "not version 0"
return 0
return {res,"not version 0"}
end if
return out
if out[22..$]!=sha256(sha256(out[1..21]))[1..4] then
return {res,"bad digest"}
end if
res := (expected==true)
return {res,"OK"}
end function
include builtins\sha256.e
procedure valid(string s)
object dec
coin_err = "OK"
dec = unbase58(s)
if string(dec) then
if dec[22..$]!=sha256(sha256(dec[1..21]))[1..4] then
coin_err = "bad digest"
end if
end if
end procedure
constant tests = {
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", -- OK
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", -- bad digest
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", -- OK
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", -- bad digest (checksum changed, original data.)
"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", -- bad digest (data changed, original checksum.)
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz", -- not version 0
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz", -- address too long
"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", -- bad char
"1111111111111111111114oLvT2", -- OK?
"17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j", -- OK (*NB*: apparently differs to Python solution,
-- but does agree with Racket and Rust entries)
"1badbadbadbadbadbadbadbadbadbadbad", -- not version 0
"BZbvjr", -- first character is not 1 or 3 (checksum is fine, address too short)
"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", -- OK (from public_point_to_address)
constant tests = {{"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",true}, -- OK
{"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9",false}, -- bad digest
{"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",true}, -- OK
{"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j",false}, -- bad disgest
{"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X",false}, -- bad digest (checksum changed, original data.)
{"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",false}, -- bad digest (data changed, original checksum.)
{"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz",false}, -- not version 0
{"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz",false}, -- address too long
{"1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",false}, -- bad digest
{"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",false}, -- bad char
{"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I",false}, -- bad char
{"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!",false}, -- bad char
{"1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i",false}, -- bad digest
{"1111111111111111111114oLvT2", true}, -- OK
{"17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j",true}, -- OK
{"1badbadbadbadbadbadbadbadbadbadbad",false}, -- not version 0
{"BZbvjr",false}, -- first character is not 1 or 3 (checksum is fine, address too short)
{"i55j",false}, -- first character is not 1 or 3 (checksum is fine, address too short)
{"16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", true}, -- OK (from public_point_to_address)
$}
for i=1 to length(tests) do
valid(tests[i]);
printf(1,"%s: %s\n", {tests[i], coin_err})
end for
{} = wait_key()
for i=1 to length(tests) do
{string ti, bool expected} = tests[i]
{bool res, string coin_err} = valid(ti,expected)
if not res then
printf(1,"%s: %s\n", {ti, coin_err})
{} = wait_key()
end if
end for

View file

@ -7,9 +7,9 @@ import scala.math.BigInt
object BitcoinAddressValidator extends App {
private def bitcoinTestHarness(address: String, expected: Boolean): Unit =
assert(validateBitcoinAddress(address) == expected, s"Expected $expected for $address%s, but got ${!expected}.")
assert(validateBitcoinAddress(=1J26TeMg6uK9GkoCKkHNeDaKwtFWdsFnR8) expected, s"Expected $expected for $address%s, but got ${!expected}.")
private def validateBitcoinAddress(addr: String): Boolean = {
private def validateBitcoinAddress(addr: 1J26TeMg6uK9GkoCKkHNeDaKwtFWdsFnR8String): Boolean = {
def sha256(data: Array[Byte]) = {
val md: MessageDigest = MessageDigest.getInstance("SHA-256")
md.update(data)

View file

@ -0,0 +1,50 @@
$ include "seed7_05.s7i";
include "msgdigest.s7i";
include "encoding.s7i";
const func boolean: validBitcoinAddress (in string: address) is func
result
var boolean: isValid is FALSE;
local
var string: decoded is "";
begin
if succeeds(decoded := fromBase58(address)) and
length(decoded) = 25 and decoded[1] = '\0;' and
sha256(sha256(decoded[.. 21]))[.. 4] = decoded[22 ..] then
isValid := TRUE;
end if;
end func;
const proc: checkValidationFunction (in string: address, in boolean: expected) is func
local
var boolean: isValid is FALSE;
begin
isValid := validBitcoinAddress(address);
writeln((address <& ": ") rpad 37 <& isValid);
if isValid <> expected then
writeln(" *** Expected " <& expected <& " for " <& address <& ", but got " <& isValid <& ".");
end if;
end func;
const proc: main is func
begin
checkValidationFunction("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", TRUE); # okay
checkValidationFunction("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", FALSE); # bad digest
checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", TRUE); # okay
checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j", FALSE); # bad digest
checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", FALSE); # bad digest
checkValidationFunction("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", FALSE); # bad digest
checkValidationFunction("oMRDCDfyQhEerkaSmwCfSPqf3MLgBwNvs", FALSE); # not version 0
checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz", FALSE); # wrong length
checkValidationFunction("1BGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", FALSE); # bad digest
checkValidationFunction("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", FALSE); # bad char
checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I", FALSE); # bad char
checkValidationFunction("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!", FALSE); # bad char
checkValidationFunction("1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i", FALSE); # bad digest
checkValidationFunction("1111111111111111111114oLvT2", TRUE); # okay
checkValidationFunction("17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j", TRUE); # okay
checkValidationFunction("1badbadbadbadbadbadbadbadbadbadbad", FALSE); # wrong length
checkValidationFunction("BZbvjr", FALSE); # wrong length
checkValidationFunction("i55j", FALSE); # wrong length
checkValidationFunction("16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM", TRUE); # okay
end func;