/*
* Multi-precision integer library
*
- * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine
+ * Copyright (C) 2006-2010, Brainspark B.V.
*
- * Copyright (C) 2009 Paul Bakker <polarssl_maintainer at polarssl dot org>
+ * This file is part of PolarSSL (http://www.polarssl.org)
+ * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ * All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* http://math.libtomcrypt.com/files/tommath.pdf
*/
-/* $Cambridge: exim/src/src/pdkim/bignum.c,v 1.2 2009/06/10 07:34:05 tom Exp $ */
-
#include "bignum.h"
#include "bn_mul.h"
/*
* Copy the contents of Y into X
*/
-int mpi_copy( mpi *X, mpi *Y )
+int mpi_copy( mpi *X, const mpi *Y )
{
int ret, i;
/*
* Return the number of least significant bits
*/
-int mpi_lsb( mpi *X )
+int mpi_lsb( const mpi *X )
{
int i, j, count = 0;
/*
* Return the number of most significant bits
*/
-int mpi_msb( mpi *X )
+int mpi_msb( const mpi *X )
{
int i, j;
/*
* Return the total size in bytes
*/
-int mpi_size( mpi *X )
+int mpi_size( const mpi *X )
{
return( ( mpi_msb( X ) + 7 ) >> 3 );
}
/*
* Import from an ASCII string
*/
-int mpi_read_string( mpi *X, int radix, char *s )
+int mpi_read_string( mpi *X, int radix, const char *s )
{
- int ret, i, j, n;
+ int ret, i, j, n, slen;
t_int d;
mpi T;
mpi_init( &T, NULL );
+ slen = strlen( s );
+
if( radix == 16 )
{
- n = BITS_TO_LIMBS( strlen( s ) << 2 );
+ n = BITS_TO_LIMBS( slen << 2 );
MPI_CHK( mpi_grow( X, n ) );
MPI_CHK( mpi_lset( X, 0 ) );
- for( i = strlen( s ) - 1, j = 0; i >= 0; i--, j++ )
+ for( i = slen - 1, j = 0; i >= 0; i--, j++ )
{
if( i == 0 && s[i] == '-' )
{
{
MPI_CHK( mpi_lset( X, 0 ) );
- for( i = 0; i < (int) strlen( s ); i++ )
+ for( i = 0; i < slen; i++ )
{
if( i == 0 && s[i] == '-' )
{
MPI_CHK( mpi_get_digit( &d, radix, s[i] ) );
MPI_CHK( mpi_mul_int( &T, X, radix ) );
- MPI_CHK( mpi_add_int( X, &T, d ) );
+
+ if( X->s == 1 )
+ {
+ MPI_CHK( mpi_add_int( X, &T, d ) );
+ }
+ else
+ {
+ MPI_CHK( mpi_sub_int( X, &T, d ) );
+ }
}
}
/*
* Export into an ASCII string
*/
-int mpi_write_string( mpi *X, int radix, char *s, int *slen )
+int mpi_write_string( const mpi *X, int radix, char *s, int *slen )
{
int ret = 0, n;
char *p;
else
{
MPI_CHK( mpi_copy( &T, X ) );
+
+ if( T.s == -1 )
+ T.s = 1;
+
MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
}
/*
* Write X into an opened file (or stdout if fout == NULL)
*/
-int mpi_write_file( char *p, mpi *X, int radix, FILE *fout )
+int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout )
{
int n, ret;
size_t slen;
size_t plen;
- char s[1024];
+ char s[2048];
n = sizeof( s );
memset( s, 0, n );
/*
* Import X from unsigned binary data, big endian
*/
-int mpi_read_binary( mpi *X, unsigned char *buf, int buflen )
+int mpi_read_binary( mpi *X, const unsigned char *buf, int buflen )
{
int ret, i, j, n;
/*
* Export X into unsigned binary data, big endian
*/
-int mpi_write_binary( mpi *X, unsigned char *buf, int buflen )
+int mpi_write_binary( const mpi *X, unsigned char *buf, int buflen )
{
int i, j, n;
/*
* Compare unsigned values
*/
-int mpi_cmp_abs( mpi *X, mpi *Y )
+int mpi_cmp_abs( const mpi *X, const mpi *Y )
{
int i, j;
/*
* Compare signed values
*/
-int mpi_cmp_mpi( mpi *X, mpi *Y )
+int mpi_cmp_mpi( const mpi *X, const mpi *Y )
{
int i, j;
/*
* Compare signed values
*/
-int mpi_cmp_int( mpi *X, int z )
+int mpi_cmp_int( const mpi *X, int z )
{
mpi Y;
t_int p[1];
/*
* Unsigned addition: X = |A| + |B| (HAC 14.7)
*/
-int mpi_add_abs( mpi *X, mpi *A, mpi *B )
+int mpi_add_abs( mpi *X, const mpi *A, const mpi *B )
{
int ret, i, j;
t_int *o, *p, c;
if( X == B )
{
- mpi *T = A; A = X; B = T;
+ const mpi *T = A; A = X; B = T;
}
if( X != A )
MPI_CHK( mpi_copy( X, A ) );
+ /*
+ * X should always be positive as a result of unsigned additions.
+ */
+ X->s = 1;
+
for( j = B->n - 1; j >= 0; j-- )
if( B->p[j] != 0 )
break;
/*
* Unsigned substraction: X = |A| - |B| (HAC 14.9)
*/
-int mpi_sub_abs( mpi *X, mpi *A, mpi *B )
+int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B )
{
mpi TB;
int ret, n;
if( X != A )
MPI_CHK( mpi_copy( X, A ) );
+ /*
+ * X should always be positive as a result of unsigned substractions.
+ */
+ X->s = 1;
+
ret = 0;
for( n = B->n - 1; n >= 0; n-- )
/*
* Signed addition: X = A + B
*/
-int mpi_add_mpi( mpi *X, mpi *A, mpi *B )
+int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B )
{
int ret, s = A->s;
/*
* Signed substraction: X = A - B
*/
-int mpi_sub_mpi( mpi *X, mpi *A, mpi *B )
+int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B )
{
int ret, s = A->s;
/*
* Signed addition: X = A + b
*/
-int mpi_add_int( mpi *X, mpi *A, int b )
+int mpi_add_int( mpi *X, const mpi *A, int b )
{
mpi _B;
t_int p[1];
/*
* Signed substraction: X = A - b
*/
-int mpi_sub_int( mpi *X, mpi *A, int b )
+int mpi_sub_int( mpi *X, const mpi *A, int b )
{
mpi _B;
t_int p[1];
/*
* Baseline multiplication: X = A * B (HAC 14.12)
*/
-int mpi_mul_mpi( mpi *X, mpi *A, mpi *B )
+int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B )
{
int ret, i, j;
mpi TA, TB;
/*
* Baseline multiplication: X = A * b
*/
-int mpi_mul_int( mpi *X, mpi *A, t_int b )
+int mpi_mul_int( mpi *X, const mpi *A, t_int b )
{
mpi _B;
t_int p[1];
/*
* Division by mpi: A = Q * B + R (HAC 14.20)
*/
-int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B )
+int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B )
{
int ret, i, n, t, k;
mpi X, Y, Z, T1, T2;
* 1 if memory allocation failed
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
*/
-int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b )
+int mpi_div_int( mpi *Q, mpi *R, const mpi *A, int b )
{
mpi _B;
t_int p[1];
/*
* Modulo: R = A mod B
*/
-int mpi_mod_mpi( mpi *R, mpi *A, mpi *B )
+int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B )
{
int ret;
+ if( mpi_cmp_int( B, 0 ) < 0 )
+ return POLARSSL_ERR_MPI_NEGATIVE_VALUE;
+
MPI_CHK( mpi_div_mpi( NULL, R, A, B ) );
while( mpi_cmp_int( R, 0 ) < 0 )
/*
* Modulo: r = A mod b
*/
-int mpi_mod_int( t_int *r, mpi *A, int b )
+int mpi_mod_int( t_int *r, const mpi *A, int b )
{
int i;
t_int x, y, z;
return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO );
if( b < 0 )
- b = -b;
+ return POLARSSL_ERR_MPI_NEGATIVE_VALUE;
/*
* handle trivial cases
y -= z * b;
}
+ /*
+ * If A is negative, then the current y represents a negative value.
+ * Flipping it to the positive side.
+ */
+ if( A->s < 0 && y != 0 )
+ y = b - y;
+
*r = y;
return( 0 );
/*
* Fast Montgomery initialization (thanks to Tom St Denis)
*/
-static void mpi_montg_init( t_int *mm, mpi *N )
+static void mpi_montg_init( t_int *mm, const mpi *N )
{
t_int x, m0 = N->p[0];
/*
* Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36)
*/
-static void mpi_montmul( mpi *A, mpi *B, mpi *N, t_int mm, mpi *T )
+static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, t_int mm, const mpi *T )
{
int i, n, m;
t_int u0, u1, *d;
/*
* Montgomery reduction: A = A * R^-1 mod N
*/
-static void mpi_montred( mpi *A, mpi *N, t_int mm, mpi *T )
+static void mpi_montred( mpi *A, const mpi *N, t_int mm, const mpi *T )
{
t_int z = 1;
mpi U;
/*
* Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
*/
-int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR )
+int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
{
int ret, i, j, wsize, wbits;
int bufsize, nblimbs, nbits;
/*
* Greatest common divisor: G = gcd(A, B) (HAC 14.54)
*/
-int mpi_gcd( mpi *G, mpi *A, mpi *B )
+int mpi_gcd( mpi *G, const mpi *A, const mpi *B )
{
- int ret;
+ int ret, lz, lzt;
mpi TG, TA, TB;
mpi_init( &TG, &TA, &TB, NULL );
- MPI_CHK( mpi_lset( &TG, 1 ) );
MPI_CHK( mpi_copy( &TA, A ) );
MPI_CHK( mpi_copy( &TB, B ) );
+ lz = mpi_lsb( &TA );
+ lzt = mpi_lsb( &TB );
+
+ if ( lzt < lz )
+ lz = lzt;
+
+ MPI_CHK( mpi_shift_r( &TA, lz ) );
+ MPI_CHK( mpi_shift_r( &TB, lz ) );
+
TA.s = TB.s = 1;
while( mpi_cmp_int( &TA, 0 ) != 0 )
{
- while( ( TA.p[0] & 1 ) == 0 ) MPI_CHK( mpi_shift_r( &TA, 1 ) );
- while( ( TB.p[0] & 1 ) == 0 ) MPI_CHK( mpi_shift_r( &TB, 1 ) );
+ MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) );
+ MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) );
if( mpi_cmp_mpi( &TA, &TB ) >= 0 )
{
}
}
- MPI_CHK( mpi_mul_mpi( G, &TG, &TB ) );
+ MPI_CHK( mpi_shift_l( &TB, lz ) );
+ MPI_CHK( mpi_copy( G, &TB ) );
cleanup:
return( ret );
}
+#if defined(POLARSSL_GENPRIME)
+
/*
* Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
*/
-int mpi_inv_mod( mpi *X, mpi *A, mpi *N )
+int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N )
{
int ret;
mpi G, TA, TU, U1, U2, TB, TV, V1, V2;
mpi W, R, T, A, RR;
unsigned char *p;
- if( mpi_cmp_int( X, 0 ) == 0 )
+ if( mpi_cmp_int( X, 0 ) == 0 ||
+ mpi_cmp_int( X, 1 ) == 0 )
+ return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE );
+
+ if( mpi_cmp_int( X, 2 ) == 0 )
return( 0 );
mpi_init( &W, &R, &T, &A, &RR, NULL );
* W = |X| - 1
* R = W >> lsb( W )
*/
- s = mpi_lsb( &W );
MPI_CHK( mpi_sub_int( &W, X, 1 ) );
+ s = mpi_lsb( &W );
MPI_CHK( mpi_copy( &R, &W ) );
MPI_CHK( mpi_shift_r( &R, s ) );
return( ret );
}
+
+#endif