284 lines
5.6 KiB
C
284 lines
5.6 KiB
C
/* Routines to make gcrypt routines feel at home in Pluto.
|
|
* Copyright (C) 1999 D. Hugh Redelmeier.
|
|
*
|
|
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
*
|
|
* 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.
|
|
*
|
|
* RCSID $Id$
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <gmp.h>
|
|
#include <freeswan.h>
|
|
#include "constants.h"
|
|
#include "defs.h"
|
|
#include "log.h"
|
|
#include "rnd.h"
|
|
#include "gcryptfix.h" /* includes <gmp.h> "defs.h" "rnd.h" */
|
|
|
|
MPI
|
|
mpi_alloc( unsigned nlimbs UNUSED )
|
|
{
|
|
MPI n = malloc(sizeof *n);
|
|
|
|
mpz_init(n);
|
|
return n;
|
|
}
|
|
|
|
MPI
|
|
mpi_alloc_secure( unsigned nlimbs )
|
|
{
|
|
return mpi_alloc(nlimbs);
|
|
}
|
|
|
|
MPI
|
|
mpi_alloc_set_ui( unsigned long u)
|
|
{
|
|
MPI n = malloc(sizeof *n);
|
|
|
|
mpz_init_set_ui(n, u);
|
|
return n;
|
|
}
|
|
|
|
MPI
|
|
mpi_copy( MPI a )
|
|
{
|
|
MPI n = malloc(sizeof *n);
|
|
|
|
mpz_init_set(n, a);
|
|
return n;
|
|
}
|
|
|
|
void
|
|
mpi_free( MPI a )
|
|
{
|
|
mpz_clear(a);
|
|
free(a);
|
|
}
|
|
|
|
int
|
|
mpi_divisible_ui(MPI dividend, ulong divisor )
|
|
{
|
|
ulong rem;
|
|
mpz_t remtoo;
|
|
|
|
mpz_init(remtoo);
|
|
rem = mpz_mod_ui(remtoo, dividend, divisor);
|
|
mpz_clear(remtoo);
|
|
return rem == 0;
|
|
}
|
|
|
|
unsigned
|
|
mpi_trailing_zeros( MPI a )
|
|
{
|
|
return mpz_scan1(a, 0);
|
|
}
|
|
|
|
unsigned
|
|
mpi_get_nbits( MPI a )
|
|
{
|
|
return mpz_sizeinbase(a, 2);
|
|
}
|
|
|
|
int
|
|
mpi_test_bit( MPI a, unsigned n )
|
|
{
|
|
/* inspired by gmp/mpz/clrbit.c */
|
|
mp_size_t li = n / mp_bits_per_limb;
|
|
|
|
if (li >= a->_mp_size)
|
|
return 0;
|
|
return (a->_mp_d[li] & ((mp_limb_t) 1 << (n % mp_bits_per_limb))) != 0;
|
|
}
|
|
|
|
void
|
|
mpi_set_bit( MPI a, unsigned n )
|
|
{
|
|
mpz_setbit(a, n);
|
|
}
|
|
|
|
void
|
|
mpi_clear_bit( MPI a, unsigned n )
|
|
{
|
|
mpz_clrbit(a, n);
|
|
}
|
|
|
|
void
|
|
mpi_clear_highbit( MPI a, unsigned n )
|
|
{
|
|
/* This seems whacky, but what do I know. */
|
|
mpz_fdiv_r_2exp(a, a, n);
|
|
}
|
|
|
|
void
|
|
mpi_set_highbit( MPI a, unsigned n )
|
|
{
|
|
/* This seems whacky, but what do I know. */
|
|
mpz_fdiv_r_2exp(a, a, n+1);
|
|
mpz_setbit(a, n);
|
|
}
|
|
|
|
void
|
|
mpi_set_buffer( MPI a, const u_char *buffer, unsigned nbytes, int sign )
|
|
{
|
|
/* this is a lot like n_to_mpz */
|
|
size_t i;
|
|
|
|
passert(sign == 0); /* we won't hit any negative numbers */
|
|
mpz_init_set_ui(a, 0);
|
|
|
|
for (i = 0; i != nbytes; i++)
|
|
{
|
|
mpz_mul_ui(a, a, 1 << BITS_PER_BYTE);
|
|
mpz_add_ui(a, a, buffer[i]);
|
|
}
|
|
}
|
|
|
|
u_char *
|
|
get_random_bits(size_t nbits, int level UNUSED, int secure UNUSED)
|
|
{
|
|
size_t nbytes = (nbits+7)/8;
|
|
u_char *b = malloc(nbytes);
|
|
|
|
get_rnd_bytes(b, nbytes);
|
|
return b;
|
|
}
|
|
/**************** from gnupg-1.0.0/mpi/mpi-mpow.c
|
|
* RES = (BASE[0] ^ EXP[0]) * (BASE[1] ^ EXP[1]) * ... * mod M
|
|
*/
|
|
#define barrett_mulm( w, u, v, m, y, k, r1, r2 ) mpi_mulm( (w), (u), (v), (m) )
|
|
|
|
static int
|
|
build_index( MPI *exparray, int k, int i, int t )
|
|
{
|
|
int j, bitno;
|
|
int index = 0;
|
|
|
|
bitno = t-i;
|
|
for(j=k-1; j >= 0; j-- ) {
|
|
index <<= 1;
|
|
if( mpi_test_bit( exparray[j], bitno ) )
|
|
index |= 1;
|
|
}
|
|
/*log_debug("t=%d i=%d index=%d\n", t, i, index );*/
|
|
return index;
|
|
}
|
|
|
|
void
|
|
mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m)
|
|
{
|
|
int k; /* number of elements */
|
|
int t; /* bit size of largest exponent */
|
|
int i, j, idx;
|
|
MPI *G; /* table with precomputed values of size 2^k */
|
|
MPI tmp;
|
|
#ifdef USE_BARRETT
|
|
MPI barrett_y, barrett_r1, barrett_r2;
|
|
int barrett_k;
|
|
#endif
|
|
|
|
for(k=0; basearray[k]; k++ )
|
|
;
|
|
passert(k);
|
|
for(t=0, i=0; (tmp=exparray[i]); i++ ) {
|
|
/*log_mpidump("exp: ", tmp );*/
|
|
j = mpi_get_nbits(tmp);
|
|
if( j > t )
|
|
t = j;
|
|
}
|
|
/*log_mpidump("mod: ", m );*/
|
|
passert(i==k);
|
|
passert(t);
|
|
passert( k < 10 );
|
|
|
|
#ifdef PLUTO
|
|
m_alloc_ptrs_clear(G, 1<<k);
|
|
#else
|
|
G = m_alloc_clear( (1<<k) * sizeof *G );
|
|
#endif
|
|
|
|
#ifdef USE_BARRETT
|
|
barrett_y = init_barrett( m, &barrett_k, &barrett_r1, &barrett_r2 );
|
|
#endif
|
|
/* and calculate */
|
|
tmp = mpi_alloc( mpi_get_nlimbs(m)+1 );
|
|
mpi_set_ui( res, 1 );
|
|
for(i = 1; i <= t; i++ ) {
|
|
barrett_mulm(tmp, res, res, m, barrett_y, barrett_k,
|
|
barrett_r1, barrett_r2 );
|
|
idx = build_index( exparray, k, i, t );
|
|
passert( idx >= 0 && idx < (1<<k) );
|
|
if( !G[idx] ) {
|
|
if( !idx )
|
|
G[0] = mpi_alloc_set_ui( 1 );
|
|
else {
|
|
for(j=0; j < k; j++ ) {
|
|
if( (idx & (1<<j) ) ) {
|
|
if( !G[idx] )
|
|
G[idx] = mpi_copy( basearray[j] );
|
|
else
|
|
barrett_mulm( G[idx], G[idx], basearray[j],
|
|
m, barrett_y, barrett_k, barrett_r1, barrett_r2 );
|
|
}
|
|
}
|
|
if( !G[idx] )
|
|
G[idx] = mpi_alloc(0);
|
|
}
|
|
}
|
|
barrett_mulm(res, tmp, G[idx], m, barrett_y, barrett_k, barrett_r1, barrett_r2 );
|
|
}
|
|
|
|
/* cleanup */
|
|
mpi_free(tmp);
|
|
#ifdef USE_BARRETT
|
|
mpi_free(barrett_y);
|
|
mpi_free(barrett_r1);
|
|
mpi_free(barrett_r2);
|
|
#endif
|
|
for(i=0; i < (1<<k); i++ )
|
|
mpi_free(G[i]);
|
|
m_free(G);
|
|
}
|
|
|
|
void
|
|
log_mpidump( const char *text UNUSED, MPI a )
|
|
{
|
|
/* Print number in hex -- helpful to see if they match bytes.
|
|
* Humans are not going to do arithmetic with the large numbers!
|
|
* Much code adapted from mpz_to_n.
|
|
*/
|
|
u_char buf[8048]; /* this ought to be big enough */
|
|
size_t len = (mpz_sizeinbase(a, 16) + 1) / 2; /* bytes */
|
|
MP_INT temp1, temp2;
|
|
int i;
|
|
|
|
passert(len <= sizeof(buf));
|
|
|
|
mpz_init(&temp1);
|
|
mpz_init(&temp2);
|
|
|
|
mpz_set(&temp1, a);
|
|
|
|
for (i = len-1; i >= 0; i--)
|
|
{
|
|
buf[i] = mpz_mdivmod_ui(&temp2, NULL, &temp1, 1 << BITS_PER_BYTE);
|
|
mpz_set(&temp1, &temp2);
|
|
}
|
|
|
|
passert(mpz_sgn(&temp1) == 0); /* we must have done all the bits */
|
|
mpz_clear(&temp1);
|
|
mpz_clear(&temp2);
|
|
|
|
#ifdef DEBUG
|
|
DBG_dump(text, buf, len);
|
|
#endif /* DEBUG */
|
|
}
|