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 Edon-R code).
30 */
31#ifdef	_KERNEL
32#undef	_KERNEL
33#endif
34
35#include <sys/edonr.h>
36#include <stdlib.h>
37#include <string.h>
38#include <stdio.h>
39#include <sys/note.h>
40#include <sys/time.h>
41#include <sys/stdtypes.h>
42
43/*
44 * Test messages from:
45 * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
46 */
47const char	*test_msg0 = "abc";
48const char	*test_msg1 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmn"
49	"lmnomnopnopq";
50const char	*test_msg2 = "abcdefghbcdefghicdefghijdefghijkefghijklfghi"
51	"jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
52
53/*
54 * Test digests computed by hand. There's no formal standard or spec for edonr.
55 */
56const uint8_t	edonr_224_test_digests[][28] = {
57	{
58		/* for test_msg0 */
59		0x56, 0x63, 0xc4, 0x93, 0x95, 0x20, 0xfa, 0xf6,
60		0x12, 0x31, 0x65, 0xa4, 0x66, 0xf2, 0x56, 0x01,
61		0x95, 0x2e, 0xa9, 0xe4, 0x24, 0xdd, 0xc9, 0x6b,
62		0xef, 0xd0, 0x40, 0x94
63	},
64	{
65		/* for test_msg1 */
66		0xd0, 0x13, 0xe4, 0x87, 0x4d, 0x06, 0x8d, 0xca,
67		0x4e, 0x14, 0xb9, 0x37, 0x2f, 0xce, 0x12, 0x20,
68		0x60, 0xf8, 0x5c, 0x0a, 0xfd, 0x7a, 0x7d, 0x97,
69		0x88, 0x2b, 0x05, 0x75
70	}
71	/* no test vector for test_msg2 */
72};
73
74const uint8_t	edonr_256_test_digests[][32] = {
75	{
76		/* for test_msg0 */
77		0x54, 0xd7, 0x8b, 0x13, 0xc7, 0x4e, 0xda, 0x5a,
78		0xed, 0xc2, 0x71, 0xcc, 0x88, 0x1f, 0xb2, 0x2f,
79		0x83, 0x99, 0xaf, 0xd3, 0x04, 0x0b, 0x6a, 0x39,
80		0x2d, 0x73, 0x94, 0x05, 0x50, 0x8d, 0xd8, 0x51
81	},
82	{
83		/* for test_msg1 */
84		0x49, 0x2d, 0x0b, 0x19, 0xab, 0x1e, 0xde, 0x3a,
85		0xea, 0x9b, 0xf2, 0x39, 0x3a, 0xb1, 0x21, 0xde,
86		0x21, 0xf6, 0x80, 0x1f, 0xad, 0xbe, 0x8b, 0x07,
87		0xc7, 0xfb, 0xe6, 0x99, 0x0e, 0x4d, 0x73, 0x63
88	}
89	/* no test vectorfor test_msg2 */
90};
91
92const uint8_t	edonr_384_test_digests[][48] = {
93	{
94		/* for test_msg0 */
95		0x0e, 0x7c, 0xd7, 0x85, 0x78, 0x77, 0xe0, 0x89,
96		0x5b, 0x1c, 0xdf, 0x49, 0xf4, 0x1d, 0x20, 0x9c,
97		0x72, 0x7d, 0x2e, 0x57, 0x9b, 0x9b, 0x9a, 0xdc,
98		0x60, 0x27, 0x97, 0x82, 0xb9, 0x90, 0x72, 0xec,
99		0x7e, 0xce, 0xd3, 0x16, 0x5f, 0x47, 0x75, 0x48,
100		0xfa, 0x60, 0x72, 0x7e, 0x01, 0xc7, 0x7c, 0xc6
101	},
102	{
103		/* no test vector for test_msg1 */
104		0
105	},
106	{
107		/* for test_msg2 */
108		0xe2, 0x34, 0xa1, 0x02, 0x83, 0x76, 0xae, 0xe6,
109		0x82, 0xd9, 0x38, 0x32, 0x0e, 0x00, 0x78, 0xd2,
110		0x34, 0xdb, 0xb9, 0xbd, 0xf0, 0x08, 0xa8, 0x0f,
111		0x63, 0x1c, 0x3d, 0x4a, 0xfd, 0x0a, 0xe9, 0x59,
112		0xdc, 0xd4, 0xce, 0xcd, 0x8d, 0x67, 0x6c, 0xea,
113		0xbb, 0x1a, 0x32, 0xed, 0x5c, 0x6b, 0xf1, 0x7f
114	}
115};
116
117const uint8_t	edonr_512_test_digests[][64] = {
118	{
119		/* for test_msg0 */
120		0x1b, 0x14, 0xdb, 0x15, 0x5f, 0x1d, 0x40, 0x65,
121		0x94, 0xb8, 0xce, 0xf7, 0x0a, 0x43, 0x62, 0xec,
122		0x6b, 0x5d, 0xe6, 0xa5, 0xda, 0xf5, 0x0e, 0xc9,
123		0x99, 0xe9, 0x87, 0xc1, 0x9d, 0x30, 0x49, 0xe2,
124		0xde, 0x59, 0x77, 0xbb, 0x05, 0xb1, 0xbb, 0x22,
125		0x00, 0x50, 0xa1, 0xea, 0x5b, 0x46, 0xa9, 0xf1,
126		0x74, 0x0a, 0xca, 0xfb, 0xf6, 0xb4, 0x50, 0x32,
127		0xad, 0xc9, 0x0c, 0x62, 0x83, 0x72, 0xc2, 0x2b
128	},
129	{
130		/* no test vector for test_msg1 */
131		0
132	},
133	{
134		/* for test_msg2 */
135		0x53, 0x51, 0x07, 0x0d, 0xc5, 0x1c, 0x3b, 0x2b,
136		0xac, 0xa5, 0xa6, 0x0d, 0x02, 0x52, 0xcc, 0xb4,
137		0xe4, 0x92, 0x1a, 0x96, 0xfe, 0x5a, 0x69, 0xe7,
138		0x6d, 0xad, 0x48, 0xfd, 0x21, 0xa0, 0x84, 0x5a,
139		0xd5, 0x7f, 0x88, 0x0b, 0x3e, 0x4a, 0x90, 0x7b,
140		0xc5, 0x03, 0x15, 0x18, 0x42, 0xbb, 0x94, 0x9e,
141		0x1c, 0xba, 0x74, 0x39, 0xa6, 0x40, 0x9a, 0x34,
142		0xb8, 0x43, 0x6c, 0xb4, 0x69, 0x21, 0x58, 0x3c
143	}
144};
145
146int
147main(int argc, char *argv[])
148{
149	boolean_t	failed = B_FALSE;
150	uint64_t	cpu_mhz = 0;
151
152	if (argc == 2)
153		cpu_mhz = atoi(argv[1]);
154
155#define	EDONR_ALGO_TEST(_m, mode, testdigest)				\
156	do {								\
157		EdonRState	ctx;					\
158		uint8_t		digest[mode / 8];			\
159		EdonRInit(&ctx, mode);					\
160		EdonRUpdate(&ctx, (const uint8_t *) _m, strlen(_m) * 8);\
161		EdonRFinal(&ctx, digest);				\
162		(void) printf("Edon-R-%-6sMessage: " #_m		\
163		    "\tResult: ", #mode);				\
164		if (bcmp(digest, testdigest, mode / 8) == 0) {		\
165			(void) printf("OK\n");				\
166		} else {						\
167			(void) printf("FAILED!\n");			\
168			failed = B_TRUE;				\
169		}							\
170		NOTE(CONSTCOND)						\
171	} while (0)
172
173#define	EDONR_PERF_TEST(mode)						\
174	do {								\
175		EdonRState	ctx;					\
176		uint8_t		digest[mode / 8];			\
177		uint8_t		block[131072];				\
178		uint64_t	delta;					\
179		double		cpb = 0;				\
180		int		i;					\
181		struct timeval	start, end;				\
182		bzero(block, sizeof (block));				\
183		(void) gettimeofday(&start, NULL);			\
184		EdonRInit(&ctx, mode);					\
185		for (i = 0; i < 8192; i++)				\
186			EdonRUpdate(&ctx, block, sizeof (block) * 8);	\
187		EdonRFinal(&ctx, digest);				\
188		(void) gettimeofday(&end, NULL);			\
189		delta = (end.tv_sec * 1000000llu + end.tv_usec) -	\
190		    (start.tv_sec * 1000000llu + start.tv_usec);	\
191		if (cpu_mhz != 0) {					\
192			cpb = (cpu_mhz * 1e6 * ((double)delta /		\
193			    1000000)) / (8192 * 128 * 1024);		\
194		}							\
195		(void) printf("Edon-R-%-6s%llu us (%.02f CPB)\n", #mode,\
196		    (u_longlong_t)delta, cpb);				\
197		NOTE(CONSTCOND)						\
198	} while (0)
199
200	(void) printf("Running algorithm correctness tests:\n");
201	EDONR_ALGO_TEST(test_msg0, 224, edonr_224_test_digests[0]);
202	EDONR_ALGO_TEST(test_msg1, 224, edonr_224_test_digests[1]);
203	EDONR_ALGO_TEST(test_msg0, 256, edonr_256_test_digests[0]);
204	EDONR_ALGO_TEST(test_msg1, 256, edonr_256_test_digests[1]);
205	EDONR_ALGO_TEST(test_msg0, 384, edonr_384_test_digests[0]);
206	EDONR_ALGO_TEST(test_msg2, 384, edonr_384_test_digests[2]);
207	EDONR_ALGO_TEST(test_msg0, 512, edonr_512_test_digests[0]);
208	EDONR_ALGO_TEST(test_msg2, 512, edonr_512_test_digests[2]);
209	if (failed)
210		return (1);
211
212	(void) printf("Running performance tests (hashing 1024 MiB of "
213	    "data):\n");
214	EDONR_PERF_TEST(256);
215	EDONR_PERF_TEST(512);
216
217	return (0);
218}
219