egra: don't use ENTER/LEAVE (because intel sux, and they are slower than the correspo...
[iv.d.git] / ripemd160.d
blob22579b01ff12b039d1d28768cb4917cb7c423122
1 // RIPEMD-160, based on the algorithm description
2 // public domain
3 // this is around 2 times faster than `std.digest.ripemd`
4 module iv.ripemd160;
6 public enum RIPEMD160_BITS = 160;
8 // Buffer size for RIPEMD-160 hash, in bytes.
9 public enum RIPEMD160_BYTES = (RIPEMD160_BITS>>3);
11 // RIPEMD-160 context.
12 public struct RIPEMD160_Ctx {
13 uint[RIPEMD160_BYTES>>2] wkbuf = [0x67452301U, 0xefcdab89U, 0x98badcfeU, 0x10325476U, 0xc3d2e1f0U];
14 ubyte[64] chunkd = 0;
15 uint chunkpos = 0;
16 uint total = 0;
17 uint totalhi = 0;
21 private:
22 enum RIPEMD160_ROL(string x, string n) = `(((`~x~`)<<(`~n~`))|((`~x~`)>>(32-(`~n~`))))`;
24 template RIPEMD160_PRIM(string bop, string x, string y, string z) {
25 static if (bop == "F") enum RIPEMD160_PRIM = `((`~x~`)^(`~y~`)^(`~z~`))`;
26 else static if (bop == "G") enum RIPEMD160_PRIM = `(((`~x~`)&(`~y~`))|(~(`~x~`)&(`~z~`)))`;
27 else static if (bop == "H") enum RIPEMD160_PRIM = `(((`~x~`)|~(`~y~`))^(`~z~`))`;
28 else static if (bop == "I") enum RIPEMD160_PRIM = `(((`~x~`)&(`~z~`))|((`~y~`)&~(`~z~`)))`;
29 else static if (bop == "J") enum RIPEMD160_PRIM = `((`~x~`)^((`~y~`)|~(`~z~`)))`;
30 else static assert(0, "invalid bop");
33 enum RIPEMD160_BOP(string bop, string addconst, string a, string b, string c, string d, string e, string x, string s) =
34 `(`~a~`) += `~RIPEMD160_PRIM!(bop, b, c, d)~`+(`~x~`)+`~addconst~`;`~
35 `(`~a~`) = `~RIPEMD160_ROL!(a, s)~`+(`~e~`);`~
36 `(`~c~`) = `~RIPEMD160_ROL!(c, "10")~`;`;
38 enum RIPEMD160_FF(string a, string b, string c, string d, string e, string x, string s) = RIPEMD160_BOP!("F", "0U", a, b, c, d, e, x, s);
39 enum RIPEMD160_GG(string a, string b, string c, string d, string e, string x, string s) = RIPEMD160_BOP!("G", "0x5a827999U", a, b, c, d, e, x, s);
40 enum RIPEMD160_HH(string a, string b, string c, string d, string e, string x, string s) = RIPEMD160_BOP!("H", "0x6ed9eba1U", a, b, c, d, e, x, s);
41 enum RIPEMD160_II(string a, string b, string c, string d, string e, string x, string s) = RIPEMD160_BOP!("I", "0x8f1bbcdcU", a, b, c, d, e, x, s);
42 enum RIPEMD160_JJ(string a, string b, string c, string d, string e, string x, string s) = RIPEMD160_BOP!("J", "0xa953fd4eU", a, b, c, d, e, x, s);
43 enum RIPEMD160_FFF(string a, string b, string c, string d, string e, string x, string s) = RIPEMD160_BOP!("F", "0U", a, b, c, d, e, x, s);
44 enum RIPEMD160_GGG(string a, string b, string c, string d, string e, string x, string s) = RIPEMD160_BOP!("G", "0x7a6d76e9U", a, b, c, d, e, x, s);
45 enum RIPEMD160_HHH(string a, string b, string c, string d, string e, string x, string s) = RIPEMD160_BOP!("H", "0x6d703ef3U", a, b, c, d, e, x, s);
46 enum RIPEMD160_III(string a, string b, string c, string d, string e, string x, string s) = RIPEMD160_BOP!("I", "0x5c4dd124U", a, b, c, d, e, x, s);
47 enum RIPEMD160_JJJ(string a, string b, string c, string d, string e, string x, string s) = RIPEMD160_BOP!("J", "0x50a28be6U", a, b, c, d, e, x, s);
50 static void ripemd160_compress (uint *wkbuf/*[RIPEMD160_BYTES>>2]*/, const uint* X) nothrow @trusted @nogc {
51 uint aa = wkbuf[0];
52 uint bb = wkbuf[1];
53 uint cc = wkbuf[2];
54 uint dd = wkbuf[3];
55 uint ee = wkbuf[4];
56 uint aaa = wkbuf[0];
57 uint bbb = wkbuf[1];
58 uint ccc = wkbuf[2];
59 uint ddd = wkbuf[3];
60 uint eee = wkbuf[4];
62 // round 1
63 mixin(RIPEMD160_FF!("aa", "bb", "cc", "dd", "ee", "X[ 0]", "11"));
64 mixin(RIPEMD160_FF!("ee", "aa", "bb", "cc", "dd", "X[ 1]", "14"));
65 mixin(RIPEMD160_FF!("dd", "ee", "aa", "bb", "cc", "X[ 2]", "15"));
66 mixin(RIPEMD160_FF!("cc", "dd", "ee", "aa", "bb", "X[ 3]", "12"));
67 mixin(RIPEMD160_FF!("bb", "cc", "dd", "ee", "aa", "X[ 4]", " 5"));
68 mixin(RIPEMD160_FF!("aa", "bb", "cc", "dd", "ee", "X[ 5]", " 8"));
69 mixin(RIPEMD160_FF!("ee", "aa", "bb", "cc", "dd", "X[ 6]", " 7"));
70 mixin(RIPEMD160_FF!("dd", "ee", "aa", "bb", "cc", "X[ 7]", " 9"));
71 mixin(RIPEMD160_FF!("cc", "dd", "ee", "aa", "bb", "X[ 8]", "11"));
72 mixin(RIPEMD160_FF!("bb", "cc", "dd", "ee", "aa", "X[ 9]", "13"));
73 mixin(RIPEMD160_FF!("aa", "bb", "cc", "dd", "ee", "X[10]", "14"));
74 mixin(RIPEMD160_FF!("ee", "aa", "bb", "cc", "dd", "X[11]", "15"));
75 mixin(RIPEMD160_FF!("dd", "ee", "aa", "bb", "cc", "X[12]", " 6"));
76 mixin(RIPEMD160_FF!("cc", "dd", "ee", "aa", "bb", "X[13]", " 7"));
77 mixin(RIPEMD160_FF!("bb", "cc", "dd", "ee", "aa", "X[14]", " 9"));
78 mixin(RIPEMD160_FF!("aa", "bb", "cc", "dd", "ee", "X[15]", " 8"));
80 // round 2
81 mixin(RIPEMD160_GG!("ee", "aa", "bb", "cc", "dd", "X[ 7]", " 7"));
82 mixin(RIPEMD160_GG!("dd", "ee", "aa", "bb", "cc", "X[ 4]", " 6"));
83 mixin(RIPEMD160_GG!("cc", "dd", "ee", "aa", "bb", "X[13]", " 8"));
84 mixin(RIPEMD160_GG!("bb", "cc", "dd", "ee", "aa", "X[ 1]", "13"));
85 mixin(RIPEMD160_GG!("aa", "bb", "cc", "dd", "ee", "X[10]", "11"));
86 mixin(RIPEMD160_GG!("ee", "aa", "bb", "cc", "dd", "X[ 6]", " 9"));
87 mixin(RIPEMD160_GG!("dd", "ee", "aa", "bb", "cc", "X[15]", " 7"));
88 mixin(RIPEMD160_GG!("cc", "dd", "ee", "aa", "bb", "X[ 3]", "15"));
89 mixin(RIPEMD160_GG!("bb", "cc", "dd", "ee", "aa", "X[12]", " 7"));
90 mixin(RIPEMD160_GG!("aa", "bb", "cc", "dd", "ee", "X[ 0]", "12"));
91 mixin(RIPEMD160_GG!("ee", "aa", "bb", "cc", "dd", "X[ 9]", "15"));
92 mixin(RIPEMD160_GG!("dd", "ee", "aa", "bb", "cc", "X[ 5]", " 9"));
93 mixin(RIPEMD160_GG!("cc", "dd", "ee", "aa", "bb", "X[ 2]", "11"));
94 mixin(RIPEMD160_GG!("bb", "cc", "dd", "ee", "aa", "X[14]", " 7"));
95 mixin(RIPEMD160_GG!("aa", "bb", "cc", "dd", "ee", "X[11]", "13"));
96 mixin(RIPEMD160_GG!("ee", "aa", "bb", "cc", "dd", "X[ 8]", "12"));
98 // round 3
99 mixin(RIPEMD160_HH!("dd", "ee", "aa", "bb", "cc", "X[ 3]", "11"));
100 mixin(RIPEMD160_HH!("cc", "dd", "ee", "aa", "bb", "X[10]", "13"));
101 mixin(RIPEMD160_HH!("bb", "cc", "dd", "ee", "aa", "X[14]", " 6"));
102 mixin(RIPEMD160_HH!("aa", "bb", "cc", "dd", "ee", "X[ 4]", " 7"));
103 mixin(RIPEMD160_HH!("ee", "aa", "bb", "cc", "dd", "X[ 9]", "14"));
104 mixin(RIPEMD160_HH!("dd", "ee", "aa", "bb", "cc", "X[15]", " 9"));
105 mixin(RIPEMD160_HH!("cc", "dd", "ee", "aa", "bb", "X[ 8]", "13"));
106 mixin(RIPEMD160_HH!("bb", "cc", "dd", "ee", "aa", "X[ 1]", "15"));
107 mixin(RIPEMD160_HH!("aa", "bb", "cc", "dd", "ee", "X[ 2]", "14"));
108 mixin(RIPEMD160_HH!("ee", "aa", "bb", "cc", "dd", "X[ 7]", " 8"));
109 mixin(RIPEMD160_HH!("dd", "ee", "aa", "bb", "cc", "X[ 0]", "13"));
110 mixin(RIPEMD160_HH!("cc", "dd", "ee", "aa", "bb", "X[ 6]", " 6"));
111 mixin(RIPEMD160_HH!("bb", "cc", "dd", "ee", "aa", "X[13]", " 5"));
112 mixin(RIPEMD160_HH!("aa", "bb", "cc", "dd", "ee", "X[11]", "12"));
113 mixin(RIPEMD160_HH!("ee", "aa", "bb", "cc", "dd", "X[ 5]", " 7"));
114 mixin(RIPEMD160_HH!("dd", "ee", "aa", "bb", "cc", "X[12]", " 5"));
116 // round 4
117 mixin(RIPEMD160_II!("cc", "dd", "ee", "aa", "bb", "X[ 1]", "11"));
118 mixin(RIPEMD160_II!("bb", "cc", "dd", "ee", "aa", "X[ 9]", "12"));
119 mixin(RIPEMD160_II!("aa", "bb", "cc", "dd", "ee", "X[11]", "14"));
120 mixin(RIPEMD160_II!("ee", "aa", "bb", "cc", "dd", "X[10]", "15"));
121 mixin(RIPEMD160_II!("dd", "ee", "aa", "bb", "cc", "X[ 0]", "14"));
122 mixin(RIPEMD160_II!("cc", "dd", "ee", "aa", "bb", "X[ 8]", "15"));
123 mixin(RIPEMD160_II!("bb", "cc", "dd", "ee", "aa", "X[12]", " 9"));
124 mixin(RIPEMD160_II!("aa", "bb", "cc", "dd", "ee", "X[ 4]", " 8"));
125 mixin(RIPEMD160_II!("ee", "aa", "bb", "cc", "dd", "X[13]", " 9"));
126 mixin(RIPEMD160_II!("dd", "ee", "aa", "bb", "cc", "X[ 3]", "14"));
127 mixin(RIPEMD160_II!("cc", "dd", "ee", "aa", "bb", "X[ 7]", " 5"));
128 mixin(RIPEMD160_II!("bb", "cc", "dd", "ee", "aa", "X[15]", " 6"));
129 mixin(RIPEMD160_II!("aa", "bb", "cc", "dd", "ee", "X[14]", " 8"));
130 mixin(RIPEMD160_II!("ee", "aa", "bb", "cc", "dd", "X[ 5]", " 6"));
131 mixin(RIPEMD160_II!("dd", "ee", "aa", "bb", "cc", "X[ 6]", " 5"));
132 mixin(RIPEMD160_II!("cc", "dd", "ee", "aa", "bb", "X[ 2]", "12"));
134 // round 5
135 mixin(RIPEMD160_JJ!("bb", "cc", "dd", "ee", "aa", "X[ 4]", " 9"));
136 mixin(RIPEMD160_JJ!("aa", "bb", "cc", "dd", "ee", "X[ 0]", "15"));
137 mixin(RIPEMD160_JJ!("ee", "aa", "bb", "cc", "dd", "X[ 5]", " 5"));
138 mixin(RIPEMD160_JJ!("dd", "ee", "aa", "bb", "cc", "X[ 9]", "11"));
139 mixin(RIPEMD160_JJ!("cc", "dd", "ee", "aa", "bb", "X[ 7]", " 6"));
140 mixin(RIPEMD160_JJ!("bb", "cc", "dd", "ee", "aa", "X[12]", " 8"));
141 mixin(RIPEMD160_JJ!("aa", "bb", "cc", "dd", "ee", "X[ 2]", "13"));
142 mixin(RIPEMD160_JJ!("ee", "aa", "bb", "cc", "dd", "X[10]", "12"));
143 mixin(RIPEMD160_JJ!("dd", "ee", "aa", "bb", "cc", "X[14]", " 5"));
144 mixin(RIPEMD160_JJ!("cc", "dd", "ee", "aa", "bb", "X[ 1]", "12"));
145 mixin(RIPEMD160_JJ!("bb", "cc", "dd", "ee", "aa", "X[ 3]", "13"));
146 mixin(RIPEMD160_JJ!("aa", "bb", "cc", "dd", "ee", "X[ 8]", "14"));
147 mixin(RIPEMD160_JJ!("ee", "aa", "bb", "cc", "dd", "X[11]", "11"));
148 mixin(RIPEMD160_JJ!("dd", "ee", "aa", "bb", "cc", "X[ 6]", " 8"));
149 mixin(RIPEMD160_JJ!("cc", "dd", "ee", "aa", "bb", "X[15]", " 5"));
150 mixin(RIPEMD160_JJ!("bb", "cc", "dd", "ee", "aa", "X[13]", " 6"));
152 // parallel round 1
153 mixin(RIPEMD160_JJJ!("aaa", "bbb", "ccc", "ddd", "eee", "X[ 5]", " 8"));
154 mixin(RIPEMD160_JJJ!("eee", "aaa", "bbb", "ccc", "ddd", "X[14]", " 9"));
155 mixin(RIPEMD160_JJJ!("ddd", "eee", "aaa", "bbb", "ccc", "X[ 7]", " 9"));
156 mixin(RIPEMD160_JJJ!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 0]", "11"));
157 mixin(RIPEMD160_JJJ!("bbb", "ccc", "ddd", "eee", "aaa", "X[ 9]", "13"));
158 mixin(RIPEMD160_JJJ!("aaa", "bbb", "ccc", "ddd", "eee", "X[ 2]", "15"));
159 mixin(RIPEMD160_JJJ!("eee", "aaa", "bbb", "ccc", "ddd", "X[11]", "15"));
160 mixin(RIPEMD160_JJJ!("ddd", "eee", "aaa", "bbb", "ccc", "X[ 4]", " 5"));
161 mixin(RIPEMD160_JJJ!("ccc", "ddd", "eee", "aaa", "bbb", "X[13]", " 7"));
162 mixin(RIPEMD160_JJJ!("bbb", "ccc", "ddd", "eee", "aaa", "X[ 6]", " 7"));
163 mixin(RIPEMD160_JJJ!("aaa", "bbb", "ccc", "ddd", "eee", "X[15]", " 8"));
164 mixin(RIPEMD160_JJJ!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 8]", "11"));
165 mixin(RIPEMD160_JJJ!("ddd", "eee", "aaa", "bbb", "ccc", "X[ 1]", "14"));
166 mixin(RIPEMD160_JJJ!("ccc", "ddd", "eee", "aaa", "bbb", "X[10]", "14"));
167 mixin(RIPEMD160_JJJ!("bbb", "ccc", "ddd", "eee", "aaa", "X[ 3]", "12"));
168 mixin(RIPEMD160_JJJ!("aaa", "bbb", "ccc", "ddd", "eee", "X[12]", " 6"));
170 // parallel round 2
171 mixin(RIPEMD160_III!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 6]", " 9"));
172 mixin(RIPEMD160_III!("ddd", "eee", "aaa", "bbb", "ccc", "X[11]", "13"));
173 mixin(RIPEMD160_III!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 3]", "15"));
174 mixin(RIPEMD160_III!("bbb", "ccc", "ddd", "eee", "aaa", "X[ 7]", " 7"));
175 mixin(RIPEMD160_III!("aaa", "bbb", "ccc", "ddd", "eee", "X[ 0]", "12"));
176 mixin(RIPEMD160_III!("eee", "aaa", "bbb", "ccc", "ddd", "X[13]", " 8"));
177 mixin(RIPEMD160_III!("ddd", "eee", "aaa", "bbb", "ccc", "X[ 5]", " 9"));
178 mixin(RIPEMD160_III!("ccc", "ddd", "eee", "aaa", "bbb", "X[10]", "11"));
179 mixin(RIPEMD160_III!("bbb", "ccc", "ddd", "eee", "aaa", "X[14]", " 7"));
180 mixin(RIPEMD160_III!("aaa", "bbb", "ccc", "ddd", "eee", "X[15]", " 7"));
181 mixin(RIPEMD160_III!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 8]", "12"));
182 mixin(RIPEMD160_III!("ddd", "eee", "aaa", "bbb", "ccc", "X[12]", " 7"));
183 mixin(RIPEMD160_III!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 4]", " 6"));
184 mixin(RIPEMD160_III!("bbb", "ccc", "ddd", "eee", "aaa", "X[ 9]", "15"));
185 mixin(RIPEMD160_III!("aaa", "bbb", "ccc", "ddd", "eee", "X[ 1]", "13"));
186 mixin(RIPEMD160_III!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 2]", "11"));
188 // parallel round 3
189 mixin(RIPEMD160_HHH!("ddd", "eee", "aaa", "bbb", "ccc", "X[15]", " 9"));
190 mixin(RIPEMD160_HHH!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 5]", " 7"));
191 mixin(RIPEMD160_HHH!("bbb", "ccc", "ddd", "eee", "aaa", "X[ 1]", "15"));
192 mixin(RIPEMD160_HHH!("aaa", "bbb", "ccc", "ddd", "eee", "X[ 3]", "11"));
193 mixin(RIPEMD160_HHH!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 7]", " 8"));
194 mixin(RIPEMD160_HHH!("ddd", "eee", "aaa", "bbb", "ccc", "X[14]", " 6"));
195 mixin(RIPEMD160_HHH!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 6]", " 6"));
196 mixin(RIPEMD160_HHH!("bbb", "ccc", "ddd", "eee", "aaa", "X[ 9]", "14"));
197 mixin(RIPEMD160_HHH!("aaa", "bbb", "ccc", "ddd", "eee", "X[11]", "12"));
198 mixin(RIPEMD160_HHH!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 8]", "13"));
199 mixin(RIPEMD160_HHH!("ddd", "eee", "aaa", "bbb", "ccc", "X[12]", " 5"));
200 mixin(RIPEMD160_HHH!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 2]", "14"));
201 mixin(RIPEMD160_HHH!("bbb", "ccc", "ddd", "eee", "aaa", "X[10]", "13"));
202 mixin(RIPEMD160_HHH!("aaa", "bbb", "ccc", "ddd", "eee", "X[ 0]", "13"));
203 mixin(RIPEMD160_HHH!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 4]", " 7"));
204 mixin(RIPEMD160_HHH!("ddd", "eee", "aaa", "bbb", "ccc", "X[13]", " 5"));
206 // parallel round 4
207 mixin(RIPEMD160_GGG!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 8]", "15"));
208 mixin(RIPEMD160_GGG!("bbb", "ccc", "ddd", "eee", "aaa", "X[ 6]", " 5"));
209 mixin(RIPEMD160_GGG!("aaa", "bbb", "ccc", "ddd", "eee", "X[ 4]", " 8"));
210 mixin(RIPEMD160_GGG!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 1]", "11"));
211 mixin(RIPEMD160_GGG!("ddd", "eee", "aaa", "bbb", "ccc", "X[ 3]", "14"));
212 mixin(RIPEMD160_GGG!("ccc", "ddd", "eee", "aaa", "bbb", "X[11]", "14"));
213 mixin(RIPEMD160_GGG!("bbb", "ccc", "ddd", "eee", "aaa", "X[15]", " 6"));
214 mixin(RIPEMD160_GGG!("aaa", "bbb", "ccc", "ddd", "eee", "X[ 0]", "14"));
215 mixin(RIPEMD160_GGG!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 5]", " 6"));
216 mixin(RIPEMD160_GGG!("ddd", "eee", "aaa", "bbb", "ccc", "X[12]", " 9"));
217 mixin(RIPEMD160_GGG!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 2]", "12"));
218 mixin(RIPEMD160_GGG!("bbb", "ccc", "ddd", "eee", "aaa", "X[13]", " 9"));
219 mixin(RIPEMD160_GGG!("aaa", "bbb", "ccc", "ddd", "eee", "X[ 9]", "12"));
220 mixin(RIPEMD160_GGG!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 7]", " 5"));
221 mixin(RIPEMD160_GGG!("ddd", "eee", "aaa", "bbb", "ccc", "X[10]", "15"));
222 mixin(RIPEMD160_GGG!("ccc", "ddd", "eee", "aaa", "bbb", "X[14]", " 8"));
224 // parallel round 5
225 mixin(RIPEMD160_FFF!("bbb", "ccc", "ddd", "eee", "aaa", "X[12] ", " 8"));
226 mixin(RIPEMD160_FFF!("aaa", "bbb", "ccc", "ddd", "eee", "X[15] ", " 5"));
227 mixin(RIPEMD160_FFF!("eee", "aaa", "bbb", "ccc", "ddd", "X[10] ", "12"));
228 mixin(RIPEMD160_FFF!("ddd", "eee", "aaa", "bbb", "ccc", "X[ 4] ", " 9"));
229 mixin(RIPEMD160_FFF!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 1] ", "12"));
230 mixin(RIPEMD160_FFF!("bbb", "ccc", "ddd", "eee", "aaa", "X[ 5] ", " 5"));
231 mixin(RIPEMD160_FFF!("aaa", "bbb", "ccc", "ddd", "eee", "X[ 8] ", "14"));
232 mixin(RIPEMD160_FFF!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 7] ", " 6"));
233 mixin(RIPEMD160_FFF!("ddd", "eee", "aaa", "bbb", "ccc", "X[ 6] ", " 8"));
234 mixin(RIPEMD160_FFF!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 2] ", "13"));
235 mixin(RIPEMD160_FFF!("bbb", "ccc", "ddd", "eee", "aaa", "X[13] ", " 6"));
236 mixin(RIPEMD160_FFF!("aaa", "bbb", "ccc", "ddd", "eee", "X[14] ", " 5"));
237 mixin(RIPEMD160_FFF!("eee", "aaa", "bbb", "ccc", "ddd", "X[ 0] ", "15"));
238 mixin(RIPEMD160_FFF!("ddd", "eee", "aaa", "bbb", "ccc", "X[ 3] ", "13"));
239 mixin(RIPEMD160_FFF!("ccc", "ddd", "eee", "aaa", "bbb", "X[ 9] ", "11"));
240 mixin(RIPEMD160_FFF!("bbb", "ccc", "ddd", "eee", "aaa", "X[11] ", "11"));
242 // combine results
243 ddd += cc+wkbuf[1]; // final result for wkbuf[0]
244 wkbuf[1] = wkbuf[2]+dd+eee;
245 wkbuf[2] = wkbuf[3]+ee+aaa;
246 wkbuf[3] = wkbuf[4]+aa+bbb;
247 wkbuf[4] = wkbuf[0]+bb+ccc;
248 wkbuf[0] = ddd;
252 // ////////////////////////////////////////////////////////////////////////// //
253 public void ripemd160_init (ref RIPEMD160_Ctx ctx) nothrow @trusted @nogc {
254 import core.stdc.string : memset;
255 memset(cast(void*)&ctx, 0, RIPEMD160_Ctx.sizeof);
256 ctx.wkbuf.ptr[0] = 0x67452301U;
257 ctx.wkbuf.ptr[1] = 0xefcdab89U;
258 ctx.wkbuf.ptr[2] = 0x98badcfeU;
259 ctx.wkbuf.ptr[3] = 0x10325476U;
260 ctx.wkbuf.ptr[4] = 0xc3d2e1f0U;
264 // ////////////////////////////////////////////////////////////////////////// //
265 public void ripemd160_putbyte (ref RIPEMD160_Ctx ctx, in ubyte b) nothrow @trusted @nogc {
266 pragma(inline, true);
267 version(BigEndian) {
268 (cast(uint*)ctx.chunkd.ptr)[ctx.chunkpos>>2] |= (cast(uint)b)<<((ctx.chunkpos&0x03U)<<3);
269 } else {
270 ctx.chunkd.ptr[ctx.chunkpos] = b;
272 if (++ctx.chunkpos == 64U) {
273 ripemd160_compress(ctx.wkbuf.ptr, cast(const uint*)ctx.chunkd.ptr);
274 version(BigEndian) {
275 import core.stdc.string : memset;
276 memset(ctx.chunkd.ptr, 0, ctx.chunkd.sizeof);
278 ctx.chunkpos = 0U;
283 // ////////////////////////////////////////////////////////////////////////// //
284 public void ripemd160_put (ref RIPEMD160_Ctx ctx, const(void)[] data) nothrow @trusted @nogc {
285 if (data.length == 0) return;
286 static if ((void*).sizeof <= 4) {
287 if (ctx.total+data.length <= ctx.total) ++ctx.totalhi;
288 ctx.total += data.length;
289 } else {
290 if (ctx.total+cast(uint)data.length <= ctx.total) ++ctx.totalhi;
291 ctx.total += cast(uint)data.length;
292 ctx.totalhi += cast(uint)(data.length>>32);
294 const(ubyte)* b = cast(const(ubyte)*)data.ptr;
295 usize datasize = data.length;
296 version(BigEndian) {
297 while (datasize--) ripemd160_putbyte(ctx, *b++);
298 } else {
299 // process full chunks, if possible
300 if (ctx.chunkpos == 0 && datasize >= cast(usize)64) {
301 do {
302 ripemd160_compress(ctx.wkbuf.ptr, cast(const uint*)b);
303 b += 64;
304 } while ((datasize -= cast(usize)64) >= cast(usize)64);
305 if (datasize == 0) return;
307 // we can use `memcpy()` here
308 import core.stdc.string : memcpy, memset;
309 uint left = 64U-ctx.chunkpos;
310 if (cast(usize)left > datasize) left = cast(uint)datasize;
311 memcpy(ctx.chunkd.ptr+ctx.chunkpos, b, cast(usize)left);
312 if ((ctx.chunkpos += left) == 64U) {
313 ripemd160_compress(ctx.wkbuf.ptr, cast(const uint*)ctx.chunkd.ptr);
314 b += left;
315 datasize -= cast(usize)left;
316 while (datasize >= cast(usize)64) {
317 ripemd160_compress(ctx.wkbuf.ptr, cast(const uint*)b);
318 b += 64;
319 datasize -= 64;
321 if ((ctx.chunkpos = cast(uint)datasize) != 0) memcpy(ctx.chunkd.ptr, b, datasize);
322 } else {
323 // this is invariant
324 version(none) {
325 datasize -= cast(usize)left;
326 if (datasize) assert(0);
333 // ////////////////////////////////////////////////////////////////////////// //
334 public ubyte[RIPEMD160_BYTES] ripemd160_finish (const ref RIPEMD160_Ctx ctx) nothrow @trusted @nogc {
335 import core.stdc.string : memcpy, memset;
337 RIPEMD160_Ctx rctx = void;
338 memcpy(cast(void*)&rctx, cast(void*)&ctx, RIPEMD160_Ctx.sizeof);
340 // padding with `1` bit
341 ripemd160_putbyte(ref rctx, 0x80);
342 // length in bits goes into two last dwords
343 version(BigEndian) {
344 if (64U-rctx.chunkpos < 8U) {
345 while (rctx.chunkpos) ripemd160_putbyte(&rctx, 0);
346 ripemd160_compress(rctx.wkbuf.ptr, cast(const uint*)rctx.chunkd.ptr);
347 memset(rctx.chunkd.ptr, 0, rctx.chunkd.sizeof);
349 // chunk is guaranteed to be properly cleared here
350 immutable uint t0 = ctx.total<<3;
351 rctx.chunkd.ptr[56U] = t0&0xffU;
352 rctx.chunkd.ptr[57U] = (t0>>8)&0xffU;
353 rctx.chunkd.ptr[58U] = (t0>>16)&0xffU;
354 rctx.chunkd.ptr[59U] = (t0>>24)&0xffU;
355 immutable uint t1 = (ctx.total>>29)|(ctx.totalhi<<3);
356 rctx.chunkd.ptr[60U] = t1&0xffU;
357 rctx.chunkd.ptr[61U] = (t1>>8)&0xffU;
358 rctx.chunkd.ptr[62U] = (t1>>16)&0xffU;
359 rctx.chunkd.ptr[63U] = (t1>>24)&0xffU;
360 } else {
361 uint left = 64U-rctx.chunkpos;
362 if (left < 8U) {
363 if (left) memset(rctx.chunkd.ptr+64U-left, 0, left);
364 ripemd160_compress(rctx.wkbuf.ptr, cast(const uint*)rctx.chunkd.ptr);
365 left = 64U;
367 left -= 8U;
368 if (left) memset(rctx.chunkd.ptr+64U-8U-left, 0, left);
369 (cast(uint*)rctx.chunkd.ptr)[14] = ctx.total<<3;
370 (cast(uint*)rctx.chunkd.ptr)[15] = (ctx.total>>29)|(ctx.totalhi<<3);
372 ripemd160_compress(rctx.wkbuf.ptr, cast(const uint*)rctx.chunkd);
374 ubyte[RIPEMD160_BYTES] hash = void;
375 memcpy(hash.ptr, cast(void*)rctx.wkbuf.ptr, RIPEMD160_BYTES);
376 return hash;
380 public int ripemd160_canput (const ref RIPEMD160_Ctx ctx, in usize datasize) pure nothrow @trusted @nogc {
381 static if ((void*).sizeof <= 4) {
382 return (ctx.totalhi < 0x1fffffffU+(ctx.total+datasize > ctx.total));
383 } else {
384 // totally untested
385 immutable uint lo = cast(uint)datasize;
386 immutable uint hi = cast(uint)(datasize>>32);
387 if (ctx.totalhi+hi >= 0x20000000U) return 0;
388 return ((hi+ctx.totalhi) < 0x1fffffffU+(ctx.total+lo > ctx.total));
393 version(unittest_ripemd160)
394 unittest {
395 static void selftest_str (const(void)[] str, string res) {
396 import core.stdc.stdio : snprintf;
397 import core.stdc.string : memcmp;
398 assert(res.length == RIPEMD160_BYTES*2);
400 RIPEMD160_Ctx ctx;
401 ubyte[RIPEMD160_BYTES] hash;
402 char[RIPEMD160_BYTES*2+2] hhex;
404 ripemd160_init(ref ctx);
405 ripemd160_put(ref ctx, str[]);
406 hash = ripemd160_finish(ref ctx);
407 foreach (immutable c; 0..RIPEMD160_BYTES) snprintf(hhex.ptr+c*2, 3, "%02x", hash[c]);
409 if (memcmp(hhex.ptr, res.ptr, RIPEMD160_BYTES*2) != 0) {
410 import core.stdc.stdio : stderr, fprintf;
411 fprintf(stderr, "FAILURE!\n");
412 fprintf(stderr, "string : %.*s\n", cast(uint)str.length, str.ptr);
413 fprintf(stderr, "result : %s\n", hhex.ptr);
414 fprintf(stderr, "expected: %.*s\n", cast(uint)res.length, res.ptr);
415 assert(0);
420 static void selftest (void) {
421 selftest_str("", "9c1185a5c5e9fc54612808977ee8f548b2258d31");
422 selftest_str("abcdefghijklmnopqrstuvwxyz", "f71c27109c692c1b56bbdceb5b9d2865b3708dbc");
424 selftest_str("a", "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe");
425 selftest_str("abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc");
426 selftest_str("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "12a053384a9c0c88e405a06c27dcf49ada62eb2b");
427 selftest_str("message digest", "5d0689ef49d2fae572b881b123a85ffa21595f36");
428 selftest_str("abcdefghijklmnopqrstuvwxyz", "f71c27109c692c1b56bbdceb5b9d2865b3708dbc");
429 selftest_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "b0e20b6e3116640286ed3a87a5713079b21f5189");
430 selftest_str("1234567890123456789012345678901234567890"~"1234567890123456789012345678901234567890", "9b752e45573d4b39f4dbd3323cab82bf63326bfb");
432 selftest_str(
433 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"~
434 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"~
435 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"~
436 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"~
437 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"~
438 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"~
439 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"~
440 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
441 , "160dd118d84b2ceff71261ab78fb9239e257c8d3");
443 // 160 zero bits
444 char[160/8] zero = 0;
445 selftest_str(zero[], "5c00bd4aca04a9057c09b20b05f723f2e23deb65");
447 selftest_str("Alice", "b417ed99b95ce21448b7d789c50009e4f088e3a7");
448 selftest_str("Miriel", "c95659db5eb45fe56023c073e96ca597347860d9");
451 selftest();