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, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // BASE58 codec; because i can!
19 module iv
.base58
/*is aliced*/;
24 // all alphanumeric characters except for "0", "I", "O", and "l"
25 static immutable string base58Alphabet
= "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
26 static immutable ubyte[256] b58idx
= () {
28 foreach (immutable idx
, immutable char ch
; base58Alphabet
) res
[ch
] = cast(ubyte)idx
;
33 public struct Base58Decoder
{
35 ubyte[2048] b256
= 0; // int size = cast(int)(buf.length)*733/1000+1; // log(58) / log(256), rounded up
36 uint zeroes
= 0; // bit 31 set: done zero counting; 0xffff_ffffU is error
39 void clear () nothrow @trusted @nogc { pragma(inline
, true); this = this.init
; }
41 @property bool error () const nothrow @trusted @nogc { pragma(inline
, true); return (zeroes
== 0xffff_ffffU
); }
43 bool put (const(char)[] buf
...) nothrow @trusted @nogc {
44 if (error
) return false;
45 foreach (immutable char ch
; buf
) {
47 if (zeroes
< 0x8000_0000U) {
49 if (++zeroes
== 0x0fff_ffffU
) { zeroes
= 0xffff_ffffU
; return false; }
52 zeroes |
= 0x8000_0000U;
54 // ok, this should be a valid char
55 int carry
= b58idx
.ptr
[cast(ubyte)ch
];
56 if (carry
> 57) { zeroes
= 0xffff_ffffU
; return false; }
57 foreach_reverse (ref ubyte vb
; b256
[]) {
61 if (carry
== 0 && vb
== 0) break;
63 if (carry
!= 0) { zeroes
= 0xffff_ffffU
; return false; }
68 uint length () const nothrow @trusted @nogc {
71 while (bpos
< b256
.length
&& b256
.ptr
[bpos
] == 0) ++bpos
;
72 return cast(uint)(b256
.length
)-bpos
+(zeroes
&0x7fff_ffffU
);
78 @property uint getZeroes () const nothrow @trusted @nogc { pragma(inline
, true); return (zeroes
== 0xffff_ffffU ?
0 : zeroes
&0x7fff_ffffU
); }
80 const(ubyte)[] getBuf () const nothrow @trusted @nogc {
81 if (error
) return null;
83 while (bpos
< b256
.length
&& b256
.ptr
[bpos
] == 0) ++bpos
;
84 uint xlen
= cast(uint)(b256
.length
)-bpos
;
88 // return slice of the resuling buffer or `null` if there is no room in `dest`
89 ubyte[] get (ubyte[] dest
) const nothrow @trusted @nogc {
90 if (error
) return null;
92 while (bpos
< b256
.length
&& b256
.ptr
[bpos
] == 0) ++bpos
;
93 uint xlen
= cast(uint)(b256
.length
)-bpos
+(zeroes
&0x7fff_ffffU
);
94 if (dest
.length
< xlen
) return null;
95 auto res
= dest
[0..xlen
];
96 res
[0..(zeroes
&0x7fff_ffffU
)] = 0;
97 res
[(zeroes
&0x7fff_ffffU
)..$] = b256
[bpos
..$];
101 // allocate resuling buffer
102 ubyte[] get () const nothrow @trusted {
103 if (error
) return null;
104 auto res
= new ubyte[](length
);
106 if (rx
is null) { delete res
; return null; }
112 public struct Base58Encoder
{
114 ubyte[2048] b58
= 0; // int size = cast(int)(buf.length)*138/100+1; // log(256) / log(58), rounded up
115 uint zeroes
= 0; // bit 31 set: done zero counting; 0xffff_ffffU is error
118 void clear () nothrow @trusted @nogc { pragma(inline
, true); this = this.init
; }
120 @property bool error () const nothrow @trusted @nogc { pragma(inline
, true); return (zeroes
== 0xffff_ffffU
); }
122 bool put (const(ubyte)[] buf
...) nothrow @trusted @nogc {
123 if (error
) return false;
124 foreach (immutable ubyte b
; buf
) {
126 if (zeroes
< 0x8000_0000U) {
128 if (++zeroes
== 0x0fff_ffffU
) { zeroes
= 0xffff_ffffU
; return false; }
131 zeroes |
= 0x8000_0000U;
133 // ok, this should be a valid char
135 foreach_reverse (immutable idx
, ref ubyte vb
; b58
[]) {
137 vb
= cast(ubyte)(carry
%58);
139 if (carry
== 0 && vb
== 0) break;
141 if (carry
!= 0) { zeroes
= 0xffff_ffffU
; return false; }
146 uint length () const nothrow @trusted @nogc {
149 while (bpos
< b58
.length
&& b58
.ptr
[bpos
] == 0) ++bpos
;
150 return cast(uint)(b58
.length
)-bpos
+(zeroes
&0x7fff_ffffU
);
156 // allocate resuling buffer
157 char[] get (char[] dest
) const nothrow @trusted @nogc {
158 if (error
) return null;
160 while (bpos
< b58
.length
&& b58
.ptr
[bpos
] == 0) ++bpos
;
161 uint xlen
= cast(uint)(b58
.length
)-bpos
+(zeroes
&0x7fff_ffffU
);
162 if (dest
.length
< xlen
) return null;
163 auto res
= dest
[0..xlen
];
164 res
[0..(zeroes
&0x7fff_ffffU
)] = '1';
165 foreach (ref char rc
; res
) {
166 assert(bpos
< b58
.length
);
167 assert(b58
.ptr
[bpos
] < 58);
168 rc
= base58Alphabet
.ptr
[b58
.ptr
[bpos
++]];
173 // allocate resuling buffer
174 char[] get () const nothrow @trusted {
175 if (error
) return null;
176 auto res
= new char[](length
);
178 if (rx
is null) { delete res
; return null; }
184 public ubyte[] base58Decode (const(void)[] vbuf
) {
186 foreach (immutable char ch
; cast(const(char)[])vbuf
) if (!dc
.put(ch
)) return null;
191 public char[] base58Encode (const(void)[] vbuf
) {
193 foreach (immutable ubyte ch
; cast(const(ubyte)[])vbuf
) if (!ec
.put(ch
)) return null;
198 public char[] base58EncodeCheck() (ubyte prefixbyte
, const(void)[] data
) {
199 import std
.digest
.sha
: SHA256
, sha256Of
;
202 hasher
.put(prefixbyte
);
203 hasher
.put(cast(const(ubyte)[])data
);
204 auto hash1
= hasher
.finish();
205 scope(exit
) hash1
[] = 0;
206 auto hash2
= sha256Of(hash1
[]);
207 scope(exit
) hash2
[] = 0;
209 if (!ec
.put(prefixbyte
)) return null;
210 foreach (immutable ubyte b
; cast(const(ubyte)[])data
) if (!ec
.put(b
)) return null;
211 foreach (immutable ubyte b
; hash2
[0..4]) if (!ec
.put(b
)) return null;
216 public ubyte[] base58DecodeCheck() (const(void)[] data
) {
217 import std
.digest
.sha
: SHA256
, sha256Of
;
219 foreach (immutable char ch
; cast(const(char)[])data
) if (!dc
.put(ch
)) return null;
220 if (dc
.length
< 5) return null;
224 hasher
.put(res
[0..$-4]);
225 auto hash1
= hasher
.finish();
226 scope(exit
) hash1
[] = 0;
227 auto hash2
= sha256Of(hash1
[]);
228 scope(exit
) hash2
[] = 0;
229 if (hash2
[0..4] != res
[$-4..$]) { res
[] = 0; delete res
; }