xref: /illumos-gate/usr/src/uts/common/io/sha2_ktest.c (revision d6004f2d6507e58bb1cb59ab594185cfe4214f85)
1*d6004f2dSGernotS /*
2*d6004f2dSGernotS  * This file and its contents are supplied under the terms of the
3*d6004f2dSGernotS  * Common Development and Distribution License ("CDDL"), version 1.0.
4*d6004f2dSGernotS  * You may only use this file in accordance with the terms of version
5*d6004f2dSGernotS  * 1.0 of the CDDL.
6*d6004f2dSGernotS  *
7*d6004f2dSGernotS  * A full copy of the text of the CDDL should have accompanied this
8*d6004f2dSGernotS  * source.  A copy of the CDDL is also available via the Internet at
9*d6004f2dSGernotS  * http://www.illumos.org/license/CDDL.
10*d6004f2dSGernotS  */
11*d6004f2dSGernotS 
12*d6004f2dSGernotS /*
13*d6004f2dSGernotS  * Copyright 2026 Gernot Strasser
14*d6004f2dSGernotS  */
15*d6004f2dSGernotS 
16*d6004f2dSGernotS /*
17*d6004f2dSGernotS  * ktest(8) coverage for the kernel SHA-256 block transform, in particular the
18*d6004f2dSGernotS  * amd64 runtime dispatch between the generic transform and the Intel SHA
19*d6004f2dSGernotS  * Extensions ("SHA-NI") path in sha2.c.
20*d6004f2dSGernotS  *
21*d6004f2dSGernotS  * Tests:
22*d6004f2dSGernotS  *   kat            - known-answer test against precomputed digests for inputs
23*d6004f2dSGernotS  *                    of many lengths, including ones that cross the dispatch's
24*d6004f2dSGernotS  *                    32 KiB (512-block) kernel-FPU window and odd tail blocks.
25*d6004f2dSGernotS  *   incremental    - the same inputs fed via varied SHA2Update() increments,
26*d6004f2dSGernotS  *                    exercising the partial-block buffering and the single
27*d6004f2dSGernotS  *                    block tail path in SHA2Final().
28*d6004f2dSGernotS  *   fallback_equiv - hashes each input twice, once with SHA-NI forced off
29*d6004f2dSGernotS  *                    (sha256_ni_disable=1, generic path) and once on, and
30*d6004f2dSGernotS  *                    asserts both match each other and the known answer.  This
31*d6004f2dSGernotS  *                    is the differential that catches dispatch / chunking /
32*d6004f2dSGernotS  *                    kernel-FPU bugs without needing an external reference.
33*d6004f2dSGernotS  *                    It is skipped on non-amd64 platforms and on CPUs without
34*d6004f2dSGernotS  *                    the SHA extensions, where both paths would be identical.
35*d6004f2dSGernotS  *
36*d6004f2dSGernotS  * The test input of length L is the deterministic byte pattern b[i] = i & 0xff,
37*d6004f2dSGernotS  * so the expected digests below are reproducible with any sha256 tool.
38*d6004f2dSGernotS  */
39*d6004f2dSGernotS 
40*d6004f2dSGernotS #include <sys/types.h>
41*d6004f2dSGernotS #include <sys/ddi.h>
42*d6004f2dSGernotS #include <sys/sunddi.h>
43*d6004f2dSGernotS #include <sys/modctl.h>
44*d6004f2dSGernotS #include <sys/kmem.h>
45*d6004f2dSGernotS #include <sys/systm.h>
46*d6004f2dSGernotS #include <sys/sysmacros.h>
47*d6004f2dSGernotS #include <sys/stdbool.h>
48*d6004f2dSGernotS #include <sys/debug.h>
49*d6004f2dSGernotS #include <sys/sha2.h>
50*d6004f2dSGernotS #include <sys/ktest.h>
51*d6004f2dSGernotS #ifdef	__amd64
52*d6004f2dSGernotS #include <sys/x86_archext.h>
53*d6004f2dSGernotS #endif
54*d6004f2dSGernotS 
55*d6004f2dSGernotS /*
56*d6004f2dSGernotS  * The largest test vector, 128 KiB + 1 byte.  The amd64 dispatch in sha2.c
57*d6004f2dSGernotS  * hands the SHA-NI transform at most 512 64-byte blocks (32 KiB) per
58*d6004f2dSGernotS  * kernel-FPU window, so this length spans four full windows plus a trailing
59*d6004f2dSGernotS  * partial block; the 32704..32833 vectors below straddle the first window
60*d6004f2dSGernotS  * boundary (32 KiB - 64, exactly 32 KiB, +1, +64, and +65 bytes).
61*d6004f2dSGernotS  */
62*d6004f2dSGernotS #define	SHA256_KT_MAXLEN	131073
63*d6004f2dSGernotS 
64*d6004f2dSGernotS /* Expected SHA-256 of b[i] = (i & 0xff) for i in [0, len). */
65*d6004f2dSGernotS static const struct {
66*d6004f2dSGernotS 	size_t		len;
67*d6004f2dSGernotS 	uint8_t		dig[SHA256_DIGEST_LENGTH];
68*d6004f2dSGernotS } sha256_kat_vec[] = {
69*d6004f2dSGernotS 	{ 0, {
70*d6004f2dSGernotS 	    0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
71*d6004f2dSGernotS 	    0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
72*d6004f2dSGernotS 	    0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
73*d6004f2dSGernotS 	    0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 } },
74*d6004f2dSGernotS 	{ 1, {
75*d6004f2dSGernotS 	    0x6e, 0x34, 0x0b, 0x9c, 0xff, 0xb3, 0x7a, 0x98,
76*d6004f2dSGernotS 	    0x9c, 0xa5, 0x44, 0xe6, 0xbb, 0x78, 0x0a, 0x2c,
77*d6004f2dSGernotS 	    0x78, 0x90, 0x1d, 0x3f, 0xb3, 0x37, 0x38, 0x76,
78*d6004f2dSGernotS 	    0x85, 0x11, 0xa3, 0x06, 0x17, 0xaf, 0xa0, 0x1d } },
79*d6004f2dSGernotS 	{ 3, {
80*d6004f2dSGernotS 	    0xae, 0x4b, 0x32, 0x80, 0xe5, 0x6e, 0x2f, 0xaf,
81*d6004f2dSGernotS 	    0x83, 0xf4, 0x14, 0xa6, 0xe3, 0xda, 0xbe, 0x9d,
82*d6004f2dSGernotS 	    0x5f, 0xbe, 0x18, 0x97, 0x65, 0x44, 0xc0, 0x5f,
83*d6004f2dSGernotS 	    0xed, 0x12, 0x1a, 0xcc, 0xb8, 0x5b, 0x53, 0xfc } },
84*d6004f2dSGernotS 	{ 55, {
85*d6004f2dSGernotS 	    0x46, 0x3e, 0xb2, 0x8e, 0x72, 0xf8, 0x2e, 0x0a,
86*d6004f2dSGernotS 	    0x96, 0xc0, 0xa4, 0xcc, 0x53, 0x69, 0x0c, 0x57,
87*d6004f2dSGernotS 	    0x12, 0x81, 0x13, 0x1f, 0x67, 0x2a, 0xa2, 0x29,
88*d6004f2dSGernotS 	    0xe0, 0xd4, 0x5a, 0xe5, 0x9b, 0x59, 0x8b, 0x59 } },
89*d6004f2dSGernotS 	{ 56, {
90*d6004f2dSGernotS 	    0xda, 0x2a, 0xe4, 0xd6, 0xb3, 0x67, 0x48, 0xf2,
91*d6004f2dSGernotS 	    0xa3, 0x18, 0xf2, 0x3e, 0x7a, 0xb1, 0xdf, 0xdf,
92*d6004f2dSGernotS 	    0x45, 0xac, 0xdc, 0x9d, 0x04, 0x9b, 0xd8, 0x0e,
93*d6004f2dSGernotS 	    0x59, 0xde, 0x82, 0xa6, 0x08, 0x95, 0xf5, 0x62 } },
94*d6004f2dSGernotS 	{ 57, {
95*d6004f2dSGernotS 	    0x2f, 0xe7, 0x41, 0xaf, 0x80, 0x1c, 0xc2, 0x38,
96*d6004f2dSGernotS 	    0x60, 0x2a, 0xc0, 0xec, 0x6a, 0x7b, 0x0c, 0x3a,
97*d6004f2dSGernotS 	    0x8a, 0x87, 0xc7, 0xfc, 0x7d, 0x7f, 0x02, 0xa3,
98*d6004f2dSGernotS 	    0xfe, 0x03, 0xd1, 0xc1, 0x2e, 0xac, 0x4d, 0x8f } },
99*d6004f2dSGernotS 	{ 63, {
100*d6004f2dSGernotS 	    0x29, 0xaf, 0x26, 0x86, 0xfd, 0x53, 0x37, 0x4a,
101*d6004f2dSGernotS 	    0x36, 0xb0, 0x84, 0x66, 0x94, 0xcc, 0x34, 0x21,
102*d6004f2dSGernotS 	    0x77, 0xe4, 0x28, 0xd1, 0x64, 0x75, 0x15, 0xf0,
103*d6004f2dSGernotS 	    0x78, 0x78, 0x4d, 0x69, 0xcd, 0xb9, 0xe4, 0x88 } },
104*d6004f2dSGernotS 	{ 64, {
105*d6004f2dSGernotS 	    0xfd, 0xea, 0xb9, 0xac, 0xf3, 0x71, 0x03, 0x62,
106*d6004f2dSGernotS 	    0xbd, 0x26, 0x58, 0xcd, 0xc9, 0xa2, 0x9e, 0x8f,
107*d6004f2dSGernotS 	    0x9c, 0x75, 0x7f, 0xcf, 0x98, 0x11, 0x60, 0x3a,
108*d6004f2dSGernotS 	    0x8c, 0x44, 0x7c, 0xd1, 0xd9, 0x15, 0x11, 0x08 } },
109*d6004f2dSGernotS 	{ 65, {
110*d6004f2dSGernotS 	    0x4b, 0xfd, 0x2c, 0x8b, 0x6f, 0x1e, 0xec, 0x7a,
111*d6004f2dSGernotS 	    0x2a, 0xfe, 0xb4, 0x8b, 0x93, 0x4e, 0xe4, 0xb2,
112*d6004f2dSGernotS 	    0x69, 0x41, 0x82, 0x02, 0x7e, 0x6d, 0x0f, 0xc0,
113*d6004f2dSGernotS 	    0x75, 0x07, 0x4f, 0x2f, 0xab, 0xb3, 0x17, 0x81 } },
114*d6004f2dSGernotS 	{ 127, {
115*d6004f2dSGernotS 	    0x92, 0xca, 0x0f, 0xa6, 0x65, 0x1e, 0xe2, 0xf9,
116*d6004f2dSGernotS 	    0x7b, 0x88, 0x4b, 0x72, 0x46, 0xa5, 0x62, 0xfa,
117*d6004f2dSGernotS 	    0x71, 0x25, 0x0f, 0xed, 0xef, 0xe5, 0xeb, 0xf2,
118*d6004f2dSGernotS 	    0x70, 0xd3, 0x1c, 0x54, 0x6b, 0xfe, 0xa9, 0x76 } },
119*d6004f2dSGernotS 	{ 128, {
120*d6004f2dSGernotS 	    0x47, 0x1f, 0xb9, 0x43, 0xaa, 0x23, 0xc5, 0x11,
121*d6004f2dSGernotS 	    0xf6, 0xf7, 0x2f, 0x8d, 0x16, 0x52, 0xd9, 0xc8,
122*d6004f2dSGernotS 	    0x80, 0xcf, 0xa3, 0x92, 0xad, 0x80, 0x50, 0x31,
123*d6004f2dSGernotS 	    0x20, 0x54, 0x77, 0x03, 0xe5, 0x6a, 0x2b, 0xe5 } },
124*d6004f2dSGernotS 	{ 129, {
125*d6004f2dSGernotS 	    0x50, 0x99, 0xc6, 0xa5, 0x62, 0x03, 0xf9, 0x68,
126*d6004f2dSGernotS 	    0x7f, 0x7d, 0x33, 0xf4, 0xbf, 0xdf, 0x57, 0x6d,
127*d6004f2dSGernotS 	    0x31, 0xdc, 0x91, 0xf6, 0xb6, 0x95, 0xec, 0xea,
128*d6004f2dSGernotS 	    0x38, 0xb2, 0x77, 0x0c, 0x87, 0x63, 0x11, 0x35 } },
129*d6004f2dSGernotS 	{ 8192, {
130*d6004f2dSGernotS 	    0xdc, 0x40, 0x4a, 0x61, 0x3f, 0xed, 0xae, 0xb5,
131*d6004f2dSGernotS 	    0x40, 0x34, 0x51, 0x4b, 0xc6, 0x50, 0x5f, 0x56,
132*d6004f2dSGernotS 	    0xb9, 0x33, 0xca, 0xa5, 0x25, 0x02, 0x99, 0xba,
133*d6004f2dSGernotS 	    0x7d, 0x09, 0x43, 0x77, 0xa5, 0x1c, 0xaa, 0x46 } },
134*d6004f2dSGernotS 	{ 32704, {
135*d6004f2dSGernotS 	    0x6a, 0x1c, 0xd5, 0xbb, 0x6e, 0x41, 0xf2, 0x83,
136*d6004f2dSGernotS 	    0x45, 0x2a, 0x9b, 0xa5, 0x15, 0x24, 0xdd, 0x9e,
137*d6004f2dSGernotS 	    0xbb, 0x8b, 0x43, 0x3c, 0x1d, 0x23, 0x05, 0x14,
138*d6004f2dSGernotS 	    0x1c, 0xa9, 0x02, 0x09, 0xbd, 0x63, 0x53, 0xb5 } },
139*d6004f2dSGernotS 	{ 32768, {
140*d6004f2dSGernotS 	    0xe1, 0x13, 0x60, 0x25, 0x1d, 0x11, 0x73, 0x65,
141*d6004f2dSGernotS 	    0x0c, 0xdc, 0xd2, 0x0f, 0x11, 0x1d, 0x8f, 0x1c,
142*d6004f2dSGernotS 	    0xa2, 0xe4, 0x12, 0xf5, 0x72, 0xe8, 0xb3, 0x6a,
143*d6004f2dSGernotS 	    0x4d, 0xc0, 0x67, 0x12, 0x1c, 0x17, 0x99, 0xb8 } },
144*d6004f2dSGernotS 	{ 32769, {
145*d6004f2dSGernotS 	    0xb9, 0x3c, 0x16, 0xc9, 0x98, 0x95, 0xf1, 0x59,
146*d6004f2dSGernotS 	    0x33, 0x47, 0xab, 0x57, 0xaf, 0x0c, 0x0a, 0x82,
147*d6004f2dSGernotS 	    0xf9, 0x67, 0x2e, 0xcb, 0x3d, 0xeb, 0xb5, 0x9d,
148*d6004f2dSGernotS 	    0x12, 0x4e, 0x1b, 0x38, 0xf3, 0x87, 0x1f, 0x01 } },
149*d6004f2dSGernotS 	{ 32832, {
150*d6004f2dSGernotS 	    0x20, 0x6a, 0xa6, 0xcc, 0x56, 0xb0, 0x0c, 0x13,
151*d6004f2dSGernotS 	    0xa5, 0xce, 0x97, 0xf3, 0xf8, 0x02, 0x99, 0xda,
152*d6004f2dSGernotS 	    0x72, 0x3c, 0xa1, 0xeb, 0xea, 0xc3, 0x5f, 0xba,
153*d6004f2dSGernotS 	    0x5f, 0xba, 0x1b, 0xf9, 0xd3, 0x96, 0x45, 0xcc } },
154*d6004f2dSGernotS 	{ 32833, {
155*d6004f2dSGernotS 	    0xa7, 0x9b, 0xe6, 0x6d, 0x16, 0xb1, 0x3e, 0x05,
156*d6004f2dSGernotS 	    0xd7, 0x4b, 0xa2, 0xd8, 0x89, 0x64, 0x8f, 0x02,
157*d6004f2dSGernotS 	    0x5e, 0x5e, 0xb0, 0x52, 0xf1, 0x83, 0x0b, 0x29,
158*d6004f2dSGernotS 	    0xe8, 0xa9, 0x27, 0x64, 0x85, 0x78, 0x40, 0x2d } },
159*d6004f2dSGernotS 	{ 65536, {
160*d6004f2dSGernotS 	    0x7d, 0xac, 0xa2, 0x09, 0x5d, 0x04, 0x38, 0x26,
161*d6004f2dSGernotS 	    0x0f, 0xa8, 0x49, 0x18, 0x3d, 0xfc, 0x67, 0xfa,
162*d6004f2dSGernotS 	    0xa4, 0x59, 0xfd, 0xf4, 0x93, 0x6e, 0x1b, 0xc9,
163*d6004f2dSGernotS 	    0x1e, 0xec, 0x6b, 0x28, 0x1b, 0x27, 0xe4, 0xc2 } },
164*d6004f2dSGernotS 	{ 131073, {
165*d6004f2dSGernotS 	    0x59, 0x14, 0x3c, 0x73, 0xfb, 0xc6, 0x69, 0xc1,
166*d6004f2dSGernotS 	    0x8b, 0xde, 0xb3, 0x6c, 0x7c, 0xfa, 0x13, 0x88,
167*d6004f2dSGernotS 	    0x8c, 0x03, 0xa2, 0xd9, 0x35, 0xb1, 0x8d, 0x93,
168*d6004f2dSGernotS 	    0x9c, 0x62, 0x86, 0x92, 0x36, 0x0c, 0x16, 0xff } },
169*d6004f2dSGernotS };
170*d6004f2dSGernotS 
171*d6004f2dSGernotS /* SHA-256("abc"), the canonical FIPS 180-2 anchor. */
172*d6004f2dSGernotS static const uint8_t sha256_abc_dig[SHA256_DIGEST_LENGTH] = {
173*d6004f2dSGernotS 	0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
174*d6004f2dSGernotS 	0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
175*d6004f2dSGernotS 	0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
176*d6004f2dSGernotS 	0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
177*d6004f2dSGernotS };
178*d6004f2dSGernotS 
179*d6004f2dSGernotS /*
180*d6004f2dSGernotS  * Allocate a SHA256_KT_MAXLEN buffer and fill it with the deterministic
181*d6004f2dSGernotS  * b[i] = i & 0xff pattern.  Each test allocates its own buffer rather than
182*d6004f2dSGernotS  * sharing one, so the tests carry no mutable global state and make no
183*d6004f2dSGernotS  * assumption about whether ktest runs them serially.  Freed with
184*d6004f2dSGernotS  * sha256_kt_free().
185*d6004f2dSGernotS  */
186*d6004f2dSGernotS static uint8_t *
187*d6004f2dSGernotS sha256_kt_alloc(void)
188*d6004f2dSGernotS {
189*d6004f2dSGernotS 	uint8_t *buf = kmem_alloc(SHA256_KT_MAXLEN, KM_SLEEP);
190*d6004f2dSGernotS 
191*d6004f2dSGernotS 	for (size_t i = 0; i < SHA256_KT_MAXLEN; i++)
192*d6004f2dSGernotS 		buf[i] = (uint8_t)(i & 0xff);
193*d6004f2dSGernotS 
194*d6004f2dSGernotS 	return (buf);
195*d6004f2dSGernotS }
196*d6004f2dSGernotS 
197*d6004f2dSGernotS static void
198*d6004f2dSGernotS sha256_kt_free(uint8_t *buf)
199*d6004f2dSGernotS {
200*d6004f2dSGernotS 	kmem_free(buf, SHA256_KT_MAXLEN);
201*d6004f2dSGernotS }
202*d6004f2dSGernotS 
203*d6004f2dSGernotS static void
204*d6004f2dSGernotS sha256_kt_oneshot(const uint8_t *in, size_t len, uint8_t *out)
205*d6004f2dSGernotS {
206*d6004f2dSGernotS 	SHA256_CTX ctx;
207*d6004f2dSGernotS 
208*d6004f2dSGernotS 	SHA2Init(SHA256, &ctx);
209*d6004f2dSGernotS 	SHA2Update(&ctx, in, len);
210*d6004f2dSGernotS 	SHA2Final(out, &ctx);
211*d6004f2dSGernotS }
212*d6004f2dSGernotS 
213*d6004f2dSGernotS /*
214*d6004f2dSGernotS  * kat: one-shot hash of each vector, compared against the precomputed digest.
215*d6004f2dSGernotS  */
216*d6004f2dSGernotS void
217*d6004f2dSGernotS sha256_kat_test(ktest_ctx_hdl_t *ctx)
218*d6004f2dSGernotS {
219*d6004f2dSGernotS 	uint8_t out[SHA256_DIGEST_LENGTH];
220*d6004f2dSGernotS 	uint8_t *buf = sha256_kt_alloc();
221*d6004f2dSGernotS 	bool fail = false;
222*d6004f2dSGernotS 	size_t faillen = 0;
223*d6004f2dSGernotS 	uint_t nfail = 0;
224*d6004f2dSGernotS 
225*d6004f2dSGernotS 	/* canonical "abc" anchor */
226*d6004f2dSGernotS 	sha256_kt_oneshot((const uint8_t *)"abc", 3, out);
227*d6004f2dSGernotS 	if (bcmp(out, sha256_abc_dig, SHA256_DIGEST_LENGTH) != 0) {
228*d6004f2dSGernotS 		KT_FAIL(ctx, "SHA-256(\"abc\") mismatch");
229*d6004f2dSGernotS 		sha256_kt_free(buf);
230*d6004f2dSGernotS 		return;
231*d6004f2dSGernotS 	}
232*d6004f2dSGernotS 
233*d6004f2dSGernotS 	for (size_t v = 0; v < ARRAY_SIZE(sha256_kat_vec); v++) {
234*d6004f2dSGernotS 		const size_t len = sha256_kat_vec[v].len;
235*d6004f2dSGernotS 
236*d6004f2dSGernotS 		sha256_kt_oneshot(buf, len, out);
237*d6004f2dSGernotS 		if (bcmp(out, sha256_kat_vec[v].dig,
238*d6004f2dSGernotS 		    SHA256_DIGEST_LENGTH) != 0) {
239*d6004f2dSGernotS 			if (!fail)
240*d6004f2dSGernotS 				faillen = len;
241*d6004f2dSGernotS 			fail = true;
242*d6004f2dSGernotS 			nfail++;
243*d6004f2dSGernotS 		}
244*d6004f2dSGernotS 	}
245*d6004f2dSGernotS 
246*d6004f2dSGernotS 	sha256_kt_free(buf);
247*d6004f2dSGernotS 
248*d6004f2dSGernotS 	if (fail) {
249*d6004f2dSGernotS 		KT_FAIL(ctx, "%u vector(s) mismatched, first at len %zu",
250*d6004f2dSGernotS 		    nfail, faillen);
251*d6004f2dSGernotS 	} else {
252*d6004f2dSGernotS 		KT_PASS(ctx);
253*d6004f2dSGernotS 	}
254*d6004f2dSGernotS }
255*d6004f2dSGernotS 
256*d6004f2dSGernotS /*
257*d6004f2dSGernotS  * incremental: feed each vector through SHA2Update() in a range of step
258*d6004f2dSGernotS  * sizes to exercise the partial-block buffering and the Final() tail path.
259*d6004f2dSGernotS  */
260*d6004f2dSGernotS void
261*d6004f2dSGernotS sha256_incremental_test(ktest_ctx_hdl_t *ctx)
262*d6004f2dSGernotS {
263*d6004f2dSGernotS 	static const size_t steps[] = { 1, 7, 31, 64, 1000 };
264*d6004f2dSGernotS 	uint8_t out[SHA256_DIGEST_LENGTH];
265*d6004f2dSGernotS 	uint8_t *buf = sha256_kt_alloc();
266*d6004f2dSGernotS 	bool fail = false;
267*d6004f2dSGernotS 	size_t faillen = 0, failstep = 0;
268*d6004f2dSGernotS 	uint_t nfail = 0;
269*d6004f2dSGernotS 
270*d6004f2dSGernotS 	for (size_t v = 0; v < ARRAY_SIZE(sha256_kat_vec); v++) {
271*d6004f2dSGernotS 		const size_t len = sha256_kat_vec[v].len;
272*d6004f2dSGernotS 
273*d6004f2dSGernotS 		for (size_t s = 0; s < ARRAY_SIZE(steps); s++) {
274*d6004f2dSGernotS 			const size_t step = steps[s];
275*d6004f2dSGernotS 			SHA256_CTX c;
276*d6004f2dSGernotS 
277*d6004f2dSGernotS 			SHA2Init(SHA256, &c);
278*d6004f2dSGernotS 			for (size_t off = 0; off < len; off += step) {
279*d6004f2dSGernotS 				SHA2Update(&c, buf + off,
280*d6004f2dSGernotS 				    MIN(step, len - off));
281*d6004f2dSGernotS 			}
282*d6004f2dSGernotS 			SHA2Final(out, &c);
283*d6004f2dSGernotS 
284*d6004f2dSGernotS 			if (bcmp(out, sha256_kat_vec[v].dig,
285*d6004f2dSGernotS 			    SHA256_DIGEST_LENGTH) != 0) {
286*d6004f2dSGernotS 				if (!fail) {
287*d6004f2dSGernotS 					faillen = len;
288*d6004f2dSGernotS 					failstep = step;
289*d6004f2dSGernotS 				}
290*d6004f2dSGernotS 				fail = true;
291*d6004f2dSGernotS 				nfail++;
292*d6004f2dSGernotS 			}
293*d6004f2dSGernotS 		}
294*d6004f2dSGernotS 	}
295*d6004f2dSGernotS 
296*d6004f2dSGernotS 	sha256_kt_free(buf);
297*d6004f2dSGernotS 
298*d6004f2dSGernotS 	if (fail) {
299*d6004f2dSGernotS 		KT_FAIL(ctx, "%u case(s) mismatched, first at len %zu "
300*d6004f2dSGernotS 		    "step %zu", nfail, faillen, failstep);
301*d6004f2dSGernotS 	} else {
302*d6004f2dSGernotS 		KT_PASS(ctx);
303*d6004f2dSGernotS 	}
304*d6004f2dSGernotS }
305*d6004f2dSGernotS 
306*d6004f2dSGernotS /*
307*d6004f2dSGernotS  * fallback_equiv: hash each vector with SHA-NI forced off and on, and assert
308*d6004f2dSGernotS  * both equal the known answer.  This exercises the amd64 dispatch and its
309*d6004f2dSGernotS  * sha256_ni_disable tunable in sha2.c, so it is skipped elsewhere, and it is
310*d6004f2dSGernotS  * skipped unless the CPU has every feature the dispatch requires before it
311*d6004f2dSGernotS  * will use the SHA-NI path -- otherwise both the "on" and "off" runs take
312*d6004f2dSGernotS  * the generic path (which the kat test already covers) and the differential
313*d6004f2dSGernotS  * proves nothing.  The set checked here mirrors sha256_ni_usable() in sha2.c
314*d6004f2dSGernotS  * exactly: the SHA extensions plus the SSE2, SSSE3 and SSE4.1 instructions
315*d6004f2dSGernotS  * that amd64/sha256-ni.S uses around them.
316*d6004f2dSGernotS  */
317*d6004f2dSGernotS #ifdef	__amd64
318*d6004f2dSGernotS extern int sha256_ni_disable;
319*d6004f2dSGernotS 
320*d6004f2dSGernotS void
321*d6004f2dSGernotS sha256_fallback_equiv_test(ktest_ctx_hdl_t *ctx)
322*d6004f2dSGernotS {
323*d6004f2dSGernotS 	uint8_t gen_dig[SHA256_DIGEST_LENGTH];
324*d6004f2dSGernotS 	uint8_t ni_dig[SHA256_DIGEST_LENGTH];
325*d6004f2dSGernotS 	uint8_t *buf;
326*d6004f2dSGernotS 	int saved;
327*d6004f2dSGernotS 	bool fail = false;
328*d6004f2dSGernotS 	size_t faillen = 0;
329*d6004f2dSGernotS 	uint_t nfail = 0;
330*d6004f2dSGernotS 
331*d6004f2dSGernotS 	if (!is_x86_feature(x86_featureset, X86FSET_SSE2) ||
332*d6004f2dSGernotS 	    !is_x86_feature(x86_featureset, X86FSET_SSSE3) ||
333*d6004f2dSGernotS 	    !is_x86_feature(x86_featureset, X86FSET_SSE4_1) ||
334*d6004f2dSGernotS 	    !is_x86_feature(x86_featureset, X86FSET_SHA)) {
335*d6004f2dSGernotS 		KT_SKIP(ctx, "CPU lacks a feature the SHA-NI path requires");
336*d6004f2dSGernotS 		return;
337*d6004f2dSGernotS 	}
338*d6004f2dSGernotS 
339*d6004f2dSGernotS 	buf = sha256_kt_alloc();
340*d6004f2dSGernotS 	saved = sha256_ni_disable;
341*d6004f2dSGernotS 
342*d6004f2dSGernotS 	for (size_t v = 0; v < ARRAY_SIZE(sha256_kat_vec); v++) {
343*d6004f2dSGernotS 		const size_t len = sha256_kat_vec[v].len;
344*d6004f2dSGernotS 
345*d6004f2dSGernotS 		sha256_ni_disable = 1;			/* generic */
346*d6004f2dSGernotS 		sha256_kt_oneshot(buf, len, gen_dig);
347*d6004f2dSGernotS 		sha256_ni_disable = 0;			/* SHA-NI */
348*d6004f2dSGernotS 		sha256_kt_oneshot(buf, len, ni_dig);
349*d6004f2dSGernotS 
350*d6004f2dSGernotS 		if (bcmp(gen_dig, ni_dig, SHA256_DIGEST_LENGTH) != 0 ||
351*d6004f2dSGernotS 		    bcmp(ni_dig, sha256_kat_vec[v].dig,
352*d6004f2dSGernotS 		    SHA256_DIGEST_LENGTH) != 0) {
353*d6004f2dSGernotS 			if (!fail)
354*d6004f2dSGernotS 				faillen = len;
355*d6004f2dSGernotS 			fail = true;
356*d6004f2dSGernotS 			nfail++;
357*d6004f2dSGernotS 		}
358*d6004f2dSGernotS 	}
359*d6004f2dSGernotS 
360*d6004f2dSGernotS 	sha256_ni_disable = saved;
361*d6004f2dSGernotS 	sha256_kt_free(buf);
362*d6004f2dSGernotS 
363*d6004f2dSGernotS 	if (fail) {
364*d6004f2dSGernotS 		KT_FAIL(ctx, "%u vector(s) mismatched, first at len %zu",
365*d6004f2dSGernotS 		    nfail, faillen);
366*d6004f2dSGernotS 	} else {
367*d6004f2dSGernotS 		KT_PASS(ctx);
368*d6004f2dSGernotS 	}
369*d6004f2dSGernotS }
370*d6004f2dSGernotS #else	/* !__amd64 */
371*d6004f2dSGernotS void
372*d6004f2dSGernotS sha256_fallback_equiv_test(ktest_ctx_hdl_t *ctx)
373*d6004f2dSGernotS {
374*d6004f2dSGernotS 	KT_SKIP(ctx, "SHA-NI dispatch is amd64-only");
375*d6004f2dSGernotS }
376*d6004f2dSGernotS #endif	/* __amd64 */
377*d6004f2dSGernotS 
378*d6004f2dSGernotS static struct modlmisc sha256_ktest_modlmisc = {
379*d6004f2dSGernotS 	.misc_modops = &mod_miscops,
380*d6004f2dSGernotS 	.misc_linkinfo = "SHA-256 ktest module"
381*d6004f2dSGernotS };
382*d6004f2dSGernotS 
383*d6004f2dSGernotS static struct modlinkage sha256_ktest_modlinkage = {
384*d6004f2dSGernotS 	.ml_rev = MODREV_1,
385*d6004f2dSGernotS 	.ml_linkage = { &sha256_ktest_modlmisc, NULL }
386*d6004f2dSGernotS };
387*d6004f2dSGernotS 
388*d6004f2dSGernotS int
389*d6004f2dSGernotS _init(void)
390*d6004f2dSGernotS {
391*d6004f2dSGernotS 	int ret;
392*d6004f2dSGernotS 	ktest_module_hdl_t *km = NULL;
393*d6004f2dSGernotS 	ktest_suite_hdl_t *ks = NULL;
394*d6004f2dSGernotS 
395*d6004f2dSGernotS 	VERIFY0(ktest_create_module("sha2", &km));
396*d6004f2dSGernotS 	VERIFY0(ktest_add_suite(km, "sha256", &ks));
397*d6004f2dSGernotS 	VERIFY0(ktest_add_test(ks, "kat", sha256_kat_test,
398*d6004f2dSGernotS 	    KTEST_FLAG_NONE));
399*d6004f2dSGernotS 	VERIFY0(ktest_add_test(ks, "incremental", sha256_incremental_test,
400*d6004f2dSGernotS 	    KTEST_FLAG_NONE));
401*d6004f2dSGernotS 	VERIFY0(ktest_add_test(ks, "fallback_equiv",
402*d6004f2dSGernotS 	    sha256_fallback_equiv_test, KTEST_FLAG_NONE));
403*d6004f2dSGernotS 
404*d6004f2dSGernotS 	if ((ret = ktest_register_module(km)) != 0) {
405*d6004f2dSGernotS 		ktest_free_module(km);
406*d6004f2dSGernotS 		return (ret);
407*d6004f2dSGernotS 	}
408*d6004f2dSGernotS 
409*d6004f2dSGernotS 	if ((ret = mod_install(&sha256_ktest_modlinkage)) != 0) {
410*d6004f2dSGernotS 		ktest_unregister_module("sha2");
411*d6004f2dSGernotS 		return (ret);
412*d6004f2dSGernotS 	}
413*d6004f2dSGernotS 
414*d6004f2dSGernotS 	return (0);
415*d6004f2dSGernotS }
416*d6004f2dSGernotS 
417*d6004f2dSGernotS int
418*d6004f2dSGernotS _fini(void)
419*d6004f2dSGernotS {
420*d6004f2dSGernotS 	int ret;
421*d6004f2dSGernotS 
422*d6004f2dSGernotS 	if ((ret = mod_remove(&sha256_ktest_modlinkage)) != 0)
423*d6004f2dSGernotS 		return (ret);
424*d6004f2dSGernotS 
425*d6004f2dSGernotS 	ktest_unregister_module("sha2");
426*d6004f2dSGernotS 	return (0);
427*d6004f2dSGernotS }
428*d6004f2dSGernotS 
429*d6004f2dSGernotS int
430*d6004f2dSGernotS _info(struct modinfo *modinfop)
431*d6004f2dSGernotS {
432*d6004f2dSGernotS 	return (mod_info(&sha256_ktest_modlinkage, modinfop));
433*d6004f2dSGernotS }
434