]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/opencrypto/gfmult.c
ktls: Inline ktls_cleanup() into ktls_destroy().
[FreeBSD/FreeBSD.git] / sys / opencrypto / gfmult.c
1 /*-
2  * Copyright (c) 2014 The FreeBSD Foundation
3  *
4  * This software was developed by John-Mark Gurney under
5  * the sponsorship of the FreeBSD Foundation and
6  * Rubicon Communications, LLC (Netgate).
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  *      $FreeBSD$
29  *
30  */
31
32 #include "gfmult.h"
33
34 #define REV_POLY_REDUCT 0xe1    /* 0x87 bit reversed */
35
36 /* reverse the bits of a nibble */
37 static const uint8_t nib_rev[] = {
38         0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
39         0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf,
40 };
41
42 /* calculate v * 2 */
43 static inline struct gf128
44 gf128_mulalpha(struct gf128 v)
45 {
46         uint64_t mask;
47
48         mask = !!(v.v[1] & 1);
49         mask = ~(mask - 1);
50         v.v[1] = (v.v[1] >> 1) | ((v.v[0] & 1) << 63);
51         v.v[0] = (v.v[0] >> 1) ^ ((mask & REV_POLY_REDUCT) << 56);
52
53         return v;
54 }
55
56 /*
57  * Generate a table for 0-16 * h.  Store the results in the table w/ indexes
58  * bit reversed, and the words striped across the values.
59  */
60 void
61 gf128_genmultable(struct gf128 h, struct gf128table *t)
62 {
63         struct gf128 tbl[16];
64         int i;
65
66         tbl[0] = MAKE_GF128(0, 0);
67         tbl[1] = h;
68
69         for (i = 2; i < 16; i += 2) {
70                 tbl[i] = gf128_mulalpha(tbl[i / 2]);
71                 tbl[i + 1] = gf128_add(tbl[i], h);
72         }
73
74         for (i = 0; i < 16; i++) {
75                 t->a[nib_rev[i]] = tbl[i].v[0] >> 32;
76                 t->b[nib_rev[i]] = tbl[i].v[0];
77                 t->c[nib_rev[i]] = tbl[i].v[1] >> 32;
78                 t->d[nib_rev[i]] = tbl[i].v[1];
79         }
80 }
81
82 /*
83  * Generate tables containing h, h^2, h^3 and h^4, starting at 0.
84  */
85 void
86 gf128_genmultable4(struct gf128 h, struct gf128table4 *t)
87 {
88         struct gf128 h2, h3, h4;
89
90         gf128_genmultable(h, &t->tbls[0]);
91
92         h2 = gf128_mul(h, &t->tbls[0]);
93
94         gf128_genmultable(h2, &t->tbls[1]);
95
96         h3 = gf128_mul(h, &t->tbls[1]);
97         gf128_genmultable(h3, &t->tbls[2]);
98
99         h4 = gf128_mul(h2, &t->tbls[1]);
100         gf128_genmultable(h4, &t->tbls[3]);
101 }
102
103 /*
104  * Read a row from the table.
105  */
106 static inline struct gf128
107 readrow(struct gf128table *tbl, unsigned bits)
108 {
109         struct gf128 r;
110
111         bits = bits % 16;
112
113         r.v[0] = ((uint64_t)tbl->a[bits] << 32) | tbl->b[bits];
114         r.v[1] = ((uint64_t)tbl->c[bits] << 32) | tbl->d[bits];
115
116         return r;
117 }
118
119 /*
120  * These are the reduction values.  Since we are dealing with bit reversed
121  * version, the values need to be bit reversed, AND the indexes are also
122  * bit reversed to make lookups quicker.
123  */
124 static uint16_t reduction[] = {
125         0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,
126         0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0,
127 };
128
129 /*
130  * Calculate:
131  * (x*2^4 + word[3,0]*h) *
132  * 2^4 + word[7,4]*h) *
133  * ...
134  * 2^4 + word[63,60]*h
135  */
136 static struct gf128
137 gfmultword(uint64_t word, struct gf128 x, struct gf128table *tbl)
138 {
139         struct gf128 row;
140         unsigned bits;
141         unsigned redbits;
142         int i;
143
144         for (i = 0; i < 64; i += 4) {
145                 bits = word % 16;
146
147                 /* fetch row */
148                 row = readrow(tbl, bits);
149
150                 /* x * 2^4 */
151                 redbits = x.v[1] % 16;
152                 x.v[1] = (x.v[1] >> 4) | (x.v[0] % 16) << 60;
153                 x.v[0] >>= 4;
154                 x.v[0] ^= (uint64_t)reduction[redbits] << (64 - 16);
155
156                 word >>= 4;
157
158                 x = gf128_add(x, row);
159         }
160
161         return x;
162 }
163
164 /*
165  * Calculate
166  * (x*2^4 + worda[3,0]*h^4+wordb[3,0]*h^3+...+wordd[3,0]*h) *
167  * ...
168  * 2^4 + worda[63,60]*h^4+ ... + wordd[63,60]*h
169  *
170  * Passing/returning struct is .5% faster than passing in via pointer on
171  * amd64.
172  */
173 static struct gf128
174 gfmultword4(uint64_t worda, uint64_t wordb, uint64_t wordc, uint64_t wordd,
175     struct gf128 x, struct gf128table4 *tbl)
176 {
177         struct gf128 rowa, rowb, rowc, rowd;
178         unsigned bitsa, bitsb, bitsc, bitsd;
179         unsigned redbits;
180         int i;
181
182         /*
183          * XXX - nibble reverse words to save a shift? probably not as
184          * nibble reverse would take 20 ops (5 * 4) verse 16
185          */
186
187         for (i = 0; i < 64; i += 4) {
188                 bitsa = worda % 16;
189                 bitsb = wordb % 16;
190                 bitsc = wordc % 16;
191                 bitsd = wordd % 16;
192
193                 /* fetch row */
194                 rowa = readrow(&tbl->tbls[3], bitsa);
195                 rowb = readrow(&tbl->tbls[2], bitsb);
196                 rowc = readrow(&tbl->tbls[1], bitsc);
197                 rowd = readrow(&tbl->tbls[0], bitsd);
198
199                 /* x * 2^4 */
200                 redbits = x.v[1] % 16;
201                 x.v[1] = (x.v[1] >> 4) | (x.v[0] % 16) << 60;
202                 x.v[0] >>= 4;
203                 x.v[0] ^= (uint64_t)reduction[redbits] << (64 - 16);
204
205                 worda >>= 4;
206                 wordb >>= 4;
207                 wordc >>= 4;
208                 wordd >>= 4;
209
210                 x = gf128_add(x, gf128_add(rowa, gf128_add(rowb,
211                     gf128_add(rowc, rowd))));
212         }
213
214         return x;
215 }
216
217 struct gf128
218 gf128_mul(struct gf128 v, struct gf128table *tbl)
219 {
220         struct gf128 ret;
221
222         ret = MAKE_GF128(0, 0);
223
224         ret = gfmultword(v.v[1], ret, tbl);
225         ret = gfmultword(v.v[0], ret, tbl);
226
227         return ret;
228 }
229
230 /*
231  * Calculate a*h^4 + b*h^3 + c*h^2 + d*h, or:
232  * (((a*h+b)*h+c)*h+d)*h
233  */
234 struct gf128
235 gf128_mul4(struct gf128 a, struct gf128 b, struct gf128 c, struct gf128 d,
236     struct gf128table4 *tbl)
237 {
238         struct gf128 tmp;
239
240         tmp = MAKE_GF128(0, 0);
241
242         tmp = gfmultword4(a.v[1], b.v[1], c.v[1], d.v[1], tmp, tbl);
243         tmp = gfmultword4(a.v[0], b.v[0], c.v[0], d.v[0], tmp, tbl);
244
245         return tmp;
246 }
247
248 /*
249  * a = data[0..15] + r
250  * b = data[16..31]
251  * c = data[32..47]
252  * d = data[48..63]
253  *
254  * Calculate a*h^4 + b*h^3 + c*h^2 + d*h, or:
255  * (((a*h+b)*h+c)*h+d)*h
256  */
257 struct gf128
258 gf128_mul4b(struct gf128 r, const uint8_t *v, struct gf128table4 *tbl)
259 {
260         struct gf128 a, b, c, d;
261         struct gf128 tmp;
262
263         tmp = MAKE_GF128(0, 0);
264
265         a = gf128_add(r, gf128_read(&v[0*16]));
266         b = gf128_read(&v[1*16]);
267         c = gf128_read(&v[2*16]);
268         d = gf128_read(&v[3*16]);
269
270         tmp = gfmultword4(a.v[1], b.v[1], c.v[1], d.v[1], tmp, tbl);
271         tmp = gfmultword4(a.v[0], b.v[0], c.v[0], d.v[0], tmp, tbl);
272
273         return tmp;
274 }