[wip] add untested base58 encode in ts

This commit is contained in:
2022-10-21 04:47:55 -06:00
parent 0e600f0f05
commit aa9b8b7339
4 changed files with 575 additions and 11 deletions
+54 -10
View File
@@ -6,7 +6,7 @@
%% https://digitalbazaar.github.io/base58-spec/#encode
main([]) ->
{ok, Cases} = file:consult("b58_cases.eterms"),
{ok, Cases} = file:consult("b58_cases_3.eterms"),
test_cases(Cases).
test_cases([{{encoded, E}, {decoded, D}} | Rest]) ->
@@ -19,8 +19,8 @@ test_cases([{{encoded, E}, {decoded, D}} | Rest]) ->
"YOU ARE A FAILURE TO ENCODE~n"
"===============================~n"
"decoded : ~tw~n"
"expected : ~tw~n"
"actual : ~tw~n~n",
"expected : ~ts~n"
"actual : ~ts~n~n",
[D, E, enc(D)])
end,
ok =
@@ -29,7 +29,7 @@ test_cases([{{encoded, E}, {decoded, D}} | Rest]) ->
false -> io:format("===============================~n"
"YOU ARE A FAILURE TO DECODE~n"
"===============================~n"
"encoded : ~tw~n"
"encoded : ~ts~n"
"expected : ~tw~n"
"actual : ~tw~n~n",
[E, D, dec(E)])
@@ -40,10 +40,39 @@ test_cases([]) ->
% this was much clearer: https://www.youtube.com/watch?v=GedV3S9X89c
enc(Bits) ->
NBits = bit_size(Bits),
<<BitNum:NBits>> = Bits,
enc(BitNum, []).
-spec enc(Bytes) -> Base58
when Bytes :: binary(),
Base58 :: string().
enc(Bytes) ->
% grab leading 0s
{NumLeadingZeros, Rest} = split_zeros(Bytes, 0),
NBitsInRest = bit_size(Rest),
<<RestBigNum:NBitsInRest>> = Rest,
ZerosBase58 = [$1 || _ <- lists:seq(1, NumLeadingZeros)],
RestBase58 = enc(RestBigNum, []),
ZerosBase58 ++ RestBase58.
-spec split_zeros(Bytes, InitZeros) -> {NumLeadingZeros, Rest}
when Bytes :: binary(),
InitZeros :: integer(),
NumLeadingZeros :: binary(),
Rest :: binary().
split_zeros(<<0:8, Rest/binary>>, NumZerosAcc) ->
NewNumZerosAcc = NumZerosAcc + 1,
split_zeros(Rest, NewNumZerosAcc);
split_zeros(Rest, NumZerosAcc) ->
{NumZerosAcc, Rest}.
-spec enc(BytesBigNum, Base58Acc) -> Base58
when BytesBigNum :: integer(),
Base58Acc :: [0..57],
Base58 :: string().
enc(0, Acc) ->
lists:map(fun int2char/1, Acc);
@@ -53,9 +82,24 @@ enc(BitNum, Acc) ->
enc(Q, [R | Acc]).
-spec dec(Base58) -> DecodedBytes
when Base58 :: string(),
DecodedBytes :: binary().
dec(Str) ->
Ns = lists:map(fun char2int/1, Str),
dec(Ns, 0).
% the number of leading 1s tells us the number of leading zeros
{NumLeadingZeros, RestStr} = split_ones(Str, 0),
LeadingZeros = << <<0>> || _ <- lists:seq(1, NumLeadingZeros) >>,
RestNs = lists:map(fun char2int/1, RestStr),
RestBytes = dec(RestNs, 0),
<<LeadingZeros/binary, RestBytes/binary>>.
split_ones([$1 | Rest], NOnes) ->
split_ones(Rest, NOnes + 1);
split_ones(B58Str, NOnes) ->
{NOnes, B58Str}.
dec([N | Ns], Acc) ->
NewAcc = (Acc*58) + N,
+97 -1
View File
@@ -9,27 +9,123 @@ really checking to see if my code matches the base58 package
import base58 as b
import random as r
###########################
### simple cases (single bytes, two bytes, 10 bytes of same byte)
###########################
## 1 byte cases
def single_byte_case(byte):
'''
return the encode/decode pair corresponding to a single byte
'''
decoded_bytes = bytes([byte])
encoded_bytes = b.b58encode(decoded_bytes)
return {'db': decoded_bytes, 'eb': encoded_bytes}
def single_byte_cases():
'''
return the encode/decode pairs corresponding to every single byte case for
byte between 0 and 255
'''
# range(0, 256) = [0, 256) intersect Z
return [single_byte_case(n) for n in range(0, 256)]
## too many of these
### 2 byte cases
#
#def two_bytes(n):
# '''
# return the two bytes corresponding to <<n // 256, n % 256>>
# '''
# return bytes([n // 256, n % 256])
#
#
#def two_byte_case(n):
# '''
# return the encode/decode pair corresponding to <<n // 256, n % 256>>
# '''
# decoded_bytes = two_bytes(n)
# encoded_bytes = b.b58encode(decoded_bytes)
# return {'db': decoded_bytes, 'eb': encoded_bytes}
#
#
#def two_byte_cases():
# '''
# return the encode/decode pairs for each two bytes <<n:8, m:8>>
# '''
# return [two_byte_case(n) for n in range(0, 256*256)]
## 10 byte cases
def ten_bytes(byte):
'''
return the ten byte string which is byte repeated 10 times
'''
return bytes([byte for _ in range(10)])
def ten_byte_case(n):
'''
return the encode/decode pair corresponding to <<n>> * 10
'''
decoded_bytes = ten_bytes(n)
encoded_bytes = b.b58encode(decoded_bytes)
return {'db': decoded_bytes, 'eb': encoded_bytes}
def ten_byte_cases():
'''
return the encode/decode pairs for each string <<n:8>> * 10
'''
return [ten_byte_case(n) for n in range(0, 256)]
## all simple cases in one function
def simple_cases():
return single_byte_cases() + ten_byte_cases()
###########################
### case generation
###########################
def random_bytes():
'''
return between 0 and 999 random bytes
'''
# randint is between [left, right]
len = r.randint(0, 999)
#len = 10
acc = []
for _ in range(len):
# randint is between [left, right]
randbyte = r.randint(0, 255)
acc.append(randbyte)
return bytes(acc)
def case():
'''
return a random encode/decode pair
'''
decoded_bytes = random_bytes()
encoded_bytes = b.b58encode(decoded_bytes)
return {'db': decoded_bytes, 'eb': encoded_bytes}
def cases(n):
'''
return n randomly generated encode/decode pairs
'''
return [case() for _ in range(n)]
###########################
### js formatting
###########################
@@ -99,7 +195,7 @@ def format_cases_erl(cases):
###########################
def main():
c = cases(100)
c = simple_cases() + cases(100_000)
#print(format_cases_js(c))
print(format_cases_erl(c))
+236
View File
@@ -0,0 +1,236 @@
%-module(b58).
%-export([enc/1, dec/1]).
-mode(compile).
%-spec enc(binary()) -> string().
%% https://digitalbazaar.github.io/base58-spec/#encode
main([]) ->
{ok, Cases} = file:consult("b58_cases_3.eterms"),
DoCase =
fun(Case) ->
spawn(fun() -> test_case(Case) end)
end,
lists:foreach(DoCase, Cases).
test_case({{encoded, E}, {decoded, D}}) ->
EncodeOk = E =:= enc(D),
DecodeOk = D =:= dec(E),
ok =
case EncodeOk of
true -> ok;
false -> io:format("===============================~n"
"YOU ARE A FAILURE TO ENCODE~n"
"===============================~n"
"decoded : ~tw~n"
"expected : ~ts~n"
"actual : ~ts~n~n",
[D, E, enc(D)])
end,
ok =
case DecodeOk of
true -> ok;
false -> io:format("===============================~n"
"YOU ARE A FAILURE TO DECODE~n"
"===============================~n"
"encoded : ~ts~n"
"expected : ~tw~n"
"actual : ~tw~n~n",
[E, D, dec(E)])
end,
ok.
% this was much clearer: https://www.youtube.com/watch?v=GedV3S9X89c
-spec enc(Bytes) -> Base58
when Bytes :: binary(),
Base58 :: string().
enc(Bytes) ->
% grab leading 0s
{NumLeadingZeros, Rest} = split_zeros(Bytes, 0),
NBitsInRest = bit_size(Rest),
<<RestBigNum:NBitsInRest>> = Rest,
ZerosBase58 = [$1 || _ <- lists:seq(1, NumLeadingZeros)],
RestBase58 = enc(RestBigNum, []),
ZerosBase58 ++ RestBase58.
-spec split_zeros(Bytes, InitZeros) -> {NumLeadingZeros, Rest}
when Bytes :: binary(),
InitZeros :: integer(),
NumLeadingZeros :: binary(),
Rest :: binary().
split_zeros(<<0:8, Rest/binary>>, NumZerosAcc) ->
NewNumZerosAcc = NumZerosAcc + 1,
split_zeros(Rest, NewNumZerosAcc);
split_zeros(Rest, NumZerosAcc) ->
{NumZerosAcc, Rest}.
-spec enc(BytesBigNum, Base58Acc) -> Base58
when BytesBigNum :: integer(),
Base58Acc :: [0..57],
Base58 :: string().
enc(0, Acc) ->
lists:map(fun int2char/1, Acc);
enc(BitNum, Acc) ->
Q = BitNum div 58,
R = BitNum rem 58,
enc(Q, [R | Acc]).
-spec dec(Base58) -> DecodedBytes
when Base58 :: string(),
DecodedBytes :: binary().
dec(Str) ->
% the number of leading 1s tells us the number of leading zeros
{NumLeadingZeros, RestStr} = split_ones(Str, 0),
LeadingZeros = << <<0>> || _ <- lists:seq(1, NumLeadingZeros) >>,
RestNs = lists:map(fun char2int/1, RestStr),
RestBytes = dec(RestNs, 0),
<<LeadingZeros/binary, RestBytes/binary>>.
split_ones([$1 | Rest], NOnes) ->
split_ones(Rest, NOnes + 1);
split_ones(B58Str, NOnes) ->
{NOnes, B58Str}.
dec([N | Ns], Acc) ->
NewAcc = (Acc*58) + N,
dec(Ns, NewAcc);
dec([], FinalAccN) ->
bignum_to_binary_bige(FinalAccN, <<>>).
bignum_to_binary_bige(0, Acc) ->
Acc;
bignum_to_binary_bige(N, Acc) ->
Q = N div 256,
R = N rem 256,
NewAcc = <<R, Acc/binary>>,
bignum_to_binary_bige(Q, NewAcc).
int2char( 0) -> $1;
int2char( 1) -> $2;
int2char( 2) -> $3;
int2char( 3) -> $4;
int2char( 4) -> $5;
int2char( 5) -> $6;
int2char( 6) -> $7;
int2char( 7) -> $8;
int2char( 8) -> $9;
int2char( 9) -> $A;
int2char(10) -> $B;
int2char(11) -> $C;
int2char(12) -> $D;
int2char(13) -> $E;
int2char(14) -> $F;
int2char(15) -> $G;
int2char(16) -> $H;
int2char(17) -> $J;
int2char(18) -> $K;
int2char(19) -> $L;
int2char(20) -> $M;
int2char(21) -> $N;
int2char(22) -> $P;
int2char(23) -> $Q;
int2char(24) -> $R;
int2char(25) -> $S;
int2char(26) -> $T;
int2char(27) -> $U;
int2char(28) -> $V;
int2char(29) -> $W;
int2char(30) -> $X;
int2char(31) -> $Y;
int2char(32) -> $Z;
int2char(33) -> $a;
int2char(34) -> $b;
int2char(35) -> $c;
int2char(36) -> $d;
int2char(37) -> $e;
int2char(38) -> $f;
int2char(39) -> $g;
int2char(40) -> $h;
int2char(41) -> $i;
int2char(42) -> $j;
int2char(43) -> $k;
int2char(44) -> $m;
int2char(45) -> $n;
int2char(46) -> $o;
int2char(47) -> $p;
int2char(48) -> $q;
int2char(49) -> $r;
int2char(50) -> $s;
int2char(51) -> $t;
int2char(52) -> $u;
int2char(53) -> $v;
int2char(54) -> $w;
int2char(55) -> $x;
int2char(56) -> $y;
int2char(57) -> $z.
char2int($1) -> 0;
char2int($2) -> 1;
char2int($3) -> 2;
char2int($4) -> 3;
char2int($5) -> 4;
char2int($6) -> 5;
char2int($7) -> 6;
char2int($8) -> 7;
char2int($9) -> 8;
char2int($A) -> 9;
char2int($B) -> 10;
char2int($C) -> 11;
char2int($D) -> 12;
char2int($E) -> 13;
char2int($F) -> 14;
char2int($G) -> 15;
char2int($H) -> 16;
char2int($J) -> 17;
char2int($K) -> 18;
char2int($L) -> 19;
char2int($M) -> 20;
char2int($N) -> 21;
char2int($P) -> 22;
char2int($Q) -> 23;
char2int($R) -> 24;
char2int($S) -> 25;
char2int($T) -> 26;
char2int($U) -> 27;
char2int($V) -> 28;
char2int($W) -> 29;
char2int($X) -> 30;
char2int($Y) -> 31;
char2int($Z) -> 32;
char2int($a) -> 33;
char2int($b) -> 34;
char2int($c) -> 35;
char2int($d) -> 36;
char2int($e) -> 37;
char2int($f) -> 38;
char2int($g) -> 39;
char2int($h) -> 40;
char2int($i) -> 41;
char2int($j) -> 42;
char2int($k) -> 43;
char2int($m) -> 44;
char2int($n) -> 45;
char2int($o) -> 46;
char2int($p) -> 47;
char2int($q) -> 48;
char2int($r) -> 49;
char2int($s) -> 50;
char2int($t) -> 51;
char2int($u) -> 52;
char2int($v) -> 53;
char2int($w) -> 54;
char2int($x) -> 55;
char2int($y) -> 56;
char2int($z) -> 57.