xref: /qemu/crypto/clmul.c (revision b49f4755)
1 /*
2  * Carry-less multiply operations.
3  * SPDX-License-Identifier: GPL-2.0-or-later
4  *
5  * Copyright (C) 2023 Linaro, Ltd.
6  */
7 
8 #include "qemu/osdep.h"
9 #include "crypto/clmul.h"
10 
11 uint64_t clmul_8x8_low(uint64_t n, uint64_t m)
12 {
13     uint64_t r = 0;
14 
15     for (int i = 0; i < 8; ++i) {
16         uint64_t mask = (n & 0x0101010101010101ull) * 0xff;
17         r ^= m & mask;
18         m = (m << 1) & 0xfefefefefefefefeull;
19         n >>= 1;
20     }
21     return r;
22 }
23 
24 static uint64_t clmul_8x4_even_int(uint64_t n, uint64_t m)
25 {
26     uint64_t r = 0;
27 
28     for (int i = 0; i < 8; ++i) {
29         uint64_t mask = (n & 0x0001000100010001ull) * 0xffff;
30         r ^= m & mask;
31         n >>= 1;
32         m <<= 1;
33     }
34     return r;
35 }
36 
37 uint64_t clmul_8x4_even(uint64_t n, uint64_t m)
38 {
39     n &= 0x00ff00ff00ff00ffull;
40     m &= 0x00ff00ff00ff00ffull;
41     return clmul_8x4_even_int(n, m);
42 }
43 
44 uint64_t clmul_8x4_odd(uint64_t n, uint64_t m)
45 {
46     return clmul_8x4_even(n >> 8, m >> 8);
47 }
48 
49 static uint64_t unpack_8_to_16(uint64_t x)
50 {
51     return  (x & 0x000000ff)
52          | ((x & 0x0000ff00) << 8)
53          | ((x & 0x00ff0000) << 16)
54          | ((x & 0xff000000) << 24);
55 }
56 
57 uint64_t clmul_8x4_packed(uint32_t n, uint32_t m)
58 {
59     return clmul_8x4_even_int(unpack_8_to_16(n), unpack_8_to_16(m));
60 }
61 
62 uint64_t clmul_16x2_even(uint64_t n, uint64_t m)
63 {
64     uint64_t r = 0;
65 
66     n &= 0x0000ffff0000ffffull;
67     m &= 0x0000ffff0000ffffull;
68 
69     for (int i = 0; i < 16; ++i) {
70         uint64_t mask = (n & 0x0000000100000001ull) * 0xffffffffull;
71         r ^= m & mask;
72         n >>= 1;
73         m <<= 1;
74     }
75     return r;
76 }
77 
78 uint64_t clmul_16x2_odd(uint64_t n, uint64_t m)
79 {
80     return clmul_16x2_even(n >> 16, m >> 16);
81 }
82 
83 uint64_t clmul_32(uint32_t n, uint32_t m32)
84 {
85     uint64_t r = 0;
86     uint64_t m = m32;
87 
88     for (int i = 0; i < 32; ++i) {
89         r ^= n & 1 ? m : 0;
90         n >>= 1;
91         m <<= 1;
92     }
93     return r;
94 }
95 
96 Int128 clmul_64_gen(uint64_t n, uint64_t m)
97 {
98     uint64_t rl = 0, rh = 0;
99 
100     /* Bit 0 can only influence the low 64-bit result.  */
101     if (n & 1) {
102         rl = m;
103     }
104 
105     for (int i = 1; i < 64; ++i) {
106         uint64_t mask = -((n >> i) & 1);
107         rl ^= (m << i) & mask;
108         rh ^= (m >> (64 - i)) & mask;
109     }
110     return int128_make128(rl, rh);
111 }
112