1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2013 Saso Kiselkov. All rights reserved.
24 */
25
26/*
27 * This is just to keep the compiler happy about sys/time.h not declaring
28 * gettimeofday due to -D_KERNEL (we can do this since we're actually
29 * running in userspace, but we need -D_KERNEL for the remaining Skein code).
30 */
31
32#include <sys/skein.h>
33#include <stdlib.h>
34#include <string.h>
35#include <stdio.h>
36#include <sys/time.h>
37#include <sys/stdtypes.h>
38
39/*
40 * Skein test suite using values from the Skein V1.3 specification found at:
41 * http://www.skein-hash.info/sites/default/files/skein1.3.pdf
42 */
43
44/*
45 * Test messages from the Skein spec, Appendix C.
46 */
47static const uint8_t	test_msg0[] = {
48	0xFF
49};
50
51static const uint8_t	test_msg1[] = {
52	0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
53	0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
54	0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8,
55	0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0
56};
57
58static const uint8_t	test_msg2[] = {
59	0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
60	0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
61	0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8,
62	0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0,
63	0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8,
64	0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xD0,
65	0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8,
66	0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0
67};
68
69static const uint8_t	test_msg3[] = {
70	0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
71	0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
72	0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8,
73	0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0,
74	0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8,
75	0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xD0,
76	0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8,
77	0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0,
78	0xBF, 0xBE, 0xBD, 0xBC, 0xBB, 0xBA, 0xB9, 0xB8,
79	0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0,
80	0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8,
81	0xA7, 0xA6, 0xA5, 0xA4, 0xA3, 0xA2, 0xA1, 0xA0,
82	0x9F, 0x9E, 0x9D, 0x9C, 0x9B, 0x9A, 0x99, 0x98,
83	0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
84	0x8F, 0x8E, 0x8D, 0x8C, 0x8B, 0x8A, 0x89, 0x88,
85	0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80
86};
87
88static const uint8_t	test_msg4[] = {
89	0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
90	0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
91	0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8,
92	0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0,
93	0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8,
94	0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xD0,
95	0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8,
96	0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0,
97	0xBF, 0xBE, 0xBD, 0xBC, 0xBB, 0xBA, 0xB9, 0xB8,
98	0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0,
99	0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8,
100	0xA7, 0xA6, 0xA5, 0xA4, 0xA3, 0xA2, 0xA1, 0xA0,
101	0x9F, 0x9E, 0x9D, 0x9C, 0x9B, 0x9A, 0x99, 0x98,
102	0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
103	0x8F, 0x8E, 0x8D, 0x8C, 0x8B, 0x8A, 0x89, 0x88,
104	0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
105	0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78,
106	0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
107	0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68,
108	0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
109	0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58,
110	0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
111	0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48,
112	0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
113	0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38,
114	0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
115	0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28,
116	0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
117	0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18,
118	0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
119	0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
120	0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
121};
122
123/*
124 * Test digests from the Skein spec, Appendix C.
125 */
126static const uint8_t	skein_256_test_digests[][32] = {
127	{
128		/* for test_msg0 */
129		0x0B, 0x98, 0xDC, 0xD1, 0x98, 0xEA, 0x0E, 0x50,
130		0xA7, 0xA2, 0x44, 0xC4, 0x44, 0xE2, 0x5C, 0x23,
131		0xDA, 0x30, 0xC1, 0x0F, 0xC9, 0xA1, 0xF2, 0x70,
132		0xA6, 0x63, 0x7F, 0x1F, 0x34, 0xE6, 0x7E, 0xD2
133	},
134	{
135		/* for test_msg1 */
136		0x8D, 0x0F, 0xA4, 0xEF, 0x77, 0x7F, 0xD7, 0x59,
137		0xDF, 0xD4, 0x04, 0x4E, 0x6F, 0x6A, 0x5A, 0xC3,
138		0xC7, 0x74, 0xAE, 0xC9, 0x43, 0xDC, 0xFC, 0x07,
139		0x92, 0x7B, 0x72, 0x3B, 0x5D, 0xBF, 0x40, 0x8B
140	},
141	{
142		/* for test_msg2 */
143		0xDF, 0x28, 0xE9, 0x16, 0x63, 0x0D, 0x0B, 0x44,
144		0xC4, 0xA8, 0x49, 0xDC, 0x9A, 0x02, 0xF0, 0x7A,
145		0x07, 0xCB, 0x30, 0xF7, 0x32, 0x31, 0x82, 0x56,
146		0xB1, 0x5D, 0x86, 0x5A, 0xC4, 0xAE, 0x16, 0x2F
147	}
148	/* no test digests for test_msg3 and test_msg4 */
149};
150
151static const uint8_t	skein_512_test_digests[][64] = {
152	{
153		/* for test_msg0 */
154		0x71, 0xB7, 0xBC, 0xE6, 0xFE, 0x64, 0x52, 0x22,
155		0x7B, 0x9C, 0xED, 0x60, 0x14, 0x24, 0x9E, 0x5B,
156		0xF9, 0xA9, 0x75, 0x4C, 0x3A, 0xD6, 0x18, 0xCC,
157		0xC4, 0xE0, 0xAA, 0xE1, 0x6B, 0x31, 0x6C, 0xC8,
158		0xCA, 0x69, 0x8D, 0x86, 0x43, 0x07, 0xED, 0x3E,
159		0x80, 0xB6, 0xEF, 0x15, 0x70, 0x81, 0x2A, 0xC5,
160		0x27, 0x2D, 0xC4, 0x09, 0xB5, 0xA0, 0x12, 0xDF,
161		0x2A, 0x57, 0x91, 0x02, 0xF3, 0x40, 0x61, 0x7A
162	},
163	{
164		/* no test vector for test_msg1 */
165		0,
166	},
167	{
168		/* for test_msg2 */
169		0x45, 0x86, 0x3B, 0xA3, 0xBE, 0x0C, 0x4D, 0xFC,
170		0x27, 0xE7, 0x5D, 0x35, 0x84, 0x96, 0xF4, 0xAC,
171		0x9A, 0x73, 0x6A, 0x50, 0x5D, 0x93, 0x13, 0xB4,
172		0x2B, 0x2F, 0x5E, 0xAD, 0xA7, 0x9F, 0xC1, 0x7F,
173		0x63, 0x86, 0x1E, 0x94, 0x7A, 0xFB, 0x1D, 0x05,
174		0x6A, 0xA1, 0x99, 0x57, 0x5A, 0xD3, 0xF8, 0xC9,
175		0xA3, 0xCC, 0x17, 0x80, 0xB5, 0xE5, 0xFA, 0x4C,
176		0xAE, 0x05, 0x0E, 0x98, 0x98, 0x76, 0x62, 0x5B
177	},
178	{
179		/* for test_msg3 */
180		0x91, 0xCC, 0xA5, 0x10, 0xC2, 0x63, 0xC4, 0xDD,
181		0xD0, 0x10, 0x53, 0x0A, 0x33, 0x07, 0x33, 0x09,
182		0x62, 0x86, 0x31, 0xF3, 0x08, 0x74, 0x7E, 0x1B,
183		0xCB, 0xAA, 0x90, 0xE4, 0x51, 0xCA, 0xB9, 0x2E,
184		0x51, 0x88, 0x08, 0x7A, 0xF4, 0x18, 0x87, 0x73,
185		0xA3, 0x32, 0x30, 0x3E, 0x66, 0x67, 0xA7, 0xA2,
186		0x10, 0x85, 0x6F, 0x74, 0x21, 0x39, 0x00, 0x00,
187		0x71, 0xF4, 0x8E, 0x8B, 0xA2, 0xA5, 0xAD, 0xB7
188	}
189	/* no test digests for test_msg4 */
190};
191
192static const uint8_t	skein_1024_test_digests[][128] = {
193	{
194		/* for test_msg0 */
195		0xE6, 0x2C, 0x05, 0x80, 0x2E, 0xA0, 0x15, 0x24,
196		0x07, 0xCD, 0xD8, 0x78, 0x7F, 0xDA, 0x9E, 0x35,
197		0x70, 0x3D, 0xE8, 0x62, 0xA4, 0xFB, 0xC1, 0x19,
198		0xCF, 0xF8, 0x59, 0x0A, 0xFE, 0x79, 0x25, 0x0B,
199		0xCC, 0xC8, 0xB3, 0xFA, 0xF1, 0xBD, 0x24, 0x22,
200		0xAB, 0x5C, 0x0D, 0x26, 0x3F, 0xB2, 0xF8, 0xAF,
201		0xB3, 0xF7, 0x96, 0xF0, 0x48, 0x00, 0x03, 0x81,
202		0x53, 0x1B, 0x6F, 0x00, 0xD8, 0x51, 0x61, 0xBC,
203		0x0F, 0xFF, 0x4B, 0xEF, 0x24, 0x86, 0xB1, 0xEB,
204		0xCD, 0x37, 0x73, 0xFA, 0xBF, 0x50, 0xAD, 0x4A,
205		0xD5, 0x63, 0x9A, 0xF9, 0x04, 0x0E, 0x3F, 0x29,
206		0xC6, 0xC9, 0x31, 0x30, 0x1B, 0xF7, 0x98, 0x32,
207		0xE9, 0xDA, 0x09, 0x85, 0x7E, 0x83, 0x1E, 0x82,
208		0xEF, 0x8B, 0x46, 0x91, 0xC2, 0x35, 0x65, 0x65,
209		0x15, 0xD4, 0x37, 0xD2, 0xBD, 0xA3, 0x3B, 0xCE,
210		0xC0, 0x01, 0xC6, 0x7F, 0xFD, 0xE1, 0x5B, 0xA8
211	},
212	{
213		/* no test vector for test_msg1 */
214		0
215	},
216	{
217		/* no test vector for test_msg2 */
218		0
219	},
220	{
221		/* for test_msg3 */
222		0x1F, 0x3E, 0x02, 0xC4, 0x6F, 0xB8, 0x0A, 0x3F,
223		0xCD, 0x2D, 0xFB, 0xBC, 0x7C, 0x17, 0x38, 0x00,
224		0xB4, 0x0C, 0x60, 0xC2, 0x35, 0x4A, 0xF5, 0x51,
225		0x18, 0x9E, 0xBF, 0x43, 0x3C, 0x3D, 0x85, 0xF9,
226		0xFF, 0x18, 0x03, 0xE6, 0xD9, 0x20, 0x49, 0x31,
227		0x79, 0xED, 0x7A, 0xE7, 0xFC, 0xE6, 0x9C, 0x35,
228		0x81, 0xA5, 0xA2, 0xF8, 0x2D, 0x3E, 0x0C, 0x7A,
229		0x29, 0x55, 0x74, 0xD0, 0xCD, 0x7D, 0x21, 0x7C,
230		0x48, 0x4D, 0x2F, 0x63, 0x13, 0xD5, 0x9A, 0x77,
231		0x18, 0xEA, 0xD0, 0x7D, 0x07, 0x29, 0xC2, 0x48,
232		0x51, 0xD7, 0xE7, 0xD2, 0x49, 0x1B, 0x90, 0x2D,
233		0x48, 0x91, 0x94, 0xE6, 0xB7, 0xD3, 0x69, 0xDB,
234		0x0A, 0xB7, 0xAA, 0x10, 0x6F, 0x0E, 0xE0, 0xA3,
235		0x9A, 0x42, 0xEF, 0xC5, 0x4F, 0x18, 0xD9, 0x37,
236		0x76, 0x08, 0x09, 0x85, 0xF9, 0x07, 0x57, 0x4F,
237		0x99, 0x5E, 0xC6, 0xA3, 0x71, 0x53, 0xA5, 0x78
238	},
239	{
240		/* for test_msg4 */
241		0x84, 0x2A, 0x53, 0xC9, 0x9C, 0x12, 0xB0, 0xCF,
242		0x80, 0xCF, 0x69, 0x49, 0x1B, 0xE5, 0xE2, 0xF7,
243		0x51, 0x5D, 0xE8, 0x73, 0x3B, 0x6E, 0xA9, 0x42,
244		0x2D, 0xFD, 0x67, 0x66, 0x65, 0xB5, 0xFA, 0x42,
245		0xFF, 0xB3, 0xA9, 0xC4, 0x8C, 0x21, 0x77, 0x77,
246		0x95, 0x08, 0x48, 0xCE, 0xCD, 0xB4, 0x8F, 0x64,
247		0x0F, 0x81, 0xFB, 0x92, 0xBE, 0xF6, 0xF8, 0x8F,
248		0x7A, 0x85, 0xC1, 0xF7, 0xCD, 0x14, 0x46, 0xC9,
249		0x16, 0x1C, 0x0A, 0xFE, 0x8F, 0x25, 0xAE, 0x44,
250		0x4F, 0x40, 0xD3, 0x68, 0x00, 0x81, 0xC3, 0x5A,
251		0xA4, 0x3F, 0x64, 0x0F, 0xD5, 0xFA, 0x3C, 0x3C,
252		0x03, 0x0B, 0xCC, 0x06, 0xAB, 0xAC, 0x01, 0xD0,
253		0x98, 0xBC, 0xC9, 0x84, 0xEB, 0xD8, 0x32, 0x27,
254		0x12, 0x92, 0x1E, 0x00, 0xB1, 0xBA, 0x07, 0xD6,
255		0xD0, 0x1F, 0x26, 0x90, 0x70, 0x50, 0x25, 0x5E,
256		0xF2, 0xC8, 0xE2, 0x4F, 0x71, 0x6C, 0x52, 0xA5
257	}
258};
259
260int
261main(int argc, char *argv[])
262{
263	boolean_t	failed = B_FALSE;
264	uint64_t	cpu_mhz = 0;
265
266	if (argc == 2)
267		cpu_mhz = atoi(argv[1]);
268
269#define	SKEIN_ALGO_TEST(_m, mode, diglen, testdigest)			\
270	do {								\
271		Skein ## mode ## _Ctxt_t	ctx;			\
272		uint8_t				digest[diglen / 8];	\
273		(void) Skein ## mode ## _Init(&ctx, diglen);		\
274		(void) Skein ## mode ## _Update(&ctx, _m, sizeof (_m));	\
275		(void) Skein ## mode ## _Final(&ctx, digest);		\
276		(void) printf("Skein" #mode "/" #diglen			\
277		    "\tMessage: " #_m "\tResult: ");			\
278		if (memcmp(digest, testdigest, diglen / 8) == 0) {	\
279			(void) printf("OK\n");				\
280		} else {						\
281			(void) printf("FAILED!\n");			\
282			failed = B_TRUE;				\
283		}							\
284	} while (0)
285
286#define	SKEIN_PERF_TEST(mode, diglen)					\
287	do {								\
288		Skein ## mode ## _Ctxt_t ctx;				\
289		uint8_t		digest[diglen / 8];			\
290		uint8_t		block[131072];				\
291		uint64_t	delta;					\
292		double		cpb = 0;				\
293		int		i;					\
294		struct timeval	start, end;				\
295		memset(block, 0, sizeof (block));			\
296		(void) gettimeofday(&start, NULL);			\
297		(void) Skein ## mode ## _Init(&ctx, diglen);		\
298		for (i = 0; i < 8192; i++) {				\
299			(void) Skein ## mode ## _Update(&ctx, block,	\
300			    sizeof (block));				\
301		}							\
302		(void) Skein ## mode ## _Final(&ctx, digest);		\
303		(void) gettimeofday(&end, NULL);			\
304		delta = (end.tv_sec * 1000000llu + end.tv_usec) -	\
305		    (start.tv_sec * 1000000llu + start.tv_usec);	\
306		if (cpu_mhz != 0) {					\
307			cpb = (cpu_mhz * 1e6 * ((double)delta /		\
308			    1000000)) / (8192 * 128 * 1024);		\
309		}							\
310		(void) printf("Skein" #mode "/" #diglen "\t%llu us "	\
311		    "(%.02f CPB)\n", (u_longlong_t)delta, cpb);		\
312	} while (0)
313
314	(void) printf("Running algorithm correctness tests:\n");
315	SKEIN_ALGO_TEST(test_msg0, _256, 256, skein_256_test_digests[0]);
316	SKEIN_ALGO_TEST(test_msg1, _256, 256, skein_256_test_digests[1]);
317	SKEIN_ALGO_TEST(test_msg2, _256, 256, skein_256_test_digests[2]);
318	SKEIN_ALGO_TEST(test_msg0, _512, 512, skein_512_test_digests[0]);
319	SKEIN_ALGO_TEST(test_msg2, _512, 512, skein_512_test_digests[2]);
320	SKEIN_ALGO_TEST(test_msg3, _512, 512, skein_512_test_digests[3]);
321	SKEIN_ALGO_TEST(test_msg0, 1024, 1024, skein_1024_test_digests[0]);
322	SKEIN_ALGO_TEST(test_msg3, 1024, 1024, skein_1024_test_digests[3]);
323	SKEIN_ALGO_TEST(test_msg4, 1024, 1024, skein_1024_test_digests[4]);
324	if (failed)
325		return (1);
326
327	(void) printf("Running performance tests (hashing 1024 MiB of "
328	    "data):\n");
329	SKEIN_PERF_TEST(_256, 256);
330	SKEIN_PERF_TEST(_512, 512);
331	SKEIN_PERF_TEST(1024, 1024);
332
333	return (0);
334}
335