(Sorry if this is already known...)

BN_mod_mul_montgomery returns wrong answers when computing
R = C*D mod P, where the size of P is smaller then the size of
C and D by some amount X of words.

In attachment is a c file that illustrates the error, it compares
the result of BN_mod_mul_montgomery and BN_mod_mul
(bc results agree with BN_mod_mul).  Note that no errors
are returned by the calls to BN_to_mongomery or any other
BN function.
The function works if |P| >= |C|, |D|, and some other bizarre
cases.
I tested it with openssl-0.9.4 and SSLeay 0.9.0b, it gives the
same wrong answers.

-- 
___________________________________________

 Anton Stiglic <[EMAIL PROTECTED]>
 Crypto Punk
 Zero-Knowledge Systems Inc.
___________________________________________
 
/*
 * This shows that BN_mod_mul_montgomery returns the wrong result`
 * when computing R = C*D mod P, with P's lenght smaller than
 * C and D's by some value X.
 * Anton Stiglic ([EMAIL PROTECTED]).
 */

#include <stdio.h>
#include <stdlib.h>
#include "openssl/bn.h" 

int main(void) {
  
  int ret = EXIT_FAILURE;
  
  BIGNUM *C = BN_new();
  BIGNUM *D = BN_new();
  BIGNUM *P = BN_new();
  BIGNUM *R1 = BN_new();
  BIGNUM *R2 = BN_new();
  
  BN_CTX *ctx = BN_CTX_new();
  BN_MONT_CTX *mont = BN_MONT_CTX_new(); 
  
  /* pick random values to test */
  if (! BN_rand(C, 60, 0, 0)) goto done;
  if (! BN_rand(D, 60, 0, 0)) goto done;
  if (! BN_generate_prime(P, 20, 0, 0, 0, 0, 0)) goto done;
  
  /* set the montgomery context with P */
  if (! BN_MONT_CTX_set(mont,P,ctx)) goto done;
  
  /* montgomery reduction to use montgomery mul mod */
  if (!  BN_to_montgomery(R1, R1, mont, ctx)) goto done; 
  if (!  BN_to_montgomery(C, C, mont, ctx)) goto done;
  if (!  BN_to_montgomery(D, D, mont, ctx)) goto done;
  
  /* compute montgomery mod mul */
  if (!  BN_mod_mul_montgomery(R1, C, D, mont, ctx)) goto done;
  
  /* put back everything to regular expression */
  if (! BN_from_montgomery(R1, R1, mont, ctx)) goto done;
  if (! BN_from_montgomery(C, C, mont, ctx)) goto done;
  if (! BN_from_montgomery(D, D, mont, ctx)) goto done; 
  
  /* Now try regular way mod mul, put result in R2  */
  if ( ! BN_mod_mul(R2, C, D, P, ctx)) goto done;
  
  /* compare *should* return 0 since they *should* be the same */  
  if (BN_cmp(R1, R2)) {
    fprintf(stderr, "NO MATCH!!!\n");
  }
  
  ret = EXIT_SUCCESS;
 done:
  if (C) BN_free(C);
  if (D) BN_free(D);
  if (P) BN_free(P);
  if (R1) BN_free(R1);
  if (R2) BN_free(R2);
  
  return ret;
}

Reply via email to