1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 // BASE58 codec; because i can!
18 module iv
.base58
/*is aliced*/;
23 // all alphanumeric characters except for "0", "I", "O", and "l"
24 static immutable string base58Alphabet
= "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
25 static immutable ubyte[256] b58idx
= () {
27 foreach (immutable idx
, immutable char ch
; base58Alphabet
) res
[ch
] = cast(ubyte)idx
;
32 public struct Base58Decoder
{
34 ubyte[2048] b256
= 0; // int size = cast(int)(buf.length)*733/1000+1; // log(58) / log(256), rounded up
35 uint zeroes
= 0; // bit 31 set: done zero counting; 0xffff_ffffU is error
38 void clear () nothrow @trusted @nogc { pragma(inline
, true); this = this.init
; }
40 @property bool error () const nothrow @trusted @nogc { pragma(inline
, true); return (zeroes
== 0xffff_ffffU
); }
42 bool put (const(char)[] buf
...) nothrow @trusted @nogc {
43 if (error
) return false;
44 foreach (immutable char ch
; buf
) {
46 if (zeroes
< 0x8000_0000U) {
48 if (++zeroes
== 0x0fff_ffffU
) { zeroes
= 0xffff_ffffU
; return false; }
51 zeroes |
= 0x8000_0000U;
53 // ok, this should be a valid char
54 int carry
= b58idx
.ptr
[cast(ubyte)ch
];
55 if (carry
> 57) { zeroes
= 0xffff_ffffU
; return false; }
56 foreach_reverse (ref ubyte vb
; b256
[]) {
60 if (carry
== 0 && vb
== 0) break;
62 if (carry
!= 0) { zeroes
= 0xffff_ffffU
; return false; }
67 uint length () const nothrow @trusted @nogc {
70 while (bpos
< b256
.length
&& b256
.ptr
[bpos
] == 0) ++bpos
;
71 return cast(uint)(b256
.length
)-bpos
+(zeroes
&0x7fff_ffffU
);
77 @property uint getZeroes () const nothrow @trusted @nogc { pragma(inline
, true); return (zeroes
== 0xffff_ffffU ?
0 : zeroes
&0x7fff_ffffU
); }
79 const(ubyte)[] getBuf () const nothrow @trusted @nogc {
80 if (error
) return null;
82 while (bpos
< b256
.length
&& b256
.ptr
[bpos
] == 0) ++bpos
;
83 uint xlen
= cast(uint)(b256
.length
)-bpos
;
87 // return slice of the resuling buffer or `null` if there is no room in `dest`
88 ubyte[] get (ubyte[] dest
) const nothrow @trusted @nogc {
89 if (error
) return null;
91 while (bpos
< b256
.length
&& b256
.ptr
[bpos
] == 0) ++bpos
;
92 uint xlen
= cast(uint)(b256
.length
)-bpos
+(zeroes
&0x7fff_ffffU
);
93 if (dest
.length
< xlen
) return null;
94 auto res
= dest
[0..xlen
];
95 res
[0..(zeroes
&0x7fff_ffffU
)] = 0;
96 res
[(zeroes
&0x7fff_ffffU
)..$] = b256
[bpos
..$];
100 // allocate resuling buffer
101 ubyte[] get () const nothrow @trusted {
102 if (error
) return null;
103 auto res
= new ubyte[](length
);
105 if (rx
is null) { delete res
; return null; }
111 public struct Base58Encoder
{
113 ubyte[2048] b58
= 0; // int size = cast(int)(buf.length)*138/100+1; // log(256) / log(58), rounded up
114 uint zeroes
= 0; // bit 31 set: done zero counting; 0xffff_ffffU is error
117 void clear () nothrow @trusted @nogc { pragma(inline
, true); this = this.init
; }
119 @property bool error () const nothrow @trusted @nogc { pragma(inline
, true); return (zeroes
== 0xffff_ffffU
); }
121 bool put (const(ubyte)[] buf
...) nothrow @trusted @nogc {
122 if (error
) return false;
123 foreach (immutable ubyte b
; buf
) {
125 if (zeroes
< 0x8000_0000U) {
127 if (++zeroes
== 0x0fff_ffffU
) { zeroes
= 0xffff_ffffU
; return false; }
130 zeroes |
= 0x8000_0000U;
132 // ok, this should be a valid char
134 foreach_reverse (immutable idx
, ref ubyte vb
; b58
[]) {
136 vb
= cast(ubyte)(carry
%58);
138 if (carry
== 0 && vb
== 0) break;
140 if (carry
!= 0) { zeroes
= 0xffff_ffffU
; return false; }
145 uint length () const nothrow @trusted @nogc {
148 while (bpos
< b58
.length
&& b58
.ptr
[bpos
] == 0) ++bpos
;
149 return cast(uint)(b58
.length
)-bpos
+(zeroes
&0x7fff_ffffU
);
155 // allocate resuling buffer
156 char[] get (char[] dest
) const nothrow @trusted @nogc {
157 if (error
) return null;
159 while (bpos
< b58
.length
&& b58
.ptr
[bpos
] == 0) ++bpos
;
160 uint xlen
= cast(uint)(b58
.length
)-bpos
+(zeroes
&0x7fff_ffffU
);
161 if (dest
.length
< xlen
) return null;
162 auto res
= dest
[0..xlen
];
163 res
[0..(zeroes
&0x7fff_ffffU
)] = '1';
164 foreach (ref char rc
; res
) {
165 assert(bpos
< b58
.length
);
166 assert(b58
.ptr
[bpos
] < 58);
167 rc
= base58Alphabet
.ptr
[b58
.ptr
[bpos
++]];
172 // allocate resuling buffer
173 char[] get () const nothrow @trusted {
174 if (error
) return null;
175 auto res
= new char[](length
);
177 if (rx
is null) { delete res
; return null; }
183 public ubyte[] base58Decode (const(void)[] vbuf
) {
185 foreach (immutable char ch
; cast(const(char)[])vbuf
) if (!dc
.put(ch
)) return null;
190 public char[] base58Encode (const(void)[] vbuf
) {
192 foreach (immutable ubyte ch
; cast(const(ubyte)[])vbuf
) if (!ec
.put(ch
)) return null;
197 public char[] base58EncodeCheck() (ubyte prefixbyte
, const(void)[] data
) {
198 import std
.digest
.sha
: SHA256
, sha256Of
;
201 hasher
.put(prefixbyte
);
202 hasher
.put(cast(const(ubyte)[])data
);
203 auto hash1
= hasher
.finish();
204 scope(exit
) hash1
[] = 0;
205 auto hash2
= sha256Of(hash1
[]);
206 scope(exit
) hash2
[] = 0;
208 if (!ec
.put(prefixbyte
)) return null;
209 foreach (immutable ubyte b
; cast(const(ubyte)[])data
) if (!ec
.put(b
)) return null;
210 foreach (immutable ubyte b
; hash2
[0..4]) if (!ec
.put(b
)) return null;
215 public ubyte[] base58DecodeCheck() (const(void)[] data
) {
216 import std
.digest
.sha
: SHA256
, sha256Of
;
218 foreach (immutable char ch
; cast(const(char)[])data
) if (!dc
.put(ch
)) return null;
219 if (dc
.length
< 5) return null;
223 hasher
.put(res
[0..$-4]);
224 auto hash1
= hasher
.finish();
225 scope(exit
) hash1
[] = 0;
226 auto hash2
= sha256Of(hash1
[]);
227 scope(exit
) hash2
[] = 0;
228 if (hash2
[0..4] != res
[$-4..$]) { res
[] = 0; delete res
; }