Repository: randombit/botan
Pull request #3536 (2023-05-01 21:55:53)

Add vpternlogd based Serpent sboxes
Can get each sbox down to 8 or 9 vpternlogs, and it has the same cost per instruction as XOR/AND/OR [*], so this should be ~2x faster.

[*] On Intel. On AMD it seems PAND/POR/PXOR have latency 1 and recip throughput .25, while vpternlogd has latency 1 and recip .5. So it will probably be basically the same perf as the original sboxes on Zen4.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/59503217/badge)](https://coveralls.io/builds/59503217)

Coverage: 91.484% (-0.2%) from 91.719% when pulling **a2a1554a4de7f1ca9d94811e0ba954fff819d6a9 on jack/avx512-serpent-ternlogd** into **1881cd8ed31c4ba6c36cdb4dc93c9e89746ecf3d on master**.


Patch:
diff --git a/src/lib/block/serpent/serpent_avx512/serpent_avx512.cpp b/src/lib/block/serpent/serpent_avx512/serpent_avx512.cpp
index eea422a3c..44542dc6b 100644
--- a/src/lib/block/serpent/serpent_avx512/serpent_avx512.cpp
+++ b/src/lib/block/serpent/serpent_avx512/serpent_avx512.cpp
@@ -10,6 +10,273 @@
 
 namespace Botan {
 
+BOTAN_FORCE_INLINE
+void SBoxE0(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0xb9>(b, d, c);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0xe2>(a, b, d);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0x36>(a, b, d);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x26>(t0, d, b);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t3);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0x96>(t1, c, o0);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0xa9>(o0, o1, t2);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x3c>(t2, c, t0);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxE1(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0xe5>(d, b, c);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x26>(c, d, b);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0xa6>(a, b, c);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x2b>(a, b, d);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0x83>(t2, d, t0);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x69>(t3, c, o1);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0x65>(o3, o1, t2);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxE2(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0x96>(c, b, d);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0xda>(a, b, c);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0x66>(d, t0, c);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x94>(a, b, t0);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0xa1>(a, d, t0);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t2);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0xd2>(t3, d, o0);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0x2d>(t4, b, c);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x2d>(t1, d, t2);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxE3(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0x92>(d, c, b);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x3b>(d, b, c);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0xbc>(a, c, t0);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0x68>(t2, d, t1);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x6e>(a, c, o2);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0xb9>(a, d, t3);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0x6d>(t4, b, t2);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x38>(t3, b, t0);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxE4(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0xc2>(c, b, d);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x79>(b, c, d);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0x71>(a, b, d);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x6b>(a, b, d);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0xc2>(a, t0, t3);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0x3c>(t2, c, t0);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x49>(t3, c, t0);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0xd6>(t4, b, t1);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxE5(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0xa9>(b, d, c);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x93>(b, c, d);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0xc3>(a, b, c);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x27>(a, b, d);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0x85>(a, c, t1);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0x2d>(t2, d, o0);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0x7a>(t4, b, t0);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x87>(t3, t0, o0);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxE6(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0x61>(d, c, b);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x9c>(b, d, t0);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0x93>(a, b, d);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0xb5>(a, b, c);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0x3c>(t2, c, t0);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0x7c>(a, b, o1);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0x1e>(t4, d, t0);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x29>(t3, t0, t1);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxE7(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0x9b>(b, c, d);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x61>(c, b, d);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0xe3>(a, d, t1);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x83>(b, c, d);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0x49>(a, b, c);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0xe1>(t2, b, c);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0xd1>(t3, a, t1);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x87>(t4, d, t2);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxD0(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0x67>(c, d, b);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x49>(b, d, c);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0xa9>(a, b, c);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0x3c>(t2, d, t0);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x4d>(a, b, d);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x69>(t3, c, o0);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0x56>(o3, o0, t2);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxD1(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0x73>(d, b, c);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x68>(c, d, b);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0xc5>(a, b, d);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x2d>(a, b, d);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0x96>(t2, c, o0);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0xd2>(t3, o0, o1);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x99>(o0, t3, c);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxD2(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0xc6>(d, b, c);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x9c>(d, c, b);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0xe1>(a, b, c);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0x87>(t2, d, t0);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0xd1>(t0, a, t1);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x9b>(a, c, o2);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x5b>(t3, b, d);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxD3(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0x94>(c, d, b);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x99>(b, d, t0);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0x97>(a, b, d);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0x4b>(t2, c, o0);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x94>(c, d, t2);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0x0e>(t3, b, t0);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0x1c>(a, b, t0);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0xb4>(t4, c, d);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxD4(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0xa9>(d, c, b);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0xa6>(d, b, c);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0xb5>(a, b, d);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x5e>(a, b, d);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0x50>(a, b, t0);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0x96>(t4, c, d);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0x4b>(t3, c, t4);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x5a>(t2, c, t0);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxD5(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0xc9>(a, b, c);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x65>(a, b, c);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0x25>(a, b, d);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x63>(c, d, t0);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0x86>(a, b, t3);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0x87>(t2, c, t0);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0xc3>(t4, c, d);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0x47>(t1, d, t0);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0xac>(a, t0, t3);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxD6(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0x07>(d, b, c);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x9e>(c, d, b);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0xc6>(a, b, c);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x34>(a, b, d);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0x2b>(a, c, d);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t1);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0xcb>(t2, d, t0);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0x4b>(t3, c, t0);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x69>(t4, b, o0);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
+BOTAN_FORCE_INLINE
+void SBoxD7(SIMD_16x32& a, SIMD_16x32& b, SIMD_16x32& c, SIMD_16x32& d) {
+   const SIMD_16x32 t0 = SIMD_16x32::ternary_fn<0x67>(b, d, c);
+   const SIMD_16x32 t1 = SIMD_16x32::ternary_fn<0x3e>(a, c, d);
+   const SIMD_16x32 t2 = SIMD_16x32::ternary_fn<0x1c>(a, b, d);
+   const SIMD_16x32 t3 = SIMD_16x32::ternary_fn<0x87>(t0, d, b);
+   const SIMD_16x32 t4 = SIMD_16x32::ternary_fn<0x7d>(a, b, t1);
+   const SIMD_16x32 o0 = SIMD_16x32::ternary_fn<0xac>(a, t0, t3);
+   const SIMD_16x32 o1 = SIMD_16x32::ternary_fn<0x96>(t1, b, t0);
+   const SIMD_16x32 o2 = SIMD_16x32::ternary_fn<0xd2>(t2, c, t1);
+   const SIMD_16x32 o3 = SIMD_16x32::ternary_fn<0x6d>(t4, c, d);
+   a = o0;
+   b = o1;
+   c = o2;
+   d = o3;
+}
+
 BOTAN_AVX512_FN
 void Serpent::avx512_encrypt_16(const uint8_t in[16 * 16], uint8_t out[16 * 16]) const {
    using namespace Botan::Serpent_F;
diff --git a/src/lib/block/serpent/serpent_fn.h b/src/lib/block/serpent/serpent_fn.h
new file mode 100644
index 000000000..c54549ab3
--- /dev/null
+++ b/src/lib/block/serpent/serpent_fn.h
@@ -0,0 +1,72 @@
+/*
+* (C) 1999-2007,2013 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_SERPENT_FUNCS_H_
+#define BOTAN_SERPENT_FUNCS_H_
+
+#include <botan/types.h>
+#include <botan/internal/rotate.h>
+
+namespace Botan::Serpent_F {
+
+template <size_t S>
+BOTAN_FORCE_INLINE uint32_t shl(uint32_t v) {
+   return v << S;
+}
+
+/*
+* Serpent's Linear Transform
+*/
+template <typename T>
+BOTAN_FORCE_INLINE void transform(T& B0, T& B1, T& B2, T& B3) {
+   B0 = rotl<13>(B0);
+   B2 = rotl<3>(B2);
+   B1 ^= B0 ^ B2;
+   B3 ^= B2 ^ shl<3>(B0);
+   B1 = rotl<1>(B1);
+   B3 = rotl<7>(B3);
+   B0 ^= B1 ^ B3;
+   B2 ^= B3 ^ shl<7>(B1);
+   B0 = rotl<5>(B0);
+   B2 = rotl<22>(B2);
+}
+
+/*
+* Serpent's Inverse Linear Transform
+*/
+template <typename T>
+BOTAN_FORCE_INLINE void i_transform(T& B0, T& B1, T& B2, T& B3) {
+   B2 = rotr<22>(B2);
+   B0 = rotr<5>(B0);
+   B2 ^= B3 ^ shl<7>(B1);
+   B0 ^= B1 ^ B3;
+   B3 = rotr<7>(B3);
+   B1 = rotr<1>(B1);
+   B3 ^= B2 ^ shl<3>(B0);
+   B1 ^= B0 ^ B2;
+   B2 = rotr<3>(B2);
+   B0 = rotr<13>(B0);
+}
+
+class Key_Inserter final {
+   public:
+      Key_Inserter(const uint32_t* RK) : m_RK(RK) {}
+
+      template <typename T>
+      inline void operator()(size_t R, T& B0, T& B1, T& B2, T& B3) const {
+         B0 ^= m_RK[4 * R];
+         B1 ^= m_RK[4 * R + 1];
+         B2 ^= m_RK[4 * R + 2];
+         B3 ^= m_RK[4 * R + 3];
+      }
+
+   private:
+      const uint32_t* m_RK;
+};
+
+}  // namespace Botan::Serpent_F
+
+#endif
diff --git a/src/lib/block/serpent/serpent_sbox.h b/src/lib/block/serpent/serpent_sbox.h
index 07c6e669d..9cea961da 100644
--- a/src/lib/block/serpent/serpent_sbox.h
+++ b/src/lib/block/serpent/serpent_sbox.h
@@ -7,11 +7,11 @@
 * Botan is released under the Simplified BSD License (see license.txt)
 */
 
-#ifndef BOTAN_SERPENT_FUNCS_H_
-#define BOTAN_SERPENT_FUNCS_H_
+#ifndef BOTAN_SERPENT_SBOX_FN_H_
+#define BOTAN_SERPENT_SBOX_FN_H_
 
 #include <botan/types.h>
-#include <botan/internal/rotate.h>
+#include <botan/internal/serpent_fn.h>
 
 namespace Botan::Serpent_F {
 
@@ -429,61 +429,6 @@ BOTAN_FORCE_INLINE void SBoxD7(T& a, T& b, T& c, T& d) {
    d = t0;
 }
 
-template <size_t S>
-BOTAN_FORCE_INLINE uint32_t shl(uint32_t v) {
-   return v << S;
-}
-
-/*
-* Serpent's Linear Transform
-*/
-template <typename T>
-BOTAN_FORCE_INLINE void transform(T& B0, T& B1, T& B2, T& B3) {
-   B0 = rotl<13>(B0);
-   B2 = rotl<3>(B2);
-   B1 ^= B0 ^ B2;
-   B3 ^= B2 ^ shl<3>(B0);
-   B1 = rotl<1>(B1);
-   B3 = rotl<7>(B3);
-   B0 ^= B1 ^ B3;
-   B2 ^= B3 ^ shl<7>(B1);
-   B0 = rotl<5>(B0);
-   B2 = rotl<22>(B2);
-}
-
-/*
-* Serpent's Inverse Linear Transform
-*/
-template <typename T>
-BOTAN_FORCE_INLINE void i_transform(T& B0, T& B1, T& B2, T& B3) {
-   B2 = rotr<22>(B2);
-   B0 = rotr<5>(B0);
-   B2 ^= B3 ^ shl<7>(B1);
-   B0 ^= B1 ^ B3;
-   B3 = rotr<7>(B3);
-   B1 = rotr<1>(B1);
-   B3 ^= B2 ^ shl<3>(B0);
-   B1 ^= B0 ^ B2;
-   B2 = rotr<3>(B2);
-   B0 = rotr<13>(B0);
-}
-
-class Key_Inserter final {
-   public:
-      Key_Inserter(const uint32_t* RK) : m_RK(RK) {}
-
-      template <typename T>
-      inline void operator()(size_t R, T& B0, T& B1, T& B2, T& B3) const {
-         B0 ^= m_RK[4 * R];
-         B1 ^= m_RK[4 * R + 1];
-         B2 ^= m_RK[4 * R + 2];
-         B3 ^= m_RK[4 * R + 3];
-      }
-
-   private:
-      const uint32_t* m_RK;
-};
-
 }  // namespace Botan::Serpent_F
 
 #endif


Test patch:
diff --git a/src/tests/data/block/serpent.vec b/src/tests/data/block/serpent.vec
index 8e75f341a..f8936464a 100644
--- a/src/tests/data/block/serpent.vec
+++ b/src/tests/data/block/serpent.vec
@@ -14,6 +14,10 @@ Key = 00000000000000000000000000000000
 In = D29D576FCEA3A3A7ED9099F29273D78E2D62A890CEA3A3A7ED9099F29273D78ED29D576F315C5C58ED9099F29273D78E2D62A890315C5C58ED9099F29273D78ED29D576FCEA3A3A7126F660D9273D78E2D62A890CEA3A3A7126F660D9273D78ED29D576F315C5C58126F660D9273D78E2D62A890315C5C58126F660D9273D78ED29D576FCEA3A3A7ED9099F26D8C28712D62A890CEA3A3A7ED9099F26D8C2871D29D576F315C5C58ED9099F26D8C28712D62A890315C5C58ED9099F26D8C2871D29D576FCEA3A3A7126F660D6D8C28712D62A890CEA3A3A7126F660D6D8C2871D29D576F315C5C58126F660D6D8C28712D62A890315C5C58126F660D6D8C2871AA26D561F567520E8AE47528C24C18D731A2193D9A97FED6922B17AAA6372B74BE5DEBD559E303C9C92B174A5107BBFEB626D8F65EDCCDF3AEE475C8A183772241DDE7C1F1631F5FDED4F42746471BD651D238BA86176EFE39E4695AAEB73B52EA5926CADAD8018962E469BA920CB8BF1EA9062E4D9CEDD5FAD4F4C7990367A4B966E5C5D2277288C61B96A559CC84AFB6A6583C5AACFCD6212B0BD8AEF3C6A9A11DDBD175639341052B0B384678D8D9352299B71DD880E29D1B96452DB86540B2288B968AE8B08648D1CE9606FD992D717EB02EB81A2E939D54ACA91087112D0D809C5EE82F477EBA7B956DBB23463B0F0190D616F5294112FFB7884E8B37F941BA1B505386B7428B88338188F7E718A3348230BF5CFA552F88D22463D9703A115351622E016BCA26918D17E13225F67EE4E3F2C46FE52ECBDA044C585717DC563A8403FF5309D62370B1DCF5A11EDD2F7D73602B70CD2553E44C1D3F170126155BBD9BE3A965B345E834718F651CEF6CC65E8C5C566E894817350F497816F1EEFA51FC91FEBB6E9F8CB141CC0EB6AF3C6F8380CBD3C996167F2F0E90E71B756C87EB62A4975356B28DCBF6A64A0BD107206D48FE6DBE19D50314B90AC87B8335706F9B26007071AD8105CFAA1C1E2FF7FEAE5CEC4D11477F24E6B2009068703C0E29E2950F2AC2DACD63DEEB5C7EFA9FDB9F3B740563D5518287DC981FC9CB46D4B5A5A86FEC08FE70D18297DCF51072DDBE038DA040EBB12C509F5940A212DDEB59F02132BE4581FC23EABAA960D6341D9352E36DFD6E4EAF0F6F439BC8CE73A9AB3164FF30350F2DC08E939A104D6DF0C2C28F8E2D44468A61278BB6B4294DAE45AE0CAA032FC97CD4D8C57FB83BBA8AFCAE22070BC882D3A42B38A09E65
 Out = B2288B968AE8B08648D1CE9606FD992D717EB02EB81A2E939D54ACA91087112D0D809C5EE82F477EBA7B956DBB23463B0F0190D616F5294112FFB7884E8B37F941BA1B505386B7428B88338188F7E718A3348230BF5CFA552F88D22463D9703A115351622E016BCA26918D17E13225F67EE4E3F2C46FE52ECBDA044C585717DC563A8403FF5309D62370B1DCF5A11EDD2F7D73602B70CD2553E44C1D3F170126155BBD9BE3A965B345E834718F651CEF6CC65E8C5C566E894817350F497816F1EEFA51FC91FEBB6E9F8CB141CC0EB6AF3C6F8380CBD3C996167F2F0E90E71B756C87EB62A4975356B28DCBF6A64A0BD107206D48FE6DBE19D50314B90AC87B8335706F9B26007071AD8105CFAA1C1E2FF7FEAE5CEC4D11477F24E6B2009068703C0E29E2950F2AC2DACD63DEEB5C7EFA9FDB9F3B740563D5518287DC981FC9CB46D4B5A5A86FEC08FE70D18297DCF51072DDBE038DA040EBB12C509F5940A212DDEB59F02132BE4581FC23EABAA960D6341D9352E36DFD6E4EAF0F6F439BC8CE73A9AB3164FF30350F2DC08E939A104D6DF0C2C28F8E2D44468A61278BB6B4294DAE45AE0CAA032FC97CD4D8C57FB83BBA8AFCAE22070BC882D3A42B38A09E6558A51ED82169DE7027CBE72452626CA3FF6BBF2FB2C574EC9D5656505B51688047AEA89DBBB5C4EBE819C5BDFDAB16033D2FE7D01071373624D99845D90E32C1708C609C4E75BE40D8DE77F8EA78C2CC98852792C22E971F29C2E125247FB43CAD1FD857DE9B8016C5971FFF86AD399ED669FEF7481FD73B9A45B1CFFE9C556DAE9A816916FB1F5822B2CEC8986F6E5B156775D0F6F432D57D351C62A24AFE63AE812270F7416D05E153E5AB703DCD3FF320F6AD3D00647C23F08699E0EE9F5EDDB3C717C2A6D3E58D38269DBA0243926D64CCD92B1101086DD3F0DDB73312A31D5F5EA0FD18AB84E242C96FFCC222F9FE12D5B15F5A3C365E9FF3248FB43B385A0F73507F49A08E68952BEE09DC7D35E7B29A44C8970624CB3A93DA4AE7E49835AE41A5BE2EE591750FF9A7D431B1EE8A69099E689A06324AA0AE431ACAE762FD3B90A8B269090A4CEEA076CF1EB7A580DEDE896BED63917384B1C5E18B7B57A7EB6B127A7A32898989E32CFF9A46BF6A62268500E53AD8A5FBC95226266BD9AAE1BA501274C49A7A7EC67D7577114B7707DAB9D066AF086C09E7DD4116CEA6EE25DA9A65EF05A31ED0BDF56D525EC8968D1D01AF7165C5AEAC76BD367A575A
 
+Key = 00000000000000000000000000000000
+In = 2B2CD6A0E6F2F57A8976E67BF30A788C9DDAF2A859AB715CA933C1B6ED4B60D94AC402E1A00FF866555B2A37A2B4421A1EBF43A667F3FC3DB751A6BD75EA272F51C974F3B8C61854AA7D31DE0DE744168ABA09D248326C6C8D3E688E103C0BB1847CF705B2D43F71DD35FEC1188FE730EB7342B5C661EB2499FC990C400068FB0DE08798A65789C66E40E659AC3DA39CA90759D1A5B47425F32348A9B580A25295FA6CA151DC1C98363A742150597C0B1D4FDF226C0F863889CFA17CECF5EB3B26FCE46C1AEE0ABC22C312899A1129CD08B6A9509F1684A022264AC586D75CA73846952F454BA6FB419BF08F7A275167A98DC86CD05AC1FC152D80321458D8B5349287CC6D1F51FE664B15DE49C6090792346C8B7286038F8E7F99372ABD45CE6D169DAFE048749FC5B5E85834641F2465299E0B46D9FDDCF846B864BF8871F5E517364DB0D57CC667BDB97C906A9690F14CF08BD4D9260C01FF809E1A380D6895D44AE20DECF7C90080D977B07496B3B042F519F46B43A5CDF181E9A9302B540D3D1D575FFFAD11274C6B1B00367280AC49B2F6FF7EA05389A44A4ADC14F79EE8CDCB4409B5F65297C2173D22D5031619359695AAEE0BB8A98860C4E409A3410C1FBF1E0289996497D1249591785B908C065B18F14BF871D775EB8DE067CBD2324125778118035527C5FF5EDC578A0816DCDC5002F01AB1E4C49F4095E2DB06
+Out = 8712C0024B98CAA78720EEAA0F3F7C2A514ABC87DA1C047E1707AEF502ABC7F046AC6E33B02B737F96BB579FC4237AE3B3ECBD8A6A27DC83893DB962D18C2864DF5C07BE8FF042586D2513318E37CB0683DE0C3B0536CFAAA36BD207D4D675EEBED4D785DC4F7CD9070A13A0050DAF7ACA6EBC7EA71F5B17A3F154C8BC2A71BB6D4B5C93B0C9306D0C7DDA22AB784B2F0F77EDAE235DE391516457F2574463ACA225EEDF009137E86E66E736AD5C7D3AD31CFD6D5EAB831DE2040F16EDC80E45278DCEF44E1DF179D888ACCEECF3EB314D5717FB0CDA47D720B167B9B788DE52ABAB118416F67BB1DFBDC1079904D32CAF8001808DF389DE5ADFC6BFAD4110EB8B1838F176B9B74B1E6BD203211FF2F825BD9AE3E09EF111045B3FBBC22D0C19EF28C45A930A00222D8574F6D688C52B7C33A7FE1112C2991F8C27FD223E70BD6D50D341DFF687714B21B4ACF3A677325E1B92E4D7F2971ED66F47A760D716E55496410BFA640BF1ECD092A444F0BAD1D1CC49887E6672BD6C5D0CCF4BF402E99EE4C1DC72A26F7BD561C2C8F2571BCB142AB09334108965329BD5D4B87AC488240A4A317BD8EE442253FF5A6962A892AC1D4EE0801D3356F5F701A58F3F18354699699C3D0D7D7EE95F4172FFD81C9CB7A126030F0D7EB9093216CA240B10672EE2789887C91134BF0B785B0F56F3DD61C51D8BB2288F44F9CC85FEB7F42E10
+
 Key = 000000000000000000000000000000000000000000000000
 In = D29D576FCEABA3A7ED9899F2927BD78E
 Out = 130E353E1037C22405E8FAEFB2C3C3E9