📄 mpi.cpp
字号:
mpi_init( &TA, &TB, NULL );
if( X == A ) { CHK( mpi_copy( &TA, A ) ); A = &TA; }
if( X == B ) { CHK( mpi_copy( &TB, B ) ); B = &TB; }
for( i = A->n - 1; i >= 0; i-- )
if( A->p[i] != 0 )
break;
for( j = B->n - 1; j >= 0; j-- )
if( B->p[j] != 0 )
break;
CHK( mpi_grow( X, i + j + 2 ) );
CHK( mpi_lset( X, 0 ) );
for( i++; j >= 0; j-- )
MULADDC( i, A->p, X->p + j, B->p[j] );
X->s = A->s * B->s;
cleanup:
mpi_free( &TB, &TA, NULL );
return( ret );
}
/*
* Baseline multiplication: X = A * b
*
* Returns 0 if successful
* 1 if memory allocation failed
*/
int mpi_mul_int( mpi *X, mpi *A, t_int b )
{
mpi _B;
t_int p[1];
_B.s = 1;
_B.n = 1;
_B.p = p;
p[0] = b;
return( mpi_mul_mpi( X, A, &_B ) );
}
/*
* Division by mpi: A = Q * B + R (HAC 14.20)
*
* Returns 0 if successful
* 1 if memory allocation failed
* ERR_MPI_DIVISION_BY_ZERO if B == 0
*/
int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B )
{
int ret, i, n, t, k;
mpi X, Y, Z, T1, T2;
t_int q0, q1, r0, r1;
t_int d0, d1, d, m;
if( mpi_cmp_int( B, 0 ) == 0 )
return( ERR_MPI_DIVISION_BY_ZERO );
mpi_init( &X, &Y, &Z, &T1, &T2, NULL );
if( mpi_cmp_abs( A, B ) < 0 )
{
if( Q != NULL ) CHK( mpi_lset( Q, 0 ) );
if( R != NULL ) CHK( mpi_copy( R, A ) );
return( 0 );
}
CHK( mpi_copy( &X, A ) );
CHK( mpi_copy( &Y, B ) );
X.s = Y.s = 1;
CHK( mpi_grow( &Z, A->n + 2 ) );
CHK( mpi_lset( &Z, 0 ) );
CHK( mpi_grow( &T1, 2 ) );
CHK( mpi_grow( &T2, 3 ) );
k = mpi_size( &Y ) % biL;
if( k < (int) biL - 1 )
{
k = biL - 1 - k;
CHK( mpi_shift_l( &X, k ) );
CHK( mpi_shift_l( &Y, k ) );
}
else k = 0;
n = X.n - 1;
t = Y.n - 1;
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] = ~0;
else
{
/*
* __udiv_qrnnd_c, from GMP/longlong.h
*/
d = Y.p[t];
d0 = ( d << biH ) >> biH;
d1 = ( d >> biH );
q1 = X.p[i] / d1;
r1 = X.p[i] - d1 * q1;
r1 <<= biH;
r1 |= ( X.p[i - 1] >> biH );
m = q1 * d0;
if( r1 < m )
{
q1--, r1 += d;
while( r1 >= d && r1 < m )
q1--, r1 += d;
}
r1 -= m;
q0 = r1 / d1;
r0 = r1 - d1 * q0;
r0 <<= biH;
r0 |= ( X.p[i - 1] << biH ) >> biH;
m = q0 * d0;
if( r0 < m )
{
q0--, r0 += d;
while( r0 >= d && r0 < m )
q0--, r0 += d;
}
r0 -= m;
Z.p[i - t - 1] = ( q1 << biH ) | q0;
}
Z.p[i - t - 1]++;
do
{
Z.p[i - t - 1]--;
CHK( mpi_lset( &T1, 0 ) );
T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
T1.p[1] = Y.p[t];
CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) );
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 );
CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) );
CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
CHK( mpi_sub_mpi( &X, &X, &T1 ) );
if( mpi_cmp_int( &X, 0 ) < 0 )
{
CHK( mpi_copy( &T1, &Y ) );
CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) );
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 );
mpi_copy( R, &X );
R->s = A->s;
if( mpi_cmp_int( R, 0 ) == 0 )
R->s = 1;
}
cleanup:
mpi_free( &X, &Y, &Z, &T1, &T2, NULL );
return( ret );
}
/*
* Division by int: A = Q * b + R
*
* Returns 0 if successful
* 1 if memory allocation failed
* ERR_MPI_DIVISION_BY_ZERO if b == 0
*/
int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b )
{
mpi _B;
t_int 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: X = A mod N
*
* Returns 0 if successful
* 1 if memory allocation failed
* ERR_MPI_DIVISION_BY_ZERO if N == 0
*/
int mpi_mod_mpi( mpi *R, mpi *A, mpi *B )
{
int ret;
CHK( mpi_div_mpi( NULL, R, A, B ) );
while( mpi_cmp_int( R, 0 ) < 0 )
CHK( mpi_add_mpi( R, R, B ) );
while( mpi_cmp_mpi( R, B ) >= 0 )
CHK( mpi_sub_mpi( R, R, B ) );
cleanup:
return( ret );
}
/*
* Modulo: r = A mod b
*
* Returns 0 if successful
* 1 if memory allocation failed
* ERR_MPI_DIVISION_BY_ZERO if b == 0
* ERR_MPI_INVALID_PARAMETER if |sign| != 1
*/
int mpi_mod_int( t_int *r, mpi *A, int b )
{
int i;
t_int x, y, z;
if( b == 0 )
return( ERR_MPI_DIVISION_BY_ZERO );
if( b < 0 )
b = -b;
/*
* 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 - 1, y = 0; i >= 0; i-- )
{
x = A->p[i];
y = ( y << biH ) | ( x >> biH );
z = y / b;
y -= z * b;
x <<= biH;
y = ( y << biH ) | ( x >> biH );
z = y / b;
y -= z * b;
}
*r = y;
return( 0 );
}
/*
* Fast Montgomery initialization (thanks to Tom St Denis)
*/
void mpi_montg_init( t_int *mm, mpi *N )
{
t_int 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: X = A * B * R^-1 mod N (HAC 14.36)
* (Z is a decoy used to prevent timing attacks)
*
* Returns 0 if successful
* 1 if memory allocation failed
*/
int mpi_montgomery( mpi *X, mpi *A, mpi *B, mpi *N, mpi *Z, t_int mm )
{
int ret, i, maxB;
t_int j;
t_int u0, *x0, z = 1;
t_int u1, *x1;
mpi U;
U.s = U.n = 1; U.p = &z;
if( A == NULL ) A = &U;
if( B == NULL ) B = &U;
CHK( mpi_grow( X, N->n + 2 ) );
CHK( mpi_lset( X, 0 ) );
maxB = ( B->n > N->n ) ? N->n : B->n;
for( i = 0; i < N->n; i++ )
{
/*
* X = X + u0*B + u1*M
*/
u0 = ( i < A->n ) ? A->p[i] : 0;
u1 = ( X->p[0] + u0 * B->p[0] ) * mm;
MULADDC( maxB, B->p, X->p, u0 );
MULADDC( N->n, N->p, X->p, u1 );
/*
* right-shift X by one limb
*/
x0 = X->p;
x1 = X->p + 1;
for( j = X->n - 1; j > 0; j-- )
*x0++ = *x1++;
*x0 = 0;
}
CHK( mpi_copy( Z, N ) );
if( mpi_cmp_abs( X, N ) >= 0 )
{ CHK( mpi_sub_abs( X, X, N ) ); }
else
{ CHK( mpi_sub_abs( Z, Z, X ) ); }
cleanup:
return( ret );
}
/*
* Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
*
* Returns 0 if successful
* 1 if memory allocation failed
* ERR_MPI_INVALID_PARAMETER if N is negative or even
*/
int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N )
{
int ret, i, j, wsize, wbits, nbits;
int bufsize, nblimbs, state;
mpi R, S, T, W[64], Z;
t_int mm, ei;
if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
return( ERR_MPI_INVALID_PARAMETER );
mpi_init( &Z, &R, &S, &T, NULL );
memset( W, 0, sizeof( W ) );
/*
* S = R mod N
*/
CHK( mpi_lset( &R, 1 ) );
CHK( mpi_shift_l( &R, N->n * biL ) );
CHK( mpi_mod_mpi( &S, &R, N ) );
/*
* W[1] = A * R mod N
*/
CHK( mpi_copy( &R, A ) );
CHK( mpi_shift_l( &R, N->n * biL ) );
CHK( mpi_mod_mpi( &W[1], &R, N ) );
i = mpi_size( E );
wsize = ( i > 671 ) ? 6 :
( i > 239 ) ? 5 :
( i > 79 ) ? 4 :
( i > 23 ) ? 3 : 2;
mpi_montg_init( &mm, N );
if( wsize > 1 )
{
/*
* W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
*/
j = 1 << (wsize - 1);
CHK( mpi_copy( &W[j], &W[1] ) );
for( i = 0; i < wsize - 1; i++ )
{
CHK( mpi_montgomery( &T, &W[j], &W[j], N, &Z, mm ) );
CHK( mpi_copy( &W[j], &T ) );
}
/*
* W[i] = W[1] * W[i - 1]
*/
for( i = j + 1; i < (1 << wsize); i++ )
{
CHK( mpi_montgomery( &T, &W[i - 1], &W[1], N, &Z, mm ) );
CHK( mpi_copy( &W[i], &T ) );
}
}
nblimbs = E->n;
bufsize = 0;
nbits = 0;
wbits = 0;
state = 0;
while( 1 )
{
if( bufsize == 0 )
{
if( nblimbs-- == 0 )
break;
bufsize = sizeof( t_int ) << 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 S
*/
CHK( mpi_montgomery( &T, &S, &S, N, &Z, mm ) );
CHK( mpi_copy( &S, &T ) );
continue;
}
/*
* add ei to current window
*/
state = 2;
nbits++;
wbits |= (ei << (wsize - nbits));
if( nbits == wsize )
{
/*
* S = S^wsize R^-1 mod N
*/
for( i = 0; i < wsize; i++ )
{
CHK( mpi_montgomery( &T, &S, &S, N, &Z, mm ) );
CHK( mpi_copy( &S, &T ) );
}
/*
* S = S * W[wbits] R^-1 mod N
*/
CHK( mpi_montgomery( &T, &S, &W[wbits], N, &Z, mm ) );
CHK( mpi_copy( &S, &T ) );
state--;
nbits = 0;
wbits = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -