1
0
mirror of https://github.com/ARMmbed/mbedtls.git synced 2025-10-19 19:53:48 +08:00

Add test case exercising (almost) max iterations

With this data, the loop only settles to its final state u == 0 and v ==
GCD(A, N) at the last iteration. However it already has v == GCD(A, N)
at the previous iteration. Concretely, this means that if in
mbedtls_mpi_core_gcd_modinv_odd() we change the main loop as follows

-    for (size_t i = 0; i < (A_limbs + N_limbs) * biL; i++) {
+    for (size_t i = 0; i < (A_limbs + N_limbs) * biL - 2; i++) {

then this test case would fail. Ideally we'd like a test case that would
fail with -1 above but I've not been able to find one and I have no idea
whether that's possible.

Experimentally I've systematically tried small values (8 bit) and
noticed the case A = 2^n and N significantly larger then A is promising,
so I explored that further. Clearly we want A and N's bitlength to be a
multiple of biL because the bound in the paper is with bitlenths while
we use limbs * biL.

Anyway, I ended up with the following Python script.

import secrets
import math

bil = 64

def bitlimbs(x):
    return (x.bit_length() + bil - 1) // bil * bil

def sict_gcd(p, a):
    assert p >= a >= 0
    assert p & 1 != 0 or a & 1 != 0

    u, v = a, p
    for i in range(2 * p.bit_length()):
        s, z = u & 1, v & 1
        t1 = (s ^ z) * v + (2 * s * z - 1) * u
        t2 = (s * v + (2 - 2 * s - z) * u) >> 1

        if t2 >= t1:
            u, v = t1, t2
        else:
            u, v = t2, t1

        if u == 0:  # v == 1 ideally, but can't get it
            return bitlimbs(a) + bitlimbs(p) - (i + 1)

    return 0

a = 2 ** (bil - 1)
m = 1000
while m != 0:
    n = secrets.randbits(2 * bil) | 1
    d = sict_gcd(n, a)
    if d < m:
        m = d
        print(d)

g = math.gcd(a, n)
i = pow(a, -1, n)
print(f'mpi_core_gcd_modinv_odd:"{a:x}":"{n:x}":"{g:x}":"{i:x}"')

Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
This commit is contained in:
Manuel Pégourié-Gonnard
2025-07-17 10:10:56 +02:00
parent 5972096114
commit 0d25cd965d

View File

@@ -530,6 +530,11 @@ mpi_core_gcd_modinv_odd:"e4518a1900fce698fa3":"1a84113636607520200d":"3":""
GCD-modinv random 80-bit, trivial GCD -> inverse GCD-modinv random 80-bit, trivial GCD -> inverse
mpi_core_gcd_modinv_odd:"7f2405d6de7db80a7bc":"1a84113636607520200d":"1":"15f158844a59cd7a3ed2" mpi_core_gcd_modinv_odd:"7f2405d6de7db80a7bc":"1a84113636607520200d":"1":"15f158844a59cd7a3ed2"
# This data results in the gcd-modinv loop converging to its final state
# only in the last iteration. See python script in commit message.
GCD-modinv (almost) max iterations
mpi_core_gcd_modinv_odd:"8000000000000000":"b26eb5721a2cb24c36acb4550b176671":"1":"77e1dd63583a6b3c8deefe7737862c89"
Div2 mod odd: even value Div2 mod odd: even value
mpi_core_div2_mod_odd:"4":"7":"2" mpi_core_div2_mod_odd:"4":"7":"2"