/src/botan/src/lib/block/sm4/sm4_gfni/sm4_gfni.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * (C) 2024 Jack Lloyd |
3 | | * |
4 | | * Botan is released under the Simplified BSD License (see license.txt) |
5 | | */ |
6 | | |
7 | | #include <botan/internal/sm4.h> |
8 | | |
9 | | #include <botan/internal/simd_avx2.h> |
10 | | #include <botan/internal/simd_avx2_gfni.h> |
11 | | |
12 | | namespace Botan { |
13 | | |
14 | | namespace { |
15 | | |
16 | 0 | BOTAN_FUNC_ISA_INLINE(BOTAN_GFNI_ISA) SIMD_8x32 sm4_sbox(const SIMD_8x32& x) { |
17 | | /* |
18 | | * See https://eprint.iacr.org/2022/1154 section 3.3 for details on |
19 | | * how this works |
20 | | */ |
21 | 0 | constexpr uint64_t pre_a = gfni_matrix(R"( |
22 | 0 | 0 0 1 1 0 0 1 0 |
23 | 0 | 0 0 0 1 0 1 0 0 |
24 | 0 | 1 0 1 1 1 1 1 0 |
25 | 0 | 1 0 0 1 1 1 0 1 |
26 | 0 | 0 1 0 1 1 0 0 0 |
27 | 0 | 0 1 0 0 0 1 0 0 |
28 | 0 | 0 0 0 0 1 0 1 0 |
29 | 0 | 1 0 1 1 1 0 1 0)"); |
30 | |
|
31 | 0 | constexpr uint8_t pre_c = 0b00111110; |
32 | |
|
33 | 0 | constexpr uint64_t post_a = gfni_matrix(R"( |
34 | 0 | 1 1 0 0 1 1 1 1 |
35 | 0 | 1 1 0 1 0 1 0 1 |
36 | 0 | 0 0 1 0 1 1 0 0 |
37 | 0 | 1 0 0 1 0 1 0 1 |
38 | 0 | 0 0 1 0 1 1 1 0 |
39 | 0 | 0 1 1 0 0 1 0 1 |
40 | 0 | 1 0 1 0 1 1 0 1 |
41 | 0 | 1 0 0 1 0 0 0 1)"); |
42 | |
|
43 | 0 | constexpr uint8_t post_c = 0b11010011; |
44 | |
|
45 | 0 | auto y = gf2p8affine<pre_a, pre_c>(x); |
46 | 0 | return gf2p8affineinv<post_a, post_c>(y); |
47 | 0 | } |
48 | | |
49 | 0 | BOTAN_FUNC_ISA_INLINE(BOTAN_GFNI_ISA) SIMD_8x32 sm4_f(const SIMD_8x32& x) { |
50 | 0 | SIMD_8x32 sx = sm4_sbox(x); |
51 | 0 | return sx ^ sx.rotl<2>() ^ sx.rotl<10>() ^ sx.rotl<18>() ^ sx.rotl<24>(); |
52 | 0 | } |
53 | | |
54 | | BOTAN_FUNC_ISA_INLINE(BOTAN_GFNI_ISA) |
55 | 0 | void sm4_gfni_encrypt_8(const uint8_t ptext[8 * 16], uint8_t ctext[8 * 16], std::span<const uint32_t> RK) { |
56 | 0 | SIMD_8x32 B0 = SIMD_8x32::load_be(ptext); |
57 | 0 | SIMD_8x32 B1 = SIMD_8x32::load_be(ptext + 16 * 2); |
58 | 0 | SIMD_8x32 B2 = SIMD_8x32::load_be(ptext + 16 * 4); |
59 | 0 | SIMD_8x32 B3 = SIMD_8x32::load_be(ptext + 16 * 6); |
60 | |
|
61 | 0 | SIMD_8x32::transpose(B0, B1, B2, B3); |
62 | |
|
63 | 0 | B0 = B0.rev_words(); |
64 | 0 | B1 = B1.rev_words(); |
65 | 0 | B2 = B2.rev_words(); |
66 | 0 | B3 = B3.rev_words(); |
67 | |
|
68 | 0 | for(size_t j = 0; j != 8; ++j) { |
69 | 0 | B0 ^= sm4_f(B1 ^ B2 ^ B3 ^ SIMD_8x32::splat(RK[4 * j])); |
70 | 0 | B1 ^= sm4_f(B2 ^ B3 ^ B0 ^ SIMD_8x32::splat(RK[4 * j + 1])); |
71 | 0 | B2 ^= sm4_f(B3 ^ B0 ^ B1 ^ SIMD_8x32::splat(RK[4 * j + 2])); |
72 | 0 | B3 ^= sm4_f(B0 ^ B1 ^ B2 ^ SIMD_8x32::splat(RK[4 * j + 3])); |
73 | 0 | } |
74 | |
|
75 | 0 | SIMD_8x32::transpose(B0, B1, B2, B3); |
76 | |
|
77 | 0 | B3.rev_words().store_be(ctext); |
78 | 0 | B2.rev_words().store_be(ctext + 16 * 2); |
79 | 0 | B1.rev_words().store_be(ctext + 16 * 4); |
80 | 0 | B0.rev_words().store_be(ctext + 16 * 6); |
81 | 0 | } |
82 | | |
83 | | BOTAN_FUNC_ISA_INLINE(BOTAN_GFNI_ISA) |
84 | 0 | void sm4_gfni_decrypt_8(const uint8_t ctext[8 * 16], uint8_t ptext[8 * 16], std::span<const uint32_t> RK) { |
85 | 0 | SIMD_8x32 B0 = SIMD_8x32::load_be(ctext); |
86 | 0 | SIMD_8x32 B1 = SIMD_8x32::load_be(ctext + 16 * 2); |
87 | 0 | SIMD_8x32 B2 = SIMD_8x32::load_be(ctext + 16 * 4); |
88 | 0 | SIMD_8x32 B3 = SIMD_8x32::load_be(ctext + 16 * 6); |
89 | |
|
90 | 0 | SIMD_8x32::transpose(B0, B1, B2, B3); |
91 | |
|
92 | 0 | B0 = B0.rev_words(); |
93 | 0 | B1 = B1.rev_words(); |
94 | 0 | B2 = B2.rev_words(); |
95 | 0 | B3 = B3.rev_words(); |
96 | |
|
97 | 0 | for(size_t j = 0; j != 8; ++j) { |
98 | 0 | B0 ^= sm4_f(B1 ^ B2 ^ B3 ^ SIMD_8x32::splat(RK[32 - (4 * j + 1)])); |
99 | 0 | B1 ^= sm4_f(B2 ^ B3 ^ B0 ^ SIMD_8x32::splat(RK[32 - (4 * j + 2)])); |
100 | 0 | B2 ^= sm4_f(B3 ^ B0 ^ B1 ^ SIMD_8x32::splat(RK[32 - (4 * j + 3)])); |
101 | 0 | B3 ^= sm4_f(B0 ^ B1 ^ B2 ^ SIMD_8x32::splat(RK[32 - (4 * j + 4)])); |
102 | 0 | } |
103 | |
|
104 | 0 | SIMD_8x32::transpose(B0, B1, B2, B3); |
105 | |
|
106 | 0 | B3.rev_words().store_be(ptext); |
107 | 0 | B2.rev_words().store_be(ptext + 16 * 2); |
108 | 0 | B1.rev_words().store_be(ptext + 16 * 4); |
109 | 0 | B0.rev_words().store_be(ptext + 16 * 6); |
110 | 0 | } |
111 | | |
112 | | } // namespace |
113 | | |
114 | 0 | void BOTAN_FUNC_ISA("gfni,avx2") SM4::sm4_gfni_encrypt(const uint8_t ptext[], uint8_t ctext[], size_t blocks) const { |
115 | 0 | while(blocks >= 8) { |
116 | 0 | sm4_gfni_encrypt_8(ptext, ctext, m_RK); |
117 | 0 | ptext += 16 * 8; |
118 | 0 | ctext += 16 * 8; |
119 | 0 | blocks -= 8; |
120 | 0 | } |
121 | |
|
122 | 0 | if(blocks > 0) { |
123 | 0 | uint8_t pbuf[8 * 16] = {0}; |
124 | 0 | uint8_t cbuf[8 * 16] = {0}; |
125 | 0 | copy_mem(pbuf, ptext, blocks * 16); |
126 | 0 | sm4_gfni_encrypt_8(pbuf, cbuf, m_RK); |
127 | 0 | copy_mem(ctext, cbuf, blocks * 16); |
128 | 0 | } |
129 | 0 | } |
130 | | |
131 | 0 | void BOTAN_FUNC_ISA("gfni,avx2") SM4::sm4_gfni_decrypt(const uint8_t ctext[], uint8_t ptext[], size_t blocks) const { |
132 | 0 | while(blocks >= 8) { |
133 | 0 | sm4_gfni_decrypt_8(ctext, ptext, m_RK); |
134 | 0 | ptext += 16 * 8; |
135 | 0 | ctext += 16 * 8; |
136 | 0 | blocks -= 8; |
137 | 0 | } |
138 | |
|
139 | 0 | if(blocks > 0) { |
140 | 0 | uint8_t cbuf[8 * 16] = {0}; |
141 | 0 | uint8_t pbuf[8 * 16] = {0}; |
142 | 0 | copy_mem(cbuf, ctext, blocks * 16); |
143 | 0 | sm4_gfni_decrypt_8(cbuf, pbuf, m_RK); |
144 | 0 | copy_mem(ptext, pbuf, blocks * 16); |
145 | 0 | } |
146 | 0 | } |
147 | | |
148 | | } // namespace Botan |