From cdd44324e9b8954e8a9d5719a0827ad0d2db8fbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 21 Nov 2012 16:00:55 +0100 Subject: [PATCH] Added ecp_normalize_many() for faster precompute() --- library/ecp.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 8 deletions(-) diff --git a/library/ecp.c b/library/ecp.c index 0898e4d54..802f532f1 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -37,6 +37,7 @@ #include "polarssl/ecp.h" #include +#include #if defined(POLARSSL_SELF_TEST) /* @@ -472,12 +473,12 @@ int ecp_use_known_dp( ecp_group *grp, size_t index ) static int ecp_normalize( const ecp_group *grp, ecp_point *pt ) { int ret; - mpi Zi, ZZi, T; + mpi Zi, ZZi; if( mpi_cmp_int( &pt->Z, 0 ) == 0 ) return( 0 ); - mpi_init( &Zi ); mpi_init( &ZZi ); mpi_init( &T ); + mpi_init( &Zi ); mpi_init( &ZZi ); /* * X = X / Z^2 mod p @@ -499,11 +500,90 @@ static int ecp_normalize( const ecp_group *grp, ecp_point *pt ) cleanup: - mpi_free( &Zi ); mpi_free( &ZZi ); mpi_free( &T ); + mpi_free( &Zi ); mpi_free( &ZZi ); return( ret ); } +/* + * Normalize jacobian coordinates of an array of points, + * using Montgomery's trick to perform only one division. + * (See for example Cohen's "A Course in Computational Algebraic Number + * Theory", Algorithm 10.3.4.) + * + * FIXME: assumes all points are non zero + */ +static int ecp_normalize_many( const ecp_group *grp, + ecp_point T[], size_t t_len ) +{ + int ret; + size_t i; + mpi *c, u, Zi, ZZi; + + if( t_len < 2 ) + return( ecp_normalize( grp, T ) ); + + if( ( c = (mpi *) malloc( t_len * sizeof( mpi ) ) ) == NULL ) + return( POLARSSL_ERR_ECP_GENERIC ); + + mpi_init( &u ); mpi_init( &Zi ); mpi_init( &ZZi ); + for( i = 0; i < t_len; i++ ) + mpi_init( &c[i] ); + + /* + * c[i] = Z_0 * ... * Z_i + */ + MPI_CHK( mpi_copy( &c[0], &T[0].Z ) ); + for( i = 1; i < t_len; i++ ) + { + MPI_CHK( mpi_mul_mpi( &c[i], &c[i-1], &T[i].Z ) ); + MOD_MUL( c[i] ); + } + + /* + * u = 1 / (Z_0 * ... * Z_n) mod P + */ + MPI_CHK( mpi_inv_mod( &u, &c[t_len-1], &grp->P ) ); + + for( i = t_len - 1; ; i-- ) + { + /* + * Zi = 1 / Z_i mod p + * u = 1 / (Z_0 * ... * Z_i) mod P + */ + if( i == 0 ) { + MPI_CHK( mpi_copy( &Zi, &u ) ); + } + else + { + MPI_CHK( mpi_mul_mpi( &Zi, &u, &c[i-1] ) ); MOD_MUL( Zi ); + MPI_CHK( mpi_mul_mpi( &u, &u, &T[i].Z ) ); MOD_MUL( u ); + } + + /* + * proceed as in normalize() + */ + MPI_CHK( mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi ); + MPI_CHK( mpi_mul_mpi( &T[i].X, &T[i].X, &ZZi ) ); MOD_MUL( T[i].X ); + MPI_CHK( mpi_mul_mpi( &T[i].Y, &T[i].Y, &ZZi ) ); MOD_MUL( T[i].Y ); + MPI_CHK( mpi_mul_mpi( &T[i].Y, &T[i].Y, &Zi ) ); MOD_MUL( T[i].Y ); + MPI_CHK( mpi_lset( &T[i].Z, 1 ) ); + + if( i == 0 ) + break; + } + +cleanup: + + mpi_free( &u ); mpi_free( &Zi ); mpi_free( &ZZi ); + for( i = 0; i < t_len; i++ ) + mpi_free( &c[i] ); + free( c ); + + return( ret ); +} + + /* * Point doubling R = 2 P, Jacobian coordinates (GECC 3.21) */ @@ -782,11 +862,13 @@ static int ecp_precompute( const ecp_group *grp, MPI_CHK( ecp_copy( &T[0], P ) ); - /* - * TODO: use Montgomery's trick for less inversions - */ for( i = 1; i < t_len; i++ ) - MPI_CHK( ecp_add( grp, &T[i], &T[i-1], &PP ) ); + MPI_CHK( ecp_add_mixed( grp, &T[i], &T[i-1], &PP, +1 ) ); + + /* + * T[0] = P already has normalized coordinates + */ + ecp_normalize_many( grp, T + 1, t_len - 1 ); cleanup: @@ -829,7 +911,7 @@ int ecp_mul( const ecp_group *grp, ecp_point *R, if( mpi_cmp_int( m, 0 ) < 0 || mpi_msb( m ) > grp->nbits ) return( POLARSSL_ERR_ECP_GENERIC ); - w = 3; // TODO: find optimal values once precompute() is optimized + w = 5; // TODO: find optimal values once precompute() is optimized if( w < 2 ) w = 2;