[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