forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2560 lines
55 KiB
2560 lines
55 KiB
/* |
|
* Multi-precision integer library |
|
* |
|
* Copyright (C) 2006-2010, Brainspark B.V. |
|
* |
|
* 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 |
|
* the Free Software Foundation; either version 2 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License along |
|
* with this program; if not, write to the Free Software Foundation, Inc., |
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|
*/ |
|
/* |
|
* This MPI implementation is based on: |
|
* |
|
* http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf |
|
* http://www.stillhq.com/extracted/gnupg-api/mpi/ |
|
* http://math.libtomcrypt.com/files/tommath.pdf |
|
*/ |
|
|
|
#include "polarssl/config.h" |
|
|
|
#if defined(POLARSSL_BIGNUM_C) |
|
|
|
#include "polarssl/bignum.h" |
|
#include "polarssl/bn_mul.h" |
|
|
|
#include <gnuk-malloc.h> |
|
|
|
#define ciL (sizeof(t_uint)) /* chars in limb */ |
|
#define biL (ciL << 3) /* bits in limb */ |
|
#define biH (ciL << 2) /* half limb size */ |
|
|
|
/* |
|
* Convert between bits/chars and number of limbs |
|
*/ |
|
#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) |
|
#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) |
|
|
|
/* |
|
* Initialize one MPI |
|
*/ |
|
void mpi_init( mpi *X ) |
|
{ |
|
if( X == NULL ) |
|
return; |
|
|
|
X->s = 1; |
|
X->n = 0; |
|
X->p = NULL; |
|
} |
|
|
|
/* |
|
* Unallocate one MPI |
|
*/ |
|
void mpi_free( mpi *X ) |
|
{ |
|
if( X == NULL ) |
|
return; |
|
|
|
if( X->p != NULL ) |
|
{ |
|
memset( X->p, 0, X->n * ciL ); |
|
free( X->p ); |
|
} |
|
|
|
X->s = 1; |
|
X->n = 0; |
|
X->p = NULL; |
|
} |
|
|
|
/* |
|
* Enlarge to the specified number of limbs |
|
*/ |
|
int mpi_grow( mpi *X, size_t nblimbs ) |
|
{ |
|
t_uint *p; |
|
|
|
if( nblimbs > POLARSSL_MPI_MAX_LIMBS ) |
|
return( POLARSSL_ERR_MPI_MALLOC_FAILED ); |
|
|
|
if( X->n < nblimbs ) |
|
{ |
|
if( ( p = (t_uint *) malloc( nblimbs * ciL ) ) == NULL ) |
|
return( POLARSSL_ERR_MPI_MALLOC_FAILED ); |
|
|
|
memset( p, 0, nblimbs * ciL ); |
|
|
|
if( X->p != NULL ) |
|
{ |
|
memcpy( p, X->p, X->n * ciL ); |
|
memset( X->p, 0, X->n * ciL ); |
|
free( X->p ); |
|
} |
|
|
|
X->n = nblimbs; |
|
X->p = p; |
|
} |
|
|
|
return( 0 ); |
|
} |
|
|
|
/* |
|
* Copy the contents of Y into X |
|
*/ |
|
int mpi_copy( mpi *X, const mpi *Y ) |
|
{ |
|
int ret; |
|
size_t i; |
|
|
|
if( X == Y ) |
|
return( 0 ); |
|
|
|
for( i = Y->n - 1; i > 0; i-- ) |
|
if( Y->p[i] != 0 ) |
|
break; |
|
i++; |
|
|
|
X->s = Y->s; |
|
|
|
MPI_CHK( mpi_grow( X, i ) ); |
|
|
|
memset( X->p, 0, X->n * ciL ); |
|
memcpy( X->p, Y->p, i * ciL ); |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Swap the contents of X and Y |
|
*/ |
|
void mpi_swap( mpi *X, mpi *Y ) |
|
{ |
|
mpi T; |
|
|
|
memcpy( &T, X, sizeof( mpi ) ); |
|
memcpy( X, Y, sizeof( mpi ) ); |
|
memcpy( Y, &T, sizeof( mpi ) ); |
|
} |
|
|
|
/* |
|
* Set value from integer |
|
*/ |
|
int mpi_lset( mpi *X, t_sint z ) |
|
{ |
|
int ret; |
|
|
|
MPI_CHK( mpi_grow( X, 1 ) ); |
|
memset( X->p, 0, X->n * ciL ); |
|
|
|
X->p[0] = ( z < 0 ) ? -z : z; |
|
X->s = ( z < 0 ) ? -1 : 1; |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Get a specific bit |
|
*/ |
|
int mpi_get_bit( const mpi *X, size_t pos ) |
|
{ |
|
if( X->n * biL <= pos ) |
|
return( 0 ); |
|
|
|
return ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01; |
|
} |
|
|
|
/* |
|
* Set a bit to a specific value of 0 or 1 |
|
*/ |
|
int mpi_set_bit( mpi *X, size_t pos, unsigned char val ) |
|
{ |
|
int ret = 0; |
|
size_t off = pos / biL; |
|
size_t idx = pos % biL; |
|
|
|
if( val != 0 && val != 1 ) |
|
return POLARSSL_ERR_MPI_BAD_INPUT_DATA; |
|
|
|
if( X->n * biL <= pos ) |
|
{ |
|
if( val == 0 ) |
|
return ( 0 ); |
|
|
|
MPI_CHK( mpi_grow( X, off + 1 ) ); |
|
} |
|
|
|
X->p[off] = ( X->p[off] & ~( 0x01 << idx ) ) | ( val << idx ); |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Return the number of least significant bits |
|
*/ |
|
size_t mpi_lsb( const mpi *X ) |
|
{ |
|
size_t i, j, count = 0; |
|
|
|
for( i = 0; i < X->n; i++ ) |
|
for( j = 0; j < biL; j++, count++ ) |
|
if( ( ( X->p[i] >> j ) & 1 ) != 0 ) |
|
return( count ); |
|
|
|
return( 0 ); |
|
} |
|
|
|
#if !defined(POLARSSL_HAVE_UDBL) |
|
/* |
|
* Count leading zero bits in a given integer |
|
*/ |
|
static size_t int_clz( const t_uint x ) |
|
{ |
|
size_t j; |
|
t_uint mask = (t_uint) 1 << (biL - 1); |
|
|
|
for( j = 0; j < biL; j++ ) |
|
{ |
|
if( x & mask ) break; |
|
|
|
mask >>= 1; |
|
} |
|
|
|
return j; |
|
} |
|
#endif |
|
|
|
/* |
|
* Return the number of most significant bits |
|
*/ |
|
size_t mpi_msb( const mpi *X ) |
|
{ |
|
size_t i, j; |
|
|
|
for( i = X->n - 1; i > 0; i-- ) |
|
if( X->p[i] != 0 ) |
|
break; |
|
|
|
for( j = biL; j > 0; j-- ) |
|
if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 ) |
|
break; |
|
|
|
return( ( i * biL ) + j ); |
|
} |
|
|
|
/* |
|
* Return the total size in bytes |
|
*/ |
|
size_t mpi_size( const mpi *X ) |
|
{ |
|
return( ( mpi_msb( X ) + 7 ) >> 3 ); |
|
} |
|
|
|
/* |
|
* Convert an ASCII character to digit value |
|
*/ |
|
static int mpi_get_digit( t_uint *d, int radix, char c ) |
|
{ |
|
*d = 255; |
|
|
|
if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; |
|
if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; |
|
if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; |
|
|
|
if( *d >= (t_uint) radix ) |
|
return( POLARSSL_ERR_MPI_INVALID_CHARACTER ); |
|
|
|
return( 0 ); |
|
} |
|
|
|
/* |
|
* Import from an ASCII string |
|
*/ |
|
int mpi_read_string( mpi *X, int radix, const char *s ) |
|
{ |
|
int ret; |
|
size_t i, j, slen, n; |
|
t_uint d; |
|
mpi T; |
|
|
|
if( radix < 2 || radix > 16 ) |
|
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); |
|
|
|
mpi_init( &T ); |
|
|
|
slen = strlen( s ); |
|
|
|
if( radix == 16 ) |
|
{ |
|
n = BITS_TO_LIMBS( slen << 2 ); |
|
|
|
MPI_CHK( mpi_grow( X, n ) ); |
|
MPI_CHK( mpi_lset( X, 0 ) ); |
|
|
|
for( i = slen, j = 0; i > 0; i--, j++ ) |
|
{ |
|
if( i == 1 && s[i - 1] == '-' ) |
|
{ |
|
X->s = -1; |
|
break; |
|
} |
|
|
|
MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); |
|
X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 ); |
|
} |
|
} |
|
else |
|
{ |
|
MPI_CHK( mpi_lset( X, 0 ) ); |
|
|
|
for( i = 0; i < slen; i++ ) |
|
{ |
|
if( i == 0 && s[i] == '-' ) |
|
{ |
|
X->s = -1; |
|
continue; |
|
} |
|
|
|
MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); |
|
MPI_CHK( mpi_mul_int( &T, X, radix ) ); |
|
|
|
if( X->s == 1 ) |
|
{ |
|
MPI_CHK( mpi_add_int( X, &T, d ) ); |
|
} |
|
else |
|
{ |
|
MPI_CHK( mpi_sub_int( X, &T, d ) ); |
|
} |
|
} |
|
} |
|
|
|
cleanup: |
|
|
|
mpi_free( &T ); |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Helper to write the digits high-order first |
|
*/ |
|
static int mpi_write_hlp( mpi *X, int radix, char **p ) |
|
{ |
|
int ret; |
|
t_uint r; |
|
|
|
if( radix < 2 || radix > 16 ) |
|
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); |
|
|
|
MPI_CHK( mpi_mod_int( &r, X, radix ) ); |
|
MPI_CHK( mpi_div_int( X, NULL, X, radix ) ); |
|
|
|
if( mpi_cmp_int( X, 0 ) != 0 ) |
|
MPI_CHK( mpi_write_hlp( X, radix, p ) ); |
|
|
|
if( r < 10 ) |
|
*(*p)++ = (char)( r + 0x30 ); |
|
else |
|
*(*p)++ = (char)( r + 0x37 ); |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Export into an ASCII string |
|
*/ |
|
int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ) |
|
{ |
|
int ret = 0; |
|
size_t n; |
|
char *p; |
|
mpi T; |
|
|
|
if( radix < 2 || radix > 16 ) |
|
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); |
|
|
|
n = mpi_msb( X ); |
|
if( radix >= 4 ) n >>= 1; |
|
if( radix >= 16 ) n >>= 1; |
|
n += 3; |
|
|
|
if( *slen < n ) |
|
{ |
|
*slen = n; |
|
return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); |
|
} |
|
|
|
p = s; |
|
mpi_init( &T ); |
|
|
|
if( X->s == -1 ) |
|
*p++ = '-'; |
|
|
|
if( radix == 16 ) |
|
{ |
|
int c; |
|
size_t i, j, k; |
|
|
|
for( i = X->n, k = 0; i > 0; i-- ) |
|
{ |
|
for( j = ciL; j > 0; j-- ) |
|
{ |
|
c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; |
|
|
|
if( c == 0 && k == 0 && ( i + j + 3 ) != 0 ) |
|
continue; |
|
|
|
*(p++) = "0123456789ABCDEF" [c / 16]; |
|
*(p++) = "0123456789ABCDEF" [c % 16]; |
|
k = 1; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
MPI_CHK( mpi_copy( &T, X ) ); |
|
|
|
if( T.s == -1 ) |
|
T.s = 1; |
|
|
|
MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); |
|
} |
|
|
|
*p++ = '\0'; |
|
*slen = p - s; |
|
|
|
cleanup: |
|
|
|
mpi_free( &T ); |
|
|
|
return( ret ); |
|
} |
|
|
|
#if defined(POLARSSL_FS_IO) |
|
/* |
|
* Read X from an opened file |
|
*/ |
|
int mpi_read_file( mpi *X, int radix, FILE *fin ) |
|
{ |
|
t_uint d; |
|
size_t slen; |
|
char *p; |
|
/* |
|
* Buffer should have space for (short) label and decimal formatted MPI, |
|
* newline characters and '\0' |
|
*/ |
|
char s[ POLARSSL_MPI_RW_BUFFER_SIZE ]; |
|
|
|
memset( s, 0, sizeof( s ) ); |
|
if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) |
|
return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); |
|
|
|
slen = strlen( s ); |
|
if( slen == sizeof( s ) - 2 ) |
|
return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); |
|
|
|
if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } |
|
if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } |
|
|
|
p = s + slen; |
|
while( --p >= s ) |
|
if( mpi_get_digit( &d, radix, *p ) != 0 ) |
|
break; |
|
|
|
return( mpi_read_string( X, radix, p + 1 ) ); |
|
} |
|
|
|
/* |
|
* Write X into an opened file (or stdout if fout == NULL) |
|
*/ |
|
int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ) |
|
{ |
|
int ret; |
|
size_t n, slen, plen; |
|
/* |
|
* Buffer should have space for (short) label and decimal formatted MPI, |
|
* newline characters and '\0' |
|
*/ |
|
char s[ POLARSSL_MPI_RW_BUFFER_SIZE ]; |
|
|
|
n = sizeof( s ); |
|
memset( s, 0, n ); |
|
n -= 2; |
|
|
|
MPI_CHK( mpi_write_string( X, radix, s, (size_t *) &n ) ); |
|
|
|
if( p == NULL ) p = ""; |
|
|
|
plen = strlen( p ); |
|
slen = strlen( s ); |
|
s[slen++] = '\r'; |
|
s[slen++] = '\n'; |
|
|
|
if( fout != NULL ) |
|
{ |
|
if( fwrite( p, 1, plen, fout ) != plen || |
|
fwrite( s, 1, slen, fout ) != slen ) |
|
return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); |
|
} |
|
else |
|
printf( "%s%s", p, s ); |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
#endif /* POLARSSL_FS_IO */ |
|
|
|
/* |
|
* Import X from unsigned binary data, big endian |
|
*/ |
|
int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ) |
|
{ |
|
int ret; |
|
size_t i, j, n; |
|
|
|
for( n = 0; n < buflen; n++ ) |
|
if( buf[n] != 0 ) |
|
break; |
|
|
|
MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); |
|
MPI_CHK( mpi_lset( X, 0 ) ); |
|
|
|
for( i = buflen, j = 0; i > n; i--, j++ ) |
|
X->p[j / ciL] |= ((t_uint) buf[i - 1]) << ((j % ciL) << 3); |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Export X into unsigned binary data, big endian |
|
*/ |
|
int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ) |
|
{ |
|
size_t i, j, n; |
|
|
|
n = mpi_size( X ); |
|
|
|
if( buflen < n ) |
|
return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); |
|
|
|
memset( buf, 0, buflen ); |
|
|
|
for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) |
|
buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); |
|
|
|
return( 0 ); |
|
} |
|
|
|
/* |
|
* Left-shift: X <<= count |
|
*/ |
|
int mpi_shift_l( mpi *X, size_t count ) |
|
{ |
|
int ret; |
|
size_t i, v0, t1; |
|
t_uint r0 = 0, r1; |
|
|
|
v0 = count / (biL ); |
|
t1 = count & (biL - 1); |
|
|
|
i = mpi_msb( X ) + count; |
|
|
|
if( X->n * biL < i ) |
|
MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); |
|
|
|
ret = 0; |
|
|
|
/* |
|
* shift by count / limb_size |
|
*/ |
|
if( v0 > 0 ) |
|
{ |
|
for( i = X->n; i > v0; i-- ) |
|
X->p[i - 1] = X->p[i - v0 - 1]; |
|
|
|
for( ; i > 0; i-- ) |
|
X->p[i - 1] = 0; |
|
} |
|
|
|
/* |
|
* shift by count % limb_size |
|
*/ |
|
if( t1 > 0 ) |
|
{ |
|
for( i = v0; i < X->n; i++ ) |
|
{ |
|
r1 = X->p[i] >> (biL - t1); |
|
X->p[i] <<= t1; |
|
X->p[i] |= r0; |
|
r0 = r1; |
|
} |
|
} |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Right-shift: X >>= count |
|
*/ |
|
int mpi_shift_r( mpi *X, size_t count ) |
|
{ |
|
size_t i, v0, v1; |
|
t_uint r0 = 0, r1; |
|
|
|
v0 = count / biL; |
|
v1 = count & (biL - 1); |
|
|
|
if( v0 > X->n || ( v0 == X->n && v1 > 0 ) ) |
|
return mpi_lset( X, 0 ); |
|
|
|
/* |
|
* shift by count / limb_size |
|
*/ |
|
if( v0 > 0 ) |
|
{ |
|
for( i = 0; i < X->n - v0; i++ ) |
|
X->p[i] = X->p[i + v0]; |
|
|
|
for( ; i < X->n; i++ ) |
|
X->p[i] = 0; |
|
} |
|
|
|
/* |
|
* shift by count % limb_size |
|
*/ |
|
if( v1 > 0 ) |
|
{ |
|
for( i = X->n; i > 0; i-- ) |
|
{ |
|
r1 = X->p[i - 1] << (biL - v1); |
|
X->p[i - 1] >>= v1; |
|
X->p[i - 1] |= r0; |
|
r0 = r1; |
|
} |
|
} |
|
|
|
return( 0 ); |
|
} |
|
|
|
/* |
|
* Compare unsigned values |
|
*/ |
|
static int mpi_cmp_abs_limbs (size_t n, const t_uint *p0, const t_uint *p1) |
|
{ |
|
size_t i, j; |
|
|
|
p0 += n; |
|
for( i = n; i > 0; i-- ) |
|
if( *--p0 != 0 ) |
|
break; |
|
|
|
p1 += n; |
|
for( j = n; j > 0; j-- ) |
|
if( *--p1 != 0 ) |
|
break; |
|
|
|
if( i == 0 && j == 0 ) |
|
return( 0 ); |
|
|
|
if( i > j ) return( 1 ); |
|
if( j > i ) return( -1 ); |
|
|
|
for( ; i > 0; i-- ) |
|
{ |
|
if( *p0 > *p1 ) return( 1 ); |
|
if( *p0 < *p1 ) return( -1 ); |
|
p0--; p1--; |
|
} |
|
|
|
return( 0 ); |
|
} |
|
|
|
/* |
|
* Compare unsigned values |
|
*/ |
|
int mpi_cmp_abs( const mpi *X, const mpi *Y ) |
|
{ |
|
size_t i, j; |
|
|
|
for( i = X->n; i > 0; i-- ) |
|
if( X->p[i - 1] != 0 ) |
|
break; |
|
|
|
for( j = Y->n; j > 0; j-- ) |
|
if( Y->p[j - 1] != 0 ) |
|
break; |
|
|
|
if( i == 0 && j == 0 ) |
|
return( 0 ); |
|
|
|
if( i > j ) return( 1 ); |
|
if( j > i ) return( -1 ); |
|
|
|
for( ; i > 0; i-- ) |
|
{ |
|
if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); |
|
if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); |
|
} |
|
|
|
return( 0 ); |
|
} |
|
|
|
/* |
|
* Compare signed values |
|
*/ |
|
int mpi_cmp_mpi( const mpi *X, const mpi *Y ) |
|
{ |
|
size_t i, j; |
|
|
|
for( i = X->n; i > 0; i-- ) |
|
if( X->p[i - 1] != 0 ) |
|
break; |
|
|
|
for( j = Y->n; j > 0; j-- ) |
|
if( Y->p[j - 1] != 0 ) |
|
break; |
|
|
|
if( i == 0 && j == 0 ) |
|
return( 0 ); |
|
|
|
if( i > j ) return( X->s ); |
|
if( j > i ) return( -Y->s ); |
|
|
|
if( X->s > 0 && Y->s < 0 ) return( 1 ); |
|
if( Y->s > 0 && X->s < 0 ) return( -1 ); |
|
|
|
for( ; i > 0; i-- ) |
|
{ |
|
if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); |
|
if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); |
|
} |
|
|
|
return( 0 ); |
|
} |
|
|
|
/* |
|
* Compare signed values |
|
*/ |
|
int mpi_cmp_int( const mpi *X, t_sint z ) |
|
{ |
|
mpi Y; |
|
t_uint p[1]; |
|
|
|
*p = ( z < 0 ) ? -z : z; |
|
Y.s = ( z < 0 ) ? -1 : 1; |
|
Y.n = 1; |
|
Y.p = p; |
|
|
|
return( mpi_cmp_mpi( X, &Y ) ); |
|
} |
|
|
|
/* |
|
* Unsigned addition: X = |A| + |B| (HAC 14.7) |
|
*/ |
|
int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ) |
|
{ |
|
int ret; |
|
size_t i, j; |
|
t_uint *o, *p, c; |
|
|
|
if( X == B ) |
|
{ |
|
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; j > 0; j-- ) |
|
if( B->p[j - 1] != 0 ) |
|
break; |
|
|
|
MPI_CHK( mpi_grow( X, j ) ); |
|
|
|
o = B->p; p = X->p; c = 0; |
|
|
|
for( i = 0; i < j; i++, o++, p++ ) |
|
{ |
|
*p += c; c = ( *p < c ); |
|
*p += *o; c += ( *p < *o ); |
|
} |
|
|
|
while( c != 0 ) |
|
{ |
|
if( i >= X->n ) |
|
{ |
|
MPI_CHK( mpi_grow( X, i + 1 ) ); |
|
p = X->p + i; |
|
} |
|
|
|
*p += c; c = ( *p < c ); i++; p++; |
|
} |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Helper for mpi substraction |
|
*/ |
|
static t_uint mpi_sub_hlp( size_t n, const t_uint *s, t_uint *d ) |
|
{ |
|
size_t i; |
|
t_uint c, z; |
|
|
|
for( i = c = 0; i < n; i++, s++, d++ ) |
|
{ |
|
z = ( *d < c ); *d -= c; |
|
c = ( *d < *s ) + z; *d -= *s; |
|
} |
|
|
|
return c; |
|
} |
|
|
|
/* |
|
* Unsigned substraction: X = |A| - |B| (HAC 14.9) |
|
*/ |
|
int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ) |
|
{ |
|
mpi TB; |
|
int ret; |
|
size_t n; |
|
t_uint *d; |
|
t_uint c, z; |
|
|
|
if( mpi_cmp_abs( A, B ) < 0 ) |
|
return( POLARSSL_ERR_MPI_NEGATIVE_VALUE ); |
|
|
|
mpi_init( &TB ); |
|
|
|
if( X == B ) |
|
{ |
|
MPI_CHK( mpi_copy( &TB, B ) ); |
|
B = &TB; |
|
} |
|
|
|
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; n > 0; n-- ) |
|
if( B->p[n - 1] != 0 ) |
|
break; |
|
|
|
c = mpi_sub_hlp( n, B->p, X->p ); |
|
d = X->p + n; |
|
|
|
while( c != 0 ) |
|
{ |
|
z = ( *d < c ); *d -= c; |
|
c = z; d++; |
|
} |
|
|
|
cleanup: |
|
|
|
mpi_free( &TB ); |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Signed addition: X = A + B |
|
*/ |
|
int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ) |
|
{ |
|
int ret, s = A->s; |
|
|
|
if( A->s * B->s < 0 ) |
|
{ |
|
if( mpi_cmp_abs( A, B ) >= 0 ) |
|
{ |
|
MPI_CHK( mpi_sub_abs( X, A, B ) ); |
|
X->s = s; |
|
} |
|
else |
|
{ |
|
MPI_CHK( mpi_sub_abs( X, B, A ) ); |
|
X->s = -s; |
|
} |
|
} |
|
else |
|
{ |
|
MPI_CHK( mpi_add_abs( X, A, B ) ); |
|
X->s = s; |
|
} |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Signed substraction: X = A - B |
|
*/ |
|
int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ) |
|
{ |
|
int ret, s = A->s; |
|
|
|
if( A->s * B->s > 0 ) |
|
{ |
|
if( mpi_cmp_abs( A, B ) >= 0 ) |
|
{ |
|
MPI_CHK( mpi_sub_abs( X, A, B ) ); |
|
X->s = s; |
|
} |
|
else |
|
{ |
|
MPI_CHK( mpi_sub_abs( X, B, A ) ); |
|
X->s = -s; |
|
} |
|
} |
|
else |
|
{ |
|
MPI_CHK( mpi_add_abs( X, A, B ) ); |
|
X->s = s; |
|
} |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Signed addition: X = A + b |
|
*/ |
|
int mpi_add_int( mpi *X, const mpi *A, t_sint b ) |
|
{ |
|
mpi _B; |
|
t_uint p[1]; |
|
|
|
p[0] = ( b < 0 ) ? -b : b; |
|
_B.s = ( b < 0 ) ? -1 : 1; |
|
_B.n = 1; |
|
_B.p = p; |
|
|
|
return( mpi_add_mpi( X, A, &_B ) ); |
|
} |
|
|
|
/* |
|
* Signed substraction: X = A - b |
|
*/ |
|
int mpi_sub_int( mpi *X, const mpi *A, t_sint b ) |
|
{ |
|
mpi _B; |
|
t_uint p[1]; |
|
|
|
p[0] = ( b < 0 ) ? -b : b; |
|
_B.s = ( b < 0 ) ? -1 : 1; |
|
_B.n = 1; |
|
_B.p = p; |
|
|
|
return( mpi_sub_mpi( X, A, &_B ) ); |
|
} |
|
|
|
/* |
|
* Helper for mpi multiplication |
|
*/ |
|
static |
|
#if defined(__APPLE__) && defined(__arm__) |
|
/* |
|
* Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) |
|
* appears to need this to prevent bad ARM code generation at -O3. |
|
*/ |
|
__attribute__ ((noinline)) |
|
#endif |
|
t_uint mpi_mul_hlp( size_t i, const t_uint *s, t_uint *d, t_uint b ) |
|
{ |
|
t_uint c = 0, t = 0; |
|
|
|
#if defined(MULADDC_1024_LOOP) |
|
MULADDC_1024_LOOP |
|
|
|
for( ; i > 0; i-- ) |
|
{ |
|
MULADDC_INIT |
|
MULADDC_CORE |
|
MULADDC_STOP |
|
} |
|
#elif defined(MULADDC_HUIT) |
|
for( ; i >= 8; i -= 8 ) |
|
{ |
|
MULADDC_INIT |
|
MULADDC_HUIT |
|
MULADDC_STOP |
|
} |
|
|
|
for( ; i > 0; i-- ) |
|
{ |
|
MULADDC_INIT |
|
MULADDC_CORE |
|
MULADDC_STOP |
|
} |
|
#else |
|
for( ; i >= 16; i -= 16 ) |
|
{ |
|
MULADDC_INIT |
|
MULADDC_CORE MULADDC_CORE |
|
MULADDC_CORE MULADDC_CORE |
|
MULADDC_CORE MULADDC_CORE |
|
MULADDC_CORE MULADDC_CORE |
|
|
|
MULADDC_CORE MULADDC_CORE |
|
MULADDC_CORE MULADDC_CORE |
|
MULADDC_CORE MULADDC_CORE |
|
MULADDC_CORE MULADDC_CORE |
|
MULADDC_STOP |
|
} |
|
|
|
for( ; i >= 8; i -= 8 ) |
|
{ |
|
MULADDC_INIT |
|
MULADDC_CORE MULADDC_CORE |
|
MULADDC_CORE MULADDC_CORE |
|
|
|
MULADDC_CORE MULADDC_CORE |
|
MULADDC_CORE MULADDC_CORE |
|
MULADDC_STOP |
|
} |
|
|
|
for( ; i > 0; i-- ) |
|
{ |
|
MULADDC_INIT |
|
MULADDC_CORE |
|
MULADDC_STOP |
|
} |
|
#endif |
|
|
|
t++; |
|
|
|
*d += c; c = ( *d < c ); |
|
return c; |
|
} |
|
|
|
/* |
|
* Baseline multiplication: X = A * B (HAC 14.12) |
|
*/ |
|
int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ) |
|
{ |
|
int ret; |
|
size_t i, j, k; |
|
mpi TA, TB; |
|
|
|
mpi_init( &TA ); mpi_init( &TB ); |
|
|
|
if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; } |
|
if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; } |
|
|
|
for( i = A->n; i > 0; i-- ) |
|
if( A->p[i - 1] != 0 ) |
|
break; |
|
|
|
for( j = B->n; j > 0; j-- ) |
|
if( B->p[j - 1] != 0 ) |
|
break; |
|
|
|
MPI_CHK( mpi_grow( X, i + j ) ); |
|
MPI_CHK( mpi_lset( X, 0 ) ); |
|
|
|
for(k = 0; k < j; k++ ) |
|
mpi_mul_hlp( i, A->p, X->p + k, B->p[k]); |
|
|
|
X->s = A->s * B->s; |
|
|
|
cleanup: |
|
|
|
mpi_free( &TB ); mpi_free( &TA ); |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Baseline multiplication: X = A * b |
|
*/ |
|
int mpi_mul_int( mpi *X, const mpi *A, t_sint b ) |
|
{ |
|
mpi _B; |
|
t_uint p[1]; |
|
|
|
_B.s = 1; |
|
_B.n = 1; |
|
_B.p = p; |
|
p[0] = b; |
|
|
|
return( mpi_mul_mpi( X, A, &_B ) ); |
|
} |
|
|
|
/* |
|
* Unsigned integer divide - 64bit dividend and 32bit divisor |
|
*/ |
|
static t_uint int_div_int(t_uint u1, t_uint u0, t_uint d, t_uint *r) |
|
{ |
|
#if defined(POLARSSL_HAVE_UDBL) |
|
t_udbl dividend, quotient; |
|
#else |
|
const t_uint radix = (t_uint) 1 << biH; |
|
const t_uint uint_halfword_mask = ( (t_uint) 1 << biH ) - 1; |
|
t_uint d0, d1, q0, q1, rAX, r0, quotient; |
|
t_uint u0_msw, u0_lsw; |
|
size_t s; |
|
#endif |
|
|
|
/* |
|
* Check for overflow |
|
*/ |
|
if(( 0 == d ) || ( u1 >= d )) |
|
{ |
|
if (r != NULL) *r = (~0UL); |
|
|
|
return (~0UL); |
|
} |
|
|
|
#if defined(POLARSSL_HAVE_UDBL) |
|
dividend = (t_udbl) u1 << biL; |
|
dividend |= (t_udbl) u0; |
|
quotient = dividend / d; |
|
if( quotient > ( (t_udbl) 1 << biL ) - 1 ) |
|
quotient = ( (t_udbl) 1 << biL ) - 1; |
|
|
|
if( r != NULL ) |
|
*r = (t_uint)( dividend - (quotient * d ) ); |
|
|
|
return (t_uint) quotient; |
|
#else |
|
|
|
/* |
|
* Algorithm D, Section 4.3.1 - The Art of Computer Programming |
|
* Vol. 2 - Seminumerical Algorithms, Knuth |
|
*/ |
|
|
|
/* |
|
* Normalize the divisor, d, and dividend, u0, u1 |
|
*/ |
|
s = int_clz( d ); |
|
d = d << s; |
|
|
|
u1 = u1 << s; |
|
u1 |= ( u0 >> ( biL - s ) ) & ( -(t_sint)s >> ( biL - 1 ) ); |
|
u0 = u0 << s; |
|
|
|
d1 = d >> biH; |
|
d0 = d & uint_halfword_mask; |
|
|
|
u0_msw = u0 >> biH; |
|
u0_lsw = u0 & uint_halfword_mask; |
|
|
|
/* |
|
* Find the first quotient and remainder |
|
*/ |
|
q1 = u1 / d1; |
|
r0 = u1 - d1 * q1; |
|
|
|
while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) ) |
|
{ |
|
q1 -= 1; |
|
r0 += d1; |
|
|
|
if ( r0 >= radix ) break; |
|
} |
|
|
|
rAX = (u1 * radix) + (u0_msw - q1 * d); |
|
q0 = rAX / d1; |
|
r0 = rAX - q0 * d1; |
|
|
|
while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) ) |
|
{ |
|
q0 -= 1; |
|
r0 += d1; |
|
|
|
if ( r0 >= radix ) break; |
|
} |
|
|
|
if (r != NULL) |
|
*r = (rAX * radix + u0_lsw - q0 * d) >> s; |
|
|
|
quotient = q1 * radix + q0; |
|
|
|
return quotient; |
|
#endif |
|
} |
|
|
|
/* |
|
* Division by mpi: A = Q * B + R (HAC 14.20) |
|
*/ |
|
int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ) |
|
{ |
|
int ret; |
|
size_t i, n, t, k; |
|
mpi X, Y, Z, T1, T2; |
|
|
|
if( mpi_cmp_int( B, 0 ) == 0 ) |
|
return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); |
|
|
|
mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z ); |
|
mpi_init( &T1 ); mpi_init( &T2 ); |
|
|
|
if( mpi_cmp_abs( A, B ) < 0 ) |
|
{ |
|
if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) ); |
|
if( R != NULL ) MPI_CHK( mpi_copy( R, A ) ); |
|
return( 0 ); |
|
} |
|
|
|
MPI_CHK( mpi_copy( &X, A ) ); |
|
MPI_CHK( mpi_copy( &Y, B ) ); |
|
X.s = Y.s = 1; |
|
|
|
MPI_CHK( mpi_grow( &Z, A->n + 2 ) ); |
|
MPI_CHK( mpi_lset( &Z, 0 ) ); |
|
MPI_CHK( mpi_grow( &T1, 2 ) ); |
|
MPI_CHK( mpi_grow( &T2, 3 ) ); |
|
|
|
k = mpi_msb( &Y ) % biL; |
|
if( k < biL - 1 ) |
|
{ |
|
k = biL - 1 - k; |
|
MPI_CHK( mpi_shift_l( &X, k ) ); |
|
MPI_CHK( mpi_shift_l( &Y, k ) ); |
|
} |
|
else k = 0; |
|
|
|
n = X.n - 1; |
|
t = Y.n - 1; |
|
MPI_CHK( mpi_shift_l( &Y, biL * (n - t) ) ); |
|
|
|
while( mpi_cmp_mpi( &X, &Y ) >= 0 ) |
|
{ |
|
Z.p[n - t]++; |
|
mpi_sub_mpi( &X, &X, &Y ); |
|
} |
|
mpi_shift_r( &Y, biL * (n - t) ); |
|
|
|
for( i = n; i > t ; i-- ) |
|
{ |
|
if( X.p[i] >= Y.p[t] ) |
|
Z.p[i - t - 1] = ~0UL; |
|
else |
|
{ |
|
Z.p[i - t - 1] = int_div_int( X.p[i], X.p[i-1], Y.p[t], NULL); |
|
} |
|
|
|
Z.p[i - t - 1]++; |
|
do |
|
{ |
|
Z.p[i - t - 1]--; |
|
|
|
MPI_CHK( mpi_lset( &T1, 0 ) ); |
|
T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; |
|
T1.p[1] = Y.p[t]; |
|
MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); |
|
|
|
MPI_CHK( mpi_lset( &T2, 0 ) ); |
|
T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; |
|
T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; |
|
T2.p[2] = X.p[i]; |
|
} |
|
while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); |
|
|
|
MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); |
|
MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); |
|
MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); |
|
|
|
while( mpi_cmp_int( &X, 0 ) < 0 ) |
|
{ |
|
MPI_CHK( mpi_copy( &T1, &Y ) ); |
|
MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); |
|
MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) ); |
|
Z.p[i - t - 1]--; |
|
} |
|
} |
|
|
|
if( Q != NULL ) |
|
{ |
|
mpi_copy( Q, &Z ); |
|
Q->s = A->s * B->s; |
|
} |
|
|
|
if( R != NULL ) |
|
{ |
|
mpi_shift_r( &X, k ); |
|
X.s = A->s; |
|
mpi_copy( R, &X ); |
|
|
|
if( mpi_cmp_int( R, 0 ) == 0 ) |
|
R->s = 1; |
|
} |
|
|
|
cleanup: |
|
|
|
mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z ); |
|
mpi_free( &T1 ); mpi_free( &T2 ); |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Division by int: A = Q * b + R |
|
*/ |
|
int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ) |
|
{ |
|
mpi _B; |
|
t_uint p[1]; |
|
|
|
p[0] = ( b < 0 ) ? -b : b; |
|
_B.s = ( b < 0 ) ? -1 : 1; |
|
_B.n = 1; |
|
_B.p = p; |
|
|
|
return( mpi_div_mpi( Q, R, A, &_B ) ); |
|
} |
|
|
|
/* |
|
* Modulo: R = A mod 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 ) |
|
MPI_CHK( mpi_add_mpi( R, R, B ) ); |
|
|
|
while( mpi_cmp_mpi( R, B ) >= 0 ) |
|
MPI_CHK( mpi_sub_mpi( R, R, B ) ); |
|
|
|
cleanup: |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Modulo: r = A mod b |
|
*/ |
|
int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ) |
|
{ |
|
size_t i; |
|
t_uint x, y, z; |
|
|
|
if( b == 0 ) |
|
return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); |
|
|
|
if( b < 0 ) |
|
return POLARSSL_ERR_MPI_NEGATIVE_VALUE; |
|
|
|
/* |
|
* handle trivial cases |
|
*/ |
|
if( b == 1 ) |
|
{ |
|
*r = 0; |
|
return( 0 ); |
|
} |
|
|
|
if( b == 2 ) |
|
{ |
|
*r = A->p[0] & 1; |
|
return( 0 ); |
|
} |
|
|
|
/* |
|
* general case |
|
*/ |
|
for( i = A->n, y = 0; i > 0; i-- ) |
|
{ |
|
x = A->p[i - 1]; |
|
y = ( y << biH ) | ( x >> biH ); |
|
z = y / b; |
|
y -= z * b; |
|
|
|
x <<= biH; |
|
y = ( y << biH ) | ( x >> biH ); |
|
z = y / b; |
|
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_uint *mm, const mpi *N ) |
|
{ |
|
t_uint x, m0 = N->p[0]; |
|
|
|
x = m0; |
|
x += ( ( m0 + 2 ) & 4 ) << 1; |
|
x *= ( 2 - ( m0 * x ) ); |
|
|
|
if( biL >= 16 ) x *= ( 2 - ( m0 * x ) ); |
|
if( biL >= 32 ) x *= ( 2 - ( m0 * x ) ); |
|
if( biL >= 64 ) x *= ( 2 - ( m0 * x ) ); |
|
|
|
*mm = ~x + 1; |
|
} |
|
|
|
/* |
|
* Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) |
|
* A is placed at the upper half of D. |
|
*/ |
|
static void mpi_montmul( size_t n, const t_uint *np, t_uint mm, t_uint *d, |
|
const t_uint *bp ) |
|
{ |
|
size_t i; |
|
t_uint u0, u1, c = 0; |
|
|
|
for( i = 0; i < n; i++ ) |
|
{ |
|
/* |
|
* T = (T + u0*B + u1*N) / 2^biL |
|
*/ |
|
u0 = d[n]; |
|
d[n] = c; |
|
u1 = ( d[0] + u0 * bp[0] ) * mm; |
|
|
|
mpi_mul_hlp( n, bp, d, u0 ); |
|
c = mpi_mul_hlp( n, np, d, u1 ); |
|
d++; |
|
} |
|
|
|
/* prevent timing attacks */ |
|
if( ((mpi_cmp_abs_limbs ( n, d, np ) >= 0) | c) ) |
|
mpi_sub_hlp( n, np, d ); |
|
else |
|
mpi_sub_hlp( n, d - n, d - n); |
|
} |
|
|
|
/* |
|
* Montgomery reduction: A = A * R^-1 mod N |
|
* A is placed at the upper half of D. |
|
*/ |
|
static void mpi_montred( size_t n, const t_uint *np, t_uint mm, t_uint *d ) |
|
{ |
|
size_t i, j; |
|
t_uint u0, u1, c = 0; |
|
|
|
for( i = 0; i < n; i++ ) |
|
{ |
|
/* |
|
* T = (T + u0 + u1*N) / 2^biL |
|
*/ |
|
u0 = d[n]; |
|
d[n] = c; |
|
u1 = (d[0] + u0) * mm; |
|
|
|
d[0] += u0; |
|
c = (d[0] < u0); |
|
for (j = 1; j < n; j++) |
|
{ |
|
d[j] += c; c = ( d[j] < c ); |
|
} |
|
|
|
c = mpi_mul_hlp( n, np, d, u1 ); |
|
d++; |
|
} |
|
|
|
/* prevent timing attacks */ |
|
if( ((mpi_cmp_abs_limbs ( n, d, np ) >= 0) | c) ) |
|
mpi_sub_hlp( n, np, d ); |
|
else |
|
mpi_sub_hlp( n, d - n, d - n); |
|
} |
|
|
|
/* |
|
* Montgomery square: A = A * A * R^-1 mod N |
|
* A is placed at the upper half of D. |
|
* |
|
* n : number of limbs of N |
|
* np: pointer to limbs of bignum N |
|
* mm: m' = -N^(-1) mod b where b = 2^number-of-bit-in-limb |
|
* d (destination): the result [<-- temp -->][<--- A ---->] |
|
* lower part upper part |
|
* n-limb n-limb |
|
*/ |
|
static void mpi_montsqr( size_t n, const t_uint *np, t_uint mm, t_uint *d ) |
|
{ |
|
#if defined(POLARSSL_HAVE_ASM) && defined(__arm__) |
|
size_t i; |
|
register t_uint c = 0; |
|
|
|
for (i = 0; i < n; i++) |
|
{ |
|
t_uint *wij = &d[i*2]; |
|
t_uint *xj = &d[i+n]; |
|
t_uint x_i; |
|
|
|
x_i = *xj; |
|
*xj++ = c; |
|
|
|
#if defined(__ARM_FEATURE_DSP) |
|
asm (/* (C,R4,R5) := w_i_i + x_i*x_i; w_i_i := R5; */ |
|
"mov %[c], #0\n\t" |
|
"ldr r5, [%[wij]]\n\t" /* R5 := w_i_i; */ |
|
"mov r4, %[c]\n\t" |
|
"umlal r5, r4, %[x_i], %[x_i]\n\t" |
|
"str r5, [%[wij]], #4\n\t" |
|
"cmp %[xj], %[x_max1]\n\t" |
|
"bhi 0f\n\t" |
|
"mov r9, %[c]\n\t" /* R9 := 0, the constant ZERO from here. */ |
|
"beq 1f\n" |
|
"2:\n\t" |
|
"ldmia %[xj]!, { r7, r8 }\n\t" |
|
"ldmia %[wij], { r5, r6 }\n\t" |
|
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */ |
|
"umaal r5, r4, %[x_i], r7\n\t" |
|
"umlal r5, %[c], %[x_i], r7\n\t" |
|
"umaal r4, %[c], r9, r9\n\t" |
|
/* (C,R4,R6) := (C,R4) + w_i_j + 2*x_i*x_j; */ |
|
"umaal r6, r4, %[x_i], r8\n\t" |
|
"umlal r6, %[c], %[x_i], r8\n\t" |
|
"umaal r4, %[c], r9, r9\n\t" |
|
/**/ |
|
"stmia %[wij]!, { r5, r6 }\n\t" |
|
"cmp %[xj], %[x_max1]\n\t" |
|
"bcc 2b\n\t" |
|
"bne 0f\n" |
|
"1:\n\t" |
|
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */ |
|
"ldr r5, [%[wij]]\n\t" |
|
"ldr r6, [%[xj]], #4\n\t" |
|
"umaal r5, r4, %[x_i], r6\n\t" |
|
"umlal r5, %[c], %[x_i], r6\n\t" |
|
"umaal r4, %[c], r9, r9\n\t" |
|
"str r5, [%[wij]], #4\n" |
|
"0:\n\t" |
|
"ldr r5, [%[wij]]\n\t" |
|
"adds r4, r4, r5\n\t" |
|
"adc %[c], %[c], #0\n\t" |
|
"str r4, [%[wij]]" |
|
: [c] "=&r" (c), [wij] "=r" (wij), [xj] "=r" (xj) |
|
: [x_i] "r" (x_i), [x_max1] "r" (&d[n*2-1]), |
|
"[wij]" (wij), "[xj]" (xj) |
|
: "r4", "r5", "r6", "r7", "r8", "r9", "memory", "cc"); |
|
#else |
|
asm (/* (C,R4,R5) := w_i_i + x_i*x_i; w_i_i := R5; */ |
|
"mov %[c], #0\n\t" |
|
"ldr r5, [%[wij]]\n\t" /* R5 := w_i_i; */ |
|
"mov r4, %[c]\n\t" |
|
"umlal r5, r4, %[x_i], %[x_i]\n\t" |
|
"str r5, [%[wij]], #4\n\t" |
|
"cmp %[xj], %[x_max1]\n\t" |
|
"bhi 0f\n\t" |
|
"mov r9, %[c]\n\t" /* R9 := 0, the constant ZERO from here. */ |
|
"beq 1f\n" |
|
"2:\n\t" |
|
"ldmia %[xj]!, { r7, r8 }\n\t" |
|
"ldmia %[wij], { r5, r6 }\n\t" |
|
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */ |
|
"umull r7, r12, %[x_i], r7\n\t" |
|
"adds r5, r5, r4\n\t" |
|
"adc r4, %[c], r9\n\t" |
|
"adds r5, r5, r7\n\t" |
|
"adcs r4, r4, r12\n\t" |
|
"adc %[c], r9, r9\n\t" |
|
"adds r5, r5, r7\n\t" |
|
"adcs r4, r4, r12\n\t" |
|
"adc %[c], %[c], r9\n\t" |
|
/* (C,R4,R6) := (C,R4) + w_i_j + 2*x_i*x_j; */ |
|
"adds r6, r6, r4\n\t" |
|
"adc r4, %[c], r9\n\t" |
|
"umull r7, r12, %[x_i], r8\n\t" |
|
"adds r6, r6, r7\n\t" |
|
"adcs r4, r4, r12\n\t" |
|
"adc %[c], r9, r9\n\t" |
|
"adds r6, r6, r7\n\t" |
|
"adcs r4, r4, r12\n\t" |
|
"adc %[c], %[c], r9\n\t" |
|
/**/ |
|
"stmia %[wij]!, { r5, r6 }\n\t" |
|
"cmp %[xj], %[x_max1]\n\t" |
|
"bcc 2b\n\t" |
|
"bne 0f\n" |
|
"1:\n\t" |
|
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */ |
|
"ldr r5, [%[wij]]\n\t" |
|
"ldr r6, [%[xj]], #4\n\t" |
|
"adds r5, r5, r4\n\t" |
|
"adc r4, %[c], r9\n\t" |
|
"umull r7, r12, %[x_i], r6\n\t" |
|
"adds r5, r5, r7\n\t" |
|
"adcs r4, r4, r12\n\t" |
|
"adc %[c], r9, r9\n\t" |
|
"adds r5, r5, r7\n\t" |
|
"adcs r4, r4, r12\n\t" |
|
"adc %[c], %[c], r9\n\t" |
|
"str r5, [%[wij]], #4\n" |
|
"0:\n\t" |
|
"ldr r5, [%[wij]]\n\t" |
|
"adds r4, r4, r5\n\t" |
|
"adc %[c], %[c], #0\n\t" |
|
"str r4, [%[wij]]" |
|
: [c] "=&r" (c), [wij] "=r" (wij), [xj] "=r" (xj) |
|
: [x_i] "r" (x_i), [x_max1] "r" (&d[n*2-1]), |
|
"[wij]" (wij), "[xj]" (xj) |
|
: "r4", "r5", "r6", "r7", "r8", "r9", "r12", "memory", "cc"); |
|
#endif |
|
|
|
c += mpi_mul_hlp( n, np, &d[i], d[i] * mm ); |
|
} |
|
|
|
d += n; |
|
|
|
/* prevent timing attacks */ |
|
if( ((mpi_cmp_abs_limbs ( n, d, np ) >= 0) | c) ) |
|
mpi_sub_hlp( n, np, d ); |
|
else |
|
mpi_sub_hlp( n, d - n, d - n); |
|
#else |
|
t_uint a_input[n]; |
|
|
|
memcpy (a_input, &d[n], sizeof (a_input)); |
|
mpi_montmul (n, np, mm, d, a_input); |
|
#endif |
|
} |
|
|
|
/* |
|
* Sliding-window exponentiation: X = A^E mod N (HAC 14.85) |
|
*/ |
|
#if MEMORY_SIZE >= 32 |
|
#define MAX_WSIZE 6 |
|
#elif MEMORY_SIZE >= 24 |
|
#define MAX_WSIZE 5 |
|
#else |
|
#define MAX_WSIZE 4 |
|
#endif |
|
int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ) |
|
{ |
|
int ret; |
|
size_t i = mpi_msb( E ); |
|
size_t wsize = ( i > 1024 ) ? MAX_WSIZE : |
|
( i > 671 ) ? 6 : ( i > 239 ) ? 5 : |
|
( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; |
|
size_t wbits, one = 1; |
|
size_t nblimbs; |
|
size_t bufsize, nbits; |
|
t_uint ei, mm, state; |
|
mpi RR; |
|
t_uint d[N->n*2]; |
|
t_uint w1[N->n]; |
|
t_uint wn[(one << (wsize - 1))][N->n]; |
|
|
|
if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) |
|
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); |
|
|
|
if( mpi_cmp_int( E, 0 ) < 0 ) |
|
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); |
|
|
|
if( A->s == -1 ) |
|
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); |
|
|
|
/* |
|
* Init temps and window size |
|
*/ |
|
mpi_montg_init( &mm, N ); |
|
|
|
/* |
|
* If 1st call, pre-compute R^2 mod N |
|
*/ |
|
if( _RR == NULL || _RR->p == NULL ) |
|
{ |
|
mpi T; |
|
|
|
mpi_init( &RR ); |
|
T.s = 1; T.n = N->n * 2; T.p = d; |
|
memset (d, 0, 2 * N->n * ciL); /* Set D zero. */ |
|
mpi_sub_hlp( N->n, N->p, d + N->n); |
|
MPI_CHK( mpi_mod_mpi( &RR, &T, N ) ); |
|
MPI_CHK( mpi_grow( &RR, N->n ) ); |
|
|
|
if( _RR != NULL ) |
|
memcpy( _RR, &RR, sizeof( mpi ) ); |
|
|
|
/* The condition of "the lower half of D is all zero" is kept. */ |
|
} |
|
else { |
|
memcpy( &RR, _RR, sizeof( mpi ) ); |
|
memset (d, 0, N->n * ciL); /* Set lower half of D zero. */ |
|
} |
|
|
|
MPI_CHK( mpi_grow( X, N->n ) ); |
|
|
|
/* |
|
* W[1] = A * R^2 * R^-1 mod N = A * R mod N |
|
*/ |
|
if( mpi_cmp_mpi( A, N ) >= 0 ) { |
|
mpi W1; |
|
W1.s = 1; W1.n = N->n; W1.p = d + N->n; |
|
mpi_mod_mpi( &W1, A, N ); |
|
} else { |
|
memset (d + N->n, 0, N->n * ciL); |
|
memcpy (d + N->n, A->p, A->n * ciL); |
|
} |
|
|
|
mpi_montmul( N->n, N->p, mm, d, RR.p ); |
|
memcpy (w1, d + N->n, N->n * ciL); |
|
|
|
{ |
|
/* |
|
* W[1 << (wsize - 1)] = W[1] ^ ( 2 ^ (wsize - 1) ) |
|
*/ |
|
for( i = 0; i < wsize - 1; i++ ) |
|
mpi_montsqr( N->n, N->p, mm, d ); |
|
memcpy (wn[0], d + N->n, N->n * ciL); |
|
|
|
/* |
|
* W[i] = W[i - 1] * W[1] |
|
*/ |
|
for( i = 1; i < (one << (wsize - 1)); i++ ) |
|
{ |
|
mpi_montmul( N->n, N->p, mm, d, w1 ); |
|
memcpy (wn[i], d + N->n, N->n * ciL); |
|
} |
|
} |
|
|
|
/* |
|
* X = R^2 * R^-1 mod N = R mod N |
|
*/ |
|
memcpy (d + N->n, RR.p, N->n * ciL); |
|
mpi_montred( N->n, N->p, mm, d ); |
|
|
|
nblimbs = E->n; |
|
bufsize = 0; |
|
nbits = 0; |
|
wbits = 0; |
|
state = 0; |
|
|
|
while( 1 ) |
|
{ |
|
if( bufsize == 0 ) |
|
{ |
|
if( nblimbs-- == 0 ) |
|
break; |
|
|
|
bufsize = sizeof( t_uint ) << 3; |
|
} |
|
|
|
bufsize--; |
|
|
|
ei = (E->p[nblimbs] >> bufsize) & 1; |
|
|
|
/* |
|
* skip leading 0s |
|
*/ |
|
if( ei == 0 && state == 0 ) |
|
continue; |
|
|
|
if( ei == 0 && state == 1 ) |
|
{ |
|
/* |
|
* out of window, square X |
|
*/ |
|
mpi_montsqr( N->n, N->p, mm, d ); |
|
continue; |
|
} |
|
|
|
/* |
|
* add ei to current window |
|
*/ |
|
state = 2; |
|
|
|
nbits++; |
|
wbits |= (ei << (wsize - nbits)); |
|
|
|
if( nbits == wsize ) |
|
{ |
|
/* |
|
* X = X^wsize R^-1 mod N |
|
*/ |
|
for( i = 0; i < wsize; i++ ) |
|
mpi_montsqr( N->n, N->p, mm, d ); |
|
|
|
/* |
|
* X = X * W[wbits] R^-1 mod N |
|
*/ |
|
mpi_montmul( N->n, N->p, mm, d, wn[wbits - (one << (wsize - 1))]); |
|
|
|
state--; |
|
nbits = 0; |
|
wbits = 0; |
|
} |
|
} |
|
|
|
/* |
|
* process the remaining bits |
|
*/ |
|
for( i = 0; i < nbits; i++ ) |
|
{ |
|
mpi_montsqr( N->n, N->p, mm, d ); |
|
|
|
wbits <<= 1; |
|
|
|
if( (wbits & (one << wsize)) != 0 ) |
|
mpi_montmul( N->n, N->p, mm, d, w1); |
|
} |
|
|
|
/* |
|
* X = A^E * R * R^-1 mod N = A^E mod N |
|
*/ |
|
mpi_montred( N->n, N->p, mm, d ); |
|
memcpy (X->p, d + N->n, N->n * ciL); |
|
|
|
cleanup: |
|
|
|
if( _RR == NULL ) |
|
mpi_free( &RR ); |
|
|
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Greatest common divisor: G = gcd(A, B) (HAC 14.54) |
|
*/ |
|
int mpi_gcd( mpi *G, const mpi *A, const mpi *B ) |
|
{ |
|
int ret; |
|
size_t lz, lzt; |
|
mpi TG, TA, TB; |
|
|
|
mpi_init( &TG ); mpi_init( &TA ); mpi_init( &TB ); |
|
|
|
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 ) |
|
{ |
|
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_sub_abs( &TA, &TA, &TB ) ); |
|
MPI_CHK( mpi_shift_r( &TA, 1 ) ); |
|
} |
|
else |
|
{ |
|
MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) ); |
|
MPI_CHK( mpi_shift_r( &TB, 1 ) ); |
|
} |
|
} |
|
|
|
MPI_CHK( mpi_shift_l( &TB, lz ) ); |
|
MPI_CHK( mpi_copy( G, &TB ) ); |
|
|
|
cleanup: |
|
|
|
mpi_free( &TG ); mpi_free( &TA ); mpi_free( &TB ); |
|
|
|
return( ret ); |
|
} |
|
|
|
int mpi_fill_random( mpi *X, size_t size, |
|
int (*f_rng)(void *, unsigned char *, size_t), |
|
void *p_rng ) |
|
{ |
|
int ret; |
|
|
|
MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) ); |
|
MPI_CHK( mpi_lset( X, 0 ) ); |
|
|
|
MPI_CHK( f_rng( p_rng, (unsigned char *) X->p, size ) ); |
|
|
|
cleanup: |
|
return( ret ); |
|
} |
|
|
|
/* |
|
* Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) |
|
*/ |
|
int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ) |
|
{ |
|
int ret; |
|
mpi G, TA, TU, U1, U2, TB, TV, V1, V2; |
|
|
|
if( mpi_cmp_int( N, 0 ) <= 0 ) |
|
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); |
|
|
|
mpi_init( &TA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 ); |
|
mpi_init( &G ); mpi_init( &TB ); mpi_init( &TV ); |
|
mpi_init( &V1 ); mpi_init( &V2 ); |
|
|
|
MPI_CHK( mpi_gcd( &G, A, N ) ); |
|
|
|
if( mpi_cmp_int( &G, 1 ) != 0 ) |
|
{ |
|
ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; |
|
goto cleanup; |
|
} |
|
|
|
MPI_CHK( mpi_mod_mpi( &TA, A, N ) ); |
|
MPI_CHK( mpi_copy( &TU, &TA ) ); |
|
MPI_CHK( mpi_copy( &TB, N ) ); |
|
MPI_CHK( mpi_copy( &TV, N ) ); |
|
|
|
MPI_CHK( mpi_lset( &U1, 1 ) ); |
|
MPI_CHK( mpi_lset( &U2, 0 ) ); |
|
MPI_CHK( mpi_lset( &V1, 0 ) ); |
|
MPI_CHK( mpi_lset( &V2, 1 ) ); |
|
|
|
do |
|
{ |
|
while( ( TU.p[0] & 1 ) == 0 ) |
|
{ |
|
MPI_CHK( mpi_shift_r( &TU, 1 ) ); |
|
|
|
if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) |
|
{ |
|
MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) ); |
|
MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) ); |
|
} |
|
|
|
MPI_CHK( mpi_shift_r( &U1, 1 ) ); |
|
MPI_CHK( mpi_shift_r( &U2, 1 ) ); |
|
} |
|
|
|
while( ( TV.p[0] & 1 ) == 0 ) |
|
{ |
|
MPI_CHK( mpi_shift_r( &TV, 1 ) ); |
|
|
|
if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) |
|
{ |
|
MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) ); |
|
MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) ); |
|
} |
|
|
|
MPI_CHK( mpi_shift_r( &V1, 1 ) ); |
|
MPI_CHK( mpi_shift_r( &V2, 1 ) ); |
|
} |
|
|
|
if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) |
|
{ |
|
MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); |
|
MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); |
|
MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); |
|
} |
|
else |
|
{ |
|
MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); |
|
MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); |
|
MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); |
|
} |
|
} |
|
while( mpi_cmp_int( &TU, 0 ) != 0 ); |
|
|
|
while( mpi_cmp_int( &V1, 0 ) < 0 ) |
|
MPI_CHK( mpi_add_mpi( &V1, &V1, N ) ); |
|
|
|
while( mpi_cmp_mpi( &V1, N ) >= 0 ) |
|
MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) ); |
|
|
|
MPI_CHK( mpi_copy( X, &V1 ) ); |
|
|
|
cleanup: |
|
|
|
mpi_free( &TA ); mpi_free( &TU ); mpi_free( &U1 ); mpi_free( &U2 ); |
|
mpi_free( &G ); mpi_free( &TB ); mpi_free( &TV ); |
|
mpi_free( &V1 ); mpi_free( &V2 ); |
|
|
|
return( ret ); |
|
} |
|
|
|
#if defined(POLARSSL_GENPRIME) |
|
|
|
static const int small_prime[] = |
|
{ |
|
#if 0 |
|
3, 5, 7, 11, 13, 17, 19, 23, |
|
29, 31, 37, 41, 43, 47, 53, 59, |
|
61, 67, 71, 73, 79, 83, 89, 97, |
|
101, 103, 107, 109, 113, 127, 131, 137, |
|
139, 149, 151, 157, 163, 167, 173, 179, |
|
181, 191, 193, 197, 199, 211, 223, 227, |
|
229, 233, 239, 241, 251, 257, 263, 269, |
|
271, 277, 281, 283, 293, 307, 311, 313, |
|
317, 331, 337, 347, 349, 353, 359, 367, |
|
373, 379, 383, 389, 397, 401, 409, 419, |
|
421, 431, 433, 439, 443, 449, 457, 461, |
|
463, 467, 479, 487, 491, 499, 503, 509, |
|
521, 523, 541, 547, 557, 563, 569, 571, |
|
577, 587, 593, 599, 601, 607, 613, 617, |
|
619, 631, 641, 643, 647, 653, 659, 661, |
|
673, 677, 683, 691, 701, |
|
#else |
|
97, |
|
#endif |
|
709, 719, 727, |
|
733, 739, 743, 751, 757, 761, 769, 773, |
|
787, |
|
#if 0 |
|
797, |
|
#endif |
|
809, 811, 821, 823, 827, 829, |
|
839, 853, 857, 859, 863, 877, 881, 883, |
|
887, 907, 911, 919, 929, 937, 941, 947, |
|
953, 967, 971, 977, 983, 991, 997, |
|
#if 1 |
|
1009, |
|
1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, |
|
1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, |
|
1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, |
|
1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, |
|
1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, |
|
1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, |
|
1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, |
|
1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, |
|
1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, |
|
1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, |
|
1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, |
|
1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, |
|
1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, |
|
1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, |
|
1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, |
|
1889, |
|
#endif |
|
|
|
-103 |
|
}; |
|
|
|
/* |
|
* From Public domain code of JKISS RNG. |
|
* |
|
* Reference: David Jones, UCL Bioinformatics Group |
|
* Good Practice in (Pseudo) Random Number Generation for |
|
* Bioinformatics Applications |
|
* |
|
*/ |
|
struct jkiss_state { uint32_t x, y, z, c; }; |
|
static struct jkiss_state jkiss_state_v; |
|
|
|
int prng_seed (int (*f_rng)(void *, unsigned char *, size_t), |
|
void *p_rng) |
|
{ |
|
int ret; |
|
|
|
struct jkiss_state *s = &jkiss_state_v; |
|
|
|
MPI_CHK ( f_rng (p_rng, (unsigned char *)s, sizeof (struct jkiss_state)) ); |
|
while (s->y == 0) |
|
MPI_CHK ( f_rng (p_rng, (unsigned char *)&s->y, sizeof (uint32_t)) ); |
|
s->z |= 1; /* avoiding z=c=0 */ |
|
|
|
cleanup: |
|
return ret; |
|
} |
|
|
|
static uint32_t |
|
jkiss (struct jkiss_state *s) |
|
{ |
|
uint64_t t; |
|
|
|
s->x = 314527869 * s->x + 1234567; |
|
s->y ^= s->y << 5; |
|
s->y ^= s->y >> 7; |
|
s->y ^= s->y << 22; |
|
t = 4294584393ULL * s->z + s->c; |
|
s->c = (uint32_t)(t >> 32); |
|
s->z = (uint32_t)t; |
|
|
|
return s->x + s->y + s->z; |
|
} |
|
|
|
static int mpi_fill_pseudo_random ( mpi *X, size_t size) |
|
{ |
|
int ret; |
|
uint32_t *p, *p_end; |
|
|
|
MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) ); |
|
MPI_CHK( mpi_lset( X, 0 ) ); |
|
|
|
/* Assume little endian. */ |
|
p = (uint32_t *)X->p; |
|
p_end = (uint32_t *)(X->p + (size/sizeof (uint32_t))); |
|
while (p < p_end) |
|
*p++ = jkiss (&jkiss_state_v); |
|
|
|
if ((size%sizeof (uint32_t))) |
|
*p = jkiss (&jkiss_state_v) & ((1 << (8*(size % sizeof (uint32_t)))) - 1); |
|
|
|
cleanup: |
|
return ret; |
|
} |
|
|
|
/* |
|
* Miller-Rabin primality test (HAC 4.24) |
|
*/ |
|
static |
|
int mpi_is_prime( mpi *X) |
|
{ |
|
int ret, xs; |
|
size_t i, j, n, s; |
|
mpi W, R, T, A, RR; |
|
|
|
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 ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A ); |
|
mpi_init( &RR ); |
|
|
|
xs = X->s; X->s = 1; |
|
ret = 0; |
|
|
|
#if 0 |
|
/* |
|
* test trivial factors first |
|
*/ |
|
if( ( X->p[0] & 1 ) == 0 ) |
|
return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); |
|
#endif |
|
|
|
for( i = 0; small_prime[i] > 0; i++ ) |
|
{ |
|
t_uint r; |
|
|
|
if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) |
|
return( 0 ); |
|
|
|
MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) ); |
|
|
|
if( r == 0 ) |
|
return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); |
|
} |
|
|
|
/* |
|
* W = |X| - 1 |
|
* R = W >> 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 ) ); |
|
i = mpi_msb( X ); |
|
|
|
/* Fermat primality test with 2. */ |
|
mpi_lset (&T, 2); |
|
MPI_CHK( mpi_exp_mod( &T, &T, &W, X, &RR ) ); |
|
if ( mpi_cmp_int (&T, 1) != 0) |
|
{ |
|
ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; |
|
goto cleanup; |
|
} |
|
|
|
|
|
/* |
|
* HAC, table 4.4 |
|
*/ |
|
n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : |
|
( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : |
|
( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); |
|
|
|
for( i = 0; i < n; i++ ) |
|
{ |
|
/* |
|
* pick a random A, 1 < A < |X| - 1 |
|
*/ |
|
MPI_CHK( mpi_fill_pseudo_random( &A, X->n * ciL ) ); |
|
|
|
if( mpi_cmp_mpi( &A, &W ) >= 0 ) |
|
{ |
|
j = mpi_msb( &A ) - mpi_msb( &W ); |
|
MPI_CHK( mpi_shift_r( &A, j + 1 ) ); |
|
} |
|
A.p[0] |= 3; |
|
|
|
/* |
|
* A = A^R mod |X| |
|
*/ |
|
MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); |
|
|
|
if( mpi_cmp_mpi( &A, &W ) == 0 || |
|
mpi_cmp_int( &A, 1 ) == 0 ) |
|
continue; |
|
|
|
j = 1; |
|
while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) |
|
{ |
|
/* |
|
* A = A * A mod |X| |
|
*/ |
|
MPI_CHK( mpi_mul_mpi( &T, &A, &A ) ); |
|
MPI_CHK( mpi_mod_mpi( &A, &T, X ) ); |
|
|
|
if( mpi_cmp_int( &A, 1 ) == 0 ) |
|
break; |
|
|
|
j++; |
|
} |
|
|
|
/* |
|
* not prime if A != |X| - 1 or A == 1 |
|
*/ |
|
if( mpi_cmp_mpi( &A, &W ) != 0 || |
|
mpi_cmp_int( &A, 1 ) == 0 ) |
|
{ |
|
ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; |
|
break; |
|
} |
|
} |
|
|
|
cleanup: |
|
|
|
X->s = xs; |
|
|
|
mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A ); |
|
mpi_free( &RR ); |
|
|
|
return( ret ); |
|
} |
|
|
|
|
|
/* |
|
* Value M: multiply all primes up to 701 (except 97) and 797 |
|
* (so that MAX_A will be convenient value) |
|
*/ |
|
#ifdef __LP64__ |
|
#define M_LIMBS 16 |
|
#else |
|
#define M_LIMBS 31 |
|
#endif |
|
#define M_SIZE 122 |
|
|
|
static const t_uint limbs_M[] = { /* Little endian */ |
|
#ifdef __LP64__ |
|
0x9344A6AB84EEB59EUL, 0xEC855CDAFF21529FUL, |
|
0x477E991E009BAB38UL, 0x2EEA23579F5B86F3UL, |
|
0xAC17D30441D6502FUL, 0x38FF52B90A468A6DUL, |
|
0x63630419FD42E5EFUL, 0x48CE17D091DB2572UL, |
|
0x708AB00AE3B57D0EUL, 0xF8A9DE08CD723598UL, |
|
0x731411374432C93BUL, 0x554DF2612779FAB3UL, |
|
0xDEEBDA58953D2BA5UL, 0xD1D66F2F5F57D007UL, |
|
0xB85C9607E84E9F2BUL, 0x000000000000401DUL |
|
#else |
|
0x84EEB59E, 0x9344A6AB, 0xFF21529F, 0xEC855CDA, |
|
0x009BAB38, 0x477E991E, 0x9F5B86F3, 0x2EEA2357, |
|
0x41D6502F, 0xAC17D304, 0x0A468A6D, 0x38FF52B9, |
|
0xFD42E5EF, 0x63630419, 0x91DB2572, 0x48CE17D0, |
|
0xE3B57D0E, 0x708AB00A, 0xCD723598, 0xF8A9DE08, |
|
0x4432C93B, 0x73141137, 0x2779FAB3, 0x554DF261, |
|
0x953D2BA5, 0xDEEBDA58, 0x5F57D007, 0xD1D66F2F, |
|
0xE84E9F2B, 0xB85C9607, 0x0000401D |
|
#endif |
|
}; |
|
|
|
static const mpi M[1] = {{ 1, M_LIMBS, (t_uint *)limbs_M }}; |
|
|
|
/* |
|
* MAX_A : 2^1024 / M - 1 |
|
*/ |
|
#ifdef __LP64__ |
|
#define MAX_A_LIMBS 1 |
|
#else |
|
#define MAX_A_LIMBS 2 |
|
#endif |
|
#define MAX_A_FILL_SIZE 6 |
|
static const t_uint limbs_MAX_A[] = { /* Little endian */ |
|
#ifdef __LP64__ |
|
0x0003FE2556A2B35FUL |
|
#else |
|
0x56A2B35F, 0x0003FE25 |
|
#endif |
|
}; |
|
|
|
static const mpi MAX_A[1] = {{ 1, MAX_A_LIMBS, (t_uint *)limbs_MAX_A }}; |
|
|
|
/* |
|
* Prime number generation |
|
* |
|
* Special version for 1024-bit only. Ignores DH_FLAG. |
|
*/ |
|
int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, |
|
int (*f_rng)(void *, unsigned char *, size_t), |
|
void *p_rng ) |
|
{ |
|
int ret; |
|
mpi B[1], G[1]; |
|
|
|
(void)dh_flag; |
|
if (nbits != 1024) |
|
return POLARSSL_ERR_MPI_BAD_INPUT_DATA; |
|
|
|
mpi_init ( B ); mpi_init ( G ); |
|
|
|
/* |
|
* Get random value 1 to M-1 avoiding bias, and proceed when it is |
|
* coprime to all small primes. |
|
*/ |
|
do |
|
{ |
|
MPI_CHK ( mpi_fill_random ( B, M_SIZE, f_rng, p_rng ) ); |
|
B->p[0] |= 0x1; |
|
B->p[M_LIMBS - 1] &= 0x00007FFF; |
|
if (mpi_cmp_abs (B, M) >= 0) |
|
continue; |
|
|
|
MPI_CHK ( mpi_gcd ( G, B, M ) ); |
|
} |
|
while (mpi_cmp_int ( G, 1 ) != 0); |
|
|
|
/* |
|
* Get random value avoiding bias, comput P with the value, |
|
* check if it's big enough, lastly, check if it's prime. |
|
*/ |
|
while (1) |
|
{ |
|
MPI_CHK( mpi_fill_random( X, MAX_A_FILL_SIZE, f_rng, p_rng ) ); |
|
MPI_CHK ( mpi_sub_abs (X, MAX_A, X) ); |
|
|
|
MPI_CHK ( mpi_mul_mpi ( X, X, M ) ); |
|
MPI_CHK ( mpi_add_abs ( X, X, B ) ); |
|
if (X->n <= M_LIMBS || (X->p[M_LIMBS-1] & 0xc0000000) == 0) |
|
continue; |
|
ret = mpi_is_prime ( X ); |
|
if (ret == 0 || ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE) |
|
break; |
|
} |
|
|
|
cleanup: |
|
|
|
mpi_free ( B ); mpi_free ( G ); |
|
|
|
return ret; |
|
} |
|
|
|
#endif |
|
|
|
#if defined(POLARSSL_SELF_TEST) |
|
|
|
#define GCD_PAIR_COUNT 3 |
|
|
|
static const int gcd_pairs[GCD_PAIR_COUNT][3] = |
|
{ |
|
{ 693, 609, 21 }, |
|
{ 1764, 868, 28 }, |
|
{ 768454923, 542167814, 1 } |
|
}; |
|
|
|
/* |
|
* Checkup routine |
|
*/ |
|
int mpi_self_test( int verbose ) |
|
{ |
|
int ret, i; |
|
mpi A, E, N, X, Y, U, V; |
|
|
|
mpi_init( &A ); mpi_init( &E ); mpi_init( &N ); mpi_init( &X ); |
|
mpi_init( &Y ); mpi_init( &U ); mpi_init( &V ); |
|
|
|
MPI_CHK( mpi_read_string( &A, 16, |
|
"EFE021C2645FD1DC586E69184AF4A31E" \ |
|
"D5F53E93B5F123FA41680867BA110131" \ |
|
"944FE7952E2517337780CB0DB80E61AA" \ |
|
"E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); |
|
|
|
MPI_CHK( mpi_read_string( &E, 16, |
|
"B2E7EFD37075B9F03FF989C7C5051C20" \ |
|
"34D2A323810251127E7BF8625A4F49A5" \ |
|
"F3E27F4DA8BD59C47D6DAABA4C8127BD" \ |
|
"5B5C25763222FEFCCFC38B832366C29E" ) ); |
|
|
|
MPI_CHK( mpi_read_string( &N, 16, |
|
"0066A198186C18C10B2F5ED9B522752A" \ |
|
"9830B69916E535C8F047518A889A43A5" \ |
|
"94B6BED27A168D31D4A52F88925AA8F5" ) ); |
|
|
|
MPI_CHK( mpi_mul_mpi( &X, &A, &N ) ); |
|
|
|
MPI_CHK( mpi_read_string( &U, 16, |
|
"602AB7ECA597A3D6B56FF9829A5E8B85" \ |
|
"9E857EA95A03512E2BAE7391688D264A" \ |
|
"A5663B0341DB9CCFD2C4C5F421FEC814" \ |
|
"8001B72E848A38CAE1C65F78E56ABDEF" \ |
|
"E12D3C039B8A02D6BE593F0BBBDA56F1" \ |
|
"ECF677152EF804370C1A305CAF3B5BF1" \ |
|
"30879B56C61DE584A0F53A2447A51E" ) ); |
|
|
|
if( verbose != 0 ) |
|
printf( " MPI test #1 (mul_mpi): " ); |
|
|
|
if( mpi_cmp_mpi( &X, &U ) != 0 ) |
|
{ |
|
if( verbose != 0 ) |
|
printf( "failed\n" ); |
|
|
|
return( 1 ); |
|
} |
|
|
|
if( verbose != 0 ) |
|
printf( "passed\n" ); |
|
|
|
MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) ); |
|
|
|
MPI_CHK( mpi_read_string( &U, 16, |
|
"256567336059E52CAE22925474705F39A94" ) ); |
|
|
|
MPI_CHK( mpi_read_string( &V, 16, |
|
"6613F26162223DF488E9CD48CC132C7A" \ |
|
"0AC93C701B001B092E4E5B9F73BCD27B" \ |
|
"9EE50D0657C77F374E903CDFA4C642" ) ); |
|
|
|
if( verbose != 0 ) |
|
printf( " MPI test #2 (div_mpi): " ); |
|
|
|
if( mpi_cmp_mpi( &X, &U ) != 0 || |
|
mpi_cmp_mpi( &Y, &V ) != 0 ) |
|
{ |
|
if( verbose != 0 ) |
|
printf( "failed\n" ); |
|
|
|
return( 1 ); |
|
} |
|
|
|
if( verbose != 0 ) |
|
printf( "passed\n" ); |
|
|
|
MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) ); |
|
|
|
MPI_CHK( mpi_read_string( &U, 16, |
|
"36E139AEA55215609D2816998ED020BB" \ |
|
"BD96C37890F65171D948E9BC7CBAA4D9" \ |
|
"325D24D6A3C12710F10A09FA08AB87" ) ); |
|
|
|
if( verbose != 0 ) |
|
printf( " MPI test #3 (exp_mod): " ); |
|
|
|
if( mpi_cmp_mpi( &X, &U ) != 0 ) |
|
{ |
|
if( verbose != 0 ) |
|
printf( "failed\n" ); |
|
|
|
return( 1 ); |
|
} |
|
|
|
if( verbose != 0 ) |
|
printf( "passed\n" ); |
|
|
|
#if defined(POLARSSL_GENPRIME) |
|
MPI_CHK( mpi_inv_mod( &X, &A, &N ) ); |
|
|
|
MPI_CHK( mpi_read_string( &U, 16, |
|
"003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ |
|
"C3DBA76456363A10869622EAC2DD84EC" \ |
|
"C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); |
|
|
|
if( verbose != 0 ) |
|
printf( " MPI test #4 (inv_mod): " ); |
|
|
|
if( mpi_cmp_mpi( &X, &U ) != 0 ) |
|
{ |
|
if( verbose != 0 ) |
|
printf( "failed\n" ); |
|
|
|
return( 1 ); |
|
} |
|
|
|
if( verbose != 0 ) |
|
printf( "passed\n" ); |
|
#endif |
|
|
|
if( verbose != 0 ) |
|
printf( " MPI test #5 (simple gcd): " ); |
|
|
|
for ( i = 0; i < GCD_PAIR_COUNT; i++) |
|
{ |
|
MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) ); |
|
MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) ); |
|
|
|
MPI_CHK( mpi_gcd( &A, &X, &Y ) ); |
|
|
|
if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) |
|
{ |
|
if( verbose != 0 ) |
|
printf( "failed at %d\n", i ); |
|
|
|
return( 1 ); |
|
} |
|
} |
|
|
|
if( verbose != 0 ) |
|
printf( "passed\n" ); |
|
|
|
cleanup: |
|
|
|
if( ret != 0 && verbose != 0 ) |
|
printf( "Unexpected error, return code = %08X\n", ret ); |
|
|
|
mpi_free( &A ); mpi_free( &E ); mpi_free( &N ); mpi_free( &X ); |
|
mpi_free( &Y ); mpi_free( &U ); mpi_free( &V ); |
|
|
|
if( verbose != 0 ) |
|
printf( "\n" ); |
|
|
|
return( ret ); |
|
} |
|
|
|
#endif |
|
|
|
#endif
|
|
|