Loading CHANGES +7 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,13 @@ Changes between 0.9.6 and 0.9.7 [xx XXX 2000] *) Implement binary inversion algorithm for BN_mod_inverse in addition to the algorithm using long divison. The binary algorithm can be used only if the modulus is odd. It is faster only for relatively small moduli (roughly 20% for 128-bit moduli, roughly 5% for 256-bit moduli), so we use it only for moduli up to 400 bits. [Bodo Moeller] *) Change bctest again: '-x' expressions are not available in all versions of 'test'. [Bodo Moeller] Loading crypto/bn/bn_gcd.c +181 −96 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ * [including the GNU Public Licence.] */ /* ==================================================================== * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions Loading Loading @@ -240,18 +240,102 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, /* From B = a mod |n|, A = |n| it follows that * * 0 <= B < A, * sign*X*a == B (mod |n|), * -sign*Y*a == A (mod |n|). * -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|). */ if (BN_is_odd(n) && (BN_num_bits(n) <= 400)) { /* Binary inversion algorithm; requires odd modulus. * This is faster than the general algorithm if the modulus * is sufficiently small. */ int shift; while (!BN_is_zero(B)) { /* * 0 < B < A <= |n|, * (1) -sign*X*a == B (mod |n|), * (2) sign*Y*a == A (mod |n|) */ /* Now divide B by the maximum possible power of two in the integers, * and divide X by the same value mod |n|. * When we're done, (1) still holds. */ shift = 0; while (!BN_is_bit_set(B, shift)) /* note that 0 < B */ { shift++; if (BN_is_odd(X)) { if (!BN_uadd(X, X, n)) goto err; } /* now X is even, so we can easily divide it by two */ if (!BN_rshift1(X, X)) goto err; } if (shift > 0) { if (!BN_rshift(B, B, shift)) goto err; } /* Same for A and Y. Afterwards, (2) still holds. */ shift = 0; while (!BN_is_bit_set(A, shift)) /* note that 0 < A */ { shift++; if (BN_is_odd(Y)) { if (!BN_uadd(Y, Y, n)) goto err; } /* now Y is even */ if (!BN_rshift1(Y, Y)) goto err; } if (shift > 0) { if (!BN_rshift(A, A, shift)) goto err; } /* We still have (1) and (2), but A may no longer be larger than B. * Both A and B are odd. * The following computations ensure that * * 0 =< B < A = |n|, * (1) -sign*X*a == B (mod |n|), * (2) sign*Y*a == A (mod |n|) */ if (BN_ucmp(B, A) >= 0) { /* -sign*(X + Y)*a == B - A (mod |n|) */ if (!BN_uadd(X, X, Y)) goto err; /* NB: we could use BN_mod_add_quick(X, X, Y, n), but that * actually makes the algorithm slower */ if (!BN_usub(B, B, A)) goto err; } else { /* sign*(X + Y)*a == A - B (mod |n|) */ if (!BN_uadd(Y, Y, X)) goto err; /* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */ if (!BN_usub(A, A, B)) goto err; } } } else { /* general inversion algorithm (less efficient than binary inversion) */ while (!BN_is_zero(B)) { BIGNUM *tmp; /* * 0 < B < A, * (*) sign*X*a == B (mod |n|), * -sign*Y*a == A (mod |n|) * (*) -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|) */ /* (D, M) := (A/B, A%B) ... */ Loading Loading @@ -298,7 +382,7 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, /* Now * A = D*B + M; * thus we have * (**) -sign*Y*a == D*B + M (mod |n|). * (**) sign*Y*a == D*B + M (mod |n|). */ tmp=A; /* keep the BIGNUM object, the value does not matter */ Loading @@ -310,20 +394,20 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, /* Since the former M is now B and the former B is now A, * (**) translates into * -sign*Y*a == D*A + B (mod |n|), * sign*Y*a == D*A + B (mod |n|), * i.e. * -sign*Y*a - D*A == B (mod |n|). * sign*Y*a - D*A == B (mod |n|). * Similarly, (*) translates into * sign*X*a == A (mod |n|). * -sign*X*a == A (mod |n|). * * Thus, * -sign*Y*a - D*sign*X*a == B (mod |n|), * sign*Y*a + D*sign*X*a == B (mod |n|), * i.e. * -sign*(Y + D*X)*a == B (mod |n|). * sign*(Y + D*X)*a == B (mod |n|). * * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at * sign*X*a == B (mod |n|), * -sign*Y*a == A (mod |n|). * -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|). * Note that X and Y stay non-negative all the time. */ Loading Loading @@ -359,12 +443,13 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, X=tmp; sign = -sign; } } /* * The while loop (Euclid's algorithm) ends when * A == gcd(a,n); * we have * -sign*Y*a == A (mod |n|), * sign*Y*a == A (mod |n|), * where Y is non-negative. */ Loading @@ -378,7 +463,7 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, if (BN_is_one(A)) { /* Y*a == 1 (mod |n|) */ if (BN_ucmp(Y,n) < 0) if (!Y->neg && BN_ucmp(Y,n) < 0) { if (!BN_copy(R,Y)) goto err; } Loading crypto/bn/bn_mod.c +2 −2 Original line number Diff line number Diff line Loading @@ -150,8 +150,8 @@ int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_ int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m) { if (!BN_add(r, a, b)) return 0; if (BN_cmp(r, m) >= 0) return BN_sub(r, r, m); if (BN_ucmp(r, m) >= 0) return BN_usub(r, r, m); return 1; } Loading Loading
CHANGES +7 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,13 @@ Changes between 0.9.6 and 0.9.7 [xx XXX 2000] *) Implement binary inversion algorithm for BN_mod_inverse in addition to the algorithm using long divison. The binary algorithm can be used only if the modulus is odd. It is faster only for relatively small moduli (roughly 20% for 128-bit moduli, roughly 5% for 256-bit moduli), so we use it only for moduli up to 400 bits. [Bodo Moeller] *) Change bctest again: '-x' expressions are not available in all versions of 'test'. [Bodo Moeller] Loading
crypto/bn/bn_gcd.c +181 −96 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ * [including the GNU Public Licence.] */ /* ==================================================================== * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions Loading Loading @@ -240,18 +240,102 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, /* From B = a mod |n|, A = |n| it follows that * * 0 <= B < A, * sign*X*a == B (mod |n|), * -sign*Y*a == A (mod |n|). * -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|). */ if (BN_is_odd(n) && (BN_num_bits(n) <= 400)) { /* Binary inversion algorithm; requires odd modulus. * This is faster than the general algorithm if the modulus * is sufficiently small. */ int shift; while (!BN_is_zero(B)) { /* * 0 < B < A <= |n|, * (1) -sign*X*a == B (mod |n|), * (2) sign*Y*a == A (mod |n|) */ /* Now divide B by the maximum possible power of two in the integers, * and divide X by the same value mod |n|. * When we're done, (1) still holds. */ shift = 0; while (!BN_is_bit_set(B, shift)) /* note that 0 < B */ { shift++; if (BN_is_odd(X)) { if (!BN_uadd(X, X, n)) goto err; } /* now X is even, so we can easily divide it by two */ if (!BN_rshift1(X, X)) goto err; } if (shift > 0) { if (!BN_rshift(B, B, shift)) goto err; } /* Same for A and Y. Afterwards, (2) still holds. */ shift = 0; while (!BN_is_bit_set(A, shift)) /* note that 0 < A */ { shift++; if (BN_is_odd(Y)) { if (!BN_uadd(Y, Y, n)) goto err; } /* now Y is even */ if (!BN_rshift1(Y, Y)) goto err; } if (shift > 0) { if (!BN_rshift(A, A, shift)) goto err; } /* We still have (1) and (2), but A may no longer be larger than B. * Both A and B are odd. * The following computations ensure that * * 0 =< B < A = |n|, * (1) -sign*X*a == B (mod |n|), * (2) sign*Y*a == A (mod |n|) */ if (BN_ucmp(B, A) >= 0) { /* -sign*(X + Y)*a == B - A (mod |n|) */ if (!BN_uadd(X, X, Y)) goto err; /* NB: we could use BN_mod_add_quick(X, X, Y, n), but that * actually makes the algorithm slower */ if (!BN_usub(B, B, A)) goto err; } else { /* sign*(X + Y)*a == A - B (mod |n|) */ if (!BN_uadd(Y, Y, X)) goto err; /* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */ if (!BN_usub(A, A, B)) goto err; } } } else { /* general inversion algorithm (less efficient than binary inversion) */ while (!BN_is_zero(B)) { BIGNUM *tmp; /* * 0 < B < A, * (*) sign*X*a == B (mod |n|), * -sign*Y*a == A (mod |n|) * (*) -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|) */ /* (D, M) := (A/B, A%B) ... */ Loading Loading @@ -298,7 +382,7 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, /* Now * A = D*B + M; * thus we have * (**) -sign*Y*a == D*B + M (mod |n|). * (**) sign*Y*a == D*B + M (mod |n|). */ tmp=A; /* keep the BIGNUM object, the value does not matter */ Loading @@ -310,20 +394,20 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, /* Since the former M is now B and the former B is now A, * (**) translates into * -sign*Y*a == D*A + B (mod |n|), * sign*Y*a == D*A + B (mod |n|), * i.e. * -sign*Y*a - D*A == B (mod |n|). * sign*Y*a - D*A == B (mod |n|). * Similarly, (*) translates into * sign*X*a == A (mod |n|). * -sign*X*a == A (mod |n|). * * Thus, * -sign*Y*a - D*sign*X*a == B (mod |n|), * sign*Y*a + D*sign*X*a == B (mod |n|), * i.e. * -sign*(Y + D*X)*a == B (mod |n|). * sign*(Y + D*X)*a == B (mod |n|). * * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at * sign*X*a == B (mod |n|), * -sign*Y*a == A (mod |n|). * -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|). * Note that X and Y stay non-negative all the time. */ Loading Loading @@ -359,12 +443,13 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, X=tmp; sign = -sign; } } /* * The while loop (Euclid's algorithm) ends when * A == gcd(a,n); * we have * -sign*Y*a == A (mod |n|), * sign*Y*a == A (mod |n|), * where Y is non-negative. */ Loading @@ -378,7 +463,7 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, if (BN_is_one(A)) { /* Y*a == 1 (mod |n|) */ if (BN_ucmp(Y,n) < 0) if (!Y->neg && BN_ucmp(Y,n) < 0) { if (!BN_copy(R,Y)) goto err; } Loading
crypto/bn/bn_mod.c +2 −2 Original line number Diff line number Diff line Loading @@ -150,8 +150,8 @@ int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_ int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m) { if (!BN_add(r, a, b)) return 0; if (BN_cmp(r, m) >= 0) return BN_sub(r, r, m); if (BN_ucmp(r, m) >= 0) return BN_usub(r, r, m); return 1; } Loading