[mask_rom, sig_verify] Add modular exponentiation
This change adds modular exponentiation using Montgomery multiplication
for exponents 3 and 65537.
Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/device/silicon_creator/mask_rom/rsa_verify.c b/sw/device/silicon_creator/mask_rom/rsa_verify.c
index 9974342..c98663f 100644
--- a/sw/device/silicon_creator/mask_rom/rsa_verify.c
+++ b/sw/device/silicon_creator/mask_rom/rsa_verify.c
@@ -26,6 +26,24 @@
}
}
+/**
+ * Checks if `a` is greater than or equal to `b`.
+ *
+ * @param a A `kRsaNumWords` long buffer, little-endian.
+ * @param b A `kRsaNumWords` long buffer, little-endian.
+ * @return Comparison result.
+ */
+static bool greater_equal(const uint32_t *a, const uint32_t *b) {
+ // TODO(#33): Hardening?
+ // Note: Loop terminates when `i` wraps around.
+ for (size_t i = kRsaNumWords - 1; i < kRsaNumWords; --i) {
+ if (a[i] != b[i]) {
+ return a[i] > b[i];
+ }
+ }
+ return true;
+}
+
// FIXME: Merge this comment with the one in the header file.
// This function implements Alg. 14.36 in Handbook of Applied Cryptography:
// 1. result = 0
@@ -35,7 +53,7 @@
// 3. If result >= m then result = result - m
// 4. Return result
void mont_mul(const uint32_t *x, const uint32_t *y, const uint32_t *m,
- const uint32_t m_prime, uint32_t *result) {
+ const uint32_t m0_inv, uint32_t *result) {
memset(result, 0, kRsaNumWords * sizeof(uint32_t));
for (size_t i = 0; i < kRsaNumWords; ++i) {
@@ -50,7 +68,7 @@
// Holds the sum of the first two addends in step 2.2.
uint64_t acc0 = (uint64_t)x[i] * y[0] + result[0];
- const uint32_t u_i = (uint32_t)acc0 * m_prime;
+ const uint32_t u_i = (uint32_t)acc0 * m0_inv;
// Holds the sum of the all three addends in step 2.2.
uint64_t acc1 = (uint64_t)u_i * m[0] + (uint32_t)acc0;
@@ -78,3 +96,39 @@
}
}
}
+
+bool mod_exp(const uint32_t *sig, const rsa_verify_exponent_t e,
+ const uint32_t *r_square, const uint32_t *m, const uint32_t m0_inv,
+ uint32_t *result) {
+ uint32_t buf[kRsaNumWords];
+
+ if (e == kRsaVerifyExponent3) {
+ // result = sig * R mod m
+ mont_mul(sig, r_square, m, m0_inv, result);
+ // buf = sig^2 * R mod m
+ mont_mul(result, result, m, m0_inv, buf);
+ } else if (e == kRsaVerifyExponent65537) {
+ // buf = sig * R mod m
+ mont_mul(sig, r_square, m, m0_inv, buf);
+ for (size_t i = 0; i < 8; ++i) {
+ // result = sig^{2*i+1} * R mod m (sig's exponent: 2, 8, 32, ..., 32768)
+ mont_mul(buf, buf, m, m0_inv, result);
+ // buf = sig^{4*i+2} * R mod m (sig's exponent: 4, 16, 64, ..., 65536)
+ mont_mul(result, result, m, m0_inv, buf);
+ }
+ } else {
+ return false;
+ }
+ // result = sig^e mod m
+ mont_mul(buf, sig, m, m0_inv, result);
+
+ // We need this check because the result of `mont_mul` is not guaranteed to be
+ // the least non-negative residue. We need to subtract `m` from `result` at
+ // most once because `m` is the modulus of an RSA public key and therefore
+ // R/2 < m < R.
+ if (greater_equal(result, m)) {
+ subtract(result, m);
+ }
+
+ return true;
+}
diff --git a/sw/device/silicon_creator/mask_rom/rsa_verify.h b/sw/device/silicon_creator/mask_rom/rsa_verify.h
index 1f818d2..f232703 100644
--- a/sw/device/silicon_creator/mask_rom/rsa_verify.h
+++ b/sw/device/silicon_creator/mask_rom/rsa_verify.h
@@ -5,6 +5,7 @@
#ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_MASK_ROM_RSA_VERIFY_H_
#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_MASK_ROM_RSA_VERIFY_H_
+#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
@@ -18,6 +19,23 @@
kRsaNumWords = 96,
};
+/**
+ * Exponent to use for signature verification.
+ *
+ * This determines the e in s^e mod n.
+ */
+// TODO(#22): May need to be updated after we decide on a key storage format.
+typedef enum rsa_verify_exponent {
+ /**
+ * e = 3.
+ */
+ kRsaVerifyExponent3,
+ /**
+ * e = 65537.
+ */
+ kRsaVerifyExponent65537,
+} rsa_verify_exponent_t;
+
// FIXME: Make static and move this comment to the source file. This is here
// just to be able to add a simple test.
/**
@@ -34,11 +52,37 @@
* @param x A `kRsaNumWords` long buffer, little-endian.
* @param y A `kRsaNumWords` long buffer, little-endian.
* @param m A `kRsaNumWords` long buffer, little-endian.
- * @param m_prime Negative of the multiplicative inverse of m modulo b.
+ * @param m0_inv Negative of the multiplicative inverse of m modulo b.
* @param[out] result A `kRsaNumWords` long buffer, little-endian.
*/
void mont_mul(const uint32_t *x, const uint32_t *y, const uint32_t *m,
- uint32_t m_prime, uint32_t *result);
+ uint32_t m0_inv, uint32_t *result);
+
+/**
+ * Computes the modular exponentiation of an integer.
+ *
+ * Given sig, e, R^2 mod m, m, and m', this function computes sig^e mod m using
+ * Montgomery multiplication, where
+ * - sig, R^2 mod m, and m are integers with kRsaNumWords base b digits,
+ * - e is the exponent (3 or 65537),
+ * - m' = -m^-1 mod b,
+ * - R is b^kRsaNumWords, e.g. 2^3072 for RSA-3072, and
+ * - b is 2^32.
+ *
+ * @param sig A `kRsaNumWords` long buffer, little-endian.
+ * @param exponent Exponent to use for signature verification.
+ * @param r_square A `kRsaNumWords` long buffer, little-endian.
+ * @param m A `kRsaNumWords` long buffer, little-endian.
+ * @param m0_inv Negative of the multiplicative inverse of m modulo b.
+ * @param[out] result A `kRsaNumWords` long buffer, little-endian.
+ * @return True if successful, false otherwise.
+ */
+// TODO(#22): Update this after we decide on a key storage format.
+// FIXME: Error codes are still under discussion, update after we reach a
+// decision.
+bool mod_exp(const uint32_t *sig, rsa_verify_exponent_t e,
+ const uint32_t *r_square, const uint32_t *m, uint32_t m0_inv,
+ uint32_t *result);
#ifdef __cplusplus
} // extern "C"
diff --git a/sw/device/tests/silicon_creator/mask_rom/rsa_verify_unittest.cc b/sw/device/tests/silicon_creator/mask_rom/rsa_verify_unittest.cc
index 45392e8..ff6753c 100644
--- a/sw/device/tests/silicon_creator/mask_rom/rsa_verify_unittest.cc
+++ b/sw/device/tests/silicon_creator/mask_rom/rsa_verify_unittest.cc
@@ -22,12 +22,12 @@
constexpr RsaBuffer x{5792};
constexpr RsaBuffer y{1229};
constexpr RsaBuffer m{72639};
- constexpr uint32_t m_prime = 3837733825;
+ constexpr uint32_t m0_inv = 3837733825;
constexpr RsaBuffer exp_result{55123};
// Uninitialized on purpose.
RsaBuffer act_res;
- mont_mul(x.data(), y.data(), m.data(), m_prime, act_res.data());
+ mont_mul(x.data(), y.data(), m.data(), m0_inv, act_res.data());
EXPECT_EQ(exp_result, act_res);
}
@@ -69,7 +69,7 @@
0xa29d7536, 0x55c19326, 0x9ebbc63e, 0x20c75aee, 0xef6783d7, 0x59ffdba5,
0x879b937b, 0x43a5c74c, 0x82b8f825, 0xfdf04b3a, 0x8fc62fbe, 0x114e6da5,
};
- constexpr uint32_t m_prime = 4036719071;
+ constexpr uint32_t m0_inv = 4036719071;
constexpr RsaBuffer exp_result{
0x7603d6bd, 0xe7714c93, 0x97cf4c0a, 0xa2f79f2b, 0xd6d9a47a, 0x666d8e1d,
0x298e418a, 0xdbb713ec, 0x84d319fd, 0x1e89e6c3, 0xa4671f40, 0xc324a13b,
@@ -91,10 +91,222 @@
// Uninitialized on purpose.
RsaBuffer act_res;
- mont_mul(sig.data(), sig.data(), m.data(), m_prime, act_res.data());
+ mont_mul(sig.data(), sig.data(), m.data(), m0_inv, act_res.data());
EXPECT_EQ(exp_result, act_res);
}
+TEST(ModExp, BadExp) {
+ RsaBuffer empty{};
+ rsa_verify_exponent_t bad_enum =
+ static_cast<rsa_verify_exponent_t>(kRsaVerifyExponent65537 + 1);
+
+ EXPECT_EQ(mod_exp(empty.data(), bad_enum, empty.data(), empty.data(), 0,
+ empty.data()),
+ false);
+}
+
+TEST(ModExp, Exp65537) {
+ // Private key d: {
+ // 0xbebf06e3, 0x59d7e511, 0xe619ae0c, 0xb93ce7f6, 0xa83b89ca, 0x53c176f4,
+ // 0x869ef22b, 0xf8df4b83, 0x12ab013a, 0x98c927fc, 0xa4d57150, 0x0ce4696f,
+ // 0xdc931298, 0x2ced7d20, 0x973b5537, 0x2069a742, 0xf1559248, 0x13158c94,
+ // 0x16fef892, 0x82581bed, 0x15a7cba4, 0xc72a52e0, 0x7455bd70, 0x23eab41c,
+ // 0x0158da45, 0x82db6557, 0xec7bc157, 0x111b4eb0, 0x81c487dc, 0xf166df69,
+ // 0xde9a6b93, 0xedec8247, 0x6ddc889a, 0x5224cc0a, 0xce4b46fd, 0xde1e8772,
+ // 0x6417d968, 0x1d960144, 0x72dffbec, 0xd2619e50, 0x4ce73407, 0x25d7da23,
+ // 0xae72329a, 0xe43d4e29, 0x3e177edf, 0x70c58f2c, 0x8c9b7735, 0x514af916,
+ // 0x7e40bb19, 0xfab769ff, 0xdebb08e7, 0x6814f4f4, 0x352e82b3, 0x29c4d1b5,
+ // 0x61d485c8, 0x5cdb05a4, 0xcc6dd5cb, 0xd36a6e38, 0xf987ff5b, 0x2d060e8b,
+ // 0x84e66f62, 0xb0812761, 0x43414a06, 0xd21ff673, 0xa1317052, 0xf6f8cc01,
+ // 0x51c14c15, 0x1809b28f, 0x176965e5, 0x19b912be, 0x4097243f, 0xd7db29e3,
+ // 0xdf239b2c, 0xd08adbd2, 0xe25a3638, 0x2aac03ff, 0xa852eef0, 0xc41587cb,
+ // 0x8e20154b, 0x5232c192, 0x1d222a04, 0x5dedf724, 0x2fc54533, 0x3280b58b,
+ // 0x48e91ae9, 0x7748ae0c, 0x5a41dee3, 0xf5d82e3e, 0x85ff1006, 0x84bd1a55,
+ // 0x51f24349, 0x6f3e7cb3, 0x2cdaa80f, 0x947efef7, 0x07bffad6, 0x60417307,
+ // };
+ constexpr RsaBuffer m{
+ 0x6a6a75e1, 0xa018ddc5, 0x687bb168, 0x8e8205a5, 0x7dbfffa7, 0xc8722ac5,
+ 0xf84d21cf, 0xe1312531, 0x0ce3f8a3, 0xa825f988, 0x57f51964, 0xb27e206a,
+ 0x8e1dd008, 0x1c4fb8d7, 0x824fb142, 0x1c8be7b3, 0x7b9d6366, 0xc56ad0f2,
+ 0xef762d5b, 0x4b1431e3, 0x8ae28eb9, 0xd41db7aa, 0x43cccdf7, 0x91b74a84,
+ 0x80183850, 0x30e74d0d, 0xb62ed015, 0x235574d2, 0x8c28f251, 0x4f40def2,
+ 0x24e2efdb, 0x9ebd1ff2, 0xfa7b49ee, 0x2819a938, 0x6e66b8c8, 0x24e41546,
+ 0x4d783a7c, 0xd2947d3d, 0x1ab269e9, 0xfad39f16, 0xaab78f7b, 0x49d8b510,
+ 0x35bf0dfb, 0xeb274754, 0x069eccc9, 0xc13c437e, 0xe3bc0f60, 0xc9e0e12f,
+ 0xc253ac43, 0x89c240e0, 0xc4aba4e5, 0xedf34bc0, 0x5402c462, 0x4021b0bd,
+ 0x996b6241, 0xc3d9945f, 0xa137ac60, 0xf0250bf5, 0xc8c7100f, 0xb70d6b88,
+ 0x78916a8c, 0x33370e5d, 0x3970dcb9, 0xaf4c58b4, 0x5f78cb0d, 0xb02d90b7,
+ 0xeb6c3d05, 0x04afc71a, 0x45185f0f, 0x987caa5b, 0x33976249, 0x565afdbc,
+ 0x80a85056, 0x59e07655, 0x9a29e77d, 0x7a8dfb7f, 0x782e0204, 0x4d6713ff,
+ 0x131000ea, 0xe18e1206, 0x21f57f30, 0xf24f038b, 0x59cf874d, 0x24c50525,
+ 0xb52f170d, 0x46c9adde, 0x90e82c73, 0x1344ceaf, 0x663209f2, 0x24bd4fbf,
+ 0x5e4ed04d, 0x0fce770a, 0x81f78793, 0xa792e13e, 0xa6c7bf58, 0xe1df9be8,
+ };
+ constexpr uint32_t m0_inv = 4036719071;
+ constexpr RsaBuffer sig{
+ 0xceb7e983, 0xe693b200, 0xf9153989, 0xcf899599, 0x1ec09fae, 0xf2f88007,
+ 0x2a24eed5, 0x9c5b7c4e, 0x21a153b2, 0xaf7583ae, 0x04fdd694, 0x7550094b,
+ 0xb2a69ac4, 0xe49d8022, 0x7ed6f162, 0x14bb3a1b, 0xbb29d8dd, 0x5c5815c2,
+ 0x7a80d848, 0xb122f449, 0x59dca808, 0xbc1443e2, 0xe304ff93, 0xcc97ee4b,
+ 0x42ef6b57, 0x1436839f, 0xae860b45, 0x6a843a17, 0x2381fb91, 0x09fd0635,
+ 0xa431aac3, 0xd7220269, 0xdf3e2697, 0x35e2915e, 0xedba6956, 0x1d387448,
+ 0x930006df, 0x961e5f00, 0xf2a7e960, 0x884e4add, 0x7dfe76b1, 0x4079aa79,
+ 0x1f3a378d, 0x96c20697, 0x268aea57, 0x2c8569a4, 0x0474f512, 0x2388555c,
+ 0x58679953, 0xe73da3a0, 0x43431b9a, 0x699f04d3, 0xfc0be066, 0xcce606f2,
+ 0xd94cdfa0, 0x6c1ddca3, 0xe96c11f6, 0xfc635db4, 0x3bdb4f69, 0xa621c3e7,
+ 0x9f292111, 0xb86e1e6b, 0xb74f923b, 0x592967a0, 0xc412097f, 0x8c1c8ca7,
+ 0x494fcdb6, 0x87c5fe0f, 0x50c01aee, 0x8a26368e, 0xeaf12232, 0x7dade4d8,
+ 0x39eb2ac6, 0x744f8aaa, 0xf34908ca, 0x1e0c656c, 0xe96d4e29, 0x8575d194,
+ 0xe439bd31, 0xa74a77e3, 0x0f465b88, 0xf4e21152, 0x80400ad8, 0xe58501ec,
+ 0xa29d7536, 0x55c19326, 0x9ebbc63e, 0x20c75aee, 0xef6783d7, 0x59ffdba5,
+ 0x879b937b, 0x43a5c74c, 0x82b8f825, 0xfdf04b3a, 0x8fc62fbe, 0x114e6da5,
+ };
+ constexpr RsaBuffer r_square{
+ 0xa3eb77fa, 0x9db9a2ac, 0x2c19d4ae, 0xfb5be1e7, 0xdd38f5fb, 0xd0f4fdda,
+ 0xeb165cd3, 0x546a7cfe, 0xcd410c5c, 0x73f5cf6b, 0x1185bcae, 0xda2e2103,
+ 0xbab5ae26, 0x76e77aba, 0xf49dd5f7, 0x32318a29, 0x689a85bc, 0x8aa862a9,
+ 0x538c240e, 0xb61eab77, 0x9ccd73f2, 0x6563c81a, 0x6c65ac0e, 0x90b209bf,
+ 0xe642e25e, 0x7e351549, 0x879a1830, 0xc75cbb02, 0xe0112362, 0xebc2405f,
+ 0x01dc7990, 0x3d3d07f3, 0xc5b9a5be, 0x98d8cc33, 0xdd65e108, 0xce301343,
+ 0x0dbdc0cb, 0xc204b9ca, 0xeabe1810, 0x9849163a, 0x234c8ff7, 0x9bc14e3b,
+ 0x4b4c2226, 0x079883be, 0xba59c5f5, 0xd9c77317, 0x1ce689f5, 0x05f49af5,
+ 0x7a83d42a, 0xc509b5ca, 0x0811a95f, 0x093520a2, 0x73649941, 0xd9691ef5,
+ 0x6878ec0d, 0x4043add6, 0x7516d8b7, 0x5c7070ff, 0x4ce52e1d, 0xf209e123,
+ 0xfe4319c4, 0x9774620a, 0x7a58d047, 0x524b09b7, 0x96cbf044, 0x2a9044a2,
+ 0x514995dc, 0xe4b83ed6, 0xd21be300, 0x2966d4f8, 0xd9ee19c4, 0xb60788f6,
+ 0xf8d074ab, 0xa7e13295, 0x93718edc, 0xba9fc096, 0x0ad2fbbc, 0x9fe0c363,
+ 0x472a10b4, 0xda9c946b, 0x37276997, 0x04e452fc, 0xd19233b5, 0xa277ef0e,
+ 0x49619ddd, 0xb5822d56, 0x6ca4d02f, 0x7d0c0fc3, 0xa29196e2, 0xb6988a4f,
+ 0x785b7552, 0xeaee3c24, 0x87993424, 0xfcb49693, 0x21e64d84, 0x9e2dcea8,
+ };
+ constexpr RsaBuffer exp_res{
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ };
+ // Uninitialized on purpose.
+ RsaBuffer act_res;
+
+ EXPECT_EQ(mod_exp(sig.data(), kRsaVerifyExponent65537, r_square.data(),
+ m.data(), m0_inv, act_res.data()),
+ true);
+ EXPECT_EQ(exp_res, act_res);
+}
+
+TEST(ModExp, Exp3) {
+ // Private key d: {
+ // 0x129c022b, 0x13e47956, 0xdfec2aca, 0xb814ecac, 0x72c55992, 0xfcf87ab5,
+ // 0x29091c15, 0xed118f4d, 0xcdf98cba, 0x8ce9d3c4, 0x5870f4aa, 0x1466b189,
+ // 0xf61cd198, 0x898e7523, 0xb083e2af, 0x41c9533c, 0xf3a3d236, 0xb85f886e,
+ // 0x3a3d6426, 0x310a128e, 0x6bd63e65, 0xa8b5a275, 0xb01bd973, 0x0bfd31a7,
+ // 0xc0860d67, 0x9c82b2e4, 0x58b5313d, 0x10a5cdbb, 0x4c8756e1, 0xde699fc1,
+ // 0x64b7ea15, 0x0de1a5ab, 0x5ec3810e, 0xcdab8036, 0x2914896e, 0x3fc10cdd,
+ // 0x029e6787, 0x8a9fb6ee, 0x114d4a63, 0x48e7fb42, 0x28593dc1, 0x72ae9ccf,
+ // 0x921ad67b, 0xcccc6d1e, 0x79956f79, 0x6bc6189e, 0x1cb13c91, 0x80c0e7c9,
+ // 0x0c6ea14b, 0xf631e8ac, 0x866f54e7, 0xe1771b9a, 0x57026f77, 0xa4068cb9,
+ // 0xde218576, 0x932e8df6, 0xd0641b5b, 0x65cc6e0f, 0x3fdaac0e, 0x9d036254,
+ // 0x74f8e2f2, 0x55245512, 0xa3626209, 0x8bdec1d9, 0x393ce8b3, 0xa013b9bb,
+ // 0xf9708b92, 0x62aa3401, 0x7eed6670, 0xcc084151, 0xc594ff05, 0x359ba561,
+ // 0x6735cc4a, 0xbba98282, 0x3dec3980, 0xe91eb975, 0x854dc579, 0x09c5dc6f,
+ // 0x660655d4, 0x46d4c3fc, 0x7b942f7c, 0x756586c2, 0x7057ce35, 0x2ca213c7,
+ // 0xd900854e, 0xb22aab06, 0xb8c816a0, 0x941aa9ae, 0x864e97a1, 0xf69ecc7d,
+ // 0x5a3b56bc, 0xca0180ca, 0x67012e82, 0x4f7ac33c, 0x391a1b40, 0x1e70f217,
+ // };
+ constexpr RsaBuffer m{
+ 0x3489eab3, 0x23e3d222, 0xbe69ae96, 0xccc537fa, 0xf83c6774, 0xe683f91b,
+ 0x9c588896, 0x44654dec, 0x96729ce1, 0x625a6410, 0x6435e750, 0xec42933f,
+ 0x130c9e34, 0xeb1834b6, 0x2a117689, 0xb3b2f7bf, 0x21f92171, 0x4c1a1765,
+ 0x9a92fe4b, 0xac9b5286, 0x0049c14f, 0x2531d556, 0x3f6e28ae, 0xe12124a6,
+ 0x40b11690, 0xecfb1d29, 0x9af61602, 0x3d0f71b9, 0x1b9246cf, 0xbe254ff6,
+ 0xb2003ba0, 0x440c6682, 0x251589aa, 0xb65e34bb, 0x3c17861f, 0xc24717a0,
+ 0x35588598, 0xf8b64e80, 0x71cd790b, 0xa7ba410a, 0x98ece611, 0x3502cc9b,
+ 0xc75ac49f, 0x415dd4ee, 0x657989ed, 0x784146ac, 0x3d6dada5, 0xb59e1a7a,
+ 0x4a97c7c6, 0xc52b7408, 0x269bfd6f, 0x48caa59f, 0x0a0e9ccf, 0xd8274c58,
+ 0x34c920c7, 0x731753c9, 0xe258a425, 0x62ca945e, 0x7f200856, 0xae144df9,
+ 0xbdd551af, 0xfed9fe6e, 0xd44e4c37, 0x47388b19, 0x576d7435, 0xc0765a63,
+ 0xd8a3456f, 0x4ffd380b, 0xf99066a2, 0xc83187e8, 0xa17dfa22, 0x41a5e04a,
+ 0x6b42c9bd, 0x65f90f0e, 0x73895904, 0x76b858bf, 0x1fd2a0db, 0x3aa32a9d,
+ 0x642602f8, 0xa8fc97ea, 0xe5791ce9, 0xc061288e, 0xa20ed540, 0x0bcc76ac,
+ 0x16031fd5, 0x2d000229, 0x54b087c4, 0x789ffa18, 0x25d78dc9, 0xc7b8caf1,
+ 0x1d64086d, 0xbc0904be, 0x6a071710, 0xdce0936a, 0x569ca381, 0xb6a5ac8b,
+ };
+ constexpr uint32_t m0_inv = 0x88df2b85;
+ constexpr RsaBuffer sig{
+ 0xca60cb6e, 0xd3a786de, 0x37623afb, 0x7f6cbc1a, 0x5366d957, 0xe69ffe2f,
+ 0x3560dc40, 0xf8b205c5, 0xa612764f, 0xb0415cf7, 0x5c5b87d9, 0xe0081c67,
+ 0xadc8d9bd, 0xdd072b18, 0x8e22b48b, 0x758b9df3, 0xb208d5ab, 0x5f1bcb08,
+ 0xb16f9e88, 0xf2d37daf, 0xf7fc6ecb, 0x5a102bb9, 0xe61a9b3f, 0x96541e3e,
+ 0x3718d3ef, 0x769b35c2, 0xf571f77a, 0x82a6f325, 0xaa5ef30c, 0x17048840,
+ 0xc71ddc21, 0xc7bc71ed, 0x14f7ed74, 0x7a3d6a80, 0xebb0c73d, 0x5f28b2c2,
+ 0x56a502db, 0x39a3814f, 0x37df9ba4, 0x397e700d, 0x6c03a24d, 0x9efa0232,
+ 0x257c4b77, 0xa928a03a, 0x43455edd, 0x57e509fb, 0x32458a00, 0x09941f22,
+ 0xca9af629, 0x76a01068, 0x4c638cbe, 0x9b8a3ff6, 0x3979752d, 0x6d4c9bb8,
+ 0x3ee6189c, 0xab9b7212, 0x2116de70, 0x429344c4, 0x072412c7, 0x747fff3d,
+ 0x9d07cc3f, 0xb188d846, 0xcf4959ed, 0xc622387c, 0x32aeb26b, 0xf2921d28,
+ 0x60793032, 0x061e4108, 0x6d70682b, 0x062ffa0b, 0x2b1f1696, 0x507a26f5,
+ 0x1401059c, 0x202485a9, 0xfe963ae9, 0x54423a9d, 0x9731f9bb, 0x227e9788,
+ 0x50846b54, 0x1e9f59f1, 0x3f158119, 0xc36f0b7b, 0xbef3b349, 0xf9172b6f,
+ 0x3daf21c0, 0x819ee37e, 0x0bba9299, 0x90727884, 0xc74908f9, 0xec095a40,
+ 0x8e2120dd, 0xfbefd497, 0x2227f721, 0xb7abdc98, 0xf7e55656, 0x3be75b5c,
+ };
+ constexpr RsaBuffer r_square{
+ 0x3863b1be, 0x2913ebf7, 0x4fc03d0e, 0x482a3973, 0xa3b8f6a9, 0xf7473acb,
+ 0xbf4bd684, 0xa22a9423, 0x8d2fa6f6, 0x7f1acc71, 0x718c39ed, 0xffeaa651,
+ 0xba592ce4, 0xa05e4c98, 0x89d5b580, 0x7f394220, 0xd02c350b, 0x71692df1,
+ 0xf896a5b7, 0x791e5249, 0x0c7bf245, 0x80c8c8b2, 0x8bb7ca49, 0xc91f3f3a,
+ 0x223bc9b1, 0x22b07bc8, 0xce145fbc, 0xa04cd67e, 0x3d7999d4, 0xaac652fc,
+ 0x70380397, 0x7ad5512a, 0x605df8bb, 0x6e694ebf, 0x498901cb, 0x6966203d,
+ 0x34ae90b6, 0x0859c604, 0x16b2ebaa, 0x44d734e0, 0x39caa18e, 0x76d1d9a3,
+ 0x985570c8, 0xbd4216e8, 0x6ee8a815, 0xf45f6b13, 0xcafa40e9, 0xb8884042,
+ 0xcda1fc24, 0x34e64f10, 0xeee01c26, 0x6b42d326, 0xe26972cd, 0x71f6230c,
+ 0x27febf17, 0xdafc774b, 0x75777ad5, 0x6e5c4c40, 0x7995b95e, 0x2465f6f7,
+ 0x6783399a, 0xe571421a, 0x8faf084a, 0xd303dd08, 0x92cc413e, 0x1029f59f,
+ 0x08bec8f5, 0x8d3ae156, 0xbe3b3cae, 0x4a52fd6a, 0xc9979f63, 0x66dc5646,
+ 0x315f0f71, 0xf867366a, 0x809ce4b1, 0xb69b56d3, 0xb0b219d7, 0xede105a6,
+ 0xfc70656a, 0x7f27b7bd, 0x74e0004b, 0xe8bb9577, 0x2df61aba, 0x4ef701ea,
+ 0x2d1f4d03, 0x17961c80, 0x7b01bded, 0x852a41bb, 0x5e173716, 0xf48a5071,
+ 0x3dba1742, 0xa3a5c9ae, 0xfd275d1c, 0x2f3937f9, 0x45579413, 0x2951778f,
+ };
+ constexpr RsaBuffer exp_res{
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ };
+ // Uninitialized on purpose.
+ RsaBuffer act_res;
+
+ EXPECT_EQ(mod_exp(sig.data(), kRsaVerifyExponent3, r_square.data(), m.data(),
+ m0_inv, act_res.data()),
+ true);
+ EXPECT_EQ(exp_res, act_res);
+}
+
} // namespace
} // namespace rsa_verify_unittest