diff --git a/sw/otbn/crypto/rsa_keygen.s b/sw/otbn/crypto/rsa_keygen.s index 2d39c736a589a..2c4a56bafcd95 100644 --- a/sw/otbn/crypto/rsa_keygen.s +++ b/sw/otbn/crypto/rsa_keygen.s @@ -178,10 +178,9 @@ check_d: bn.or w23, w23, w20 /* Get the FG0.Z flag into a register. - x2 <= (CSRs[FG0] >> 3) & 1 = FG0.Z */ + x2 <= CSRs[FG0] & 8 = FG0.Z << 3 */ csrrs x2, FG0, x0 - srli x2, x2, 3 - andi x2, x2, 1 + andi x2, x2, 8 /* If x2 != 0, then d is too small and we need to restart key generation from scratch. */ @@ -733,10 +732,9 @@ modinv_f4: bn.cmp w22, w23 /* Get the FG0.Z flag into a register. - x2 <= (CSRs[FG0] >> 3) & 1 = FG0.Z */ + x2 <= CSRs[FG0] & 8 = FG0.Z << 3 */ csrrs x2, FG0, x0 - srli x2, x2, 3 - andi x2, x2, 1 + andi x2, x2, 8 /* If the flag is unset (x2 == 0) then u != 1; in this case GCD(65537, m) != 1 and the modular inverse cannot be computed. This should never happen @@ -859,10 +857,9 @@ _generate_p_counter_nonzero: bn.cmp w20, w24 /* Get the FG0.Z flag into a register. - x2 <= (CSRs[FG0] >> 3) & 1 = FG0.Z */ + x2 <= CSRs[FG0] & 8 = FG0.Z << 3 */ csrrs x2, FG0, x0 - srli x2, x2, 3 - andi x2, x2, 1 + andi x2, x2, 8 /* If the flag is set, then the check passed. Otherwise, retry.*/ beq x2, x0, _generate_p_retry @@ -932,10 +929,9 @@ _generate_q_counter_nonzero: bn.cmp w20, w24 /* Get the FG0.Z flag into a register. - x2 <= (CSRs[FG0] >> 3) & 1 = FG0.Z */ + x2 <= CSRs[FG0] & 8 = FG0.Z << 3 */ csrrs x2, FG0, x0 - srli x2, x2, 3 - andi x2, x2, 1 + andi x2, x2, 8 /* If the flag is set, then the check passed. Otherwise, retry.*/ beq x2, x0, _generate_q_retry @@ -1002,7 +998,7 @@ check_p: bn.sel w24, w31, w24, FG0.Z /* Get the FG0.Z flag into a register. - x2 <= (CSRs[FG0] >> 3) & 1 = FG0.Z */ + x2 <= CSRs[FG0] & 8 = FG0.Z << 3 */ csrrs x2, FG0, x0 andi x2, x2, 8 @@ -1133,10 +1129,9 @@ check_q: bn.addi w20, w20, 0 /* Get the FG0.Z flag into a register. - x2 <= (CSRs[FG0] >> 3) & 1 = FG0.Z */ + x2 <= CSRs[FG0] & 8 = FG0.Z << 3 */ 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. */ @@ -1209,7 +1204,8 @@ generate_prime_candidate: * * Returns r such that r mod m = x mod m and r < 2^35. * - * Can be used to speed up modular reduction on certain numbers. + * Can be used to speed up modular reduction on certain numbers, such as 3, 5, + * 17, and 65537. * * 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 @@ -1252,7 +1248,7 @@ fold_bignum: Loop invariants for iteration i (i=0..n-1): x2 = dptr_x + i*32 x22 = 22 - (w23 + FG0.C) \equiv x[0] + x[1] + ... + x[i-1] (mod F4) + (w23 + FG0.C) \equiv x[0] + x[1] + ... + x[i-1] (mod m) */ loop x30, 2 /* Load the next limb. @@ -1260,7 +1256,7 @@ fold_bignum: bn.lid x22, 0(x2++) /* Accumulate the new limb, incorporating the carry bit from the previous - round if there was one (this works because 2^256 \equiv 1 mod F4). + round if there was one (this works because 2^256 \equiv 1 mod m). w23 <= (w23 + x[i] + FG0.C) mod 2^256 FG0.C <= (w23 + x[i] + FG0.C) / 2^256 */ bn.addc w23, w23, w22 @@ -1295,6 +1291,129 @@ fold_bignum: ret +/** + * Partially reduce a value modulo m such that 2^32 mod m == 4. + * + * Returns r such that r mod m = x mod m and r < 2^33. + * + * Can be used to speed up modular reduction on certain numbers, such as 7, 11, + * and 31. + * + * The logic here is very similar to `fold_bignum`, except we need to multiply + * by a power of 4 each time we fold. The core reasoning is that, for any + * positive k: + * x0 + 2^(32*k)x1 \equiv x0 + (4**k)*x1 (mod m) + * + * This routine assumes that the number of limbs `n` is at most 8 (i.e. enough + * for RSA-4096); bounds analysis may not work out for larger numbers. + * + * 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, 1 <= n < 8 + * @param[in] w24: constant, 2^256 - 1 + * @param[in] w31: all-zero + * @param[out] w23: r, result + * + * clobbered registers: x2, x3, w22, w23, w25 + * clobbered flag groups: FG0 + */ +fold_bignum_pow2_32_equiv_4: + /* Initialize constants for loop. */ + li x3, 32 + li x22, 22 + + /* Get a pointer to the end of the input. + x2 <= dptr_x + n*32 */ + slli x2, x30, 5 + add x2, x2, x16 + + /* Initialize the two-limb sum to zero and clear FG0.C. + w25, w23 <= 0 + FG0.C <= 0 */ + bn.sub w23, w23, w23 + bn.sub w25, w25, w25 + + /* Iterate through the limbs of x and add them together. + + We shift by 16 each time, since 2^256 mod m = 4**8 = 2^16. The size of the + sum therefore increases by 17 bits on each iteration (16 from the shift + and 1 from the addition). Since we are assuming at most 8 limbs, the + maximum value of the final sum should fit in 256+8*17 = 375 bits. + + Loop invariants for iteration i (i=0..n-1): + x2 = dptr_x + (n-i)*32 + x3 = 32 + x22 = 22 + (w23 + (w25 << 256)) \equiv x[i+1] + x[i+2] + ... + x[n-1] (mod m) + (w23 + (w25 << 256)) < 2^(256+(n-1-i)*17) + */ + loop x30, 5 + /* Move the pointer down one limb. + x2 <= dptr_x + (n-1-i)*32 */ + sub x2, x2, x3 + + /* Load the next limb. + w22 <= x[n-1-i] */ + bn.lid x22, 0(x2) + + /* Get the high part of the shifted sum. + w25 <= ([w25,w23] << 16) >> 256 */ + bn.rshi w25, w25, w23 >> 240 + + /* Accumulate the new limb. + [w25,w23] <= ([w25,w23] << 16 + x[i]) mod 2^256 */ + bn.add w23, w22, w23 << 16 + bn.addc w25, w31, w25 + + /* Add the two limbs of the sum for a 257-bit result. + w23 + (FG0.C << 256) <= w23 + (w25 << 16) */ + bn.add w23, w23, w25 << 16 + + /* Add the carry bit to the high 128 bits of the sum. + w25 <= (w23 >> 128) + FG0.C */ + bn.addc w25, w31, w23 >> 128 + + /* Isolate the lower 128 bits of the sum. + w22 <= w23[127:0] */ + bn.and w22, w23, w24 >> 128 + + /* Add the two halves of the sum to get a 129+8+1=138-bit value. + w23 <= w22 + w25 << 8 */ + bn.addc w23, w22, w25 << 8 + + /* Isolate the lower 64 bits of the sum. + w22 <= w23[63:0] */ + bn.and w22, w23, w24 >> 192 + + /* Add the two halves of the sum to get a (138-64)+4+1=79-bit value. + w23 <= (w22 + ((w23 >> 64) << 4)) */ + bn.rshi w23, w31, w23 >> 64 + bn.rshi w23, w23, w31 >> 252 + bn.add w23, w22, w23 + + /* Isolate the lower 32 bits of the sum. + w22 <= w23[31:0] */ + bn.and w22, w23, w24 >> 224 + + /* Add the two halves of the sum to get a (79-32)+2+1=50-bit value. + w23 <= (w22 + ((w23 >> 32) << 2)) */ + bn.rshi w23, w31, w23 >> 32 + bn.rshi w23, w23, w31 >> 254 + bn.add w23, w22, w23 + + /* Isolate the lower 32 bits of the sum again. + w22 <= w23[31:0] */ + bn.and w22, w23, w24 >> 224 + + /* Add the two halves of the sum to get a 33-bit value. + w23 <= (w22 + ((w23 >> 32) << 2)) */ + bn.rshi w23, w31, w23 >> 32 + bn.rshi w23, w23, w31 >> 254 + bn.add w23, w22, w23 + + ret + /** * Check if a large number is relatively prime to 65537 (aka F4). * @@ -1354,8 +1473,8 @@ relprime_f4: w22 <= w22 + (w23 >> 32) */ bn.add w22, w22, w23 >> 32 - /* 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. + /* The sum from the previous addition is at most 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 @@ -1375,13 +1494,21 @@ relprime_f4: * * 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. + * In this implementation, we check the primes 3, 5, 7, 11, 17, and 31. + * These primes have special properties that allow us to compute the residue + * quickly: + * - p = {3,5,17} have the property that (2^8) mod p = 1 + * - p = {7,11,31} have the property that (2^32) mod p = 4 * - * Testing + * Testing for these primes will catch approximately: + * 1 - ((1 - 1/3) * (1 - 1/5) * ... * (1 - 1/31)) + * = 62.1% of composite numbers. + * + * Quick intuition for the estimate above: the multiplications calculate the + * proportion of composites we will *fail* to catch. At each multiplication + * step, we multiply the proportion of composites we still haven't caught by + * the proportion that the next small prime will *not* catch (e.g. 4/5 of + * numbers will not be multiples of 5). * * 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 @@ -1394,7 +1521,7 @@ relprime_f4: * @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 registers: x2, w22, w23, w24, w25, w26 * clobbered flag groups: FG0 */ relprime_small_primes: @@ -1402,7 +1529,8 @@ relprime_small_primes: 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. + /* Fold the bignum to get a 35-bit number r such that r mod m = x mod m for + all m such that 2^32 mod m == 1. w23 <= r */ jal x1, fold_bignum @@ -1430,10 +1558,12 @@ relprime_small_primes: w23 <= w22 + (w23 >> 8) */ bn.add w23, w22, w23 >> 8 + /* Load the bit-length for `is_zero_mod_small_prime`. */ + li x10, 9 + /* Check the residue modulo 3. x2 <= if (w23 mod 3) == 0 then 8 else 0 */ - bn.mov w25, w23 - bn.addi w24, w31, 3 + bn.addi w26, w31, 3 jal x1, is_zero_mod_small_prime /* If x2 != 0, exit early. */ @@ -1441,8 +1571,7 @@ relprime_small_primes: /* Check the residue modulo 5. x2 <= if (w23 mod 5) == 0 then 8 else 0 */ - bn.mov w25, w23 - bn.addi w24, w31, 5 + bn.addi w26, w31, 5 jal x1, is_zero_mod_small_prime /* If x2 != 0, exit early. */ @@ -1450,8 +1579,43 @@ relprime_small_primes: /* Check the residue modulo 17. x2 <= if (w23 mod 17) == 0 then 8 else 0 */ - bn.mov w25, w23 - bn.addi w24, w31, 17 + bn.addi w26, w31, 17 + jal x1, is_zero_mod_small_prime + + /* If x2 != 0, exit early. */ + bne x2, x0, __relprime_small_primes_fail + + /* We didn't find any divisors among the primes p such that 2^8 mod p == 1; + now let's try primes such that 2^32 mod p == 4. This includes 7, 11, and + 31. */ + + /* Fold the bignum to get a 33-bit number r such that r mod m = x mod m for + all m such that 2^32 mod m == 4. + w23 <= r */ + jal x1, fold_bignum_pow2_32_equiv_4 + + /* Load the bit-length for `is_zero_mod_small_prime`. */ + li x10, 33 + + /* Check the residue modulo 7. + x2 <= if (w23 mod 7) == 0 then 8 else 0 */ + bn.addi w26, w31, 7 + jal x1, is_zero_mod_small_prime + + /* If x2 != 0, exit early. */ + bne x2, x0, __relprime_small_primes_fail + + /* Check the residue modulo 11. + x2 <= if (w23 mod 5) == 0 then 8 else 0 */ + bn.addi w26, w31, 11 + jal x1, is_zero_mod_small_prime + + /* If x2 != 0, exit early. */ + bne x2, x0, __relprime_small_primes_fail + + /* Check the residue modulo 31. + x2 <= if (w23 mod 17) == 0 then 8 else 0 */ + bn.addi w26, w31, 31 jal x1, is_zero_mod_small_prime /* If x2 != 0, exit early. */ @@ -1467,54 +1631,62 @@ __relprime_small_primes_fail: ret /** - * Reduce a 9-bit number modulo a small number with conditional subtractions. + * Reduce input modulo a small number with conditional subtractions. * - * Returns r = 8 if x mod m = 0, otherwise r = 0. + * Returns r = 8 if a mod m = 0, otherwise r = 0. * - * Helper function for `relprime_small_primes`. + * Helper function for `relprime_small_primes`. This routine takes time linear + * in the number of bits of the input, so it's slow for large numbers and + * should only be used as a last step once the bit-bound is low. + * + * The sum of the bit-length of the input and the modulus should not exceed + * 256. * * 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] x10: len, max. number of bits in input, 1 < len + * @param[in] w23: a, input, a < 2^len. + * @param[in] w26: m, modulus, 2 < m < 2^(256-len). * @param[in] w31: all-zero - * @param[out] x2: result, 8 if x mod m = 0 and otherwise 0 + * @param[out] x2: result, 8 if a mod m = 0 and otherwise 0 * - * clobbered registers: x2, w24, w25 + * clobbered registers: x2, w22, w25, w26 * 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 + /* Initialize shifted modulus for loop. + w26 <= m << (len - 1) */ + li x2, 1 + sub x2, x10, x2 + loop x2, 1 + bn.add w26, w26, w26 /* Repeatedly reduce using conditional subtractions. - Loop invariant (i=7 to 0): - w24 = m << i + Loop invariant (i=len-1 to 0): + w26 = m << i w25 < 2*(m << i) - w25 mod m = x mod m + w25 mod m = a mod m */ - loopi 8, 3 - /* w22 <= w25 - w24 */ - bn.sub w22, w25, w24 + loop x10, 3 + /* w22 <= w25 - w26 */ + bn.sub w22, w25, w26 /* 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 + /* w26 <= w26 >> 1 */ + bn.rshi w26, w31, w26 >> 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 + x2 <= CSRs[FG0] & 8 = FG0.Z << 3 */ + csrrs x2, FG0, x0 andi x2, x2, 8 ret diff --git a/sw/otbn/crypto/tests/BUILD b/sw/otbn/crypto/tests/BUILD index 0885553abc82d..94ee207996725 100644 --- a/sw/otbn/crypto/tests/BUILD +++ b/sw/otbn/crypto/tests/BUILD @@ -814,6 +814,40 @@ otbn_sim_test( ], ) +otbn_sim_test( + name = "relprime_small_primes_multiple_of_7_test", + srcs = [ + "relprime_small_primes_multiple_of_7_test.s", + ], + exp = "relprime_small_primes_multiple_of_7_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_11_test", + srcs = [ + "relprime_small_primes_multiple_of_11_test.s", + ], + exp = "relprime_small_primes_multiple_of_11_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 = [ @@ -831,6 +865,23 @@ otbn_sim_test( ], ) +otbn_sim_test( + name = "relprime_small_primes_multiple_of_31_test", + srcs = [ + "relprime_small_primes_multiple_of_31_test.s", + ], + exp = "relprime_small_primes_multiple_of_31_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 = [ diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_11_test.exp b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_11_test.exp new file mode 100644 index 0000000000000..70cbf8d4bbdf8 --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_11_test.exp @@ -0,0 +1,2 @@ +# Expect 0 (check failed). +w22 = 0 diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_11_test.s b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_11_test.s new file mode 100644 index 0000000000000..e129204034f09 --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_11_test.s @@ -0,0 +1,68 @@ +/* Copyright lowRISC contributors (OpenTitan project). */ +/* 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 11. + */ + +.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 11 and NOT 3, 5, 7, 17, or 31. + * + * Full value for reference = + */ +.balign 32 +input: +.word 0x0a9a411f +.word 0xca52e7f3 +.word 0x2c301918 +.word 0x948c97b0 +.word 0x171f68fc +.word 0xe36be04a +.word 0x0a7ffbaa +.word 0xf9cf072d +.word 0x51b76bd5 +.word 0x19d0fec0 +.word 0x0771be64 +.word 0x49c95131 +.word 0x1ed7cd7a +.word 0xda4a6077 +.word 0x11fa0022 +.word 0x66e409f1 +.word 0x95548bfd +.word 0x7938113a +.word 0x9296d0f5 +.word 0x1352294c +.word 0x33eaf657 +.word 0x6c47a7dc +.word 0xf57e2b6b +.word 0xd1194a3e +.word 0x84402e7e +.word 0x87641b66 +.word 0x2c3c225e +.word 0x5e27e299 +.word 0x5ee52414 +.word 0xab6816c2 +.word 0x0ea3266c +.word 0x5f4b97ff 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 index f2b6fd43430bd..314ce16ba259c 100644 --- 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 @@ -1,4 +1,4 @@ -/* Copyright lowRISC contributors. */ +/* Copyright lowRISC contributors (OpenTitan project). */ /* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ /* SPDX-License-Identifier: Apache-2.0 */ @@ -28,42 +28,42 @@ main: .data /** - * A 1024-bit value that is a multiple of 17 and NOT 3 or 5. + * A 1024-bit value that is a multiple of 17 and NOT 3, 5, 11, 17, or 31. * * Full value for reference = - * 0xfbe7d1a3a6642d2eb873e0b4c23eda03f9d299d8b5cbd03e735f18989c2f3e275e1d38306b2de24f70253a17b1197785e775bfbd717249031f4258944965eb3ff3078793cbff7898739b0062121017b7a328b77eddc338ec653f324f08771703909453a99c976fdc385d405480f795117ee9807fbe51cbe4b96770fb961719ba + * 0x5143649b8bf054404d0ebedfa7a956dabd297218a15c6410335f8fc10f679ea7b4c0c055a34801e48f9a22cc124580ae9de9fda12300eb6cc6a5ab1e9edb8ff24329ef86ec8833131fbfcbbf8e97f9ac5475dc577367b017cb30d1df1c4baa3c63be79499d79f3e1fda86b6ad1790701b6156e77604ad67d9a8e49e8a4c2a845 */ .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 +.word 0xa4c2a845 +.word 0x9a8e49e8 +.word 0x604ad67d +.word 0xb6156e77 +.word 0xd1790701 +.word 0xfda86b6a +.word 0x9d79f3e1 +.word 0x63be7949 +.word 0x1c4baa3c +.word 0xcb30d1df +.word 0x7367b017 +.word 0x5475dc57 +.word 0x8e97f9ac +.word 0x1fbfcbbf +.word 0xec883313 +.word 0x4329ef86 +.word 0x9edb8ff2 +.word 0xc6a5ab1e +.word 0x2300eb6c +.word 0x9de9fda1 +.word 0x124580ae +.word 0x8f9a22cc +.word 0xa34801e4 +.word 0xb4c0c055 +.word 0x0f679ea7 +.word 0x335f8fc1 +.word 0xa15c6410 +.word 0xbd297218 +.word 0xa7a956da +.word 0x4d0ebedf +.word 0x8bf05440 +.word 0x5143649b diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_31_test.exp b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_31_test.exp new file mode 100644 index 0000000000000..70cbf8d4bbdf8 --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_31_test.exp @@ -0,0 +1,2 @@ +# Expect 0 (check failed). +w22 = 0 diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_31_test.s b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_31_test.s new file mode 100644 index 0000000000000..4699a37ee9fbf --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_31_test.s @@ -0,0 +1,69 @@ +/* Copyright lowRISC contributors (OpenTitan project). */ +/* 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 31. + */ + +.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 31 and NOT 3, 5, 7, 11, or 17. + * + * Full value for reference = + * 0xc6b202813cf17e3c55fefc6282020980fa205b3ccfb384f597e2c0749b1d5213c2ebbf45d5f239e911062650cd43d3c008183c6c2cf217ac48af2bcfeac39a280afd60eea8508324e97f40fa78d5d70a5b5fcb80c1e260feaa1f02f54c072a915d48a0d13a162f1e22f40b26c1eb29d4e7a44c48956c2daa5edfd222e7cf7221 + */ +.balign 32 +input: +.word 0xe7cf7221 +.word 0x5edfd222 +.word 0x956c2daa +.word 0xe7a44c48 +.word 0xc1eb29d4 +.word 0x22f40b26 +.word 0x3a162f1e +.word 0x5d48a0d1 +.word 0x4c072a91 +.word 0xaa1f02f5 +.word 0xc1e260fe +.word 0x5b5fcb80 +.word 0x78d5d70a +.word 0xe97f40fa +.word 0xa8508324 +.word 0x0afd60ee +.word 0xeac39a28 +.word 0x48af2bcf +.word 0x2cf217ac +.word 0x08183c6c +.word 0xcd43d3c0 +.word 0x11062650 +.word 0xd5f239e9 +.word 0xc2ebbf45 +.word 0x9b1d5213 +.word 0x97e2c074 +.word 0xcfb384f5 +.word 0xfa205b3c +.word 0x82020980 +.word 0x55fefc62 +.word 0x3cf17e3c +.word 0xc6b20281 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 index 134cf5f9baaf1..1fd36654d2111 100644 --- 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 @@ -1,4 +1,4 @@ -/* Copyright lowRISC contributors. */ +/* Copyright lowRISC contributors (OpenTitan project). */ /* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ /* SPDX-License-Identifier: Apache-2.0 */ @@ -28,42 +28,42 @@ main: .data /** - * A 1024-bit value that is a multiple of 3 and NOT 5 or 17. + * A 1024-bit value that is a multiple of 3 and NOT 5, 7, 11, 17, or 31. * * Full value for reference = - * 0x859619e48009dbf121db2000c823862f3ac30d8806a7babf54e784b3a8e2a63c70cca37ce01839e3c6eb780ce56eed882cb9603835f194b2f93ec68a397229d0159827ceb0881ef9c54bc11956b19b9894b2f99373d4d7996bf59a4bcb592cc0933519023a53e46b311acf7565307ad9a419d45066edbfb174bbb8169d56b246 + * 0xaf8f432e511b6294ef296e4c0c73fdad210a09a5355a5150cc190b64f9e384fbc3bff603b12bf716d6b7493876ea0aa119eb3cca8706f1cfde452289edf554350bfec6b4812f05bcfd3d799c703a901cf7bc99536b6d1c0df187a62eed3114384bba11b8132de7aed844a98ac7597ea336a01df3664d9ebf3126dc99a5896a45 */ .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 +.word 0xa5896a45 +.word 0x3126dc99 +.word 0x664d9ebf +.word 0x36a01df3 +.word 0xc7597ea3 +.word 0xd844a98a +.word 0x132de7ae +.word 0x4bba11b8 +.word 0xed311438 +.word 0xf187a62e +.word 0x6b6d1c0d +.word 0xf7bc9953 +.word 0x703a901c +.word 0xfd3d799c +.word 0x812f05bc +.word 0x0bfec6b4 +.word 0xedf55435 +.word 0xde452289 +.word 0x8706f1cf +.word 0x19eb3cca +.word 0x76ea0aa1 +.word 0xd6b74938 +.word 0xb12bf716 +.word 0xc3bff603 +.word 0xf9e384fb +.word 0xcc190b64 +.word 0x355a5150 +.word 0x210a09a5 +.word 0x0c73fdad +.word 0xef296e4c +.word 0x511b6294 +.word 0xaf8f432e 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 index baef8448eba98..5b0e6c9ffac3a 100644 --- 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 @@ -1,4 +1,4 @@ -/* Copyright lowRISC contributors. */ +/* Copyright lowRISC contributors (OpenTitan project). */ /* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ /* SPDX-License-Identifier: Apache-2.0 */ @@ -28,42 +28,42 @@ main: .data /** - * A 1024-bit value that is a multiple of 5 and NOT 3 or 17. + * A 1024-bit value that is a multiple of 5 and NOT 3, 7, 11, 17, or 31. * * Full value for reference = - * 0x7dd35aeb866062ae017ae1f605b19b348668ad55367975302fa84bc99ef347339199cdb22e9bd1f4ef3340edc27e18b79ad3168f7bba3f36bd642650d1e0fc061f17fe99ba598320a03b3f503e63d9017b375642188965eda30f5d792390a6cc080768f3e1d07e76b992e92a1f7f383bb40ef314e55b90ec12e4323a97af0ac5 + * 0x95746f2e1cadd653af519d764878e64c332cc27a5ccd76c989ff609bdee59d4d487c89bb09057b968afd2fd69fe76d25b99c1399a7b8e7e5f9bb301f6d62651a62c9c3aea5ff9e44f2f7065b96b16fda5b776f60760644686798018c960f96eaf2fa5e0dd0cbc707c4a06380dccaeea77ac0775afa2eb98d0e560c47f2ddb2bd */ .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 +.word 0x2e6f7495 +.word 0x53d6ad1c +.word 0x769d51af +.word 0x4ce67848 +.word 0x7ac22c33 +.word 0xc976cd5c +.word 0x9b60ff89 +.word 0x4d9de5de +.word 0xbb897c48 +.word 0x967b0509 +.word 0xd62ffd8a +.word 0x256de79f +.word 0x99139cb9 +.word 0xe5e7b8a7 +.word 0x1f30bbf9 +.word 0x1a65626d +.word 0xaec3c962 +.word 0x449effa5 +.word 0x5b06f7f2 +.word 0xda6fb196 +.word 0x606f775b +.word 0x68440676 +.word 0x8c019867 +.word 0xea960f96 +.word 0x0d5efaf2 +.word 0x07c7cbd0 +.word 0x8063a0c4 +.word 0xa7eecadc +.word 0x5a77c07a +.word 0x8db92efa +.word 0x470c560e +.word 0xbdb2ddf2 diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_7_test.exp b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_7_test.exp new file mode 100644 index 0000000000000..70cbf8d4bbdf8 --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_7_test.exp @@ -0,0 +1,2 @@ +# Expect 0 (check failed). +w22 = 0 diff --git a/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_7_test.s b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_7_test.s new file mode 100644 index 0000000000000..adc0bae0007ce --- /dev/null +++ b/sw/otbn/crypto/tests/relprime_small_primes_multiple_of_7_test.s @@ -0,0 +1,69 @@ +/* Copyright lowRISC contributors (OpenTitan project). */ +/* 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 7. + */ + +.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 7 and NOT 3, 5, 11, 17, or 31. + * + * Full value for reference = + * 0x91986e138a0211deddc97f1f4284182b075166745a567a4866c7093a0e4ba084f82346b6572d6b3110ee488087c5b5385227e1671f48b4460afc72659e7e70521b347174161d184c63788c24b4b2e2db3fc1a6b56f86abfaeb7d19a2902a2223a2e51e15f5bc2b4a1f7ee67a1210881cb8b0c7a949efce5d4422e19865050a9f + */ +.balign 32 +input: +.word 0x65050a9f +.word 0x4422e198 +.word 0x49efce5d +.word 0xb8b0c7a9 +.word 0x1210881c +.word 0x1f7ee67a +.word 0xf5bc2b4a +.word 0xa2e51e15 +.word 0x902a2223 +.word 0xeb7d19a2 +.word 0x6f86abfa +.word 0x3fc1a6b5 +.word 0xb4b2e2db +.word 0x63788c24 +.word 0x161d184c +.word 0x1b347174 +.word 0x9e7e7052 +.word 0x0afc7265 +.word 0x1f48b446 +.word 0x5227e167 +.word 0x87c5b538 +.word 0x10ee4880 +.word 0x572d6b31 +.word 0xf82346b6 +.word 0x0e4ba084 +.word 0x66c7093a +.word 0x5a567a48 +.word 0x07516674 +.word 0x4284182b +.word 0xddc97f1f +.word 0x8a0211de +.word 0x91986e13 diff --git a/sw/otbn/crypto/tests/relprime_small_primes_negative_test.s b/sw/otbn/crypto/tests/relprime_small_primes_negative_test.s index 4a9b44e94be02..729028b490656 100644 --- a/sw/otbn/crypto/tests/relprime_small_primes_negative_test.s +++ b/sw/otbn/crypto/tests/relprime_small_primes_negative_test.s @@ -1,4 +1,4 @@ -/* Copyright lowRISC contributors. */ +/* Copyright lowRISC contributors (OpenTitan project). */ /* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ /* SPDX-License-Identifier: Apache-2.0 */