gfmult.c 6.5 KB

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