Path: blob/main/contrib/bearssl/src/hash/ghash_ctmul32.c
39536 views
/*1* Copyright (c) 2016 Thomas Pornin <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining4* a copy of this software and associated documentation files (the5* "Software"), to deal in the Software without restriction, including6* without limitation the rights to use, copy, modify, merge, publish,7* distribute, sublicense, and/or sell copies of the Software, and to8* permit persons to whom the Software is furnished to do so, subject to9* the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*/2324#include "inner.h"2526/*27* This implementation uses 32-bit multiplications, and only the low28* 32 bits for each multiplication result. This is meant primarily for29* the ARM Cortex M0 and M0+, whose multiplication opcode does not yield30* the upper 32 bits; but it might also be useful on architectures where31* access to the upper 32 bits requires use of specific registers that32* create contention (e.g. on i386, "mul" necessarily outputs the result33* in edx:eax, while "imul" can use any registers but is limited to the34* low 32 bits).35*36* The implementation trick that is used here is bit-reversing (bit 037* is swapped with bit 31, bit 1 with bit 30, and so on). In GF(2)[X],38* for all values x and y, we have:39* rev32(x) * rev32(y) = rev64(x * y)40* In other words, if we bit-reverse (over 32 bits) the operands, then we41* bit-reverse (over 64 bits) the result.42*/4344/*45* Multiplication in GF(2)[X], truncated to its low 32 bits.46*/47static inline uint32_t48bmul32(uint32_t x, uint32_t y)49{50uint32_t x0, x1, x2, x3;51uint32_t y0, y1, y2, y3;52uint32_t z0, z1, z2, z3;5354x0 = x & (uint32_t)0x11111111;55x1 = x & (uint32_t)0x22222222;56x2 = x & (uint32_t)0x44444444;57x3 = x & (uint32_t)0x88888888;58y0 = y & (uint32_t)0x11111111;59y1 = y & (uint32_t)0x22222222;60y2 = y & (uint32_t)0x44444444;61y3 = y & (uint32_t)0x88888888;62z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);63z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);64z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);65z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);66z0 &= (uint32_t)0x11111111;67z1 &= (uint32_t)0x22222222;68z2 &= (uint32_t)0x44444444;69z3 &= (uint32_t)0x88888888;70return z0 | z1 | z2 | z3;71}7273/*74* Bit-reverse a 32-bit word.75*/76static uint32_t77rev32(uint32_t x)78{79#define RMS(m, s) do { \80x = ((x & (uint32_t)(m)) << (s)) \81| ((x >> (s)) & (uint32_t)(m)); \82} while (0)8384RMS(0x55555555, 1);85RMS(0x33333333, 2);86RMS(0x0F0F0F0F, 4);87RMS(0x00FF00FF, 8);88return (x << 16) | (x >> 16);8990#undef RMS91}9293/* see bearssl_hash.h */94void95br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len)96{97/*98* This implementation is similar to br_ghash_ctmul() except99* that we have to do the multiplication twice, with the100* "normal" and "bit reversed" operands. Hence we end up with101* eighteen 32-bit multiplications instead of nine.102*/103104const unsigned char *buf, *hb;105unsigned char *yb;106uint32_t yw[4];107uint32_t hw[4], hwr[4];108109buf = data;110yb = y;111hb = h;112yw[3] = br_dec32be(yb);113yw[2] = br_dec32be(yb + 4);114yw[1] = br_dec32be(yb + 8);115yw[0] = br_dec32be(yb + 12);116hw[3] = br_dec32be(hb);117hw[2] = br_dec32be(hb + 4);118hw[1] = br_dec32be(hb + 8);119hw[0] = br_dec32be(hb + 12);120hwr[3] = rev32(hw[3]);121hwr[2] = rev32(hw[2]);122hwr[1] = rev32(hw[1]);123hwr[0] = rev32(hw[0]);124while (len > 0) {125const unsigned char *src;126unsigned char tmp[16];127int i;128uint32_t a[18], b[18], c[18];129uint32_t d0, d1, d2, d3, d4, d5, d6, d7;130uint32_t zw[8];131132if (len >= 16) {133src = buf;134buf += 16;135len -= 16;136} else {137memcpy(tmp, buf, len);138memset(tmp + len, 0, (sizeof tmp) - len);139src = tmp;140len = 0;141}142yw[3] ^= br_dec32be(src);143yw[2] ^= br_dec32be(src + 4);144yw[1] ^= br_dec32be(src + 8);145yw[0] ^= br_dec32be(src + 12);146147/*148* We are using Karatsuba: the 128x128 multiplication is149* reduced to three 64x64 multiplications, hence nine150* 32x32 multiplications. With the bit-reversal trick,151* we have to perform 18 32x32 multiplications.152*/153154/*155* y[0,1]*h[0,1] -> 0,1,4156* y[2,3]*h[2,3] -> 2,3,5157* (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6,7,8158*/159160a[0] = yw[0];161a[1] = yw[1];162a[2] = yw[2];163a[3] = yw[3];164a[4] = a[0] ^ a[1];165a[5] = a[2] ^ a[3];166a[6] = a[0] ^ a[2];167a[7] = a[1] ^ a[3];168a[8] = a[6] ^ a[7];169170a[ 9] = rev32(yw[0]);171a[10] = rev32(yw[1]);172a[11] = rev32(yw[2]);173a[12] = rev32(yw[3]);174a[13] = a[ 9] ^ a[10];175a[14] = a[11] ^ a[12];176a[15] = a[ 9] ^ a[11];177a[16] = a[10] ^ a[12];178a[17] = a[15] ^ a[16];179180b[0] = hw[0];181b[1] = hw[1];182b[2] = hw[2];183b[3] = hw[3];184b[4] = b[0] ^ b[1];185b[5] = b[2] ^ b[3];186b[6] = b[0] ^ b[2];187b[7] = b[1] ^ b[3];188b[8] = b[6] ^ b[7];189190b[ 9] = hwr[0];191b[10] = hwr[1];192b[11] = hwr[2];193b[12] = hwr[3];194b[13] = b[ 9] ^ b[10];195b[14] = b[11] ^ b[12];196b[15] = b[ 9] ^ b[11];197b[16] = b[10] ^ b[12];198b[17] = b[15] ^ b[16];199200for (i = 0; i < 18; i ++) {201c[i] = bmul32(a[i], b[i]);202}203204c[4] ^= c[0] ^ c[1];205c[5] ^= c[2] ^ c[3];206c[8] ^= c[6] ^ c[7];207208c[13] ^= c[ 9] ^ c[10];209c[14] ^= c[11] ^ c[12];210c[17] ^= c[15] ^ c[16];211212/*213* y[0,1]*h[0,1] -> 0,9^4,1^13,10214* y[2,3]*h[2,3] -> 2,11^5,3^14,12215* (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6,15^8,7^17,16216*/217d0 = c[0];218d1 = c[4] ^ (rev32(c[9]) >> 1);219d2 = c[1] ^ c[0] ^ c[2] ^ c[6] ^ (rev32(c[13]) >> 1);220d3 = c[4] ^ c[5] ^ c[8]221^ (rev32(c[10] ^ c[9] ^ c[11] ^ c[15]) >> 1);222d4 = c[2] ^ c[1] ^ c[3] ^ c[7]223^ (rev32(c[13] ^ c[14] ^ c[17]) >> 1);224d5 = c[5] ^ (rev32(c[11] ^ c[10] ^ c[12] ^ c[16]) >> 1);225d6 = c[3] ^ (rev32(c[14]) >> 1);226d7 = rev32(c[12]) >> 1;227228zw[0] = d0 << 1;229zw[1] = (d1 << 1) | (d0 >> 31);230zw[2] = (d2 << 1) | (d1 >> 31);231zw[3] = (d3 << 1) | (d2 >> 31);232zw[4] = (d4 << 1) | (d3 >> 31);233zw[5] = (d5 << 1) | (d4 >> 31);234zw[6] = (d6 << 1) | (d5 >> 31);235zw[7] = (d7 << 1) | (d6 >> 31);236237for (i = 0; i < 4; i ++) {238uint32_t lw;239240lw = zw[i];241zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7);242zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25);243}244memcpy(yw, zw + 4, sizeof yw);245}246br_enc32be(yb, yw[3]);247br_enc32be(yb + 4, yw[2]);248br_enc32be(yb + 8, yw[1]);249br_enc32be(yb + 12, yw[0]);250}251252253