Botan 3.9.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/mem_ops.h>
10#include <botan/internal/isa_extn.h>
11#include <botan/internal/simd_avx2.h>
12#include <botan/internal/simd_avx2_gfni.h>
13
14namespace Botan {
15
16namespace {
17
18BOTAN_FORCE_INLINE BOTAN_FN_ISA_AVX2_GFNI SIMD_8x32 sm4_sbox(const SIMD_8x32& x) {
19 /*
20 * See https://eprint.iacr.org/2022/1154 section 3.3 for details on
21 * how this works
22 */
23 constexpr uint64_t pre_a = gfni_matrix(R"(
24 0 0 1 1 0 0 1 0
25 0 0 0 1 0 1 0 0
26 1 0 1 1 1 1 1 0
27 1 0 0 1 1 1 0 1
28 0 1 0 1 1 0 0 0
29 0 1 0 0 0 1 0 0
30 0 0 0 0 1 0 1 0
31 1 0 1 1 1 0 1 0)");
32
33 constexpr uint8_t pre_c = 0b00111110;
34
35 constexpr uint64_t post_a = gfni_matrix(R"(
36 1 1 0 0 1 1 1 1
37 1 1 0 1 0 1 0 1
38 0 0 1 0 1 1 0 0
39 1 0 0 1 0 1 0 1
40 0 0 1 0 1 1 1 0
41 0 1 1 0 0 1 0 1
42 1 0 1 0 1 1 0 1
43 1 0 0 1 0 0 0 1)");
44
45 constexpr uint8_t post_c = 0b11010011;
46
47 auto y = gf2p8affine<pre_a, pre_c>(x);
49}
50
51BOTAN_FORCE_INLINE BOTAN_FN_ISA_AVX2_GFNI SIMD_8x32 sm4_f(const SIMD_8x32& x) {
52 SIMD_8x32 sx = sm4_sbox(x);
53 return sx ^ sx.rotl<2>() ^ sx.rotl<10>() ^ sx.rotl<18>() ^ sx.rotl<24>();
54}
55
56BOTAN_FORCE_INLINE BOTAN_FN_ISA_AVX2_GFNI void sm4_gfni_encrypt_8(const uint8_t ptext[8 * 16],
57 uint8_t ctext[8 * 16],
58 std::span<const uint32_t> RK) {
59 SIMD_8x32 B0 = SIMD_8x32::load_be(ptext);
60 SIMD_8x32 B1 = SIMD_8x32::load_be(ptext + 16 * 2);
61 SIMD_8x32 B2 = SIMD_8x32::load_be(ptext + 16 * 4);
62 SIMD_8x32 B3 = SIMD_8x32::load_be(ptext + 16 * 6);
63
64 SIMD_8x32::transpose(B0, B1, B2, B3);
65
66 B0 = B0.rev_words();
67 B1 = B1.rev_words();
68 B2 = B2.rev_words();
69 B3 = B3.rev_words();
70
71 for(size_t j = 0; j != 8; ++j) {
72 B0 ^= sm4_f(B1 ^ B2 ^ B3 ^ SIMD_8x32::splat(RK[4 * j]));
73 B1 ^= sm4_f(B2 ^ B3 ^ B0 ^ SIMD_8x32::splat(RK[4 * j + 1]));
74 B2 ^= sm4_f(B3 ^ B0 ^ B1 ^ SIMD_8x32::splat(RK[4 * j + 2]));
75 B3 ^= sm4_f(B0 ^ B1 ^ B2 ^ SIMD_8x32::splat(RK[4 * j + 3]));
76 }
77
78 SIMD_8x32::transpose(B0, B1, B2, B3);
79
80 B3.rev_words().store_be(ctext);
81 B2.rev_words().store_be(ctext + 16 * 2);
82 B1.rev_words().store_be(ctext + 16 * 4);
83 B0.rev_words().store_be(ctext + 16 * 6);
84}
85
86BOTAN_FORCE_INLINE BOTAN_FN_ISA_AVX2_GFNI void sm4_gfni_decrypt_8(const uint8_t ctext[8 * 16],
87 uint8_t ptext[8 * 16],
88 std::span<const uint32_t> RK) {
89 SIMD_8x32 B0 = SIMD_8x32::load_be(ctext);
90 SIMD_8x32 B1 = SIMD_8x32::load_be(ctext + 16 * 2);
91 SIMD_8x32 B2 = SIMD_8x32::load_be(ctext + 16 * 4);
92 SIMD_8x32 B3 = SIMD_8x32::load_be(ctext + 16 * 6);
93
94 SIMD_8x32::transpose(B0, B1, B2, B3);
95
96 B0 = B0.rev_words();
97 B1 = B1.rev_words();
98 B2 = B2.rev_words();
99 B3 = B3.rev_words();
100
101 for(size_t j = 0; j != 8; ++j) {
102 B0 ^= sm4_f(B1 ^ B2 ^ B3 ^ SIMD_8x32::splat(RK[32 - (4 * j + 1)]));
103 B1 ^= sm4_f(B2 ^ B3 ^ B0 ^ SIMD_8x32::splat(RK[32 - (4 * j + 2)]));
104 B2 ^= sm4_f(B3 ^ B0 ^ B1 ^ SIMD_8x32::splat(RK[32 - (4 * j + 3)]));
105 B3 ^= sm4_f(B0 ^ B1 ^ B2 ^ SIMD_8x32::splat(RK[32 - (4 * j + 4)]));
106 }
107
108 SIMD_8x32::transpose(B0, B1, B2, B3);
109
110 B3.rev_words().store_be(ptext);
111 B2.rev_words().store_be(ptext + 16 * 2);
112 B1.rev_words().store_be(ptext + 16 * 4);
113 B0.rev_words().store_be(ptext + 16 * 6);
114}
115
116} // namespace
117
118void BOTAN_FN_ISA_AVX2_GFNI SM4::sm4_gfni_encrypt(const uint8_t ptext[], uint8_t ctext[], size_t blocks) const {
119 while(blocks >= 8) {
120 sm4_gfni_encrypt_8(ptext, ctext, m_RK);
121 ptext += 16 * 8;
122 ctext += 16 * 8;
123 blocks -= 8;
124 }
125
126 if(blocks > 0) {
127 uint8_t pbuf[8 * 16] = {0};
128 uint8_t cbuf[8 * 16] = {0};
129 copy_mem(pbuf, ptext, blocks * 16);
130 sm4_gfni_encrypt_8(pbuf, cbuf, m_RK);
131 copy_mem(ctext, cbuf, blocks * 16);
132 }
133}
134
135void BOTAN_FN_ISA_AVX2_GFNI SM4::sm4_gfni_decrypt(const uint8_t ctext[], uint8_t ptext[], size_t blocks) const {
136 while(blocks >= 8) {
137 sm4_gfni_decrypt_8(ctext, ptext, m_RK);
138 ptext += 16 * 8;
139 ctext += 16 * 8;
140 blocks -= 8;
141 }
142
143 if(blocks > 0) {
144 uint8_t cbuf[8 * 16] = {0};
145 uint8_t pbuf[8 * 16] = {0};
146 copy_mem(cbuf, ctext, blocks * 16);
147 sm4_gfni_decrypt_8(cbuf, pbuf, m_RK);
148 copy_mem(ptext, pbuf, blocks * 16);
149 }
150}
151
152} // namespace Botan
static BOTAN_FN_ISA_AVX2 void transpose(SIMD_8x32 &B0, SIMD_8x32 &B1, SIMD_8x32 &B2, SIMD_8x32 &B3) noexcept
Definition simd_avx2.h:264
static BOTAN_FN_ISA_AVX2 SIMD_8x32 splat(uint32_t B) noexcept
Definition simd_avx2.h:58
static BOTAN_FN_ISA_AVX2 SIMD_8x32 load_be(const uint8_t *in) noexcept
Definition simd_avx2.h:81
#define BOTAN_FORCE_INLINE
Definition compiler.h:87
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:145
consteval uint64_t gfni_matrix(std::string_view s)
BOTAN_FORCE_INLINE BOTAN_FN_ISA_AVX2_GFNI SIMD_8x32 gf2p8affineinv(const SIMD_8x32 &x)
BOTAN_FORCE_INLINE BOTAN_FN_ISA_AVX2_GFNI SIMD_8x32 gf2p8affine(const SIMD_8x32 &x)