Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/opencrypto/gfmult.c
39475 views
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
*/
29
30
#include "gfmult.h"
31
32
#define REV_POLY_REDUCT 0xe1 /* 0x87 bit reversed */
33
34
/* reverse the bits of a nibble */
35
static const uint8_t nib_rev[] = {
36
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
37
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf,
38
};
39
40
/* calculate v * 2 */
41
static inline struct gf128
42
gf128_mulalpha(struct gf128 v)
43
{
44
uint64_t mask;
45
46
mask = !!(v.v[1] & 1);
47
mask = ~(mask - 1);
48
v.v[1] = (v.v[1] >> 1) | ((v.v[0] & 1) << 63);
49
v.v[0] = (v.v[0] >> 1) ^ ((mask & REV_POLY_REDUCT) << 56);
50
51
return v;
52
}
53
54
/*
55
* Generate a table for 0-16 * h. Store the results in the table w/ indexes
56
* bit reversed, and the words striped across the values.
57
*/
58
void
59
gf128_genmultable(struct gf128 h, struct gf128table *t)
60
{
61
struct gf128 tbl[16];
62
int i;
63
64
tbl[0] = MAKE_GF128(0, 0);
65
tbl[1] = h;
66
67
for (i = 2; i < 16; i += 2) {
68
tbl[i] = gf128_mulalpha(tbl[i / 2]);
69
tbl[i + 1] = gf128_add(tbl[i], h);
70
}
71
72
for (i = 0; i < 16; i++) {
73
t->a[nib_rev[i]] = tbl[i].v[0] >> 32;
74
t->b[nib_rev[i]] = tbl[i].v[0];
75
t->c[nib_rev[i]] = tbl[i].v[1] >> 32;
76
t->d[nib_rev[i]] = tbl[i].v[1];
77
}
78
}
79
80
/*
81
* Generate tables containing h, h^2, h^3 and h^4, starting at 0.
82
*/
83
void
84
gf128_genmultable4(struct gf128 h, struct gf128table4 *t)
85
{
86
struct gf128 h2, h3, h4;
87
88
gf128_genmultable(h, &t->tbls[0]);
89
90
h2 = gf128_mul(h, &t->tbls[0]);
91
92
gf128_genmultable(h2, &t->tbls[1]);
93
94
h3 = gf128_mul(h, &t->tbls[1]);
95
gf128_genmultable(h3, &t->tbls[2]);
96
97
h4 = gf128_mul(h2, &t->tbls[1]);
98
gf128_genmultable(h4, &t->tbls[3]);
99
}
100
101
/*
102
* Read a row from the table.
103
*/
104
static inline struct gf128
105
readrow(struct gf128table *tbl, unsigned bits)
106
{
107
struct gf128 r;
108
109
bits = bits % 16;
110
111
r.v[0] = ((uint64_t)tbl->a[bits] << 32) | tbl->b[bits];
112
r.v[1] = ((uint64_t)tbl->c[bits] << 32) | tbl->d[bits];
113
114
return r;
115
}
116
117
/*
118
* These are the reduction values. Since we are dealing with bit reversed
119
* version, the values need to be bit reversed, AND the indexes are also
120
* bit reversed to make lookups quicker.
121
*/
122
static uint16_t reduction[] = {
123
0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,
124
0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0,
125
};
126
127
/*
128
* Calculate:
129
* (x*2^4 + word[3,0]*h) *
130
* 2^4 + word[7,4]*h) *
131
* ...
132
* 2^4 + word[63,60]*h
133
*/
134
static struct gf128
135
gfmultword(uint64_t word, struct gf128 x, struct gf128table *tbl)
136
{
137
struct gf128 row;
138
unsigned bits;
139
unsigned redbits;
140
int i;
141
142
for (i = 0; i < 64; i += 4) {
143
bits = word % 16;
144
145
/* fetch row */
146
row = readrow(tbl, bits);
147
148
/* x * 2^4 */
149
redbits = x.v[1] % 16;
150
x.v[1] = (x.v[1] >> 4) | (x.v[0] % 16) << 60;
151
x.v[0] >>= 4;
152
x.v[0] ^= (uint64_t)reduction[redbits] << (64 - 16);
153
154
word >>= 4;
155
156
x = gf128_add(x, row);
157
}
158
159
return x;
160
}
161
162
/*
163
* Calculate
164
* (x*2^4 + worda[3,0]*h^4+wordb[3,0]*h^3+...+wordd[3,0]*h) *
165
* ...
166
* 2^4 + worda[63,60]*h^4+ ... + wordd[63,60]*h
167
*
168
* Passing/returning struct is .5% faster than passing in via pointer on
169
* amd64.
170
*/
171
static struct gf128
172
gfmultword4(uint64_t worda, uint64_t wordb, uint64_t wordc, uint64_t wordd,
173
struct gf128 x, struct gf128table4 *tbl)
174
{
175
struct gf128 rowa, rowb, rowc, rowd;
176
unsigned bitsa, bitsb, bitsc, bitsd;
177
unsigned redbits;
178
int i;
179
180
/*
181
* XXX - nibble reverse words to save a shift? probably not as
182
* nibble reverse would take 20 ops (5 * 4) verse 16
183
*/
184
185
for (i = 0; i < 64; i += 4) {
186
bitsa = worda % 16;
187
bitsb = wordb % 16;
188
bitsc = wordc % 16;
189
bitsd = wordd % 16;
190
191
/* fetch row */
192
rowa = readrow(&tbl->tbls[3], bitsa);
193
rowb = readrow(&tbl->tbls[2], bitsb);
194
rowc = readrow(&tbl->tbls[1], bitsc);
195
rowd = readrow(&tbl->tbls[0], bitsd);
196
197
/* x * 2^4 */
198
redbits = x.v[1] % 16;
199
x.v[1] = (x.v[1] >> 4) | (x.v[0] % 16) << 60;
200
x.v[0] >>= 4;
201
x.v[0] ^= (uint64_t)reduction[redbits] << (64 - 16);
202
203
worda >>= 4;
204
wordb >>= 4;
205
wordc >>= 4;
206
wordd >>= 4;
207
208
x = gf128_add(x, gf128_add(rowa, gf128_add(rowb,
209
gf128_add(rowc, rowd))));
210
}
211
212
return x;
213
}
214
215
struct gf128
216
gf128_mul(struct gf128 v, struct gf128table *tbl)
217
{
218
struct gf128 ret;
219
220
ret = MAKE_GF128(0, 0);
221
222
ret = gfmultword(v.v[1], ret, tbl);
223
ret = gfmultword(v.v[0], ret, tbl);
224
225
return ret;
226
}
227
228
/*
229
* Calculate a*h^4 + b*h^3 + c*h^2 + d*h, or:
230
* (((a*h+b)*h+c)*h+d)*h
231
*/
232
struct gf128
233
gf128_mul4(struct gf128 a, struct gf128 b, struct gf128 c, struct gf128 d,
234
struct gf128table4 *tbl)
235
{
236
struct gf128 tmp;
237
238
tmp = MAKE_GF128(0, 0);
239
240
tmp = gfmultword4(a.v[1], b.v[1], c.v[1], d.v[1], tmp, tbl);
241
tmp = gfmultword4(a.v[0], b.v[0], c.v[0], d.v[0], tmp, tbl);
242
243
return tmp;
244
}
245
246
/*
247
* a = data[0..15] + r
248
* b = data[16..31]
249
* c = data[32..47]
250
* d = data[48..63]
251
*
252
* Calculate a*h^4 + b*h^3 + c*h^2 + d*h, or:
253
* (((a*h+b)*h+c)*h+d)*h
254
*/
255
struct gf128
256
gf128_mul4b(struct gf128 r, const uint8_t *v, struct gf128table4 *tbl)
257
{
258
struct gf128 a, b, c, d;
259
struct gf128 tmp;
260
261
tmp = MAKE_GF128(0, 0);
262
263
a = gf128_add(r, gf128_read(&v[0*16]));
264
b = gf128_read(&v[1*16]);
265
c = gf128_read(&v[2*16]);
266
d = gf128_read(&v[3*16]);
267
268
tmp = gfmultword4(a.v[1], b.v[1], c.v[1], d.v[1], tmp, tbl);
269
tmp = gfmultword4(a.v[0], b.v[0], c.v[0], d.v[0], tmp, tbl);
270
271
return tmp;
272
}
273
274