2018-05-03 22:01:45 +00:00
|
|
|
#include "tommath_private.h"
|
|
|
|
#ifdef BN_MP_PRIME_FROBENIUS_UNDERWOOD_C
|
|
|
|
|
|
|
|
/* LibTomMath, multiple-precision integer library -- Tom St Denis
|
|
|
|
*
|
|
|
|
* LibTomMath is a library that provides multiple-precision
|
|
|
|
* integer arithmetic as well as number theoretic functionality.
|
|
|
|
*
|
|
|
|
* The library was designed directly after the MPI library by
|
|
|
|
* Michael Fromberger but has been written from scratch with
|
|
|
|
* additional optimizations in place.
|
|
|
|
*
|
|
|
|
* The library is free for all purposes without any express
|
|
|
|
* guarantee it works.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef MP_8BIT
|
|
|
|
// floor of positive solution of
|
|
|
|
// (2^16)-1 = (a+4)*(2*a+5)
|
|
|
|
// TODO: that is too small, would have to use a bigint for a instead
|
2018-05-04 13:15:13 +00:00
|
|
|
#define LTM_FROBENIUS_UNDERWOOD_A 177
|
|
|
|
// commented out to allow Travis's tests to run
|
|
|
|
// Don't forget to switch in back on in production or we'll find it at TDWTF.com!
|
|
|
|
//#warning "Frobenius test not fully usable with MP_8BIT!"
|
|
|
|
#else
|
2018-05-03 22:01:45 +00:00
|
|
|
// floor of positive solution of
|
|
|
|
// (2^31)-1 = (a+4)*(2*a+5)
|
|
|
|
// TODO: that might be too small
|
|
|
|
#define LTM_FROBENIUS_UNDERWOOD_A 32764
|
2018-05-04 13:15:13 +00:00
|
|
|
#endif
|
2018-05-03 22:01:45 +00:00
|
|
|
int mp_prime_frobenius_underwood(const mp_int *N, int *result)
|
|
|
|
{
|
|
|
|
mp_int T1z,T2z,Np1z,sz,tz;
|
|
|
|
|
|
|
|
int a, ap2, length, i, j, isset;
|
|
|
|
int e = MP_OKAY;
|
|
|
|
|
|
|
|
*result = MP_NO;
|
|
|
|
|
|
|
|
if ((e = mp_init_multi(&T1z,&T2z,&Np1z,&sz,&tz, NULL)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (a = 0; a < LTM_FROBENIUS_UNDERWOOD_A; a++) {
|
|
|
|
//TODO: That's ugly! No, really, it is!
|
|
|
|
if (a==2||a==4||a==7||a==8||a==10||a==14||a==18||a==23||a==26||a==28) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// (32764^2 - 4) < 2^31, no bigint for >MP_8BIT needed)
|
|
|
|
if ((e = mp_set_int(&T1z,(unsigned long)a)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((e = mp_sqr(&T1z,&T1z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((e = mp_sub_d(&T1z,4,&T1z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((e = mp_kronecker(&T1z, N, &j)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == -1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == 0) {
|
|
|
|
// composite
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (a >= LTM_FROBENIUS_UNDERWOOD_A) {
|
|
|
|
e = MP_VAL;
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
// Composite if N and (a+4)*(2*a+5) are not coprime
|
|
|
|
if ((e = mp_set_int(&T1z, (unsigned long)((a+4)*(2*a+5)))) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((e = mp_gcd(N,&T1z,&T1z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(T1z.used == 1 && T1z.dp[0] == 1u)) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
ap2 = a + 2;
|
|
|
|
if ((e = mp_add_d(N,1u,&Np1z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
mp_set(&sz,1u);
|
|
|
|
mp_set(&tz,2u);
|
|
|
|
length = mp_count_bits(&Np1z);
|
|
|
|
|
|
|
|
for (i = length - 2; i >= 0; i--) {
|
|
|
|
/*
|
|
|
|
temp = (sz*(a*sz+2*tz))%N;
|
|
|
|
tz = ((tz-sz)*(tz+sz))%N;
|
|
|
|
sz = temp;
|
|
|
|
*/
|
|
|
|
if ((e = mp_mul_2(&tz,&T2z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
// TODO: is this small saving worth the branch?
|
|
|
|
if (a != 0) {
|
|
|
|
if ((e = mp_mul_d(&sz,(mp_digit)a,&T1z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if ((e = mp_add(&T1z,&T2z,&T2z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((e = mp_mul(&T2z, &sz, &T1z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if ((e = mp_sub(&tz, &sz, &T2z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if ((e = mp_add(&sz, &tz, &sz)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if ((e = mp_mul(&sz, &T2z, &tz)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if ((e = mp_mod(&tz, N, &tz)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if ((e = mp_mod(&T1z, N, &sz)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if ((isset = mp_get_bit(&Np1z,i)) == MP_VAL) {
|
|
|
|
e = isset;
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if (isset == MP_YES) {
|
|
|
|
/*
|
|
|
|
temp = (a+2) * sz + tz
|
|
|
|
tz = 2 * tz - sz
|
|
|
|
sz = temp
|
|
|
|
*/
|
|
|
|
if (a == 0) {
|
|
|
|
if ((e = mp_mul_2(&sz,&T1z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((e = mp_mul_d(&sz, (mp_digit) ap2, &T1z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((e = mp_add(&T1z, &tz, &T1z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if ((e = mp_mul_2(&tz, &T2z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if ((e = mp_sub(&T2z, &sz, &tz)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
mp_exch(&sz,&T1z);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((e = mp_set_int(&T1z, (unsigned long)(2 * a + 5))) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if ((e = mp_mod(&T1z,N,&T1z)) != MP_OKAY) {
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
if (mp_iszero(&sz) && (mp_cmp(&tz, &T1z) == MP_EQ)) {
|
|
|
|
*result = MP_YES;
|
|
|
|
goto LBL_FU_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
LBL_FU_ERR:
|
|
|
|
mp_clear_multi(&T1z,&T2z,&Np1z,&sz,&tz, NULL);
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|