diff --git a/sw/otbn/crypto/rsa_keygen.s b/sw/otbn/crypto/rsa_keygen.s index 8e34a40ba7a9f..2d39c736a589a 100644 --- a/sw/otbn/crypto/rsa_keygen.s +++ b/sw/otbn/crypto/rsa_keygen.s @@ -11,6 +11,7 @@ .globl check_p .globl check_q .globl modinv_f4 +.globl relprime_small_primes /** * Generate a random RSA key pair. @@ -1003,8 +1004,7 @@ check_p: /* Get the FG0.Z flag into a register. x2 <= (CSRs[FG0] >> 3) & 1 = FG0.Z */ csrrs x2, FG0, x0 - srli x2, x2, 3 - andi x2, x2, 1 + andi x2, x2, 8 /* If the flag is set, then the check failed and we can skip the remaining checks. */ @@ -1033,13 +1033,6 @@ check_p: li x2, 256 add x15, x14, x2 - /** - * TODO: add something like BoringSSL's is_obviously_composite to filter out - * numbers that are divisible by the first few hundred primes. This filters - * out 80-90% of composites without resorting to the very slow Miller-Rabin - * check. - */ - /* Calculate the number of Miller-Rabin rounds. The number of rounds is selected based on the bit-length according to FIPS 186-5, table B.1. According to that table, the minimums for an error probability matching @@ -1212,58 +1205,37 @@ generate_prime_candidate: ret /** - * Check if a large number is relatively prime to 65537 (aka F4). - * - * Returns a nonzero value if GCD(x,65537) == 1, and 0 otherwise + * Partially reduce a value modulo m such that 2^32 mod m == 1. * - * A naive implementation would simply check if GCD(x, F4) == 1, However, we - * can simplify the check for relative primality using a few helpful facts - * about F4 specifically: - * 1. It is prime. - * 2. It has the special form (2^16 + 1). + * Returns r such that r mod m = x mod m and r < 2^35. * - * Because F4 is prime, checking if a number x is relatively prime to F4 means - * simply checking if x is a direct multiple of F4; if (x % F4) != 0, then x is - * relatively prime to F4. This means that instead of computing GCD, we can use - * basic modular arithmetic. + * Can be used to speed up modular reduction on certain numbers. * - * Here, the special form of F4, fact (2), comes in handy. Note that 2^16 is - * equivalent to -1 modulo F4. So if we express a number x in base-2^16, we can - * simplify as - * follows: - * x = x0 + 2^16 * x1 + 2^32 * x2 + 2^48 * x3 + ... - * x \equiv x0 + (-1) * x1 + (-1)^2 * x2 + (-1)^3 * x3 + ... (mod F4) - * x \equiv x0 - x1 + x2 - x3 + ... (mod F4) - * - * An additionally helpful observation based on fact (2) is that 2^32, 2^64, - * and in general 2^(32*k) for any k are all 1 modulo F4. This includes 2^256, - * so when we receive the input as a bignum in 256-bit limbs, we can simply - * all the limbs together to get an equivalent number modulo F4: + * Because we know 2^32 mod m is 1, it follows that in general 2^(32*k) for any + * k are all 1 modulo m. This includes 2^256, so when we receive the input as + * a bignum in 256-bit limbs, we can simply all the limbs together to get an + * equivalent number modulo m: * x = x[0] + 2^256 * x[1] + 2^512 * x[2] + ... * x \equiv x[0] + x[1] + x[2] + ... (mod F4) * * From there, we can essentially use the same trick to bisect the number into * 128-bit, 64-bit, and 32-bit chunks and add these together to get an - * equivalent number modulo F4. For the final 16-bit chunks, we need to - * subtract because 2^16 mod F4 = -1 rather than 1. + * equivalent number modulo m. This operation is visually sort of like folding + * the number over itself repeatedly, which is where the function gets its + * name. * * Flags: Flags have no meaning beyond the scope of this subroutine. * * @param[in] x16: dptr_x, pointer to first limb of x in dmem * @param[in] x30: plen, number of 256-bit limbs for x + * @param[in] w24: constant, 2^256 - 1 * @param[in] w31: all-zero - * @param[out] w22: result, 0 only if x is not relatively prime to F4 + * @param[out] w23: r, result * * clobbered registers: x2, w22, w23 * clobbered flag groups: FG0 */ -relprime_f4: - /* Load F4 into the modulus register for later. - MOD <= 2^16 + 1 */ - bn.addi w22, w31, 1 - bn.add w22, w22, w22 << 16 - bn.wsrw MOD, w22 - +fold_bignum: /* Initialize constants for loop. */ li x22, 22 @@ -1295,8 +1267,7 @@ relprime_f4: /* Isolate the lower 128 bits of the sum. w22 <= w23[127:0] */ - bn.rshi w22, w23, w31 >> 128 - bn.rshi w22, w31, w22 >> 128 + bn.and w22, w23, w24 >> 128 /* Add the two 128-bit halves of the sum, plus the carry from the last round of the sum computation. The sum is now up to 129 bits. @@ -1305,8 +1276,7 @@ relprime_f4: /* Isolate the lower 64 bits of the sum. w22 <= w23[63:0] */ - bn.rshi w22, w23, w31 >> 64 - bn.rshi w22, w31, w22 >> 192 + bn.and w22, w23, w24 >> 192 /* Add the two halves of the sum (technically 64 and 65 bits). A carry was not possible in the previous addition since the value is too small. The @@ -1316,29 +1286,76 @@ relprime_f4: /* Isolate the lower 32 bits of the sum. w22 <= w23[31:0] */ - bn.rshi w22, w23, w31 >> 32 - bn.rshi w22, w31, w22 >> 224 + bn.and w22, w23, w24 >> 224 /* Add the two halves of the sum (technically 32 and 34 bits). A carry was not possible in the previous addition since the value is too small. w23 <= (w22 + (w23 >> 32)) */ bn.add w23, w22, w23 >> 32 - /* Note: At this point, we're down to the last few terms: - x \equiv (w23[15:0] - w23[31:16] + w23[34:32]) mod F4 */ + ret + +/** + * Check if a large number is relatively prime to 65537 (aka F4). + * + * Returns a nonzero value if GCD(x,65537) == 1, and 0 otherwise + * + * A naive implementation would simply check if GCD(x, F4) == 1, However, we + * can simplify the check for relative primality using a few helpful facts + * about F4 specifically: + * 1. It is prime. + * 2. It has the special form (2^16 + 1). + * + * Because F4 is prime, checking if a number x is relatively prime to F4 means + * simply checking if x is a direct multiple of F4; if (x % F4) != 0, then x is + * relatively prime to F4. This means that instead of computing GCD, we can use + * basic modular arithmetic. + * + * Here, the special form of F4, fact (2), comes in handy. Since 2^32 mod F4 = + * 1, we can use `fold_bignum` to bring the number down to 35 bits cheaply. + * + * Since 2^16 is equivalent to -1 modulo F4, we can express the resulting + * number in base-2^16 and simplify as follows: + * x = x0 + 2^16 * x1 + 2^32 * x2 + * x \equiv x0 + (-1) * x1 + (-1)^2 * x2 + * x \equiv x0 - x1 + x2 (mod F4) + * + * Flags: Flags have no meaning beyond the scope of this subroutine. + * + * @param[in] x16: dptr_x, pointer to first limb of x in dmem + * @param[in] x30: n, number of 256-bit limbs for x + * @param[in] w31: all-zero + * @param[out] w22: result, 0 only if x is not relatively prime to F4 + * + * clobbered registers: x2, w22, w23 + * clobbered flag groups: FG0 + */ +relprime_f4: + /* Load F4 into the modulus register for later. + MOD <= 2^16 + 1 */ + bn.addi w22, w31, 1 + bn.add w22, w22, w22 << 16 + bn.wsrw MOD, w22 + + /* Generate a 256-bit mask. + w24 <= 2^256 - 1 */ + bn.not w24, w31 + + /* Fold the bignum to get a 35-bit number r such that r mod F4 = x mod F4. + w23 <= r */ + jal x1, fold_bignum /* Isolate the lower 16 bits of the 35-bit working sum. w22 <= w23[15:0] */ - bn.rshi w22, w23, w31 >> 16 - bn.rshi w22, w31, w22 >> 240 + bn.and w22, w23, w24 >> 240 /* Add the lower 16 bits of the sum to the highest 3 bits to get a 17-bit result. w22 <= w22 + (w23 >> 32) */ bn.add w22, w22, w23 >> 32 - /* The sum from the previous addition is < 2 * F4, so a modular addition with - zero is sufficient to fully reduce. + /* The sum from the previous addition is <= 2^16 - 1 + 2^3 - 1 < 2 * F4, so a + modular addition with zero is sufficient to fully reduce. w22 <= w22 mod F4 */ bn.addm w22, w22, w31 @@ -1353,6 +1370,155 @@ relprime_f4: ret +/** + * Check if a large number is divisible by a few small primes. + * + * Returns 0 if x is divisible by a small prime, 2^256 - 1 otherwise. + * + * In this implementation we specifically check the primes 3, 8, and 17, since + * these values m have the property that (1 << 8) mod m is 1, so we can use + * `fold_bignum` to check them very quickly. We use `fold_bignum` to get a + * 35-bit result and then fold the number a few more times to get a 9-bit + * result. + * + * Testing + * + * This routine is constant-time relative to x if x is not divisible by any + * small primes, but exits early if it finds that x is divisible by a small + * prime. + * + * Flags: Flags have no meaning beyond the scope of this subroutine. + * + * @param[in] x16: dptr_x, pointer to first limb of x in dmem + * @param[in] x30: n, number of 256-bit limbs for x + * @param[in] w31: all-zero + * @param[out] w22: result, 0 if x is divisible by a small prime + * + * clobbered registers: x2, w22, w23, w24, w25 + * clobbered flag groups: FG0 + */ +relprime_small_primes: + /* Generate a 256-bit mask. + w24 <= 2^256 - 1 */ + bn.not w24, w31 + + /* Fold the bignum to get a 35-bit number r such that r mod F4 = x mod F4. + w23 <= r */ + jal x1, fold_bignum + + /* Isolate the lower 16 bits of the 35-bit working sum. + w22 <= w23[15:0] */ + bn.and w22, w23, w24 >> 240 + + /* Add the lower 16 bits to the higher 19 bits to get a 20-bit result. + w23 <= w22 + (w23 >> 16) */ + bn.add w23, w22, w23 >> 16 + + /* Isolate the lower 8 bits of the 20-bit working sum. + w22 <= w23[7:0] */ + bn.and w22, w23, w24 >> 248 + + /* Add the lower 8 bits to the higher 12 bits to get a 13-bit result. + w23 <= w22 + (w23 >> 8) */ + bn.add w23, w22, w23 >> 8 + + /* Isolate the lower 8 bits of the 13-bit working sum. + w22 <= w23[7:0] */ + bn.and w22, w23, w24 >> 248 + + /* Add the lower 8 bits to the higher 5 bits to get a 9-bit result. + w23 <= w22 + (w23 >> 8) */ + bn.add w23, w22, w23 >> 8 + + /* Check the residue modulo 3. + x2 <= if (w23 mod 3) == 0 then 8 else 0 */ + bn.mov w25, w23 + bn.addi w24, w31, 3 + jal x1, is_zero_mod_small_prime + + /* If x2 != 0, exit early. */ + bne x2, x0, __relprime_small_primes_fail + + /* Check the residue modulo 5. + x2 <= if (w23 mod 5) == 0 then 8 else 0 */ + bn.mov w25, w23 + bn.addi w24, w31, 5 + jal x1, is_zero_mod_small_prime + + /* If x2 != 0, exit early. */ + bne x2, x0, __relprime_small_primes_fail + + /* Check the residue modulo 17. + x2 <= if (w23 mod 17) == 0 then 8 else 0 */ + bn.mov w25, w23 + bn.addi w24, w31, 17 + jal x1, is_zero_mod_small_prime + + /* If x2 != 0, exit early. */ + bne x2, x0, __relprime_small_primes_fail + + /* No small prime divisors found; return 2^256 - 1. */ + bn.not w22, w31 + ret + +__relprime_small_primes_fail: + /* Small prime divisor found; return 0. */ + bn.sub w22, w22, w22 + ret + +/** + * Reduce a 9-bit number modulo a small number with conditional subtractions. + * + * Returns r = 8 if x mod m = 0, otherwise r = 0. + * + * Helper function for `relprime_small_primes`. + * + * This function runs in constant time. + * + * @param[in] w23: x, input, x < 2^9. + * @param[in] w24: m, modulus, 2 < m < 2^256. + * @param[in] w31: all-zero + * @param[out] x2: result, 8 if x mod m = 0 and otherwise 0 + * + * clobbered registers: x2, w24, w25 + * clobbered flag groups: FG0 + */ +is_zero_mod_small_prime: + /* Copy input. */ + bn.mov w25, w23 + + /* Since we know m is at least 2 bits, start with m << 7 as a value that will + definitely be greater than x / 2. + w24 <= m << 7 */ + bn.rshi w24, w24, w31 >> 249 + + /* Repeatedly reduce using conditional subtractions. + + Loop invariant (i=7 to 0): + w24 = m << i + w25 < 2*(m << i) + w25 mod m = x mod m + */ + loopi 8, 3 + /* w22 <= w25 - w24 */ + bn.sub w22, w25, w24 + /* Select the subtraction only if it did not underflow. + w25 <= FG0.C ? w25 : w22 */ + bn.sel w25, w25, w22, FG0.C + /* w24 <= w24 >> 1 */ + bn.rshi w24, w31, w24 >> 1 + + /* Check if w25 is 0. + FG0.Z <= w25 == 0 */ + bn.cmp w25, w31 + + /* Get the FG0.Z flag into a register and return. + x2 <= FG0 & 8 = FG0.Z << 3 */ + csrrs x2, 0x7c0, x0 + andi x2, x2, 8 + + ret + .section .scratchpad /* Extra label marking the start of p || q in memory. The `derive_d` function diff --git a/sw/otbn/crypto/tests/BUILD b/sw/otbn/crypto/tests/BUILD index 991d6a5fda3a0..0885553abc82d 100644 --- a/sw/otbn/crypto/tests/BUILD +++ b/sw/otbn/crypto/tests/BUILD @@ -780,6 +780,74 @@ otbn_consttime_test( ], ) +otbn_sim_test( + name = "relprime_small_primes_multiple_of_3_test", + srcs = [ + "relprime_small_primes_multiple_of_3_test.s", + ], + exp = "relprime_small_primes_multiple_of_3_test.exp", + deps = [ + "//sw/otbn/crypto:div", + "//sw/otbn/crypto:gcd", + "//sw/otbn/crypto:lcm", + "//sw/otbn/crypto:montmul", + "//sw/otbn/crypto:mul", + "//sw/otbn/crypto:primality", + "//sw/otbn/crypto:rsa_keygen", + ], +) + +otbn_sim_test( + name = "relprime_small_primes_multiple_of_5_test", + srcs = [ + "relprime_small_primes_multiple_of_5_test.s", + ], + exp = "relprime_small_primes_multiple_of_5_test.exp", + deps = [ + "//sw/otbn/crypto:div", + "//sw/otbn/crypto:gcd", + "//sw/otbn/crypto:lcm", + "//sw/otbn/crypto:montmul", + "//sw/otbn/crypto:mul", + "//sw/otbn/crypto:primality", + "//sw/otbn/crypto:rsa_keygen", + ], +) + +otbn_sim_test( + name = "relprime_small_primes_multiple_of_17_test", + srcs = [ + "relprime_small_primes_multiple_of_17_test.s", + ], + exp = "relprime_small_primes_multiple_of_17_test.exp", + deps = [ + "//sw/otbn/crypto:div", + "//sw/otbn/crypto:gcd", + "//sw/otbn/crypto:lcm", + "//sw/otbn/crypto:montmul", + "//sw/otbn/crypto:mul", + "//sw/otbn/crypto:primality", + "//sw/otbn/crypto:rsa_keygen", + ], +) + +otbn_sim_test( + name = "relprime_small_primes_negative_test", + srcs = [ + "relprime_small_primes_negative_test.s", + ], + exp = "relprime_small_primes_negative_test.exp", + deps = [ + "//sw/otbn/crypto:div", + "//sw/otbn/crypto:gcd", + "//sw/otbn/crypto:lcm", + "//sw/otbn/crypto:montmul", + "//sw/otbn/crypto:mul", + "//sw/otbn/crypto:primality", + "//sw/otbn/crypto:rsa_keygen", + ], +) + otbn_library( name = "rsa_keygen_checkpq_test_data", srcs = [ diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_17_test.exp b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_17_test.exp new file mode 100644 index 0000000000000..70cbf8d4bbdf8 --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_17_test.exp @@ -0,0 +1,2 @@ +# Expect 0 (check failed). +w22 = 0 diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_17_test.s b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_17_test.s new file mode 100644 index 0000000000000..f2b6fd43430bd --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_17_test.s @@ -0,0 +1,69 @@ +/* Copyright lowRISC contributors. */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/** + * Standalone test to check an RSA keygen subroutine. + * + * The `relprime_small_primes` subroutine checks if a candidate prime is a + * multiple of a small prime. This test ensures that the check detects a + * multiple of 17. + */ + +.section .text.start + +main: + /* Init all-zero register. */ + bn.xor w31, w31, w31 + + /* Load the number of limbs for this test. */ + li x30, 4 + + /* w22 <= 0 if dmem[simple_positive_input] is NOT relatively prime to F4 */ + la x16, input + jal x1, relprime_small_primes + + ecall + +.data + +/** + * A 1024-bit value that is a multiple of 17 and NOT 3 or 5. + * + * Full value for reference = + * 0xfbe7d1a3a6642d2eb873e0b4c23eda03f9d299d8b5cbd03e735f18989c2f3e275e1d38306b2de24f70253a17b1197785e775bfbd717249031f4258944965eb3ff3078793cbff7898739b0062121017b7a328b77eddc338ec653f324f08771703909453a99c976fdc385d405480f795117ee9807fbe51cbe4b96770fb961719ba + */ +.balign 32 +input: +.word 0x961719ba +.word 0xb96770fb +.word 0xbe51cbe4 +.word 0x7ee9807f +.word 0x80f79511 +.word 0x385d4054 +.word 0x9c976fdc +.word 0x909453a9 +.word 0x08771703 +.word 0x653f324f +.word 0xddc338ec +.word 0xa328b77e +.word 0x121017b7 +.word 0x739b0062 +.word 0xcbff7898 +.word 0xf3078793 +.word 0x4965eb3f +.word 0x1f425894 +.word 0x71724903 +.word 0xe775bfbd +.word 0xb1197785 +.word 0x70253a17 +.word 0x6b2de24f +.word 0x5e1d3830 +.word 0x9c2f3e27 +.word 0x735f1898 +.word 0xb5cbd03e +.word 0xf9d299d8 +.word 0xc23eda03 +.word 0xb873e0b4 +.word 0xa6642d2e +.word 0xfbe7d1a3 diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_3_test.exp b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_3_test.exp new file mode 100644 index 0000000000000..70cbf8d4bbdf8 --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_3_test.exp @@ -0,0 +1,2 @@ +# Expect 0 (check failed). +w22 = 0 diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_3_test.s b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_3_test.s new file mode 100644 index 0000000000000..134cf5f9baaf1 --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_3_test.s @@ -0,0 +1,69 @@ +/* Copyright lowRISC contributors. */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/** + * Standalone test to check an RSA keygen subroutine. + * + * The `relprime_small_primes` subroutine checks if a candidate prime is a + * multiple of a small prime. This test ensures that the check detects a + * multiple of 3. + */ + +.section .text.start + +main: + /* Init all-zero register. */ + bn.xor w31, w31, w31 + + /* Load the number of limbs for this test. */ + li x30, 4 + + /* w22 <= 0 if dmem[simple_positive_input] is NOT relatively prime to F4 */ + la x16, input + jal x1, relprime_small_primes + + ecall + +.data + +/** + * A 1024-bit value that is a multiple of 3 and NOT 5 or 17. + * + * Full value for reference = + * 0x859619e48009dbf121db2000c823862f3ac30d8806a7babf54e784b3a8e2a63c70cca37ce01839e3c6eb780ce56eed882cb9603835f194b2f93ec68a397229d0159827ceb0881ef9c54bc11956b19b9894b2f99373d4d7996bf59a4bcb592cc0933519023a53e46b311acf7565307ad9a419d45066edbfb174bbb8169d56b246 + */ +.balign 32 +input: +.word 0x9d56b246 +.word 0x74bbb816 +.word 0x66edbfb1 +.word 0xa419d450 +.word 0x65307ad9 +.word 0x311acf75 +.word 0x3a53e46b +.word 0x93351902 +.word 0xcb592cc0 +.word 0x6bf59a4b +.word 0x73d4d799 +.word 0x94b2f993 +.word 0x56b19b98 +.word 0xc54bc119 +.word 0xb0881ef9 +.word 0x159827ce +.word 0x397229d0 +.word 0xf93ec68a +.word 0x35f194b2 +.word 0x2cb96038 +.word 0xe56eed88 +.word 0xc6eb780c +.word 0xe01839e3 +.word 0x70cca37c +.word 0xa8e2a63c +.word 0x54e784b3 +.word 0x06a7babf +.word 0x3ac30d88 +.word 0xc823862f +.word 0x21db2000 +.word 0x8009dbf1 +.word 0x859619e4 diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_5_test.exp b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_5_test.exp new file mode 100644 index 0000000000000..70cbf8d4bbdf8 --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_5_test.exp @@ -0,0 +1,2 @@ +# Expect 0 (check failed). +w22 = 0 diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_5_test.s b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_5_test.s new file mode 100644 index 0000000000000..baef8448eba98 --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_5_test.s @@ -0,0 +1,69 @@ +/* Copyright lowRISC contributors. */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/** + * Standalone test to check an RSA keygen subroutine. + * + * The `relprime_small_primes` subroutine checks if a candidate prime is a + * multiple of a small prime. This test ensures that the check detects a + * multiple of 5. + */ + +.section .text.start + +main: + /* Init all-zero register. */ + bn.xor w31, w31, w31 + + /* Load the number of limbs for this test. */ + li x30, 4 + + /* w22 <= 0 if dmem[simple_positive_input] is NOT relatively prime to F4 */ + la x16, input + jal x1, relprime_small_primes + + ecall + +.data + +/** + * A 1024-bit value that is a multiple of 5 and NOT 3 or 17. + * + * Full value for reference = + * 0x7dd35aeb866062ae017ae1f605b19b348668ad55367975302fa84bc99ef347339199cdb22e9bd1f4ef3340edc27e18b79ad3168f7bba3f36bd642650d1e0fc061f17fe99ba598320a03b3f503e63d9017b375642188965eda30f5d792390a6cc080768f3e1d07e76b992e92a1f7f383bb40ef314e55b90ec12e4323a97af0ac5 + */ +.balign 32 +input: +.word 0x97af0ac5 +.word 0x12e4323a +.word 0xe55b90ec +.word 0xb40ef314 +.word 0x1f7f383b +.word 0xb992e92a +.word 0xe1d07e76 +.word 0x080768f3 +.word 0x2390a6cc +.word 0xa30f5d79 +.word 0x188965ed +.word 0x7b375642 +.word 0x3e63d901 +.word 0xa03b3f50 +.word 0xba598320 +.word 0x1f17fe99 +.word 0xd1e0fc06 +.word 0xbd642650 +.word 0x7bba3f36 +.word 0x9ad3168f +.word 0xc27e18b7 +.word 0xef3340ed +.word 0x2e9bd1f4 +.word 0x9199cdb2 +.word 0x9ef34733 +.word 0x2fa84bc9 +.word 0x36797530 +.word 0x8668ad55 +.word 0x05b19b34 +.word 0x017ae1f6 +.word 0x866062ae +.word 0x7dd35aeb diff --git a/sw/otbn/crypto/tests/relprime_small_primes_negative_test.exp b/sw/otbn/crypto/tests/relprime_small_primes_negative_test.exp new file mode 100644 index 0000000000000..3e1f598212b4b --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_negative_test.exp @@ -0,0 +1,2 @@ +# Expect 2^256 - 1 (check passed). +w22 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/sw/otbn/crypto/tests/relprime_small_primes_negative_test.s b/sw/otbn/crypto/tests/relprime_small_primes_negative_test.s new file mode 100644 index 0000000000000..4a9b44e94be02 --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_negative_test.s @@ -0,0 +1,69 @@ +/* Copyright lowRISC contributors. */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/** + * Standalone test to check an RSA keygen subroutine. + * + * The `relprime_small_primes` subroutine checks if a candidate prime is a + * multiple of a small prime. This test ensures that the check does not think a + * prime number is divisible by small primes. + */ + +.section .text.start + +main: + /* Init all-zero register. */ + bn.xor w31, w31, w31 + + /* Load the number of limbs for this test. */ + li x30, 4 + + /* w22 <= 0 if dmem[simple_positive_input] is NOT relatively prime to F4 */ + la x16, input + jal x1, relprime_small_primes + + ecall + +.data + +/** + * A 1024-bit value that is prime. + * + * Full value for reference = + * 0xde7d8c0eb2b3beca4db93f640590f62840bbe2435734ee154ef9dfd6eb5f8b9367a86989b88ee86dea529f5d1d62eb7fff904bd9a62d864a50aac31e5dec899a09255b18d8d61eca4b1bc038d3c655397cac166eb3ae6232e9dc11d31398fd4c0bb0af114cd5670c2c99f59cd6963500d0e9edcac0957b414a394ec915bd9377 + */ +.balign 32 +input: +.word 0x15bd9377 +.word 0x4a394ec9 +.word 0xc0957b41 +.word 0xd0e9edca +.word 0xd6963500 +.word 0x2c99f59c +.word 0x4cd5670c +.word 0x0bb0af11 +.word 0x1398fd4c +.word 0xe9dc11d3 +.word 0xb3ae6232 +.word 0x7cac166e +.word 0xd3c65539 +.word 0x4b1bc038 +.word 0xd8d61eca +.word 0x09255b18 +.word 0x5dec899a +.word 0x50aac31e +.word 0xa62d864a +.word 0xff904bd9 +.word 0x1d62eb7f +.word 0xea529f5d +.word 0xb88ee86d +.word 0x67a86989 +.word 0xeb5f8b93 +.word 0x4ef9dfd6 +.word 0x5734ee15 +.word 0x40bbe243 +.word 0x0590f628 +.word 0x4db93f64 +.word 0xb2b3beca +.word 0xde7d8c0e