1 /**
2 #
3 # Copyright (c) 2018 IoTone, Inc. All rights reserved.
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a copy of this
6 # software and associated documentation files (the "Software"), to deal in the 
7 # Software without restriction, including without limitation the rights to use, 
8 # copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
9 # Software, and to permit persons to whom the Software is furnished to do so, subject
10 # to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included in all
13 # copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
17 # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
18 # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
19 # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20 # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 #
22 **/
23 module iotone.libkeccak;
24 
25 import core.stdc.config;
26 import core.stdc.stdint;
27 
28 
29 //
30 // Major code debt/inspiration goes to https://github.com/coruus/keccak-tiny
31 // for the super minified C code library
32 // All data output can be hex encoded using preferred method
33 // 
34 enum RET
35 {
36     OK                          =   0,
37     ERROR_INIT                  =   -1,
38     ERROR_INPUT_INVALID         =   -2,
39     ERROR_FINALIZE              =   -3
40 }
41 
42 nothrow extern (C)
43 {
44     int shake128(uint8_t*, size_t /* bytes */, const uint8_t*, size_t);
45     int shake256(uint8_t*, size_t /* bytes */, const uint8_t*, size_t);
46 
47     int sha3_224(uint8_t*, size_t /* bytes */, const uint8_t*, size_t);
48     int sha3_256(uint8_t*, size_t /* bytes */, const uint8_t*, size_t);
49     int sha3_384(uint8_t*, size_t /* bytes */, const uint8_t*, size_t);
50     int sha3_512(uint8_t*, size_t /* bytes */, const uint8_t*, size_t);
51 
52     int keccak_224(uint8_t*, size_t /* bytes */, const uint8_t*, size_t);
53     int keccak_256(uint8_t*, size_t /* bytes */, const uint8_t*, size_t);
54     int keccak_384(uint8_t*, size_t /* bytes */, const uint8_t*, size_t);
55     int keccak_512(uint8_t*, size_t /* bytes */, const uint8_t*, size_t);
56 };
57 
58 
59 
60 
61 unittest {
62     import std.stdio;
63     import std.string;
64 
65     //
66     // Including simple+efficient ubyte2hex converter
67     // from https://forum.dlang.org/post/opsfp9hj065a2sq9@digitalmars.com
68     //
69     const char[16] hexdigits = "0123456789abcdef";
70     char[] hexStringT(ubyte[] d) {
71         char[] result;
72 
73         /* No point converting an empty array now is there? */
74         if (d.length != 0) {
75             ubyte u;
76             uint sz = u.sizeof*2; /* number of chars required to represent one 'u' */
77             uint ndigits = 0;
78 
79             /* pre-allocate space required. */
80             result = new char[sz*d.length];
81             
82             /* start at end of resulting string, loop back to start. */
83             for(int i = cast(int)d.length-1; i >= 0; i--) {
84                 /*this loop takes the remainder of u/16, uses it as an index
85                 into the hexdigits array, then does u/16, repeating
86                 till u == 0
87                 */
88                 u = d[i];
89                 for(; u; u /= 16) {
90                     /* you can use u & 15 or u % 16 below
91                     both give you the remainder of u/16
92                     */
93                     result[result.length-1-ndigits] = hexdigits[u & 15];
94                     ndigits++;
95                 }
96                 
97                 /* Pad each value with 0's */
98                 for(; ndigits < (d.length-i)*sz; ndigits++)
99                     result[result.length-1-ndigits] = '0';
100             }
101         }
102 
103         return result;
104     }
105 
106     ubyte[28] dataout28;
107     ubyte[32] dataout32;
108     ubyte[48] dataout48;
109     ubyte[56] dataout56;
110     ubyte[64] dataout64;
111     ubyte[128] dataout128;
112     ubyte[256] dataout256;
113     ubyte[] datain = cast(ubyte[])("The quick brown fox jumps over the lazy dog".dup);
114     ubyte[] datain2 = cast(ubyte[])("".dup);
115     ubyte[] datain3 = cast(ubyte[])("The quick brown fox jumps over the lazy dog.".dup);
116     
117 
118     // A basic example
119     shake256(dataout32.ptr, 32 /* bytes */, datain.ptr, datain.length);
120     assert(dataout32.length == 32);
121     writeln(dataout32);
122     // writeln(hexStringT(dataout32));
123     assert(hexStringT(dataout32) == "2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca");
124 
125     sha3_512(dataout64.ptr, 64, datain2.ptr, datain2.length);
126     assert(dataout64.length == 64);
127     writeln(dataout64);
128     assert(hexStringT(dataout64) == "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26");
129 
130     
131     sha3_512(dataout64.ptr, 64, datain.ptr, datain.length);
132     assert(dataout64.length == 64);
133     writeln(dataout64);
134     assert(hexStringT(dataout64) == "01dedd5de4ef14642445ba5f5b97c15e47b9ad931326e4b0727cd94cefc44fff23f07bf543139939b49128caf436dc1bdee54fcb24023a08d9403f9b4bf0d450");
135 
136     sha3_512(dataout64.ptr, 64, datain3.ptr, datain3.length);
137     assert(dataout64.length == 64);
138     writeln(dataout64);
139     assert(hexStringT(dataout64) == "18f4f4bd419603f95538837003d9d254c26c23765565162247483f65c50303597bc9ce4d289f21d1c2f1f458828e33dc442100331b35e7eb031b5d38ba6460f8");
140 
141     sha3_384(dataout48.ptr, 48, datain2.ptr, datain2.length);
142     assert(dataout48.length == 48);
143     writeln(dataout48);
144     assert(hexStringT(dataout48) == "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004");
145 
146     sha3_384(dataout48.ptr, 48, datain.ptr, datain.length);
147     assert(dataout48.length == 48);
148     writeln(dataout48);
149     assert(hexStringT(dataout48) == "7063465e08a93bce31cd89d2e3ca8f602498696e253592ed26f07bf7e703cf328581e1471a7ba7ab119b1a9ebdf8be41");
150 
151     sha3_384(dataout48.ptr, 48, datain3.ptr, datain3.length);
152     assert(dataout48.length == 48);
153     writeln(dataout48);
154     assert(hexStringT(dataout48) == "1a34d81695b622df178bc74df7124fe12fac0f64ba5250b78b99c1273d4b080168e10652894ecad5f1f4d5b965437fb9");
155 
156     sha3_256(dataout32.ptr, 32, datain2.ptr, datain2.length);
157     assert(dataout32.length == 32);
158     writeln(dataout32);
159     assert(hexStringT(dataout32) == "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a");
160 
161     sha3_256(dataout32.ptr, 32, datain.ptr, datain.length);
162     assert(dataout32.length == 32);
163     writeln(dataout32);
164     assert(hexStringT(dataout32) == "69070dda01975c8c120c3aada1b282394e7f032fa9cf32f4cb2259a0897dfc04");
165 
166     sha3_256(dataout32.ptr, 32, datain3.ptr, datain3.length);
167     assert(dataout32.length == 32);
168     writeln(dataout32);
169     assert(hexStringT(dataout32) == "a80f839cd4f83f6c3dafc87feae470045e4eb0d366397d5c6ce34ba1739f734d");
170 
171     sha3_224(dataout28.ptr, 28, datain2.ptr, datain2.length);
172     assert(dataout28.length == 28);
173     writeln(dataout28);
174     assert(hexStringT(dataout28) == "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7");
175 
176     sha3_224(dataout28.ptr, 28, datain.ptr, datain.length);
177     assert(dataout28.length == 28);
178     writeln(dataout28);
179     assert(hexStringT(dataout28) == "d15dadceaa4d5d7bb3b48f446421d542e08ad8887305e28d58335795");
180 
181     sha3_224(dataout28.ptr, 28, datain3.ptr, datain3.length);
182     assert(dataout28.length == 28);
183     writeln(dataout28);
184     assert(hexStringT(dataout28) == "2d0708903833afabdd232a20201176e8b58c5be8a6fe74265ac54db0");
185 
186     shake128(dataout32.ptr, 32 /* bytes */, datain2.ptr, datain2.length);
187     assert(dataout32.length == 32);
188     writeln(dataout32);
189     assert(hexStringT(dataout32) == "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26");
190 
191     shake256(dataout64.ptr, 64 /* bytes */, datain2.ptr, datain2.length);
192     assert(dataout64.length == 64);
193     writeln(dataout64);
194     assert(hexStringT(dataout64) == "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be");
195 
196     keccak_512(dataout64.ptr, 64, datain2.ptr, datain2.length);
197     assert(dataout64.length == 64);
198     writeln(dataout64);
199     assert(hexStringT(dataout64) == "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e");
200 
201     keccak_512(dataout64.ptr, 64, datain.ptr, datain.length);
202     assert(dataout64.length == 64);
203     writeln(dataout64);
204     assert(hexStringT(dataout64) == "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609");
205 
206     keccak_512(dataout64.ptr, 64, datain3.ptr, datain3.length);
207     assert(dataout64.length == 64);
208     writeln(dataout64);
209     assert(hexStringT(dataout64) == "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760");
210 
211     keccak_384(dataout48.ptr, 48, datain2.ptr, datain2.length);
212     assert(dataout48.length == 48);
213     writeln(dataout48);
214     assert(hexStringT(dataout48) == "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff");
215 
216     keccak_384(dataout48.ptr, 48, datain.ptr, datain.length);
217     assert(dataout48.length == 48);
218     writeln(dataout48);
219     assert(hexStringT(dataout48) == "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3");
220 
221     keccak_384(dataout48.ptr, 48, datain3.ptr, datain3.length);
222     assert(dataout48.length == 48);
223     writeln(dataout48);
224     assert(hexStringT(dataout48) == "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b");
225 
226     keccak_256(dataout32.ptr, 32 /* bytes */, datain2.ptr, datain2.length);
227     assert(dataout32.length == 32);
228     writeln(dataout32);
229     assert(hexStringT(dataout32) == "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
230 
231     keccak_256(dataout32.ptr, 32 /* bytes */, datain.ptr, datain.length);
232     assert(dataout32.length == 32);
233     writeln(dataout32);
234     assert(hexStringT(dataout32) == "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15");
235 
236     keccak_256(dataout32.ptr, 32 /* bytes */, datain3.ptr, datain3.length);
237     assert(dataout32.length == 32);
238     writeln(dataout32);
239     assert(hexStringT(dataout32) == "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d");
240 
241     keccak_224(dataout28.ptr, 28, datain2.ptr, datain2.length);
242     assert(dataout28.length == 28);
243     writeln(dataout28);
244     assert(hexStringT(dataout28) == "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd");
245 
246     keccak_224(dataout28.ptr, 28, datain.ptr, datain.length);
247     assert(dataout28.length == 28);
248     writeln(dataout28);
249     assert(hexStringT(dataout28) == "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe");
250 
251     keccak_224(dataout28.ptr, 28, datain3.ptr, datain3.length);
252     assert(dataout28.length == 28);
253     writeln(dataout28);
254     assert(hexStringT(dataout28) == "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab");
255 }