[PATCH v1 5/5] tests/qtest/aspeed-acry-test: Add RSA ModExp tests

Jamin Lin <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <[email protected]>
Add qtest cases exercising the AST2600 ACRY RSA ModExp engine end to
end. Each case lays out the exponent, modulus and message in the
scattered SRAM byte layout the engine expects, triggers the
engine, checks that both completion bits (RSA_ENG_DONE and
RSA_DMA_DONE) are asserted together in the status register, reads the
result back from the result SRAM, and checks the status bits clear
afterwards.

Comparing the result against a known-answer ciphertext
also validates the SRAM byte mapping end to end.

The cases cover raw (unpadded) public-exponent RSA, c = m^e mod n -
exactly what the "rsa" akcipher transform backed by the ACRY FW
performs, since PKCS1 padding is applied by a separate template
layered on top in Linux, not by the ACRY hardware. QEMU's akcipher
backend only implements raw RSA via libgcrypt, so the tests skip
rather than fail when the build lacks it.

The 2048- and 4096-bit vectors are rsa_tv_template[2] and [3] from the
Linux kernel crypto self-test suite (crypto/testmgr.h, v6.18); the
4096-bit one matches the sha512,rsa4096 key size the FW uses.

Signed-off-by: Jamin Lin <[email protected]>
---
 tests/qtest/aspeed-acry-test.c | 408 +++++++++++++++++++++++++++++++++
 tests/qtest/meson.build        |   5 +-
 2 files changed, 412 insertions(+), 1 deletion(-)
 create mode 100644 tests/qtest/aspeed-acry-test.c

