summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig13
-rw-r--r--lib/Kconfig.debug231
-rw-r--r--lib/Kconfig.ubsan2
-rw-r--r--lib/Makefile9
-rw-r--r--lib/alloc_tag.c32
-rw-r--r--lib/assoc_array.c31
-rw-r--r--lib/bch.c2
-rw-r--r--lib/bootconfig.c27
-rw-r--r--lib/bucket_locks.c2
-rwxr-xr-xlib/build_OID_registry26
-rw-r--r--lib/buildid.c74
-rw-r--r--lib/codetag.c4
-rw-r--r--lib/cpu_rmap.c2
-rw-r--r--lib/crypto/Kconfig32
-rw-r--r--lib/crypto/Makefile59
-rw-r--r--lib/crypto/aes.c473
-rw-r--r--lib/crypto/aescfb.c30
-rw-r--r--lib/crypto/aesgcm.c12
-rw-r--r--lib/crypto/arm/aes-cipher-core.S201
-rw-r--r--lib/crypto/arm/aes.h56
-rw-r--r--lib/crypto/arm/nh-neon-core.S116
-rw-r--r--lib/crypto/arm/nh.h33
-rw-r--r--lib/crypto/arm64/aes-ce-core.S84
-rw-r--r--lib/crypto/arm64/aes-cipher-core.S132
-rw-r--r--lib/crypto/arm64/aes.h164
-rw-r--r--lib/crypto/arm64/nh-neon-core.S103
-rw-r--r--lib/crypto/arm64/nh.h34
-rw-r--r--lib/crypto/fips-mldsa.h458
-rw-r--r--lib/crypto/gf128mul.c6
-rw-r--r--lib/crypto/md5.c2
-rw-r--r--lib/crypto/mldsa.c682
-rw-r--r--lib/crypto/mpi/mpih-mul.c2
-rw-r--r--lib/crypto/mpi/mpiutil.c6
-rw-r--r--lib/crypto/nh.c82
-rw-r--r--lib/crypto/powerpc/.gitignore2
-rw-r--r--lib/crypto/powerpc/aes-spe-core.S346
-rw-r--r--lib/crypto/powerpc/aes-spe-keys.S278
-rw-r--r--lib/crypto/powerpc/aes-spe-modes.S625
-rw-r--r--lib/crypto/powerpc/aes-spe-regs.h37
-rw-r--r--lib/crypto/powerpc/aes-tab-4k.S326
-rw-r--r--lib/crypto/powerpc/aes.h240
-rw-r--r--lib/crypto/powerpc/aesp8-ppc.pl3890
-rw-r--r--lib/crypto/riscv/aes-riscv64-zvkned.S84
-rw-r--r--lib/crypto/riscv/aes.h63
-rw-r--r--lib/crypto/s390/aes.h106
-rw-r--r--lib/crypto/sha1.c63
-rw-r--r--lib/crypto/sparc/aes.h149
-rw-r--r--lib/crypto/sparc/aes_asm.S1543
-rw-r--r--lib/crypto/tests/Kconfig17
-rw-r--r--lib/crypto/tests/Makefile2
-rw-r--r--lib/crypto/tests/mldsa-testvecs.h1887
-rw-r--r--lib/crypto/tests/mldsa_kunit.c438
-rw-r--r--lib/crypto/tests/nh-testvecs.h298
-rw-r--r--lib/crypto/tests/nh_kunit.c43
-rw-r--r--lib/crypto/x86/aes-aesni.S261
-rw-r--r--lib/crypto/x86/aes.h85
-rw-r--r--lib/crypto/x86/nh-avx2.S158
-rw-r--r--lib/crypto/x86/nh-sse2.S123
-rw-r--r--lib/crypto/x86/nh.h45
-rw-r--r--lib/dec_and_lock.c8
-rw-r--r--lib/decompress_unxz.c4
-rw-r--r--lib/dhry_1.c4
-rw-r--r--lib/dim/net_dim.c2
-rw-r--r--lib/dynamic_debug.c2
-rw-r--r--lib/error-inject.c2
-rw-r--r--lib/find_bit.c2
-rw-r--r--lib/flex_proportions.c5
-rw-r--r--lib/globtest.c167
-rw-r--r--lib/group_cpus.c281
-rw-r--r--lib/hexdump.c1
-rw-r--r--lib/idr.c6
-rw-r--r--lib/interval_tree_test.c3
-rw-r--r--lib/iov_iter.c102
-rw-r--r--lib/kfifo.c2
-rw-r--r--lib/kobject.c4
-rw-r--r--lib/kobject_uevent.c6
-rw-r--r--lib/kstrtox.c4
-rw-r--r--lib/kunit/assert.c12
-rw-r--r--lib/kunit/attributes.c2
-rw-r--r--lib/kunit/device.c2
-rw-r--r--lib/kunit/executor.c6
-rw-r--r--lib/kunit/executor_test.c2
-rw-r--r--lib/kunit/kunit-example-test.c2
-rw-r--r--lib/kunit/kunit-test.c3
-rw-r--r--lib/kunit/resource.c2
-rw-r--r--lib/kunit/static_stub.c2
-rw-r--r--lib/kunit/string-stream.c4
-rw-r--r--lib/lockref.c1
-rw-r--r--lib/logic_iomem.c2
-rw-r--r--lib/lru_cache.c6
-rw-r--r--lib/lwq.c2
-rw-r--r--lib/objagg.c17
-rw-r--r--lib/objpool.c2
-rw-r--r--lib/once.c4
-rw-r--r--lib/parman.c2
-rw-r--r--lib/percpu-refcount.c2
-rw-r--r--lib/pldmfw/pldmfw.c8
-rw-r--r--lib/rbtree_test.c2
-rw-r--r--lib/reed_solomon/reed_solomon.c2
-rw-r--r--lib/reed_solomon/test_rslib.c4
-rw-r--r--lib/ref_tracker.c5
-rw-r--r--lib/rhashtable.c5
-rw-r--r--lib/scatterlist.c32
-rw-r--r--lib/sg_split.c7
-rw-r--r--lib/stackdepot.c22
-rw-r--r--lib/string_helpers.c3
-rw-r--r--lib/test_bpf.c50
-rw-r--r--lib/test_context-analysis.c598
-rw-r--r--lib/test_debug_virtual.c2
-rw-r--r--lib/test_firmware.c4
-rw-r--r--lib/test_fortify/test_fortify.sh4
-rw-r--r--lib/test_hmm.c8
-rw-r--r--lib/test_kho.c9
-rw-r--r--lib/test_memcat_p.c8
-rw-r--r--lib/test_objagg.c4
-rw-r--r--lib/test_parman.c2
-rw-r--r--lib/test_rhashtable.c2
-rw-r--r--lib/test_uuid.c134
-rw-r--r--lib/test_vmalloc.c15
-rw-r--r--lib/tests/Makefile6
-rw-r--r--lib/tests/bitops_kunit.c205
-rw-r--r--lib/tests/glob_kunit.c125
-rw-r--r--lib/tests/kunit_iov_iter.c6
-rw-r--r--lib/tests/list-private-test.c76
-rw-r--r--lib/tests/list-test.c8
-rw-r--r--lib/tests/liveupdate.c158
-rw-r--r--lib/tests/min_heap_kunit.c (renamed from lib/test_min_heap.c)147
-rw-r--r--lib/tests/printf_kunit.c20
-rw-r--r--lib/tests/test_list_sort.c4
-rw-r--r--lib/tests/test_ratelimit.c2
-rw-r--r--lib/tests/uuid_kunit.c106
-rw-r--r--lib/uuid.c1
-rw-r--r--lib/vdso/gettimeofday.c2
-rw-r--r--lib/vsprintf.c1
-rw-r--r--lib/xz/xz_dec_bcj.c2
-rw-r--r--lib/xz/xz_dec_lzma2.c4
-rw-r--r--lib/xz/xz_dec_stream.c2
-rw-r--r--lib/zlib_inflate/infutil.c2
138 files changed, 15841 insertions, 977 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index 2923924bea78..0f2fb9610647 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -430,19 +430,6 @@ config GLOB
are compiling an out-of tree driver which tells you that it
depends on this.
-config GLOB_SELFTEST
- tristate "glob self-test on init"
- depends on GLOB
- help
- This option enables a simple self-test of the glob_match
- function on startup. It is primarily useful for people
- working on the code to ensure they haven't introduced any
- regressions.
-
- It only adds a little bit of code and slows kernel boot (or
- module load) by a small amount, so you're welcome to play with
- it, but you probably don't need it.
-
#
# Netlink attribute parsing support is select'ed if needed
#
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ba36939fda79..4e2dfbbd3d78 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -35,6 +35,18 @@ config PRINTK_CALLER
no option to enable/disable at the kernel command line parameter or
sysfs interface.
+config PRINTK_EXECUTION_CTX
+ bool
+ depends on PRINTK
+ help
+ This option extends struct printk_info to include extra execution
+ context in printk, such as task name and CPU number from where the
+ message originated. This is useful for correlating printk messages
+ with specific execution contexts.
+
+ This is automatically enabled when a console driver that supports
+ execution context is selected.
+
config STACKTRACE_BUILD_ID
bool "Show build ID information in stacktraces"
depends on PRINTK
@@ -388,18 +400,13 @@ config DEBUG_INFO_BTF
depends on !DEBUG_INFO_SPLIT && !DEBUG_INFO_REDUCED
depends on !GCC_PLUGIN_RANDSTRUCT || COMPILE_TEST
depends on BPF_SYSCALL
- depends on PAHOLE_VERSION >= 116
- depends on DEBUG_INFO_DWARF4 || PAHOLE_VERSION >= 121
+ depends on PAHOLE_VERSION >= 122
# pahole uses elfutils, which does not have support for Hexagon relocations
depends on !HEXAGON
help
Generate deduplicated BTF type information from DWARF debug info.
- Turning this on requires pahole v1.16 or later (v1.21 or later to
- support DWARF 5), which will convert DWARF type info into equivalent
- deduplicated BTF type info.
-
-config PAHOLE_HAS_SPLIT_BTF
- def_bool PAHOLE_VERSION >= 119
+ Turning this on requires pahole v1.22 or later, which will convert
+ DWARF type info into equivalent deduplicated BTF type info.
config PAHOLE_HAS_BTF_TAG
def_bool PAHOLE_VERSION >= 123
@@ -421,7 +428,7 @@ config PAHOLE_HAS_LANG_EXCLUDE
config DEBUG_INFO_BTF_MODULES
bool "Generate BTF type information for kernel modules"
default y
- depends on DEBUG_INFO_BTF && MODULES && PAHOLE_HAS_SPLIT_BTF
+ depends on DEBUG_INFO_BTF && MODULES
help
Generate compact split BTF type information for kernel modules.
@@ -621,6 +628,36 @@ config DEBUG_FORCE_WEAK_PER_CPU
To ensure that generic code follows the above rules, this
option forces all percpu variables to be defined as weak.
+config WARN_CONTEXT_ANALYSIS
+ bool "Compiler context-analysis warnings"
+ depends on CC_IS_CLANG && CLANG_VERSION >= 220000
+ # Branch profiling re-defines "if", which messes with the compiler's
+ # ability to analyze __cond_acquires(..), resulting in false positives.
+ depends on !TRACE_BRANCH_PROFILING
+ default y
+ help
+ Context Analysis is a language extension, which enables statically
+ checking that required contexts are active (or inactive) by acquiring
+ and releasing user-definable "context locks".
+
+ Clang's name of the feature is "Thread Safety Analysis". Requires
+ Clang 22 or later.
+
+ Produces warnings by default. Select CONFIG_WERROR if you wish to
+ turn these warnings into errors.
+
+ For more details, see Documentation/dev-tools/context-analysis.rst.
+
+config WARN_CONTEXT_ANALYSIS_ALL
+ bool "Enable context analysis for all source files"
+ depends on WARN_CONTEXT_ANALYSIS
+ depends on EXPERT && !COMPILE_TEST
+ help
+ Enable tree-wide context analysis. This is likely to produce a
+ large number of false positives - enable at your own risk.
+
+ If unsure, say N.
+
endmenu # "Compiler options"
menu "Generic Kernel Debugging Instruments"
@@ -1110,13 +1147,14 @@ config SOFTLOCKUP_DETECTOR_INTR_STORM
the CPU stats and the interrupt counts during the "soft lockups".
config BOOTPARAM_SOFTLOCKUP_PANIC
- bool "Panic (Reboot) On Soft Lockups"
+ int "Panic (Reboot) On Soft Lockups"
depends on SOFTLOCKUP_DETECTOR
+ default 0
help
- Say Y here to enable the kernel to panic on "soft lockups",
- which are bugs that cause the kernel to loop in kernel
- mode for more than 20 seconds (configurable using the watchdog_thresh
- sysctl), without giving other tasks a chance to run.
+ Set to a non-zero value N to enable the kernel to panic on "soft
+ lockups", which are bugs that cause the kernel to loop in kernel
+ mode for more than (N * 20 seconds) (configurable using the
+ watchdog_thresh sysctl), without giving other tasks a chance to run.
The panic can be used in combination with panic_timeout,
to cause the system to reboot automatically after a
@@ -1124,7 +1162,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC
high-availability systems that have uptime guarantees and
where a lockup must be resolved ASAP.
- Say N if unsure.
+ Say 0 if unsure.
config HAVE_HARDLOCKUP_DETECTOR_BUDDY
bool
@@ -1273,7 +1311,7 @@ config BOOTPARAM_HUNG_TASK_PANIC
high-availability systems that have uptime guarantees and
where a hung tasks must be resolved ASAP.
- Say N if unsure.
+ Say 0 if unsure.
config DETECT_HUNG_TASK_BLOCKER
bool "Dump Hung Tasks Blocker"
@@ -1297,6 +1335,29 @@ config WQ_WATCHDOG
state. This can be configured through kernel parameter
"workqueue.watchdog_thresh" and its sysfs counterpart.
+config BOOTPARAM_WQ_STALL_PANIC
+ int "Panic on Nth workqueue stall"
+ default 0
+ range 0 100
+ depends on WQ_WATCHDOG
+ help
+ Set the number of workqueue stalls to trigger a kernel panic.
+ A workqueue stall occurs when a worker pool doesn't make forward
+ progress on a pending work item for over 30 seconds (configurable
+ using the workqueue.watchdog_thresh parameter).
+
+ If n = 0, the kernel will not panic on stall. If n > 0, the kernel
+ will panic after n stall warnings.
+
+ The panic can be used in combination with panic_timeout,
+ to cause the system to reboot automatically after a
+ stall has been detected. This feature is useful for
+ high-availability systems that have uptime guarantees and
+ where a stall must be resolved ASAP.
+
+ This setting can be overridden at runtime via the
+ workqueue.panic_on_stall kernel parameter.
+
config WQ_CPU_INTENSIVE_REPORT
bool "Report per-cpu work items which hog CPU for too long"
depends on DEBUG_KERNEL
@@ -1359,6 +1420,24 @@ config DEBUG_PREEMPT
depending on workload as it triggers debugging routines for each
this_cpu operation. It should only be used for debugging purposes.
+config DEBUG_ATOMIC
+ bool "Debug atomic variables"
+ depends on DEBUG_KERNEL
+ help
+ If you say Y here then the kernel will add a runtime alignment check
+ to atomic accesses. Useful for architectures that do not have trap on
+ mis-aligned access.
+
+ This option has potentially significant overhead.
+
+config DEBUG_ATOMIC_LARGEST_ALIGN
+ bool "Check alignment only up to __aligned_largest"
+ depends on DEBUG_ATOMIC
+ help
+ If you say Y here then the check for natural alignment of
+ atomic accesses will be constrained to the compiler's largest
+ alignment for scalar types.
+
menu "Lock Debugging (spinlocks, mutexes, etc...)"
config LOCK_DEBUGGING_SUPPORT
@@ -2277,16 +2356,6 @@ config TEST_LIST_SORT
If unsure, say N.
-config TEST_MIN_HEAP
- tristate "Min heap test"
- depends on DEBUG_KERNEL || m
- help
- Enable this to turn on min heap function tests. This test is
- executed only once during system boot (so affects only boot time),
- or at module load time.
-
- If unsure, say N.
-
config TEST_SORT
tristate "Array-based sort test" if !KUNIT_ALL_TESTS
depends on KUNIT
@@ -2499,9 +2568,6 @@ config TEST_BITMAP
If unsure, say N.
-config TEST_UUID
- tristate "Test functions located in the uuid module at runtime"
-
config TEST_XARRAY
tristate "Test the XArray code at runtime"
@@ -2551,14 +2617,6 @@ config TEST_PARMAN
If unsure, say N.
-config TEST_IRQ_TIMINGS
- bool "IRQ timings selftest"
- depends on IRQ_TIMINGS
- help
- Enable this option to test the irq timings code on boot.
-
- If unsure, say N.
-
config TEST_LKM
tristate "Test module loading with 'hello world' module"
depends on m
@@ -2652,6 +2710,19 @@ config TEST_SYSCTL
If unsure, say N.
+config BITOPS_KUNIT
+ tristate "KUnit test for bitops" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ This option enables the KUnit test for the bitops library
+ which provides functions for bit operations.
+
+ Note that this is derived from the original test_bitops module.
+ For micro-benchmarks and compiler warning checks, enable TEST_BITOPS.
+
+ If unsure, say N.
+
config BITFIELD_KUNIT
tristate "KUnit test bitfield functions at runtime" if !KUNIT_ALL_TESTS
depends on KUNIT
@@ -2780,6 +2851,20 @@ config LIST_KUNIT_TEST
If unsure, say N.
+config LIST_PRIVATE_KUNIT_TEST
+ tristate "KUnit Test for Kernel Private Linked-list structures" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ This builds the KUnit test for the private linked-list primitives
+ defined in include/linux/list_private.h.
+
+ These primitives allow manipulation of list_head members that are
+ marked as private and require special accessors (ACCESS_PRIVATE)
+ to strip qualifiers or handle encapsulation.
+
+ If unsure, say N.
+
config HASHTABLE_KUNIT_TEST
tristate "KUnit Test for Kernel Hashtable structures" if !KUNIT_ALL_TESTS
depends on KUNIT
@@ -2805,6 +2890,43 @@ config LINEAR_RANGES_TEST
If unsure, say N.
+config CONTEXT_ANALYSIS_TEST
+ bool "Compiler context-analysis warnings test"
+ depends on EXPERT
+ help
+ This builds the test for compiler-based context analysis. The test
+ does not add executable code to the kernel, but is meant to test that
+ common patterns supported by the analysis do not result in false
+ positive warnings.
+
+ When adding support for new context locks, it is strongly recommended
+ to add supported patterns to this test.
+
+ If unsure, say N.
+
+config LIVEUPDATE_TEST
+ bool "Live Update Kernel Test"
+ default n
+ depends on LIVEUPDATE
+ help
+ Enable a built-in kernel test module for the Live Update
+ Orchestrator.
+
+ This module validates the File-Lifecycle-Bound subsystem by
+ registering a set of mock FLB objects with any real file handlers
+ that support live update (such as the memfd handler).
+
+ When live update operations are performed, this test module will
+ output messages to the kernel log (dmesg), confirming that its
+ registration and various callback functions (preserve, retrieve,
+ finish, etc.) are being invoked correctly.
+
+ This is a debugging and regression testing tool for developers
+ working on the Live Update subsystem. It should not be enabled in
+ production kernels.
+
+ If unsure, say N
+
config CMDLINE_KUNIT_TEST
tristate "KUnit test for cmdline API" if !KUNIT_ALL_TESTS
depends on KUNIT
@@ -2880,6 +3002,17 @@ config MEMCPY_KUNIT_TEST
If unsure, say N.
+config MIN_HEAP_KUNIT_TEST
+ tristate "Min heap test" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ This option enables the KUnit test suite for the min heap library
+ which provides functions for creating and managing min heaps.
+ The test suite checks the functionality of the min heap library.
+
+ If unsure, say N
+
config IS_SIGNED_TYPE_KUNIT_TEST
tristate "Test is_signed_type() macro" if !KUNIT_ALL_TESTS
depends on KUNIT
@@ -3285,6 +3418,17 @@ config RATELIMIT_KUNIT_TEST
If unsure, say N.
+config UUID_KUNIT_TEST
+ tristate "KUnit test for UUID" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ This option enables the KUnit test suite for the uuid library,
+ which provides functions for generating and parsing UUID and GUID.
+ The test suite checks parsing of UUID and GUID strings.
+
+ If unsure, say N.
+
config INT_POW_KUNIT_TEST
tristate "Integer exponentiation (int_pow) test" if !KUNIT_ALL_TESTS
depends on KUNIT
@@ -3354,6 +3498,19 @@ config PRIME_NUMBERS_KUNIT_TEST
If unsure, say N
+config GLOB_KUNIT_TEST
+ tristate "Glob matching test" if !KUNIT_ALL_TESTS
+ depends on GLOB
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Enable this option to test the glob functions at runtime.
+
+ This test suite verifies the correctness of glob_match() across various
+ scenarios, including edge cases.
+
+ If unsure, say N
+
endif # RUNTIME_TESTING_MENU
config ARCH_USE_MEMTEST
diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan
index 744121178815..1ecaae7064d2 100644
--- a/lib/Kconfig.ubsan
+++ b/lib/Kconfig.ubsan
@@ -104,7 +104,7 @@ config UBSAN_DIV_ZERO
This option enables -fsanitize=integer-divide-by-zero which checks
for integer division by zero. This is effectively redundant with the
kernel's existing exception handling, though it can provide greater
- debugging information under CONFIG_UBSAN_REPORT_FULL.
+ debugging information.
config UBSAN_UNREACHABLE
bool "Perform checking for unreachable code"
diff --git a/lib/Makefile b/lib/Makefile
index aaf677cf4527..1b9ee167517f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -50,6 +50,8 @@ lib-$(CONFIG_MIN_HEAP) += min_heap.o
lib-y += kobject.o klist.o
obj-y += lockref.o
+CONTEXT_ANALYSIS_rhashtable.o := y
+
obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \
bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \
list_sort.o uuid.o iov_iter.o clz_ctz.o \
@@ -75,7 +77,6 @@ obj-$(CONFIG_TEST_UBSAN) += test_ubsan.o
CFLAGS_test_ubsan.o += $(call cc-disable-warning, unused-but-set-variable)
UBSAN_SANITIZE_test_ubsan.o := y
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
-obj-$(CONFIG_TEST_MIN_HEAP) += test_min_heap.o
obj-$(CONFIG_TEST_LKM) += test_module.o
obj-$(CONFIG_TEST_VMALLOC) += test_vmalloc.o
obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o
@@ -89,7 +90,6 @@ ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_KASAN),yy)
GCOV_PROFILE_test_bitmap.o := n
endif
-obj-$(CONFIG_TEST_UUID) += test_uuid.o
obj-$(CONFIG_TEST_XARRAY) += test_xarray.o
obj-$(CONFIG_TEST_MAPLE_TREE) += test_maple_tree.o
obj-$(CONFIG_TEST_PARMAN) += test_parman.o
@@ -226,7 +226,6 @@ obj-$(CONFIG_CLOSURES) += closure.o
obj-$(CONFIG_DQL) += dynamic_queue_limits.o
obj-$(CONFIG_GLOB) += glob.o
-obj-$(CONFIG_GLOB_SELFTEST) += globtest.o
obj-$(CONFIG_DIMLIB) += dim/
obj-$(CONFIG_SIGNATURE) += digsig.o
@@ -250,6 +249,7 @@ obj-$(CONFIG_POLYNOMIAL) += polynomial.o
# Prevent the compiler from calling builtins like memcmp() or bcmp() from this
# file.
CFLAGS_stackdepot.o += -fno-builtin
+CONTEXT_ANALYSIS_stackdepot.o := y
obj-$(CONFIG_STACKDEPOT) += stackdepot.o
KASAN_SANITIZE_stackdepot.o := n
# In particular, instrumenting stackdepot.c with KMSAN will result in infinite
@@ -331,4 +331,7 @@ obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
obj-$(CONFIG_FIRMWARE_TABLE) += fw_table.o
+CONTEXT_ANALYSIS_test_context-analysis.o := y
+obj-$(CONFIG_CONTEXT_ANALYSIS_TEST) += test_context-analysis.o
+
subdir-$(CONFIG_FORTIFY_SOURCE) += test_fortify
diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c
index 27fee57a5c91..58991ab09d84 100644
--- a/lib/alloc_tag.c
+++ b/lib/alloc_tag.c
@@ -669,8 +669,9 @@ static int __init alloc_mod_tags_mem(void)
return -ENOMEM;
}
- vm_module_tags->pages = kmalloc_array(get_vm_area_size(vm_module_tags) >> PAGE_SHIFT,
- sizeof(struct page *), GFP_KERNEL | __GFP_ZERO);
+ vm_module_tags->pages = kmalloc_objs(struct page *,
+ get_vm_area_size(vm_module_tags) >> PAGE_SHIFT,
+ GFP_KERNEL | __GFP_ZERO);
if (!vm_module_tags->pages) {
free_vm_area(vm_module_tags);
return -ENOMEM;
@@ -776,31 +777,38 @@ EXPORT_SYMBOL(page_alloc_tagging_ops);
static int proc_mem_profiling_handler(const struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
- if (!mem_profiling_support && write)
- return -EINVAL;
+ if (write) {
+ /*
+ * Call from do_sysctl_args() which is a no-op since the same
+ * value was already set by setup_early_mem_profiling.
+ * Return success to avoid warnings from do_sysctl_args().
+ */
+ if (!current->mm)
+ return 0;
+
+#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG
+ /* User can't toggle profiling while debugging */
+ return -EACCES;
+#endif
+ if (!mem_profiling_support)
+ return -EINVAL;
+ }
return proc_do_static_key(table, write, buffer, lenp, ppos);
}
-static struct ctl_table memory_allocation_profiling_sysctls[] = {
+static const struct ctl_table memory_allocation_profiling_sysctls[] = {
{
.procname = "mem_profiling",
.data = &mem_alloc_profiling_key,
-#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG
- .mode = 0444,
-#else
.mode = 0644,
-#endif
.proc_handler = proc_mem_profiling_handler,
},
};
static void __init sysctl_init(void)
{
- if (!mem_profiling_support)
- memory_allocation_profiling_sysctls[0].mode = 0444;
-
register_sysctl_init("vm", memory_allocation_profiling_sysctls);
}
#else /* CONFIG_SYSCTL */
diff --git a/lib/assoc_array.c b/lib/assoc_array.c
index 388e656ac974..bcc6e0a013eb 100644
--- a/lib/assoc_array.c
+++ b/lib/assoc_array.c
@@ -454,7 +454,7 @@ static bool assoc_array_insert_in_empty_tree(struct assoc_array_edit *edit)
pr_devel("-->%s()\n", __func__);
- new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
+ new_n0 = kzalloc_obj(struct assoc_array_node);
if (!new_n0)
return false;
@@ -536,11 +536,11 @@ static bool assoc_array_insert_into_terminal_node(struct assoc_array_edit *edit,
* those now. We may also need a new shortcut, but we deal with that
* when we need it.
*/
- new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
+ new_n0 = kzalloc_obj(struct assoc_array_node);
if (!new_n0)
return false;
edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
- new_n1 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
+ new_n1 = kzalloc_obj(struct assoc_array_node);
if (!new_n1)
return false;
edit->new_meta[1] = assoc_array_node_to_ptr(new_n1);
@@ -741,7 +741,7 @@ all_leaves_cluster_together:
keylen = round_up(diff, ASSOC_ARRAY_KEY_CHUNK_SIZE);
keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
- new_s0 = kzalloc(struct_size(new_s0, index_key, keylen), GFP_KERNEL);
+ new_s0 = kzalloc_flex(*new_s0, index_key, keylen);
if (!new_s0)
return false;
edit->new_meta[2] = assoc_array_shortcut_to_ptr(new_s0);
@@ -832,7 +832,7 @@ static bool assoc_array_insert_mid_shortcut(struct assoc_array_edit *edit,
edit->excised_meta[0] = assoc_array_shortcut_to_ptr(shortcut);
/* Create a new node now since we're going to need it anyway */
- new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
+ new_n0 = kzalloc_obj(struct assoc_array_node);
if (!new_n0)
return false;
edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
@@ -848,8 +848,7 @@ static bool assoc_array_insert_mid_shortcut(struct assoc_array_edit *edit,
keylen = round_up(diff, ASSOC_ARRAY_KEY_CHUNK_SIZE);
keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
- new_s0 = kzalloc(struct_size(new_s0, index_key, keylen),
- GFP_KERNEL);
+ new_s0 = kzalloc_flex(*new_s0, index_key, keylen);
if (!new_s0)
return false;
edit->new_meta[1] = assoc_array_shortcut_to_ptr(new_s0);
@@ -898,8 +897,7 @@ static bool assoc_array_insert_mid_shortcut(struct assoc_array_edit *edit,
keylen = round_up(shortcut->skip_to_level, ASSOC_ARRAY_KEY_CHUNK_SIZE);
keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
- new_s1 = kzalloc(struct_size(new_s1, index_key, keylen),
- GFP_KERNEL);
+ new_s1 = kzalloc_flex(*new_s1, index_key, keylen);
if (!new_s1)
return false;
edit->new_meta[2] = assoc_array_shortcut_to_ptr(new_s1);
@@ -977,7 +975,7 @@ struct assoc_array_edit *assoc_array_insert(struct assoc_array *array,
*/
BUG_ON(assoc_array_ptr_is_meta(object));
- edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
+ edit = kzalloc_obj(struct assoc_array_edit);
if (!edit)
return ERR_PTR(-ENOMEM);
edit->array = array;
@@ -1089,7 +1087,7 @@ struct assoc_array_edit *assoc_array_delete(struct assoc_array *array,
pr_devel("-->%s()\n", __func__);
- edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
+ edit = kzalloc_obj(struct assoc_array_edit);
if (!edit)
return ERR_PTR(-ENOMEM);
edit->array = array;
@@ -1206,7 +1204,7 @@ found_leaf:
node = parent;
/* Create a new node to collapse into */
- new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
+ new_n0 = kzalloc_obj(struct assoc_array_node);
if (!new_n0)
goto enomem;
edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
@@ -1281,7 +1279,7 @@ struct assoc_array_edit *assoc_array_clear(struct assoc_array *array,
if (!array->root)
return NULL;
- edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
+ edit = kzalloc_obj(struct assoc_array_edit);
if (!edit)
return ERR_PTR(-ENOMEM);
edit->array = array;
@@ -1469,7 +1467,7 @@ int assoc_array_gc(struct assoc_array *array,
if (!array->root)
return 0;
- edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
+ edit = kzalloc_obj(struct assoc_array_edit);
if (!edit)
return -ENOMEM;
edit->array = array;
@@ -1490,8 +1488,7 @@ descend:
shortcut = assoc_array_ptr_to_shortcut(cursor);
keylen = round_up(shortcut->skip_to_level, ASSOC_ARRAY_KEY_CHUNK_SIZE);
keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
- new_s = kmalloc(struct_size(new_s, index_key, keylen),
- GFP_KERNEL);
+ new_s = kmalloc_flex(*new_s, index_key, keylen);
if (!new_s)
goto enomem;
pr_devel("dup shortcut %p -> %p\n", shortcut, new_s);
@@ -1505,7 +1502,7 @@ descend:
/* Duplicate the node at this position */
node = assoc_array_ptr_to_node(cursor);
- new_n = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
+ new_n = kzalloc_obj(struct assoc_array_node);
if (!new_n)
goto enomem;
pr_devel("dup node %p -> %p\n", node, new_n);
diff --git a/lib/bch.c b/lib/bch.c
index 1c0cb07cdfeb..9561c0828802 100644
--- a/lib/bch.c
+++ b/lib/bch.c
@@ -1320,7 +1320,7 @@ struct bch_control *bch_init(int m, int t, unsigned int prim_poly,
if (prim_poly == 0)
prim_poly = prim_poly_tab[m-min_m];
- bch = kzalloc(sizeof(*bch), GFP_KERNEL);
+ bch = kzalloc_obj(*bch);
if (bch == NULL)
goto fail;
diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index 81f29c29f47b..449369a60846 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -557,17 +557,13 @@ static int __init __xbc_close_brace(char *p)
/*
* Return delimiter or error, no node added. As same as lib/cmdline.c,
* you can use " around spaces, but can't escape " for value.
+ * *@__v must point real value string. (not including spaces before value.)
*/
static int __init __xbc_parse_value(char **__v, char **__n)
{
char *p, *v = *__v;
int c, quotes = 0;
- v = skip_spaces(v);
- while (*v == '#') {
- v = skip_comment(v);
- v = skip_spaces(v);
- }
if (*v == '"' || *v == '\'') {
quotes = *v;
v++;
@@ -617,6 +613,13 @@ static int __init xbc_parse_array(char **__v)
last_parent = xbc_node_get_child(last_parent);
do {
+ /* Search the next array value beyond comments and empty lines */
+ next = skip_spaces(*__v);
+ while (*next == '#') {
+ next = skip_comment(next);
+ next = skip_spaces(next);
+ }
+ *__v = next;
c = __xbc_parse_value(__v, &next);
if (c < 0)
return c;
@@ -701,9 +704,17 @@ static int __init xbc_parse_kv(char **k, char *v, int op)
if (ret)
return ret;
- c = __xbc_parse_value(&v, &next);
- if (c < 0)
- return c;
+ v = skip_spaces_until_newline(v);
+ /* If there is a comment, this has an empty value. */
+ if (*v == '#') {
+ next = skip_comment(v);
+ *v = '\0';
+ c = '\n';
+ } else {
+ c = __xbc_parse_value(&v, &next);
+ if (c < 0)
+ return c;
+ }
child = xbc_node_get_child(last_parent);
if (child && xbc_node_is_value(child)) {
diff --git a/lib/bucket_locks.c b/lib/bucket_locks.c
index 64b92e1dbace..d29516ca0554 100644
--- a/lib/bucket_locks.c
+++ b/lib/bucket_locks.c
@@ -31,7 +31,7 @@ int __alloc_bucket_spinlocks(spinlock_t **locks, unsigned int *locks_mask,
}
if (sizeof(spinlock_t) != 0) {
- tlocks = kvmalloc_array(size, sizeof(spinlock_t), gfp);
+ tlocks = kvmalloc_objs(spinlock_t, size, gfp);
if (!tlocks)
return -ENOMEM;
for (i = 0; i < size; i++) {
diff --git a/lib/build_OID_registry b/lib/build_OID_registry
index 8267e8d71338..30493ac190c0 100755
--- a/lib/build_OID_registry
+++ b/lib/build_OID_registry
@@ -60,10 +60,12 @@ for (my $i = 0; $i <= $#names; $i++) {
# Determine the encoded length of this OID
my $size = $#components;
for (my $loop = 2; $loop <= $#components; $loop++) {
- my $c = $components[$loop];
+ $ENV{'BC_LINE_LENGTH'} = "0";
+ my $c = `echo "ibase=10; obase=2; $components[$loop]" | bc`;
+ chomp($c);
# We will base128 encode the number
- my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
+ my $tmp = length($c) - 1;
$tmp = int($tmp / 7);
$size += $tmp;
}
@@ -100,16 +102,24 @@ for (my $i = 0; $i <= $#names; $i++) {
push @octets, $components[0] * 40 + $components[1];
for (my $loop = 2; $loop <= $#components; $loop++) {
- my $c = $components[$loop];
+ # get the base 2 representation of the component
+ $ENV{'BC_LINE_LENGTH'} = "0";
+ my $c = `echo "ibase=10; obase=2; $components[$loop]" | bc`;
+ chomp($c);
- # Base128 encode the number
- my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
+ my $tmp = length($c) - 1;
$tmp = int($tmp / 7);
- for (; $tmp > 0; $tmp--) {
- push @octets, (($c >> $tmp * 7) & 0x7f) | 0x80;
+ # zero pad upto length multiple of 7
+ $c = substr("0000000", 0, ($tmp + 1) * 7 - length($c)).$c;
+
+ # Base128 encode the number
+ for (my $j = 0; $j < $tmp; $j++) {
+ my $b = oct("0b".substr($c, $j * 7, 7));
+
+ push @octets, $b | 0x80;
}
- push @octets, $c & 0x7f;
+ push @octets, oct("0b".substr($c, $tmp * 7, 7));
}
push @encoded_oids, \@octets;
diff --git a/lib/buildid.c b/lib/buildid.c
index aaf61dfc0919..c4b737640621 100644
--- a/lib/buildid.c
+++ b/lib/buildid.c
@@ -5,6 +5,7 @@
#include <linux/elf.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
+#include <linux/fs.h>
#include <linux/secretmem.h>
#define BUILD_ID 3
@@ -46,20 +47,9 @@ static int freader_get_folio(struct freader *r, loff_t file_off)
freader_put_folio(r);
- /* reject secretmem folios created with memfd_secret() */
- if (secretmem_mapping(r->file->f_mapping))
- return -EFAULT;
-
+ /* only use page cache lookup - fail if not already cached */
r->folio = filemap_get_folio(r->file->f_mapping, file_off >> PAGE_SHIFT);
- /* if sleeping is allowed, wait for the page, if necessary */
- if (r->may_fault && (IS_ERR(r->folio) || !folio_test_uptodate(r->folio))) {
- filemap_invalidate_lock_shared(r->file->f_mapping);
- r->folio = read_cache_folio(r->file->f_mapping, file_off >> PAGE_SHIFT,
- NULL, r->file);
- filemap_invalidate_unlock_shared(r->file->f_mapping);
- }
-
if (IS_ERR(r->folio) || !folio_test_uptodate(r->folio)) {
if (!IS_ERR(r->folio))
folio_put(r->folio);
@@ -97,6 +87,24 @@ const void *freader_fetch(struct freader *r, loff_t file_off, size_t sz)
return r->data + file_off;
}
+ /* reject secretmem folios created with memfd_secret() */
+ if (secretmem_mapping(r->file->f_mapping)) {
+ r->err = -EFAULT;
+ return NULL;
+ }
+
+ /* use __kernel_read() for sleepable context */
+ if (r->may_fault) {
+ ssize_t ret;
+
+ ret = __kernel_read(r->file, r->buf, sz, &file_off);
+ if (ret != sz) {
+ r->err = (ret < 0) ? ret : -EIO;
+ return NULL;
+ }
+ return r->buf;
+ }
+
/* fetch or reuse folio for given file offset */
r->err = freader_get_folio(r, file_off);
if (r->err)
@@ -271,7 +279,7 @@ static int get_build_id_64(struct freader *r, unsigned char *build_id, __u32 *si
/* enough for Elf64_Ehdr, Elf64_Phdr, and all the smaller requests */
#define MAX_FREADER_BUF_SZ 64
-static int __build_id_parse(struct vm_area_struct *vma, unsigned char *build_id,
+static int __build_id_parse(struct file *file, unsigned char *build_id,
__u32 *size, bool may_fault)
{
const Elf32_Ehdr *ehdr;
@@ -279,11 +287,7 @@ static int __build_id_parse(struct vm_area_struct *vma, unsigned char *build_id,
char buf[MAX_FREADER_BUF_SZ];
int ret;
- /* only works for page backed storage */
- if (!vma->vm_file)
- return -EINVAL;
-
- freader_init_from_file(&r, buf, sizeof(buf), vma->vm_file, may_fault);
+ freader_init_from_file(&r, buf, sizeof(buf), file, may_fault);
/* fetch first 18 bytes of ELF header for checks */
ehdr = freader_fetch(&r, 0, offsetofend(Elf32_Ehdr, e_type));
@@ -311,8 +315,8 @@ out:
return ret;
}
-/*
- * Parse build ID of ELF file mapped to vma
+/**
+ * build_id_parse_nofault() - Parse build ID of ELF file mapped to vma
* @vma: vma object
* @build_id: buffer to store build id, at least BUILD_ID_SIZE long
* @size: returns actual build id size in case of success
@@ -324,11 +328,14 @@ out:
*/
int build_id_parse_nofault(struct vm_area_struct *vma, unsigned char *build_id, __u32 *size)
{
- return __build_id_parse(vma, build_id, size, false /* !may_fault */);
+ if (!vma->vm_file)
+ return -EINVAL;
+
+ return __build_id_parse(vma->vm_file, build_id, size, false /* !may_fault */);
}
-/*
- * Parse build ID of ELF file mapped to VMA
+/**
+ * build_id_parse() - Parse build ID of ELF file mapped to VMA
* @vma: vma object
* @build_id: buffer to store build id, at least BUILD_ID_SIZE long
* @size: returns actual build id size in case of success
@@ -340,7 +347,26 @@ int build_id_parse_nofault(struct vm_area_struct *vma, unsigned char *build_id,
*/
int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id, __u32 *size)
{
- return __build_id_parse(vma, build_id, size, true /* may_fault */);
+ if (!vma->vm_file)
+ return -EINVAL;
+
+ return __build_id_parse(vma->vm_file, build_id, size, true /* may_fault */);
+}
+
+/**
+ * build_id_parse_file() - Parse build ID of ELF file
+ * @file: file object
+ * @build_id: buffer to store build id, at least BUILD_ID_SIZE long
+ * @size: returns actual build id size in case of success
+ *
+ * Assumes faultable context and can cause page faults to bring in file data
+ * into page cache.
+ *
+ * Return: 0 on success; negative error, otherwise
+ */
+int build_id_parse_file(struct file *file, unsigned char *build_id, __u32 *size)
+{
+ return __build_id_parse(file, build_id, size, true /* may_fault */);
}
/**
diff --git a/lib/codetag.c b/lib/codetag.c
index 545911cebd25..304667897ad4 100644
--- a/lib/codetag.c
+++ b/lib/codetag.c
@@ -193,7 +193,7 @@ static int codetag_module_init(struct codetag_type *cttype, struct module *mod)
BUG_ON(range.start > range.stop);
- cmod = kmalloc(sizeof(*cmod), GFP_KERNEL);
+ cmod = kmalloc_obj(*cmod);
if (unlikely(!cmod))
return -ENOMEM;
@@ -383,7 +383,7 @@ codetag_register_type(const struct codetag_type_desc *desc)
BUG_ON(desc->tag_size <= 0);
- cttype = kzalloc(sizeof(*cttype), GFP_KERNEL);
+ cttype = kzalloc_obj(*cttype);
if (unlikely(!cttype))
return ERR_PTR(-ENOMEM);
diff --git a/lib/cpu_rmap.c b/lib/cpu_rmap.c
index f03d9be3f06b..c86ab6e55d17 100644
--- a/lib/cpu_rmap.c
+++ b/lib/cpu_rmap.c
@@ -309,7 +309,7 @@ EXPORT_SYMBOL(irq_cpu_rmap_remove);
*/
int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq)
{
- struct irq_glue *glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ struct irq_glue *glue = kzalloc_obj(*glue);
int rc;
if (!glue)
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index 6871a41e5069..032f9755f999 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -11,6 +11,18 @@ config CRYPTO_LIB_UTILS
config CRYPTO_LIB_AES
tristate
+config CRYPTO_LIB_AES_ARCH
+ bool
+ depends on CRYPTO_LIB_AES && !UML && !KMSAN
+ default y if ARM
+ default y if ARM64
+ default y if PPC && (SPE || (PPC64 && VSX))
+ default y if RISCV && 64BIT && TOOLCHAIN_HAS_VECTOR_CRYPTO && \
+ RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS
+ default y if S390
+ default y if SPARC64
+ default y if X86
+
config CRYPTO_LIB_AESCFB
tristate
select CRYPTO_LIB_AES
@@ -101,6 +113,26 @@ config CRYPTO_LIB_MD5_ARCH
default y if PPC
default y if SPARC64
+config CRYPTO_LIB_MLDSA
+ tristate
+ select CRYPTO_LIB_SHA3
+ help
+ The ML-DSA library functions. Select this if your module uses any of
+ the functions from <crypto/mldsa.h>.
+
+config CRYPTO_LIB_NH
+ tristate
+ help
+ Implementation of the NH almost-universal hash function, specifically
+ the variant of NH used in Adiantum.
+
+config CRYPTO_LIB_NH_ARCH
+ bool
+ depends on CRYPTO_LIB_NH && !UML && !KMSAN
+ default y if ARM && KERNEL_MODE_NEON
+ default y if ARM64 && KERNEL_MODE_NEON
+ default y if X86_64
+
config CRYPTO_LIB_POLY1305
tristate
help
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index 330ab65b29c4..725eef05b758 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -15,8 +15,47 @@ obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o
obj-$(CONFIG_CRYPTO_LIB_UTILS) += libcryptoutils.o
libcryptoutils-y := memneq.o utils.o
-obj-$(CONFIG_CRYPTO_LIB_AES) += libaes.o
-libaes-y := aes.o
+################################################################################
+
+obj-$(CONFIG_CRYPTO_LIB_AES) += libaes.o
+libaes-y := aes.o
+ifeq ($(CONFIG_CRYPTO_LIB_AES_ARCH),y)
+CFLAGS_aes.o += -I$(src)/$(SRCARCH)
+
+libaes-$(CONFIG_ARM) += arm/aes-cipher-core.o
+
+ifeq ($(CONFIG_ARM64),y)
+libaes-y += arm64/aes-cipher-core.o
+libaes-$(CONFIG_KERNEL_MODE_NEON) += arm64/aes-ce-core.o
+endif
+
+ifeq ($(CONFIG_PPC),y)
+ifeq ($(CONFIG_SPE),y)
+libaes-y += powerpc/aes-spe-core.o \
+ powerpc/aes-spe-keys.o \
+ powerpc/aes-spe-modes.o \
+ powerpc/aes-tab-4k.o
+else
+libaes-y += powerpc/aesp8-ppc.o
+aes-perlasm-flavour-y := linux-ppc64
+aes-perlasm-flavour-$(CONFIG_PPC64_ELF_ABI_V2) := linux-ppc64-elfv2
+aes-perlasm-flavour-$(CONFIG_CPU_LITTLE_ENDIAN) := linux-ppc64le
+quiet_cmd_perlasm_aes = PERLASM $@
+ cmd_perlasm_aes = $(PERL) $< $(aes-perlasm-flavour-y) $@
+# Use if_changed instead of cmd, in case the flavour changed.
+$(obj)/powerpc/aesp8-ppc.S: $(src)/powerpc/aesp8-ppc.pl FORCE
+ $(call if_changed,perlasm_aes)
+targets += powerpc/aesp8-ppc.S
+OBJECT_FILES_NON_STANDARD_powerpc/aesp8-ppc.o := y
+endif # !CONFIG_SPE
+endif # CONFIG_PPC
+
+libaes-$(CONFIG_RISCV) += riscv/aes-riscv64-zvkned.o
+libaes-$(CONFIG_SPARC) += sparc/aes_asm.o
+libaes-$(CONFIG_X86) += x86/aes-aesni.o
+endif # CONFIG_CRYPTO_LIB_AES_ARCH
+
+################################################################################
obj-$(CONFIG_CRYPTO_LIB_AESCFB) += libaescfb.o
libaescfb-y := aescfb.o
@@ -126,6 +165,22 @@ endif # CONFIG_CRYPTO_LIB_MD5_ARCH
################################################################################
+obj-$(CONFIG_CRYPTO_LIB_MLDSA) += libmldsa.o
+libmldsa-y := mldsa.o
+
+################################################################################
+
+obj-$(CONFIG_CRYPTO_LIB_NH) += libnh.o
+libnh-y := nh.o
+ifeq ($(CONFIG_CRYPTO_LIB_NH_ARCH),y)
+CFLAGS_nh.o += -I$(src)/$(SRCARCH)
+libnh-$(CONFIG_ARM) += arm/nh-neon-core.o
+libnh-$(CONFIG_ARM64) += arm64/nh-neon-core.o
+libnh-$(CONFIG_X86) += x86/nh-sse2.o x86/nh-avx2.o
+endif
+
+################################################################################
+
obj-$(CONFIG_CRYPTO_LIB_POLY1305) += libpoly1305.o
libpoly1305-y := poly1305.o
ifeq ($(CONFIG_ARCH_SUPPORTS_INT128),y)
diff --git a/lib/crypto/aes.c b/lib/crypto/aes.c
index 102aaa76bc8d..b73e19f1bb95 100644
--- a/lib/crypto/aes.c
+++ b/lib/crypto/aes.c
@@ -1,19 +1,17 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2017-2019 Linaro Ltd <ard.biesheuvel@linaro.org>
+ * Copyright 2026 Google LLC
*/
#include <crypto/aes.h>
+#include <linux/cache.h>
#include <linux/crypto.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/unaligned.h>
-/*
- * Emit the sbox as volatile const to prevent the compiler from doing
- * constant folding on sbox references involving fixed indexes.
- */
-static volatile const u8 ____cacheline_aligned aes_sbox[] = {
+static const u8 ____cacheline_aligned aes_sbox[] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
@@ -48,7 +46,7 @@ static volatile const u8 ____cacheline_aligned aes_sbox[] = {
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
};
-static volatile const u8 ____cacheline_aligned aes_inv_sbox[] = {
+static const u8 ____cacheline_aligned aes_inv_sbox[] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
@@ -89,6 +87,110 @@ extern const u8 crypto_aes_inv_sbox[256] __alias(aes_inv_sbox);
EXPORT_SYMBOL(crypto_aes_sbox);
EXPORT_SYMBOL(crypto_aes_inv_sbox);
+/* aes_enc_tab[i] contains MixColumn([SubByte(i), 0, 0, 0]). */
+const u32 ____cacheline_aligned aes_enc_tab[256] = {
+ 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6,
+ 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56,
+ 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 0x45caca8f, 0x9d82821f,
+ 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,
+ 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
+ 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c,
+ 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551,
+ 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
+ 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637,
+ 0x0f05050a, 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+ 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d,
+ 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
+ 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd,
+ 0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1,
+ 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
+ 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
+ 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a,
+ 0x55333366, 0x94858511, 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe,
+ 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d,
+ 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+ 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5,
+ 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3,
+ 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755,
+ 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
+ 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
+ 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428,
+ 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 0x3be0e0db, 0x56323264,
+ 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,
+ 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531,
+ 0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+ 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac,
+ 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
+ 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657,
+ 0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e,
+ 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
+ 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c,
+ 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199,
+ 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122,
+ 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c,
+ 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+ 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7,
+ 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e,
+ 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c,
+};
+EXPORT_SYMBOL(aes_enc_tab);
+
+/* aes_dec_tab[i] contains InvMixColumn([InvSubByte(i), 0, 0, 0]). */
+const u32 ____cacheline_aligned aes_dec_tab[256] = {
+ 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f,
+ 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5,
+ 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, 0x495ab1de, 0x671bba25,
+ 0x980eea45, 0xe1c0fe5d, 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b,
+ 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
+ 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927,
+ 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 0x184adf63, 0x82311ae5,
+ 0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9,
+ 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72,
+ 0x578f1fe3, 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
+ 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 0x92b479a7,
+ 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4,
+ 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040,
+ 0x069f715e, 0x51106ebd, 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d,
+ 0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
+ 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879,
+ 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 0x83868009, 0x48ed2b32,
+ 0xac70111e, 0x4e725a6c, 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36,
+ 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793,
+ 0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
+ 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, 0xadc78bf2,
+ 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3,
+ 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, 0x7629438b, 0xdcc623cb,
+ 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684,
+ 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
+ 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947,
+ 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 0xc74e4987, 0xc1d138d9,
+ 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f,
+ 0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890,
+ 0x5ef7392e, 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
+ 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, 0xf418596e,
+ 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef,
+ 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 0xafb2a431, 0x31233f2a,
+ 0x3094a5c6, 0xc066a235, 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733,
+ 0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
+ 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546,
+ 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92,
+ 0x335610e9, 0x1347d66d, 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb,
+ 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255,
+ 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
+ 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0x0c25e2bc,
+ 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664,
+ 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0,
+};
+EXPORT_SYMBOL(aes_dec_tab);
+
+/* Prefetch data into L1 cache. @mem should be cacheline-aligned. */
+static __always_inline void aes_prefetch(const void *mem, size_t len)
+{
+ for (size_t i = 0; i < len; i += L1_CACHE_BYTES)
+ *(volatile const u8 *)(mem + i);
+ barrier();
+}
+
static u32 mul_by_x(u32 w)
{
u32 x = w & 0x7f7f7f7f;
@@ -145,22 +247,6 @@ static u32 inv_mix_columns(u32 x)
return mix_columns(x ^ y ^ ror32(y, 16));
}
-static __always_inline u32 subshift(u32 in[], int pos)
-{
- return (aes_sbox[in[pos] & 0xff]) ^
- (aes_sbox[(in[(pos + 1) % 4] >> 8) & 0xff] << 8) ^
- (aes_sbox[(in[(pos + 2) % 4] >> 16) & 0xff] << 16) ^
- (aes_sbox[(in[(pos + 3) % 4] >> 24) & 0xff] << 24);
-}
-
-static __always_inline u32 inv_subshift(u32 in[], int pos)
-{
- return (aes_inv_sbox[in[pos] & 0xff]) ^
- (aes_inv_sbox[(in[(pos + 3) % 4] >> 8) & 0xff] << 8) ^
- (aes_inv_sbox[(in[(pos + 2) % 4] >> 16) & 0xff] << 16) ^
- (aes_inv_sbox[(in[(pos + 1) % 4] >> 24) & 0xff] << 24);
-}
-
static u32 subw(u32 in)
{
return (aes_sbox[in & 0xff]) ^
@@ -169,38 +255,17 @@ static u32 subw(u32 in)
(aes_sbox[(in >> 24) & 0xff] << 24);
}
-/**
- * aes_expandkey - Expands the AES key as described in FIPS-197
- * @ctx: The location where the computed key will be stored.
- * @in_key: The supplied key.
- * @key_len: The length of the supplied key.
- *
- * Returns 0 on success. The function fails only if an invalid key size (or
- * pointer) is supplied.
- * The expanded key size is 240 bytes (max of 14 rounds with a unique 16 bytes
- * key schedule plus a 16 bytes key which is used before the first round).
- * The decryption key is prepared for the "Equivalent Inverse Cipher" as
- * described in FIPS-197. The first slot (16 bytes) of each key (enc or dec) is
- * for the initial combination, the second slot for the first round and so on.
- */
-int aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
- unsigned int key_len)
+static void aes_expandkey_generic(u32 rndkeys[], u32 *inv_rndkeys,
+ const u8 *in_key, int key_len)
{
u32 kwords = key_len / sizeof(u32);
u32 rc, i, j;
- int err;
-
- err = aes_check_keylen(key_len);
- if (err)
- return err;
-
- ctx->key_length = key_len;
for (i = 0; i < kwords; i++)
- ctx->key_enc[i] = get_unaligned_le32(in_key + i * sizeof(u32));
+ rndkeys[i] = get_unaligned_le32(&in_key[i * sizeof(u32)]);
for (i = 0, rc = 1; i < 10; i++, rc = mul_by_x(rc)) {
- u32 *rki = ctx->key_enc + (i * kwords);
+ u32 *rki = &rndkeys[i * kwords];
u32 *rko = rki + kwords;
rko[0] = ror32(subw(rki[kwords - 1]), 8) ^ rc ^ rki[0];
@@ -229,129 +294,239 @@ int aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
* the Inverse Mix Columns transformation to all but the first and
* the last one.
*/
- ctx->key_dec[0] = ctx->key_enc[key_len + 24];
- ctx->key_dec[1] = ctx->key_enc[key_len + 25];
- ctx->key_dec[2] = ctx->key_enc[key_len + 26];
- ctx->key_dec[3] = ctx->key_enc[key_len + 27];
-
- for (i = 4, j = key_len + 20; j > 0; i += 4, j -= 4) {
- ctx->key_dec[i] = inv_mix_columns(ctx->key_enc[j]);
- ctx->key_dec[i + 1] = inv_mix_columns(ctx->key_enc[j + 1]);
- ctx->key_dec[i + 2] = inv_mix_columns(ctx->key_enc[j + 2]);
- ctx->key_dec[i + 3] = inv_mix_columns(ctx->key_enc[j + 3]);
- }
+ if (inv_rndkeys) {
+ inv_rndkeys[0] = rndkeys[key_len + 24];
+ inv_rndkeys[1] = rndkeys[key_len + 25];
+ inv_rndkeys[2] = rndkeys[key_len + 26];
+ inv_rndkeys[3] = rndkeys[key_len + 27];
+
+ for (i = 4, j = key_len + 20; j > 0; i += 4, j -= 4) {
+ inv_rndkeys[i] = inv_mix_columns(rndkeys[j]);
+ inv_rndkeys[i + 1] = inv_mix_columns(rndkeys[j + 1]);
+ inv_rndkeys[i + 2] = inv_mix_columns(rndkeys[j + 2]);
+ inv_rndkeys[i + 3] = inv_mix_columns(rndkeys[j + 3]);
+ }
- ctx->key_dec[i] = ctx->key_enc[0];
- ctx->key_dec[i + 1] = ctx->key_enc[1];
- ctx->key_dec[i + 2] = ctx->key_enc[2];
- ctx->key_dec[i + 3] = ctx->key_enc[3];
+ inv_rndkeys[i] = rndkeys[0];
+ inv_rndkeys[i + 1] = rndkeys[1];
+ inv_rndkeys[i + 2] = rndkeys[2];
+ inv_rndkeys[i + 3] = rndkeys[3];
+ }
+}
+int aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
+ unsigned int key_len)
+{
+ if (aes_check_keylen(key_len) != 0)
+ return -EINVAL;
+ ctx->key_length = key_len;
+ aes_expandkey_generic(ctx->key_enc, ctx->key_dec, in_key, key_len);
return 0;
}
EXPORT_SYMBOL(aes_expandkey);
-/**
- * aes_encrypt - Encrypt a single AES block
- * @ctx: Context struct containing the key schedule
- * @out: Buffer to store the ciphertext
- * @in: Buffer containing the plaintext
- */
-void aes_encrypt(const struct crypto_aes_ctx *ctx, u8 *out, const u8 *in)
+static __always_inline u32 enc_quarterround(const u32 w[4], int i, u32 rk)
{
- const u32 *rkp = ctx->key_enc + 4;
- int rounds = 6 + ctx->key_length / 4;
- u32 st0[4], st1[4];
- int round;
+ return rk ^ aes_enc_tab[(u8)w[i]] ^
+ rol32(aes_enc_tab[(u8)(w[(i + 1) % 4] >> 8)], 8) ^
+ rol32(aes_enc_tab[(u8)(w[(i + 2) % 4] >> 16)], 16) ^
+ rol32(aes_enc_tab[(u8)(w[(i + 3) % 4] >> 24)], 24);
+}
+
+static __always_inline u32 enclast_quarterround(const u32 w[4], int i, u32 rk)
+{
+ return rk ^ ((aes_enc_tab[(u8)w[i]] & 0x0000ff00) >> 8) ^
+ (aes_enc_tab[(u8)(w[(i + 1) % 4] >> 8)] & 0x0000ff00) ^
+ ((aes_enc_tab[(u8)(w[(i + 2) % 4] >> 16)] & 0x0000ff00) << 8) ^
+ ((aes_enc_tab[(u8)(w[(i + 3) % 4] >> 24)] & 0x0000ff00) << 16);
+}
+
+static void __maybe_unused aes_encrypt_generic(const u32 rndkeys[], int nrounds,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ const u32 *rkp = rndkeys;
+ int n = nrounds - 1;
+ u32 w[4];
- st0[0] = ctx->key_enc[0] ^ get_unaligned_le32(in);
- st0[1] = ctx->key_enc[1] ^ get_unaligned_le32(in + 4);
- st0[2] = ctx->key_enc[2] ^ get_unaligned_le32(in + 8);
- st0[3] = ctx->key_enc[3] ^ get_unaligned_le32(in + 12);
+ w[0] = get_unaligned_le32(&in[0]) ^ *rkp++;
+ w[1] = get_unaligned_le32(&in[4]) ^ *rkp++;
+ w[2] = get_unaligned_le32(&in[8]) ^ *rkp++;
+ w[3] = get_unaligned_le32(&in[12]) ^ *rkp++;
/*
- * Force the compiler to emit data independent Sbox references,
- * by xoring the input with Sbox values that are known to add up
- * to zero. This pulls the entire Sbox into the D-cache before any
- * data dependent lookups are done.
+ * Prefetch the table before doing data and key-dependent loads from it.
+ *
+ * This is intended only as a basic constant-time hardening measure that
+ * avoids interfering with performance too much. Its effectiveness is
+ * not guaranteed. For proper constant-time AES, a CPU that supports
+ * AES instructions should be used instead.
*/
- st0[0] ^= aes_sbox[ 0] ^ aes_sbox[ 64] ^ aes_sbox[134] ^ aes_sbox[195];
- st0[1] ^= aes_sbox[16] ^ aes_sbox[ 82] ^ aes_sbox[158] ^ aes_sbox[221];
- st0[2] ^= aes_sbox[32] ^ aes_sbox[ 96] ^ aes_sbox[160] ^ aes_sbox[234];
- st0[3] ^= aes_sbox[48] ^ aes_sbox[112] ^ aes_sbox[186] ^ aes_sbox[241];
-
- for (round = 0;; round += 2, rkp += 8) {
- st1[0] = mix_columns(subshift(st0, 0)) ^ rkp[0];
- st1[1] = mix_columns(subshift(st0, 1)) ^ rkp[1];
- st1[2] = mix_columns(subshift(st0, 2)) ^ rkp[2];
- st1[3] = mix_columns(subshift(st0, 3)) ^ rkp[3];
-
- if (round == rounds - 2)
- break;
-
- st0[0] = mix_columns(subshift(st1, 0)) ^ rkp[4];
- st0[1] = mix_columns(subshift(st1, 1)) ^ rkp[5];
- st0[2] = mix_columns(subshift(st1, 2)) ^ rkp[6];
- st0[3] = mix_columns(subshift(st1, 3)) ^ rkp[7];
- }
+ aes_prefetch(aes_enc_tab, sizeof(aes_enc_tab));
+
+ do {
+ u32 w0 = enc_quarterround(w, 0, *rkp++);
+ u32 w1 = enc_quarterround(w, 1, *rkp++);
+ u32 w2 = enc_quarterround(w, 2, *rkp++);
+ u32 w3 = enc_quarterround(w, 3, *rkp++);
+
+ w[0] = w0;
+ w[1] = w1;
+ w[2] = w2;
+ w[3] = w3;
+ } while (--n);
+
+ put_unaligned_le32(enclast_quarterround(w, 0, *rkp++), &out[0]);
+ put_unaligned_le32(enclast_quarterround(w, 1, *rkp++), &out[4]);
+ put_unaligned_le32(enclast_quarterround(w, 2, *rkp++), &out[8]);
+ put_unaligned_le32(enclast_quarterround(w, 3, *rkp++), &out[12]);
+}
- put_unaligned_le32(subshift(st1, 0) ^ rkp[4], out);
- put_unaligned_le32(subshift(st1, 1) ^ rkp[5], out + 4);
- put_unaligned_le32(subshift(st1, 2) ^ rkp[6], out + 8);
- put_unaligned_le32(subshift(st1, 3) ^ rkp[7], out + 12);
+static __always_inline u32 dec_quarterround(const u32 w[4], int i, u32 rk)
+{
+ return rk ^ aes_dec_tab[(u8)w[i]] ^
+ rol32(aes_dec_tab[(u8)(w[(i + 3) % 4] >> 8)], 8) ^
+ rol32(aes_dec_tab[(u8)(w[(i + 2) % 4] >> 16)], 16) ^
+ rol32(aes_dec_tab[(u8)(w[(i + 1) % 4] >> 24)], 24);
+}
+
+static __always_inline u32 declast_quarterround(const u32 w[4], int i, u32 rk)
+{
+ return rk ^ aes_inv_sbox[(u8)w[i]] ^
+ ((u32)aes_inv_sbox[(u8)(w[(i + 3) % 4] >> 8)] << 8) ^
+ ((u32)aes_inv_sbox[(u8)(w[(i + 2) % 4] >> 16)] << 16) ^
+ ((u32)aes_inv_sbox[(u8)(w[(i + 1) % 4] >> 24)] << 24);
+}
+
+static void __maybe_unused aes_decrypt_generic(const u32 inv_rndkeys[],
+ int nrounds,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ const u32 *rkp = inv_rndkeys;
+ int n = nrounds - 1;
+ u32 w[4];
+
+ w[0] = get_unaligned_le32(&in[0]) ^ *rkp++;
+ w[1] = get_unaligned_le32(&in[4]) ^ *rkp++;
+ w[2] = get_unaligned_le32(&in[8]) ^ *rkp++;
+ w[3] = get_unaligned_le32(&in[12]) ^ *rkp++;
+
+ aes_prefetch(aes_dec_tab, sizeof(aes_dec_tab));
+
+ do {
+ u32 w0 = dec_quarterround(w, 0, *rkp++);
+ u32 w1 = dec_quarterround(w, 1, *rkp++);
+ u32 w2 = dec_quarterround(w, 2, *rkp++);
+ u32 w3 = dec_quarterround(w, 3, *rkp++);
+
+ w[0] = w0;
+ w[1] = w1;
+ w[2] = w2;
+ w[3] = w3;
+ } while (--n);
+
+ aes_prefetch(aes_inv_sbox, sizeof(aes_inv_sbox));
+ put_unaligned_le32(declast_quarterround(w, 0, *rkp++), &out[0]);
+ put_unaligned_le32(declast_quarterround(w, 1, *rkp++), &out[4]);
+ put_unaligned_le32(declast_quarterround(w, 2, *rkp++), &out[8]);
+ put_unaligned_le32(declast_quarterround(w, 3, *rkp++), &out[12]);
}
-EXPORT_SYMBOL(aes_encrypt);
-/**
- * aes_decrypt - Decrypt a single AES block
- * @ctx: Context struct containing the key schedule
- * @out: Buffer to store the plaintext
- * @in: Buffer containing the ciphertext
+/*
+ * Note: the aes_prepare*key_* names reflect the fact that the implementation
+ * might not actually expand the key. (The s390 code for example doesn't.)
+ * Where the key is expanded we use the more specific names aes_expandkey_*.
+ *
+ * aes_preparekey_arch() is passed an optional pointer 'inv_k' which points to
+ * the area to store the prepared decryption key. It will be NULL if the user
+ * is requesting encryption-only. aes_preparekey_arch() is also passed a valid
+ * 'key_len' and 'nrounds', corresponding to AES-128, AES-192, or AES-256.
*/
-void aes_decrypt(const struct crypto_aes_ctx *ctx, u8 *out, const u8 *in)
+#ifdef CONFIG_CRYPTO_LIB_AES_ARCH
+/* An arch-specific implementation of AES is available. Include it. */
+#include "aes.h" /* $(SRCARCH)/aes.h */
+#else
+/* No arch-specific implementation of AES is available. Use generic code. */
+
+static void aes_preparekey_arch(union aes_enckey_arch *k,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, int key_len, int nrounds)
{
- const u32 *rkp = ctx->key_dec + 4;
- int rounds = 6 + ctx->key_length / 4;
- u32 st0[4], st1[4];
- int round;
+ aes_expandkey_generic(k->rndkeys, inv_k ? inv_k->inv_rndkeys : NULL,
+ in_key, key_len);
+}
- st0[0] = ctx->key_dec[0] ^ get_unaligned_le32(in);
- st0[1] = ctx->key_dec[1] ^ get_unaligned_le32(in + 4);
- st0[2] = ctx->key_dec[2] ^ get_unaligned_le32(in + 8);
- st0[3] = ctx->key_dec[3] ^ get_unaligned_le32(in + 12);
+static void aes_encrypt_arch(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ aes_encrypt_generic(key->k.rndkeys, key->nrounds, out, in);
+}
- /*
- * Force the compiler to emit data independent Sbox references,
- * by xoring the input with Sbox values that are known to add up
- * to zero. This pulls the entire Sbox into the D-cache before any
- * data dependent lookups are done.
- */
- st0[0] ^= aes_inv_sbox[ 0] ^ aes_inv_sbox[ 64] ^ aes_inv_sbox[129] ^ aes_inv_sbox[200];
- st0[1] ^= aes_inv_sbox[16] ^ aes_inv_sbox[ 83] ^ aes_inv_sbox[150] ^ aes_inv_sbox[212];
- st0[2] ^= aes_inv_sbox[32] ^ aes_inv_sbox[ 96] ^ aes_inv_sbox[160] ^ aes_inv_sbox[236];
- st0[3] ^= aes_inv_sbox[48] ^ aes_inv_sbox[112] ^ aes_inv_sbox[187] ^ aes_inv_sbox[247];
-
- for (round = 0;; round += 2, rkp += 8) {
- st1[0] = inv_mix_columns(inv_subshift(st0, 0)) ^ rkp[0];
- st1[1] = inv_mix_columns(inv_subshift(st0, 1)) ^ rkp[1];
- st1[2] = inv_mix_columns(inv_subshift(st0, 2)) ^ rkp[2];
- st1[3] = inv_mix_columns(inv_subshift(st0, 3)) ^ rkp[3];
-
- if (round == rounds - 2)
- break;
-
- st0[0] = inv_mix_columns(inv_subshift(st1, 0)) ^ rkp[4];
- st0[1] = inv_mix_columns(inv_subshift(st1, 1)) ^ rkp[5];
- st0[2] = inv_mix_columns(inv_subshift(st1, 2)) ^ rkp[6];
- st0[3] = inv_mix_columns(inv_subshift(st1, 3)) ^ rkp[7];
- }
+static void aes_decrypt_arch(const struct aes_key *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ aes_decrypt_generic(key->inv_k.inv_rndkeys, key->nrounds, out, in);
+}
+#endif
- put_unaligned_le32(inv_subshift(st1, 0) ^ rkp[4], out);
- put_unaligned_le32(inv_subshift(st1, 1) ^ rkp[5], out + 4);
- put_unaligned_le32(inv_subshift(st1, 2) ^ rkp[6], out + 8);
- put_unaligned_le32(inv_subshift(st1, 3) ^ rkp[7], out + 12);
+static int __aes_preparekey(struct aes_enckey *enc_key,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, size_t key_len)
+{
+ if (aes_check_keylen(key_len) != 0)
+ return -EINVAL;
+ enc_key->len = key_len;
+ enc_key->nrounds = 6 + key_len / 4;
+ aes_preparekey_arch(&enc_key->k, inv_k, in_key, key_len,
+ enc_key->nrounds);
+ return 0;
+}
+
+int aes_preparekey(struct aes_key *key, const u8 *in_key, size_t key_len)
+{
+ return __aes_preparekey((struct aes_enckey *)key, &key->inv_k,
+ in_key, key_len);
+}
+EXPORT_SYMBOL(aes_preparekey);
+
+int aes_prepareenckey(struct aes_enckey *key, const u8 *in_key, size_t key_len)
+{
+ return __aes_preparekey(key, NULL, in_key, key_len);
+}
+EXPORT_SYMBOL(aes_prepareenckey);
+
+void aes_encrypt(aes_encrypt_arg key, u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ aes_encrypt_arch(key.enc_key, out, in);
+}
+EXPORT_SYMBOL(aes_encrypt);
+
+void aes_decrypt(const struct aes_key *key, u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ aes_decrypt_arch(key, out, in);
}
EXPORT_SYMBOL(aes_decrypt);
-MODULE_DESCRIPTION("Generic AES library");
+#ifdef aes_mod_init_arch
+static int __init aes_mod_init(void)
+{
+ aes_mod_init_arch();
+ return 0;
+}
+subsys_initcall(aes_mod_init);
+
+static void __exit aes_mod_exit(void)
+{
+}
+module_exit(aes_mod_exit);
+#endif
+
+MODULE_DESCRIPTION("AES block cipher");
MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
+MODULE_AUTHOR("Eric Biggers <ebiggers@kernel.org>");
MODULE_LICENSE("GPL v2");
diff --git a/lib/crypto/aescfb.c b/lib/crypto/aescfb.c
index 0f294c8cbf3c..147e5211728f 100644
--- a/lib/crypto/aescfb.c
+++ b/lib/crypto/aescfb.c
@@ -11,7 +11,7 @@
#include <linux/module.h>
#include <asm/irqflags.h>
-static void aescfb_encrypt_block(const struct crypto_aes_ctx *ctx, void *dst,
+static void aescfb_encrypt_block(const struct aes_enckey *key, void *dst,
const void *src)
{
unsigned long flags;
@@ -25,27 +25,27 @@ static void aescfb_encrypt_block(const struct crypto_aes_ctx *ctx, void *dst,
* interrupts disabled.
*/
local_irq_save(flags);
- aes_encrypt(ctx, dst, src);
+ aes_encrypt(key, dst, src);
local_irq_restore(flags);
}
/**
* aescfb_encrypt - Perform AES-CFB encryption on a block of data
*
- * @ctx: The AES-CFB key schedule
+ * @key: The AES-CFB key schedule
* @dst: Pointer to the ciphertext output buffer
* @src: Pointer the plaintext (may equal @dst for encryption in place)
* @len: The size in bytes of the plaintext and ciphertext.
* @iv: The initialization vector (IV) to use for this block of data
*/
-void aescfb_encrypt(const struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src,
+void aescfb_encrypt(const struct aes_enckey *key, u8 *dst, const u8 *src,
int len, const u8 iv[AES_BLOCK_SIZE])
{
u8 ks[AES_BLOCK_SIZE];
const u8 *v = iv;
while (len > 0) {
- aescfb_encrypt_block(ctx, ks, v);
+ aescfb_encrypt_block(key, ks, v);
crypto_xor_cpy(dst, src, ks, min(len, AES_BLOCK_SIZE));
v = dst;
@@ -61,18 +61,18 @@ EXPORT_SYMBOL(aescfb_encrypt);
/**
* aescfb_decrypt - Perform AES-CFB decryption on a block of data
*
- * @ctx: The AES-CFB key schedule
+ * @key: The AES-CFB key schedule
* @dst: Pointer to the plaintext output buffer
* @src: Pointer the ciphertext (may equal @dst for decryption in place)
* @len: The size in bytes of the plaintext and ciphertext.
* @iv: The initialization vector (IV) to use for this block of data
*/
-void aescfb_decrypt(const struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src,
+void aescfb_decrypt(const struct aes_enckey *key, u8 *dst, const u8 *src,
int len, const u8 iv[AES_BLOCK_SIZE])
{
u8 ks[2][AES_BLOCK_SIZE];
- aescfb_encrypt_block(ctx, ks[0], iv);
+ aescfb_encrypt_block(key, ks[0], iv);
for (int i = 0; len > 0; i ^= 1) {
if (len > AES_BLOCK_SIZE)
@@ -81,7 +81,7 @@ void aescfb_decrypt(const struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src,
* performing the XOR, as that may update in place and
* overwrite the ciphertext.
*/
- aescfb_encrypt_block(ctx, ks[!i], src);
+ aescfb_encrypt_block(key, ks[!i], src);
crypto_xor_cpy(dst, src, ks[i], min(len, AES_BLOCK_SIZE));
@@ -214,15 +214,15 @@ static struct {
static int __init libaescfb_init(void)
{
for (int i = 0; i < ARRAY_SIZE(aescfb_tv); i++) {
- struct crypto_aes_ctx ctx;
+ struct aes_enckey key;
u8 buf[64];
- if (aes_expandkey(&ctx, aescfb_tv[i].key, aescfb_tv[i].klen)) {
- pr_err("aes_expandkey() failed on vector %d\n", i);
+ if (aes_prepareenckey(&key, aescfb_tv[i].key, aescfb_tv[i].klen)) {
+ pr_err("aes_prepareenckey() failed on vector %d\n", i);
return -ENODEV;
}
- aescfb_encrypt(&ctx, buf, aescfb_tv[i].ptext, aescfb_tv[i].len,
+ aescfb_encrypt(&key, buf, aescfb_tv[i].ptext, aescfb_tv[i].len,
aescfb_tv[i].iv);
if (memcmp(buf, aescfb_tv[i].ctext, aescfb_tv[i].len)) {
pr_err("aescfb_encrypt() #1 failed on vector %d\n", i);
@@ -230,14 +230,14 @@ static int __init libaescfb_init(void)
}
/* decrypt in place */
- aescfb_decrypt(&ctx, buf, buf, aescfb_tv[i].len, aescfb_tv[i].iv);
+ aescfb_decrypt(&key, buf, buf, aescfb_tv[i].len, aescfb_tv[i].iv);
if (memcmp(buf, aescfb_tv[i].ptext, aescfb_tv[i].len)) {
pr_err("aescfb_decrypt() failed on vector %d\n", i);
return -ENODEV;
}
/* encrypt in place */
- aescfb_encrypt(&ctx, buf, buf, aescfb_tv[i].len, aescfb_tv[i].iv);
+ aescfb_encrypt(&key, buf, buf, aescfb_tv[i].len, aescfb_tv[i].iv);
if (memcmp(buf, aescfb_tv[i].ctext, aescfb_tv[i].len)) {
pr_err("aescfb_encrypt() #2 failed on vector %d\n", i);
diff --git a/lib/crypto/aesgcm.c b/lib/crypto/aesgcm.c
index ac0b2fcfd606..02f5b5f32c76 100644
--- a/lib/crypto/aesgcm.c
+++ b/lib/crypto/aesgcm.c
@@ -12,7 +12,7 @@
#include <linux/module.h>
#include <asm/irqflags.h>
-static void aesgcm_encrypt_block(const struct crypto_aes_ctx *ctx, void *dst,
+static void aesgcm_encrypt_block(const struct aes_enckey *key, void *dst,
const void *src)
{
unsigned long flags;
@@ -26,7 +26,7 @@ static void aesgcm_encrypt_block(const struct crypto_aes_ctx *ctx, void *dst,
* effective when running with interrupts disabled.
*/
local_irq_save(flags);
- aes_encrypt(ctx, dst, src);
+ aes_encrypt(key, dst, src);
local_irq_restore(flags);
}
@@ -49,12 +49,12 @@ int aesgcm_expandkey(struct aesgcm_ctx *ctx, const u8 *key,
int ret;
ret = crypto_gcm_check_authsize(authsize) ?:
- aes_expandkey(&ctx->aes_ctx, key, keysize);
+ aes_prepareenckey(&ctx->aes_key, key, keysize);
if (ret)
return ret;
ctx->authsize = authsize;
- aesgcm_encrypt_block(&ctx->aes_ctx, &ctx->ghash_key, kin);
+ aesgcm_encrypt_block(&ctx->aes_key, &ctx->ghash_key, kin);
return 0;
}
@@ -97,7 +97,7 @@ static void aesgcm_mac(const struct aesgcm_ctx *ctx, const u8 *src, int src_len,
aesgcm_ghash(&ghash, &ctx->ghash_key, &tail, sizeof(tail));
ctr[3] = cpu_to_be32(1);
- aesgcm_encrypt_block(&ctx->aes_ctx, buf, ctr);
+ aesgcm_encrypt_block(&ctx->aes_key, buf, ctr);
crypto_xor_cpy(authtag, buf, (u8 *)&ghash, ctx->authsize);
memzero_explicit(&ghash, sizeof(ghash));
@@ -119,7 +119,7 @@ static void aesgcm_crypt(const struct aesgcm_ctx *ctx, u8 *dst, const u8 *src,
* len', this cannot happen, so no explicit test is necessary.
*/
ctr[3] = cpu_to_be32(n++);
- aesgcm_encrypt_block(&ctx->aes_ctx, buf, ctr);
+ aesgcm_encrypt_block(&ctx->aes_key, buf, ctr);
crypto_xor_cpy(dst, src, buf, min(len, AES_BLOCK_SIZE));
dst += AES_BLOCK_SIZE;
diff --git a/lib/crypto/arm/aes-cipher-core.S b/lib/crypto/arm/aes-cipher-core.S
new file mode 100644
index 000000000000..87567d6822ba
--- /dev/null
+++ b/lib/crypto/arm/aes-cipher-core.S
@@ -0,0 +1,201 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Scalar AES core transform
+ *
+ * Copyright (C) 2017 Linaro Ltd.
+ * Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/cache.h>
+
+ .text
+ .align 5
+
+ rk .req r0
+ rounds .req r1
+ in .req r2
+ out .req r3
+ ttab .req ip
+
+ t0 .req lr
+ t1 .req r2
+ t2 .req r3
+
+ .macro __select, out, in, idx
+ .if __LINUX_ARM_ARCH__ < 7
+ and \out, \in, #0xff << (8 * \idx)
+ .else
+ ubfx \out, \in, #(8 * \idx), #8
+ .endif
+ .endm
+
+ .macro __load, out, in, idx, sz, op
+ .if __LINUX_ARM_ARCH__ < 7 && \idx > 0
+ ldr\op \out, [ttab, \in, lsr #(8 * \idx) - \sz]
+ .else
+ ldr\op \out, [ttab, \in, lsl #\sz]
+ .endif
+ .endm
+
+ .macro __hround, out0, out1, in0, in1, in2, in3, t3, t4, enc, sz, op, oldcpsr
+ __select \out0, \in0, 0
+ __select t0, \in1, 1
+ __load \out0, \out0, 0, \sz, \op
+ __load t0, t0, 1, \sz, \op
+
+ .if \enc
+ __select \out1, \in1, 0
+ __select t1, \in2, 1
+ .else
+ __select \out1, \in3, 0
+ __select t1, \in0, 1
+ .endif
+ __load \out1, \out1, 0, \sz, \op
+ __select t2, \in2, 2
+ __load t1, t1, 1, \sz, \op
+ __load t2, t2, 2, \sz, \op
+
+ eor \out0, \out0, t0, ror #24
+
+ __select t0, \in3, 3
+ .if \enc
+ __select \t3, \in3, 2
+ __select \t4, \in0, 3
+ .else
+ __select \t3, \in1, 2
+ __select \t4, \in2, 3
+ .endif
+ __load \t3, \t3, 2, \sz, \op
+ __load t0, t0, 3, \sz, \op
+ __load \t4, \t4, 3, \sz, \op
+
+ .ifnb \oldcpsr
+ /*
+ * This is the final round and we're done with all data-dependent table
+ * lookups, so we can safely re-enable interrupts.
+ */
+ restore_irqs \oldcpsr
+ .endif
+
+ eor \out1, \out1, t1, ror #24
+ eor \out0, \out0, t2, ror #16
+ ldm rk!, {t1, t2}
+ eor \out1, \out1, \t3, ror #16
+ eor \out0, \out0, t0, ror #8
+ eor \out1, \out1, \t4, ror #8
+ eor \out0, \out0, t1
+ eor \out1, \out1, t2
+ .endm
+
+ .macro fround, out0, out1, out2, out3, in0, in1, in2, in3, sz=2, op, oldcpsr
+ __hround \out0, \out1, \in0, \in1, \in2, \in3, \out2, \out3, 1, \sz, \op
+ __hround \out2, \out3, \in2, \in3, \in0, \in1, \in1, \in2, 1, \sz, \op, \oldcpsr
+ .endm
+
+ .macro iround, out0, out1, out2, out3, in0, in1, in2, in3, sz=2, op, oldcpsr
+ __hround \out0, \out1, \in0, \in3, \in2, \in1, \out2, \out3, 0, \sz, \op
+ __hround \out2, \out3, \in2, \in1, \in0, \in3, \in1, \in0, 0, \sz, \op, \oldcpsr
+ .endm
+
+ .macro do_crypt, round, ttab, ltab, bsz
+ push {r3-r11, lr}
+
+ // Load keys first, to reduce latency in case they're not cached yet.
+ ldm rk!, {r8-r11}
+
+ ldr r4, [in]
+ ldr r5, [in, #4]
+ ldr r6, [in, #8]
+ ldr r7, [in, #12]
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ rev_l r4, t0
+ rev_l r5, t0
+ rev_l r6, t0
+ rev_l r7, t0
+#endif
+
+ eor r4, r4, r8
+ eor r5, r5, r9
+ eor r6, r6, r10
+ eor r7, r7, r11
+
+ mov_l ttab, \ttab
+ /*
+ * Disable interrupts and prefetch the 1024-byte 'ft' or 'it' table into
+ * L1 cache, assuming cacheline size >= 32. This is a hardening measure
+ * intended to make cache-timing attacks more difficult. They may not
+ * be fully prevented, however; see the paper
+ * https://cr.yp.to/antiforgery/cachetiming-20050414.pdf
+ * ("Cache-timing attacks on AES") for a discussion of the many
+ * difficulties involved in writing truly constant-time AES software.
+ */
+ save_and_disable_irqs t0
+ .set i, 0
+ .rept 1024 / 128
+ ldr r8, [ttab, #i + 0]
+ ldr r9, [ttab, #i + 32]
+ ldr r10, [ttab, #i + 64]
+ ldr r11, [ttab, #i + 96]
+ .set i, i + 128
+ .endr
+ push {t0} // oldcpsr
+
+ tst rounds, #2
+ bne 1f
+
+0: \round r8, r9, r10, r11, r4, r5, r6, r7
+ \round r4, r5, r6, r7, r8, r9, r10, r11
+
+1: subs rounds, rounds, #4
+ \round r8, r9, r10, r11, r4, r5, r6, r7
+ bls 2f
+ \round r4, r5, r6, r7, r8, r9, r10, r11
+ b 0b
+
+2: .ifb \ltab
+ add ttab, ttab, #1
+ .else
+ mov_l ttab, \ltab
+ // Prefetch inverse S-box for final round; see explanation above
+ .set i, 0
+ .rept 256 / 64
+ ldr t0, [ttab, #i + 0]
+ ldr t1, [ttab, #i + 32]
+ .set i, i + 64
+ .endr
+ .endif
+
+ pop {rounds} // oldcpsr
+ \round r4, r5, r6, r7, r8, r9, r10, r11, \bsz, b, rounds
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ rev_l r4, t0
+ rev_l r5, t0
+ rev_l r6, t0
+ rev_l r7, t0
+#endif
+
+ ldr out, [sp]
+
+ str r4, [out]
+ str r5, [out, #4]
+ str r6, [out, #8]
+ str r7, [out, #12]
+
+ pop {r3-r11, pc}
+
+ .align 3
+ .ltorg
+ .endm
+
+ENTRY(__aes_arm_encrypt)
+ do_crypt fround, aes_enc_tab,, 2
+ENDPROC(__aes_arm_encrypt)
+
+ .align 5
+ENTRY(__aes_arm_decrypt)
+ do_crypt iround, aes_dec_tab, crypto_aes_inv_sbox, 0
+ENDPROC(__aes_arm_decrypt)
diff --git a/lib/crypto/arm/aes.h b/lib/crypto/arm/aes.h
new file mode 100644
index 000000000000..1dd7dfa657bb
--- /dev/null
+++ b/lib/crypto/arm/aes.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AES block cipher, optimized for ARM
+ *
+ * Copyright (C) 2017 Linaro Ltd.
+ * Copyright 2026 Google LLC
+ */
+
+asmlinkage void __aes_arm_encrypt(const u32 rk[], int rounds,
+ const u8 in[AES_BLOCK_SIZE],
+ u8 out[AES_BLOCK_SIZE]);
+asmlinkage void __aes_arm_decrypt(const u32 inv_rk[], int rounds,
+ const u8 in[AES_BLOCK_SIZE],
+ u8 out[AES_BLOCK_SIZE]);
+
+static void aes_preparekey_arch(union aes_enckey_arch *k,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, int key_len, int nrounds)
+{
+ aes_expandkey_generic(k->rndkeys, inv_k ? inv_k->inv_rndkeys : NULL,
+ in_key, key_len);
+}
+
+static void aes_encrypt_arch(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
+ !IS_ALIGNED((uintptr_t)out | (uintptr_t)in, 4)) {
+ u8 bounce_buf[AES_BLOCK_SIZE] __aligned(4);
+
+ memcpy(bounce_buf, in, AES_BLOCK_SIZE);
+ __aes_arm_encrypt(key->k.rndkeys, key->nrounds, bounce_buf,
+ bounce_buf);
+ memcpy(out, bounce_buf, AES_BLOCK_SIZE);
+ return;
+ }
+ __aes_arm_encrypt(key->k.rndkeys, key->nrounds, in, out);
+}
+
+static void aes_decrypt_arch(const struct aes_key *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
+ !IS_ALIGNED((uintptr_t)out | (uintptr_t)in, 4)) {
+ u8 bounce_buf[AES_BLOCK_SIZE] __aligned(4);
+
+ memcpy(bounce_buf, in, AES_BLOCK_SIZE);
+ __aes_arm_decrypt(key->inv_k.inv_rndkeys, key->nrounds,
+ bounce_buf, bounce_buf);
+ memcpy(out, bounce_buf, AES_BLOCK_SIZE);
+ return;
+ }
+ __aes_arm_decrypt(key->inv_k.inv_rndkeys, key->nrounds, in, out);
+}
diff --git a/lib/crypto/arm/nh-neon-core.S b/lib/crypto/arm/nh-neon-core.S
new file mode 100644
index 000000000000..01620a0782ca
--- /dev/null
+++ b/lib/crypto/arm/nh-neon-core.S
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NH - ε-almost-universal hash function, NEON accelerated version
+ *
+ * Copyright 2018 Google LLC
+ *
+ * Author: Eric Biggers <ebiggers@google.com>
+ */
+
+#include <linux/linkage.h>
+
+ .text
+ .fpu neon
+
+ KEY .req r0
+ MESSAGE .req r1
+ MESSAGE_LEN .req r2
+ HASH .req r3
+
+ PASS0_SUMS .req q0
+ PASS0_SUM_A .req d0
+ PASS0_SUM_B .req d1
+ PASS1_SUMS .req q1
+ PASS1_SUM_A .req d2
+ PASS1_SUM_B .req d3
+ PASS2_SUMS .req q2
+ PASS2_SUM_A .req d4
+ PASS2_SUM_B .req d5
+ PASS3_SUMS .req q3
+ PASS3_SUM_A .req d6
+ PASS3_SUM_B .req d7
+ K0 .req q4
+ K1 .req q5
+ K2 .req q6
+ K3 .req q7
+ T0 .req q8
+ T0_L .req d16
+ T0_H .req d17
+ T1 .req q9
+ T1_L .req d18
+ T1_H .req d19
+ T2 .req q10
+ T2_L .req d20
+ T2_H .req d21
+ T3 .req q11
+ T3_L .req d22
+ T3_H .req d23
+
+.macro _nh_stride k0, k1, k2, k3
+
+ // Load next message stride
+ vld1.8 {T3}, [MESSAGE]!
+
+ // Load next key stride
+ vld1.32 {\k3}, [KEY]!
+
+ // Add message words to key words
+ vadd.u32 T0, T3, \k0
+ vadd.u32 T1, T3, \k1
+ vadd.u32 T2, T3, \k2
+ vadd.u32 T3, T3, \k3
+
+ // Multiply 32x32 => 64 and accumulate
+ vmlal.u32 PASS0_SUMS, T0_L, T0_H
+ vmlal.u32 PASS1_SUMS, T1_L, T1_H
+ vmlal.u32 PASS2_SUMS, T2_L, T2_H
+ vmlal.u32 PASS3_SUMS, T3_L, T3_H
+.endm
+
+/*
+ * void nh_neon(const u32 *key, const u8 *message, size_t message_len,
+ * __le64 hash[NH_NUM_PASSES])
+ *
+ * It's guaranteed that message_len % 16 == 0.
+ */
+ENTRY(nh_neon)
+
+ vld1.32 {K0,K1}, [KEY]!
+ vmov.u64 PASS0_SUMS, #0
+ vmov.u64 PASS1_SUMS, #0
+ vld1.32 {K2}, [KEY]!
+ vmov.u64 PASS2_SUMS, #0
+ vmov.u64 PASS3_SUMS, #0
+
+ subs MESSAGE_LEN, MESSAGE_LEN, #64
+ blt .Lloop4_done
+.Lloop4:
+ _nh_stride K0, K1, K2, K3
+ _nh_stride K1, K2, K3, K0
+ _nh_stride K2, K3, K0, K1
+ _nh_stride K3, K0, K1, K2
+ subs MESSAGE_LEN, MESSAGE_LEN, #64
+ bge .Lloop4
+
+.Lloop4_done:
+ ands MESSAGE_LEN, MESSAGE_LEN, #63
+ beq .Ldone
+ _nh_stride K0, K1, K2, K3
+
+ subs MESSAGE_LEN, MESSAGE_LEN, #16
+ beq .Ldone
+ _nh_stride K1, K2, K3, K0
+
+ subs MESSAGE_LEN, MESSAGE_LEN, #16
+ beq .Ldone
+ _nh_stride K2, K3, K0, K1
+
+.Ldone:
+ // Sum the accumulators for each pass, then store the sums to 'hash'
+ vadd.u64 T0_L, PASS0_SUM_A, PASS0_SUM_B
+ vadd.u64 T0_H, PASS1_SUM_A, PASS1_SUM_B
+ vadd.u64 T1_L, PASS2_SUM_A, PASS2_SUM_B
+ vadd.u64 T1_H, PASS3_SUM_A, PASS3_SUM_B
+ vst1.8 {T0-T1}, [HASH]
+ bx lr
+ENDPROC(nh_neon)
diff --git a/lib/crypto/arm/nh.h b/lib/crypto/arm/nh.h
new file mode 100644
index 000000000000..c9f39d819336
--- /dev/null
+++ b/lib/crypto/arm/nh.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ARM32 accelerated implementation of NH
+ *
+ * Copyright 2018 Google LLC
+ */
+
+#include <asm/neon.h>
+#include <asm/simd.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
+
+asmlinkage void nh_neon(const u32 *key, const u8 *message, size_t message_len,
+ __le64 hash[NH_NUM_PASSES]);
+
+static bool nh_arch(const u32 *key, const u8 *message, size_t message_len,
+ __le64 hash[NH_NUM_PASSES])
+{
+ if (static_branch_likely(&have_neon) && message_len >= 64 &&
+ may_use_simd()) {
+ scoped_ksimd()
+ nh_neon(key, message, message_len, hash);
+ return true;
+ }
+ return false;
+}
+
+#define nh_mod_init_arch nh_mod_init_arch
+static void nh_mod_init_arch(void)
+{
+ if (elf_hwcap & HWCAP_NEON)
+ static_branch_enable(&have_neon);
+}
diff --git a/lib/crypto/arm64/aes-ce-core.S b/lib/crypto/arm64/aes-ce-core.S
new file mode 100644
index 000000000000..e52e13eb8fdb
--- /dev/null
+++ b/lib/crypto/arm64/aes-ce-core.S
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013 - 2017 Linaro Ltd <ard.biesheuvel@linaro.org>
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+ .arch armv8-a+crypto
+
+SYM_FUNC_START(__aes_ce_encrypt)
+ sub w3, w3, #2
+ ld1 {v0.16b}, [x2]
+ ld1 {v1.4s}, [x0], #16
+ cmp w3, #10
+ bmi 0f
+ bne 3f
+ mov v3.16b, v1.16b
+ b 2f
+0: mov v2.16b, v1.16b
+ ld1 {v3.4s}, [x0], #16
+1: aese v0.16b, v2.16b
+ aesmc v0.16b, v0.16b
+2: ld1 {v1.4s}, [x0], #16
+ aese v0.16b, v3.16b
+ aesmc v0.16b, v0.16b
+3: ld1 {v2.4s}, [x0], #16
+ subs w3, w3, #3
+ aese v0.16b, v1.16b
+ aesmc v0.16b, v0.16b
+ ld1 {v3.4s}, [x0], #16
+ bpl 1b
+ aese v0.16b, v2.16b
+ eor v0.16b, v0.16b, v3.16b
+ st1 {v0.16b}, [x1]
+ ret
+SYM_FUNC_END(__aes_ce_encrypt)
+
+SYM_FUNC_START(__aes_ce_decrypt)
+ sub w3, w3, #2
+ ld1 {v0.16b}, [x2]
+ ld1 {v1.4s}, [x0], #16
+ cmp w3, #10
+ bmi 0f
+ bne 3f
+ mov v3.16b, v1.16b
+ b 2f
+0: mov v2.16b, v1.16b
+ ld1 {v3.4s}, [x0], #16
+1: aesd v0.16b, v2.16b
+ aesimc v0.16b, v0.16b
+2: ld1 {v1.4s}, [x0], #16
+ aesd v0.16b, v3.16b
+ aesimc v0.16b, v0.16b
+3: ld1 {v2.4s}, [x0], #16
+ subs w3, w3, #3
+ aesd v0.16b, v1.16b
+ aesimc v0.16b, v0.16b
+ ld1 {v3.4s}, [x0], #16
+ bpl 1b
+ aesd v0.16b, v2.16b
+ eor v0.16b, v0.16b, v3.16b
+ st1 {v0.16b}, [x1]
+ ret
+SYM_FUNC_END(__aes_ce_decrypt)
+
+/*
+ * __aes_ce_sub() - use the aese instruction to perform the AES sbox
+ * substitution on each byte in 'input'
+ */
+SYM_FUNC_START(__aes_ce_sub)
+ dup v1.4s, w0
+ movi v0.16b, #0
+ aese v0.16b, v1.16b
+ umov w0, v0.s[0]
+ ret
+SYM_FUNC_END(__aes_ce_sub)
+
+SYM_FUNC_START(__aes_ce_invert)
+ ld1 {v0.4s}, [x1]
+ aesimc v1.16b, v0.16b
+ st1 {v1.4s}, [x0]
+ ret
+SYM_FUNC_END(__aes_ce_invert)
diff --git a/lib/crypto/arm64/aes-cipher-core.S b/lib/crypto/arm64/aes-cipher-core.S
new file mode 100644
index 000000000000..651f701c56a8
--- /dev/null
+++ b/lib/crypto/arm64/aes-cipher-core.S
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Scalar AES core transform
+ *
+ * Copyright (C) 2017 Linaro Ltd <ard.biesheuvel@linaro.org>
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/cache.h>
+
+ .text
+
+ rk .req x0
+ out .req x1
+ in .req x2
+ rounds .req x3
+ tt .req x2
+
+ .macro __pair1, sz, op, reg0, reg1, in0, in1e, in1d, shift
+ .ifc \op\shift, b0
+ ubfiz \reg0, \in0, #2, #8
+ ubfiz \reg1, \in1e, #2, #8
+ .else
+ ubfx \reg0, \in0, #\shift, #8
+ ubfx \reg1, \in1e, #\shift, #8
+ .endif
+
+ /*
+ * AArch64 cannot do byte size indexed loads from a table containing
+ * 32-bit quantities, i.e., 'ldrb w12, [tt, w12, uxtw #2]' is not a
+ * valid instruction. So perform the shift explicitly first for the
+ * high bytes (the low byte is shifted implicitly by using ubfiz rather
+ * than ubfx above)
+ */
+ .ifnc \op, b
+ ldr \reg0, [tt, \reg0, uxtw #2]
+ ldr \reg1, [tt, \reg1, uxtw #2]
+ .else
+ .if \shift > 0
+ lsl \reg0, \reg0, #2
+ lsl \reg1, \reg1, #2
+ .endif
+ ldrb \reg0, [tt, \reg0, uxtw]
+ ldrb \reg1, [tt, \reg1, uxtw]
+ .endif
+ .endm
+
+ .macro __pair0, sz, op, reg0, reg1, in0, in1e, in1d, shift
+ ubfx \reg0, \in0, #\shift, #8
+ ubfx \reg1, \in1d, #\shift, #8
+ ldr\op \reg0, [tt, \reg0, uxtw #\sz]
+ ldr\op \reg1, [tt, \reg1, uxtw #\sz]
+ .endm
+
+ .macro __hround, out0, out1, in0, in1, in2, in3, t0, t1, enc, sz, op
+ ldp \out0, \out1, [rk], #8
+
+ __pair\enc \sz, \op, w12, w13, \in0, \in1, \in3, 0
+ __pair\enc \sz, \op, w14, w15, \in1, \in2, \in0, 8
+ __pair\enc \sz, \op, w16, w17, \in2, \in3, \in1, 16
+ __pair\enc \sz, \op, \t0, \t1, \in3, \in0, \in2, 24
+
+ eor \out0, \out0, w12
+ eor \out1, \out1, w13
+ eor \out0, \out0, w14, ror #24
+ eor \out1, \out1, w15, ror #24
+ eor \out0, \out0, w16, ror #16
+ eor \out1, \out1, w17, ror #16
+ eor \out0, \out0, \t0, ror #8
+ eor \out1, \out1, \t1, ror #8
+ .endm
+
+ .macro fround, out0, out1, out2, out3, in0, in1, in2, in3, sz=2, op
+ __hround \out0, \out1, \in0, \in1, \in2, \in3, \out2, \out3, 1, \sz, \op
+ __hround \out2, \out3, \in2, \in3, \in0, \in1, \in1, \in2, 1, \sz, \op
+ .endm
+
+ .macro iround, out0, out1, out2, out3, in0, in1, in2, in3, sz=2, op
+ __hround \out0, \out1, \in0, \in3, \in2, \in1, \out2, \out3, 0, \sz, \op
+ __hround \out2, \out3, \in2, \in1, \in0, \in3, \in1, \in0, 0, \sz, \op
+ .endm
+
+ .macro do_crypt, round, ttab, ltab, bsz
+ ldp w4, w5, [in]
+ ldp w6, w7, [in, #8]
+ ldp w8, w9, [rk], #16
+ ldp w10, w11, [rk, #-8]
+
+CPU_BE( rev w4, w4 )
+CPU_BE( rev w5, w5 )
+CPU_BE( rev w6, w6 )
+CPU_BE( rev w7, w7 )
+
+ eor w4, w4, w8
+ eor w5, w5, w9
+ eor w6, w6, w10
+ eor w7, w7, w11
+
+ adr_l tt, \ttab
+
+ tbnz rounds, #1, 1f
+
+0: \round w8, w9, w10, w11, w4, w5, w6, w7
+ \round w4, w5, w6, w7, w8, w9, w10, w11
+
+1: subs rounds, rounds, #4
+ \round w8, w9, w10, w11, w4, w5, w6, w7
+ b.ls 3f
+2: \round w4, w5, w6, w7, w8, w9, w10, w11
+ b 0b
+3: adr_l tt, \ltab
+ \round w4, w5, w6, w7, w8, w9, w10, w11, \bsz, b
+
+CPU_BE( rev w4, w4 )
+CPU_BE( rev w5, w5 )
+CPU_BE( rev w6, w6 )
+CPU_BE( rev w7, w7 )
+
+ stp w4, w5, [out]
+ stp w6, w7, [out, #8]
+ ret
+ .endm
+
+SYM_FUNC_START(__aes_arm64_encrypt)
+ do_crypt fround, aes_enc_tab, aes_enc_tab + 1, 2
+SYM_FUNC_END(__aes_arm64_encrypt)
+
+ .align 5
+SYM_FUNC_START(__aes_arm64_decrypt)
+ do_crypt iround, aes_dec_tab, crypto_aes_inv_sbox, 0
+SYM_FUNC_END(__aes_arm64_decrypt)
diff --git a/lib/crypto/arm64/aes.h b/lib/crypto/arm64/aes.h
new file mode 100644
index 000000000000..63eea6271ef9
--- /dev/null
+++ b/lib/crypto/arm64/aes.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AES block cipher, optimized for ARM64
+ *
+ * Copyright (C) 2013 - 2017 Linaro Ltd <ard.biesheuvel@linaro.org>
+ * Copyright 2026 Google LLC
+ */
+
+#include <asm/neon.h>
+#include <asm/simd.h>
+#include <linux/unaligned.h>
+#include <linux/cpufeature.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_aes);
+
+struct aes_block {
+ u8 b[AES_BLOCK_SIZE];
+};
+
+asmlinkage void __aes_arm64_encrypt(const u32 rk[], u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE], int rounds);
+asmlinkage void __aes_arm64_decrypt(const u32 inv_rk[], u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE], int rounds);
+asmlinkage void __aes_ce_encrypt(const u32 rk[], u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE], int rounds);
+asmlinkage void __aes_ce_decrypt(const u32 inv_rk[], u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE], int rounds);
+asmlinkage u32 __aes_ce_sub(u32 l);
+asmlinkage void __aes_ce_invert(struct aes_block *out,
+ const struct aes_block *in);
+
+/*
+ * Expand an AES key using the crypto extensions if supported and usable or
+ * generic code otherwise. The expanded key format is compatible between the
+ * two cases. The outputs are @rndkeys (required) and @inv_rndkeys (optional).
+ */
+static void aes_expandkey_arm64(u32 rndkeys[], u32 *inv_rndkeys,
+ const u8 *in_key, int key_len, int nrounds)
+{
+ /*
+ * The AES key schedule round constants
+ */
+ static u8 const rcon[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
+ };
+
+ u32 kwords = key_len / sizeof(u32);
+ struct aes_block *key_enc, *key_dec;
+ int i, j;
+
+ if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) ||
+ !static_branch_likely(&have_aes) || unlikely(!may_use_simd())) {
+ aes_expandkey_generic(rndkeys, inv_rndkeys, in_key, key_len);
+ return;
+ }
+
+ for (i = 0; i < kwords; i++)
+ rndkeys[i] = get_unaligned_le32(&in_key[i * sizeof(u32)]);
+
+ scoped_ksimd() {
+ for (i = 0; i < sizeof(rcon); i++) {
+ u32 *rki = &rndkeys[i * kwords];
+ u32 *rko = rki + kwords;
+
+ rko[0] = ror32(__aes_ce_sub(rki[kwords - 1]), 8) ^
+ rcon[i] ^ rki[0];
+ rko[1] = rko[0] ^ rki[1];
+ rko[2] = rko[1] ^ rki[2];
+ rko[3] = rko[2] ^ rki[3];
+
+ if (key_len == AES_KEYSIZE_192) {
+ if (i >= 7)
+ break;
+ rko[4] = rko[3] ^ rki[4];
+ rko[5] = rko[4] ^ rki[5];
+ } else if (key_len == AES_KEYSIZE_256) {
+ if (i >= 6)
+ break;
+ rko[4] = __aes_ce_sub(rko[3]) ^ rki[4];
+ rko[5] = rko[4] ^ rki[5];
+ rko[6] = rko[5] ^ rki[6];
+ rko[7] = rko[6] ^ rki[7];
+ }
+ }
+
+ /*
+ * Generate the decryption keys for the Equivalent Inverse
+ * Cipher. This involves reversing the order of the round
+ * keys, and applying the Inverse Mix Columns transformation on
+ * all but the first and the last one.
+ */
+ if (inv_rndkeys) {
+ key_enc = (struct aes_block *)rndkeys;
+ key_dec = (struct aes_block *)inv_rndkeys;
+ j = nrounds;
+
+ key_dec[0] = key_enc[j];
+ for (i = 1, j--; j > 0; i++, j--)
+ __aes_ce_invert(key_dec + i, key_enc + j);
+ key_dec[i] = key_enc[0];
+ }
+ }
+}
+
+static void aes_preparekey_arch(union aes_enckey_arch *k,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, int key_len, int nrounds)
+{
+ aes_expandkey_arm64(k->rndkeys, inv_k ? inv_k->inv_rndkeys : NULL,
+ in_key, key_len, nrounds);
+}
+
+/*
+ * This is here temporarily until the remaining AES mode implementations are
+ * migrated from arch/arm64/crypto/ to lib/crypto/arm64/.
+ */
+int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
+ unsigned int key_len)
+{
+ if (aes_check_keylen(key_len) != 0)
+ return -EINVAL;
+ ctx->key_length = key_len;
+ aes_expandkey_arm64(ctx->key_enc, ctx->key_dec, in_key, key_len,
+ 6 + key_len / 4);
+ return 0;
+}
+EXPORT_SYMBOL(ce_aes_expandkey);
+
+static void aes_encrypt_arch(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) &&
+ static_branch_likely(&have_aes) && likely(may_use_simd())) {
+ scoped_ksimd()
+ __aes_ce_encrypt(key->k.rndkeys, out, in, key->nrounds);
+ } else {
+ __aes_arm64_encrypt(key->k.rndkeys, out, in, key->nrounds);
+ }
+}
+
+static void aes_decrypt_arch(const struct aes_key *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) &&
+ static_branch_likely(&have_aes) && likely(may_use_simd())) {
+ scoped_ksimd()
+ __aes_ce_decrypt(key->inv_k.inv_rndkeys, out, in,
+ key->nrounds);
+ } else {
+ __aes_arm64_decrypt(key->inv_k.inv_rndkeys, out, in,
+ key->nrounds);
+ }
+}
+
+#ifdef CONFIG_KERNEL_MODE_NEON
+#define aes_mod_init_arch aes_mod_init_arch
+static void aes_mod_init_arch(void)
+{
+ if (cpu_have_named_feature(AES))
+ static_branch_enable(&have_aes);
+}
+#endif /* CONFIG_KERNEL_MODE_NEON */
diff --git a/lib/crypto/arm64/nh-neon-core.S b/lib/crypto/arm64/nh-neon-core.S
new file mode 100644
index 000000000000..6fa57fce8085
--- /dev/null
+++ b/lib/crypto/arm64/nh-neon-core.S
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NH - ε-almost-universal hash function, ARM64 NEON accelerated version
+ *
+ * Copyright 2018 Google LLC
+ *
+ * Author: Eric Biggers <ebiggers@google.com>
+ */
+
+#include <linux/linkage.h>
+
+ KEY .req x0
+ MESSAGE .req x1
+ MESSAGE_LEN .req x2
+ HASH .req x3
+
+ PASS0_SUMS .req v0
+ PASS1_SUMS .req v1
+ PASS2_SUMS .req v2
+ PASS3_SUMS .req v3
+ K0 .req v4
+ K1 .req v5
+ K2 .req v6
+ K3 .req v7
+ T0 .req v8
+ T1 .req v9
+ T2 .req v10
+ T3 .req v11
+ T4 .req v12
+ T5 .req v13
+ T6 .req v14
+ T7 .req v15
+
+.macro _nh_stride k0, k1, k2, k3
+
+ // Load next message stride
+ ld1 {T3.16b}, [MESSAGE], #16
+
+ // Load next key stride
+ ld1 {\k3\().4s}, [KEY], #16
+
+ // Add message words to key words
+ add T0.4s, T3.4s, \k0\().4s
+ add T1.4s, T3.4s, \k1\().4s
+ add T2.4s, T3.4s, \k2\().4s
+ add T3.4s, T3.4s, \k3\().4s
+
+ // Multiply 32x32 => 64 and accumulate
+ mov T4.d[0], T0.d[1]
+ mov T5.d[0], T1.d[1]
+ mov T6.d[0], T2.d[1]
+ mov T7.d[0], T3.d[1]
+ umlal PASS0_SUMS.2d, T0.2s, T4.2s
+ umlal PASS1_SUMS.2d, T1.2s, T5.2s
+ umlal PASS2_SUMS.2d, T2.2s, T6.2s
+ umlal PASS3_SUMS.2d, T3.2s, T7.2s
+.endm
+
+/*
+ * void nh_neon(const u32 *key, const u8 *message, size_t message_len,
+ * __le64 hash[NH_NUM_PASSES])
+ *
+ * It's guaranteed that message_len % 16 == 0.
+ */
+SYM_FUNC_START(nh_neon)
+
+ ld1 {K0.4s,K1.4s}, [KEY], #32
+ movi PASS0_SUMS.2d, #0
+ movi PASS1_SUMS.2d, #0
+ ld1 {K2.4s}, [KEY], #16
+ movi PASS2_SUMS.2d, #0
+ movi PASS3_SUMS.2d, #0
+
+ subs MESSAGE_LEN, MESSAGE_LEN, #64
+ blt .Lloop4_done
+.Lloop4:
+ _nh_stride K0, K1, K2, K3
+ _nh_stride K1, K2, K3, K0
+ _nh_stride K2, K3, K0, K1
+ _nh_stride K3, K0, K1, K2
+ subs MESSAGE_LEN, MESSAGE_LEN, #64
+ bge .Lloop4
+
+.Lloop4_done:
+ ands MESSAGE_LEN, MESSAGE_LEN, #63
+ beq .Ldone
+ _nh_stride K0, K1, K2, K3
+
+ subs MESSAGE_LEN, MESSAGE_LEN, #16
+ beq .Ldone
+ _nh_stride K1, K2, K3, K0
+
+ subs MESSAGE_LEN, MESSAGE_LEN, #16
+ beq .Ldone
+ _nh_stride K2, K3, K0, K1
+
+.Ldone:
+ // Sum the accumulators for each pass, then store the sums to 'hash'
+ addp T0.2d, PASS0_SUMS.2d, PASS1_SUMS.2d
+ addp T1.2d, PASS2_SUMS.2d, PASS3_SUMS.2d
+ st1 {T0.16b,T1.16b}, [HASH]
+ ret
+SYM_FUNC_END(nh_neon)
diff --git a/lib/crypto/arm64/nh.h b/lib/crypto/arm64/nh.h
new file mode 100644
index 000000000000..08902630bdd1
--- /dev/null
+++ b/lib/crypto/arm64/nh.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ARM64 accelerated implementation of NH
+ *
+ * Copyright 2018 Google LLC
+ */
+
+#include <asm/hwcap.h>
+#include <asm/simd.h>
+#include <linux/cpufeature.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
+
+asmlinkage void nh_neon(const u32 *key, const u8 *message, size_t message_len,
+ __le64 hash[NH_NUM_PASSES]);
+
+static bool nh_arch(const u32 *key, const u8 *message, size_t message_len,
+ __le64 hash[NH_NUM_PASSES])
+{
+ if (static_branch_likely(&have_neon) && message_len >= 64 &&
+ may_use_simd()) {
+ scoped_ksimd()
+ nh_neon(key, message, message_len, hash);
+ return true;
+ }
+ return false;
+}
+
+#define nh_mod_init_arch nh_mod_init_arch
+static void nh_mod_init_arch(void)
+{
+ if (cpu_have_named_feature(ASIMD))
+ static_branch_enable(&have_neon);
+}
diff --git a/lib/crypto/fips-mldsa.h b/lib/crypto/fips-mldsa.h
new file mode 100644
index 000000000000..1b9a60a59e68
--- /dev/null
+++ b/lib/crypto/fips-mldsa.h
@@ -0,0 +1,458 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* ML-DSA test vector extracted from leancrypto */
+
+#include <linux/fips.h>
+
+static const u8 fips_test_mldsa65_signature[] __initconst __maybe_unused = {
+ 0xda, 0xcf, 0x8d, 0x67, 0x59, 0x60, 0x6c, 0x39, 0x2d, 0x89, 0xb6, 0xa1,
+ 0xf3, 0x8c, 0x70, 0xcf, 0x25, 0x86, 0x21, 0xa1, 0x9f, 0x20, 0x9e, 0xf5,
+ 0xd2, 0xdd, 0xbd, 0x99, 0xfa, 0xe4, 0xab, 0x77, 0x31, 0x65, 0x18, 0xa1,
+ 0xd1, 0x3f, 0x21, 0x70, 0x36, 0xe1, 0xf9, 0x5c, 0x28, 0xb6, 0x7d, 0x34,
+ 0xae, 0x66, 0xc9, 0x1c, 0x8e, 0xc6, 0xf9, 0x45, 0x8c, 0xa9, 0xb2, 0xfb,
+ 0x0f, 0x5b, 0xb8, 0xf9, 0xf5, 0xe2, 0x37, 0x79, 0x12, 0xda, 0xa7, 0x72,
+ 0x9e, 0x0d, 0xf8, 0x88, 0x5b, 0x34, 0x49, 0x6c, 0xed, 0xa3, 0x7f, 0x86,
+ 0xd3, 0xd9, 0x2f, 0x44, 0x08, 0x0d, 0xb7, 0xdb, 0x4a, 0xce, 0x02, 0x14,
+ 0x02, 0xd6, 0x40, 0x75, 0xe3, 0xc0, 0x97, 0xfc, 0x6c, 0x6a, 0x88, 0x29,
+ 0x0c, 0xe2, 0x3a, 0x2b, 0x28, 0x82, 0x8f, 0x27, 0x09, 0x69, 0x91, 0xc6,
+ 0xc3, 0xb7, 0x07, 0x61, 0x86, 0x8d, 0x89, 0x8a, 0xd5, 0x00, 0x3b, 0x4b,
+ 0xfc, 0x6f, 0xb3, 0x3f, 0x4c, 0x93, 0x31, 0xfc, 0x88, 0x53, 0x26, 0xea,
+ 0xe5, 0x3a, 0xfc, 0xc1, 0x59, 0x16, 0xf0, 0xb7, 0xac, 0xde, 0x1e, 0xd8,
+ 0x74, 0x85, 0x72, 0xd9, 0xbb, 0xbe, 0x76, 0x32, 0x25, 0x9d, 0x21, 0xbc,
+ 0xfd, 0x8d, 0x32, 0xfe, 0xae, 0x24, 0xe5, 0x4a, 0xcc, 0x5d, 0x15, 0x23,
+ 0xd3, 0x57, 0xe7, 0xa9, 0x2c, 0x31, 0xd7, 0xc5, 0x6b, 0x70, 0x6c, 0x22,
+ 0x5a, 0x13, 0x1f, 0x76, 0x13, 0x78, 0x6f, 0xac, 0x42, 0x4c, 0x46, 0x81,
+ 0xa2, 0x20, 0x91, 0x30, 0xed, 0xcb, 0x90, 0xfe, 0x3c, 0xa3, 0xc7, 0xb4,
+ 0x1f, 0x21, 0x1d, 0x98, 0x74, 0x6a, 0x3e, 0xc8, 0xcc, 0xd2, 0x68, 0x87,
+ 0x69, 0xa9, 0xdf, 0x50, 0xd5, 0x0a, 0x8e, 0x10, 0x54, 0xab, 0xea, 0x65,
+ 0x2a, 0x52, 0xd7, 0x22, 0xae, 0x2f, 0x1e, 0xc3, 0x16, 0x58, 0x20, 0x18,
+ 0x6d, 0x35, 0x46, 0x31, 0x43, 0x5d, 0x62, 0xfb, 0xb1, 0x47, 0x32, 0xfa,
+ 0x14, 0xcc, 0x51, 0xa3, 0xcd, 0x99, 0x4f, 0x97, 0x0f, 0xca, 0x24, 0x93,
+ 0x17, 0xea, 0xa3, 0xf3, 0x1f, 0xbe, 0xb5, 0xa3, 0xac, 0x80, 0xcc, 0x20,
+ 0x3b, 0xa6, 0xd3, 0x32, 0x72, 0x4e, 0xd9, 0x25, 0xf9, 0xc2, 0x24, 0x15,
+ 0xbd, 0x1e, 0x1e, 0x41, 0x8c, 0x18, 0x8c, 0x58, 0xe8, 0x75, 0x20, 0xff,
+ 0xa3, 0xf4, 0xd4, 0xab, 0x75, 0x78, 0x4e, 0xbb, 0x7c, 0x94, 0x93, 0x28,
+ 0x5b, 0x07, 0x3a, 0x3c, 0xc9, 0xf1, 0x55, 0x3e, 0x33, 0xed, 0xf8, 0x72,
+ 0x55, 0xab, 0x5a, 0xea, 0xbe, 0x65, 0xfa, 0x81, 0x50, 0xc0, 0x9d, 0x2d,
+ 0xfb, 0x04, 0x25, 0x7c, 0xb9, 0xee, 0xe2, 0xa3, 0x00, 0x44, 0xd3, 0x9d,
+ 0xee, 0x4f, 0x80, 0x77, 0xfb, 0x26, 0x6b, 0x07, 0xd0, 0xff, 0x82, 0x39,
+ 0x0e, 0x2b, 0x47, 0xa3, 0xe7, 0x3e, 0xc5, 0x4e, 0x15, 0x8a, 0x48, 0x28,
+ 0xfb, 0xf7, 0xa4, 0x86, 0xfb, 0x77, 0x60, 0xcd, 0xc5, 0x68, 0x96, 0xd7,
+ 0x4c, 0x3c, 0xf2, 0x51, 0x71, 0x79, 0x2e, 0x2e, 0x57, 0x10, 0xa7, 0xfc,
+ 0xd1, 0xd4, 0x61, 0x71, 0x81, 0x85, 0x74, 0x09, 0x7d, 0x80, 0xd0, 0xc2,
+ 0xe9, 0xff, 0xb7, 0x88, 0x53, 0x74, 0x1e, 0xb0, 0xca, 0x65, 0x48, 0x8e,
+ 0xdb, 0x59, 0x3a, 0xcb, 0x80, 0xeb, 0xfd, 0xd2, 0xc9, 0x38, 0x43, 0xae,
+ 0x76, 0xf2, 0xbb, 0x51, 0xb2, 0xcb, 0xe6, 0x85, 0x31, 0xb5, 0x62, 0xd4,
+ 0x5e, 0x48, 0x08, 0xf1, 0x40, 0x5b, 0x16, 0x83, 0x5e, 0xa5, 0x9c, 0x6b,
+ 0x91, 0x49, 0x44, 0xff, 0x3b, 0xa9, 0x2b, 0xf3, 0x06, 0x33, 0x9e, 0x6e,
+ 0x3c, 0x66, 0x7e, 0x27, 0xa2, 0x59, 0x7b, 0xe3, 0xb6, 0xb4, 0x28, 0xeb,
+ 0x93, 0x35, 0x87, 0xac, 0x0e, 0x0b, 0x7e, 0xbc, 0x35, 0x28, 0x72, 0x1f,
+ 0x26, 0x59, 0xd0, 0x1f, 0x63, 0xe4, 0x86, 0x5d, 0x70, 0xf3, 0xa8, 0xa4,
+ 0xb8, 0xcd, 0xb3, 0xf8, 0x8d, 0xaa, 0x41, 0xd2, 0xcc, 0x0b, 0x15, 0x66,
+ 0x22, 0x83, 0x92, 0xe3, 0x0b, 0xf9, 0xea, 0xa0, 0x33, 0xa1, 0x4e, 0x92,
+ 0xae, 0x81, 0x95, 0xa4, 0x58, 0x3f, 0xa9, 0x15, 0x52, 0xf9, 0xda, 0xb7,
+ 0x10, 0x8d, 0xc6, 0xab, 0x77, 0xe9, 0xbe, 0xad, 0xc9, 0x3a, 0x6a, 0x8d,
+ 0x92, 0x6c, 0x69, 0xff, 0x31, 0x49, 0x25, 0x04, 0xc8, 0x93, 0x6f, 0xc8,
+ 0xe7, 0x60, 0x7a, 0x76, 0xb5, 0xc1, 0x07, 0xef, 0xa3, 0x39, 0xa6, 0xf2,
+ 0x36, 0x04, 0xde, 0x3c, 0x4a, 0x4e, 0x96, 0xbd, 0x64, 0x26, 0x80, 0x01,
+ 0x88, 0x47, 0xd2, 0xa4, 0x46, 0xcd, 0xe1, 0x30, 0x7f, 0xa3, 0x00, 0x11,
+ 0x38, 0x55, 0xfa, 0xeb, 0x10, 0xeb, 0xa0, 0x65, 0x04, 0x09, 0xc8, 0xde,
+ 0x9c, 0x73, 0xba, 0x0c, 0xbd, 0xd3, 0xa5, 0x84, 0x5e, 0xb9, 0x3b, 0xd4,
+ 0x94, 0xbd, 0xa6, 0x53, 0xbe, 0x93, 0x69, 0x3e, 0xaa, 0x32, 0x31, 0x06,
+ 0xc8, 0x1b, 0x4a, 0x48, 0xb5, 0x17, 0x85, 0xbf, 0x72, 0xec, 0xf5, 0x29,
+ 0x8a, 0xd8, 0xeb, 0x99, 0x8b, 0x74, 0x84, 0x57, 0x8c, 0xe1, 0x85, 0x94,
+ 0xa0, 0xbc, 0x7a, 0x14, 0xf0, 0xf4, 0x8b, 0x25, 0x37, 0x43, 0xa1, 0x34,
+ 0x09, 0x71, 0xca, 0x5c, 0x9f, 0x08, 0x38, 0xd9, 0x9c, 0x0c, 0x0e, 0xcb,
+ 0xe4, 0xad, 0x4b, 0x2a, 0x89, 0x67, 0xf8, 0x29, 0x6c, 0x69, 0x0e, 0x5d,
+ 0xca, 0xfa, 0xa6, 0x6b, 0x0e, 0xb5, 0x94, 0x17, 0x71, 0xf0, 0xc9, 0xcd,
+ 0x02, 0x1d, 0xa5, 0xd5, 0xc6, 0xa7, 0xbc, 0x5f, 0x6e, 0x67, 0x43, 0x68,
+ 0xce, 0xac, 0x54, 0x81, 0x2a, 0x25, 0x22, 0x52, 0x35, 0xad, 0x7b, 0xd5,
+ 0x06, 0x8c, 0x00, 0xfb, 0xca, 0xc4, 0x0a, 0x49, 0x1e, 0xc8, 0xeb, 0x77,
+ 0xc1, 0x63, 0x23, 0x96, 0xbd, 0x35, 0xfa, 0x13, 0xae, 0xbf, 0x1d, 0x1e,
+ 0x69, 0x8d, 0xb3, 0xe3, 0x07, 0xde, 0x4e, 0xd0, 0x12, 0xa9, 0xc3, 0x36,
+ 0x30, 0x46, 0xef, 0x92, 0x76, 0x17, 0x8f, 0x10, 0xe7, 0xba, 0x99, 0x4b,
+ 0xdf, 0xad, 0xb8, 0x11, 0x80, 0xdf, 0xe7, 0xfd, 0x80, 0x64, 0xf7, 0x2a,
+ 0xac, 0x60, 0x2a, 0x54, 0x8f, 0x4f, 0xaf, 0xaf, 0x60, 0xf9, 0x67, 0x20,
+ 0x80, 0x53, 0x5c, 0xb6, 0x81, 0xa6, 0x2a, 0x74, 0x2d, 0xc5, 0x74, 0x2a,
+ 0x95, 0x26, 0x13, 0x17, 0x01, 0xdd, 0x31, 0xac, 0x5a, 0x05, 0xda, 0xde,
+ 0xba, 0xf6, 0x37, 0x13, 0x8d, 0xe4, 0xa8, 0x93, 0x46, 0x9e, 0xa9, 0x82,
+ 0x24, 0x7e, 0xc8, 0xda, 0x63, 0x89, 0xcd, 0x33, 0xc9, 0xf7, 0xf9, 0x71,
+ 0x35, 0xe6, 0xa5, 0x5f, 0x6b, 0x3b, 0xbb, 0x0c, 0xe0, 0xa4, 0x0b, 0xe3,
+ 0x29, 0xc0, 0xae, 0x8e, 0xce, 0x03, 0x09, 0x73, 0x0e, 0x1e, 0x9c, 0xe9,
+ 0x59, 0xb6, 0x8b, 0x78, 0x67, 0x32, 0x8b, 0xf1, 0x93, 0xcc, 0x72, 0x1b,
+ 0x6f, 0xa2, 0xf1, 0x04, 0x9c, 0xfa, 0x98, 0x02, 0xca, 0xdf, 0x35, 0x3c,
+ 0x38, 0xac, 0xa8, 0xdb, 0x90, 0xae, 0xaa, 0xf9, 0x70, 0xfb, 0xed, 0xbd,
+ 0xa6, 0x25, 0x14, 0x58, 0x09, 0x8a, 0x36, 0xaf, 0x41, 0x09, 0x19, 0xcb,
+ 0xd3, 0x25, 0x5d, 0x0e, 0xe6, 0x20, 0x14, 0x71, 0x24, 0x79, 0x19, 0x55,
+ 0xaf, 0x51, 0x5b, 0xa4, 0xc0, 0x93, 0x9e, 0xdd, 0x88, 0x31, 0x13, 0x96,
+ 0xbf, 0xca, 0x0a, 0xd7, 0xbc, 0xc4, 0x00, 0xa1, 0x10, 0x2d, 0x92, 0x79,
+ 0xf9, 0x14, 0xdb, 0xd2, 0xba, 0x74, 0xfa, 0xa8, 0xe5, 0x40, 0x14, 0xc2,
+ 0x56, 0x3c, 0x7f, 0x50, 0x07, 0x60, 0x86, 0x93, 0x51, 0x2e, 0xf9, 0x70,
+ 0x61, 0x70, 0x0e, 0xa4, 0x87, 0x75, 0xcc, 0x6c, 0x72, 0xb7, 0x68, 0x23,
+ 0xb7, 0x3d, 0x76, 0xaf, 0x96, 0x9b, 0x4a, 0xe5, 0x12, 0x28, 0x4a, 0x8f,
+ 0x79, 0x34, 0xff, 0xec, 0x92, 0xeb, 0x6b, 0xaf, 0xc9, 0xbd, 0xc1, 0x77,
+ 0x07, 0xd0, 0xfa, 0x55, 0x57, 0x10, 0x0c, 0xad, 0x29, 0x2a, 0x79, 0xd6,
+ 0x09, 0x9e, 0x7d, 0x18, 0xd4, 0xd6, 0xdd, 0x72, 0x1a, 0x8f, 0x24, 0x11,
+ 0x70, 0xd2, 0x52, 0x36, 0x0f, 0x38, 0x79, 0x38, 0x4a, 0x02, 0x4f, 0x73,
+ 0x2a, 0xaa, 0x6a, 0xb5, 0x0c, 0x72, 0x32, 0x85, 0x21, 0x76, 0x1a, 0x8a,
+ 0x7d, 0x51, 0x0e, 0xf1, 0xf9, 0x19, 0xfa, 0x6b, 0x9b, 0x22, 0x71, 0x8c,
+ 0x13, 0xcc, 0xba, 0x7d, 0xee, 0xd8, 0x34, 0xf6, 0x85, 0x60, 0xe1, 0xe4,
+ 0x59, 0x6e, 0x32, 0x60, 0xd9, 0xfa, 0xb7, 0x56, 0x54, 0x25, 0xd1, 0x73,
+ 0x6a, 0xf2, 0xa0, 0xc7, 0xa0, 0x67, 0x10, 0x89, 0x9c, 0x27, 0x5f, 0x7f,
+ 0x2e, 0x5a, 0x29, 0x70, 0x7a, 0x7b, 0xaf, 0x21, 0xd0, 0xf4, 0x06, 0xb9,
+ 0x2d, 0xf1, 0xb8, 0x32, 0xed, 0xc5, 0xc9, 0xac, 0x2f, 0x54, 0x0a, 0xf9,
+ 0x08, 0x39, 0x39, 0x7d, 0x1d, 0xaf, 0xb4, 0x5f, 0x4d, 0x75, 0xc3, 0xe8,
+ 0x52, 0x3a, 0x47, 0x72, 0x2c, 0xa9, 0x2d, 0xcb, 0x74, 0x06, 0xfe, 0x69,
+ 0xd3, 0xf3, 0x1a, 0xb2, 0xd3, 0x01, 0xed, 0x6c, 0xc1, 0xca, 0x4f, 0xaf,
+ 0x11, 0x9b, 0xa2, 0x27, 0x2a, 0x59, 0x56, 0x58, 0xdf, 0x79, 0x8b, 0xc9,
+ 0x87, 0xe9, 0x58, 0x81, 0x48, 0xc6, 0xb6, 0x7d, 0x60, 0x54, 0x87, 0x9c,
+ 0x61, 0xbb, 0x4b, 0xbb, 0x61, 0xac, 0x0a, 0x5a, 0x66, 0x7e, 0x70, 0x8b,
+ 0xfd, 0x92, 0x76, 0x4a, 0xa9, 0xa5, 0xc3, 0xf4, 0xf2, 0x93, 0x48, 0xc4,
+ 0xf3, 0x91, 0x2b, 0x60, 0x04, 0x0e, 0xb0, 0x6b, 0x60, 0x5e, 0xf0, 0xf1,
+ 0x54, 0x41, 0x56, 0xdc, 0x25, 0x57, 0xc3, 0xb6, 0x0b, 0x5e, 0x15, 0xb5,
+ 0x2a, 0x36, 0x4f, 0xe7, 0x1d, 0x70, 0xa8, 0xa7, 0xec, 0xd6, 0x74, 0xba,
+ 0xa4, 0x79, 0x83, 0x7c, 0x9e, 0x1a, 0x5d, 0x32, 0xc8, 0xcb, 0x41, 0xca,
+ 0x04, 0xec, 0x0b, 0x18, 0x54, 0xe1, 0x67, 0xbf, 0xa8, 0x7a, 0xc3, 0x0f,
+ 0x27, 0x2a, 0xaf, 0x2a, 0x41, 0x19, 0x1f, 0xe8, 0xa2, 0xe8, 0xfa, 0xfc,
+ 0x88, 0x41, 0x46, 0xc3, 0x1c, 0x44, 0xe5, 0xee, 0x47, 0xec, 0xfe, 0xbf,
+ 0xb8, 0x29, 0x2e, 0xae, 0x47, 0x0a, 0x42, 0x69, 0x8a, 0x9a, 0x94, 0x97,
+ 0x9e, 0xf5, 0xb6, 0x37, 0x1c, 0x10, 0xc2, 0x99, 0xa8, 0xe9, 0x9e, 0x0e,
+ 0x6e, 0xb5, 0xbe, 0xba, 0x1f, 0x77, 0xa6, 0x35, 0x02, 0x1e, 0x8c, 0xe6,
+ 0x02, 0x53, 0xe2, 0x9a, 0xdd, 0x09, 0x6e, 0x9b, 0x7a, 0x36, 0x4f, 0x38,
+ 0x8d, 0x4c, 0xa4, 0xb4, 0xff, 0x90, 0x76, 0x0d, 0x11, 0x7d, 0xe1, 0xe9,
+ 0x7f, 0x2a, 0x4a, 0x80, 0xe0, 0xd8, 0x3c, 0x23, 0xd2, 0xa5, 0xe5, 0x39,
+ 0x77, 0xbf, 0x3d, 0x71, 0x0d, 0x45, 0xbb, 0x39, 0x66, 0x1a, 0x4d, 0x59,
+ 0xb7, 0xd0, 0x0a, 0xee, 0x87, 0xee, 0x1f, 0xcf, 0x6f, 0xc2, 0x50, 0xb1,
+ 0xa5, 0x4c, 0xee, 0x40, 0x69, 0xd7, 0x36, 0x38, 0x14, 0xcd, 0x6a, 0x9a,
+ 0x90, 0x40, 0xad, 0x76, 0xf1, 0xa6, 0xd4, 0x3c, 0x75, 0x10, 0xba, 0xcb,
+ 0xab, 0x22, 0x28, 0x5f, 0x0c, 0xe0, 0xee, 0xf4, 0xfd, 0x61, 0x52, 0x0a,
+ 0x59, 0xfe, 0x61, 0xc5, 0x40, 0xf9, 0x91, 0x8e, 0x36, 0x29, 0x63, 0x6c,
+ 0x6e, 0x45, 0xa5, 0x42, 0xe3, 0x36, 0x90, 0xe7, 0x90, 0x9f, 0x58, 0xbb,
+ 0xf9, 0x1b, 0xee, 0x2c, 0xbb, 0x3a, 0xfd, 0x3d, 0xbe, 0x3d, 0x45, 0xf0,
+ 0xc2, 0x18, 0xaa, 0x46, 0x10, 0x23, 0xe9, 0x63, 0xba, 0x7f, 0xc2, 0xe1,
+ 0xf4, 0x05, 0xdd, 0x4a, 0x7c, 0xa8, 0xab, 0xa9, 0xbd, 0x6f, 0xdf, 0x48,
+ 0x59, 0x11, 0xd4, 0xba, 0x75, 0xb6, 0x22, 0xd4, 0xd7, 0x35, 0x6f, 0x27,
+ 0x70, 0xc7, 0x3d, 0x90, 0x06, 0x39, 0x2a, 0x16, 0xd0, 0x8b, 0xd7, 0xfb,
+ 0x5e, 0x85, 0x2e, 0xb0, 0xd8, 0xc7, 0xdb, 0xe5, 0x24, 0x3a, 0x6e, 0xc4,
+ 0x5e, 0xd4, 0x22, 0x25, 0x14, 0xee, 0xa5, 0x30, 0x8b, 0xd6, 0x27, 0x61,
+ 0x33, 0x13, 0x46, 0x0b, 0x26, 0x45, 0xa6, 0xb4, 0xfa, 0x8d, 0xa3, 0xf2,
+ 0x27, 0xd2, 0xc5, 0x04, 0xaa, 0x96, 0xa4, 0x55, 0xfa, 0x40, 0xf1, 0xfc,
+ 0x66, 0x33, 0x9e, 0x4b, 0x39, 0x75, 0xae, 0x7f, 0x52, 0x87, 0x7b, 0x8a,
+ 0xf9, 0x7d, 0x5f, 0x8a, 0x7e, 0xf7, 0xfe, 0xc4, 0x7f, 0xf4, 0xf6, 0x9a,
+ 0x86, 0x78, 0x21, 0x02, 0x94, 0x9e, 0x50, 0x2d, 0xdc, 0xd6, 0xa5, 0x53,
+ 0xf1, 0xef, 0x06, 0xe8, 0xb5, 0x46, 0x81, 0xcc, 0x91, 0x4f, 0x37, 0xee,
+ 0x27, 0xcb, 0x91, 0xad, 0xff, 0x1d, 0xd1, 0x00, 0xa8, 0x96, 0x22, 0xaa,
+ 0x63, 0x23, 0x2a, 0x7a, 0x75, 0x6f, 0xe9, 0x2d, 0x26, 0xde, 0x11, 0x97,
+ 0x4b, 0x17, 0x3f, 0xde, 0x51, 0x1a, 0x22, 0xed, 0x38, 0x6f, 0x3e, 0x7a,
+ 0xd0, 0xd6, 0x60, 0x06, 0x7e, 0x3f, 0xa4, 0x29, 0xfa, 0x18, 0x91, 0xda,
+ 0x73, 0x38, 0xe3, 0xe3, 0xb5, 0xc0, 0x5b, 0x4e, 0xe8, 0x94, 0xea, 0x45,
+ 0x6e, 0x5b, 0x50, 0xaa, 0x38, 0xb6, 0x6f, 0xdb, 0x90, 0x1b, 0x3b, 0x82,
+ 0xbb, 0x0d, 0x38, 0xe3, 0xca, 0xd9, 0xf1, 0x2e, 0x27, 0x4c, 0x2c, 0x5a,
+ 0x42, 0xdf, 0x44, 0xc8, 0x07, 0xe4, 0x95, 0xb5, 0xec, 0x91, 0x34, 0x1c,
+ 0x9a, 0x0c, 0x50, 0x1a, 0xce, 0x67, 0xe4, 0x4b, 0x87, 0x61, 0x43, 0x95,
+ 0x95, 0xb8, 0x8a, 0xf4, 0xc9, 0x92, 0x33, 0x33, 0xe3, 0xfe, 0x98, 0x2a,
+ 0xae, 0x8e, 0xf2, 0x6b, 0x13, 0x7c, 0xe4, 0x44, 0x40, 0x66, 0xea, 0x0c,
+ 0xe4, 0xdb, 0x16, 0x65, 0xa8, 0x8b, 0x37, 0x08, 0xec, 0x1e, 0xfc, 0xa6,
+ 0xd0, 0x9b, 0x9e, 0x0a, 0xd2, 0xe3, 0xcf, 0x5d, 0xb2, 0xaf, 0x8e, 0x05,
+ 0x7d, 0x8d, 0x84, 0xbc, 0x9f, 0xb1, 0xe6, 0x6a, 0x2e, 0x4b, 0x6d, 0x64,
+ 0x91, 0x17, 0x9d, 0xb5, 0x35, 0x15, 0x02, 0xe9, 0x1b, 0x85, 0xc1, 0x89,
+ 0xc2, 0x5a, 0x32, 0x3a, 0x80, 0x78, 0x5e, 0xcc, 0x50, 0x26, 0xf5, 0x11,
+ 0x01, 0x79, 0xf3, 0xaf, 0xb6, 0x40, 0x00, 0x73, 0x8f, 0xeb, 0x5a, 0xd1,
+ 0x26, 0x00, 0xe2, 0xa3, 0xcd, 0xfd, 0xaa, 0x15, 0x5b, 0x98, 0x2a, 0x76,
+ 0x41, 0x07, 0xc2, 0xde, 0xb6, 0x71, 0xe7, 0xc3, 0xe9, 0x92, 0xb3, 0xd8,
+ 0xfe, 0xaf, 0x12, 0x61, 0x86, 0x5b, 0x6e, 0x74, 0x45, 0x7b, 0x9b, 0x6f,
+ 0x1a, 0x13, 0x84, 0xf6, 0x31, 0x5f, 0x5b, 0x6c, 0xde, 0x47, 0xb8, 0x73,
+ 0x32, 0xc7, 0x94, 0x92, 0xa5, 0xc3, 0x65, 0xdf, 0x96, 0x6c, 0xfd, 0xb7,
+ 0x80, 0xfb, 0x47, 0xba, 0x6e, 0x43, 0xb3, 0x7e, 0x86, 0xc9, 0x97, 0x45,
+ 0xde, 0x3f, 0x3a, 0xf6, 0xb0, 0x9e, 0x9a, 0xcb, 0xfd, 0xf2, 0x5c, 0xba,
+ 0x6e, 0x3f, 0xed, 0xfa, 0x74, 0x84, 0xe2, 0xb1, 0xae, 0x66, 0x57, 0x0b,
+ 0x96, 0x6c, 0x77, 0xe4, 0x8a, 0x67, 0x97, 0xc7, 0xe0, 0x44, 0xb2, 0x83,
+ 0x2d, 0x3c, 0x2e, 0x01, 0x19, 0x2e, 0x4c, 0x74, 0xe1, 0x35, 0x73, 0xeb,
+ 0x85, 0x63, 0x8c, 0x3a, 0xb8, 0xbc, 0x25, 0x6a, 0x8d, 0xaf, 0xd2, 0xfb,
+ 0xef, 0xd3, 0x12, 0x93, 0x0b, 0x39, 0xfa, 0x66, 0xbe, 0x3b, 0xfd, 0x6c,
+ 0x0b, 0xbb, 0xb2, 0x5a, 0x78, 0xa1, 0xcf, 0x8c, 0x7d, 0x60, 0x55, 0xeb,
+ 0x33, 0x4e, 0x8e, 0xf9, 0x19, 0x4d, 0x42, 0xd4, 0xf8, 0xd8, 0xba, 0xad,
+ 0x0a, 0x6e, 0x62, 0xd4, 0xe1, 0x6a, 0xcc, 0xea, 0x09, 0x91, 0x8e, 0x62,
+ 0xc9, 0x1e, 0x9e, 0x48, 0xaa, 0xde, 0xf7, 0xa2, 0x5a, 0xcb, 0x83, 0x20,
+ 0xe8, 0xf5, 0xd1, 0xfe, 0x9d, 0x18, 0x2f, 0xd6, 0xf8, 0x97, 0x17, 0xce,
+ 0xc2, 0x05, 0x08, 0xef, 0x61, 0x70, 0x9d, 0x95, 0x79, 0x59, 0x4c, 0x06,
+ 0x24, 0x3d, 0x24, 0x69, 0xff, 0x46, 0xda, 0xbc, 0x71, 0x7a, 0x74, 0x93,
+ 0x58, 0xf5, 0xc8, 0x91, 0xfb, 0x66, 0xed, 0x78, 0x8f, 0xf8, 0x28, 0xa8,
+ 0x1d, 0xa5, 0x3a, 0x13, 0x76, 0xc2, 0xcc, 0xba, 0xb9, 0x56, 0x29, 0x74,
+ 0xd6, 0x14, 0x75, 0x58, 0xe6, 0x2e, 0x79, 0x6e, 0x9d, 0x41, 0x94, 0x8a,
+ 0xcf, 0xf1, 0xb1, 0xe0, 0x36, 0xe5, 0x89, 0x9a, 0x95, 0xa1, 0x11, 0xd1,
+ 0xbe, 0x45, 0xe4, 0xb3, 0xb0, 0x62, 0x32, 0x1d, 0xba, 0xe0, 0xde, 0x57,
+ 0x81, 0x0e, 0x01, 0x9b, 0x52, 0x3d, 0xd5, 0xde, 0x3b, 0x3a, 0xdd, 0x8f,
+ 0xe3, 0x2e, 0xce, 0x1e, 0x89, 0x4d, 0x81, 0xf0, 0xf6, 0x20, 0x63, 0x7a,
+ 0x4c, 0xbb, 0x66, 0xe0, 0xbe, 0x2b, 0xee, 0xd0, 0x3b, 0x60, 0x1e, 0x65,
+ 0xd1, 0x2c, 0x7c, 0x5c, 0x6c, 0x16, 0x5b, 0x90, 0xc8, 0x05, 0x10, 0xf2,
+ 0xde, 0x33, 0x90, 0x35, 0x69, 0x24, 0x3f, 0xc1, 0x8f, 0x1e, 0x4a, 0x60,
+ 0xf1, 0x03, 0x65, 0x46, 0x40, 0x76, 0xe9, 0x83, 0x97, 0xda, 0x0b, 0xb8,
+ 0x22, 0xfa, 0x55, 0x99, 0xfd, 0x18, 0x24, 0xd2, 0x66, 0xb0, 0x7b, 0x70,
+ 0x56, 0x93, 0xad, 0x09, 0x95, 0x8e, 0x1f, 0x2f, 0xe8, 0x12, 0x55, 0xd4,
+ 0x1f, 0xde, 0x09, 0x85, 0x05, 0xd1, 0xd5, 0x10, 0x2c, 0x8c, 0x6b, 0x53,
+ 0x28, 0xce, 0x06, 0xc5, 0x52, 0x0f, 0xfa, 0x09, 0x09, 0x23, 0x1b, 0xe3,
+ 0xbf, 0xb1, 0x89, 0x72, 0x26, 0x0d, 0xa6, 0xbb, 0x7d, 0x9e, 0xdc, 0xf8,
+ 0xf5, 0x0b, 0x8c, 0xe0, 0xbc, 0x97, 0x3b, 0x72, 0xdd, 0xf5, 0x9d, 0xc5,
+ 0xb6, 0x37, 0x2c, 0x76, 0x5b, 0x58, 0x67, 0xdb, 0xed, 0x3b, 0x6e, 0xe5,
+ 0xe5, 0x6d, 0x6f, 0x0d, 0x7e, 0xff, 0xa9, 0x57, 0x4a, 0x84, 0x85, 0x82,
+ 0xac, 0x00, 0x50, 0xa3, 0x4f, 0x87, 0xfe, 0x2a, 0x40, 0x52, 0x54, 0x81,
+ 0x69, 0x42, 0x0b, 0x0c, 0xd7, 0x18, 0x98, 0x01, 0x8c, 0x5a, 0xa2, 0xf4,
+ 0xe8, 0x61, 0xd1, 0x38, 0xfd, 0x0f, 0x63, 0x75, 0xd3, 0x4b, 0x1d, 0xdc,
+ 0xdf, 0xb2, 0xeb, 0x94, 0x97, 0x5c, 0x2a, 0xb4, 0x12, 0x5c, 0x49, 0x2b,
+ 0xfc, 0xd0, 0x8d, 0xfb, 0xe7, 0xb3, 0xcb, 0x0f, 0x3c, 0x2e, 0x04, 0x36,
+ 0xa8, 0x03, 0xc9, 0xd7, 0x11, 0x2d, 0x2a, 0x93, 0xff, 0xda, 0x26, 0xb0,
+ 0x54, 0x7e, 0xaf, 0x30, 0x7d, 0xce, 0x46, 0x8a, 0x3d, 0x7c, 0xa4, 0x7a,
+ 0x2c, 0xfa, 0xba, 0xa1, 0xc9, 0x41, 0xd3, 0xb8, 0x84, 0x03, 0x78, 0xdd,
+ 0xe9, 0x57, 0x19, 0x62, 0x62, 0xff, 0x5b, 0x3b, 0x48, 0x62, 0x0e, 0xee,
+ 0x19, 0xb0, 0x32, 0x6e, 0x6a, 0x07, 0xd8, 0x4e, 0x25, 0x76, 0xa7, 0xe3,
+ 0x98, 0xa1, 0x6f, 0xb6, 0x99, 0x32, 0x67, 0x7d, 0x46, 0x42, 0x4a, 0x82,
+ 0xd1, 0x29, 0x1b, 0x87, 0xeb, 0x4b, 0x9e, 0xdf, 0x69, 0x75, 0xbd, 0x4f,
+ 0xd3, 0xde, 0xc9, 0x83, 0xe6, 0xd6, 0xea, 0x03, 0x81, 0x12, 0xf3, 0x5d,
+ 0x99, 0xf1, 0xb1, 0xd9, 0x3e, 0xbe, 0xf3, 0xa8, 0xdc, 0xb6, 0xf8, 0x4b,
+ 0x9e, 0x26, 0x3f, 0xf0, 0x7c, 0xb3, 0xf4, 0xca, 0x00, 0x6c, 0x6c, 0xe5,
+ 0x43, 0xa1, 0xfd, 0x3a, 0xf8, 0x8e, 0xe3, 0x9f, 0x88, 0xc5, 0x44, 0xfd,
+ 0x24, 0x69, 0x76, 0xd5, 0xcb, 0xdc, 0x9d, 0x12, 0xf3, 0x13, 0x7e, 0xe7,
+ 0xc3, 0xa8, 0x6a, 0xb2, 0xe0, 0xb3, 0x1d, 0xab, 0x3b, 0xc9, 0x77, 0x3d,
+ 0x0f, 0xc3, 0xbe, 0x4b, 0x8b, 0x28, 0xbd, 0x7c, 0xe6, 0xb2, 0x06, 0x1f,
+ 0xf9, 0x8f, 0x16, 0x62, 0xbf, 0xc7, 0x55, 0x73, 0xd4, 0xf1, 0x5a, 0x95,
+ 0x80, 0xa3, 0x4e, 0xaa, 0x60, 0x17, 0x3c, 0xc9, 0x5e, 0xd4, 0x0c, 0x56,
+ 0x7a, 0x77, 0x8e, 0x7f, 0x67, 0x08, 0x2f, 0xd9, 0x21, 0x19, 0xfd, 0x86,
+ 0x8c, 0x23, 0x8d, 0xf6, 0x92, 0x1f, 0x36, 0x2c, 0x7c, 0x83, 0xbd, 0x2f,
+ 0x6c, 0x63, 0x7c, 0xb7, 0x93, 0x74, 0x1b, 0xc2, 0x95, 0x34, 0x26, 0x1e,
+ 0x07, 0x87, 0x3a, 0xb6, 0xe2, 0x39, 0x71, 0x9b, 0x20, 0xcd, 0x63, 0xf0,
+ 0xbf, 0x48, 0xb5, 0x0e, 0x49, 0x86, 0x50, 0x80, 0xbd, 0xd6, 0x0e, 0xab,
+ 0xd5, 0x69, 0x1b, 0xa4, 0xb3, 0x63, 0x3c, 0x8f, 0xcb, 0x42, 0xdb, 0xd7,
+ 0x1a, 0xf4, 0xdf, 0x9e, 0x25, 0xfc, 0xd4, 0x00, 0xcb, 0xec, 0x57, 0x69,
+ 0x30, 0x15, 0x4d, 0x7a, 0x69, 0x28, 0x2f, 0x2b, 0x34, 0x26, 0xd1, 0xe7,
+ 0x01, 0x42, 0x5e, 0x02, 0xe2, 0x75, 0xe8, 0x52, 0x8a, 0xb4, 0x71, 0xfa,
+ 0xc3, 0x3d, 0xe6, 0xac, 0xeb, 0xf3, 0x93, 0xe0, 0x37, 0xcd, 0x66, 0x92,
+ 0x66, 0x2c, 0xfe, 0x4b, 0xd6, 0x3c, 0xf1, 0x57, 0xe5, 0xcf, 0xf5, 0xd0,
+ 0xdb, 0x0e, 0x1f, 0x82, 0x65, 0x3b, 0xab, 0x69, 0x42, 0x53, 0x7d, 0xa4,
+ 0x7c, 0xb7, 0x86, 0xeb, 0x23, 0x45, 0xa8, 0x4a, 0x73, 0xfc, 0x38, 0xc6,
+ 0xe5, 0x2c, 0xab, 0x80, 0xfb, 0x23, 0xb2, 0x0c, 0x53, 0x28, 0x21, 0x37,
+ 0x54, 0x9c, 0x72, 0x51, 0x0f, 0x44, 0x50, 0xd3, 0xe1, 0xd5, 0xb2, 0x27,
+ 0x83, 0xb6, 0xe9, 0x4d, 0x64, 0x5c, 0x17, 0x0f, 0xe0, 0x13, 0xe4, 0x26,
+ 0x6b, 0xd0, 0xd8, 0x25, 0xe3, 0x69, 0x6a, 0x95, 0x3f, 0x4a, 0x4e, 0xa0,
+ 0x58, 0xbc, 0x28, 0x47, 0x8b, 0x68, 0xe4, 0x41, 0x90, 0x46, 0x1b, 0x84,
+ 0xa0, 0x7b, 0x46, 0x46, 0x03, 0xee, 0x21, 0x0d, 0x34, 0xed, 0xff, 0x15,
+ 0x57, 0x06, 0xdf, 0x71, 0x09, 0xb2, 0x66, 0x0d, 0x6e, 0xcc, 0xa5, 0x0c,
+ 0xaf, 0x3f, 0x24, 0x8f, 0xd1, 0xc8, 0x44, 0x86, 0xaf, 0xbf, 0xeb, 0x2f,
+ 0xb9, 0xee, 0xa7, 0xcf, 0xe4, 0xe8, 0xec, 0x47, 0x09, 0xd8, 0x95, 0x9e,
+ 0x3c, 0xda, 0x92, 0x41, 0x61, 0xf5, 0xc3, 0xec, 0x00, 0xe4, 0xa3, 0x0d,
+ 0x4a, 0xb3, 0xf6, 0x82, 0x05, 0x38, 0x70, 0x6a, 0xd1, 0x28, 0x2c, 0xb3,
+ 0xc6, 0xbb, 0x38, 0xb3, 0x06, 0x7f, 0xd6, 0x4c, 0xe7, 0xfb, 0xef, 0x0d,
+ 0x52, 0x66, 0xbe, 0xd8, 0xa6, 0x6f, 0xe8, 0xd9, 0x42, 0x4f, 0xad, 0xe8,
+ 0xe8, 0x6c, 0xf9, 0xe9, 0x42, 0xd9, 0x66, 0x6e, 0xec, 0xfe, 0xf5, 0x91,
+ 0xbf, 0x0a, 0x98, 0xd8, 0x7b, 0x23, 0x12, 0xa6, 0x04, 0xa8, 0xb3, 0x61,
+ 0x13, 0x65, 0xc0, 0xe2, 0x82, 0xb9, 0xb2, 0x38, 0x07, 0x06, 0xca, 0x64,
+ 0x6c, 0x23, 0x93, 0x60, 0x1d, 0x4d, 0x38, 0x5e, 0x8e, 0x90, 0x16, 0x4a,
+ 0xfd, 0xb3, 0xcd, 0x84, 0x9c, 0xa5, 0xfa, 0x73, 0x2d, 0xcb, 0x87, 0x31,
+ 0x3d, 0xf8, 0xfc, 0xeb, 0xa7, 0x56, 0x2f, 0x5b, 0x95, 0x9a, 0xc6, 0x82,
+ 0x29, 0x86, 0x47, 0xe2, 0xc2, 0x84, 0x01, 0xaf, 0xc8, 0x0b, 0x2d, 0xfb,
+ 0x34, 0xba, 0x5d, 0x9d, 0xd1, 0x85, 0xd5, 0x1e, 0x63, 0xcb, 0x3c, 0xa8,
+ 0xfa, 0x79, 0xef, 0x12, 0xa6, 0xb5, 0xdb, 0xc5, 0x1d, 0x6a, 0xa7, 0x54,
+ 0x58, 0x0c, 0xbe, 0x61, 0xe5, 0x96, 0x7f, 0x4a, 0x3b, 0x59, 0x32, 0x2d,
+ 0x06, 0x44, 0x83, 0x5c, 0xad, 0xe9, 0xfe, 0x7c, 0xd7, 0x5b, 0x34, 0xa1,
+ 0xa3, 0xad, 0x9a, 0xbf, 0xd5, 0x30, 0xf0, 0x22, 0xfc, 0x94, 0x7f, 0xd4,
+ 0xa4, 0xca, 0x88, 0x31, 0xe7, 0xf2, 0x89, 0x2d, 0xda, 0xe6, 0x91, 0xa6,
+ 0x27, 0x22, 0x74, 0x9f, 0xc6, 0x72, 0x4f, 0xf6, 0xa9, 0xfe, 0x7a, 0xf0,
+ 0xa8, 0x6b, 0x6c, 0x9f, 0xe9, 0x2a, 0x9b, 0x23, 0x9e, 0xb8, 0x2b, 0x29,
+ 0x65, 0xa7, 0x5d, 0xbd, 0x10, 0xe4, 0x56, 0x02, 0x94, 0xdd, 0xd1, 0xab,
+ 0x9b, 0x82, 0x2d, 0x8d, 0xf6, 0xd3, 0x65, 0x63, 0x4a, 0xc4, 0x86, 0x61,
+ 0x37, 0x9f, 0xdb, 0x4b, 0x34, 0x20, 0x0a, 0xca, 0x45, 0x6c, 0x06, 0xc4,
+ 0x9c, 0x74, 0x4d, 0x83, 0x6a, 0x8d, 0xad, 0xc6, 0x61, 0x3a, 0x8d, 0xde,
+ 0x6c, 0xf9, 0x8e, 0x33, 0xa2, 0xee, 0x99, 0xc7, 0xe4, 0x52, 0xb2, 0x44,
+ 0x6f, 0x2f, 0x0f, 0x41, 0xa9, 0x1a, 0xd3, 0x96, 0x42, 0xc6, 0x49, 0x12,
+ 0x6a, 0xf0, 0x29, 0xa9, 0x0c, 0x9c, 0x50, 0x5d, 0x1d, 0xd1, 0x42, 0x7e,
+ 0x6f, 0x36, 0x48, 0x0f, 0x58, 0x14, 0x94, 0xc0, 0x10, 0x1e, 0xe0, 0xb2,
+ 0xdd, 0xba, 0x57, 0x91, 0x4d, 0xd5, 0xdc, 0xa6, 0x4c, 0x68, 0x00, 0x6c,
+ 0xb3, 0x5d, 0x32, 0x13, 0xbe, 0xa8, 0xc3, 0xfb, 0xd4, 0x19, 0x40, 0xf5,
+ 0x6f, 0x63, 0xa1, 0x07, 0xbf, 0xa2, 0x8b, 0xfc, 0xfe, 0xf8, 0xa1, 0x33,
+ 0x70, 0x07, 0x6d, 0xc5, 0x72, 0xa0, 0x39, 0xd6, 0xd7, 0x76, 0x6c, 0xfa,
+ 0x1f, 0x04, 0xd6, 0x23, 0xbf, 0x66, 0x78, 0x92, 0x00, 0x11, 0x8a, 0x75,
+ 0x67, 0x44, 0xa6, 0x7c, 0xd0, 0x14, 0xe6, 0xd0, 0x31, 0x6d, 0xdb, 0xc5,
+ 0xb1, 0xa7, 0x99, 0xc3, 0xaf, 0x18, 0x7a, 0x26, 0x46, 0xad, 0x6d, 0x0c,
+ 0xb6, 0xb5, 0xad, 0xc1, 0xcf, 0x60, 0x99, 0xf5, 0x9f, 0x88, 0xaf, 0x0e,
+ 0x37, 0x15, 0xf9, 0x2b, 0x1a, 0x5f, 0xfb, 0xc9, 0xf8, 0xd4, 0xf0, 0x97,
+ 0xd2, 0x91, 0xf4, 0x94, 0xa2, 0xd3, 0x3b, 0x8b, 0x0c, 0x22, 0xa0, 0xac,
+ 0xb3, 0xb5, 0xdf, 0xf2, 0x27, 0x38, 0x47, 0x53, 0x5b, 0x6e, 0x8f, 0x98,
+ 0x9e, 0xad, 0xb6, 0xf5, 0x0e, 0x17, 0x20, 0x35, 0x54, 0x6b, 0x73, 0xa6,
+ 0x64, 0x65, 0xac, 0xb8, 0xc1, 0xd3, 0xf7, 0x07, 0x82, 0x93, 0x9d, 0xcb,
+ 0xcc, 0xe9, 0x0c, 0x51, 0x52, 0x85, 0x8b, 0x95, 0xa6, 0xb1, 0xce, 0xdc,
+ 0xfa, 0x00, 0x00, 0x08, 0x14, 0x1c, 0x23, 0x2a, 0x35,
+};
+
+static const u8 fips_test_mldsa65_public_key[] __initconst __maybe_unused = {
+ 0x9f, 0x55, 0x1e, 0x7f, 0x9c, 0x08, 0xb2, 0x83, 0xfd, 0x5b, 0xa2, 0xac,
+ 0x4f, 0x26, 0xc2, 0xf5, 0x06, 0x05, 0x96, 0x08, 0x24, 0xad, 0xec, 0xe4,
+ 0x99, 0xcc, 0x6c, 0xbd, 0x55, 0x37, 0x15, 0x94, 0xab, 0x31, 0x9e, 0x56,
+ 0xe5, 0xe4, 0x55, 0xec, 0x4d, 0x49, 0x5b, 0x5a, 0x7a, 0xe8, 0xc3, 0x4a,
+ 0x08, 0x44, 0x4a, 0xc2, 0x2d, 0xe4, 0x61, 0x33, 0x90, 0x20, 0x71, 0x45,
+ 0xa5, 0x45, 0xd0, 0x83, 0x2b, 0x32, 0x6c, 0xa7, 0x9e, 0x76, 0xcd, 0xfb,
+ 0x58, 0x15, 0x9e, 0x74, 0x0d, 0x67, 0x57, 0xb1, 0x06, 0x5b, 0x5d, 0xd5,
+ 0x1c, 0xbb, 0x95, 0x40, 0x1c, 0x71, 0x31, 0x03, 0xef, 0xff, 0x04, 0x6b,
+ 0xdd, 0xa2, 0xf0, 0x32, 0x00, 0x72, 0xbc, 0x87, 0xb6, 0x2c, 0x1f, 0x90,
+ 0x7f, 0x92, 0xa0, 0xb2, 0x04, 0xdd, 0xa9, 0xaf, 0x7f, 0x01, 0x28, 0x4c,
+ 0xb2, 0x57, 0x2d, 0x56, 0x93, 0xd0, 0xc7, 0x54, 0x02, 0x90, 0x57, 0x70,
+ 0x23, 0x57, 0xe8, 0xe7, 0x33, 0x32, 0x98, 0xfc, 0x9b, 0x8e, 0x6e, 0x7b,
+ 0xaa, 0x5d, 0xb5, 0x4e, 0xe0, 0x5d, 0x97, 0xa3, 0xea, 0x43, 0x7e, 0xb3,
+ 0xa4, 0x8c, 0xcf, 0xdc, 0xc0, 0x51, 0xa7, 0x99, 0x45, 0x3d, 0x3c, 0xa0,
+ 0xba, 0xc5, 0xff, 0xe1, 0x89, 0xb3, 0x7d, 0xc3, 0xdc, 0xe2, 0x23, 0x81,
+ 0xff, 0xa9, 0xc7, 0x93, 0xc6, 0x67, 0xad, 0x94, 0xcf, 0xeb, 0x91, 0x78,
+ 0x15, 0x25, 0xf7, 0xf5, 0x06, 0x08, 0x2f, 0x0c, 0xee, 0x0b, 0x6a, 0x06,
+ 0x59, 0xe0, 0x1f, 0x2e, 0x5a, 0x12, 0x06, 0xf5, 0xf4, 0x8e, 0x75, 0x57,
+ 0xa9, 0x33, 0x23, 0x0f, 0xc2, 0x6f, 0x02, 0xf8, 0x68, 0x0f, 0x62, 0x02,
+ 0x81, 0xfe, 0x03, 0x7c, 0xaf, 0xd7, 0x42, 0x5b, 0xcc, 0xe7, 0x2b, 0xea,
+ 0x49, 0xab, 0x03, 0x6d, 0x0a, 0x02, 0xae, 0x47, 0x79, 0xce, 0xfd, 0x18,
+ 0x76, 0x07, 0x9e, 0xa6, 0xbf, 0x7e, 0x8d, 0x73, 0xf9, 0x44, 0xeb, 0x8c,
+ 0xc5, 0x59, 0xb7, 0x19, 0xf6, 0x73, 0x53, 0x42, 0x2a, 0x55, 0x7b, 0xb4,
+ 0x56, 0x49, 0x08, 0x9e, 0x9a, 0x65, 0x60, 0x70, 0x1d, 0xbd, 0xc6, 0x85,
+ 0x29, 0xde, 0xfe, 0x44, 0xae, 0xdf, 0x25, 0xfd, 0x5b, 0x74, 0x6c, 0x96,
+ 0xe6, 0x81, 0x37, 0x80, 0xe0, 0x9e, 0xf3, 0x75, 0x63, 0xb4, 0xc9, 0x2f,
+ 0x71, 0xe6, 0xeb, 0xdf, 0xaf, 0x7e, 0xff, 0x9e, 0xe0, 0xbf, 0xca, 0xca,
+ 0x11, 0xed, 0xc6, 0x04, 0xd8, 0x49, 0x13, 0x2c, 0x63, 0xf1, 0xb3, 0x17,
+ 0x74, 0xd9, 0x50, 0x3f, 0xb9, 0x29, 0x0e, 0x48, 0xa7, 0xf0, 0xdc, 0x78,
+ 0x18, 0x0e, 0x9f, 0xb7, 0xde, 0x36, 0x79, 0x67, 0xa4, 0x23, 0x08, 0xe7,
+ 0x62, 0xe8, 0xa4, 0xe5, 0xcf, 0xff, 0x35, 0x55, 0x36, 0x2e, 0x3a, 0xe4,
+ 0x45, 0x6a, 0x80, 0xf2, 0xca, 0xe7, 0x40, 0x79, 0x14, 0xc4, 0x62, 0x38,
+ 0xbb, 0xd0, 0x4e, 0x6c, 0xb5, 0x85, 0x42, 0x3f, 0x35, 0xf7, 0xd7, 0x54,
+ 0xb8, 0x2b, 0x8b, 0xd5, 0x6f, 0x16, 0x61, 0x27, 0x23, 0xac, 0xdb, 0xea,
+ 0x9b, 0x3b, 0x99, 0xcd, 0x79, 0xe6, 0x12, 0x09, 0x99, 0x09, 0xa4, 0xe1,
+ 0x88, 0x25, 0x00, 0x9e, 0x60, 0x16, 0x63, 0xd7, 0x42, 0x9b, 0xcc, 0x36,
+ 0x9a, 0x8d, 0xa3, 0x75, 0x36, 0xa1, 0xa8, 0xfc, 0xa2, 0xfe, 0x29, 0x26,
+ 0x4c, 0x93, 0x21, 0x44, 0x6b, 0x1c, 0xba, 0xbd, 0xef, 0xff, 0x6d, 0x1f,
+ 0x2b, 0x6c, 0x66, 0x81, 0x9a, 0x3a, 0x1d, 0x0b, 0xd7, 0x24, 0xd4, 0xb8,
+ 0x93, 0xb5, 0x22, 0xf9, 0xd2, 0xf4, 0xa5, 0x05, 0x78, 0x38, 0xae, 0x58,
+ 0xf6, 0x50, 0x8f, 0x47, 0x1d, 0xf3, 0xfb, 0x0d, 0x04, 0x14, 0xd1, 0xd6,
+ 0xd8, 0x2e, 0xf2, 0xbd, 0xf5, 0x71, 0x86, 0x4c, 0xdd, 0x61, 0x24, 0x18,
+ 0x5b, 0x54, 0xf5, 0xcd, 0x99, 0x89, 0x01, 0x8e, 0xd1, 0x19, 0x52, 0xbc,
+ 0x45, 0xed, 0x0e, 0xec, 0x72, 0x2f, 0x5a, 0xe7, 0xdf, 0x36, 0x1c, 0x57,
+ 0x9f, 0xb2, 0x8b, 0xf2, 0x78, 0x1b, 0x3e, 0xc5, 0x48, 0x1f, 0x27, 0x04,
+ 0x76, 0x10, 0x44, 0xee, 0x5c, 0x68, 0x8f, 0xca, 0xd7, 0x31, 0xfc, 0x5c,
+ 0x40, 0x03, 0x2e, 0xbd, 0x1d, 0x59, 0x13, 0x57, 0xbc, 0x33, 0xc6, 0xa1,
+ 0xa3, 0xe5, 0x55, 0x79, 0x9b, 0x7e, 0x49, 0xbb, 0x23, 0x96, 0xc3, 0x1c,
+ 0xfe, 0x66, 0xeb, 0x5b, 0x5f, 0xe5, 0x03, 0xc9, 0xa4, 0xac, 0x4d, 0xc4,
+ 0x50, 0xbb, 0xd3, 0xc1, 0x91, 0x48, 0xe0, 0x93, 0x92, 0x2a, 0xdb, 0x41,
+ 0x37, 0x98, 0xbc, 0xa2, 0x7a, 0x09, 0x92, 0x0b, 0x1c, 0xe6, 0x4b, 0x1e,
+ 0x8e, 0x78, 0x81, 0x74, 0x7d, 0x6b, 0x71, 0xd5, 0xe7, 0x0e, 0x7b, 0xc2,
+ 0x74, 0x5d, 0x89, 0xf1, 0xfa, 0x59, 0xaa, 0xf7, 0x86, 0x66, 0x7e, 0xc2,
+ 0x9c, 0xf4, 0xd5, 0x8d, 0xc0, 0xb7, 0xb7, 0xa2, 0xd5, 0xcd, 0x51, 0xc3,
+ 0x7d, 0xa9, 0x5e, 0x46, 0xba, 0x06, 0xa3, 0x4d, 0x60, 0xd6, 0x68, 0xc6,
+ 0xf9, 0x63, 0x88, 0x17, 0x5c, 0x20, 0xe1, 0xc4, 0x0f, 0x3f, 0xc1, 0xa9,
+ 0xa7, 0x3e, 0x39, 0xef, 0x2f, 0xaf, 0xc4, 0x69, 0x29, 0xe3, 0xd4, 0x8d,
+ 0xe0, 0x0e, 0x88, 0xc2, 0x93, 0x43, 0xfb, 0x28, 0xcf, 0x5d, 0x85, 0x50,
+ 0xf7, 0xeb, 0x42, 0xf5, 0x87, 0xde, 0xa5, 0x65, 0xef, 0x43, 0x0c, 0x57,
+ 0x76, 0x09, 0xf4, 0x5f, 0xde, 0x81, 0x0a, 0xd9, 0x59, 0x41, 0xa4, 0x6a,
+ 0xb7, 0x05, 0xc7, 0xa5, 0xfe, 0x49, 0xd5, 0x9b, 0x57, 0x13, 0x14, 0x66,
+ 0xe2, 0xb9, 0xcc, 0x09, 0x35, 0xd4, 0xb0, 0xe0, 0xd1, 0x0d, 0x7e, 0x50,
+ 0x48, 0x45, 0x21, 0x00, 0x67, 0xb2, 0xad, 0xa7, 0x46, 0xe2, 0x6f, 0x70,
+ 0xe5, 0x3c, 0x88, 0x04, 0xaa, 0x21, 0xde, 0x03, 0xb6, 0x6f, 0xfe, 0x43,
+ 0x51, 0xdc, 0x2e, 0x5c, 0x6c, 0x77, 0x8f, 0x8e, 0x9d, 0x1a, 0x5b, 0x35,
+ 0xc5, 0xe4, 0x48, 0x82, 0x17, 0x4b, 0xf0, 0xea, 0xc9, 0x0e, 0xd2, 0x8f,
+ 0xcd, 0xd5, 0x01, 0xbd, 0x7f, 0x0f, 0xf5, 0xae, 0x92, 0x28, 0x1e, 0x2c,
+ 0xf4, 0xe9, 0x03, 0xf7, 0x0a, 0xeb, 0x84, 0x18, 0xa1, 0x37, 0x38, 0x8a,
+ 0x11, 0xa2, 0x5d, 0x8c, 0xf6, 0xe4, 0x3f, 0x5b, 0x87, 0x07, 0x6b, 0xb4,
+ 0x07, 0xe0, 0x8f, 0x30, 0xc4, 0xfa, 0x27, 0xae, 0xfc, 0x02, 0xd1, 0x21,
+ 0x5c, 0xbc, 0x0b, 0x93, 0x6e, 0x7e, 0xf9, 0x6b, 0x80, 0x7a, 0x25, 0x84,
+ 0x20, 0xf1, 0x6a, 0xfa, 0x75, 0xed, 0x57, 0x61, 0x62, 0xa7, 0xf6, 0x5b,
+ 0xe1, 0xb0, 0x38, 0xc8, 0xe9, 0x6d, 0x3f, 0xef, 0x1e, 0x99, 0x0b, 0xb7,
+ 0xc8, 0x9f, 0x76, 0x5c, 0x04, 0x1f, 0x02, 0x92, 0x00, 0xa7, 0x38, 0x3d,
+ 0x00, 0x3b, 0xa7, 0xbc, 0x39, 0x6e, 0xab, 0xf5, 0x10, 0xa8, 0xba, 0xd6,
+ 0x28, 0x6b, 0x0e, 0x00, 0x48, 0xf9, 0x3b, 0x5c, 0xde, 0x59, 0x93, 0x46,
+ 0xd6, 0x61, 0x52, 0x81, 0x71, 0x0f, 0x0e, 0x61, 0xac, 0xc6, 0x7f, 0x15,
+ 0x93, 0xa7, 0xc1, 0x16, 0xb5, 0xef, 0x85, 0xd1, 0xa7, 0x61, 0xc2, 0x85,
+ 0x1d, 0x61, 0xc6, 0xae, 0xb3, 0x9e, 0x8d, 0x23, 0xa3, 0xc8, 0xd5, 0xf2,
+ 0xc7, 0x1b, 0x7e, 0xef, 0xd2, 0xdf, 0x25, 0xaf, 0x4e, 0x81, 0x15, 0x59,
+ 0xe5, 0x36, 0xb1, 0xf1, 0xd5, 0xda, 0x58, 0xd8, 0xd9, 0x0d, 0x6d, 0xc9,
+ 0x25, 0xb5, 0xe8, 0x1d, 0x3b, 0xca, 0x2d, 0xab, 0xf2, 0xe2, 0xe9, 0x55,
+ 0xd7, 0xf4, 0xc7, 0xd0, 0x57, 0x7a, 0x86, 0x15, 0x0a, 0x5a, 0x8b, 0xd7,
+ 0x3f, 0x66, 0x0f, 0x80, 0xb4, 0xe0, 0x5c, 0x33, 0xed, 0xaf, 0x1b, 0x3b,
+ 0x6d, 0x1c, 0xd9, 0x8c, 0xb5, 0x96, 0xa3, 0xfb, 0xcf, 0xcc, 0x97, 0x1c,
+ 0xae, 0x06, 0x19, 0x41, 0x61, 0xf8, 0x97, 0x6b, 0x82, 0x5e, 0x1c, 0xbf,
+ 0x6f, 0x43, 0x3d, 0xe5, 0x00, 0xf5, 0xfe, 0x66, 0x48, 0x26, 0x31, 0xa1,
+ 0x72, 0x67, 0x6e, 0xd4, 0x5b, 0x6f, 0x66, 0xde, 0x70, 0x8b, 0x2b, 0xc3,
+ 0xa2, 0x30, 0xe9, 0x55, 0xc8, 0xff, 0xf8, 0xd0, 0xdd, 0xa9, 0x21, 0x85,
+ 0x6e, 0x6c, 0x82, 0x66, 0xcc, 0x52, 0xf0, 0x9e, 0x1e, 0xb5, 0x3a, 0xff,
+ 0x4c, 0xf3, 0xae, 0x02, 0xc3, 0x4b, 0x76, 0x25, 0xbd, 0xb0, 0x21, 0x54,
+ 0x61, 0xda, 0x16, 0xd3, 0x23, 0x86, 0x41, 0xa1, 0x4c, 0x59, 0x15, 0x95,
+ 0x65, 0x85, 0xb6, 0x8e, 0xa6, 0x37, 0xc0, 0xa2, 0x71, 0x1d, 0x67, 0x44,
+ 0x7b, 0xe5, 0x4c, 0x4f, 0xb6, 0x2c, 0x46, 0xf7, 0x29, 0xa5, 0xf2, 0xd3,
+ 0x51, 0x19, 0x91, 0x4d, 0xa7, 0xb5, 0x05, 0xb9, 0x6e, 0x61, 0x6e, 0xf8,
+ 0xc0, 0x01, 0xe5, 0x41, 0x0a, 0x89, 0x64, 0x77, 0xf2, 0xc8, 0x63, 0x2d,
+ 0x9d, 0x27, 0x7f, 0x47, 0x30, 0x39, 0xdf, 0xb6, 0x6e, 0x4f, 0x00, 0x3f,
+ 0x15, 0xc6, 0xaf, 0x62, 0xdf, 0x3f, 0x47, 0xe8, 0x42, 0x90, 0x77, 0x23,
+ 0x7a, 0xaa, 0x99, 0x53, 0x03, 0x63, 0x60, 0x59, 0x07, 0x52, 0x3c, 0xb5,
+ 0x67, 0x59, 0xfe, 0x08, 0xe6, 0x43, 0x0f, 0x3b, 0x08, 0x7c, 0xc7, 0x07,
+ 0x3c, 0xfa, 0x65, 0xea, 0x69, 0x51, 0x41, 0x31, 0xb3, 0x05, 0x69, 0xba,
+ 0x2c, 0xbf, 0x89, 0x25, 0x9e, 0xfe, 0x07, 0x13, 0x78, 0x0e, 0x16, 0x54,
+ 0xdf, 0x23, 0xdf, 0x10, 0x69, 0x79, 0xd0, 0x33, 0xd7, 0x21, 0x8b, 0xc8,
+ 0x2a, 0xd0, 0x74, 0x0a, 0xfa, 0xb1, 0x6f, 0xa3, 0xcb, 0x1d, 0xca, 0x4f,
+ 0x00, 0x46, 0x6c, 0x42, 0x09, 0xe0, 0x30, 0x89, 0x08, 0x33, 0x9b, 0x7b,
+ 0x7b, 0x0f, 0x69, 0x5c, 0x0d, 0x34, 0x91, 0xfc, 0xfe, 0x22, 0x82, 0x02,
+ 0xcd, 0xfa, 0x97, 0xe8, 0x28, 0x1d, 0xbc, 0x13, 0x0b, 0xfd, 0x47, 0xa1,
+ 0x7e, 0xa2, 0x86, 0x4d, 0x6f, 0x12, 0x51, 0x35, 0x7d, 0x76, 0x8a, 0x58,
+ 0x05, 0xb6, 0x39, 0xa1, 0x2f, 0xd7, 0xda, 0xaf, 0x00, 0xa0, 0x1a, 0x94,
+ 0xd8, 0x23, 0x34, 0x99, 0x5c, 0xaf, 0xcc, 0x15, 0x4b, 0x56, 0xb2, 0xd2,
+ 0x81, 0x07, 0xd3, 0xf3, 0x47, 0xa2, 0x45, 0x93, 0xcb, 0xae, 0xa7, 0x6b,
+ 0x3f, 0xf9, 0xea, 0xfc, 0x0e, 0x64, 0xf2, 0x93, 0x7f, 0x24, 0x22, 0x73,
+ 0x86, 0xc7, 0x2d, 0x75, 0x9b, 0x41, 0x8b, 0xfb, 0x3b, 0x26, 0x2a, 0xe5,
+ 0x0b, 0xd4, 0x00, 0xe3, 0x2c, 0x69, 0x49, 0x62, 0x6c, 0x13, 0x58, 0x6e,
+ 0xac, 0x43, 0xe5, 0x2b, 0x3b, 0x88, 0xdc, 0xd4, 0x41, 0xe8, 0xee, 0x4e,
+ 0xc3, 0x28, 0x91, 0x17, 0x9a, 0x5a, 0xdb, 0x80, 0x8b, 0x4d, 0x64, 0xcc,
+ 0xbe, 0x66, 0xa4, 0x62, 0xfb, 0x13, 0x44, 0x10, 0xd9, 0xe4, 0xd5, 0xa5,
+ 0xae, 0x9e, 0x42, 0x50, 0xfc, 0x78, 0xad, 0xfa, 0xc4, 0xd0, 0x5a, 0x60,
+ 0x9b, 0x45, 0x2b, 0x61, 0x5c, 0x57, 0xb5, 0x92, 0x28, 0xe9, 0xf5, 0x35,
+ 0x67, 0xc1, 0x5e, 0xa8, 0x1c, 0x99, 0x36, 0x38, 0xb8, 0x5c, 0xff, 0x3d,
+ 0xa0, 0xfc, 0xb0, 0xbc, 0x3d, 0x2c, 0xb4, 0x36, 0x17, 0xb4, 0x6d, 0xb5,
+ 0x39, 0x45, 0xa9, 0x2a, 0x6b, 0xa2, 0x24, 0x44, 0x30, 0xab, 0x2c, 0x82,
+ 0x36, 0xdc, 0xd6, 0x36, 0x5d, 0x0a, 0xdc, 0xee, 0x0f, 0x2b, 0x28, 0x99,
+ 0xdc, 0x67, 0x0d, 0xea, 0x6e, 0x42, 0xb9, 0x45, 0x7f, 0xd2, 0x96, 0x1e,
+ 0x60, 0x42, 0xeb, 0x1e, 0x5f, 0x8e, 0xa9, 0xdc, 0xd3, 0x8a, 0xd6, 0xbd,
+ 0x4e, 0x1f, 0x42, 0x75, 0x1d, 0xe2, 0xc6, 0x11, 0xc9, 0x80, 0x1f, 0xfe,
+ 0x99, 0x52, 0x4d, 0x7b, 0x35, 0xf7, 0xb7, 0xc3, 0xee, 0xd6, 0x94, 0xf5,
+ 0x74, 0xa0, 0x69, 0xcd, 0x1f, 0x2b, 0xd0, 0x87, 0xf7, 0x8c, 0x69, 0xc5,
+ 0x96, 0x70, 0x91, 0xe8, 0x3d, 0xd2, 0xcc, 0xf1, 0x4c, 0xcd, 0xe2, 0x14,
+ 0x00, 0x10, 0x4a, 0xd9, 0x6a, 0x5d, 0x65, 0x2c, 0x4b, 0x79, 0x0c, 0xc4,
+ 0x78, 0x5e, 0xc8, 0xc5, 0x37, 0x74, 0x6d, 0x50, 0x5c, 0x34, 0x1f, 0xe0,
+ 0xf4, 0xe3, 0xe1, 0x86, 0x68, 0xb1, 0xea, 0x70, 0xf0, 0xae, 0xe4, 0x59,
+ 0xa1, 0x08, 0x7e, 0x35, 0xa3, 0x16, 0xd2, 0xb0, 0xa3, 0xd4, 0xb0, 0x74,
+ 0x8c, 0x05, 0x79, 0x73, 0xfb, 0xe6, 0x65, 0x96, 0x15, 0x07, 0xd5, 0xaf,
+ 0x88, 0x9e, 0x6b, 0xf0, 0xbb, 0x3f, 0xe6, 0xd1, 0x6a, 0xe7, 0xc9, 0xae,
+ 0xd9, 0xb0, 0x16, 0x1c, 0x40, 0xeb, 0xdb, 0xc1, 0xbf, 0x83, 0xdb, 0x8a,
+ 0x4f, 0x96, 0xca, 0xd7, 0x22, 0x06, 0x87, 0x08, 0x9d, 0x65, 0x2f, 0xd9,
+ 0x8e, 0x95, 0x6c, 0xcc, 0xbf, 0x76, 0x2a, 0xea, 0x5c, 0x8e, 0x5b, 0x17,
+ 0x0f, 0x75, 0x7b, 0xfa, 0xf9, 0xfb, 0xaa, 0x92, 0xc7, 0x7e, 0x63, 0x63,
+ 0x54, 0xa4, 0xff, 0xf6, 0xc0, 0xc0, 0xf5, 0x70, 0xd8, 0xe3, 0xa4, 0x79,
+ 0x16, 0xf0, 0x6f, 0x90, 0x5e, 0xb7, 0xab, 0x6f, 0xab, 0x75, 0x3b, 0xe1,
+ 0x4c, 0xa8, 0x0b, 0x72, 0x5f, 0x5f, 0x11, 0x22, 0x36, 0x71, 0x20, 0xd3,
+ 0x5b, 0x5e, 0x07, 0x06, 0x76, 0x1a, 0xcc, 0x5e, 0x7c, 0x97, 0x7d, 0xb2,
+ 0x6b, 0xf8, 0x39, 0x89, 0x37, 0xb6, 0x6d, 0xea, 0x74, 0x57, 0x28, 0xd7,
+ 0x0e, 0x9b, 0xeb, 0x28, 0x88, 0x90, 0xfd, 0x2d, 0x16, 0x21, 0x74, 0x26,
+ 0xc5, 0xb8, 0x44, 0xad, 0x9f, 0x97, 0xf9, 0x65, 0x36, 0xd8, 0x00, 0x59,
+ 0x17, 0x49, 0xf9, 0xc7, 0xb3, 0x84, 0xb9, 0xe2, 0x95, 0xe0, 0xd1, 0x7f,
+ 0x5f, 0xaa, 0xd7, 0xfd, 0x6a, 0x6a, 0x83, 0x14, 0x46, 0x1d, 0x12, 0x8d,
+ 0x09, 0xc3, 0xa5, 0xca, 0x72, 0xa3, 0x25, 0x65, 0xb6, 0x40, 0x25, 0x04,
+ 0x51, 0xab, 0x22, 0xeb, 0xd7, 0x69, 0xc9, 0x22, 0x9c, 0xa0, 0x19, 0x5c,
+ 0x1a, 0xfd, 0x41, 0x8f, 0x98, 0xc5, 0x71, 0xb8, 0x6f, 0x76, 0xae, 0xfa,
+ 0x9b, 0x03, 0xab, 0x43, 0x81, 0x3b, 0x66, 0xae, 0xf0, 0xd2, 0xb7, 0xee,
+ 0x9a, 0xe3, 0xae, 0x45, 0xc1, 0x86, 0xb0, 0xce, 0x9e, 0x2b, 0xec, 0xb8,
+ 0xcf, 0xca, 0x0e, 0x8c, 0x33, 0xfa, 0xa7, 0xef, 0xf7, 0xfc, 0xa1, 0x41,
+ 0x49, 0xd3, 0x6d, 0xb5, 0x58, 0xe4, 0x0e, 0x24, 0xd2, 0x8a, 0x74, 0xc9,
+ 0x56, 0x2e, 0x53, 0xc7, 0x7a, 0x38, 0x0f, 0x4b, 0xd9, 0xf9, 0x2f, 0xfa,
+ 0x7d, 0xee, 0x14, 0x18, 0xce, 0x75, 0x42, 0x6c, 0x03, 0x34, 0xce, 0x80,
+ 0xec, 0xf2, 0x05, 0xf0, 0xdf, 0xcd, 0xf8, 0xdb, 0x26, 0x7d, 0xb6, 0x3d,
+ 0x28, 0x24, 0x7e, 0x7e, 0x39, 0x9f, 0xa6, 0xc6, 0xeb, 0x2a, 0xc8, 0x17,
+ 0x94, 0xa9, 0x89, 0xf5, 0xdf, 0xcb, 0x77, 0xfd, 0xc9, 0x9e, 0x68, 0x98,
+ 0x7d, 0x04, 0x50, 0x3c, 0x64, 0x1d, 0x66, 0xb0, 0x97, 0x06, 0xb6, 0x08,
+ 0x5b, 0xe4, 0x17, 0x44, 0xd6, 0x94, 0x39, 0x6b, 0x03, 0x2c, 0xcb, 0x5a,
+ 0x8d, 0x86, 0x08, 0x23, 0x4f, 0x95, 0xa8, 0x1a,
+};
+
+static const u8 fips_test_mldsa65_message[] __initconst __maybe_unused = {
+ 0x1a, 0x84, 0x21, 0x0d, 0x35, 0x7a, 0x88, 0xc8, 0x6a, 0x11, 0xe3,
+ 0x15, 0x24, 0xec, 0x0d, 0x2e, 0x76, 0xb9, 0xcf, 0x2b, 0x04, 0x25,
+ 0x16, 0xae, 0x62, 0x42, 0xa0, 0x20, 0x68, 0x25, 0x3e, 0xb4, 0x75,
+ 0xa7, 0x1d, 0x64, 0xc3, 0xd1, 0x08, 0x07, 0x67, 0xb6, 0xf7, 0x76,
+ 0x76, 0xf6, 0xd6, 0x62, 0x66, 0x04, 0x89, 0x0c, 0x8f, 0x07, 0xac,
+ 0xc8, 0x51, 0x77, 0xd9, 0x47, 0x5e, 0xb5, 0x22, 0x20,
+};
diff --git a/lib/crypto/gf128mul.c b/lib/crypto/gf128mul.c
index 2a34590fe3f1..e5a727b15f07 100644
--- a/lib/crypto/gf128mul.c
+++ b/lib/crypto/gf128mul.c
@@ -245,12 +245,12 @@ struct gf128mul_64k *gf128mul_init_64k_bbe(const be128 *g)
struct gf128mul_64k *t;
int i, j, k;
- t = kzalloc(sizeof(*t), GFP_KERNEL);
+ t = kzalloc_obj(*t);
if (!t)
goto out;
for (i = 0; i < 16; i++) {
- t->t[i] = kzalloc(sizeof(*t->t[i]), GFP_KERNEL);
+ t->t[i] = kzalloc_obj(*t->t[i]);
if (!t->t[i]) {
gf128mul_free_64k(t);
t = NULL;
@@ -326,7 +326,7 @@ struct gf128mul_4k *gf128mul_init_4k_lle(const be128 *g)
struct gf128mul_4k *t;
int j, k;
- t = kzalloc(sizeof(*t), GFP_KERNEL);
+ t = kzalloc_obj(*t);
if (!t)
goto out;
diff --git a/lib/crypto/md5.c b/lib/crypto/md5.c
index c0610ea1370e..c4af57db0ea8 100644
--- a/lib/crypto/md5.c
+++ b/lib/crypto/md5.c
@@ -29,7 +29,7 @@ static const struct md5_block_state md5_iv = {
#define F4(x, y, z) (y ^ (x | ~z))
#define MD5STEP(f, w, x, y, z, in, s) \
- (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x)
+ (w += f(x, y, z) + in, w = rol32(w, s) + x)
static void md5_block_generic(struct md5_block_state *state,
const u8 data[MD5_BLOCK_SIZE])
diff --git a/lib/crypto/mldsa.c b/lib/crypto/mldsa.c
new file mode 100644
index 000000000000..c96fddc4e7dc
--- /dev/null
+++ b/lib/crypto/mldsa.c
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Support for verifying ML-DSA signatures
+ *
+ * Copyright 2025 Google LLC
+ */
+
+#include <crypto/mldsa.h>
+#include <crypto/sha3.h>
+#include <kunit/visibility.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/unaligned.h>
+#include "fips-mldsa.h"
+
+#define Q 8380417 /* The prime q = 2^23 - 2^13 + 1 */
+#define QINV_MOD_2_32 58728449 /* Multiplicative inverse of q mod 2^32 */
+#define N 256 /* Number of components per ring element */
+#define D 13 /* Number of bits dropped from the public key vector t */
+#define RHO_LEN 32 /* Length of the public random seed in bytes */
+#define MAX_W1_ENCODED_LEN 192 /* Max encoded length of one element of w'_1 */
+
+/*
+ * The zetas array in Montgomery form, i.e. with extra factor of 2^32.
+ * Reference: FIPS 204 Section 7.5 "NTT and NTT^-1"
+ * Generated by the following Python code:
+ * q=8380417; [a%q - q*(a%q > q//2) for a in [1753**(int(f'{i:08b}'[::-1], 2)) << 32 for i in range(256)]]
+ */
+static const s32 zetas_times_2_32[N] = {
+ -4186625, 25847, -2608894, -518909, 237124, -777960, -876248,
+ 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855,
+ 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488,
+ -1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672,
+ 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325,
+ 3530437, -1661693, -3592148, -2537516, 3915439, -3861115, -3043716,
+ 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267,
+ -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596,
+ 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892,
+ -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950,
+ 2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144,
+ -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295,
+ -2967645, -3693493, -411027, -2477047, -671102, -1228525, -22981,
+ -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944,
+ 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342,
+ -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856,
+ 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589,
+ 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060,
+ -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478,
+ 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181,
+ -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542,
+ 819034, 495491, -1613174, -43260, -522500, -655327, -3122442,
+ 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297,
+ 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044,
+ 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353,
+ 1595974, -3767016, 1250494, 2635921, -3548272, -2994039, 1869119,
+ 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100,
+ 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803,
+ 1500165, 777191, 2235880, 3406031, -542412, -2831860, -1671176,
+ -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395,
+ 2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426,
+ 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107,
+ -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735,
+ 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333,
+ -260646, -3833893, -2939036, -2235985, -420899, -2286327, 183443,
+ -976891, 1612842, -3545687, -554416, 3919660, -48306, -1362209,
+ 3937738, 1400424, -846154, 1976782
+};
+
+/* Reference: FIPS 204 Section 4 "Parameter Sets" */
+static const struct mldsa_parameter_set {
+ u8 k; /* num rows in the matrix A */
+ u8 l; /* num columns in the matrix A */
+ u8 ctilde_len; /* length of commitment hash ctilde in bytes; lambda/4 */
+ u8 omega; /* max num of 1's in the hint vector h */
+ u8 tau; /* num of +-1's in challenge c */
+ u8 beta; /* tau times eta */
+ u16 pk_len; /* length of public keys in bytes */
+ u16 sig_len; /* length of signatures in bytes */
+ s32 gamma1; /* coefficient range of y */
+} mldsa_parameter_sets[] = {
+ [MLDSA44] = {
+ .k = 4,
+ .l = 4,
+ .ctilde_len = 32,
+ .omega = 80,
+ .tau = 39,
+ .beta = 78,
+ .pk_len = MLDSA44_PUBLIC_KEY_SIZE,
+ .sig_len = MLDSA44_SIGNATURE_SIZE,
+ .gamma1 = 1 << 17,
+ },
+ [MLDSA65] = {
+ .k = 6,
+ .l = 5,
+ .ctilde_len = 48,
+ .omega = 55,
+ .tau = 49,
+ .beta = 196,
+ .pk_len = MLDSA65_PUBLIC_KEY_SIZE,
+ .sig_len = MLDSA65_SIGNATURE_SIZE,
+ .gamma1 = 1 << 19,
+ },
+ [MLDSA87] = {
+ .k = 8,
+ .l = 7,
+ .ctilde_len = 64,
+ .omega = 75,
+ .tau = 60,
+ .beta = 120,
+ .pk_len = MLDSA87_PUBLIC_KEY_SIZE,
+ .sig_len = MLDSA87_SIGNATURE_SIZE,
+ .gamma1 = 1 << 19,
+ },
+};
+
+/*
+ * An element of the ring R_q (normal form) or the ring T_q (NTT form). It
+ * consists of N integers mod q: either the polynomial coefficients of the R_q
+ * element or the components of the T_q element. In either case, whether they
+ * are fully reduced to [0, q - 1] varies in the different parts of the code.
+ */
+struct mldsa_ring_elem {
+ s32 x[N];
+};
+
+struct mldsa_verification_workspace {
+ /* SHAKE context for computing c, mu, and ctildeprime */
+ struct shake_ctx shake;
+ /* The fields in this union are used in their order of declaration. */
+ union {
+ /* The hash of the public key */
+ u8 tr[64];
+ /* The message representative mu */
+ u8 mu[64];
+ /* Temporary space for rej_ntt_poly() */
+ u8 block[SHAKE128_BLOCK_SIZE + 1];
+ /* Encoded element of w'_1 */
+ u8 w1_encoded[MAX_W1_ENCODED_LEN];
+ /* The commitment hash. Real length is params->ctilde_len */
+ u8 ctildeprime[64];
+ };
+ /* SHAKE context for generating elements of the matrix A */
+ struct shake_ctx a_shake;
+ /*
+ * An element of the matrix A generated from the public seed, or an
+ * element of the vector t_1 decoded from the public key and pre-scaled
+ * by 2^d. Both are in NTT form. To reduce memory usage, we generate
+ * or decode these elements only as needed.
+ */
+ union {
+ struct mldsa_ring_elem a;
+ struct mldsa_ring_elem t1_scaled;
+ };
+ /* The challenge c, generated from ctilde */
+ struct mldsa_ring_elem c;
+ /* A temporary element used during calculations */
+ struct mldsa_ring_elem tmp;
+
+ /* The following fields are variable-length: */
+
+ /* The signer's response vector */
+ struct mldsa_ring_elem z[/* l */];
+
+ /* The signer's hint vector */
+ /* u8 h[k * N]; */
+};
+
+/*
+ * Compute a * b * 2^-32 mod q. a * b must be in the range [-2^31 * q, 2^31 * q
+ * - 1] before reduction. The return value is in the range [-q + 1, q - 1].
+ *
+ * To reduce mod q efficiently, this uses Montgomery reduction with R=2^32.
+ * That's where the factor of 2^-32 comes from. The caller must include a
+ * factor of 2^32 at some point to compensate for that.
+ *
+ * To keep the input and output ranges very close to symmetric, this
+ * specifically does a "signed" Montgomery reduction. That is, when computing
+ * d = c * q^-1 mod 2^32, this chooses a representative in [S32_MIN, S32_MAX]
+ * rather than [0, U32_MAX], i.e. s32 rather than u32. This matters in the
+ * wider multiplication d * Q when d keeps its value via sign extension.
+ *
+ * Reference: FIPS 204 Appendix A "Montgomery Multiplication". But, it doesn't
+ * explain it properly: it has an off-by-one error in the upper end of the input
+ * range, it doesn't clarify that the signed version should be used, and it
+ * gives an unnecessarily large output range. A better citation is perhaps the
+ * Dilithium reference code, which functionally matches the below code and
+ * merely has the (benign) off-by-one error in its documentation.
+ */
+static inline s32 Zq_mult(s32 a, s32 b)
+{
+ /* Compute the unreduced product c. */
+ s64 c = (s64)a * b;
+
+ /*
+ * Compute d = c * q^-1 mod 2^32. Generate a signed result, as
+ * explained above, but do the actual multiplication using an unsigned
+ * type to avoid signed integer overflow which is undefined behavior.
+ */
+ s32 d = (u32)c * QINV_MOD_2_32;
+
+ /*
+ * Compute e = c - d * q. This makes the low 32 bits zero, since
+ * c - (c * q^-1) * q mod 2^32
+ * = c - c * (q^-1 * q) mod 2^32
+ * = c - c * 1 mod 2^32
+ * = c - c mod 2^32
+ * = 0 mod 2^32
+ */
+ s64 e = c - (s64)d * Q;
+
+ /* Finally, return e * 2^-32. */
+ return e >> 32;
+}
+
+/*
+ * Convert @w to its number-theoretically-transformed representation in-place.
+ * Reference: FIPS 204 Algorithm 41, NTT
+ *
+ * To prevent intermediate overflows, all input coefficients must have absolute
+ * value < q. All output components have absolute value < 9*q.
+ */
+static void ntt(struct mldsa_ring_elem *w)
+{
+ int m = 0; /* index in zetas_times_2_32 */
+
+ for (int len = 128; len >= 1; len /= 2) {
+ for (int start = 0; start < 256; start += 2 * len) {
+ const s32 z = zetas_times_2_32[++m];
+
+ for (int j = start; j < start + len; j++) {
+ s32 t = Zq_mult(z, w->x[j + len]);
+
+ w->x[j + len] = w->x[j] - t;
+ w->x[j] += t;
+ }
+ }
+ }
+}
+
+/*
+ * Convert @w from its number-theoretically-transformed representation in-place.
+ * Reference: FIPS 204 Algorithm 42, NTT^-1
+ *
+ * This also multiplies the coefficients by 2^32, undoing an extra factor of
+ * 2^-32 introduced earlier, and reduces the coefficients to [0, q - 1].
+ */
+static void invntt_and_mul_2_32(struct mldsa_ring_elem *w)
+{
+ int m = 256; /* index in zetas_times_2_32 */
+
+ /* Prevent intermediate overflows. */
+ for (int j = 0; j < 256; j++)
+ w->x[j] %= Q;
+
+ for (int len = 1; len < 256; len *= 2) {
+ for (int start = 0; start < 256; start += 2 * len) {
+ const s32 z = -zetas_times_2_32[--m];
+
+ for (int j = start; j < start + len; j++) {
+ s32 t = w->x[j];
+
+ w->x[j] = t + w->x[j + len];
+ w->x[j + len] = Zq_mult(z, t - w->x[j + len]);
+ }
+ }
+ }
+ /*
+ * Multiply by 2^32 * 256^-1. 2^32 cancels the factor of 2^-32 from
+ * earlier Montgomery multiplications. 256^-1 is for NTT^-1. This
+ * itself uses Montgomery multiplication, so *another* 2^32 is needed.
+ * Thus the actual multiplicand is 2^32 * 2^32 * 256^-1 mod q = 41978.
+ *
+ * Finally, also reduce from [-q + 1, q - 1] to [0, q - 1].
+ */
+ for (int j = 0; j < 256; j++) {
+ w->x[j] = Zq_mult(w->x[j], 41978);
+ w->x[j] += (w->x[j] >> 31) & Q;
+ }
+}
+
+/*
+ * Decode an element of t_1, i.e. the high d bits of t = A*s_1 + s_2.
+ * Reference: FIPS 204 Algorithm 23, pkDecode.
+ * Also multiply it by 2^d and convert it to NTT form.
+ */
+static const u8 *decode_t1_elem(struct mldsa_ring_elem *out,
+ const u8 *t1_encoded)
+{
+ for (int j = 0; j < N; j += 4, t1_encoded += 5) {
+ u32 v = get_unaligned_le32(t1_encoded);
+
+ out->x[j + 0] = ((v >> 0) & 0x3ff) << D;
+ out->x[j + 1] = ((v >> 10) & 0x3ff) << D;
+ out->x[j + 2] = ((v >> 20) & 0x3ff) << D;
+ out->x[j + 3] = ((v >> 30) | (t1_encoded[4] << 2)) << D;
+ static_assert(0x3ff << D < Q); /* All coefficients < q. */
+ }
+ ntt(out);
+ return t1_encoded; /* Return updated pointer. */
+}
+
+/*
+ * Decode the signer's response vector 'z' from the signature.
+ * Reference: FIPS 204 Algorithm 27, sigDecode.
+ *
+ * This also validates that the coefficients of z are in range, corresponding
+ * the infinity norm check at the end of Algorithm 8, ML-DSA.Verify_internal.
+ *
+ * Finally, this also converts z to NTT form.
+ */
+static bool decode_z(struct mldsa_ring_elem z[/* l */], int l, s32 gamma1,
+ int beta, const u8 **sig_ptr)
+{
+ const u8 *sig = *sig_ptr;
+
+ for (int i = 0; i < l; i++) {
+ if (l == 4) { /* ML-DSA-44? */
+ /* 18-bit coefficients: decode 4 from 9 bytes. */
+ for (int j = 0; j < N; j += 4, sig += 9) {
+ u64 v = get_unaligned_le64(sig);
+
+ z[i].x[j + 0] = (v >> 0) & 0x3ffff;
+ z[i].x[j + 1] = (v >> 18) & 0x3ffff;
+ z[i].x[j + 2] = (v >> 36) & 0x3ffff;
+ z[i].x[j + 3] = (v >> 54) | (sig[8] << 10);
+ }
+ } else {
+ /* 20-bit coefficients: decode 4 from 10 bytes. */
+ for (int j = 0; j < N; j += 4, sig += 10) {
+ u64 v = get_unaligned_le64(sig);
+
+ z[i].x[j + 0] = (v >> 0) & 0xfffff;
+ z[i].x[j + 1] = (v >> 20) & 0xfffff;
+ z[i].x[j + 2] = (v >> 40) & 0xfffff;
+ z[i].x[j + 3] =
+ (v >> 60) |
+ (get_unaligned_le16(&sig[8]) << 4);
+ }
+ }
+ for (int j = 0; j < N; j++) {
+ z[i].x[j] = gamma1 - z[i].x[j];
+ if (z[i].x[j] <= -(gamma1 - beta) ||
+ z[i].x[j] >= gamma1 - beta)
+ return false;
+ }
+ ntt(&z[i]);
+ }
+ *sig_ptr = sig; /* Return updated pointer. */
+ return true;
+}
+
+/*
+ * Decode the signer's hint vector 'h' from the signature.
+ * Reference: FIPS 204 Algorithm 21, HintBitUnpack
+ *
+ * Note that there are several ways in which the hint vector can be malformed.
+ */
+static bool decode_hint_vector(u8 h[/* k * N */], int k, int omega, const u8 *y)
+{
+ int index = 0;
+
+ memset(h, 0, k * N);
+ for (int i = 0; i < k; i++) {
+ int count = y[omega + i]; /* num 1's in elems 0 through i */
+ int prev = -1;
+
+ /* Cumulative count mustn't decrease or exceed omega. */
+ if (count < index || count > omega)
+ return false;
+ for (; index < count; index++) {
+ if (prev >= y[index]) /* Coefficients out of order? */
+ return false;
+ prev = y[index];
+ h[i * N + y[index]] = 1;
+ }
+ }
+ return mem_is_zero(&y[index], omega - index);
+}
+
+/*
+ * Expand @seed into an element of R_q @c with coefficients in {-1, 0, 1},
+ * exactly @tau of them nonzero. Reference: FIPS 204 Algorithm 29, SampleInBall
+ */
+static void sample_in_ball(struct mldsa_ring_elem *c, const u8 *seed,
+ size_t seed_len, int tau, struct shake_ctx *shake)
+{
+ u64 signs;
+ u8 j;
+
+ shake256_init(shake);
+ shake_update(shake, seed, seed_len);
+ shake_squeeze(shake, (u8 *)&signs, sizeof(signs));
+ le64_to_cpus(&signs);
+ *c = (struct mldsa_ring_elem){};
+ for (int i = N - tau; i < N; i++, signs >>= 1) {
+ do {
+ shake_squeeze(shake, &j, 1);
+ } while (j > i);
+ c->x[i] = c->x[j];
+ c->x[j] = 1 - 2 * (s32)(signs & 1);
+ }
+}
+
+/*
+ * Expand the public seed @rho and @row_and_column into an element of T_q @out.
+ * Reference: FIPS 204 Algorithm 30, RejNTTPoly
+ *
+ * @shake and @block are temporary space used by the expansion. @block has
+ * space for one SHAKE128 block, plus an extra byte to allow reading a u32 from
+ * the final 3-byte group without reading out-of-bounds.
+ */
+static void rej_ntt_poly(struct mldsa_ring_elem *out, const u8 rho[RHO_LEN],
+ __le16 row_and_column, struct shake_ctx *shake,
+ u8 block[SHAKE128_BLOCK_SIZE + 1])
+{
+ shake128_init(shake);
+ shake_update(shake, rho, RHO_LEN);
+ shake_update(shake, (u8 *)&row_and_column, sizeof(row_and_column));
+ for (int i = 0; i < N;) {
+ shake_squeeze(shake, block, SHAKE128_BLOCK_SIZE);
+ block[SHAKE128_BLOCK_SIZE] = 0; /* for KMSAN */
+ static_assert(SHAKE128_BLOCK_SIZE % 3 == 0);
+ for (int j = 0; j < SHAKE128_BLOCK_SIZE && i < N; j += 3) {
+ u32 x = get_unaligned_le32(&block[j]) & 0x7fffff;
+
+ if (x < Q) /* Ignore values >= q. */
+ out->x[i++] = x;
+ }
+ }
+}
+
+/*
+ * Return the HighBits of r adjusted according to hint h
+ * Reference: FIPS 204 Algorithm 40, UseHint
+ *
+ * This is needed because of the public key compression in ML-DSA.
+ *
+ * h is either 0 or 1, r is in [0, q - 1], and gamma2 is either (q - 1) / 88 or
+ * (q - 1) / 32. Except when invoked via the unit test interface, gamma2 is a
+ * compile-time constant, so compilers will optimize the code accordingly.
+ */
+static __always_inline s32 use_hint(u8 h, s32 r, const s32 gamma2)
+{
+ const s32 m = (Q - 1) / (2 * gamma2); /* 44 or 16, compile-time const */
+ s32 r1;
+
+ /*
+ * Handle the special case where r - (r mod+- (2 * gamma2)) == q - 1,
+ * i.e. r >= q - gamma2. This is also exactly where the computation of
+ * r1 below would produce 'm' and would need a correction.
+ */
+ if (r >= Q - gamma2)
+ return h == 0 ? 0 : m - 1;
+
+ /*
+ * Compute the (non-hint-adjusted) HighBits r1 as:
+ *
+ * r1 = (r - (r mod+- (2 * gamma2))) / (2 * gamma2)
+ * = floor((r + gamma2 - 1) / (2 * gamma2))
+ *
+ * Note that when '2 * gamma2' is a compile-time constant, compilers
+ * optimize the division to a reciprocal multiplication and shift.
+ */
+ r1 = (u32)(r + gamma2 - 1) / (2 * gamma2);
+
+ /*
+ * Return the HighBits r1:
+ * + 0 if the hint is 0;
+ * + 1 (mod m) if the hint is 1 and the LowBits are positive;
+ * - 1 (mod m) if the hint is 1 and the LowBits are negative or 0.
+ *
+ * r1 is in (and remains in) [0, m - 1]. Note that when 'm' is a
+ * compile-time constant, compilers optimize the '% m' accordingly.
+ */
+ if (h == 0)
+ return r1;
+ if (r > r1 * (2 * gamma2))
+ return (u32)(r1 + 1) % m;
+ return (u32)(r1 + m - 1) % m;
+}
+
+static __always_inline void use_hint_elem(struct mldsa_ring_elem *w,
+ const u8 h[N], const s32 gamma2)
+{
+ for (int j = 0; j < N; j++)
+ w->x[j] = use_hint(h[j], w->x[j], gamma2);
+}
+
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_MLDSA_KUNIT_TEST)
+/* Allow the __always_inline function use_hint() to be unit-tested. */
+s32 mldsa_use_hint(u8 h, s32 r, s32 gamma2)
+{
+ return use_hint(h, r, gamma2);
+}
+EXPORT_SYMBOL_IF_KUNIT(mldsa_use_hint);
+#endif
+
+/*
+ * Encode one element of the commitment vector w'_1 into a byte string.
+ * Reference: FIPS 204 Algorithm 28, w1Encode.
+ * Return the number of bytes used: 192 for ML-DSA-44 and 128 for the others.
+ */
+static size_t encode_w1(u8 out[MAX_W1_ENCODED_LEN],
+ const struct mldsa_ring_elem *w1, int k)
+{
+ size_t pos = 0;
+
+ static_assert(N * 6 / 8 == MAX_W1_ENCODED_LEN);
+ if (k == 4) { /* ML-DSA-44? */
+ /* 6 bits per coefficient. Pack 4 at a time. */
+ for (int j = 0; j < N; j += 4) {
+ u32 v = (w1->x[j + 0] << 0) | (w1->x[j + 1] << 6) |
+ (w1->x[j + 2] << 12) | (w1->x[j + 3] << 18);
+ out[pos++] = v >> 0;
+ out[pos++] = v >> 8;
+ out[pos++] = v >> 16;
+ }
+ } else {
+ /* 4 bits per coefficient. Pack 2 at a time. */
+ for (int j = 0; j < N; j += 2)
+ out[pos++] = w1->x[j] | (w1->x[j + 1] << 4);
+ }
+ return pos;
+}
+
+int mldsa_verify(enum mldsa_alg alg, const u8 *sig, size_t sig_len,
+ const u8 *msg, size_t msg_len, const u8 *pk, size_t pk_len)
+{
+ const struct mldsa_parameter_set *params = &mldsa_parameter_sets[alg];
+ const int k = params->k, l = params->l;
+ /* For now this just does pure ML-DSA with an empty context string. */
+ static const u8 msg_prefix[2] = { /* dom_sep= */ 0, /* ctx_len= */ 0 };
+ const u8 *ctilde; /* The signer's commitment hash */
+ const u8 *t1_encoded = &pk[RHO_LEN]; /* Next encoded element of t_1 */
+ u8 *h; /* The signer's hint vector, length k * N */
+ size_t w1_enc_len;
+
+ /* Validate the public key and signature lengths. */
+ if (pk_len != params->pk_len || sig_len != params->sig_len)
+ return -EBADMSG;
+
+ /*
+ * Allocate the workspace, including variable-length fields. Its size
+ * depends only on the ML-DSA parameter set, not the other inputs.
+ *
+ * For freeing it, use kfree_sensitive() rather than kfree(). This is
+ * mainly to comply with FIPS 204 Section 3.6.3 "Intermediate Values".
+ * In reality it's a bit gratuitous, as this is a public key operation.
+ */
+ struct mldsa_verification_workspace *ws __free(kfree_sensitive) =
+ kmalloc(sizeof(*ws) + (l * sizeof(ws->z[0])) + (k * N),
+ GFP_KERNEL);
+ if (!ws)
+ return -ENOMEM;
+ h = (u8 *)&ws->z[l];
+
+ /* Decode the signature. Reference: FIPS 204 Algorithm 27, sigDecode */
+ ctilde = sig;
+ sig += params->ctilde_len;
+ if (!decode_z(ws->z, l, params->gamma1, params->beta, &sig))
+ return -EBADMSG;
+ if (!decode_hint_vector(h, k, params->omega, sig))
+ return -EBADMSG;
+
+ /* Recreate the challenge c from the signer's commitment hash. */
+ sample_in_ball(&ws->c, ctilde, params->ctilde_len, params->tau,
+ &ws->shake);
+ ntt(&ws->c);
+
+ /* Compute the message representative mu. */
+ shake256(pk, pk_len, ws->tr, sizeof(ws->tr));
+ shake256_init(&ws->shake);
+ shake_update(&ws->shake, ws->tr, sizeof(ws->tr));
+ shake_update(&ws->shake, msg_prefix, sizeof(msg_prefix));
+ shake_update(&ws->shake, msg, msg_len);
+ shake_squeeze(&ws->shake, ws->mu, sizeof(ws->mu));
+
+ /* Start computing ctildeprime = H(mu || w1Encode(w'_1)). */
+ shake256_init(&ws->shake);
+ shake_update(&ws->shake, ws->mu, sizeof(ws->mu));
+
+ /*
+ * Compute the commitment w'_1 from A, z, c, t_1, and h.
+ *
+ * The computation is the same for each of the k rows. Just do each row
+ * before moving on to the next, resulting in only one loop over k.
+ */
+ for (int i = 0; i < k; i++) {
+ /*
+ * tmp = NTT(A) * NTT(z) * 2^-32
+ * To reduce memory use, generate each element of NTT(A)
+ * on-demand. Note that each element is used only once.
+ */
+ ws->tmp = (struct mldsa_ring_elem){};
+ for (int j = 0; j < l; j++) {
+ rej_ntt_poly(&ws->a, pk /* rho is first field of pk */,
+ cpu_to_le16((i << 8) | j), &ws->a_shake,
+ ws->block);
+ for (int n = 0; n < N; n++)
+ ws->tmp.x[n] +=
+ Zq_mult(ws->a.x[n], ws->z[j].x[n]);
+ }
+ /* All components of tmp now have abs value < l*q. */
+
+ /* Decode the next element of t_1. */
+ t1_encoded = decode_t1_elem(&ws->t1_scaled, t1_encoded);
+
+ /*
+ * tmp -= NTT(c) * NTT(t_1 * 2^d) * 2^-32
+ *
+ * Taking a conservative bound for the output of ntt(), the
+ * multiplicands can have absolute value up to 9*q. That
+ * corresponds to a product with absolute value 81*q^2. That is
+ * within the limits of Zq_mult() which needs < ~256*q^2.
+ */
+ for (int j = 0; j < N; j++)
+ ws->tmp.x[j] -= Zq_mult(ws->c.x[j], ws->t1_scaled.x[j]);
+ /* All components of tmp now have abs value < (l+1)*q. */
+
+ /* tmp = w'_Approx = NTT^-1(tmp) * 2^32 */
+ invntt_and_mul_2_32(&ws->tmp);
+ /* All coefficients of tmp are now in [0, q - 1]. */
+
+ /*
+ * tmp = w'_1 = UseHint(h, w'_Approx)
+ * For efficiency, set gamma2 to a compile-time constant.
+ */
+ if (k == 4)
+ use_hint_elem(&ws->tmp, &h[i * N], (Q - 1) / 88);
+ else
+ use_hint_elem(&ws->tmp, &h[i * N], (Q - 1) / 32);
+
+ /* Encode and hash the next element of w'_1. */
+ w1_enc_len = encode_w1(ws->w1_encoded, &ws->tmp, k);
+ shake_update(&ws->shake, ws->w1_encoded, w1_enc_len);
+ }
+
+ /* Finish computing ctildeprime. */
+ shake_squeeze(&ws->shake, ws->ctildeprime, params->ctilde_len);
+
+ /* Verify that ctilde == ctildeprime. */
+ if (memcmp(ws->ctildeprime, ctilde, params->ctilde_len) != 0)
+ return -EKEYREJECTED;
+ /* ||z||_infinity < gamma1 - beta was already checked in decode_z(). */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mldsa_verify);
+
+#ifdef CONFIG_CRYPTO_FIPS
+static int __init mldsa_mod_init(void)
+{
+ if (fips_enabled) {
+ /*
+ * FIPS cryptographic algorithm self-test. As per the FIPS
+ * Implementation Guidance, testing any ML-DSA parameter set
+ * satisfies the test requirement for all of them, and only a
+ * positive test is required.
+ */
+ int err = mldsa_verify(MLDSA65, fips_test_mldsa65_signature,
+ sizeof(fips_test_mldsa65_signature),
+ fips_test_mldsa65_message,
+ sizeof(fips_test_mldsa65_message),
+ fips_test_mldsa65_public_key,
+ sizeof(fips_test_mldsa65_public_key));
+ if (err)
+ panic("mldsa: FIPS self-test failed; err=%pe\n",
+ ERR_PTR(err));
+ }
+ return 0;
+}
+subsys_initcall(mldsa_mod_init);
+
+static void __exit mldsa_mod_exit(void)
+{
+}
+module_exit(mldsa_mod_exit);
+#endif /* CONFIG_CRYPTO_FIPS */
+
+MODULE_DESCRIPTION("ML-DSA signature verification");
+MODULE_LICENSE("GPL");
diff --git a/lib/crypto/mpi/mpih-mul.c b/lib/crypto/mpi/mpih-mul.c
index a93647564054..29dd80609c47 100644
--- a/lib/crypto/mpi/mpih-mul.c
+++ b/lib/crypto/mpi/mpih-mul.c
@@ -372,7 +372,7 @@ mpihelp_mul_karatsuba_case(mpi_ptr_t prodp,
return -ENOMEM;
} else {
if (!ctx->next) {
- ctx->next = kzalloc(sizeof *ctx, GFP_KERNEL);
+ ctx->next = kzalloc_obj(*ctx);
if (!ctx->next)
return -ENOMEM;
}
diff --git a/lib/crypto/mpi/mpiutil.c b/lib/crypto/mpi/mpiutil.c
index 7f2db830f404..f4faf7c903f9 100644
--- a/lib/crypto/mpi/mpiutil.c
+++ b/lib/crypto/mpi/mpiutil.c
@@ -33,7 +33,7 @@ MPI mpi_alloc(unsigned nlimbs)
{
MPI a;
- a = kmalloc(sizeof *a, GFP_KERNEL);
+ a = kmalloc_obj(*a);
if (!a)
return a;
@@ -93,14 +93,14 @@ int mpi_resize(MPI a, unsigned nlimbs)
return 0; /* no need to do it */
if (a->d) {
- p = kcalloc(nlimbs, sizeof(mpi_limb_t), GFP_KERNEL);
+ p = kzalloc_objs(mpi_limb_t, nlimbs);
if (!p)
return -ENOMEM;
memcpy(p, a->d, a->alloced * sizeof(mpi_limb_t));
kfree_sensitive(a->d);
a->d = p;
} else {
- a->d = kcalloc(nlimbs, sizeof(mpi_limb_t), GFP_KERNEL);
+ a->d = kzalloc_objs(mpi_limb_t, nlimbs);
if (!a->d)
return -ENOMEM;
}
diff --git a/lib/crypto/nh.c b/lib/crypto/nh.c
new file mode 100644
index 000000000000..e1d0095b5289
--- /dev/null
+++ b/lib/crypto/nh.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 Google LLC
+ */
+
+/*
+ * Implementation of the NH almost-universal hash function, specifically the
+ * variant of NH used in Adiantum. This is *not* a cryptographic hash function.
+ *
+ * Reference: section 6.3 of "Adiantum: length-preserving encryption for
+ * entry-level processors" (https://eprint.iacr.org/2018/720.pdf).
+ */
+
+#include <crypto/nh.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/unaligned.h>
+
+#ifdef CONFIG_CRYPTO_LIB_NH_ARCH
+#include "nh.h" /* $(SRCARCH)/nh.h */
+#else
+static bool nh_arch(const u32 *key, const u8 *message, size_t message_len,
+ __le64 hash[NH_NUM_PASSES])
+{
+ return false;
+}
+#endif
+
+void nh(const u32 *key, const u8 *message, size_t message_len,
+ __le64 hash[NH_NUM_PASSES])
+{
+ u64 sums[4] = { 0, 0, 0, 0 };
+
+ if (nh_arch(key, message, message_len, hash))
+ return;
+
+ static_assert(NH_PAIR_STRIDE == 2);
+ static_assert(NH_NUM_PASSES == 4);
+
+ while (message_len) {
+ u32 m0 = get_unaligned_le32(message + 0);
+ u32 m1 = get_unaligned_le32(message + 4);
+ u32 m2 = get_unaligned_le32(message + 8);
+ u32 m3 = get_unaligned_le32(message + 12);
+
+ sums[0] += (u64)(u32)(m0 + key[0]) * (u32)(m2 + key[2]);
+ sums[1] += (u64)(u32)(m0 + key[4]) * (u32)(m2 + key[6]);
+ sums[2] += (u64)(u32)(m0 + key[8]) * (u32)(m2 + key[10]);
+ sums[3] += (u64)(u32)(m0 + key[12]) * (u32)(m2 + key[14]);
+ sums[0] += (u64)(u32)(m1 + key[1]) * (u32)(m3 + key[3]);
+ sums[1] += (u64)(u32)(m1 + key[5]) * (u32)(m3 + key[7]);
+ sums[2] += (u64)(u32)(m1 + key[9]) * (u32)(m3 + key[11]);
+ sums[3] += (u64)(u32)(m1 + key[13]) * (u32)(m3 + key[15]);
+ key += NH_MESSAGE_UNIT / sizeof(key[0]);
+ message += NH_MESSAGE_UNIT;
+ message_len -= NH_MESSAGE_UNIT;
+ }
+
+ hash[0] = cpu_to_le64(sums[0]);
+ hash[1] = cpu_to_le64(sums[1]);
+ hash[2] = cpu_to_le64(sums[2]);
+ hash[3] = cpu_to_le64(sums[3]);
+}
+EXPORT_SYMBOL_GPL(nh);
+
+#ifdef nh_mod_init_arch
+static int __init nh_mod_init(void)
+{
+ nh_mod_init_arch();
+ return 0;
+}
+subsys_initcall(nh_mod_init);
+
+static void __exit nh_mod_exit(void)
+{
+}
+module_exit(nh_mod_exit);
+#endif
+
+MODULE_DESCRIPTION("NH almost-universal hash function");
+MODULE_LICENSE("GPL");
diff --git a/lib/crypto/powerpc/.gitignore b/lib/crypto/powerpc/.gitignore
new file mode 100644
index 000000000000..598ca7aff6b1
--- /dev/null
+++ b/lib/crypto/powerpc/.gitignore
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+aesp8-ppc.S
diff --git a/lib/crypto/powerpc/aes-spe-core.S b/lib/crypto/powerpc/aes-spe-core.S
new file mode 100644
index 000000000000..8e00eccc352b
--- /dev/null
+++ b/lib/crypto/powerpc/aes-spe-core.S
@@ -0,0 +1,346 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Fast AES implementation for SPE instruction set (PPC)
+ *
+ * This code makes use of the SPE SIMD instruction set as defined in
+ * http://cache.freescale.com/files/32bit/doc/ref_manual/SPEPIM.pdf
+ * Implementation is based on optimization guide notes from
+ * http://cache.freescale.com/files/32bit/doc/app_note/AN2665.pdf
+ *
+ * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de>
+ */
+
+#include <asm/ppc_asm.h>
+#include "aes-spe-regs.h"
+
+#define EAD(in, bpos) \
+ rlwimi rT0,in,28-((bpos+3)%4)*8,20,27;
+
+#define DAD(in, bpos) \
+ rlwimi rT1,in,24-((bpos+3)%4)*8,24,31;
+
+#define LWH(out, off) \
+ evlwwsplat out,off(rT0); /* load word high */
+
+#define LWL(out, off) \
+ lwz out,off(rT0); /* load word low */
+
+#define LBZ(out, tab, off) \
+ lbz out,off(tab); /* load byte */
+
+#define LAH(out, in, bpos, off) \
+ EAD(in, bpos) /* calc addr + load word high */ \
+ LWH(out, off)
+
+#define LAL(out, in, bpos, off) \
+ EAD(in, bpos) /* calc addr + load word low */ \
+ LWL(out, off)
+
+#define LAE(out, in, bpos) \
+ EAD(in, bpos) /* calc addr + load enc byte */ \
+ LBZ(out, rT0, 8)
+
+#define LBE(out) \
+ LBZ(out, rT0, 8) /* load enc byte */
+
+#define LAD(out, in, bpos) \
+ DAD(in, bpos) /* calc addr + load dec byte */ \
+ LBZ(out, rT1, 0)
+
+#define LBD(out) \
+ LBZ(out, rT1, 0)
+
+/*
+ * ppc_encrypt_block: The central encryption function for a single 16 bytes
+ * block. It does no stack handling or register saving to support fast calls
+ * via bl/blr. It expects that caller has pre-xored input data with first
+ * 4 words of encryption key into rD0-rD3. Pointer/counter registers must
+ * have also been set up before (rT0, rKP, CTR). Output is stored in rD0-rD3
+ * and rW0-rW3 and caller must execute a final xor on the output registers.
+ * All working registers rD0-rD3 & rW0-rW7 are overwritten during processing.
+ *
+ */
+_GLOBAL(ppc_encrypt_block)
+ LAH(rW4, rD1, 2, 4)
+ LAH(rW6, rD0, 3, 0)
+ LAH(rW3, rD0, 1, 8)
+ppc_encrypt_block_loop:
+ LAH(rW0, rD3, 0, 12)
+ LAL(rW0, rD0, 0, 12)
+ LAH(rW1, rD1, 0, 12)
+ LAH(rW2, rD2, 1, 8)
+ LAL(rW2, rD3, 1, 8)
+ LAL(rW3, rD1, 1, 8)
+ LAL(rW4, rD2, 2, 4)
+ LAL(rW6, rD1, 3, 0)
+ LAH(rW5, rD3, 2, 4)
+ LAL(rW5, rD0, 2, 4)
+ LAH(rW7, rD2, 3, 0)
+ evldw rD1,16(rKP)
+ EAD(rD3, 3)
+ evxor rW2,rW2,rW4
+ LWL(rW7, 0)
+ evxor rW2,rW2,rW6
+ EAD(rD2, 0)
+ evxor rD1,rD1,rW2
+ LWL(rW1, 12)
+ evxor rD1,rD1,rW0
+ evldw rD3,24(rKP)
+ evmergehi rD0,rD0,rD1
+ EAD(rD1, 2)
+ evxor rW3,rW3,rW5
+ LWH(rW4, 4)
+ evxor rW3,rW3,rW7
+ EAD(rD0, 3)
+ evxor rD3,rD3,rW3
+ LWH(rW6, 0)
+ evxor rD3,rD3,rW1
+ EAD(rD0, 1)
+ evmergehi rD2,rD2,rD3
+ LWH(rW3, 8)
+ LAH(rW0, rD3, 0, 12)
+ LAL(rW0, rD0, 0, 12)
+ LAH(rW1, rD1, 0, 12)
+ LAH(rW2, rD2, 1, 8)
+ LAL(rW2, rD3, 1, 8)
+ LAL(rW3, rD1, 1, 8)
+ LAL(rW4, rD2, 2, 4)
+ LAL(rW6, rD1, 3, 0)
+ LAH(rW5, rD3, 2, 4)
+ LAL(rW5, rD0, 2, 4)
+ LAH(rW7, rD2, 3, 0)
+ evldw rD1,32(rKP)
+ EAD(rD3, 3)
+ evxor rW2,rW2,rW4
+ LWL(rW7, 0)
+ evxor rW2,rW2,rW6
+ EAD(rD2, 0)
+ evxor rD1,rD1,rW2
+ LWL(rW1, 12)
+ evxor rD1,rD1,rW0
+ evldw rD3,40(rKP)
+ evmergehi rD0,rD0,rD1
+ EAD(rD1, 2)
+ evxor rW3,rW3,rW5
+ LWH(rW4, 4)
+ evxor rW3,rW3,rW7
+ EAD(rD0, 3)
+ evxor rD3,rD3,rW3
+ LWH(rW6, 0)
+ evxor rD3,rD3,rW1
+ EAD(rD0, 1)
+ evmergehi rD2,rD2,rD3
+ LWH(rW3, 8)
+ addi rKP,rKP,32
+ bdnz ppc_encrypt_block_loop
+ LAH(rW0, rD3, 0, 12)
+ LAL(rW0, rD0, 0, 12)
+ LAH(rW1, rD1, 0, 12)
+ LAH(rW2, rD2, 1, 8)
+ LAL(rW2, rD3, 1, 8)
+ LAL(rW3, rD1, 1, 8)
+ LAL(rW4, rD2, 2, 4)
+ LAH(rW5, rD3, 2, 4)
+ LAL(rW6, rD1, 3, 0)
+ LAL(rW5, rD0, 2, 4)
+ LAH(rW7, rD2, 3, 0)
+ evldw rD1,16(rKP)
+ EAD(rD3, 3)
+ evxor rW2,rW2,rW4
+ LWL(rW7, 0)
+ evxor rW2,rW2,rW6
+ EAD(rD2, 0)
+ evxor rD1,rD1,rW2
+ LWL(rW1, 12)
+ evxor rD1,rD1,rW0
+ evldw rD3,24(rKP)
+ evmergehi rD0,rD0,rD1
+ EAD(rD1, 0)
+ evxor rW3,rW3,rW5
+ LBE(rW2)
+ evxor rW3,rW3,rW7
+ EAD(rD0, 1)
+ evxor rD3,rD3,rW3
+ LBE(rW6)
+ evxor rD3,rD3,rW1
+ EAD(rD0, 0)
+ evmergehi rD2,rD2,rD3
+ LBE(rW1)
+ LAE(rW0, rD3, 0)
+ LAE(rW1, rD0, 0)
+ LAE(rW4, rD2, 1)
+ LAE(rW5, rD3, 1)
+ LAE(rW3, rD2, 0)
+ LAE(rW7, rD1, 1)
+ rlwimi rW0,rW4,8,16,23
+ rlwimi rW1,rW5,8,16,23
+ LAE(rW4, rD1, 2)
+ LAE(rW5, rD2, 2)
+ rlwimi rW2,rW6,8,16,23
+ rlwimi rW3,rW7,8,16,23
+ LAE(rW6, rD3, 2)
+ LAE(rW7, rD0, 2)
+ rlwimi rW0,rW4,16,8,15
+ rlwimi rW1,rW5,16,8,15
+ LAE(rW4, rD0, 3)
+ LAE(rW5, rD1, 3)
+ rlwimi rW2,rW6,16,8,15
+ lwz rD0,32(rKP)
+ rlwimi rW3,rW7,16,8,15
+ lwz rD1,36(rKP)
+ LAE(rW6, rD2, 3)
+ LAE(rW7, rD3, 3)
+ rlwimi rW0,rW4,24,0,7
+ lwz rD2,40(rKP)
+ rlwimi rW1,rW5,24,0,7
+ lwz rD3,44(rKP)
+ rlwimi rW2,rW6,24,0,7
+ rlwimi rW3,rW7,24,0,7
+ blr
+
+/*
+ * ppc_decrypt_block: The central decryption function for a single 16 bytes
+ * block. It does no stack handling or register saving to support fast calls
+ * via bl/blr. It expects that caller has pre-xored input data with first
+ * 4 words of encryption key into rD0-rD3. Pointer/counter registers must
+ * have also been set up before (rT0, rKP, CTR). Output is stored in rD0-rD3
+ * and rW0-rW3 and caller must execute a final xor on the output registers.
+ * All working registers rD0-rD3 & rW0-rW7 are overwritten during processing.
+ *
+ */
+_GLOBAL(ppc_decrypt_block)
+ LAH(rW0, rD1, 0, 12)
+ LAH(rW6, rD0, 3, 0)
+ LAH(rW3, rD0, 1, 8)
+ppc_decrypt_block_loop:
+ LAH(rW1, rD3, 0, 12)
+ LAL(rW0, rD2, 0, 12)
+ LAH(rW2, rD2, 1, 8)
+ LAL(rW2, rD3, 1, 8)
+ LAH(rW4, rD3, 2, 4)
+ LAL(rW4, rD0, 2, 4)
+ LAL(rW6, rD1, 3, 0)
+ LAH(rW5, rD1, 2, 4)
+ LAH(rW7, rD2, 3, 0)
+ LAL(rW7, rD3, 3, 0)
+ LAL(rW3, rD1, 1, 8)
+ evldw rD1,16(rKP)
+ EAD(rD0, 0)
+ evxor rW4,rW4,rW6
+ LWL(rW1, 12)
+ evxor rW0,rW0,rW4
+ EAD(rD2, 2)
+ evxor rW0,rW0,rW2
+ LWL(rW5, 4)
+ evxor rD1,rD1,rW0
+ evldw rD3,24(rKP)
+ evmergehi rD0,rD0,rD1
+ EAD(rD1, 0)
+ evxor rW3,rW3,rW7
+ LWH(rW0, 12)
+ evxor rW3,rW3,rW1
+ EAD(rD0, 3)
+ evxor rD3,rD3,rW3
+ LWH(rW6, 0)
+ evxor rD3,rD3,rW5
+ EAD(rD0, 1)
+ evmergehi rD2,rD2,rD3
+ LWH(rW3, 8)
+ LAH(rW1, rD3, 0, 12)
+ LAL(rW0, rD2, 0, 12)
+ LAH(rW2, rD2, 1, 8)
+ LAL(rW2, rD3, 1, 8)
+ LAH(rW4, rD3, 2, 4)
+ LAL(rW4, rD0, 2, 4)
+ LAL(rW6, rD1, 3, 0)
+ LAH(rW5, rD1, 2, 4)
+ LAH(rW7, rD2, 3, 0)
+ LAL(rW7, rD3, 3, 0)
+ LAL(rW3, rD1, 1, 8)
+ evldw rD1,32(rKP)
+ EAD(rD0, 0)
+ evxor rW4,rW4,rW6
+ LWL(rW1, 12)
+ evxor rW0,rW0,rW4
+ EAD(rD2, 2)
+ evxor rW0,rW0,rW2
+ LWL(rW5, 4)
+ evxor rD1,rD1,rW0
+ evldw rD3,40(rKP)
+ evmergehi rD0,rD0,rD1
+ EAD(rD1, 0)
+ evxor rW3,rW3,rW7
+ LWH(rW0, 12)
+ evxor rW3,rW3,rW1
+ EAD(rD0, 3)
+ evxor rD3,rD3,rW3
+ LWH(rW6, 0)
+ evxor rD3,rD3,rW5
+ EAD(rD0, 1)
+ evmergehi rD2,rD2,rD3
+ LWH(rW3, 8)
+ addi rKP,rKP,32
+ bdnz ppc_decrypt_block_loop
+ LAH(rW1, rD3, 0, 12)
+ LAL(rW0, rD2, 0, 12)
+ LAH(rW2, rD2, 1, 8)
+ LAL(rW2, rD3, 1, 8)
+ LAH(rW4, rD3, 2, 4)
+ LAL(rW4, rD0, 2, 4)
+ LAL(rW6, rD1, 3, 0)
+ LAH(rW5, rD1, 2, 4)
+ LAH(rW7, rD2, 3, 0)
+ LAL(rW7, rD3, 3, 0)
+ LAL(rW3, rD1, 1, 8)
+ evldw rD1,16(rKP)
+ EAD(rD0, 0)
+ evxor rW4,rW4,rW6
+ LWL(rW1, 12)
+ evxor rW0,rW0,rW4
+ EAD(rD2, 2)
+ evxor rW0,rW0,rW2
+ LWL(rW5, 4)
+ evxor rD1,rD1,rW0
+ evldw rD3,24(rKP)
+ evmergehi rD0,rD0,rD1
+ DAD(rD1, 0)
+ evxor rW3,rW3,rW7
+ LBD(rW0)
+ evxor rW3,rW3,rW1
+ DAD(rD0, 1)
+ evxor rD3,rD3,rW3
+ LBD(rW6)
+ evxor rD3,rD3,rW5
+ DAD(rD0, 0)
+ evmergehi rD2,rD2,rD3
+ LBD(rW3)
+ LAD(rW2, rD3, 0)
+ LAD(rW1, rD2, 0)
+ LAD(rW4, rD2, 1)
+ LAD(rW5, rD3, 1)
+ LAD(rW7, rD1, 1)
+ rlwimi rW0,rW4,8,16,23
+ rlwimi rW1,rW5,8,16,23
+ LAD(rW4, rD3, 2)
+ LAD(rW5, rD0, 2)
+ rlwimi rW2,rW6,8,16,23
+ rlwimi rW3,rW7,8,16,23
+ LAD(rW6, rD1, 2)
+ LAD(rW7, rD2, 2)
+ rlwimi rW0,rW4,16,8,15
+ rlwimi rW1,rW5,16,8,15
+ LAD(rW4, rD0, 3)
+ LAD(rW5, rD1, 3)
+ rlwimi rW2,rW6,16,8,15
+ lwz rD0,32(rKP)
+ rlwimi rW3,rW7,16,8,15
+ lwz rD1,36(rKP)
+ LAD(rW6, rD2, 3)
+ LAD(rW7, rD3, 3)
+ rlwimi rW0,rW4,24,0,7
+ lwz rD2,40(rKP)
+ rlwimi rW1,rW5,24,0,7
+ lwz rD3,44(rKP)
+ rlwimi rW2,rW6,24,0,7
+ rlwimi rW3,rW7,24,0,7
+ blr
diff --git a/lib/crypto/powerpc/aes-spe-keys.S b/lib/crypto/powerpc/aes-spe-keys.S
new file mode 100644
index 000000000000..2e1bc0d099bf
--- /dev/null
+++ b/lib/crypto/powerpc/aes-spe-keys.S
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Key handling functions for PPC AES implementation
+ *
+ * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de>
+ */
+
+#include <asm/ppc_asm.h>
+
+#ifdef __BIG_ENDIAN__
+#define LOAD_KEY(d, s, off) \
+ lwz d,off(s);
+#else
+#define LOAD_KEY(d, s, off) \
+ li r0,off; \
+ lwbrx d,s,r0;
+#endif
+
+#define INITIALIZE_KEY \
+ stwu r1,-32(r1); /* create stack frame */ \
+ stw r14,8(r1); /* save registers */ \
+ stw r15,12(r1); \
+ stw r16,16(r1);
+
+#define FINALIZE_KEY \
+ lwz r14,8(r1); /* restore registers */ \
+ lwz r15,12(r1); \
+ lwz r16,16(r1); \
+ xor r5,r5,r5; /* clear sensitive data */ \
+ xor r6,r6,r6; \
+ xor r7,r7,r7; \
+ xor r8,r8,r8; \
+ xor r9,r9,r9; \
+ xor r10,r10,r10; \
+ xor r11,r11,r11; \
+ xor r12,r12,r12; \
+ addi r1,r1,32; /* cleanup stack */
+
+#define LS_BOX(r, t1, t2) \
+ lis t2,PPC_AES_4K_ENCTAB@h; \
+ ori t2,t2,PPC_AES_4K_ENCTAB@l; \
+ rlwimi t2,r,4,20,27; \
+ lbz t1,8(t2); \
+ rlwimi r,t1,0,24,31; \
+ rlwimi t2,r,28,20,27; \
+ lbz t1,8(t2); \
+ rlwimi r,t1,8,16,23; \
+ rlwimi t2,r,20,20,27; \
+ lbz t1,8(t2); \
+ rlwimi r,t1,16,8,15; \
+ rlwimi t2,r,12,20,27; \
+ lbz t1,8(t2); \
+ rlwimi r,t1,24,0,7;
+
+#define GF8_MUL(out, in, t1, t2) \
+ lis t1,0x8080; /* multiplication in GF8 */ \
+ ori t1,t1,0x8080; \
+ and t1,t1,in; \
+ srwi t1,t1,7; \
+ mulli t1,t1,0x1b; \
+ lis t2,0x7f7f; \
+ ori t2,t2,0x7f7f; \
+ and t2,t2,in; \
+ slwi t2,t2,1; \
+ xor out,t1,t2;
+
+/*
+ * ppc_expand_key_128(u32 *key_enc, const u8 *key)
+ *
+ * Expand 128 bit key into 176 bytes encryption key. It consists of
+ * key itself plus 10 rounds with 16 bytes each
+ *
+ */
+_GLOBAL(ppc_expand_key_128)
+ INITIALIZE_KEY
+ LOAD_KEY(r5,r4,0)
+ LOAD_KEY(r6,r4,4)
+ LOAD_KEY(r7,r4,8)
+ LOAD_KEY(r8,r4,12)
+ stw r5,0(r3) /* key[0..3] = input data */
+ stw r6,4(r3)
+ stw r7,8(r3)
+ stw r8,12(r3)
+ li r16,10 /* 10 expansion rounds */
+ lis r0,0x0100 /* RCO(1) */
+ppc_expand_128_loop:
+ addi r3,r3,16
+ mr r14,r8 /* apply LS_BOX to 4th temp */
+ rotlwi r14,r14,8
+ LS_BOX(r14, r15, r4)
+ xor r14,r14,r0
+ xor r5,r5,r14 /* xor next 4 keys */
+ xor r6,r6,r5
+ xor r7,r7,r6
+ xor r8,r8,r7
+ stw r5,0(r3) /* store next 4 keys */
+ stw r6,4(r3)
+ stw r7,8(r3)
+ stw r8,12(r3)
+ GF8_MUL(r0, r0, r4, r14) /* multiply RCO by 2 in GF */
+ subi r16,r16,1
+ cmpwi r16,0
+ bt eq,ppc_expand_128_end
+ b ppc_expand_128_loop
+ppc_expand_128_end:
+ FINALIZE_KEY
+ blr
+
+/*
+ * ppc_expand_key_192(u32 *key_enc, const u8 *key)
+ *
+ * Expand 192 bit key into 208 bytes encryption key. It consists of key
+ * itself plus 12 rounds with 16 bytes each
+ *
+ */
+_GLOBAL(ppc_expand_key_192)
+ INITIALIZE_KEY
+ LOAD_KEY(r5,r4,0)
+ LOAD_KEY(r6,r4,4)
+ LOAD_KEY(r7,r4,8)
+ LOAD_KEY(r8,r4,12)
+ LOAD_KEY(r9,r4,16)
+ LOAD_KEY(r10,r4,20)
+ stw r5,0(r3)
+ stw r6,4(r3)
+ stw r7,8(r3)
+ stw r8,12(r3)
+ stw r9,16(r3)
+ stw r10,20(r3)
+ li r16,8 /* 8 expansion rounds */
+ lis r0,0x0100 /* RCO(1) */
+ppc_expand_192_loop:
+ addi r3,r3,24
+ mr r14,r10 /* apply LS_BOX to 6th temp */
+ rotlwi r14,r14,8
+ LS_BOX(r14, r15, r4)
+ xor r14,r14,r0
+ xor r5,r5,r14 /* xor next 6 keys */
+ xor r6,r6,r5
+ xor r7,r7,r6
+ xor r8,r8,r7
+ xor r9,r9,r8
+ xor r10,r10,r9
+ stw r5,0(r3)
+ stw r6,4(r3)
+ stw r7,8(r3)
+ stw r8,12(r3)
+ subi r16,r16,1
+ cmpwi r16,0 /* last round early kick out */
+ bt eq,ppc_expand_192_end
+ stw r9,16(r3)
+ stw r10,20(r3)
+ GF8_MUL(r0, r0, r4, r14) /* multiply RCO GF8 */
+ b ppc_expand_192_loop
+ppc_expand_192_end:
+ FINALIZE_KEY
+ blr
+
+/*
+ * ppc_expand_key_256(u32 *key_enc, const u8 *key)
+ *
+ * Expand 256 bit key into 240 bytes encryption key. It consists of key
+ * itself plus 14 rounds with 16 bytes each
+ *
+ */
+_GLOBAL(ppc_expand_key_256)
+ INITIALIZE_KEY
+ LOAD_KEY(r5,r4,0)
+ LOAD_KEY(r6,r4,4)
+ LOAD_KEY(r7,r4,8)
+ LOAD_KEY(r8,r4,12)
+ LOAD_KEY(r9,r4,16)
+ LOAD_KEY(r10,r4,20)
+ LOAD_KEY(r11,r4,24)
+ LOAD_KEY(r12,r4,28)
+ stw r5,0(r3)
+ stw r6,4(r3)
+ stw r7,8(r3)
+ stw r8,12(r3)
+ stw r9,16(r3)
+ stw r10,20(r3)
+ stw r11,24(r3)
+ stw r12,28(r3)
+ li r16,7 /* 7 expansion rounds */
+ lis r0,0x0100 /* RCO(1) */
+ppc_expand_256_loop:
+ addi r3,r3,32
+ mr r14,r12 /* apply LS_BOX to 8th temp */
+ rotlwi r14,r14,8
+ LS_BOX(r14, r15, r4)
+ xor r14,r14,r0
+ xor r5,r5,r14 /* xor 4 keys */
+ xor r6,r6,r5
+ xor r7,r7,r6
+ xor r8,r8,r7
+ mr r14,r8
+ LS_BOX(r14, r15, r4) /* apply LS_BOX to 4th temp */
+ xor r9,r9,r14 /* xor 4 keys */
+ xor r10,r10,r9
+ xor r11,r11,r10
+ xor r12,r12,r11
+ stw r5,0(r3)
+ stw r6,4(r3)
+ stw r7,8(r3)
+ stw r8,12(r3)
+ subi r16,r16,1
+ cmpwi r16,0 /* last round early kick out */
+ bt eq,ppc_expand_256_end
+ stw r9,16(r3)
+ stw r10,20(r3)
+ stw r11,24(r3)
+ stw r12,28(r3)
+ GF8_MUL(r0, r0, r4, r14)
+ b ppc_expand_256_loop
+ppc_expand_256_end:
+ FINALIZE_KEY
+ blr
+
+/*
+ * ppc_generate_decrypt_key: derive decryption key from encryption key
+ * number of bytes to handle are calculated from length of key (16/24/32)
+ *
+ */
+_GLOBAL(ppc_generate_decrypt_key)
+ addi r6,r5,24
+ slwi r6,r6,2
+ lwzx r7,r4,r6 /* first/last 4 words are same */
+ stw r7,0(r3)
+ lwz r7,0(r4)
+ stwx r7,r3,r6
+ addi r6,r6,4
+ lwzx r7,r4,r6
+ stw r7,4(r3)
+ lwz r7,4(r4)
+ stwx r7,r3,r6
+ addi r6,r6,4
+ lwzx r7,r4,r6
+ stw r7,8(r3)
+ lwz r7,8(r4)
+ stwx r7,r3,r6
+ addi r6,r6,4
+ lwzx r7,r4,r6
+ stw r7,12(r3)
+ lwz r7,12(r4)
+ stwx r7,r3,r6
+ addi r3,r3,16
+ add r4,r4,r6
+ subi r4,r4,28
+ addi r5,r5,20
+ srwi r5,r5,2
+ppc_generate_decrypt_block:
+ li r6,4
+ mtctr r6
+ppc_generate_decrypt_word:
+ lwz r6,0(r4)
+ GF8_MUL(r7, r6, r0, r7)
+ GF8_MUL(r8, r7, r0, r8)
+ GF8_MUL(r9, r8, r0, r9)
+ xor r10,r9,r6
+ xor r11,r7,r8
+ xor r11,r11,r9
+ xor r12,r7,r10
+ rotrwi r12,r12,24
+ xor r11,r11,r12
+ xor r12,r8,r10
+ rotrwi r12,r12,16
+ xor r11,r11,r12
+ rotrwi r12,r10,8
+ xor r11,r11,r12
+ stw r11,0(r3)
+ addi r3,r3,4
+ addi r4,r4,4
+ bdnz ppc_generate_decrypt_word
+ subi r4,r4,32
+ subi r5,r5,1
+ cmpwi r5,0
+ bt gt,ppc_generate_decrypt_block
+ blr
diff --git a/lib/crypto/powerpc/aes-spe-modes.S b/lib/crypto/powerpc/aes-spe-modes.S
new file mode 100644
index 000000000000..3f92a6a85785
--- /dev/null
+++ b/lib/crypto/powerpc/aes-spe-modes.S
@@ -0,0 +1,625 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AES modes (ECB/CBC/CTR/XTS) for PPC AES implementation
+ *
+ * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de>
+ */
+
+#include <asm/ppc_asm.h>
+#include "aes-spe-regs.h"
+
+#ifdef __BIG_ENDIAN__ /* Macros for big endian builds */
+
+#define LOAD_DATA(reg, off) \
+ lwz reg,off(rSP); /* load with offset */
+#define SAVE_DATA(reg, off) \
+ stw reg,off(rDP); /* save with offset */
+#define NEXT_BLOCK \
+ addi rSP,rSP,16; /* increment pointers per bloc */ \
+ addi rDP,rDP,16;
+#define LOAD_IV(reg, off) \
+ lwz reg,off(rIP); /* IV loading with offset */
+#define SAVE_IV(reg, off) \
+ stw reg,off(rIP); /* IV saving with offset */
+#define START_IV /* nothing to reset */
+#define CBC_DEC 16 /* CBC decrement per block */
+#define CTR_DEC 1 /* CTR decrement one byte */
+
+#else /* Macros for little endian */
+
+#define LOAD_DATA(reg, off) \
+ lwbrx reg,0,rSP; /* load reversed */ \
+ addi rSP,rSP,4; /* and increment pointer */
+#define SAVE_DATA(reg, off) \
+ stwbrx reg,0,rDP; /* save reversed */ \
+ addi rDP,rDP,4; /* and increment pointer */
+#define NEXT_BLOCK /* nothing todo */
+#define LOAD_IV(reg, off) \
+ lwbrx reg,0,rIP; /* load reversed */ \
+ addi rIP,rIP,4; /* and increment pointer */
+#define SAVE_IV(reg, off) \
+ stwbrx reg,0,rIP; /* load reversed */ \
+ addi rIP,rIP,4; /* and increment pointer */
+#define START_IV \
+ subi rIP,rIP,16; /* must reset pointer */
+#define CBC_DEC 32 /* 2 blocks because of incs */
+#define CTR_DEC 17 /* 1 block because of incs */
+
+#endif
+
+#define SAVE_0_REGS
+#define LOAD_0_REGS
+
+#define SAVE_4_REGS \
+ stw rI0,96(r1); /* save 32 bit registers */ \
+ stw rI1,100(r1); \
+ stw rI2,104(r1); \
+ stw rI3,108(r1);
+
+#define LOAD_4_REGS \
+ lwz rI0,96(r1); /* restore 32 bit registers */ \
+ lwz rI1,100(r1); \
+ lwz rI2,104(r1); \
+ lwz rI3,108(r1);
+
+#define SAVE_8_REGS \
+ SAVE_4_REGS \
+ stw rG0,112(r1); /* save 32 bit registers */ \
+ stw rG1,116(r1); \
+ stw rG2,120(r1); \
+ stw rG3,124(r1);
+
+#define LOAD_8_REGS \
+ LOAD_4_REGS \
+ lwz rG0,112(r1); /* restore 32 bit registers */ \
+ lwz rG1,116(r1); \
+ lwz rG2,120(r1); \
+ lwz rG3,124(r1);
+
+#define INITIALIZE_CRYPT(tab,nr32bitregs) \
+ mflr r0; \
+ stwu r1,-160(r1); /* create stack frame */ \
+ lis rT0,tab@h; /* en-/decryption table pointer */ \
+ stw r0,8(r1); /* save link register */ \
+ ori rT0,rT0,tab@l; \
+ evstdw r14,16(r1); \
+ mr rKS,rKP; \
+ evstdw r15,24(r1); /* We must save non volatile */ \
+ evstdw r16,32(r1); /* registers. Take the chance */ \
+ evstdw r17,40(r1); /* and save the SPE part too */ \
+ evstdw r18,48(r1); \
+ evstdw r19,56(r1); \
+ evstdw r20,64(r1); \
+ evstdw r21,72(r1); \
+ evstdw r22,80(r1); \
+ evstdw r23,88(r1); \
+ SAVE_##nr32bitregs##_REGS
+
+#define FINALIZE_CRYPT(nr32bitregs) \
+ lwz r0,8(r1); \
+ evldw r14,16(r1); /* restore SPE registers */ \
+ evldw r15,24(r1); \
+ evldw r16,32(r1); \
+ evldw r17,40(r1); \
+ evldw r18,48(r1); \
+ evldw r19,56(r1); \
+ evldw r20,64(r1); \
+ evldw r21,72(r1); \
+ evldw r22,80(r1); \
+ evldw r23,88(r1); \
+ LOAD_##nr32bitregs##_REGS \
+ mtlr r0; /* restore link register */ \
+ xor r0,r0,r0; \
+ stw r0,16(r1); /* delete sensitive data */ \
+ stw r0,24(r1); /* that we might have pushed */ \
+ stw r0,32(r1); /* from other context that runs */ \
+ stw r0,40(r1); /* the same code */ \
+ stw r0,48(r1); \
+ stw r0,56(r1); \
+ stw r0,64(r1); \
+ stw r0,72(r1); \
+ stw r0,80(r1); \
+ stw r0,88(r1); \
+ addi r1,r1,160; /* cleanup stack frame */
+
+#define ENDIAN_SWAP(t0, t1, s0, s1) \
+ rotrwi t0,s0,8; /* swap endianness for 2 GPRs */ \
+ rotrwi t1,s1,8; \
+ rlwimi t0,s0,8,8,15; \
+ rlwimi t1,s1,8,8,15; \
+ rlwimi t0,s0,8,24,31; \
+ rlwimi t1,s1,8,24,31;
+
+#define GF128_MUL(d0, d1, d2, d3, t0) \
+ li t0,0x87; /* multiplication in GF128 */ \
+ cmpwi d3,-1; \
+ iselgt t0,0,t0; \
+ rlwimi d3,d2,0,0,0; /* propagate "carry" bits */ \
+ rotlwi d3,d3,1; \
+ rlwimi d2,d1,0,0,0; \
+ rotlwi d2,d2,1; \
+ rlwimi d1,d0,0,0,0; \
+ slwi d0,d0,1; /* shift left 128 bit */ \
+ rotlwi d1,d1,1; \
+ xor d0,d0,t0;
+
+#define START_KEY(d0, d1, d2, d3) \
+ lwz rW0,0(rKP); \
+ mtctr rRR; \
+ lwz rW1,4(rKP); \
+ lwz rW2,8(rKP); \
+ lwz rW3,12(rKP); \
+ xor rD0,d0,rW0; \
+ xor rD1,d1,rW1; \
+ xor rD2,d2,rW2; \
+ xor rD3,d3,rW3;
+
+/*
+ * ppc_encrypt_aes(u8 *out, const u8 *in, u32 *key_enc,
+ * u32 rounds)
+ *
+ * called from glue layer to encrypt a single 16 byte block
+ * round values are AES128 = 4, AES192 = 5, AES256 = 6
+ *
+ */
+_GLOBAL(ppc_encrypt_aes)
+ INITIALIZE_CRYPT(PPC_AES_4K_ENCTAB, 0)
+ LOAD_DATA(rD0, 0)
+ LOAD_DATA(rD1, 4)
+ LOAD_DATA(rD2, 8)
+ LOAD_DATA(rD3, 12)
+ START_KEY(rD0, rD1, rD2, rD3)
+ bl ppc_encrypt_block
+ xor rD0,rD0,rW0
+ SAVE_DATA(rD0, 0)
+ xor rD1,rD1,rW1
+ SAVE_DATA(rD1, 4)
+ xor rD2,rD2,rW2
+ SAVE_DATA(rD2, 8)
+ xor rD3,rD3,rW3
+ SAVE_DATA(rD3, 12)
+ FINALIZE_CRYPT(0)
+ blr
+
+/*
+ * ppc_decrypt_aes(u8 *out, const u8 *in, u32 *key_dec,
+ * u32 rounds)
+ *
+ * called from glue layer to decrypt a single 16 byte block
+ * round values are AES128 = 4, AES192 = 5, AES256 = 6
+ *
+ */
+_GLOBAL(ppc_decrypt_aes)
+ INITIALIZE_CRYPT(PPC_AES_4K_DECTAB,0)
+ LOAD_DATA(rD0, 0)
+ addi rT1,rT0,4096
+ LOAD_DATA(rD1, 4)
+ LOAD_DATA(rD2, 8)
+ LOAD_DATA(rD3, 12)
+ START_KEY(rD0, rD1, rD2, rD3)
+ bl ppc_decrypt_block
+ xor rD0,rD0,rW0
+ SAVE_DATA(rD0, 0)
+ xor rD1,rD1,rW1
+ SAVE_DATA(rD1, 4)
+ xor rD2,rD2,rW2
+ SAVE_DATA(rD2, 8)
+ xor rD3,rD3,rW3
+ SAVE_DATA(rD3, 12)
+ FINALIZE_CRYPT(0)
+ blr
+
+/*
+ * ppc_encrypt_ecb(u8 *out, const u8 *in, u32 *key_enc,
+ * u32 rounds, u32 bytes);
+ *
+ * called from glue layer to encrypt multiple blocks via ECB
+ * Bytes must be larger or equal 16 and only whole blocks are
+ * processed. round values are AES128 = 4, AES192 = 5 and
+ * AES256 = 6
+ *
+ */
+_GLOBAL(ppc_encrypt_ecb)
+ INITIALIZE_CRYPT(PPC_AES_4K_ENCTAB, 0)
+ppc_encrypt_ecb_loop:
+ LOAD_DATA(rD0, 0)
+ mr rKP,rKS
+ LOAD_DATA(rD1, 4)
+ subi rLN,rLN,16
+ LOAD_DATA(rD2, 8)
+ cmpwi rLN,15
+ LOAD_DATA(rD3, 12)
+ START_KEY(rD0, rD1, rD2, rD3)
+ bl ppc_encrypt_block
+ xor rD0,rD0,rW0
+ SAVE_DATA(rD0, 0)
+ xor rD1,rD1,rW1
+ SAVE_DATA(rD1, 4)
+ xor rD2,rD2,rW2
+ SAVE_DATA(rD2, 8)
+ xor rD3,rD3,rW3
+ SAVE_DATA(rD3, 12)
+ NEXT_BLOCK
+ bt gt,ppc_encrypt_ecb_loop
+ FINALIZE_CRYPT(0)
+ blr
+
+/*
+ * ppc_decrypt_ecb(u8 *out, const u8 *in, u32 *key_dec,
+ * u32 rounds, u32 bytes);
+ *
+ * called from glue layer to decrypt multiple blocks via ECB
+ * Bytes must be larger or equal 16 and only whole blocks are
+ * processed. round values are AES128 = 4, AES192 = 5 and
+ * AES256 = 6
+ *
+ */
+_GLOBAL(ppc_decrypt_ecb)
+ INITIALIZE_CRYPT(PPC_AES_4K_DECTAB, 0)
+ addi rT1,rT0,4096
+ppc_decrypt_ecb_loop:
+ LOAD_DATA(rD0, 0)
+ mr rKP,rKS
+ LOAD_DATA(rD1, 4)
+ subi rLN,rLN,16
+ LOAD_DATA(rD2, 8)
+ cmpwi rLN,15
+ LOAD_DATA(rD3, 12)
+ START_KEY(rD0, rD1, rD2, rD3)
+ bl ppc_decrypt_block
+ xor rD0,rD0,rW0
+ SAVE_DATA(rD0, 0)
+ xor rD1,rD1,rW1
+ SAVE_DATA(rD1, 4)
+ xor rD2,rD2,rW2
+ SAVE_DATA(rD2, 8)
+ xor rD3,rD3,rW3
+ SAVE_DATA(rD3, 12)
+ NEXT_BLOCK
+ bt gt,ppc_decrypt_ecb_loop
+ FINALIZE_CRYPT(0)
+ blr
+
+/*
+ * ppc_encrypt_cbc(u8 *out, const u8 *in, u32 *key_enc,
+ * 32 rounds, u32 bytes, u8 *iv);
+ *
+ * called from glue layer to encrypt multiple blocks via CBC
+ * Bytes must be larger or equal 16 and only whole blocks are
+ * processed. round values are AES128 = 4, AES192 = 5 and
+ * AES256 = 6
+ *
+ */
+_GLOBAL(ppc_encrypt_cbc)
+ INITIALIZE_CRYPT(PPC_AES_4K_ENCTAB, 4)
+ LOAD_IV(rI0, 0)
+ LOAD_IV(rI1, 4)
+ LOAD_IV(rI2, 8)
+ LOAD_IV(rI3, 12)
+ppc_encrypt_cbc_loop:
+ LOAD_DATA(rD0, 0)
+ mr rKP,rKS
+ LOAD_DATA(rD1, 4)
+ subi rLN,rLN,16
+ LOAD_DATA(rD2, 8)
+ cmpwi rLN,15
+ LOAD_DATA(rD3, 12)
+ xor rD0,rD0,rI0
+ xor rD1,rD1,rI1
+ xor rD2,rD2,rI2
+ xor rD3,rD3,rI3
+ START_KEY(rD0, rD1, rD2, rD3)
+ bl ppc_encrypt_block
+ xor rI0,rD0,rW0
+ SAVE_DATA(rI0, 0)
+ xor rI1,rD1,rW1
+ SAVE_DATA(rI1, 4)
+ xor rI2,rD2,rW2
+ SAVE_DATA(rI2, 8)
+ xor rI3,rD3,rW3
+ SAVE_DATA(rI3, 12)
+ NEXT_BLOCK
+ bt gt,ppc_encrypt_cbc_loop
+ START_IV
+ SAVE_IV(rI0, 0)
+ SAVE_IV(rI1, 4)
+ SAVE_IV(rI2, 8)
+ SAVE_IV(rI3, 12)
+ FINALIZE_CRYPT(4)
+ blr
+
+/*
+ * ppc_decrypt_cbc(u8 *out, const u8 *in, u32 *key_dec,
+ * u32 rounds, u32 bytes, u8 *iv);
+ *
+ * called from glue layer to decrypt multiple blocks via CBC
+ * round values are AES128 = 4, AES192 = 5, AES256 = 6
+ *
+ */
+_GLOBAL(ppc_decrypt_cbc)
+ INITIALIZE_CRYPT(PPC_AES_4K_DECTAB, 4)
+ li rT1,15
+ LOAD_IV(rI0, 0)
+ andc rLN,rLN,rT1
+ LOAD_IV(rI1, 4)
+ subi rLN,rLN,16
+ LOAD_IV(rI2, 8)
+ add rSP,rSP,rLN /* reverse processing */
+ LOAD_IV(rI3, 12)
+ add rDP,rDP,rLN
+ LOAD_DATA(rD0, 0)
+ addi rT1,rT0,4096
+ LOAD_DATA(rD1, 4)
+ LOAD_DATA(rD2, 8)
+ LOAD_DATA(rD3, 12)
+ START_IV
+ SAVE_IV(rD0, 0)
+ SAVE_IV(rD1, 4)
+ SAVE_IV(rD2, 8)
+ cmpwi rLN,16
+ SAVE_IV(rD3, 12)
+ bt lt,ppc_decrypt_cbc_end
+ppc_decrypt_cbc_loop:
+ mr rKP,rKS
+ START_KEY(rD0, rD1, rD2, rD3)
+ bl ppc_decrypt_block
+ subi rLN,rLN,16
+ subi rSP,rSP,CBC_DEC
+ xor rW0,rD0,rW0
+ LOAD_DATA(rD0, 0)
+ xor rW1,rD1,rW1
+ LOAD_DATA(rD1, 4)
+ xor rW2,rD2,rW2
+ LOAD_DATA(rD2, 8)
+ xor rW3,rD3,rW3
+ LOAD_DATA(rD3, 12)
+ xor rW0,rW0,rD0
+ SAVE_DATA(rW0, 0)
+ xor rW1,rW1,rD1
+ SAVE_DATA(rW1, 4)
+ xor rW2,rW2,rD2
+ SAVE_DATA(rW2, 8)
+ xor rW3,rW3,rD3
+ SAVE_DATA(rW3, 12)
+ cmpwi rLN,15
+ subi rDP,rDP,CBC_DEC
+ bt gt,ppc_decrypt_cbc_loop
+ppc_decrypt_cbc_end:
+ mr rKP,rKS
+ START_KEY(rD0, rD1, rD2, rD3)
+ bl ppc_decrypt_block
+ xor rW0,rW0,rD0
+ xor rW1,rW1,rD1
+ xor rW2,rW2,rD2
+ xor rW3,rW3,rD3
+ xor rW0,rW0,rI0 /* decrypt with initial IV */
+ SAVE_DATA(rW0, 0)
+ xor rW1,rW1,rI1
+ SAVE_DATA(rW1, 4)
+ xor rW2,rW2,rI2
+ SAVE_DATA(rW2, 8)
+ xor rW3,rW3,rI3
+ SAVE_DATA(rW3, 12)
+ FINALIZE_CRYPT(4)
+ blr
+
+/*
+ * ppc_crypt_ctr(u8 *out, const u8 *in, u32 *key_enc,
+ * u32 rounds, u32 bytes, u8 *iv);
+ *
+ * called from glue layer to encrypt/decrypt multiple blocks
+ * via CTR. Number of bytes does not need to be a multiple of
+ * 16. Round values are AES128 = 4, AES192 = 5, AES256 = 6
+ *
+ */
+_GLOBAL(ppc_crypt_ctr)
+ INITIALIZE_CRYPT(PPC_AES_4K_ENCTAB, 4)
+ LOAD_IV(rI0, 0)
+ LOAD_IV(rI1, 4)
+ LOAD_IV(rI2, 8)
+ cmpwi rLN,16
+ LOAD_IV(rI3, 12)
+ START_IV
+ bt lt,ppc_crypt_ctr_partial
+ppc_crypt_ctr_loop:
+ mr rKP,rKS
+ START_KEY(rI0, rI1, rI2, rI3)
+ bl ppc_encrypt_block
+ xor rW0,rD0,rW0
+ xor rW1,rD1,rW1
+ xor rW2,rD2,rW2
+ xor rW3,rD3,rW3
+ LOAD_DATA(rD0, 0)
+ subi rLN,rLN,16
+ LOAD_DATA(rD1, 4)
+ LOAD_DATA(rD2, 8)
+ LOAD_DATA(rD3, 12)
+ xor rD0,rD0,rW0
+ SAVE_DATA(rD0, 0)
+ xor rD1,rD1,rW1
+ SAVE_DATA(rD1, 4)
+ xor rD2,rD2,rW2
+ SAVE_DATA(rD2, 8)
+ xor rD3,rD3,rW3
+ SAVE_DATA(rD3, 12)
+ addic rI3,rI3,1 /* increase counter */
+ addze rI2,rI2
+ addze rI1,rI1
+ addze rI0,rI0
+ NEXT_BLOCK
+ cmpwi rLN,15
+ bt gt,ppc_crypt_ctr_loop
+ppc_crypt_ctr_partial:
+ cmpwi rLN,0
+ bt eq,ppc_crypt_ctr_end
+ mr rKP,rKS
+ START_KEY(rI0, rI1, rI2, rI3)
+ bl ppc_encrypt_block
+ xor rW0,rD0,rW0
+ SAVE_IV(rW0, 0)
+ xor rW1,rD1,rW1
+ SAVE_IV(rW1, 4)
+ xor rW2,rD2,rW2
+ SAVE_IV(rW2, 8)
+ xor rW3,rD3,rW3
+ SAVE_IV(rW3, 12)
+ mtctr rLN
+ subi rIP,rIP,CTR_DEC
+ subi rSP,rSP,1
+ subi rDP,rDP,1
+ppc_crypt_ctr_xorbyte:
+ lbzu rW4,1(rIP) /* bytewise xor for partial block */
+ lbzu rW5,1(rSP)
+ xor rW4,rW4,rW5
+ stbu rW4,1(rDP)
+ bdnz ppc_crypt_ctr_xorbyte
+ subf rIP,rLN,rIP
+ addi rIP,rIP,1
+ addic rI3,rI3,1
+ addze rI2,rI2
+ addze rI1,rI1
+ addze rI0,rI0
+ppc_crypt_ctr_end:
+ SAVE_IV(rI0, 0)
+ SAVE_IV(rI1, 4)
+ SAVE_IV(rI2, 8)
+ SAVE_IV(rI3, 12)
+ FINALIZE_CRYPT(4)
+ blr
+
+/*
+ * ppc_encrypt_xts(u8 *out, const u8 *in, u32 *key_enc,
+ * u32 rounds, u32 bytes, u8 *iv, u32 *key_twk);
+ *
+ * called from glue layer to encrypt multiple blocks via XTS
+ * If key_twk is given, the initial IV encryption will be
+ * processed too. Round values are AES128 = 4, AES192 = 5,
+ * AES256 = 6
+ *
+ */
+_GLOBAL(ppc_encrypt_xts)
+ INITIALIZE_CRYPT(PPC_AES_4K_ENCTAB, 8)
+ LOAD_IV(rI0, 0)
+ LOAD_IV(rI1, 4)
+ LOAD_IV(rI2, 8)
+ cmpwi rKT,0
+ LOAD_IV(rI3, 12)
+ bt eq,ppc_encrypt_xts_notweak
+ mr rKP,rKT
+ START_KEY(rI0, rI1, rI2, rI3)
+ bl ppc_encrypt_block
+ xor rI0,rD0,rW0
+ xor rI1,rD1,rW1
+ xor rI2,rD2,rW2
+ xor rI3,rD3,rW3
+ppc_encrypt_xts_notweak:
+ ENDIAN_SWAP(rG0, rG1, rI0, rI1)
+ ENDIAN_SWAP(rG2, rG3, rI2, rI3)
+ppc_encrypt_xts_loop:
+ LOAD_DATA(rD0, 0)
+ mr rKP,rKS
+ LOAD_DATA(rD1, 4)
+ subi rLN,rLN,16
+ LOAD_DATA(rD2, 8)
+ LOAD_DATA(rD3, 12)
+ xor rD0,rD0,rI0
+ xor rD1,rD1,rI1
+ xor rD2,rD2,rI2
+ xor rD3,rD3,rI3
+ START_KEY(rD0, rD1, rD2, rD3)
+ bl ppc_encrypt_block
+ xor rD0,rD0,rW0
+ xor rD1,rD1,rW1
+ xor rD2,rD2,rW2
+ xor rD3,rD3,rW3
+ xor rD0,rD0,rI0
+ SAVE_DATA(rD0, 0)
+ xor rD1,rD1,rI1
+ SAVE_DATA(rD1, 4)
+ xor rD2,rD2,rI2
+ SAVE_DATA(rD2, 8)
+ xor rD3,rD3,rI3
+ SAVE_DATA(rD3, 12)
+ GF128_MUL(rG0, rG1, rG2, rG3, rW0)
+ ENDIAN_SWAP(rI0, rI1, rG0, rG1)
+ ENDIAN_SWAP(rI2, rI3, rG2, rG3)
+ cmpwi rLN,0
+ NEXT_BLOCK
+ bt gt,ppc_encrypt_xts_loop
+ START_IV
+ SAVE_IV(rI0, 0)
+ SAVE_IV(rI1, 4)
+ SAVE_IV(rI2, 8)
+ SAVE_IV(rI3, 12)
+ FINALIZE_CRYPT(8)
+ blr
+
+/*
+ * ppc_decrypt_xts(u8 *out, const u8 *in, u32 *key_dec,
+ * u32 rounds, u32 blocks, u8 *iv, u32 *key_twk);
+ *
+ * called from glue layer to decrypt multiple blocks via XTS
+ * If key_twk is given, the initial IV encryption will be
+ * processed too. Round values are AES128 = 4, AES192 = 5,
+ * AES256 = 6
+ *
+ */
+_GLOBAL(ppc_decrypt_xts)
+ INITIALIZE_CRYPT(PPC_AES_4K_DECTAB, 8)
+ LOAD_IV(rI0, 0)
+ addi rT1,rT0,4096
+ LOAD_IV(rI1, 4)
+ LOAD_IV(rI2, 8)
+ cmpwi rKT,0
+ LOAD_IV(rI3, 12)
+ bt eq,ppc_decrypt_xts_notweak
+ subi rT0,rT0,4096
+ mr rKP,rKT
+ START_KEY(rI0, rI1, rI2, rI3)
+ bl ppc_encrypt_block
+ xor rI0,rD0,rW0
+ xor rI1,rD1,rW1
+ xor rI2,rD2,rW2
+ xor rI3,rD3,rW3
+ addi rT0,rT0,4096
+ppc_decrypt_xts_notweak:
+ ENDIAN_SWAP(rG0, rG1, rI0, rI1)
+ ENDIAN_SWAP(rG2, rG3, rI2, rI3)
+ppc_decrypt_xts_loop:
+ LOAD_DATA(rD0, 0)
+ mr rKP,rKS
+ LOAD_DATA(rD1, 4)
+ subi rLN,rLN,16
+ LOAD_DATA(rD2, 8)
+ LOAD_DATA(rD3, 12)
+ xor rD0,rD0,rI0
+ xor rD1,rD1,rI1
+ xor rD2,rD2,rI2
+ xor rD3,rD3,rI3
+ START_KEY(rD0, rD1, rD2, rD3)
+ bl ppc_decrypt_block
+ xor rD0,rD0,rW0
+ xor rD1,rD1,rW1
+ xor rD2,rD2,rW2
+ xor rD3,rD3,rW3
+ xor rD0,rD0,rI0
+ SAVE_DATA(rD0, 0)
+ xor rD1,rD1,rI1
+ SAVE_DATA(rD1, 4)
+ xor rD2,rD2,rI2
+ SAVE_DATA(rD2, 8)
+ xor rD3,rD3,rI3
+ SAVE_DATA(rD3, 12)
+ GF128_MUL(rG0, rG1, rG2, rG3, rW0)
+ ENDIAN_SWAP(rI0, rI1, rG0, rG1)
+ ENDIAN_SWAP(rI2, rI3, rG2, rG3)
+ cmpwi rLN,0
+ NEXT_BLOCK
+ bt gt,ppc_decrypt_xts_loop
+ START_IV
+ SAVE_IV(rI0, 0)
+ SAVE_IV(rI1, 4)
+ SAVE_IV(rI2, 8)
+ SAVE_IV(rI3, 12)
+ FINALIZE_CRYPT(8)
+ blr
diff --git a/lib/crypto/powerpc/aes-spe-regs.h b/lib/crypto/powerpc/aes-spe-regs.h
new file mode 100644
index 000000000000..2eb4c9b94152
--- /dev/null
+++ b/lib/crypto/powerpc/aes-spe-regs.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Common registers for PPC AES implementation
+ *
+ * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de>
+ */
+
+#define rKS r0 /* copy of en-/decryption key pointer */
+#define rDP r3 /* destination pointer */
+#define rSP r4 /* source pointer */
+#define rKP r5 /* pointer to en-/decryption key pointer */
+#define rRR r6 /* en-/decryption rounds */
+#define rLN r7 /* length of data to be processed */
+#define rIP r8 /* potiner to IV (CBC/CTR/XTS modes) */
+#define rKT r9 /* pointer to tweak key (XTS mode) */
+#define rT0 r11 /* pointers to en-/decryption tables */
+#define rT1 r10
+#define rD0 r9 /* data */
+#define rD1 r14
+#define rD2 r12
+#define rD3 r15
+#define rW0 r16 /* working registers */
+#define rW1 r17
+#define rW2 r18
+#define rW3 r19
+#define rW4 r20
+#define rW5 r21
+#define rW6 r22
+#define rW7 r23
+#define rI0 r24 /* IV */
+#define rI1 r25
+#define rI2 r26
+#define rI3 r27
+#define rG0 r28 /* endian reversed tweak (XTS mode) */
+#define rG1 r29
+#define rG2 r30
+#define rG3 r31
diff --git a/lib/crypto/powerpc/aes-tab-4k.S b/lib/crypto/powerpc/aes-tab-4k.S
new file mode 100644
index 000000000000..ceb604bc6f72
--- /dev/null
+++ b/lib/crypto/powerpc/aes-tab-4k.S
@@ -0,0 +1,326 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * 4K AES tables for PPC AES implementation
+ *
+ * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de>
+ */
+
+/*
+ * These big endian AES encryption/decryption tables have been taken from
+ * crypto/aes_generic.c and are designed to be simply accessed by a combination
+ * of rlwimi/lwz instructions with a minimum of table registers (usually only
+ * one required). Thus they are aligned to 4K. The locality of rotated values
+ * is derived from the reduced offsets that are available in the SPE load
+ * instructions. E.g. evldw, evlwwsplat, ...
+ *
+ * For the safety-conscious it has to be noted that they might be vulnerable
+ * to cache timing attacks because of their size. Nevertheless in contrast to
+ * the generic tables they have been reduced from 16KB to 8KB + 256 bytes.
+ * This is a quite good tradeoff for low power devices (e.g. routers) without
+ * dedicated encryption hardware where we usually have no multiuser
+ * environment.
+ *
+ */
+
+#define R(a, b, c, d) \
+ 0x##a##b##c##d, 0x##d##a##b##c, 0x##c##d##a##b, 0x##b##c##d##a
+
+.data
+.align 12
+.globl PPC_AES_4K_ENCTAB
+PPC_AES_4K_ENCTAB:
+/* encryption table, same as crypto_ft_tab in crypto/aes-generic.c */
+ .long R(c6, 63, 63, a5), R(f8, 7c, 7c, 84)
+ .long R(ee, 77, 77, 99), R(f6, 7b, 7b, 8d)
+ .long R(ff, f2, f2, 0d), R(d6, 6b, 6b, bd)
+ .long R(de, 6f, 6f, b1), R(91, c5, c5, 54)
+ .long R(60, 30, 30, 50), R(02, 01, 01, 03)
+ .long R(ce, 67, 67, a9), R(56, 2b, 2b, 7d)
+ .long R(e7, fe, fe, 19), R(b5, d7, d7, 62)
+ .long R(4d, ab, ab, e6), R(ec, 76, 76, 9a)
+ .long R(8f, ca, ca, 45), R(1f, 82, 82, 9d)
+ .long R(89, c9, c9, 40), R(fa, 7d, 7d, 87)
+ .long R(ef, fa, fa, 15), R(b2, 59, 59, eb)
+ .long R(8e, 47, 47, c9), R(fb, f0, f0, 0b)
+ .long R(41, ad, ad, ec), R(b3, d4, d4, 67)
+ .long R(5f, a2, a2, fd), R(45, af, af, ea)
+ .long R(23, 9c, 9c, bf), R(53, a4, a4, f7)
+ .long R(e4, 72, 72, 96), R(9b, c0, c0, 5b)
+ .long R(75, b7, b7, c2), R(e1, fd, fd, 1c)
+ .long R(3d, 93, 93, ae), R(4c, 26, 26, 6a)
+ .long R(6c, 36, 36, 5a), R(7e, 3f, 3f, 41)
+ .long R(f5, f7, f7, 02), R(83, cc, cc, 4f)
+ .long R(68, 34, 34, 5c), R(51, a5, a5, f4)
+ .long R(d1, e5, e5, 34), R(f9, f1, f1, 08)
+ .long R(e2, 71, 71, 93), R(ab, d8, d8, 73)
+ .long R(62, 31, 31, 53), R(2a, 15, 15, 3f)
+ .long R(08, 04, 04, 0c), R(95, c7, c7, 52)
+ .long R(46, 23, 23, 65), R(9d, c3, c3, 5e)
+ .long R(30, 18, 18, 28), R(37, 96, 96, a1)
+ .long R(0a, 05, 05, 0f), R(2f, 9a, 9a, b5)
+ .long R(0e, 07, 07, 09), R(24, 12, 12, 36)
+ .long R(1b, 80, 80, 9b), R(df, e2, e2, 3d)
+ .long R(cd, eb, eb, 26), R(4e, 27, 27, 69)
+ .long R(7f, b2, b2, cd), R(ea, 75, 75, 9f)
+ .long R(12, 09, 09, 1b), R(1d, 83, 83, 9e)
+ .long R(58, 2c, 2c, 74), R(34, 1a, 1a, 2e)
+ .long R(36, 1b, 1b, 2d), R(dc, 6e, 6e, b2)
+ .long R(b4, 5a, 5a, ee), R(5b, a0, a0, fb)
+ .long R(a4, 52, 52, f6), R(76, 3b, 3b, 4d)
+ .long R(b7, d6, d6, 61), R(7d, b3, b3, ce)
+ .long R(52, 29, 29, 7b), R(dd, e3, e3, 3e)
+ .long R(5e, 2f, 2f, 71), R(13, 84, 84, 97)
+ .long R(a6, 53, 53, f5), R(b9, d1, d1, 68)
+ .long R(00, 00, 00, 00), R(c1, ed, ed, 2c)
+ .long R(40, 20, 20, 60), R(e3, fc, fc, 1f)
+ .long R(79, b1, b1, c8), R(b6, 5b, 5b, ed)
+ .long R(d4, 6a, 6a, be), R(8d, cb, cb, 46)
+ .long R(67, be, be, d9), R(72, 39, 39, 4b)
+ .long R(94, 4a, 4a, de), R(98, 4c, 4c, d4)
+ .long R(b0, 58, 58, e8), R(85, cf, cf, 4a)
+ .long R(bb, d0, d0, 6b), R(c5, ef, ef, 2a)
+ .long R(4f, aa, aa, e5), R(ed, fb, fb, 16)
+ .long R(86, 43, 43, c5), R(9a, 4d, 4d, d7)
+ .long R(66, 33, 33, 55), R(11, 85, 85, 94)
+ .long R(8a, 45, 45, cf), R(e9, f9, f9, 10)
+ .long R(04, 02, 02, 06), R(fe, 7f, 7f, 81)
+ .long R(a0, 50, 50, f0), R(78, 3c, 3c, 44)
+ .long R(25, 9f, 9f, ba), R(4b, a8, a8, e3)
+ .long R(a2, 51, 51, f3), R(5d, a3, a3, fe)
+ .long R(80, 40, 40, c0), R(05, 8f, 8f, 8a)
+ .long R(3f, 92, 92, ad), R(21, 9d, 9d, bc)
+ .long R(70, 38, 38, 48), R(f1, f5, f5, 04)
+ .long R(63, bc, bc, df), R(77, b6, b6, c1)
+ .long R(af, da, da, 75), R(42, 21, 21, 63)
+ .long R(20, 10, 10, 30), R(e5, ff, ff, 1a)
+ .long R(fd, f3, f3, 0e), R(bf, d2, d2, 6d)
+ .long R(81, cd, cd, 4c), R(18, 0c, 0c, 14)
+ .long R(26, 13, 13, 35), R(c3, ec, ec, 2f)
+ .long R(be, 5f, 5f, e1), R(35, 97, 97, a2)
+ .long R(88, 44, 44, cc), R(2e, 17, 17, 39)
+ .long R(93, c4, c4, 57), R(55, a7, a7, f2)
+ .long R(fc, 7e, 7e, 82), R(7a, 3d, 3d, 47)
+ .long R(c8, 64, 64, ac), R(ba, 5d, 5d, e7)
+ .long R(32, 19, 19, 2b), R(e6, 73, 73, 95)
+ .long R(c0, 60, 60, a0), R(19, 81, 81, 98)
+ .long R(9e, 4f, 4f, d1), R(a3, dc, dc, 7f)
+ .long R(44, 22, 22, 66), R(54, 2a, 2a, 7e)
+ .long R(3b, 90, 90, ab), R(0b, 88, 88, 83)
+ .long R(8c, 46, 46, ca), R(c7, ee, ee, 29)
+ .long R(6b, b8, b8, d3), R(28, 14, 14, 3c)
+ .long R(a7, de, de, 79), R(bc, 5e, 5e, e2)
+ .long R(16, 0b, 0b, 1d), R(ad, db, db, 76)
+ .long R(db, e0, e0, 3b), R(64, 32, 32, 56)
+ .long R(74, 3a, 3a, 4e), R(14, 0a, 0a, 1e)
+ .long R(92, 49, 49, db), R(0c, 06, 06, 0a)
+ .long R(48, 24, 24, 6c), R(b8, 5c, 5c, e4)
+ .long R(9f, c2, c2, 5d), R(bd, d3, d3, 6e)
+ .long R(43, ac, ac, ef), R(c4, 62, 62, a6)
+ .long R(39, 91, 91, a8), R(31, 95, 95, a4)
+ .long R(d3, e4, e4, 37), R(f2, 79, 79, 8b)
+ .long R(d5, e7, e7, 32), R(8b, c8, c8, 43)
+ .long R(6e, 37, 37, 59), R(da, 6d, 6d, b7)
+ .long R(01, 8d, 8d, 8c), R(b1, d5, d5, 64)
+ .long R(9c, 4e, 4e, d2), R(49, a9, a9, e0)
+ .long R(d8, 6c, 6c, b4), R(ac, 56, 56, fa)
+ .long R(f3, f4, f4, 07), R(cf, ea, ea, 25)
+ .long R(ca, 65, 65, af), R(f4, 7a, 7a, 8e)
+ .long R(47, ae, ae, e9), R(10, 08, 08, 18)
+ .long R(6f, ba, ba, d5), R(f0, 78, 78, 88)
+ .long R(4a, 25, 25, 6f), R(5c, 2e, 2e, 72)
+ .long R(38, 1c, 1c, 24), R(57, a6, a6, f1)
+ .long R(73, b4, b4, c7), R(97, c6, c6, 51)
+ .long R(cb, e8, e8, 23), R(a1, dd, dd, 7c)
+ .long R(e8, 74, 74, 9c), R(3e, 1f, 1f, 21)
+ .long R(96, 4b, 4b, dd), R(61, bd, bd, dc)
+ .long R(0d, 8b, 8b, 86), R(0f, 8a, 8a, 85)
+ .long R(e0, 70, 70, 90), R(7c, 3e, 3e, 42)
+ .long R(71, b5, b5, c4), R(cc, 66, 66, aa)
+ .long R(90, 48, 48, d8), R(06, 03, 03, 05)
+ .long R(f7, f6, f6, 01), R(1c, 0e, 0e, 12)
+ .long R(c2, 61, 61, a3), R(6a, 35, 35, 5f)
+ .long R(ae, 57, 57, f9), R(69, b9, b9, d0)
+ .long R(17, 86, 86, 91), R(99, c1, c1, 58)
+ .long R(3a, 1d, 1d, 27), R(27, 9e, 9e, b9)
+ .long R(d9, e1, e1, 38), R(eb, f8, f8, 13)
+ .long R(2b, 98, 98, b3), R(22, 11, 11, 33)
+ .long R(d2, 69, 69, bb), R(a9, d9, d9, 70)
+ .long R(07, 8e, 8e, 89), R(33, 94, 94, a7)
+ .long R(2d, 9b, 9b, b6), R(3c, 1e, 1e, 22)
+ .long R(15, 87, 87, 92), R(c9, e9, e9, 20)
+ .long R(87, ce, ce, 49), R(aa, 55, 55, ff)
+ .long R(50, 28, 28, 78), R(a5, df, df, 7a)
+ .long R(03, 8c, 8c, 8f), R(59, a1, a1, f8)
+ .long R(09, 89, 89, 80), R(1a, 0d, 0d, 17)
+ .long R(65, bf, bf, da), R(d7, e6, e6, 31)
+ .long R(84, 42, 42, c6), R(d0, 68, 68, b8)
+ .long R(82, 41, 41, c3), R(29, 99, 99, b0)
+ .long R(5a, 2d, 2d, 77), R(1e, 0f, 0f, 11)
+ .long R(7b, b0, b0, cb), R(a8, 54, 54, fc)
+ .long R(6d, bb, bb, d6), R(2c, 16, 16, 3a)
+.globl PPC_AES_4K_DECTAB
+PPC_AES_4K_DECTAB:
+/* decryption table, same as crypto_it_tab in crypto/aes-generic.c */
+ .long R(51, f4, a7, 50), R(7e, 41, 65, 53)
+ .long R(1a, 17, a4, c3), R(3a, 27, 5e, 96)
+ .long R(3b, ab, 6b, cb), R(1f, 9d, 45, f1)
+ .long R(ac, fa, 58, ab), R(4b, e3, 03, 93)
+ .long R(20, 30, fa, 55), R(ad, 76, 6d, f6)
+ .long R(88, cc, 76, 91), R(f5, 02, 4c, 25)
+ .long R(4f, e5, d7, fc), R(c5, 2a, cb, d7)
+ .long R(26, 35, 44, 80), R(b5, 62, a3, 8f)
+ .long R(de, b1, 5a, 49), R(25, ba, 1b, 67)
+ .long R(45, ea, 0e, 98), R(5d, fe, c0, e1)
+ .long R(c3, 2f, 75, 02), R(81, 4c, f0, 12)
+ .long R(8d, 46, 97, a3), R(6b, d3, f9, c6)
+ .long R(03, 8f, 5f, e7), R(15, 92, 9c, 95)
+ .long R(bf, 6d, 7a, eb), R(95, 52, 59, da)
+ .long R(d4, be, 83, 2d), R(58, 74, 21, d3)
+ .long R(49, e0, 69, 29), R(8e, c9, c8, 44)
+ .long R(75, c2, 89, 6a), R(f4, 8e, 79, 78)
+ .long R(99, 58, 3e, 6b), R(27, b9, 71, dd)
+ .long R(be, e1, 4f, b6), R(f0, 88, ad, 17)
+ .long R(c9, 20, ac, 66), R(7d, ce, 3a, b4)
+ .long R(63, df, 4a, 18), R(e5, 1a, 31, 82)
+ .long R(97, 51, 33, 60), R(62, 53, 7f, 45)
+ .long R(b1, 64, 77, e0), R(bb, 6b, ae, 84)
+ .long R(fe, 81, a0, 1c), R(f9, 08, 2b, 94)
+ .long R(70, 48, 68, 58), R(8f, 45, fd, 19)
+ .long R(94, de, 6c, 87), R(52, 7b, f8, b7)
+ .long R(ab, 73, d3, 23), R(72, 4b, 02, e2)
+ .long R(e3, 1f, 8f, 57), R(66, 55, ab, 2a)
+ .long R(b2, eb, 28, 07), R(2f, b5, c2, 03)
+ .long R(86, c5, 7b, 9a), R(d3, 37, 08, a5)
+ .long R(30, 28, 87, f2), R(23, bf, a5, b2)
+ .long R(02, 03, 6a, ba), R(ed, 16, 82, 5c)
+ .long R(8a, cf, 1c, 2b), R(a7, 79, b4, 92)
+ .long R(f3, 07, f2, f0), R(4e, 69, e2, a1)
+ .long R(65, da, f4, cd), R(06, 05, be, d5)
+ .long R(d1, 34, 62, 1f), R(c4, a6, fe, 8a)
+ .long R(34, 2e, 53, 9d), R(a2, f3, 55, a0)
+ .long R(05, 8a, e1, 32), R(a4, f6, eb, 75)
+ .long R(0b, 83, ec, 39), R(40, 60, ef, aa)
+ .long R(5e, 71, 9f, 06), R(bd, 6e, 10, 51)
+ .long R(3e, 21, 8a, f9), R(96, dd, 06, 3d)
+ .long R(dd, 3e, 05, ae), R(4d, e6, bd, 46)
+ .long R(91, 54, 8d, b5), R(71, c4, 5d, 05)
+ .long R(04, 06, d4, 6f), R(60, 50, 15, ff)
+ .long R(19, 98, fb, 24), R(d6, bd, e9, 97)
+ .long R(89, 40, 43, cc), R(67, d9, 9e, 77)
+ .long R(b0, e8, 42, bd), R(07, 89, 8b, 88)
+ .long R(e7, 19, 5b, 38), R(79, c8, ee, db)
+ .long R(a1, 7c, 0a, 47), R(7c, 42, 0f, e9)
+ .long R(f8, 84, 1e, c9), R(00, 00, 00, 00)
+ .long R(09, 80, 86, 83), R(32, 2b, ed, 48)
+ .long R(1e, 11, 70, ac), R(6c, 5a, 72, 4e)
+ .long R(fd, 0e, ff, fb), R(0f, 85, 38, 56)
+ .long R(3d, ae, d5, 1e), R(36, 2d, 39, 27)
+ .long R(0a, 0f, d9, 64), R(68, 5c, a6, 21)
+ .long R(9b, 5b, 54, d1), R(24, 36, 2e, 3a)
+ .long R(0c, 0a, 67, b1), R(93, 57, e7, 0f)
+ .long R(b4, ee, 96, d2), R(1b, 9b, 91, 9e)
+ .long R(80, c0, c5, 4f), R(61, dc, 20, a2)
+ .long R(5a, 77, 4b, 69), R(1c, 12, 1a, 16)
+ .long R(e2, 93, ba, 0a), R(c0, a0, 2a, e5)
+ .long R(3c, 22, e0, 43), R(12, 1b, 17, 1d)
+ .long R(0e, 09, 0d, 0b), R(f2, 8b, c7, ad)
+ .long R(2d, b6, a8, b9), R(14, 1e, a9, c8)
+ .long R(57, f1, 19, 85), R(af, 75, 07, 4c)
+ .long R(ee, 99, dd, bb), R(a3, 7f, 60, fd)
+ .long R(f7, 01, 26, 9f), R(5c, 72, f5, bc)
+ .long R(44, 66, 3b, c5), R(5b, fb, 7e, 34)
+ .long R(8b, 43, 29, 76), R(cb, 23, c6, dc)
+ .long R(b6, ed, fc, 68), R(b8, e4, f1, 63)
+ .long R(d7, 31, dc, ca), R(42, 63, 85, 10)
+ .long R(13, 97, 22, 40), R(84, c6, 11, 20)
+ .long R(85, 4a, 24, 7d), R(d2, bb, 3d, f8)
+ .long R(ae, f9, 32, 11), R(c7, 29, a1, 6d)
+ .long R(1d, 9e, 2f, 4b), R(dc, b2, 30, f3)
+ .long R(0d, 86, 52, ec), R(77, c1, e3, d0)
+ .long R(2b, b3, 16, 6c), R(a9, 70, b9, 99)
+ .long R(11, 94, 48, fa), R(47, e9, 64, 22)
+ .long R(a8, fc, 8c, c4), R(a0, f0, 3f, 1a)
+ .long R(56, 7d, 2c, d8), R(22, 33, 90, ef)
+ .long R(87, 49, 4e, c7), R(d9, 38, d1, c1)
+ .long R(8c, ca, a2, fe), R(98, d4, 0b, 36)
+ .long R(a6, f5, 81, cf), R(a5, 7a, de, 28)
+ .long R(da, b7, 8e, 26), R(3f, ad, bf, a4)
+ .long R(2c, 3a, 9d, e4), R(50, 78, 92, 0d)
+ .long R(6a, 5f, cc, 9b), R(54, 7e, 46, 62)
+ .long R(f6, 8d, 13, c2), R(90, d8, b8, e8)
+ .long R(2e, 39, f7, 5e), R(82, c3, af, f5)
+ .long R(9f, 5d, 80, be), R(69, d0, 93, 7c)
+ .long R(6f, d5, 2d, a9), R(cf, 25, 12, b3)
+ .long R(c8, ac, 99, 3b), R(10, 18, 7d, a7)
+ .long R(e8, 9c, 63, 6e), R(db, 3b, bb, 7b)
+ .long R(cd, 26, 78, 09), R(6e, 59, 18, f4)
+ .long R(ec, 9a, b7, 01), R(83, 4f, 9a, a8)
+ .long R(e6, 95, 6e, 65), R(aa, ff, e6, 7e)
+ .long R(21, bc, cf, 08), R(ef, 15, e8, e6)
+ .long R(ba, e7, 9b, d9), R(4a, 6f, 36, ce)
+ .long R(ea, 9f, 09, d4), R(29, b0, 7c, d6)
+ .long R(31, a4, b2, af), R(2a, 3f, 23, 31)
+ .long R(c6, a5, 94, 30), R(35, a2, 66, c0)
+ .long R(74, 4e, bc, 37), R(fc, 82, ca, a6)
+ .long R(e0, 90, d0, b0), R(33, a7, d8, 15)
+ .long R(f1, 04, 98, 4a), R(41, ec, da, f7)
+ .long R(7f, cd, 50, 0e), R(17, 91, f6, 2f)
+ .long R(76, 4d, d6, 8d), R(43, ef, b0, 4d)
+ .long R(cc, aa, 4d, 54), R(e4, 96, 04, df)
+ .long R(9e, d1, b5, e3), R(4c, 6a, 88, 1b)
+ .long R(c1, 2c, 1f, b8), R(46, 65, 51, 7f)
+ .long R(9d, 5e, ea, 04), R(01, 8c, 35, 5d)
+ .long R(fa, 87, 74, 73), R(fb, 0b, 41, 2e)
+ .long R(b3, 67, 1d, 5a), R(92, db, d2, 52)
+ .long R(e9, 10, 56, 33), R(6d, d6, 47, 13)
+ .long R(9a, d7, 61, 8c), R(37, a1, 0c, 7a)
+ .long R(59, f8, 14, 8e), R(eb, 13, 3c, 89)
+ .long R(ce, a9, 27, ee), R(b7, 61, c9, 35)
+ .long R(e1, 1c, e5, ed), R(7a, 47, b1, 3c)
+ .long R(9c, d2, df, 59), R(55, f2, 73, 3f)
+ .long R(18, 14, ce, 79), R(73, c7, 37, bf)
+ .long R(53, f7, cd, ea), R(5f, fd, aa, 5b)
+ .long R(df, 3d, 6f, 14), R(78, 44, db, 86)
+ .long R(ca, af, f3, 81), R(b9, 68, c4, 3e)
+ .long R(38, 24, 34, 2c), R(c2, a3, 40, 5f)
+ .long R(16, 1d, c3, 72), R(bc, e2, 25, 0c)
+ .long R(28, 3c, 49, 8b), R(ff, 0d, 95, 41)
+ .long R(39, a8, 01, 71), R(08, 0c, b3, de)
+ .long R(d8, b4, e4, 9c), R(64, 56, c1, 90)
+ .long R(7b, cb, 84, 61), R(d5, 32, b6, 70)
+ .long R(48, 6c, 5c, 74), R(d0, b8, 57, 42)
+.globl PPC_AES_4K_DECTAB2
+PPC_AES_4K_DECTAB2:
+/* decryption table, same as crypto_il_tab in crypto/aes-generic.c */
+ .byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
+ .byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
+ .byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
+ .byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
+ .byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
+ .byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
+ .byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
+ .byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
+ .byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
+ .byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
+ .byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
+ .byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
+ .byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
+ .byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
+ .byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
+ .byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
+ .byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
+ .byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
+ .byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
+ .byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
+ .byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
+ .byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
+ .byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
+ .byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
+ .byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
+ .byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
+ .byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
+ .byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
+ .byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
+ .byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
+ .byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
+ .byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
diff --git a/lib/crypto/powerpc/aes.h b/lib/crypto/powerpc/aes.h
new file mode 100644
index 000000000000..5a36b637e6b9
--- /dev/null
+++ b/lib/crypto/powerpc/aes.h
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de>
+ * Copyright (C) 2015 International Business Machines Inc.
+ * Copyright 2026 Google LLC
+ */
+#include <asm/simd.h>
+#include <asm/switch_to.h>
+#include <linux/cpufeature.h>
+#include <linux/jump_label.h>
+#include <linux/preempt.h>
+#include <linux/uaccess.h>
+
+#ifdef CONFIG_SPE
+
+EXPORT_SYMBOL_GPL(ppc_expand_key_128);
+EXPORT_SYMBOL_GPL(ppc_expand_key_192);
+EXPORT_SYMBOL_GPL(ppc_expand_key_256);
+EXPORT_SYMBOL_GPL(ppc_generate_decrypt_key);
+EXPORT_SYMBOL_GPL(ppc_encrypt_ecb);
+EXPORT_SYMBOL_GPL(ppc_decrypt_ecb);
+EXPORT_SYMBOL_GPL(ppc_encrypt_cbc);
+EXPORT_SYMBOL_GPL(ppc_decrypt_cbc);
+EXPORT_SYMBOL_GPL(ppc_crypt_ctr);
+EXPORT_SYMBOL_GPL(ppc_encrypt_xts);
+EXPORT_SYMBOL_GPL(ppc_decrypt_xts);
+
+void ppc_encrypt_aes(u8 *out, const u8 *in, const u32 *key_enc, u32 rounds);
+void ppc_decrypt_aes(u8 *out, const u8 *in, const u32 *key_dec, u32 rounds);
+
+static void spe_begin(void)
+{
+ /* disable preemption and save users SPE registers if required */
+ preempt_disable();
+ enable_kernel_spe();
+}
+
+static void spe_end(void)
+{
+ disable_kernel_spe();
+ /* reenable preemption */
+ preempt_enable();
+}
+
+static void aes_preparekey_arch(union aes_enckey_arch *k,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, int key_len, int nrounds)
+{
+ if (key_len == AES_KEYSIZE_128)
+ ppc_expand_key_128(k->spe_enc_key, in_key);
+ else if (key_len == AES_KEYSIZE_192)
+ ppc_expand_key_192(k->spe_enc_key, in_key);
+ else
+ ppc_expand_key_256(k->spe_enc_key, in_key);
+
+ if (inv_k)
+ ppc_generate_decrypt_key(inv_k->spe_dec_key, k->spe_enc_key,
+ key_len);
+}
+
+static void aes_encrypt_arch(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ spe_begin();
+ ppc_encrypt_aes(out, in, key->k.spe_enc_key, key->nrounds / 2 - 1);
+ spe_end();
+}
+
+static void aes_decrypt_arch(const struct aes_key *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ spe_begin();
+ ppc_decrypt_aes(out, in, key->inv_k.spe_dec_key, key->nrounds / 2 - 1);
+ spe_end();
+}
+
+#else /* CONFIG_SPE */
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_vec_crypto);
+
+EXPORT_SYMBOL_GPL(aes_p8_set_encrypt_key);
+EXPORT_SYMBOL_GPL(aes_p8_set_decrypt_key);
+EXPORT_SYMBOL_GPL(aes_p8_encrypt);
+EXPORT_SYMBOL_GPL(aes_p8_decrypt);
+EXPORT_SYMBOL_GPL(aes_p8_cbc_encrypt);
+EXPORT_SYMBOL_GPL(aes_p8_ctr32_encrypt_blocks);
+EXPORT_SYMBOL_GPL(aes_p8_xts_encrypt);
+EXPORT_SYMBOL_GPL(aes_p8_xts_decrypt);
+
+static inline bool is_vsx_format(const struct p8_aes_key *key)
+{
+ return key->nrounds != 0;
+}
+
+/*
+ * Convert a round key from VSX to generic format by reflecting all 16 bytes (if
+ * little endian) or reflecting the bytes in each 4-byte word (if big endian),
+ * and (if apply_inv_mix=true) applying InvMixColumn to each column.
+ *
+ * It would be nice if the VSX and generic key formats would be compatible. But
+ * that's very difficult to do, with the assembly code having been borrowed from
+ * OpenSSL and also targeted to POWER8 rather than POWER9.
+ *
+ * Fortunately, this conversion should only be needed in extremely rare cases,
+ * possibly not at all in practice. It's just included for full correctness.
+ */
+static void rndkey_from_vsx(u32 out[4], const u32 in[4], bool apply_inv_mix)
+{
+ const bool be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
+ u32 k0 = swab32(in[0]);
+ u32 k1 = swab32(in[1]);
+ u32 k2 = swab32(in[2]);
+ u32 k3 = swab32(in[3]);
+
+ if (apply_inv_mix) {
+ k0 = inv_mix_columns(k0);
+ k1 = inv_mix_columns(k1);
+ k2 = inv_mix_columns(k2);
+ k3 = inv_mix_columns(k3);
+ }
+ out[0] = be ? k0 : k3;
+ out[1] = be ? k1 : k2;
+ out[2] = be ? k2 : k1;
+ out[3] = be ? k3 : k0;
+}
+
+static void aes_preparekey_arch(union aes_enckey_arch *k,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, int key_len, int nrounds)
+{
+ const int keybits = 8 * key_len;
+ int ret;
+
+ if (static_branch_likely(&have_vec_crypto) && likely(may_use_simd())) {
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_vsx();
+ ret = aes_p8_set_encrypt_key(in_key, keybits, &k->p8);
+ /*
+ * aes_p8_set_encrypt_key() should never fail here, since the
+ * key length was already validated.
+ */
+ WARN_ON_ONCE(ret);
+ if (inv_k) {
+ ret = aes_p8_set_decrypt_key(in_key, keybits,
+ &inv_k->p8);
+ /* ... and likewise for aes_p8_set_decrypt_key(). */
+ WARN_ON_ONCE(ret);
+ }
+ disable_kernel_vsx();
+ pagefault_enable();
+ preempt_enable();
+ } else {
+ aes_expandkey_generic(k->rndkeys,
+ inv_k ? inv_k->inv_rndkeys : NULL,
+ in_key, key_len);
+ /* Mark the key as using the generic format. */
+ k->p8.nrounds = 0;
+ if (inv_k)
+ inv_k->p8.nrounds = 0;
+ }
+}
+
+static void aes_encrypt_arch(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (static_branch_likely(&have_vec_crypto) &&
+ likely(is_vsx_format(&key->k.p8) && may_use_simd())) {
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_vsx();
+ aes_p8_encrypt(in, out, &key->k.p8);
+ disable_kernel_vsx();
+ pagefault_enable();
+ preempt_enable();
+ } else if (unlikely(is_vsx_format(&key->k.p8))) {
+ /*
+ * This handles (the hopefully extremely rare) case where a key
+ * was prepared using the VSX optimized format, then encryption
+ * is done in a context that cannot use VSX instructions.
+ */
+ u32 rndkeys[AES_MAX_KEYLENGTH_U32];
+
+ for (int i = 0; i < 4 * (key->nrounds + 1); i += 4)
+ rndkey_from_vsx(&rndkeys[i],
+ &key->k.p8.rndkeys[i], false);
+ aes_encrypt_generic(rndkeys, key->nrounds, out, in);
+ } else {
+ aes_encrypt_generic(key->k.rndkeys, key->nrounds, out, in);
+ }
+}
+
+static void aes_decrypt_arch(const struct aes_key *key, u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (static_branch_likely(&have_vec_crypto) &&
+ likely(is_vsx_format(&key->inv_k.p8) && may_use_simd())) {
+ preempt_disable();
+ pagefault_disable();
+ enable_kernel_vsx();
+ aes_p8_decrypt(in, out, &key->inv_k.p8);
+ disable_kernel_vsx();
+ pagefault_enable();
+ preempt_enable();
+ } else if (unlikely(is_vsx_format(&key->inv_k.p8))) {
+ /*
+ * This handles (the hopefully extremely rare) case where a key
+ * was prepared using the VSX optimized format, then decryption
+ * is done in a context that cannot use VSX instructions.
+ */
+ u32 inv_rndkeys[AES_MAX_KEYLENGTH_U32];
+ int i;
+
+ rndkey_from_vsx(&inv_rndkeys[0],
+ &key->inv_k.p8.rndkeys[0], false);
+ for (i = 4; i < 4 * key->nrounds; i += 4) {
+ rndkey_from_vsx(&inv_rndkeys[i],
+ &key->inv_k.p8.rndkeys[i], true);
+ }
+ rndkey_from_vsx(&inv_rndkeys[i],
+ &key->inv_k.p8.rndkeys[i], false);
+ aes_decrypt_generic(inv_rndkeys, key->nrounds, out, in);
+ } else {
+ aes_decrypt_generic(key->inv_k.inv_rndkeys, key->nrounds,
+ out, in);
+ }
+}
+
+#define aes_mod_init_arch aes_mod_init_arch
+static void aes_mod_init_arch(void)
+{
+ if (cpu_has_feature(CPU_FTR_ARCH_207S) &&
+ (cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_VEC_CRYPTO))
+ static_branch_enable(&have_vec_crypto);
+}
+
+#endif /* !CONFIG_SPE */
diff --git a/lib/crypto/powerpc/aesp8-ppc.pl b/lib/crypto/powerpc/aesp8-ppc.pl
new file mode 100644
index 000000000000..253a06758057
--- /dev/null
+++ b/lib/crypto/powerpc/aesp8-ppc.pl
@@ -0,0 +1,3890 @@
+#! /usr/bin/env perl
+# SPDX-License-Identifier: GPL-2.0
+
+# This code is taken from CRYPTOGAMs[1] and is included here using the option
+# in the license to distribute the code under the GPL. Therefore this program
+# is free software; you can redistribute it and/or modify it under the terms of
+# the GNU General Public License version 2 as published by the Free Software
+# Foundation.
+#
+# [1] https://www.openssl.org/~appro/cryptogams/
+
+# Copyright (c) 2006-2017, CRYPTOGAMS by <appro@openssl.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain copyright notices,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# * Neither the name of the CRYPTOGAMS nor the names of its
+# copyright holder and contributors may be used to endorse or
+# promote products derived from this software without specific
+# prior written permission.
+#
+# ALTERNATIVELY, provided that this notice is retained in full, this
+# product may be distributed under the terms of the GNU General Public
+# License (GPL), in which case the provisions of the GPL apply INSTEAD OF
+# those given above.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see https://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# This module implements support for AES instructions as per PowerISA
+# specification version 2.07, first implemented by POWER8 processor.
+# The module is endian-agnostic in sense that it supports both big-
+# and little-endian cases. Data alignment in parallelizable modes is
+# handled with VSX loads and stores, which implies MSR.VSX flag being
+# set. It should also be noted that ISA specification doesn't prohibit
+# alignment exceptions for these instructions on page boundaries.
+# Initially alignment was handled in pure AltiVec/VMX way [when data
+# is aligned programmatically, which in turn guarantees exception-
+# free execution], but it turned to hamper performance when vcipher
+# instructions are interleaved. It's reckoned that eventual
+# misalignment penalties at page boundaries are in average lower
+# than additional overhead in pure AltiVec approach.
+#
+# May 2016
+#
+# Add XTS subroutine, 9x on little- and 12x improvement on big-endian
+# systems were measured.
+#
+######################################################################
+# Current large-block performance in cycles per byte processed with
+# 128-bit key (less is better).
+#
+# CBC en-/decrypt CTR XTS
+# POWER8[le] 3.96/0.72 0.74 1.1
+# POWER8[be] 3.75/0.65 0.66 1.0
+
+$flavour = shift;
+
+if ($flavour =~ /64/) {
+ $SIZE_T =8;
+ $LRSAVE =2*$SIZE_T;
+ $STU ="stdu";
+ $POP ="ld";
+ $PUSH ="std";
+ $UCMP ="cmpld";
+ $SHL ="sldi";
+} elsif ($flavour =~ /32/) {
+ $SIZE_T =4;
+ $LRSAVE =$SIZE_T;
+ $STU ="stwu";
+ $POP ="lwz";
+ $PUSH ="stw";
+ $UCMP ="cmplw";
+ $SHL ="slwi";
+} else { die "nonsense $flavour"; }
+
+$LITTLE_ENDIAN = ($flavour=~/le$/) ? $SIZE_T : 0;
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
+( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
+( $xlate="${dir}../../../arch/powerpc/crypto/ppc-xlate.pl" and -f $xlate) or
+die "can't locate ppc-xlate.pl";
+
+open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
+
+$FRAME=8*$SIZE_T;
+$prefix="aes_p8";
+
+$sp="r1";
+$vrsave="r12";
+
+#########################################################################
+{{{ # Key setup procedures #
+my ($inp,$bits,$out,$ptr,$cnt,$rounds)=map("r$_",(3..8));
+my ($zero,$in0,$in1,$key,$rcon,$mask,$tmp)=map("v$_",(0..6));
+my ($stage,$outperm,$outmask,$outhead,$outtail)=map("v$_",(7..11));
+
+$code.=<<___;
+.machine "any"
+
+.text
+
+.align 7
+rcon:
+.long 0x01000000, 0x01000000, 0x01000000, 0x01000000 ?rev
+.long 0x1b000000, 0x1b000000, 0x1b000000, 0x1b000000 ?rev
+.long 0x0d0e0f0c, 0x0d0e0f0c, 0x0d0e0f0c, 0x0d0e0f0c ?rev
+.long 0,0,0,0 ?asis
+.long 0x0f102132, 0x43546576, 0x8798a9ba, 0xcbdcedfe
+Lconsts:
+ mflr r0
+ bcl 20,31,\$+4
+ mflr $ptr #vvvvv "distance between . and rcon
+ addi $ptr,$ptr,-0x58
+ mtlr r0
+ blr
+ .long 0
+ .byte 0,12,0x14,0,0,0,0,0
+.asciz "AES for PowerISA 2.07, CRYPTOGAMS by <appro\@openssl.org>"
+
+.globl .${prefix}_set_encrypt_key
+Lset_encrypt_key:
+ mflr r11
+ $PUSH r11,$LRSAVE($sp)
+
+ li $ptr,-1
+ ${UCMP}i $inp,0
+ beq- Lenc_key_abort # if ($inp==0) return -1;
+ ${UCMP}i $out,0
+ beq- Lenc_key_abort # if ($out==0) return -1;
+ li $ptr,-2
+ cmpwi $bits,128
+ blt- Lenc_key_abort
+ cmpwi $bits,256
+ bgt- Lenc_key_abort
+ andi. r0,$bits,0x3f
+ bne- Lenc_key_abort
+
+ lis r0,0xfff0
+ mfspr $vrsave,256
+ mtspr 256,r0
+
+ bl Lconsts
+ mtlr r11
+
+ neg r9,$inp
+ lvx $in0,0,$inp
+ addi $inp,$inp,15 # 15 is not typo
+ lvsr $key,0,r9 # borrow $key
+ li r8,0x20
+ cmpwi $bits,192
+ lvx $in1,0,$inp
+ le?vspltisb $mask,0x0f # borrow $mask
+ lvx $rcon,0,$ptr
+ le?vxor $key,$key,$mask # adjust for byte swap
+ lvx $mask,r8,$ptr
+ addi $ptr,$ptr,0x10
+ vperm $in0,$in0,$in1,$key # align [and byte swap in LE]
+ li $cnt,8
+ vxor $zero,$zero,$zero
+ mtctr $cnt
+
+ ?lvsr $outperm,0,$out
+ vspltisb $outmask,-1
+ lvx $outhead,0,$out
+ ?vperm $outmask,$zero,$outmask,$outperm
+
+ blt Loop128
+ addi $inp,$inp,8
+ beq L192
+ addi $inp,$inp,8
+ b L256
+
+.align 4
+Loop128:
+ vperm $key,$in0,$in0,$mask # rotate-n-splat
+ vsldoi $tmp,$zero,$in0,12 # >>32
+ vperm $outtail,$in0,$in0,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ vcipherlast $key,$key,$rcon
+ stvx $stage,0,$out
+ addi $out,$out,16
+
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+ vadduwm $rcon,$rcon,$rcon
+ vxor $in0,$in0,$key
+ bdnz Loop128
+
+ lvx $rcon,0,$ptr # last two round keys
+
+ vperm $key,$in0,$in0,$mask # rotate-n-splat
+ vsldoi $tmp,$zero,$in0,12 # >>32
+ vperm $outtail,$in0,$in0,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ vcipherlast $key,$key,$rcon
+ stvx $stage,0,$out
+ addi $out,$out,16
+
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+ vadduwm $rcon,$rcon,$rcon
+ vxor $in0,$in0,$key
+
+ vperm $key,$in0,$in0,$mask # rotate-n-splat
+ vsldoi $tmp,$zero,$in0,12 # >>32
+ vperm $outtail,$in0,$in0,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ vcipherlast $key,$key,$rcon
+ stvx $stage,0,$out
+ addi $out,$out,16
+
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+ vxor $in0,$in0,$key
+ vperm $outtail,$in0,$in0,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ stvx $stage,0,$out
+
+ addi $inp,$out,15 # 15 is not typo
+ addi $out,$out,0x50
+
+ li $rounds,10
+ b Ldone
+
+.align 4
+L192:
+ lvx $tmp,0,$inp
+ li $cnt,4
+ vperm $outtail,$in0,$in0,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ stvx $stage,0,$out
+ addi $out,$out,16
+ vperm $in1,$in1,$tmp,$key # align [and byte swap in LE]
+ vspltisb $key,8 # borrow $key
+ mtctr $cnt
+ vsububm $mask,$mask,$key # adjust the mask
+
+Loop192:
+ vperm $key,$in1,$in1,$mask # roate-n-splat
+ vsldoi $tmp,$zero,$in0,12 # >>32
+ vcipherlast $key,$key,$rcon
+
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+
+ vsldoi $stage,$zero,$in1,8
+ vspltw $tmp,$in0,3
+ vxor $tmp,$tmp,$in1
+ vsldoi $in1,$zero,$in1,12 # >>32
+ vadduwm $rcon,$rcon,$rcon
+ vxor $in1,$in1,$tmp
+ vxor $in0,$in0,$key
+ vxor $in1,$in1,$key
+ vsldoi $stage,$stage,$in0,8
+
+ vperm $key,$in1,$in1,$mask # rotate-n-splat
+ vsldoi $tmp,$zero,$in0,12 # >>32
+ vperm $outtail,$stage,$stage,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ vcipherlast $key,$key,$rcon
+ stvx $stage,0,$out
+ addi $out,$out,16
+
+ vsldoi $stage,$in0,$in1,8
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vperm $outtail,$stage,$stage,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+ stvx $stage,0,$out
+ addi $out,$out,16
+
+ vspltw $tmp,$in0,3
+ vxor $tmp,$tmp,$in1
+ vsldoi $in1,$zero,$in1,12 # >>32
+ vadduwm $rcon,$rcon,$rcon
+ vxor $in1,$in1,$tmp
+ vxor $in0,$in0,$key
+ vxor $in1,$in1,$key
+ vperm $outtail,$in0,$in0,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ stvx $stage,0,$out
+ addi $inp,$out,15 # 15 is not typo
+ addi $out,$out,16
+ bdnz Loop192
+
+ li $rounds,12
+ addi $out,$out,0x20
+ b Ldone
+
+.align 4
+L256:
+ lvx $tmp,0,$inp
+ li $cnt,7
+ li $rounds,14
+ vperm $outtail,$in0,$in0,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ stvx $stage,0,$out
+ addi $out,$out,16
+ vperm $in1,$in1,$tmp,$key # align [and byte swap in LE]
+ mtctr $cnt
+
+Loop256:
+ vperm $key,$in1,$in1,$mask # rotate-n-splat
+ vsldoi $tmp,$zero,$in0,12 # >>32
+ vperm $outtail,$in1,$in1,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ vcipherlast $key,$key,$rcon
+ stvx $stage,0,$out
+ addi $out,$out,16
+
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in0,$in0,$tmp
+ vadduwm $rcon,$rcon,$rcon
+ vxor $in0,$in0,$key
+ vperm $outtail,$in0,$in0,$outperm # rotate
+ vsel $stage,$outhead,$outtail,$outmask
+ vmr $outhead,$outtail
+ stvx $stage,0,$out
+ addi $inp,$out,15 # 15 is not typo
+ addi $out,$out,16
+ bdz Ldone
+
+ vspltw $key,$in0,3 # just splat
+ vsldoi $tmp,$zero,$in1,12 # >>32
+ vsbox $key,$key
+
+ vxor $in1,$in1,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in1,$in1,$tmp
+ vsldoi $tmp,$zero,$tmp,12 # >>32
+ vxor $in1,$in1,$tmp
+
+ vxor $in1,$in1,$key
+ b Loop256
+
+.align 4
+Ldone:
+ lvx $in1,0,$inp # redundant in aligned case
+ vsel $in1,$outhead,$in1,$outmask
+ stvx $in1,0,$inp
+ li $ptr,0
+ mtspr 256,$vrsave
+ stw $rounds,0($out)
+
+Lenc_key_abort:
+ mr r3,$ptr
+ blr
+ .long 0
+ .byte 0,12,0x14,1,0,0,3,0
+ .long 0
+.size .${prefix}_set_encrypt_key,.-.${prefix}_set_encrypt_key
+
+.globl .${prefix}_set_decrypt_key
+ $STU $sp,-$FRAME($sp)
+ mflr r10
+ $PUSH r10,$FRAME+$LRSAVE($sp)
+ bl Lset_encrypt_key
+ mtlr r10
+
+ cmpwi r3,0
+ bne- Ldec_key_abort
+
+ slwi $cnt,$rounds,4
+ subi $inp,$out,240 # first round key
+ srwi $rounds,$rounds,1
+ add $out,$inp,$cnt # last round key
+ mtctr $rounds
+
+Ldeckey:
+ lwz r0, 0($inp)
+ lwz r6, 4($inp)
+ lwz r7, 8($inp)
+ lwz r8, 12($inp)
+ addi $inp,$inp,16
+ lwz r9, 0($out)
+ lwz r10,4($out)
+ lwz r11,8($out)
+ lwz r12,12($out)
+ stw r0, 0($out)
+ stw r6, 4($out)
+ stw r7, 8($out)
+ stw r8, 12($out)
+ subi $out,$out,16
+ stw r9, -16($inp)
+ stw r10,-12($inp)
+ stw r11,-8($inp)
+ stw r12,-4($inp)
+ bdnz Ldeckey
+
+ xor r3,r3,r3 # return value
+Ldec_key_abort:
+ addi $sp,$sp,$FRAME
+ blr
+ .long 0
+ .byte 0,12,4,1,0x80,0,3,0
+ .long 0
+.size .${prefix}_set_decrypt_key,.-.${prefix}_set_decrypt_key
+___
+}}}
+#########################################################################
+{{{ # Single block en- and decrypt procedures #
+sub gen_block () {
+my $dir = shift;
+my $n = $dir eq "de" ? "n" : "";
+my ($inp,$out,$key,$rounds,$idx)=map("r$_",(3..7));
+
+$code.=<<___;
+.globl .${prefix}_${dir}crypt
+ lwz $rounds,240($key)
+ lis r0,0xfc00
+ mfspr $vrsave,256
+ li $idx,15 # 15 is not typo
+ mtspr 256,r0
+
+ lvx v0,0,$inp
+ neg r11,$out
+ lvx v1,$idx,$inp
+ lvsl v2,0,$inp # inpperm
+ le?vspltisb v4,0x0f
+ ?lvsl v3,0,r11 # outperm
+ le?vxor v2,v2,v4
+ li $idx,16
+ vperm v0,v0,v1,v2 # align [and byte swap in LE]
+ lvx v1,0,$key
+ ?lvsl v5,0,$key # keyperm
+ srwi $rounds,$rounds,1
+ lvx v2,$idx,$key
+ addi $idx,$idx,16
+ subi $rounds,$rounds,1
+ ?vperm v1,v1,v2,v5 # align round key
+
+ vxor v0,v0,v1
+ lvx v1,$idx,$key
+ addi $idx,$idx,16
+ mtctr $rounds
+
+Loop_${dir}c:
+ ?vperm v2,v2,v1,v5
+ v${n}cipher v0,v0,v2
+ lvx v2,$idx,$key
+ addi $idx,$idx,16
+ ?vperm v1,v1,v2,v5
+ v${n}cipher v0,v0,v1
+ lvx v1,$idx,$key
+ addi $idx,$idx,16
+ bdnz Loop_${dir}c
+
+ ?vperm v2,v2,v1,v5
+ v${n}cipher v0,v0,v2
+ lvx v2,$idx,$key
+ ?vperm v1,v1,v2,v5
+ v${n}cipherlast v0,v0,v1
+
+ vspltisb v2,-1
+ vxor v1,v1,v1
+ li $idx,15 # 15 is not typo
+ ?vperm v2,v1,v2,v3 # outmask
+ le?vxor v3,v3,v4
+ lvx v1,0,$out # outhead
+ vperm v0,v0,v0,v3 # rotate [and byte swap in LE]
+ vsel v1,v1,v0,v2
+ lvx v4,$idx,$out
+ stvx v1,0,$out
+ vsel v0,v0,v4,v2
+ stvx v0,$idx,$out
+
+ mtspr 256,$vrsave
+ blr
+ .long 0
+ .byte 0,12,0x14,0,0,0,3,0
+ .long 0
+.size .${prefix}_${dir}crypt,.-.${prefix}_${dir}crypt
+___
+}
+&gen_block("en");
+&gen_block("de");
+}}}
+#########################################################################
+{{{ # CBC en- and decrypt procedures #
+my ($inp,$out,$len,$key,$ivp,$enc,$rounds,$idx)=map("r$_",(3..10));
+my ($rndkey0,$rndkey1,$inout,$tmp)= map("v$_",(0..3));
+my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm)=
+ map("v$_",(4..10));
+$code.=<<___;
+.globl .${prefix}_cbc_encrypt
+ ${UCMP}i $len,16
+ bltlr-
+
+ cmpwi $enc,0 # test direction
+ lis r0,0xffe0
+ mfspr $vrsave,256
+ mtspr 256,r0
+
+ li $idx,15
+ vxor $rndkey0,$rndkey0,$rndkey0
+ le?vspltisb $tmp,0x0f
+
+ lvx $ivec,0,$ivp # load [unaligned] iv
+ lvsl $inpperm,0,$ivp
+ lvx $inptail,$idx,$ivp
+ le?vxor $inpperm,$inpperm,$tmp
+ vperm $ivec,$ivec,$inptail,$inpperm
+
+ neg r11,$inp
+ ?lvsl $keyperm,0,$key # prepare for unaligned key
+ lwz $rounds,240($key)
+
+ lvsr $inpperm,0,r11 # prepare for unaligned load
+ lvx $inptail,0,$inp
+ addi $inp,$inp,15 # 15 is not typo
+ le?vxor $inpperm,$inpperm,$tmp
+
+ ?lvsr $outperm,0,$out # prepare for unaligned store
+ vspltisb $outmask,-1
+ lvx $outhead,0,$out
+ ?vperm $outmask,$rndkey0,$outmask,$outperm
+ le?vxor $outperm,$outperm,$tmp
+
+ srwi $rounds,$rounds,1
+ li $idx,16
+ subi $rounds,$rounds,1
+ beq Lcbc_dec
+
+Lcbc_enc:
+ vmr $inout,$inptail
+ lvx $inptail,0,$inp
+ addi $inp,$inp,16
+ mtctr $rounds
+ subi $len,$len,16 # len-=16
+
+ lvx $rndkey0,0,$key
+ vperm $inout,$inout,$inptail,$inpperm
+ lvx $rndkey1,$idx,$key
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key
+ addi $idx,$idx,16
+ vxor $inout,$inout,$ivec
+
+Loop_cbc_enc:
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vcipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vcipher $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key
+ addi $idx,$idx,16
+ bdnz Loop_cbc_enc
+
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vcipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key
+ li $idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vcipherlast $ivec,$inout,$rndkey0
+ ${UCMP}i $len,16
+
+ vperm $tmp,$ivec,$ivec,$outperm
+ vsel $inout,$outhead,$tmp,$outmask
+ vmr $outhead,$tmp
+ stvx $inout,0,$out
+ addi $out,$out,16
+ bge Lcbc_enc
+
+ b Lcbc_done
+
+.align 4
+Lcbc_dec:
+ ${UCMP}i $len,128
+ bge _aesp8_cbc_decrypt8x
+ vmr $tmp,$inptail
+ lvx $inptail,0,$inp
+ addi $inp,$inp,16
+ mtctr $rounds
+ subi $len,$len,16 # len-=16
+
+ lvx $rndkey0,0,$key
+ vperm $tmp,$tmp,$inptail,$inpperm
+ lvx $rndkey1,$idx,$key
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $inout,$tmp,$rndkey0
+ lvx $rndkey0,$idx,$key
+ addi $idx,$idx,16
+
+Loop_cbc_dec:
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vncipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vncipher $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key
+ addi $idx,$idx,16
+ bdnz Loop_cbc_dec
+
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vncipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key
+ li $idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vncipherlast $inout,$inout,$rndkey0
+ ${UCMP}i $len,16
+
+ vxor $inout,$inout,$ivec
+ vmr $ivec,$tmp
+ vperm $tmp,$inout,$inout,$outperm
+ vsel $inout,$outhead,$tmp,$outmask
+ vmr $outhead,$tmp
+ stvx $inout,0,$out
+ addi $out,$out,16
+ bge Lcbc_dec
+
+Lcbc_done:
+ addi $out,$out,-1
+ lvx $inout,0,$out # redundant in aligned case
+ vsel $inout,$outhead,$inout,$outmask
+ stvx $inout,0,$out
+
+ neg $enc,$ivp # write [unaligned] iv
+ li $idx,15 # 15 is not typo
+ vxor $rndkey0,$rndkey0,$rndkey0
+ vspltisb $outmask,-1
+ le?vspltisb $tmp,0x0f
+ ?lvsl $outperm,0,$enc
+ ?vperm $outmask,$rndkey0,$outmask,$outperm
+ le?vxor $outperm,$outperm,$tmp
+ lvx $outhead,0,$ivp
+ vperm $ivec,$ivec,$ivec,$outperm
+ vsel $inout,$outhead,$ivec,$outmask
+ lvx $inptail,$idx,$ivp
+ stvx $inout,0,$ivp
+ vsel $inout,$ivec,$inptail,$outmask
+ stvx $inout,$idx,$ivp
+
+ mtspr 256,$vrsave
+ blr
+ .long 0
+ .byte 0,12,0x14,0,0,0,6,0
+ .long 0
+___
+#########################################################################
+{{ # Optimized CBC decrypt procedure #
+my $key_="r11";
+my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,8,26..31));
+my ($in0, $in1, $in2, $in3, $in4, $in5, $in6, $in7 )=map("v$_",(0..3,10..13));
+my ($out0,$out1,$out2,$out3,$out4,$out5,$out6,$out7)=map("v$_",(14..21));
+my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys
+ # v26-v31 last 6 round keys
+my ($tmp,$keyperm)=($in3,$in4); # aliases with "caller", redundant assignment
+
+$code.=<<___;
+.align 5
+_aesp8_cbc_decrypt8x:
+ $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
+ li r10,`$FRAME+8*16+15`
+ li r11,`$FRAME+8*16+31`
+ stvx v20,r10,$sp # ABI says so
+ addi r10,r10,32
+ stvx v21,r11,$sp
+ addi r11,r11,32
+ stvx v22,r10,$sp
+ addi r10,r10,32
+ stvx v23,r11,$sp
+ addi r11,r11,32
+ stvx v24,r10,$sp
+ addi r10,r10,32
+ stvx v25,r11,$sp
+ addi r11,r11,32
+ stvx v26,r10,$sp
+ addi r10,r10,32
+ stvx v27,r11,$sp
+ addi r11,r11,32
+ stvx v28,r10,$sp
+ addi r10,r10,32
+ stvx v29,r11,$sp
+ addi r11,r11,32
+ stvx v30,r10,$sp
+ stvx v31,r11,$sp
+ li r0,-1
+ stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave
+ li $x10,0x10
+ $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+ li $x20,0x20
+ $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+ li $x30,0x30
+ $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+ li $x40,0x40
+ $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+ li $x50,0x50
+ $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+ li $x60,0x60
+ $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+ li $x70,0x70
+ mtspr 256,r0
+
+ subi $rounds,$rounds,3 # -4 in total
+ subi $len,$len,128 # bias
+
+ lvx $rndkey0,$x00,$key # load key schedule
+ lvx v30,$x10,$key
+ addi $key,$key,0x20
+ lvx v31,$x00,$key
+ ?vperm $rndkey0,$rndkey0,v30,$keyperm
+ addi $key_,$sp,$FRAME+15
+ mtctr $rounds
+
+Load_cbc_dec_key:
+ ?vperm v24,v30,v31,$keyperm
+ lvx v30,$x10,$key
+ addi $key,$key,0x20
+ stvx v24,$x00,$key_ # off-load round[1]
+ ?vperm v25,v31,v30,$keyperm
+ lvx v31,$x00,$key
+ stvx v25,$x10,$key_ # off-load round[2]
+ addi $key_,$key_,0x20
+ bdnz Load_cbc_dec_key
+
+ lvx v26,$x10,$key
+ ?vperm v24,v30,v31,$keyperm
+ lvx v27,$x20,$key
+ stvx v24,$x00,$key_ # off-load round[3]
+ ?vperm v25,v31,v26,$keyperm
+ lvx v28,$x30,$key
+ stvx v25,$x10,$key_ # off-load round[4]
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ ?vperm v26,v26,v27,$keyperm
+ lvx v29,$x40,$key
+ ?vperm v27,v27,v28,$keyperm
+ lvx v30,$x50,$key
+ ?vperm v28,v28,v29,$keyperm
+ lvx v31,$x60,$key
+ ?vperm v29,v29,v30,$keyperm
+ lvx $out0,$x70,$key # borrow $out0
+ ?vperm v30,v30,v31,$keyperm
+ lvx v24,$x00,$key_ # pre-load round[1]
+ ?vperm v31,v31,$out0,$keyperm
+ lvx v25,$x10,$key_ # pre-load round[2]
+
+ #lvx $inptail,0,$inp # "caller" already did this
+ #addi $inp,$inp,15 # 15 is not typo
+ subi $inp,$inp,15 # undo "caller"
+
+ le?li $idx,8
+ lvx_u $in0,$x00,$inp # load first 8 "words"
+ le?lvsl $inpperm,0,$idx
+ le?vspltisb $tmp,0x0f
+ lvx_u $in1,$x10,$inp
+ le?vxor $inpperm,$inpperm,$tmp # transform for lvx_u/stvx_u
+ lvx_u $in2,$x20,$inp
+ le?vperm $in0,$in0,$in0,$inpperm
+ lvx_u $in3,$x30,$inp
+ le?vperm $in1,$in1,$in1,$inpperm
+ lvx_u $in4,$x40,$inp
+ le?vperm $in2,$in2,$in2,$inpperm
+ vxor $out0,$in0,$rndkey0
+ lvx_u $in5,$x50,$inp
+ le?vperm $in3,$in3,$in3,$inpperm
+ vxor $out1,$in1,$rndkey0
+ lvx_u $in6,$x60,$inp
+ le?vperm $in4,$in4,$in4,$inpperm
+ vxor $out2,$in2,$rndkey0
+ lvx_u $in7,$x70,$inp
+ addi $inp,$inp,0x80
+ le?vperm $in5,$in5,$in5,$inpperm
+ vxor $out3,$in3,$rndkey0
+ le?vperm $in6,$in6,$in6,$inpperm
+ vxor $out4,$in4,$rndkey0
+ le?vperm $in7,$in7,$in7,$inpperm
+ vxor $out5,$in5,$rndkey0
+ vxor $out6,$in6,$rndkey0
+ vxor $out7,$in7,$rndkey0
+
+ mtctr $rounds
+ b Loop_cbc_dec8x
+.align 5
+Loop_cbc_dec8x:
+ vncipher $out0,$out0,v24
+ vncipher $out1,$out1,v24
+ vncipher $out2,$out2,v24
+ vncipher $out3,$out3,v24
+ vncipher $out4,$out4,v24
+ vncipher $out5,$out5,v24
+ vncipher $out6,$out6,v24
+ vncipher $out7,$out7,v24
+ lvx v24,$x20,$key_ # round[3]
+ addi $key_,$key_,0x20
+
+ vncipher $out0,$out0,v25
+ vncipher $out1,$out1,v25
+ vncipher $out2,$out2,v25
+ vncipher $out3,$out3,v25
+ vncipher $out4,$out4,v25
+ vncipher $out5,$out5,v25
+ vncipher $out6,$out6,v25
+ vncipher $out7,$out7,v25
+ lvx v25,$x10,$key_ # round[4]
+ bdnz Loop_cbc_dec8x
+
+ subic $len,$len,128 # $len-=128
+ vncipher $out0,$out0,v24
+ vncipher $out1,$out1,v24
+ vncipher $out2,$out2,v24
+ vncipher $out3,$out3,v24
+ vncipher $out4,$out4,v24
+ vncipher $out5,$out5,v24
+ vncipher $out6,$out6,v24
+ vncipher $out7,$out7,v24
+
+ subfe. r0,r0,r0 # borrow?-1:0
+ vncipher $out0,$out0,v25
+ vncipher $out1,$out1,v25
+ vncipher $out2,$out2,v25
+ vncipher $out3,$out3,v25
+ vncipher $out4,$out4,v25
+ vncipher $out5,$out5,v25
+ vncipher $out6,$out6,v25
+ vncipher $out7,$out7,v25
+
+ and r0,r0,$len
+ vncipher $out0,$out0,v26
+ vncipher $out1,$out1,v26
+ vncipher $out2,$out2,v26
+ vncipher $out3,$out3,v26
+ vncipher $out4,$out4,v26
+ vncipher $out5,$out5,v26
+ vncipher $out6,$out6,v26
+ vncipher $out7,$out7,v26
+
+ add $inp,$inp,r0 # $inp is adjusted in such
+ # way that at exit from the
+ # loop inX-in7 are loaded
+ # with last "words"
+ vncipher $out0,$out0,v27
+ vncipher $out1,$out1,v27
+ vncipher $out2,$out2,v27
+ vncipher $out3,$out3,v27
+ vncipher $out4,$out4,v27
+ vncipher $out5,$out5,v27
+ vncipher $out6,$out6,v27
+ vncipher $out7,$out7,v27
+
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ vncipher $out0,$out0,v28
+ vncipher $out1,$out1,v28
+ vncipher $out2,$out2,v28
+ vncipher $out3,$out3,v28
+ vncipher $out4,$out4,v28
+ vncipher $out5,$out5,v28
+ vncipher $out6,$out6,v28
+ vncipher $out7,$out7,v28
+ lvx v24,$x00,$key_ # re-pre-load round[1]
+
+ vncipher $out0,$out0,v29
+ vncipher $out1,$out1,v29
+ vncipher $out2,$out2,v29
+ vncipher $out3,$out3,v29
+ vncipher $out4,$out4,v29
+ vncipher $out5,$out5,v29
+ vncipher $out6,$out6,v29
+ vncipher $out7,$out7,v29
+ lvx v25,$x10,$key_ # re-pre-load round[2]
+
+ vncipher $out0,$out0,v30
+ vxor $ivec,$ivec,v31 # xor with last round key
+ vncipher $out1,$out1,v30
+ vxor $in0,$in0,v31
+ vncipher $out2,$out2,v30
+ vxor $in1,$in1,v31
+ vncipher $out3,$out3,v30
+ vxor $in2,$in2,v31
+ vncipher $out4,$out4,v30
+ vxor $in3,$in3,v31
+ vncipher $out5,$out5,v30
+ vxor $in4,$in4,v31
+ vncipher $out6,$out6,v30
+ vxor $in5,$in5,v31
+ vncipher $out7,$out7,v30
+ vxor $in6,$in6,v31
+
+ vncipherlast $out0,$out0,$ivec
+ vncipherlast $out1,$out1,$in0
+ lvx_u $in0,$x00,$inp # load next input block
+ vncipherlast $out2,$out2,$in1
+ lvx_u $in1,$x10,$inp
+ vncipherlast $out3,$out3,$in2
+ le?vperm $in0,$in0,$in0,$inpperm
+ lvx_u $in2,$x20,$inp
+ vncipherlast $out4,$out4,$in3
+ le?vperm $in1,$in1,$in1,$inpperm
+ lvx_u $in3,$x30,$inp
+ vncipherlast $out5,$out5,$in4
+ le?vperm $in2,$in2,$in2,$inpperm
+ lvx_u $in4,$x40,$inp
+ vncipherlast $out6,$out6,$in5
+ le?vperm $in3,$in3,$in3,$inpperm
+ lvx_u $in5,$x50,$inp
+ vncipherlast $out7,$out7,$in6
+ le?vperm $in4,$in4,$in4,$inpperm
+ lvx_u $in6,$x60,$inp
+ vmr $ivec,$in7
+ le?vperm $in5,$in5,$in5,$inpperm
+ lvx_u $in7,$x70,$inp
+ addi $inp,$inp,0x80
+
+ le?vperm $out0,$out0,$out0,$inpperm
+ le?vperm $out1,$out1,$out1,$inpperm
+ stvx_u $out0,$x00,$out
+ le?vperm $in6,$in6,$in6,$inpperm
+ vxor $out0,$in0,$rndkey0
+ le?vperm $out2,$out2,$out2,$inpperm
+ stvx_u $out1,$x10,$out
+ le?vperm $in7,$in7,$in7,$inpperm
+ vxor $out1,$in1,$rndkey0
+ le?vperm $out3,$out3,$out3,$inpperm
+ stvx_u $out2,$x20,$out
+ vxor $out2,$in2,$rndkey0
+ le?vperm $out4,$out4,$out4,$inpperm
+ stvx_u $out3,$x30,$out
+ vxor $out3,$in3,$rndkey0
+ le?vperm $out5,$out5,$out5,$inpperm
+ stvx_u $out4,$x40,$out
+ vxor $out4,$in4,$rndkey0
+ le?vperm $out6,$out6,$out6,$inpperm
+ stvx_u $out5,$x50,$out
+ vxor $out5,$in5,$rndkey0
+ le?vperm $out7,$out7,$out7,$inpperm
+ stvx_u $out6,$x60,$out
+ vxor $out6,$in6,$rndkey0
+ stvx_u $out7,$x70,$out
+ addi $out,$out,0x80
+ vxor $out7,$in7,$rndkey0
+
+ mtctr $rounds
+ beq Loop_cbc_dec8x # did $len-=128 borrow?
+
+ addic. $len,$len,128
+ beq Lcbc_dec8x_done
+ nop
+ nop
+
+Loop_cbc_dec8x_tail: # up to 7 "words" tail...
+ vncipher $out1,$out1,v24
+ vncipher $out2,$out2,v24
+ vncipher $out3,$out3,v24
+ vncipher $out4,$out4,v24
+ vncipher $out5,$out5,v24
+ vncipher $out6,$out6,v24
+ vncipher $out7,$out7,v24
+ lvx v24,$x20,$key_ # round[3]
+ addi $key_,$key_,0x20
+
+ vncipher $out1,$out1,v25
+ vncipher $out2,$out2,v25
+ vncipher $out3,$out3,v25
+ vncipher $out4,$out4,v25
+ vncipher $out5,$out5,v25
+ vncipher $out6,$out6,v25
+ vncipher $out7,$out7,v25
+ lvx v25,$x10,$key_ # round[4]
+ bdnz Loop_cbc_dec8x_tail
+
+ vncipher $out1,$out1,v24
+ vncipher $out2,$out2,v24
+ vncipher $out3,$out3,v24
+ vncipher $out4,$out4,v24
+ vncipher $out5,$out5,v24
+ vncipher $out6,$out6,v24
+ vncipher $out7,$out7,v24
+
+ vncipher $out1,$out1,v25
+ vncipher $out2,$out2,v25
+ vncipher $out3,$out3,v25
+ vncipher $out4,$out4,v25
+ vncipher $out5,$out5,v25
+ vncipher $out6,$out6,v25
+ vncipher $out7,$out7,v25
+
+ vncipher $out1,$out1,v26
+ vncipher $out2,$out2,v26
+ vncipher $out3,$out3,v26
+ vncipher $out4,$out4,v26
+ vncipher $out5,$out5,v26
+ vncipher $out6,$out6,v26
+ vncipher $out7,$out7,v26
+
+ vncipher $out1,$out1,v27
+ vncipher $out2,$out2,v27
+ vncipher $out3,$out3,v27
+ vncipher $out4,$out4,v27
+ vncipher $out5,$out5,v27
+ vncipher $out6,$out6,v27
+ vncipher $out7,$out7,v27
+
+ vncipher $out1,$out1,v28
+ vncipher $out2,$out2,v28
+ vncipher $out3,$out3,v28
+ vncipher $out4,$out4,v28
+ vncipher $out5,$out5,v28
+ vncipher $out6,$out6,v28
+ vncipher $out7,$out7,v28
+
+ vncipher $out1,$out1,v29
+ vncipher $out2,$out2,v29
+ vncipher $out3,$out3,v29
+ vncipher $out4,$out4,v29
+ vncipher $out5,$out5,v29
+ vncipher $out6,$out6,v29
+ vncipher $out7,$out7,v29
+
+ vncipher $out1,$out1,v30
+ vxor $ivec,$ivec,v31 # last round key
+ vncipher $out2,$out2,v30
+ vxor $in1,$in1,v31
+ vncipher $out3,$out3,v30
+ vxor $in2,$in2,v31
+ vncipher $out4,$out4,v30
+ vxor $in3,$in3,v31
+ vncipher $out5,$out5,v30
+ vxor $in4,$in4,v31
+ vncipher $out6,$out6,v30
+ vxor $in5,$in5,v31
+ vncipher $out7,$out7,v30
+ vxor $in6,$in6,v31
+
+ cmplwi $len,32 # switch($len)
+ blt Lcbc_dec8x_one
+ nop
+ beq Lcbc_dec8x_two
+ cmplwi $len,64
+ blt Lcbc_dec8x_three
+ nop
+ beq Lcbc_dec8x_four
+ cmplwi $len,96
+ blt Lcbc_dec8x_five
+ nop
+ beq Lcbc_dec8x_six
+
+Lcbc_dec8x_seven:
+ vncipherlast $out1,$out1,$ivec
+ vncipherlast $out2,$out2,$in1
+ vncipherlast $out3,$out3,$in2
+ vncipherlast $out4,$out4,$in3
+ vncipherlast $out5,$out5,$in4
+ vncipherlast $out6,$out6,$in5
+ vncipherlast $out7,$out7,$in6
+ vmr $ivec,$in7
+
+ le?vperm $out1,$out1,$out1,$inpperm
+ le?vperm $out2,$out2,$out2,$inpperm
+ stvx_u $out1,$x00,$out
+ le?vperm $out3,$out3,$out3,$inpperm
+ stvx_u $out2,$x10,$out
+ le?vperm $out4,$out4,$out4,$inpperm
+ stvx_u $out3,$x20,$out
+ le?vperm $out5,$out5,$out5,$inpperm
+ stvx_u $out4,$x30,$out
+ le?vperm $out6,$out6,$out6,$inpperm
+ stvx_u $out5,$x40,$out
+ le?vperm $out7,$out7,$out7,$inpperm
+ stvx_u $out6,$x50,$out
+ stvx_u $out7,$x60,$out
+ addi $out,$out,0x70
+ b Lcbc_dec8x_done
+
+.align 5
+Lcbc_dec8x_six:
+ vncipherlast $out2,$out2,$ivec
+ vncipherlast $out3,$out3,$in2
+ vncipherlast $out4,$out4,$in3
+ vncipherlast $out5,$out5,$in4
+ vncipherlast $out6,$out6,$in5
+ vncipherlast $out7,$out7,$in6
+ vmr $ivec,$in7
+
+ le?vperm $out2,$out2,$out2,$inpperm
+ le?vperm $out3,$out3,$out3,$inpperm
+ stvx_u $out2,$x00,$out
+ le?vperm $out4,$out4,$out4,$inpperm
+ stvx_u $out3,$x10,$out
+ le?vperm $out5,$out5,$out5,$inpperm
+ stvx_u $out4,$x20,$out
+ le?vperm $out6,$out6,$out6,$inpperm
+ stvx_u $out5,$x30,$out
+ le?vperm $out7,$out7,$out7,$inpperm
+ stvx_u $out6,$x40,$out
+ stvx_u $out7,$x50,$out
+ addi $out,$out,0x60
+ b Lcbc_dec8x_done
+
+.align 5
+Lcbc_dec8x_five:
+ vncipherlast $out3,$out3,$ivec
+ vncipherlast $out4,$out4,$in3
+ vncipherlast $out5,$out5,$in4
+ vncipherlast $out6,$out6,$in5
+ vncipherlast $out7,$out7,$in6
+ vmr $ivec,$in7
+
+ le?vperm $out3,$out3,$out3,$inpperm
+ le?vperm $out4,$out4,$out4,$inpperm
+ stvx_u $out3,$x00,$out
+ le?vperm $out5,$out5,$out5,$inpperm
+ stvx_u $out4,$x10,$out
+ le?vperm $out6,$out6,$out6,$inpperm
+ stvx_u $out5,$x20,$out
+ le?vperm $out7,$out7,$out7,$inpperm
+ stvx_u $out6,$x30,$out
+ stvx_u $out7,$x40,$out
+ addi $out,$out,0x50
+ b Lcbc_dec8x_done
+
+.align 5
+Lcbc_dec8x_four:
+ vncipherlast $out4,$out4,$ivec
+ vncipherlast $out5,$out5,$in4
+ vncipherlast $out6,$out6,$in5
+ vncipherlast $out7,$out7,$in6
+ vmr $ivec,$in7
+
+ le?vperm $out4,$out4,$out4,$inpperm
+ le?vperm $out5,$out5,$out5,$inpperm
+ stvx_u $out4,$x00,$out
+ le?vperm $out6,$out6,$out6,$inpperm
+ stvx_u $out5,$x10,$out
+ le?vperm $out7,$out7,$out7,$inpperm
+ stvx_u $out6,$x20,$out
+ stvx_u $out7,$x30,$out
+ addi $out,$out,0x40
+ b Lcbc_dec8x_done
+
+.align 5
+Lcbc_dec8x_three:
+ vncipherlast $out5,$out5,$ivec
+ vncipherlast $out6,$out6,$in5
+ vncipherlast $out7,$out7,$in6
+ vmr $ivec,$in7
+
+ le?vperm $out5,$out5,$out5,$inpperm
+ le?vperm $out6,$out6,$out6,$inpperm
+ stvx_u $out5,$x00,$out
+ le?vperm $out7,$out7,$out7,$inpperm
+ stvx_u $out6,$x10,$out
+ stvx_u $out7,$x20,$out
+ addi $out,$out,0x30
+ b Lcbc_dec8x_done
+
+.align 5
+Lcbc_dec8x_two:
+ vncipherlast $out6,$out6,$ivec
+ vncipherlast $out7,$out7,$in6
+ vmr $ivec,$in7
+
+ le?vperm $out6,$out6,$out6,$inpperm
+ le?vperm $out7,$out7,$out7,$inpperm
+ stvx_u $out6,$x00,$out
+ stvx_u $out7,$x10,$out
+ addi $out,$out,0x20
+ b Lcbc_dec8x_done
+
+.align 5
+Lcbc_dec8x_one:
+ vncipherlast $out7,$out7,$ivec
+ vmr $ivec,$in7
+
+ le?vperm $out7,$out7,$out7,$inpperm
+ stvx_u $out7,0,$out
+ addi $out,$out,0x10
+
+Lcbc_dec8x_done:
+ le?vperm $ivec,$ivec,$ivec,$inpperm
+ stvx_u $ivec,0,$ivp # write [unaligned] iv
+
+ li r10,`$FRAME+15`
+ li r11,`$FRAME+31`
+ stvx $inpperm,r10,$sp # wipe copies of round keys
+ addi r10,r10,32
+ stvx $inpperm,r11,$sp
+ addi r11,r11,32
+ stvx $inpperm,r10,$sp
+ addi r10,r10,32
+ stvx $inpperm,r11,$sp
+ addi r11,r11,32
+ stvx $inpperm,r10,$sp
+ addi r10,r10,32
+ stvx $inpperm,r11,$sp
+ addi r11,r11,32
+ stvx $inpperm,r10,$sp
+ addi r10,r10,32
+ stvx $inpperm,r11,$sp
+ addi r11,r11,32
+
+ mtspr 256,$vrsave
+ lvx v20,r10,$sp # ABI says so
+ addi r10,r10,32
+ lvx v21,r11,$sp
+ addi r11,r11,32
+ lvx v22,r10,$sp
+ addi r10,r10,32
+ lvx v23,r11,$sp
+ addi r11,r11,32
+ lvx v24,r10,$sp
+ addi r10,r10,32
+ lvx v25,r11,$sp
+ addi r11,r11,32
+ lvx v26,r10,$sp
+ addi r10,r10,32
+ lvx v27,r11,$sp
+ addi r11,r11,32
+ lvx v28,r10,$sp
+ addi r10,r10,32
+ lvx v29,r11,$sp
+ addi r11,r11,32
+ lvx v30,r10,$sp
+ lvx v31,r11,$sp
+ $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+ $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+ $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+ $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+ $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+ $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+ addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T`
+ blr
+ .long 0
+ .byte 0,12,0x14,0,0x80,6,6,0
+ .long 0
+.size .${prefix}_cbc_encrypt,.-.${prefix}_cbc_encrypt
+___
+}} }}}
+
+#########################################################################
+{{{ # CTR procedure[s] #
+
+####################### WARNING: Here be dragons! #######################
+#
+# This code is written as 'ctr32', based on a 32-bit counter used
+# upstream. The kernel does *not* use a 32-bit counter. The kernel uses
+# a 128-bit counter.
+#
+# This leads to subtle changes from the upstream code: the counter
+# is incremented with vaddu_q_m rather than vaddu_w_m. This occurs in
+# both the bulk (8 blocks at a time) path, and in the individual block
+# path. Be aware of this when doing updates.
+#
+# See:
+# 1d4aa0b4c181 ("crypto: vmx - Fixing AES-CTR counter bug")
+# 009b30ac7444 ("crypto: vmx - CTR: always increment IV as quadword")
+# https://github.com/openssl/openssl/pull/8942
+#
+#########################################################################
+my ($inp,$out,$len,$key,$ivp,$x10,$rounds,$idx)=map("r$_",(3..10));
+my ($rndkey0,$rndkey1,$inout,$tmp)= map("v$_",(0..3));
+my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm,$one)=
+ map("v$_",(4..11));
+my $dat=$tmp;
+
+$code.=<<___;
+.globl .${prefix}_ctr32_encrypt_blocks
+ ${UCMP}i $len,1
+ bltlr-
+
+ lis r0,0xfff0
+ mfspr $vrsave,256
+ mtspr 256,r0
+
+ li $idx,15
+ vxor $rndkey0,$rndkey0,$rndkey0
+ le?vspltisb $tmp,0x0f
+
+ lvx $ivec,0,$ivp # load [unaligned] iv
+ lvsl $inpperm,0,$ivp
+ lvx $inptail,$idx,$ivp
+ vspltisb $one,1
+ le?vxor $inpperm,$inpperm,$tmp
+ vperm $ivec,$ivec,$inptail,$inpperm
+ vsldoi $one,$rndkey0,$one,1
+
+ neg r11,$inp
+ ?lvsl $keyperm,0,$key # prepare for unaligned key
+ lwz $rounds,240($key)
+
+ lvsr $inpperm,0,r11 # prepare for unaligned load
+ lvx $inptail,0,$inp
+ addi $inp,$inp,15 # 15 is not typo
+ le?vxor $inpperm,$inpperm,$tmp
+
+ srwi $rounds,$rounds,1
+ li $idx,16
+ subi $rounds,$rounds,1
+
+ ${UCMP}i $len,8
+ bge _aesp8_ctr32_encrypt8x
+
+ ?lvsr $outperm,0,$out # prepare for unaligned store
+ vspltisb $outmask,-1
+ lvx $outhead,0,$out
+ ?vperm $outmask,$rndkey0,$outmask,$outperm
+ le?vxor $outperm,$outperm,$tmp
+
+ lvx $rndkey0,0,$key
+ mtctr $rounds
+ lvx $rndkey1,$idx,$key
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $inout,$ivec,$rndkey0
+ lvx $rndkey0,$idx,$key
+ addi $idx,$idx,16
+ b Loop_ctr32_enc
+
+.align 5
+Loop_ctr32_enc:
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vcipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vcipher $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key
+ addi $idx,$idx,16
+ bdnz Loop_ctr32_enc
+
+ vadduqm $ivec,$ivec,$one # Kernel change for 128-bit
+ vmr $dat,$inptail
+ lvx $inptail,0,$inp
+ addi $inp,$inp,16
+ subic. $len,$len,1 # blocks--
+
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vcipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key
+ vperm $dat,$dat,$inptail,$inpperm
+ li $idx,16
+ ?vperm $rndkey1,$rndkey0,$rndkey1,$keyperm
+ lvx $rndkey0,0,$key
+ vxor $dat,$dat,$rndkey1 # last round key
+ vcipherlast $inout,$inout,$dat
+
+ lvx $rndkey1,$idx,$key
+ addi $idx,$idx,16
+ vperm $inout,$inout,$inout,$outperm
+ vsel $dat,$outhead,$inout,$outmask
+ mtctr $rounds
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vmr $outhead,$inout
+ vxor $inout,$ivec,$rndkey0
+ lvx $rndkey0,$idx,$key
+ addi $idx,$idx,16
+ stvx $dat,0,$out
+ addi $out,$out,16
+ bne Loop_ctr32_enc
+
+ addi $out,$out,-1
+ lvx $inout,0,$out # redundant in aligned case
+ vsel $inout,$outhead,$inout,$outmask
+ stvx $inout,0,$out
+
+ mtspr 256,$vrsave
+ blr
+ .long 0
+ .byte 0,12,0x14,0,0,0,6,0
+ .long 0
+___
+#########################################################################
+{{ # Optimized CTR procedure #
+my $key_="r11";
+my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,8,26..31));
+my ($in0, $in1, $in2, $in3, $in4, $in5, $in6, $in7 )=map("v$_",(0..3,10,12..14));
+my ($out0,$out1,$out2,$out3,$out4,$out5,$out6,$out7)=map("v$_",(15..22));
+my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys
+ # v26-v31 last 6 round keys
+my ($tmp,$keyperm)=($in3,$in4); # aliases with "caller", redundant assignment
+my ($two,$three,$four)=($outhead,$outperm,$outmask);
+
+$code.=<<___;
+.align 5
+_aesp8_ctr32_encrypt8x:
+ $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
+ li r10,`$FRAME+8*16+15`
+ li r11,`$FRAME+8*16+31`
+ stvx v20,r10,$sp # ABI says so
+ addi r10,r10,32
+ stvx v21,r11,$sp
+ addi r11,r11,32
+ stvx v22,r10,$sp
+ addi r10,r10,32
+ stvx v23,r11,$sp
+ addi r11,r11,32
+ stvx v24,r10,$sp
+ addi r10,r10,32
+ stvx v25,r11,$sp
+ addi r11,r11,32
+ stvx v26,r10,$sp
+ addi r10,r10,32
+ stvx v27,r11,$sp
+ addi r11,r11,32
+ stvx v28,r10,$sp
+ addi r10,r10,32
+ stvx v29,r11,$sp
+ addi r11,r11,32
+ stvx v30,r10,$sp
+ stvx v31,r11,$sp
+ li r0,-1
+ stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave
+ li $x10,0x10
+ $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+ li $x20,0x20
+ $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+ li $x30,0x30
+ $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+ li $x40,0x40
+ $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+ li $x50,0x50
+ $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+ li $x60,0x60
+ $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+ li $x70,0x70
+ mtspr 256,r0
+
+ subi $rounds,$rounds,3 # -4 in total
+
+ lvx $rndkey0,$x00,$key # load key schedule
+ lvx v30,$x10,$key
+ addi $key,$key,0x20
+ lvx v31,$x00,$key
+ ?vperm $rndkey0,$rndkey0,v30,$keyperm
+ addi $key_,$sp,$FRAME+15
+ mtctr $rounds
+
+Load_ctr32_enc_key:
+ ?vperm v24,v30,v31,$keyperm
+ lvx v30,$x10,$key
+ addi $key,$key,0x20
+ stvx v24,$x00,$key_ # off-load round[1]
+ ?vperm v25,v31,v30,$keyperm
+ lvx v31,$x00,$key
+ stvx v25,$x10,$key_ # off-load round[2]
+ addi $key_,$key_,0x20
+ bdnz Load_ctr32_enc_key
+
+ lvx v26,$x10,$key
+ ?vperm v24,v30,v31,$keyperm
+ lvx v27,$x20,$key
+ stvx v24,$x00,$key_ # off-load round[3]
+ ?vperm v25,v31,v26,$keyperm
+ lvx v28,$x30,$key
+ stvx v25,$x10,$key_ # off-load round[4]
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ ?vperm v26,v26,v27,$keyperm
+ lvx v29,$x40,$key
+ ?vperm v27,v27,v28,$keyperm
+ lvx v30,$x50,$key
+ ?vperm v28,v28,v29,$keyperm
+ lvx v31,$x60,$key
+ ?vperm v29,v29,v30,$keyperm
+ lvx $out0,$x70,$key # borrow $out0
+ ?vperm v30,v30,v31,$keyperm
+ lvx v24,$x00,$key_ # pre-load round[1]
+ ?vperm v31,v31,$out0,$keyperm
+ lvx v25,$x10,$key_ # pre-load round[2]
+
+ vadduqm $two,$one,$one
+ subi $inp,$inp,15 # undo "caller"
+ $SHL $len,$len,4
+
+ vadduqm $out1,$ivec,$one # counter values ...
+ vadduqm $out2,$ivec,$two # (do all ctr adds as 128-bit)
+ vxor $out0,$ivec,$rndkey0 # ... xored with rndkey[0]
+ le?li $idx,8
+ vadduqm $out3,$out1,$two
+ vxor $out1,$out1,$rndkey0
+ le?lvsl $inpperm,0,$idx
+ vadduqm $out4,$out2,$two
+ vxor $out2,$out2,$rndkey0
+ le?vspltisb $tmp,0x0f
+ vadduqm $out5,$out3,$two
+ vxor $out3,$out3,$rndkey0
+ le?vxor $inpperm,$inpperm,$tmp # transform for lvx_u/stvx_u
+ vadduqm $out6,$out4,$two
+ vxor $out4,$out4,$rndkey0
+ vadduqm $out7,$out5,$two
+ vxor $out5,$out5,$rndkey0
+ vadduqm $ivec,$out6,$two # next counter value
+ vxor $out6,$out6,$rndkey0
+ vxor $out7,$out7,$rndkey0
+
+ mtctr $rounds
+ b Loop_ctr32_enc8x
+.align 5
+Loop_ctr32_enc8x:
+ vcipher $out0,$out0,v24
+ vcipher $out1,$out1,v24
+ vcipher $out2,$out2,v24
+ vcipher $out3,$out3,v24
+ vcipher $out4,$out4,v24
+ vcipher $out5,$out5,v24
+ vcipher $out6,$out6,v24
+ vcipher $out7,$out7,v24
+Loop_ctr32_enc8x_middle:
+ lvx v24,$x20,$key_ # round[3]
+ addi $key_,$key_,0x20
+
+ vcipher $out0,$out0,v25
+ vcipher $out1,$out1,v25
+ vcipher $out2,$out2,v25
+ vcipher $out3,$out3,v25
+ vcipher $out4,$out4,v25
+ vcipher $out5,$out5,v25
+ vcipher $out6,$out6,v25
+ vcipher $out7,$out7,v25
+ lvx v25,$x10,$key_ # round[4]
+ bdnz Loop_ctr32_enc8x
+
+ subic r11,$len,256 # $len-256, borrow $key_
+ vcipher $out0,$out0,v24
+ vcipher $out1,$out1,v24
+ vcipher $out2,$out2,v24
+ vcipher $out3,$out3,v24
+ vcipher $out4,$out4,v24
+ vcipher $out5,$out5,v24
+ vcipher $out6,$out6,v24
+ vcipher $out7,$out7,v24
+
+ subfe r0,r0,r0 # borrow?-1:0
+ vcipher $out0,$out0,v25
+ vcipher $out1,$out1,v25
+ vcipher $out2,$out2,v25
+ vcipher $out3,$out3,v25
+ vcipher $out4,$out4,v25
+ vcipher $out5,$out5,v25
+ vcipher $out6,$out6,v25
+ vcipher $out7,$out7,v25
+
+ and r0,r0,r11
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ vcipher $out0,$out0,v26
+ vcipher $out1,$out1,v26
+ vcipher $out2,$out2,v26
+ vcipher $out3,$out3,v26
+ vcipher $out4,$out4,v26
+ vcipher $out5,$out5,v26
+ vcipher $out6,$out6,v26
+ vcipher $out7,$out7,v26
+ lvx v24,$x00,$key_ # re-pre-load round[1]
+
+ subic $len,$len,129 # $len-=129
+ vcipher $out0,$out0,v27
+ addi $len,$len,1 # $len-=128 really
+ vcipher $out1,$out1,v27
+ vcipher $out2,$out2,v27
+ vcipher $out3,$out3,v27
+ vcipher $out4,$out4,v27
+ vcipher $out5,$out5,v27
+ vcipher $out6,$out6,v27
+ vcipher $out7,$out7,v27
+ lvx v25,$x10,$key_ # re-pre-load round[2]
+
+ vcipher $out0,$out0,v28
+ lvx_u $in0,$x00,$inp # load input
+ vcipher $out1,$out1,v28
+ lvx_u $in1,$x10,$inp
+ vcipher $out2,$out2,v28
+ lvx_u $in2,$x20,$inp
+ vcipher $out3,$out3,v28
+ lvx_u $in3,$x30,$inp
+ vcipher $out4,$out4,v28
+ lvx_u $in4,$x40,$inp
+ vcipher $out5,$out5,v28
+ lvx_u $in5,$x50,$inp
+ vcipher $out6,$out6,v28
+ lvx_u $in6,$x60,$inp
+ vcipher $out7,$out7,v28
+ lvx_u $in7,$x70,$inp
+ addi $inp,$inp,0x80
+
+ vcipher $out0,$out0,v29
+ le?vperm $in0,$in0,$in0,$inpperm
+ vcipher $out1,$out1,v29
+ le?vperm $in1,$in1,$in1,$inpperm
+ vcipher $out2,$out2,v29
+ le?vperm $in2,$in2,$in2,$inpperm
+ vcipher $out3,$out3,v29
+ le?vperm $in3,$in3,$in3,$inpperm
+ vcipher $out4,$out4,v29
+ le?vperm $in4,$in4,$in4,$inpperm
+ vcipher $out5,$out5,v29
+ le?vperm $in5,$in5,$in5,$inpperm
+ vcipher $out6,$out6,v29
+ le?vperm $in6,$in6,$in6,$inpperm
+ vcipher $out7,$out7,v29
+ le?vperm $in7,$in7,$in7,$inpperm
+
+ add $inp,$inp,r0 # $inp is adjusted in such
+ # way that at exit from the
+ # loop inX-in7 are loaded
+ # with last "words"
+ subfe. r0,r0,r0 # borrow?-1:0
+ vcipher $out0,$out0,v30
+ vxor $in0,$in0,v31 # xor with last round key
+ vcipher $out1,$out1,v30
+ vxor $in1,$in1,v31
+ vcipher $out2,$out2,v30
+ vxor $in2,$in2,v31
+ vcipher $out3,$out3,v30
+ vxor $in3,$in3,v31
+ vcipher $out4,$out4,v30
+ vxor $in4,$in4,v31
+ vcipher $out5,$out5,v30
+ vxor $in5,$in5,v31
+ vcipher $out6,$out6,v30
+ vxor $in6,$in6,v31
+ vcipher $out7,$out7,v30
+ vxor $in7,$in7,v31
+
+ bne Lctr32_enc8x_break # did $len-129 borrow?
+
+ vcipherlast $in0,$out0,$in0
+ vcipherlast $in1,$out1,$in1
+ vadduqm $out1,$ivec,$one # counter values ...
+ vcipherlast $in2,$out2,$in2
+ vadduqm $out2,$ivec,$two
+ vxor $out0,$ivec,$rndkey0 # ... xored with rndkey[0]
+ vcipherlast $in3,$out3,$in3
+ vadduqm $out3,$out1,$two
+ vxor $out1,$out1,$rndkey0
+ vcipherlast $in4,$out4,$in4
+ vadduqm $out4,$out2,$two
+ vxor $out2,$out2,$rndkey0
+ vcipherlast $in5,$out5,$in5
+ vadduqm $out5,$out3,$two
+ vxor $out3,$out3,$rndkey0
+ vcipherlast $in6,$out6,$in6
+ vadduqm $out6,$out4,$two
+ vxor $out4,$out4,$rndkey0
+ vcipherlast $in7,$out7,$in7
+ vadduqm $out7,$out5,$two
+ vxor $out5,$out5,$rndkey0
+ le?vperm $in0,$in0,$in0,$inpperm
+ vadduqm $ivec,$out6,$two # next counter value
+ vxor $out6,$out6,$rndkey0
+ le?vperm $in1,$in1,$in1,$inpperm
+ vxor $out7,$out7,$rndkey0
+ mtctr $rounds
+
+ vcipher $out0,$out0,v24
+ stvx_u $in0,$x00,$out
+ le?vperm $in2,$in2,$in2,$inpperm
+ vcipher $out1,$out1,v24
+ stvx_u $in1,$x10,$out
+ le?vperm $in3,$in3,$in3,$inpperm
+ vcipher $out2,$out2,v24
+ stvx_u $in2,$x20,$out
+ le?vperm $in4,$in4,$in4,$inpperm
+ vcipher $out3,$out3,v24
+ stvx_u $in3,$x30,$out
+ le?vperm $in5,$in5,$in5,$inpperm
+ vcipher $out4,$out4,v24
+ stvx_u $in4,$x40,$out
+ le?vperm $in6,$in6,$in6,$inpperm
+ vcipher $out5,$out5,v24
+ stvx_u $in5,$x50,$out
+ le?vperm $in7,$in7,$in7,$inpperm
+ vcipher $out6,$out6,v24
+ stvx_u $in6,$x60,$out
+ vcipher $out7,$out7,v24
+ stvx_u $in7,$x70,$out
+ addi $out,$out,0x80
+
+ b Loop_ctr32_enc8x_middle
+
+.align 5
+Lctr32_enc8x_break:
+ cmpwi $len,-0x60
+ blt Lctr32_enc8x_one
+ nop
+ beq Lctr32_enc8x_two
+ cmpwi $len,-0x40
+ blt Lctr32_enc8x_three
+ nop
+ beq Lctr32_enc8x_four
+ cmpwi $len,-0x20
+ blt Lctr32_enc8x_five
+ nop
+ beq Lctr32_enc8x_six
+ cmpwi $len,0x00
+ blt Lctr32_enc8x_seven
+
+Lctr32_enc8x_eight:
+ vcipherlast $out0,$out0,$in0
+ vcipherlast $out1,$out1,$in1
+ vcipherlast $out2,$out2,$in2
+ vcipherlast $out3,$out3,$in3
+ vcipherlast $out4,$out4,$in4
+ vcipherlast $out5,$out5,$in5
+ vcipherlast $out6,$out6,$in6
+ vcipherlast $out7,$out7,$in7
+
+ le?vperm $out0,$out0,$out0,$inpperm
+ le?vperm $out1,$out1,$out1,$inpperm
+ stvx_u $out0,$x00,$out
+ le?vperm $out2,$out2,$out2,$inpperm
+ stvx_u $out1,$x10,$out
+ le?vperm $out3,$out3,$out3,$inpperm
+ stvx_u $out2,$x20,$out
+ le?vperm $out4,$out4,$out4,$inpperm
+ stvx_u $out3,$x30,$out
+ le?vperm $out5,$out5,$out5,$inpperm
+ stvx_u $out4,$x40,$out
+ le?vperm $out6,$out6,$out6,$inpperm
+ stvx_u $out5,$x50,$out
+ le?vperm $out7,$out7,$out7,$inpperm
+ stvx_u $out6,$x60,$out
+ stvx_u $out7,$x70,$out
+ addi $out,$out,0x80
+ b Lctr32_enc8x_done
+
+.align 5
+Lctr32_enc8x_seven:
+ vcipherlast $out0,$out0,$in1
+ vcipherlast $out1,$out1,$in2
+ vcipherlast $out2,$out2,$in3
+ vcipherlast $out3,$out3,$in4
+ vcipherlast $out4,$out4,$in5
+ vcipherlast $out5,$out5,$in6
+ vcipherlast $out6,$out6,$in7
+
+ le?vperm $out0,$out0,$out0,$inpperm
+ le?vperm $out1,$out1,$out1,$inpperm
+ stvx_u $out0,$x00,$out
+ le?vperm $out2,$out2,$out2,$inpperm
+ stvx_u $out1,$x10,$out
+ le?vperm $out3,$out3,$out3,$inpperm
+ stvx_u $out2,$x20,$out
+ le?vperm $out4,$out4,$out4,$inpperm
+ stvx_u $out3,$x30,$out
+ le?vperm $out5,$out5,$out5,$inpperm
+ stvx_u $out4,$x40,$out
+ le?vperm $out6,$out6,$out6,$inpperm
+ stvx_u $out5,$x50,$out
+ stvx_u $out6,$x60,$out
+ addi $out,$out,0x70
+ b Lctr32_enc8x_done
+
+.align 5
+Lctr32_enc8x_six:
+ vcipherlast $out0,$out0,$in2
+ vcipherlast $out1,$out1,$in3
+ vcipherlast $out2,$out2,$in4
+ vcipherlast $out3,$out3,$in5
+ vcipherlast $out4,$out4,$in6
+ vcipherlast $out5,$out5,$in7
+
+ le?vperm $out0,$out0,$out0,$inpperm
+ le?vperm $out1,$out1,$out1,$inpperm
+ stvx_u $out0,$x00,$out
+ le?vperm $out2,$out2,$out2,$inpperm
+ stvx_u $out1,$x10,$out
+ le?vperm $out3,$out3,$out3,$inpperm
+ stvx_u $out2,$x20,$out
+ le?vperm $out4,$out4,$out4,$inpperm
+ stvx_u $out3,$x30,$out
+ le?vperm $out5,$out5,$out5,$inpperm
+ stvx_u $out4,$x40,$out
+ stvx_u $out5,$x50,$out
+ addi $out,$out,0x60
+ b Lctr32_enc8x_done
+
+.align 5
+Lctr32_enc8x_five:
+ vcipherlast $out0,$out0,$in3
+ vcipherlast $out1,$out1,$in4
+ vcipherlast $out2,$out2,$in5
+ vcipherlast $out3,$out3,$in6
+ vcipherlast $out4,$out4,$in7
+
+ le?vperm $out0,$out0,$out0,$inpperm
+ le?vperm $out1,$out1,$out1,$inpperm
+ stvx_u $out0,$x00,$out
+ le?vperm $out2,$out2,$out2,$inpperm
+ stvx_u $out1,$x10,$out
+ le?vperm $out3,$out3,$out3,$inpperm
+ stvx_u $out2,$x20,$out
+ le?vperm $out4,$out4,$out4,$inpperm
+ stvx_u $out3,$x30,$out
+ stvx_u $out4,$x40,$out
+ addi $out,$out,0x50
+ b Lctr32_enc8x_done
+
+.align 5
+Lctr32_enc8x_four:
+ vcipherlast $out0,$out0,$in4
+ vcipherlast $out1,$out1,$in5
+ vcipherlast $out2,$out2,$in6
+ vcipherlast $out3,$out3,$in7
+
+ le?vperm $out0,$out0,$out0,$inpperm
+ le?vperm $out1,$out1,$out1,$inpperm
+ stvx_u $out0,$x00,$out
+ le?vperm $out2,$out2,$out2,$inpperm
+ stvx_u $out1,$x10,$out
+ le?vperm $out3,$out3,$out3,$inpperm
+ stvx_u $out2,$x20,$out
+ stvx_u $out3,$x30,$out
+ addi $out,$out,0x40
+ b Lctr32_enc8x_done
+
+.align 5
+Lctr32_enc8x_three:
+ vcipherlast $out0,$out0,$in5
+ vcipherlast $out1,$out1,$in6
+ vcipherlast $out2,$out2,$in7
+
+ le?vperm $out0,$out0,$out0,$inpperm
+ le?vperm $out1,$out1,$out1,$inpperm
+ stvx_u $out0,$x00,$out
+ le?vperm $out2,$out2,$out2,$inpperm
+ stvx_u $out1,$x10,$out
+ stvx_u $out2,$x20,$out
+ addi $out,$out,0x30
+ b Lctr32_enc8x_done
+
+.align 5
+Lctr32_enc8x_two:
+ vcipherlast $out0,$out0,$in6
+ vcipherlast $out1,$out1,$in7
+
+ le?vperm $out0,$out0,$out0,$inpperm
+ le?vperm $out1,$out1,$out1,$inpperm
+ stvx_u $out0,$x00,$out
+ stvx_u $out1,$x10,$out
+ addi $out,$out,0x20
+ b Lctr32_enc8x_done
+
+.align 5
+Lctr32_enc8x_one:
+ vcipherlast $out0,$out0,$in7
+
+ le?vperm $out0,$out0,$out0,$inpperm
+ stvx_u $out0,0,$out
+ addi $out,$out,0x10
+
+Lctr32_enc8x_done:
+ li r10,`$FRAME+15`
+ li r11,`$FRAME+31`
+ stvx $inpperm,r10,$sp # wipe copies of round keys
+ addi r10,r10,32
+ stvx $inpperm,r11,$sp
+ addi r11,r11,32
+ stvx $inpperm,r10,$sp
+ addi r10,r10,32
+ stvx $inpperm,r11,$sp
+ addi r11,r11,32
+ stvx $inpperm,r10,$sp
+ addi r10,r10,32
+ stvx $inpperm,r11,$sp
+ addi r11,r11,32
+ stvx $inpperm,r10,$sp
+ addi r10,r10,32
+ stvx $inpperm,r11,$sp
+ addi r11,r11,32
+
+ mtspr 256,$vrsave
+ lvx v20,r10,$sp # ABI says so
+ addi r10,r10,32
+ lvx v21,r11,$sp
+ addi r11,r11,32
+ lvx v22,r10,$sp
+ addi r10,r10,32
+ lvx v23,r11,$sp
+ addi r11,r11,32
+ lvx v24,r10,$sp
+ addi r10,r10,32
+ lvx v25,r11,$sp
+ addi r11,r11,32
+ lvx v26,r10,$sp
+ addi r10,r10,32
+ lvx v27,r11,$sp
+ addi r11,r11,32
+ lvx v28,r10,$sp
+ addi r10,r10,32
+ lvx v29,r11,$sp
+ addi r11,r11,32
+ lvx v30,r10,$sp
+ lvx v31,r11,$sp
+ $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+ $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+ $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+ $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+ $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+ $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+ addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T`
+ blr
+ .long 0
+ .byte 0,12,0x14,0,0x80,6,6,0
+ .long 0
+.size .${prefix}_ctr32_encrypt_blocks,.-.${prefix}_ctr32_encrypt_blocks
+___
+}} }}}
+
+#########################################################################
+{{{ # XTS procedures #
+# int aes_p8_xts_[en|de]crypt(const char *inp, char *out, size_t len, #
+# const AES_KEY *key1, const AES_KEY *key2, #
+# [const] unsigned char iv[16]); #
+# If $key2 is NULL, then a "tweak chaining" mode is engaged, in which #
+# input tweak value is assumed to be encrypted already, and last tweak #
+# value, one suitable for consecutive call on same chunk of data, is #
+# written back to original buffer. In addition, in "tweak chaining" #
+# mode only complete input blocks are processed. #
+
+my ($inp,$out,$len,$key1,$key2,$ivp,$rounds,$idx) = map("r$_",(3..10));
+my ($rndkey0,$rndkey1,$inout) = map("v$_",(0..2));
+my ($output,$inptail,$inpperm,$leperm,$keyperm) = map("v$_",(3..7));
+my ($tweak,$seven,$eighty7,$tmp,$tweak1) = map("v$_",(8..12));
+my $taillen = $key2;
+
+ ($inp,$idx) = ($idx,$inp); # reassign
+
+$code.=<<___;
+.globl .${prefix}_xts_encrypt
+ mr $inp,r3 # reassign
+ li r3,-1
+ ${UCMP}i $len,16
+ bltlr-
+
+ lis r0,0xfff0
+ mfspr r12,256 # save vrsave
+ li r11,0
+ mtspr 256,r0
+
+ vspltisb $seven,0x07 # 0x070707..07
+ le?lvsl $leperm,r11,r11
+ le?vspltisb $tmp,0x0f
+ le?vxor $leperm,$leperm,$seven
+
+ li $idx,15
+ lvx $tweak,0,$ivp # load [unaligned] iv
+ lvsl $inpperm,0,$ivp
+ lvx $inptail,$idx,$ivp
+ le?vxor $inpperm,$inpperm,$tmp
+ vperm $tweak,$tweak,$inptail,$inpperm
+
+ neg r11,$inp
+ lvsr $inpperm,0,r11 # prepare for unaligned load
+ lvx $inout,0,$inp
+ addi $inp,$inp,15 # 15 is not typo
+ le?vxor $inpperm,$inpperm,$tmp
+
+ ${UCMP}i $key2,0 # key2==NULL?
+ beq Lxts_enc_no_key2
+
+ ?lvsl $keyperm,0,$key2 # prepare for unaligned key
+ lwz $rounds,240($key2)
+ srwi $rounds,$rounds,1
+ subi $rounds,$rounds,1
+ li $idx,16
+
+ lvx $rndkey0,0,$key2
+ lvx $rndkey1,$idx,$key2
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $tweak,$tweak,$rndkey0
+ lvx $rndkey0,$idx,$key2
+ addi $idx,$idx,16
+ mtctr $rounds
+
+Ltweak_xts_enc:
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vcipher $tweak,$tweak,$rndkey1
+ lvx $rndkey1,$idx,$key2
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vcipher $tweak,$tweak,$rndkey0
+ lvx $rndkey0,$idx,$key2
+ addi $idx,$idx,16
+ bdnz Ltweak_xts_enc
+
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vcipher $tweak,$tweak,$rndkey1
+ lvx $rndkey1,$idx,$key2
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vcipherlast $tweak,$tweak,$rndkey0
+
+ li $ivp,0 # don't chain the tweak
+ b Lxts_enc
+
+Lxts_enc_no_key2:
+ li $idx,-16
+ and $len,$len,$idx # in "tweak chaining"
+ # mode only complete
+ # blocks are processed
+Lxts_enc:
+ lvx $inptail,0,$inp
+ addi $inp,$inp,16
+
+ ?lvsl $keyperm,0,$key1 # prepare for unaligned key
+ lwz $rounds,240($key1)
+ srwi $rounds,$rounds,1
+ subi $rounds,$rounds,1
+ li $idx,16
+
+ vslb $eighty7,$seven,$seven # 0x808080..80
+ vor $eighty7,$eighty7,$seven # 0x878787..87
+ vspltisb $tmp,1 # 0x010101..01
+ vsldoi $eighty7,$eighty7,$tmp,15 # 0x870101..01
+
+ ${UCMP}i $len,96
+ bge _aesp8_xts_encrypt6x
+
+ andi. $taillen,$len,15
+ subic r0,$len,32
+ subi $taillen,$taillen,16
+ subfe r0,r0,r0
+ and r0,r0,$taillen
+ add $inp,$inp,r0
+
+ lvx $rndkey0,0,$key1
+ lvx $rndkey1,$idx,$key1
+ addi $idx,$idx,16
+ vperm $inout,$inout,$inptail,$inpperm
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $inout,$inout,$tweak
+ vxor $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key1
+ addi $idx,$idx,16
+ mtctr $rounds
+ b Loop_xts_enc
+
+.align 5
+Loop_xts_enc:
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vcipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key1
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vcipher $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key1
+ addi $idx,$idx,16
+ bdnz Loop_xts_enc
+
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vcipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key1
+ li $idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $rndkey0,$rndkey0,$tweak
+ vcipherlast $output,$inout,$rndkey0
+
+ le?vperm $tmp,$output,$output,$leperm
+ be?nop
+ le?stvx_u $tmp,0,$out
+ be?stvx_u $output,0,$out
+ addi $out,$out,16
+
+ subic. $len,$len,16
+ beq Lxts_enc_done
+
+ vmr $inout,$inptail
+ lvx $inptail,0,$inp
+ addi $inp,$inp,16
+ lvx $rndkey0,0,$key1
+ lvx $rndkey1,$idx,$key1
+ addi $idx,$idx,16
+
+ subic r0,$len,32
+ subfe r0,r0,r0
+ and r0,r0,$taillen
+ add $inp,$inp,r0
+
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ vsldoi $tmp,$tmp,$tmp,15
+ vand $tmp,$tmp,$eighty7
+ vxor $tweak,$tweak,$tmp
+
+ vperm $inout,$inout,$inptail,$inpperm
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $inout,$inout,$tweak
+ vxor $output,$output,$rndkey0 # just in case $len<16
+ vxor $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key1
+ addi $idx,$idx,16
+
+ mtctr $rounds
+ ${UCMP}i $len,16
+ bge Loop_xts_enc
+
+ vxor $output,$output,$tweak
+ lvsr $inpperm,0,$len # $inpperm is no longer needed
+ vxor $inptail,$inptail,$inptail # $inptail is no longer needed
+ vspltisb $tmp,-1
+ vperm $inptail,$inptail,$tmp,$inpperm
+ vsel $inout,$inout,$output,$inptail
+
+ subi r11,$out,17
+ subi $out,$out,16
+ mtctr $len
+ li $len,16
+Loop_xts_enc_steal:
+ lbzu r0,1(r11)
+ stb r0,16(r11)
+ bdnz Loop_xts_enc_steal
+
+ mtctr $rounds
+ b Loop_xts_enc # one more time...
+
+Lxts_enc_done:
+ ${UCMP}i $ivp,0
+ beq Lxts_enc_ret
+
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ vsldoi $tmp,$tmp,$tmp,15
+ vand $tmp,$tmp,$eighty7
+ vxor $tweak,$tweak,$tmp
+
+ le?vperm $tweak,$tweak,$tweak,$leperm
+ stvx_u $tweak,0,$ivp
+
+Lxts_enc_ret:
+ mtspr 256,r12 # restore vrsave
+ li r3,0
+ blr
+ .long 0
+ .byte 0,12,0x04,0,0x80,6,6,0
+ .long 0
+.size .${prefix}_xts_encrypt,.-.${prefix}_xts_encrypt
+
+.globl .${prefix}_xts_decrypt
+ mr $inp,r3 # reassign
+ li r3,-1
+ ${UCMP}i $len,16
+ bltlr-
+
+ lis r0,0xfff8
+ mfspr r12,256 # save vrsave
+ li r11,0
+ mtspr 256,r0
+
+ andi. r0,$len,15
+ neg r0,r0
+ andi. r0,r0,16
+ sub $len,$len,r0
+
+ vspltisb $seven,0x07 # 0x070707..07
+ le?lvsl $leperm,r11,r11
+ le?vspltisb $tmp,0x0f
+ le?vxor $leperm,$leperm,$seven
+
+ li $idx,15
+ lvx $tweak,0,$ivp # load [unaligned] iv
+ lvsl $inpperm,0,$ivp
+ lvx $inptail,$idx,$ivp
+ le?vxor $inpperm,$inpperm,$tmp
+ vperm $tweak,$tweak,$inptail,$inpperm
+
+ neg r11,$inp
+ lvsr $inpperm,0,r11 # prepare for unaligned load
+ lvx $inout,0,$inp
+ addi $inp,$inp,15 # 15 is not typo
+ le?vxor $inpperm,$inpperm,$tmp
+
+ ${UCMP}i $key2,0 # key2==NULL?
+ beq Lxts_dec_no_key2
+
+ ?lvsl $keyperm,0,$key2 # prepare for unaligned key
+ lwz $rounds,240($key2)
+ srwi $rounds,$rounds,1
+ subi $rounds,$rounds,1
+ li $idx,16
+
+ lvx $rndkey0,0,$key2
+ lvx $rndkey1,$idx,$key2
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $tweak,$tweak,$rndkey0
+ lvx $rndkey0,$idx,$key2
+ addi $idx,$idx,16
+ mtctr $rounds
+
+Ltweak_xts_dec:
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vcipher $tweak,$tweak,$rndkey1
+ lvx $rndkey1,$idx,$key2
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vcipher $tweak,$tweak,$rndkey0
+ lvx $rndkey0,$idx,$key2
+ addi $idx,$idx,16
+ bdnz Ltweak_xts_dec
+
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vcipher $tweak,$tweak,$rndkey1
+ lvx $rndkey1,$idx,$key2
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vcipherlast $tweak,$tweak,$rndkey0
+
+ li $ivp,0 # don't chain the tweak
+ b Lxts_dec
+
+Lxts_dec_no_key2:
+ neg $idx,$len
+ andi. $idx,$idx,15
+ add $len,$len,$idx # in "tweak chaining"
+ # mode only complete
+ # blocks are processed
+Lxts_dec:
+ lvx $inptail,0,$inp
+ addi $inp,$inp,16
+
+ ?lvsl $keyperm,0,$key1 # prepare for unaligned key
+ lwz $rounds,240($key1)
+ srwi $rounds,$rounds,1
+ subi $rounds,$rounds,1
+ li $idx,16
+
+ vslb $eighty7,$seven,$seven # 0x808080..80
+ vor $eighty7,$eighty7,$seven # 0x878787..87
+ vspltisb $tmp,1 # 0x010101..01
+ vsldoi $eighty7,$eighty7,$tmp,15 # 0x870101..01
+
+ ${UCMP}i $len,96
+ bge _aesp8_xts_decrypt6x
+
+ lvx $rndkey0,0,$key1
+ lvx $rndkey1,$idx,$key1
+ addi $idx,$idx,16
+ vperm $inout,$inout,$inptail,$inpperm
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $inout,$inout,$tweak
+ vxor $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key1
+ addi $idx,$idx,16
+ mtctr $rounds
+
+ ${UCMP}i $len,16
+ blt Ltail_xts_dec
+ be?b Loop_xts_dec
+
+.align 5
+Loop_xts_dec:
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vncipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key1
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vncipher $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key1
+ addi $idx,$idx,16
+ bdnz Loop_xts_dec
+
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vncipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key1
+ li $idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $rndkey0,$rndkey0,$tweak
+ vncipherlast $output,$inout,$rndkey0
+
+ le?vperm $tmp,$output,$output,$leperm
+ be?nop
+ le?stvx_u $tmp,0,$out
+ be?stvx_u $output,0,$out
+ addi $out,$out,16
+
+ subic. $len,$len,16
+ beq Lxts_dec_done
+
+ vmr $inout,$inptail
+ lvx $inptail,0,$inp
+ addi $inp,$inp,16
+ lvx $rndkey0,0,$key1
+ lvx $rndkey1,$idx,$key1
+ addi $idx,$idx,16
+
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ vsldoi $tmp,$tmp,$tmp,15
+ vand $tmp,$tmp,$eighty7
+ vxor $tweak,$tweak,$tmp
+
+ vperm $inout,$inout,$inptail,$inpperm
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $inout,$inout,$tweak
+ vxor $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key1
+ addi $idx,$idx,16
+
+ mtctr $rounds
+ ${UCMP}i $len,16
+ bge Loop_xts_dec
+
+Ltail_xts_dec:
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak1,$tweak,$tweak
+ vsldoi $tmp,$tmp,$tmp,15
+ vand $tmp,$tmp,$eighty7
+ vxor $tweak1,$tweak1,$tmp
+
+ subi $inp,$inp,16
+ add $inp,$inp,$len
+
+ vxor $inout,$inout,$tweak # :-(
+ vxor $inout,$inout,$tweak1 # :-)
+
+Loop_xts_dec_short:
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vncipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key1
+ addi $idx,$idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vncipher $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key1
+ addi $idx,$idx,16
+ bdnz Loop_xts_dec_short
+
+ ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm
+ vncipher $inout,$inout,$rndkey1
+ lvx $rndkey1,$idx,$key1
+ li $idx,16
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+ vxor $rndkey0,$rndkey0,$tweak1
+ vncipherlast $output,$inout,$rndkey0
+
+ le?vperm $tmp,$output,$output,$leperm
+ be?nop
+ le?stvx_u $tmp,0,$out
+ be?stvx_u $output,0,$out
+
+ vmr $inout,$inptail
+ lvx $inptail,0,$inp
+ #addi $inp,$inp,16
+ lvx $rndkey0,0,$key1
+ lvx $rndkey1,$idx,$key1
+ addi $idx,$idx,16
+ vperm $inout,$inout,$inptail,$inpperm
+ ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm
+
+ lvsr $inpperm,0,$len # $inpperm is no longer needed
+ vxor $inptail,$inptail,$inptail # $inptail is no longer needed
+ vspltisb $tmp,-1
+ vperm $inptail,$inptail,$tmp,$inpperm
+ vsel $inout,$inout,$output,$inptail
+
+ vxor $rndkey0,$rndkey0,$tweak
+ vxor $inout,$inout,$rndkey0
+ lvx $rndkey0,$idx,$key1
+ addi $idx,$idx,16
+
+ subi r11,$out,1
+ mtctr $len
+ li $len,16
+Loop_xts_dec_steal:
+ lbzu r0,1(r11)
+ stb r0,16(r11)
+ bdnz Loop_xts_dec_steal
+
+ mtctr $rounds
+ b Loop_xts_dec # one more time...
+
+Lxts_dec_done:
+ ${UCMP}i $ivp,0
+ beq Lxts_dec_ret
+
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ vsldoi $tmp,$tmp,$tmp,15
+ vand $tmp,$tmp,$eighty7
+ vxor $tweak,$tweak,$tmp
+
+ le?vperm $tweak,$tweak,$tweak,$leperm
+ stvx_u $tweak,0,$ivp
+
+Lxts_dec_ret:
+ mtspr 256,r12 # restore vrsave
+ li r3,0
+ blr
+ .long 0
+ .byte 0,12,0x04,0,0x80,6,6,0
+ .long 0
+.size .${prefix}_xts_decrypt,.-.${prefix}_xts_decrypt
+___
+#########################################################################
+{{ # Optimized XTS procedures #
+my $key_=$key2;
+my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,3,26..31));
+ $x00=0 if ($flavour =~ /osx/);
+my ($in0, $in1, $in2, $in3, $in4, $in5 )=map("v$_",(0..5));
+my ($out0, $out1, $out2, $out3, $out4, $out5)=map("v$_",(7,12..16));
+my ($twk0, $twk1, $twk2, $twk3, $twk4, $twk5)=map("v$_",(17..22));
+my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys
+ # v26-v31 last 6 round keys
+my ($keyperm)=($out0); # aliases with "caller", redundant assignment
+my $taillen=$x70;
+
+$code.=<<___;
+.align 5
+_aesp8_xts_encrypt6x:
+ $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
+ mflr r11
+ li r7,`$FRAME+8*16+15`
+ li r3,`$FRAME+8*16+31`
+ $PUSH r11,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp)
+ stvx v20,r7,$sp # ABI says so
+ addi r7,r7,32
+ stvx v21,r3,$sp
+ addi r3,r3,32
+ stvx v22,r7,$sp
+ addi r7,r7,32
+ stvx v23,r3,$sp
+ addi r3,r3,32
+ stvx v24,r7,$sp
+ addi r7,r7,32
+ stvx v25,r3,$sp
+ addi r3,r3,32
+ stvx v26,r7,$sp
+ addi r7,r7,32
+ stvx v27,r3,$sp
+ addi r3,r3,32
+ stvx v28,r7,$sp
+ addi r7,r7,32
+ stvx v29,r3,$sp
+ addi r3,r3,32
+ stvx v30,r7,$sp
+ stvx v31,r3,$sp
+ li r0,-1
+ stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave
+ li $x10,0x10
+ $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+ li $x20,0x20
+ $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+ li $x30,0x30
+ $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+ li $x40,0x40
+ $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+ li $x50,0x50
+ $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+ li $x60,0x60
+ $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+ li $x70,0x70
+ mtspr 256,r0
+
+ xxlor 2, 32+$eighty7, 32+$eighty7
+ vsldoi $eighty7,$tmp,$eighty7,1 # 0x010101..87
+ xxlor 1, 32+$eighty7, 32+$eighty7
+
+ # Load XOR Lconsts.
+ mr $x70, r6
+ bl Lconsts
+ lxvw4x 0, $x40, r6 # load XOR contents
+ mr r6, $x70
+ li $x70,0x70
+
+ subi $rounds,$rounds,3 # -4 in total
+
+ lvx $rndkey0,$x00,$key1 # load key schedule
+ lvx v30,$x10,$key1
+ addi $key1,$key1,0x20
+ lvx v31,$x00,$key1
+ ?vperm $rndkey0,$rndkey0,v30,$keyperm
+ addi $key_,$sp,$FRAME+15
+ mtctr $rounds
+
+Load_xts_enc_key:
+ ?vperm v24,v30,v31,$keyperm
+ lvx v30,$x10,$key1
+ addi $key1,$key1,0x20
+ stvx v24,$x00,$key_ # off-load round[1]
+ ?vperm v25,v31,v30,$keyperm
+ lvx v31,$x00,$key1
+ stvx v25,$x10,$key_ # off-load round[2]
+ addi $key_,$key_,0x20
+ bdnz Load_xts_enc_key
+
+ lvx v26,$x10,$key1
+ ?vperm v24,v30,v31,$keyperm
+ lvx v27,$x20,$key1
+ stvx v24,$x00,$key_ # off-load round[3]
+ ?vperm v25,v31,v26,$keyperm
+ lvx v28,$x30,$key1
+ stvx v25,$x10,$key_ # off-load round[4]
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ ?vperm v26,v26,v27,$keyperm
+ lvx v29,$x40,$key1
+ ?vperm v27,v27,v28,$keyperm
+ lvx v30,$x50,$key1
+ ?vperm v28,v28,v29,$keyperm
+ lvx v31,$x60,$key1
+ ?vperm v29,v29,v30,$keyperm
+ lvx $twk5,$x70,$key1 # borrow $twk5
+ ?vperm v30,v30,v31,$keyperm
+ lvx v24,$x00,$key_ # pre-load round[1]
+ ?vperm v31,v31,$twk5,$keyperm
+ lvx v25,$x10,$key_ # pre-load round[2]
+
+ # Switch to use the following codes with 0x010101..87 to generate tweak.
+ # eighty7 = 0x010101..87
+ # vsrab tmp, tweak, seven # next tweak value, right shift 7 bits
+ # vand tmp, tmp, eighty7 # last byte with carry
+ # vaddubm tweak, tweak, tweak # left shift 1 bit (x2)
+ # xxlor vsx, 0, 0
+ # vpermxor tweak, tweak, tmp, vsx
+
+ vperm $in0,$inout,$inptail,$inpperm
+ subi $inp,$inp,31 # undo "caller"
+ vxor $twk0,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ vand $tmp,$tmp,$eighty7
+ vxor $out0,$in0,$twk0
+ xxlor 32+$in1, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in1
+
+ lvx_u $in1,$x10,$inp
+ vxor $twk1,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ le?vperm $in1,$in1,$in1,$leperm
+ vand $tmp,$tmp,$eighty7
+ vxor $out1,$in1,$twk1
+ xxlor 32+$in2, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in2
+
+ lvx_u $in2,$x20,$inp
+ andi. $taillen,$len,15
+ vxor $twk2,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ le?vperm $in2,$in2,$in2,$leperm
+ vand $tmp,$tmp,$eighty7
+ vxor $out2,$in2,$twk2
+ xxlor 32+$in3, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in3
+
+ lvx_u $in3,$x30,$inp
+ sub $len,$len,$taillen
+ vxor $twk3,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ le?vperm $in3,$in3,$in3,$leperm
+ vand $tmp,$tmp,$eighty7
+ vxor $out3,$in3,$twk3
+ xxlor 32+$in4, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in4
+
+ lvx_u $in4,$x40,$inp
+ subi $len,$len,0x60
+ vxor $twk4,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ le?vperm $in4,$in4,$in4,$leperm
+ vand $tmp,$tmp,$eighty7
+ vxor $out4,$in4,$twk4
+ xxlor 32+$in5, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in5
+
+ lvx_u $in5,$x50,$inp
+ addi $inp,$inp,0x60
+ vxor $twk5,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ le?vperm $in5,$in5,$in5,$leperm
+ vand $tmp,$tmp,$eighty7
+ vxor $out5,$in5,$twk5
+ xxlor 32+$in0, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in0
+
+ vxor v31,v31,$rndkey0
+ mtctr $rounds
+ b Loop_xts_enc6x
+
+.align 5
+Loop_xts_enc6x:
+ vcipher $out0,$out0,v24
+ vcipher $out1,$out1,v24
+ vcipher $out2,$out2,v24
+ vcipher $out3,$out3,v24
+ vcipher $out4,$out4,v24
+ vcipher $out5,$out5,v24
+ lvx v24,$x20,$key_ # round[3]
+ addi $key_,$key_,0x20
+
+ vcipher $out0,$out0,v25
+ vcipher $out1,$out1,v25
+ vcipher $out2,$out2,v25
+ vcipher $out3,$out3,v25
+ vcipher $out4,$out4,v25
+ vcipher $out5,$out5,v25
+ lvx v25,$x10,$key_ # round[4]
+ bdnz Loop_xts_enc6x
+
+ xxlor 32+$eighty7, 1, 1 # 0x010101..87
+
+ subic $len,$len,96 # $len-=96
+ vxor $in0,$twk0,v31 # xor with last round key
+ vcipher $out0,$out0,v24
+ vcipher $out1,$out1,v24
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk0,$tweak,$rndkey0
+ vaddubm $tweak,$tweak,$tweak
+ vcipher $out2,$out2,v24
+ vcipher $out3,$out3,v24
+ vcipher $out4,$out4,v24
+ vcipher $out5,$out5,v24
+
+ subfe. r0,r0,r0 # borrow?-1:0
+ vand $tmp,$tmp,$eighty7
+ vcipher $out0,$out0,v25
+ vcipher $out1,$out1,v25
+ xxlor 32+$in1, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in1
+ vcipher $out2,$out2,v25
+ vcipher $out3,$out3,v25
+ vxor $in1,$twk1,v31
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk1,$tweak,$rndkey0
+ vcipher $out4,$out4,v25
+ vcipher $out5,$out5,v25
+
+ and r0,r0,$len
+ vaddubm $tweak,$tweak,$tweak
+ vcipher $out0,$out0,v26
+ vcipher $out1,$out1,v26
+ vand $tmp,$tmp,$eighty7
+ vcipher $out2,$out2,v26
+ vcipher $out3,$out3,v26
+ xxlor 32+$in2, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in2
+ vcipher $out4,$out4,v26
+ vcipher $out5,$out5,v26
+
+ add $inp,$inp,r0 # $inp is adjusted in such
+ # way that at exit from the
+ # loop inX-in5 are loaded
+ # with last "words"
+ vxor $in2,$twk2,v31
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk2,$tweak,$rndkey0
+ vaddubm $tweak,$tweak,$tweak
+ vcipher $out0,$out0,v27
+ vcipher $out1,$out1,v27
+ vcipher $out2,$out2,v27
+ vcipher $out3,$out3,v27
+ vand $tmp,$tmp,$eighty7
+ vcipher $out4,$out4,v27
+ vcipher $out5,$out5,v27
+
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ xxlor 32+$in3, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in3
+ vcipher $out0,$out0,v28
+ vcipher $out1,$out1,v28
+ vxor $in3,$twk3,v31
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk3,$tweak,$rndkey0
+ vcipher $out2,$out2,v28
+ vcipher $out3,$out3,v28
+ vaddubm $tweak,$tweak,$tweak
+ vcipher $out4,$out4,v28
+ vcipher $out5,$out5,v28
+ lvx v24,$x00,$key_ # re-pre-load round[1]
+ vand $tmp,$tmp,$eighty7
+
+ vcipher $out0,$out0,v29
+ vcipher $out1,$out1,v29
+ xxlor 32+$in4, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in4
+ vcipher $out2,$out2,v29
+ vcipher $out3,$out3,v29
+ vxor $in4,$twk4,v31
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk4,$tweak,$rndkey0
+ vcipher $out4,$out4,v29
+ vcipher $out5,$out5,v29
+ lvx v25,$x10,$key_ # re-pre-load round[2]
+ vaddubm $tweak,$tweak,$tweak
+
+ vcipher $out0,$out0,v30
+ vcipher $out1,$out1,v30
+ vand $tmp,$tmp,$eighty7
+ vcipher $out2,$out2,v30
+ vcipher $out3,$out3,v30
+ xxlor 32+$in5, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in5
+ vcipher $out4,$out4,v30
+ vcipher $out5,$out5,v30
+ vxor $in5,$twk5,v31
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk5,$tweak,$rndkey0
+
+ vcipherlast $out0,$out0,$in0
+ lvx_u $in0,$x00,$inp # load next input block
+ vaddubm $tweak,$tweak,$tweak
+ vcipherlast $out1,$out1,$in1
+ lvx_u $in1,$x10,$inp
+ vcipherlast $out2,$out2,$in2
+ le?vperm $in0,$in0,$in0,$leperm
+ lvx_u $in2,$x20,$inp
+ vand $tmp,$tmp,$eighty7
+ vcipherlast $out3,$out3,$in3
+ le?vperm $in1,$in1,$in1,$leperm
+ lvx_u $in3,$x30,$inp
+ vcipherlast $out4,$out4,$in4
+ le?vperm $in2,$in2,$in2,$leperm
+ lvx_u $in4,$x40,$inp
+ xxlor 10, 32+$in0, 32+$in0
+ xxlor 32+$in0, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in0
+ xxlor 32+$in0, 10, 10
+ vcipherlast $tmp,$out5,$in5 # last block might be needed
+ # in stealing mode
+ le?vperm $in3,$in3,$in3,$leperm
+ lvx_u $in5,$x50,$inp
+ addi $inp,$inp,0x60
+ le?vperm $in4,$in4,$in4,$leperm
+ le?vperm $in5,$in5,$in5,$leperm
+
+ le?vperm $out0,$out0,$out0,$leperm
+ le?vperm $out1,$out1,$out1,$leperm
+ stvx_u $out0,$x00,$out # store output
+ vxor $out0,$in0,$twk0
+ le?vperm $out2,$out2,$out2,$leperm
+ stvx_u $out1,$x10,$out
+ vxor $out1,$in1,$twk1
+ le?vperm $out3,$out3,$out3,$leperm
+ stvx_u $out2,$x20,$out
+ vxor $out2,$in2,$twk2
+ le?vperm $out4,$out4,$out4,$leperm
+ stvx_u $out3,$x30,$out
+ vxor $out3,$in3,$twk3
+ le?vperm $out5,$tmp,$tmp,$leperm
+ stvx_u $out4,$x40,$out
+ vxor $out4,$in4,$twk4
+ le?stvx_u $out5,$x50,$out
+ be?stvx_u $tmp, $x50,$out
+ vxor $out5,$in5,$twk5
+ addi $out,$out,0x60
+
+ mtctr $rounds
+ beq Loop_xts_enc6x # did $len-=96 borrow?
+
+ xxlor 32+$eighty7, 2, 2 # 0x010101..87
+
+ addic. $len,$len,0x60
+ beq Lxts_enc6x_zero
+ cmpwi $len,0x20
+ blt Lxts_enc6x_one
+ nop
+ beq Lxts_enc6x_two
+ cmpwi $len,0x40
+ blt Lxts_enc6x_three
+ nop
+ beq Lxts_enc6x_four
+
+Lxts_enc6x_five:
+ vxor $out0,$in1,$twk0
+ vxor $out1,$in2,$twk1
+ vxor $out2,$in3,$twk2
+ vxor $out3,$in4,$twk3
+ vxor $out4,$in5,$twk4
+
+ bl _aesp8_xts_enc5x
+
+ le?vperm $out0,$out0,$out0,$leperm
+ vmr $twk0,$twk5 # unused tweak
+ le?vperm $out1,$out1,$out1,$leperm
+ stvx_u $out0,$x00,$out # store output
+ le?vperm $out2,$out2,$out2,$leperm
+ stvx_u $out1,$x10,$out
+ le?vperm $out3,$out3,$out3,$leperm
+ stvx_u $out2,$x20,$out
+ vxor $tmp,$out4,$twk5 # last block prep for stealing
+ le?vperm $out4,$out4,$out4,$leperm
+ stvx_u $out3,$x30,$out
+ stvx_u $out4,$x40,$out
+ addi $out,$out,0x50
+ bne Lxts_enc6x_steal
+ b Lxts_enc6x_done
+
+.align 4
+Lxts_enc6x_four:
+ vxor $out0,$in2,$twk0
+ vxor $out1,$in3,$twk1
+ vxor $out2,$in4,$twk2
+ vxor $out3,$in5,$twk3
+ vxor $out4,$out4,$out4
+
+ bl _aesp8_xts_enc5x
+
+ le?vperm $out0,$out0,$out0,$leperm
+ vmr $twk0,$twk4 # unused tweak
+ le?vperm $out1,$out1,$out1,$leperm
+ stvx_u $out0,$x00,$out # store output
+ le?vperm $out2,$out2,$out2,$leperm
+ stvx_u $out1,$x10,$out
+ vxor $tmp,$out3,$twk4 # last block prep for stealing
+ le?vperm $out3,$out3,$out3,$leperm
+ stvx_u $out2,$x20,$out
+ stvx_u $out3,$x30,$out
+ addi $out,$out,0x40
+ bne Lxts_enc6x_steal
+ b Lxts_enc6x_done
+
+.align 4
+Lxts_enc6x_three:
+ vxor $out0,$in3,$twk0
+ vxor $out1,$in4,$twk1
+ vxor $out2,$in5,$twk2
+ vxor $out3,$out3,$out3
+ vxor $out4,$out4,$out4
+
+ bl _aesp8_xts_enc5x
+
+ le?vperm $out0,$out0,$out0,$leperm
+ vmr $twk0,$twk3 # unused tweak
+ le?vperm $out1,$out1,$out1,$leperm
+ stvx_u $out0,$x00,$out # store output
+ vxor $tmp,$out2,$twk3 # last block prep for stealing
+ le?vperm $out2,$out2,$out2,$leperm
+ stvx_u $out1,$x10,$out
+ stvx_u $out2,$x20,$out
+ addi $out,$out,0x30
+ bne Lxts_enc6x_steal
+ b Lxts_enc6x_done
+
+.align 4
+Lxts_enc6x_two:
+ vxor $out0,$in4,$twk0
+ vxor $out1,$in5,$twk1
+ vxor $out2,$out2,$out2
+ vxor $out3,$out3,$out3
+ vxor $out4,$out4,$out4
+
+ bl _aesp8_xts_enc5x
+
+ le?vperm $out0,$out0,$out0,$leperm
+ vmr $twk0,$twk2 # unused tweak
+ vxor $tmp,$out1,$twk2 # last block prep for stealing
+ le?vperm $out1,$out1,$out1,$leperm
+ stvx_u $out0,$x00,$out # store output
+ stvx_u $out1,$x10,$out
+ addi $out,$out,0x20
+ bne Lxts_enc6x_steal
+ b Lxts_enc6x_done
+
+.align 4
+Lxts_enc6x_one:
+ vxor $out0,$in5,$twk0
+ nop
+Loop_xts_enc1x:
+ vcipher $out0,$out0,v24
+ lvx v24,$x20,$key_ # round[3]
+ addi $key_,$key_,0x20
+
+ vcipher $out0,$out0,v25
+ lvx v25,$x10,$key_ # round[4]
+ bdnz Loop_xts_enc1x
+
+ add $inp,$inp,$taillen
+ cmpwi $taillen,0
+ vcipher $out0,$out0,v24
+
+ subi $inp,$inp,16
+ vcipher $out0,$out0,v25
+
+ lvsr $inpperm,0,$taillen
+ vcipher $out0,$out0,v26
+
+ lvx_u $in0,0,$inp
+ vcipher $out0,$out0,v27
+
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ vcipher $out0,$out0,v28
+ lvx v24,$x00,$key_ # re-pre-load round[1]
+
+ vcipher $out0,$out0,v29
+ lvx v25,$x10,$key_ # re-pre-load round[2]
+ vxor $twk0,$twk0,v31
+
+ le?vperm $in0,$in0,$in0,$leperm
+ vcipher $out0,$out0,v30
+
+ vperm $in0,$in0,$in0,$inpperm
+ vcipherlast $out0,$out0,$twk0
+
+ vmr $twk0,$twk1 # unused tweak
+ vxor $tmp,$out0,$twk1 # last block prep for stealing
+ le?vperm $out0,$out0,$out0,$leperm
+ stvx_u $out0,$x00,$out # store output
+ addi $out,$out,0x10
+ bne Lxts_enc6x_steal
+ b Lxts_enc6x_done
+
+.align 4
+Lxts_enc6x_zero:
+ cmpwi $taillen,0
+ beq Lxts_enc6x_done
+
+ add $inp,$inp,$taillen
+ subi $inp,$inp,16
+ lvx_u $in0,0,$inp
+ lvsr $inpperm,0,$taillen # $in5 is no more
+ le?vperm $in0,$in0,$in0,$leperm
+ vperm $in0,$in0,$in0,$inpperm
+ vxor $tmp,$tmp,$twk0
+Lxts_enc6x_steal:
+ vxor $in0,$in0,$twk0
+ vxor $out0,$out0,$out0
+ vspltisb $out1,-1
+ vperm $out0,$out0,$out1,$inpperm
+ vsel $out0,$in0,$tmp,$out0 # $tmp is last block, remember?
+
+ subi r30,$out,17
+ subi $out,$out,16
+ mtctr $taillen
+Loop_xts_enc6x_steal:
+ lbzu r0,1(r30)
+ stb r0,16(r30)
+ bdnz Loop_xts_enc6x_steal
+
+ li $taillen,0
+ mtctr $rounds
+ b Loop_xts_enc1x # one more time...
+
+.align 4
+Lxts_enc6x_done:
+ ${UCMP}i $ivp,0
+ beq Lxts_enc6x_ret
+
+ vxor $tweak,$twk0,$rndkey0
+ le?vperm $tweak,$tweak,$tweak,$leperm
+ stvx_u $tweak,0,$ivp
+
+Lxts_enc6x_ret:
+ mtlr r11
+ li r10,`$FRAME+15`
+ li r11,`$FRAME+31`
+ stvx $seven,r10,$sp # wipe copies of round keys
+ addi r10,r10,32
+ stvx $seven,r11,$sp
+ addi r11,r11,32
+ stvx $seven,r10,$sp
+ addi r10,r10,32
+ stvx $seven,r11,$sp
+ addi r11,r11,32
+ stvx $seven,r10,$sp
+ addi r10,r10,32
+ stvx $seven,r11,$sp
+ addi r11,r11,32
+ stvx $seven,r10,$sp
+ addi r10,r10,32
+ stvx $seven,r11,$sp
+ addi r11,r11,32
+
+ mtspr 256,$vrsave
+ lvx v20,r10,$sp # ABI says so
+ addi r10,r10,32
+ lvx v21,r11,$sp
+ addi r11,r11,32
+ lvx v22,r10,$sp
+ addi r10,r10,32
+ lvx v23,r11,$sp
+ addi r11,r11,32
+ lvx v24,r10,$sp
+ addi r10,r10,32
+ lvx v25,r11,$sp
+ addi r11,r11,32
+ lvx v26,r10,$sp
+ addi r10,r10,32
+ lvx v27,r11,$sp
+ addi r11,r11,32
+ lvx v28,r10,$sp
+ addi r10,r10,32
+ lvx v29,r11,$sp
+ addi r11,r11,32
+ lvx v30,r10,$sp
+ lvx v31,r11,$sp
+ $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+ $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+ $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+ $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+ $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+ $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+ addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T`
+ blr
+ .long 0
+ .byte 0,12,0x04,1,0x80,6,6,0
+ .long 0
+
+.align 5
+_aesp8_xts_enc5x:
+ vcipher $out0,$out0,v24
+ vcipher $out1,$out1,v24
+ vcipher $out2,$out2,v24
+ vcipher $out3,$out3,v24
+ vcipher $out4,$out4,v24
+ lvx v24,$x20,$key_ # round[3]
+ addi $key_,$key_,0x20
+
+ vcipher $out0,$out0,v25
+ vcipher $out1,$out1,v25
+ vcipher $out2,$out2,v25
+ vcipher $out3,$out3,v25
+ vcipher $out4,$out4,v25
+ lvx v25,$x10,$key_ # round[4]
+ bdnz _aesp8_xts_enc5x
+
+ add $inp,$inp,$taillen
+ cmpwi $taillen,0
+ vcipher $out0,$out0,v24
+ vcipher $out1,$out1,v24
+ vcipher $out2,$out2,v24
+ vcipher $out3,$out3,v24
+ vcipher $out4,$out4,v24
+
+ subi $inp,$inp,16
+ vcipher $out0,$out0,v25
+ vcipher $out1,$out1,v25
+ vcipher $out2,$out2,v25
+ vcipher $out3,$out3,v25
+ vcipher $out4,$out4,v25
+ vxor $twk0,$twk0,v31
+
+ vcipher $out0,$out0,v26
+ lvsr $inpperm,r0,$taillen # $in5 is no more
+ vcipher $out1,$out1,v26
+ vcipher $out2,$out2,v26
+ vcipher $out3,$out3,v26
+ vcipher $out4,$out4,v26
+ vxor $in1,$twk1,v31
+
+ vcipher $out0,$out0,v27
+ lvx_u $in0,0,$inp
+ vcipher $out1,$out1,v27
+ vcipher $out2,$out2,v27
+ vcipher $out3,$out3,v27
+ vcipher $out4,$out4,v27
+ vxor $in2,$twk2,v31
+
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ vcipher $out0,$out0,v28
+ vcipher $out1,$out1,v28
+ vcipher $out2,$out2,v28
+ vcipher $out3,$out3,v28
+ vcipher $out4,$out4,v28
+ lvx v24,$x00,$key_ # re-pre-load round[1]
+ vxor $in3,$twk3,v31
+
+ vcipher $out0,$out0,v29
+ le?vperm $in0,$in0,$in0,$leperm
+ vcipher $out1,$out1,v29
+ vcipher $out2,$out2,v29
+ vcipher $out3,$out3,v29
+ vcipher $out4,$out4,v29
+ lvx v25,$x10,$key_ # re-pre-load round[2]
+ vxor $in4,$twk4,v31
+
+ vcipher $out0,$out0,v30
+ vperm $in0,$in0,$in0,$inpperm
+ vcipher $out1,$out1,v30
+ vcipher $out2,$out2,v30
+ vcipher $out3,$out3,v30
+ vcipher $out4,$out4,v30
+
+ vcipherlast $out0,$out0,$twk0
+ vcipherlast $out1,$out1,$in1
+ vcipherlast $out2,$out2,$in2
+ vcipherlast $out3,$out3,$in3
+ vcipherlast $out4,$out4,$in4
+ blr
+ .long 0
+ .byte 0,12,0x14,0,0,0,0,0
+
+.align 5
+_aesp8_xts_decrypt6x:
+ $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp)
+ mflr r11
+ li r7,`$FRAME+8*16+15`
+ li r3,`$FRAME+8*16+31`
+ $PUSH r11,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp)
+ stvx v20,r7,$sp # ABI says so
+ addi r7,r7,32
+ stvx v21,r3,$sp
+ addi r3,r3,32
+ stvx v22,r7,$sp
+ addi r7,r7,32
+ stvx v23,r3,$sp
+ addi r3,r3,32
+ stvx v24,r7,$sp
+ addi r7,r7,32
+ stvx v25,r3,$sp
+ addi r3,r3,32
+ stvx v26,r7,$sp
+ addi r7,r7,32
+ stvx v27,r3,$sp
+ addi r3,r3,32
+ stvx v28,r7,$sp
+ addi r7,r7,32
+ stvx v29,r3,$sp
+ addi r3,r3,32
+ stvx v30,r7,$sp
+ stvx v31,r3,$sp
+ li r0,-1
+ stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave
+ li $x10,0x10
+ $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+ li $x20,0x20
+ $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+ li $x30,0x30
+ $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+ li $x40,0x40
+ $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+ li $x50,0x50
+ $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+ li $x60,0x60
+ $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+ li $x70,0x70
+ mtspr 256,r0
+
+ xxlor 2, 32+$eighty7, 32+$eighty7
+ vsldoi $eighty7,$tmp,$eighty7,1 # 0x010101..87
+ xxlor 1, 32+$eighty7, 32+$eighty7
+
+ # Load XOR Lconsts.
+ mr $x70, r6
+ bl Lconsts
+ lxvw4x 0, $x40, r6 # load XOR contents
+ mr r6, $x70
+ li $x70,0x70
+
+ subi $rounds,$rounds,3 # -4 in total
+
+ lvx $rndkey0,$x00,$key1 # load key schedule
+ lvx v30,$x10,$key1
+ addi $key1,$key1,0x20
+ lvx v31,$x00,$key1
+ ?vperm $rndkey0,$rndkey0,v30,$keyperm
+ addi $key_,$sp,$FRAME+15
+ mtctr $rounds
+
+Load_xts_dec_key:
+ ?vperm v24,v30,v31,$keyperm
+ lvx v30,$x10,$key1
+ addi $key1,$key1,0x20
+ stvx v24,$x00,$key_ # off-load round[1]
+ ?vperm v25,v31,v30,$keyperm
+ lvx v31,$x00,$key1
+ stvx v25,$x10,$key_ # off-load round[2]
+ addi $key_,$key_,0x20
+ bdnz Load_xts_dec_key
+
+ lvx v26,$x10,$key1
+ ?vperm v24,v30,v31,$keyperm
+ lvx v27,$x20,$key1
+ stvx v24,$x00,$key_ # off-load round[3]
+ ?vperm v25,v31,v26,$keyperm
+ lvx v28,$x30,$key1
+ stvx v25,$x10,$key_ # off-load round[4]
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ ?vperm v26,v26,v27,$keyperm
+ lvx v29,$x40,$key1
+ ?vperm v27,v27,v28,$keyperm
+ lvx v30,$x50,$key1
+ ?vperm v28,v28,v29,$keyperm
+ lvx v31,$x60,$key1
+ ?vperm v29,v29,v30,$keyperm
+ lvx $twk5,$x70,$key1 # borrow $twk5
+ ?vperm v30,v30,v31,$keyperm
+ lvx v24,$x00,$key_ # pre-load round[1]
+ ?vperm v31,v31,$twk5,$keyperm
+ lvx v25,$x10,$key_ # pre-load round[2]
+
+ vperm $in0,$inout,$inptail,$inpperm
+ subi $inp,$inp,31 # undo "caller"
+ vxor $twk0,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ vand $tmp,$tmp,$eighty7
+ vxor $out0,$in0,$twk0
+ xxlor 32+$in1, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in1
+
+ lvx_u $in1,$x10,$inp
+ vxor $twk1,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ le?vperm $in1,$in1,$in1,$leperm
+ vand $tmp,$tmp,$eighty7
+ vxor $out1,$in1,$twk1
+ xxlor 32+$in2, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in2
+
+ lvx_u $in2,$x20,$inp
+ andi. $taillen,$len,15
+ vxor $twk2,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ le?vperm $in2,$in2,$in2,$leperm
+ vand $tmp,$tmp,$eighty7
+ vxor $out2,$in2,$twk2
+ xxlor 32+$in3, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in3
+
+ lvx_u $in3,$x30,$inp
+ sub $len,$len,$taillen
+ vxor $twk3,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ le?vperm $in3,$in3,$in3,$leperm
+ vand $tmp,$tmp,$eighty7
+ vxor $out3,$in3,$twk3
+ xxlor 32+$in4, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in4
+
+ lvx_u $in4,$x40,$inp
+ subi $len,$len,0x60
+ vxor $twk4,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ le?vperm $in4,$in4,$in4,$leperm
+ vand $tmp,$tmp,$eighty7
+ vxor $out4,$in4,$twk4
+ xxlor 32+$in5, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in5
+
+ lvx_u $in5,$x50,$inp
+ addi $inp,$inp,0x60
+ vxor $twk5,$tweak,$rndkey0
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vaddubm $tweak,$tweak,$tweak
+ le?vperm $in5,$in5,$in5,$leperm
+ vand $tmp,$tmp,$eighty7
+ vxor $out5,$in5,$twk5
+ xxlor 32+$in0, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in0
+
+ vxor v31,v31,$rndkey0
+ mtctr $rounds
+ b Loop_xts_dec6x
+
+.align 5
+Loop_xts_dec6x:
+ vncipher $out0,$out0,v24
+ vncipher $out1,$out1,v24
+ vncipher $out2,$out2,v24
+ vncipher $out3,$out3,v24
+ vncipher $out4,$out4,v24
+ vncipher $out5,$out5,v24
+ lvx v24,$x20,$key_ # round[3]
+ addi $key_,$key_,0x20
+
+ vncipher $out0,$out0,v25
+ vncipher $out1,$out1,v25
+ vncipher $out2,$out2,v25
+ vncipher $out3,$out3,v25
+ vncipher $out4,$out4,v25
+ vncipher $out5,$out5,v25
+ lvx v25,$x10,$key_ # round[4]
+ bdnz Loop_xts_dec6x
+
+ xxlor 32+$eighty7, 1, 1 # 0x010101..87
+
+ subic $len,$len,96 # $len-=96
+ vxor $in0,$twk0,v31 # xor with last round key
+ vncipher $out0,$out0,v24
+ vncipher $out1,$out1,v24
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk0,$tweak,$rndkey0
+ vaddubm $tweak,$tweak,$tweak
+ vncipher $out2,$out2,v24
+ vncipher $out3,$out3,v24
+ vncipher $out4,$out4,v24
+ vncipher $out5,$out5,v24
+
+ subfe. r0,r0,r0 # borrow?-1:0
+ vand $tmp,$tmp,$eighty7
+ vncipher $out0,$out0,v25
+ vncipher $out1,$out1,v25
+ xxlor 32+$in1, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in1
+ vncipher $out2,$out2,v25
+ vncipher $out3,$out3,v25
+ vxor $in1,$twk1,v31
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk1,$tweak,$rndkey0
+ vncipher $out4,$out4,v25
+ vncipher $out5,$out5,v25
+
+ and r0,r0,$len
+ vaddubm $tweak,$tweak,$tweak
+ vncipher $out0,$out0,v26
+ vncipher $out1,$out1,v26
+ vand $tmp,$tmp,$eighty7
+ vncipher $out2,$out2,v26
+ vncipher $out3,$out3,v26
+ xxlor 32+$in2, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in2
+ vncipher $out4,$out4,v26
+ vncipher $out5,$out5,v26
+
+ add $inp,$inp,r0 # $inp is adjusted in such
+ # way that at exit from the
+ # loop inX-in5 are loaded
+ # with last "words"
+ vxor $in2,$twk2,v31
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk2,$tweak,$rndkey0
+ vaddubm $tweak,$tweak,$tweak
+ vncipher $out0,$out0,v27
+ vncipher $out1,$out1,v27
+ vncipher $out2,$out2,v27
+ vncipher $out3,$out3,v27
+ vand $tmp,$tmp,$eighty7
+ vncipher $out4,$out4,v27
+ vncipher $out5,$out5,v27
+
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ xxlor 32+$in3, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in3
+ vncipher $out0,$out0,v28
+ vncipher $out1,$out1,v28
+ vxor $in3,$twk3,v31
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk3,$tweak,$rndkey0
+ vncipher $out2,$out2,v28
+ vncipher $out3,$out3,v28
+ vaddubm $tweak,$tweak,$tweak
+ vncipher $out4,$out4,v28
+ vncipher $out5,$out5,v28
+ lvx v24,$x00,$key_ # re-pre-load round[1]
+ vand $tmp,$tmp,$eighty7
+
+ vncipher $out0,$out0,v29
+ vncipher $out1,$out1,v29
+ xxlor 32+$in4, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in4
+ vncipher $out2,$out2,v29
+ vncipher $out3,$out3,v29
+ vxor $in4,$twk4,v31
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk4,$tweak,$rndkey0
+ vncipher $out4,$out4,v29
+ vncipher $out5,$out5,v29
+ lvx v25,$x10,$key_ # re-pre-load round[2]
+ vaddubm $tweak,$tweak,$tweak
+
+ vncipher $out0,$out0,v30
+ vncipher $out1,$out1,v30
+ vand $tmp,$tmp,$eighty7
+ vncipher $out2,$out2,v30
+ vncipher $out3,$out3,v30
+ xxlor 32+$in5, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in5
+ vncipher $out4,$out4,v30
+ vncipher $out5,$out5,v30
+ vxor $in5,$twk5,v31
+ vsrab $tmp,$tweak,$seven # next tweak value
+ vxor $twk5,$tweak,$rndkey0
+
+ vncipherlast $out0,$out0,$in0
+ lvx_u $in0,$x00,$inp # load next input block
+ vaddubm $tweak,$tweak,$tweak
+ vncipherlast $out1,$out1,$in1
+ lvx_u $in1,$x10,$inp
+ vncipherlast $out2,$out2,$in2
+ le?vperm $in0,$in0,$in0,$leperm
+ lvx_u $in2,$x20,$inp
+ vand $tmp,$tmp,$eighty7
+ vncipherlast $out3,$out3,$in3
+ le?vperm $in1,$in1,$in1,$leperm
+ lvx_u $in3,$x30,$inp
+ vncipherlast $out4,$out4,$in4
+ le?vperm $in2,$in2,$in2,$leperm
+ lvx_u $in4,$x40,$inp
+ xxlor 10, 32+$in0, 32+$in0
+ xxlor 32+$in0, 0, 0
+ vpermxor $tweak, $tweak, $tmp, $in0
+ xxlor 32+$in0, 10, 10
+ vncipherlast $out5,$out5,$in5
+ le?vperm $in3,$in3,$in3,$leperm
+ lvx_u $in5,$x50,$inp
+ addi $inp,$inp,0x60
+ le?vperm $in4,$in4,$in4,$leperm
+ le?vperm $in5,$in5,$in5,$leperm
+
+ le?vperm $out0,$out0,$out0,$leperm
+ le?vperm $out1,$out1,$out1,$leperm
+ stvx_u $out0,$x00,$out # store output
+ vxor $out0,$in0,$twk0
+ le?vperm $out2,$out2,$out2,$leperm
+ stvx_u $out1,$x10,$out
+ vxor $out1,$in1,$twk1
+ le?vperm $out3,$out3,$out3,$leperm
+ stvx_u $out2,$x20,$out
+ vxor $out2,$in2,$twk2
+ le?vperm $out4,$out4,$out4,$leperm
+ stvx_u $out3,$x30,$out
+ vxor $out3,$in3,$twk3
+ le?vperm $out5,$out5,$out5,$leperm
+ stvx_u $out4,$x40,$out
+ vxor $out4,$in4,$twk4
+ stvx_u $out5,$x50,$out
+ vxor $out5,$in5,$twk5
+ addi $out,$out,0x60
+
+ mtctr $rounds
+ beq Loop_xts_dec6x # did $len-=96 borrow?
+
+ xxlor 32+$eighty7, 2, 2 # 0x010101..87
+
+ addic. $len,$len,0x60
+ beq Lxts_dec6x_zero
+ cmpwi $len,0x20
+ blt Lxts_dec6x_one
+ nop
+ beq Lxts_dec6x_two
+ cmpwi $len,0x40
+ blt Lxts_dec6x_three
+ nop
+ beq Lxts_dec6x_four
+
+Lxts_dec6x_five:
+ vxor $out0,$in1,$twk0
+ vxor $out1,$in2,$twk1
+ vxor $out2,$in3,$twk2
+ vxor $out3,$in4,$twk3
+ vxor $out4,$in5,$twk4
+
+ bl _aesp8_xts_dec5x
+
+ le?vperm $out0,$out0,$out0,$leperm
+ vmr $twk0,$twk5 # unused tweak
+ vxor $twk1,$tweak,$rndkey0
+ le?vperm $out1,$out1,$out1,$leperm
+ stvx_u $out0,$x00,$out # store output
+ vxor $out0,$in0,$twk1
+ le?vperm $out2,$out2,$out2,$leperm
+ stvx_u $out1,$x10,$out
+ le?vperm $out3,$out3,$out3,$leperm
+ stvx_u $out2,$x20,$out
+ le?vperm $out4,$out4,$out4,$leperm
+ stvx_u $out3,$x30,$out
+ stvx_u $out4,$x40,$out
+ addi $out,$out,0x50
+ bne Lxts_dec6x_steal
+ b Lxts_dec6x_done
+
+.align 4
+Lxts_dec6x_four:
+ vxor $out0,$in2,$twk0
+ vxor $out1,$in3,$twk1
+ vxor $out2,$in4,$twk2
+ vxor $out3,$in5,$twk3
+ vxor $out4,$out4,$out4
+
+ bl _aesp8_xts_dec5x
+
+ le?vperm $out0,$out0,$out0,$leperm
+ vmr $twk0,$twk4 # unused tweak
+ vmr $twk1,$twk5
+ le?vperm $out1,$out1,$out1,$leperm
+ stvx_u $out0,$x00,$out # store output
+ vxor $out0,$in0,$twk5
+ le?vperm $out2,$out2,$out2,$leperm
+ stvx_u $out1,$x10,$out
+ le?vperm $out3,$out3,$out3,$leperm
+ stvx_u $out2,$x20,$out
+ stvx_u $out3,$x30,$out
+ addi $out,$out,0x40
+ bne Lxts_dec6x_steal
+ b Lxts_dec6x_done
+
+.align 4
+Lxts_dec6x_three:
+ vxor $out0,$in3,$twk0
+ vxor $out1,$in4,$twk1
+ vxor $out2,$in5,$twk2
+ vxor $out3,$out3,$out3
+ vxor $out4,$out4,$out4
+
+ bl _aesp8_xts_dec5x
+
+ le?vperm $out0,$out0,$out0,$leperm
+ vmr $twk0,$twk3 # unused tweak
+ vmr $twk1,$twk4
+ le?vperm $out1,$out1,$out1,$leperm
+ stvx_u $out0,$x00,$out # store output
+ vxor $out0,$in0,$twk4
+ le?vperm $out2,$out2,$out2,$leperm
+ stvx_u $out1,$x10,$out
+ stvx_u $out2,$x20,$out
+ addi $out,$out,0x30
+ bne Lxts_dec6x_steal
+ b Lxts_dec6x_done
+
+.align 4
+Lxts_dec6x_two:
+ vxor $out0,$in4,$twk0
+ vxor $out1,$in5,$twk1
+ vxor $out2,$out2,$out2
+ vxor $out3,$out3,$out3
+ vxor $out4,$out4,$out4
+
+ bl _aesp8_xts_dec5x
+
+ le?vperm $out0,$out0,$out0,$leperm
+ vmr $twk0,$twk2 # unused tweak
+ vmr $twk1,$twk3
+ le?vperm $out1,$out1,$out1,$leperm
+ stvx_u $out0,$x00,$out # store output
+ vxor $out0,$in0,$twk3
+ stvx_u $out1,$x10,$out
+ addi $out,$out,0x20
+ bne Lxts_dec6x_steal
+ b Lxts_dec6x_done
+
+.align 4
+Lxts_dec6x_one:
+ vxor $out0,$in5,$twk0
+ nop
+Loop_xts_dec1x:
+ vncipher $out0,$out0,v24
+ lvx v24,$x20,$key_ # round[3]
+ addi $key_,$key_,0x20
+
+ vncipher $out0,$out0,v25
+ lvx v25,$x10,$key_ # round[4]
+ bdnz Loop_xts_dec1x
+
+ subi r0,$taillen,1
+ vncipher $out0,$out0,v24
+
+ andi. r0,r0,16
+ cmpwi $taillen,0
+ vncipher $out0,$out0,v25
+
+ sub $inp,$inp,r0
+ vncipher $out0,$out0,v26
+
+ lvx_u $in0,0,$inp
+ vncipher $out0,$out0,v27
+
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ vncipher $out0,$out0,v28
+ lvx v24,$x00,$key_ # re-pre-load round[1]
+
+ vncipher $out0,$out0,v29
+ lvx v25,$x10,$key_ # re-pre-load round[2]
+ vxor $twk0,$twk0,v31
+
+ le?vperm $in0,$in0,$in0,$leperm
+ vncipher $out0,$out0,v30
+
+ mtctr $rounds
+ vncipherlast $out0,$out0,$twk0
+
+ vmr $twk0,$twk1 # unused tweak
+ vmr $twk1,$twk2
+ le?vperm $out0,$out0,$out0,$leperm
+ stvx_u $out0,$x00,$out # store output
+ addi $out,$out,0x10
+ vxor $out0,$in0,$twk2
+ bne Lxts_dec6x_steal
+ b Lxts_dec6x_done
+
+.align 4
+Lxts_dec6x_zero:
+ cmpwi $taillen,0
+ beq Lxts_dec6x_done
+
+ lvx_u $in0,0,$inp
+ le?vperm $in0,$in0,$in0,$leperm
+ vxor $out0,$in0,$twk1
+Lxts_dec6x_steal:
+ vncipher $out0,$out0,v24
+ lvx v24,$x20,$key_ # round[3]
+ addi $key_,$key_,0x20
+
+ vncipher $out0,$out0,v25
+ lvx v25,$x10,$key_ # round[4]
+ bdnz Lxts_dec6x_steal
+
+ add $inp,$inp,$taillen
+ vncipher $out0,$out0,v24
+
+ cmpwi $taillen,0
+ vncipher $out0,$out0,v25
+
+ lvx_u $in0,0,$inp
+ vncipher $out0,$out0,v26
+
+ lvsr $inpperm,0,$taillen # $in5 is no more
+ vncipher $out0,$out0,v27
+
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ vncipher $out0,$out0,v28
+ lvx v24,$x00,$key_ # re-pre-load round[1]
+
+ vncipher $out0,$out0,v29
+ lvx v25,$x10,$key_ # re-pre-load round[2]
+ vxor $twk1,$twk1,v31
+
+ le?vperm $in0,$in0,$in0,$leperm
+ vncipher $out0,$out0,v30
+
+ vperm $in0,$in0,$in0,$inpperm
+ vncipherlast $tmp,$out0,$twk1
+
+ le?vperm $out0,$tmp,$tmp,$leperm
+ le?stvx_u $out0,0,$out
+ be?stvx_u $tmp,0,$out
+
+ vxor $out0,$out0,$out0
+ vspltisb $out1,-1
+ vperm $out0,$out0,$out1,$inpperm
+ vsel $out0,$in0,$tmp,$out0
+ vxor $out0,$out0,$twk0
+
+ subi r30,$out,1
+ mtctr $taillen
+Loop_xts_dec6x_steal:
+ lbzu r0,1(r30)
+ stb r0,16(r30)
+ bdnz Loop_xts_dec6x_steal
+
+ li $taillen,0
+ mtctr $rounds
+ b Loop_xts_dec1x # one more time...
+
+.align 4
+Lxts_dec6x_done:
+ ${UCMP}i $ivp,0
+ beq Lxts_dec6x_ret
+
+ vxor $tweak,$twk0,$rndkey0
+ le?vperm $tweak,$tweak,$tweak,$leperm
+ stvx_u $tweak,0,$ivp
+
+Lxts_dec6x_ret:
+ mtlr r11
+ li r10,`$FRAME+15`
+ li r11,`$FRAME+31`
+ stvx $seven,r10,$sp # wipe copies of round keys
+ addi r10,r10,32
+ stvx $seven,r11,$sp
+ addi r11,r11,32
+ stvx $seven,r10,$sp
+ addi r10,r10,32
+ stvx $seven,r11,$sp
+ addi r11,r11,32
+ stvx $seven,r10,$sp
+ addi r10,r10,32
+ stvx $seven,r11,$sp
+ addi r11,r11,32
+ stvx $seven,r10,$sp
+ addi r10,r10,32
+ stvx $seven,r11,$sp
+ addi r11,r11,32
+
+ mtspr 256,$vrsave
+ lvx v20,r10,$sp # ABI says so
+ addi r10,r10,32
+ lvx v21,r11,$sp
+ addi r11,r11,32
+ lvx v22,r10,$sp
+ addi r10,r10,32
+ lvx v23,r11,$sp
+ addi r11,r11,32
+ lvx v24,r10,$sp
+ addi r10,r10,32
+ lvx v25,r11,$sp
+ addi r11,r11,32
+ lvx v26,r10,$sp
+ addi r10,r10,32
+ lvx v27,r11,$sp
+ addi r11,r11,32
+ lvx v28,r10,$sp
+ addi r10,r10,32
+ lvx v29,r11,$sp
+ addi r11,r11,32
+ lvx v30,r10,$sp
+ lvx v31,r11,$sp
+ $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp)
+ $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp)
+ $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp)
+ $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp)
+ $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp)
+ $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp)
+ addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T`
+ blr
+ .long 0
+ .byte 0,12,0x04,1,0x80,6,6,0
+ .long 0
+
+.align 5
+_aesp8_xts_dec5x:
+ vncipher $out0,$out0,v24
+ vncipher $out1,$out1,v24
+ vncipher $out2,$out2,v24
+ vncipher $out3,$out3,v24
+ vncipher $out4,$out4,v24
+ lvx v24,$x20,$key_ # round[3]
+ addi $key_,$key_,0x20
+
+ vncipher $out0,$out0,v25
+ vncipher $out1,$out1,v25
+ vncipher $out2,$out2,v25
+ vncipher $out3,$out3,v25
+ vncipher $out4,$out4,v25
+ lvx v25,$x10,$key_ # round[4]
+ bdnz _aesp8_xts_dec5x
+
+ subi r0,$taillen,1
+ vncipher $out0,$out0,v24
+ vncipher $out1,$out1,v24
+ vncipher $out2,$out2,v24
+ vncipher $out3,$out3,v24
+ vncipher $out4,$out4,v24
+
+ andi. r0,r0,16
+ cmpwi $taillen,0
+ vncipher $out0,$out0,v25
+ vncipher $out1,$out1,v25
+ vncipher $out2,$out2,v25
+ vncipher $out3,$out3,v25
+ vncipher $out4,$out4,v25
+ vxor $twk0,$twk0,v31
+
+ sub $inp,$inp,r0
+ vncipher $out0,$out0,v26
+ vncipher $out1,$out1,v26
+ vncipher $out2,$out2,v26
+ vncipher $out3,$out3,v26
+ vncipher $out4,$out4,v26
+ vxor $in1,$twk1,v31
+
+ vncipher $out0,$out0,v27
+ lvx_u $in0,0,$inp
+ vncipher $out1,$out1,v27
+ vncipher $out2,$out2,v27
+ vncipher $out3,$out3,v27
+ vncipher $out4,$out4,v27
+ vxor $in2,$twk2,v31
+
+ addi $key_,$sp,$FRAME+15 # rewind $key_
+ vncipher $out0,$out0,v28
+ vncipher $out1,$out1,v28
+ vncipher $out2,$out2,v28
+ vncipher $out3,$out3,v28
+ vncipher $out4,$out4,v28
+ lvx v24,$x00,$key_ # re-pre-load round[1]
+ vxor $in3,$twk3,v31
+
+ vncipher $out0,$out0,v29
+ le?vperm $in0,$in0,$in0,$leperm
+ vncipher $out1,$out1,v29
+ vncipher $out2,$out2,v29
+ vncipher $out3,$out3,v29
+ vncipher $out4,$out4,v29
+ lvx v25,$x10,$key_ # re-pre-load round[2]
+ vxor $in4,$twk4,v31
+
+ vncipher $out0,$out0,v30
+ vncipher $out1,$out1,v30
+ vncipher $out2,$out2,v30
+ vncipher $out3,$out3,v30
+ vncipher $out4,$out4,v30
+
+ vncipherlast $out0,$out0,$twk0
+ vncipherlast $out1,$out1,$in1
+ vncipherlast $out2,$out2,$in2
+ vncipherlast $out3,$out3,$in3
+ vncipherlast $out4,$out4,$in4
+ mtctr $rounds
+ blr
+ .long 0
+ .byte 0,12,0x14,0,0,0,0,0
+___
+}} }}}
+
+my $consts=1;
+foreach(split("\n",$code)) {
+ s/\`([^\`]*)\`/eval($1)/geo;
+
+ # constants table endian-specific conversion
+ if ($consts && m/\.(long|byte)\s+(.+)\s+(\?[a-z]*)$/o) {
+ my $conv=$3;
+ my @bytes=();
+
+ # convert to endian-agnostic format
+ if ($1 eq "long") {
+ foreach (split(/,\s*/,$2)) {
+ my $l = /^0/?oct:int;
+ push @bytes,($l>>24)&0xff,($l>>16)&0xff,($l>>8)&0xff,$l&0xff;
+ }
+ } else {
+ @bytes = map(/^0/?oct:int,split(/,\s*/,$2));
+ }
+
+ # little-endian conversion
+ if ($flavour =~ /le$/o) {
+ SWITCH: for($conv) {
+ /\?inv/ && do { @bytes=map($_^0xf,@bytes); last; };
+ /\?rev/ && do { @bytes=reverse(@bytes); last; };
+ }
+ }
+
+ #emit
+ print ".byte\t",join(',',map (sprintf("0x%02x",$_),@bytes)),"\n";
+ next;
+ }
+ $consts=0 if (m/Lconsts:/o); # end of table
+
+ # instructions prefixed with '?' are endian-specific and need
+ # to be adjusted accordingly...
+ if ($flavour =~ /le$/o) { # little-endian
+ s/le\?//o or
+ s/be\?/#be#/o or
+ s/\?lvsr/lvsl/o or
+ s/\?lvsl/lvsr/o or
+ s/\?(vperm\s+v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+)/$1$3$2$4/o or
+ s/\?(vsldoi\s+v[0-9]+,\s*)(v[0-9]+,)\s*(v[0-9]+,\s*)([0-9]+)/$1$3$2 16-$4/o or
+ s/\?(vspltw\s+v[0-9]+,\s*)(v[0-9]+,)\s*([0-9])/$1$2 3-$3/o;
+ } else { # big-endian
+ s/le\?/#le#/o or
+ s/be\?//o or
+ s/\?([a-z]+)/$1/o;
+ }
+
+ print $_,"\n";
+}
+
+close STDOUT;
diff --git a/lib/crypto/riscv/aes-riscv64-zvkned.S b/lib/crypto/riscv/aes-riscv64-zvkned.S
new file mode 100644
index 000000000000..0d988bc3d37b
--- /dev/null
+++ b/lib/crypto/riscv/aes-riscv64-zvkned.S
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu>
+// Copyright (c) 2023, Phoebe Chen <phoebe.chen@sifive.com>
+// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The generated code of this file depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128
+// - RISC-V Vector AES block cipher extension ('Zvkned')
+
+#include <linux/linkage.h>
+
+.text
+.option arch, +zvkned
+
+#include "../../arch/riscv/crypto/aes-macros.S"
+
+#define RNDKEYS a0
+#define KEY_LEN a1
+#define OUTP a2
+#define INP a3
+
+.macro __aes_crypt_zvkned enc, keybits
+ vle32.v v16, (INP)
+ aes_crypt v16, \enc, \keybits
+ vse32.v v16, (OUTP)
+ ret
+.endm
+
+.macro aes_crypt_zvkned enc
+ aes_begin RNDKEYS, 128f, 192f, KEY_LEN
+ __aes_crypt_zvkned \enc, 256
+128:
+ __aes_crypt_zvkned \enc, 128
+192:
+ __aes_crypt_zvkned \enc, 192
+.endm
+
+// void aes_encrypt_zvkned(const u32 rndkeys[], int key_len,
+// u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]);
+SYM_FUNC_START(aes_encrypt_zvkned)
+ aes_crypt_zvkned 1
+SYM_FUNC_END(aes_encrypt_zvkned)
+
+// void aes_decrypt_zvkned(const u32 rndkeys[], int key_len,
+// u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]);
+SYM_FUNC_START(aes_decrypt_zvkned)
+ aes_crypt_zvkned 0
+SYM_FUNC_END(aes_decrypt_zvkned)
diff --git a/lib/crypto/riscv/aes.h b/lib/crypto/riscv/aes.h
new file mode 100644
index 000000000000..0b26f58faf2b
--- /dev/null
+++ b/lib/crypto/riscv/aes.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023 VRULL GmbH
+ * Copyright (C) 2023 SiFive, Inc.
+ * Copyright 2024 Google LLC
+ */
+
+#include <asm/simd.h>
+#include <asm/vector.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_zvkned);
+
+void aes_encrypt_zvkned(const u32 rndkeys[], int key_len,
+ u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]);
+void aes_decrypt_zvkned(const u32 rndkeys[], int key_len,
+ u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]);
+
+static void aes_preparekey_arch(union aes_enckey_arch *k,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, int key_len, int nrounds)
+{
+ aes_expandkey_generic(k->rndkeys, inv_k ? inv_k->inv_rndkeys : NULL,
+ in_key, key_len);
+}
+
+static void aes_encrypt_arch(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (static_branch_likely(&have_zvkned) && likely(may_use_simd())) {
+ kernel_vector_begin();
+ aes_encrypt_zvkned(key->k.rndkeys, key->len, out, in);
+ kernel_vector_end();
+ } else {
+ aes_encrypt_generic(key->k.rndkeys, key->nrounds, out, in);
+ }
+}
+
+static void aes_decrypt_arch(const struct aes_key *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ /*
+ * Note that the Zvkned code uses the standard round keys, while the
+ * fallback uses the inverse round keys. Thus both must be present.
+ */
+ if (static_branch_likely(&have_zvkned) && likely(may_use_simd())) {
+ kernel_vector_begin();
+ aes_decrypt_zvkned(key->k.rndkeys, key->len, out, in);
+ kernel_vector_end();
+ } else {
+ aes_decrypt_generic(key->inv_k.inv_rndkeys, key->nrounds,
+ out, in);
+ }
+}
+
+#define aes_mod_init_arch aes_mod_init_arch
+static void aes_mod_init_arch(void)
+{
+ if (riscv_isa_extension_available(NULL, ZVKNED) &&
+ riscv_vector_vlen() >= 128)
+ static_branch_enable(&have_zvkned);
+}
diff --git a/lib/crypto/s390/aes.h b/lib/crypto/s390/aes.h
new file mode 100644
index 000000000000..5466f6ecbce7
--- /dev/null
+++ b/lib/crypto/s390/aes.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AES optimized using the CP Assist for Cryptographic Functions (CPACF)
+ *
+ * Copyright 2026 Google LLC
+ */
+#include <asm/cpacf.h>
+#include <linux/cpufeature.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_cpacf_aes128);
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_cpacf_aes192);
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_cpacf_aes256);
+
+/*
+ * When the CPU supports CPACF AES for the requested key length, we need only
+ * save a copy of the raw AES key, as that's what the CPACF instructions need.
+ *
+ * When unsupported, fall back to the generic key expansion and en/decryption.
+ */
+static void aes_preparekey_arch(union aes_enckey_arch *k,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, int key_len, int nrounds)
+{
+ if (key_len == AES_KEYSIZE_128) {
+ if (static_branch_likely(&have_cpacf_aes128)) {
+ memcpy(k->raw_key, in_key, AES_KEYSIZE_128);
+ return;
+ }
+ } else if (key_len == AES_KEYSIZE_192) {
+ if (static_branch_likely(&have_cpacf_aes192)) {
+ memcpy(k->raw_key, in_key, AES_KEYSIZE_192);
+ return;
+ }
+ } else {
+ if (static_branch_likely(&have_cpacf_aes256)) {
+ memcpy(k->raw_key, in_key, AES_KEYSIZE_256);
+ return;
+ }
+ }
+ aes_expandkey_generic(k->rndkeys, inv_k ? inv_k->inv_rndkeys : NULL,
+ in_key, key_len);
+}
+
+static inline bool aes_crypt_s390(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE], int decrypt)
+{
+ if (key->len == AES_KEYSIZE_128) {
+ if (static_branch_likely(&have_cpacf_aes128)) {
+ cpacf_km(CPACF_KM_AES_128 | decrypt,
+ (void *)key->k.raw_key, out, in,
+ AES_BLOCK_SIZE);
+ return true;
+ }
+ } else if (key->len == AES_KEYSIZE_192) {
+ if (static_branch_likely(&have_cpacf_aes192)) {
+ cpacf_km(CPACF_KM_AES_192 | decrypt,
+ (void *)key->k.raw_key, out, in,
+ AES_BLOCK_SIZE);
+ return true;
+ }
+ } else {
+ if (static_branch_likely(&have_cpacf_aes256)) {
+ cpacf_km(CPACF_KM_AES_256 | decrypt,
+ (void *)key->k.raw_key, out, in,
+ AES_BLOCK_SIZE);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void aes_encrypt_arch(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (likely(aes_crypt_s390(key, out, in, 0)))
+ return;
+ aes_encrypt_generic(key->k.rndkeys, key->nrounds, out, in);
+}
+
+static void aes_decrypt_arch(const struct aes_key *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (likely(aes_crypt_s390((const struct aes_enckey *)key, out, in,
+ CPACF_DECRYPT)))
+ return;
+ aes_decrypt_generic(key->inv_k.inv_rndkeys, key->nrounds, out, in);
+}
+
+#define aes_mod_init_arch aes_mod_init_arch
+static void aes_mod_init_arch(void)
+{
+ if (cpu_have_feature(S390_CPU_FEATURE_MSA)) {
+ cpacf_mask_t km_functions;
+
+ cpacf_query(CPACF_KM, &km_functions);
+ if (cpacf_test_func(&km_functions, CPACF_KM_AES_128))
+ static_branch_enable(&have_cpacf_aes128);
+ if (cpacf_test_func(&km_functions, CPACF_KM_AES_192))
+ static_branch_enable(&have_cpacf_aes192);
+ if (cpacf_test_func(&km_functions, CPACF_KM_AES_256))
+ static_branch_enable(&have_cpacf_aes256);
+ }
+}
diff --git a/lib/crypto/sha1.c b/lib/crypto/sha1.c
index 52788278cd17..daf18c862fdf 100644
--- a/lib/crypto/sha1.c
+++ b/lib/crypto/sha1.c
@@ -49,7 +49,7 @@ static const struct sha1_block_state sha1_iv = {
#endif
/* This "rolls" over the 512-bit array */
-#define W(x) (array[(x)&15])
+#define W(x) (workspace[(x)&15])
/*
* Where do we get the source from? The first 16 iterations get it from
@@ -70,34 +70,20 @@ static const struct sha1_block_state sha1_iv = {
#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )
#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E )
-/**
- * sha1_transform - single block SHA1 transform (deprecated)
- *
- * @digest: 160 bit digest to update
- * @data: 512 bits of data to hash
- * @array: 16 words of workspace (see note)
- *
- * This function executes SHA-1's internal compression function. It updates the
- * 160-bit internal state (@digest) with a single 512-bit data block (@data).
- *
- * Don't use this function. SHA-1 is no longer considered secure. And even if
- * you do have to use SHA-1, this isn't the correct way to hash something with
- * SHA-1 as this doesn't handle padding and finalization.
- *
- * Note: If the hash is security sensitive, the caller should be sure
- * to clear the workspace. This is left to the caller to avoid
- * unnecessary clears between chained hashing operations.
- */
-void sha1_transform(__u32 *digest, const char *data, __u32 *array)
+#define SHA1_WORKSPACE_WORDS 16
+
+static void sha1_block_generic(struct sha1_block_state *state,
+ const u8 data[SHA1_BLOCK_SIZE],
+ u32 workspace[SHA1_WORKSPACE_WORDS])
{
__u32 A, B, C, D, E;
unsigned int i = 0;
- A = digest[0];
- B = digest[1];
- C = digest[2];
- D = digest[3];
- E = digest[4];
+ A = state->h[0];
+ B = state->h[1];
+ C = state->h[2];
+ D = state->h[3];
+ E = state->h[4];
/* Round 1 - iterations 0-16 take their input from 'data' */
for (; i < 16; ++i)
@@ -119,27 +105,12 @@ void sha1_transform(__u32 *digest, const char *data, __u32 *array)
for (; i < 80; ++i)
T_60_79(i, A, B, C, D, E);
- digest[0] += A;
- digest[1] += B;
- digest[2] += C;
- digest[3] += D;
- digest[4] += E;
-}
-EXPORT_SYMBOL(sha1_transform);
-
-/**
- * sha1_init_raw - initialize the vectors for a SHA1 digest
- * @buf: vector to initialize
- */
-void sha1_init_raw(__u32 *buf)
-{
- buf[0] = 0x67452301;
- buf[1] = 0xefcdab89;
- buf[2] = 0x98badcfe;
- buf[3] = 0x10325476;
- buf[4] = 0xc3d2e1f0;
+ state->h[0] += A;
+ state->h[1] += B;
+ state->h[2] += C;
+ state->h[3] += D;
+ state->h[4] += E;
}
-EXPORT_SYMBOL(sha1_init_raw);
static void __maybe_unused sha1_blocks_generic(struct sha1_block_state *state,
const u8 *data, size_t nblocks)
@@ -147,7 +118,7 @@ static void __maybe_unused sha1_blocks_generic(struct sha1_block_state *state,
u32 workspace[SHA1_WORKSPACE_WORDS];
do {
- sha1_transform(state->h, data, workspace);
+ sha1_block_generic(state, data, workspace);
data += SHA1_BLOCK_SIZE;
} while (--nblocks);
diff --git a/lib/crypto/sparc/aes.h b/lib/crypto/sparc/aes.h
new file mode 100644
index 000000000000..e354aa507ee0
--- /dev/null
+++ b/lib/crypto/sparc/aes.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * AES accelerated using the sparc64 aes opcodes
+ *
+ * Copyright (C) 2008, Intel Corp.
+ * Copyright (c) 2010, Intel Corporation.
+ * Copyright 2026 Google LLC
+ */
+
+#include <asm/fpumacro.h>
+#include <asm/opcodes.h>
+#include <asm/pstate.h>
+#include <asm/elf.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_aes_opcodes);
+
+EXPORT_SYMBOL_GPL(aes_sparc64_key_expand);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_encrypt_keys_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_encrypt_keys_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_encrypt_keys_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_decrypt_keys_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_decrypt_keys_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_load_decrypt_keys_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_encrypt_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_encrypt_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_encrypt_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_decrypt_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_decrypt_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_ecb_decrypt_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_encrypt_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_encrypt_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_encrypt_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_decrypt_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_decrypt_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_cbc_decrypt_256);
+EXPORT_SYMBOL_GPL(aes_sparc64_ctr_crypt_128);
+EXPORT_SYMBOL_GPL(aes_sparc64_ctr_crypt_192);
+EXPORT_SYMBOL_GPL(aes_sparc64_ctr_crypt_256);
+
+void aes_sparc64_encrypt_128(const u64 *key, const u32 *input, u32 *output);
+void aes_sparc64_encrypt_192(const u64 *key, const u32 *input, u32 *output);
+void aes_sparc64_encrypt_256(const u64 *key, const u32 *input, u32 *output);
+void aes_sparc64_decrypt_128(const u64 *key, const u32 *input, u32 *output);
+void aes_sparc64_decrypt_192(const u64 *key, const u32 *input, u32 *output);
+void aes_sparc64_decrypt_256(const u64 *key, const u32 *input, u32 *output);
+
+static void aes_preparekey_arch(union aes_enckey_arch *k,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, int key_len, int nrounds)
+{
+ if (static_branch_likely(&have_aes_opcodes)) {
+ u32 aligned_key[AES_MAX_KEY_SIZE / 4];
+
+ if (IS_ALIGNED((uintptr_t)in_key, 4)) {
+ aes_sparc64_key_expand((const u32 *)in_key,
+ k->sparc_rndkeys, key_len);
+ } else {
+ memcpy(aligned_key, in_key, key_len);
+ aes_sparc64_key_expand(aligned_key,
+ k->sparc_rndkeys, key_len);
+ memzero_explicit(aligned_key, key_len);
+ }
+ /*
+ * Note that nothing needs to be written to inv_k (if it's
+ * non-NULL) here, since the SPARC64 assembly code uses
+ * k->sparc_rndkeys for both encryption and decryption.
+ */
+ } else {
+ aes_expandkey_generic(k->rndkeys,
+ inv_k ? inv_k->inv_rndkeys : NULL,
+ in_key, key_len);
+ }
+}
+
+static void aes_sparc64_encrypt(const struct aes_enckey *key,
+ const u32 *input, u32 *output)
+{
+ if (key->len == AES_KEYSIZE_128)
+ aes_sparc64_encrypt_128(key->k.sparc_rndkeys, input, output);
+ else if (key->len == AES_KEYSIZE_192)
+ aes_sparc64_encrypt_192(key->k.sparc_rndkeys, input, output);
+ else
+ aes_sparc64_encrypt_256(key->k.sparc_rndkeys, input, output);
+}
+
+static void aes_encrypt_arch(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ u32 bounce_buf[AES_BLOCK_SIZE / 4];
+
+ if (static_branch_likely(&have_aes_opcodes)) {
+ if (IS_ALIGNED((uintptr_t)in | (uintptr_t)out, 4)) {
+ aes_sparc64_encrypt(key, (const u32 *)in, (u32 *)out);
+ } else {
+ memcpy(bounce_buf, in, AES_BLOCK_SIZE);
+ aes_sparc64_encrypt(key, bounce_buf, bounce_buf);
+ memcpy(out, bounce_buf, AES_BLOCK_SIZE);
+ }
+ } else {
+ aes_encrypt_generic(key->k.rndkeys, key->nrounds, out, in);
+ }
+}
+
+static void aes_sparc64_decrypt(const struct aes_key *key,
+ const u32 *input, u32 *output)
+{
+ if (key->len == AES_KEYSIZE_128)
+ aes_sparc64_decrypt_128(key->k.sparc_rndkeys, input, output);
+ else if (key->len == AES_KEYSIZE_192)
+ aes_sparc64_decrypt_192(key->k.sparc_rndkeys, input, output);
+ else
+ aes_sparc64_decrypt_256(key->k.sparc_rndkeys, input, output);
+}
+
+static void aes_decrypt_arch(const struct aes_key *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ u32 bounce_buf[AES_BLOCK_SIZE / 4];
+
+ if (static_branch_likely(&have_aes_opcodes)) {
+ if (IS_ALIGNED((uintptr_t)in | (uintptr_t)out, 4)) {
+ aes_sparc64_decrypt(key, (const u32 *)in, (u32 *)out);
+ } else {
+ memcpy(bounce_buf, in, AES_BLOCK_SIZE);
+ aes_sparc64_decrypt(key, bounce_buf, bounce_buf);
+ memcpy(out, bounce_buf, AES_BLOCK_SIZE);
+ }
+ } else {
+ aes_decrypt_generic(key->inv_k.inv_rndkeys, key->nrounds,
+ out, in);
+ }
+}
+
+#define aes_mod_init_arch aes_mod_init_arch
+static void aes_mod_init_arch(void)
+{
+ unsigned long cfr;
+
+ if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
+ return;
+
+ __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
+ if (!(cfr & CFR_AES))
+ return;
+
+ static_branch_enable(&have_aes_opcodes);
+}
diff --git a/lib/crypto/sparc/aes_asm.S b/lib/crypto/sparc/aes_asm.S
new file mode 100644
index 000000000000..f291174a72a1
--- /dev/null
+++ b/lib/crypto/sparc/aes_asm.S
@@ -0,0 +1,1543 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/linkage.h>
+#include <asm/opcodes.h>
+#include <asm/visasm.h>
+
+#define ENCRYPT_TWO_ROUNDS(KEY_BASE, I0, I1, T0, T1) \
+ AES_EROUND01(KEY_BASE + 0, I0, I1, T0) \
+ AES_EROUND23(KEY_BASE + 2, I0, I1, T1) \
+ AES_EROUND01(KEY_BASE + 4, T0, T1, I0) \
+ AES_EROUND23(KEY_BASE + 6, T0, T1, I1)
+
+#define ENCRYPT_TWO_ROUNDS_2(KEY_BASE, I0, I1, I2, I3, T0, T1, T2, T3) \
+ AES_EROUND01(KEY_BASE + 0, I0, I1, T0) \
+ AES_EROUND23(KEY_BASE + 2, I0, I1, T1) \
+ AES_EROUND01(KEY_BASE + 0, I2, I3, T2) \
+ AES_EROUND23(KEY_BASE + 2, I2, I3, T3) \
+ AES_EROUND01(KEY_BASE + 4, T0, T1, I0) \
+ AES_EROUND23(KEY_BASE + 6, T0, T1, I1) \
+ AES_EROUND01(KEY_BASE + 4, T2, T3, I2) \
+ AES_EROUND23(KEY_BASE + 6, T2, T3, I3)
+
+#define ENCRYPT_TWO_ROUNDS_LAST(KEY_BASE, I0, I1, T0, T1) \
+ AES_EROUND01(KEY_BASE + 0, I0, I1, T0) \
+ AES_EROUND23(KEY_BASE + 2, I0, I1, T1) \
+ AES_EROUND01_L(KEY_BASE + 4, T0, T1, I0) \
+ AES_EROUND23_L(KEY_BASE + 6, T0, T1, I1)
+
+#define ENCRYPT_TWO_ROUNDS_LAST_2(KEY_BASE, I0, I1, I2, I3, T0, T1, T2, T3) \
+ AES_EROUND01(KEY_BASE + 0, I0, I1, T0) \
+ AES_EROUND23(KEY_BASE + 2, I0, I1, T1) \
+ AES_EROUND01(KEY_BASE + 0, I2, I3, T2) \
+ AES_EROUND23(KEY_BASE + 2, I2, I3, T3) \
+ AES_EROUND01_L(KEY_BASE + 4, T0, T1, I0) \
+ AES_EROUND23_L(KEY_BASE + 6, T0, T1, I1) \
+ AES_EROUND01_L(KEY_BASE + 4, T2, T3, I2) \
+ AES_EROUND23_L(KEY_BASE + 6, T2, T3, I3)
+
+ /* 10 rounds */
+#define ENCRYPT_128(KEY_BASE, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 0, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 8, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 16, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 24, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS_LAST(KEY_BASE + 32, I0, I1, T0, T1)
+
+#define ENCRYPT_128_2(KEY_BASE, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_2(KEY_BASE + 0, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_2(KEY_BASE + 8, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_2(KEY_BASE + 16, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_2(KEY_BASE + 24, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_LAST_2(KEY_BASE + 32, I0, I1, I2, I3, T0, T1, T2, T3)
+
+ /* 12 rounds */
+#define ENCRYPT_192(KEY_BASE, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 0, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 8, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 16, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 24, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 32, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS_LAST(KEY_BASE + 40, I0, I1, T0, T1)
+
+#define ENCRYPT_192_2(KEY_BASE, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_2(KEY_BASE + 0, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_2(KEY_BASE + 8, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_2(KEY_BASE + 16, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_2(KEY_BASE + 24, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_2(KEY_BASE + 32, I0, I1, I2, I3, T0, T1, T2, T3) \
+ ENCRYPT_TWO_ROUNDS_LAST_2(KEY_BASE + 40, I0, I1, I2, I3, T0, T1, T2, T3)
+
+ /* 14 rounds */
+#define ENCRYPT_256(KEY_BASE, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 0, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 8, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 16, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 24, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 32, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS(KEY_BASE + 40, I0, I1, T0, T1) \
+ ENCRYPT_TWO_ROUNDS_LAST(KEY_BASE + 48, I0, I1, T0, T1)
+
+#define ENCRYPT_256_TWO_ROUNDS_2(KEY_BASE, I0, I1, I2, I3, TMP_BASE) \
+ ENCRYPT_TWO_ROUNDS_2(KEY_BASE, I0, I1, I2, I3, \
+ TMP_BASE + 0, TMP_BASE + 2, TMP_BASE + 4, TMP_BASE + 6)
+
+#define ENCRYPT_256_2(KEY_BASE, I0, I1, I2, I3) \
+ ENCRYPT_256_TWO_ROUNDS_2(KEY_BASE + 0, I0, I1, I2, I3, KEY_BASE + 48) \
+ ldd [%o0 + 0xd0], %f56; \
+ ldd [%o0 + 0xd8], %f58; \
+ ENCRYPT_256_TWO_ROUNDS_2(KEY_BASE + 8, I0, I1, I2, I3, KEY_BASE + 0) \
+ ldd [%o0 + 0xe0], %f60; \
+ ldd [%o0 + 0xe8], %f62; \
+ ENCRYPT_256_TWO_ROUNDS_2(KEY_BASE + 16, I0, I1, I2, I3, KEY_BASE + 0) \
+ ENCRYPT_256_TWO_ROUNDS_2(KEY_BASE + 24, I0, I1, I2, I3, KEY_BASE + 0) \
+ ENCRYPT_256_TWO_ROUNDS_2(KEY_BASE + 32, I0, I1, I2, I3, KEY_BASE + 0) \
+ ENCRYPT_256_TWO_ROUNDS_2(KEY_BASE + 40, I0, I1, I2, I3, KEY_BASE + 0) \
+ AES_EROUND01(KEY_BASE + 48, I0, I1, KEY_BASE + 0) \
+ AES_EROUND23(KEY_BASE + 50, I0, I1, KEY_BASE + 2) \
+ AES_EROUND01(KEY_BASE + 48, I2, I3, KEY_BASE + 4) \
+ AES_EROUND23(KEY_BASE + 50, I2, I3, KEY_BASE + 6) \
+ AES_EROUND01_L(KEY_BASE + 52, KEY_BASE + 0, KEY_BASE + 2, I0) \
+ AES_EROUND23_L(KEY_BASE + 54, KEY_BASE + 0, KEY_BASE + 2, I1) \
+ ldd [%o0 + 0x10], %f8; \
+ ldd [%o0 + 0x18], %f10; \
+ AES_EROUND01_L(KEY_BASE + 52, KEY_BASE + 4, KEY_BASE + 6, I2) \
+ AES_EROUND23_L(KEY_BASE + 54, KEY_BASE + 4, KEY_BASE + 6, I3) \
+ ldd [%o0 + 0x20], %f12; \
+ ldd [%o0 + 0x28], %f14;
+
+#define DECRYPT_TWO_ROUNDS(KEY_BASE, I0, I1, T0, T1) \
+ AES_DROUND23(KEY_BASE + 0, I0, I1, T1) \
+ AES_DROUND01(KEY_BASE + 2, I0, I1, T0) \
+ AES_DROUND23(KEY_BASE + 4, T0, T1, I1) \
+ AES_DROUND01(KEY_BASE + 6, T0, T1, I0)
+
+#define DECRYPT_TWO_ROUNDS_2(KEY_BASE, I0, I1, I2, I3, T0, T1, T2, T3) \
+ AES_DROUND23(KEY_BASE + 0, I0, I1, T1) \
+ AES_DROUND01(KEY_BASE + 2, I0, I1, T0) \
+ AES_DROUND23(KEY_BASE + 0, I2, I3, T3) \
+ AES_DROUND01(KEY_BASE + 2, I2, I3, T2) \
+ AES_DROUND23(KEY_BASE + 4, T0, T1, I1) \
+ AES_DROUND01(KEY_BASE + 6, T0, T1, I0) \
+ AES_DROUND23(KEY_BASE + 4, T2, T3, I3) \
+ AES_DROUND01(KEY_BASE + 6, T2, T3, I2)
+
+#define DECRYPT_TWO_ROUNDS_LAST(KEY_BASE, I0, I1, T0, T1) \
+ AES_DROUND23(KEY_BASE + 0, I0, I1, T1) \
+ AES_DROUND01(KEY_BASE + 2, I0, I1, T0) \
+ AES_DROUND23_L(KEY_BASE + 4, T0, T1, I1) \
+ AES_DROUND01_L(KEY_BASE + 6, T0, T1, I0)
+
+#define DECRYPT_TWO_ROUNDS_LAST_2(KEY_BASE, I0, I1, I2, I3, T0, T1, T2, T3) \
+ AES_DROUND23(KEY_BASE + 0, I0, I1, T1) \
+ AES_DROUND01(KEY_BASE + 2, I0, I1, T0) \
+ AES_DROUND23(KEY_BASE + 0, I2, I3, T3) \
+ AES_DROUND01(KEY_BASE + 2, I2, I3, T2) \
+ AES_DROUND23_L(KEY_BASE + 4, T0, T1, I1) \
+ AES_DROUND01_L(KEY_BASE + 6, T0, T1, I0) \
+ AES_DROUND23_L(KEY_BASE + 4, T2, T3, I3) \
+ AES_DROUND01_L(KEY_BASE + 6, T2, T3, I2)
+
+ /* 10 rounds */
+#define DECRYPT_128(KEY_BASE, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 0, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 8, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 16, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 24, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS_LAST(KEY_BASE + 32, I0, I1, T0, T1)
+
+#define DECRYPT_128_2(KEY_BASE, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_2(KEY_BASE + 0, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_2(KEY_BASE + 8, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_2(KEY_BASE + 16, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_2(KEY_BASE + 24, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_LAST_2(KEY_BASE + 32, I0, I1, I2, I3, T0, T1, T2, T3)
+
+ /* 12 rounds */
+#define DECRYPT_192(KEY_BASE, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 0, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 8, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 16, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 24, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 32, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS_LAST(KEY_BASE + 40, I0, I1, T0, T1)
+
+#define DECRYPT_192_2(KEY_BASE, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_2(KEY_BASE + 0, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_2(KEY_BASE + 8, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_2(KEY_BASE + 16, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_2(KEY_BASE + 24, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_2(KEY_BASE + 32, I0, I1, I2, I3, T0, T1, T2, T3) \
+ DECRYPT_TWO_ROUNDS_LAST_2(KEY_BASE + 40, I0, I1, I2, I3, T0, T1, T2, T3)
+
+ /* 14 rounds */
+#define DECRYPT_256(KEY_BASE, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 0, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 8, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 16, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 24, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 32, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS(KEY_BASE + 40, I0, I1, T0, T1) \
+ DECRYPT_TWO_ROUNDS_LAST(KEY_BASE + 48, I0, I1, T0, T1)
+
+#define DECRYPT_256_TWO_ROUNDS_2(KEY_BASE, I0, I1, I2, I3, TMP_BASE) \
+ DECRYPT_TWO_ROUNDS_2(KEY_BASE, I0, I1, I2, I3, \
+ TMP_BASE + 0, TMP_BASE + 2, TMP_BASE + 4, TMP_BASE + 6)
+
+#define DECRYPT_256_2(KEY_BASE, I0, I1, I2, I3) \
+ DECRYPT_256_TWO_ROUNDS_2(KEY_BASE + 0, I0, I1, I2, I3, KEY_BASE + 48) \
+ ldd [%o0 + 0x18], %f56; \
+ ldd [%o0 + 0x10], %f58; \
+ DECRYPT_256_TWO_ROUNDS_2(KEY_BASE + 8, I0, I1, I2, I3, KEY_BASE + 0) \
+ ldd [%o0 + 0x08], %f60; \
+ ldd [%o0 + 0x00], %f62; \
+ DECRYPT_256_TWO_ROUNDS_2(KEY_BASE + 16, I0, I1, I2, I3, KEY_BASE + 0) \
+ DECRYPT_256_TWO_ROUNDS_2(KEY_BASE + 24, I0, I1, I2, I3, KEY_BASE + 0) \
+ DECRYPT_256_TWO_ROUNDS_2(KEY_BASE + 32, I0, I1, I2, I3, KEY_BASE + 0) \
+ DECRYPT_256_TWO_ROUNDS_2(KEY_BASE + 40, I0, I1, I2, I3, KEY_BASE + 0) \
+ AES_DROUND23(KEY_BASE + 48, I0, I1, KEY_BASE + 2) \
+ AES_DROUND01(KEY_BASE + 50, I0, I1, KEY_BASE + 0) \
+ AES_DROUND23(KEY_BASE + 48, I2, I3, KEY_BASE + 6) \
+ AES_DROUND01(KEY_BASE + 50, I2, I3, KEY_BASE + 4) \
+ AES_DROUND23_L(KEY_BASE + 52, KEY_BASE + 0, KEY_BASE + 2, I1) \
+ AES_DROUND01_L(KEY_BASE + 54, KEY_BASE + 0, KEY_BASE + 2, I0) \
+ ldd [%o0 + 0xd8], %f8; \
+ ldd [%o0 + 0xd0], %f10; \
+ AES_DROUND23_L(KEY_BASE + 52, KEY_BASE + 4, KEY_BASE + 6, I3) \
+ AES_DROUND01_L(KEY_BASE + 54, KEY_BASE + 4, KEY_BASE + 6, I2) \
+ ldd [%o0 + 0xc8], %f12; \
+ ldd [%o0 + 0xc0], %f14;
+
+ .align 32
+ENTRY(aes_sparc64_key_expand)
+ /* %o0=input_key, %o1=output_key, %o2=key_len */
+ VISEntry
+ ld [%o0 + 0x00], %f0
+ ld [%o0 + 0x04], %f1
+ ld [%o0 + 0x08], %f2
+ ld [%o0 + 0x0c], %f3
+
+ std %f0, [%o1 + 0x00]
+ std %f2, [%o1 + 0x08]
+ add %o1, 0x10, %o1
+
+ cmp %o2, 24
+ bl 2f
+ nop
+
+ be 1f
+ nop
+
+ /* 256-bit key expansion */
+ ld [%o0 + 0x10], %f4
+ ld [%o0 + 0x14], %f5
+ ld [%o0 + 0x18], %f6
+ ld [%o0 + 0x1c], %f7
+
+ std %f4, [%o1 + 0x00]
+ std %f6, [%o1 + 0x08]
+ add %o1, 0x10, %o1
+
+ AES_KEXPAND1(0, 6, 0x0, 8)
+ AES_KEXPAND2(2, 8, 10)
+ AES_KEXPAND0(4, 10, 12)
+ AES_KEXPAND2(6, 12, 14)
+ AES_KEXPAND1(8, 14, 0x1, 16)
+ AES_KEXPAND2(10, 16, 18)
+ AES_KEXPAND0(12, 18, 20)
+ AES_KEXPAND2(14, 20, 22)
+ AES_KEXPAND1(16, 22, 0x2, 24)
+ AES_KEXPAND2(18, 24, 26)
+ AES_KEXPAND0(20, 26, 28)
+ AES_KEXPAND2(22, 28, 30)
+ AES_KEXPAND1(24, 30, 0x3, 32)
+ AES_KEXPAND2(26, 32, 34)
+ AES_KEXPAND0(28, 34, 36)
+ AES_KEXPAND2(30, 36, 38)
+ AES_KEXPAND1(32, 38, 0x4, 40)
+ AES_KEXPAND2(34, 40, 42)
+ AES_KEXPAND0(36, 42, 44)
+ AES_KEXPAND2(38, 44, 46)
+ AES_KEXPAND1(40, 46, 0x5, 48)
+ AES_KEXPAND2(42, 48, 50)
+ AES_KEXPAND0(44, 50, 52)
+ AES_KEXPAND2(46, 52, 54)
+ AES_KEXPAND1(48, 54, 0x6, 56)
+ AES_KEXPAND2(50, 56, 58)
+
+ std %f8, [%o1 + 0x00]
+ std %f10, [%o1 + 0x08]
+ std %f12, [%o1 + 0x10]
+ std %f14, [%o1 + 0x18]
+ std %f16, [%o1 + 0x20]
+ std %f18, [%o1 + 0x28]
+ std %f20, [%o1 + 0x30]
+ std %f22, [%o1 + 0x38]
+ std %f24, [%o1 + 0x40]
+ std %f26, [%o1 + 0x48]
+ std %f28, [%o1 + 0x50]
+ std %f30, [%o1 + 0x58]
+ std %f32, [%o1 + 0x60]
+ std %f34, [%o1 + 0x68]
+ std %f36, [%o1 + 0x70]
+ std %f38, [%o1 + 0x78]
+ std %f40, [%o1 + 0x80]
+ std %f42, [%o1 + 0x88]
+ std %f44, [%o1 + 0x90]
+ std %f46, [%o1 + 0x98]
+ std %f48, [%o1 + 0xa0]
+ std %f50, [%o1 + 0xa8]
+ std %f52, [%o1 + 0xb0]
+ std %f54, [%o1 + 0xb8]
+ std %f56, [%o1 + 0xc0]
+ ba,pt %xcc, 80f
+ std %f58, [%o1 + 0xc8]
+
+1:
+ /* 192-bit key expansion */
+ ld [%o0 + 0x10], %f4
+ ld [%o0 + 0x14], %f5
+
+ std %f4, [%o1 + 0x00]
+ add %o1, 0x08, %o1
+
+ AES_KEXPAND1(0, 4, 0x0, 6)
+ AES_KEXPAND2(2, 6, 8)
+ AES_KEXPAND2(4, 8, 10)
+ AES_KEXPAND1(6, 10, 0x1, 12)
+ AES_KEXPAND2(8, 12, 14)
+ AES_KEXPAND2(10, 14, 16)
+ AES_KEXPAND1(12, 16, 0x2, 18)
+ AES_KEXPAND2(14, 18, 20)
+ AES_KEXPAND2(16, 20, 22)
+ AES_KEXPAND1(18, 22, 0x3, 24)
+ AES_KEXPAND2(20, 24, 26)
+ AES_KEXPAND2(22, 26, 28)
+ AES_KEXPAND1(24, 28, 0x4, 30)
+ AES_KEXPAND2(26, 30, 32)
+ AES_KEXPAND2(28, 32, 34)
+ AES_KEXPAND1(30, 34, 0x5, 36)
+ AES_KEXPAND2(32, 36, 38)
+ AES_KEXPAND2(34, 38, 40)
+ AES_KEXPAND1(36, 40, 0x6, 42)
+ AES_KEXPAND2(38, 42, 44)
+ AES_KEXPAND2(40, 44, 46)
+ AES_KEXPAND1(42, 46, 0x7, 48)
+ AES_KEXPAND2(44, 48, 50)
+
+ std %f6, [%o1 + 0x00]
+ std %f8, [%o1 + 0x08]
+ std %f10, [%o1 + 0x10]
+ std %f12, [%o1 + 0x18]
+ std %f14, [%o1 + 0x20]
+ std %f16, [%o1 + 0x28]
+ std %f18, [%o1 + 0x30]
+ std %f20, [%o1 + 0x38]
+ std %f22, [%o1 + 0x40]
+ std %f24, [%o1 + 0x48]
+ std %f26, [%o1 + 0x50]
+ std %f28, [%o1 + 0x58]
+ std %f30, [%o1 + 0x60]
+ std %f32, [%o1 + 0x68]
+ std %f34, [%o1 + 0x70]
+ std %f36, [%o1 + 0x78]
+ std %f38, [%o1 + 0x80]
+ std %f40, [%o1 + 0x88]
+ std %f42, [%o1 + 0x90]
+ std %f44, [%o1 + 0x98]
+ std %f46, [%o1 + 0xa0]
+ std %f48, [%o1 + 0xa8]
+ ba,pt %xcc, 80f
+ std %f50, [%o1 + 0xb0]
+
+2:
+ /* 128-bit key expansion */
+ AES_KEXPAND1(0, 2, 0x0, 4)
+ AES_KEXPAND2(2, 4, 6)
+ AES_KEXPAND1(4, 6, 0x1, 8)
+ AES_KEXPAND2(6, 8, 10)
+ AES_KEXPAND1(8, 10, 0x2, 12)
+ AES_KEXPAND2(10, 12, 14)
+ AES_KEXPAND1(12, 14, 0x3, 16)
+ AES_KEXPAND2(14, 16, 18)
+ AES_KEXPAND1(16, 18, 0x4, 20)
+ AES_KEXPAND2(18, 20, 22)
+ AES_KEXPAND1(20, 22, 0x5, 24)
+ AES_KEXPAND2(22, 24, 26)
+ AES_KEXPAND1(24, 26, 0x6, 28)
+ AES_KEXPAND2(26, 28, 30)
+ AES_KEXPAND1(28, 30, 0x7, 32)
+ AES_KEXPAND2(30, 32, 34)
+ AES_KEXPAND1(32, 34, 0x8, 36)
+ AES_KEXPAND2(34, 36, 38)
+ AES_KEXPAND1(36, 38, 0x9, 40)
+ AES_KEXPAND2(38, 40, 42)
+
+ std %f4, [%o1 + 0x00]
+ std %f6, [%o1 + 0x08]
+ std %f8, [%o1 + 0x10]
+ std %f10, [%o1 + 0x18]
+ std %f12, [%o1 + 0x20]
+ std %f14, [%o1 + 0x28]
+ std %f16, [%o1 + 0x30]
+ std %f18, [%o1 + 0x38]
+ std %f20, [%o1 + 0x40]
+ std %f22, [%o1 + 0x48]
+ std %f24, [%o1 + 0x50]
+ std %f26, [%o1 + 0x58]
+ std %f28, [%o1 + 0x60]
+ std %f30, [%o1 + 0x68]
+ std %f32, [%o1 + 0x70]
+ std %f34, [%o1 + 0x78]
+ std %f36, [%o1 + 0x80]
+ std %f38, [%o1 + 0x88]
+ std %f40, [%o1 + 0x90]
+ std %f42, [%o1 + 0x98]
+80:
+ retl
+ VISExit
+ENDPROC(aes_sparc64_key_expand)
+
+ .align 32
+ENTRY(aes_sparc64_encrypt_128)
+ /* %o0=key, %o1=input, %o2=output */
+ VISEntry
+ ld [%o1 + 0x00], %f4
+ ld [%o1 + 0x04], %f5
+ ld [%o1 + 0x08], %f6
+ ld [%o1 + 0x0c], %f7
+ ldd [%o0 + 0x00], %f8
+ ldd [%o0 + 0x08], %f10
+ ldd [%o0 + 0x10], %f12
+ ldd [%o0 + 0x18], %f14
+ ldd [%o0 + 0x20], %f16
+ ldd [%o0 + 0x28], %f18
+ ldd [%o0 + 0x30], %f20
+ ldd [%o0 + 0x38], %f22
+ ldd [%o0 + 0x40], %f24
+ ldd [%o0 + 0x48], %f26
+ ldd [%o0 + 0x50], %f28
+ ldd [%o0 + 0x58], %f30
+ ldd [%o0 + 0x60], %f32
+ ldd [%o0 + 0x68], %f34
+ ldd [%o0 + 0x70], %f36
+ ldd [%o0 + 0x78], %f38
+ ldd [%o0 + 0x80], %f40
+ ldd [%o0 + 0x88], %f42
+ ldd [%o0 + 0x90], %f44
+ ldd [%o0 + 0x98], %f46
+ ldd [%o0 + 0xa0], %f48
+ ldd [%o0 + 0xa8], %f50
+ fxor %f8, %f4, %f4
+ fxor %f10, %f6, %f6
+ ENCRYPT_128(12, 4, 6, 0, 2)
+ st %f4, [%o2 + 0x00]
+ st %f5, [%o2 + 0x04]
+ st %f6, [%o2 + 0x08]
+ st %f7, [%o2 + 0x0c]
+ retl
+ VISExit
+ENDPROC(aes_sparc64_encrypt_128)
+
+ .align 32
+ENTRY(aes_sparc64_encrypt_192)
+ /* %o0=key, %o1=input, %o2=output */
+ VISEntry
+ ld [%o1 + 0x00], %f4
+ ld [%o1 + 0x04], %f5
+ ld [%o1 + 0x08], %f6
+ ld [%o1 + 0x0c], %f7
+
+ ldd [%o0 + 0x00], %f8
+ ldd [%o0 + 0x08], %f10
+
+ fxor %f8, %f4, %f4
+ fxor %f10, %f6, %f6
+
+ ldd [%o0 + 0x10], %f8
+ ldd [%o0 + 0x18], %f10
+ ldd [%o0 + 0x20], %f12
+ ldd [%o0 + 0x28], %f14
+ add %o0, 0x20, %o0
+
+ ENCRYPT_TWO_ROUNDS(8, 4, 6, 0, 2)
+
+ ldd [%o0 + 0x10], %f12
+ ldd [%o0 + 0x18], %f14
+ ldd [%o0 + 0x20], %f16
+ ldd [%o0 + 0x28], %f18
+ ldd [%o0 + 0x30], %f20
+ ldd [%o0 + 0x38], %f22
+ ldd [%o0 + 0x40], %f24
+ ldd [%o0 + 0x48], %f26
+ ldd [%o0 + 0x50], %f28
+ ldd [%o0 + 0x58], %f30
+ ldd [%o0 + 0x60], %f32
+ ldd [%o0 + 0x68], %f34
+ ldd [%o0 + 0x70], %f36
+ ldd [%o0 + 0x78], %f38
+ ldd [%o0 + 0x80], %f40
+ ldd [%o0 + 0x88], %f42
+ ldd [%o0 + 0x90], %f44
+ ldd [%o0 + 0x98], %f46
+ ldd [%o0 + 0xa0], %f48
+ ldd [%o0 + 0xa8], %f50
+
+
+ ENCRYPT_128(12, 4, 6, 0, 2)
+
+ st %f4, [%o2 + 0x00]
+ st %f5, [%o2 + 0x04]
+ st %f6, [%o2 + 0x08]
+ st %f7, [%o2 + 0x0c]
+
+ retl
+ VISExit
+ENDPROC(aes_sparc64_encrypt_192)
+
+ .align 32
+ENTRY(aes_sparc64_encrypt_256)
+ /* %o0=key, %o1=input, %o2=output */
+ VISEntry
+ ld [%o1 + 0x00], %f4
+ ld [%o1 + 0x04], %f5
+ ld [%o1 + 0x08], %f6
+ ld [%o1 + 0x0c], %f7
+
+ ldd [%o0 + 0x00], %f8
+ ldd [%o0 + 0x08], %f10
+
+ fxor %f8, %f4, %f4
+ fxor %f10, %f6, %f6
+
+ ldd [%o0 + 0x10], %f8
+
+ ldd [%o0 + 0x18], %f10
+ ldd [%o0 + 0x20], %f12
+ ldd [%o0 + 0x28], %f14
+ add %o0, 0x20, %o0
+
+ ENCRYPT_TWO_ROUNDS(8, 4, 6, 0, 2)
+
+ ldd [%o0 + 0x10], %f8
+
+ ldd [%o0 + 0x18], %f10
+ ldd [%o0 + 0x20], %f12
+ ldd [%o0 + 0x28], %f14
+ add %o0, 0x20, %o0
+
+ ENCRYPT_TWO_ROUNDS(8, 4, 6, 0, 2)
+
+ ldd [%o0 + 0x10], %f12
+ ldd [%o0 + 0x18], %f14
+ ldd [%o0 + 0x20], %f16
+ ldd [%o0 + 0x28], %f18
+ ldd [%o0 + 0x30], %f20
+ ldd [%o0 + 0x38], %f22
+ ldd [%o0 + 0x40], %f24
+ ldd [%o0 + 0x48], %f26
+ ldd [%o0 + 0x50], %f28
+ ldd [%o0 + 0x58], %f30
+ ldd [%o0 + 0x60], %f32
+ ldd [%o0 + 0x68], %f34
+ ldd [%o0 + 0x70], %f36
+ ldd [%o0 + 0x78], %f38
+ ldd [%o0 + 0x80], %f40
+ ldd [%o0 + 0x88], %f42
+ ldd [%o0 + 0x90], %f44
+ ldd [%o0 + 0x98], %f46
+ ldd [%o0 + 0xa0], %f48
+ ldd [%o0 + 0xa8], %f50
+
+ ENCRYPT_128(12, 4, 6, 0, 2)
+
+ st %f4, [%o2 + 0x00]
+ st %f5, [%o2 + 0x04]
+ st %f6, [%o2 + 0x08]
+ st %f7, [%o2 + 0x0c]
+
+ retl
+ VISExit
+ENDPROC(aes_sparc64_encrypt_256)
+
+ .align 32
+ENTRY(aes_sparc64_decrypt_128)
+ /* %o0=key, %o1=input, %o2=output */
+ VISEntry
+ ld [%o1 + 0x00], %f4
+ ld [%o1 + 0x04], %f5
+ ld [%o1 + 0x08], %f6
+ ld [%o1 + 0x0c], %f7
+ ldd [%o0 + 0xa0], %f8
+ ldd [%o0 + 0xa8], %f10
+ ldd [%o0 + 0x98], %f12
+ ldd [%o0 + 0x90], %f14
+ ldd [%o0 + 0x88], %f16
+ ldd [%o0 + 0x80], %f18
+ ldd [%o0 + 0x78], %f20
+ ldd [%o0 + 0x70], %f22
+ ldd [%o0 + 0x68], %f24
+ ldd [%o0 + 0x60], %f26
+ ldd [%o0 + 0x58], %f28
+ ldd [%o0 + 0x50], %f30
+ ldd [%o0 + 0x48], %f32
+ ldd [%o0 + 0x40], %f34
+ ldd [%o0 + 0x38], %f36
+ ldd [%o0 + 0x30], %f38
+ ldd [%o0 + 0x28], %f40
+ ldd [%o0 + 0x20], %f42
+ ldd [%o0 + 0x18], %f44
+ ldd [%o0 + 0x10], %f46
+ ldd [%o0 + 0x08], %f48
+ ldd [%o0 + 0x00], %f50
+ fxor %f8, %f4, %f4
+ fxor %f10, %f6, %f6
+ DECRYPT_128(12, 4, 6, 0, 2)
+ st %f4, [%o2 + 0x00]
+ st %f5, [%o2 + 0x04]
+ st %f6, [%o2 + 0x08]
+ st %f7, [%o2 + 0x0c]
+ retl
+ VISExit
+ENDPROC(aes_sparc64_decrypt_128)
+
+ .align 32
+ENTRY(aes_sparc64_decrypt_192)
+ /* %o0=key, %o1=input, %o2=output */
+ VISEntry
+ ld [%o1 + 0x00], %f4
+ ld [%o1 + 0x04], %f5
+ ld [%o1 + 0x08], %f6
+ ld [%o1 + 0x0c], %f7
+ ldd [%o0 + 0xc0], %f8
+ ldd [%o0 + 0xc8], %f10
+ ldd [%o0 + 0xb8], %f12
+ ldd [%o0 + 0xb0], %f14
+ ldd [%o0 + 0xa8], %f16
+ ldd [%o0 + 0xa0], %f18
+ fxor %f8, %f4, %f4
+ fxor %f10, %f6, %f6
+ ldd [%o0 + 0x98], %f20
+ ldd [%o0 + 0x90], %f22
+ ldd [%o0 + 0x88], %f24
+ ldd [%o0 + 0x80], %f26
+ DECRYPT_TWO_ROUNDS(12, 4, 6, 0, 2)
+ ldd [%o0 + 0x78], %f28
+ ldd [%o0 + 0x70], %f30
+ ldd [%o0 + 0x68], %f32
+ ldd [%o0 + 0x60], %f34
+ ldd [%o0 + 0x58], %f36
+ ldd [%o0 + 0x50], %f38
+ ldd [%o0 + 0x48], %f40
+ ldd [%o0 + 0x40], %f42
+ ldd [%o0 + 0x38], %f44
+ ldd [%o0 + 0x30], %f46
+ ldd [%o0 + 0x28], %f48
+ ldd [%o0 + 0x20], %f50
+ ldd [%o0 + 0x18], %f52
+ ldd [%o0 + 0x10], %f54
+ ldd [%o0 + 0x08], %f56
+ ldd [%o0 + 0x00], %f58
+ DECRYPT_128(20, 4, 6, 0, 2)
+ st %f4, [%o2 + 0x00]
+ st %f5, [%o2 + 0x04]
+ st %f6, [%o2 + 0x08]
+ st %f7, [%o2 + 0x0c]
+ retl
+ VISExit
+ENDPROC(aes_sparc64_decrypt_192)
+
+ .align 32
+ENTRY(aes_sparc64_decrypt_256)
+ /* %o0=key, %o1=input, %o2=output */
+ VISEntry
+ ld [%o1 + 0x00], %f4
+ ld [%o1 + 0x04], %f5
+ ld [%o1 + 0x08], %f6
+ ld [%o1 + 0x0c], %f7
+ ldd [%o0 + 0xe0], %f8
+ ldd [%o0 + 0xe8], %f10
+ ldd [%o0 + 0xd8], %f12
+ ldd [%o0 + 0xd0], %f14
+ ldd [%o0 + 0xc8], %f16
+ fxor %f8, %f4, %f4
+ ldd [%o0 + 0xc0], %f18
+ fxor %f10, %f6, %f6
+ ldd [%o0 + 0xb8], %f20
+ AES_DROUND23(12, 4, 6, 2)
+ ldd [%o0 + 0xb0], %f22
+ AES_DROUND01(14, 4, 6, 0)
+ ldd [%o0 + 0xa8], %f24
+ AES_DROUND23(16, 0, 2, 6)
+ ldd [%o0 + 0xa0], %f26
+ AES_DROUND01(18, 0, 2, 4)
+ ldd [%o0 + 0x98], %f12
+ AES_DROUND23(20, 4, 6, 2)
+ ldd [%o0 + 0x90], %f14
+ AES_DROUND01(22, 4, 6, 0)
+ ldd [%o0 + 0x88], %f16
+ AES_DROUND23(24, 0, 2, 6)
+ ldd [%o0 + 0x80], %f18
+ AES_DROUND01(26, 0, 2, 4)
+ ldd [%o0 + 0x78], %f20
+ AES_DROUND23(12, 4, 6, 2)
+ ldd [%o0 + 0x70], %f22
+ AES_DROUND01(14, 4, 6, 0)
+ ldd [%o0 + 0x68], %f24
+ AES_DROUND23(16, 0, 2, 6)
+ ldd [%o0 + 0x60], %f26
+ AES_DROUND01(18, 0, 2, 4)
+ ldd [%o0 + 0x58], %f28
+ AES_DROUND23(20, 4, 6, 2)
+ ldd [%o0 + 0x50], %f30
+ AES_DROUND01(22, 4, 6, 0)
+ ldd [%o0 + 0x48], %f32
+ AES_DROUND23(24, 0, 2, 6)
+ ldd [%o0 + 0x40], %f34
+ AES_DROUND01(26, 0, 2, 4)
+ ldd [%o0 + 0x38], %f36
+ AES_DROUND23(28, 4, 6, 2)
+ ldd [%o0 + 0x30], %f38
+ AES_DROUND01(30, 4, 6, 0)
+ ldd [%o0 + 0x28], %f40
+ AES_DROUND23(32, 0, 2, 6)
+ ldd [%o0 + 0x20], %f42
+ AES_DROUND01(34, 0, 2, 4)
+ ldd [%o0 + 0x18], %f44
+ AES_DROUND23(36, 4, 6, 2)
+ ldd [%o0 + 0x10], %f46
+ AES_DROUND01(38, 4, 6, 0)
+ ldd [%o0 + 0x08], %f48
+ AES_DROUND23(40, 0, 2, 6)
+ ldd [%o0 + 0x00], %f50
+ AES_DROUND01(42, 0, 2, 4)
+ AES_DROUND23(44, 4, 6, 2)
+ AES_DROUND01(46, 4, 6, 0)
+ AES_DROUND23_L(48, 0, 2, 6)
+ AES_DROUND01_L(50, 0, 2, 4)
+ st %f4, [%o2 + 0x00]
+ st %f5, [%o2 + 0x04]
+ st %f6, [%o2 + 0x08]
+ st %f7, [%o2 + 0x0c]
+ retl
+ VISExit
+ENDPROC(aes_sparc64_decrypt_256)
+
+ .align 32
+ENTRY(aes_sparc64_load_encrypt_keys_128)
+ /* %o0=key */
+ VISEntry
+ ldd [%o0 + 0x10], %f8
+ ldd [%o0 + 0x18], %f10
+ ldd [%o0 + 0x20], %f12
+ ldd [%o0 + 0x28], %f14
+ ldd [%o0 + 0x30], %f16
+ ldd [%o0 + 0x38], %f18
+ ldd [%o0 + 0x40], %f20
+ ldd [%o0 + 0x48], %f22
+ ldd [%o0 + 0x50], %f24
+ ldd [%o0 + 0x58], %f26
+ ldd [%o0 + 0x60], %f28
+ ldd [%o0 + 0x68], %f30
+ ldd [%o0 + 0x70], %f32
+ ldd [%o0 + 0x78], %f34
+ ldd [%o0 + 0x80], %f36
+ ldd [%o0 + 0x88], %f38
+ ldd [%o0 + 0x90], %f40
+ ldd [%o0 + 0x98], %f42
+ ldd [%o0 + 0xa0], %f44
+ retl
+ ldd [%o0 + 0xa8], %f46
+ENDPROC(aes_sparc64_load_encrypt_keys_128)
+
+ .align 32
+ENTRY(aes_sparc64_load_encrypt_keys_192)
+ /* %o0=key */
+ VISEntry
+ ldd [%o0 + 0x10], %f8
+ ldd [%o0 + 0x18], %f10
+ ldd [%o0 + 0x20], %f12
+ ldd [%o0 + 0x28], %f14
+ ldd [%o0 + 0x30], %f16
+ ldd [%o0 + 0x38], %f18
+ ldd [%o0 + 0x40], %f20
+ ldd [%o0 + 0x48], %f22
+ ldd [%o0 + 0x50], %f24
+ ldd [%o0 + 0x58], %f26
+ ldd [%o0 + 0x60], %f28
+ ldd [%o0 + 0x68], %f30
+ ldd [%o0 + 0x70], %f32
+ ldd [%o0 + 0x78], %f34
+ ldd [%o0 + 0x80], %f36
+ ldd [%o0 + 0x88], %f38
+ ldd [%o0 + 0x90], %f40
+ ldd [%o0 + 0x98], %f42
+ ldd [%o0 + 0xa0], %f44
+ ldd [%o0 + 0xa8], %f46
+ ldd [%o0 + 0xb0], %f48
+ ldd [%o0 + 0xb8], %f50
+ ldd [%o0 + 0xc0], %f52
+ retl
+ ldd [%o0 + 0xc8], %f54
+ENDPROC(aes_sparc64_load_encrypt_keys_192)
+
+ .align 32
+ENTRY(aes_sparc64_load_encrypt_keys_256)
+ /* %o0=key */
+ VISEntry
+ ldd [%o0 + 0x10], %f8
+ ldd [%o0 + 0x18], %f10
+ ldd [%o0 + 0x20], %f12
+ ldd [%o0 + 0x28], %f14
+ ldd [%o0 + 0x30], %f16
+ ldd [%o0 + 0x38], %f18
+ ldd [%o0 + 0x40], %f20
+ ldd [%o0 + 0x48], %f22
+ ldd [%o0 + 0x50], %f24
+ ldd [%o0 + 0x58], %f26
+ ldd [%o0 + 0x60], %f28
+ ldd [%o0 + 0x68], %f30
+ ldd [%o0 + 0x70], %f32
+ ldd [%o0 + 0x78], %f34
+ ldd [%o0 + 0x80], %f36
+ ldd [%o0 + 0x88], %f38
+ ldd [%o0 + 0x90], %f40
+ ldd [%o0 + 0x98], %f42
+ ldd [%o0 + 0xa0], %f44
+ ldd [%o0 + 0xa8], %f46
+ ldd [%o0 + 0xb0], %f48
+ ldd [%o0 + 0xb8], %f50
+ ldd [%o0 + 0xc0], %f52
+ ldd [%o0 + 0xc8], %f54
+ ldd [%o0 + 0xd0], %f56
+ ldd [%o0 + 0xd8], %f58
+ ldd [%o0 + 0xe0], %f60
+ retl
+ ldd [%o0 + 0xe8], %f62
+ENDPROC(aes_sparc64_load_encrypt_keys_256)
+
+ .align 32
+ENTRY(aes_sparc64_load_decrypt_keys_128)
+ /* %o0=key */
+ VISEntry
+ ldd [%o0 + 0x98], %f8
+ ldd [%o0 + 0x90], %f10
+ ldd [%o0 + 0x88], %f12
+ ldd [%o0 + 0x80], %f14
+ ldd [%o0 + 0x78], %f16
+ ldd [%o0 + 0x70], %f18
+ ldd [%o0 + 0x68], %f20
+ ldd [%o0 + 0x60], %f22
+ ldd [%o0 + 0x58], %f24
+ ldd [%o0 + 0x50], %f26
+ ldd [%o0 + 0x48], %f28
+ ldd [%o0 + 0x40], %f30
+ ldd [%o0 + 0x38], %f32
+ ldd [%o0 + 0x30], %f34
+ ldd [%o0 + 0x28], %f36
+ ldd [%o0 + 0x20], %f38
+ ldd [%o0 + 0x18], %f40
+ ldd [%o0 + 0x10], %f42
+ ldd [%o0 + 0x08], %f44
+ retl
+ ldd [%o0 + 0x00], %f46
+ENDPROC(aes_sparc64_load_decrypt_keys_128)
+
+ .align 32
+ENTRY(aes_sparc64_load_decrypt_keys_192)
+ /* %o0=key */
+ VISEntry
+ ldd [%o0 + 0xb8], %f8
+ ldd [%o0 + 0xb0], %f10
+ ldd [%o0 + 0xa8], %f12
+ ldd [%o0 + 0xa0], %f14
+ ldd [%o0 + 0x98], %f16
+ ldd [%o0 + 0x90], %f18
+ ldd [%o0 + 0x88], %f20
+ ldd [%o0 + 0x80], %f22
+ ldd [%o0 + 0x78], %f24
+ ldd [%o0 + 0x70], %f26
+ ldd [%o0 + 0x68], %f28
+ ldd [%o0 + 0x60], %f30
+ ldd [%o0 + 0x58], %f32
+ ldd [%o0 + 0x50], %f34
+ ldd [%o0 + 0x48], %f36
+ ldd [%o0 + 0x40], %f38
+ ldd [%o0 + 0x38], %f40
+ ldd [%o0 + 0x30], %f42
+ ldd [%o0 + 0x28], %f44
+ ldd [%o0 + 0x20], %f46
+ ldd [%o0 + 0x18], %f48
+ ldd [%o0 + 0x10], %f50
+ ldd [%o0 + 0x08], %f52
+ retl
+ ldd [%o0 + 0x00], %f54
+ENDPROC(aes_sparc64_load_decrypt_keys_192)
+
+ .align 32
+ENTRY(aes_sparc64_load_decrypt_keys_256)
+ /* %o0=key */
+ VISEntry
+ ldd [%o0 + 0xd8], %f8
+ ldd [%o0 + 0xd0], %f10
+ ldd [%o0 + 0xc8], %f12
+ ldd [%o0 + 0xc0], %f14
+ ldd [%o0 + 0xb8], %f16
+ ldd [%o0 + 0xb0], %f18
+ ldd [%o0 + 0xa8], %f20
+ ldd [%o0 + 0xa0], %f22
+ ldd [%o0 + 0x98], %f24
+ ldd [%o0 + 0x90], %f26
+ ldd [%o0 + 0x88], %f28
+ ldd [%o0 + 0x80], %f30
+ ldd [%o0 + 0x78], %f32
+ ldd [%o0 + 0x70], %f34
+ ldd [%o0 + 0x68], %f36
+ ldd [%o0 + 0x60], %f38
+ ldd [%o0 + 0x58], %f40
+ ldd [%o0 + 0x50], %f42
+ ldd [%o0 + 0x48], %f44
+ ldd [%o0 + 0x40], %f46
+ ldd [%o0 + 0x38], %f48
+ ldd [%o0 + 0x30], %f50
+ ldd [%o0 + 0x28], %f52
+ ldd [%o0 + 0x20], %f54
+ ldd [%o0 + 0x18], %f56
+ ldd [%o0 + 0x10], %f58
+ ldd [%o0 + 0x08], %f60
+ retl
+ ldd [%o0 + 0x00], %f62
+ENDPROC(aes_sparc64_load_decrypt_keys_256)
+
+ .align 32
+ENTRY(aes_sparc64_ecb_encrypt_128)
+ /* %o0=key, %o1=input, %o2=output, %o3=len */
+ ldx [%o0 + 0x00], %g1
+ subcc %o3, 0x10, %o3
+ be 10f
+ ldx [%o0 + 0x08], %g2
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ ldx [%o1 + 0x10], %o4
+ ldx [%o1 + 0x18], %o5
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ xor %g1, %o4, %g3
+ xor %g2, %o5, %g7
+ MOVXTOD_G3_F60
+ MOVXTOD_G7_F62
+ ENCRYPT_128_2(8, 4, 6, 60, 62, 0, 2, 56, 58)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ std %f60, [%o2 + 0x10]
+ std %f62, [%o2 + 0x18]
+ sub %o3, 0x20, %o3
+ add %o1, 0x20, %o1
+ brgz %o3, 1b
+ add %o2, 0x20, %o2
+ brlz,pt %o3, 11f
+ nop
+10: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ ENCRYPT_128(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+11: retl
+ nop
+ENDPROC(aes_sparc64_ecb_encrypt_128)
+
+ .align 32
+ENTRY(aes_sparc64_ecb_encrypt_192)
+ /* %o0=key, %o1=input, %o2=output, %o3=len */
+ ldx [%o0 + 0x00], %g1
+ subcc %o3, 0x10, %o3
+ be 10f
+ ldx [%o0 + 0x08], %g2
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ ldx [%o1 + 0x10], %o4
+ ldx [%o1 + 0x18], %o5
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ xor %g1, %o4, %g3
+ xor %g2, %o5, %g7
+ MOVXTOD_G3_F60
+ MOVXTOD_G7_F62
+ ENCRYPT_192_2(8, 4, 6, 60, 62, 0, 2, 56, 58)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ std %f60, [%o2 + 0x10]
+ std %f62, [%o2 + 0x18]
+ sub %o3, 0x20, %o3
+ add %o1, 0x20, %o1
+ brgz %o3, 1b
+ add %o2, 0x20, %o2
+ brlz,pt %o3, 11f
+ nop
+10: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ ENCRYPT_192(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+11: retl
+ nop
+ENDPROC(aes_sparc64_ecb_encrypt_192)
+
+ .align 32
+ENTRY(aes_sparc64_ecb_encrypt_256)
+ /* %o0=key, %o1=input, %o2=output, %o3=len */
+ ldx [%o0 + 0x00], %g1
+ subcc %o3, 0x10, %o3
+ be 10f
+ ldx [%o0 + 0x08], %g2
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ ldx [%o1 + 0x10], %o4
+ ldx [%o1 + 0x18], %o5
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ xor %g1, %o4, %g3
+ xor %g2, %o5, %g7
+ MOVXTOD_G3_F0
+ MOVXTOD_G7_F2
+ ENCRYPT_256_2(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ std %f0, [%o2 + 0x10]
+ std %f2, [%o2 + 0x18]
+ sub %o3, 0x20, %o3
+ add %o1, 0x20, %o1
+ brgz %o3, 1b
+ add %o2, 0x20, %o2
+ brlz,pt %o3, 11f
+ nop
+10: ldd [%o0 + 0xd0], %f56
+ ldd [%o0 + 0xd8], %f58
+ ldd [%o0 + 0xe0], %f60
+ ldd [%o0 + 0xe8], %f62
+ ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ ENCRYPT_256(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+11: retl
+ nop
+ENDPROC(aes_sparc64_ecb_encrypt_256)
+
+ .align 32
+ENTRY(aes_sparc64_ecb_decrypt_128)
+ /* %o0=&key[key_len], %o1=input, %o2=output, %o3=len */
+ ldx [%o0 - 0x10], %g1
+ subcc %o3, 0x10, %o3
+ be 10f
+ ldx [%o0 - 0x08], %g2
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ ldx [%o1 + 0x10], %o4
+ ldx [%o1 + 0x18], %o5
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ xor %g1, %o4, %g3
+ xor %g2, %o5, %g7
+ MOVXTOD_G3_F60
+ MOVXTOD_G7_F62
+ DECRYPT_128_2(8, 4, 6, 60, 62, 0, 2, 56, 58)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ std %f60, [%o2 + 0x10]
+ std %f62, [%o2 + 0x18]
+ sub %o3, 0x20, %o3
+ add %o1, 0x20, %o1
+ brgz,pt %o3, 1b
+ add %o2, 0x20, %o2
+ brlz,pt %o3, 11f
+ nop
+10: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ DECRYPT_128(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+11: retl
+ nop
+ENDPROC(aes_sparc64_ecb_decrypt_128)
+
+ .align 32
+ENTRY(aes_sparc64_ecb_decrypt_192)
+ /* %o0=&key[key_len], %o1=input, %o2=output, %o3=len */
+ ldx [%o0 - 0x10], %g1
+ subcc %o3, 0x10, %o3
+ be 10f
+ ldx [%o0 - 0x08], %g2
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ ldx [%o1 + 0x10], %o4
+ ldx [%o1 + 0x18], %o5
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ xor %g1, %o4, %g3
+ xor %g2, %o5, %g7
+ MOVXTOD_G3_F60
+ MOVXTOD_G7_F62
+ DECRYPT_192_2(8, 4, 6, 60, 62, 0, 2, 56, 58)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ std %f60, [%o2 + 0x10]
+ std %f62, [%o2 + 0x18]
+ sub %o3, 0x20, %o3
+ add %o1, 0x20, %o1
+ brgz,pt %o3, 1b
+ add %o2, 0x20, %o2
+ brlz,pt %o3, 11f
+ nop
+10: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ DECRYPT_192(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+11: retl
+ nop
+ENDPROC(aes_sparc64_ecb_decrypt_192)
+
+ .align 32
+ENTRY(aes_sparc64_ecb_decrypt_256)
+ /* %o0=&key[key_len], %o1=input, %o2=output, %o3=len */
+ ldx [%o0 - 0x10], %g1
+ subcc %o3, 0x10, %o3
+ ldx [%o0 - 0x08], %g2
+ be 10f
+ sub %o0, 0xf0, %o0
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ ldx [%o1 + 0x10], %o4
+ ldx [%o1 + 0x18], %o5
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ xor %g1, %o4, %g3
+ xor %g2, %o5, %g7
+ MOVXTOD_G3_F0
+ MOVXTOD_G7_F2
+ DECRYPT_256_2(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ std %f0, [%o2 + 0x10]
+ std %f2, [%o2 + 0x18]
+ sub %o3, 0x20, %o3
+ add %o1, 0x20, %o1
+ brgz,pt %o3, 1b
+ add %o2, 0x20, %o2
+ brlz,pt %o3, 11f
+ nop
+10: ldd [%o0 + 0x18], %f56
+ ldd [%o0 + 0x10], %f58
+ ldd [%o0 + 0x08], %f60
+ ldd [%o0 + 0x00], %f62
+ ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ DECRYPT_256(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+11: retl
+ nop
+ENDPROC(aes_sparc64_ecb_decrypt_256)
+
+ .align 32
+ENTRY(aes_sparc64_cbc_encrypt_128)
+ /* %o0=key, %o1=input, %o2=output, %o3=len, %o4=IV */
+ ldd [%o4 + 0x00], %f4
+ ldd [%o4 + 0x08], %f6
+ ldx [%o0 + 0x00], %g1
+ ldx [%o0 + 0x08], %g2
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ add %o1, 0x10, %o1
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F0
+ MOVXTOD_G7_F2
+ fxor %f4, %f0, %f4
+ fxor %f6, %f2, %f6
+ ENCRYPT_128(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ subcc %o3, 0x10, %o3
+ bne,pt %xcc, 1b
+ add %o2, 0x10, %o2
+ std %f4, [%o4 + 0x00]
+ std %f6, [%o4 + 0x08]
+ retl
+ nop
+ENDPROC(aes_sparc64_cbc_encrypt_128)
+
+ .align 32
+ENTRY(aes_sparc64_cbc_encrypt_192)
+ /* %o0=key, %o1=input, %o2=output, %o3=len, %o4=IV */
+ ldd [%o4 + 0x00], %f4
+ ldd [%o4 + 0x08], %f6
+ ldx [%o0 + 0x00], %g1
+ ldx [%o0 + 0x08], %g2
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ add %o1, 0x10, %o1
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F0
+ MOVXTOD_G7_F2
+ fxor %f4, %f0, %f4
+ fxor %f6, %f2, %f6
+ ENCRYPT_192(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ subcc %o3, 0x10, %o3
+ bne,pt %xcc, 1b
+ add %o2, 0x10, %o2
+ std %f4, [%o4 + 0x00]
+ std %f6, [%o4 + 0x08]
+ retl
+ nop
+ENDPROC(aes_sparc64_cbc_encrypt_192)
+
+ .align 32
+ENTRY(aes_sparc64_cbc_encrypt_256)
+ /* %o0=key, %o1=input, %o2=output, %o3=len, %o4=IV */
+ ldd [%o4 + 0x00], %f4
+ ldd [%o4 + 0x08], %f6
+ ldx [%o0 + 0x00], %g1
+ ldx [%o0 + 0x08], %g2
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ add %o1, 0x10, %o1
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F0
+ MOVXTOD_G7_F2
+ fxor %f4, %f0, %f4
+ fxor %f6, %f2, %f6
+ ENCRYPT_256(8, 4, 6, 0, 2)
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ subcc %o3, 0x10, %o3
+ bne,pt %xcc, 1b
+ add %o2, 0x10, %o2
+ std %f4, [%o4 + 0x00]
+ std %f6, [%o4 + 0x08]
+ retl
+ nop
+ENDPROC(aes_sparc64_cbc_encrypt_256)
+
+ .align 32
+ENTRY(aes_sparc64_cbc_decrypt_128)
+ /* %o0=&key[key_len], %o1=input, %o2=output, %o3=len, %o4=iv */
+ ldx [%o0 - 0x10], %g1
+ ldx [%o0 - 0x08], %g2
+ ldx [%o4 + 0x00], %o0
+ ldx [%o4 + 0x08], %o5
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ add %o1, 0x10, %o1
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ DECRYPT_128(8, 4, 6, 0, 2)
+ MOVXTOD_O0_F0
+ MOVXTOD_O5_F2
+ xor %g1, %g3, %o0
+ xor %g2, %g7, %o5
+ fxor %f4, %f0, %f4
+ fxor %f6, %f2, %f6
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ subcc %o3, 0x10, %o3
+ bne,pt %xcc, 1b
+ add %o2, 0x10, %o2
+ stx %o0, [%o4 + 0x00]
+ stx %o5, [%o4 + 0x08]
+ retl
+ nop
+ENDPROC(aes_sparc64_cbc_decrypt_128)
+
+ .align 32
+ENTRY(aes_sparc64_cbc_decrypt_192)
+ /* %o0=&key[key_len], %o1=input, %o2=output, %o3=len, %o4=iv */
+ ldx [%o0 - 0x10], %g1
+ ldx [%o0 - 0x08], %g2
+ ldx [%o4 + 0x00], %o0
+ ldx [%o4 + 0x08], %o5
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ add %o1, 0x10, %o1
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ DECRYPT_192(8, 4, 6, 0, 2)
+ MOVXTOD_O0_F0
+ MOVXTOD_O5_F2
+ xor %g1, %g3, %o0
+ xor %g2, %g7, %o5
+ fxor %f4, %f0, %f4
+ fxor %f6, %f2, %f6
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ subcc %o3, 0x10, %o3
+ bne,pt %xcc, 1b
+ add %o2, 0x10, %o2
+ stx %o0, [%o4 + 0x00]
+ stx %o5, [%o4 + 0x08]
+ retl
+ nop
+ENDPROC(aes_sparc64_cbc_decrypt_192)
+
+ .align 32
+ENTRY(aes_sparc64_cbc_decrypt_256)
+ /* %o0=&key[key_len], %o1=input, %o2=output, %o3=len, %o4=iv */
+ ldx [%o0 - 0x10], %g1
+ ldx [%o0 - 0x08], %g2
+ ldx [%o4 + 0x00], %o0
+ ldx [%o4 + 0x08], %o5
+1: ldx [%o1 + 0x00], %g3
+ ldx [%o1 + 0x08], %g7
+ add %o1, 0x10, %o1
+ xor %g1, %g3, %g3
+ xor %g2, %g7, %g7
+ MOVXTOD_G3_F4
+ MOVXTOD_G7_F6
+ DECRYPT_256(8, 4, 6, 0, 2)
+ MOVXTOD_O0_F0
+ MOVXTOD_O5_F2
+ xor %g1, %g3, %o0
+ xor %g2, %g7, %o5
+ fxor %f4, %f0, %f4
+ fxor %f6, %f2, %f6
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+ subcc %o3, 0x10, %o3
+ bne,pt %xcc, 1b
+ add %o2, 0x10, %o2
+ stx %o0, [%o4 + 0x00]
+ stx %o5, [%o4 + 0x08]
+ retl
+ nop
+ENDPROC(aes_sparc64_cbc_decrypt_256)
+
+ .align 32
+ENTRY(aes_sparc64_ctr_crypt_128)
+ /* %o0=key, %o1=input, %o2=output, %o3=len, %o4=IV */
+ ldx [%o4 + 0x00], %g3
+ ldx [%o4 + 0x08], %g7
+ subcc %o3, 0x10, %o3
+ ldx [%o0 + 0x00], %g1
+ be 10f
+ ldx [%o0 + 0x08], %g2
+1: xor %g1, %g3, %o5
+ MOVXTOD_O5_F0
+ xor %g2, %g7, %o5
+ MOVXTOD_O5_F2
+ add %g7, 1, %g7
+ add %g3, 1, %o5
+ movrz %g7, %o5, %g3
+ xor %g1, %g3, %o5
+ MOVXTOD_O5_F4
+ xor %g2, %g7, %o5
+ MOVXTOD_O5_F6
+ add %g7, 1, %g7
+ add %g3, 1, %o5
+ movrz %g7, %o5, %g3
+ ENCRYPT_128_2(8, 0, 2, 4, 6, 56, 58, 60, 62)
+ ldd [%o1 + 0x00], %f56
+ ldd [%o1 + 0x08], %f58
+ ldd [%o1 + 0x10], %f60
+ ldd [%o1 + 0x18], %f62
+ fxor %f56, %f0, %f56
+ fxor %f58, %f2, %f58
+ fxor %f60, %f4, %f60
+ fxor %f62, %f6, %f62
+ std %f56, [%o2 + 0x00]
+ std %f58, [%o2 + 0x08]
+ std %f60, [%o2 + 0x10]
+ std %f62, [%o2 + 0x18]
+ subcc %o3, 0x20, %o3
+ add %o1, 0x20, %o1
+ brgz %o3, 1b
+ add %o2, 0x20, %o2
+ brlz,pt %o3, 11f
+ nop
+10: xor %g1, %g3, %o5
+ MOVXTOD_O5_F0
+ xor %g2, %g7, %o5
+ MOVXTOD_O5_F2
+ add %g7, 1, %g7
+ add %g3, 1, %o5
+ movrz %g7, %o5, %g3
+ ENCRYPT_128(8, 0, 2, 4, 6)
+ ldd [%o1 + 0x00], %f4
+ ldd [%o1 + 0x08], %f6
+ fxor %f4, %f0, %f4
+ fxor %f6, %f2, %f6
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+11: stx %g3, [%o4 + 0x00]
+ retl
+ stx %g7, [%o4 + 0x08]
+ENDPROC(aes_sparc64_ctr_crypt_128)
+
+ .align 32
+ENTRY(aes_sparc64_ctr_crypt_192)
+ /* %o0=key, %o1=input, %o2=output, %o3=len, %o4=IV */
+ ldx [%o4 + 0x00], %g3
+ ldx [%o4 + 0x08], %g7
+ subcc %o3, 0x10, %o3
+ ldx [%o0 + 0x00], %g1
+ be 10f
+ ldx [%o0 + 0x08], %g2
+1: xor %g1, %g3, %o5
+ MOVXTOD_O5_F0
+ xor %g2, %g7, %o5
+ MOVXTOD_O5_F2
+ add %g7, 1, %g7
+ add %g3, 1, %o5
+ movrz %g7, %o5, %g3
+ xor %g1, %g3, %o5
+ MOVXTOD_O5_F4
+ xor %g2, %g7, %o5
+ MOVXTOD_O5_F6
+ add %g7, 1, %g7
+ add %g3, 1, %o5
+ movrz %g7, %o5, %g3
+ ENCRYPT_192_2(8, 0, 2, 4, 6, 56, 58, 60, 62)
+ ldd [%o1 + 0x00], %f56
+ ldd [%o1 + 0x08], %f58
+ ldd [%o1 + 0x10], %f60
+ ldd [%o1 + 0x18], %f62
+ fxor %f56, %f0, %f56
+ fxor %f58, %f2, %f58
+ fxor %f60, %f4, %f60
+ fxor %f62, %f6, %f62
+ std %f56, [%o2 + 0x00]
+ std %f58, [%o2 + 0x08]
+ std %f60, [%o2 + 0x10]
+ std %f62, [%o2 + 0x18]
+ subcc %o3, 0x20, %o3
+ add %o1, 0x20, %o1
+ brgz %o3, 1b
+ add %o2, 0x20, %o2
+ brlz,pt %o3, 11f
+ nop
+10: xor %g1, %g3, %o5
+ MOVXTOD_O5_F0
+ xor %g2, %g7, %o5
+ MOVXTOD_O5_F2
+ add %g7, 1, %g7
+ add %g3, 1, %o5
+ movrz %g7, %o5, %g3
+ ENCRYPT_192(8, 0, 2, 4, 6)
+ ldd [%o1 + 0x00], %f4
+ ldd [%o1 + 0x08], %f6
+ fxor %f4, %f0, %f4
+ fxor %f6, %f2, %f6
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+11: stx %g3, [%o4 + 0x00]
+ retl
+ stx %g7, [%o4 + 0x08]
+ENDPROC(aes_sparc64_ctr_crypt_192)
+
+ .align 32
+ENTRY(aes_sparc64_ctr_crypt_256)
+ /* %o0=key, %o1=input, %o2=output, %o3=len, %o4=IV */
+ ldx [%o4 + 0x00], %g3
+ ldx [%o4 + 0x08], %g7
+ subcc %o3, 0x10, %o3
+ ldx [%o0 + 0x00], %g1
+ be 10f
+ ldx [%o0 + 0x08], %g2
+1: xor %g1, %g3, %o5
+ MOVXTOD_O5_F0
+ xor %g2, %g7, %o5
+ MOVXTOD_O5_F2
+ add %g7, 1, %g7
+ add %g3, 1, %o5
+ movrz %g7, %o5, %g3
+ xor %g1, %g3, %o5
+ MOVXTOD_O5_F4
+ xor %g2, %g7, %o5
+ MOVXTOD_O5_F6
+ add %g7, 1, %g7
+ add %g3, 1, %o5
+ movrz %g7, %o5, %g3
+ ENCRYPT_256_2(8, 0, 2, 4, 6)
+ ldd [%o1 + 0x00], %f56
+ ldd [%o1 + 0x08], %f58
+ ldd [%o1 + 0x10], %f60
+ ldd [%o1 + 0x18], %f62
+ fxor %f56, %f0, %f56
+ fxor %f58, %f2, %f58
+ fxor %f60, %f4, %f60
+ fxor %f62, %f6, %f62
+ std %f56, [%o2 + 0x00]
+ std %f58, [%o2 + 0x08]
+ std %f60, [%o2 + 0x10]
+ std %f62, [%o2 + 0x18]
+ subcc %o3, 0x20, %o3
+ add %o1, 0x20, %o1
+ brgz %o3, 1b
+ add %o2, 0x20, %o2
+ brlz,pt %o3, 11f
+ nop
+10: ldd [%o0 + 0xd0], %f56
+ ldd [%o0 + 0xd8], %f58
+ ldd [%o0 + 0xe0], %f60
+ ldd [%o0 + 0xe8], %f62
+ xor %g1, %g3, %o5
+ MOVXTOD_O5_F0
+ xor %g2, %g7, %o5
+ MOVXTOD_O5_F2
+ add %g7, 1, %g7
+ add %g3, 1, %o5
+ movrz %g7, %o5, %g3
+ ENCRYPT_256(8, 0, 2, 4, 6)
+ ldd [%o1 + 0x00], %f4
+ ldd [%o1 + 0x08], %f6
+ fxor %f4, %f0, %f4
+ fxor %f6, %f2, %f6
+ std %f4, [%o2 + 0x00]
+ std %f6, [%o2 + 0x08]
+11: stx %g3, [%o4 + 0x00]
+ retl
+ stx %g7, [%o4 + 0x08]
+ENDPROC(aes_sparc64_ctr_crypt_256)
diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig
index 61d435c450bb..4970463ea0aa 100644
--- a/lib/crypto/tests/Kconfig
+++ b/lib/crypto/tests/Kconfig
@@ -38,6 +38,23 @@ config CRYPTO_LIB_MD5_KUNIT_TEST
KUnit tests for the MD5 cryptographic hash function and its
corresponding HMAC.
+config CRYPTO_LIB_MLDSA_KUNIT_TEST
+ tristate "KUnit tests for ML-DSA" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
+ select CRYPTO_LIB_BENCHMARK_VISIBLE
+ select CRYPTO_LIB_MLDSA
+ help
+ KUnit tests for the ML-DSA digital signature algorithm.
+
+config CRYPTO_LIB_NH_KUNIT_TEST
+ tristate "KUnit tests for NH" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
+ select CRYPTO_LIB_NH
+ help
+ KUnit tests for the NH almost-universal hash function.
+
config CRYPTO_LIB_POLY1305_KUNIT_TEST
tristate "KUnit tests for Poly1305" if !KUNIT_ALL_TESTS
depends on KUNIT
diff --git a/lib/crypto/tests/Makefile b/lib/crypto/tests/Makefile
index 5109a0651925..f4262379f56c 100644
--- a/lib/crypto/tests/Makefile
+++ b/lib/crypto/tests/Makefile
@@ -4,6 +4,8 @@ obj-$(CONFIG_CRYPTO_LIB_BLAKE2B_KUNIT_TEST) += blake2b_kunit.o
obj-$(CONFIG_CRYPTO_LIB_BLAKE2S_KUNIT_TEST) += blake2s_kunit.o
obj-$(CONFIG_CRYPTO_LIB_CURVE25519_KUNIT_TEST) += curve25519_kunit.o
obj-$(CONFIG_CRYPTO_LIB_MD5_KUNIT_TEST) += md5_kunit.o
+obj-$(CONFIG_CRYPTO_LIB_MLDSA_KUNIT_TEST) += mldsa_kunit.o
+obj-$(CONFIG_CRYPTO_LIB_NH_KUNIT_TEST) += nh_kunit.o
obj-$(CONFIG_CRYPTO_LIB_POLY1305_KUNIT_TEST) += poly1305_kunit.o
obj-$(CONFIG_CRYPTO_LIB_POLYVAL_KUNIT_TEST) += polyval_kunit.o
obj-$(CONFIG_CRYPTO_LIB_SHA1_KUNIT_TEST) += sha1_kunit.o
diff --git a/lib/crypto/tests/mldsa-testvecs.h b/lib/crypto/tests/mldsa-testvecs.h
new file mode 100644
index 000000000000..d2d6a042a829
--- /dev/null
+++ b/lib/crypto/tests/mldsa-testvecs.h
@@ -0,0 +1,1887 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* ML-DSA test vectors extracted from leancrypto */
+
+struct mldsa_testvector {
+ enum mldsa_alg alg;
+ int sig_len;
+ int msg_len;
+ int pk_len;
+ const u8 *sig;
+ const u8 *msg;
+ const u8 *pk;
+};
+
+static const struct mldsa_testvector mldsa44_testvector = {
+ .alg = MLDSA44,
+ .pk_len = MLDSA44_PUBLIC_KEY_SIZE,
+ .pk =
+ (const u8[MLDSA44_PUBLIC_KEY_SIZE]) {
+ 0x8f, 0x61, 0x67, 0xa9, 0x7c, 0x61, 0xc2, 0xf2, 0x87,
+ 0xe2, 0x28, 0xf8, 0x44, 0x80, 0x6f, 0xb0, 0x10, 0xc1,
+ 0x14, 0xf6, 0x88, 0x42, 0x76, 0xbe, 0x05, 0xd2, 0x56,
+ 0xa0, 0xb7, 0x46, 0xcf, 0xc5, 0x76, 0x0a, 0x52, 0xfe,
+ 0xa3, 0x3c, 0x05, 0x6e, 0xd5, 0xd3, 0xbd, 0x80, 0x03,
+ 0x29, 0x25, 0x96, 0xdf, 0xa9, 0x5b, 0x12, 0x42, 0x89,
+ 0x6e, 0x03, 0x2c, 0x42, 0x64, 0xee, 0xc7, 0xf7, 0x55,
+ 0xfe, 0xfd, 0x15, 0x74, 0xee, 0x2d, 0xb3, 0xbf, 0xf2,
+ 0x24, 0xe7, 0x35, 0x45, 0x77, 0x67, 0x44, 0xd2, 0x0c,
+ 0x43, 0xfc, 0x7b, 0x47, 0x56, 0xad, 0xc5, 0xe7, 0x37,
+ 0x49, 0x21, 0x12, 0x57, 0x7f, 0xca, 0x7f, 0x5d, 0xac,
+ 0x62, 0x5b, 0x8d, 0xbf, 0xdb, 0x64, 0xac, 0x12, 0x1d,
+ 0x7f, 0x7a, 0x2f, 0xa0, 0x2c, 0xfe, 0x95, 0x4b, 0x78,
+ 0xdb, 0xf0, 0x98, 0x97, 0x70, 0x62, 0xfc, 0x64, 0x4a,
+ 0x1b, 0xbc, 0x30, 0x1b, 0x51, 0x13, 0x47, 0x6e, 0x83,
+ 0xd2, 0xa2, 0xcf, 0x39, 0xba, 0xd3, 0x00, 0x62, 0x7c,
+ 0x5b, 0xe6, 0x14, 0x55, 0xd5, 0xfc, 0xbf, 0x15, 0x65,
+ 0xd7, 0x1f, 0xbb, 0xf6, 0x2b, 0x46, 0x38, 0x1e, 0xf3,
+ 0x8f, 0x0d, 0x57, 0x8a, 0x41, 0xfb, 0x47, 0x19, 0xe1,
+ 0x79, 0xca, 0x98, 0x1a, 0x73, 0x4d, 0x8a, 0xc0, 0xa1,
+ 0xa7, 0x4a, 0x28, 0x4a, 0x92, 0x6c, 0x77, 0x4f, 0x18,
+ 0xe1, 0xce, 0x11, 0x14, 0xd5, 0xf6, 0xc0, 0xa8, 0x1e,
+ 0x26, 0x25, 0xe4, 0x30, 0xb2, 0x6f, 0x89, 0x6e, 0xc6,
+ 0x44, 0x1a, 0xd3, 0xca, 0xe1, 0x05, 0x0d, 0x61, 0x80,
+ 0xd7, 0xbc, 0x56, 0x0a, 0x57, 0x9f, 0x16, 0x40, 0x84,
+ 0x1e, 0xc0, 0x5e, 0xcd, 0xb6, 0xc8, 0x5d, 0x87, 0xd6,
+ 0xee, 0xcb, 0x21, 0x2f, 0x22, 0x9a, 0x7e, 0xea, 0x2e,
+ 0xf5, 0x87, 0xf0, 0x44, 0x10, 0x3d, 0x42, 0x6d, 0x3f,
+ 0x4f, 0xa0, 0x21, 0x8e, 0x40, 0x75, 0x3b, 0xaa, 0xd4,
+ 0xd9, 0x37, 0x0a, 0x35, 0x5b, 0xba, 0xbd, 0x11, 0x17,
+ 0x7b, 0x7e, 0xfc, 0xb1, 0x1c, 0x5c, 0x71, 0xce, 0xde,
+ 0xa5, 0xec, 0xd6, 0x8b, 0x50, 0x64, 0x02, 0xca, 0x84,
+ 0x26, 0xfe, 0x03, 0x9e, 0xaf, 0x13, 0x05, 0x1c, 0x85,
+ 0x32, 0x92, 0x85, 0x84, 0x83, 0xb6, 0x76, 0x27, 0xa7,
+ 0xd8, 0x0c, 0xa4, 0xb5, 0x65, 0x7a, 0xbf, 0x2e, 0x64,
+ 0xce, 0x82, 0x0d, 0x27, 0xd3, 0x2c, 0x9d, 0xb5, 0xa5,
+ 0x51, 0xe3, 0xab, 0xbd, 0xe2, 0xe0, 0x64, 0x71, 0x0f,
+ 0x99, 0x09, 0x6a, 0x40, 0x9d, 0x8c, 0x6d, 0x63, 0x70,
+ 0x42, 0xe2, 0xa8, 0x5c, 0x71, 0xd2, 0x88, 0x10, 0xbc,
+ 0x3b, 0x9d, 0xc8, 0x3a, 0x8a, 0xf3, 0x81, 0x0a, 0x0e,
+ 0xd8, 0xf6, 0x13, 0x90, 0xc2, 0xda, 0x4c, 0x4f, 0x6f,
+ 0x1f, 0x61, 0x0d, 0x46, 0xac, 0x5c, 0x4a, 0xcc, 0x23,
+ 0xfb, 0xf2, 0xf8, 0x9f, 0x48, 0x1f, 0xaf, 0x24, 0xb4,
+ 0xc7, 0xcb, 0x6f, 0x80, 0x74, 0xa3, 0xdb, 0xa8, 0x61,
+ 0x12, 0x60, 0x08, 0x56, 0x85, 0x47, 0x05, 0x32, 0x93,
+ 0x43, 0x9b, 0xa6, 0xf6, 0x56, 0x3b, 0xab, 0x93, 0x28,
+ 0x19, 0xda, 0xad, 0xb5, 0xaa, 0x2e, 0x83, 0x3d, 0x37,
+ 0x0e, 0x83, 0xf2, 0xfe, 0xdd, 0xe8, 0xd9, 0x53, 0x36,
+ 0x3b, 0x5d, 0x8e, 0x24, 0xa9, 0x3a, 0x8f, 0x85, 0x4b,
+ 0x50, 0xf7, 0x61, 0x0f, 0x20, 0x92, 0x09, 0x1f, 0xe4,
+ 0x24, 0x98, 0x9f, 0xa4, 0x52, 0x12, 0x2a, 0xae, 0x6f,
+ 0xd6, 0x0d, 0xb5, 0x22, 0x72, 0x83, 0xfb, 0x4f, 0xef,
+ 0xa6, 0x55, 0x9a, 0x14, 0xab, 0x82, 0x89, 0x1f, 0xf2,
+ 0x0b, 0x14, 0x76, 0xb7, 0xf7, 0x14, 0xdd, 0xd6, 0xc1,
+ 0xe8, 0xb2, 0x99, 0x23, 0x28, 0xe8, 0xa4, 0x69, 0x18,
+ 0xf6, 0x3e, 0xb1, 0xff, 0xde, 0xf2, 0x2c, 0x7c, 0x73,
+ 0x93, 0x32, 0x52, 0x06, 0xeb, 0x59, 0xb2, 0x8f, 0x2f,
+ 0x1d, 0x6a, 0x85, 0x74, 0xd3, 0xe5, 0xa1, 0x95, 0xe4,
+ 0x96, 0x1e, 0x75, 0x16, 0xe4, 0x5c, 0x40, 0xf0, 0x20,
+ 0xb1, 0x10, 0xe7, 0x2a, 0x70, 0x41, 0xac, 0x49, 0x40,
+ 0x55, 0xef, 0xd1, 0x58, 0x24, 0x6a, 0xa6, 0x20, 0xdc,
+ 0x23, 0xdc, 0x66, 0x45, 0x4f, 0x6a, 0x52, 0x3c, 0x61,
+ 0xc8, 0xfb, 0x28, 0x1e, 0x8c, 0x3f, 0xfc, 0xc7, 0x73,
+ 0x2f, 0xf1, 0xe2, 0x31, 0xee, 0xa0, 0x5f, 0x12, 0x3f,
+ 0x94, 0xe5, 0x26, 0xc0, 0x62, 0xcc, 0x67, 0x8f, 0x5d,
+ 0xfd, 0x3d, 0x8f, 0x16, 0xae, 0x4e, 0x04, 0x54, 0x5b,
+ 0x02, 0x66, 0x00, 0x70, 0xe5, 0xcc, 0xb9, 0x51, 0x8c,
+ 0x1a, 0x5d, 0xf0, 0xfe, 0x7d, 0x1b, 0x2f, 0x0a, 0x48,
+ 0x94, 0xda, 0x4b, 0xb3, 0x05, 0x75, 0x3b, 0x25, 0xda,
+ 0xf2, 0x12, 0x47, 0xe2, 0xd7, 0xbb, 0xe7, 0x05, 0xa2,
+ 0x4e, 0xaf, 0x2f, 0x29, 0x6c, 0xbd, 0x80, 0x82, 0xdf,
+ 0xbb, 0x4b, 0x9d, 0x29, 0x9b, 0xef, 0xff, 0x17, 0x2a,
+ 0xa7, 0x2f, 0x4a, 0x2e, 0xbf, 0x29, 0x38, 0xcb, 0x94,
+ 0x9c, 0x10, 0x87, 0x69, 0x57, 0x7d, 0xd7, 0xcf, 0xc1,
+ 0x57, 0x0f, 0xc2, 0x9c, 0x3b, 0x1e, 0xbc, 0x55, 0x08,
+ 0xb1, 0x50, 0xb0, 0x28, 0x79, 0x1d, 0xd9, 0x2f, 0xa5,
+ 0x12, 0xcc, 0xa7, 0x5b, 0xcb, 0x67, 0x57, 0x13, 0x4a,
+ 0xb3, 0xd5, 0x34, 0xea, 0xd9, 0x6b, 0x15, 0x17, 0x1f,
+ 0xe7, 0x52, 0x2a, 0x11, 0xdf, 0xab, 0x3a, 0x8d, 0x1b,
+ 0xaa, 0xfa, 0x54, 0xf0, 0x20, 0x94, 0x40, 0x2d, 0x3e,
+ 0xf2, 0xa2, 0x8b, 0xbb, 0x86, 0xce, 0x29, 0x87, 0xb1,
+ 0xfa, 0x27, 0xf2, 0x5a, 0x79, 0xc2, 0xf8, 0xe9, 0xf2,
+ 0x7c, 0x5a, 0xcd, 0x45, 0x8e, 0x8b, 0xba, 0xad, 0x13,
+ 0x52, 0x79, 0xd5, 0x0f, 0x59, 0xfb, 0x07, 0x15, 0x1f,
+ 0xb3, 0xe6, 0xc8, 0x66, 0xf7, 0x37, 0x19, 0xd8, 0x33,
+ 0xdd, 0xc1, 0xb3, 0x96, 0x4b, 0x28, 0x43, 0xf8, 0x5e,
+ 0xc7, 0xe8, 0x81, 0x6e, 0xd0, 0xb2, 0x5a, 0x3d, 0xf1,
+ 0x68, 0x8f, 0xf0, 0xf5, 0x1a, 0x6d, 0xc3, 0xaa, 0x5b,
+ 0x72, 0x27, 0xbd, 0xd6, 0x7c, 0x9b, 0xbf, 0x89, 0x6a,
+ 0x09, 0xf0, 0x48, 0xf0, 0x8c, 0x27, 0x69, 0x28, 0xf3,
+ 0x5f, 0x53, 0xe3, 0x4d, 0x60, 0x4a, 0xb8, 0xc5, 0xf9,
+ 0x85, 0x07, 0x3e, 0xfb, 0xd7, 0x21, 0x69, 0xd5, 0xec,
+ 0x18, 0x68, 0xb6, 0x55, 0x15, 0xac, 0x2e, 0x0f, 0x5c,
+ 0x2e, 0x9e, 0x12, 0x10, 0x5e, 0xc6, 0xb3, 0xcd, 0xe6,
+ 0x3a, 0x2f, 0x43, 0xf6, 0x75, 0x31, 0x3c, 0x90, 0x34,
+ 0x1c, 0x3d, 0x45, 0xaa, 0x8e, 0x08, 0xcf, 0x58, 0x67,
+ 0x34, 0xd4, 0x24, 0xb8, 0x20, 0x69, 0xfe, 0xf0, 0x33,
+ 0xe9, 0x3e, 0xbd, 0xe5, 0x18, 0x9f, 0x66, 0xc9, 0x0d,
+ 0x6f, 0x47, 0x99, 0xf7, 0x0c, 0xdd, 0xad, 0x8c, 0x6b,
+ 0x80, 0xed, 0x19, 0x61, 0x8a, 0xba, 0x62, 0x2f, 0xcc,
+ 0x0e, 0x47, 0xe0, 0xc6, 0x1f, 0x2f, 0x44, 0x40, 0x17,
+ 0xb6, 0x89, 0xc6, 0xf5, 0xc2, 0x97, 0x89, 0x38, 0x6c,
+ 0x8e, 0x2c, 0x46, 0x0b, 0x6e, 0x01, 0x47, 0xd3, 0x2f,
+ 0x58, 0xf8, 0xc7, 0x3b, 0x49, 0xb2, 0x35, 0x9f, 0x67,
+ 0xc9, 0x6c, 0xde, 0x30, 0x3b, 0x50, 0x19, 0x65, 0xbb,
+ 0x73, 0xa1, 0x47, 0x01, 0x6a, 0x3d, 0xe3, 0x85, 0x4d,
+ 0xd0, 0x72, 0x0d, 0xbc, 0x81, 0x52, 0xe8, 0x1a, 0x8b,
+ 0x85, 0x4c, 0x6f, 0x0e, 0xfc, 0x59, 0x84, 0x7a, 0xf2,
+ 0x28, 0x3e, 0x02, 0xcb, 0xe2, 0x4a, 0xbf, 0xac, 0x22,
+ 0x34, 0x86, 0xe4, 0x7d, 0x6b, 0xa3, 0x52, 0xac, 0xff,
+ 0xe5, 0xbe, 0x0c, 0x8d, 0xf5, 0xd8, 0xfd, 0x5a, 0x3d,
+ 0xad, 0x0d, 0xc0, 0x02, 0xd0, 0x58, 0x8e, 0x7c, 0x50,
+ 0x7c, 0x09, 0xc0, 0xdb, 0xd7, 0xdf, 0xe0, 0xb2, 0x6f,
+ 0xb2, 0x79, 0x0d, 0xc1, 0xa0, 0xb1, 0x7e, 0xe3, 0x0d,
+ 0xfc, 0x93, 0x43, 0x8c, 0x86, 0x68, 0xa6, 0x51, 0x93,
+ 0x42, 0xb7, 0xcd, 0x13, 0x56, 0x6e, 0xdc, 0x63, 0x51,
+ 0x23, 0xcf, 0x29, 0xc5, 0x5a, 0x66, 0x43, 0x80, 0xfe,
+ 0x28, 0x15, 0x71, 0x52, 0x87, 0xe2, 0x18, 0x10, 0xad,
+ 0x94, 0x47, 0x2f, 0xe3, 0x5d, 0x7a, 0x02, 0x6d, 0x31,
+ 0x58, 0xae, 0x2f, 0x96, 0x53, 0x1b, 0x6c, 0x0e, 0x25,
+ 0xea, 0x41, 0xd3, 0x29, 0x27, 0x22, 0x24, 0x8d, 0x1d,
+ 0x8e, 0xd1, 0x33, 0x76, 0x67, 0x7d, 0x9d, 0xd9, 0xa7,
+ 0x3e, 0x61, 0xd0, 0xad, 0x93, 0xb9, 0xdf, 0x87, 0x3a,
+ 0x7b, 0x89, 0xc7, 0x1d, 0x91, 0xec, 0x43, 0xa4, 0xdc,
+ 0x02, 0x88, 0x2e, 0xaa, 0xb2, 0x58, 0xa5, 0xd3, 0x68,
+ 0x9c, 0x9f, 0x60, 0x12, 0xc8, 0x7e, 0x7d, 0x40, 0x80,
+ 0xfd, 0xb4, 0xbf, 0x56, 0xf4, 0x01, 0x39, 0x3d, 0xa0,
+ 0x34, 0x48, 0x79, 0x75, 0xe2, 0x0f, 0x60, 0x09, 0x42,
+ 0x11, 0x6f, 0xa5, 0x31, 0x46, 0xb7, 0x03, 0xc8, 0x61,
+ 0x53, 0x39, 0x1e, 0xf4, 0x99, 0x36, 0x7d, 0xc0, 0x87,
+ 0xda, 0x63, 0x71, 0x9b, 0x29, 0x7b, 0x4e, 0x6f, 0x09,
+ 0xa2, 0x2c, 0xa5, 0xc2, 0xb9, 0xe7, 0xe0, 0x56, 0x8b,
+ 0x1d, 0xbb, 0xcc, 0x34, 0x8c, 0xbc, 0xb6, 0x0a, 0xc9,
+ 0xfa, 0x4a, 0x31, 0x63, 0x0d, 0x30, 0xff, 0x59, 0x3d,
+ 0x8c, 0x4d, 0x74, 0x28, 0xf4, 0xe9, 0x97, 0x43, 0x05,
+ 0x3a, 0x33, 0x51, 0x51, 0xe4, 0x0e, 0x33, 0xae, 0x2c,
+ 0xda, 0x28, 0x83, 0x93, 0x4e, 0xfe, 0x37, 0x1d, 0x6c,
+ 0x25, 0x1e, 0x24, 0xbc, 0x3a, 0x5c, 0x68, 0xac, 0x54,
+ 0x3a, 0x47, 0x74, 0x35, 0xff, 0x37, 0x80, 0x12, 0x30,
+ 0xd7, 0x31, 0x2a, 0x49, 0x51, 0x2d, 0x4f, 0xd2, 0x9c,
+ 0xca, 0x55, 0x87, 0xd0, 0x41, 0x86, 0xc7, 0xf2, 0xda,
+ 0xf8, 0x4b, 0x08, 0x23, 0xb3, 0x00, 0xb7, 0xb6, 0x4f,
+ 0x2e, 0xaf, 0xb8, 0x8e, 0xb1, 0x44, 0xe1, 0xed, 0x67,
+ 0xf8, 0x80, 0xa7, 0x04, 0xa0, 0x66, 0xe6, 0xb5, 0x69,
+ 0xca, 0x95, 0x71, 0xc8, 0x0d, 0x3d, 0xf6, 0x77, 0xfd,
+ 0x2c, 0x95, 0xed, 0xe5, 0x22, 0x43, 0xd9,
+ },
+ .msg_len = 64,
+ .msg =
+ (const u8[64]) {
+ 0x6d, 0xb3, 0x8e, 0x80, 0xaf, 0x5f, 0x19, 0xd9,
+ 0xb0, 0xcf, 0xad, 0x58, 0xc7, 0x27, 0xae, 0x12,
+ 0x4e, 0x7d, 0xa3, 0x1a, 0xe3, 0x85, 0xc6, 0xaa,
+ 0xf6, 0xa1, 0x9a, 0xb1, 0xe9, 0xe0, 0xfe, 0x89,
+ 0x1e, 0xc5, 0x6f, 0x10, 0x18, 0x24, 0xab, 0xa8,
+ 0x6d, 0x03, 0xd0, 0x3d, 0xc3, 0xff, 0x67, 0xe7,
+ 0x3a, 0x95, 0x94, 0xc8, 0x49, 0x51, 0x8f, 0xa0,
+ 0x65, 0xcb, 0x20, 0x29, 0x2a, 0x6d, 0xf7, 0xf2,
+ },
+ .sig_len = MLDSA44_SIGNATURE_SIZE,
+ .sig =
+ (const u8[MLDSA44_SIGNATURE_SIZE]) {
+ 0x5e, 0x05, 0x37, 0xe2, 0xc1, 0x20, 0xce, 0x7b, 0x8a,
+ 0xdf, 0xf2, 0x22, 0x61, 0x17, 0x58, 0xaa, 0x3c, 0xe4,
+ 0x82, 0x9c, 0x0e, 0xb6, 0x1f, 0xb4, 0x98, 0x0f, 0xba,
+ 0x8e, 0x51, 0x15, 0x67, 0x76, 0x0b, 0x98, 0x63, 0xda,
+ 0x17, 0xd3, 0xbb, 0xbe, 0x16, 0x29, 0x71, 0xab, 0xba,
+ 0x99, 0xed, 0x3f, 0xd4, 0xc2, 0x16, 0x71, 0xb6, 0x21,
+ 0x87, 0x48, 0xaa, 0xb5, 0x39, 0x5e, 0xfb, 0x5d, 0x68,
+ 0x3b, 0xd3, 0x60, 0xf4, 0x5b, 0x85, 0x2a, 0x5b, 0xb5,
+ 0xce, 0x6e, 0xf3, 0x39, 0xc3, 0xbe, 0x96, 0xa7, 0x61,
+ 0xc9, 0xbf, 0xdf, 0x33, 0x1d, 0xec, 0xb9, 0x2b, 0x7a,
+ 0x05, 0xce, 0x1e, 0xd9, 0x46, 0x70, 0xca, 0x54, 0xbf,
+ 0xdc, 0x46, 0x9e, 0x2f, 0x29, 0x18, 0x57, 0x96, 0x84,
+ 0xac, 0xe9, 0xd7, 0x74, 0xeb, 0x8e, 0x6b, 0xec, 0x46,
+ 0x9a, 0x2a, 0xfa, 0xde, 0x80, 0x09, 0x53, 0xd9, 0xeb,
+ 0x9d, 0xf7, 0xaa, 0xe2, 0xe5, 0xdc, 0xc3, 0xd9, 0x70,
+ 0xe5, 0x8b, 0xa8, 0xba, 0x2b, 0x41, 0x72, 0x92, 0x25,
+ 0xaf, 0xd9, 0xb4, 0x5a, 0x53, 0xb7, 0xcc, 0x1d, 0x69,
+ 0xf1, 0x53, 0x5b, 0x52, 0x38, 0xbc, 0x47, 0x24, 0x8c,
+ 0x1d, 0x28, 0x5d, 0x5c, 0x1c, 0xc9, 0x9d, 0xea, 0x1c,
+ 0xb1, 0xb3, 0x49, 0x68, 0xd5, 0xad, 0xdc, 0x47, 0x58,
+ 0x6d, 0x38, 0x33, 0xe7, 0x9b, 0xaa, 0x89, 0xb1, 0x96,
+ 0x0b, 0xcb, 0xc4, 0x24, 0x73, 0xf2, 0xe7, 0xb6, 0xca,
+ 0x74, 0x55, 0x1b, 0xb5, 0xb7, 0x9e, 0x2e, 0xe3, 0x3a,
+ 0x32, 0x5d, 0x1d, 0x6e, 0x15, 0xe6, 0xb8, 0xfb, 0xce,
+ 0x57, 0x81, 0x15, 0xb5, 0xcf, 0x67, 0x2b, 0x55, 0x4c,
+ 0x85, 0x6f, 0x28, 0xa6, 0xbb, 0xb4, 0x28, 0x76, 0x91,
+ 0xa4, 0x29, 0xa1, 0x50, 0x7c, 0xed, 0x9a, 0xfc, 0xe4,
+ 0xbc, 0xd7, 0x28, 0x62, 0x28, 0x61, 0x4d, 0x8d, 0x8c,
+ 0x5a, 0x5e, 0x4d, 0x1d, 0x5e, 0x73, 0xcc, 0x0b, 0x9d,
+ 0x56, 0x73, 0xc7, 0xf2, 0x26, 0xf7, 0x7e, 0x61, 0xa4,
+ 0x86, 0xf5, 0x1c, 0xd1, 0x00, 0xd0, 0x31, 0xc5, 0x03,
+ 0x17, 0x1c, 0xec, 0x04, 0xe5, 0xc7, 0x13, 0xb6, 0x81,
+ 0x78, 0x3d, 0x27, 0x87, 0x36, 0xf3, 0x2a, 0x59, 0x96,
+ 0xeb, 0x44, 0xfd, 0xb9, 0x95, 0xb7, 0x76, 0xb1, 0x08,
+ 0xc4, 0x98, 0xb1, 0x08, 0x36, 0x2a, 0x63, 0x72, 0x4f,
+ 0xef, 0x47, 0xfc, 0x84, 0x09, 0x18, 0x60, 0xb7, 0x8a,
+ 0xff, 0xae, 0x32, 0x3c, 0x79, 0xdf, 0xd6, 0x24, 0xbe,
+ 0x9c, 0x38, 0x68, 0x92, 0xde, 0x81, 0x80, 0x22, 0x06,
+ 0xf2, 0xe4, 0xde, 0x75, 0x4e, 0xd6, 0x36, 0x93, 0x44,
+ 0xd1, 0xa4, 0x2e, 0x2e, 0x05, 0x87, 0xbd, 0xf7, 0xc5,
+ 0xc8, 0x1c, 0x7b, 0x00, 0xe8, 0x11, 0x7f, 0xc2, 0x39,
+ 0x4b, 0x7b, 0x97, 0x11, 0x92, 0x6c, 0xff, 0x89, 0x7f,
+ 0x26, 0x89, 0x4f, 0x38, 0xfd, 0xdd, 0x08, 0xa7, 0xce,
+ 0x6f, 0xe8, 0x57, 0x9b, 0x46, 0xe5, 0xdb, 0x72, 0x03,
+ 0x1e, 0x7d, 0xb0, 0x77, 0xb9, 0xcc, 0xdb, 0x6c, 0xa7,
+ 0xd8, 0x30, 0x34, 0xad, 0xa7, 0xe4, 0x63, 0xf0, 0x19,
+ 0x0e, 0x5d, 0x3b, 0xe0, 0xff, 0x40, 0x1c, 0xa5, 0xb3,
+ 0xb9, 0x87, 0x6e, 0x2c, 0xf3, 0x5f, 0xcd, 0x54, 0x2a,
+ 0xc0, 0x6e, 0x2b, 0xd9, 0x2d, 0xcc, 0xd5, 0x68, 0x95,
+ 0x4a, 0x4a, 0x84, 0x60, 0x54, 0xee, 0xa0, 0x21, 0x9e,
+ 0x8d, 0x20, 0xcb, 0xe8, 0xc5, 0x5a, 0xba, 0xe2, 0xaa,
+ 0x6e, 0x1c, 0xb1, 0xdf, 0x18, 0x9f, 0x94, 0xc7, 0x77,
+ 0x5a, 0x2c, 0x0e, 0x05, 0xaa, 0x2a, 0x54, 0x58, 0x6c,
+ 0xb3, 0x2e, 0x2f, 0xa4, 0x6e, 0x98, 0xbb, 0x6f, 0x41,
+ 0x6d, 0xbd, 0x71, 0x95, 0xe4, 0xbc, 0x13, 0x37, 0x99,
+ 0x0d, 0xac, 0x27, 0x69, 0xb9, 0x0b, 0x14, 0x5f, 0x6e,
+ 0xd2, 0x2b, 0xe2, 0x0c, 0xc6, 0xbc, 0x10, 0x11, 0x47,
+ 0xb7, 0x37, 0x2c, 0x0e, 0x88, 0xcd, 0xbb, 0xf7, 0x28,
+ 0xd6, 0x4a, 0x9d, 0xff, 0x3c, 0x2f, 0x7d, 0x2b, 0xe8,
+ 0xe8, 0x9e, 0xae, 0x7b, 0xe6, 0x2a, 0xb3, 0x4e, 0x20,
+ 0xcc, 0xf1, 0x81, 0x8e, 0xed, 0x6d, 0xe2, 0x99, 0xf5,
+ 0xb5, 0x1a, 0x30, 0x95, 0x52, 0x34, 0xf5, 0x3f, 0xc3,
+ 0x31, 0xd6, 0xbe, 0xa2, 0xc8, 0xdc, 0xe4, 0x1c, 0xf6,
+ 0x0f, 0x4d, 0x0b, 0x89, 0x8e, 0x66, 0x93, 0x88, 0xb8,
+ 0xad, 0xbc, 0xdc, 0x96, 0x01, 0x9f, 0x16, 0x70, 0xf5,
+ 0x4f, 0xa4, 0x0e, 0x0f, 0xc3, 0xf6, 0x9c, 0xe1, 0xa1,
+ 0xe3, 0xec, 0x9d, 0x09, 0xcd, 0x90, 0x52, 0x26, 0x09,
+ 0xd9, 0x9c, 0xde, 0xbd, 0xdf, 0xbb, 0xf4, 0x50, 0xd1,
+ 0x89, 0x68, 0xf6, 0x86, 0x53, 0x33, 0x5a, 0xf6, 0x54,
+ 0xb5, 0x7c, 0xe1, 0xd7, 0x8d, 0xb8, 0x58, 0xf5, 0xda,
+ 0x14, 0xc8, 0x35, 0x1c, 0xcf, 0x44, 0x62, 0xbc, 0xd7,
+ 0xe3, 0xd8, 0x32, 0xcf, 0x16, 0xf5, 0x2f, 0x55, 0x23,
+ 0xc0, 0x1b, 0xc4, 0xe3, 0x28, 0xc8, 0xc8, 0x97, 0x70,
+ 0x8b, 0x06, 0x98, 0xfb, 0xf6, 0x33, 0x6b, 0x86, 0x1c,
+ 0xdb, 0x2a, 0x3c, 0x08, 0x08, 0x57, 0xd3, 0x4a, 0xf8,
+ 0x22, 0x26, 0x78, 0x65, 0x5f, 0xa6, 0xf8, 0x9f, 0x22,
+ 0x76, 0x62, 0xb0, 0x08, 0x68, 0x70, 0xea, 0x72, 0x57,
+ 0x6b, 0xe7, 0xf7, 0xc6, 0x12, 0x9a, 0x49, 0x50, 0xa9,
+ 0xa5, 0x6c, 0xe7, 0xda, 0xb4, 0xbf, 0xb6, 0xbf, 0x4f,
+ 0xdf, 0x9e, 0x9b, 0xb4, 0xb3, 0x8d, 0x1a, 0x12, 0x16,
+ 0x68, 0xd2, 0x63, 0xae, 0x92, 0x77, 0x1f, 0x03, 0xa5,
+ 0xed, 0x58, 0x3b, 0xe9, 0x0b, 0xfe, 0xfc, 0xae, 0x53,
+ 0x0b, 0x5f, 0x13, 0xf2, 0xd2, 0xe2, 0x0b, 0xec, 0x75,
+ 0x85, 0x68, 0x0c, 0x57, 0xde, 0x1b, 0x6d, 0x78, 0x0b,
+ 0x19, 0x66, 0xa8, 0xf5, 0x45, 0x72, 0x2b, 0x01, 0x06,
+ 0xf6, 0xd1, 0x47, 0x21, 0x24, 0x07, 0xf7, 0x71, 0x03,
+ 0xbc, 0xb0, 0x7c, 0x5b, 0x5c, 0x24, 0xff, 0x74, 0x47,
+ 0x62, 0x81, 0xc3, 0x0b, 0x31, 0x76, 0x90, 0x5b, 0xef,
+ 0x95, 0xa8, 0xa7, 0x02, 0xa1, 0xbf, 0xe1, 0xf4, 0x16,
+ 0x06, 0x8a, 0x97, 0x39, 0x35, 0xcf, 0xf3, 0xa7, 0x4a,
+ 0x43, 0xba, 0x05, 0x95, 0x7d, 0x73, 0x76, 0x7a, 0x53,
+ 0xef, 0xf8, 0x4e, 0xcb, 0x04, 0x70, 0x4c, 0xee, 0xff,
+ 0x82, 0xbd, 0xcd, 0xc1, 0xbe, 0x3d, 0x83, 0x71, 0x03,
+ 0xf0, 0xc0, 0x2b, 0x98, 0xf9, 0x60, 0x54, 0x02, 0x7d,
+ 0xa6, 0x41, 0xcc, 0xa3, 0xd7, 0x8d, 0xfd, 0xce, 0x28,
+ 0xae, 0x0f, 0x48, 0x17, 0x2a, 0xaf, 0xe9, 0xb9, 0x4a,
+ 0x8a, 0x22, 0xd2, 0x4d, 0xd3, 0x1b, 0xa3, 0x39, 0x88,
+ 0x8a, 0x8f, 0x5b, 0x44, 0x97, 0xb9, 0x04, 0x1b, 0x58,
+ 0x67, 0x74, 0x2f, 0x07, 0x7a, 0x52, 0xa9, 0x9d, 0xa4,
+ 0x41, 0x28, 0xf2, 0x35, 0xca, 0x68, 0x4e, 0x4a, 0x3a,
+ 0x66, 0xb9, 0x88, 0x2e, 0x65, 0x1d, 0x47, 0x04, 0xed,
+ 0xdb, 0xe1, 0x40, 0x12, 0x06, 0x13, 0x62, 0x28, 0x3d,
+ 0x0b, 0x35, 0x06, 0xc6, 0x2b, 0xb3, 0x71, 0x3c, 0xfa,
+ 0x77, 0xec, 0x47, 0x93, 0x78, 0x36, 0x25, 0x19, 0xd7,
+ 0x70, 0x30, 0x8a, 0x4c, 0x94, 0xdc, 0x3e, 0xeb, 0x61,
+ 0x25, 0xbc, 0xa0, 0x27, 0xd9, 0x17, 0xa5, 0x19, 0x4f,
+ 0xf4, 0x93, 0x32, 0x56, 0x9a, 0x0b, 0x77, 0xb4, 0x55,
+ 0x1b, 0x8f, 0x9e, 0x69, 0x5b, 0xe2, 0x6d, 0x70, 0x15,
+ 0x79, 0x5c, 0xf6, 0xb6, 0x04, 0xa2, 0x01, 0x37, 0x74,
+ 0x20, 0xb8, 0x62, 0xf6, 0x37, 0x3c, 0xab, 0xca, 0x71,
+ 0xa5, 0x8a, 0x56, 0x5d, 0x6a, 0x4a, 0x61, 0x2e, 0xb8,
+ 0x62, 0x7d, 0x47, 0x34, 0x7d, 0xcd, 0x4d, 0x70, 0x23,
+ 0xf5, 0xaa, 0xd1, 0xa5, 0xf0, 0x4c, 0x38, 0xc3, 0x98,
+ 0x79, 0x4c, 0x0b, 0x6b, 0xcc, 0xe7, 0xd7, 0x09, 0xae,
+ 0x23, 0x9b, 0x2f, 0xde, 0x70, 0xc6, 0xad, 0x0f, 0x66,
+ 0xb5, 0x78, 0x6b, 0x0b, 0xb0, 0x2e, 0x94, 0xf2, 0xa8,
+ 0x8b, 0x74, 0xf0, 0x03, 0x47, 0xd8, 0xec, 0xe8, 0x1f,
+ 0xa3, 0x7b, 0x38, 0x9e, 0x0e, 0xc0, 0x47, 0xd2, 0x0f,
+ 0x8e, 0x7f, 0xb1, 0x83, 0xd3, 0x86, 0x79, 0x3c, 0xa1,
+ 0xae, 0xc4, 0xaf, 0xae, 0x9d, 0x83, 0xc0, 0xd1, 0x2b,
+ 0x2b, 0xda, 0x50, 0x8c, 0xea, 0x41, 0x97, 0x9b, 0x0f,
+ 0x15, 0xc2, 0xe2, 0x8f, 0x39, 0x0b, 0x92, 0xdd, 0xde,
+ 0x52, 0x62, 0x74, 0xdc, 0xda, 0x11, 0x87, 0x4d, 0xa9,
+ 0x4a, 0xc5, 0x2f, 0xae, 0xaf, 0xc1, 0xc3, 0x05, 0xfa,
+ 0x38, 0xcc, 0x5c, 0xb1, 0x9f, 0xe0, 0x82, 0x90, 0xb3,
+ 0xd5, 0xdc, 0xf4, 0x55, 0xdb, 0xea, 0x94, 0x06, 0x7c,
+ 0x2c, 0x82, 0x78, 0xeb, 0xa5, 0x01, 0xf0, 0x3d, 0x4b,
+ 0x87, 0xdd, 0xd5, 0x91, 0x4f, 0xf3, 0xa7, 0xdf, 0xa1,
+ 0xd8, 0x31, 0xde, 0x05, 0x99, 0x67, 0x3d, 0xa4, 0x6b,
+ 0x19, 0xa3, 0xe8, 0x55, 0xb7, 0xf5, 0xc3, 0x63, 0x5e,
+ 0xd4, 0x38, 0xf9, 0x24, 0x64, 0x7d, 0x17, 0xc1, 0x07,
+ 0xbe, 0x39, 0x54, 0x1b, 0x44, 0xe5, 0xc6, 0x3c, 0x02,
+ 0xb1, 0x6f, 0xff, 0x8c, 0xcb, 0x79, 0xe2, 0xec, 0x4d,
+ 0x01, 0xfa, 0x7f, 0x88, 0x1d, 0xc3, 0x4c, 0x6a, 0xfb,
+ 0x0b, 0xc6, 0x57, 0xc3, 0xd8, 0x24, 0x47, 0x41, 0xbd,
+ 0x27, 0xc4, 0xd4, 0x49, 0xfb, 0x52, 0xe6, 0x77, 0x5f,
+ 0x0a, 0xdf, 0xea, 0xd5, 0xd3, 0x22, 0xc3, 0x53, 0x16,
+ 0xf3, 0x1b, 0x7b, 0x09, 0xd7, 0x10, 0x0e, 0x23, 0xae,
+ 0x16, 0x8a, 0x93, 0xcb, 0xc9, 0xb7, 0xb8, 0xff, 0xd2,
+ 0x50, 0x1f, 0x25, 0xa7, 0x71, 0x8f, 0x3f, 0xc0, 0xe1,
+ 0x37, 0x10, 0x0b, 0x43, 0x6e, 0x2b, 0x16, 0x59, 0x8f,
+ 0x77, 0x77, 0x6b, 0x77, 0xce, 0x76, 0x6b, 0x37, 0x81,
+ 0xaf, 0x83, 0x42, 0x92, 0x93, 0xe5, 0x39, 0xca, 0xd2,
+ 0x20, 0x2e, 0xcf, 0x24, 0x26, 0x4c, 0x51, 0x1c, 0x58,
+ 0xc5, 0x8d, 0x05, 0x11, 0xdf, 0xae, 0x51, 0x38, 0xde,
+ 0xab, 0x4e, 0x04, 0xc8, 0x24, 0x24, 0x0d, 0xd5, 0x9c,
+ 0x5b, 0x2b, 0xe6, 0x0d, 0x83, 0x95, 0xcd, 0x1c, 0x89,
+ 0xa1, 0xaf, 0x67, 0x47, 0xfb, 0x08, 0x02, 0xf8, 0x8b,
+ 0x63, 0x05, 0x73, 0x20, 0x64, 0xd7, 0x52, 0x15, 0xa4,
+ 0x5d, 0x63, 0x73, 0x73, 0x12, 0x0b, 0xdd, 0xfe, 0x9f,
+ 0xb7, 0xe8, 0xa8, 0x94, 0x3a, 0x86, 0xff, 0xcf, 0x7d,
+ 0x24, 0xbd, 0xb9, 0xea, 0x68, 0x23, 0xf4, 0x07, 0xc3,
+ 0xfe, 0x63, 0xd0, 0xab, 0x65, 0x8a, 0xf0, 0x6d, 0x81,
+ 0x8c, 0xc8, 0x0e, 0xc6, 0x6b, 0xdd, 0x2e, 0x65, 0x9b,
+ 0x17, 0xcf, 0x82, 0x69, 0x46, 0xba, 0x62, 0x5d, 0x31,
+ 0x33, 0x60, 0x18, 0x94, 0xa5, 0x77, 0x24, 0xc6, 0x45,
+ 0xe5, 0xb3, 0xd5, 0x12, 0x10, 0xc9, 0x22, 0x98, 0xf9,
+ 0xca, 0x20, 0x89, 0x79, 0x04, 0x08, 0xf5, 0x1c, 0xf8,
+ 0x50, 0x8c, 0x25, 0xaa, 0x90, 0x90, 0x44, 0xbc, 0xfb,
+ 0x5d, 0x3f, 0xf8, 0x38, 0x64, 0xca, 0x8d, 0xff, 0x17,
+ 0xce, 0x70, 0x51, 0x90, 0x75, 0x6b, 0x7d, 0x64, 0x43,
+ 0x56, 0xcd, 0xf8, 0x85, 0x93, 0x65, 0x09, 0x81, 0x30,
+ 0x76, 0x79, 0xcc, 0xdf, 0x9c, 0x6d, 0xff, 0x89, 0x38,
+ 0x60, 0xbf, 0x07, 0xcb, 0x2f, 0xc9, 0x87, 0xd7, 0xac,
+ 0x74, 0x19, 0x57, 0x90, 0x5e, 0x69, 0x61, 0xf6, 0xca,
+ 0xea, 0x45, 0x6b, 0xe2, 0xfe, 0x2c, 0xff, 0x1b, 0x23,
+ 0x15, 0x52, 0xdd, 0x57, 0xfe, 0x1d, 0x10, 0xea, 0x0f,
+ 0xce, 0x98, 0xe7, 0x47, 0x27, 0xec, 0x36, 0xe5, 0x68,
+ 0x17, 0xcf, 0xdc, 0xb9, 0xef, 0x6a, 0xbc, 0xec, 0x78,
+ 0x08, 0x64, 0x06, 0xe1, 0x1c, 0xc6, 0x87, 0xd6, 0x0a,
+ 0xb1, 0x81, 0xc6, 0xb6, 0xf8, 0x8b, 0xe3, 0x19, 0x8c,
+ 0xce, 0x46, 0x40, 0xc5, 0xc2, 0xae, 0x50, 0x26, 0x4a,
+ 0x90, 0x91, 0x8d, 0xfe, 0x6b, 0x7d, 0x0a, 0x54, 0x4a,
+ 0x4b, 0x48, 0x74, 0x4a, 0x37, 0x21, 0x7f, 0xdd, 0x87,
+ 0xa3, 0x1e, 0xac, 0xcd, 0xf5, 0x9e, 0x75, 0xa2, 0x52,
+ 0x63, 0x76, 0xca, 0x9e, 0x02, 0xeb, 0xe6, 0xa6, 0x73,
+ 0xad, 0xea, 0xe8, 0x3e, 0x6f, 0x44, 0xed, 0xe8, 0x01,
+ 0x29, 0x19, 0x6a, 0x20, 0x35, 0xa7, 0xf0, 0xf1, 0xaf,
+ 0xc0, 0x3b, 0xb1, 0xd5, 0xe4, 0xfb, 0xf7, 0xd7, 0x2f,
+ 0x33, 0x6c, 0x73, 0xfd, 0xe5, 0x5c, 0x63, 0xf6, 0x1c,
+ 0x06, 0x13, 0xaf, 0xc1, 0x80, 0x55, 0x07, 0xae, 0x8c,
+ 0x13, 0x74, 0xf6, 0xe0, 0x54, 0x15, 0xd8, 0xe0, 0xa5,
+ 0x03, 0xcf, 0x22, 0xbe, 0x18, 0xef, 0x26, 0xad, 0x9c,
+ 0x9d, 0x51, 0xb1, 0x3b, 0x37, 0x03, 0xbf, 0xf0, 0xc5,
+ 0xcb, 0x6c, 0x5d, 0x30, 0xa9, 0x5a, 0x10, 0x90, 0xfa,
+ 0xb4, 0xd4, 0x0e, 0x6b, 0x4a, 0x0a, 0x6c, 0x9d, 0x2e,
+ 0x69, 0xe8, 0xec, 0x69, 0xe2, 0x50, 0xab, 0x2f, 0xdc,
+ 0xff, 0xaf, 0xac, 0x65, 0xe7, 0xf0, 0xc1, 0x6f, 0x7c,
+ 0x2d, 0xa1, 0xeb, 0x97, 0x90, 0x7c, 0x1e, 0xa8, 0x53,
+ 0x1b, 0x87, 0xc5, 0xa9, 0xa1, 0xcf, 0x86, 0x7e, 0x11,
+ 0xf8, 0xd6, 0x14, 0xda, 0x19, 0x81, 0x19, 0xb4, 0x45,
+ 0x1c, 0x7c, 0xb9, 0x96, 0xa2, 0xac, 0x79, 0x24, 0x94,
+ 0x7c, 0xb2, 0x1e, 0x83, 0xea, 0xc4, 0xb9, 0xd2, 0x0d,
+ 0x4c, 0x55, 0x3d, 0x15, 0x7b, 0x65, 0xd8, 0xff, 0x03,
+ 0x5d, 0xed, 0x3c, 0x94, 0x76, 0x19, 0x40, 0x3b, 0xcc,
+ 0x45, 0xbe, 0x91, 0x19, 0x8c, 0x75, 0xe5, 0xd2, 0xbe,
+ 0x67, 0x40, 0xb1, 0x67, 0x8e, 0x2a, 0x34, 0xd5, 0x99,
+ 0xee, 0xd9, 0x4f, 0x89, 0x7c, 0xf0, 0xd6, 0x93, 0x59,
+ 0x4b, 0x3a, 0x8d, 0xe6, 0xbd, 0xde, 0xce, 0xef, 0x8b,
+ 0x3c, 0xe3, 0xf7, 0x06, 0x33, 0x27, 0x8d, 0xd9, 0x22,
+ 0x1a, 0x65, 0x40, 0xfc, 0x69, 0x1b, 0x7d, 0xf0, 0xed,
+ 0xe4, 0xe0, 0x7f, 0x6d, 0x23, 0xed, 0x11, 0xd1, 0x07,
+ 0xb0, 0x2f, 0x8a, 0xbf, 0x51, 0x37, 0x22, 0x04, 0xed,
+ 0x93, 0xea, 0x1d, 0x0b, 0x30, 0x15, 0x89, 0x22, 0x7a,
+ 0x45, 0x56, 0x99, 0xc6, 0xac, 0xd6, 0xce, 0x61, 0xea,
+ 0xb2, 0x59, 0xe8, 0xb5, 0xfc, 0x87, 0xa7, 0xfe, 0x09,
+ 0xa2, 0x0d, 0x5e, 0xbe, 0xb9, 0xd4, 0x9a, 0x1b, 0x60,
+ 0xda, 0xb9, 0x32, 0xf1, 0x30, 0x3e, 0xb2, 0x45, 0x6d,
+ 0x55, 0x0c, 0x2c, 0x4b, 0x9a, 0xc0, 0xbb, 0x8e, 0xac,
+ 0x9c, 0x95, 0x5f, 0x08, 0x88, 0xa0, 0x53, 0x05, 0x75,
+ 0x8d, 0x9e, 0x9d, 0x3f, 0x0f, 0xdd, 0x50, 0x0d, 0xf8,
+ 0x11, 0xbd, 0xf9, 0xfb, 0x22, 0x5c, 0x7b, 0x9e, 0x7c,
+ 0x8e, 0x2f, 0x0e, 0xdb, 0xb8, 0x1d, 0x0c, 0x5e, 0x82,
+ 0xf3, 0x8e, 0xec, 0x32, 0x1c, 0x59, 0x73, 0xa5, 0xf3,
+ 0x5b, 0x47, 0x00, 0x64, 0x89, 0x68, 0x3b, 0xaf, 0xe8,
+ 0xe2, 0x9b, 0xa6, 0xac, 0x2c, 0xf9, 0x2b, 0x92, 0xf3,
+ 0xf0, 0x5b, 0xcc, 0x75, 0x22, 0xd5, 0xf4, 0x2b, 0x06,
+ 0x96, 0xc8, 0x50, 0xee, 0xac, 0x62, 0x16, 0x45, 0x9e,
+ 0xbc, 0xcc, 0x8f, 0x5a, 0x66, 0xc6, 0x30, 0x7c, 0xe0,
+ 0x22, 0xcc, 0xb9, 0xda, 0x0b, 0x0a, 0xbd, 0x2a, 0x2e,
+ 0x46, 0x7d, 0xb6, 0x86, 0x70, 0xa3, 0x16, 0x49, 0x85,
+ 0x28, 0x7b, 0xe9, 0x00, 0x6b, 0xfa, 0x06, 0xb0, 0xeb,
+ 0xbd, 0x67, 0x28, 0x6f, 0x27, 0xd7, 0x9c, 0x7f, 0xda,
+ 0xec, 0xf4, 0x7e, 0x55, 0xe1, 0x0c, 0x29, 0x61, 0x7a,
+ 0xf5, 0xb6, 0xb8, 0xa5, 0xef, 0x36, 0x6a, 0xad, 0x59,
+ 0x22, 0xbd, 0x3d, 0xad, 0x86, 0xe7, 0x4c, 0x69, 0x26,
+ 0x0f, 0xbf, 0x67, 0xad, 0x65, 0x32, 0xbd, 0x21, 0xd6,
+ 0x59, 0x6b, 0xe3, 0xda, 0xc1, 0x6f, 0x82, 0x41, 0x2c,
+ 0xaa, 0xe4, 0x8c, 0xfc, 0x7c, 0x61, 0x28, 0x51, 0x52,
+ 0x3d, 0xf1, 0x84, 0xb5, 0x0b, 0xfd, 0x1f, 0x2a, 0x06,
+ 0x2e, 0x30, 0xed, 0x63, 0x43, 0xc9, 0x83, 0x97, 0xb1,
+ 0xd4, 0x80, 0x6f, 0x2c, 0x50, 0xec, 0x20, 0x95, 0x42,
+ 0xa0, 0x34, 0x94, 0x1a, 0xa9, 0x5e, 0x5b, 0x59, 0xe3,
+ 0x39, 0xac, 0xbd, 0x2f, 0x77, 0x36, 0x59, 0x9c, 0xc3,
+ 0x3c, 0x66, 0x87, 0xf5, 0x81, 0x4b, 0xb0, 0x10, 0x4a,
+ 0xe6, 0x46, 0xe7, 0xce, 0x93, 0x7b, 0x24, 0x6b, 0x2e,
+ 0xc1, 0xe5, 0xaf, 0x4b, 0x71, 0x22, 0xad, 0x88, 0xda,
+ 0x55, 0xcb, 0xe0, 0x73, 0xd1, 0x65, 0x7d, 0xa5, 0x7f,
+ 0x36, 0xbc, 0x42, 0xc2, 0x78, 0x9f, 0x88, 0xe8, 0xdb,
+ 0xff, 0x8a, 0x5a, 0x80, 0x34, 0x3a, 0x23, 0x4c, 0x8a,
+ 0x81, 0xff, 0xbd, 0xb7, 0x88, 0xd0, 0x73, 0x07, 0x8a,
+ 0x4e, 0xa7, 0x4a, 0x61, 0x0f, 0x1f, 0x1c, 0xe7, 0x34,
+ 0x37, 0x1c, 0x53, 0x90, 0x3b, 0xa4, 0x32, 0x6c, 0x6d,
+ 0xe8, 0x00, 0xde, 0xe0, 0x0c, 0x5e, 0x06, 0xef, 0xb8,
+ 0x48, 0x2e, 0xb3, 0xda, 0xac, 0x92, 0x4d, 0x0d, 0x95,
+ 0x75, 0x44, 0x01, 0x6f, 0x97, 0xc3, 0x29, 0x76, 0x33,
+ 0x36, 0x9a, 0xae, 0xfb, 0x1b, 0x43, 0xe5, 0xb1, 0x54,
+ 0x3a, 0x9c, 0x76, 0x7f, 0x76, 0x83, 0xc9, 0x9c, 0xd6,
+ 0x56, 0x59, 0x83, 0xa9, 0xde, 0xd7, 0xb0, 0xf3, 0x34,
+ 0x11, 0x31, 0x06, 0x8e, 0xe9, 0xd4, 0x79, 0xd5, 0x3d,
+ 0x31, 0x6b, 0x59, 0xe9, 0x54, 0x69, 0x12, 0xfd, 0x44,
+ 0x59, 0x4e, 0x1b, 0x3b, 0xb4, 0x12, 0xe9, 0xfb, 0xb0,
+ 0xb4, 0x84, 0xb9, 0x7d, 0xea, 0x4f, 0xd1, 0x5f, 0xd0,
+ 0x3e, 0xce, 0xef, 0x5c, 0xf7, 0xea, 0x55, 0xa0, 0x8f,
+ 0xa8, 0xa7, 0x98, 0xe7, 0xa1, 0x6b, 0x3f, 0xba, 0x5a,
+ 0x32, 0x4b, 0xfa, 0x31, 0xb6, 0x63, 0x86, 0x19, 0x00,
+ 0xa2, 0x6d, 0x7d, 0x15, 0x56, 0x05, 0x68, 0xa3, 0xe0,
+ 0xf3, 0xd4, 0x82, 0xcf, 0xeb, 0xd4, 0x1c, 0xd0, 0xb6,
+ 0x14, 0x5e, 0x9e, 0x6b, 0xed, 0x7a, 0x02, 0x1a, 0xcd,
+ 0x09, 0xdc, 0x26, 0x98, 0x50, 0x11, 0x34, 0x39, 0x50,
+ 0x5a, 0x70, 0x79, 0x85, 0xca, 0xd2, 0xf2, 0x0c, 0x0d,
+ 0x12, 0x1f, 0x2e, 0x41, 0x46, 0x51, 0x72, 0x75, 0x78,
+ 0x8c, 0xa4, 0xaf, 0xba, 0xca, 0xd3, 0xdf, 0xea, 0xf8,
+ 0x09, 0x0b, 0x36, 0x45, 0x4f, 0x77, 0x83, 0xae, 0xbc,
+ 0xc5, 0xce, 0xe1, 0xf6, 0x1d, 0x1e, 0x38, 0x56, 0x9c,
+ 0x9f, 0xb1, 0xbd, 0xda, 0xe7, 0xf0, 0xf4, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1f, 0x2c, 0x38,
+ },
+};
+
+static const struct mldsa_testvector mldsa65_testvector = {
+ .alg = MLDSA65,
+ .pk_len = MLDSA65_PUBLIC_KEY_SIZE,
+ .pk =
+ (const u8[MLDSA65_PUBLIC_KEY_SIZE]) {
+ 0x9f, 0x55, 0x1e, 0x7f, 0x9c, 0x08, 0xb2, 0x83, 0xfd,
+ 0x5b, 0xa2, 0xac, 0x4f, 0x26, 0xc2, 0xf5, 0x06, 0x05,
+ 0x96, 0x08, 0x24, 0xad, 0xec, 0xe4, 0x99, 0xcc, 0x6c,
+ 0xbd, 0x55, 0x37, 0x15, 0x94, 0xab, 0x31, 0x9e, 0x56,
+ 0xe5, 0xe4, 0x55, 0xec, 0x4d, 0x49, 0x5b, 0x5a, 0x7a,
+ 0xe8, 0xc3, 0x4a, 0x08, 0x44, 0x4a, 0xc2, 0x2d, 0xe4,
+ 0x61, 0x33, 0x90, 0x20, 0x71, 0x45, 0xa5, 0x45, 0xd0,
+ 0x83, 0x2b, 0x32, 0x6c, 0xa7, 0x9e, 0x76, 0xcd, 0xfb,
+ 0x58, 0x15, 0x9e, 0x74, 0x0d, 0x67, 0x57, 0xb1, 0x06,
+ 0x5b, 0x5d, 0xd5, 0x1c, 0xbb, 0x95, 0x40, 0x1c, 0x71,
+ 0x31, 0x03, 0xef, 0xff, 0x04, 0x6b, 0xdd, 0xa2, 0xf0,
+ 0x32, 0x00, 0x72, 0xbc, 0x87, 0xb6, 0x2c, 0x1f, 0x90,
+ 0x7f, 0x92, 0xa0, 0xb2, 0x04, 0xdd, 0xa9, 0xaf, 0x7f,
+ 0x01, 0x28, 0x4c, 0xb2, 0x57, 0x2d, 0x56, 0x93, 0xd0,
+ 0xc7, 0x54, 0x02, 0x90, 0x57, 0x70, 0x23, 0x57, 0xe8,
+ 0xe7, 0x33, 0x32, 0x98, 0xfc, 0x9b, 0x8e, 0x6e, 0x7b,
+ 0xaa, 0x5d, 0xb5, 0x4e, 0xe0, 0x5d, 0x97, 0xa3, 0xea,
+ 0x43, 0x7e, 0xb3, 0xa4, 0x8c, 0xcf, 0xdc, 0xc0, 0x51,
+ 0xa7, 0x99, 0x45, 0x3d, 0x3c, 0xa0, 0xba, 0xc5, 0xff,
+ 0xe1, 0x89, 0xb3, 0x7d, 0xc3, 0xdc, 0xe2, 0x23, 0x81,
+ 0xff, 0xa9, 0xc7, 0x93, 0xc6, 0x67, 0xad, 0x94, 0xcf,
+ 0xeb, 0x91, 0x78, 0x15, 0x25, 0xf7, 0xf5, 0x06, 0x08,
+ 0x2f, 0x0c, 0xee, 0x0b, 0x6a, 0x06, 0x59, 0xe0, 0x1f,
+ 0x2e, 0x5a, 0x12, 0x06, 0xf5, 0xf4, 0x8e, 0x75, 0x57,
+ 0xa9, 0x33, 0x23, 0x0f, 0xc2, 0x6f, 0x02, 0xf8, 0x68,
+ 0x0f, 0x62, 0x02, 0x81, 0xfe, 0x03, 0x7c, 0xaf, 0xd7,
+ 0x42, 0x5b, 0xcc, 0xe7, 0x2b, 0xea, 0x49, 0xab, 0x03,
+ 0x6d, 0x0a, 0x02, 0xae, 0x47, 0x79, 0xce, 0xfd, 0x18,
+ 0x76, 0x07, 0x9e, 0xa6, 0xbf, 0x7e, 0x8d, 0x73, 0xf9,
+ 0x44, 0xeb, 0x8c, 0xc5, 0x59, 0xb7, 0x19, 0xf6, 0x73,
+ 0x53, 0x42, 0x2a, 0x55, 0x7b, 0xb4, 0x56, 0x49, 0x08,
+ 0x9e, 0x9a, 0x65, 0x60, 0x70, 0x1d, 0xbd, 0xc6, 0x85,
+ 0x29, 0xde, 0xfe, 0x44, 0xae, 0xdf, 0x25, 0xfd, 0x5b,
+ 0x74, 0x6c, 0x96, 0xe6, 0x81, 0x37, 0x80, 0xe0, 0x9e,
+ 0xf3, 0x75, 0x63, 0xb4, 0xc9, 0x2f, 0x71, 0xe6, 0xeb,
+ 0xdf, 0xaf, 0x7e, 0xff, 0x9e, 0xe0, 0xbf, 0xca, 0xca,
+ 0x11, 0xed, 0xc6, 0x04, 0xd8, 0x49, 0x13, 0x2c, 0x63,
+ 0xf1, 0xb3, 0x17, 0x74, 0xd9, 0x50, 0x3f, 0xb9, 0x29,
+ 0x0e, 0x48, 0xa7, 0xf0, 0xdc, 0x78, 0x18, 0x0e, 0x9f,
+ 0xb7, 0xde, 0x36, 0x79, 0x67, 0xa4, 0x23, 0x08, 0xe7,
+ 0x62, 0xe8, 0xa4, 0xe5, 0xcf, 0xff, 0x35, 0x55, 0x36,
+ 0x2e, 0x3a, 0xe4, 0x45, 0x6a, 0x80, 0xf2, 0xca, 0xe7,
+ 0x40, 0x79, 0x14, 0xc4, 0x62, 0x38, 0xbb, 0xd0, 0x4e,
+ 0x6c, 0xb5, 0x85, 0x42, 0x3f, 0x35, 0xf7, 0xd7, 0x54,
+ 0xb8, 0x2b, 0x8b, 0xd5, 0x6f, 0x16, 0x61, 0x27, 0x23,
+ 0xac, 0xdb, 0xea, 0x9b, 0x3b, 0x99, 0xcd, 0x79, 0xe6,
+ 0x12, 0x09, 0x99, 0x09, 0xa4, 0xe1, 0x88, 0x25, 0x00,
+ 0x9e, 0x60, 0x16, 0x63, 0xd7, 0x42, 0x9b, 0xcc, 0x36,
+ 0x9a, 0x8d, 0xa3, 0x75, 0x36, 0xa1, 0xa8, 0xfc, 0xa2,
+ 0xfe, 0x29, 0x26, 0x4c, 0x93, 0x21, 0x44, 0x6b, 0x1c,
+ 0xba, 0xbd, 0xef, 0xff, 0x6d, 0x1f, 0x2b, 0x6c, 0x66,
+ 0x81, 0x9a, 0x3a, 0x1d, 0x0b, 0xd7, 0x24, 0xd4, 0xb8,
+ 0x93, 0xb5, 0x22, 0xf9, 0xd2, 0xf4, 0xa5, 0x05, 0x78,
+ 0x38, 0xae, 0x58, 0xf6, 0x50, 0x8f, 0x47, 0x1d, 0xf3,
+ 0xfb, 0x0d, 0x04, 0x14, 0xd1, 0xd6, 0xd8, 0x2e, 0xf2,
+ 0xbd, 0xf5, 0x71, 0x86, 0x4c, 0xdd, 0x61, 0x24, 0x18,
+ 0x5b, 0x54, 0xf5, 0xcd, 0x99, 0x89, 0x01, 0x8e, 0xd1,
+ 0x19, 0x52, 0xbc, 0x45, 0xed, 0x0e, 0xec, 0x72, 0x2f,
+ 0x5a, 0xe7, 0xdf, 0x36, 0x1c, 0x57, 0x9f, 0xb2, 0x8b,
+ 0xf2, 0x78, 0x1b, 0x3e, 0xc5, 0x48, 0x1f, 0x27, 0x04,
+ 0x76, 0x10, 0x44, 0xee, 0x5c, 0x68, 0x8f, 0xca, 0xd7,
+ 0x31, 0xfc, 0x5c, 0x40, 0x03, 0x2e, 0xbd, 0x1d, 0x59,
+ 0x13, 0x57, 0xbc, 0x33, 0xc6, 0xa1, 0xa3, 0xe5, 0x55,
+ 0x79, 0x9b, 0x7e, 0x49, 0xbb, 0x23, 0x96, 0xc3, 0x1c,
+ 0xfe, 0x66, 0xeb, 0x5b, 0x5f, 0xe5, 0x03, 0xc9, 0xa4,
+ 0xac, 0x4d, 0xc4, 0x50, 0xbb, 0xd3, 0xc1, 0x91, 0x48,
+ 0xe0, 0x93, 0x92, 0x2a, 0xdb, 0x41, 0x37, 0x98, 0xbc,
+ 0xa2, 0x7a, 0x09, 0x92, 0x0b, 0x1c, 0xe6, 0x4b, 0x1e,
+ 0x8e, 0x78, 0x81, 0x74, 0x7d, 0x6b, 0x71, 0xd5, 0xe7,
+ 0x0e, 0x7b, 0xc2, 0x74, 0x5d, 0x89, 0xf1, 0xfa, 0x59,
+ 0xaa, 0xf7, 0x86, 0x66, 0x7e, 0xc2, 0x9c, 0xf4, 0xd5,
+ 0x8d, 0xc0, 0xb7, 0xb7, 0xa2, 0xd5, 0xcd, 0x51, 0xc3,
+ 0x7d, 0xa9, 0x5e, 0x46, 0xba, 0x06, 0xa3, 0x4d, 0x60,
+ 0xd6, 0x68, 0xc6, 0xf9, 0x63, 0x88, 0x17, 0x5c, 0x20,
+ 0xe1, 0xc4, 0x0f, 0x3f, 0xc1, 0xa9, 0xa7, 0x3e, 0x39,
+ 0xef, 0x2f, 0xaf, 0xc4, 0x69, 0x29, 0xe3, 0xd4, 0x8d,
+ 0xe0, 0x0e, 0x88, 0xc2, 0x93, 0x43, 0xfb, 0x28, 0xcf,
+ 0x5d, 0x85, 0x50, 0xf7, 0xeb, 0x42, 0xf5, 0x87, 0xde,
+ 0xa5, 0x65, 0xef, 0x43, 0x0c, 0x57, 0x76, 0x09, 0xf4,
+ 0x5f, 0xde, 0x81, 0x0a, 0xd9, 0x59, 0x41, 0xa4, 0x6a,
+ 0xb7, 0x05, 0xc7, 0xa5, 0xfe, 0x49, 0xd5, 0x9b, 0x57,
+ 0x13, 0x14, 0x66, 0xe2, 0xb9, 0xcc, 0x09, 0x35, 0xd4,
+ 0xb0, 0xe0, 0xd1, 0x0d, 0x7e, 0x50, 0x48, 0x45, 0x21,
+ 0x00, 0x67, 0xb2, 0xad, 0xa7, 0x46, 0xe2, 0x6f, 0x70,
+ 0xe5, 0x3c, 0x88, 0x04, 0xaa, 0x21, 0xde, 0x03, 0xb6,
+ 0x6f, 0xfe, 0x43, 0x51, 0xdc, 0x2e, 0x5c, 0x6c, 0x77,
+ 0x8f, 0x8e, 0x9d, 0x1a, 0x5b, 0x35, 0xc5, 0xe4, 0x48,
+ 0x82, 0x17, 0x4b, 0xf0, 0xea, 0xc9, 0x0e, 0xd2, 0x8f,
+ 0xcd, 0xd5, 0x01, 0xbd, 0x7f, 0x0f, 0xf5, 0xae, 0x92,
+ 0x28, 0x1e, 0x2c, 0xf4, 0xe9, 0x03, 0xf7, 0x0a, 0xeb,
+ 0x84, 0x18, 0xa1, 0x37, 0x38, 0x8a, 0x11, 0xa2, 0x5d,
+ 0x8c, 0xf6, 0xe4, 0x3f, 0x5b, 0x87, 0x07, 0x6b, 0xb4,
+ 0x07, 0xe0, 0x8f, 0x30, 0xc4, 0xfa, 0x27, 0xae, 0xfc,
+ 0x02, 0xd1, 0x21, 0x5c, 0xbc, 0x0b, 0x93, 0x6e, 0x7e,
+ 0xf9, 0x6b, 0x80, 0x7a, 0x25, 0x84, 0x20, 0xf1, 0x6a,
+ 0xfa, 0x75, 0xed, 0x57, 0x61, 0x62, 0xa7, 0xf6, 0x5b,
+ 0xe1, 0xb0, 0x38, 0xc8, 0xe9, 0x6d, 0x3f, 0xef, 0x1e,
+ 0x99, 0x0b, 0xb7, 0xc8, 0x9f, 0x76, 0x5c, 0x04, 0x1f,
+ 0x02, 0x92, 0x00, 0xa7, 0x38, 0x3d, 0x00, 0x3b, 0xa7,
+ 0xbc, 0x39, 0x6e, 0xab, 0xf5, 0x10, 0xa8, 0xba, 0xd6,
+ 0x28, 0x6b, 0x0e, 0x00, 0x48, 0xf9, 0x3b, 0x5c, 0xde,
+ 0x59, 0x93, 0x46, 0xd6, 0x61, 0x52, 0x81, 0x71, 0x0f,
+ 0x0e, 0x61, 0xac, 0xc6, 0x7f, 0x15, 0x93, 0xa7, 0xc1,
+ 0x16, 0xb5, 0xef, 0x85, 0xd1, 0xa7, 0x61, 0xc2, 0x85,
+ 0x1d, 0x61, 0xc6, 0xae, 0xb3, 0x9e, 0x8d, 0x23, 0xa3,
+ 0xc8, 0xd5, 0xf2, 0xc7, 0x1b, 0x7e, 0xef, 0xd2, 0xdf,
+ 0x25, 0xaf, 0x4e, 0x81, 0x15, 0x59, 0xe5, 0x36, 0xb1,
+ 0xf1, 0xd5, 0xda, 0x58, 0xd8, 0xd9, 0x0d, 0x6d, 0xc9,
+ 0x25, 0xb5, 0xe8, 0x1d, 0x3b, 0xca, 0x2d, 0xab, 0xf2,
+ 0xe2, 0xe9, 0x55, 0xd7, 0xf4, 0xc7, 0xd0, 0x57, 0x7a,
+ 0x86, 0x15, 0x0a, 0x5a, 0x8b, 0xd7, 0x3f, 0x66, 0x0f,
+ 0x80, 0xb4, 0xe0, 0x5c, 0x33, 0xed, 0xaf, 0x1b, 0x3b,
+ 0x6d, 0x1c, 0xd9, 0x8c, 0xb5, 0x96, 0xa3, 0xfb, 0xcf,
+ 0xcc, 0x97, 0x1c, 0xae, 0x06, 0x19, 0x41, 0x61, 0xf8,
+ 0x97, 0x6b, 0x82, 0x5e, 0x1c, 0xbf, 0x6f, 0x43, 0x3d,
+ 0xe5, 0x00, 0xf5, 0xfe, 0x66, 0x48, 0x26, 0x31, 0xa1,
+ 0x72, 0x67, 0x6e, 0xd4, 0x5b, 0x6f, 0x66, 0xde, 0x70,
+ 0x8b, 0x2b, 0xc3, 0xa2, 0x30, 0xe9, 0x55, 0xc8, 0xff,
+ 0xf8, 0xd0, 0xdd, 0xa9, 0x21, 0x85, 0x6e, 0x6c, 0x82,
+ 0x66, 0xcc, 0x52, 0xf0, 0x9e, 0x1e, 0xb5, 0x3a, 0xff,
+ 0x4c, 0xf3, 0xae, 0x02, 0xc3, 0x4b, 0x76, 0x25, 0xbd,
+ 0xb0, 0x21, 0x54, 0x61, 0xda, 0x16, 0xd3, 0x23, 0x86,
+ 0x41, 0xa1, 0x4c, 0x59, 0x15, 0x95, 0x65, 0x85, 0xb6,
+ 0x8e, 0xa6, 0x37, 0xc0, 0xa2, 0x71, 0x1d, 0x67, 0x44,
+ 0x7b, 0xe5, 0x4c, 0x4f, 0xb6, 0x2c, 0x46, 0xf7, 0x29,
+ 0xa5, 0xf2, 0xd3, 0x51, 0x19, 0x91, 0x4d, 0xa7, 0xb5,
+ 0x05, 0xb9, 0x6e, 0x61, 0x6e, 0xf8, 0xc0, 0x01, 0xe5,
+ 0x41, 0x0a, 0x89, 0x64, 0x77, 0xf2, 0xc8, 0x63, 0x2d,
+ 0x9d, 0x27, 0x7f, 0x47, 0x30, 0x39, 0xdf, 0xb6, 0x6e,
+ 0x4f, 0x00, 0x3f, 0x15, 0xc6, 0xaf, 0x62, 0xdf, 0x3f,
+ 0x47, 0xe8, 0x42, 0x90, 0x77, 0x23, 0x7a, 0xaa, 0x99,
+ 0x53, 0x03, 0x63, 0x60, 0x59, 0x07, 0x52, 0x3c, 0xb5,
+ 0x67, 0x59, 0xfe, 0x08, 0xe6, 0x43, 0x0f, 0x3b, 0x08,
+ 0x7c, 0xc7, 0x07, 0x3c, 0xfa, 0x65, 0xea, 0x69, 0x51,
+ 0x41, 0x31, 0xb3, 0x05, 0x69, 0xba, 0x2c, 0xbf, 0x89,
+ 0x25, 0x9e, 0xfe, 0x07, 0x13, 0x78, 0x0e, 0x16, 0x54,
+ 0xdf, 0x23, 0xdf, 0x10, 0x69, 0x79, 0xd0, 0x33, 0xd7,
+ 0x21, 0x8b, 0xc8, 0x2a, 0xd0, 0x74, 0x0a, 0xfa, 0xb1,
+ 0x6f, 0xa3, 0xcb, 0x1d, 0xca, 0x4f, 0x00, 0x46, 0x6c,
+ 0x42, 0x09, 0xe0, 0x30, 0x89, 0x08, 0x33, 0x9b, 0x7b,
+ 0x7b, 0x0f, 0x69, 0x5c, 0x0d, 0x34, 0x91, 0xfc, 0xfe,
+ 0x22, 0x82, 0x02, 0xcd, 0xfa, 0x97, 0xe8, 0x28, 0x1d,
+ 0xbc, 0x13, 0x0b, 0xfd, 0x47, 0xa1, 0x7e, 0xa2, 0x86,
+ 0x4d, 0x6f, 0x12, 0x51, 0x35, 0x7d, 0x76, 0x8a, 0x58,
+ 0x05, 0xb6, 0x39, 0xa1, 0x2f, 0xd7, 0xda, 0xaf, 0x00,
+ 0xa0, 0x1a, 0x94, 0xd8, 0x23, 0x34, 0x99, 0x5c, 0xaf,
+ 0xcc, 0x15, 0x4b, 0x56, 0xb2, 0xd2, 0x81, 0x07, 0xd3,
+ 0xf3, 0x47, 0xa2, 0x45, 0x93, 0xcb, 0xae, 0xa7, 0x6b,
+ 0x3f, 0xf9, 0xea, 0xfc, 0x0e, 0x64, 0xf2, 0x93, 0x7f,
+ 0x24, 0x22, 0x73, 0x86, 0xc7, 0x2d, 0x75, 0x9b, 0x41,
+ 0x8b, 0xfb, 0x3b, 0x26, 0x2a, 0xe5, 0x0b, 0xd4, 0x00,
+ 0xe3, 0x2c, 0x69, 0x49, 0x62, 0x6c, 0x13, 0x58, 0x6e,
+ 0xac, 0x43, 0xe5, 0x2b, 0x3b, 0x88, 0xdc, 0xd4, 0x41,
+ 0xe8, 0xee, 0x4e, 0xc3, 0x28, 0x91, 0x17, 0x9a, 0x5a,
+ 0xdb, 0x80, 0x8b, 0x4d, 0x64, 0xcc, 0xbe, 0x66, 0xa4,
+ 0x62, 0xfb, 0x13, 0x44, 0x10, 0xd9, 0xe4, 0xd5, 0xa5,
+ 0xae, 0x9e, 0x42, 0x50, 0xfc, 0x78, 0xad, 0xfa, 0xc4,
+ 0xd0, 0x5a, 0x60, 0x9b, 0x45, 0x2b, 0x61, 0x5c, 0x57,
+ 0xb5, 0x92, 0x28, 0xe9, 0xf5, 0x35, 0x67, 0xc1, 0x5e,
+ 0xa8, 0x1c, 0x99, 0x36, 0x38, 0xb8, 0x5c, 0xff, 0x3d,
+ 0xa0, 0xfc, 0xb0, 0xbc, 0x3d, 0x2c, 0xb4, 0x36, 0x17,
+ 0xb4, 0x6d, 0xb5, 0x39, 0x45, 0xa9, 0x2a, 0x6b, 0xa2,
+ 0x24, 0x44, 0x30, 0xab, 0x2c, 0x82, 0x36, 0xdc, 0xd6,
+ 0x36, 0x5d, 0x0a, 0xdc, 0xee, 0x0f, 0x2b, 0x28, 0x99,
+ 0xdc, 0x67, 0x0d, 0xea, 0x6e, 0x42, 0xb9, 0x45, 0x7f,
+ 0xd2, 0x96, 0x1e, 0x60, 0x42, 0xeb, 0x1e, 0x5f, 0x8e,
+ 0xa9, 0xdc, 0xd3, 0x8a, 0xd6, 0xbd, 0x4e, 0x1f, 0x42,
+ 0x75, 0x1d, 0xe2, 0xc6, 0x11, 0xc9, 0x80, 0x1f, 0xfe,
+ 0x99, 0x52, 0x4d, 0x7b, 0x35, 0xf7, 0xb7, 0xc3, 0xee,
+ 0xd6, 0x94, 0xf5, 0x74, 0xa0, 0x69, 0xcd, 0x1f, 0x2b,
+ 0xd0, 0x87, 0xf7, 0x8c, 0x69, 0xc5, 0x96, 0x70, 0x91,
+ 0xe8, 0x3d, 0xd2, 0xcc, 0xf1, 0x4c, 0xcd, 0xe2, 0x14,
+ 0x00, 0x10, 0x4a, 0xd9, 0x6a, 0x5d, 0x65, 0x2c, 0x4b,
+ 0x79, 0x0c, 0xc4, 0x78, 0x5e, 0xc8, 0xc5, 0x37, 0x74,
+ 0x6d, 0x50, 0x5c, 0x34, 0x1f, 0xe0, 0xf4, 0xe3, 0xe1,
+ 0x86, 0x68, 0xb1, 0xea, 0x70, 0xf0, 0xae, 0xe4, 0x59,
+ 0xa1, 0x08, 0x7e, 0x35, 0xa3, 0x16, 0xd2, 0xb0, 0xa3,
+ 0xd4, 0xb0, 0x74, 0x8c, 0x05, 0x79, 0x73, 0xfb, 0xe6,
+ 0x65, 0x96, 0x15, 0x07, 0xd5, 0xaf, 0x88, 0x9e, 0x6b,
+ 0xf0, 0xbb, 0x3f, 0xe6, 0xd1, 0x6a, 0xe7, 0xc9, 0xae,
+ 0xd9, 0xb0, 0x16, 0x1c, 0x40, 0xeb, 0xdb, 0xc1, 0xbf,
+ 0x83, 0xdb, 0x8a, 0x4f, 0x96, 0xca, 0xd7, 0x22, 0x06,
+ 0x87, 0x08, 0x9d, 0x65, 0x2f, 0xd9, 0x8e, 0x95, 0x6c,
+ 0xcc, 0xbf, 0x76, 0x2a, 0xea, 0x5c, 0x8e, 0x5b, 0x17,
+ 0x0f, 0x75, 0x7b, 0xfa, 0xf9, 0xfb, 0xaa, 0x92, 0xc7,
+ 0x7e, 0x63, 0x63, 0x54, 0xa4, 0xff, 0xf6, 0xc0, 0xc0,
+ 0xf5, 0x70, 0xd8, 0xe3, 0xa4, 0x79, 0x16, 0xf0, 0x6f,
+ 0x90, 0x5e, 0xb7, 0xab, 0x6f, 0xab, 0x75, 0x3b, 0xe1,
+ 0x4c, 0xa8, 0x0b, 0x72, 0x5f, 0x5f, 0x11, 0x22, 0x36,
+ 0x71, 0x20, 0xd3, 0x5b, 0x5e, 0x07, 0x06, 0x76, 0x1a,
+ 0xcc, 0x5e, 0x7c, 0x97, 0x7d, 0xb2, 0x6b, 0xf8, 0x39,
+ 0x89, 0x37, 0xb6, 0x6d, 0xea, 0x74, 0x57, 0x28, 0xd7,
+ 0x0e, 0x9b, 0xeb, 0x28, 0x88, 0x90, 0xfd, 0x2d, 0x16,
+ 0x21, 0x74, 0x26, 0xc5, 0xb8, 0x44, 0xad, 0x9f, 0x97,
+ 0xf9, 0x65, 0x36, 0xd8, 0x00, 0x59, 0x17, 0x49, 0xf9,
+ 0xc7, 0xb3, 0x84, 0xb9, 0xe2, 0x95, 0xe0, 0xd1, 0x7f,
+ 0x5f, 0xaa, 0xd7, 0xfd, 0x6a, 0x6a, 0x83, 0x14, 0x46,
+ 0x1d, 0x12, 0x8d, 0x09, 0xc3, 0xa5, 0xca, 0x72, 0xa3,
+ 0x25, 0x65, 0xb6, 0x40, 0x25, 0x04, 0x51, 0xab, 0x22,
+ 0xeb, 0xd7, 0x69, 0xc9, 0x22, 0x9c, 0xa0, 0x19, 0x5c,
+ 0x1a, 0xfd, 0x41, 0x8f, 0x98, 0xc5, 0x71, 0xb8, 0x6f,
+ 0x76, 0xae, 0xfa, 0x9b, 0x03, 0xab, 0x43, 0x81, 0x3b,
+ 0x66, 0xae, 0xf0, 0xd2, 0xb7, 0xee, 0x9a, 0xe3, 0xae,
+ 0x45, 0xc1, 0x86, 0xb0, 0xce, 0x9e, 0x2b, 0xec, 0xb8,
+ 0xcf, 0xca, 0x0e, 0x8c, 0x33, 0xfa, 0xa7, 0xef, 0xf7,
+ 0xfc, 0xa1, 0x41, 0x49, 0xd3, 0x6d, 0xb5, 0x58, 0xe4,
+ 0x0e, 0x24, 0xd2, 0x8a, 0x74, 0xc9, 0x56, 0x2e, 0x53,
+ 0xc7, 0x7a, 0x38, 0x0f, 0x4b, 0xd9, 0xf9, 0x2f, 0xfa,
+ 0x7d, 0xee, 0x14, 0x18, 0xce, 0x75, 0x42, 0x6c, 0x03,
+ 0x34, 0xce, 0x80, 0xec, 0xf2, 0x05, 0xf0, 0xdf, 0xcd,
+ 0xf8, 0xdb, 0x26, 0x7d, 0xb6, 0x3d, 0x28, 0x24, 0x7e,
+ 0x7e, 0x39, 0x9f, 0xa6, 0xc6, 0xeb, 0x2a, 0xc8, 0x17,
+ 0x94, 0xa9, 0x89, 0xf5, 0xdf, 0xcb, 0x77, 0xfd, 0xc9,
+ 0x9e, 0x68, 0x98, 0x7d, 0x04, 0x50, 0x3c, 0x64, 0x1d,
+ 0x66, 0xb0, 0x97, 0x06, 0xb6, 0x08, 0x5b, 0xe4, 0x17,
+ 0x44, 0xd6, 0x94, 0x39, 0x6b, 0x03, 0x2c, 0xcb, 0x5a,
+ 0x8d, 0x86, 0x08, 0x23, 0x4f, 0x95, 0xa8, 0x1a,
+ },
+ .msg_len = 64,
+ .msg =
+ (const u8[64]) {
+ 0x1a, 0x84, 0x21, 0x0d, 0x35, 0x7a, 0x88, 0xc8,
+ 0x6a, 0x11, 0xe3, 0x15, 0x24, 0xec, 0x0d, 0x2e,
+ 0x76, 0xb9, 0xcf, 0x2b, 0x04, 0x25, 0x16, 0xae,
+ 0x62, 0x42, 0xa0, 0x20, 0x68, 0x25, 0x3e, 0xb4,
+ 0x75, 0xa7, 0x1d, 0x64, 0xc3, 0xd1, 0x08, 0x07,
+ 0x67, 0xb6, 0xf7, 0x76, 0x76, 0xf6, 0xd6, 0x62,
+ 0x66, 0x04, 0x89, 0x0c, 0x8f, 0x07, 0xac, 0xc8,
+ 0x51, 0x77, 0xd9, 0x47, 0x5e, 0xb5, 0x22, 0x20,
+ },
+ .sig_len = MLDSA65_SIGNATURE_SIZE,
+ .sig =
+ (const u8[MLDSA65_SIGNATURE_SIZE]) {
+ 0xda, 0xcf, 0x8d, 0x67, 0x59, 0x60, 0x6c, 0x39, 0x2d,
+ 0x89, 0xb6, 0xa1, 0xf3, 0x8c, 0x70, 0xcf, 0x25, 0x86,
+ 0x21, 0xa1, 0x9f, 0x20, 0x9e, 0xf5, 0xd2, 0xdd, 0xbd,
+ 0x99, 0xfa, 0xe4, 0xab, 0x77, 0x31, 0x65, 0x18, 0xa1,
+ 0xd1, 0x3f, 0x21, 0x70, 0x36, 0xe1, 0xf9, 0x5c, 0x28,
+ 0xb6, 0x7d, 0x34, 0xae, 0x66, 0xc9, 0x1c, 0x8e, 0xc6,
+ 0xf9, 0x45, 0x8c, 0xa9, 0xb2, 0xfb, 0x0f, 0x5b, 0xb8,
+ 0xf9, 0xf5, 0xe2, 0x37, 0x79, 0x12, 0xda, 0xa7, 0x72,
+ 0x9e, 0x0d, 0xf8, 0x88, 0x5b, 0x34, 0x49, 0x6c, 0xed,
+ 0xa3, 0x7f, 0x86, 0xd3, 0xd9, 0x2f, 0x44, 0x08, 0x0d,
+ 0xb7, 0xdb, 0x4a, 0xce, 0x02, 0x14, 0x02, 0xd6, 0x40,
+ 0x75, 0xe3, 0xc0, 0x97, 0xfc, 0x6c, 0x6a, 0x88, 0x29,
+ 0x0c, 0xe2, 0x3a, 0x2b, 0x28, 0x82, 0x8f, 0x27, 0x09,
+ 0x69, 0x91, 0xc6, 0xc3, 0xb7, 0x07, 0x61, 0x86, 0x8d,
+ 0x89, 0x8a, 0xd5, 0x00, 0x3b, 0x4b, 0xfc, 0x6f, 0xb3,
+ 0x3f, 0x4c, 0x93, 0x31, 0xfc, 0x88, 0x53, 0x26, 0xea,
+ 0xe5, 0x3a, 0xfc, 0xc1, 0x59, 0x16, 0xf0, 0xb7, 0xac,
+ 0xde, 0x1e, 0xd8, 0x74, 0x85, 0x72, 0xd9, 0xbb, 0xbe,
+ 0x76, 0x32, 0x25, 0x9d, 0x21, 0xbc, 0xfd, 0x8d, 0x32,
+ 0xfe, 0xae, 0x24, 0xe5, 0x4a, 0xcc, 0x5d, 0x15, 0x23,
+ 0xd3, 0x57, 0xe7, 0xa9, 0x2c, 0x31, 0xd7, 0xc5, 0x6b,
+ 0x70, 0x6c, 0x22, 0x5a, 0x13, 0x1f, 0x76, 0x13, 0x78,
+ 0x6f, 0xac, 0x42, 0x4c, 0x46, 0x81, 0xa2, 0x20, 0x91,
+ 0x30, 0xed, 0xcb, 0x90, 0xfe, 0x3c, 0xa3, 0xc7, 0xb4,
+ 0x1f, 0x21, 0x1d, 0x98, 0x74, 0x6a, 0x3e, 0xc8, 0xcc,
+ 0xd2, 0x68, 0x87, 0x69, 0xa9, 0xdf, 0x50, 0xd5, 0x0a,
+ 0x8e, 0x10, 0x54, 0xab, 0xea, 0x65, 0x2a, 0x52, 0xd7,
+ 0x22, 0xae, 0x2f, 0x1e, 0xc3, 0x16, 0x58, 0x20, 0x18,
+ 0x6d, 0x35, 0x46, 0x31, 0x43, 0x5d, 0x62, 0xfb, 0xb1,
+ 0x47, 0x32, 0xfa, 0x14, 0xcc, 0x51, 0xa3, 0xcd, 0x99,
+ 0x4f, 0x97, 0x0f, 0xca, 0x24, 0x93, 0x17, 0xea, 0xa3,
+ 0xf3, 0x1f, 0xbe, 0xb5, 0xa3, 0xac, 0x80, 0xcc, 0x20,
+ 0x3b, 0xa6, 0xd3, 0x32, 0x72, 0x4e, 0xd9, 0x25, 0xf9,
+ 0xc2, 0x24, 0x15, 0xbd, 0x1e, 0x1e, 0x41, 0x8c, 0x18,
+ 0x8c, 0x58, 0xe8, 0x75, 0x20, 0xff, 0xa3, 0xf4, 0xd4,
+ 0xab, 0x75, 0x78, 0x4e, 0xbb, 0x7c, 0x94, 0x93, 0x28,
+ 0x5b, 0x07, 0x3a, 0x3c, 0xc9, 0xf1, 0x55, 0x3e, 0x33,
+ 0xed, 0xf8, 0x72, 0x55, 0xab, 0x5a, 0xea, 0xbe, 0x65,
+ 0xfa, 0x81, 0x50, 0xc0, 0x9d, 0x2d, 0xfb, 0x04, 0x25,
+ 0x7c, 0xb9, 0xee, 0xe2, 0xa3, 0x00, 0x44, 0xd3, 0x9d,
+ 0xee, 0x4f, 0x80, 0x77, 0xfb, 0x26, 0x6b, 0x07, 0xd0,
+ 0xff, 0x82, 0x39, 0x0e, 0x2b, 0x47, 0xa3, 0xe7, 0x3e,
+ 0xc5, 0x4e, 0x15, 0x8a, 0x48, 0x28, 0xfb, 0xf7, 0xa4,
+ 0x86, 0xfb, 0x77, 0x60, 0xcd, 0xc5, 0x68, 0x96, 0xd7,
+ 0x4c, 0x3c, 0xf2, 0x51, 0x71, 0x79, 0x2e, 0x2e, 0x57,
+ 0x10, 0xa7, 0xfc, 0xd1, 0xd4, 0x61, 0x71, 0x81, 0x85,
+ 0x74, 0x09, 0x7d, 0x80, 0xd0, 0xc2, 0xe9, 0xff, 0xb7,
+ 0x88, 0x53, 0x74, 0x1e, 0xb0, 0xca, 0x65, 0x48, 0x8e,
+ 0xdb, 0x59, 0x3a, 0xcb, 0x80, 0xeb, 0xfd, 0xd2, 0xc9,
+ 0x38, 0x43, 0xae, 0x76, 0xf2, 0xbb, 0x51, 0xb2, 0xcb,
+ 0xe6, 0x85, 0x31, 0xb5, 0x62, 0xd4, 0x5e, 0x48, 0x08,
+ 0xf1, 0x40, 0x5b, 0x16, 0x83, 0x5e, 0xa5, 0x9c, 0x6b,
+ 0x91, 0x49, 0x44, 0xff, 0x3b, 0xa9, 0x2b, 0xf3, 0x06,
+ 0x33, 0x9e, 0x6e, 0x3c, 0x66, 0x7e, 0x27, 0xa2, 0x59,
+ 0x7b, 0xe3, 0xb6, 0xb4, 0x28, 0xeb, 0x93, 0x35, 0x87,
+ 0xac, 0x0e, 0x0b, 0x7e, 0xbc, 0x35, 0x28, 0x72, 0x1f,
+ 0x26, 0x59, 0xd0, 0x1f, 0x63, 0xe4, 0x86, 0x5d, 0x70,
+ 0xf3, 0xa8, 0xa4, 0xb8, 0xcd, 0xb3, 0xf8, 0x8d, 0xaa,
+ 0x41, 0xd2, 0xcc, 0x0b, 0x15, 0x66, 0x22, 0x83, 0x92,
+ 0xe3, 0x0b, 0xf9, 0xea, 0xa0, 0x33, 0xa1, 0x4e, 0x92,
+ 0xae, 0x81, 0x95, 0xa4, 0x58, 0x3f, 0xa9, 0x15, 0x52,
+ 0xf9, 0xda, 0xb7, 0x10, 0x8d, 0xc6, 0xab, 0x77, 0xe9,
+ 0xbe, 0xad, 0xc9, 0x3a, 0x6a, 0x8d, 0x92, 0x6c, 0x69,
+ 0xff, 0x31, 0x49, 0x25, 0x04, 0xc8, 0x93, 0x6f, 0xc8,
+ 0xe7, 0x60, 0x7a, 0x76, 0xb5, 0xc1, 0x07, 0xef, 0xa3,
+ 0x39, 0xa6, 0xf2, 0x36, 0x04, 0xde, 0x3c, 0x4a, 0x4e,
+ 0x96, 0xbd, 0x64, 0x26, 0x80, 0x01, 0x88, 0x47, 0xd2,
+ 0xa4, 0x46, 0xcd, 0xe1, 0x30, 0x7f, 0xa3, 0x00, 0x11,
+ 0x38, 0x55, 0xfa, 0xeb, 0x10, 0xeb, 0xa0, 0x65, 0x04,
+ 0x09, 0xc8, 0xde, 0x9c, 0x73, 0xba, 0x0c, 0xbd, 0xd3,
+ 0xa5, 0x84, 0x5e, 0xb9, 0x3b, 0xd4, 0x94, 0xbd, 0xa6,
+ 0x53, 0xbe, 0x93, 0x69, 0x3e, 0xaa, 0x32, 0x31, 0x06,
+ 0xc8, 0x1b, 0x4a, 0x48, 0xb5, 0x17, 0x85, 0xbf, 0x72,
+ 0xec, 0xf5, 0x29, 0x8a, 0xd8, 0xeb, 0x99, 0x8b, 0x74,
+ 0x84, 0x57, 0x8c, 0xe1, 0x85, 0x94, 0xa0, 0xbc, 0x7a,
+ 0x14, 0xf0, 0xf4, 0x8b, 0x25, 0x37, 0x43, 0xa1, 0x34,
+ 0x09, 0x71, 0xca, 0x5c, 0x9f, 0x08, 0x38, 0xd9, 0x9c,
+ 0x0c, 0x0e, 0xcb, 0xe4, 0xad, 0x4b, 0x2a, 0x89, 0x67,
+ 0xf8, 0x29, 0x6c, 0x69, 0x0e, 0x5d, 0xca, 0xfa, 0xa6,
+ 0x6b, 0x0e, 0xb5, 0x94, 0x17, 0x71, 0xf0, 0xc9, 0xcd,
+ 0x02, 0x1d, 0xa5, 0xd5, 0xc6, 0xa7, 0xbc, 0x5f, 0x6e,
+ 0x67, 0x43, 0x68, 0xce, 0xac, 0x54, 0x81, 0x2a, 0x25,
+ 0x22, 0x52, 0x35, 0xad, 0x7b, 0xd5, 0x06, 0x8c, 0x00,
+ 0xfb, 0xca, 0xc4, 0x0a, 0x49, 0x1e, 0xc8, 0xeb, 0x77,
+ 0xc1, 0x63, 0x23, 0x96, 0xbd, 0x35, 0xfa, 0x13, 0xae,
+ 0xbf, 0x1d, 0x1e, 0x69, 0x8d, 0xb3, 0xe3, 0x07, 0xde,
+ 0x4e, 0xd0, 0x12, 0xa9, 0xc3, 0x36, 0x30, 0x46, 0xef,
+ 0x92, 0x76, 0x17, 0x8f, 0x10, 0xe7, 0xba, 0x99, 0x4b,
+ 0xdf, 0xad, 0xb8, 0x11, 0x80, 0xdf, 0xe7, 0xfd, 0x80,
+ 0x64, 0xf7, 0x2a, 0xac, 0x60, 0x2a, 0x54, 0x8f, 0x4f,
+ 0xaf, 0xaf, 0x60, 0xf9, 0x67, 0x20, 0x80, 0x53, 0x5c,
+ 0xb6, 0x81, 0xa6, 0x2a, 0x74, 0x2d, 0xc5, 0x74, 0x2a,
+ 0x95, 0x26, 0x13, 0x17, 0x01, 0xdd, 0x31, 0xac, 0x5a,
+ 0x05, 0xda, 0xde, 0xba, 0xf6, 0x37, 0x13, 0x8d, 0xe4,
+ 0xa8, 0x93, 0x46, 0x9e, 0xa9, 0x82, 0x24, 0x7e, 0xc8,
+ 0xda, 0x63, 0x89, 0xcd, 0x33, 0xc9, 0xf7, 0xf9, 0x71,
+ 0x35, 0xe6, 0xa5, 0x5f, 0x6b, 0x3b, 0xbb, 0x0c, 0xe0,
+ 0xa4, 0x0b, 0xe3, 0x29, 0xc0, 0xae, 0x8e, 0xce, 0x03,
+ 0x09, 0x73, 0x0e, 0x1e, 0x9c, 0xe9, 0x59, 0xb6, 0x8b,
+ 0x78, 0x67, 0x32, 0x8b, 0xf1, 0x93, 0xcc, 0x72, 0x1b,
+ 0x6f, 0xa2, 0xf1, 0x04, 0x9c, 0xfa, 0x98, 0x02, 0xca,
+ 0xdf, 0x35, 0x3c, 0x38, 0xac, 0xa8, 0xdb, 0x90, 0xae,
+ 0xaa, 0xf9, 0x70, 0xfb, 0xed, 0xbd, 0xa6, 0x25, 0x14,
+ 0x58, 0x09, 0x8a, 0x36, 0xaf, 0x41, 0x09, 0x19, 0xcb,
+ 0xd3, 0x25, 0x5d, 0x0e, 0xe6, 0x20, 0x14, 0x71, 0x24,
+ 0x79, 0x19, 0x55, 0xaf, 0x51, 0x5b, 0xa4, 0xc0, 0x93,
+ 0x9e, 0xdd, 0x88, 0x31, 0x13, 0x96, 0xbf, 0xca, 0x0a,
+ 0xd7, 0xbc, 0xc4, 0x00, 0xa1, 0x10, 0x2d, 0x92, 0x79,
+ 0xf9, 0x14, 0xdb, 0xd2, 0xba, 0x74, 0xfa, 0xa8, 0xe5,
+ 0x40, 0x14, 0xc2, 0x56, 0x3c, 0x7f, 0x50, 0x07, 0x60,
+ 0x86, 0x93, 0x51, 0x2e, 0xf9, 0x70, 0x61, 0x70, 0x0e,
+ 0xa4, 0x87, 0x75, 0xcc, 0x6c, 0x72, 0xb7, 0x68, 0x23,
+ 0xb7, 0x3d, 0x76, 0xaf, 0x96, 0x9b, 0x4a, 0xe5, 0x12,
+ 0x28, 0x4a, 0x8f, 0x79, 0x34, 0xff, 0xec, 0x92, 0xeb,
+ 0x6b, 0xaf, 0xc9, 0xbd, 0xc1, 0x77, 0x07, 0xd0, 0xfa,
+ 0x55, 0x57, 0x10, 0x0c, 0xad, 0x29, 0x2a, 0x79, 0xd6,
+ 0x09, 0x9e, 0x7d, 0x18, 0xd4, 0xd6, 0xdd, 0x72, 0x1a,
+ 0x8f, 0x24, 0x11, 0x70, 0xd2, 0x52, 0x36, 0x0f, 0x38,
+ 0x79, 0x38, 0x4a, 0x02, 0x4f, 0x73, 0x2a, 0xaa, 0x6a,
+ 0xb5, 0x0c, 0x72, 0x32, 0x85, 0x21, 0x76, 0x1a, 0x8a,
+ 0x7d, 0x51, 0x0e, 0xf1, 0xf9, 0x19, 0xfa, 0x6b, 0x9b,
+ 0x22, 0x71, 0x8c, 0x13, 0xcc, 0xba, 0x7d, 0xee, 0xd8,
+ 0x34, 0xf6, 0x85, 0x60, 0xe1, 0xe4, 0x59, 0x6e, 0x32,
+ 0x60, 0xd9, 0xfa, 0xb7, 0x56, 0x54, 0x25, 0xd1, 0x73,
+ 0x6a, 0xf2, 0xa0, 0xc7, 0xa0, 0x67, 0x10, 0x89, 0x9c,
+ 0x27, 0x5f, 0x7f, 0x2e, 0x5a, 0x29, 0x70, 0x7a, 0x7b,
+ 0xaf, 0x21, 0xd0, 0xf4, 0x06, 0xb9, 0x2d, 0xf1, 0xb8,
+ 0x32, 0xed, 0xc5, 0xc9, 0xac, 0x2f, 0x54, 0x0a, 0xf9,
+ 0x08, 0x39, 0x39, 0x7d, 0x1d, 0xaf, 0xb4, 0x5f, 0x4d,
+ 0x75, 0xc3, 0xe8, 0x52, 0x3a, 0x47, 0x72, 0x2c, 0xa9,
+ 0x2d, 0xcb, 0x74, 0x06, 0xfe, 0x69, 0xd3, 0xf3, 0x1a,
+ 0xb2, 0xd3, 0x01, 0xed, 0x6c, 0xc1, 0xca, 0x4f, 0xaf,
+ 0x11, 0x9b, 0xa2, 0x27, 0x2a, 0x59, 0x56, 0x58, 0xdf,
+ 0x79, 0x8b, 0xc9, 0x87, 0xe9, 0x58, 0x81, 0x48, 0xc6,
+ 0xb6, 0x7d, 0x60, 0x54, 0x87, 0x9c, 0x61, 0xbb, 0x4b,
+ 0xbb, 0x61, 0xac, 0x0a, 0x5a, 0x66, 0x7e, 0x70, 0x8b,
+ 0xfd, 0x92, 0x76, 0x4a, 0xa9, 0xa5, 0xc3, 0xf4, 0xf2,
+ 0x93, 0x48, 0xc4, 0xf3, 0x91, 0x2b, 0x60, 0x04, 0x0e,
+ 0xb0, 0x6b, 0x60, 0x5e, 0xf0, 0xf1, 0x54, 0x41, 0x56,
+ 0xdc, 0x25, 0x57, 0xc3, 0xb6, 0x0b, 0x5e, 0x15, 0xb5,
+ 0x2a, 0x36, 0x4f, 0xe7, 0x1d, 0x70, 0xa8, 0xa7, 0xec,
+ 0xd6, 0x74, 0xba, 0xa4, 0x79, 0x83, 0x7c, 0x9e, 0x1a,
+ 0x5d, 0x32, 0xc8, 0xcb, 0x41, 0xca, 0x04, 0xec, 0x0b,
+ 0x18, 0x54, 0xe1, 0x67, 0xbf, 0xa8, 0x7a, 0xc3, 0x0f,
+ 0x27, 0x2a, 0xaf, 0x2a, 0x41, 0x19, 0x1f, 0xe8, 0xa2,
+ 0xe8, 0xfa, 0xfc, 0x88, 0x41, 0x46, 0xc3, 0x1c, 0x44,
+ 0xe5, 0xee, 0x47, 0xec, 0xfe, 0xbf, 0xb8, 0x29, 0x2e,
+ 0xae, 0x47, 0x0a, 0x42, 0x69, 0x8a, 0x9a, 0x94, 0x97,
+ 0x9e, 0xf5, 0xb6, 0x37, 0x1c, 0x10, 0xc2, 0x99, 0xa8,
+ 0xe9, 0x9e, 0x0e, 0x6e, 0xb5, 0xbe, 0xba, 0x1f, 0x77,
+ 0xa6, 0x35, 0x02, 0x1e, 0x8c, 0xe6, 0x02, 0x53, 0xe2,
+ 0x9a, 0xdd, 0x09, 0x6e, 0x9b, 0x7a, 0x36, 0x4f, 0x38,
+ 0x8d, 0x4c, 0xa4, 0xb4, 0xff, 0x90, 0x76, 0x0d, 0x11,
+ 0x7d, 0xe1, 0xe9, 0x7f, 0x2a, 0x4a, 0x80, 0xe0, 0xd8,
+ 0x3c, 0x23, 0xd2, 0xa5, 0xe5, 0x39, 0x77, 0xbf, 0x3d,
+ 0x71, 0x0d, 0x45, 0xbb, 0x39, 0x66, 0x1a, 0x4d, 0x59,
+ 0xb7, 0xd0, 0x0a, 0xee, 0x87, 0xee, 0x1f, 0xcf, 0x6f,
+ 0xc2, 0x50, 0xb1, 0xa5, 0x4c, 0xee, 0x40, 0x69, 0xd7,
+ 0x36, 0x38, 0x14, 0xcd, 0x6a, 0x9a, 0x90, 0x40, 0xad,
+ 0x76, 0xf1, 0xa6, 0xd4, 0x3c, 0x75, 0x10, 0xba, 0xcb,
+ 0xab, 0x22, 0x28, 0x5f, 0x0c, 0xe0, 0xee, 0xf4, 0xfd,
+ 0x61, 0x52, 0x0a, 0x59, 0xfe, 0x61, 0xc5, 0x40, 0xf9,
+ 0x91, 0x8e, 0x36, 0x29, 0x63, 0x6c, 0x6e, 0x45, 0xa5,
+ 0x42, 0xe3, 0x36, 0x90, 0xe7, 0x90, 0x9f, 0x58, 0xbb,
+ 0xf9, 0x1b, 0xee, 0x2c, 0xbb, 0x3a, 0xfd, 0x3d, 0xbe,
+ 0x3d, 0x45, 0xf0, 0xc2, 0x18, 0xaa, 0x46, 0x10, 0x23,
+ 0xe9, 0x63, 0xba, 0x7f, 0xc2, 0xe1, 0xf4, 0x05, 0xdd,
+ 0x4a, 0x7c, 0xa8, 0xab, 0xa9, 0xbd, 0x6f, 0xdf, 0x48,
+ 0x59, 0x11, 0xd4, 0xba, 0x75, 0xb6, 0x22, 0xd4, 0xd7,
+ 0x35, 0x6f, 0x27, 0x70, 0xc7, 0x3d, 0x90, 0x06, 0x39,
+ 0x2a, 0x16, 0xd0, 0x8b, 0xd7, 0xfb, 0x5e, 0x85, 0x2e,
+ 0xb0, 0xd8, 0xc7, 0xdb, 0xe5, 0x24, 0x3a, 0x6e, 0xc4,
+ 0x5e, 0xd4, 0x22, 0x25, 0x14, 0xee, 0xa5, 0x30, 0x8b,
+ 0xd6, 0x27, 0x61, 0x33, 0x13, 0x46, 0x0b, 0x26, 0x45,
+ 0xa6, 0xb4, 0xfa, 0x8d, 0xa3, 0xf2, 0x27, 0xd2, 0xc5,
+ 0x04, 0xaa, 0x96, 0xa4, 0x55, 0xfa, 0x40, 0xf1, 0xfc,
+ 0x66, 0x33, 0x9e, 0x4b, 0x39, 0x75, 0xae, 0x7f, 0x52,
+ 0x87, 0x7b, 0x8a, 0xf9, 0x7d, 0x5f, 0x8a, 0x7e, 0xf7,
+ 0xfe, 0xc4, 0x7f, 0xf4, 0xf6, 0x9a, 0x86, 0x78, 0x21,
+ 0x02, 0x94, 0x9e, 0x50, 0x2d, 0xdc, 0xd6, 0xa5, 0x53,
+ 0xf1, 0xef, 0x06, 0xe8, 0xb5, 0x46, 0x81, 0xcc, 0x91,
+ 0x4f, 0x37, 0xee, 0x27, 0xcb, 0x91, 0xad, 0xff, 0x1d,
+ 0xd1, 0x00, 0xa8, 0x96, 0x22, 0xaa, 0x63, 0x23, 0x2a,
+ 0x7a, 0x75, 0x6f, 0xe9, 0x2d, 0x26, 0xde, 0x11, 0x97,
+ 0x4b, 0x17, 0x3f, 0xde, 0x51, 0x1a, 0x22, 0xed, 0x38,
+ 0x6f, 0x3e, 0x7a, 0xd0, 0xd6, 0x60, 0x06, 0x7e, 0x3f,
+ 0xa4, 0x29, 0xfa, 0x18, 0x91, 0xda, 0x73, 0x38, 0xe3,
+ 0xe3, 0xb5, 0xc0, 0x5b, 0x4e, 0xe8, 0x94, 0xea, 0x45,
+ 0x6e, 0x5b, 0x50, 0xaa, 0x38, 0xb6, 0x6f, 0xdb, 0x90,
+ 0x1b, 0x3b, 0x82, 0xbb, 0x0d, 0x38, 0xe3, 0xca, 0xd9,
+ 0xf1, 0x2e, 0x27, 0x4c, 0x2c, 0x5a, 0x42, 0xdf, 0x44,
+ 0xc8, 0x07, 0xe4, 0x95, 0xb5, 0xec, 0x91, 0x34, 0x1c,
+ 0x9a, 0x0c, 0x50, 0x1a, 0xce, 0x67, 0xe4, 0x4b, 0x87,
+ 0x61, 0x43, 0x95, 0x95, 0xb8, 0x8a, 0xf4, 0xc9, 0x92,
+ 0x33, 0x33, 0xe3, 0xfe, 0x98, 0x2a, 0xae, 0x8e, 0xf2,
+ 0x6b, 0x13, 0x7c, 0xe4, 0x44, 0x40, 0x66, 0xea, 0x0c,
+ 0xe4, 0xdb, 0x16, 0x65, 0xa8, 0x8b, 0x37, 0x08, 0xec,
+ 0x1e, 0xfc, 0xa6, 0xd0, 0x9b, 0x9e, 0x0a, 0xd2, 0xe3,
+ 0xcf, 0x5d, 0xb2, 0xaf, 0x8e, 0x05, 0x7d, 0x8d, 0x84,
+ 0xbc, 0x9f, 0xb1, 0xe6, 0x6a, 0x2e, 0x4b, 0x6d, 0x64,
+ 0x91, 0x17, 0x9d, 0xb5, 0x35, 0x15, 0x02, 0xe9, 0x1b,
+ 0x85, 0xc1, 0x89, 0xc2, 0x5a, 0x32, 0x3a, 0x80, 0x78,
+ 0x5e, 0xcc, 0x50, 0x26, 0xf5, 0x11, 0x01, 0x79, 0xf3,
+ 0xaf, 0xb6, 0x40, 0x00, 0x73, 0x8f, 0xeb, 0x5a, 0xd1,
+ 0x26, 0x00, 0xe2, 0xa3, 0xcd, 0xfd, 0xaa, 0x15, 0x5b,
+ 0x98, 0x2a, 0x76, 0x41, 0x07, 0xc2, 0xde, 0xb6, 0x71,
+ 0xe7, 0xc3, 0xe9, 0x92, 0xb3, 0xd8, 0xfe, 0xaf, 0x12,
+ 0x61, 0x86, 0x5b, 0x6e, 0x74, 0x45, 0x7b, 0x9b, 0x6f,
+ 0x1a, 0x13, 0x84, 0xf6, 0x31, 0x5f, 0x5b, 0x6c, 0xde,
+ 0x47, 0xb8, 0x73, 0x32, 0xc7, 0x94, 0x92, 0xa5, 0xc3,
+ 0x65, 0xdf, 0x96, 0x6c, 0xfd, 0xb7, 0x80, 0xfb, 0x47,
+ 0xba, 0x6e, 0x43, 0xb3, 0x7e, 0x86, 0xc9, 0x97, 0x45,
+ 0xde, 0x3f, 0x3a, 0xf6, 0xb0, 0x9e, 0x9a, 0xcb, 0xfd,
+ 0xf2, 0x5c, 0xba, 0x6e, 0x3f, 0xed, 0xfa, 0x74, 0x84,
+ 0xe2, 0xb1, 0xae, 0x66, 0x57, 0x0b, 0x96, 0x6c, 0x77,
+ 0xe4, 0x8a, 0x67, 0x97, 0xc7, 0xe0, 0x44, 0xb2, 0x83,
+ 0x2d, 0x3c, 0x2e, 0x01, 0x19, 0x2e, 0x4c, 0x74, 0xe1,
+ 0x35, 0x73, 0xeb, 0x85, 0x63, 0x8c, 0x3a, 0xb8, 0xbc,
+ 0x25, 0x6a, 0x8d, 0xaf, 0xd2, 0xfb, 0xef, 0xd3, 0x12,
+ 0x93, 0x0b, 0x39, 0xfa, 0x66, 0xbe, 0x3b, 0xfd, 0x6c,
+ 0x0b, 0xbb, 0xb2, 0x5a, 0x78, 0xa1, 0xcf, 0x8c, 0x7d,
+ 0x60, 0x55, 0xeb, 0x33, 0x4e, 0x8e, 0xf9, 0x19, 0x4d,
+ 0x42, 0xd4, 0xf8, 0xd8, 0xba, 0xad, 0x0a, 0x6e, 0x62,
+ 0xd4, 0xe1, 0x6a, 0xcc, 0xea, 0x09, 0x91, 0x8e, 0x62,
+ 0xc9, 0x1e, 0x9e, 0x48, 0xaa, 0xde, 0xf7, 0xa2, 0x5a,
+ 0xcb, 0x83, 0x20, 0xe8, 0xf5, 0xd1, 0xfe, 0x9d, 0x18,
+ 0x2f, 0xd6, 0xf8, 0x97, 0x17, 0xce, 0xc2, 0x05, 0x08,
+ 0xef, 0x61, 0x70, 0x9d, 0x95, 0x79, 0x59, 0x4c, 0x06,
+ 0x24, 0x3d, 0x24, 0x69, 0xff, 0x46, 0xda, 0xbc, 0x71,
+ 0x7a, 0x74, 0x93, 0x58, 0xf5, 0xc8, 0x91, 0xfb, 0x66,
+ 0xed, 0x78, 0x8f, 0xf8, 0x28, 0xa8, 0x1d, 0xa5, 0x3a,
+ 0x13, 0x76, 0xc2, 0xcc, 0xba, 0xb9, 0x56, 0x29, 0x74,
+ 0xd6, 0x14, 0x75, 0x58, 0xe6, 0x2e, 0x79, 0x6e, 0x9d,
+ 0x41, 0x94, 0x8a, 0xcf, 0xf1, 0xb1, 0xe0, 0x36, 0xe5,
+ 0x89, 0x9a, 0x95, 0xa1, 0x11, 0xd1, 0xbe, 0x45, 0xe4,
+ 0xb3, 0xb0, 0x62, 0x32, 0x1d, 0xba, 0xe0, 0xde, 0x57,
+ 0x81, 0x0e, 0x01, 0x9b, 0x52, 0x3d, 0xd5, 0xde, 0x3b,
+ 0x3a, 0xdd, 0x8f, 0xe3, 0x2e, 0xce, 0x1e, 0x89, 0x4d,
+ 0x81, 0xf0, 0xf6, 0x20, 0x63, 0x7a, 0x4c, 0xbb, 0x66,
+ 0xe0, 0xbe, 0x2b, 0xee, 0xd0, 0x3b, 0x60, 0x1e, 0x65,
+ 0xd1, 0x2c, 0x7c, 0x5c, 0x6c, 0x16, 0x5b, 0x90, 0xc8,
+ 0x05, 0x10, 0xf2, 0xde, 0x33, 0x90, 0x35, 0x69, 0x24,
+ 0x3f, 0xc1, 0x8f, 0x1e, 0x4a, 0x60, 0xf1, 0x03, 0x65,
+ 0x46, 0x40, 0x76, 0xe9, 0x83, 0x97, 0xda, 0x0b, 0xb8,
+ 0x22, 0xfa, 0x55, 0x99, 0xfd, 0x18, 0x24, 0xd2, 0x66,
+ 0xb0, 0x7b, 0x70, 0x56, 0x93, 0xad, 0x09, 0x95, 0x8e,
+ 0x1f, 0x2f, 0xe8, 0x12, 0x55, 0xd4, 0x1f, 0xde, 0x09,
+ 0x85, 0x05, 0xd1, 0xd5, 0x10, 0x2c, 0x8c, 0x6b, 0x53,
+ 0x28, 0xce, 0x06, 0xc5, 0x52, 0x0f, 0xfa, 0x09, 0x09,
+ 0x23, 0x1b, 0xe3, 0xbf, 0xb1, 0x89, 0x72, 0x26, 0x0d,
+ 0xa6, 0xbb, 0x7d, 0x9e, 0xdc, 0xf8, 0xf5, 0x0b, 0x8c,
+ 0xe0, 0xbc, 0x97, 0x3b, 0x72, 0xdd, 0xf5, 0x9d, 0xc5,
+ 0xb6, 0x37, 0x2c, 0x76, 0x5b, 0x58, 0x67, 0xdb, 0xed,
+ 0x3b, 0x6e, 0xe5, 0xe5, 0x6d, 0x6f, 0x0d, 0x7e, 0xff,
+ 0xa9, 0x57, 0x4a, 0x84, 0x85, 0x82, 0xac, 0x00, 0x50,
+ 0xa3, 0x4f, 0x87, 0xfe, 0x2a, 0x40, 0x52, 0x54, 0x81,
+ 0x69, 0x42, 0x0b, 0x0c, 0xd7, 0x18, 0x98, 0x01, 0x8c,
+ 0x5a, 0xa2, 0xf4, 0xe8, 0x61, 0xd1, 0x38, 0xfd, 0x0f,
+ 0x63, 0x75, 0xd3, 0x4b, 0x1d, 0xdc, 0xdf, 0xb2, 0xeb,
+ 0x94, 0x97, 0x5c, 0x2a, 0xb4, 0x12, 0x5c, 0x49, 0x2b,
+ 0xfc, 0xd0, 0x8d, 0xfb, 0xe7, 0xb3, 0xcb, 0x0f, 0x3c,
+ 0x2e, 0x04, 0x36, 0xa8, 0x03, 0xc9, 0xd7, 0x11, 0x2d,
+ 0x2a, 0x93, 0xff, 0xda, 0x26, 0xb0, 0x54, 0x7e, 0xaf,
+ 0x30, 0x7d, 0xce, 0x46, 0x8a, 0x3d, 0x7c, 0xa4, 0x7a,
+ 0x2c, 0xfa, 0xba, 0xa1, 0xc9, 0x41, 0xd3, 0xb8, 0x84,
+ 0x03, 0x78, 0xdd, 0xe9, 0x57, 0x19, 0x62, 0x62, 0xff,
+ 0x5b, 0x3b, 0x48, 0x62, 0x0e, 0xee, 0x19, 0xb0, 0x32,
+ 0x6e, 0x6a, 0x07, 0xd8, 0x4e, 0x25, 0x76, 0xa7, 0xe3,
+ 0x98, 0xa1, 0x6f, 0xb6, 0x99, 0x32, 0x67, 0x7d, 0x46,
+ 0x42, 0x4a, 0x82, 0xd1, 0x29, 0x1b, 0x87, 0xeb, 0x4b,
+ 0x9e, 0xdf, 0x69, 0x75, 0xbd, 0x4f, 0xd3, 0xde, 0xc9,
+ 0x83, 0xe6, 0xd6, 0xea, 0x03, 0x81, 0x12, 0xf3, 0x5d,
+ 0x99, 0xf1, 0xb1, 0xd9, 0x3e, 0xbe, 0xf3, 0xa8, 0xdc,
+ 0xb6, 0xf8, 0x4b, 0x9e, 0x26, 0x3f, 0xf0, 0x7c, 0xb3,
+ 0xf4, 0xca, 0x00, 0x6c, 0x6c, 0xe5, 0x43, 0xa1, 0xfd,
+ 0x3a, 0xf8, 0x8e, 0xe3, 0x9f, 0x88, 0xc5, 0x44, 0xfd,
+ 0x24, 0x69, 0x76, 0xd5, 0xcb, 0xdc, 0x9d, 0x12, 0xf3,
+ 0x13, 0x7e, 0xe7, 0xc3, 0xa8, 0x6a, 0xb2, 0xe0, 0xb3,
+ 0x1d, 0xab, 0x3b, 0xc9, 0x77, 0x3d, 0x0f, 0xc3, 0xbe,
+ 0x4b, 0x8b, 0x28, 0xbd, 0x7c, 0xe6, 0xb2, 0x06, 0x1f,
+ 0xf9, 0x8f, 0x16, 0x62, 0xbf, 0xc7, 0x55, 0x73, 0xd4,
+ 0xf1, 0x5a, 0x95, 0x80, 0xa3, 0x4e, 0xaa, 0x60, 0x17,
+ 0x3c, 0xc9, 0x5e, 0xd4, 0x0c, 0x56, 0x7a, 0x77, 0x8e,
+ 0x7f, 0x67, 0x08, 0x2f, 0xd9, 0x21, 0x19, 0xfd, 0x86,
+ 0x8c, 0x23, 0x8d, 0xf6, 0x92, 0x1f, 0x36, 0x2c, 0x7c,
+ 0x83, 0xbd, 0x2f, 0x6c, 0x63, 0x7c, 0xb7, 0x93, 0x74,
+ 0x1b, 0xc2, 0x95, 0x34, 0x26, 0x1e, 0x07, 0x87, 0x3a,
+ 0xb6, 0xe2, 0x39, 0x71, 0x9b, 0x20, 0xcd, 0x63, 0xf0,
+ 0xbf, 0x48, 0xb5, 0x0e, 0x49, 0x86, 0x50, 0x80, 0xbd,
+ 0xd6, 0x0e, 0xab, 0xd5, 0x69, 0x1b, 0xa4, 0xb3, 0x63,
+ 0x3c, 0x8f, 0xcb, 0x42, 0xdb, 0xd7, 0x1a, 0xf4, 0xdf,
+ 0x9e, 0x25, 0xfc, 0xd4, 0x00, 0xcb, 0xec, 0x57, 0x69,
+ 0x30, 0x15, 0x4d, 0x7a, 0x69, 0x28, 0x2f, 0x2b, 0x34,
+ 0x26, 0xd1, 0xe7, 0x01, 0x42, 0x5e, 0x02, 0xe2, 0x75,
+ 0xe8, 0x52, 0x8a, 0xb4, 0x71, 0xfa, 0xc3, 0x3d, 0xe6,
+ 0xac, 0xeb, 0xf3, 0x93, 0xe0, 0x37, 0xcd, 0x66, 0x92,
+ 0x66, 0x2c, 0xfe, 0x4b, 0xd6, 0x3c, 0xf1, 0x57, 0xe5,
+ 0xcf, 0xf5, 0xd0, 0xdb, 0x0e, 0x1f, 0x82, 0x65, 0x3b,
+ 0xab, 0x69, 0x42, 0x53, 0x7d, 0xa4, 0x7c, 0xb7, 0x86,
+ 0xeb, 0x23, 0x45, 0xa8, 0x4a, 0x73, 0xfc, 0x38, 0xc6,
+ 0xe5, 0x2c, 0xab, 0x80, 0xfb, 0x23, 0xb2, 0x0c, 0x53,
+ 0x28, 0x21, 0x37, 0x54, 0x9c, 0x72, 0x51, 0x0f, 0x44,
+ 0x50, 0xd3, 0xe1, 0xd5, 0xb2, 0x27, 0x83, 0xb6, 0xe9,
+ 0x4d, 0x64, 0x5c, 0x17, 0x0f, 0xe0, 0x13, 0xe4, 0x26,
+ 0x6b, 0xd0, 0xd8, 0x25, 0xe3, 0x69, 0x6a, 0x95, 0x3f,
+ 0x4a, 0x4e, 0xa0, 0x58, 0xbc, 0x28, 0x47, 0x8b, 0x68,
+ 0xe4, 0x41, 0x90, 0x46, 0x1b, 0x84, 0xa0, 0x7b, 0x46,
+ 0x46, 0x03, 0xee, 0x21, 0x0d, 0x34, 0xed, 0xff, 0x15,
+ 0x57, 0x06, 0xdf, 0x71, 0x09, 0xb2, 0x66, 0x0d, 0x6e,
+ 0xcc, 0xa5, 0x0c, 0xaf, 0x3f, 0x24, 0x8f, 0xd1, 0xc8,
+ 0x44, 0x86, 0xaf, 0xbf, 0xeb, 0x2f, 0xb9, 0xee, 0xa7,
+ 0xcf, 0xe4, 0xe8, 0xec, 0x47, 0x09, 0xd8, 0x95, 0x9e,
+ 0x3c, 0xda, 0x92, 0x41, 0x61, 0xf5, 0xc3, 0xec, 0x00,
+ 0xe4, 0xa3, 0x0d, 0x4a, 0xb3, 0xf6, 0x82, 0x05, 0x38,
+ 0x70, 0x6a, 0xd1, 0x28, 0x2c, 0xb3, 0xc6, 0xbb, 0x38,
+ 0xb3, 0x06, 0x7f, 0xd6, 0x4c, 0xe7, 0xfb, 0xef, 0x0d,
+ 0x52, 0x66, 0xbe, 0xd8, 0xa6, 0x6f, 0xe8, 0xd9, 0x42,
+ 0x4f, 0xad, 0xe8, 0xe8, 0x6c, 0xf9, 0xe9, 0x42, 0xd9,
+ 0x66, 0x6e, 0xec, 0xfe, 0xf5, 0x91, 0xbf, 0x0a, 0x98,
+ 0xd8, 0x7b, 0x23, 0x12, 0xa6, 0x04, 0xa8, 0xb3, 0x61,
+ 0x13, 0x65, 0xc0, 0xe2, 0x82, 0xb9, 0xb2, 0x38, 0x07,
+ 0x06, 0xca, 0x64, 0x6c, 0x23, 0x93, 0x60, 0x1d, 0x4d,
+ 0x38, 0x5e, 0x8e, 0x90, 0x16, 0x4a, 0xfd, 0xb3, 0xcd,
+ 0x84, 0x9c, 0xa5, 0xfa, 0x73, 0x2d, 0xcb, 0x87, 0x31,
+ 0x3d, 0xf8, 0xfc, 0xeb, 0xa7, 0x56, 0x2f, 0x5b, 0x95,
+ 0x9a, 0xc6, 0x82, 0x29, 0x86, 0x47, 0xe2, 0xc2, 0x84,
+ 0x01, 0xaf, 0xc8, 0x0b, 0x2d, 0xfb, 0x34, 0xba, 0x5d,
+ 0x9d, 0xd1, 0x85, 0xd5, 0x1e, 0x63, 0xcb, 0x3c, 0xa8,
+ 0xfa, 0x79, 0xef, 0x12, 0xa6, 0xb5, 0xdb, 0xc5, 0x1d,
+ 0x6a, 0xa7, 0x54, 0x58, 0x0c, 0xbe, 0x61, 0xe5, 0x96,
+ 0x7f, 0x4a, 0x3b, 0x59, 0x32, 0x2d, 0x06, 0x44, 0x83,
+ 0x5c, 0xad, 0xe9, 0xfe, 0x7c, 0xd7, 0x5b, 0x34, 0xa1,
+ 0xa3, 0xad, 0x9a, 0xbf, 0xd5, 0x30, 0xf0, 0x22, 0xfc,
+ 0x94, 0x7f, 0xd4, 0xa4, 0xca, 0x88, 0x31, 0xe7, 0xf2,
+ 0x89, 0x2d, 0xda, 0xe6, 0x91, 0xa6, 0x27, 0x22, 0x74,
+ 0x9f, 0xc6, 0x72, 0x4f, 0xf6, 0xa9, 0xfe, 0x7a, 0xf0,
+ 0xa8, 0x6b, 0x6c, 0x9f, 0xe9, 0x2a, 0x9b, 0x23, 0x9e,
+ 0xb8, 0x2b, 0x29, 0x65, 0xa7, 0x5d, 0xbd, 0x10, 0xe4,
+ 0x56, 0x02, 0x94, 0xdd, 0xd1, 0xab, 0x9b, 0x82, 0x2d,
+ 0x8d, 0xf6, 0xd3, 0x65, 0x63, 0x4a, 0xc4, 0x86, 0x61,
+ 0x37, 0x9f, 0xdb, 0x4b, 0x34, 0x20, 0x0a, 0xca, 0x45,
+ 0x6c, 0x06, 0xc4, 0x9c, 0x74, 0x4d, 0x83, 0x6a, 0x8d,
+ 0xad, 0xc6, 0x61, 0x3a, 0x8d, 0xde, 0x6c, 0xf9, 0x8e,
+ 0x33, 0xa2, 0xee, 0x99, 0xc7, 0xe4, 0x52, 0xb2, 0x44,
+ 0x6f, 0x2f, 0x0f, 0x41, 0xa9, 0x1a, 0xd3, 0x96, 0x42,
+ 0xc6, 0x49, 0x12, 0x6a, 0xf0, 0x29, 0xa9, 0x0c, 0x9c,
+ 0x50, 0x5d, 0x1d, 0xd1, 0x42, 0x7e, 0x6f, 0x36, 0x48,
+ 0x0f, 0x58, 0x14, 0x94, 0xc0, 0x10, 0x1e, 0xe0, 0xb2,
+ 0xdd, 0xba, 0x57, 0x91, 0x4d, 0xd5, 0xdc, 0xa6, 0x4c,
+ 0x68, 0x00, 0x6c, 0xb3, 0x5d, 0x32, 0x13, 0xbe, 0xa8,
+ 0xc3, 0xfb, 0xd4, 0x19, 0x40, 0xf5, 0x6f, 0x63, 0xa1,
+ 0x07, 0xbf, 0xa2, 0x8b, 0xfc, 0xfe, 0xf8, 0xa1, 0x33,
+ 0x70, 0x07, 0x6d, 0xc5, 0x72, 0xa0, 0x39, 0xd6, 0xd7,
+ 0x76, 0x6c, 0xfa, 0x1f, 0x04, 0xd6, 0x23, 0xbf, 0x66,
+ 0x78, 0x92, 0x00, 0x11, 0x8a, 0x75, 0x67, 0x44, 0xa6,
+ 0x7c, 0xd0, 0x14, 0xe6, 0xd0, 0x31, 0x6d, 0xdb, 0xc5,
+ 0xb1, 0xa7, 0x99, 0xc3, 0xaf, 0x18, 0x7a, 0x26, 0x46,
+ 0xad, 0x6d, 0x0c, 0xb6, 0xb5, 0xad, 0xc1, 0xcf, 0x60,
+ 0x99, 0xf5, 0x9f, 0x88, 0xaf, 0x0e, 0x37, 0x15, 0xf9,
+ 0x2b, 0x1a, 0x5f, 0xfb, 0xc9, 0xf8, 0xd4, 0xf0, 0x97,
+ 0xd2, 0x91, 0xf4, 0x94, 0xa2, 0xd3, 0x3b, 0x8b, 0x0c,
+ 0x22, 0xa0, 0xac, 0xb3, 0xb5, 0xdf, 0xf2, 0x27, 0x38,
+ 0x47, 0x53, 0x5b, 0x6e, 0x8f, 0x98, 0x9e, 0xad, 0xb6,
+ 0xf5, 0x0e, 0x17, 0x20, 0x35, 0x54, 0x6b, 0x73, 0xa6,
+ 0x64, 0x65, 0xac, 0xb8, 0xc1, 0xd3, 0xf7, 0x07, 0x82,
+ 0x93, 0x9d, 0xcb, 0xcc, 0xe9, 0x0c, 0x51, 0x52, 0x85,
+ 0x8b, 0x95, 0xa6, 0xb1, 0xce, 0xdc, 0xfa, 0x00, 0x00,
+ 0x08, 0x14, 0x1c, 0x23, 0x2a, 0x35,
+ },
+};
+
+static const struct mldsa_testvector mldsa87_testvector = {
+ .alg = MLDSA87,
+ .pk_len = MLDSA87_PUBLIC_KEY_SIZE,
+ .pk =
+ (const u8[MLDSA87_PUBLIC_KEY_SIZE]) {
+ 0xd4, 0x9d, 0xdc, 0x3d, 0xa4, 0xa5, 0x87, 0xa5, 0x54,
+ 0x61, 0xf3, 0xf4, 0xe0, 0x11, 0xc9, 0x1c, 0x78, 0x0a,
+ 0xf1, 0x8a, 0xa8, 0xb2, 0xff, 0xb2, 0x9a, 0x2c, 0xe0,
+ 0x86, 0x5c, 0xaa, 0x86, 0xe0, 0xd9, 0x42, 0x54, 0x18,
+ 0x3e, 0x4c, 0x96, 0x1a, 0xb4, 0xc7, 0x18, 0xcf, 0x7d,
+ 0xca, 0xe2, 0x74, 0x6c, 0x81, 0x3e, 0xcb, 0xf8, 0x7b,
+ 0xc4, 0x90, 0x50, 0xd5, 0xe8, 0xd3, 0xbc, 0x8b, 0xa8,
+ 0x3e, 0xb0, 0x96, 0x65, 0xd7, 0xbb, 0xa9, 0xab, 0x9c,
+ 0x82, 0x5e, 0x6e, 0x8d, 0xf8, 0xc3, 0x6d, 0xe9, 0xbf,
+ 0xbd, 0x30, 0xc9, 0xca, 0x47, 0x85, 0xae, 0x6f, 0x5d,
+ 0x09, 0x4d, 0xd7, 0xdd, 0x05, 0x51, 0xe0, 0x9e, 0x94,
+ 0x3b, 0x1d, 0xfa, 0x30, 0x57, 0xdc, 0x58, 0x48, 0xe5,
+ 0x45, 0xf3, 0x34, 0x8a, 0x73, 0x66, 0x8a, 0xe0, 0x62,
+ 0x3d, 0x0d, 0xfb, 0x13, 0x52, 0x25, 0xf5, 0xd3, 0x94,
+ 0x15, 0x9d, 0xac, 0x6a, 0x74, 0x8a, 0x64, 0x91, 0x5b,
+ 0xa3, 0xe2, 0xd0, 0x5c, 0xd2, 0xee, 0x52, 0xc0, 0x0c,
+ 0x6c, 0x81, 0x34, 0x94, 0xfb, 0x87, 0xf6, 0x6b, 0x0f,
+ 0x7e, 0x99, 0xa7, 0xaf, 0xb3, 0x74, 0xa7, 0xb6, 0x64,
+ 0xd7, 0x36, 0x39, 0x3f, 0x7d, 0x0e, 0xc3, 0x76, 0xb3,
+ 0x3a, 0xc9, 0x94, 0x6f, 0xc0, 0xaa, 0x92, 0x2a, 0xf1,
+ 0x38, 0x8c, 0x62, 0xa1, 0x9a, 0xbe, 0x8d, 0x32, 0xec,
+ 0x05, 0xb9, 0x8d, 0xb0, 0xdb, 0x37, 0x8d, 0x61, 0xfa,
+ 0x79, 0x55, 0x1d, 0xf2, 0xc3, 0x19, 0x15, 0x3b, 0x26,
+ 0xef, 0xe5, 0xf3, 0x29, 0xa1, 0x13, 0x60, 0x68, 0xd3,
+ 0x22, 0x57, 0xcd, 0x99, 0xe6, 0x22, 0x54, 0xdf, 0x02,
+ 0xe4, 0xd5, 0xd2, 0x66, 0xce, 0x5a, 0x90, 0x13, 0x7e,
+ 0x7c, 0xad, 0x4c, 0x4c, 0xb6, 0x93, 0x65, 0xda, 0x4b,
+ 0xb6, 0x13, 0x0e, 0x1b, 0x36, 0xaa, 0x2c, 0xbd, 0x60,
+ 0x57, 0x98, 0x35, 0xa9, 0xe9, 0xad, 0xc5, 0x8e, 0x33,
+ 0x47, 0x00, 0xe9, 0xf2, 0x1b, 0xe7, 0x5a, 0xd0, 0x55,
+ 0x3b, 0x0e, 0x77, 0x09, 0x7e, 0x1f, 0x11, 0x0b, 0xf0,
+ 0xe4, 0x07, 0x27, 0xe7, 0x72, 0xe9, 0x50, 0x9c, 0x9c,
+ 0x84, 0xb0, 0x5c, 0xe0, 0x13, 0x79, 0xfa, 0x3f, 0x80,
+ 0x96, 0xe2, 0x04, 0xde, 0x35, 0x5f, 0xa4, 0x4e, 0x8a,
+ 0x12, 0x7a, 0xba, 0x53, 0x20, 0x36, 0x3d, 0xf0, 0x63,
+ 0xb6, 0x14, 0xab, 0xce, 0x6b, 0x24, 0xfd, 0xc9, 0xd2,
+ 0x52, 0xd9, 0xc0, 0x40, 0xdf, 0xdd, 0xd5, 0xc2, 0xa0,
+ 0xf5, 0x74, 0x46, 0x17, 0xdc, 0xf5, 0x81, 0x68, 0xbd,
+ 0x1a, 0x01, 0x33, 0xd0, 0x2f, 0xdc, 0x3a, 0x43, 0x4a,
+ 0x08, 0x07, 0x98, 0x9f, 0x75, 0x5d, 0x70, 0x15, 0x1d,
+ 0x58, 0x7f, 0x26, 0x30, 0x28, 0xe1, 0x17, 0x6d, 0x14,
+ 0x0f, 0x01, 0x4a, 0x88, 0x3b, 0xf5, 0x70, 0x1d, 0x97,
+ 0xd5, 0xda, 0x18, 0xa8, 0xb3, 0xa4, 0x0e, 0x04, 0x3f,
+ 0xe8, 0x50, 0xf4, 0x87, 0x65, 0x75, 0x5a, 0x5d, 0x2f,
+ 0x94, 0x63, 0x7a, 0xd0, 0x06, 0xce, 0xfb, 0xeb, 0x41,
+ 0x65, 0xc9, 0x55, 0x38, 0x54, 0xd3, 0xc4, 0xac, 0x24,
+ 0x46, 0x06, 0x2a, 0x87, 0xb1, 0x0f, 0x06, 0xd8, 0x1e,
+ 0xa7, 0x35, 0xc4, 0xa3, 0xdc, 0x60, 0x80, 0x83, 0xe7,
+ 0xf0, 0x74, 0xf6, 0xd6, 0xa7, 0x1d, 0x50, 0xff, 0xba,
+ 0x82, 0xc0, 0xca, 0x72, 0x6b, 0xda, 0x4a, 0xcb, 0x3b,
+ 0xe8, 0xa3, 0xaa, 0x32, 0x86, 0xc0, 0x94, 0x75, 0x2b,
+ 0x2f, 0x44, 0xad, 0x5b, 0x8d, 0xab, 0xc2, 0x03, 0x55,
+ 0xb1, 0x7e, 0x67, 0x07, 0x39, 0x33, 0x83, 0x67, 0xec,
+ 0xbf, 0x52, 0xad, 0x55, 0x37, 0x3e, 0xa1, 0x41, 0xed,
+ 0xa0, 0x91, 0xbf, 0x28, 0x1b, 0x04, 0x32, 0xbf, 0xf1,
+ 0xb0, 0x0a, 0x11, 0x99, 0x98, 0x77, 0xee, 0x14, 0x13,
+ 0x15, 0x13, 0xad, 0x1f, 0xb6, 0x6b, 0xcd, 0x3b, 0xb8,
+ 0x75, 0x9a, 0x55, 0x9b, 0x0c, 0x6c, 0xf7, 0x7c, 0x21,
+ 0x06, 0xb7, 0xf0, 0x43, 0x41, 0x96, 0xc1, 0x73, 0x44,
+ 0x53, 0xd8, 0x18, 0x3e, 0x09, 0x4e, 0xc2, 0x5f, 0xa0,
+ 0xd5, 0x18, 0xdb, 0x9f, 0xf4, 0xa0, 0xf8, 0x4d, 0xa7,
+ 0x72, 0x7e, 0x85, 0xbb, 0xb7, 0xcc, 0x7b, 0x51, 0xb0,
+ 0xf1, 0x5e, 0x03, 0xcd, 0xe8, 0x5b, 0x83, 0x3f, 0x95,
+ 0xe2, 0x0b, 0xa1, 0xc7, 0x6f, 0x74, 0x98, 0xcd, 0x95,
+ 0xf4, 0xd4, 0xb8, 0x40, 0xff, 0x75, 0x54, 0x83, 0x3a,
+ 0x2c, 0x64, 0x38, 0x10, 0xcb, 0x6d, 0xad, 0xf9, 0x91,
+ 0xcb, 0xcf, 0xbe, 0xf6, 0xf7, 0x94, 0x15, 0xea, 0xaf,
+ 0x37, 0x65, 0x7c, 0xd2, 0xff, 0x99, 0x79, 0xf8, 0x95,
+ 0x27, 0x75, 0x09, 0x60, 0xa4, 0x6f, 0x06, 0x0f, 0x6c,
+ 0x13, 0xdd, 0x32, 0x79, 0xa7, 0x40, 0xa5, 0xdd, 0x2c,
+ 0x22, 0xc1, 0xee, 0xc3, 0x31, 0x59, 0xb1, 0x3d, 0xa1,
+ 0x77, 0x69, 0xb5, 0xd6, 0xae, 0xd7, 0x86, 0xab, 0xa4,
+ 0xdf, 0x9f, 0x36, 0xb4, 0xb2, 0xe6, 0x88, 0xd6, 0x45,
+ 0x9b, 0x8b, 0x87, 0xbd, 0x27, 0xe9, 0x55, 0xd5, 0xac,
+ 0xe9, 0x33, 0x80, 0x00, 0x1d, 0x00, 0x21, 0x74, 0xe2,
+ 0x0a, 0x5b, 0xd2, 0x37, 0xab, 0x6f, 0x48, 0x5e, 0x14,
+ 0x76, 0x3a, 0x84, 0xf9, 0x34, 0x03, 0x74, 0x8d, 0x6c,
+ 0xd8, 0xd4, 0x0f, 0xc7, 0xc8, 0x0c, 0xb5, 0x18, 0x12,
+ 0xa5, 0x5a, 0x76, 0x4b, 0x5d, 0x1e, 0x75, 0x89, 0x3a,
+ 0x01, 0x60, 0xf1, 0x1e, 0x5b, 0x98, 0x71, 0x7a, 0x15,
+ 0x79, 0xff, 0x3d, 0x37, 0x5e, 0xc9, 0x56, 0xa5, 0x43,
+ 0xe7, 0xd0, 0x2b, 0x63, 0xfb, 0x2f, 0x1a, 0x55, 0x37,
+ 0x15, 0x02, 0x7f, 0x9a, 0x84, 0xf0, 0x07, 0x45, 0x2b,
+ 0xa0, 0x9a, 0xb4, 0x60, 0x4d, 0x48, 0xd5, 0xee, 0x64,
+ 0xf9, 0xe7, 0x4b, 0x1c, 0xb9, 0x05, 0xd1, 0xd1, 0x47,
+ 0x4f, 0xca, 0x26, 0x32, 0xad, 0x7b, 0x2e, 0x7e, 0x54,
+ 0x05, 0x96, 0x12, 0x29, 0xbc, 0xd3, 0x45, 0x4e, 0x05,
+ 0x83, 0x6d, 0x30, 0x38, 0xd0, 0x3c, 0x46, 0xcd, 0xb6,
+ 0x21, 0xb6, 0x5c, 0x2a, 0x40, 0x7a, 0x2e, 0x97, 0xd7,
+ 0xbf, 0xa6, 0x55, 0x2a, 0xa6, 0x28, 0x54, 0xc4, 0x66,
+ 0xbe, 0xf6, 0xea, 0xc1, 0x19, 0xcb, 0xcc, 0x52, 0x07,
+ 0xcd, 0x90, 0x3f, 0x09, 0x23, 0x77, 0xf7, 0xc6, 0x03,
+ 0xcc, 0x8b, 0x18, 0xac, 0x63, 0x6d, 0x2a, 0x01, 0x82,
+ 0xad, 0x20, 0x11, 0x82, 0xf3, 0xfe, 0x2d, 0x53, 0x3f,
+ 0x18, 0xb5, 0xbc, 0xf7, 0x0c, 0xa7, 0xca, 0x63, 0xfa,
+ 0x77, 0x8a, 0x3c, 0xc1, 0xc4, 0xb0, 0x15, 0x4b, 0x08,
+ 0xdd, 0xb3, 0xd2, 0x33, 0xc8, 0xc2, 0xaa, 0x1a, 0xe4,
+ 0x9b, 0x1b, 0x18, 0x78, 0x07, 0x6c, 0x08, 0x28, 0x3f,
+ 0xc6, 0xb7, 0x46, 0x8f, 0x8e, 0xc6, 0xff, 0xb1, 0x2d,
+ 0x63, 0x12, 0x7c, 0xe5, 0xd8, 0xa5, 0xf8, 0x64, 0x76,
+ 0xf7, 0x1b, 0xbc, 0x41, 0xad, 0xee, 0xe8, 0x6f, 0xd4,
+ 0x13, 0xea, 0x59, 0x72, 0xfa, 0x04, 0xb4, 0x6e, 0x52,
+ 0x3a, 0xff, 0x60, 0xa0, 0xd8, 0xdf, 0x41, 0x1a, 0x4e,
+ 0xc8, 0x80, 0x2d, 0x29, 0x13, 0xd3, 0xd0, 0x55, 0x20,
+ 0xb5, 0x33, 0x4f, 0x02, 0xd2, 0xea, 0xca, 0x94, 0x99,
+ 0xdf, 0x3c, 0xfd, 0xe5, 0x2b, 0x45, 0x04, 0x85, 0xfe,
+ 0x87, 0x42, 0x53, 0x11, 0x62, 0x2f, 0xcf, 0x05, 0x35,
+ 0x29, 0x6a, 0xa5, 0x37, 0x80, 0x9b, 0x4a, 0x44, 0x3c,
+ 0x6d, 0xe1, 0xd3, 0x88, 0x6a, 0xe7, 0x6f, 0x45, 0xfc,
+ 0x99, 0x33, 0xe4, 0x18, 0x62, 0x19, 0x36, 0x37, 0x6f,
+ 0xe9, 0x37, 0xbb, 0x86, 0xa2, 0x07, 0xec, 0xbc, 0x33,
+ 0x0d, 0x0a, 0x18, 0x30, 0x13, 0xcf, 0x36, 0x31, 0x2f,
+ 0xd2, 0xf6, 0x7e, 0xa8, 0xa4, 0x95, 0x71, 0xc8, 0x40,
+ 0x1f, 0x34, 0xf1, 0x95, 0xde, 0x3e, 0xe1, 0xb7, 0xef,
+ 0x26, 0x1e, 0x20, 0x78, 0xf8, 0x9a, 0x24, 0xbc, 0x7f,
+ 0x64, 0x30, 0x42, 0x63, 0x77, 0x89, 0x96, 0xf8, 0x9b,
+ 0x60, 0x51, 0xb3, 0x02, 0x7a, 0x64, 0x19, 0xd3, 0x13,
+ 0x98, 0xcd, 0xb6, 0x1e, 0x68, 0x82, 0x9b, 0x23, 0x44,
+ 0x3e, 0xa8, 0x57, 0xf5, 0x4d, 0xd8, 0xea, 0x93, 0x84,
+ 0x4e, 0x56, 0x18, 0xb7, 0x94, 0x02, 0xfa, 0x6e, 0x8e,
+ 0xa0, 0x75, 0xd2, 0xb4, 0xbb, 0x50, 0x6f, 0x3f, 0x58,
+ 0xe2, 0x28, 0xb6, 0x87, 0xd6, 0xc5, 0xe0, 0x76, 0xa6,
+ 0xc6, 0x5b, 0xed, 0x6b, 0x48, 0xd4, 0x25, 0xd3, 0x5f,
+ 0x64, 0xab, 0xe3, 0x5a, 0xae, 0x69, 0xe8, 0x06, 0xff,
+ 0xef, 0x67, 0x0b, 0x49, 0xe4, 0xe8, 0x31, 0xee, 0x1a,
+ 0x35, 0x86, 0x0c, 0x81, 0x8a, 0x1f, 0x7f, 0x06, 0x20,
+ 0x66, 0x81, 0x8b, 0xfb, 0xdc, 0x99, 0x78, 0x7b, 0x43,
+ 0x84, 0x35, 0xa7, 0x4f, 0x27, 0xb5, 0xc9, 0x44, 0xbf,
+ 0x05, 0x59, 0xce, 0x4c, 0xe5, 0xaa, 0x18, 0x37, 0x32,
+ 0x5b, 0x41, 0x62, 0x89, 0x0a, 0xec, 0x0a, 0xae, 0x67,
+ 0xcf, 0x0b, 0xef, 0xf6, 0x3a, 0x3b, 0x13, 0x1d, 0xf8,
+ 0x8b, 0x20, 0x5f, 0x2c, 0x55, 0x75, 0xec, 0xf4, 0x9d,
+ 0x2d, 0x0d, 0x0d, 0xb7, 0x88, 0x71, 0xf7, 0xc6, 0xf8,
+ 0x65, 0x1a, 0xba, 0xdb, 0xdc, 0x53, 0xd2, 0x80, 0x92,
+ 0x72, 0x14, 0xce, 0x68, 0xb8, 0xf4, 0x78, 0x4b, 0x92,
+ 0xee, 0x15, 0xfc, 0xd4, 0xe0, 0x89, 0x49, 0x82, 0xf8,
+ 0x7f, 0xce, 0xf6, 0xce, 0x86, 0xfa, 0xa5, 0xd9, 0x3a,
+ 0xfb, 0xef, 0xa8, 0xd9, 0x3b, 0x6e, 0xb5, 0xe2, 0x29,
+ 0x31, 0x6f, 0x5f, 0xa7, 0x34, 0x58, 0x49, 0x07, 0x9c,
+ 0x4d, 0x74, 0x46, 0xb6, 0xd5, 0x0c, 0x3c, 0x26, 0x4b,
+ 0xee, 0x37, 0x9c, 0x92, 0xa2, 0x37, 0x95, 0x35, 0x71,
+ 0xee, 0x46, 0xdd, 0xef, 0xd0, 0xf2, 0xd4, 0xef, 0xe0,
+ 0xdb, 0x28, 0xf4, 0x5d, 0x12, 0xe0, 0x85, 0x4a, 0x3c,
+ 0x5b, 0x2f, 0xd8, 0x9c, 0x9a, 0xcf, 0x6f, 0x01, 0xe7,
+ 0x1b, 0x2e, 0x41, 0x5d, 0x5d, 0xdd, 0xdd, 0xb6, 0x6d,
+ 0xb3, 0x7d, 0xbc, 0x33, 0x50, 0xc5, 0xaf, 0x1b, 0xee,
+ 0x33, 0xc4, 0x42, 0x46, 0xca, 0xe2, 0x00, 0xe9, 0xc9,
+ 0xec, 0x9e, 0x9b, 0x67, 0xba, 0x39, 0x3c, 0xc5, 0xa1,
+ 0x7d, 0xac, 0x9e, 0xbe, 0x67, 0x92, 0x20, 0x5b, 0x36,
+ 0x85, 0xde, 0xdd, 0xd3, 0xec, 0x4e, 0x82, 0x03, 0x4a,
+ 0x44, 0x6e, 0xee, 0x9c, 0xd0, 0x13, 0x9e, 0x98, 0x6f,
+ 0x77, 0xd8, 0xfe, 0xb7, 0x54, 0x01, 0x15, 0xcd, 0xd3,
+ 0x31, 0xf5, 0xd7, 0x74, 0x2d, 0x4d, 0x4f, 0x18, 0xd2,
+ 0x8f, 0x80, 0xb6, 0x46, 0x80, 0xa7, 0xa8, 0x8c, 0xf2,
+ 0x64, 0x4f, 0x40, 0x8a, 0x64, 0x96, 0x2c, 0x1e, 0xd2,
+ 0x3c, 0xe9, 0x50, 0xc4, 0x86, 0xd9, 0x19, 0x93, 0x7a,
+ 0xba, 0x95, 0x35, 0x35, 0xe3, 0x4d, 0x83, 0xda, 0x15,
+ 0x09, 0x87, 0xb8, 0x1a, 0x54, 0x6f, 0x61, 0xdd, 0x55,
+ 0x01, 0xe1, 0x39, 0x1c, 0xb2, 0xac, 0x8c, 0x15, 0x82,
+ 0x7c, 0xa6, 0x69, 0x54, 0x64, 0x2f, 0x5c, 0x0c, 0x79,
+ 0xaf, 0x85, 0x71, 0x2d, 0xff, 0xc0, 0xf2, 0x40, 0xbb,
+ 0x05, 0x31, 0x31, 0x00, 0x8d, 0x0c, 0x40, 0x11, 0x88,
+ 0xf2, 0x91, 0x9f, 0x7a, 0x8e, 0x99, 0x82, 0x72, 0xd8,
+ 0x45, 0x08, 0x83, 0x5c, 0x2b, 0x73, 0x46, 0xd6, 0x54,
+ 0x9a, 0x3d, 0x42, 0x48, 0x67, 0x19, 0x2b, 0x19, 0xae,
+ 0x0c, 0x16, 0x08, 0xa4, 0xec, 0x7e, 0x15, 0xad, 0x4f,
+ 0xa9, 0xbd, 0x4f, 0x09, 0xf0, 0xc2, 0x9f, 0xb5, 0xb7,
+ 0xff, 0x96, 0xf9, 0xf9, 0xc6, 0x5d, 0x57, 0x07, 0xe8,
+ 0xf2, 0x7c, 0x95, 0xa0, 0x8a, 0x15, 0x8b, 0x34, 0x84,
+ 0xb5, 0x28, 0x7a, 0xf5, 0x04, 0xb8, 0xcb, 0x5e, 0x77,
+ 0x4d, 0xdd, 0x14, 0x8d, 0xa6, 0xe2, 0x45, 0x44, 0xfd,
+ 0xd0, 0x9c, 0x41, 0x10, 0xfc, 0xe5, 0xdd, 0x2c, 0xda,
+ 0x6b, 0xfe, 0xf9, 0xff, 0x65, 0xe7, 0x66, 0x40, 0x69,
+ 0x0c, 0x09, 0x99, 0xaf, 0x02, 0xd0, 0x85, 0x55, 0xcc,
+ 0x0d, 0x59, 0xaa, 0xb6, 0x37, 0x9b, 0x58, 0xfa, 0xb5,
+ 0xc5, 0xcd, 0xd5, 0x1c, 0xf9, 0x9f, 0x31, 0x4c, 0x8a,
+ 0x78, 0xca, 0x1e, 0x22, 0xdc, 0x33, 0x64, 0xce, 0x56,
+ 0x6d, 0x57, 0xe9, 0xbd, 0xe0, 0xdd, 0x23, 0x22, 0x9c,
+ 0x70, 0x5a, 0xe7, 0x46, 0x08, 0xc5, 0xa6, 0x85, 0x34,
+ 0x5f, 0x9c, 0x96, 0xbb, 0xbe, 0xb4, 0x2f, 0xbb, 0x47,
+ 0xdc, 0x38, 0xad, 0xb7, 0x92, 0x08, 0x0d, 0x93, 0xf4,
+ 0x7f, 0xe6, 0x64, 0xa5, 0xb3, 0x9e, 0xdd, 0xdb, 0x99,
+ 0x8e, 0xca, 0x82, 0x4f, 0x77, 0xf7, 0xff, 0x92, 0xd3,
+ 0x48, 0xe0, 0x80, 0x71, 0x14, 0x61, 0x6b, 0x77, 0x1b,
+ 0x58, 0xbd, 0xb6, 0xb6, 0xe5, 0xb0, 0xa8, 0x16, 0xe7,
+ 0x4c, 0xc2, 0x5e, 0x40, 0xbc, 0x9f, 0x77, 0x76, 0x98,
+ 0xf7, 0x00, 0xd1, 0xdf, 0x3c, 0x2e, 0x16, 0x4f, 0xe7,
+ 0x91, 0xec, 0xeb, 0xfb, 0xa1, 0x9f, 0x66, 0x6d, 0xef,
+ 0xaf, 0x36, 0xd8, 0xb6, 0x40, 0x7e, 0x2f, 0x51, 0x3b,
+ 0x75, 0x56, 0x1d, 0x33, 0xee, 0x4b, 0xcf, 0x98, 0xb3,
+ 0x9f, 0x4f, 0xff, 0xfd, 0x2a, 0xb9, 0x4e, 0x4b, 0xe0,
+ 0x39, 0x60, 0xd5, 0x7c, 0xaa, 0x28, 0x7e, 0x7e, 0x27,
+ 0xd8, 0x09, 0x85, 0x6d, 0xfa, 0x57, 0x8a, 0xee, 0x84,
+ 0xbe, 0x48, 0xf9, 0x62, 0x78, 0x8a, 0x4d, 0x2a, 0x80,
+ 0x2f, 0x6f, 0xc9, 0xa7, 0xb5, 0x56, 0xbb, 0x58, 0xc2,
+ 0xb9, 0xd0, 0xfe, 0x8d, 0x68, 0x86, 0x2b, 0x7b, 0xf0,
+ 0x01, 0x57, 0xff, 0xaf, 0x88, 0xad, 0x53, 0xf9, 0x63,
+ 0xfe, 0xf4, 0x5a, 0x97, 0xb7, 0x8f, 0x92, 0x0f, 0x90,
+ 0x63, 0xcf, 0xfe, 0x08, 0xbc, 0x8c, 0x5a, 0x9c, 0xac,
+ 0x8b, 0x0a, 0x94, 0x17, 0x25, 0xae, 0x87, 0xa7, 0x1d,
+ 0x3f, 0x28, 0xfe, 0x45, 0x3e, 0x48, 0xef, 0x19, 0x4a,
+ 0xbe, 0xc6, 0xd5, 0x64, 0xe1, 0xf2, 0xf5, 0xd2, 0x3a,
+ 0x03, 0xe0, 0x50, 0x31, 0x7e, 0xdf, 0xd5, 0x15, 0xc6,
+ 0xb6, 0xb2, 0x1e, 0x44, 0x6a, 0x0f, 0x67, 0xf2, 0x34,
+ 0x69, 0xb9, 0xd2, 0x51, 0xeb, 0x86, 0xab, 0x7e, 0x60,
+ 0x68, 0xe4, 0xc2, 0x4b, 0x8b, 0xa2, 0xc6, 0x78, 0xb2,
+ 0x61, 0xa1, 0xe5, 0xb6, 0x33, 0x47, 0x3f, 0xfa, 0xde,
+ 0x5b, 0x6b, 0x95, 0x89, 0x51, 0xbb, 0xd3, 0x8a, 0x00,
+ 0x1d, 0xad, 0xfc, 0x7a, 0x47, 0xc8, 0xa0, 0x69, 0xa6,
+ 0xa3, 0x3f, 0xa9, 0xdb, 0xd8, 0xe4, 0x0d, 0x2c, 0xba,
+ 0x26, 0x2c, 0xa6, 0x82, 0x62, 0x5a, 0x1e, 0x9f, 0xa8,
+ 0x24, 0x9d, 0xe5, 0xc7, 0xcf, 0x6d, 0x2f, 0x68, 0xe1,
+ 0xc0, 0x04, 0xad, 0xde, 0x00, 0x5b, 0x57, 0x35, 0x2b,
+ 0x9a, 0x9b, 0xe5, 0x90, 0x31, 0x8a, 0x5b, 0xea, 0xe5,
+ 0xf6, 0x73, 0x02, 0xc1, 0x33, 0xaf, 0xe7, 0x61, 0x6c,
+ 0x04, 0x8c, 0x08, 0xb2, 0xfb, 0xa2, 0x18, 0x51, 0x39,
+ 0x1a, 0x61, 0x2c, 0x8c, 0x7d, 0x11, 0xb8, 0x2e, 0x38,
+ 0xb7, 0xe0, 0xde, 0x5e, 0x6f, 0xc5, 0xf4, 0x31, 0x72,
+ 0xcb, 0xd6, 0xec, 0xbc, 0xe9, 0x36, 0x2e, 0x2b, 0x63,
+ 0xea, 0xa1, 0xab, 0xf8, 0x11, 0xe7, 0x31, 0xad, 0xe4,
+ 0xcb, 0x23, 0xe4, 0x64, 0x54, 0x50, 0x4f, 0x15, 0x8b,
+ 0x58, 0xa4, 0xa1, 0x35, 0xea, 0x73, 0x3e, 0xc3, 0x3e,
+ 0x31, 0x81, 0x80, 0x53, 0x6a, 0x2c, 0xfe, 0xd7, 0xd8,
+ 0x8f, 0xe7, 0x50, 0x2d, 0x99, 0x69, 0x32, 0xfa, 0x4e,
+ 0xb4, 0xf9, 0x89, 0x18, 0xbe, 0x5a, 0x95, 0x7a, 0x0f,
+ 0x34, 0xc5, 0xd9, 0x28, 0xff, 0x93, 0x3a, 0x13, 0x22,
+ 0xe6, 0xdb, 0x5c, 0xfe, 0x51, 0x05, 0xaf, 0xa3, 0xcd,
+ 0x17, 0x01, 0xd1, 0x84, 0x76, 0x23, 0xff, 0x91, 0xc4,
+ 0x6b, 0xc7, 0xa8, 0x77, 0xe0, 0xda, 0x45, 0xef, 0xd7,
+ 0x13, 0xe3, 0x02, 0x7c, 0x74, 0x7e, 0x66, 0xbb, 0x9f,
+ 0x48, 0x35, 0x56, 0xa8, 0x08, 0x41, 0xf7, 0xa7, 0xe3,
+ 0x60, 0xa6, 0xce, 0x73, 0xdf, 0x73, 0x99, 0xc6, 0xbd,
+ 0x7b, 0xb4, 0xde, 0x31, 0xe6, 0x35, 0xaf, 0x3e, 0x93,
+ 0xd2, 0x69, 0xb5, 0xb9, 0xbe, 0x9f, 0xf4, 0x0d, 0xd8,
+ 0x82, 0xc1, 0x4f, 0xf6, 0xf3, 0x23, 0x1c, 0xe7, 0xff,
+ 0xac, 0xb2, 0x79, 0xe3, 0x62, 0x6a, 0xb7, 0x85, 0x08,
+ 0xda, 0x4a, 0x3f, 0x22, 0x62, 0x2b, 0xcd, 0xb7, 0x59,
+ 0xf5, 0x82, 0xef, 0x08, 0x7f, 0xb5, 0xa0, 0x6c, 0xba,
+ 0x61, 0x45, 0x8f, 0xf4, 0xa2, 0x66, 0x83, 0x72, 0x65,
+ 0x34, 0x34, 0x68, 0x99, 0xf5, 0x99, 0xc9, 0x52, 0x6a,
+ 0xc2, 0x7f, 0xde, 0x25, 0xa3, 0x7b, 0xce, 0xa3, 0xde,
+ 0x6d, 0x62, 0x98, 0x84, 0xe4, 0x2a, 0xe1, 0x1c, 0xa9,
+ 0x0b, 0x7e, 0x45, 0xd3, 0x78, 0x40, 0x85, 0x61, 0x9d,
+ 0xce, 0xcd, 0xfd, 0x7b, 0x66, 0x92, 0x5f, 0xb9, 0x37,
+ 0x04, 0xea, 0xec, 0x37, 0x32, 0xbe, 0xcd, 0x3e, 0x5e,
+ 0x37, 0xcd, 0xe3, 0x81, 0x92, 0x69, 0xdf, 0xa1, 0xb9,
+ 0x8c, 0x44, 0x43, 0xae, 0xcd, 0xe5, 0xd5, 0x4e, 0xb9,
+ 0x2f, 0x1e, 0xbc, 0xf2, 0xd1, 0x88, 0x93, 0xde, 0x6a,
+ 0x8a, 0x43, 0xa1, 0x6b, 0xdc, 0x5b, 0xd2, 0xdd, 0xe8,
+ 0xca, 0x0a, 0x95, 0x45, 0x9f, 0xd8, 0x8c, 0xfd, 0xe0,
+ 0xc3, 0xbd, 0x0e, 0xa0, 0xbd, 0x72, 0xa7, 0x77, 0x9a,
+ 0x79, 0xd9, 0x15, 0xad, 0x50, 0x13, 0xa7, 0x41, 0xc7,
+ 0xd1, 0xec, 0x2f, 0x45, 0x14, 0x02, 0xb7, 0x8e, 0x51,
+ 0x76, 0xd4, 0x2f, 0x1c, 0xea, 0x9c, 0x6d, 0x35, 0x1c,
+ 0xa7, 0xeb, 0xd7, 0x79, 0xe4, 0x35, 0xbc, 0x02, 0xa6,
+ 0xd0, 0x58, 0xcb, 0xdf, 0xea, 0x90, 0x16, 0x53, 0x3c,
+ 0xc5, 0xda, 0x36, 0x4f, 0x61, 0x4a, 0x1b, 0xfa, 0x15,
+ 0x52, 0x0d, 0x3d, 0x73, 0xc5, 0xfe, 0x2a, 0xa2, 0x4a,
+ 0x6e, 0x95, 0x99, 0xfc, 0xbf, 0xb2, 0xfc, 0x22, 0xbe,
+ 0x45, 0x10, 0x5a, 0xc5, 0x38, 0xa0, 0xc1, 0xba, 0x46,
+ 0x6d, 0x8e, 0xbe, 0x0b, 0x5f, 0xf6, 0x6f, 0xbb, 0x4d,
+ 0x22, 0xf5, 0x95, 0x4d, 0x12, 0xc2, 0x6f, 0x8d, 0xde,
+ 0x86, 0xaf, 0x3f, 0x08, 0x24, 0x56, 0xa3, 0xcd, 0xfc,
+ 0xeb, 0xa1, 0x3c, 0x22, 0x66, 0x45, 0x03, 0x8b, 0x04,
+ 0x12, 0x80, 0x34, 0xf9, 0xf4, 0x64, 0xbf, 0xb9, 0x3d,
+ 0xd7, 0x34, 0xe4, 0xc8, 0x8e, 0x86, 0xc9, 0x73, 0x21,
+ 0x7f, 0x30, 0x01, 0xc8, 0xd2, 0x91, 0x8d, 0xc4, 0xca,
+ 0xd5, 0x59, 0xac, 0xd7, 0xb4, 0xfb, 0x98, 0xfb, 0xc4,
+ 0x48, 0x82, 0x93, 0xc6, 0x58, 0x8b, 0x0c, 0xdf, 0x3f,
+ 0x07, 0x5a, 0x94, 0x89, 0xc6, 0xbe, 0x1a, 0x19, 0x63,
+ 0x8b, 0xa8, 0x0c, 0x20, 0xae, 0x9a, 0x1b, 0xd3, 0x45,
+ 0xa0, 0xd9, 0x8c, 0xbb, 0x67, 0xa0, 0x54, 0x86, 0x9b,
+ 0x7b, 0xa8, 0x16, 0x6f, 0xa4, 0x59, 0x45, 0x1e, 0x34,
+ 0xb5, 0xa7, 0x1b, 0x3f, 0xda, 0xc6, 0x80, 0x19, 0xdc,
+ 0xc2, 0xee, 0xeb, 0xd9, 0x96, 0xdc, 0x4f, 0xec, 0x02,
+ 0xde, 0x34, 0x43, 0x5a, 0x37, 0xc8, 0xdf, 0x3b, 0x53,
+ 0x82, 0xfa, 0xf8, 0x8a, 0x32, 0x97, 0x1e, 0xf6, 0x0e,
+ 0x7d, 0x39, 0xe0, 0xdb, 0x0b, 0x22, 0xa4, 0xd0, 0x56,
+ 0x13, 0xbc, 0xe9, 0x38, 0x92, 0x76, 0xff, 0x2b, 0xc2,
+ 0xa0, 0x98, 0x7d, 0x8c, 0x58, 0x8e, 0x7f, 0x6d, 0x80,
+ 0x06, 0xff, 0xc7, 0xb3, 0xb7, 0x1b, 0xac, 0xc4, 0x68,
+ 0x61, 0x11, 0x15, 0xb7, 0xee, 0x8d, 0x66, 0x34, 0x9f,
+ 0x18, 0x03, 0x88, 0xd1, 0x04, 0xd0, 0x86, 0xc0, 0xca,
+ 0x2a, 0xe1, 0x1b, 0x47, 0x18, 0xc9, 0x97, 0xed, 0x1f,
+ 0x99, 0xc6, 0xa9, 0x20, 0x3f, 0xf6, 0x43, 0x96, 0x30,
+ 0x8b, 0xa5, 0xcb, 0x2e, 0xc5, 0xdb, 0x26, 0xc0, 0xf6,
+ 0x48, 0x07, 0x3a, 0x28, 0x3e, 0x35, 0x38, 0x50, 0x80,
+ 0xdf, 0x80, 0xfa, 0x12, 0x92, 0x83, 0x55, 0xde, 0x31,
+ },
+ .msg_len = 64,
+ .msg =
+ (const u8[64]) {
+ 0x48, 0x11, 0x92, 0xb3, 0xaa, 0x7e, 0xb3, 0x14,
+ 0xdc, 0x46, 0xd6, 0xbf, 0x26, 0xb2, 0x66, 0xc5,
+ 0xd8, 0xc4, 0x69, 0x9f, 0x67, 0x50, 0x67, 0xc0,
+ 0x3b, 0x8d, 0xc5, 0xb5, 0x68, 0x59, 0x6f, 0x9c,
+ 0xd4, 0xf2, 0x49, 0xfb, 0xa4, 0xd0, 0xbf, 0xc5,
+ 0x3c, 0xee, 0x3b, 0x03, 0x25, 0x6c, 0x51, 0x94,
+ 0xb3, 0xd4, 0xdb, 0x2a, 0xbd, 0x26, 0xef, 0x58,
+ 0xb3, 0x91, 0x62, 0x81, 0x1b, 0x29, 0x9c, 0x12,
+ },
+ .sig_len = MLDSA87_SIGNATURE_SIZE,
+ .sig =
+ (const u8[MLDSA87_SIGNATURE_SIZE]) {
+ 0xba, 0x08, 0xf3, 0x0c, 0xa1, 0x48, 0xad, 0x67, 0x12,
+ 0x68, 0x51, 0x9b, 0xa4, 0x21, 0x66, 0x8d, 0xea, 0x0a,
+ 0x71, 0x4f, 0x4c, 0xab, 0x1b, 0x42, 0x84, 0xb7, 0x9c,
+ 0x78, 0xa9, 0x18, 0xd9, 0xe8, 0x08, 0x8f, 0xee, 0xf7,
+ 0x4b, 0xcf, 0x0e, 0xcd, 0xf6, 0x36, 0xcf, 0xd5, 0xa1,
+ 0x5e, 0x59, 0xc6, 0x8c, 0x6c, 0x4d, 0xfe, 0xfa, 0xfa,
+ 0xbc, 0x52, 0x3a, 0x35, 0xba, 0xd9, 0xe1, 0xf2, 0x26,
+ 0x73, 0xbd, 0x64, 0x93, 0xe7, 0x83, 0x76, 0xc4, 0xf8,
+ 0x4b, 0xa9, 0x91, 0x8c, 0xd2, 0xf5, 0x08, 0xe6, 0x58,
+ 0xcd, 0xfb, 0x90, 0xc1, 0x84, 0x72, 0x77, 0x72, 0x47,
+ 0x5f, 0xcb, 0x7f, 0x74, 0x85, 0x56, 0xba, 0x73, 0x86,
+ 0xc1, 0x32, 0x1c, 0xaf, 0xc5, 0x60, 0x2c, 0x91, 0x99,
+ 0x09, 0x03, 0xcb, 0xe6, 0xa4, 0xae, 0x0b, 0xdc, 0x15,
+ 0x70, 0x4c, 0x91, 0xa9, 0x9e, 0x5e, 0x63, 0x5c, 0x24,
+ 0xc9, 0x26, 0x39, 0x56, 0xe4, 0x6c, 0x2c, 0x65, 0xf8,
+ 0x0b, 0x4f, 0x56, 0x8f, 0x1e, 0x74, 0xda, 0x31, 0xad,
+ 0x8f, 0x1b, 0xa7, 0xb1, 0xb3, 0x9b, 0x48, 0x09, 0x08,
+ 0xdd, 0xe1, 0x25, 0x20, 0xa4, 0xc7, 0x12, 0xd4, 0xb0,
+ 0xa0, 0xcb, 0x90, 0xf5, 0x9f, 0xc1, 0x8b, 0xbc, 0x9d,
+ 0xcf, 0x78, 0xfc, 0xa1, 0x04, 0x4b, 0x0b, 0x7e, 0x82,
+ 0x94, 0x80, 0x0e, 0x70, 0x77, 0xce, 0x63, 0x1c, 0x43,
+ 0x41, 0x3f, 0x5d, 0x61, 0x1a, 0x44, 0xaa, 0xd0, 0xb7,
+ 0x18, 0xd8, 0x91, 0x83, 0xa4, 0xa7, 0xa1, 0x86, 0x13,
+ 0x54, 0xaf, 0xa8, 0xdb, 0x1a, 0xd7, 0xa9, 0x54, 0xca,
+ 0x67, 0xb5, 0xb6, 0xb4, 0x22, 0x1a, 0x24, 0x8e, 0x65,
+ 0x01, 0xa8, 0xd2, 0x15, 0x9d, 0x98, 0x59, 0x70, 0x94,
+ 0xb4, 0x96, 0xeb, 0xf2, 0x95, 0x41, 0x9a, 0x89, 0x02,
+ 0xb7, 0x6a, 0x20, 0x2a, 0x64, 0xf1, 0x1c, 0x1e, 0x3d,
+ 0xd8, 0xdb, 0x6d, 0xef, 0xf2, 0x1a, 0x24, 0xa4, 0xd0,
+ 0xb9, 0x98, 0xd3, 0xe5, 0xbd, 0x7a, 0xa3, 0xc3, 0x19,
+ 0x97, 0x54, 0x77, 0x97, 0xb5, 0x57, 0x93, 0x71, 0x24,
+ 0x91, 0x81, 0xcf, 0x5f, 0x38, 0xb9, 0xd5, 0x7e, 0x8b,
+ 0x0f, 0xea, 0x56, 0x49, 0xac, 0x25, 0xc4, 0x6c, 0x5e,
+ 0x4e, 0x08, 0x31, 0xc8, 0xdf, 0x0b, 0x19, 0xb9, 0xbc,
+ 0xec, 0x3b, 0x89, 0xf8, 0x98, 0xe3, 0x6c, 0xf6, 0x0f,
+ 0x5b, 0x7e, 0x03, 0x10, 0x68, 0x78, 0x2c, 0xfa, 0x39,
+ 0x5c, 0x64, 0x5b, 0xa1, 0xfc, 0x8d, 0x14, 0x87, 0x62,
+ 0x04, 0x57, 0xc0, 0x5b, 0x6f, 0x6e, 0x3c, 0xea, 0xe6,
+ 0x23, 0xde, 0x9b, 0x1d, 0x89, 0x69, 0x38, 0xfb, 0x10,
+ 0xab, 0xb9, 0xda, 0xee, 0xa8, 0x8d, 0x96, 0xc0, 0xa5,
+ 0x40, 0xce, 0x16, 0x1e, 0xf5, 0xf4, 0x74, 0x6f, 0x0e,
+ 0x38, 0xe5, 0x1d, 0xe6, 0x6c, 0x19, 0xa5, 0x71, 0x48,
+ 0xda, 0x3e, 0xe9, 0x10, 0x57, 0x16, 0x89, 0xd3, 0x5b,
+ 0x4a, 0x5b, 0xa9, 0xb1, 0x13, 0xad, 0x77, 0xaf, 0x1f,
+ 0x8b, 0x71, 0x3f, 0xff, 0x7c, 0xc4, 0x31, 0xb2, 0xa7,
+ 0x18, 0x2f, 0x4b, 0x99, 0xe2, 0x14, 0xbf, 0x1e, 0x69,
+ 0x8f, 0x56, 0xe2, 0x2c, 0x84, 0x34, 0xd6, 0x76, 0x27,
+ 0x06, 0x7f, 0x2e, 0x9d, 0xbe, 0x90, 0x95, 0xda, 0x5a,
+ 0xfb, 0xaa, 0x8a, 0x51, 0x3d, 0x97, 0xb8, 0x75, 0xe9,
+ 0xba, 0x2a, 0x03, 0x7e, 0xb0, 0xe3, 0xdc, 0xe3, 0x3b,
+ 0x2a, 0xd8, 0x77, 0xa5, 0xf3, 0x76, 0x69, 0xf1, 0xd2,
+ 0xd5, 0xb3, 0xba, 0xfa, 0x97, 0x55, 0x5f, 0xd1, 0xc3,
+ 0x10, 0x55, 0x9a, 0xb6, 0xce, 0x32, 0x80, 0x7f, 0x48,
+ 0xb7, 0x15, 0x85, 0x3f, 0x22, 0x58, 0x00, 0x51, 0x12,
+ 0x5c, 0xcc, 0xd0, 0x77, 0x26, 0x57, 0x4b, 0xbb, 0x67,
+ 0x21, 0x0d, 0x92, 0x80, 0xe0, 0xec, 0x2f, 0x58, 0x44,
+ 0x8b, 0x98, 0x70, 0x16, 0x13, 0x91, 0x38, 0xee, 0x9e,
+ 0x4f, 0xf2, 0x6f, 0x95, 0x49, 0xe8, 0xcc, 0xc5, 0x6d,
+ 0x20, 0x20, 0x4d, 0x1b, 0x08, 0xf4, 0xa5, 0x8b, 0xf3,
+ 0xf6, 0x89, 0x2c, 0x17, 0xa6, 0xa8, 0xa8, 0xfb, 0xab,
+ 0x6f, 0xa0, 0xe3, 0xcd, 0xc5, 0xfb, 0xac, 0x91, 0x42,
+ 0x8c, 0xf2, 0x28, 0xd1, 0x13, 0xdb, 0x63, 0x59, 0x69,
+ 0xab, 0x16, 0x5a, 0xaf, 0x0a, 0xfa, 0x43, 0x6d, 0x53,
+ 0x7f, 0x14, 0x88, 0xc8, 0xa1, 0x71, 0x45, 0x54, 0x30,
+ 0xa7, 0x91, 0x55, 0x44, 0x07, 0x03, 0x78, 0xf3, 0xf6,
+ 0x23, 0xc0, 0x21, 0x4b, 0x39, 0xc4, 0x9a, 0x5a, 0xe8,
+ 0xad, 0x28, 0x6b, 0xd2, 0xd7, 0xc9, 0xed, 0xf4, 0x30,
+ 0xff, 0xf8, 0xc4, 0x7a, 0xfe, 0x49, 0x1c, 0x28, 0xbb,
+ 0x89, 0xfa, 0x9d, 0x64, 0xcc, 0x37, 0x76, 0x6a, 0xf3,
+ 0x8b, 0x94, 0x60, 0xe0, 0xb2, 0x29, 0xf8, 0x5a, 0xc6,
+ 0x3e, 0xcc, 0x6f, 0x13, 0x85, 0x7c, 0xaa, 0xc4, 0x35,
+ 0x56, 0x9a, 0xb6, 0x96, 0x76, 0x41, 0xe2, 0x11, 0xbe,
+ 0x07, 0xba, 0x0c, 0x21, 0x32, 0xc3, 0xb3, 0xf3, 0x96,
+ 0x49, 0xa2, 0xc4, 0x49, 0x48, 0xfe, 0x17, 0xef, 0xdf,
+ 0x1e, 0xf3, 0xde, 0x5f, 0xa0, 0x49, 0xfc, 0xa5, 0xb5,
+ 0xf3, 0x4c, 0x99, 0x5f, 0xcb, 0x33, 0xc6, 0x54, 0x52,
+ 0xa0, 0x85, 0x16, 0x75, 0x2c, 0x5f, 0x87, 0x61, 0x58,
+ 0xc9, 0x23, 0x0a, 0x36, 0x66, 0x3b, 0x78, 0x65, 0xcc,
+ 0xd4, 0x8e, 0xe1, 0x27, 0x9a, 0x74, 0x37, 0x79, 0x4c,
+ 0x5c, 0x35, 0xf9, 0xa5, 0x7f, 0x79, 0x35, 0xa8, 0x7d,
+ 0xcf, 0x64, 0xa3, 0x44, 0xb9, 0xee, 0x1e, 0x07, 0x5c,
+ 0xda, 0xcd, 0x93, 0xfc, 0x33, 0x77, 0x68, 0xfc, 0xd6,
+ 0xea, 0xf4, 0xcd, 0x0a, 0x3a, 0xe3, 0xb3, 0xef, 0xf9,
+ 0xb5, 0x1a, 0x4b, 0x50, 0x2e, 0xcb, 0x88, 0x48, 0x60,
+ 0xc3, 0x5c, 0x1b, 0xb7, 0xcc, 0x7a, 0x49, 0x2e, 0xf0,
+ 0x9e, 0x96, 0x47, 0x7d, 0x82, 0x85, 0xcb, 0x37, 0x85,
+ 0x26, 0xfd, 0xe1, 0x13, 0x57, 0xad, 0x51, 0xdc, 0x02,
+ 0x8d, 0x3c, 0x4e, 0xdd, 0xf3, 0xdf, 0xbe, 0xab, 0x0d,
+ 0x99, 0xf8, 0x13, 0x37, 0x0b, 0x1b, 0xaf, 0x08, 0x9b,
+ 0x38, 0x5b, 0x3a, 0x91, 0x71, 0x9a, 0xe6, 0xc1, 0x7d,
+ 0xd4, 0xd8, 0xf2, 0x66, 0x57, 0x99, 0x29, 0x58, 0xb5,
+ 0x9d, 0x8f, 0x86, 0x7f, 0xe9, 0x17, 0xff, 0x3c, 0xfd,
+ 0x0a, 0xfd, 0x15, 0x5c, 0x2f, 0x77, 0x6c, 0x2b, 0x86,
+ 0x72, 0xcb, 0x00, 0x4d, 0x31, 0x98, 0xfe, 0x28, 0xc5,
+ 0x54, 0x36, 0x97, 0x8c, 0xc9, 0x31, 0xae, 0xff, 0xfc,
+ 0xa6, 0x15, 0xf9, 0x9d, 0x49, 0x83, 0x47, 0xb4, 0xe5,
+ 0x8c, 0x55, 0x2f, 0x35, 0x6d, 0x7c, 0x47, 0xb9, 0xeb,
+ 0x0a, 0x64, 0xea, 0x22, 0xae, 0xe3, 0x6b, 0xae, 0x0e,
+ 0xf8, 0xc4, 0x64, 0x18, 0x56, 0xa7, 0x78, 0x92, 0x20,
+ 0xe0, 0x03, 0x93, 0x42, 0x1f, 0x1a, 0x48, 0xa1, 0x11,
+ 0xdd, 0x83, 0x99, 0x67, 0xc5, 0xf2, 0x0a, 0x9e, 0xfa,
+ 0xab, 0x68, 0x54, 0x1d, 0xa7, 0xe8, 0x44, 0x5f, 0x46,
+ 0x23, 0xea, 0xdd, 0xb2, 0xf5, 0x83, 0x76, 0x84, 0x13,
+ 0xd6, 0xe4, 0xb2, 0x59, 0x92, 0x92, 0xf4, 0xb5, 0x56,
+ 0xd7, 0x29, 0xc7, 0x05, 0x00, 0x79, 0x17, 0x59, 0x20,
+ 0xc6, 0x6a, 0xdc, 0x45, 0x93, 0xe7, 0xfc, 0x29, 0x37,
+ 0xa7, 0x7e, 0xbc, 0x21, 0xe7, 0xe1, 0xff, 0x18, 0x54,
+ 0xf9, 0xd3, 0x0c, 0x78, 0xe1, 0xc9, 0x40, 0x36, 0x36,
+ 0x68, 0x46, 0x3c, 0x9a, 0x4d, 0xa6, 0xbc, 0xc3, 0xc7,
+ 0xc9, 0x8c, 0x7e, 0xc6, 0x07, 0x2a, 0xd0, 0x4d, 0x45,
+ 0x3d, 0x65, 0xef, 0x56, 0x7f, 0xf1, 0xcd, 0x6d, 0x97,
+ 0x0c, 0x11, 0x66, 0xf4, 0x27, 0xfc, 0xe3, 0xf3, 0x93,
+ 0x0d, 0xa1, 0x5a, 0x95, 0x86, 0xcc, 0x0f, 0xf4, 0x97,
+ 0xbc, 0x7c, 0x62, 0x78, 0xe5, 0x01, 0xe0, 0xc7, 0x0c,
+ 0xe7, 0xa9, 0x84, 0xa6, 0x17, 0xaa, 0x36, 0x06, 0x2a,
+ 0x0f, 0x2f, 0x7e, 0x3d, 0xe8, 0x70, 0x8d, 0x36, 0x73,
+ 0x9a, 0x7f, 0x47, 0x95, 0xc5, 0x5d, 0xc5, 0xfa, 0x9c,
+ 0x64, 0x52, 0xcb, 0x52, 0x74, 0xda, 0xb0, 0x1f, 0x82,
+ 0x01, 0x43, 0x98, 0xa6, 0xe7, 0xf2, 0x89, 0x51, 0x92,
+ 0xf8, 0x37, 0x82, 0x8e, 0x91, 0x58, 0x40, 0x2c, 0xac,
+ 0xcf, 0xde, 0x92, 0x63, 0x5a, 0x64, 0xf9, 0x9c, 0xa4,
+ 0x47, 0x6d, 0x13, 0x43, 0xd3, 0xa6, 0x89, 0xbb, 0x7b,
+ 0x32, 0x45, 0x2d, 0x0e, 0x52, 0x25, 0x67, 0xda, 0x1d,
+ 0x9e, 0x42, 0x38, 0xfc, 0x92, 0x84, 0x4d, 0x13, 0x53,
+ 0xef, 0x46, 0x81, 0xdd, 0xf6, 0x79, 0x9f, 0xba, 0x45,
+ 0x49, 0x4b, 0x93, 0x4a, 0x54, 0x1c, 0x72, 0xa0, 0xfd,
+ 0xa1, 0x13, 0x1c, 0x5e, 0xa5, 0x4e, 0xd5, 0xdf, 0xd1,
+ 0x6a, 0x40, 0x1d, 0x5e, 0x57, 0xf8, 0xe3, 0x3a, 0xe8,
+ 0x35, 0xf4, 0x67, 0xa2, 0x37, 0xf2, 0xe0, 0xd1, 0xfe,
+ 0x08, 0x5e, 0x5c, 0x41, 0x17, 0x87, 0x24, 0xae, 0xf3,
+ 0xe2, 0xc8, 0xb4, 0xfc, 0x3b, 0xef, 0xdb, 0x5e, 0x27,
+ 0x93, 0x0f, 0x01, 0xf9, 0x35, 0xcf, 0x67, 0x4f, 0x65,
+ 0xde, 0xca, 0xb6, 0xf1, 0x12, 0xa0, 0xd7, 0x53, 0x09,
+ 0xec, 0x83, 0x9a, 0xb6, 0x8f, 0xf6, 0x03, 0xdf, 0x92,
+ 0xa9, 0xc4, 0x85, 0x55, 0x5a, 0x74, 0x66, 0x9e, 0xc0,
+ 0x46, 0xc7, 0x50, 0x7b, 0xda, 0x56, 0x4a, 0xf5, 0x38,
+ 0x37, 0xd5, 0x82, 0x81, 0xf3, 0x2d, 0x51, 0xa6, 0xa3,
+ 0x34, 0xf9, 0x24, 0xed, 0x35, 0x80, 0x72, 0xae, 0x3d,
+ 0x8b, 0xf8, 0x66, 0xb2, 0x6c, 0x3f, 0x4e, 0x2c, 0xdb,
+ 0x89, 0x76, 0x95, 0x8f, 0x1a, 0xbe, 0xfc, 0x6c, 0x37,
+ 0xec, 0xf9, 0x80, 0x32, 0xac, 0x94, 0x97, 0x85, 0xe4,
+ 0xa5, 0x19, 0x32, 0x46, 0x1f, 0x98, 0x89, 0x4c, 0x85,
+ 0xf1, 0xfc, 0xed, 0x01, 0x98, 0x4d, 0x4a, 0xd4, 0xd1,
+ 0x4e, 0x82, 0x0b, 0x32, 0x0d, 0x48, 0x34, 0x64, 0x98,
+ 0xea, 0x6c, 0xf9, 0x11, 0x25, 0xbc, 0x48, 0xc3, 0xf4,
+ 0x96, 0xfc, 0x5e, 0x71, 0x5d, 0xfa, 0xf7, 0x9f, 0x75,
+ 0x89, 0x1d, 0xe7, 0x3b, 0x97, 0x39, 0x18, 0x90, 0xca,
+ 0xa5, 0x46, 0x01, 0x2a, 0x13, 0x54, 0x5c, 0x2a, 0x14,
+ 0xed, 0x1b, 0x65, 0x0a, 0xb0, 0xd9, 0x95, 0x01, 0xd0,
+ 0xb3, 0x78, 0xd6, 0xc4, 0x06, 0xf3, 0x7f, 0x51, 0xe0,
+ 0x39, 0xed, 0x2c, 0xf3, 0xfa, 0xc3, 0xfa, 0x1d, 0x7c,
+ 0x82, 0x0f, 0x45, 0xb7, 0x15, 0xcf, 0x99, 0x53, 0x59,
+ 0x9d, 0x54, 0x31, 0x6a, 0xf8, 0xb8, 0x73, 0x2d, 0xd1,
+ 0xab, 0x1b, 0x69, 0xc9, 0x86, 0xdc, 0x7a, 0xca, 0xb9,
+ 0x6a, 0xaf, 0x1e, 0x8f, 0x83, 0xa8, 0xf0, 0xae, 0x44,
+ 0x85, 0x0d, 0x1f, 0x6c, 0x3a, 0x90, 0x50, 0xef, 0x7c,
+ 0x3c, 0x1c, 0xc4, 0xb8, 0x66, 0x1c, 0x14, 0xf7, 0xf2,
+ 0x5f, 0x5c, 0x70, 0x28, 0xa7, 0x55, 0x93, 0xdb, 0xa0,
+ 0x95, 0x9c, 0x1b, 0xb7, 0xb6, 0x44, 0x5e, 0x98, 0x88,
+ 0x89, 0xb8, 0x5a, 0xee, 0xba, 0xfc, 0xc6, 0x87, 0x2a,
+ 0xdb, 0xb7, 0xcf, 0xb2, 0x4b, 0x96, 0x2c, 0x91, 0x54,
+ 0x34, 0x33, 0xfb, 0x57, 0xbe, 0xf5, 0x7b, 0xbe, 0x6b,
+ 0xa0, 0x3b, 0x4d, 0x09, 0x18, 0x9b, 0x75, 0x2c, 0xde,
+ 0x28, 0x87, 0xd3, 0x7b, 0xf5, 0xbe, 0x0d, 0x33, 0x5a,
+ 0x3b, 0x92, 0x41, 0x35, 0x50, 0x65, 0xc9, 0xa9, 0xfa,
+ 0xab, 0x22, 0x4b, 0x8c, 0x3a, 0xb1, 0x9e, 0x31, 0x41,
+ 0xd2, 0x2f, 0xca, 0x9e, 0xd0, 0x96, 0x0c, 0x03, 0x08,
+ 0xec, 0x94, 0xa5, 0xb1, 0x65, 0x2b, 0xe1, 0xe4, 0x48,
+ 0x11, 0xd6, 0x8c, 0x60, 0x6d, 0xf4, 0x64, 0x89, 0xa6,
+ 0x69, 0x4b, 0xa0, 0xbe, 0xae, 0xf5, 0xde, 0xba, 0x45,
+ 0x12, 0xc8, 0x28, 0xe0, 0x7a, 0xb5, 0xd4, 0x75, 0x7a,
+ 0x24, 0x59, 0x4f, 0xbf, 0x0a, 0xa4, 0x53, 0x9a, 0x59,
+ 0xca, 0x06, 0x51, 0x6d, 0xcb, 0x93, 0x63, 0x6e, 0x24,
+ 0xe2, 0x41, 0xa5, 0xa9, 0x19, 0xc3, 0x59, 0x9a, 0x0c,
+ 0xb6, 0x4e, 0x65, 0x60, 0xa0, 0x49, 0xf0, 0x7f, 0x50,
+ 0x96, 0xed, 0xe9, 0xfc, 0x33, 0x5b, 0x52, 0x51, 0x7e,
+ 0x77, 0xd7, 0xbb, 0xaf, 0xdd, 0x12, 0x4b, 0xbc, 0xc6,
+ 0xae, 0xca, 0x92, 0x3a, 0x9f, 0xc1, 0x0c, 0x8f, 0x01,
+ 0xbe, 0x4c, 0x78, 0x23, 0x7c, 0x8b, 0x82, 0xb7, 0x45,
+ 0x80, 0x44, 0x34, 0x9d, 0x13, 0xdb, 0xc4, 0x3f, 0x1b,
+ 0x39, 0xb0, 0xee, 0xa9, 0xac, 0x5e, 0x3d, 0xc3, 0x59,
+ 0x92, 0xcc, 0x6e, 0x6c, 0x97, 0xcc, 0xba, 0x15, 0xa6,
+ 0x53, 0x92, 0x76, 0x35, 0x01, 0x70, 0x16, 0xde, 0xde,
+ 0x56, 0xc3, 0xb3, 0x48, 0x8b, 0x4d, 0xfa, 0xa7, 0xcb,
+ 0x43, 0xb5, 0x76, 0x9a, 0x56, 0x03, 0xd6, 0x41, 0xbe,
+ 0x73, 0x89, 0x1f, 0x6f, 0x02, 0x3f, 0xcc, 0xaf, 0x49,
+ 0xe3, 0x5e, 0xb3, 0xf4, 0xbc, 0x61, 0xf9, 0x9e, 0x9e,
+ 0xec, 0x10, 0x98, 0x0d, 0x5a, 0x6d, 0xcf, 0xbf, 0xe3,
+ 0xe5, 0xf5, 0x1b, 0x17, 0x46, 0x7a, 0x32, 0xc7, 0x18,
+ 0x40, 0x20, 0x8e, 0x06, 0x62, 0x2d, 0x1b, 0x90, 0x54,
+ 0x4f, 0x7f, 0xe4, 0x50, 0x09, 0xdc, 0x57, 0x22, 0xe9,
+ 0x7c, 0x3c, 0x77, 0x57, 0xc2, 0x8b, 0xc9, 0x6a, 0x2b,
+ 0x31, 0xa1, 0x7f, 0x14, 0xdf, 0x22, 0x7d, 0xed, 0xc9,
+ 0x0d, 0xbb, 0x93, 0xba, 0x72, 0x85, 0x33, 0x58, 0x80,
+ 0xc0, 0xf5, 0x75, 0x5d, 0x7e, 0x5f, 0xfb, 0x41, 0xbc,
+ 0x5f, 0x62, 0x13, 0xb9, 0x16, 0x1e, 0xfe, 0x9e, 0x53,
+ 0x53, 0xce, 0xa0, 0xfc, 0x7f, 0xf6, 0x18, 0xc2, 0x0f,
+ 0xb9, 0x7f, 0xbf, 0x09, 0xc3, 0x37, 0x08, 0xb0, 0x1f,
+ 0x16, 0x80, 0x5e, 0xf6, 0xcb, 0xfe, 0x22, 0x7c, 0x07,
+ 0x99, 0xb3, 0x12, 0x69, 0xa4, 0x05, 0xc9, 0x29, 0xc7,
+ 0xd0, 0x57, 0x05, 0x33, 0x85, 0x0c, 0xd4, 0xfe, 0xfc,
+ 0x54, 0xa8, 0xc9, 0x7b, 0x92, 0x67, 0xa6, 0xa7, 0xbf,
+ 0x5f, 0xfc, 0xe9, 0x65, 0x31, 0x4f, 0x85, 0x8f, 0x89,
+ 0xbe, 0xa1, 0xdb, 0x6d, 0x96, 0x52, 0x09, 0x56, 0x12,
+ 0xc6, 0xb2, 0x28, 0x26, 0x07, 0x39, 0x21, 0x39, 0xce,
+ 0x55, 0xf9, 0x82, 0x23, 0xc2, 0x3f, 0x3a, 0x66, 0xc4,
+ 0xee, 0x10, 0x4b, 0xf1, 0x1e, 0x1d, 0x59, 0xfa, 0x28,
+ 0x20, 0x34, 0x26, 0x49, 0x7c, 0xc3, 0x85, 0x2f, 0x80,
+ 0xbe, 0x2c, 0xbc, 0x94, 0x81, 0x74, 0x2a, 0x21, 0x49,
+ 0x1d, 0xa7, 0xff, 0xf0, 0x21, 0x56, 0x98, 0x68, 0x8f,
+ 0x52, 0x2d, 0xa0, 0xf2, 0x84, 0x73, 0x2f, 0xe2, 0x90,
+ 0x8c, 0x56, 0xd1, 0xbf, 0x67, 0xc3, 0x19, 0x47, 0x14,
+ 0x71, 0x62, 0x25, 0xdc, 0x11, 0xbc, 0x24, 0xa0, 0xb2,
+ 0x42, 0x72, 0x37, 0x78, 0xe6, 0xe0, 0xf6, 0x8c, 0x66,
+ 0xe5, 0x1b, 0x7a, 0x79, 0x46, 0xc0, 0x76, 0xcd, 0xa9,
+ 0x3c, 0xb2, 0x17, 0x8c, 0xc9, 0xb1, 0xc4, 0x2a, 0x1f,
+ 0xdb, 0xf7, 0xeb, 0x8a, 0x5d, 0x29, 0xd1, 0xd1, 0x98,
+ 0x43, 0x9e, 0x22, 0xf3, 0x96, 0x1e, 0x83, 0xeb, 0x44,
+ 0x08, 0xc4, 0xa0, 0xd2, 0xd3, 0x36, 0xf8, 0x94, 0xab,
+ 0x3c, 0x4b, 0x68, 0xf3, 0x7c, 0x1a, 0x16, 0x1a, 0x66,
+ 0x77, 0x67, 0xee, 0x64, 0xc2, 0xdb, 0x53, 0xae, 0x1f,
+ 0xeb, 0x44, 0x77, 0x3b, 0x5f, 0x74, 0x48, 0xe9, 0x05,
+ 0xfa, 0x3a, 0x03, 0x1b, 0x54, 0x36, 0xb0, 0x28, 0x79,
+ 0x70, 0xe6, 0x2f, 0xb4, 0xf5, 0x28, 0x60, 0x1e, 0x63,
+ 0xf6, 0x03, 0x09, 0x4f, 0x0f, 0x7f, 0x01, 0xe5, 0x02,
+ 0x6a, 0x76, 0x96, 0xb9, 0x58, 0x39, 0xf9, 0xc4, 0x05,
+ 0xac, 0x93, 0x2f, 0x30, 0xab, 0xc5, 0x2b, 0xad, 0xed,
+ 0x3c, 0xb0, 0x6c, 0x66, 0x94, 0x7e, 0x79, 0x01, 0x90,
+ 0xf0, 0x10, 0xb5, 0xcd, 0x6b, 0x07, 0xc2, 0xe7, 0x8a,
+ 0xac, 0xf7, 0x5b, 0xb5, 0x11, 0xf8, 0x1a, 0x52, 0xc7,
+ 0x5d, 0x2c, 0xc1, 0xce, 0x8f, 0x0c, 0xc1, 0x6a, 0x95,
+ 0x80, 0x25, 0xf9, 0x95, 0x28, 0x18, 0x65, 0xd3, 0x15,
+ 0x0e, 0xbf, 0x6f, 0xa6, 0x86, 0xd9, 0xea, 0xdc, 0xb8,
+ 0x89, 0x02, 0x08, 0x6b, 0xd1, 0x96, 0xb1, 0x6f, 0xb1,
+ 0x28, 0x6b, 0xc4, 0xe3, 0xa8, 0x53, 0xd3, 0xd0, 0x67,
+ 0x00, 0x7c, 0xa1, 0x0a, 0xd1, 0x9a, 0x89, 0x12, 0xc9,
+ 0xa7, 0x3f, 0x03, 0x03, 0xad, 0x0f, 0x34, 0x2c, 0xd8,
+ 0xdf, 0x70, 0xed, 0x38, 0xf4, 0xb1, 0xf7, 0xb1, 0x72,
+ 0x5e, 0x2d, 0xa6, 0xb7, 0x8d, 0x9c, 0x7f, 0x96, 0x73,
+ 0xc8, 0x47, 0x46, 0x20, 0x2f, 0x44, 0x2c, 0x2b, 0xa2,
+ 0x30, 0xe4, 0x81, 0x91, 0x7e, 0xce, 0x4c, 0x8b, 0xcc,
+ 0x5f, 0xfd, 0xff, 0x2f, 0x94, 0xbd, 0xe5, 0xaf, 0x09,
+ 0xcd, 0xb6, 0xbc, 0x65, 0x83, 0xc3, 0xcd, 0x79, 0xc4,
+ 0x68, 0xda, 0x46, 0x36, 0x97, 0x52, 0x35, 0x90, 0x4f,
+ 0x1d, 0x8d, 0x66, 0x1f, 0xea, 0x5d, 0xef, 0xdf, 0x8c,
+ 0xa8, 0x6b, 0xb0, 0xdc, 0x1a, 0x1e, 0x79, 0x43, 0xe9,
+ 0x29, 0x71, 0x11, 0xbd, 0xe5, 0xd6, 0x71, 0xf4, 0xa7,
+ 0xf8, 0x64, 0x40, 0x73, 0x46, 0x5b, 0x2a, 0xb5, 0x9a,
+ 0xa1, 0x9a, 0x64, 0x4c, 0x5e, 0xa5, 0x8d, 0xfd, 0x49,
+ 0x91, 0xba, 0xe3, 0xa7, 0x19, 0xac, 0x2b, 0xe9, 0xea,
+ 0xf1, 0x1c, 0x85, 0x91, 0xea, 0xfb, 0xc7, 0x5c, 0x46,
+ 0x7e, 0xa8, 0x0a, 0x92, 0xbf, 0x61, 0x2d, 0xc2, 0x20,
+ 0x7e, 0xf7, 0x0d, 0xb8, 0x65, 0x41, 0x48, 0x39, 0xb9,
+ 0xb0, 0xd4, 0xc1, 0x84, 0xee, 0x21, 0xba, 0x9c, 0x74,
+ 0xf3, 0x6d, 0x0a, 0x33, 0x87, 0xab, 0x2e, 0x15, 0x1b,
+ 0xad, 0xac, 0x98, 0xae, 0x7c, 0xd8, 0xae, 0x03, 0x50,
+ 0xfa, 0xae, 0xfe, 0x8c, 0x6d, 0x51, 0x67, 0x76, 0x70,
+ 0xa6, 0x2f, 0x1e, 0x6a, 0x4f, 0xf0, 0xbe, 0x51, 0xbb,
+ 0xa6, 0x20, 0x1f, 0x56, 0x72, 0x34, 0xd0, 0x13, 0x6e,
+ 0x0f, 0x1a, 0xcb, 0x34, 0xe1, 0xfb, 0x3c, 0xf1, 0x43,
+ 0x1b, 0x73, 0x40, 0xa0, 0x1f, 0x5d, 0x40, 0x51, 0x9f,
+ 0x97, 0x56, 0x1f, 0x26, 0x54, 0x03, 0xb8, 0x2e, 0xfd,
+ 0xc7, 0x52, 0xea, 0x85, 0x5d, 0x45, 0x71, 0xa3, 0x5c,
+ 0x86, 0x23, 0xcb, 0x08, 0xc5, 0xd8, 0x21, 0xfd, 0x10,
+ 0x49, 0xac, 0xaa, 0xd5, 0x97, 0x37, 0xbb, 0xad, 0xd5,
+ 0x84, 0xc2, 0x65, 0xeb, 0xdd, 0x92, 0x7c, 0x50, 0x64,
+ 0x4f, 0x08, 0x32, 0x56, 0x81, 0x39, 0xa4, 0xfc, 0x3f,
+ 0x04, 0xbb, 0xde, 0xe9, 0xcd, 0xb6, 0xbb, 0x29, 0x6b,
+ 0x75, 0x64, 0x32, 0x5f, 0xca, 0xd0, 0x3a, 0x19, 0x3d,
+ 0x01, 0x8c, 0x0b, 0xd5, 0x76, 0xe6, 0x97, 0x5d, 0x73,
+ 0x7b, 0xb3, 0xcd, 0xdf, 0xbc, 0x29, 0xda, 0xa5, 0x22,
+ 0xfb, 0x1d, 0xf6, 0xf1, 0x50, 0x71, 0x50, 0xd3, 0xf8,
+ 0x0a, 0xbf, 0x37, 0x28, 0xca, 0x3b, 0xab, 0xec, 0xf5,
+ 0xee, 0x2d, 0x1e, 0x21, 0x35, 0x39, 0x56, 0x55, 0x3c,
+ 0x9e, 0x5a, 0x58, 0x94, 0x85, 0xa7, 0xba, 0x0d, 0xa4,
+ 0x0b, 0x4c, 0x73, 0xb2, 0x56, 0x68, 0x5a, 0x5d, 0x6c,
+ 0x18, 0xce, 0xc5, 0x25, 0x14, 0xc9, 0xb3, 0xc9, 0x94,
+ 0x57, 0x62, 0x95, 0xd5, 0x1c, 0xf6, 0x93, 0x12, 0x45,
+ 0x28, 0xa1, 0x7e, 0x96, 0x53, 0x68, 0xf5, 0x6a, 0xca,
+ 0xbe, 0x04, 0x94, 0x97, 0xcf, 0xb5, 0xcf, 0x70, 0xe1,
+ 0x7e, 0x15, 0x2d, 0x6a, 0x67, 0x0c, 0x86, 0x07, 0xd1,
+ 0xe2, 0x95, 0xc3, 0xd8, 0x22, 0xdf, 0x6a, 0x88, 0xc1,
+ 0xad, 0x83, 0x57, 0x30, 0xd0, 0x59, 0xaf, 0xf4, 0x9f,
+ 0x8d, 0x89, 0x7d, 0x0b, 0xee, 0xb7, 0x1c, 0xaa, 0xd2,
+ 0x4c, 0x7a, 0xa4, 0xfb, 0x99, 0xe0, 0x0a, 0xd7, 0x4d,
+ 0xc4, 0xe9, 0x88, 0x18, 0x27, 0x1d, 0xb2, 0xe9, 0x43,
+ 0x16, 0x25, 0x29, 0x04, 0x98, 0x81, 0xfd, 0xaf, 0xdd,
+ 0x3f, 0xf1, 0x61, 0x32, 0x20, 0x51, 0x96, 0xe4, 0xd2,
+ 0xab, 0xc4, 0x00, 0x33, 0xb4, 0x7b, 0x3c, 0xc2, 0x2d,
+ 0x61, 0x11, 0x4d, 0x72, 0x16, 0x6d, 0xfb, 0x24, 0x67,
+ 0x7c, 0xea, 0xf0, 0x79, 0xa3, 0x50, 0x93, 0xe3, 0x9b,
+ 0x7f, 0x89, 0xf0, 0xa6, 0x8c, 0xb0, 0xaf, 0x1c, 0xe0,
+ 0x91, 0xce, 0x3f, 0xe5, 0x43, 0x90, 0x41, 0x95, 0xc7,
+ 0x1f, 0x8f, 0x0a, 0xb2, 0x1e, 0x84, 0x3e, 0x86, 0xf0,
+ 0x81, 0x87, 0x8b, 0x04, 0x52, 0xa6, 0x46, 0xb0, 0xe4,
+ 0xf4, 0x5b, 0x97, 0x7b, 0x7b, 0x32, 0xb6, 0x17, 0x96,
+ 0x48, 0x12, 0xb6, 0x31, 0xf1, 0x5c, 0xd4, 0x8b, 0x93,
+ 0x60, 0xc4, 0x00, 0xea, 0x12, 0xe1, 0x93, 0x6f, 0x53,
+ 0x82, 0x2a, 0x48, 0x1d, 0xc1, 0x91, 0x79, 0x7c, 0x30,
+ 0x43, 0xe5, 0x1e, 0x10, 0x7e, 0x7f, 0xbc, 0x18, 0x60,
+ 0x03, 0x2a, 0xe5, 0xbb, 0x92, 0x7f, 0x24, 0x54, 0x12,
+ 0x21, 0x77, 0x89, 0xc9, 0x22, 0xfb, 0x57, 0xaa, 0x69,
+ 0xdd, 0x69, 0x06, 0xb0, 0xe5, 0x5b, 0x74, 0x1f, 0x02,
+ 0x99, 0x62, 0x56, 0x21, 0x29, 0xd2, 0x26, 0x0f, 0x6a,
+ 0x3a, 0x05, 0x96, 0x92, 0xb9, 0xff, 0xe9, 0x3b, 0x24,
+ 0x70, 0xd4, 0x13, 0xa4, 0xb2, 0x6c, 0x76, 0xe3, 0x55,
+ 0xe5, 0xc8, 0x18, 0x66, 0x60, 0x91, 0xba, 0x98, 0x5d,
+ 0x67, 0x13, 0x97, 0xce, 0x49, 0xaa, 0x52, 0x7b, 0x20,
+ 0x65, 0x65, 0x0a, 0x4f, 0x7b, 0x0a, 0x26, 0x62, 0xa7,
+ 0xb5, 0xab, 0x2d, 0x5d, 0x37, 0xad, 0xb8, 0x97, 0xcf,
+ 0xf5, 0x4f, 0xef, 0x03, 0xed, 0xce, 0x73, 0x68, 0x5d,
+ 0x9f, 0x6c, 0x3d, 0x3f, 0xd5, 0xc1, 0xca, 0x5f, 0xef,
+ 0xe4, 0xf8, 0xfb, 0xc7, 0xbb, 0x49, 0x30, 0x1a, 0xe1,
+ 0x3c, 0xd1, 0x7f, 0x7c, 0x26, 0xa2, 0x87, 0x6e, 0x80,
+ 0xa6, 0x47, 0x2c, 0x0f, 0xa6, 0x68, 0xf6, 0xde, 0x65,
+ 0x1f, 0x02, 0xa7, 0x09, 0x08, 0x34, 0xbe, 0x2c, 0xc7,
+ 0xed, 0x4c, 0xb0, 0xa1, 0x63, 0x63, 0x35, 0xe0, 0x11,
+ 0xfd, 0xe1, 0x2d, 0xb4, 0xcf, 0x9e, 0x18, 0x78, 0xa8,
+ 0x63, 0xbf, 0xb7, 0xe8, 0x22, 0x82, 0xc5, 0x9c, 0x0b,
+ 0x3a, 0x1c, 0x2f, 0x73, 0x80, 0xf1, 0xbb, 0x9a, 0x84,
+ 0x51, 0x2c, 0x1c, 0x2e, 0xda, 0xb8, 0xa3, 0x43, 0x4f,
+ 0x95, 0x8c, 0x06, 0x12, 0xdc, 0x75, 0x53, 0x01, 0xc4,
+ 0x50, 0x95, 0x31, 0x7e, 0x75, 0x33, 0x69, 0x3e, 0x82,
+ 0xad, 0x51, 0x1a, 0x4d, 0xa4, 0xe7, 0xbb, 0x7c, 0x9e,
+ 0x3c, 0xbc, 0x1a, 0xf7, 0x7d, 0x0f, 0xdd, 0x93, 0xb5,
+ 0x91, 0x61, 0x28, 0x28, 0x3b, 0x8f, 0xdd, 0xfa, 0xe6,
+ 0xf4, 0xcc, 0x21, 0x82, 0x0c, 0xe2, 0xe4, 0xc7, 0x39,
+ 0x69, 0x8e, 0xd6, 0xc0, 0x45, 0x94, 0x26, 0x27, 0x1b,
+ 0xca, 0x02, 0x39, 0x00, 0x12, 0xef, 0xad, 0x0f, 0xf2,
+ 0xdb, 0x19, 0x39, 0x6e, 0x4e, 0xfd, 0x14, 0x56, 0x3c,
+ 0xd3, 0xfb, 0x43, 0x2d, 0x14, 0xb1, 0x62, 0xd2, 0xc8,
+ 0x09, 0xe3, 0xb4, 0xf3, 0x24, 0x4e, 0xeb, 0xe5, 0xd6,
+ 0x42, 0x48, 0xa5, 0xf8, 0xd8, 0xcc, 0x0b, 0xd6, 0x23,
+ 0x59, 0x46, 0xaf, 0x15, 0xb2, 0x36, 0x2d, 0x52, 0xbe,
+ 0x4a, 0x5f, 0xc6, 0xb2, 0x3d, 0xc5, 0x53, 0x57, 0x35,
+ 0x2a, 0xa1, 0x06, 0xc8, 0x93, 0xa8, 0x3e, 0xc6, 0xcb,
+ 0xa4, 0xd9, 0xe4, 0x53, 0xa9, 0xe8, 0x6d, 0xe1, 0x73,
+ 0x97, 0xb9, 0x6f, 0xb3, 0xf8, 0x1d, 0xb4, 0xae, 0xd8,
+ 0x77, 0xa7, 0xef, 0xe1, 0xeb, 0x83, 0x3d, 0xc3, 0x35,
+ 0xf0, 0xc6, 0xd8, 0x66, 0xb5, 0x29, 0x7f, 0x74, 0xdb,
+ 0xa1, 0xf2, 0x16, 0xc9, 0x07, 0x0f, 0x5c, 0x3e, 0x18,
+ 0x64, 0x82, 0xfd, 0xae, 0x80, 0xca, 0xcf, 0xf9, 0x7e,
+ 0x7f, 0x36, 0x58, 0xd5, 0x4d, 0x2d, 0x5a, 0x27, 0x27,
+ 0xcc, 0x7e, 0x45, 0x0d, 0xf8, 0xd6, 0x5f, 0xee, 0x83,
+ 0x42, 0x83, 0x48, 0x0b, 0x64, 0xc6, 0x03, 0x4d, 0x1e,
+ 0x24, 0x90, 0xba, 0x2a, 0x92, 0x7d, 0x43, 0x77, 0x17,
+ 0xc8, 0xcc, 0x9f, 0x31, 0x80, 0x4e, 0x19, 0x7f, 0x8f,
+ 0xcf, 0xd7, 0x27, 0x48, 0x10, 0xea, 0x3d, 0xd6, 0x0f,
+ 0x70, 0x7a, 0xb9, 0xed, 0x53, 0x67, 0x1c, 0x56, 0xb1,
+ 0x78, 0xfc, 0x0c, 0xcc, 0x1f, 0xf8, 0x89, 0x45, 0x57,
+ 0x4a, 0x72, 0xd2, 0xa0, 0x07, 0x53, 0x73, 0x3d, 0x0e,
+ 0x45, 0x5a, 0x31, 0x94, 0x8f, 0x5f, 0x11, 0xe4, 0x36,
+ 0xe2, 0x19, 0xc4, 0x84, 0x94, 0xb9, 0xc0, 0xe6, 0x5d,
+ 0x66, 0x7e, 0x4c, 0x05, 0xc6, 0xcd, 0x9c, 0x6c, 0x8f,
+ 0x32, 0x68, 0xfb, 0x66, 0x86, 0x22, 0xf5, 0xfa, 0x9a,
+ 0x46, 0x26, 0xb5, 0xd5, 0xc1, 0x7d, 0xeb, 0x7b, 0x82,
+ 0x3e, 0x62, 0x8c, 0x76, 0x0b, 0x08, 0x1d, 0xe0, 0x75,
+ 0x34, 0x30, 0x4b, 0xc2, 0x4b, 0xcb, 0x49, 0xa3, 0x65,
+ 0x0e, 0x90, 0xd3, 0x57, 0xe5, 0xf5, 0x83, 0x1b, 0xa2,
+ 0xbb, 0x4a, 0x23, 0x63, 0x25, 0x64, 0xd7, 0xf1, 0x85,
+ 0x9b, 0xbe, 0x2e, 0xda, 0xad, 0xc8, 0x60, 0x37, 0x3c,
+ 0x78, 0x33, 0xb5, 0x76, 0x7c, 0xc6, 0xe5, 0x97, 0x86,
+ 0x6d, 0x70, 0xdc, 0x4f, 0x79, 0x39, 0xe6, 0x27, 0x78,
+ 0x57, 0x98, 0x69, 0x79, 0xaf, 0x0a, 0xc0, 0x64, 0x0c,
+ 0x1a, 0x09, 0xa0, 0x98, 0x06, 0x41, 0x5c, 0x29, 0x27,
+ 0xbd, 0x2e, 0xbe, 0xe8, 0x08, 0x5f, 0xdf, 0xed, 0xd9,
+ 0x31, 0x97, 0xdb, 0x0a, 0x1f, 0x4e, 0x1b, 0x67, 0x32,
+ 0xef, 0x84, 0xa2, 0x14, 0xa7, 0x83, 0x33, 0xdc, 0x40,
+ 0x55, 0x76, 0x27, 0x01, 0x9f, 0x98, 0x90, 0xa9, 0xfa,
+ 0xfb, 0x73, 0x86, 0x38, 0x6b, 0xa8, 0x57, 0xc9, 0xaa,
+ 0x06, 0xbf, 0x84, 0x97, 0xfa, 0xc8, 0xde, 0x67, 0x6b,
+ 0xa6, 0x2c, 0xa1, 0x90, 0x6c, 0x6d, 0xcd, 0xb5, 0x73,
+ 0x3c, 0x16, 0x68, 0xb4, 0x00, 0x55, 0xf6, 0xd8, 0x35,
+ 0xb0, 0xf9, 0x8e, 0x2e, 0xfb, 0x54, 0xc1, 0x8e, 0x51,
+ 0x90, 0x2d, 0x28, 0x83, 0x5d, 0x81, 0xd6, 0x00, 0x00,
+ 0x41, 0xf2, 0x97, 0xdf, 0x2f, 0x8d, 0xa8, 0xc2, 0x1d,
+ 0xe3, 0xbd, 0x1d, 0x2a, 0x6f, 0x4a, 0xfd, 0xd3, 0xcd,
+ 0x0b, 0xac, 0x28, 0x93, 0x87, 0x3e, 0xd9, 0x7b, 0x17,
+ 0xe2, 0x66, 0x0a, 0x6e, 0xcb, 0xa8, 0x3e, 0x3d, 0x9b,
+ 0x3c, 0xbe, 0x78, 0xe1, 0x2a, 0xa5, 0x42, 0x5f, 0xdc,
+ 0xe0, 0x0e, 0x06, 0x10, 0x59, 0xac, 0x4a, 0xd3, 0x63,
+ 0x95, 0x92, 0x31, 0x1c, 0x7d, 0xb1, 0x5e, 0x48, 0x01,
+ 0x23, 0x16, 0x61, 0xb3, 0xfc, 0xe6, 0x9a, 0x5d, 0x39,
+ 0xf9, 0x2f, 0xb5, 0xc6, 0x6d, 0xeb, 0xb2, 0x6e, 0x93,
+ 0x9d, 0x8b, 0x19, 0x74, 0xa9, 0xc4, 0x57, 0x96, 0xbc,
+ 0x1c, 0xbb, 0x88, 0x5a, 0xd6, 0xf7, 0xc0, 0xe2, 0xb6,
+ 0xf2, 0xb3, 0xf0, 0x56, 0x5b, 0x2c, 0x9e, 0xdf, 0x96,
+ 0x6d, 0xcc, 0x41, 0x06, 0xce, 0x1e, 0x1b, 0x3a, 0x39,
+ 0x67, 0xe1, 0x7e, 0x81, 0xfc, 0xff, 0x0a, 0xc0, 0xf1,
+ 0x76, 0x82, 0x49, 0x76, 0x88, 0x38, 0x10, 0x5c, 0x90,
+ 0x83, 0x4b, 0x3e, 0x8d, 0xb9, 0x35, 0x77, 0xf5, 0x4c,
+ 0x7e, 0x3e, 0x12, 0x54, 0xf0, 0x33, 0x56, 0xbc, 0x9b,
+ 0x0e, 0x10, 0x7d, 0x4a, 0xb6, 0x2d, 0x02, 0x35, 0x79,
+ 0xe8, 0x0c, 0x15, 0xc1, 0xde, 0xc7, 0x2a, 0x7d, 0xe1,
+ 0x27, 0xd4, 0x99, 0x50, 0x6b, 0xde, 0x6d, 0x02, 0x65,
+ 0x12, 0x88, 0xe6, 0x80, 0x13, 0x5e, 0xad, 0xb1, 0xef,
+ 0xe7, 0x77, 0x19, 0xc9, 0x63, 0xcf, 0x14, 0x41, 0x40,
+ 0x76, 0xc8, 0xa9, 0xc3, 0x08, 0x88, 0xdb, 0x44, 0x6c,
+ 0x10, 0x74, 0x5c, 0xf6, 0x86, 0x8c, 0x61, 0x95, 0x19,
+ 0x76, 0x1f, 0x3e, 0xcb, 0xdf, 0x6e, 0x08, 0x9f, 0x43,
+ 0xb9, 0x66, 0x2b, 0x88, 0x27, 0x48, 0xbe, 0x5d, 0x9e,
+ 0x83, 0x72, 0x9a, 0x43, 0x06, 0x8e, 0xf3, 0x9e, 0xba,
+ 0xd5, 0xd8, 0x70, 0x1b, 0xe4, 0x4e, 0x39, 0x0a, 0x37,
+ 0x5b, 0x2f, 0x8c, 0xa8, 0xbd, 0x3c, 0xfe, 0xb2, 0x59,
+ 0x5b, 0x5f, 0x5a, 0x05, 0x67, 0xc8, 0xec, 0x71, 0x5d,
+ 0xb5, 0x77, 0xc7, 0xb3, 0x1c, 0xb7, 0xac, 0x90, 0xf6,
+ 0xd3, 0xb7, 0x61, 0x65, 0xbe, 0x29, 0x8f, 0x27, 0x65,
+ 0x9a, 0x9a, 0x1c, 0x00, 0x82, 0xee, 0x10, 0xb9, 0x60,
+ 0xff, 0x9f, 0x5a, 0xbe, 0x09, 0x72, 0x63, 0x79, 0x60,
+ 0x50, 0x84, 0x18, 0xc9, 0xc5, 0x0d, 0x43, 0xce, 0x29,
+ 0x80, 0x72, 0x83, 0x12, 0x73, 0x13, 0x44, 0xec, 0x25,
+ 0xe5, 0x15, 0x70, 0xe2, 0x7f, 0x6b, 0x54, 0x5b, 0x58,
+ 0x57, 0x06, 0xdc, 0xae, 0x1f, 0x9c, 0x38, 0x4c, 0xbf,
+ 0x1c, 0x42, 0xb2, 0x63, 0x9c, 0xfb, 0xae, 0xc0, 0xdf,
+ 0xd3, 0xcc, 0xcc, 0xb9, 0x9b, 0xe9, 0x66, 0x77, 0x70,
+ 0x47, 0x6c, 0x8b, 0x5b, 0xc1, 0x87, 0x7a, 0x63, 0xa3,
+ 0x13, 0xfc, 0x2d, 0x16, 0xd3, 0xe2, 0x00, 0xe9, 0x94,
+ 0x11, 0xf2, 0x28, 0xda, 0x0b, 0x58, 0x09, 0x2d, 0x59,
+ 0x2d, 0xb5, 0x25, 0x99, 0xca, 0x63, 0xc9, 0x96, 0xa3,
+ 0x17, 0x2a, 0x0e, 0x22, 0x2c, 0x5f, 0x8d, 0x53, 0xc4,
+ 0xd1, 0x3d, 0x4e, 0x20, 0xdc, 0x44, 0x18, 0xd2, 0xd8,
+ 0x5c, 0x9a, 0x78, 0x0a, 0x53, 0xa8, 0x73, 0x7d, 0x98,
+ 0xc0, 0xba, 0xfb, 0xfe, 0x27, 0xd4, 0x82, 0x87, 0xd4,
+ 0x4d, 0xc0, 0xe3, 0xd1, 0xd0, 0xff, 0xf0, 0xd3, 0x04,
+ 0xfd, 0x11, 0xf4, 0x57, 0xc2, 0xcc, 0xcf, 0xa9, 0xe6,
+ 0xc5, 0x09, 0x4d, 0xcc, 0x36, 0x69, 0x26, 0x35, 0x8c,
+ 0xe8, 0xe2, 0xe2, 0xdd, 0x5a, 0x5f, 0xaf, 0xda, 0x38,
+ 0x07, 0x33, 0xfb, 0xf8, 0xfb, 0xf9, 0x62, 0x4a, 0x75,
+ 0xad, 0xc3, 0x95, 0xd3, 0x6e, 0x5b, 0xe3, 0x10, 0x2f,
+ 0x31, 0xaf, 0xcd, 0x57, 0xb9, 0x84, 0x3d, 0xa4, 0x66,
+ 0x3f, 0x10, 0xeb, 0xa2, 0xe2, 0xfa, 0xc7, 0xd3, 0x91,
+ 0x83, 0x48, 0xbb, 0x3a, 0x6c, 0xe4, 0x12, 0x1c, 0x36,
+ 0x44, 0xc5, 0x07, 0x07, 0x9b, 0x9d, 0x51, 0x3e, 0x74,
+ 0xc5, 0x35, 0x8a, 0x10, 0x9c, 0x0d, 0x81, 0xf3, 0x10,
+ 0x0f, 0x29, 0xaf, 0x01, 0x5d, 0x6f, 0x7f, 0x50, 0x9a,
+ 0xf8, 0xbf, 0x1c, 0x57, 0xfc, 0x25, 0x5c, 0x02, 0x15,
+ 0x43, 0x0b, 0x60, 0x21, 0xf3, 0xb1, 0x43, 0x9a, 0x41,
+ 0xa0, 0xc1, 0x1b, 0x7a, 0x88, 0x97, 0xfd, 0x27, 0x56,
+ 0xf7, 0x48, 0x1f, 0xb6, 0x9a, 0xa2, 0xb1, 0xc5, 0xab,
+ 0x30, 0xa1, 0x14, 0x91, 0xef, 0x14, 0xe3, 0x01, 0x73,
+ 0xf3, 0x8d, 0xfa, 0xd7, 0xae, 0x2f, 0x13, 0x5d, 0x66,
+ 0xfb, 0x1c, 0x4b, 0x2e, 0x94, 0xdb, 0x9f, 0x10, 0x5b,
+ 0x2a, 0x5e, 0x85, 0x98, 0x73, 0x9d, 0xcd, 0x7c, 0xa0,
+ 0x79, 0xb6, 0xef, 0x8e, 0xf8, 0xdd, 0x11, 0x32, 0x0d,
+ 0xec, 0x6a, 0x04, 0xea, 0x81, 0xd7, 0x63, 0xbd, 0x01,
+ 0x77, 0x3e, 0x52, 0x30, 0x88, 0x3a, 0x9e, 0x04, 0xdf,
+ 0x42, 0x8b, 0x40, 0x23, 0xa9, 0x5a, 0x97, 0x21, 0x55,
+ 0xce, 0x72, 0x21, 0x45, 0x40, 0x01, 0x66, 0x63, 0x1d,
+ 0xab, 0x37, 0x8d, 0xd5, 0x75, 0x56, 0xc2, 0x7c, 0xa0,
+ 0x9e, 0xa5, 0x85, 0xc2, 0x0b, 0x51, 0x80, 0xae, 0x0c,
+ 0xb3, 0xde, 0xa4, 0xb5, 0xa3, 0xa3, 0x00, 0xe1, 0xc9,
+ 0x09, 0xee, 0xab, 0xbb, 0x36, 0x78, 0x5b, 0x3f, 0x45,
+ 0x3d, 0xf6, 0xe8, 0x7e, 0xa3, 0xd7, 0x24, 0x78, 0xdf,
+ 0xbc, 0x9f, 0xe4, 0x4c, 0x4d, 0x22, 0xb8, 0x76, 0xb0,
+ 0x6a, 0xc1, 0x35, 0x66, 0xfe, 0xaf, 0xf1, 0xb4, 0x44,
+ 0x5e, 0xe0, 0xff, 0xcf, 0x80, 0xf8, 0xa8, 0x5f, 0x59,
+ 0x91, 0xa4, 0x4f, 0xc0, 0x58, 0xb1, 0x2d, 0xc9, 0x6a,
+ 0xcd, 0x62, 0xcb, 0x41, 0x89, 0x9d, 0x3b, 0x3e, 0x48,
+ 0x5f, 0x23, 0x46, 0x21, 0x8a, 0x49, 0xc0, 0x16, 0x07,
+ 0x4d, 0xd9, 0x26, 0xbe, 0x86, 0xfb, 0x06, 0xbd, 0x41,
+ 0xc5, 0xd8, 0x87, 0xf6, 0x94, 0xb1, 0xef, 0xed, 0xab,
+ 0xfb, 0x93, 0x48, 0x5a, 0xe7, 0x22, 0xbc, 0x2b, 0x24,
+ 0xb4, 0x86, 0x33, 0x9b, 0xd6, 0x09, 0x46, 0x85, 0x81,
+ 0x89, 0xa9, 0x30, 0x13, 0xfa, 0x08, 0x55, 0xfc, 0xe5,
+ 0xfb, 0xc8, 0xb2, 0xa8, 0x31, 0x4c, 0x9e, 0x1c, 0xff,
+ 0x80, 0x10, 0x77, 0x5f, 0xf1, 0x07, 0x14, 0xf7, 0x88,
+ 0xb9, 0xeb, 0x48, 0xfe, 0x18, 0x48, 0xf3, 0xaf, 0xfd,
+ 0x7d, 0x0c, 0x9f, 0x30, 0x11, 0xcb, 0xed, 0xfc, 0x31,
+ 0xf5, 0x6e, 0x72, 0xfa, 0x9a, 0x3a, 0xa5, 0x1d, 0x89,
+ 0x89, 0x8b, 0xc6, 0x2c, 0xaf, 0xa6, 0xef, 0xbd, 0xb4,
+ 0xc2, 0xa0, 0x97, 0x74, 0xd0, 0x4d, 0x72, 0xb7, 0xe8,
+ 0x24, 0xba, 0x5e, 0x53, 0x4b, 0x91, 0xc1, 0xe4, 0x14,
+ 0x22, 0x50, 0xb2, 0xc3, 0x84, 0xf4, 0xa6, 0xb3, 0xa4,
+ 0x99, 0xda, 0x82, 0x55, 0x8e, 0x38, 0xb4, 0x0c, 0x21,
+ 0xe5, 0x91, 0x30, 0xc7, 0x80, 0x55, 0xf1, 0x69, 0xde,
+ 0xd7, 0x82, 0xf3, 0x08, 0xd3, 0x16, 0x69, 0xe7, 0xd4,
+ 0xeb, 0xfc, 0x9b, 0x8f, 0xd6, 0xfc, 0xf9, 0x9f, 0x95,
+ 0xb3, 0x90, 0xa6, 0x12, 0x21, 0x53, 0x50, 0xd5, 0x3e,
+ 0x2b, 0x46, 0x14, 0x52, 0x20, 0x1c, 0x33, 0xed, 0xdd,
+ 0x58, 0x81, 0x92, 0x37, 0xe5, 0x99, 0x77, 0xfa, 0x29,
+ 0x28, 0x49, 0x07, 0xc8, 0xe2, 0x41, 0x8f, 0x77, 0x3b,
+ 0xb4, 0x8c, 0x34, 0x3e, 0x80, 0xcb, 0xcf, 0x73, 0x4d,
+ 0xfc, 0x78, 0x60, 0x9e, 0xd0, 0x86, 0xc3, 0x4d, 0xa7,
+ 0x40, 0x9c, 0x03, 0x72, 0x46, 0xc3, 0xc3, 0x74, 0xdf,
+ 0x5a, 0x47, 0x8d, 0xbc, 0xc1, 0x5b, 0x10, 0x3e, 0x7e,
+ 0x09, 0x3d, 0xdb, 0x0c, 0xc4, 0x3b, 0x12, 0xbf, 0x66,
+ 0xe2, 0xb7, 0x4c, 0x1a, 0x81, 0x58, 0x63, 0x39, 0x72,
+ 0xde, 0xfa, 0x5d, 0xcc, 0x2c, 0x69, 0x11, 0x0a, 0x5f,
+ 0xb9, 0xbc, 0xda, 0x80, 0x03, 0x8e, 0xa2, 0x02, 0x6c,
+ 0xc1, 0x15, 0xcc, 0xbf, 0x01, 0x14, 0xd0, 0x36, 0xad,
+ 0xdb, 0xb7, 0x77, 0xd6, 0x99, 0x94, 0xf5, 0xa5, 0xac,
+ 0xce, 0x9a, 0x23, 0x9b, 0x1e, 0xa4, 0x97, 0x7e, 0x41,
+ 0xc1, 0x65, 0xc7, 0x94, 0xfa, 0x07, 0x1d, 0x9a, 0x87,
+ 0xba, 0xee, 0xef, 0x99, 0x92, 0xaa, 0x41, 0x29, 0x03,
+ 0xe3, 0x01, 0x17, 0x42, 0xed, 0x11, 0x68, 0x44, 0x02,
+ 0xca, 0x81, 0x4b, 0x33, 0x81, 0x64, 0x30, 0x95, 0x7f,
+ 0x81, 0x17, 0xe6, 0x59, 0x0b, 0x4e, 0xf3, 0x4a, 0x72,
+ 0x0c, 0x45, 0x1e, 0x1d, 0x44, 0xe2, 0x9e, 0x45, 0x29,
+ 0x88, 0xb4, 0xda, 0x9b, 0x9f, 0x3e, 0x92, 0x9a, 0x0b,
+ 0x21, 0x2a, 0xd4, 0xa0, 0xd8, 0xd8, 0xbd, 0x06, 0x6d,
+ 0x71, 0x3c, 0xcc, 0xd8, 0xdc, 0x19, 0xd7, 0x8f, 0x21,
+ 0x01, 0x25, 0xa5, 0x15, 0x62, 0x43, 0xfa, 0xdf, 0xb9,
+ 0x33, 0x23, 0xd3, 0xa2, 0xab, 0xb1, 0x7e, 0x4e, 0x5e,
+ 0x46, 0xbd, 0x76, 0x6e, 0x18, 0x88, 0x5f, 0x85, 0x03,
+ 0x43, 0x57, 0xd6, 0x3a, 0xf2, 0xcc, 0x9d, 0xbc, 0x2c,
+ 0x67, 0xa8, 0xcd, 0xda, 0xe8, 0x39, 0x61, 0x68, 0x6d,
+ 0xcf, 0xeb, 0x07, 0x1f, 0x58, 0x61, 0x68, 0x6d, 0x78,
+ 0xa6, 0xad, 0xb6, 0x16, 0x70, 0x89, 0x49, 0x59, 0x62,
+ 0x76, 0xc1, 0xc3, 0xc8, 0xce, 0xe2, 0xfc, 0x42, 0x51,
+ 0x8d, 0xc8, 0xf1, 0x03, 0x17, 0x36, 0x55, 0x8c, 0x8e,
+ 0x98, 0xd1, 0x33, 0x3c, 0x4c, 0x63, 0x81, 0x97, 0xc5,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x0c, 0x16, 0x19, 0x23, 0x28, 0x30,
+ 0x37,
+ },
+};
diff --git a/lib/crypto/tests/mldsa_kunit.c b/lib/crypto/tests/mldsa_kunit.c
new file mode 100644
index 000000000000..67f8f93e3dc6
--- /dev/null
+++ b/lib/crypto/tests/mldsa_kunit.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit tests and benchmark for ML-DSA
+ *
+ * Copyright 2025 Google LLC
+ */
+#include <crypto/mldsa.h>
+#include <kunit/test.h>
+#include <linux/random.h>
+#include <linux/unaligned.h>
+
+#define Q 8380417 /* The prime q = 2^23 - 2^13 + 1 */
+
+/* ML-DSA parameters that the tests use */
+static const struct {
+ int sig_len;
+ int pk_len;
+ int k;
+ int lambda;
+ int gamma1;
+ int beta;
+ int omega;
+} params[] = {
+ [MLDSA44] = {
+ .sig_len = MLDSA44_SIGNATURE_SIZE,
+ .pk_len = MLDSA44_PUBLIC_KEY_SIZE,
+ .k = 4,
+ .lambda = 128,
+ .gamma1 = 1 << 17,
+ .beta = 78,
+ .omega = 80,
+ },
+ [MLDSA65] = {
+ .sig_len = MLDSA65_SIGNATURE_SIZE,
+ .pk_len = MLDSA65_PUBLIC_KEY_SIZE,
+ .k = 6,
+ .lambda = 192,
+ .gamma1 = 1 << 19,
+ .beta = 196,
+ .omega = 55,
+ },
+ [MLDSA87] = {
+ .sig_len = MLDSA87_SIGNATURE_SIZE,
+ .pk_len = MLDSA87_PUBLIC_KEY_SIZE,
+ .k = 8,
+ .lambda = 256,
+ .gamma1 = 1 << 19,
+ .beta = 120,
+ .omega = 75,
+ },
+};
+
+#include "mldsa-testvecs.h"
+
+static void do_mldsa_and_assert_success(struct kunit *test,
+ const struct mldsa_testvector *tv)
+{
+ int err = mldsa_verify(tv->alg, tv->sig, tv->sig_len, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len);
+ KUNIT_ASSERT_EQ(test, err, 0);
+}
+
+static u8 *kunit_kmemdup_or_fail(struct kunit *test, const u8 *src, size_t len)
+{
+ u8 *dst = kunit_kmalloc(test, len, GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, dst);
+ return memcpy(dst, src, len);
+}
+
+/*
+ * Test that changing coefficients in a valid signature's z vector results in
+ * the following behavior from mldsa_verify():
+ *
+ * * -EBADMSG if a coefficient is changed to have an out-of-range value, i.e.
+ * absolute value >= gamma1 - beta, corresponding to the verifier detecting
+ * the out-of-range coefficient and rejecting the signature as malformed
+ *
+ * * -EKEYREJECTED if a coefficient is changed to a different in-range value,
+ * i.e. absolute value < gamma1 - beta, corresponding to the verifier
+ * continuing to the "real" signature check and that check failing
+ */
+static void test_mldsa_z_range(struct kunit *test,
+ const struct mldsa_testvector *tv)
+{
+ u8 *sig = kunit_kmemdup_or_fail(test, tv->sig, tv->sig_len);
+ const int lambda = params[tv->alg].lambda;
+ const s32 gamma1 = params[tv->alg].gamma1;
+ const int beta = params[tv->alg].beta;
+ /*
+ * We just modify the first coefficient. The coefficient is gamma1
+ * minus either the first 18 or 20 bits of the u32, depending on gamma1.
+ *
+ * The layout of ML-DSA signatures is ctilde || z || h. ctilde is
+ * lambda / 4 bytes, so z starts at &sig[lambda / 4].
+ */
+ u8 *z_ptr = &sig[lambda / 4];
+ const u32 z_data = get_unaligned_le32(z_ptr);
+ const u32 mask = (gamma1 << 1) - 1;
+ /* These are the four boundaries of the out-of-range values. */
+ const s32 out_of_range_coeffs[] = {
+ -gamma1 + 1,
+ -(gamma1 - beta),
+ gamma1,
+ gamma1 - beta,
+ };
+ /*
+ * These are the two boundaries of the valid range, along with 0. We
+ * assume that none of these matches the original coefficient.
+ */
+ const s32 in_range_coeffs[] = {
+ -(gamma1 - beta - 1),
+ 0,
+ gamma1 - beta - 1,
+ };
+
+ /* Initially the signature is valid. */
+ do_mldsa_and_assert_success(test, tv);
+
+ /* Test some out-of-range coefficients. */
+ for (int i = 0; i < ARRAY_SIZE(out_of_range_coeffs); i++) {
+ const s32 c = out_of_range_coeffs[i];
+
+ put_unaligned_le32((z_data & ~mask) | (mask & (gamma1 - c)),
+ z_ptr);
+ KUNIT_ASSERT_EQ(test, -EBADMSG,
+ mldsa_verify(tv->alg, sig, tv->sig_len, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len));
+ }
+
+ /* Test some in-range coefficients. */
+ for (int i = 0; i < ARRAY_SIZE(in_range_coeffs); i++) {
+ const s32 c = in_range_coeffs[i];
+
+ put_unaligned_le32((z_data & ~mask) | (mask & (gamma1 - c)),
+ z_ptr);
+ KUNIT_ASSERT_EQ(test, -EKEYREJECTED,
+ mldsa_verify(tv->alg, sig, tv->sig_len, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len));
+ }
+}
+
+/* Test that mldsa_verify() rejects malformed hint vectors with -EBADMSG. */
+static void test_mldsa_bad_hints(struct kunit *test,
+ const struct mldsa_testvector *tv)
+{
+ const int omega = params[tv->alg].omega;
+ const int k = params[tv->alg].k;
+ u8 *sig = kunit_kmemdup_or_fail(test, tv->sig, tv->sig_len);
+ /* Pointer to the encoded hint vector in the signature */
+ u8 *hintvec = &sig[tv->sig_len - omega - k];
+ u8 h;
+
+ /* Initially the signature is valid. */
+ do_mldsa_and_assert_success(test, tv);
+
+ /* Cumulative hint count exceeds omega */
+ memcpy(sig, tv->sig, tv->sig_len);
+ hintvec[omega + k - 1] = omega + 1;
+ KUNIT_ASSERT_EQ(test, -EBADMSG,
+ mldsa_verify(tv->alg, sig, tv->sig_len, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len));
+
+ /* Cumulative hint count decreases */
+ memcpy(sig, tv->sig, tv->sig_len);
+ KUNIT_ASSERT_GE(test, hintvec[omega + k - 2], 1);
+ hintvec[omega + k - 1] = hintvec[omega + k - 2] - 1;
+ KUNIT_ASSERT_EQ(test, -EBADMSG,
+ mldsa_verify(tv->alg, sig, tv->sig_len, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len));
+
+ /*
+ * Hint indices out of order. To test this, swap hintvec[0] and
+ * hintvec[1]. This assumes that the original valid signature had at
+ * least two nonzero hints in the first element (asserted below).
+ */
+ memcpy(sig, tv->sig, tv->sig_len);
+ KUNIT_ASSERT_GE(test, hintvec[omega], 2);
+ h = hintvec[0];
+ hintvec[0] = hintvec[1];
+ hintvec[1] = h;
+ KUNIT_ASSERT_EQ(test, -EBADMSG,
+ mldsa_verify(tv->alg, sig, tv->sig_len, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len));
+
+ /*
+ * Extra hint indices given. For this test to work, the original valid
+ * signature must have fewer than omega nonzero hints (asserted below).
+ */
+ memcpy(sig, tv->sig, tv->sig_len);
+ KUNIT_ASSERT_LT(test, hintvec[omega + k - 1], omega);
+ hintvec[omega - 1] = 0xff;
+ KUNIT_ASSERT_EQ(test, -EBADMSG,
+ mldsa_verify(tv->alg, sig, tv->sig_len, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len));
+}
+
+static void test_mldsa_mutation(struct kunit *test,
+ const struct mldsa_testvector *tv)
+{
+ const int sig_len = tv->sig_len;
+ const int msg_len = tv->msg_len;
+ const int pk_len = tv->pk_len;
+ const int num_iter = 200;
+ u8 *sig = kunit_kmemdup_or_fail(test, tv->sig, sig_len);
+ u8 *msg = kunit_kmemdup_or_fail(test, tv->msg, msg_len);
+ u8 *pk = kunit_kmemdup_or_fail(test, tv->pk, pk_len);
+
+ /* Initially the signature is valid. */
+ do_mldsa_and_assert_success(test, tv);
+
+ /* Changing any bit in the signature should invalidate the signature */
+ for (int i = 0; i < num_iter; i++) {
+ size_t pos = get_random_u32_below(sig_len);
+ u8 b = 1 << get_random_u32_below(8);
+
+ sig[pos] ^= b;
+ KUNIT_ASSERT_NE(test, 0,
+ mldsa_verify(tv->alg, sig, sig_len, msg,
+ msg_len, pk, pk_len));
+ sig[pos] ^= b;
+ }
+
+ /* Changing any bit in the message should invalidate the signature */
+ for (int i = 0; i < num_iter; i++) {
+ size_t pos = get_random_u32_below(msg_len);
+ u8 b = 1 << get_random_u32_below(8);
+
+ msg[pos] ^= b;
+ KUNIT_ASSERT_NE(test, 0,
+ mldsa_verify(tv->alg, sig, sig_len, msg,
+ msg_len, pk, pk_len));
+ msg[pos] ^= b;
+ }
+
+ /* Changing any bit in the public key should invalidate the signature */
+ for (int i = 0; i < num_iter; i++) {
+ size_t pos = get_random_u32_below(pk_len);
+ u8 b = 1 << get_random_u32_below(8);
+
+ pk[pos] ^= b;
+ KUNIT_ASSERT_NE(test, 0,
+ mldsa_verify(tv->alg, sig, sig_len, msg,
+ msg_len, pk, pk_len));
+ pk[pos] ^= b;
+ }
+
+ /* All changes should have been undone. */
+ KUNIT_ASSERT_EQ(test, 0,
+ mldsa_verify(tv->alg, sig, sig_len, msg, msg_len, pk,
+ pk_len));
+}
+
+static void test_mldsa(struct kunit *test, const struct mldsa_testvector *tv)
+{
+ /* Valid signature */
+ KUNIT_ASSERT_EQ(test, tv->sig_len, params[tv->alg].sig_len);
+ KUNIT_ASSERT_EQ(test, tv->pk_len, params[tv->alg].pk_len);
+ do_mldsa_and_assert_success(test, tv);
+
+ /* Signature too short */
+ KUNIT_ASSERT_EQ(test, -EBADMSG,
+ mldsa_verify(tv->alg, tv->sig, tv->sig_len - 1, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len));
+
+ /* Signature too long */
+ KUNIT_ASSERT_EQ(test, -EBADMSG,
+ mldsa_verify(tv->alg, tv->sig, tv->sig_len + 1, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len));
+
+ /* Public key too short */
+ KUNIT_ASSERT_EQ(test, -EBADMSG,
+ mldsa_verify(tv->alg, tv->sig, tv->sig_len, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len - 1));
+
+ /* Public key too long */
+ KUNIT_ASSERT_EQ(test, -EBADMSG,
+ mldsa_verify(tv->alg, tv->sig, tv->sig_len, tv->msg,
+ tv->msg_len, tv->pk, tv->pk_len + 1));
+
+ /*
+ * Message too short. Error is EKEYREJECTED because it gets rejected by
+ * the "real" signature check rather than the well-formedness checks.
+ */
+ KUNIT_ASSERT_EQ(test, -EKEYREJECTED,
+ mldsa_verify(tv->alg, tv->sig, tv->sig_len, tv->msg,
+ tv->msg_len - 1, tv->pk, tv->pk_len));
+ /*
+ * Can't simply try (tv->msg, tv->msg_len + 1) too, as tv->msg would be
+ * accessed out of bounds. However, ML-DSA just hashes the message and
+ * doesn't handle different message lengths differently anyway.
+ */
+
+ /* Test the validity checks on the z vector. */
+ test_mldsa_z_range(test, tv);
+
+ /* Test the validity checks on the hint vector. */
+ test_mldsa_bad_hints(test, tv);
+
+ /* Test randomly mutating the inputs. */
+ test_mldsa_mutation(test, tv);
+}
+
+static void test_mldsa44(struct kunit *test)
+{
+ test_mldsa(test, &mldsa44_testvector);
+}
+
+static void test_mldsa65(struct kunit *test)
+{
+ test_mldsa(test, &mldsa65_testvector);
+}
+
+static void test_mldsa87(struct kunit *test)
+{
+ test_mldsa(test, &mldsa87_testvector);
+}
+
+static s32 mod(s32 a, s32 m)
+{
+ a %= m;
+ if (a < 0)
+ a += m;
+ return a;
+}
+
+static s32 symmetric_mod(s32 a, s32 m)
+{
+ a = mod(a, m);
+ if (a > m / 2)
+ a -= m;
+ return a;
+}
+
+/* Mechanical, inefficient translation of FIPS 204 Algorithm 36, Decompose */
+static void decompose_ref(s32 r, s32 gamma2, s32 *r0, s32 *r1)
+{
+ s32 rplus = mod(r, Q);
+
+ *r0 = symmetric_mod(rplus, 2 * gamma2);
+ if (rplus - *r0 == Q - 1) {
+ *r1 = 0;
+ *r0 = *r0 - 1;
+ } else {
+ *r1 = (rplus - *r0) / (2 * gamma2);
+ }
+}
+
+/* Mechanical, inefficient translation of FIPS 204 Algorithm 40, UseHint */
+static s32 use_hint_ref(u8 h, s32 r, s32 gamma2)
+{
+ s32 m = (Q - 1) / (2 * gamma2);
+ s32 r0, r1;
+
+ decompose_ref(r, gamma2, &r0, &r1);
+ if (h == 1 && r0 > 0)
+ return mod(r1 + 1, m);
+ if (h == 1 && r0 <= 0)
+ return mod(r1 - 1, m);
+ return r1;
+}
+
+/*
+ * Test that for all possible inputs, mldsa_use_hint() gives the same output as
+ * a mechanical translation of the pseudocode from FIPS 204.
+ */
+static void test_mldsa_use_hint(struct kunit *test)
+{
+ for (int i = 0; i < 2; i++) {
+ const s32 gamma2 = (Q - 1) / (i == 0 ? 88 : 32);
+
+ for (u8 h = 0; h < 2; h++) {
+ for (s32 r = 0; r < Q; r++) {
+ KUNIT_ASSERT_EQ(test,
+ mldsa_use_hint(h, r, gamma2),
+ use_hint_ref(h, r, gamma2));
+ }
+ }
+ }
+}
+
+static void benchmark_mldsa(struct kunit *test,
+ const struct mldsa_testvector *tv)
+{
+ const int warmup_niter = 200;
+ const int benchmark_niter = 200;
+ u64 t0, t1;
+
+ if (!IS_ENABLED(CONFIG_CRYPTO_LIB_BENCHMARK))
+ kunit_skip(test, "not enabled");
+
+ for (int i = 0; i < warmup_niter; i++)
+ do_mldsa_and_assert_success(test, tv);
+
+ t0 = ktime_get_ns();
+ for (int i = 0; i < benchmark_niter; i++)
+ do_mldsa_and_assert_success(test, tv);
+ t1 = ktime_get_ns();
+ kunit_info(test, "%llu ops/s",
+ div64_u64((u64)benchmark_niter * NSEC_PER_SEC,
+ t1 - t0 ?: 1));
+}
+
+static void benchmark_mldsa44(struct kunit *test)
+{
+ benchmark_mldsa(test, &mldsa44_testvector);
+}
+
+static void benchmark_mldsa65(struct kunit *test)
+{
+ benchmark_mldsa(test, &mldsa65_testvector);
+}
+
+static void benchmark_mldsa87(struct kunit *test)
+{
+ benchmark_mldsa(test, &mldsa87_testvector);
+}
+
+static struct kunit_case mldsa_kunit_cases[] = {
+ KUNIT_CASE(test_mldsa44),
+ KUNIT_CASE(test_mldsa65),
+ KUNIT_CASE(test_mldsa87),
+ KUNIT_CASE(test_mldsa_use_hint),
+ KUNIT_CASE(benchmark_mldsa44),
+ KUNIT_CASE(benchmark_mldsa65),
+ KUNIT_CASE(benchmark_mldsa87),
+ {},
+};
+
+static struct kunit_suite mldsa_kunit_suite = {
+ .name = "mldsa",
+ .test_cases = mldsa_kunit_cases,
+};
+kunit_test_suite(mldsa_kunit_suite);
+
+MODULE_DESCRIPTION("KUnit tests and benchmark for ML-DSA");
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+MODULE_LICENSE("GPL");
diff --git a/lib/crypto/tests/nh-testvecs.h b/lib/crypto/tests/nh-testvecs.h
new file mode 100644
index 000000000000..b393e1f90f31
--- /dev/null
+++ b/lib/crypto/tests/nh-testvecs.h
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* This file was generated by: ./scripts/crypto/gen-hash-testvecs.py nh */
+
+static const u8 nh_test_key[NH_KEY_BYTES] = {
+ 0x04, 0x59, 0x66, 0x92, 0x81, 0xd7, 0xe9, 0x25,
+ 0x68, 0xfa, 0xb0, 0xca, 0x9f, 0xea, 0x98, 0xca,
+ 0xcd, 0xbf, 0x6d, 0xa5, 0x0c, 0x22, 0xc3, 0x57,
+ 0xdc, 0x35, 0x05, 0xdd, 0x5b, 0xb0, 0xce, 0xf6,
+ 0xb2, 0x4c, 0x77, 0x2e, 0xd2, 0x63, 0xf0, 0x17,
+ 0x60, 0xd8, 0xd3, 0xd9, 0xed, 0x34, 0xb6, 0xed,
+ 0x6a, 0x11, 0xc0, 0x25, 0xda, 0xba, 0x7e, 0xef,
+ 0x49, 0x13, 0xf7, 0xd9, 0xfc, 0xb6, 0xfd, 0x58,
+ 0xe9, 0x5f, 0xc5, 0xc4, 0x69, 0x89, 0xba, 0xa6,
+ 0x2b, 0x58, 0x8d, 0x36, 0x6c, 0xb9, 0x90, 0x1e,
+ 0x64, 0xc7, 0x44, 0x84, 0x03, 0x70, 0x30, 0x47,
+ 0xdd, 0x58, 0xf4, 0x87, 0x61, 0xfd, 0x9c, 0x6b,
+ 0x51, 0x1b, 0x39, 0x1d, 0x6d, 0x50, 0xae, 0x19,
+ 0x71, 0x03, 0xc7, 0xa7, 0x42, 0x82, 0x8f, 0xa5,
+ 0x63, 0x6a, 0xe2, 0x8a, 0xad, 0x4b, 0x40, 0xa7,
+ 0x3f, 0x8b, 0xe4, 0xae, 0xb2, 0x8a, 0x14, 0x78,
+ 0x91, 0x07, 0xba, 0x02, 0x08, 0xc1, 0x34, 0xb8,
+ 0xda, 0x61, 0x67, 0xf6, 0x98, 0x97, 0x1a, 0xcb,
+ 0x0f, 0x82, 0x80, 0xff, 0x02, 0x54, 0x16, 0x57,
+ 0x18, 0x35, 0xaf, 0x16, 0x17, 0x68, 0xcc, 0xc7,
+ 0x52, 0xac, 0x31, 0x39, 0x60, 0xe4, 0xb4, 0xcb,
+ 0x0e, 0xf9, 0x57, 0xe9, 0x96, 0xff, 0x99, 0xd6,
+ 0x10, 0x96, 0x09, 0xab, 0x28, 0x92, 0x1b, 0x9f,
+ 0x10, 0xde, 0x3e, 0x87, 0xb8, 0x9d, 0x2d, 0xa0,
+ 0x3c, 0x91, 0x85, 0x8c, 0x9e, 0xc0, 0x97, 0x9a,
+ 0xb4, 0x54, 0x7f, 0x4a, 0x63, 0xc2, 0x75, 0x0f,
+ 0x0d, 0x2f, 0x62, 0x56, 0x48, 0x0e, 0xb6, 0xc7,
+ 0xcf, 0x0d, 0x78, 0xca, 0xbd, 0x31, 0x9e, 0x4c,
+ 0xf7, 0x3f, 0x9e, 0xc2, 0xea, 0x5e, 0x44, 0x6d,
+ 0x76, 0xf9, 0xc5, 0xe0, 0x29, 0xea, 0x15, 0xbf,
+ 0xaf, 0xd4, 0x75, 0xc8, 0x89, 0xcf, 0x4f, 0x17,
+ 0xfd, 0x4a, 0x45, 0xa5, 0x4d, 0x2d, 0x87, 0x11,
+ 0x2b, 0x3e, 0x64, 0xa2, 0x6b, 0xc5, 0x23, 0x8c,
+ 0xfa, 0x71, 0x13, 0x72, 0x0e, 0x7c, 0xe1, 0x2c,
+ 0x9f, 0x0e, 0x29, 0xc9, 0x15, 0xde, 0x4e, 0xd7,
+ 0x42, 0x1f, 0x8e, 0xe1, 0x91, 0x99, 0x50, 0x38,
+ 0x7f, 0x15, 0xc0, 0xf6, 0x4b, 0xfd, 0x9d, 0x40,
+ 0xe9, 0x44, 0x51, 0xca, 0x3b, 0x83, 0x41, 0x9f,
+ 0x82, 0x64, 0x66, 0x22, 0x12, 0x43, 0x1c, 0x4f,
+ 0x45, 0x11, 0x3a, 0x46, 0xb1, 0x7c, 0x62, 0x0a,
+ 0x9d, 0x4c, 0x99, 0x85, 0xb0, 0x10, 0x19, 0xcf,
+ 0xeb, 0xf9, 0x65, 0xaf, 0xd8, 0x05, 0x9e, 0x61,
+ 0x03, 0x5f, 0x15, 0x99, 0xa9, 0x05, 0x20, 0xc8,
+ 0xaf, 0xab, 0x31, 0x9d, 0xd5, 0xdf, 0x24, 0xce,
+ 0x2b, 0x6d, 0xd7, 0x17, 0xc3, 0x04, 0xff, 0x82,
+ 0xa7, 0x18, 0x39, 0xe9, 0x0d, 0x0a, 0x5f, 0xb9,
+ 0xc9, 0x86, 0x1d, 0xf8, 0x02, 0x2d, 0xc3, 0x88,
+ 0x28, 0x73, 0x5c, 0xac, 0x25, 0xc9, 0xfe, 0xcb,
+ 0xd2, 0xfd, 0x63, 0x74, 0xac, 0xe1, 0xb8, 0xa2,
+ 0xc6, 0x2b, 0xb5, 0x40, 0x01, 0x9b, 0xed, 0xee,
+ 0x7b, 0x63, 0x66, 0x05, 0x45, 0xc2, 0x6c, 0xd8,
+ 0x58, 0xf1, 0xa1, 0x3d, 0xc8, 0x43, 0x59, 0x4b,
+ 0x39, 0x87, 0x24, 0x64, 0x92, 0xb0, 0xab, 0x75,
+ 0xf1, 0xb7, 0xbf, 0x7c, 0xde, 0xc0, 0xaf, 0x4a,
+ 0xc2, 0x7b, 0xd9, 0x8a, 0x99, 0xcd, 0x83, 0x01,
+ 0xe6, 0xae, 0xeb, 0x16, 0xe7, 0x54, 0x9c, 0x95,
+ 0x0a, 0x91, 0x02, 0xaf, 0x9f, 0x79, 0x40, 0x45,
+ 0xce, 0x47, 0x41, 0x65, 0xca, 0x80, 0x0d, 0x14,
+ 0x46, 0x58, 0x5d, 0x4d, 0x28, 0x55, 0x70, 0x49,
+ 0x7c, 0x32, 0x1f, 0x01, 0xaa, 0x05, 0x2f, 0xf1,
+ 0xeb, 0xa3, 0xe6, 0x1d, 0xf9, 0x43, 0xe0, 0x58,
+ 0x05, 0x61, 0x22, 0xc3, 0xee, 0xe4, 0x6f, 0x94,
+ 0xaf, 0x82, 0xda, 0x18, 0x18, 0x63, 0x9c, 0xfa,
+ 0xc0, 0x04, 0x27, 0xc5, 0x39, 0x5e, 0x7a, 0xa6,
+ 0x85, 0x46, 0xb7, 0x76, 0xc9, 0x16, 0xf2, 0xf8,
+ 0x40, 0x8d, 0x4b, 0x5e, 0x72, 0xf3, 0x3e, 0x12,
+ 0xa4, 0x80, 0x39, 0xb2, 0x92, 0xfe, 0x6e, 0x5b,
+ 0x5b, 0xad, 0xea, 0x29, 0xbc, 0x66, 0xe6, 0xfe,
+ 0x80, 0x02, 0x5d, 0x83, 0x37, 0xfc, 0xde, 0x6c,
+ 0x25, 0x54, 0xa2, 0xff, 0x7d, 0xb6, 0xe1, 0xd6,
+ 0xcf, 0xdb, 0x60, 0xe3, 0xbe, 0x2f, 0x4e, 0xb4,
+ 0xf5, 0xb4, 0x51, 0xf7, 0x5a, 0x25, 0xda, 0x40,
+ 0x84, 0x5e, 0xc0, 0x0a, 0x6b, 0xfa, 0x0c, 0xfb,
+ 0x5e, 0x3e, 0x12, 0x6c, 0x39, 0x35, 0xc0, 0x28,
+ 0xd6, 0x1b, 0x3a, 0x72, 0xc3, 0xfe, 0xa5, 0x4c,
+ 0x35, 0xa2, 0x42, 0xf6, 0x3d, 0xa5, 0xbf, 0xb5,
+ 0x39, 0xe3, 0xc9, 0xd5, 0x8c, 0x1b, 0xe5, 0xef,
+ 0x91, 0xd2, 0x80, 0x6f, 0xcc, 0x77, 0x44, 0x50,
+ 0x62, 0xc7, 0xac, 0x29, 0xcb, 0x72, 0xda, 0x6d,
+ 0xc5, 0xfe, 0xa7, 0xee, 0x8b, 0xeb, 0xfc, 0xa3,
+ 0x46, 0x18, 0x5f, 0xaa, 0xc3, 0x65, 0xd0, 0x8f,
+ 0x67, 0x98, 0xd6, 0xce, 0x5f, 0x84, 0xd4, 0x96,
+ 0x1b, 0x67, 0xa0, 0xcf, 0xfc, 0x94, 0x55, 0x5e,
+ 0x4b, 0x51, 0x68, 0xa7, 0x6d, 0x02, 0xf9, 0x53,
+ 0x54, 0x86, 0x6b, 0x53, 0x39, 0xe0, 0x36, 0x23,
+ 0x87, 0x1a, 0xfb, 0x53, 0x1a, 0x65, 0xd8, 0x42,
+ 0xa8, 0x85, 0xfd, 0x2c, 0x7f, 0x6b, 0x7f, 0x67,
+ 0x70, 0x23, 0x6c, 0xe9, 0x0b, 0xf0, 0x1e, 0x0d,
+ 0x0b, 0xb4, 0xd4, 0x96, 0x14, 0x95, 0x7e, 0xf3,
+ 0x9b, 0xdd, 0xd7, 0xc4, 0x24, 0x22, 0xb9, 0x9d,
+ 0xb3, 0xa6, 0xac, 0x09, 0x7c, 0x00, 0xbf, 0xd0,
+ 0xdc, 0xfb, 0x9b, 0x7c, 0x8c, 0xbd, 0xd4, 0x1a,
+ 0x13, 0x2b, 0x82, 0x3d, 0x7c, 0x8c, 0x10, 0x47,
+ 0x49, 0x6c, 0x53, 0xeb, 0xa7, 0xc2, 0xde, 0xed,
+ 0xe2, 0x55, 0x93, 0x2c, 0x1a, 0x5a, 0x7d, 0xe1,
+ 0x37, 0x62, 0xdd, 0x29, 0x1a, 0x72, 0x82, 0xc0,
+ 0x14, 0x73, 0x5d, 0x0e, 0x9b, 0xcc, 0x54, 0x68,
+ 0x3a, 0x4d, 0x56, 0x8f, 0xc9, 0x4e, 0xaf, 0x7b,
+ 0xde, 0x17, 0x9c, 0x5e, 0x83, 0x82, 0x22, 0xe3,
+ 0x28, 0xdf, 0x1b, 0xb6, 0xdb, 0x17, 0x90, 0x48,
+ 0xb5, 0x13, 0x4e, 0xd3, 0x97, 0x5e, 0xb3, 0x9c,
+ 0x16, 0x08, 0xc8, 0x77, 0xb3, 0xcd, 0x94, 0x90,
+ 0x4f, 0x77, 0xaf, 0x67, 0xdd, 0x80, 0x15, 0x1c,
+ 0x59, 0xfb, 0x3c, 0xec, 0xf8, 0xb3, 0x67, 0xfb,
+ 0xa0, 0x94, 0x3c, 0x53, 0x99, 0x49, 0x94, 0x2c,
+ 0x85, 0x26, 0x92, 0x6d, 0x8d, 0x48, 0xf6, 0x72,
+ 0xdd, 0xfb, 0xb2, 0x10, 0x51, 0x5b, 0xbe, 0xd5,
+ 0x70, 0x3d, 0x28, 0x94, 0x98, 0x4f, 0x6e, 0x20,
+ 0x7b, 0x7d, 0x0f, 0x56, 0xc9, 0x96, 0x5f, 0x60,
+ 0x2e, 0x2f, 0x9b, 0x38, 0x7f, 0xc7, 0x3c, 0x6b,
+ 0x2f, 0x2b, 0x8f, 0x1f, 0x07, 0x1c, 0x85, 0x57,
+ 0x16, 0x2e, 0xc7, 0x74, 0xe5, 0xf2, 0x0d, 0xfe,
+ 0xef, 0x57, 0xb0, 0xa4, 0x4f, 0x4c, 0x7d, 0x81,
+ 0xbb, 0xaa, 0xcb, 0xa0, 0xb0, 0x51, 0xcf, 0xc2,
+ 0xee, 0x90, 0x2e, 0x5e, 0x27, 0xca, 0xd3, 0xe8,
+ 0xf3, 0x55, 0x02, 0x56, 0x06, 0xa5, 0xad, 0xdf,
+ 0xa3, 0xa9, 0x06, 0x05, 0x53, 0x74, 0x55, 0xd5,
+ 0xd2, 0x20, 0x0a, 0x6d, 0x4a, 0xef, 0x16, 0xbf,
+ 0xc3, 0xb2, 0x75, 0x93, 0xd8, 0x6e, 0x0f, 0xd2,
+ 0xae, 0x3b, 0xc0, 0x00, 0x22, 0x6f, 0xb5, 0x0a,
+ 0x41, 0xfc, 0xf9, 0x41, 0xfc, 0x16, 0x4f, 0xa6,
+ 0x1c, 0x18, 0x41, 0x67, 0x73, 0xa8, 0x79, 0xa9,
+ 0x54, 0x18, 0x4e, 0x88, 0x44, 0x0f, 0xa1, 0x5b,
+ 0xf0, 0x68, 0xea, 0x3c, 0x62, 0x59, 0x8d, 0xc7,
+ 0x6f, 0xd7, 0x72, 0x20, 0x74, 0x39, 0xd4, 0x3a,
+ 0x41, 0x1b, 0x58, 0x57, 0x54, 0x85, 0x60, 0xca,
+ 0x49, 0x4b, 0xa1, 0x04, 0x91, 0xb6, 0xf2, 0xcd,
+ 0x62, 0x63, 0x67, 0xd1, 0xee, 0x6b, 0x9e, 0x5d,
+ 0xd6, 0xc4, 0x58, 0x6b, 0xe1, 0xe6, 0x4a, 0xdb,
+ 0xe8, 0xb1, 0x35, 0x03, 0x15, 0x8d, 0x34, 0x69,
+ 0x4c, 0xd2, 0x54, 0xce, 0xe8, 0x6a, 0x69, 0x6f,
+ 0xaa, 0xb5, 0x1f, 0x86, 0xed, 0xac, 0x4f, 0x16,
+ 0x1e, 0x48, 0x93, 0xe8, 0x6c, 0x24, 0x1c, 0xd0,
+ 0xbb, 0x61, 0xc2, 0x34, 0xdd, 0xc9, 0x5c, 0xce,
+};
+
+static const u8 nh_test_msg[NH_MESSAGE_BYTES] = {
+ 0x99, 0x57, 0x61, 0x41, 0xad, 0x08, 0x7e, 0x17,
+ 0xd4, 0xef, 0x0b, 0x23, 0xff, 0x0b, 0x96, 0x0a,
+ 0x6c, 0x98, 0xac, 0x78, 0x5e, 0xb6, 0xb2, 0x67,
+ 0x0f, 0x48, 0xf4, 0xa1, 0xe5, 0x1e, 0xfe, 0x83,
+ 0xe4, 0x56, 0x2a, 0x03, 0x64, 0xff, 0x7a, 0xf3,
+ 0x03, 0xfe, 0xa7, 0x86, 0xdc, 0x35, 0x79, 0x13,
+ 0xf8, 0xe1, 0x59, 0x19, 0x04, 0x43, 0x24, 0x82,
+ 0x44, 0x82, 0x41, 0x2b, 0xc7, 0xcf, 0xf5, 0xa4,
+ 0xdc, 0xca, 0xf5, 0x34, 0xc4, 0x23, 0x3c, 0x1f,
+ 0xa8, 0x84, 0x1f, 0x2a, 0xcd, 0xae, 0x9d, 0x5e,
+ 0x05, 0xe2, 0xfb, 0x0c, 0x68, 0x81, 0x90, 0x11,
+ 0x44, 0xf6, 0xdd, 0x5b, 0x51, 0xd3, 0xe0, 0xab,
+ 0x29, 0x3a, 0xa9, 0x9c, 0xf6, 0x7e, 0x2d, 0xe3,
+ 0x6c, 0x09, 0x59, 0xd7, 0xfa, 0x7f, 0x6a, 0x33,
+ 0x3b, 0x23, 0x7b, 0x1b, 0xb2, 0x79, 0x5f, 0x5c,
+ 0xb6, 0x2d, 0xb0, 0xf8, 0xab, 0x33, 0x28, 0xe0,
+ 0x72, 0x2e, 0x2f, 0x03, 0x22, 0x16, 0xb4, 0x87,
+ 0xf7, 0x14, 0x3f, 0x55, 0x8a, 0xb0, 0x47, 0xdb,
+ 0x42, 0x2d, 0xc0, 0x0c, 0x0a, 0x33, 0xf8, 0xab,
+ 0x44, 0xae, 0xa3, 0xc9, 0xfc, 0xf6, 0x34, 0x8c,
+ 0x60, 0x30, 0x6d, 0x31, 0x70, 0xf3, 0x39, 0x53,
+ 0xf1, 0x2d, 0xb9, 0x6c, 0xa6, 0x48, 0x9c, 0x9c,
+ 0xc2, 0x88, 0xb3, 0xa9, 0x98, 0xb6, 0xc3, 0x47,
+ 0x94, 0x02, 0x9d, 0x98, 0x6e, 0x25, 0x6c, 0xf5,
+ 0x9b, 0xc6, 0x4d, 0xee, 0x07, 0x1e, 0x25, 0x8f,
+ 0x01, 0xde, 0xad, 0xe5, 0x77, 0x4f, 0xd1, 0xc0,
+ 0x62, 0xbb, 0x3a, 0xb9, 0x83, 0x0b, 0x29, 0x76,
+ 0x4f, 0xb1, 0x86, 0x2c, 0x27, 0xc7, 0x38, 0x65,
+ 0xcb, 0x78, 0xb7, 0x02, 0x10, 0x9e, 0xde, 0x83,
+ 0xd1, 0xac, 0x05, 0x86, 0x23, 0xce, 0x4f, 0x8d,
+ 0xcc, 0x4e, 0x3f, 0x04, 0xf4, 0x39, 0x91, 0x81,
+ 0x1c, 0x42, 0x47, 0x4d, 0x50, 0xe5, 0x01, 0x22,
+ 0x98, 0xcf, 0x91, 0x36, 0xb3, 0x7c, 0xcf, 0x78,
+ 0x07, 0x22, 0xa9, 0x18, 0xd2, 0xcd, 0x7d, 0x4d,
+ 0xa6, 0xcb, 0xaa, 0x52, 0x13, 0x49, 0x64, 0xb0,
+ 0xa5, 0x3d, 0xc7, 0xc3, 0x10, 0x87, 0x2e, 0x76,
+ 0xa9, 0x52, 0xc5, 0x50, 0x18, 0xc0, 0x5d, 0xb4,
+ 0x4c, 0xc6, 0x7f, 0x64, 0xae, 0x53, 0xc3, 0x46,
+ 0x99, 0xb7, 0x61, 0x6b, 0x08, 0x43, 0x08, 0x4c,
+ 0x90, 0x2c, 0xee, 0x56, 0x91, 0xb4, 0x28, 0xa8,
+ 0xa8, 0x8b, 0x3b, 0x1a, 0x67, 0x71, 0xf2, 0x81,
+ 0x48, 0x20, 0x71, 0x30, 0xdd, 0x69, 0x8a, 0xc2,
+ 0x4c, 0x9d, 0x4e, 0x17, 0xfb, 0x2e, 0xe7, 0x9b,
+ 0x86, 0x94, 0xa5, 0xce, 0xf9, 0x74, 0x56, 0xff,
+ 0x3b, 0xff, 0xd9, 0x5a, 0xc8, 0x98, 0xf5, 0x25,
+ 0xa2, 0xb9, 0x66, 0x46, 0x89, 0x17, 0x39, 0x08,
+ 0x69, 0x03, 0x59, 0x1e, 0x13, 0x12, 0x68, 0xe7,
+ 0x2f, 0x00, 0xd3, 0xf3, 0x71, 0xd1, 0x20, 0xc5,
+ 0x0b, 0x38, 0x89, 0xda, 0x62, 0x3c, 0xce, 0xea,
+ 0x04, 0x19, 0x47, 0x6d, 0xd8, 0x64, 0x38, 0x60,
+ 0x96, 0x71, 0x68, 0x48, 0x79, 0xf8, 0xf4, 0x76,
+ 0x33, 0xf6, 0x60, 0x8d, 0x21, 0xd0, 0xee, 0x41,
+ 0xc0, 0xbe, 0x33, 0x61, 0x5e, 0x66, 0xe6, 0x16,
+ 0x14, 0xc7, 0xfb, 0x6c, 0xf3, 0x58, 0xef, 0x12,
+ 0x7c, 0x70, 0x65, 0x5d, 0x55, 0xe8, 0xf2, 0x92,
+ 0x3a, 0xfe, 0x34, 0x64, 0x31, 0x7c, 0x29, 0xbb,
+ 0x01, 0x18, 0xbd, 0xb6, 0xe4, 0x1e, 0xa4, 0xf3,
+ 0x7b, 0x4c, 0x6a, 0x0d, 0x01, 0xfc, 0xc7, 0x66,
+ 0xc3, 0x88, 0x37, 0x25, 0xcf, 0xe9, 0xca, 0x82,
+ 0xeb, 0xa1, 0x38, 0x40, 0xc9, 0xdb, 0x38, 0x7b,
+ 0x78, 0xcf, 0x11, 0xa3, 0x1c, 0x6b, 0x70, 0xc8,
+ 0xe1, 0x2f, 0x7c, 0x17, 0x2c, 0x58, 0x28, 0xa4,
+ 0x13, 0x40, 0xc7, 0x69, 0x0f, 0x04, 0xe5, 0x8e,
+ 0xf0, 0x67, 0x53, 0xea, 0x10, 0xf5, 0x83, 0xc9,
+ 0xcb, 0x6b, 0x16, 0xef, 0x2e, 0x55, 0xb3, 0xdd,
+ 0xed, 0xf9, 0x1a, 0x52, 0x9a, 0x73, 0x78, 0x14,
+ 0x14, 0x21, 0xfc, 0xef, 0x3c, 0x40, 0xa9, 0xfe,
+ 0xef, 0xd7, 0x6e, 0x28, 0x2f, 0xd3, 0x73, 0xed,
+ 0xa3, 0x73, 0xb5, 0x62, 0x41, 0xe6, 0xd4, 0x79,
+ 0x49, 0x31, 0x2b, 0x86, 0x74, 0x56, 0x21, 0xfe,
+ 0x6d, 0xb2, 0xbe, 0x81, 0x80, 0xa6, 0x81, 0x19,
+ 0x90, 0x79, 0x6f, 0xc4, 0x4e, 0x7d, 0x6f, 0x2f,
+ 0xa8, 0x6f, 0xd5, 0xc4, 0x7e, 0x23, 0x3b, 0xe6,
+ 0x9b, 0x60, 0x97, 0x7b, 0xe2, 0x08, 0x8a, 0xaa,
+ 0xc7, 0x7c, 0xf6, 0xe5, 0x01, 0x3e, 0xd2, 0x29,
+ 0x7d, 0xd7, 0x40, 0x84, 0x95, 0xfa, 0xdf, 0xd8,
+ 0x81, 0xe9, 0x5e, 0xdd, 0x0d, 0x17, 0x51, 0x6b,
+ 0x8c, 0x0e, 0x47, 0xf9, 0x0c, 0x92, 0x1b, 0x60,
+ 0xca, 0x06, 0x8a, 0xe5, 0xe8, 0x0f, 0x06, 0x75,
+ 0x5d, 0x76, 0xc9, 0x32, 0x2c, 0x52, 0x2c, 0x2e,
+ 0xd8, 0x66, 0x38, 0x75, 0x16, 0xc7, 0x7d, 0x51,
+ 0xc4, 0xc2, 0x22, 0xc8, 0x19, 0xfc, 0x3d, 0x69,
+ 0x1e, 0xd9, 0x64, 0x47, 0x5d, 0x21, 0x84, 0x46,
+ 0xd7, 0xe1, 0xf0, 0x95, 0x3a, 0x8f, 0xbd, 0x7a,
+ 0x53, 0x71, 0x4c, 0x54, 0xc1, 0x3e, 0x27, 0xde,
+ 0xeb, 0x04, 0x11, 0xb0, 0x33, 0x4d, 0x57, 0x0b,
+ 0x6b, 0x7d, 0x6c, 0xd5, 0x87, 0x7e, 0xb4, 0xe2,
+ 0x94, 0x9e, 0x9f, 0x74, 0xe8, 0xb7, 0xfa, 0x05,
+ 0x9b, 0x8f, 0x81, 0x43, 0x35, 0x82, 0xb8, 0x5b,
+ 0xa8, 0x5e, 0xfa, 0x7a, 0x80, 0x8d, 0xd2, 0x90,
+ 0x58, 0x79, 0x89, 0x56, 0x90, 0x2b, 0xff, 0x92,
+ 0x3c, 0x35, 0xbe, 0x99, 0x5f, 0xd2, 0x4b, 0x15,
+ 0x58, 0x4b, 0xbf, 0x08, 0x9b, 0x9b, 0x97, 0x10,
+ 0xa4, 0x55, 0xc7, 0xec, 0x29, 0xc5, 0x14, 0x3e,
+ 0x8f, 0x56, 0xa3, 0x92, 0x9e, 0x33, 0xcc, 0x9e,
+ 0x77, 0x2f, 0x33, 0xcb, 0xc4, 0xe9, 0x19, 0xf4,
+ 0x32, 0x2b, 0xef, 0x6c, 0x1c, 0x92, 0x2c, 0x45,
+ 0x88, 0x74, 0x5f, 0xcf, 0x56, 0xfd, 0x87, 0x5f,
+ 0xb6, 0x9b, 0xa2, 0x51, 0xda, 0x9b, 0x83, 0x4f,
+ 0xec, 0x14, 0xe8, 0xd2, 0x42, 0x03, 0xcb, 0xe8,
+ 0xd0, 0xb7, 0xf8, 0x38, 0xde, 0x6f, 0xdf, 0x43,
+ 0xfa, 0x41, 0xab, 0xec, 0x2e, 0x3c, 0x93, 0x39,
+ 0x76, 0xd1, 0x6f, 0x5b, 0x6c, 0x6e, 0x8d, 0xeb,
+ 0x45, 0x6b, 0xc5, 0x76, 0x00, 0x29, 0xca, 0x3b,
+ 0xdb, 0x78, 0xc2, 0x32, 0x09, 0x39, 0x19, 0x50,
+ 0xa2, 0x44, 0x92, 0x09, 0xdb, 0x8b, 0x9e, 0x16,
+ 0x76, 0x7f, 0xf1, 0x78, 0x7b, 0xb2, 0x51, 0xbc,
+ 0x28, 0xbd, 0xb0, 0x7f, 0x25, 0x63, 0x7d, 0x34,
+ 0xfb, 0xf6, 0x36, 0x24, 0xc7, 0xf9, 0x41, 0xb6,
+ 0x2a, 0x06, 0xfc, 0xf0, 0x83, 0xf2, 0x12, 0x3d,
+ 0x60, 0x2e, 0x10, 0x70, 0x31, 0x6f, 0x37, 0x08,
+ 0x3e, 0x91, 0x93, 0xb5, 0xda, 0xb8, 0x4c, 0x1b,
+ 0xd8, 0xb8, 0x3b, 0xd5, 0x3e, 0xb6, 0xc0, 0xbb,
+ 0x38, 0x0f, 0xd2, 0x68, 0x4f, 0x78, 0x56, 0xf6,
+ 0xda, 0x65, 0xb4, 0x0b, 0xb4, 0xaf, 0xa8, 0x19,
+ 0x2f, 0x70, 0x55, 0xe0, 0x47, 0x31, 0x9f, 0x37,
+ 0x1a, 0x47, 0xb9, 0x0c, 0x97, 0x79, 0xfc, 0xa9,
+ 0x76, 0xe6, 0xfa, 0x38, 0x67, 0x25, 0xd3, 0x89,
+ 0x8d, 0xad, 0xc6, 0x11, 0x2d, 0x77, 0x0b, 0x35,
+ 0xa2, 0xe2, 0xdf, 0xc8, 0x94, 0xd5, 0xdf, 0xd2,
+ 0x69, 0x2a, 0x99, 0x93, 0xfa, 0x4a, 0x5f, 0xc7,
+ 0x8a, 0x14, 0x5f, 0x2a, 0xf3, 0x02, 0xf0, 0x3e,
+ 0x21, 0x8e, 0x2e, 0x4b, 0xc4, 0xd2, 0xc8, 0xa6,
+ 0x41, 0x6e, 0x17, 0x36, 0xe9, 0xad, 0x73, 0x33,
+ 0x6c, 0xea, 0xc2, 0x31, 0x8f, 0x30, 0x51, 0x5c,
+ 0x1c, 0x20, 0xe6, 0x05, 0x1a, 0x17, 0x15, 0x5d,
+ 0x3e, 0x8f, 0xd2, 0x7f, 0xa1, 0xc5, 0x47, 0xb3,
+ 0xb2, 0x9c, 0xe8, 0xf0, 0x6d, 0xc1, 0xc3, 0xa2,
+};
+
+static const u8 nh_test_val16[NH_HASH_BYTES] = {
+ 0x30, 0x77, 0x55, 0x7c, 0x45, 0xd8, 0xce, 0xf7,
+ 0x2a, 0xb5, 0x14, 0x8c, 0x35, 0x7e, 0xaa, 0x00,
+ 0x50, 0xbc, 0x50, 0x7c, 0xd3, 0x20, 0x7c, 0x9c,
+ 0xb4, 0xf1, 0x91, 0x26, 0x81, 0x03, 0xa5, 0x68,
+};
+
+static const u8 nh_test_val96[NH_HASH_BYTES] = {
+ 0xd2, 0x19, 0xca, 0xa5, 0x6c, 0x0c, 0xdf, 0x2f,
+ 0x69, 0xfa, 0x75, 0xc1, 0x63, 0xdb, 0xfa, 0x4d,
+ 0x45, 0x2b, 0xb8, 0xdb, 0xac, 0xee, 0x61, 0xc6,
+ 0x7a, 0x83, 0xb6, 0x0f, 0x32, 0x82, 0xe4, 0xd0,
+};
+
+static const u8 nh_test_val256[NH_HASH_BYTES] = {
+ 0x33, 0x8f, 0xb4, 0x96, 0xf1, 0xb6, 0xf1, 0xb5,
+ 0x05, 0x19, 0xbb, 0x6b, 0xda, 0xd9, 0x95, 0x75,
+ 0x96, 0x3f, 0x8b, 0x42, 0xb6, 0xcd, 0xb7, 0xb7,
+ 0xe7, 0x97, 0xb5, 0xa9, 0x0b, 0xd7, 0xdd, 0x33,
+};
+
+static const u8 nh_test_val1024[NH_HASH_BYTES] = {
+ 0x32, 0x3d, 0x51, 0xe1, 0x77, 0xb6, 0xac, 0x06,
+ 0x84, 0x67, 0xb7, 0xf2, 0x24, 0xe7, 0xec, 0xfd,
+ 0x96, 0x64, 0xff, 0x55, 0xc7, 0x1b, 0xf9, 0xdc,
+ 0xa3, 0xc7, 0x32, 0x06, 0x79, 0xcf, 0xca, 0xb6,
+};
diff --git a/lib/crypto/tests/nh_kunit.c b/lib/crypto/tests/nh_kunit.c
new file mode 100644
index 000000000000..a8a3c3f345cb
--- /dev/null
+++ b/lib/crypto/tests/nh_kunit.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2025 Google LLC
+ */
+#include <crypto/nh.h>
+#include <kunit/test.h>
+#include "nh-testvecs.h"
+
+static void test_nh(struct kunit *test)
+{
+ u32 *key = kunit_kmalloc(test, NH_KEY_BYTES, GFP_KERNEL);
+ __le64 hash[NH_NUM_PASSES];
+
+ KUNIT_ASSERT_NOT_NULL(test, key);
+ memcpy(key, nh_test_key, NH_KEY_BYTES);
+ le32_to_cpu_array(key, NH_KEY_WORDS);
+
+ nh(key, nh_test_msg, 16, hash);
+ KUNIT_ASSERT_MEMEQ(test, hash, nh_test_val16, NH_HASH_BYTES);
+
+ nh(key, nh_test_msg, 96, hash);
+ KUNIT_ASSERT_MEMEQ(test, hash, nh_test_val96, NH_HASH_BYTES);
+
+ nh(key, nh_test_msg, 256, hash);
+ KUNIT_ASSERT_MEMEQ(test, hash, nh_test_val256, NH_HASH_BYTES);
+
+ nh(key, nh_test_msg, 1024, hash);
+ KUNIT_ASSERT_MEMEQ(test, hash, nh_test_val1024, NH_HASH_BYTES);
+}
+
+static struct kunit_case nh_test_cases[] = {
+ KUNIT_CASE(test_nh),
+ {},
+};
+
+static struct kunit_suite nh_test_suite = {
+ .name = "nh",
+ .test_cases = nh_test_cases,
+};
+kunit_test_suite(nh_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for NH");
+MODULE_LICENSE("GPL");
diff --git a/lib/crypto/x86/aes-aesni.S b/lib/crypto/x86/aes-aesni.S
new file mode 100644
index 000000000000..b8c3e104a3be
--- /dev/null
+++ b/lib/crypto/x86/aes-aesni.S
@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+//
+// AES block cipher using AES-NI instructions
+//
+// Copyright 2026 Google LLC
+//
+// The code in this file supports 32-bit and 64-bit CPUs, and it doesn't require
+// AVX. It does use up to SSE4.1, which all CPUs with AES-NI have.
+#include <linux/linkage.h>
+
+.section .rodata
+#ifdef __x86_64__
+#define RODATA(label) label(%rip)
+#else
+#define RODATA(label) label
+#endif
+
+ // A mask for pshufb that extracts the last dword, rotates it right by 8
+ // bits, and copies the result to all four dwords.
+.p2align 4
+.Lmask:
+ .byte 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12
+
+ // The AES round constants, used during key expansion
+.Lrcon:
+ .long 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
+
+.text
+
+// Transform four dwords [a0, a1, a2, a3] in \a into
+// [a0, a0^a1, a0^a1^a2, a0^a1^a2^a3]. \tmp is a temporary xmm register.
+//
+// Note: this could be done in four instructions, shufps + pxor + shufps + pxor,
+// if the temporary register were zero-initialized ahead of time. We instead do
+// it in an easier-to-understand way that doesn't require zero-initialization
+// and avoids the unusual shufps instruction. movdqa is usually "free" anyway.
+.macro _prefix_sum a, tmp
+ movdqa \a, \tmp // [a0, a1, a2, a3]
+ pslldq $4, \a // [0, a0, a1, a2]
+ pxor \tmp, \a // [a0, a0^a1, a1^a2, a2^a3]
+ movdqa \a, \tmp
+ pslldq $8, \a // [0, 0, a0, a0^a1]
+ pxor \tmp, \a // [a0, a0^a1, a0^a1^a2, a0^a1^a2^a3]
+.endm
+
+.macro _gen_round_key a, b
+ // Compute four copies of rcon[i] ^ SubBytes(ror32(w, 8)), where w is
+ // the last dword of the previous round key (given in \b).
+ //
+ // 'aesenclast src, dst' does dst = src XOR SubBytes(ShiftRows(dst)).
+ // It is used here solely for the SubBytes and the XOR. The ShiftRows
+ // is a no-op because all four columns are the same here.
+ //
+ // Don't use the 'aeskeygenassist' instruction, since:
+ // - On most Intel CPUs it is microcoded, making it have a much higher
+ // latency and use more execution ports than 'aesenclast'.
+ // - It cannot be used in a loop, since it requires an immediate.
+ // - It doesn't do much more than 'aesenclast' in the first place.
+ movdqa \b, %xmm2
+ pshufb MASK, %xmm2
+ aesenclast RCON, %xmm2
+
+ // XOR in the prefix sum of the four dwords of \a, which is the
+ // previous round key (AES-128) or the first round key in the previous
+ // pair of round keys (AES-256). The result is the next round key.
+ _prefix_sum \a, tmp=%xmm3
+ pxor %xmm2, \a
+
+ // Store the next round key to memory. Also leave it in \a.
+ movdqu \a, (RNDKEYS)
+.endm
+
+.macro _aes_expandkey_aesni is_aes128
+#ifdef __x86_64__
+ // Arguments
+ .set RNDKEYS, %rdi
+ .set INV_RNDKEYS, %rsi
+ .set IN_KEY, %rdx
+
+ // Other local variables
+ .set RCON_PTR, %rcx
+ .set COUNTER, %eax
+#else
+ // Arguments, assuming -mregparm=3
+ .set RNDKEYS, %eax
+ .set INV_RNDKEYS, %edx
+ .set IN_KEY, %ecx
+
+ // Other local variables
+ .set RCON_PTR, %ebx
+ .set COUNTER, %esi
+#endif
+ .set RCON, %xmm6
+ .set MASK, %xmm7
+
+#ifdef __i386__
+ push %ebx
+ push %esi
+#endif
+
+.if \is_aes128
+ // AES-128: the first round key is simply a copy of the raw key.
+ movdqu (IN_KEY), %xmm0
+ movdqu %xmm0, (RNDKEYS)
+.else
+ // AES-256: the first two round keys are simply a copy of the raw key.
+ movdqu (IN_KEY), %xmm0
+ movdqu %xmm0, (RNDKEYS)
+ movdqu 16(IN_KEY), %xmm1
+ movdqu %xmm1, 16(RNDKEYS)
+ add $32, RNDKEYS
+.endif
+
+ // Generate the remaining round keys.
+ movdqa RODATA(.Lmask), MASK
+.if \is_aes128
+ lea RODATA(.Lrcon), RCON_PTR
+ mov $10, COUNTER
+.Lgen_next_aes128_round_key:
+ add $16, RNDKEYS
+ movd (RCON_PTR), RCON
+ pshufd $0x00, RCON, RCON
+ add $4, RCON_PTR
+ _gen_round_key %xmm0, %xmm0
+ dec COUNTER
+ jnz .Lgen_next_aes128_round_key
+.else
+ // AES-256: only the first 7 round constants are needed, so instead of
+ // loading each one from memory, just start by loading [1, 1, 1, 1] and
+ // then generate the rest by doubling.
+ pshufd $0x00, RODATA(.Lrcon), RCON
+ pxor %xmm5, %xmm5 // All-zeroes
+ mov $7, COUNTER
+.Lgen_next_aes256_round_key_pair:
+ // Generate the next AES-256 round key: either the first of a pair of
+ // two, or the last one.
+ _gen_round_key %xmm0, %xmm1
+
+ dec COUNTER
+ jz .Lgen_aes256_round_keys_done
+
+ // Generate the second AES-256 round key of the pair. Compared to the
+ // first, there's no rotation and no XOR of a round constant.
+ pshufd $0xff, %xmm0, %xmm2 // Get four copies of last dword
+ aesenclast %xmm5, %xmm2 // Just does SubBytes
+ _prefix_sum %xmm1, tmp=%xmm3
+ pxor %xmm2, %xmm1
+ movdqu %xmm1, 16(RNDKEYS)
+ add $32, RNDKEYS
+ paddd RCON, RCON // RCON <<= 1
+ jmp .Lgen_next_aes256_round_key_pair
+.Lgen_aes256_round_keys_done:
+.endif
+
+ // If INV_RNDKEYS is non-NULL, write the round keys for the Equivalent
+ // Inverse Cipher to it. To do that, reverse the standard round keys,
+ // and apply aesimc (InvMixColumn) to each except the first and last.
+ test INV_RNDKEYS, INV_RNDKEYS
+ jz .Ldone\@
+ movdqu (RNDKEYS), %xmm0 // Last standard round key
+ movdqu %xmm0, (INV_RNDKEYS) // => First inverse round key
+.if \is_aes128
+ mov $9, COUNTER
+.else
+ mov $13, COUNTER
+.endif
+.Lgen_next_inv_round_key\@:
+ sub $16, RNDKEYS
+ add $16, INV_RNDKEYS
+ movdqu (RNDKEYS), %xmm0
+ aesimc %xmm0, %xmm0
+ movdqu %xmm0, (INV_RNDKEYS)
+ dec COUNTER
+ jnz .Lgen_next_inv_round_key\@
+ movdqu -16(RNDKEYS), %xmm0 // First standard round key
+ movdqu %xmm0, 16(INV_RNDKEYS) // => Last inverse round key
+
+.Ldone\@:
+#ifdef __i386__
+ pop %esi
+ pop %ebx
+#endif
+ RET
+.endm
+
+// void aes128_expandkey_aesni(u32 rndkeys[], u32 *inv_rndkeys,
+// const u8 in_key[AES_KEYSIZE_128]);
+SYM_FUNC_START(aes128_expandkey_aesni)
+ _aes_expandkey_aesni 1
+SYM_FUNC_END(aes128_expandkey_aesni)
+
+// void aes256_expandkey_aesni(u32 rndkeys[], u32 *inv_rndkeys,
+// const u8 in_key[AES_KEYSIZE_256]);
+SYM_FUNC_START(aes256_expandkey_aesni)
+ _aes_expandkey_aesni 0
+SYM_FUNC_END(aes256_expandkey_aesni)
+
+.macro _aes_crypt_aesni enc
+#ifdef __x86_64__
+ .set RNDKEYS, %rdi
+ .set NROUNDS, %esi
+ .set OUT, %rdx
+ .set IN, %rcx
+#else
+ // Assuming -mregparm=3
+ .set RNDKEYS, %eax
+ .set NROUNDS, %edx
+ .set OUT, %ecx
+ .set IN, %ebx // Passed on stack
+#endif
+
+#ifdef __i386__
+ push %ebx
+ mov 8(%esp), %ebx
+#endif
+
+ // Zero-th round
+ movdqu (IN), %xmm0
+ movdqu (RNDKEYS), %xmm1
+ pxor %xmm1, %xmm0
+
+ // Normal rounds
+ add $16, RNDKEYS
+ dec NROUNDS
+.Lnext_round\@:
+ movdqu (RNDKEYS), %xmm1
+.if \enc
+ aesenc %xmm1, %xmm0
+.else
+ aesdec %xmm1, %xmm0
+.endif
+ add $16, RNDKEYS
+ dec NROUNDS
+ jne .Lnext_round\@
+
+ // Last round
+ movdqu (RNDKEYS), %xmm1
+.if \enc
+ aesenclast %xmm1, %xmm0
+.else
+ aesdeclast %xmm1, %xmm0
+.endif
+ movdqu %xmm0, (OUT)
+
+#ifdef __i386__
+ pop %ebx
+#endif
+ RET
+.endm
+
+// void aes_encrypt_aesni(const u32 rndkeys[], int nrounds,
+// u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]);
+SYM_FUNC_START(aes_encrypt_aesni)
+ _aes_crypt_aesni 1
+SYM_FUNC_END(aes_encrypt_aesni)
+
+// void aes_decrypt_aesni(const u32 inv_rndkeys[], int nrounds,
+// u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]);
+SYM_FUNC_START(aes_decrypt_aesni)
+ _aes_crypt_aesni 0
+SYM_FUNC_END(aes_decrypt_aesni)
diff --git a/lib/crypto/x86/aes.h b/lib/crypto/x86/aes.h
new file mode 100644
index 000000000000..b047dee94f57
--- /dev/null
+++ b/lib/crypto/x86/aes.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AES block cipher using AES-NI instructions
+ *
+ * Copyright 2026 Google LLC
+ */
+
+#include <asm/fpu/api.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_aes);
+
+void aes128_expandkey_aesni(u32 rndkeys[], u32 *inv_rndkeys,
+ const u8 in_key[AES_KEYSIZE_128]);
+void aes256_expandkey_aesni(u32 rndkeys[], u32 *inv_rndkeys,
+ const u8 in_key[AES_KEYSIZE_256]);
+void aes_encrypt_aesni(const u32 rndkeys[], int nrounds,
+ u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]);
+void aes_decrypt_aesni(const u32 inv_rndkeys[], int nrounds,
+ u8 out[AES_BLOCK_SIZE], const u8 in[AES_BLOCK_SIZE]);
+
+/*
+ * Expand an AES key using AES-NI if supported and usable or generic code
+ * otherwise. The expanded key format is compatible between the two cases. The
+ * outputs are @k->rndkeys (required) and @inv_k->inv_rndkeys (optional).
+ *
+ * We could just always use the generic key expansion code. AES key expansion
+ * is usually less performance-critical than AES en/decryption. However,
+ * there's still *some* value in speed here, as well as in non-key-dependent
+ * execution time which AES-NI provides. So, do use AES-NI to expand AES-128
+ * and AES-256 keys. (Don't bother with AES-192, as it's almost never used.)
+ */
+static void aes_preparekey_arch(union aes_enckey_arch *k,
+ union aes_invkey_arch *inv_k,
+ const u8 *in_key, int key_len, int nrounds)
+{
+ u32 *rndkeys = k->rndkeys;
+ u32 *inv_rndkeys = inv_k ? inv_k->inv_rndkeys : NULL;
+
+ if (static_branch_likely(&have_aes) && key_len != AES_KEYSIZE_192 &&
+ irq_fpu_usable()) {
+ kernel_fpu_begin();
+ if (key_len == AES_KEYSIZE_128)
+ aes128_expandkey_aesni(rndkeys, inv_rndkeys, in_key);
+ else
+ aes256_expandkey_aesni(rndkeys, inv_rndkeys, in_key);
+ kernel_fpu_end();
+ } else {
+ aes_expandkey_generic(rndkeys, inv_rndkeys, in_key, key_len);
+ }
+}
+
+static void aes_encrypt_arch(const struct aes_enckey *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (static_branch_likely(&have_aes) && irq_fpu_usable()) {
+ kernel_fpu_begin();
+ aes_encrypt_aesni(key->k.rndkeys, key->nrounds, out, in);
+ kernel_fpu_end();
+ } else {
+ aes_encrypt_generic(key->k.rndkeys, key->nrounds, out, in);
+ }
+}
+
+static void aes_decrypt_arch(const struct aes_key *key,
+ u8 out[AES_BLOCK_SIZE],
+ const u8 in[AES_BLOCK_SIZE])
+{
+ if (static_branch_likely(&have_aes) && irq_fpu_usable()) {
+ kernel_fpu_begin();
+ aes_decrypt_aesni(key->inv_k.inv_rndkeys, key->nrounds,
+ out, in);
+ kernel_fpu_end();
+ } else {
+ aes_decrypt_generic(key->inv_k.inv_rndkeys, key->nrounds,
+ out, in);
+ }
+}
+
+#define aes_mod_init_arch aes_mod_init_arch
+static void aes_mod_init_arch(void)
+{
+ if (boot_cpu_has(X86_FEATURE_AES))
+ static_branch_enable(&have_aes);
+}
diff --git a/lib/crypto/x86/nh-avx2.S b/lib/crypto/x86/nh-avx2.S
new file mode 100644
index 000000000000..9c085a31b137
--- /dev/null
+++ b/lib/crypto/x86/nh-avx2.S
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NH - ε-almost-universal hash function, x86_64 AVX2 accelerated
+ *
+ * Copyright 2018 Google LLC
+ *
+ * Author: Eric Biggers <ebiggers@google.com>
+ */
+
+#include <linux/linkage.h>
+
+#define PASS0_SUMS %ymm0
+#define PASS1_SUMS %ymm1
+#define PASS2_SUMS %ymm2
+#define PASS3_SUMS %ymm3
+#define K0 %ymm4
+#define K0_XMM %xmm4
+#define K1 %ymm5
+#define K1_XMM %xmm5
+#define K2 %ymm6
+#define K2_XMM %xmm6
+#define K3 %ymm7
+#define K3_XMM %xmm7
+#define T0 %ymm8
+#define T1 %ymm9
+#define T2 %ymm10
+#define T2_XMM %xmm10
+#define T3 %ymm11
+#define T3_XMM %xmm11
+#define T4 %ymm12
+#define T5 %ymm13
+#define T6 %ymm14
+#define T7 %ymm15
+#define KEY %rdi
+#define MESSAGE %rsi
+#define MESSAGE_LEN %rdx
+#define HASH %rcx
+
+.macro _nh_2xstride k0, k1, k2, k3
+
+ // Add message words to key words
+ vpaddd \k0, T3, T0
+ vpaddd \k1, T3, T1
+ vpaddd \k2, T3, T2
+ vpaddd \k3, T3, T3
+
+ // Multiply 32x32 => 64 and accumulate
+ vpshufd $0x10, T0, T4
+ vpshufd $0x32, T0, T0
+ vpshufd $0x10, T1, T5
+ vpshufd $0x32, T1, T1
+ vpshufd $0x10, T2, T6
+ vpshufd $0x32, T2, T2
+ vpshufd $0x10, T3, T7
+ vpshufd $0x32, T3, T3
+ vpmuludq T4, T0, T0
+ vpmuludq T5, T1, T1
+ vpmuludq T6, T2, T2
+ vpmuludq T7, T3, T3
+ vpaddq T0, PASS0_SUMS, PASS0_SUMS
+ vpaddq T1, PASS1_SUMS, PASS1_SUMS
+ vpaddq T2, PASS2_SUMS, PASS2_SUMS
+ vpaddq T3, PASS3_SUMS, PASS3_SUMS
+.endm
+
+/*
+ * void nh_avx2(const u32 *key, const u8 *message, size_t message_len,
+ * __le64 hash[NH_NUM_PASSES])
+ *
+ * It's guaranteed that message_len % 16 == 0.
+ */
+SYM_FUNC_START(nh_avx2)
+
+ vmovdqu 0x00(KEY), K0
+ vmovdqu 0x10(KEY), K1
+ add $0x20, KEY
+ vpxor PASS0_SUMS, PASS0_SUMS, PASS0_SUMS
+ vpxor PASS1_SUMS, PASS1_SUMS, PASS1_SUMS
+ vpxor PASS2_SUMS, PASS2_SUMS, PASS2_SUMS
+ vpxor PASS3_SUMS, PASS3_SUMS, PASS3_SUMS
+
+ sub $0x40, MESSAGE_LEN
+ jl .Lloop4_done
+.Lloop4:
+ vmovdqu (MESSAGE), T3
+ vmovdqu 0x00(KEY), K2
+ vmovdqu 0x10(KEY), K3
+ _nh_2xstride K0, K1, K2, K3
+
+ vmovdqu 0x20(MESSAGE), T3
+ vmovdqu 0x20(KEY), K0
+ vmovdqu 0x30(KEY), K1
+ _nh_2xstride K2, K3, K0, K1
+
+ add $0x40, MESSAGE
+ add $0x40, KEY
+ sub $0x40, MESSAGE_LEN
+ jge .Lloop4
+
+.Lloop4_done:
+ and $0x3f, MESSAGE_LEN
+ jz .Ldone
+
+ cmp $0x20, MESSAGE_LEN
+ jl .Llast
+
+ // 2 or 3 strides remain; do 2 more.
+ vmovdqu (MESSAGE), T3
+ vmovdqu 0x00(KEY), K2
+ vmovdqu 0x10(KEY), K3
+ _nh_2xstride K0, K1, K2, K3
+ add $0x20, MESSAGE
+ add $0x20, KEY
+ sub $0x20, MESSAGE_LEN
+ jz .Ldone
+ vmovdqa K2, K0
+ vmovdqa K3, K1
+.Llast:
+ // Last stride. Zero the high 128 bits of the message and keys so they
+ // don't affect the result when processing them like 2 strides.
+ vmovdqu (MESSAGE), T3_XMM
+ vmovdqa K0_XMM, K0_XMM
+ vmovdqa K1_XMM, K1_XMM
+ vmovdqu 0x00(KEY), K2_XMM
+ vmovdqu 0x10(KEY), K3_XMM
+ _nh_2xstride K0, K1, K2, K3
+
+.Ldone:
+ // Sum the accumulators for each pass, then store the sums to 'hash'
+
+ // PASS0_SUMS is (0A 0B 0C 0D)
+ // PASS1_SUMS is (1A 1B 1C 1D)
+ // PASS2_SUMS is (2A 2B 2C 2D)
+ // PASS3_SUMS is (3A 3B 3C 3D)
+ // We need the horizontal sums:
+ // (0A + 0B + 0C + 0D,
+ // 1A + 1B + 1C + 1D,
+ // 2A + 2B + 2C + 2D,
+ // 3A + 3B + 3C + 3D)
+ //
+
+ vpunpcklqdq PASS1_SUMS, PASS0_SUMS, T0 // T0 = (0A 1A 0C 1C)
+ vpunpckhqdq PASS1_SUMS, PASS0_SUMS, T1 // T1 = (0B 1B 0D 1D)
+ vpunpcklqdq PASS3_SUMS, PASS2_SUMS, T2 // T2 = (2A 3A 2C 3C)
+ vpunpckhqdq PASS3_SUMS, PASS2_SUMS, T3 // T3 = (2B 3B 2D 3D)
+
+ vinserti128 $0x1, T2_XMM, T0, T4 // T4 = (0A 1A 2A 3A)
+ vinserti128 $0x1, T3_XMM, T1, T5 // T5 = (0B 1B 2B 3B)
+ vperm2i128 $0x31, T2, T0, T0 // T0 = (0C 1C 2C 3C)
+ vperm2i128 $0x31, T3, T1, T1 // T1 = (0D 1D 2D 3D)
+
+ vpaddq T5, T4, T4
+ vpaddq T1, T0, T0
+ vpaddq T4, T0, T0
+ vmovdqu T0, (HASH)
+ vzeroupper
+ RET
+SYM_FUNC_END(nh_avx2)
diff --git a/lib/crypto/x86/nh-sse2.S b/lib/crypto/x86/nh-sse2.S
new file mode 100644
index 000000000000..d36c0e6d5556
--- /dev/null
+++ b/lib/crypto/x86/nh-sse2.S
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NH - ε-almost-universal hash function, x86_64 SSE2 accelerated
+ *
+ * Copyright 2018 Google LLC
+ *
+ * Author: Eric Biggers <ebiggers@google.com>
+ */
+
+#include <linux/linkage.h>
+
+#define PASS0_SUMS %xmm0
+#define PASS1_SUMS %xmm1
+#define PASS2_SUMS %xmm2
+#define PASS3_SUMS %xmm3
+#define K0 %xmm4
+#define K1 %xmm5
+#define K2 %xmm6
+#define K3 %xmm7
+#define T0 %xmm8
+#define T1 %xmm9
+#define T2 %xmm10
+#define T3 %xmm11
+#define T4 %xmm12
+#define T5 %xmm13
+#define T6 %xmm14
+#define T7 %xmm15
+#define KEY %rdi
+#define MESSAGE %rsi
+#define MESSAGE_LEN %rdx
+#define HASH %rcx
+
+.macro _nh_stride k0, k1, k2, k3, offset
+
+ // Load next message stride
+ movdqu \offset(MESSAGE), T1
+
+ // Load next key stride
+ movdqu \offset(KEY), \k3
+
+ // Add message words to key words
+ movdqa T1, T2
+ movdqa T1, T3
+ paddd T1, \k0 // reuse k0 to avoid a move
+ paddd \k1, T1
+ paddd \k2, T2
+ paddd \k3, T3
+
+ // Multiply 32x32 => 64 and accumulate
+ pshufd $0x10, \k0, T4
+ pshufd $0x32, \k0, \k0
+ pshufd $0x10, T1, T5
+ pshufd $0x32, T1, T1
+ pshufd $0x10, T2, T6
+ pshufd $0x32, T2, T2
+ pshufd $0x10, T3, T7
+ pshufd $0x32, T3, T3
+ pmuludq T4, \k0
+ pmuludq T5, T1
+ pmuludq T6, T2
+ pmuludq T7, T3
+ paddq \k0, PASS0_SUMS
+ paddq T1, PASS1_SUMS
+ paddq T2, PASS2_SUMS
+ paddq T3, PASS3_SUMS
+.endm
+
+/*
+ * void nh_sse2(const u32 *key, const u8 *message, size_t message_len,
+ * __le64 hash[NH_NUM_PASSES])
+ *
+ * It's guaranteed that message_len % 16 == 0.
+ */
+SYM_FUNC_START(nh_sse2)
+
+ movdqu 0x00(KEY), K0
+ movdqu 0x10(KEY), K1
+ movdqu 0x20(KEY), K2
+ add $0x30, KEY
+ pxor PASS0_SUMS, PASS0_SUMS
+ pxor PASS1_SUMS, PASS1_SUMS
+ pxor PASS2_SUMS, PASS2_SUMS
+ pxor PASS3_SUMS, PASS3_SUMS
+
+ sub $0x40, MESSAGE_LEN
+ jl .Lloop4_done
+.Lloop4:
+ _nh_stride K0, K1, K2, K3, 0x00
+ _nh_stride K1, K2, K3, K0, 0x10
+ _nh_stride K2, K3, K0, K1, 0x20
+ _nh_stride K3, K0, K1, K2, 0x30
+ add $0x40, KEY
+ add $0x40, MESSAGE
+ sub $0x40, MESSAGE_LEN
+ jge .Lloop4
+
+.Lloop4_done:
+ and $0x3f, MESSAGE_LEN
+ jz .Ldone
+ _nh_stride K0, K1, K2, K3, 0x00
+
+ sub $0x10, MESSAGE_LEN
+ jz .Ldone
+ _nh_stride K1, K2, K3, K0, 0x10
+
+ sub $0x10, MESSAGE_LEN
+ jz .Ldone
+ _nh_stride K2, K3, K0, K1, 0x20
+
+.Ldone:
+ // Sum the accumulators for each pass, then store the sums to 'hash'
+ movdqa PASS0_SUMS, T0
+ movdqa PASS2_SUMS, T1
+ punpcklqdq PASS1_SUMS, T0 // => (PASS0_SUM_A PASS1_SUM_A)
+ punpcklqdq PASS3_SUMS, T1 // => (PASS2_SUM_A PASS3_SUM_A)
+ punpckhqdq PASS1_SUMS, PASS0_SUMS // => (PASS0_SUM_B PASS1_SUM_B)
+ punpckhqdq PASS3_SUMS, PASS2_SUMS // => (PASS2_SUM_B PASS3_SUM_B)
+ paddq PASS0_SUMS, T0
+ paddq PASS2_SUMS, T1
+ movdqu T0, 0x00(HASH)
+ movdqu T1, 0x10(HASH)
+ RET
+SYM_FUNC_END(nh_sse2)
diff --git a/lib/crypto/x86/nh.h b/lib/crypto/x86/nh.h
new file mode 100644
index 000000000000..83361c2e9783
--- /dev/null
+++ b/lib/crypto/x86/nh.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * x86_64 accelerated implementation of NH
+ *
+ * Copyright 2018 Google LLC
+ */
+
+#include <asm/fpu/api.h>
+#include <linux/static_call.h>
+
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_sse2);
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_avx2);
+
+asmlinkage void nh_sse2(const u32 *key, const u8 *message, size_t message_len,
+ __le64 hash[NH_NUM_PASSES]);
+asmlinkage void nh_avx2(const u32 *key, const u8 *message, size_t message_len,
+ __le64 hash[NH_NUM_PASSES]);
+
+static bool nh_arch(const u32 *key, const u8 *message, size_t message_len,
+ __le64 hash[NH_NUM_PASSES])
+{
+ if (message_len >= 64 && static_branch_likely(&have_sse2) &&
+ irq_fpu_usable()) {
+ kernel_fpu_begin();
+ if (static_branch_likely(&have_avx2))
+ nh_avx2(key, message, message_len, hash);
+ else
+ nh_sse2(key, message, message_len, hash);
+ kernel_fpu_end();
+ return true;
+ }
+ return false;
+}
+
+#define nh_mod_init_arch nh_mod_init_arch
+static void nh_mod_init_arch(void)
+{
+ if (boot_cpu_has(X86_FEATURE_XMM2)) {
+ static_branch_enable(&have_sse2);
+ if (boot_cpu_has(X86_FEATURE_AVX2) &&
+ cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM,
+ NULL))
+ static_branch_enable(&have_avx2);
+ }
+}
diff --git a/lib/dec_and_lock.c b/lib/dec_and_lock.c
index 1dcca8f2e194..8c7c398fd770 100644
--- a/lib/dec_and_lock.c
+++ b/lib/dec_and_lock.c
@@ -18,7 +18,7 @@
* because the spin-lock and the decrement must be
* "atomic".
*/
-int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
{
/* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
if (atomic_add_unless(atomic, -1, 1))
@@ -32,7 +32,7 @@ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
return 0;
}
-EXPORT_SYMBOL(_atomic_dec_and_lock);
+EXPORT_SYMBOL(atomic_dec_and_lock);
int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock,
unsigned long *flags)
@@ -50,7 +50,7 @@ int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock,
}
EXPORT_SYMBOL(_atomic_dec_and_lock_irqsave);
-int _atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock)
+int atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock)
{
/* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
if (atomic_add_unless(atomic, -1, 1))
@@ -63,7 +63,7 @@ int _atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock)
raw_spin_unlock(lock);
return 0;
}
-EXPORT_SYMBOL(_atomic_dec_and_raw_lock);
+EXPORT_SYMBOL(atomic_dec_and_raw_lock);
int _atomic_dec_and_raw_lock_irqsave(atomic_t *atomic, raw_spinlock_t *lock,
unsigned long *flags)
diff --git a/lib/decompress_unxz.c b/lib/decompress_unxz.c
index 32138bb8ef77..05d5cb490a44 100644
--- a/lib/decompress_unxz.c
+++ b/lib/decompress_unxz.c
@@ -157,11 +157,11 @@
* when XZ_DYNALLOC is used, but the pre-boot free() doesn't support it.
* Workaround it here because the other decompressors don't need it.
*/
-#undef kmalloc
+#undef kmalloc_obj
#undef kfree
#undef vmalloc
#undef vfree
-#define kmalloc(size, flags) malloc(size)
+#define kmalloc_obj(type) malloc(sizeof(type))
#define kfree(ptr) free(ptr)
#define vmalloc(size) malloc(size)
#define vfree(ptr) do { if (ptr != NULL) free(ptr); } while (0)
diff --git a/lib/dhry_1.c b/lib/dhry_1.c
index ca6c87232c58..134cc1c746c2 100644
--- a/lib/dhry_1.c
+++ b/lib/dhry_1.c
@@ -139,11 +139,11 @@ int dhry(int n)
/* Initializations */
- Next_Ptr_Glob = (Rec_Pointer)kzalloc(sizeof(Rec_Type), GFP_ATOMIC);
+ Next_Ptr_Glob = (Rec_Pointer) kzalloc_obj(Rec_Type, GFP_ATOMIC);
if (!Next_Ptr_Glob)
return -ENOMEM;
- Ptr_Glob = (Rec_Pointer)kzalloc(sizeof(Rec_Type), GFP_ATOMIC);
+ Ptr_Glob = (Rec_Pointer) kzalloc_obj(Rec_Type, GFP_ATOMIC);
if (!Ptr_Glob) {
kfree(Next_Ptr_Glob);
return -ENOMEM;
diff --git a/lib/dim/net_dim.c b/lib/dim/net_dim.c
index d6aa09a979b3..d8d4f6553559 100644
--- a/lib/dim/net_dim.c
+++ b/lib/dim/net_dim.c
@@ -105,7 +105,7 @@ int net_dim_init_irq_moder(struct net_device *dev, u8 profile_flags,
struct dim_irq_moder *moder;
int len;
- dev->irq_moder = kzalloc(sizeof(*dev->irq_moder), GFP_KERNEL);
+ dev->irq_moder = kzalloc_obj(*dev->irq_moder);
if (!dev->irq_moder)
return -ENOMEM;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 7d7892e57a01..18a71a9108d3 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1241,7 +1241,7 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
return 0;
}
- dt = kzalloc(sizeof(*dt), GFP_KERNEL);
+ dt = kzalloc_obj(*dt);
if (dt == NULL) {
pr_err("error adding module: %s\n", modname);
return -ENOMEM;
diff --git a/lib/error-inject.c b/lib/error-inject.c
index 887acd9a6ea6..f3d1b70be605 100644
--- a/lib/error-inject.c
+++ b/lib/error-inject.c
@@ -80,7 +80,7 @@ static void populate_error_injection_list(struct error_injection_entry *start,
continue;
}
- ent = kmalloc(sizeof(*ent), GFP_KERNEL);
+ ent = kmalloc_obj(*ent);
if (!ent)
break;
ent->start_addr = entry;
diff --git a/lib/find_bit.c b/lib/find_bit.c
index d4b5a29e3e72..5a0066c26d9a 100644
--- a/lib/find_bit.c
+++ b/lib/find_bit.c
@@ -71,7 +71,7 @@ out: \
#define FIND_NTH_BIT(FETCH, size, num) \
({ \
- unsigned long sz = (size), nr = (num), idx, w, tmp; \
+ unsigned long sz = (size), nr = (num), idx, w, tmp = 0; \
\
for (idx = 0; (idx + 1) * BITS_PER_LONG <= sz; idx++) { \
if (idx * BITS_PER_LONG + nr >= sz) \
diff --git a/lib/flex_proportions.c b/lib/flex_proportions.c
index 84ecccddc771..012d5614efb9 100644
--- a/lib/flex_proportions.c
+++ b/lib/flex_proportions.c
@@ -64,13 +64,14 @@ void fprop_global_destroy(struct fprop_global *p)
bool fprop_new_period(struct fprop_global *p, int periods)
{
s64 events = percpu_counter_sum(&p->events);
+ unsigned long flags;
/*
* Don't do anything if there are no events.
*/
if (events <= 1)
return false;
- preempt_disable_nested();
+ local_irq_save(flags);
write_seqcount_begin(&p->sequence);
if (periods < 64)
events -= events >> periods;
@@ -78,7 +79,7 @@ bool fprop_new_period(struct fprop_global *p, int periods)
percpu_counter_add(&p->events, -events);
p->period += periods;
write_seqcount_end(&p->sequence);
- preempt_enable_nested();
+ local_irq_restore(flags);
return true;
}
diff --git a/lib/globtest.c b/lib/globtest.c
deleted file mode 100644
index d8e97d43b905..000000000000
--- a/lib/globtest.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Extracted fronm glob.c
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/glob.h>
-#include <linux/printk.h>
-
-/* Boot with "glob.verbose=1" to show successful tests, too */
-static bool verbose = false;
-module_param(verbose, bool, 0);
-
-struct glob_test {
- char const *pat, *str;
- bool expected;
-};
-
-static bool __pure __init test(char const *pat, char const *str, bool expected)
-{
- bool match = glob_match(pat, str);
- bool success = match == expected;
-
- /* Can't get string literals into a particular section, so... */
- static char const msg_error[] __initconst =
- KERN_ERR "glob: \"%s\" vs. \"%s\": %s *** ERROR ***\n";
- static char const msg_ok[] __initconst =
- KERN_DEBUG "glob: \"%s\" vs. \"%s\": %s OK\n";
- static char const mismatch[] __initconst = "mismatch";
- char const *message;
-
- if (!success)
- message = msg_error;
- else if (verbose)
- message = msg_ok;
- else
- return success;
-
- printk(message, pat, str, mismatch + 3*match);
- return success;
-}
-
-/*
- * The tests are all jammed together in one array to make it simpler
- * to place that array in the .init.rodata section. The obvious
- * "array of structures containing char *" has no way to force the
- * pointed-to strings to be in a particular section.
- *
- * Anyway, a test consists of:
- * 1. Expected glob_match result: '1' or '0'.
- * 2. Pattern to match: null-terminated string
- * 3. String to match against: null-terminated string
- *
- * The list of tests is terminated with a final '\0' instead of
- * a glob_match result character.
- */
-static char const glob_tests[] __initconst =
- /* Some basic tests */
- "1" "a\0" "a\0"
- "0" "a\0" "b\0"
- "0" "a\0" "aa\0"
- "0" "a\0" "\0"
- "1" "\0" "\0"
- "0" "\0" "a\0"
- /* Simple character class tests */
- "1" "[a]\0" "a\0"
- "0" "[a]\0" "b\0"
- "0" "[!a]\0" "a\0"
- "1" "[!a]\0" "b\0"
- "1" "[ab]\0" "a\0"
- "1" "[ab]\0" "b\0"
- "0" "[ab]\0" "c\0"
- "1" "[!ab]\0" "c\0"
- "1" "[a-c]\0" "b\0"
- "0" "[a-c]\0" "d\0"
- /* Corner cases in character class parsing */
- "1" "[a-c-e-g]\0" "-\0"
- "0" "[a-c-e-g]\0" "d\0"
- "1" "[a-c-e-g]\0" "f\0"
- "1" "[]a-ceg-ik[]\0" "a\0"
- "1" "[]a-ceg-ik[]\0" "]\0"
- "1" "[]a-ceg-ik[]\0" "[\0"
- "1" "[]a-ceg-ik[]\0" "h\0"
- "0" "[]a-ceg-ik[]\0" "f\0"
- "0" "[!]a-ceg-ik[]\0" "h\0"
- "0" "[!]a-ceg-ik[]\0" "]\0"
- "1" "[!]a-ceg-ik[]\0" "f\0"
- /* Simple wild cards */
- "1" "?\0" "a\0"
- "0" "?\0" "aa\0"
- "0" "??\0" "a\0"
- "1" "?x?\0" "axb\0"
- "0" "?x?\0" "abx\0"
- "0" "?x?\0" "xab\0"
- /* Asterisk wild cards (backtracking) */
- "0" "*??\0" "a\0"
- "1" "*??\0" "ab\0"
- "1" "*??\0" "abc\0"
- "1" "*??\0" "abcd\0"
- "0" "??*\0" "a\0"
- "1" "??*\0" "ab\0"
- "1" "??*\0" "abc\0"
- "1" "??*\0" "abcd\0"
- "0" "?*?\0" "a\0"
- "1" "?*?\0" "ab\0"
- "1" "?*?\0" "abc\0"
- "1" "?*?\0" "abcd\0"
- "1" "*b\0" "b\0"
- "1" "*b\0" "ab\0"
- "0" "*b\0" "ba\0"
- "1" "*b\0" "bb\0"
- "1" "*b\0" "abb\0"
- "1" "*b\0" "bab\0"
- "1" "*bc\0" "abbc\0"
- "1" "*bc\0" "bc\0"
- "1" "*bc\0" "bbc\0"
- "1" "*bc\0" "bcbc\0"
- /* Multiple asterisks (complex backtracking) */
- "1" "*ac*\0" "abacadaeafag\0"
- "1" "*ac*ae*ag*\0" "abacadaeafag\0"
- "1" "*a*b*[bc]*[ef]*g*\0" "abacadaeafag\0"
- "0" "*a*b*[ef]*[cd]*g*\0" "abacadaeafag\0"
- "1" "*abcd*\0" "abcabcabcabcdefg\0"
- "1" "*ab*cd*\0" "abcabcabcabcdefg\0"
- "1" "*abcd*abcdef*\0" "abcabcdabcdeabcdefg\0"
- "0" "*abcd*\0" "abcabcabcabcefg\0"
- "0" "*ab*cd*\0" "abcabcabcabcefg\0";
-
-static int __init glob_init(void)
-{
- unsigned successes = 0;
- unsigned n = 0;
- char const *p = glob_tests;
- static char const message[] __initconst =
- KERN_INFO "glob: %u self-tests passed, %u failed\n";
-
- /*
- * Tests are jammed together in a string. The first byte is '1'
- * or '0' to indicate the expected outcome, or '\0' to indicate the
- * end of the tests. Then come two null-terminated strings: the
- * pattern and the string to match it against.
- */
- while (*p) {
- bool expected = *p++ & 1;
- char const *pat = p;
-
- p += strlen(p) + 1;
- successes += test(pat, p, expected);
- p += strlen(p) + 1;
- n++;
- }
-
- n -= successes;
- printk(message, successes, n);
-
- /* What's the errno for "kernel bug detected"? Guess... */
- return n ? -ECANCELED : 0;
-}
-
-/* We need a dummy exit function to allow unload */
-static void __exit glob_fini(void) { }
-
-module_init(glob_init);
-module_exit(glob_fini);
-
-MODULE_DESCRIPTION("glob(7) matching tests");
-MODULE_LICENSE("Dual MIT/GPL");
diff --git a/lib/group_cpus.c b/lib/group_cpus.c
index 6d08ac05f371..e6e18d7a49bb 100644
--- a/lib/group_cpus.c
+++ b/lib/group_cpus.c
@@ -47,7 +47,7 @@ static cpumask_var_t *alloc_node_to_cpumask(void)
cpumask_var_t *masks;
int node;
- masks = kcalloc(nr_node_ids, sizeof(cpumask_var_t), GFP_KERNEL);
+ masks = kzalloc_objs(cpumask_var_t, nr_node_ids);
if (!masks)
return NULL;
@@ -114,48 +114,15 @@ static int ncpus_cmp_func(const void *l, const void *r)
return ln->ncpus - rn->ncpus;
}
-/*
- * Allocate group number for each node, so that for each node:
- *
- * 1) the allocated number is >= 1
- *
- * 2) the allocated number is <= active CPU number of this node
- *
- * The actual allocated total groups may be less than @numgrps when
- * active total CPU number is less than @numgrps.
- *
- * Active CPUs means the CPUs in '@cpu_mask AND @node_to_cpumask[]'
- * for each node.
- */
-static void alloc_nodes_groups(unsigned int numgrps,
- cpumask_var_t *node_to_cpumask,
- const struct cpumask *cpu_mask,
- const nodemask_t nodemsk,
- struct cpumask *nmsk,
- struct node_groups *node_groups)
+static void alloc_groups_to_nodes(unsigned int numgrps,
+ unsigned int numcpus,
+ struct node_groups *node_groups,
+ unsigned int num_nodes)
{
- unsigned n, remaining_ncpus = 0;
-
- for (n = 0; n < nr_node_ids; n++) {
- node_groups[n].id = n;
- node_groups[n].ncpus = UINT_MAX;
- }
-
- for_each_node_mask(n, nodemsk) {
- unsigned ncpus;
-
- cpumask_and(nmsk, cpu_mask, node_to_cpumask[n]);
- ncpus = cpumask_weight(nmsk);
-
- if (!ncpus)
- continue;
- remaining_ncpus += ncpus;
- node_groups[n].ncpus = ncpus;
- }
+ unsigned int n, remaining_ncpus = numcpus;
+ unsigned int ngroups, ncpus;
- numgrps = min_t(unsigned, remaining_ncpus, numgrps);
-
- sort(node_groups, nr_node_ids, sizeof(node_groups[0]),
+ sort(node_groups, num_nodes, sizeof(node_groups[0]),
ncpus_cmp_func, NULL);
/*
@@ -226,9 +193,8 @@ static void alloc_nodes_groups(unsigned int numgrps,
* finally for each node X: grps(X) <= ncpu(X).
*
*/
- for (n = 0; n < nr_node_ids; n++) {
- unsigned ngroups, ncpus;
+ for (n = 0; n < num_nodes; n++) {
if (node_groups[n].ncpus == UINT_MAX)
continue;
@@ -246,12 +212,201 @@ static void alloc_nodes_groups(unsigned int numgrps,
}
}
+/*
+ * Allocate group number for each node, so that for each node:
+ *
+ * 1) the allocated number is >= 1
+ *
+ * 2) the allocated number is <= active CPU number of this node
+ *
+ * The actual allocated total groups may be less than @numgrps when
+ * active total CPU number is less than @numgrps.
+ *
+ * Active CPUs means the CPUs in '@cpu_mask AND @node_to_cpumask[]'
+ * for each node.
+ */
+static void alloc_nodes_groups(unsigned int numgrps,
+ cpumask_var_t *node_to_cpumask,
+ const struct cpumask *cpu_mask,
+ const nodemask_t nodemsk,
+ struct cpumask *nmsk,
+ struct node_groups *node_groups)
+{
+ unsigned int n, numcpus = 0;
+
+ for (n = 0; n < nr_node_ids; n++) {
+ node_groups[n].id = n;
+ node_groups[n].ncpus = UINT_MAX;
+ }
+
+ for_each_node_mask(n, nodemsk) {
+ unsigned int ncpus;
+
+ cpumask_and(nmsk, cpu_mask, node_to_cpumask[n]);
+ ncpus = cpumask_weight(nmsk);
+
+ if (!ncpus)
+ continue;
+ numcpus += ncpus;
+ node_groups[n].ncpus = ncpus;
+ }
+
+ numgrps = min_t(unsigned int, numcpus, numgrps);
+ alloc_groups_to_nodes(numgrps, numcpus, node_groups, nr_node_ids);
+}
+
+static void assign_cpus_to_groups(unsigned int ncpus,
+ struct cpumask *nmsk,
+ struct node_groups *nv,
+ struct cpumask *masks,
+ unsigned int *curgrp,
+ unsigned int last_grp)
+{
+ unsigned int v, cpus_per_grp, extra_grps;
+ /* Account for rounding errors */
+ extra_grps = ncpus - nv->ngroups * (ncpus / nv->ngroups);
+
+ /* Spread allocated groups on CPUs of the current node */
+ for (v = 0; v < nv->ngroups; v++, *curgrp += 1) {
+ cpus_per_grp = ncpus / nv->ngroups;
+
+ /* Account for extra groups to compensate rounding errors */
+ if (extra_grps) {
+ cpus_per_grp++;
+ --extra_grps;
+ }
+
+ /*
+ * wrapping has to be considered given 'startgrp'
+ * may start anywhere
+ */
+ if (*curgrp >= last_grp)
+ *curgrp = 0;
+ grp_spread_init_one(&masks[*curgrp], nmsk, cpus_per_grp);
+ }
+}
+
+static int alloc_cluster_groups(unsigned int ncpus,
+ unsigned int ngroups,
+ struct cpumask *node_cpumask,
+ cpumask_var_t msk,
+ const struct cpumask ***clusters_ptr,
+ struct node_groups **cluster_groups_ptr)
+{
+ unsigned int ncluster = 0;
+ unsigned int cpu, nc, n;
+ const struct cpumask *cluster_mask;
+ const struct cpumask **clusters;
+ struct node_groups *cluster_groups;
+
+ cpumask_copy(msk, node_cpumask);
+
+ /* Probe how many clusters in this node. */
+ while (1) {
+ cpu = cpumask_first(msk);
+ if (cpu >= nr_cpu_ids)
+ break;
+
+ cluster_mask = topology_cluster_cpumask(cpu);
+ if (!cpumask_weight(cluster_mask))
+ goto no_cluster;
+ /* Clean out CPUs on the same cluster. */
+ cpumask_andnot(msk, msk, cluster_mask);
+ ncluster++;
+ }
+
+ /* If ngroups < ncluster, cross cluster is inevitable, skip. */
+ if (ncluster == 0 || ncluster > ngroups)
+ goto no_cluster;
+
+ /* Allocate memory based on cluster number. */
+ clusters = kzalloc_objs(*clusters, ncluster);
+ if (!clusters)
+ goto no_cluster;
+ cluster_groups = kzalloc_objs(struct node_groups, ncluster);
+ if (!cluster_groups)
+ goto fail_cluster_groups;
+
+ /* Filling cluster info for later process. */
+ cpumask_copy(msk, node_cpumask);
+ for (n = 0; n < ncluster; n++) {
+ cpu = cpumask_first(msk);
+ cluster_mask = topology_cluster_cpumask(cpu);
+ nc = cpumask_weight_and(cluster_mask, node_cpumask);
+ clusters[n] = cluster_mask;
+ cluster_groups[n].id = n;
+ cluster_groups[n].ncpus = nc;
+ cpumask_andnot(msk, msk, cluster_mask);
+ }
+
+ alloc_groups_to_nodes(ngroups, ncpus, cluster_groups, ncluster);
+
+ *clusters_ptr = clusters;
+ *cluster_groups_ptr = cluster_groups;
+ return ncluster;
+
+ fail_cluster_groups:
+ kfree(clusters);
+ no_cluster:
+ return 0;
+}
+
+/*
+ * Try group CPUs evenly for cluster locality within a NUMA node.
+ *
+ * Return: true if success, false otherwise.
+ */
+static bool __try_group_cluster_cpus(unsigned int ncpus,
+ unsigned int ngroups,
+ struct cpumask *node_cpumask,
+ struct cpumask *masks,
+ unsigned int *curgrp,
+ unsigned int last_grp)
+{
+ struct node_groups *cluster_groups;
+ const struct cpumask **clusters;
+ unsigned int ncluster;
+ bool ret = false;
+ cpumask_var_t nmsk;
+ unsigned int i, nc;
+
+ if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL))
+ goto fail_nmsk_alloc;
+
+ ncluster = alloc_cluster_groups(ncpus, ngroups, node_cpumask, nmsk,
+ &clusters, &cluster_groups);
+
+ if (ncluster == 0)
+ goto fail_no_clusters;
+
+ for (i = 0; i < ncluster; i++) {
+ struct node_groups *nv = &cluster_groups[i];
+
+ /* Get the cpus on this cluster. */
+ cpumask_and(nmsk, node_cpumask, clusters[nv->id]);
+ nc = cpumask_weight(nmsk);
+ if (!nc)
+ continue;
+ WARN_ON_ONCE(nv->ngroups > nc);
+
+ assign_cpus_to_groups(nc, nmsk, nv, masks, curgrp, last_grp);
+ }
+
+ ret = true;
+ kfree(cluster_groups);
+ kfree(clusters);
+ fail_no_clusters:
+ free_cpumask_var(nmsk);
+ fail_nmsk_alloc:
+ return ret;
+}
+
static int __group_cpus_evenly(unsigned int startgrp, unsigned int numgrps,
cpumask_var_t *node_to_cpumask,
const struct cpumask *cpu_mask,
struct cpumask *nmsk, struct cpumask *masks)
{
- unsigned int i, n, nodes, cpus_per_grp, extra_grps, done = 0;
+ unsigned int i, n, nodes, done = 0;
unsigned int last_grp = numgrps;
unsigned int curgrp = startgrp;
nodemask_t nodemsk = NODE_MASK_NONE;
@@ -277,9 +432,7 @@ static int __group_cpus_evenly(unsigned int startgrp, unsigned int numgrps,
return numgrps;
}
- node_groups = kcalloc(nr_node_ids,
- sizeof(struct node_groups),
- GFP_KERNEL);
+ node_groups = kzalloc_objs(struct node_groups, nr_node_ids);
if (!node_groups)
return -ENOMEM;
@@ -287,7 +440,7 @@ static int __group_cpus_evenly(unsigned int startgrp, unsigned int numgrps,
alloc_nodes_groups(numgrps, node_to_cpumask, cpu_mask,
nodemsk, nmsk, node_groups);
for (i = 0; i < nr_node_ids; i++) {
- unsigned int ncpus, v;
+ unsigned int ncpus;
struct node_groups *nv = &node_groups[i];
if (nv->ngroups == UINT_MAX)
@@ -301,28 +454,14 @@ static int __group_cpus_evenly(unsigned int startgrp, unsigned int numgrps,
WARN_ON_ONCE(nv->ngroups > ncpus);
- /* Account for rounding errors */
- extra_grps = ncpus - nv->ngroups * (ncpus / nv->ngroups);
-
- /* Spread allocated groups on CPUs of the current node */
- for (v = 0; v < nv->ngroups; v++, curgrp++) {
- cpus_per_grp = ncpus / nv->ngroups;
-
- /* Account for extra groups to compensate rounding errors */
- if (extra_grps) {
- cpus_per_grp++;
- --extra_grps;
- }
-
- /*
- * wrapping has to be considered given 'startgrp'
- * may start anywhere
- */
- if (curgrp >= last_grp)
- curgrp = 0;
- grp_spread_init_one(&masks[curgrp], nmsk,
- cpus_per_grp);
+ if (__try_group_cluster_cpus(ncpus, nv->ngroups, nmsk,
+ masks, &curgrp, last_grp)) {
+ done += nv->ngroups;
+ continue;
}
+
+ assign_cpus_to_groups(ncpus, nmsk, nv, masks, &curgrp,
+ last_grp);
done += nv->ngroups;
}
kfree(node_groups);
@@ -367,7 +506,7 @@ struct cpumask *group_cpus_evenly(unsigned int numgrps, unsigned int *nummasks)
if (!node_to_cpumask)
goto fail_npresmsk;
- masks = kcalloc(numgrps, sizeof(*masks), GFP_KERNEL);
+ masks = kzalloc_objs(*masks, numgrps);
if (!masks)
goto fail_node_to_cpumask;
@@ -433,7 +572,7 @@ struct cpumask *group_cpus_evenly(unsigned int numgrps, unsigned int *nummasks)
if (numgrps == 0)
return NULL;
- masks = kcalloc(numgrps, sizeof(*masks), GFP_KERNEL);
+ masks = kzalloc_objs(*masks, numgrps);
if (!masks)
return NULL;
diff --git a/lib/hexdump.c b/lib/hexdump.c
index c3db7c3a7643..2e5cd8c24769 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -6,6 +6,7 @@
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/errno.h>
+#include <linux/hex.h>
#include <linux/kernel.h>
#include <linux/minmax.h>
#include <linux/export.h>
diff --git a/lib/idr.c b/lib/idr.c
index 457430cff8c5..69bee5369670 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -417,7 +417,7 @@ next:
}
bitmap = alloc;
if (!bitmap)
- bitmap = kzalloc(sizeof(*bitmap), GFP_NOWAIT);
+ bitmap = kzalloc_obj(*bitmap, GFP_NOWAIT);
if (!bitmap)
goto alloc;
bitmap->bitmap[0] = tmp;
@@ -444,7 +444,7 @@ next:
} else {
bitmap = alloc;
if (!bitmap)
- bitmap = kzalloc(sizeof(*bitmap), GFP_NOWAIT);
+ bitmap = kzalloc_obj(*bitmap, GFP_NOWAIT);
if (!bitmap)
goto alloc;
__set_bit(bit, bitmap->bitmap);
@@ -465,7 +465,7 @@ out:
return xas.xa_index * IDA_BITMAP_BITS + bit;
alloc:
xas_unlock_irqrestore(&xas, flags);
- alloc = kzalloc(sizeof(*bitmap), gfp);
+ alloc = kzalloc_obj(*bitmap, gfp);
if (!alloc)
return -ENOMEM;
xas_set(&xas, min / IDA_BITMAP_BITS);
diff --git a/lib/interval_tree_test.c b/lib/interval_tree_test.c
index 5fd62656f42e..16200feacbf3 100644
--- a/lib/interval_tree_test.c
+++ b/lib/interval_tree_test.c
@@ -311,8 +311,7 @@ static inline int span_iteration_check(void) {return 0; }
static int interval_tree_test_init(void)
{
- nodes = kmalloc_array(nnodes, sizeof(struct interval_tree_node),
- GFP_KERNEL);
+ nodes = kmalloc_objs(struct interval_tree_node, nnodes);
if (!nodes)
return -ENOMEM;
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 896760bad455..0a63c7fba313 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -903,7 +903,7 @@ static int want_pages_array(struct page ***res, size_t size,
count = maxpages;
WARN_ON(!count); // caller should've prevented that
if (!*res) {
- *res = kvmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
+ *res = kvmalloc_objs(struct page *, count);
if (!*res)
return 0;
}
@@ -1318,7 +1318,7 @@ struct iovec *iovec_from_user(const struct iovec __user *uvec,
if (nr_segs > UIO_MAXIOV)
return ERR_PTR(-EINVAL);
if (nr_segs > fast_segs) {
- iov = kmalloc_array(nr_segs, sizeof(struct iovec), GFP_KERNEL);
+ iov = kmalloc_objs(struct iovec, nr_segs);
if (!iov)
return ERR_PTR(-ENOMEM);
}
@@ -1845,3 +1845,101 @@ ssize_t iov_iter_extract_pages(struct iov_iter *i,
return -EFAULT;
}
EXPORT_SYMBOL_GPL(iov_iter_extract_pages);
+
+static unsigned int get_contig_folio_len(struct page **pages,
+ unsigned int *num_pages, size_t left, size_t offset)
+{
+ struct folio *folio = page_folio(pages[0]);
+ size_t contig_sz = min_t(size_t, PAGE_SIZE - offset, left);
+ unsigned int max_pages, i;
+ size_t folio_offset, len;
+
+ folio_offset = PAGE_SIZE * folio_page_idx(folio, pages[0]) + offset;
+ len = min(folio_size(folio) - folio_offset, left);
+
+ /*
+ * We might COW a single page in the middle of a large folio, so we have
+ * to check that all pages belong to the same folio.
+ */
+ left -= contig_sz;
+ max_pages = DIV_ROUND_UP(offset + len, PAGE_SIZE);
+ for (i = 1; i < max_pages; i++) {
+ size_t next = min_t(size_t, PAGE_SIZE, left);
+
+ if (page_folio(pages[i]) != folio ||
+ pages[i] != pages[i - 1] + 1)
+ break;
+ contig_sz += next;
+ left -= next;
+ }
+
+ *num_pages = i;
+ return contig_sz;
+}
+
+#define PAGE_PTRS_PER_BVEC (sizeof(struct bio_vec) / sizeof(struct page *))
+
+/**
+ * iov_iter_extract_bvecs - Extract bvecs from an iterator
+ * @iter: the iterator to extract from
+ * @bv: bvec return array
+ * @max_size: maximum size to extract from @iter
+ * @nr_vecs: number of vectors in @bv (on in and output)
+ * @max_vecs: maximum vectors in @bv, including those filled before calling
+ * @extraction_flags: flags to qualify request
+ *
+ * Like iov_iter_extract_pages(), but returns physically contiguous ranges
+ * contained in a single folio as a single bvec instead of multiple entries.
+ *
+ * Returns the number of bytes extracted when successful, or a negative errno.
+ * If @nr_vecs was non-zero on entry, the number of successfully extracted bytes
+ * can be 0.
+ */
+ssize_t iov_iter_extract_bvecs(struct iov_iter *iter, struct bio_vec *bv,
+ size_t max_size, unsigned short *nr_vecs,
+ unsigned short max_vecs, iov_iter_extraction_t extraction_flags)
+{
+ unsigned short entries_left = max_vecs - *nr_vecs;
+ unsigned short nr_pages, i = 0;
+ size_t left, offset, len;
+ struct page **pages;
+ ssize_t size;
+
+ /*
+ * Move page array up in the allocated memory for the bio vecs as far as
+ * possible so that we can start filling biovecs from the beginning
+ * without overwriting the temporary page array.
+ */
+ BUILD_BUG_ON(PAGE_PTRS_PER_BVEC < 2);
+ pages = (struct page **)(bv + *nr_vecs) +
+ entries_left * (PAGE_PTRS_PER_BVEC - 1);
+
+ size = iov_iter_extract_pages(iter, &pages, max_size, entries_left,
+ extraction_flags, &offset);
+ if (unlikely(size <= 0))
+ return size ? size : -EFAULT;
+
+ nr_pages = DIV_ROUND_UP(offset + size, PAGE_SIZE);
+ for (left = size; left > 0; left -= len) {
+ unsigned int nr_to_add;
+
+ if (*nr_vecs > 0 &&
+ !zone_device_pages_have_same_pgmap(bv[*nr_vecs - 1].bv_page,
+ pages[i]))
+ break;
+
+ len = get_contig_folio_len(&pages[i], &nr_to_add, left, offset);
+ bvec_set_page(&bv[*nr_vecs], pages[i], len, offset);
+ i += nr_to_add;
+ (*nr_vecs)++;
+ offset = 0;
+ }
+
+ iov_iter_revert(iter, left);
+ if (iov_iter_extract_will_pin(iter)) {
+ while (i < nr_pages)
+ unpin_user_page(pages[i++]);
+ }
+ return size - left;
+}
+EXPORT_SYMBOL_GPL(iov_iter_extract_bvecs);
diff --git a/lib/kfifo.c b/lib/kfifo.c
index 525e66f8294c..2633f9cc336c 100644
--- a/lib/kfifo.c
+++ b/lib/kfifo.c
@@ -41,7 +41,7 @@ int __kfifo_alloc_node(struct __kfifo *fifo, unsigned int size,
return -EINVAL;
}
- fifo->data = kmalloc_array_node(esize, size, gfp_mask, node);
+ fifo->data = kmalloc_array_node(size, esize, gfp_mask, node);
if (!fifo->data) {
fifo->mask = 0;
diff --git a/lib/kobject.c b/lib/kobject.c
index abe5f5b856ce..cfdb2c3f20a2 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -765,7 +765,7 @@ static struct kobject *kobject_create(void)
{
struct kobject *kobj;
- kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+ kobj = kzalloc_obj(*kobj);
if (!kobj)
return NULL;
@@ -962,7 +962,7 @@ static struct kset *kset_create(const char *name,
struct kset *kset;
int retval;
- kset = kzalloc(sizeof(*kset), GFP_KERNEL);
+ kset = kzalloc_obj(*kset);
if (!kset)
return NULL;
retval = kobject_set_name(&kset->kobj, "%s", name);
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 78e16b95d210..871941c9830c 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -124,7 +124,7 @@ static int kobject_action_args(const char *buf, size_t count,
if (!count)
return -EINVAL;
- env = kzalloc(sizeof(*env), GFP_KERNEL);
+ env = kzalloc_obj(*env);
if (!env)
return -ENOMEM;
@@ -537,7 +537,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
}
/* environment buffer */
- env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+ env = kzalloc_obj(struct kobj_uevent_env);
if (!env)
return -ENOMEM;
@@ -776,7 +776,7 @@ static int uevent_net_init(struct net *net)
.flags = NL_CFG_F_NONROOT_RECV
};
- ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL);
+ ue_sk = kzalloc_obj(*ue_sk);
if (!ue_sk)
return -ENOMEM;
diff --git a/lib/kstrtox.c b/lib/kstrtox.c
index bdde40cd69d7..97be2a39f537 100644
--- a/lib/kstrtox.c
+++ b/lib/kstrtox.c
@@ -340,8 +340,8 @@ EXPORT_SYMBOL(kstrtos8);
* @s: input string
* @res: result
*
- * This routine returns 0 iff the first character is one of 'YyTt1NnFf0', or
- * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value
+ * This routine returns 0 iff the first character is one of 'EeYyTt1DdNnFf0',
+ * or [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value
* pointed to by res is updated upon finding a match.
*/
noinline
diff --git a/lib/kunit/assert.c b/lib/kunit/assert.c
index 867aa5c4bccf..4c751ad8506a 100644
--- a/lib/kunit/assert.c
+++ b/lib/kunit/assert.c
@@ -51,7 +51,7 @@ void kunit_unary_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
- struct kunit_unary_assert *unary_assert;
+ const struct kunit_unary_assert *unary_assert;
unary_assert = container_of(assert, struct kunit_unary_assert, assert);
@@ -71,7 +71,7 @@ void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
- struct kunit_ptr_not_err_assert *ptr_assert;
+ const struct kunit_ptr_not_err_assert *ptr_assert;
ptr_assert = container_of(assert, struct kunit_ptr_not_err_assert,
assert);
@@ -117,7 +117,7 @@ void kunit_binary_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
- struct kunit_binary_assert *binary_assert;
+ const struct kunit_binary_assert *binary_assert;
binary_assert = container_of(assert, struct kunit_binary_assert,
assert);
@@ -145,7 +145,7 @@ void kunit_binary_ptr_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
- struct kunit_binary_ptr_assert *binary_assert;
+ const struct kunit_binary_ptr_assert *binary_assert;
binary_assert = container_of(assert, struct kunit_binary_ptr_assert,
assert);
@@ -185,7 +185,7 @@ void kunit_binary_str_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
- struct kunit_binary_str_assert *binary_assert;
+ const struct kunit_binary_str_assert *binary_assert;
binary_assert = container_of(assert, struct kunit_binary_str_assert,
assert);
@@ -237,7 +237,7 @@ void kunit_mem_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream)
{
- struct kunit_mem_assert *mem_assert;
+ const struct kunit_mem_assert *mem_assert;
mem_assert = container_of(assert, struct kunit_mem_assert,
assert);
diff --git a/lib/kunit/attributes.c b/lib/kunit/attributes.c
index 2cf04cc09372..6d7a53af94a9 100644
--- a/lib/kunit/attributes.c
+++ b/lib/kunit/attributes.c
@@ -410,7 +410,7 @@ struct kunit_suite *kunit_filter_attr_tests(const struct kunit_suite *const suit
kunit_suite_for_each_test_case(suite, test_case) { n++; }
- filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL);
+ filtered = kzalloc_objs(*filtered, n + 1);
if (!filtered) {
kfree(copy);
return ERR_PTR(-ENOMEM);
diff --git a/lib/kunit/device.c b/lib/kunit/device.c
index f201aaacd4cf..85d57ad34045 100644
--- a/lib/kunit/device.c
+++ b/lib/kunit/device.c
@@ -111,7 +111,7 @@ static struct kunit_device *kunit_device_register_internal(struct kunit *test,
struct kunit_device *kunit_dev;
int err = -ENOMEM;
- kunit_dev = kzalloc(sizeof(*kunit_dev), GFP_KERNEL);
+ kunit_dev = kzalloc_obj(*kunit_dev);
if (!kunit_dev)
return ERR_PTR(err);
diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
index 02ff380ab793..1fef217de11d 100644
--- a/lib/kunit/executor.c
+++ b/lib/kunit/executor.c
@@ -131,7 +131,7 @@ kunit_filter_glob_tests(const struct kunit_suite *const suite, const char *test_
if (!copy)
return ERR_PTR(-ENOMEM);
- filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL);
+ filtered = kzalloc_objs(*filtered, n + 1);
if (!filtered) {
kfree(copy);
return ERR_PTR(-ENOMEM);
@@ -179,7 +179,7 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
const size_t max = suite_set->end - suite_set->start;
- copy = kcalloc(max, sizeof(*copy), GFP_KERNEL);
+ copy = kzalloc_objs(*copy, max);
if (!copy) { /* won't be able to run anything, return an empty set */
return filtered;
}
@@ -194,7 +194,7 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
/* Parse attribute filters */
if (filters) {
filter_count = kunit_get_filter_count(filters);
- parsed_filters = kcalloc(filter_count, sizeof(*parsed_filters), GFP_KERNEL);
+ parsed_filters = kzalloc_objs(*parsed_filters, filter_count);
if (!parsed_filters) {
*err = -ENOMEM;
goto free_parsed_glob;
diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c
index f0090c2729cd..4cb119ad8f64 100644
--- a/lib/kunit/executor_test.c
+++ b/lib/kunit/executor_test.c
@@ -272,7 +272,7 @@ static void free_suite_set_at_end(struct kunit *test, const void *to_free)
if (!((struct kunit_suite_set *)to_free)->start)
return;
- free = kzalloc(sizeof(struct kunit_suite_set), GFP_KERNEL);
+ free = kzalloc_obj(struct kunit_suite_set);
*free = *(struct kunit_suite_set *)to_free;
kunit_add_action(test, free_suite_set, (void *)free);
diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c
index 9452b163956f..0bae7b7ca0b0 100644
--- a/lib/kunit/kunit-example-test.c
+++ b/lib/kunit/kunit-example-test.c
@@ -283,7 +283,7 @@ static void example_slow_test(struct kunit *test)
*/
static int example_resource_init(struct kunit_resource *res, void *context)
{
- int *info = kmalloc(sizeof(*info), GFP_KERNEL);
+ int *info = kmalloc_obj(*info);
if (!info)
return -ENOMEM;
diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c
index 63130a48e237..126e30879dad 100644
--- a/lib/kunit/kunit-test.c
+++ b/lib/kunit/kunit-test.c
@@ -538,8 +538,7 @@ static void kunit_resource_test_action_ordering(struct kunit *test)
static int kunit_resource_test_init(struct kunit *test)
{
- struct kunit_test_resource_context *ctx =
- kzalloc(sizeof(*ctx), GFP_KERNEL);
+ struct kunit_test_resource_context *ctx = kzalloc_obj(*ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
diff --git a/lib/kunit/resource.c b/lib/kunit/resource.c
index f0209252b179..45e55238ccf6 100644
--- a/lib/kunit/resource.c
+++ b/lib/kunit/resource.c
@@ -98,7 +98,7 @@ int kunit_add_action(struct kunit *test, void (*action)(void *), void *ctx)
KUNIT_ASSERT_NOT_NULL_MSG(test, action, "Tried to action a NULL function!");
- action_ctx = kzalloc(sizeof(*action_ctx), GFP_KERNEL);
+ action_ctx = kzalloc_obj(*action_ctx);
if (!action_ctx)
return -ENOMEM;
diff --git a/lib/kunit/static_stub.c b/lib/kunit/static_stub.c
index 484fd85251b4..d9dd6377aa38 100644
--- a/lib/kunit/static_stub.c
+++ b/lib/kunit/static_stub.c
@@ -111,7 +111,7 @@ void __kunit_activate_static_stub(struct kunit *test,
/* We got an extra reference from find_resource(), so put it. */
kunit_put_resource(res);
} else {
- ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kmalloc_obj(*ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
ctx->real_fn_addr = real_fn_addr;
ctx->replacement_addr = replacement_addr;
diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c
index 54f4fdcbfac8..0d8f1b30559b 100644
--- a/lib/kunit/string-stream.c
+++ b/lib/kunit/string-stream.c
@@ -18,7 +18,7 @@ static struct string_stream_fragment *alloc_string_stream_fragment(int len, gfp_
{
struct string_stream_fragment *frag;
- frag = kzalloc(sizeof(*frag), gfp);
+ frag = kzalloc_obj(*frag, gfp);
if (!frag)
return ERR_PTR(-ENOMEM);
@@ -158,7 +158,7 @@ struct string_stream *alloc_string_stream(gfp_t gfp)
{
struct string_stream *stream;
- stream = kzalloc(sizeof(*stream), gfp);
+ stream = kzalloc_obj(*stream, gfp);
if (!stream)
return ERR_PTR(-ENOMEM);
diff --git a/lib/lockref.c b/lib/lockref.c
index 9210fc6ae714..5d8e3ef3860e 100644
--- a/lib/lockref.c
+++ b/lib/lockref.c
@@ -105,7 +105,6 @@ EXPORT_SYMBOL(lockref_put_return);
* @lockref: pointer to lockref structure
* Return: 1 if count updated successfully or 0 if count <= 1 and lock taken
*/
-#undef lockref_put_or_lock
bool lockref_put_or_lock(struct lockref *lockref)
{
CMPXCHG_LOOP(
diff --git a/lib/logic_iomem.c b/lib/logic_iomem.c
index b247d412ddef..42a571d05670 100644
--- a/lib/logic_iomem.c
+++ b/lib/logic_iomem.c
@@ -48,7 +48,7 @@ int logic_iomem_add_region(struct resource *resource,
if (WARN_ON((resource->flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM))
return -EINVAL;
- rreg = kzalloc(sizeof(*rreg), GFP_KERNEL);
+ rreg = kzalloc_obj(*rreg);
if (!rreg)
return -ENOMEM;
diff --git a/lib/lru_cache.c b/lib/lru_cache.c
index 9e0d469c7658..82f775044056 100644
--- a/lib/lru_cache.c
+++ b/lib/lru_cache.c
@@ -94,14 +94,14 @@ struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
if (e_count > LC_MAX_ACTIVE)
return NULL;
- slot = kcalloc(e_count, sizeof(struct hlist_head), GFP_KERNEL);
+ slot = kzalloc_objs(struct hlist_head, e_count);
if (!slot)
goto out_fail;
- element = kcalloc(e_count, sizeof(struct lc_element *), GFP_KERNEL);
+ element = kzalloc_objs(struct lc_element *, e_count);
if (!element)
goto out_fail;
- lc = kzalloc(sizeof(*lc), GFP_KERNEL);
+ lc = kzalloc_obj(*lc);
if (!lc)
goto out_fail;
diff --git a/lib/lwq.c b/lib/lwq.c
index 57d080a4d53d..c1e11ba6f254 100644
--- a/lib/lwq.c
+++ b/lib/lwq.c
@@ -110,7 +110,7 @@ static int lwq_test(void)
for (i = 0; i < ARRAY_SIZE(threads); i++)
threads[i] = kthread_run(lwq_exercise, &q, "lwq-test-%d", i);
for (i = 0; i < 100; i++) {
- t = kmalloc(sizeof(*t), GFP_KERNEL);
+ t = kmalloc_obj(*t);
if (!t)
break;
t->i = i;
diff --git a/lib/objagg.c b/lib/objagg.c
index 363e43e849ac..23c7105a3f9f 100644
--- a/lib/objagg.c
+++ b/lib/objagg.c
@@ -525,7 +525,7 @@ struct objagg *objagg_create(const struct objagg_ops *ops,
!ops->delta_destroy))
return ERR_PTR(-EINVAL);
- objagg = kzalloc(sizeof(*objagg), GFP_KERNEL);
+ objagg = kzalloc_obj(*objagg);
if (!objagg)
return ERR_PTR(-ENOMEM);
objagg->ops = ops;
@@ -610,8 +610,8 @@ const struct objagg_stats *objagg_stats_get(struct objagg *objagg)
struct objagg_obj *objagg_obj;
int i;
- objagg_stats = kzalloc(struct_size(objagg_stats, stats_info,
- objagg->obj_count), GFP_KERNEL);
+ objagg_stats = kzalloc_flex(*objagg_stats, stats_info,
+ objagg->obj_count);
if (!objagg_stats)
return ERR_PTR(-ENOMEM);
@@ -786,11 +786,11 @@ static struct objagg_tmp_graph *objagg_tmp_graph_create(struct objagg *objagg)
struct objagg_obj *objagg_obj;
int i, j;
- graph = kzalloc(sizeof(*graph), GFP_KERNEL);
+ graph = kzalloc_obj(*graph);
if (!graph)
return NULL;
- graph->nodes = kcalloc(nodes_count, sizeof(*graph->nodes), GFP_KERNEL);
+ graph->nodes = kzalloc_objs(*graph->nodes, nodes_count);
if (!graph->nodes)
goto err_nodes_alloc;
graph->nodes_count = nodes_count;
@@ -930,7 +930,7 @@ struct objagg_hints *objagg_hints_get(struct objagg *objagg,
struct objagg_hints *objagg_hints;
int err;
- objagg_hints = kzalloc(sizeof(*objagg_hints), GFP_KERNEL);
+ objagg_hints = kzalloc_obj(*objagg_hints);
if (!objagg_hints)
return ERR_PTR(-ENOMEM);
@@ -1010,9 +1010,8 @@ objagg_hints_stats_get(struct objagg_hints *objagg_hints)
struct objagg_hints_node *hnode;
int i;
- objagg_stats = kzalloc(struct_size(objagg_stats, stats_info,
- objagg_hints->node_count),
- GFP_KERNEL);
+ objagg_stats = kzalloc_flex(*objagg_stats, stats_info,
+ objagg_hints->node_count);
if (!objagg_stats)
return ERR_PTR(-ENOMEM);
diff --git a/lib/objpool.c b/lib/objpool.c
index b998b720c732..d98fadf1de16 100644
--- a/lib/objpool.c
+++ b/lib/objpool.c
@@ -142,7 +142,7 @@ int objpool_init(struct objpool_head *pool, int nr_objs, int object_size,
pool->gfp = gfp & ~__GFP_ZERO;
pool->context = context;
pool->release = release;
- slot_size = nr_cpu_ids * sizeof(struct objpool_slot);
+ slot_size = nr_cpu_ids * sizeof(struct objpool_slot *);
pool->cpu_slots = kzalloc(slot_size, pool->gfp);
if (!pool->cpu_slots)
return -ENOMEM;
diff --git a/lib/once.c b/lib/once.c
index 2c306f0e891e..d801bfa945e6 100644
--- a/lib/once.c
+++ b/lib/once.c
@@ -26,7 +26,7 @@ static void once_disable_jump(struct static_key_true *key, struct module *mod)
{
struct once_work *w;
- w = kmalloc(sizeof(*w), GFP_ATOMIC);
+ w = kmalloc_obj(*w, GFP_ATOMIC);
if (!w)
return;
@@ -93,6 +93,6 @@ void __do_once_sleepable_done(bool *done, struct static_key_true *once_key,
{
*done = true;
mutex_unlock(&once_mutex);
- once_disable_jump(once_key, mod);
+ static_branch_disable(once_key);
}
EXPORT_SYMBOL(__do_once_sleepable_done);
diff --git a/lib/parman.c b/lib/parman.c
index 3f8f8d422e62..0de691c202ab 100644
--- a/lib/parman.c
+++ b/lib/parman.c
@@ -268,7 +268,7 @@ struct parman *parman_create(const struct parman_ops *ops, void *priv)
{
struct parman *parman;
- parman = kzalloc(sizeof(*parman), GFP_KERNEL);
+ parman = kzalloc_obj(*parman);
if (!parman)
return NULL;
INIT_LIST_HEAD(&parman->prio_list);
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c
index 668f6aa6a75d..97772e42b9b2 100644
--- a/lib/percpu-refcount.c
+++ b/lib/percpu-refcount.c
@@ -73,7 +73,7 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release,
if (!ref->percpu_count_ptr)
return -ENOMEM;
- data = kzalloc(sizeof(*ref->data), gfp);
+ data = kzalloc_obj(*ref->data, gfp);
if (!data) {
free_percpu((void __percpu *)ref->percpu_count_ptr);
ref->percpu_count_ptr = 0;
diff --git a/lib/pldmfw/pldmfw.c b/lib/pldmfw/pldmfw.c
index b45ceb725780..e4612ea147bb 100644
--- a/lib/pldmfw/pldmfw.c
+++ b/lib/pldmfw/pldmfw.c
@@ -287,7 +287,7 @@ pldm_parse_desc_tlvs(struct pldmfw_priv *data, struct pldmfw_record *record, u8
if (err)
return err;
- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ desc = kzalloc_obj(*desc);
if (!desc)
return -ENOMEM;
@@ -328,7 +328,7 @@ pldm_parse_one_record(struct pldmfw_priv *data,
int i;
/* Make a copy and insert it into the record list */
- record = kzalloc(sizeof(*record), GFP_KERNEL);
+ record = kzalloc_obj(*record);
if (!record)
return -ENOMEM;
@@ -465,7 +465,7 @@ static int pldm_parse_components(struct pldmfw_priv *data)
if (err)
return err;
- component = kzalloc(sizeof(*component), GFP_KERNEL);
+ component = kzalloc_obj(*component);
if (!component)
return -ENOMEM;
@@ -848,7 +848,7 @@ int pldmfw_flash_image(struct pldmfw *context, const struct firmware *fw)
struct pldmfw_priv *data;
int err;
- data = kzalloc(sizeof(*data), GFP_KERNEL);
+ data = kzalloc_obj(*data);
if (!data)
return -ENOMEM;
diff --git a/lib/rbtree_test.c b/lib/rbtree_test.c
index 690cede46ac2..768c5e6453f3 100644
--- a/lib/rbtree_test.c
+++ b/lib/rbtree_test.c
@@ -399,7 +399,7 @@ static int augmented_check(void)
static int __init rbtree_test_init(void)
{
- nodes = kmalloc_array(nnodes, sizeof(*nodes), GFP_KERNEL);
+ nodes = kmalloc_objs(*nodes, nnodes);
if (!nodes)
return -ENOMEM;
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
index a9e2dcb6f2a7..864484c01827 100644
--- a/lib/reed_solomon/reed_solomon.c
+++ b/lib/reed_solomon/reed_solomon.c
@@ -73,7 +73,7 @@ static struct rs_codec *codec_init(int symsize, int gfpoly, int (*gffunc)(int),
int i, j, sr, root, iprim;
struct rs_codec *rs;
- rs = kzalloc(sizeof(*rs), gfp);
+ rs = kzalloc_obj(*rs, gfp);
if (!rs)
return NULL;
diff --git a/lib/reed_solomon/test_rslib.c b/lib/reed_solomon/test_rslib.c
index 75cb1adac884..42b856e6c8a8 100644
--- a/lib/reed_solomon/test_rslib.c
+++ b/lib/reed_solomon/test_rslib.c
@@ -111,7 +111,7 @@ static struct wspace *alloc_ws(struct rs_codec *rs)
struct wspace *ws;
int nn = rs->nn;
- ws = kzalloc(sizeof(*ws), GFP_KERNEL);
+ ws = kzalloc_obj(*ws);
if (!ws)
return NULL;
@@ -124,7 +124,7 @@ static struct wspace *alloc_ws(struct rs_codec *rs)
ws->s = ws->r + nn;
ws->corr = ws->s + nroots;
- ws->errlocs = kmalloc_array(nn + nroots, sizeof(int), GFP_KERNEL);
+ ws->errlocs = kmalloc_objs(int, nn + nroots);
if (!ws->errlocs)
goto err;
diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c
index 258fb0e7abdf..30c999d57b10 100644
--- a/lib/ref_tracker.c
+++ b/lib/ref_tracker.c
@@ -74,8 +74,7 @@ ref_tracker_get_stats(struct ref_tracker_dir *dir, unsigned int limit)
struct ref_tracker_dir_stats *stats;
struct ref_tracker *tracker;
- stats = kmalloc(struct_size(stats, stacks, limit),
- GFP_NOWAIT);
+ stats = kmalloc_flex(*stats, stacks, limit, GFP_NOWAIT);
if (!stats)
return ERR_PTR(-ENOMEM);
stats->total = 0;
@@ -268,7 +267,7 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir,
}
if (gfp & __GFP_DIRECT_RECLAIM)
gfp_mask |= __GFP_NOFAIL;
- *trackerp = tracker = kzalloc(sizeof(*tracker), gfp_mask);
+ *trackerp = tracker = kzalloc_obj(*tracker, gfp_mask);
if (unlikely(!tracker)) {
pr_err_once("memory allocation failure, unreliable refcount tracker.\n");
refcount_inc(&dir->untracked);
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index fde0f0e556f8..6074ed5f66f3 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -358,6 +358,7 @@ static int rhashtable_rehash_table(struct rhashtable *ht)
static int rhashtable_rehash_alloc(struct rhashtable *ht,
struct bucket_table *old_tbl,
unsigned int size)
+ __must_hold(&ht->mutex)
{
struct bucket_table *new_tbl;
int err;
@@ -392,6 +393,7 @@ static int rhashtable_rehash_alloc(struct rhashtable *ht,
* bucket locks or concurrent RCU protected lookups and traversals.
*/
static int rhashtable_shrink(struct rhashtable *ht)
+ __must_hold(&ht->mutex)
{
struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht);
unsigned int nelems = atomic_read(&ht->nelems);
@@ -724,7 +726,7 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_exit);
* resize events and always continue.
*/
int rhashtable_walk_start_check(struct rhashtable_iter *iter)
- __acquires(RCU)
+ __acquires_shared(RCU)
{
struct rhashtable *ht = iter->ht;
bool rhlist = ht->rhlist;
@@ -940,7 +942,6 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_peek);
* hash table.
*/
void rhashtable_walk_stop(struct rhashtable_iter *iter)
- __releases(RCU)
{
struct rhashtable *ht;
struct bucket_table *tbl = iter->walker.tbl;
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 4af1c8b0775a..d773720d11bf 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -65,6 +65,32 @@ int sg_nents_for_len(struct scatterlist *sg, u64 len)
EXPORT_SYMBOL(sg_nents_for_len);
/**
+ * sg_nents_for_dma - return the count of DMA-capable entries in scatterlist
+ * @sgl: The scatterlist
+ * @sglen: The current number of entries
+ * @len: The maximum length of DMA-capable block
+ *
+ * Description:
+ * Determines the number of entries in @sgl which would be permitted in
+ * DMA-capable transfer if list had been split accordingly, taking into
+ * account chaining as well.
+ *
+ * Returns:
+ * the number of sgl entries needed
+ *
+ **/
+int sg_nents_for_dma(struct scatterlist *sgl, unsigned int sglen, size_t len)
+{
+ struct scatterlist *sg;
+ int i, nents = 0;
+
+ for_each_sg(sgl, sg, sglen, i)
+ nents += DIV_ROUND_UP(sg_dma_len(sg), len);
+ return nents;
+}
+EXPORT_SYMBOL(sg_nents_for_dma);
+
+/**
* sg_last - return the last scatterlist entry in a list
* @sgl: First entry in the scatterlist
* @nents: Number of entries in the scatterlist
@@ -142,8 +168,7 @@ static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask)
kmemleak_alloc(ptr, PAGE_SIZE, 1, gfp_mask);
return ptr;
} else
- return kmalloc_array(nents, sizeof(struct scatterlist),
- gfp_mask);
+ return kmalloc_objs(struct scatterlist, nents, gfp_mask);
}
static void sg_kfree(struct scatterlist *sg, unsigned int nents)
@@ -606,8 +631,7 @@ struct scatterlist *sgl_alloc_order(unsigned long long length,
return NULL;
nalloc++;
}
- sgl = kmalloc_array(nalloc, sizeof(struct scatterlist),
- gfp & ~GFP_DMA);
+ sgl = kmalloc_objs(struct scatterlist, nalloc, gfp & ~GFP_DMA);
if (!sgl)
return NULL;
diff --git a/lib/sg_split.c b/lib/sg_split.c
index 0f89aab5c671..24e8f5e48e63 100644
--- a/lib/sg_split.c
+++ b/lib/sg_split.c
@@ -152,7 +152,7 @@ int sg_split(struct scatterlist *in, const int in_mapped_nents,
int i, ret;
struct sg_splitter *splitters;
- splitters = kcalloc(nb_splits, sizeof(*splitters), gfp_mask);
+ splitters = kzalloc_objs(*splitters, nb_splits, gfp_mask);
if (!splitters)
return -ENOMEM;
@@ -163,9 +163,8 @@ int sg_split(struct scatterlist *in, const int in_mapped_nents,
ret = -ENOMEM;
for (i = 0; i < nb_splits; i++) {
- splitters[i].out_sg = kmalloc_array(splitters[i].nents,
- sizeof(struct scatterlist),
- gfp_mask);
+ splitters[i].out_sg = kmalloc_objs(struct scatterlist,
+ splitters[i].nents, gfp_mask);
if (!splitters[i].out_sg)
goto err;
}
diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index de0b0025af2b..dd2717ff94bf 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -61,18 +61,18 @@ static unsigned int stack_bucket_number_order;
/* Hash mask for indexing the table. */
static unsigned int stack_hash_mask;
+/* The lock must be held when performing pool or freelist modifications. */
+static DEFINE_RAW_SPINLOCK(pool_lock);
/* Array of memory regions that store stack records. */
-static void **stack_pools;
+static void **stack_pools __pt_guarded_by(&pool_lock);
/* Newly allocated pool that is not yet added to stack_pools. */
static void *new_pool;
/* Number of pools in stack_pools. */
static int pools_num;
/* Offset to the unused space in the currently used pool. */
-static size_t pool_offset = DEPOT_POOL_SIZE;
+static size_t pool_offset __guarded_by(&pool_lock) = DEPOT_POOL_SIZE;
/* Freelist of stack records within stack_pools. */
-static LIST_HEAD(free_stacks);
-/* The lock must be held when performing pool or freelist modifications. */
-static DEFINE_RAW_SPINLOCK(pool_lock);
+static __guarded_by(&pool_lock) LIST_HEAD(free_stacks);
/* Statistics counters for debugfs. */
enum depot_counter_id {
@@ -260,7 +260,7 @@ int stack_depot_init(void)
entries = 1UL << STACK_BUCKET_NUMBER_ORDER_MAX;
pr_info("allocating hash table of %lu entries via kvcalloc\n", entries);
- stack_table = kvcalloc(entries, sizeof(struct list_head), GFP_KERNEL);
+ stack_table = kvzalloc_objs(struct list_head, entries);
if (!stack_table) {
pr_err("hash table allocation failed, disabling\n");
stack_depot_disabled = true;
@@ -291,6 +291,7 @@ EXPORT_SYMBOL_GPL(stack_depot_init);
* Initializes new stack pool, and updates the list of pools.
*/
static bool depot_init_pool(void **prealloc)
+ __must_hold(&pool_lock)
{
lockdep_assert_held(&pool_lock);
@@ -338,6 +339,7 @@ static bool depot_init_pool(void **prealloc)
/* Keeps the preallocated memory to be used for a new stack depot pool. */
static void depot_keep_new_pool(void **prealloc)
+ __must_hold(&pool_lock)
{
lockdep_assert_held(&pool_lock);
@@ -357,6 +359,7 @@ static void depot_keep_new_pool(void **prealloc)
* the current pre-allocation.
*/
static struct stack_record *depot_pop_free_pool(void **prealloc, size_t size)
+ __must_hold(&pool_lock)
{
struct stack_record *stack;
void *current_pool;
@@ -391,6 +394,7 @@ static struct stack_record *depot_pop_free_pool(void **prealloc, size_t size)
/* Try to find next free usable entry from the freelist. */
static struct stack_record *depot_pop_free(void)
+ __must_hold(&pool_lock)
{
struct stack_record *stack;
@@ -428,6 +432,7 @@ static inline size_t depot_stack_record_size(struct stack_record *s, unsigned in
/* Allocates a new stack in a stack depot pool. */
static struct stack_record *
depot_alloc_stack(unsigned long *entries, unsigned int nr_entries, u32 hash, depot_flags_t flags, void **prealloc)
+ __must_hold(&pool_lock)
{
struct stack_record *stack = NULL;
size_t record_size;
@@ -486,6 +491,7 @@ depot_alloc_stack(unsigned long *entries, unsigned int nr_entries, u32 hash, dep
}
static struct stack_record *depot_fetch_stack(depot_stack_handle_t handle)
+ __must_not_hold(&pool_lock)
{
const int pools_num_cached = READ_ONCE(pools_num);
union handle_parts parts = { .handle = handle };
@@ -502,7 +508,8 @@ static struct stack_record *depot_fetch_stack(depot_stack_handle_t handle)
return NULL;
}
- pool = stack_pools[pool_index];
+ /* @pool_index either valid, or user passed in corrupted value. */
+ pool = context_unsafe(stack_pools[pool_index]);
if (WARN_ON(!pool))
return NULL;
@@ -515,6 +522,7 @@ static struct stack_record *depot_fetch_stack(depot_stack_handle_t handle)
/* Links stack into the freelist. */
static void depot_free_stack(struct stack_record *stack)
+ __must_not_hold(&pool_lock)
{
unsigned long flags;
diff --git a/lib/string_helpers.c b/lib/string_helpers.c
index ffb8ead6d4cd..169eaf583494 100644
--- a/lib/string_helpers.c
+++ b/lib/string_helpers.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/fs.h>
+#include <linux/hex.h>
#include <linux/limits.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -146,7 +147,7 @@ int parse_int_array(const char *buf, size_t count, int **array)
if (!nints)
return -ENOENT;
- ints = kcalloc(nints + 1, sizeof(*ints), GFP_KERNEL);
+ ints = kzalloc_objs(*ints, nints + 1);
if (!ints)
return -ENOMEM;
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index af0041df2b72..5892c0f17ddc 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -94,7 +94,7 @@ static int bpf_fill_maxinsns1(struct bpf_test *self)
__u32 k = ~0;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -113,7 +113,7 @@ static int bpf_fill_maxinsns2(struct bpf_test *self)
struct sock_filter *insn;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -133,7 +133,7 @@ static int bpf_fill_maxinsns3(struct bpf_test *self)
struct rnd_state rnd;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -159,7 +159,7 @@ static int bpf_fill_maxinsns4(struct bpf_test *self)
struct sock_filter *insn;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -178,7 +178,7 @@ static int bpf_fill_maxinsns5(struct bpf_test *self)
struct sock_filter *insn;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -201,7 +201,7 @@ static int bpf_fill_maxinsns6(struct bpf_test *self)
struct sock_filter *insn;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -223,7 +223,7 @@ static int bpf_fill_maxinsns7(struct bpf_test *self)
struct sock_filter *insn;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -249,7 +249,7 @@ static int bpf_fill_maxinsns8(struct bpf_test *self)
struct sock_filter *insn;
int i, jmp_off = len - 3;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -272,7 +272,7 @@ static int bpf_fill_maxinsns9(struct bpf_test *self)
struct bpf_insn *insn;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -298,7 +298,7 @@ static int bpf_fill_maxinsns10(struct bpf_test *self)
struct bpf_insn *insn;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -324,7 +324,7 @@ static int __bpf_fill_ja(struct bpf_test *self, unsigned int len,
unsigned int rlen;
int i, j;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -358,7 +358,7 @@ static int bpf_fill_maxinsns12(struct bpf_test *self)
struct sock_filter *insn;
int i = 0;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -381,7 +381,7 @@ static int bpf_fill_maxinsns13(struct bpf_test *self)
struct sock_filter *insn;
int i = 0;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -410,7 +410,7 @@ static int bpf_fill_ld_abs_get_processor_id(struct bpf_test *self)
struct sock_filter *insn;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -434,7 +434,7 @@ static int __bpf_fill_stxdw(struct bpf_test *self, int size)
struct bpf_insn *insn;
int i;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -484,7 +484,7 @@ static int __bpf_fill_max_jmp(struct bpf_test *self, int jmp, int imm, bool alu3
int len = S16_MAX + 5;
int i;
- insns = kmalloc_array(len, sizeof(*insns), GFP_KERNEL);
+ insns = kmalloc_objs(*insns, len);
if (!insns)
return -ENOMEM;
@@ -626,7 +626,7 @@ static int __bpf_fill_alu_shift(struct bpf_test *self, u8 op,
int imm, k;
int i = 0;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -759,7 +759,7 @@ static int __bpf_fill_alu_shift_same_reg(struct bpf_test *self, u8 op,
int i = 0;
u64 val;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -1244,7 +1244,7 @@ static int __bpf_fill_alu_imm_regs(struct bpf_test *self, u8 op, bool alu32)
u32 imm;
int rd;
- insns = kmalloc_array(len, sizeof(*insns), GFP_KERNEL);
+ insns = kmalloc_objs(*insns, len);
if (!insns)
return -ENOMEM;
@@ -1426,7 +1426,7 @@ static int __bpf_fill_alu_reg_pairs(struct bpf_test *self, u8 op, bool alu32)
int rd, rs;
int i = 0;
- insns = kmalloc_array(len, sizeof(*insns), GFP_KERNEL);
+ insns = kmalloc_objs(*insns, len);
if (!insns)
return -ENOMEM;
@@ -1917,7 +1917,7 @@ static int __bpf_fill_atomic_reg_pairs(struct bpf_test *self, u8 width, u8 op)
u64 mem, upd, res;
int rd, rs, i = 0;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -2163,7 +2163,7 @@ static int bpf_fill_ld_imm64_magn(struct bpf_test *self)
int bit, adj, sign;
int i = 0;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -2217,7 +2217,7 @@ static int __bpf_fill_ld_imm64_bytes(struct bpf_test *self,
u32 rand = 1;
int i = 0;
- insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL);
+ insn = kmalloc_objs(*insn, len);
if (!insn)
return -ENOMEM;
@@ -2724,7 +2724,7 @@ static int __bpf_fill_staggered_jumps(struct bpf_test *self,
struct bpf_insn *insns;
int off, ind;
- insns = kmalloc_array(len, sizeof(*insns), GFP_KERNEL);
+ insns = kmalloc_objs(*insns, len);
if (!insns)
return -ENOMEM;
@@ -15461,7 +15461,7 @@ static __init int prepare_tail_call_tests(struct bpf_array **pprogs)
int which, err;
/* Allocate the table of programs to be used for tail calls */
- progs = kzalloc(struct_size(progs, ptrs, ntests + 1), GFP_KERNEL);
+ progs = kzalloc_flex(*progs, ptrs, ntests + 1);
if (!progs)
goto out_nomem;
diff --git a/lib/test_context-analysis.c b/lib/test_context-analysis.c
new file mode 100644
index 000000000000..140efa8a9763
--- /dev/null
+++ b/lib/test_context-analysis.c
@@ -0,0 +1,598 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Compile-only tests for common patterns that should not generate false
+ * positive errors when compiled with Clang's context analysis.
+ */
+
+#include <linux/bit_spinlock.h>
+#include <linux/build_bug.h>
+#include <linux/local_lock.h>
+#include <linux/mutex.h>
+#include <linux/percpu.h>
+#include <linux/rcupdate.h>
+#include <linux/rwsem.h>
+#include <linux/seqlock.h>
+#include <linux/spinlock.h>
+#include <linux/srcu.h>
+#include <linux/ww_mutex.h>
+
+/*
+ * Test that helper macros work as expected.
+ */
+static void __used test_common_helpers(void)
+{
+ BUILD_BUG_ON(context_unsafe(3) != 3); /* plain expression */
+ BUILD_BUG_ON(context_unsafe((void)2; 3) != 3); /* does not swallow semi-colon */
+ BUILD_BUG_ON(context_unsafe((void)2, 3) != 3); /* does not swallow commas */
+ context_unsafe(do { } while (0)); /* works with void statements */
+}
+
+#define TEST_SPINLOCK_COMMON(class, type, type_init, type_lock, type_unlock, type_trylock, op) \
+ struct test_##class##_data { \
+ type lock; \
+ int counter __guarded_by(&lock); \
+ int *pointer __pt_guarded_by(&lock); \
+ }; \
+ static void __used test_##class##_init(struct test_##class##_data *d) \
+ { \
+ guard(type_init)(&d->lock); \
+ d->counter = 0; \
+ } \
+ static void __used test_##class(struct test_##class##_data *d) \
+ { \
+ unsigned long flags; \
+ d->pointer++; \
+ type_lock(&d->lock); \
+ op(d->counter); \
+ op(*d->pointer); \
+ type_unlock(&d->lock); \
+ type_lock##_irq(&d->lock); \
+ op(d->counter); \
+ op(*d->pointer); \
+ type_unlock##_irq(&d->lock); \
+ type_lock##_bh(&d->lock); \
+ op(d->counter); \
+ op(*d->pointer); \
+ type_unlock##_bh(&d->lock); \
+ type_lock##_irqsave(&d->lock, flags); \
+ op(d->counter); \
+ op(*d->pointer); \
+ type_unlock##_irqrestore(&d->lock, flags); \
+ } \
+ static void __used test_##class##_trylock(struct test_##class##_data *d) \
+ { \
+ if (type_trylock(&d->lock)) { \
+ op(d->counter); \
+ type_unlock(&d->lock); \
+ } \
+ } \
+ static void __used test_##class##_assert(struct test_##class##_data *d) \
+ { \
+ lockdep_assert_held(&d->lock); \
+ op(d->counter); \
+ } \
+ static void __used test_##class##_guard(struct test_##class##_data *d) \
+ { \
+ { guard(class)(&d->lock); op(d->counter); } \
+ { guard(class##_irq)(&d->lock); op(d->counter); } \
+ { guard(class##_irqsave)(&d->lock); op(d->counter); } \
+ }
+
+#define TEST_OP_RW(x) (x)++
+#define TEST_OP_RO(x) ((void)(x))
+
+TEST_SPINLOCK_COMMON(raw_spinlock,
+ raw_spinlock_t,
+ raw_spinlock_init,
+ raw_spin_lock,
+ raw_spin_unlock,
+ raw_spin_trylock,
+ TEST_OP_RW);
+static void __used test_raw_spinlock_trylock_extra(struct test_raw_spinlock_data *d)
+{
+ unsigned long flags;
+
+ data_race(d->counter++); /* no warning */
+
+ if (raw_spin_trylock_irq(&d->lock)) {
+ d->counter++;
+ raw_spin_unlock_irq(&d->lock);
+ }
+ if (raw_spin_trylock_irqsave(&d->lock, flags)) {
+ d->counter++;
+ raw_spin_unlock_irqrestore(&d->lock, flags);
+ }
+ scoped_cond_guard(raw_spinlock_try, return, &d->lock) {
+ d->counter++;
+ }
+}
+
+TEST_SPINLOCK_COMMON(spinlock,
+ spinlock_t,
+ spinlock_init,
+ spin_lock,
+ spin_unlock,
+ spin_trylock,
+ TEST_OP_RW);
+static void __used test_spinlock_trylock_extra(struct test_spinlock_data *d)
+{
+ unsigned long flags;
+
+ if (spin_trylock_irq(&d->lock)) {
+ d->counter++;
+ spin_unlock_irq(&d->lock);
+ }
+ if (spin_trylock_irqsave(&d->lock, flags)) {
+ d->counter++;
+ spin_unlock_irqrestore(&d->lock, flags);
+ }
+ scoped_cond_guard(spinlock_try, return, &d->lock) {
+ d->counter++;
+ }
+}
+
+TEST_SPINLOCK_COMMON(write_lock,
+ rwlock_t,
+ rwlock_init,
+ write_lock,
+ write_unlock,
+ write_trylock,
+ TEST_OP_RW);
+static void __used test_write_trylock_extra(struct test_write_lock_data *d)
+{
+ unsigned long flags;
+
+ if (write_trylock_irqsave(&d->lock, flags)) {
+ d->counter++;
+ write_unlock_irqrestore(&d->lock, flags);
+ }
+}
+
+TEST_SPINLOCK_COMMON(read_lock,
+ rwlock_t,
+ rwlock_init,
+ read_lock,
+ read_unlock,
+ read_trylock,
+ TEST_OP_RO);
+
+struct test_mutex_data {
+ struct mutex mtx;
+ int counter __guarded_by(&mtx);
+};
+
+static void __used test_mutex_init(struct test_mutex_data *d)
+{
+ guard(mutex_init)(&d->mtx);
+ d->counter = 0;
+}
+
+static void __used test_mutex_lock(struct test_mutex_data *d)
+{
+ mutex_lock(&d->mtx);
+ d->counter++;
+ mutex_unlock(&d->mtx);
+ mutex_lock_io(&d->mtx);
+ d->counter++;
+ mutex_unlock(&d->mtx);
+}
+
+static void __used test_mutex_trylock(struct test_mutex_data *d, atomic_t *a)
+{
+ if (!mutex_lock_interruptible(&d->mtx)) {
+ d->counter++;
+ mutex_unlock(&d->mtx);
+ }
+ if (!mutex_lock_killable(&d->mtx)) {
+ d->counter++;
+ mutex_unlock(&d->mtx);
+ }
+ if (mutex_trylock(&d->mtx)) {
+ d->counter++;
+ mutex_unlock(&d->mtx);
+ }
+ if (atomic_dec_and_mutex_lock(a, &d->mtx)) {
+ d->counter++;
+ mutex_unlock(&d->mtx);
+ }
+}
+
+static void __used test_mutex_assert(struct test_mutex_data *d)
+{
+ lockdep_assert_held(&d->mtx);
+ d->counter++;
+}
+
+static void __used test_mutex_guard(struct test_mutex_data *d)
+{
+ guard(mutex)(&d->mtx);
+ d->counter++;
+}
+
+static void __used test_mutex_cond_guard(struct test_mutex_data *d)
+{
+ scoped_cond_guard(mutex_try, return, &d->mtx) {
+ d->counter++;
+ }
+ scoped_cond_guard(mutex_intr, return, &d->mtx) {
+ d->counter++;
+ }
+}
+
+struct test_seqlock_data {
+ seqlock_t sl;
+ int counter __guarded_by(&sl);
+};
+
+static void __used test_seqlock_init(struct test_seqlock_data *d)
+{
+ guard(seqlock_init)(&d->sl);
+ d->counter = 0;
+}
+
+static void __used test_seqlock_reader(struct test_seqlock_data *d)
+{
+ unsigned int seq;
+
+ do {
+ seq = read_seqbegin(&d->sl);
+ (void)d->counter;
+ } while (read_seqretry(&d->sl, seq));
+}
+
+static void __used test_seqlock_writer(struct test_seqlock_data *d)
+{
+ unsigned long flags;
+
+ write_seqlock(&d->sl);
+ d->counter++;
+ write_sequnlock(&d->sl);
+
+ write_seqlock_irq(&d->sl);
+ d->counter++;
+ write_sequnlock_irq(&d->sl);
+
+ write_seqlock_bh(&d->sl);
+ d->counter++;
+ write_sequnlock_bh(&d->sl);
+
+ write_seqlock_irqsave(&d->sl, flags);
+ d->counter++;
+ write_sequnlock_irqrestore(&d->sl, flags);
+}
+
+static void __used test_seqlock_scoped(struct test_seqlock_data *d)
+{
+ scoped_seqlock_read (&d->sl, ss_lockless) {
+ (void)d->counter;
+ }
+}
+
+struct test_rwsem_data {
+ struct rw_semaphore sem;
+ int counter __guarded_by(&sem);
+};
+
+static void __used test_rwsem_init(struct test_rwsem_data *d)
+{
+ guard(rwsem_init)(&d->sem);
+ d->counter = 0;
+}
+
+static void __used test_rwsem_reader(struct test_rwsem_data *d)
+{
+ down_read(&d->sem);
+ (void)d->counter;
+ up_read(&d->sem);
+
+ if (down_read_trylock(&d->sem)) {
+ (void)d->counter;
+ up_read(&d->sem);
+ }
+}
+
+static void __used test_rwsem_writer(struct test_rwsem_data *d)
+{
+ down_write(&d->sem);
+ d->counter++;
+ up_write(&d->sem);
+
+ down_write(&d->sem);
+ d->counter++;
+ downgrade_write(&d->sem);
+ (void)d->counter;
+ up_read(&d->sem);
+
+ if (down_write_trylock(&d->sem)) {
+ d->counter++;
+ up_write(&d->sem);
+ }
+}
+
+static void __used test_rwsem_assert(struct test_rwsem_data *d)
+{
+ rwsem_assert_held_nolockdep(&d->sem);
+ d->counter++;
+}
+
+static void __used test_rwsem_guard(struct test_rwsem_data *d)
+{
+ { guard(rwsem_read)(&d->sem); (void)d->counter; }
+ { guard(rwsem_write)(&d->sem); d->counter++; }
+}
+
+static void __used test_rwsem_cond_guard(struct test_rwsem_data *d)
+{
+ scoped_cond_guard(rwsem_read_try, return, &d->sem) {
+ (void)d->counter;
+ }
+ scoped_cond_guard(rwsem_write_try, return, &d->sem) {
+ d->counter++;
+ }
+}
+
+struct test_bit_spinlock_data {
+ unsigned long bits;
+ int counter __guarded_by(__bitlock(3, &bits));
+};
+
+static void __used test_bit_spin_lock(struct test_bit_spinlock_data *d)
+{
+ /*
+ * Note, the analysis seems to have false negatives, because it won't
+ * precisely recognize the bit of the fake __bitlock() token.
+ */
+ bit_spin_lock(3, &d->bits);
+ d->counter++;
+ bit_spin_unlock(3, &d->bits);
+
+ bit_spin_lock(3, &d->bits);
+ d->counter++;
+ __bit_spin_unlock(3, &d->bits);
+
+ if (bit_spin_trylock(3, &d->bits)) {
+ d->counter++;
+ bit_spin_unlock(3, &d->bits);
+ }
+}
+
+/*
+ * Test that we can mark a variable guarded by RCU, and we can dereference and
+ * write to the pointer with RCU's primitives.
+ */
+struct test_rcu_data {
+ long __rcu_guarded *data;
+};
+
+static void __used test_rcu_guarded_reader(struct test_rcu_data *d)
+{
+ rcu_read_lock();
+ (void)rcu_dereference(d->data);
+ rcu_read_unlock();
+
+ rcu_read_lock_bh();
+ (void)rcu_dereference(d->data);
+ rcu_read_unlock_bh();
+
+ rcu_read_lock_sched();
+ (void)rcu_dereference(d->data);
+ rcu_read_unlock_sched();
+}
+
+static void __used test_rcu_guard(struct test_rcu_data *d)
+{
+ guard(rcu)();
+ (void)rcu_dereference(d->data);
+}
+
+static void __used test_rcu_guarded_updater(struct test_rcu_data *d)
+{
+ rcu_assign_pointer(d->data, NULL);
+ RCU_INIT_POINTER(d->data, NULL);
+ (void)unrcu_pointer(d->data);
+}
+
+static void wants_rcu_held(void) __must_hold_shared(RCU) { }
+static void wants_rcu_held_bh(void) __must_hold_shared(RCU_BH) { }
+static void wants_rcu_held_sched(void) __must_hold_shared(RCU_SCHED) { }
+
+static void __used test_rcu_lock_variants(void)
+{
+ rcu_read_lock();
+ wants_rcu_held();
+ rcu_read_unlock();
+
+ rcu_read_lock_bh();
+ wants_rcu_held_bh();
+ rcu_read_unlock_bh();
+
+ rcu_read_lock_sched();
+ wants_rcu_held_sched();
+ rcu_read_unlock_sched();
+}
+
+static void __used test_rcu_lock_reentrant(void)
+{
+ rcu_read_lock();
+ rcu_read_lock();
+ rcu_read_lock_bh();
+ rcu_read_lock_bh();
+ rcu_read_lock_sched();
+ rcu_read_lock_sched();
+
+ rcu_read_unlock_sched();
+ rcu_read_unlock_sched();
+ rcu_read_unlock_bh();
+ rcu_read_unlock_bh();
+ rcu_read_unlock();
+ rcu_read_unlock();
+}
+
+static void __used test_rcu_assert_variants(void)
+{
+ lockdep_assert_in_rcu_read_lock();
+ wants_rcu_held();
+
+ lockdep_assert_in_rcu_read_lock_bh();
+ wants_rcu_held_bh();
+
+ lockdep_assert_in_rcu_read_lock_sched();
+ wants_rcu_held_sched();
+}
+
+struct test_srcu_data {
+ struct srcu_struct srcu;
+ long __rcu_guarded *data;
+};
+
+static void __used test_srcu(struct test_srcu_data *d)
+{
+ init_srcu_struct(&d->srcu);
+
+ int idx = srcu_read_lock(&d->srcu);
+ long *data = srcu_dereference(d->data, &d->srcu);
+ (void)data;
+ srcu_read_unlock(&d->srcu, idx);
+
+ rcu_assign_pointer(d->data, NULL);
+}
+
+static void __used test_srcu_guard(struct test_srcu_data *d)
+{
+ { guard(srcu)(&d->srcu); (void)srcu_dereference(d->data, &d->srcu); }
+ { guard(srcu_fast)(&d->srcu); (void)srcu_dereference(d->data, &d->srcu); }
+ { guard(srcu_fast_notrace)(&d->srcu); (void)srcu_dereference(d->data, &d->srcu); }
+}
+
+struct test_local_lock_data {
+ local_lock_t lock;
+ int counter __guarded_by(&lock);
+};
+
+static DEFINE_PER_CPU(struct test_local_lock_data, test_local_lock_data) = {
+ .lock = INIT_LOCAL_LOCK(lock),
+};
+
+static void __used test_local_lock_init(struct test_local_lock_data *d)
+{
+ guard(local_lock_init)(&d->lock);
+ d->counter = 0;
+}
+
+static void __used test_local_lock(void)
+{
+ unsigned long flags;
+
+ local_lock(&test_local_lock_data.lock);
+ this_cpu_add(test_local_lock_data.counter, 1);
+ local_unlock(&test_local_lock_data.lock);
+
+ local_lock_irq(&test_local_lock_data.lock);
+ this_cpu_add(test_local_lock_data.counter, 1);
+ local_unlock_irq(&test_local_lock_data.lock);
+
+ local_lock_irqsave(&test_local_lock_data.lock, flags);
+ this_cpu_add(test_local_lock_data.counter, 1);
+ local_unlock_irqrestore(&test_local_lock_data.lock, flags);
+
+ local_lock_nested_bh(&test_local_lock_data.lock);
+ this_cpu_add(test_local_lock_data.counter, 1);
+ local_unlock_nested_bh(&test_local_lock_data.lock);
+}
+
+static void __used test_local_lock_guard(void)
+{
+ { guard(local_lock)(&test_local_lock_data.lock); this_cpu_add(test_local_lock_data.counter, 1); }
+ { guard(local_lock_irq)(&test_local_lock_data.lock); this_cpu_add(test_local_lock_data.counter, 1); }
+ { guard(local_lock_irqsave)(&test_local_lock_data.lock); this_cpu_add(test_local_lock_data.counter, 1); }
+ { guard(local_lock_nested_bh)(&test_local_lock_data.lock); this_cpu_add(test_local_lock_data.counter, 1); }
+}
+
+struct test_local_trylock_data {
+ local_trylock_t lock;
+ int counter __guarded_by(&lock);
+};
+
+static DEFINE_PER_CPU(struct test_local_trylock_data, test_local_trylock_data) = {
+ .lock = INIT_LOCAL_TRYLOCK(lock),
+};
+
+static void __used test_local_trylock_init(struct test_local_trylock_data *d)
+{
+ guard(local_trylock_init)(&d->lock);
+ d->counter = 0;
+}
+
+static void __used test_local_trylock(void)
+{
+ local_lock(&test_local_trylock_data.lock);
+ this_cpu_add(test_local_trylock_data.counter, 1);
+ local_unlock(&test_local_trylock_data.lock);
+
+ if (local_trylock(&test_local_trylock_data.lock)) {
+ this_cpu_add(test_local_trylock_data.counter, 1);
+ local_unlock(&test_local_trylock_data.lock);
+ }
+}
+
+static DEFINE_WD_CLASS(ww_class);
+
+struct test_ww_mutex_data {
+ struct ww_mutex mtx;
+ int counter __guarded_by(&mtx);
+};
+
+static void __used test_ww_mutex_lock_noctx(struct test_ww_mutex_data *d)
+{
+ if (!ww_mutex_lock(&d->mtx, NULL)) {
+ d->counter++;
+ ww_mutex_unlock(&d->mtx);
+ }
+
+ if (!ww_mutex_lock_interruptible(&d->mtx, NULL)) {
+ d->counter++;
+ ww_mutex_unlock(&d->mtx);
+ }
+
+ if (ww_mutex_trylock(&d->mtx, NULL)) {
+ d->counter++;
+ ww_mutex_unlock(&d->mtx);
+ }
+
+ ww_mutex_lock_slow(&d->mtx, NULL);
+ d->counter++;
+ ww_mutex_unlock(&d->mtx);
+
+ ww_mutex_destroy(&d->mtx);
+}
+
+static void __used test_ww_mutex_lock_ctx(struct test_ww_mutex_data *d)
+{
+ struct ww_acquire_ctx ctx;
+
+ ww_acquire_init(&ctx, &ww_class);
+
+ if (!ww_mutex_lock(&d->mtx, &ctx)) {
+ d->counter++;
+ ww_mutex_unlock(&d->mtx);
+ }
+
+ if (!ww_mutex_lock_interruptible(&d->mtx, &ctx)) {
+ d->counter++;
+ ww_mutex_unlock(&d->mtx);
+ }
+
+ if (ww_mutex_trylock(&d->mtx, &ctx)) {
+ d->counter++;
+ ww_mutex_unlock(&d->mtx);
+ }
+
+ ww_mutex_lock_slow(&d->mtx, &ctx);
+ d->counter++;
+ ww_mutex_unlock(&d->mtx);
+
+ ww_acquire_done(&ctx);
+ ww_acquire_fini(&ctx);
+
+ ww_mutex_destroy(&d->mtx);
+}
diff --git a/lib/test_debug_virtual.c b/lib/test_debug_virtual.c
index b7cc0aaee173..518ee8d213cd 100644
--- a/lib/test_debug_virtual.c
+++ b/lib/test_debug_virtual.c
@@ -29,7 +29,7 @@ static int __init test_debug_virtual_init(void)
pr_info("PA: %pa for VA: 0x%lx\n", &pa, (unsigned long)va);
- foo = kzalloc(sizeof(*foo), GFP_KERNEL);
+ foo = kzalloc_obj(*foo);
if (!foo)
return -ENOMEM;
diff --git a/lib/test_firmware.c b/lib/test_firmware.c
index be4f93124901..b471d720879a 100644
--- a/lib/test_firmware.c
+++ b/lib/test_firmware.c
@@ -1309,7 +1309,7 @@ static ssize_t upload_register_store(struct device *dev,
goto free_name;
}
- tst = kzalloc(sizeof(*tst), GFP_KERNEL);
+ tst = kzalloc_obj(*tst);
if (!tst) {
ret = -ENOMEM;
goto free_name;
@@ -1526,7 +1526,7 @@ static int __init test_firmware_init(void)
{
int rc;
- test_fw_config = kzalloc(sizeof(struct test_config), GFP_KERNEL);
+ test_fw_config = kzalloc_obj(struct test_config);
if (!test_fw_config)
return -ENOMEM;
diff --git a/lib/test_fortify/test_fortify.sh b/lib/test_fortify/test_fortify.sh
index c2688ab8281d..ad6dd44fa31c 100644
--- a/lib/test_fortify/test_fortify.sh
+++ b/lib/test_fortify/test_fortify.sh
@@ -17,7 +17,7 @@ WANT="__${FILE%%-*}"
# Argument 2: Where to write the build log.
OUT="$1"
shift
-TMP="${OUT}.tmp"
+TMP="${OUT%/*}/.${OUT##*/}.tmp"
# Argument 3: Path to "nm" tool.
NM="$1"
@@ -29,7 +29,7 @@ shift
__cleanup() {
rm -f "$TMP"
}
-trap __cleanup EXIT
+trap __cleanup EXIT HUP INT QUIT TERM
# Function names in warnings are wrapped in backticks under UTF-8 locales.
# Run the commands with LANG=C so that grep output will not change.
diff --git a/lib/test_hmm.c b/lib/test_hmm.c
index 8af169d3873a..0964d53365e6 100644
--- a/lib/test_hmm.c
+++ b/lib/test_hmm.c
@@ -166,7 +166,7 @@ static int dmirror_fops_open(struct inode *inode, struct file *filp)
int ret;
/* Mirror this process address space */
- dmirror = kzalloc(sizeof(*dmirror), GFP_KERNEL);
+ dmirror = kzalloc_obj(*dmirror);
if (dmirror == NULL)
return -ENOMEM;
@@ -504,7 +504,7 @@ static int dmirror_allocate_chunk(struct dmirror_device *mdevice,
void *ptr;
int ret = -ENOMEM;
- devmem = kzalloc(sizeof(*devmem), GFP_KERNEL);
+ devmem = kzalloc_obj(*devmem);
if (!devmem)
return ret;
@@ -662,7 +662,9 @@ static struct page *dmirror_devmem_alloc_page(struct dmirror *dmirror,
goto error;
}
- zone_device_folio_init(page_folio(dpage), order);
+ zone_device_folio_init(page_folio(dpage),
+ page_pgmap(folio_page(page_folio(dpage), 0)),
+ order);
dpage->zone_device_data = rpage;
return dpage;
diff --git a/lib/test_kho.c b/lib/test_kho.c
index 47de56280795..7ef9e4061869 100644
--- a/lib/test_kho.c
+++ b/lib/test_kho.c
@@ -19,6 +19,7 @@
#include <linux/printk.h>
#include <linux/vmalloc.h>
#include <linux/kexec_handover.h>
+#include <linux/kho/abi/kexec_handover.h>
#include <net/checksum.h>
@@ -210,7 +211,7 @@ static int kho_test_save(void)
max_mem = PAGE_ALIGN(max_mem);
max_nr = max_mem >> PAGE_SHIFT;
- folios = kvmalloc_array(max_nr, sizeof(*state->folios), GFP_KERNEL);
+ folios = kvmalloc_objs(*state->folios, max_nr);
if (!folios)
return -ENOMEM;
state->folios = folios;
@@ -339,11 +340,15 @@ module_init(kho_test_init);
static void kho_test_cleanup(void)
{
+ /* unpreserve and free the data stored in folios */
+ kho_test_unpreserve_data(&kho_test_state);
for (int i = 0; i < kho_test_state.nr_folios; i++)
folio_put(kho_test_state.folios[i]);
kvfree(kho_test_state.folios);
- vfree(kho_test_state.folios_info);
+
+ /* Unpreserve and release the FDT folio */
+ kho_unpreserve_folio(kho_test_state.fdt);
folio_put(kho_test_state.fdt);
}
diff --git a/lib/test_memcat_p.c b/lib/test_memcat_p.c
index 7e0797a6bebf..62f1633b30f8 100644
--- a/lib/test_memcat_p.c
+++ b/lib/test_memcat_p.c
@@ -24,20 +24,20 @@ static int __init test_memcat_p_init(void)
struct test_struct **in0, **in1, **out, **p;
int err = -ENOMEM, i, r, total = 0;
- in0 = kcalloc(INPUT_MAX, sizeof(*in0), GFP_KERNEL);
+ in0 = kzalloc_objs(*in0, INPUT_MAX);
if (!in0)
return err;
- in1 = kcalloc(INPUT_MAX, sizeof(*in1), GFP_KERNEL);
+ in1 = kzalloc_objs(*in1, INPUT_MAX);
if (!in1)
goto err_free_in0;
for (i = 0, r = 1; i < INPUT_MAX - 1; i++) {
- in0[i] = kmalloc(sizeof(**in0), GFP_KERNEL);
+ in0[i] = kmalloc_obj(**in0);
if (!in0[i])
goto err_free_elements;
- in1[i] = kmalloc(sizeof(**in1), GFP_KERNEL);
+ in1[i] = kmalloc_obj(**in1);
if (!in1[i]) {
kfree(in0[i]);
goto err_free_elements;
diff --git a/lib/test_objagg.c b/lib/test_objagg.c
index ce5c4c36a084..f21e3ae01395 100644
--- a/lib/test_objagg.c
+++ b/lib/test_objagg.c
@@ -107,7 +107,7 @@ static void *delta_create(void *priv, void *parent_obj, void *obj)
if (!delta_check(priv, parent_obj, obj))
return ERR_PTR(-EINVAL);
- delta = kzalloc(sizeof(*delta), GFP_KERNEL);
+ delta = kzalloc_obj(*delta);
if (!delta)
return ERR_PTR(-ENOMEM);
delta->key_id_diff = diff;
@@ -130,7 +130,7 @@ static void *root_create(void *priv, void *obj, unsigned int id)
struct tokey *key = obj;
struct root *root;
- root = kzalloc(sizeof(*root), GFP_KERNEL);
+ root = kzalloc_obj(*root);
if (!root)
return ERR_PTR(-ENOMEM);
memcpy(&root->key, key, sizeof(root->key));
diff --git a/lib/test_parman.c b/lib/test_parman.c
index f9b97426a337..28f0951189ab 100644
--- a/lib/test_parman.c
+++ b/lib/test_parman.c
@@ -219,7 +219,7 @@ static struct test_parman *test_parman_create(const struct parman_ops *ops)
struct test_parman *test_parman;
int err;
- test_parman = kzalloc(sizeof(*test_parman), GFP_KERNEL);
+ test_parman = kzalloc_obj(*test_parman);
if (!test_parman)
return ERR_PTR(-ENOMEM);
err = test_parman_resize(test_parman, TEST_PARMAN_BASE_COUNT);
diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c
index c63db03ebb9d..0b33559a910b 100644
--- a/lib/test_rhashtable.c
+++ b/lib/test_rhashtable.c
@@ -524,7 +524,7 @@ static int __init test_insert_dup(struct test_obj_rhl *rhl_test_objects,
const char *key;
int err = 0;
- rhlt = kmalloc(sizeof(*rhlt), GFP_KERNEL);
+ rhlt = kmalloc_obj(*rhlt);
if (WARN_ON(!rhlt))
return -EINVAL;
diff --git a/lib/test_uuid.c b/lib/test_uuid.c
deleted file mode 100644
index 0124fad5d72c..000000000000
--- a/lib/test_uuid.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Test cases for lib/uuid.c module.
- */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/uuid.h>
-
-struct test_uuid_data {
- const char *uuid;
- guid_t le;
- uuid_t be;
-};
-
-static const struct test_uuid_data test_uuid_test_data[] = {
- {
- .uuid = "c33f4995-3701-450e-9fbf-206a2e98e576",
- .le = GUID_INIT(0xc33f4995, 0x3701, 0x450e, 0x9f, 0xbf, 0x20, 0x6a, 0x2e, 0x98, 0xe5, 0x76),
- .be = UUID_INIT(0xc33f4995, 0x3701, 0x450e, 0x9f, 0xbf, 0x20, 0x6a, 0x2e, 0x98, 0xe5, 0x76),
- },
- {
- .uuid = "64b4371c-77c1-48f9-8221-29f054fc023b",
- .le = GUID_INIT(0x64b4371c, 0x77c1, 0x48f9, 0x82, 0x21, 0x29, 0xf0, 0x54, 0xfc, 0x02, 0x3b),
- .be = UUID_INIT(0x64b4371c, 0x77c1, 0x48f9, 0x82, 0x21, 0x29, 0xf0, 0x54, 0xfc, 0x02, 0x3b),
- },
- {
- .uuid = "0cb4ddff-a545-4401-9d06-688af53e7f84",
- .le = GUID_INIT(0x0cb4ddff, 0xa545, 0x4401, 0x9d, 0x06, 0x68, 0x8a, 0xf5, 0x3e, 0x7f, 0x84),
- .be = UUID_INIT(0x0cb4ddff, 0xa545, 0x4401, 0x9d, 0x06, 0x68, 0x8a, 0xf5, 0x3e, 0x7f, 0x84),
- },
-};
-
-static const char * const test_uuid_wrong_data[] = {
- "c33f4995-3701-450e-9fbf206a2e98e576 ", /* no hyphen(s) */
- "64b4371c-77c1-48f9-8221-29f054XX023b", /* invalid character(s) */
- "0cb4ddff-a545-4401-9d06-688af53e", /* not enough data */
-};
-
-static unsigned total_tests __initdata;
-static unsigned failed_tests __initdata;
-
-static void __init test_uuid_failed(const char *prefix, bool wrong, bool be,
- const char *data, const char *actual)
-{
- pr_err("%s test #%u %s %s data: '%s'\n",
- prefix,
- total_tests,
- wrong ? "passed on wrong" : "failed on",
- be ? "BE" : "LE",
- data);
- if (actual && *actual)
- pr_err("%s test #%u actual data: '%s'\n",
- prefix,
- total_tests,
- actual);
- failed_tests++;
-}
-
-static void __init test_uuid_test(const struct test_uuid_data *data)
-{
- guid_t le;
- uuid_t be;
- char buf[48];
-
- /* LE */
- total_tests++;
- if (guid_parse(data->uuid, &le))
- test_uuid_failed("conversion", false, false, data->uuid, NULL);
-
- total_tests++;
- if (!guid_equal(&data->le, &le)) {
- sprintf(buf, "%pUl", &le);
- test_uuid_failed("cmp", false, false, data->uuid, buf);
- }
-
- /* BE */
- total_tests++;
- if (uuid_parse(data->uuid, &be))
- test_uuid_failed("conversion", false, true, data->uuid, NULL);
-
- total_tests++;
- if (!uuid_equal(&data->be, &be)) {
- sprintf(buf, "%pUb", &be);
- test_uuid_failed("cmp", false, true, data->uuid, buf);
- }
-}
-
-static void __init test_uuid_wrong(const char *data)
-{
- guid_t le;
- uuid_t be;
-
- /* LE */
- total_tests++;
- if (!guid_parse(data, &le))
- test_uuid_failed("negative", true, false, data, NULL);
-
- /* BE */
- total_tests++;
- if (!uuid_parse(data, &be))
- test_uuid_failed("negative", true, true, data, NULL);
-}
-
-static int __init test_uuid_init(void)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(test_uuid_test_data); i++)
- test_uuid_test(&test_uuid_test_data[i]);
-
- for (i = 0; i < ARRAY_SIZE(test_uuid_wrong_data); i++)
- test_uuid_wrong(test_uuid_wrong_data[i]);
-
- if (failed_tests == 0)
- pr_info("all %u tests passed\n", total_tests);
- else
- pr_err("failed %u out of %u tests\n", failed_tests, total_tests);
-
- return failed_tests ? -EINVAL : 0;
-}
-module_init(test_uuid_init);
-
-static void __exit test_uuid_exit(void)
-{
- /* do nothing */
-}
-module_exit(test_uuid_exit);
-
-MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
-MODULE_DESCRIPTION("Test cases for lib/uuid.c module");
-MODULE_LICENSE("Dual BSD/GPL");
diff --git a/lib/test_vmalloc.c b/lib/test_vmalloc.c
index 6521c05c7816..876c72c18a0c 100644
--- a/lib/test_vmalloc.c
+++ b/lib/test_vmalloc.c
@@ -58,6 +58,9 @@ __param(int, run_test_mask, 7,
/* Add a new test case description here. */
);
+__param(int, nr_pcpu_objects, 35000,
+ "Number of pcpu objects to allocate for pcpu_alloc_test");
+
/*
* This is for synchronization of setup phase.
*/
@@ -317,24 +320,24 @@ pcpu_alloc_test(void)
size_t size, align;
int i;
- pcpu = vmalloc(sizeof(void __percpu *) * 35000);
+ pcpu = vmalloc(sizeof(void __percpu *) * nr_pcpu_objects);
if (!pcpu)
return -1;
- for (i = 0; i < 35000; i++) {
+ for (i = 0; i < nr_pcpu_objects; i++) {
size = get_random_u32_inclusive(1, PAGE_SIZE / 4);
/*
* Maximum PAGE_SIZE
*/
- align = 1 << get_random_u32_inclusive(1, 11);
+ align = 1 << get_random_u32_inclusive(1, PAGE_SHIFT - 1);
pcpu[i] = __alloc_percpu(size, align);
if (!pcpu[i])
rv = -1;
}
- for (i = 0; i < 35000; i++)
+ for (i = 0; i < nr_pcpu_objects; i++)
free_percpu(pcpu[i]);
vfree(pcpu);
@@ -393,7 +396,7 @@ vm_map_ram_test(void)
int i;
map_nr_pages = nr_pages > 0 ? nr_pages:1;
- pages = kcalloc(map_nr_pages, sizeof(struct page *), GFP_KERNEL);
+ pages = kzalloc_objs(struct page *, map_nr_pages);
if (!pages)
return -1;
@@ -539,7 +542,7 @@ init_test_configuration(void)
nr_threads = clamp(nr_threads, 1, (int) USHRT_MAX);
/* Allocate the space for test instances. */
- tdriver = kvcalloc(nr_threads, sizeof(*tdriver), GFP_KERNEL);
+ tdriver = kvzalloc_objs(*tdriver, nr_threads);
if (tdriver == NULL)
return -1;
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 601dba4b7d96..05f74edbc62b 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -5,6 +5,7 @@
# KUnit tests
CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN)
obj-$(CONFIG_BASE64_KUNIT) += base64_kunit.o
+obj-$(CONFIG_BITOPS_KUNIT) += bitops_kunit.o
obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o
obj-$(CONFIG_BITS_TEST) += test_bits.o
obj-$(CONFIG_BLACKHOLE_DEV_KUNIT_TEST) += blackhole_dev_kunit.o
@@ -19,20 +20,24 @@ CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN)
obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o
CFLAGS_test_fprobe.o += $(CC_FLAGS_FTRACE)
obj-$(CONFIG_FPROBE_SANITY_TEST) += test_fprobe.o
+obj-$(CONFIG_GLOB_KUNIT_TEST) += glob_kunit.o
obj-$(CONFIG_HASHTABLE_KUNIT_TEST) += hashtable_test.o
obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o
obj-$(CONFIG_TEST_IOV_ITER) += kunit_iov_iter.o
obj-$(CONFIG_IS_SIGNED_TYPE_KUNIT_TEST) += is_signed_type_kunit.o
obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o
+obj-$(CONFIG_LIST_PRIVATE_KUNIT_TEST) += list-private-test.o
obj-$(CONFIG_KFIFO_KUNIT_TEST) += kfifo_kunit.o
obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o
obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o
+obj-$(CONFIG_LIVEUPDATE_TEST) += liveupdate.o
CFLAGS_longest_symbol_kunit.o += $(call cc-disable-warning, missing-prototypes)
obj-$(CONFIG_LONGEST_SYM_KUNIT_TEST) += longest_symbol_kunit.o
obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o
+obj-$(CONFIG_MIN_HEAP_KUNIT_TEST) += min_heap_kunit.o
CFLAGS_overflow_kunit.o = $(call cc-disable-warning, tautological-constant-out-of-range-compare)
obj-$(CONFIG_OVERFLOW_KUNIT_TEST) += overflow_kunit.o
obj-$(CONFIG_PRINTF_KUNIT_TEST) += printf_kunit.o
@@ -49,5 +54,6 @@ obj-$(CONFIG_STRING_HELPERS_KUNIT_TEST) += string_helpers_kunit.o
obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o
obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o
obj-$(CONFIG_RATELIMIT_KUNIT_TEST) += test_ratelimit.o
+obj-$(CONFIG_UUID_KUNIT_TEST) += uuid_kunit.o
obj-$(CONFIG_TEST_RUNTIME_MODULE) += module/
diff --git a/lib/tests/bitops_kunit.c b/lib/tests/bitops_kunit.c
new file mode 100644
index 000000000000..7fd9d697f131
--- /dev/null
+++ b/lib/tests/bitops_kunit.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 Intel Corporation
+ * Copyright (C) 2026 Ryota Sakamoto <sakamo.ryota@gmail.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <kunit/test.h>
+
+/* use an enum because that's the most common BITMAP usage */
+enum bitops_fun {
+ BITOPS_4 = 4,
+ BITOPS_7 = 7,
+ BITOPS_11 = 11,
+ BITOPS_31 = 31,
+ BITOPS_88 = 88,
+ BITOPS_LENGTH = 256
+};
+
+struct bitops_test_case {
+ const char *str;
+ const long nr;
+};
+
+static struct bitops_test_case bitops_cases[] = {
+ {
+ .str = "BITOPS_4",
+ .nr = BITOPS_4,
+ },
+ {
+ .str = "BITOPS_7",
+ .nr = BITOPS_7,
+ },
+ {
+ .str = "BITOPS_11",
+ .nr = BITOPS_11,
+ },
+ {
+ .str = "BITOPS_31",
+ .nr = BITOPS_31,
+ },
+ {
+ .str = "BITOPS_88",
+ .nr = BITOPS_88,
+ },
+};
+
+KUNIT_ARRAY_PARAM_DESC(bitops, bitops_cases, str);
+
+static void test_set_bit_clear_bit(struct kunit *test)
+{
+ const struct bitops_test_case *params = test->param_value;
+ DECLARE_BITMAP(bitmap, BITOPS_LENGTH);
+ int bit_set;
+
+ bitmap_zero(bitmap, BITOPS_LENGTH);
+
+ set_bit(params->nr, bitmap);
+ KUNIT_EXPECT_TRUE(test, test_bit(params->nr, bitmap));
+
+ clear_bit(params->nr, bitmap);
+ KUNIT_EXPECT_FALSE(test, test_bit(params->nr, bitmap));
+
+ bit_set = find_first_bit(bitmap, BITOPS_LENGTH);
+ KUNIT_EXPECT_EQ(test, bit_set, BITOPS_LENGTH);
+}
+
+static void test_change_bit(struct kunit *test)
+{
+ const struct bitops_test_case *params = test->param_value;
+ DECLARE_BITMAP(bitmap, BITOPS_LENGTH);
+ int bit_set;
+
+ bitmap_zero(bitmap, BITOPS_LENGTH);
+
+ change_bit(params->nr, bitmap);
+ KUNIT_EXPECT_TRUE(test, test_bit(params->nr, bitmap));
+
+ change_bit(params->nr, bitmap);
+ KUNIT_EXPECT_FALSE(test, test_bit(params->nr, bitmap));
+
+ bit_set = find_first_bit(bitmap, BITOPS_LENGTH);
+ KUNIT_EXPECT_EQ(test, bit_set, BITOPS_LENGTH);
+}
+
+static void test_test_and_set_bit_test_and_clear_bit(struct kunit *test)
+{
+ const struct bitops_test_case *params = test->param_value;
+ DECLARE_BITMAP(bitmap, BITOPS_LENGTH);
+ int bit_set;
+
+ bitmap_zero(bitmap, BITOPS_LENGTH);
+
+ KUNIT_EXPECT_FALSE(test, test_and_set_bit(params->nr, bitmap));
+ KUNIT_EXPECT_TRUE(test, test_bit(params->nr, bitmap));
+
+ KUNIT_EXPECT_TRUE(test, test_and_set_bit(params->nr, bitmap));
+ KUNIT_EXPECT_TRUE(test, test_bit(params->nr, bitmap));
+
+ KUNIT_EXPECT_TRUE(test, test_and_clear_bit(params->nr, bitmap));
+ KUNIT_EXPECT_FALSE(test, test_bit(params->nr, bitmap));
+
+ KUNIT_EXPECT_FALSE(test, test_and_clear_bit(params->nr, bitmap));
+ KUNIT_EXPECT_FALSE(test, test_bit(params->nr, bitmap));
+
+ bit_set = find_first_bit(bitmap, BITOPS_LENGTH);
+ KUNIT_EXPECT_EQ(test, bit_set, BITOPS_LENGTH);
+}
+
+static void test_test_and_change_bit(struct kunit *test)
+{
+ const struct bitops_test_case *params = test->param_value;
+ DECLARE_BITMAP(bitmap, BITOPS_LENGTH);
+ int bit_set;
+
+ bitmap_zero(bitmap, BITOPS_LENGTH);
+
+ KUNIT_EXPECT_FALSE(test, test_and_change_bit(params->nr, bitmap));
+ KUNIT_EXPECT_TRUE(test, test_bit(params->nr, bitmap));
+
+ KUNIT_EXPECT_TRUE(test, test_and_change_bit(params->nr, bitmap));
+ KUNIT_EXPECT_FALSE(test, test_bit(params->nr, bitmap));
+
+ bit_set = find_first_bit(bitmap, BITOPS_LENGTH);
+ KUNIT_EXPECT_EQ(test, bit_set, BITOPS_LENGTH);
+}
+
+struct order_test_case {
+ const char *str;
+ const unsigned int count;
+ const int expected;
+};
+
+static struct order_test_case order_test_cases[] = {
+ {"0x00000003", 0x00000003, 2},
+ {"0x00000004", 0x00000004, 2},
+ {"0x00001fff", 0x00001fff, 13},
+ {"0x00002000", 0x00002000, 13},
+ {"0x50000000", 0x50000000, 31},
+ {"0x80000000", 0x80000000, 31},
+ {"0x80003000", 0x80003000, 32},
+};
+
+KUNIT_ARRAY_PARAM_DESC(order, order_test_cases, str);
+
+static void test_get_count_order(struct kunit *test)
+{
+ const struct order_test_case *params = test->param_value;
+
+ KUNIT_EXPECT_EQ(test, get_count_order(params->count), params->expected);
+ KUNIT_EXPECT_EQ(test, get_count_order_long(params->count), params->expected);
+}
+
+#ifdef CONFIG_64BIT
+struct order_long_test_case {
+ const char *str;
+ const unsigned long count;
+ const int expected;
+};
+
+static struct order_long_test_case order_long_test_cases[] = {
+ {"0x0000000300000000", 0x0000000300000000, 34},
+ {"0x0000000400000000", 0x0000000400000000, 34},
+ {"0x00001fff00000000", 0x00001fff00000000, 45},
+ {"0x0000200000000000", 0x0000200000000000, 45},
+ {"0x5000000000000000", 0x5000000000000000, 63},
+ {"0x8000000000000000", 0x8000000000000000, 63},
+ {"0x8000300000000000", 0x8000300000000000, 64},
+};
+
+KUNIT_ARRAY_PARAM_DESC(order_long, order_long_test_cases, str);
+
+static void test_get_count_order_long(struct kunit *test)
+{
+ const struct order_long_test_case *params = test->param_value;
+
+ KUNIT_EXPECT_EQ(test, get_count_order_long(params->count), params->expected);
+}
+#endif
+
+static struct kunit_case bitops_test_cases[] = {
+ KUNIT_CASE_PARAM(test_set_bit_clear_bit, bitops_gen_params),
+ KUNIT_CASE_PARAM(test_change_bit, bitops_gen_params),
+ KUNIT_CASE_PARAM(test_test_and_set_bit_test_and_clear_bit, bitops_gen_params),
+ KUNIT_CASE_PARAM(test_test_and_change_bit, bitops_gen_params),
+ KUNIT_CASE_PARAM(test_get_count_order, order_gen_params),
+#ifdef CONFIG_64BIT
+ KUNIT_CASE_PARAM(test_get_count_order_long, order_long_gen_params),
+#endif
+ {},
+};
+
+static struct kunit_suite bitops_test_suite = {
+ .name = "bitops",
+ .test_cases = bitops_test_cases,
+};
+
+kunit_test_suite(bitops_test_suite);
+
+MODULE_AUTHOR("Jesse Brandeburg <jesse.brandeburg@intel.com>");
+MODULE_AUTHOR("Wei Yang <richard.weiyang@gmail.com>");
+MODULE_AUTHOR("Ryota Sakamoto <sakamo.ryota@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Bit testing module");
diff --git a/lib/tests/glob_kunit.c b/lib/tests/glob_kunit.c
new file mode 100644
index 000000000000..362b1eda8e5b
--- /dev/null
+++ b/lib/tests/glob_kunit.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: MIT OR GPL-2.0
+/*
+ * Test cases for glob functions.
+ */
+
+#include <kunit/test.h>
+#include <linux/glob.h>
+#include <linux/module.h>
+
+/**
+ * struct glob_test_case - Test case for glob matching.
+ * @pat: Pattern to match.
+ * @str: String to match against.
+ * @expected: Expected glob_match result, true if matched.
+ */
+struct glob_test_case {
+ const char *pat;
+ const char *str;
+ bool expected;
+};
+
+static const struct glob_test_case glob_test_cases[] = {
+ /* Some basic tests */
+ { .pat = "a", .str = "a", .expected = true },
+ { .pat = "a", .str = "b", .expected = false },
+ { .pat = "a", .str = "aa", .expected = false },
+ { .pat = "a", .str = "", .expected = false },
+ { .pat = "", .str = "", .expected = true },
+ { .pat = "", .str = "a", .expected = false },
+ /* Simple character class tests */
+ { .pat = "[a]", .str = "a", .expected = true },
+ { .pat = "[a]", .str = "b", .expected = false },
+ { .pat = "[!a]", .str = "a", .expected = false },
+ { .pat = "[!a]", .str = "b", .expected = true },
+ { .pat = "[ab]", .str = "a", .expected = true },
+ { .pat = "[ab]", .str = "b", .expected = true },
+ { .pat = "[ab]", .str = "c", .expected = false },
+ { .pat = "[!ab]", .str = "c", .expected = true },
+ { .pat = "[a-c]", .str = "b", .expected = true },
+ { .pat = "[a-c]", .str = "d", .expected = false },
+ /* Corner cases in character class parsing */
+ { .pat = "[a-c-e-g]", .str = "-", .expected = true },
+ { .pat = "[a-c-e-g]", .str = "d", .expected = false },
+ { .pat = "[a-c-e-g]", .str = "f", .expected = true },
+ { .pat = "[]a-ceg-ik[]", .str = "a", .expected = true },
+ { .pat = "[]a-ceg-ik[]", .str = "]", .expected = true },
+ { .pat = "[]a-ceg-ik[]", .str = "[", .expected = true },
+ { .pat = "[]a-ceg-ik[]", .str = "h", .expected = true },
+ { .pat = "[]a-ceg-ik[]", .str = "f", .expected = false },
+ { .pat = "[!]a-ceg-ik[]", .str = "h", .expected = false },
+ { .pat = "[!]a-ceg-ik[]", .str = "]", .expected = false },
+ { .pat = "[!]a-ceg-ik[]", .str = "f", .expected = true },
+ /* Simple wild cards */
+ { .pat = "?", .str = "a", .expected = true },
+ { .pat = "?", .str = "aa", .expected = false },
+ { .pat = "??", .str = "a", .expected = false },
+ { .pat = "?x?", .str = "axb", .expected = true },
+ { .pat = "?x?", .str = "abx", .expected = false },
+ { .pat = "?x?", .str = "xab", .expected = false },
+ /* Asterisk wild cards (backtracking) */
+ { .pat = "*??", .str = "a", .expected = false },
+ { .pat = "*??", .str = "ab", .expected = true },
+ { .pat = "*??", .str = "abc", .expected = true },
+ { .pat = "*??", .str = "abcd", .expected = true },
+ { .pat = "??*", .str = "a", .expected = false },
+ { .pat = "??*", .str = "ab", .expected = true },
+ { .pat = "??*", .str = "abc", .expected = true },
+ { .pat = "??*", .str = "abcd", .expected = true },
+ { .pat = "?*?", .str = "a", .expected = false },
+ { .pat = "?*?", .str = "ab", .expected = true },
+ { .pat = "?*?", .str = "abc", .expected = true },
+ { .pat = "?*?", .str = "abcd", .expected = true },
+ { .pat = "*b", .str = "b", .expected = true },
+ { .pat = "*b", .str = "ab", .expected = true },
+ { .pat = "*b", .str = "ba", .expected = false },
+ { .pat = "*b", .str = "bb", .expected = true },
+ { .pat = "*b", .str = "abb", .expected = true },
+ { .pat = "*b", .str = "bab", .expected = true },
+ { .pat = "*bc", .str = "abbc", .expected = true },
+ { .pat = "*bc", .str = "bc", .expected = true },
+ { .pat = "*bc", .str = "bbc", .expected = true },
+ { .pat = "*bc", .str = "bcbc", .expected = true },
+ /* Multiple asterisks (complex backtracking) */
+ { .pat = "*ac*", .str = "abacadaeafag", .expected = true },
+ { .pat = "*ac*ae*ag*", .str = "abacadaeafag", .expected = true },
+ { .pat = "*a*b*[bc]*[ef]*g*", .str = "abacadaeafag", .expected = true },
+ { .pat = "*a*b*[ef]*[cd]*g*", .str = "abacadaeafag", .expected = false },
+ { .pat = "*abcd*", .str = "abcabcabcabcdefg", .expected = true },
+ { .pat = "*ab*cd*", .str = "abcabcabcabcdefg", .expected = true },
+ { .pat = "*abcd*abcdef*", .str = "abcabcdabcdeabcdefg", .expected = true },
+ { .pat = "*abcd*", .str = "abcabcabcabcefg", .expected = false },
+ { .pat = "*ab*cd*", .str = "abcabcabcabcefg", .expected = false },
+};
+
+static void glob_case_to_desc(const struct glob_test_case *t, char *desc)
+{
+ snprintf(desc, KUNIT_PARAM_DESC_SIZE, "pat:\"%s\" str:\"%s\"", t->pat, t->str);
+}
+
+KUNIT_ARRAY_PARAM(glob, glob_test_cases, glob_case_to_desc);
+
+static void glob_test_match(struct kunit *test)
+{
+ const struct glob_test_case *params = test->param_value;
+
+ KUNIT_EXPECT_EQ_MSG(test,
+ glob_match(params->pat, params->str),
+ params->expected,
+ "Pattern: \"%s\", String: \"%s\", Expected: %d",
+ params->pat, params->str, params->expected);
+}
+
+static struct kunit_case glob_kunit_test_cases[] = {
+ KUNIT_CASE_PARAM(glob_test_match, glob_gen_params),
+ {}
+};
+
+static struct kunit_suite glob_test_suite = {
+ .name = "glob",
+ .test_cases = glob_kunit_test_cases,
+};
+
+kunit_test_suite(glob_test_suite);
+MODULE_DESCRIPTION("Test cases for glob functions");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c
index 48342736d016..bb847e5010eb 100644
--- a/lib/tests/kunit_iov_iter.c
+++ b/lib/tests/kunit_iov_iter.c
@@ -387,7 +387,7 @@ static void __init iov_kunit_load_folioq(struct kunit *test,
for (i = 0; i < npages; i++) {
if (folioq_full(p)) {
- p->next = kzalloc(sizeof(struct folio_queue), GFP_KERNEL);
+ p->next = kzalloc_obj(struct folio_queue);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p->next);
folioq_init(p->next, 0);
p->next->prev = p;
@@ -403,7 +403,7 @@ static struct folio_queue *iov_kunit_create_folioq(struct kunit *test)
{
struct folio_queue *folioq;
- folioq = kzalloc(sizeof(struct folio_queue), GFP_KERNEL);
+ folioq = kzalloc_obj(struct folio_queue);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, folioq);
kunit_add_action_or_reset(test, iov_kunit_destroy_folioq, folioq);
folioq_init(folioq, 0);
@@ -565,7 +565,7 @@ static struct xarray *iov_kunit_create_xarray(struct kunit *test)
{
struct xarray *xarray;
- xarray = kzalloc(sizeof(struct xarray), GFP_KERNEL);
+ xarray = kzalloc_obj(struct xarray);
xa_init(xarray);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xarray);
kunit_add_action_or_reset(test, iov_kunit_destroy_xarray, xarray);
diff --git a/lib/tests/list-private-test.c b/lib/tests/list-private-test.c
new file mode 100644
index 000000000000..3bd62939ae67
--- /dev/null
+++ b/lib/tests/list-private-test.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit compilation/smoke test for Private list primitives.
+ *
+ * Copyright (c) 2025, Google LLC.
+ * Pasha Tatashin <pasha.tatashin@soleen.com>
+ */
+#include <linux/list_private.h>
+#include <kunit/test.h>
+
+/*
+ * This forces compiler to warn if you access it directly, because list
+ * primitives expect (struct list_head *), not (volatile struct list_head *).
+ */
+#undef __private
+#define __private volatile
+
+/* Redefine ACCESS_PRIVATE for this test. */
+#undef ACCESS_PRIVATE
+#define ACCESS_PRIVATE(p, member) \
+ (*((struct list_head *)((unsigned long)&((p)->member))))
+
+struct list_test_struct {
+ int data;
+ struct list_head __private list;
+};
+
+static void list_private_compile_test(struct kunit *test)
+{
+ struct list_test_struct entry;
+ struct list_test_struct *pos, *n;
+ LIST_HEAD(head);
+
+ INIT_LIST_HEAD(&ACCESS_PRIVATE(&entry, list));
+ list_add(&ACCESS_PRIVATE(&entry, list), &head);
+ pos = &entry;
+
+ pos = list_private_entry(&ACCESS_PRIVATE(&entry, list), struct list_test_struct, list);
+ pos = list_private_first_entry(&head, struct list_test_struct, list);
+ pos = list_private_last_entry(&head, struct list_test_struct, list);
+ pos = list_private_next_entry(pos, list);
+ pos = list_private_prev_entry(pos, list);
+ pos = list_private_next_entry_circular(pos, &head, list);
+ pos = list_private_prev_entry_circular(pos, &head, list);
+
+ if (list_private_entry_is_head(pos, &head, list))
+ return;
+
+ list_private_for_each_entry(pos, &head, list) { }
+ list_private_for_each_entry_reverse(pos, &head, list) { }
+ list_private_for_each_entry_continue(pos, &head, list) { }
+ list_private_for_each_entry_continue_reverse(pos, &head, list) { }
+ list_private_for_each_entry_from(pos, &head, list) { }
+ list_private_for_each_entry_from_reverse(pos, &head, list) { }
+
+ list_private_for_each_entry_safe(pos, n, &head, list)
+ list_private_safe_reset_next(pos, n, list);
+ list_private_for_each_entry_safe_continue(pos, n, &head, list) { }
+ list_private_for_each_entry_safe_from(pos, n, &head, list) { }
+ list_private_for_each_entry_safe_reverse(pos, n, &head, list) { }
+}
+
+static struct kunit_case list_private_test_cases[] = {
+ KUNIT_CASE(list_private_compile_test),
+ {},
+};
+
+static struct kunit_suite list_private_test_module = {
+ .name = "list-private-kunit-test",
+ .test_cases = list_private_test_cases,
+};
+
+kunit_test_suite(list_private_test_module);
+
+MODULE_DESCRIPTION("KUnit compilation test for private list primitives");
+MODULE_LICENSE("GPL");
diff --git a/lib/tests/list-test.c b/lib/tests/list-test.c
index 9135cdc1bb39..6d9227a2b204 100644
--- a/lib/tests/list-test.c
+++ b/lib/tests/list-test.c
@@ -26,10 +26,10 @@ static void list_test_list_init(struct kunit *test)
INIT_LIST_HEAD(&list2);
- list4 = kzalloc(sizeof(*list4), GFP_KERNEL | __GFP_NOFAIL);
+ list4 = kzalloc_obj(*list4, GFP_KERNEL | __GFP_NOFAIL);
INIT_LIST_HEAD(list4);
- list5 = kmalloc(sizeof(*list5), GFP_KERNEL | __GFP_NOFAIL);
+ list5 = kmalloc_obj(*list5, GFP_KERNEL | __GFP_NOFAIL);
memset(list5, 0xFF, sizeof(*list5));
INIT_LIST_HEAD(list5);
@@ -829,10 +829,10 @@ static void hlist_test_init(struct kunit *test)
INIT_HLIST_HEAD(&list2);
- list4 = kzalloc(sizeof(*list4), GFP_KERNEL | __GFP_NOFAIL);
+ list4 = kzalloc_obj(*list4, GFP_KERNEL | __GFP_NOFAIL);
INIT_HLIST_HEAD(list4);
- list5 = kmalloc(sizeof(*list5), GFP_KERNEL | __GFP_NOFAIL);
+ list5 = kmalloc_obj(*list5, GFP_KERNEL | __GFP_NOFAIL);
memset(list5, 0xFF, sizeof(*list5));
INIT_HLIST_HEAD(list5);
diff --git a/lib/tests/liveupdate.c b/lib/tests/liveupdate.c
new file mode 100644
index 000000000000..496d6ef91a30
--- /dev/null
+++ b/lib/tests/liveupdate.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2025, Google LLC.
+ * Pasha Tatashin <pasha.tatashin@soleen.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME " test: " fmt
+
+#include <linux/cleanup.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/liveupdate.h>
+#include <linux/module.h>
+#include "../../kernel/liveupdate/luo_internal.h"
+
+static const struct liveupdate_flb_ops test_flb_ops;
+#define DEFINE_TEST_FLB(i) { \
+ .ops = &test_flb_ops, \
+ .compatible = LIVEUPDATE_TEST_FLB_COMPATIBLE(i), \
+}
+
+/* Number of Test FLBs to register with every file handler */
+#define TEST_NFLBS 3
+static struct liveupdate_flb test_flbs[TEST_NFLBS] = {
+ DEFINE_TEST_FLB(0),
+ DEFINE_TEST_FLB(1),
+ DEFINE_TEST_FLB(2),
+};
+
+#define TEST_FLB_MAGIC_BASE 0xFEEDF00DCAFEBEE0ULL
+
+static int test_flb_preserve(struct liveupdate_flb_op_args *argp)
+{
+ ptrdiff_t index = argp->flb - test_flbs;
+
+ pr_info("%s: preserve was triggered\n", argp->flb->compatible);
+ argp->data = TEST_FLB_MAGIC_BASE + index;
+
+ return 0;
+}
+
+static void test_flb_unpreserve(struct liveupdate_flb_op_args *argp)
+{
+ pr_info("%s: unpreserve was triggered\n", argp->flb->compatible);
+}
+
+static int test_flb_retrieve(struct liveupdate_flb_op_args *argp)
+{
+ ptrdiff_t index = argp->flb - test_flbs;
+ u64 expected_data = TEST_FLB_MAGIC_BASE + index;
+
+ if (argp->data == expected_data) {
+ pr_info("%s: found flb data from the previous boot\n",
+ argp->flb->compatible);
+ argp->obj = (void *)argp->data;
+ } else {
+ pr_err("%s: ERROR - incorrect data handle: %llx, expected %llx\n",
+ argp->flb->compatible, argp->data, expected_data);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void test_flb_finish(struct liveupdate_flb_op_args *argp)
+{
+ ptrdiff_t index = argp->flb - test_flbs;
+ void *expected_obj = (void *)(TEST_FLB_MAGIC_BASE + index);
+
+ if (argp->obj == expected_obj) {
+ pr_info("%s: finish was triggered\n", argp->flb->compatible);
+ } else {
+ pr_err("%s: ERROR - finish called with invalid object\n",
+ argp->flb->compatible);
+ }
+}
+
+static const struct liveupdate_flb_ops test_flb_ops = {
+ .preserve = test_flb_preserve,
+ .unpreserve = test_flb_unpreserve,
+ .retrieve = test_flb_retrieve,
+ .finish = test_flb_finish,
+ .owner = THIS_MODULE,
+};
+
+static void liveupdate_test_init(void)
+{
+ static DEFINE_MUTEX(init_lock);
+ static bool initialized;
+ int i;
+
+ guard(mutex)(&init_lock);
+
+ if (initialized)
+ return;
+
+ for (i = 0; i < TEST_NFLBS; i++) {
+ struct liveupdate_flb *flb = &test_flbs[i];
+ void *obj;
+ int err;
+
+ err = liveupdate_flb_get_incoming(flb, &obj);
+ if (err && err != -ENODATA && err != -ENOENT) {
+ pr_err("liveupdate_flb_get_incoming for %s failed: %pe\n",
+ flb->compatible, ERR_PTR(err));
+ }
+ }
+ initialized = true;
+}
+
+void liveupdate_test_register(struct liveupdate_file_handler *fh)
+{
+ int err, i;
+
+ liveupdate_test_init();
+
+ for (i = 0; i < TEST_NFLBS; i++) {
+ struct liveupdate_flb *flb = &test_flbs[i];
+
+ err = liveupdate_register_flb(fh, flb);
+ if (err) {
+ pr_err("Failed to register %s %pe\n",
+ flb->compatible, ERR_PTR(err));
+ }
+ }
+
+ err = liveupdate_register_flb(fh, &test_flbs[0]);
+ if (!err || err != -EEXIST) {
+ pr_err("Failed: %s should be already registered, but got err: %pe\n",
+ test_flbs[0].compatible, ERR_PTR(err));
+ }
+
+ pr_info("Registered %d FLBs with file handler: [%s]\n",
+ TEST_NFLBS, fh->compatible);
+}
+
+void liveupdate_test_unregister(struct liveupdate_file_handler *fh)
+{
+ int err, i;
+
+ for (i = 0; i < TEST_NFLBS; i++) {
+ struct liveupdate_flb *flb = &test_flbs[i];
+
+ err = liveupdate_unregister_flb(fh, flb);
+ if (err) {
+ pr_err("Failed to unregister %s %pe\n",
+ flb->compatible, ERR_PTR(err));
+ }
+ }
+
+ pr_info("Unregistered %d FLBs from file handler: [%s]\n",
+ TEST_NFLBS, fh->compatible);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pasha Tatashin <pasha.tatashin@soleen.com>");
+MODULE_DESCRIPTION("In-kernel test for LUO mechanism");
diff --git a/lib/test_min_heap.c b/lib/tests/min_heap_kunit.c
index a9c4a74d3898..9c1122661698 100644
--- a/lib/test_min_heap.c
+++ b/lib/tests/min_heap_kunit.c
@@ -1,60 +1,66 @@
// SPDX-License-Identifier: GPL-2.0-only
-#define pr_fmt(fmt) "min_heap_test: " fmt
-
/*
* Test cases for the min max heap.
*/
-#include <linux/log2.h>
+#include <kunit/test.h>
#include <linux/min_heap.h>
#include <linux/module.h>
-#include <linux/printk.h>
#include <linux/random.h>
+struct min_heap_test_case {
+ const char *str;
+ bool min_heap;
+};
+
+static struct min_heap_test_case min_heap_cases[] = {
+ {
+ .str = "min",
+ .min_heap = true,
+ },
+ {
+ .str = "max",
+ .min_heap = false,
+ },
+};
+
+KUNIT_ARRAY_PARAM_DESC(min_heap, min_heap_cases, str);
+
DEFINE_MIN_HEAP(int, min_heap_test);
-static __init bool less_than(const void *lhs, const void *rhs, void __always_unused *args)
+static bool less_than(const void *lhs, const void *rhs, void __always_unused *args)
{
return *(int *)lhs < *(int *)rhs;
}
-static __init bool greater_than(const void *lhs, const void *rhs, void __always_unused *args)
+static bool greater_than(const void *lhs, const void *rhs, void __always_unused *args)
{
return *(int *)lhs > *(int *)rhs;
}
-static __init int pop_verify_heap(bool min_heap,
- struct min_heap_test *heap,
- const struct min_heap_callbacks *funcs)
+static void pop_verify_heap(struct kunit *test,
+ bool min_heap,
+ struct min_heap_test *heap,
+ const struct min_heap_callbacks *funcs)
{
int *values = heap->data;
- int err = 0;
int last;
last = values[0];
min_heap_pop_inline(heap, funcs, NULL);
while (heap->nr > 0) {
- if (min_heap) {
- if (last > values[0]) {
- pr_err("error: expected %d <= %d\n", last,
- values[0]);
- err++;
- }
- } else {
- if (last < values[0]) {
- pr_err("error: expected %d >= %d\n", last,
- values[0]);
- err++;
- }
- }
+ if (min_heap)
+ KUNIT_EXPECT_LE(test, last, values[0]);
+ else
+ KUNIT_EXPECT_GE(test, last, values[0]);
last = values[0];
min_heap_pop_inline(heap, funcs, NULL);
}
- return err;
}
-static __init int test_heapify_all(bool min_heap)
+static void test_heapify_all(struct kunit *test)
{
+ const struct min_heap_test_case *params = test->param_value;
int values[] = { 3, 1, 2, 4, 0x8000000, 0x7FFFFFF, 0,
-3, -1, -2, -4, 0x8000000, 0x7FFFFFF };
struct min_heap_test heap = {
@@ -63,15 +69,14 @@ static __init int test_heapify_all(bool min_heap)
.size = ARRAY_SIZE(values),
};
struct min_heap_callbacks funcs = {
- .less = min_heap ? less_than : greater_than,
+ .less = params->min_heap ? less_than : greater_than,
.swp = NULL,
};
- int i, err;
+ int i;
/* Test with known set of values. */
min_heapify_all_inline(&heap, &funcs, NULL);
- err = pop_verify_heap(min_heap, &heap, &funcs);
-
+ pop_verify_heap(test, params->min_heap, &heap, &funcs);
/* Test with randomly generated values. */
heap.nr = ARRAY_SIZE(values);
@@ -79,13 +84,12 @@ static __init int test_heapify_all(bool min_heap)
values[i] = get_random_u32();
min_heapify_all_inline(&heap, &funcs, NULL);
- err += pop_verify_heap(min_heap, &heap, &funcs);
-
- return err;
+ pop_verify_heap(test, params->min_heap, &heap, &funcs);
}
-static __init int test_heap_push(bool min_heap)
+static void test_heap_push(struct kunit *test)
{
+ const struct min_heap_test_case *params = test->param_value;
const int data[] = { 3, 1, 2, 4, 0x80000000, 0x7FFFFFFF, 0,
-3, -1, -2, -4, 0x80000000, 0x7FFFFFFF };
int values[ARRAY_SIZE(data)];
@@ -95,29 +99,28 @@ static __init int test_heap_push(bool min_heap)
.size = ARRAY_SIZE(values),
};
struct min_heap_callbacks funcs = {
- .less = min_heap ? less_than : greater_than,
+ .less = params->min_heap ? less_than : greater_than,
.swp = NULL,
};
- int i, temp, err;
+ int i, temp;
/* Test with known set of values copied from data. */
for (i = 0; i < ARRAY_SIZE(data); i++)
min_heap_push_inline(&heap, &data[i], &funcs, NULL);
- err = pop_verify_heap(min_heap, &heap, &funcs);
+ pop_verify_heap(test, params->min_heap, &heap, &funcs);
/* Test with randomly generated values. */
while (heap.nr < heap.size) {
temp = get_random_u32();
min_heap_push_inline(&heap, &temp, &funcs, NULL);
}
- err += pop_verify_heap(min_heap, &heap, &funcs);
-
- return err;
+ pop_verify_heap(test, params->min_heap, &heap, &funcs);
}
-static __init int test_heap_pop_push(bool min_heap)
+static void test_heap_pop_push(struct kunit *test)
{
+ const struct min_heap_test_case *params = test->param_value;
const int data[] = { 3, 1, 2, 4, 0x80000000, 0x7FFFFFFF, 0,
-3, -1, -2, -4, 0x80000000, 0x7FFFFFFF };
int values[ARRAY_SIZE(data)];
@@ -127,13 +130,13 @@ static __init int test_heap_pop_push(bool min_heap)
.size = ARRAY_SIZE(values),
};
struct min_heap_callbacks funcs = {
- .less = min_heap ? less_than : greater_than,
+ .less = params->min_heap ? less_than : greater_than,
.swp = NULL,
};
- int i, temp, err;
+ int i, temp;
/* Fill values with data to pop and replace. */
- temp = min_heap ? 0x80000000 : 0x7FFFFFFF;
+ temp = params->min_heap ? 0x80000000 : 0x7FFFFFFF;
for (i = 0; i < ARRAY_SIZE(data); i++)
min_heap_push_inline(&heap, &temp, &funcs, NULL);
@@ -141,7 +144,7 @@ static __init int test_heap_pop_push(bool min_heap)
for (i = 0; i < ARRAY_SIZE(data); i++)
min_heap_pop_push_inline(&heap, &data[i], &funcs, NULL);
- err = pop_verify_heap(min_heap, &heap, &funcs);
+ pop_verify_heap(test, params->min_heap, &heap, &funcs);
heap.nr = 0;
for (i = 0; i < ARRAY_SIZE(data); i++)
@@ -152,13 +155,12 @@ static __init int test_heap_pop_push(bool min_heap)
temp = get_random_u32();
min_heap_pop_push_inline(&heap, &temp, &funcs, NULL);
}
- err += pop_verify_heap(min_heap, &heap, &funcs);
-
- return err;
+ pop_verify_heap(test, params->min_heap, &heap, &funcs);
}
-static __init int test_heap_del(bool min_heap)
+static void test_heap_del(struct kunit *test)
{
+ const struct min_heap_test_case *params = test->param_value;
int values[] = { 3, 1, 2, 4, 0x8000000, 0x7FFFFFF, 0,
-3, -1, -2, -4, 0x8000000, 0x7FFFFFF };
struct min_heap_test heap;
@@ -166,17 +168,16 @@ static __init int test_heap_del(bool min_heap)
min_heap_init_inline(&heap, values, ARRAY_SIZE(values));
heap.nr = ARRAY_SIZE(values);
struct min_heap_callbacks funcs = {
- .less = min_heap ? less_than : greater_than,
+ .less = params->min_heap ? less_than : greater_than,
.swp = NULL,
};
- int i, err;
+ int i;
/* Test with known set of values. */
min_heapify_all_inline(&heap, &funcs, NULL);
for (i = 0; i < ARRAY_SIZE(values) / 2; i++)
min_heap_del_inline(&heap, get_random_u32() % heap.nr, &funcs, NULL);
- err = pop_verify_heap(min_heap, &heap, &funcs);
-
+ pop_verify_heap(test, params->min_heap, &heap, &funcs);
/* Test with randomly generated values. */
heap.nr = ARRAY_SIZE(values);
@@ -186,37 +187,23 @@ static __init int test_heap_del(bool min_heap)
for (i = 0; i < ARRAY_SIZE(values) / 2; i++)
min_heap_del_inline(&heap, get_random_u32() % heap.nr, &funcs, NULL);
- err += pop_verify_heap(min_heap, &heap, &funcs);
-
- return err;
+ pop_verify_heap(test, params->min_heap, &heap, &funcs);
}
-static int __init test_min_heap_init(void)
-{
- int err = 0;
-
- err += test_heapify_all(true);
- err += test_heapify_all(false);
- err += test_heap_push(true);
- err += test_heap_push(false);
- err += test_heap_pop_push(true);
- err += test_heap_pop_push(false);
- err += test_heap_del(true);
- err += test_heap_del(false);
- if (err) {
- pr_err("test failed with %d errors\n", err);
- return -EINVAL;
- }
- pr_info("test passed\n");
- return 0;
-}
-module_init(test_min_heap_init);
+static struct kunit_case min_heap_test_cases[] = {
+ KUNIT_CASE_PARAM(test_heapify_all, min_heap_gen_params),
+ KUNIT_CASE_PARAM(test_heap_push, min_heap_gen_params),
+ KUNIT_CASE_PARAM(test_heap_pop_push, min_heap_gen_params),
+ KUNIT_CASE_PARAM(test_heap_del, min_heap_gen_params),
+ {},
+};
-static void __exit test_min_heap_exit(void)
-{
- /* do nothing */
-}
-module_exit(test_min_heap_exit);
+static struct kunit_suite min_heap_test_suite = {
+ .name = "min_heap",
+ .test_cases = min_heap_test_cases,
+};
+
+kunit_test_suite(min_heap_test_suite);
MODULE_DESCRIPTION("Test cases for the min max heap");
MODULE_LICENSE("GPL");
diff --git a/lib/tests/printf_kunit.c b/lib/tests/printf_kunit.c
index 7617e5b8b02c..f6f21b445ece 100644
--- a/lib/tests/printf_kunit.c
+++ b/lib/tests/printf_kunit.c
@@ -266,15 +266,17 @@ hash_pointer(struct kunit *kunittest)
KUNIT_EXPECT_MEMNEQ(kunittest, buf, PTR_STR, PTR_WIDTH);
}
-static void
-test_hashed(struct kunit *kunittest, const char *fmt, const void *p)
-{
- char buf[PLAIN_BUF_SIZE];
-
- plain_hash_to_buffer(kunittest, p, buf, PLAIN_BUF_SIZE);
-
- test(buf, fmt, p);
-}
+/*
+ * This is a macro so that the compiler can compare its arguments to the
+ * __printf() attribute on __test(). This cannot be a function with a __printf()
+ * attribute because GCC requires __printf() functions to be variadic.
+ */
+#define test_hashed(kunittest, fmt, p) \
+ do { \
+ char buf[PLAIN_BUF_SIZE]; \
+ plain_hash_to_buffer(kunittest, p, buf, PLAIN_BUF_SIZE); \
+ test(buf, fmt, p); \
+ } while (0)
/*
* NULL pointers aren't hashed.
diff --git a/lib/tests/test_list_sort.c b/lib/tests/test_list_sort.c
index 30879abc8a42..28158557b164 100644
--- a/lib/tests/test_list_sort.c
+++ b/lib/tests/test_list_sort.c
@@ -26,7 +26,7 @@ struct debug_el {
unsigned int serial;
};
-static void check(struct kunit *test, struct debug_el *ela, struct debug_el *elb)
+static void check(struct kunit *test, const struct debug_el *ela, const struct debug_el *elb)
{
struct debug_el **elts = test->priv;
@@ -46,7 +46,7 @@ static void check(struct kunit *test, struct debug_el *ela, struct debug_el *elb
/* `priv` is the test pointer so check() can fail the test if the list is invalid. */
static int cmp(void *priv, const struct list_head *a, const struct list_head *b)
{
- struct debug_el *ela, *elb;
+ const struct debug_el *ela, *elb;
ela = container_of(a, struct debug_el, list);
elb = container_of(b, struct debug_el, list);
diff --git a/lib/tests/test_ratelimit.c b/lib/tests/test_ratelimit.c
index bfaeca49304a..33cea5f3d28b 100644
--- a/lib/tests/test_ratelimit.c
+++ b/lib/tests/test_ratelimit.c
@@ -104,7 +104,7 @@ static void test_ratelimit_stress(struct kunit *test)
int i;
const int n_stress_kthread = cpumask_weight(cpu_online_mask);
struct stress_kthread skt = { 0 };
- struct stress_kthread *sktp = kcalloc(n_stress_kthread, sizeof(*sktp), GFP_KERNEL);
+ struct stress_kthread *sktp = kzalloc_objs(*sktp, n_stress_kthread);
KUNIT_EXPECT_NOT_NULL_MSG(test, sktp, "Memory allocation failure");
for (i = 0; i < n_stress_kthread; i++) {
diff --git a/lib/tests/uuid_kunit.c b/lib/tests/uuid_kunit.c
new file mode 100644
index 000000000000..de71b2649dac
--- /dev/null
+++ b/lib/tests/uuid_kunit.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/*
+ * Test cases for lib/uuid.c module.
+ */
+
+#include <kunit/test.h>
+#include <linux/uuid.h>
+
+struct test_uuid_data {
+ const char *uuid;
+ guid_t le;
+ uuid_t be;
+};
+
+static const struct test_uuid_data test_uuid_test_data[] = {
+ {
+ .uuid = "c33f4995-3701-450e-9fbf-206a2e98e576",
+ .le = GUID_INIT(0xc33f4995, 0x3701, 0x450e, 0x9f, 0xbf, 0x20, 0x6a, 0x2e, 0x98, 0xe5, 0x76),
+ .be = UUID_INIT(0xc33f4995, 0x3701, 0x450e, 0x9f, 0xbf, 0x20, 0x6a, 0x2e, 0x98, 0xe5, 0x76),
+ },
+ {
+ .uuid = "64b4371c-77c1-48f9-8221-29f054fc023b",
+ .le = GUID_INIT(0x64b4371c, 0x77c1, 0x48f9, 0x82, 0x21, 0x29, 0xf0, 0x54, 0xfc, 0x02, 0x3b),
+ .be = UUID_INIT(0x64b4371c, 0x77c1, 0x48f9, 0x82, 0x21, 0x29, 0xf0, 0x54, 0xfc, 0x02, 0x3b),
+ },
+ {
+ .uuid = "0cb4ddff-a545-4401-9d06-688af53e7f84",
+ .le = GUID_INIT(0x0cb4ddff, 0xa545, 0x4401, 0x9d, 0x06, 0x68, 0x8a, 0xf5, 0x3e, 0x7f, 0x84),
+ .be = UUID_INIT(0x0cb4ddff, 0xa545, 0x4401, 0x9d, 0x06, 0x68, 0x8a, 0xf5, 0x3e, 0x7f, 0x84),
+ },
+};
+
+static const char * const test_uuid_wrong_data[] = {
+ "c33f4995-3701-450e-9fbf206a2e98e576 ", /* no hyphen(s) */
+ "64b4371c-77c1-48f9-8221-29f054XX023b", /* invalid character(s) */
+ "0cb4ddff-a545-4401-9d06-688af53e", /* not enough data */
+};
+
+static void uuid_test_guid_valid(struct kunit *test)
+{
+ unsigned int i;
+ const struct test_uuid_data *data;
+ guid_t le;
+
+ for (i = 0; i < ARRAY_SIZE(test_uuid_test_data); i++) {
+ data = &test_uuid_test_data[i];
+ KUNIT_EXPECT_EQ(test, guid_parse(data->uuid, &le), 0);
+ KUNIT_EXPECT_TRUE(test, guid_equal(&data->le, &le));
+ }
+}
+
+static void uuid_test_uuid_valid(struct kunit *test)
+{
+ unsigned int i;
+ const struct test_uuid_data *data;
+ uuid_t be;
+
+ for (i = 0; i < ARRAY_SIZE(test_uuid_test_data); i++) {
+ data = &test_uuid_test_data[i];
+ KUNIT_EXPECT_EQ(test, uuid_parse(data->uuid, &be), 0);
+ KUNIT_EXPECT_TRUE(test, uuid_equal(&data->be, &be));
+ }
+}
+
+static void uuid_test_guid_invalid(struct kunit *test)
+{
+ unsigned int i;
+ const char *uuid;
+ guid_t le;
+
+ for (i = 0; i < ARRAY_SIZE(test_uuid_wrong_data); i++) {
+ uuid = test_uuid_wrong_data[i];
+ KUNIT_EXPECT_EQ(test, guid_parse(uuid, &le), -EINVAL);
+ }
+}
+
+static void uuid_test_uuid_invalid(struct kunit *test)
+{
+ unsigned int i;
+ const char *uuid;
+ uuid_t be;
+
+ for (i = 0; i < ARRAY_SIZE(test_uuid_wrong_data); i++) {
+ uuid = test_uuid_wrong_data[i];
+ KUNIT_EXPECT_EQ(test, uuid_parse(uuid, &be), -EINVAL);
+ }
+}
+
+static struct kunit_case uuid_test_cases[] = {
+ KUNIT_CASE(uuid_test_guid_valid),
+ KUNIT_CASE(uuid_test_uuid_valid),
+ KUNIT_CASE(uuid_test_guid_invalid),
+ KUNIT_CASE(uuid_test_uuid_invalid),
+ {},
+};
+
+static struct kunit_suite uuid_test_suite = {
+ .name = "uuid",
+ .test_cases = uuid_test_cases,
+};
+
+kunit_test_suite(uuid_test_suite);
+
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
+MODULE_DESCRIPTION("Test cases for lib/uuid.c module");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/lib/uuid.c b/lib/uuid.c
index e309b4c5be3d..e8543c668dc7 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -10,6 +10,7 @@
#include <linux/ctype.h>
#include <linux/errno.h>
#include <linux/export.h>
+#include <linux/hex.h>
#include <linux/uuid.h>
#include <linux/random.h>
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c
index 95df0153f05a..4399e143d43a 100644
--- a/lib/vdso/gettimeofday.c
+++ b/lib/vdso/gettimeofday.c
@@ -421,7 +421,7 @@ static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time
#endif /* VDSO_HAS_TIME */
#ifdef VDSO_HAS_CLOCK_GETRES
-static __maybe_unused
+static __always_inline
bool __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t clock,
struct __kernel_timespec *res)
{
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index a3790c43a0ab..800b8ac49f53 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -26,6 +26,7 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ctype.h>
+#include <linux/hex.h>
#include <linux/kernel.h>
#include <linux/kallsyms.h>
#include <linux/math64.h>
diff --git a/lib/xz/xz_dec_bcj.c b/lib/xz/xz_dec_bcj.c
index 610d58d947ab..cc49a300a5b2 100644
--- a/lib/xz/xz_dec_bcj.c
+++ b/lib/xz/xz_dec_bcj.c
@@ -591,7 +591,7 @@ enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, struct xz_dec_lzma2 *lzma2,
struct xz_dec_bcj *xz_dec_bcj_create(bool single_call)
{
- struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ struct xz_dec_bcj *s = kmalloc_obj(*s);
if (s != NULL)
s->single_call = single_call;
diff --git a/lib/xz/xz_dec_lzma2.c b/lib/xz/xz_dec_lzma2.c
index 83bb66b6016d..4b783ac94e71 100644
--- a/lib/xz/xz_dec_lzma2.c
+++ b/lib/xz/xz_dec_lzma2.c
@@ -1138,7 +1138,7 @@ enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, struct xz_buf *b)
struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode, uint32_t dict_max)
{
- struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ struct xz_dec_lzma2 *s = kmalloc_obj(*s);
if (s == NULL)
return NULL;
@@ -1296,7 +1296,7 @@ struct xz_dec_microlzma *xz_dec_microlzma_alloc(enum xz_mode mode,
if (dict_size < 4096 || dict_size > (3U << 30))
return NULL;
- s = kmalloc(sizeof(*s), GFP_KERNEL);
+ s = kmalloc_obj(*s);
if (s == NULL)
return NULL;
diff --git a/lib/xz/xz_dec_stream.c b/lib/xz/xz_dec_stream.c
index f9d003684d56..59bfd54ffee7 100644
--- a/lib/xz/xz_dec_stream.c
+++ b/lib/xz/xz_dec_stream.c
@@ -784,7 +784,7 @@ enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
{
- struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ struct xz_dec *s = kmalloc_obj(*s);
if (s == NULL)
return NULL;
diff --git a/lib/zlib_inflate/infutil.c b/lib/zlib_inflate/infutil.c
index 4824c2cc7a09..12169aacd3f1 100644
--- a/lib/zlib_inflate/infutil.c
+++ b/lib/zlib_inflate/infutil.c
@@ -14,7 +14,7 @@ int zlib_inflate_blob(void *gunzip_buf, unsigned int sz,
int rc;
rc = -ENOMEM;
- strm = kmalloc(sizeof(*strm), GFP_KERNEL);
+ strm = kmalloc_obj(*strm);
if (strm == NULL)
goto gunzip_nomem1;
strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);