Botan 3.6.0
Crypto and TLS for C&
sm4_gfni.cpp
Go to the documentation of this file.
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
12namespace Botan {
13
14namespace {
15
16BOTAN_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 constexpr uint64_t pre_a = gfni_matrix(R"(
22 0 0 1 1 0 0 1 0
23 0 0 0 1 0 1 0 0
24 1 0 1 1 1 1 1 0
25 1 0 0 1 1 1 0 1
26 0 1 0 1 1 0 0 0
27 0 1 0 0 0 1 0 0
28 0 0 0 0 1 0 1 0
29 1 0 1 1 1 0 1 0)");
30
31 constexpr uint8_t pre_c = 0b00111110;
32
33 constexpr uint64_t post_a = gfni_matrix(R"(
34 1 1 0 0 1 1 1 1
35 1 1 0 1 0 1 0 1
36 0 0 1 0 1 1 0 0
37 1 0 0 1 0 1 0 1
38 0 0 1 0 1 1 1 0
39 0 1 1 0 0 1 0 1
40 1 0 1 0 1 1 0 1
41 1 0 0 1 0 0 0 1)");
42
43 constexpr uint8_t post_c = 0b11010011;
44
45 auto y = gf2p8affine<pre_a, pre_c>(x);
47}
48
49BOTAN_FUNC_ISA_INLINE(BOTAN_GFNI_ISA) SIMD_8x32 sm4_f(const SIMD_8x32& x) {
50 SIMD_8x32 sx = sm4_sbox(x);
51 return sx ^ sx.rotl<2>() ^ sx.rotl<10>() ^ sx.rotl<18>() ^ sx.rotl<24>();
52}
53
55void sm4_gfni_encrypt_8(const uint8_t ptext[8 * 16], uint8_t ctext[8 * 16], std::span<const uint32_t> RK) {
56 SIMD_8x32 B0 = SIMD_8x32::load_be(ptext);
57 SIMD_8x32 B1 = SIMD_8x32::load_be(ptext + 16 * 2);
58 SIMD_8x32 B2 = SIMD_8x32::load_be(ptext + 16 * 4);
59 SIMD_8x32 B3 = SIMD_8x32::load_be(ptext + 16 * 6);
60
61 SIMD_8x32::transpose(B0, B1, B2, B3);
62
63 B0 = B0.rev_words();
64 B1 = B1.rev_words();
65 B2 = B2.rev_words();
66 B3 = B3.rev_words();
67
68 for(size_t j = 0; j != 8; ++j) {
69 B0 ^= sm4_f(B1 ^ B2 ^ B3 ^ SIMD_8x32::splat(RK[4 * j]));
70 B1 ^= sm4_f(B2 ^ B3 ^ B0 ^ SIMD_8x32::splat(RK[4 * j + 1]));
71 B2 ^= sm4_f(B3 ^ B0 ^ B1 ^ SIMD_8x32::splat(RK[4 * j + 2]));
72 B3 ^= sm4_f(B0 ^ B1 ^ B2 ^ SIMD_8x32::splat(RK[4 * j + 3]));
73 }
74
75 SIMD_8x32::transpose(B0, B1, B2, B3);
76
77 B3.rev_words().store_be(ctext);
78 B2.rev_words().store_be(ctext + 16 * 2);
79 B1.rev_words().store_be(ctext + 16 * 4);
80 B0.rev_words().store_be(ctext + 16 * 6);
81}
82
84void sm4_gfni_decrypt_8(const uint8_t ctext[8 * 16], uint8_t ptext[8 * 16], std::span<const uint32_t> RK) {
85 SIMD_8x32 B0 = SIMD_8x32::load_be(ctext);
86 SIMD_8x32 B1 = SIMD_8x32::load_be(ctext + 16 * 2);
87 SIMD_8x32 B2 = SIMD_8x32::load_be(ctext + 16 * 4);
88 SIMD_8x32 B3 = SIMD_8x32::load_be(ctext + 16 * 6);
89
90 SIMD_8x32::transpose(B0, B1, B2, B3);
91
92 B0 = B0.rev_words();
93 B1 = B1.rev_words();
94 B2 = B2.rev_words();
95 B3 = B3.rev_words();
96
97 for(size_t j = 0; j != 8; ++j) {
98 B0 ^= sm4_f(B1 ^ B2 ^ B3 ^ SIMD_8x32::splat(RK[32 - (4 * j + 1)]));
99 B1 ^= sm4_f(B2 ^ B3 ^ B0 ^ SIMD_8x32::splat(RK[32 - (4 * j + 2)]));
100 B2 ^= sm4_f(B3 ^ B0 ^ B1 ^ SIMD_8x32::splat(RK[32 - (4 * j + 3)]));
101 B3 ^= sm4_f(B0 ^ B1 ^ B2 ^ SIMD_8x32::splat(RK[32 - (4 * j + 4)]));
102 }
103
104 SIMD_8x32::transpose(B0, B1, B2, B3);
105
106 B3.rev_words().store_be(ptext);
107 B2.rev_words().store_be(ptext + 16 * 2);
108 B1.rev_words().store_be(ptext + 16 * 4);
109 B0.rev_words().store_be(ptext + 16 * 6);
110}
111
112} // namespace
113
114void BOTAN_FUNC_ISA("gfni,avx2") SM4::sm4_gfni_encrypt(const uint8_t ptext[], uint8_t ctext[], size_t blocks) const {
115 while(blocks >= 8) {
116 sm4_gfni_encrypt_8(ptext, ctext, m_RK);
117 ptext += 16 * 8;
118 ctext += 16 * 8;
119 blocks -= 8;
120 }
121
122 if(blocks > 0) {
123 uint8_t pbuf[8 * 16] = {0};
124 uint8_t cbuf[8 * 16] = {0};
125 copy_mem(pbuf, ptext, blocks * 16);
126 sm4_gfni_encrypt_8(pbuf, cbuf, m_RK);
127 copy_mem(ctext, cbuf, blocks * 16);
128 }
129}
130
131void BOTAN_FUNC_ISA("gfni,avx2") SM4::sm4_gfni_decrypt(const uint8_t ctext[], uint8_t ptext[], size_t blocks) const {
132 while(blocks >= 8) {
133 sm4_gfni_decrypt_8(ctext, ptext, m_RK);
134 ptext += 16 * 8;
135 ctext += 16 * 8;
136 blocks -= 8;
137 }
138
139 if(blocks > 0) {
140 uint8_t cbuf[8 * 16] = {0};
141 uint8_t pbuf[8 * 16] = {0};
142 copy_mem(cbuf, ctext, blocks * 16);
143 sm4_gfni_decrypt_8(cbuf, pbuf, m_RK);
144 copy_mem(ptext, pbuf, blocks * 16);
145 }
146}
147
148} // namespace Botan
#define BOTAN_FUNC_ISA(isa)
Definition compiler.h:92
#define BOTAN_FUNC_ISA_INLINE(isa)
Definition compiler.h:98
SIMD_8x32 gf2p8affine(const SIMD_8x32 &x)
consteval uint64_t gfni_matrix(std::string_view s)
SIMD_8x32 gf2p8affineinv(const SIMD_8x32 &x)
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:146
#define BOTAN_GFNI_ISA