diff --git a/tests/qtest/aspeed-acry-test.c b/tests/qtest/aspeed-acry-test.c
new file mode 100644
index 0000000000..a774844701
--- /dev/null
+++ b/tests/qtest/aspeed-acry-test.c
@@ -0,0 +1,408 @@
+/*
+ * QTest testcase for the ASPEED ACRY Engine
+ *
+ * Copyright (C) 2026 ASPEED Technology Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/bitops.h"
+#include "crypto/akcipher.h"
+
+#define ACRY_TRIGGER                0x000
+#define  ACRY_TRIGGER_RSA_START     BIT(0)
+#define  ACRY_TRIGGER_RSA_DMA_DATA  BIT(1)
+#define ACRY_DMA_CMD                0x048
+#define  ACRY_DMA_CMD_DMEM_AHB      BIT(8)
+#define  ACRY_DMA_CMD_SRAM_MODE_RSA (0x3 << 4)
+#define ACRY_DMA_SRC                0x04C
+#define ACRY_DMA_LEN                0x050
+#define ACRY_RSA_KEY_LEN            0x058
+#define ACRY_INT_MASK               0x3F8
+#define  ACRY_INT_MASK_RSA_ENG_MASK BIT(1)
+#define  ACRY_INT_MASK_RSA_DMA_MASK BIT(2)
+#define ACRY_STATUS                 0x3FC
+#define  ACRY_STATUS_RSA_ENG_DONE   BIT(1)
+#define  ACRY_STATUS_RSA_DMA_DONE   BIT(2)
+#define  ACRY_STATUS_RSA_DONE       (ACRY_STATUS_RSA_ENG_DONE | \
+                                     ACRY_STATUS_RSA_DMA_DONE)
+
+#define ACRY_DATA_MAX_LEN 0x800
+#define ACRY_SRAM_SIZE    (3 * ACRY_DATA_MAX_LEN)
+#define ACRY_MAX_BITS     4096
+#define ACRY_MAX_BYTES    (ACRY_MAX_BITS / 8)
+
+/*
+ * Raw (unpadded) RSA known-answer vectors: c = m^e mod n with
+ * e = 0x10001 (65537) - exactly what the "rsa" akcipher transform backed by
+ * the ACRY FW computes. PKCS1 padding is a separate "pkcs1pad(rsa)" template
+ * layered on top in Linux, not done by the ACRY hardware.
+ *
+ * rsa2048_* and rsa4096_* are from the Linux kernel crypto/testmgr.h (v6.18),
+ * rsa_tv_template[2] and [3]. Grep that file's own comment to find them:
+ *
+ *   RSA test vectors. Borrowed from openSSL.
+ *
+ *   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/crypto/testmgr.h?h=v6.18
+ *
+ * There the modulus n is DER-encoded in the .key field (not a raw field), the
+ * ciphertext is .c, and every entry reuses the same 8-byte .m message.
+ */
+/* rsa_tv_template[].m, shared by every entry */
+static const uint8_t rsa_m[8] = {
+    0x54, 0x85, 0x9B, 0x34, 0x2C, 0x49, 0xEA, 0x2A,
+};
+/* public exponent e = 65537, DER-encoded in every .key */
+static const uint8_t rsa_e[3] = { 0x01, 0x00, 0x01 };
+
+/* rsa_tv_template[2].key, modulus n */
+static const uint8_t rsa2048_n[256] = {
+    0xDB, 0x10, 0x1A, 0xC2, 0xA3, 0xF1, 0xDC, 0xFF, 0x13, 0x6B, 0xED, 0x44,
+    0xDF, 0xF0, 0x02, 0x6D, 0x13, 0xC7, 0x88, 0xDA, 0x70, 0x6B, 0x54, 0xF1,
+    0xE8, 0x27, 0xDC, 0xC3, 0x0F, 0x99, 0x6A, 0xFA, 0xC6, 0x67, 0xFF, 0x1D,
+    0x1E, 0x3C, 0x1D, 0xC1, 0xB5, 0x5F, 0x6C, 0xC0, 0xB2, 0x07, 0x3A, 0x6D,
+    0x41, 0xE4, 0x25, 0x99, 0xAC, 0xFC, 0xD2, 0x0F, 0x02, 0xD3, 0xD1, 0x54,
+    0x06, 0x1A, 0x51, 0x77, 0xBD, 0xB6, 0xBF, 0xEA, 0xA7, 0x5C, 0x06, 0xA9,
+    0x5D, 0x69, 0x84, 0x45, 0xD7, 0xF5, 0x05, 0xBA, 0x47, 0xF0, 0x1B, 0xD7,
+    0x2B, 0x24, 0xEC, 0xCB, 0x9B, 0x1B, 0x10, 0x8D, 0x81, 0xA0, 0xBE, 0xB1,
+    0x8C, 0x33, 0xE4, 0x36, 0xB8, 0x43, 0xEB, 0x19, 0x2A, 0x81, 0x8D, 0xDE,
+    0x81, 0x0A, 0x99, 0x48, 0xB6, 0xF6, 0xBC, 0xCD, 0x49, 0x34, 0x3A, 0x8F,
+    0x26, 0x94, 0xE3, 0x28, 0x82, 0x1A, 0x7C, 0x8F, 0x59, 0x9F, 0x45, 0xE8,
+    0x5D, 0x1A, 0x45, 0x76, 0x04, 0x56, 0x05, 0xA1, 0xD0, 0x1B, 0x8C, 0x77,
+    0x6D, 0xAF, 0x53, 0xFA, 0x71, 0xE2, 0x67, 0xE0, 0x9A, 0xFE, 0x03, 0xA9,
+    0x85, 0xD2, 0xC9, 0xAA, 0xBA, 0x2A, 0xBC, 0xF4, 0xA0, 0x08, 0xF5, 0x13,
+    0x98, 0x13, 0x5D, 0xF0, 0xD9, 0x33, 0x34, 0x2A, 0x61, 0xC3, 0x89, 0x55,
+    0xF0, 0xAE, 0x1A, 0x9C, 0x22, 0xEE, 0x19, 0x05, 0x8D, 0x32, 0xFE, 0xEC,
+    0x9C, 0x84, 0xBA, 0xB7, 0xF9, 0x6C, 0x3A, 0x4F, 0x07, 0xFC, 0x45, 0xEB,
+    0x12, 0xE5, 0x7B, 0xFD, 0x55, 0xE6, 0x29, 0x69, 0xD1, 0xC2, 0xE8, 0xB9,
+    0x78, 0x59, 0xF6, 0x79, 0x10, 0xC6, 0x4E, 0xEB, 0x6A, 0x5E, 0xB9, 0x9A,
+    0xC7, 0xC4, 0x5B, 0x63, 0xDA, 0xA3, 0x3F, 0x5E, 0x92, 0x7A, 0x81, 0x5E,
+    0xD6, 0xB0, 0xE2, 0x62, 0x8F, 0x74, 0x26, 0xC2, 0x0C, 0xD3, 0x9A, 0x17,
+    0x47, 0xE6, 0x8E, 0xAB,
+};
+/* rsa_tv_template[2].c */
+static const uint8_t rsa2048_c[256] = {
+    0xB2, 0x97, 0x76, 0xB4, 0xAE, 0x3E, 0x38, 0x3C, 0x7E, 0x64, 0x1F, 0xCC,
+    0xA2, 0x7F, 0xF6, 0xBE, 0xCF, 0x49, 0xBC, 0x48, 0xD3, 0x6C, 0x8F, 0x0A,
+    0x0E, 0xC1, 0x73, 0xBD, 0x7B, 0x55, 0x79, 0x36, 0x0E, 0xA1, 0x87, 0x88,
+    0xB9, 0x2C, 0x90, 0xA6, 0x53, 0x5E, 0xE9, 0xEF, 0xC4, 0xE2, 0x4D, 0xDD,
+    0xF7, 0xA6, 0x69, 0x82, 0x3F, 0x56, 0xA4, 0x7B, 0xFB, 0x62, 0xE0, 0xAE,
+    0xB8, 0xD3, 0x04, 0xB3, 0xAC, 0x5A, 0x15, 0x2A, 0xE3, 0x19, 0x9B, 0x03,
+    0x9A, 0x0B, 0x41, 0xDA, 0x64, 0xEC, 0x0A, 0x69, 0xFC, 0xF2, 0x10, 0x92,
+    0xF3, 0xC1, 0xBF, 0x84, 0x7F, 0xFD, 0x2C, 0xAE, 0xC8, 0xB5, 0xF6, 0x41,
+    0x70, 0xC5, 0x47, 0x03, 0x8A, 0xF8, 0xFF, 0x6F, 0x3F, 0xD2, 0x6F, 0x09,
+    0xB4, 0x22, 0xF3, 0x30, 0xBE, 0xA9, 0x85, 0xCB, 0x9C, 0x8D, 0xF9, 0x8F,
+    0xEB, 0x32, 0x91, 0xA2, 0x25, 0x84, 0x8F, 0xF5, 0xDC, 0xC7, 0x06, 0x9C,
+    0x2D, 0xE5, 0x11, 0x2C, 0x09, 0x09, 0x87, 0x09, 0xA9, 0xF6, 0x33, 0x73,
+    0x90, 0xF1, 0x60, 0xF2, 0x65, 0xDD, 0x30, 0xA5, 0x66, 0xCE, 0x62, 0x7B,
+    0xD0, 0xF8, 0x2D, 0x3D, 0x19, 0x82, 0x77, 0xE3, 0x0A, 0x5F, 0x75, 0x2F,
+    0x8E, 0xB1, 0xE5, 0xE8, 0x91, 0x35, 0x1B, 0x3B, 0x33, 0xB7, 0x66, 0x92,
+    0xD1, 0xF2, 0x8E, 0x6F, 0xE5, 0x75, 0x0C, 0xAD, 0x36, 0xFB, 0x4E, 0xD0,
+    0x66, 0x61, 0xBD, 0x49, 0xFE, 0xF4, 0x1A, 0xA2, 0x2B, 0x49, 0xFE, 0x03,
+    0x4C, 0x74, 0x47, 0x8D, 0x9A, 0x66, 0xB2, 0x49, 0x46, 0x4D, 0x77, 0xEA,
+    0x33, 0x4D, 0x6B, 0x3C, 0xB4, 0x49, 0x4A, 0xC6, 0x7D, 0x3D, 0xB5, 0xB9,
+    0x56, 0x41, 0x15, 0x67, 0x0F, 0x94, 0x3C, 0x93, 0x65, 0x27, 0xE0, 0x21,
+    0x5D, 0x59, 0xC3, 0x62, 0xD5, 0xA6, 0xDA, 0x38, 0x26, 0x22, 0x5E, 0x34,
+    0x1C, 0x94, 0xAF, 0x98,
+};
+
+/* rsa_tv_template[3].key, modulus n */
+static const uint8_t rsa4096_n[512] = {
+    0xC3, 0x8B, 0x55, 0x7B, 0x73, 0x4D, 0xFF, 0xE9, 0x9B, 0xC6, 0xDC, 0x67,
+    0x3C, 0xB4, 0x8E, 0xA0, 0x86, 0xED, 0xF2, 0xB9, 0x50, 0x5C, 0x54, 0x5C,
+    0xBA, 0xE4, 0xA1, 0xB2, 0xA7, 0xAE, 0x2F, 0x1B, 0x7D, 0xF1, 0xFB, 0xAC,
+    0x79, 0xC5, 0xDF, 0x1A, 0x00, 0xC9, 0xB2, 0xC1, 0x61, 0x25, 0x33, 0xE6,
+    0x9C, 0xE9, 0xCF, 0xD6, 0x27, 0xC4, 0x4E, 0x44, 0x30, 0x44, 0x5E, 0x08,
+    0xA1, 0x87, 0x52, 0xCC, 0x6B, 0x97, 0x70, 0x8C, 0xBC, 0xA5, 0x06, 0x31,
+    0x0C, 0xD4, 0x2F, 0xD5, 0x7D, 0x26, 0x24, 0xA2, 0xE2, 0xAC, 0x78, 0xF4,
+    0x53, 0x14, 0xCE, 0xF7, 0x19, 0x2E, 0xD7, 0xF7, 0xE6, 0x0C, 0xB9, 0x56,
+    0x7F, 0x0B, 0xF1, 0xB1, 0xE2, 0x43, 0x70, 0xBD, 0x86, 0x1D, 0xA1, 0xCC,
+    0x2B, 0x19, 0x08, 0x76, 0xEF, 0x91, 0xAC, 0xBF, 0x20, 0x24, 0x0D, 0x38,
+    0xC0, 0x89, 0xB8, 0x9A, 0x70, 0xB3, 0x64, 0xD9, 0x8F, 0x80, 0x41, 0x10,
+    0x5B, 0x9F, 0xB1, 0xCB, 0x76, 0x43, 0x00, 0x21, 0x25, 0x36, 0xD4, 0x19,
+    0xFC, 0x55, 0x95, 0x10, 0xE4, 0x26, 0x74, 0x98, 0x2C, 0xD9, 0xBD, 0x0B,
+    0x2B, 0x04, 0xC2, 0xAC, 0x82, 0x38, 0xB4, 0xDD, 0x4C, 0x04, 0x7E, 0x51,
+    0x36, 0x40, 0x1E, 0x0B, 0xC4, 0x7C, 0x25, 0xDD, 0x4B, 0xB2, 0xE7, 0x20,
+    0x0A, 0x57, 0xF9, 0xB4, 0x94, 0xC3, 0x08, 0x33, 0x22, 0x6F, 0x8B, 0x48,
+    0xDB, 0x03, 0x68, 0x5A, 0x5B, 0xBA, 0xAE, 0xF3, 0xAD, 0xCF, 0xC3, 0x6D,
+    0xBA, 0xF1, 0x28, 0x67, 0x7E, 0x6C, 0x79, 0x07, 0xDE, 0xFC, 0xED, 0xE7,
+    0x96, 0xE3, 0x6C, 0xE0, 0x2C, 0x87, 0xF8, 0x02, 0x01, 0x28, 0x38, 0x43,
+    0x21, 0x53, 0x84, 0x69, 0x75, 0x78, 0x15, 0x7E, 0xEE, 0xD2, 0x1B, 0xB9,
+    0x23, 0x40, 0xA8, 0x86, 0x1E, 0x38, 0x83, 0xB2, 0x73, 0x1D, 0x53, 0xFB,
+    0x9E, 0x2A, 0x8A, 0xB2, 0x75, 0x35, 0x01, 0xC3, 0xC3, 0xC4, 0x94, 0xE8,
+    0x84, 0x86, 0x64, 0x81, 0xF4, 0x42, 0xAA, 0x3C, 0x0E, 0xD6, 0x4F, 0xBC,
+    0x0A, 0x09, 0x2D, 0xE7, 0x1B, 0xD4, 0x10, 0xA8, 0x54, 0xEA, 0x89, 0x84,
+    0x8A, 0xCB, 0xF7, 0x5A, 0x3C, 0xCA, 0x76, 0x08, 0x29, 0x62, 0xB4, 0x6A,
+    0x22, 0xDF, 0x14, 0x95, 0x71, 0xFD, 0xB6, 0x86, 0x39, 0xB8, 0x8B, 0xF8,
+    0x91, 0x7F, 0x38, 0xAA, 0x14, 0xCD, 0xE5, 0xF5, 0x1D, 0xC2, 0x6D, 0x53,
+    0x69, 0x52, 0x84, 0x7F, 0xA3, 0x1A, 0x5E, 0x26, 0x04, 0x83, 0x06, 0x73,
+    0x52, 0x56, 0xCF, 0x76, 0x26, 0xC9, 0xDD, 0x75, 0xD7, 0xFC, 0xF4, 0x69,
+    0xD8, 0x7B, 0x55, 0xB7, 0x68, 0x13, 0x53, 0xB9, 0xE7, 0x89, 0xC3, 0xE8,
+    0xD6, 0x6E, 0xA7, 0x6D, 0xEA, 0x81, 0xFD, 0xC4, 0xB7, 0x05, 0x5A, 0xB7,
+    0x41, 0x0A, 0x23, 0x8E, 0x03, 0x8A, 0x1C, 0xAE, 0xD3, 0x1E, 0xCE, 0xE3,
+    0x5E, 0xFC, 0x19, 0x4A, 0xEE, 0x61, 0x9B, 0x8E, 0xE5, 0xE5, 0xDD, 0x85,
+    0xF9, 0x41, 0xEC, 0x14, 0x53, 0x92, 0xF7, 0xDD, 0x06, 0x85, 0x02, 0x91,
+    0xE3, 0xEB, 0x6C, 0x43, 0x03, 0xB1, 0x36, 0x7B, 0x89, 0x5A, 0xA8, 0xEB,
+    0xFC, 0xD5, 0xA8, 0x35, 0xDC, 0x81, 0xD9, 0x5C, 0xBD, 0xCA, 0xDC, 0x9B,
+    0x98, 0x0B, 0x06, 0x5D, 0x0C, 0x5B, 0xEE, 0xF3, 0xD5, 0xCC, 0x57, 0xC9,
+    0x71, 0x2F, 0x90, 0x3B, 0x3C, 0xF0, 0x8E, 0x4E, 0x35, 0x48, 0xAE, 0x63,
+    0x74, 0xA9, 0xFC, 0x72, 0x75, 0x8E, 0x34, 0xA8, 0xF2, 0x1F, 0xEA, 0xDF,
+    0x3A, 0x37, 0x2D, 0xE5, 0x39, 0x39, 0xF8, 0x57, 0x58, 0x3C, 0x04, 0xFE,
+    0x87, 0x06, 0x98, 0xBC, 0x7B, 0xD3, 0x21, 0x36, 0x60, 0x25, 0x54, 0xA7,
+    0x3D, 0xFA, 0x91, 0xCC, 0xA8, 0x0B, 0x92, 0x8E, 0xB4, 0xF7, 0x06, 0xFF,
+    0x1E, 0x95, 0xCB, 0x07, 0x76, 0x97, 0x3B, 0x9D,
+};
+/* rsa_tv_template[3].c */
+static const uint8_t rsa4096_c[512] = {
+    0x5C, 0xCE, 0x9C, 0xD7, 0x9A, 0x9E, 0xA1, 0xFE, 0x7A, 0x82, 0x3C, 0x68,
+    0x27, 0x98, 0xE3, 0x5D, 0xD5, 0xD7, 0x07, 0x29, 0xF5, 0xFB, 0xC3, 0x1A,
+    0x7F, 0x63, 0x1E, 0x62, 0x31, 0x3B, 0x19, 0x87, 0x79, 0x4F, 0xEC, 0x7B,
+    0xF3, 0xCB, 0xEA, 0x9B, 0x95, 0x52, 0x3A, 0x40, 0xE5, 0x87, 0x7B, 0x72,
+    0xD1, 0x72, 0xC9, 0xFB, 0x54, 0x63, 0xD8, 0xC9, 0xD7, 0x2C, 0xFC, 0x7B,
+    0xC3, 0x14, 0x1E, 0xBC, 0x18, 0xB4, 0x34, 0xA1, 0xBF, 0x14, 0xB1, 0x37,
+    0x31, 0x6E, 0xF0, 0x1B, 0x35, 0x19, 0x54, 0x07, 0xF7, 0x99, 0xEC, 0x3E,
+    0x63, 0xE2, 0xCD, 0x61, 0x28, 0x65, 0xC3, 0xCD, 0xB1, 0x38, 0x36, 0xA5,
+    0xB2, 0xD7, 0xB0, 0xDC, 0x1F, 0xF5, 0xEF, 0x19, 0xC7, 0x53, 0x32, 0x2D,
+    0x1C, 0x26, 0xDA, 0xE4, 0x0D, 0xD6, 0x90, 0x7E, 0x28, 0xD8, 0xDC, 0xE4,
+    0x61, 0x05, 0xD2, 0x25, 0x90, 0x01, 0xD3, 0x96, 0x6D, 0xA6, 0xCF, 0x58,
+    0x20, 0xBB, 0x03, 0xF4, 0x01, 0xBC, 0x79, 0xB9, 0x18, 0xD8, 0xB8, 0xBA,
+    0xBD, 0x93, 0xFC, 0xF2, 0x62, 0x5D, 0x8C, 0x66, 0x1E, 0x0E, 0x84, 0x59,
+    0x93, 0xDD, 0xE2, 0x93, 0xA2, 0x62, 0x7D, 0x08, 0x82, 0x7A, 0xDD, 0xFC,
+    0xB8, 0xBC, 0xC5, 0x4F, 0x9C, 0x4E, 0xBF, 0xB4, 0xFC, 0xF4, 0xC5, 0x01,
+    0xE8, 0x00, 0x70, 0x4D, 0x28, 0x26, 0xCC, 0x2E, 0xFE, 0x0E, 0x58, 0x41,
+    0x8B, 0xEC, 0xAF, 0x7C, 0x4B, 0x54, 0xD0, 0xA0, 0x64, 0xF9, 0x32, 0xF4,
+    0x2E, 0x47, 0x65, 0x0A, 0x67, 0x88, 0x39, 0x3A, 0xDB, 0xB2, 0xDB, 0x7B,
+    0xB5, 0xF6, 0x17, 0xA8, 0xD9, 0xC6, 0x5E, 0x28, 0x13, 0x82, 0x8A, 0x99,
+    0xDB, 0x60, 0x08, 0xA5, 0x23, 0x37, 0xFA, 0x88, 0x90, 0x31, 0xC8, 0x9D,
+    0x8F, 0xEC, 0xFB, 0x85, 0x9F, 0xB1, 0xCE, 0xA6, 0x24, 0x50, 0x46, 0x44,
+    0x47, 0xCB, 0x65, 0xD1, 0xDF, 0xC0, 0xB1, 0x6C, 0x90, 0x1F, 0x99, 0x8E,
+    0x4D, 0xD5, 0x9E, 0x31, 0x07, 0x66, 0x87, 0xDF, 0x01, 0xAA, 0x56, 0x3C,
+    0x71, 0xE0, 0x2B, 0x6F, 0x67, 0x3B, 0x23, 0xED, 0xC2, 0xBD, 0x03, 0x30,
+    0x79, 0x76, 0x02, 0x10, 0x10, 0x98, 0x85, 0x8A, 0xFF, 0xFD, 0x0B, 0xDA,
+    0xA5, 0xD9, 0x32, 0x48, 0x02, 0xA0, 0x0B, 0xB9, 0x2A, 0x8A, 0x18, 0xCA,
+    0xC6, 0x8F, 0x3F, 0xBB, 0x16, 0xB2, 0xAA, 0x98, 0x27, 0xE3, 0x60, 0x43,
+    0xED, 0x15, 0x70, 0xD4, 0x57, 0x15, 0xFE, 0x19, 0xD4, 0x9B, 0x13, 0x78,
+    0x8A, 0xF7, 0x21, 0xF1, 0xA2, 0xA2, 0x2D, 0xB3, 0x09, 0xCF, 0x44, 0x91,
+    0x6E, 0x08, 0x3A, 0x30, 0x81, 0x3E, 0x90, 0x93, 0x8A, 0x67, 0x33, 0x00,
+    0x59, 0x54, 0x9A, 0x25, 0xD3, 0x49, 0x8E, 0x9F, 0xC1, 0x4B, 0xE5, 0x86,
+    0xF3, 0x50, 0x4C, 0xBC, 0xC5, 0xD3, 0xF5, 0x3A, 0x54, 0xE1, 0x36, 0x3F,
+    0xE2, 0x5A, 0xB4, 0x37, 0xC0, 0xEB, 0x70, 0x35, 0xEC, 0xF6, 0xB7, 0xE8,
+    0x44, 0x3B, 0x7B, 0xF3, 0xF1, 0xF2, 0x1E, 0xDB, 0x60, 0x7D, 0xD5, 0xBE,
+    0xF0, 0x71, 0x34, 0x90, 0x4C, 0xCB, 0xD4, 0x35, 0x51, 0xC7, 0xDD, 0xD8,
+    0xC9, 0x81, 0xF5, 0x5D, 0x57, 0x46, 0x2C, 0xB1, 0x7B, 0x9B, 0xAA, 0xCB,
+    0xD1, 0x22, 0x25, 0x49, 0x44, 0xA3, 0xD4, 0x6B, 0x29, 0x7B, 0xD8, 0xB2,
+    0x07, 0x93, 0xBF, 0x3D, 0x52, 0x49, 0x84, 0x79, 0xEF, 0xB8, 0xE5, 0xC4,
+    0xAD, 0xCA, 0xA8, 0xC6, 0xF6, 0xA6, 0x76, 0x70, 0x5B, 0x0B, 0xE5, 0x83,
+    0xC6, 0x0E, 0xEF, 0x55, 0xF2, 0xE7, 0xFF, 0x04, 0xEA, 0xE6, 0x13, 0xBE,
+    0x40, 0xE1, 0x40, 0x45, 0x48, 0x66, 0x75, 0x31, 0xAE, 0x35, 0x64, 0x91,
+    0x11, 0x6F, 0xDA, 0xEE, 0x26, 0x86, 0x45, 0x6F, 0x0B, 0xD5, 0x9F, 0x03,
+    0xB1, 0x65, 0x5B, 0xDB, 0xA4, 0xE4, 0xF9, 0x45,
+};
+
+/*
+ * Build the ACRY SRAM byte-offset lookup tables: exp_map[k] / mod_map[k] /
+ * data_map[k] give the offset in the scattered buffer of byte k
+ * (k = 0 = least significant) of the exponent / modulus / data. This is the
+ * byte layout the ACRY engine mandates, so the test lays out its DMA input
+ * and decodes the result buffer the same way the hardware does.
+ */
+static void acry_sram_mapping(uint32_t *exp_map, uint32_t *mod_map,
+                              uint32_t *data_map)
+{
+    int byte_in_dword;
+    int block_base;
+    int op_dword;
+    int op_byte;
+    int block;
+    int lane;
+
+    for (op_byte = 0; op_byte < ACRY_DATA_MAX_LEN; op_byte++) {
+        op_dword = op_byte / 4;
+        byte_in_dword = op_byte % 4;
+        block = op_dword / 4;
+        lane = op_dword % 4;
+        block_base = block * 12;
+
+        /* exp starts each block; mod is +4 dwords, data +8 dwords. */
+        data_map[op_byte] = (block_base + 8 + lane) * 4 + byte_in_dword;
+        if (op_byte < ACRY_MAX_BYTES) {
+            exp_map[op_byte] = (block_base + 0 + lane) * 4 + byte_in_dword;
+            mod_map[op_byte] = (block_base + 4 + lane) * 4 + byte_in_dword;
+        }
+    }
+}
+
+/*
+ * Write a big-endian (most significant byte first) bignum of 'be_len'
+ * bytes into the region addressed by 'map' (exponent, modulus, or data),
+ * where map[k] gives the position in the scattered buffer of the
+ * byte at significance level k (k = 0 is the least significant byte).
+ */
+static void put_bignum_be_bytes(uint8_t *buf, const uint32_t *map,
+                                const uint8_t *be, int be_len)
+{
+    int be_index;
+    int k;
+
+    /* be[0] (MSB) maps to the highest level; be_index walks up from 0. */
+    be_index = 0;
+    for (k = be_len - 1; k >= 0; k--) {
+        buf[map[k]] = be[be_index++];
+    }
+}
+
+/* Inverse of put_bignum_be_bytes(): gather a big-endian bignum back out. */
+static void get_bignum_be_bytes(const uint8_t *sram, const uint32_t *map,
+                                uint8_t *out_be, int be_len)
+{
+    int be_index;
+    int k;
+
+    /* Inverse of put_bignum_be_bytes(): highest level -> out_be[0] (MSB). */
+    be_index = 0;
+    for (k = be_len - 1; k >= 0; k--) {
+        out_be[be_index++] = sram[map[k]];
+    }
+}
+
+typedef struct AspeedACRYModExp {
+    const char *name;
+    const uint8_t *n;
+    size_t n_len;
+    const uint8_t *e;
+    size_t e_len;
+    const uint8_t *m;
+    size_t m_len;
+    const uint8_t *c;
+    size_t c_len;
+} AspeedACRYModExp;
+
+static const AspeedACRYModExp acry_modexp_tests[] = {
+    {
+        .name = "modexp_rsa2048",
+        .n = rsa2048_n,
+        .n_len = sizeof(rsa2048_n),
+        .e = rsa_e,
+        .e_len = sizeof(rsa_e),
+        .m = rsa_m,
+        .m_len = sizeof(rsa_m),
+        .c = rsa2048_c,
+        .c_len = sizeof(rsa2048_c),
+    },
+    {
+        .name = "modexp_rsa4096",
+        .n = rsa4096_n,
+        .n_len = sizeof(rsa4096_n),
+        .e = rsa_e,
+        .e_len = sizeof(rsa_e),
+        .m = rsa_m,
+        .m_len = sizeof(rsa_m),
+        .c = rsa4096_c,
+        .c_len = sizeof(rsa4096_c),
+    },
+};
+
+/*
+ * One registered ACRY test: per-machine location (register base, result SRAM
+ * base, DRAM scratch) plus an index into acry_modexp_tests[]. Passed as the
+ * qtest_add_data_func_full() data pointer.
+ */
+typedef struct AspeedACRYTest {
+    const char *machine;
+    uint64_t dram_addr;
+    uint32_t sram_base;
+    uint32_t base;
+    int index;
+} AspeedACRYTest;
+
+static void test_modexp_rsa(const void *opaque)
+{
+    const AspeedACRYTest *c = opaque;
+    const AspeedACRYModExp *t = &acry_modexp_tests[c->index];
+    QTestState *qts = qtest_init(c->machine);
+    uint32_t data_map[ACRY_DATA_MAX_LEN];
+    uint8_t buf[ACRY_SRAM_SIZE] = { 0 };
+    uint32_t exp_map[ACRY_MAX_BYTES];
+    uint32_t mod_map[ACRY_MAX_BYTES];
+    uint8_t result[ACRY_MAX_BYTES];
+    uint8_t sram[ACRY_SRAM_SIZE];
+
+    g_assert_cmpuint(t->c_len, <=, sizeof(result));
+
+    acry_sram_mapping(exp_map, mod_map, data_map);
+
+    put_bignum_be_bytes(buf, exp_map, t->e, t->e_len);
+    put_bignum_be_bytes(buf, mod_map, t->n, t->n_len);
+    put_bignum_be_bytes(buf, data_map, t->m, t->m_len);
+
+    qtest_memwrite(qts, c->dram_addr, buf, sizeof(buf));
+
+    qtest_writel(qts, c->base + ACRY_DMA_CMD, ACRY_DMA_CMD_DMEM_AHB);
+    qtest_writel(qts, c->base + ACRY_DMA_SRC, c->dram_addr);
+    qtest_writel(qts, c->base + ACRY_RSA_KEY_LEN,
+                ((uint32_t)(t->e_len * 8) << 16) | (uint32_t)(t->n_len * 8));
+    qtest_writel(qts, c->base + ACRY_DMA_LEN, ACRY_SRAM_SIZE);
+    qtest_writel(qts, c->base + ACRY_INT_MASK,
+                ACRY_INT_MASK_RSA_ENG_MASK | ACRY_INT_MASK_RSA_DMA_MASK);
+    qtest_writel(qts, c->base + ACRY_DMA_CMD, ACRY_DMA_CMD_SRAM_MODE_RSA);
+    qtest_writel(qts, c->base + ACRY_TRIGGER,
+                ACRY_TRIGGER_RSA_START | ACRY_TRIGGER_RSA_DMA_DATA);
+
+    /* Completion requires both RSA_ENG_DONE and RSA_DMA_DONE to be asserted. */
+    g_assert_cmphex(qtest_readl(qts, c->base + ACRY_STATUS), ==,
+                    ACRY_STATUS_RSA_DONE);
+
+    qtest_memread(qts, c->sram_base, sram, sizeof(sram));
+    get_bignum_be_bytes(sram, data_map, result, t->c_len);
+    g_assert_cmpmem(result, t->c_len, t->c, t->c_len);
+
+    /* Clear IRQ status and check it is deasserted */
+    qtest_writel(qts, c->base + ACRY_STATUS, ACRY_STATUS_RSA_DONE);
+    g_assert_cmphex(qtest_readl(qts, c->base + ACRY_STATUS), ==, 0);
+
+    qtest_quit(qts);
+}
+
+static void aspeed_add_acry_tests(const char *prefix, const char *machine,
+                                  uint32_t base, uint32_t sram_base,
+                                  uint64_t dram_addr)
+{
+    QCryptoAkCipherOptions opts = {
+        .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
+        .u.rsa.padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW,
+    };
+    int i;
+
+    if (!qcrypto_akcipher_supports(&opts)) {
+        g_printerr("# skip ACRY tests: raw RSA not supported by the crypto "
+                   "backend\n");
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(acry_modexp_tests); i++) {
+        g_autofree char *path = NULL;
+        AspeedACRYTest *t;
+
+        path = g_strdup_printf("%s/acry/%s", prefix,
+                               acry_modexp_tests[i].name);
+        t = g_new0(AspeedACRYTest, 1);
+        t->machine = machine;
+        t->base = base;
+        t->sram_base = sram_base;
+        t->dram_addr = dram_addr;
+        t->index = i;
+        qtest_add_data_func_full(path, t, test_modexp_rsa, g_free);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    aspeed_add_acry_tests("ast2600", "-machine ast2600-evb",
+                          0x1e6fa000, 0x1e710000, 0x80000000 + 0x1000);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index f7c7d06620..c58be94c25 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -220,7 +220,8 @@ qtests_npcm7xx = \
 qtests_npcm8xx = \
   ['npcm_gmac-test']
 qtests_aspeed = \
-  ['aspeed_gpio-test',
+  ['aspeed-acry-test',
+   'aspeed_gpio-test',
    'aspeed_hace-test',
    'aspeed_scu-test',
    'aspeed_smc-test']
@@ -392,6 +393,8 @@ if get_option('replication').allowed()
 endif
 
 qtests = {
+  'aspeed-acry-test': [files('aspeed-acry-test.c'),
+                       crypto],
   'aspeed_hace-test': [files('aspeed-hace-utils.c', 'aspeed_hace-test.c'),
                        crypto],
   'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'),
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.