mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-11-15 13:58:32 +00:00
Merge Phil Zimmermann's libzrtp as a FreeSWITCH library
Thanks to Phil Zimmermann for the code and for the license exception we needed to include it. There remains some build system integration work to be done before this code will build properly in the FreeSWITCH tree.
This commit is contained in:
commit
d2edcad66e
261 files changed
+86866
No files matched your search
Vendored
+232
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue 09/09/2006
|
||||
|
||||
This file contains the definitions required to use AES in C. See aesopt.h
|
||||
for optimisation details.
|
||||
*/
|
||||
|
||||
#ifndef __aes_h__
|
||||
#define __aes_h__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
//#include "zrtp_types.h"
|
||||
|
||||
/* This include is used to find 8 & 32 bit unsigned integer types */
|
||||
#include "brg_types.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef ZRTP_RESTRICT
|
||||
#define AES_128 /* define if AES with 128 bit keys is needed */
|
||||
#define AES_192 /* define if AES with 192 bit keys is needed */
|
||||
#define AES_256 /* define if AES with 256 bit keys is needed */
|
||||
#define AES_VAR /* define if a variable key size is needed */
|
||||
#define AES_MODES /* define if support is needed for modes */
|
||||
#else
|
||||
#define AES_128 /* define if AES with 128 bit keys is needed */
|
||||
#define AES_256 /* define if AES with 256 bit keys is needed */
|
||||
#define AES_MODES /* define if support is needed for modes */
|
||||
#endif //ZRTP_RESTRICT
|
||||
|
||||
/* The following must also be set in assembler files if being used */
|
||||
|
||||
#define AES_ENCRYPT /* if support for encryption is needed */
|
||||
|
||||
#ifndef ZRTP_RESTRICT
|
||||
#define AES_DECRYPT /* if support for decryption is needed */
|
||||
#define AES_ERR_CHK /* for parameter checks & error return codes */
|
||||
#define AES_REV_DKS /* define to reverse decryption key schedule */
|
||||
#else
|
||||
#define AES_DECRYPT /* if support for decryption is needed */
|
||||
#define AES_ERR_CHK /* for parameter checks & error return codes */
|
||||
#endif //ZRTP_RESTRICT
|
||||
|
||||
#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */
|
||||
#define N_COLS 4 /* the number of columns in the state */
|
||||
|
||||
/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */
|
||||
/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */
|
||||
/* or 44, 52 or 60 32-bit words. */
|
||||
|
||||
#if defined( AES_VAR ) || defined( AES_256 )
|
||||
#define KS_LENGTH 60
|
||||
#elif defined( AES_192 )
|
||||
#define KS_LENGTH 52
|
||||
#else
|
||||
#define KS_LENGTH 44
|
||||
#endif
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
#define AES_RETURN INT_RETURN
|
||||
#else
|
||||
#define AES_RETURN VOID_RETURN
|
||||
#endif
|
||||
|
||||
/* the character array 'inf' in the following structures is used */
|
||||
/* to hold AES context information. This AES code uses cx->inf.b[0] */
|
||||
/* to hold the number of rounds multiplied by 16. The other three */
|
||||
/* elements can be used by code that implements additional modes */
|
||||
|
||||
typedef union
|
||||
{ uint_32t l;
|
||||
uint_8t b[4];
|
||||
} aes_inf;
|
||||
|
||||
typedef struct
|
||||
{ uint_32t ks[KS_LENGTH];
|
||||
aes_inf inf;
|
||||
} aes_encrypt_ctx;
|
||||
|
||||
typedef struct
|
||||
{ uint_32t ks[KS_LENGTH];
|
||||
aes_inf inf;
|
||||
} aes_decrypt_ctx;
|
||||
|
||||
/* This routine must be called before first use if non-static */
|
||||
/* tables are being used */
|
||||
|
||||
AES_RETURN zrtp_bg_gen_tabs(void);
|
||||
|
||||
/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */
|
||||
/* those in the range 128 <= key_len <= 256 are given in bits */
|
||||
|
||||
#if defined( AES_ENCRYPT )
|
||||
|
||||
#if defined(AES_128) || defined(AES_VAR)
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined(AES_VAR)
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined(AES_VAR)
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_VAR)
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
AES_RETURN zrtp_bg_aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( AES_DECRYPT )
|
||||
|
||||
#if defined(AES_128) || defined(AES_VAR)
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined(AES_VAR)
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined(AES_VAR)
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined(AES_VAR)
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
AES_RETURN zrtp_bg_aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_MODES)
|
||||
|
||||
/* Multiple calls to the following subroutines for multiple block */
|
||||
/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */
|
||||
/* long messages incremantally provided that the context AND the iv */
|
||||
/* are preserved between all such calls. For the ECB and CBC modes */
|
||||
/* each individual call within a series of incremental calls must */
|
||||
/* process only full blocks (i.e. len must be a multiple of 16) but */
|
||||
/* the CFB, OFB and CTR mode calls can handle multiple incremental */
|
||||
/* calls of any length. Each mode is reset when a new AES key is */
|
||||
/* set but ECB and CBC operations can be reset without setting a */
|
||||
/* new key by setting a new IV value. To reset CFB, OFB and CTR */
|
||||
/* without setting the key, zrtp_bg_aes_mode_reset() must be called and the */
|
||||
/* IV must be set. NOTE: All these calls update the IV on exit so */
|
||||
/* this has to be reset if a new operation with the same IV as the */
|
||||
/* previous one is required (or decryption follows encryption with */
|
||||
/* the same IV array). */
|
||||
|
||||
AES_RETURN zrtp_bg_aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN zrtp_bg_aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_decrypt_ctx cx[1]);
|
||||
|
||||
#ifndef ZRTP_RESTRICT
|
||||
AES_RETURN zrtp_bg_aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN zrtp_bg_aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_decrypt_ctx cx[1]);
|
||||
#endif //ZRTP_RESTRICT
|
||||
|
||||
AES_RETURN zrtp_bg_aes_mode_reset(aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN zrtp_bg_aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN zrtp_bg_aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
|
||||
#ifndef ZRTP_RESTRICT
|
||||
#define zrtp_bg_aes_ofb_encrypt zrtp_bg_aes_ofb_crypt
|
||||
#define zrtp_bg_aes_ofb_decrypt zrtp_bg_aes_ofb_crypt
|
||||
|
||||
AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
|
||||
#endif //ZRTP_RESTRICT
|
||||
|
||||
typedef void cbuf_inc(unsigned char *cbuf);
|
||||
|
||||
#define zrtp_bg_aes_ctr_encrypt zrtp_bg_aes_ctr_crypt
|
||||
#define zrtp_bg_aes_ctr_decrypt zrtp_bg_aes_ctr_crypt
|
||||
|
||||
//[winfix]
|
||||
AES_RETURN zrtp_bg_aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+914
@@ -0,0 +1,914 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue 09/09/2006
|
||||
|
||||
These subroutines implement multiple block AES modes for ECB, CBC, CFB,
|
||||
OFB and CTR encryption, The code provides support for the VIA Advanced
|
||||
Cryptography Engine (ACE).
|
||||
|
||||
NOTE: In the following subroutines, the AES contexts (ctx) must be
|
||||
16 byte aligned if VIA ACE is being used
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined( AES_MODES )
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER ) && ( _MSC_VER > 800 )
|
||||
#pragma intrinsic(memcpy)
|
||||
#define in_line __inline
|
||||
#else
|
||||
#define in_line
|
||||
#endif
|
||||
|
||||
#define BFR_BLOCKS 8
|
||||
|
||||
/* These values are used to detect long word alignment in order to */
|
||||
/* speed up some buffer operations. This facility may not work on */
|
||||
/* some machines so this define can be commented out if necessary */
|
||||
|
||||
#define FAST_BUFFER_OPERATIONS
|
||||
|
||||
#define lp32(x) ((uint_32t*)(x))
|
||||
|
||||
//[{]
|
||||
|
||||
#if defined( _MSC_VER ) && ( _MSC_VER > 1200 )
|
||||
# define aligned_uint_8t(n) __declspec(align(n)) uint_8t _zrtp_bg_al_##n
|
||||
#elif defined( __GNUC__ ) || (__MWERKS__)
|
||||
# define aligned_uint_8t(n) uint_8t _zrtp_bg_al_##n __attribute__ ((aligned(n)))
|
||||
#else // disabled for VC6
|
||||
# undef FAST_BUFFER_OPERATIONS
|
||||
#endif
|
||||
|
||||
#ifdef FAST_BUFFER_OPERATIONS
|
||||
|
||||
aligned_uint_8t( 4); /* a variable that is 4 byte aligned */
|
||||
aligned_uint_8t(16); /* a variable that is 16 byte aligned */
|
||||
|
||||
#define addr_offset(x,n) (((uint_8t*)(x) - &_zrtp_bg_al_##n) & ((n) - 1))
|
||||
|
||||
#endif
|
||||
|
||||
//[}]
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
|
||||
#include "aes_via_ace.h"
|
||||
|
||||
#pragma pack(16)
|
||||
|
||||
aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA;
|
||||
aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA;
|
||||
aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA;
|
||||
aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA;
|
||||
aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA;
|
||||
aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA;
|
||||
|
||||
/* NOTE: These control word macros must only be used after */
|
||||
/* a key has been set up because they depend on key size */
|
||||
|
||||
#if NEH_KEY_TYPE == NEH_LOAD
|
||||
#define kd_adr(c) ((uint_8t*)(c)->ks)
|
||||
#elif NEH_KEY_TYPE == NEH_GENERATE
|
||||
#define kd_adr(c) ((uint_8t*)(c)->ks + (c)->inf.b[0])
|
||||
#else
|
||||
#define kd_adr(c) ((uint_8t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0))
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define aligned_array(type, name, no, stride) type name[no]
|
||||
#define aligned_auto(type, name, no, stride) type name[no]
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER ) && _MSC_VER > 1200
|
||||
|
||||
#define via_cwd(cwd, ty, dir, len) \
|
||||
unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4))
|
||||
|
||||
#else
|
||||
|
||||
#define via_cwd(cwd, ty, dir, len) \
|
||||
aligned_auto(unsigned long, cwd, 4, 16); \
|
||||
cwd[1] = cwd[2] = cwd[3] = 0; \
|
||||
cwd[0] = neh_##dir##_##ty##_key(len)
|
||||
|
||||
#endif
|
||||
|
||||
AES_RETURN zrtp_bg_aes_mode_reset(aes_encrypt_ctx ctx[1])
|
||||
{
|
||||
ctx->inf.b[2] = 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN zrtp_bg_aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_encrypt_ctx ctx[1])
|
||||
{ int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint_8t *ksp = (uint_8t*)(ctx->ks);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(addr_offset( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(!addr_offset( ibuf, 16 ) && !addr_offset( obuf, 16 ))
|
||||
{
|
||||
via_ecb_op5(ksp,cwd,ibuf,obuf,nb);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (addr_offset( ibuf, 16 ) ? buf : (uint_8t*)ibuf);
|
||||
op = (addr_offset( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ecb_op5(ksp,cwd,ip,op,m);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
while(nb--)
|
||||
{
|
||||
zrtp_bg_aes_encrypt(ibuf, obuf, ctx);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN zrtp_bg_aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_decrypt_ctx ctx[1])
|
||||
{ int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint_8t *ksp = kd_adr(ctx);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(addr_offset( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(!addr_offset( ibuf, 16 ) && !addr_offset( obuf, 16 ))
|
||||
{
|
||||
via_ecb_op5(ksp,cwd,ibuf,obuf,nb);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (addr_offset( ibuf, 16 ) ? buf : (uint_8t*)ibuf);
|
||||
op = (addr_offset( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ecb_op5(ksp,cwd,ip,op,m);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
while(nb--)
|
||||
{
|
||||
zrtp_bg_aes_decrypt(ibuf, obuf, ctx);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef ZRTP_RESTRICT
|
||||
AES_RETURN zrtp_bg_aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_encrypt_ctx ctx[1])
|
||||
{ int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(addr_offset( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(addr_offset( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!addr_offset( ibuf, 16 ) && !addr_offset( obuf, 16 ) && !addr_offset( iv, 16 ))
|
||||
{
|
||||
via_cbc_op7(ksp,cwd,ibuf,obuf,nb,ivp,ivp);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (addr_offset( ibuf, 16 ) ? buf : (uint_8t*)ibuf);
|
||||
op = (addr_offset( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cbc_op7(ksp,cwd,ip,op,m,ivp,ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
if(iv != ivp)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!addr_offset( ibuf, 4 ) && !addr_offset( iv, 4 ))
|
||||
while(nb--)
|
||||
{
|
||||
lp32(iv)[0] ^= lp32(ibuf)[0];
|
||||
lp32(iv)[1] ^= lp32(ibuf)[1];
|
||||
lp32(iv)[2] ^= lp32(ibuf)[2];
|
||||
lp32(iv)[3] ^= lp32(ibuf)[3];
|
||||
zrtp_bg_aes_encrypt(iv, iv, ctx);
|
||||
memcpy(obuf, iv, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(nb--)
|
||||
{
|
||||
iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1];
|
||||
iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3];
|
||||
iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5];
|
||||
iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7];
|
||||
iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9];
|
||||
iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11];
|
||||
iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13];
|
||||
iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15];
|
||||
zrtp_bg_aes_encrypt(iv, iv, ctx);
|
||||
memcpy(obuf, iv, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN zrtp_bg_aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_decrypt_ctx ctx[1])
|
||||
{ unsigned char tmp[AES_BLOCK_SIZE];
|
||||
int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint_8t *ksp = kd_adr(ctx), *ivp = iv;
|
||||
aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(addr_offset( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(addr_offset( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!addr_offset( ibuf, 16 ) && !addr_offset( obuf, 16 ) && !addr_offset( iv, 16 ))
|
||||
{
|
||||
via_cbc_op6(ksp,cwd,ibuf,obuf,nb,ivp);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (addr_offset( ibuf, 16 ) ? buf : (uint_8t*)ibuf);
|
||||
op = (addr_offset( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cbc_op6(ksp,cwd,ip,op,m,ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
if(iv != ivp)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!addr_offset( obuf, 4 ) && !addr_offset( iv, 4 ))
|
||||
while(nb--)
|
||||
{
|
||||
memcpy(tmp, ibuf, AES_BLOCK_SIZE);
|
||||
zrtp_bg_aes_decrypt(ibuf, obuf, ctx);
|
||||
lp32(obuf)[0] ^= lp32(iv)[0];
|
||||
lp32(obuf)[1] ^= lp32(iv)[1];
|
||||
lp32(obuf)[2] ^= lp32(iv)[2];
|
||||
lp32(obuf)[3] ^= lp32(iv)[3];
|
||||
memcpy(iv, tmp, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(nb--)
|
||||
{
|
||||
memcpy(tmp, ibuf, AES_BLOCK_SIZE);
|
||||
zrtp_bg_aes_decrypt(ibuf, obuf, ctx);
|
||||
obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1];
|
||||
obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3];
|
||||
obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5];
|
||||
obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7];
|
||||
obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9];
|
||||
obuf[10] ^= iv[10]; obuf[11] ^= iv[11];
|
||||
obuf[12] ^= iv[12]; obuf[13] ^= iv[13];
|
||||
obuf[14] ^= iv[14]; obuf[15] ^= iv[15];
|
||||
memcpy(iv, tmp, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif //ZRTP_RESTRICT
|
||||
|
||||
AES_RETURN zrtp_bg_aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
|
||||
{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len)
|
||||
*obuf++ = iv[b_pos++] ^= *ibuf++, cnt++;
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ int m;
|
||||
uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(addr_offset( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(addr_offset( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!addr_offset( ibuf, 16 ) && !addr_offset( obuf, 16 ))
|
||||
{
|
||||
via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
}
|
||||
else /* input, output or both are unaligned */
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (addr_offset( ibuf, 16 ) ? buf : (uint_8t*)ibuf);
|
||||
op = (addr_offset( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!addr_offset( ibuf, 4 ) && !addr_offset( obuf, 4 ) && !addr_offset( iv, 4 ))
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
zrtp_bg_aes_encrypt(iv, iv, ctx);
|
||||
lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0];
|
||||
lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1];
|
||||
lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2];
|
||||
lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
zrtp_bg_aes_encrypt(iv, iv, ctx);
|
||||
obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1];
|
||||
obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3];
|
||||
obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5];
|
||||
obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7];
|
||||
obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9];
|
||||
obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11];
|
||||
obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13];
|
||||
obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len)
|
||||
{
|
||||
if(!b_pos)
|
||||
zrtp_bg_aes_ecb_encrypt(iv, iv, AES_BLOCK_SIZE, ctx);
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE)
|
||||
*obuf++ = iv[b_pos++] ^= *ibuf++, cnt++;
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint_8t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN zrtp_bg_aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
|
||||
{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{ uint_8t t;
|
||||
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len)
|
||||
t = *ibuf++, *obuf++ = t ^ iv[b_pos], iv[b_pos++] = t, cnt++;
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ int m;
|
||||
uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(addr_offset( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(addr_offset( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!addr_offset( ibuf, 16 ) && !addr_offset( obuf, 16 ))
|
||||
{
|
||||
via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
}
|
||||
else /* input, output or both are unaligned */
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (addr_offset( ibuf, 16 ) ? buf : (uint_8t*)ibuf);
|
||||
op = (addr_offset( obuf, 16 ) ? buf : op);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cfb_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!addr_offset( ibuf, 4 ) && !addr_offset( obuf, 4 ) &&!addr_offset( iv, 4 ))
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{ uint_32t t;
|
||||
|
||||
assert(b_pos == 0);
|
||||
zrtp_bg_aes_encrypt(iv, iv, ctx);
|
||||
t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t;
|
||||
t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t;
|
||||
t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t;
|
||||
t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{ uint_8t t;
|
||||
|
||||
assert(b_pos == 0);
|
||||
zrtp_bg_aes_encrypt(iv, iv, ctx);
|
||||
t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t;
|
||||
t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t;
|
||||
t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t;
|
||||
t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t;
|
||||
t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t;
|
||||
t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t;
|
||||
t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t;
|
||||
t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t;
|
||||
t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t;
|
||||
t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t;
|
||||
t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t;
|
||||
t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t;
|
||||
t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t;
|
||||
t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t;
|
||||
t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t;
|
||||
t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len)
|
||||
{ uint_8t t;
|
||||
|
||||
if(!b_pos)
|
||||
zrtp_bg_aes_ecb_encrypt(iv, iv, AES_BLOCK_SIZE, ctx);
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE)
|
||||
t = *ibuf++, *obuf++ = t ^ iv[b_pos], iv[b_pos++] = t, cnt++;
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint_8t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef ZRTP_RESTRICT
|
||||
AES_RETURN zrtp_bg_aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
|
||||
{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len)
|
||||
*obuf++ = iv[b_pos++] ^ *ibuf++, cnt++;
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ int m;
|
||||
uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(addr_offset( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(addr_offset( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!addr_offset( ibuf, 16 ) && !addr_offset( obuf, 16 ))
|
||||
{
|
||||
via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
}
|
||||
else /* input, output or both are unaligned */
|
||||
{ aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint_8t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (addr_offset( ibuf, 16 ) ? buf : (uint_8t*)ibuf);
|
||||
op = (addr_offset( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ofb_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!addr_offset( ibuf, 4 ) && !addr_offset( obuf, 4 ) && !addr_offset( iv, 4 ))
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
zrtp_bg_aes_encrypt(iv, iv, ctx);
|
||||
lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0];
|
||||
lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1];
|
||||
lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2];
|
||||
lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
zrtp_bg_aes_encrypt(iv, iv, ctx);
|
||||
obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1];
|
||||
obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3];
|
||||
obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5];
|
||||
obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7];
|
||||
obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9];
|
||||
obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11];
|
||||
obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13];
|
||||
obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len)
|
||||
{
|
||||
if(!b_pos)
|
||||
zrtp_bg_aes_ecb_encrypt(iv, iv, AES_BLOCK_SIZE, ctx);
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE)
|
||||
*obuf++ = iv[b_pos++] ^ *ibuf++, cnt++;
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint_8t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif //ZRTP_RESTRICT
|
||||
|
||||
#define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE)
|
||||
|
||||
AES_RETURN zrtp_bg_aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1])
|
||||
{ uint_8t *ip;
|
||||
int i, blen, b_pos = (int)(ctx->inf.b[2]);
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
aligned_auto(uint_8t, buf, BFR_LENGTH, 16);
|
||||
if(ctx->inf.b[1] == 0xff && addr_offset( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
#else
|
||||
uint_8t buf[BFR_LENGTH];
|
||||
#endif
|
||||
|
||||
if(b_pos)
|
||||
{
|
||||
memcpy(buf, cbuf, AES_BLOCK_SIZE);
|
||||
zrtp_bg_aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx);
|
||||
while(b_pos < AES_BLOCK_SIZE && len)
|
||||
*obuf++ = *ibuf++ ^ buf[b_pos++], --len;
|
||||
if(len)
|
||||
ctr_inc(cbuf), b_pos = 0;
|
||||
}
|
||||
|
||||
while(len)
|
||||
{
|
||||
blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen;
|
||||
|
||||
for(i = 0, ip = buf; i < (blen >> 4); ++i)
|
||||
{
|
||||
memcpy(ip, cbuf, AES_BLOCK_SIZE);
|
||||
ctr_inc(cbuf);
|
||||
ip += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if(blen & (AES_BLOCK_SIZE - 1))
|
||||
memcpy(ip, cbuf, AES_BLOCK_SIZE), i++;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
via_ecb_op5((ctx->ks),cwd,buf,buf,i);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
zrtp_bg_aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx);
|
||||
|
||||
i = 0; ip = buf;
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!addr_offset( ibuf, 4 ) && !addr_offset( obuf, 4 ) && !addr_offset( ip, 4 ))
|
||||
while(i + AES_BLOCK_SIZE <= blen)
|
||||
{
|
||||
lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0];
|
||||
lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1];
|
||||
lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2];
|
||||
lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3];
|
||||
i += AES_BLOCK_SIZE;
|
||||
ip += AES_BLOCK_SIZE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while(i + AES_BLOCK_SIZE <= blen)
|
||||
{
|
||||
obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1];
|
||||
obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3];
|
||||
obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5];
|
||||
obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7];
|
||||
obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9];
|
||||
obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11];
|
||||
obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13];
|
||||
obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15];
|
||||
i += AES_BLOCK_SIZE;
|
||||
ip += AES_BLOCK_SIZE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
while(i++ < blen)
|
||||
*obuf++ = *ibuf++ ^ ip[b_pos++];
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint_8t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+316
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue 09/09/2006
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
#include "aestab.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c])
|
||||
#define so(y,x,c) word_out(y, c, s(x,c))
|
||||
|
||||
#if defined(ARRAYS)
|
||||
#define locals(y,x) x[4],y[4]
|
||||
#else
|
||||
#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
|
||||
#endif
|
||||
|
||||
#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
|
||||
s(y,2) = s(x,2); s(y,3) = s(x,3);
|
||||
#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
|
||||
#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
|
||||
#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
|
||||
|
||||
#if ( FUNCS_IN_C & ENCRYPTION_IN_C )
|
||||
|
||||
/* Visual C++ .Net v7.1 provides the fastest encryption code when using
|
||||
Pentium optimiation with small code but this is poor for decryption
|
||||
so we need to control this with the following VC++ pragmas
|
||||
*/
|
||||
|
||||
#if defined( _MSC_VER ) && !defined( _WIN64 )
|
||||
#pragma optimize( "s", on )
|
||||
#endif
|
||||
|
||||
/* Given the column (c) of the output state variable, the following
|
||||
macros give the input state variables which are needed in its
|
||||
computation for each row (r) of the state. All the alternative
|
||||
macros give the same end values but expand into different ways
|
||||
of calculating these values. In particular the complex macro
|
||||
used for dynamically variable block sizes is designed to expand
|
||||
to a compile time constant whenever possible but will expand to
|
||||
conditional clauses on some branches (I am grateful to Frank
|
||||
Yellin for this construction)
|
||||
*/
|
||||
|
||||
#define fwd_var(x,r,c)\
|
||||
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
|
||||
: r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
|
||||
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
|
||||
: ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
|
||||
|
||||
#if defined(FT4_SET)
|
||||
#undef dec_fmvars
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
|
||||
#elif defined(FT1_SET)
|
||||
#undef dec_fmvars
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c))
|
||||
#else
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c)))
|
||||
#endif
|
||||
|
||||
#if defined(FL4_SET)
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c))
|
||||
#elif defined(FL1_SET)
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c))
|
||||
#else
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c))
|
||||
#endif
|
||||
|
||||
AES_RETURN zrtp_bg_aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1])
|
||||
{ uint_32t locals(b0, b1);
|
||||
const uint_32t *kp;
|
||||
#if defined( dec_fmvars )
|
||||
dec_fmvars; /* declare variables for fwd_mcol() if needed */
|
||||
#endif
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 )
|
||||
return EXIT_FAILURE;
|
||||
#endif
|
||||
|
||||
kp = cx->ks;
|
||||
state_in(b0, in, kp);
|
||||
|
||||
#if (ENC_UNROLL == FULL)
|
||||
|
||||
switch(cx->inf.b[0])
|
||||
{
|
||||
case 14 * 16:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
kp += 2 * N_COLS;
|
||||
case 12 * 16:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
kp += 2 * N_COLS;
|
||||
case 10 * 16:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 3 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 4 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 5 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 6 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 7 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 8 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 9 * N_COLS);
|
||||
round(fwd_lrnd, b0, b1, kp +10 * N_COLS);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (ENC_UNROLL == PARTIAL)
|
||||
{ uint_32t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd)
|
||||
{
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b0, b1, kp);
|
||||
}
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
#else
|
||||
{ uint_32t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd)
|
||||
{
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
l_copy(b0, b1);
|
||||
}
|
||||
#endif
|
||||
kp += N_COLS;
|
||||
round(fwd_lrnd, b0, b1, kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
state_out(out, b0);
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if ( FUNCS_IN_C & DECRYPTION_IN_C)
|
||||
|
||||
/* Visual C++ .Net v7.1 provides the fastest encryption code when using
|
||||
Pentium optimiation with small code but this is poor for decryption
|
||||
so we need to control this with the following VC++ pragmas
|
||||
*/
|
||||
|
||||
#if defined( _MSC_VER ) && !defined( _WIN64 )
|
||||
#pragma optimize( "t", on )
|
||||
#endif
|
||||
|
||||
/* Given the column (c) of the output state variable, the following
|
||||
macros give the input state variables which are needed in its
|
||||
computation for each row (r) of the state. All the alternative
|
||||
macros give the same end values but expand into different ways
|
||||
of calculating these values. In particular the complex macro
|
||||
used for dynamically variable block sizes is designed to expand
|
||||
to a compile time constant whenever possible but will expand to
|
||||
conditional clauses on some branches (I am grateful to Frank
|
||||
Yellin for this construction)
|
||||
*/
|
||||
|
||||
#define inv_var(x,r,c)\
|
||||
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
|
||||
: r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\
|
||||
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
|
||||
: ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0)))
|
||||
|
||||
#if defined(IT4_SET)
|
||||
#undef dec_imvars
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c))
|
||||
#elif defined(IT1_SET)
|
||||
#undef dec_imvars
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c))
|
||||
#else
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)))
|
||||
#endif
|
||||
|
||||
#if defined(IL4_SET)
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c))
|
||||
#elif defined(IL1_SET)
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c))
|
||||
#else
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))
|
||||
#endif
|
||||
|
||||
/* This code can work with the decryption key schedule in the */
|
||||
/* order that is used for encrytpion (where the 1st decryption */
|
||||
/* round key is at the high end ot the schedule) or with a key */
|
||||
/* schedule that has been reversed to put the 1st decryption */
|
||||
/* round key at the low end of the schedule in memory (when */
|
||||
/* AES_REV_DKS is defined) */
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
#define key_ofs 0
|
||||
#define rnd_key(n) (kp + n * N_COLS)
|
||||
#else
|
||||
#define key_ofs 1
|
||||
#define rnd_key(n) (kp - n * N_COLS)
|
||||
#endif
|
||||
|
||||
AES_RETURN zrtp_bg_aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1])
|
||||
{ uint_32t locals(b0, b1);
|
||||
#if defined( dec_imvars )
|
||||
dec_imvars; /* declare variables for inv_mcol() if needed */
|
||||
#endif
|
||||
const uint_32t *kp;
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 )
|
||||
return EXIT_FAILURE;
|
||||
#endif
|
||||
|
||||
kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0);
|
||||
state_in(b0, in, kp);
|
||||
|
||||
#if (DEC_UNROLL == FULL)
|
||||
|
||||
kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2));
|
||||
switch(cx->inf.b[0])
|
||||
{
|
||||
case 14 * 16:
|
||||
round(inv_rnd, b1, b0, rnd_key(-13));
|
||||
round(inv_rnd, b0, b1, rnd_key(-12));
|
||||
case 12 * 16:
|
||||
round(inv_rnd, b1, b0, rnd_key(-11));
|
||||
round(inv_rnd, b0, b1, rnd_key(-10));
|
||||
case 10 * 16:
|
||||
round(inv_rnd, b1, b0, rnd_key(-9));
|
||||
round(inv_rnd, b0, b1, rnd_key(-8));
|
||||
round(inv_rnd, b1, b0, rnd_key(-7));
|
||||
round(inv_rnd, b0, b1, rnd_key(-6));
|
||||
round(inv_rnd, b1, b0, rnd_key(-5));
|
||||
round(inv_rnd, b0, b1, rnd_key(-4));
|
||||
round(inv_rnd, b1, b0, rnd_key(-3));
|
||||
round(inv_rnd, b0, b1, rnd_key(-2));
|
||||
round(inv_rnd, b1, b0, rnd_key(-1));
|
||||
round(inv_lrnd, b0, b1, rnd_key( 0));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (DEC_UNROLL == PARTIAL)
|
||||
{ uint_32t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd)
|
||||
{
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b0, b1, kp);
|
||||
}
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
#else
|
||||
{ uint_32t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd)
|
||||
{
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
l_copy(b0, b1);
|
||||
}
|
||||
#endif
|
||||
kp = rnd_key(1);
|
||||
round(inv_lrnd, b0, b1, kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
state_out(out, b0);
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
+578
@@ -0,0 +1,578 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue 09/09/2006
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
#include "aestab.h"
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
# include "aes_via_ace.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Initialise the key schedule from the user supplied key. The key
|
||||
length can be specified in bytes, with legal values of 16, 24
|
||||
and 32, or in bits, with legal values of 128, 192 and 256. These
|
||||
values correspond with Nk values of 4, 6 and 8 respectively.
|
||||
|
||||
The following macros implement a single cycle in the key
|
||||
schedule generation process. The number of cycles needed
|
||||
for each cx->n_col and nk value is:
|
||||
|
||||
nk = 4 5 6 7 8
|
||||
------------------------------
|
||||
cx->n_col = 4 10 9 8 7 7
|
||||
cx->n_col = 5 14 11 10 9 9
|
||||
cx->n_col = 6 19 15 12 11 11
|
||||
cx->n_col = 7 21 19 16 13 14
|
||||
cx->n_col = 8 29 23 19 17 14
|
||||
*/
|
||||
|
||||
#if (FUNCS_IN_C & ENC_KEYING_IN_C)
|
||||
|
||||
#if defined(AES_128) || defined(AES_VAR)
|
||||
|
||||
#define ke4(k,i) \
|
||||
{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
|
||||
k[4*(i)+5] = ss[1] ^= ss[0]; \
|
||||
k[4*(i)+6] = ss[2] ^= ss[1]; \
|
||||
k[4*(i)+7] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1])
|
||||
{ uint_32t ss[4];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
|
||||
#if ENC_UNROLL == NONE
|
||||
{ uint_32t i;
|
||||
for(i = 0; i < 9; ++i)
|
||||
ke4(cx->ks, i);
|
||||
}
|
||||
#else
|
||||
ke4(cx->ks, 0); ke4(cx->ks, 1);
|
||||
ke4(cx->ks, 2); ke4(cx->ks, 3);
|
||||
ke4(cx->ks, 4); ke4(cx->ks, 5);
|
||||
ke4(cx->ks, 6); ke4(cx->ks, 7);
|
||||
ke4(cx->ks, 8);
|
||||
#endif
|
||||
ke4(cx->ks, 9);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 10 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined(AES_VAR)
|
||||
|
||||
#define kef6(k,i) \
|
||||
{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
|
||||
k[6*(i)+ 7] = ss[1] ^= ss[0]; \
|
||||
k[6*(i)+ 8] = ss[2] ^= ss[1]; \
|
||||
k[6*(i)+ 9] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke6(k,i) \
|
||||
{ kef6(k,i); \
|
||||
k[6*(i)+10] = ss[4] ^= ss[3]; \
|
||||
k[6*(i)+11] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1])
|
||||
{ uint_32t ss[6];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
cx->ks[4] = ss[4] = word_in(key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(key, 5);
|
||||
|
||||
#if ENC_UNROLL == NONE
|
||||
{ uint_32t i;
|
||||
for(i = 0; i < 7; ++i)
|
||||
ke6(cx->ks, i);
|
||||
}
|
||||
#else
|
||||
ke6(cx->ks, 0); ke6(cx->ks, 1);
|
||||
ke6(cx->ks, 2); ke6(cx->ks, 3);
|
||||
ke6(cx->ks, 4); ke6(cx->ks, 5);
|
||||
ke6(cx->ks, 6);
|
||||
#endif
|
||||
kef6(cx->ks, 7);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 12 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined(AES_VAR)
|
||||
|
||||
#define kef8(k,i) \
|
||||
{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
|
||||
k[8*(i)+ 9] = ss[1] ^= ss[0]; \
|
||||
k[8*(i)+10] = ss[2] ^= ss[1]; \
|
||||
k[8*(i)+11] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke8(k,i) \
|
||||
{ kef8(k,i); \
|
||||
k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \
|
||||
k[8*(i)+13] = ss[5] ^= ss[4]; \
|
||||
k[8*(i)+14] = ss[6] ^= ss[5]; \
|
||||
k[8*(i)+15] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1])
|
||||
{ uint_32t ss[8];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
cx->ks[4] = ss[4] = word_in(key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(key, 5);
|
||||
cx->ks[6] = ss[6] = word_in(key, 6);
|
||||
cx->ks[7] = ss[7] = word_in(key, 7);
|
||||
|
||||
#if ENC_UNROLL == NONE
|
||||
{ uint_32t i;
|
||||
for(i = 0; i < 6; ++i)
|
||||
ke8(cx->ks, i);
|
||||
}
|
||||
#else
|
||||
ke8(cx->ks, 0); ke8(cx->ks, 1);
|
||||
ke8(cx->ks, 2); ke8(cx->ks, 3);
|
||||
ke8(cx->ks, 4); ke8(cx->ks, 5);
|
||||
#endif
|
||||
kef8(cx->ks, 6);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 14 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_VAR)
|
||||
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1])
|
||||
{
|
||||
switch(key_len)
|
||||
{
|
||||
#if defined( AES_ERR_CHK )
|
||||
case 16: case 128: return zrtp_bg_aes_encrypt_key128(key, cx);
|
||||
case 24: case 192: return zrtp_bg_aes_encrypt_key192(key, cx);
|
||||
case 32: case 256: return zrtp_bg_aes_encrypt_key256(key, cx);
|
||||
default: return EXIT_FAILURE;
|
||||
#else
|
||||
case 16: case 128: zrtp_bg_aes_encrypt_key128(key, cx); return;
|
||||
case 24: case 192: zrtp_bg_aes_encrypt_key192(key, cx); return;
|
||||
case 32: case 256: zrtp_bg_aes_encrypt_key256(key, cx); return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if (FUNCS_IN_C & DEC_KEYING_IN_C)
|
||||
|
||||
/* this is used to store the decryption round keys */
|
||||
/* in forward or reverse order */
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
#define v(n,i) ((n) - (i) + 2 * ((i) & 3))
|
||||
#else
|
||||
#define v(n,i) (i)
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES
|
||||
#define ff(x) (x)
|
||||
#else
|
||||
#define ff(x) inv_mcol(x)
|
||||
#if defined( dec_imvars )
|
||||
#define d_vars dec_imvars
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(AES_128) || defined(AES_VAR)
|
||||
|
||||
#define k4e(k,i) \
|
||||
{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
|
||||
k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \
|
||||
k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \
|
||||
k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
#define kdf4(k,i) \
|
||||
{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \
|
||||
ss[1] = ss[1] ^ ss[3]; \
|
||||
ss[2] = ss[2] ^ ss[3]; \
|
||||
ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; \
|
||||
ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \
|
||||
}
|
||||
|
||||
#define kd4(k,i) \
|
||||
{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \
|
||||
k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \
|
||||
k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \
|
||||
k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \
|
||||
k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \
|
||||
}
|
||||
|
||||
#define kdl4(k,i) \
|
||||
{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \
|
||||
k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \
|
||||
k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \
|
||||
k[v(40,(4*(i))+6)] = ss[0]; \
|
||||
k[v(40,(4*(i))+7)] = ss[1]; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define kdf4(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \
|
||||
}
|
||||
|
||||
#define kd4(k,i) \
|
||||
{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \
|
||||
ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \
|
||||
ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \
|
||||
ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \
|
||||
}
|
||||
|
||||
#define kdl4(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1])
|
||||
{ uint_32t ss[5];
|
||||
#if defined( d_vars )
|
||||
d_vars;
|
||||
#endif
|
||||
cx->ks[v(40,(0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(40,(1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(40,(2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(40,(3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#if DEC_UNROLL == NONE
|
||||
{ uint_32t i;
|
||||
for(i = 0; i < 10; ++i)
|
||||
k4e(cx->ks, i);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 10 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
kdf4(cx->ks, 0); kd4(cx->ks, 1);
|
||||
kd4(cx->ks, 2); kd4(cx->ks, 3);
|
||||
kd4(cx->ks, 4); kd4(cx->ks, 5);
|
||||
kd4(cx->ks, 6); kd4(cx->ks, 7);
|
||||
kd4(cx->ks, 8); kdl4(cx->ks, 9);
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 10 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined(AES_VAR)
|
||||
|
||||
#define k6ef(k,i) \
|
||||
{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
|
||||
k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \
|
||||
k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \
|
||||
k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define k6e(k,i) \
|
||||
{ k6ef(k,i); \
|
||||
k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \
|
||||
k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
|
||||
#define kdf6(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \
|
||||
ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \
|
||||
ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \
|
||||
}
|
||||
|
||||
#define kd6(k,i) \
|
||||
{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \
|
||||
ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \
|
||||
ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \
|
||||
ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \
|
||||
ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \
|
||||
ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \
|
||||
}
|
||||
|
||||
#define kdl6(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \
|
||||
}
|
||||
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1])
|
||||
{ uint_32t ss[7];
|
||||
#if defined( d_vars )
|
||||
d_vars;
|
||||
#endif
|
||||
cx->ks[v(48,(0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(48,(1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(48,(2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(48,(3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#if DEC_UNROLL == NONE
|
||||
cx->ks[v(48,(4))] = ss[4] = word_in(key, 4);
|
||||
cx->ks[v(48,(5))] = ss[5] = word_in(key, 5);
|
||||
{ uint_32t i;
|
||||
|
||||
for(i = 0; i < 7; ++i)
|
||||
k6e(cx->ks, i);
|
||||
k6ef(cx->ks, 7);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 12 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4));
|
||||
cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5));
|
||||
kdf6(cx->ks, 0); kd6(cx->ks, 1);
|
||||
kd6(cx->ks, 2); kd6(cx->ks, 3);
|
||||
kd6(cx->ks, 4); kd6(cx->ks, 5);
|
||||
kd6(cx->ks, 6); kdl6(cx->ks, 7);
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 12 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined(AES_VAR)
|
||||
|
||||
#define k8ef(k,i) \
|
||||
{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
|
||||
k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \
|
||||
k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \
|
||||
k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define k8e(k,i) \
|
||||
{ k8ef(k,i); \
|
||||
k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \
|
||||
k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \
|
||||
k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \
|
||||
k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
|
||||
#define kdf8(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \
|
||||
ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \
|
||||
ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \
|
||||
ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \
|
||||
ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \
|
||||
}
|
||||
|
||||
#define kd8(k,i) \
|
||||
{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \
|
||||
ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \
|
||||
ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \
|
||||
ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \
|
||||
ss[8] = ls_box(ss[3],0); \
|
||||
ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \
|
||||
ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \
|
||||
ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \
|
||||
ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \
|
||||
}
|
||||
|
||||
#define kdl8(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \
|
||||
}
|
||||
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1])
|
||||
{ uint_32t ss[9];
|
||||
#if defined( d_vars )
|
||||
d_vars;
|
||||
#endif
|
||||
cx->ks[v(56,(0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(56,(1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(56,(2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(56,(3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#if DEC_UNROLL == NONE
|
||||
cx->ks[v(56,(4))] = ss[4] = word_in(key, 4);
|
||||
cx->ks[v(56,(5))] = ss[5] = word_in(key, 5);
|
||||
cx->ks[v(56,(6))] = ss[6] = word_in(key, 6);
|
||||
cx->ks[v(56,(7))] = ss[7] = word_in(key, 7);
|
||||
{ uint_32t i;
|
||||
|
||||
for(i = 0; i < 6; ++i)
|
||||
k8e(cx->ks, i);
|
||||
k8ef(cx->ks, 6);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 14 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4));
|
||||
cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5));
|
||||
cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6));
|
||||
cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7));
|
||||
kdf8(cx->ks, 0); kd8(cx->ks, 1);
|
||||
kd8(cx->ks, 2); kd8(cx->ks, 3);
|
||||
kd8(cx->ks, 4); kd8(cx->ks, 5);
|
||||
kdl8(cx->ks, 6);
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 14 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
|
||||
#if defined( AES_ERR_CHK )
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_VAR)
|
||||
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1])
|
||||
{
|
||||
switch(key_len)
|
||||
{
|
||||
#if defined( AES_ERR_CHK )
|
||||
case 16: case 128: return zrtp_bg_aes_decrypt_key128(key, cx);
|
||||
case 24: case 192: return zrtp_bg_aes_decrypt_key192(key, cx);
|
||||
case 32: case 256: return zrtp_bg_aes_decrypt_key256(key, cx);
|
||||
default: return EXIT_FAILURE;
|
||||
#else
|
||||
case 16: case 128: zrtp_bg_aes_decrypt_key128(key, cx); return;
|
||||
case 24: case 192: zrtp_bg_aes_decrypt_key192(key, cx); return;
|
||||
case 32: case 256: zrtp_bg_aes_decrypt_key256(key, cx); return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
+728
@@ -0,0 +1,728 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue 09/09/2006
|
||||
|
||||
This file contains the compilation options for AES (Rijndael) and code
|
||||
that is common across encryption, key scheduling and table generation.
|
||||
|
||||
OPERATION
|
||||
|
||||
These source code files implement the AES algorithm Rijndael designed by
|
||||
Joan Daemen and Vincent Rijmen. This version is designed for the standard
|
||||
block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24
|
||||
and 32 bytes).
|
||||
|
||||
This version is designed for flexibility and speed using operations on
|
||||
32-bit words rather than operations on bytes. It can be compiled with
|
||||
either big or little endian internal byte order but is faster when the
|
||||
native byte order for the processor is used.
|
||||
|
||||
THE CIPHER INTERFACE
|
||||
|
||||
The cipher interface is implemented as an array of bytes in which lower
|
||||
AES bit sequence indexes map to higher numeric significance within bytes.
|
||||
|
||||
uint_8t (an unsigned 8-bit type)
|
||||
uint_32t (an unsigned 32-bit type)
|
||||
struct aes_encrypt_ctx (structure for the cipher encryption context)
|
||||
struct aes_decrypt_ctx (structure for the cipher decryption context)
|
||||
AES_RETURN the function return type
|
||||
|
||||
C subroutine calls:
|
||||
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN zrtp_bg_aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN zrtp_bg_aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out,
|
||||
const aes_decrypt_ctx cx[1]);
|
||||
|
||||
IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that
|
||||
you call zrtp_bg_gen_tabs() before AES is used so that the tables are initialised.
|
||||
|
||||
C++ aes class subroutines:
|
||||
|
||||
Class AESencrypt for encryption
|
||||
|
||||
Construtors:
|
||||
AESencrypt(void)
|
||||
AESencrypt(const unsigned char *key) - 128 bit key
|
||||
Members:
|
||||
AES_RETURN key128(const unsigned char *key)
|
||||
AES_RETURN key192(const unsigned char *key)
|
||||
AES_RETURN key256(const unsigned char *key)
|
||||
AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const
|
||||
|
||||
Class AESdecrypt for encryption
|
||||
Construtors:
|
||||
AESdecrypt(void)
|
||||
AESdecrypt(const unsigned char *key) - 128 bit key
|
||||
Members:
|
||||
AES_RETURN key128(const unsigned char *key)
|
||||
AES_RETURN key192(const unsigned char *key)
|
||||
AES_RETURN key256(const unsigned char *key)
|
||||
AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const
|
||||
*/
|
||||
|
||||
#ifdef _AESOPT_H
|
||||
#warning "_AESOPT_H already defined. aesopt.h will not be included"
|
||||
#endif
|
||||
|
||||
#if !defined( _AESOPT_H )
|
||||
#define _AESOPT_H
|
||||
|
||||
#if defined( __cplusplus )
|
||||
#include "aescpp.h"
|
||||
#else
|
||||
#include "aes.h"
|
||||
#endif
|
||||
|
||||
/* PLATFORM SPECIFIC INCLUDES */
|
||||
|
||||
//#include "brg_endian.h"
|
||||
#include "bg2zrtp.h"
|
||||
|
||||
/* CONFIGURATION - THE USE OF DEFINES
|
||||
|
||||
Later in this section there are a number of defines that control the
|
||||
operation of the code. In each section, the purpose of each define is
|
||||
explained so that the relevant form can be included or excluded by
|
||||
setting either 1's or 0's respectively on the branches of the related
|
||||
#if clauses. The following local defines should not be changed.
|
||||
*/
|
||||
|
||||
#define ENCRYPTION_IN_C 1
|
||||
#define DECRYPTION_IN_C 2
|
||||
#define ENC_KEYING_IN_C 4
|
||||
#define DEC_KEYING_IN_C 8
|
||||
|
||||
#define NO_TABLES 0
|
||||
#define ONE_TABLE 1
|
||||
#define FOUR_TABLES 4
|
||||
#define NONE 0
|
||||
#define PARTIAL 1
|
||||
#define FULL 2
|
||||
|
||||
/* --- START OF USER CONFIGURED OPTIONS --- */
|
||||
|
||||
/* 1. BYTE ORDER WITHIN 32 BIT WORDS
|
||||
|
||||
The fundamental data processing units in Rijndael are 8-bit bytes. The
|
||||
input, output and key input are all enumerated arrays of bytes in which
|
||||
bytes are numbered starting at zero and increasing to one less than the
|
||||
number of bytes in the array in question. This enumeration is only used
|
||||
for naming bytes and does not imply any adjacency or order relationship
|
||||
from one byte to another. When these inputs and outputs are considered
|
||||
as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to
|
||||
byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte.
|
||||
In this implementation bits are numbered from 0 to 7 starting at the
|
||||
numerically least significant end of each byte (bit n represents 2^n).
|
||||
|
||||
However, Rijndael can be implemented more efficiently using 32-bit
|
||||
words by packing bytes into words so that bytes 4*n to 4*n+3 are placed
|
||||
into word[n]. While in principle these bytes can be assembled into words
|
||||
in any positions, this implementation only supports the two formats in
|
||||
which bytes in adjacent positions within words also have adjacent byte
|
||||
numbers. This order is called big-endian if the lowest numbered bytes
|
||||
in words have the highest numeric significance and little-endian if the
|
||||
opposite applies.
|
||||
|
||||
This code can work in either order irrespective of the order used by the
|
||||
machine on which it runs. Normally the internal byte order will be set
|
||||
to the order of the processor on which the code is to be run but this
|
||||
define can be used to reverse this in special situations
|
||||
|
||||
WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set.
|
||||
This define will hence be redefined later (in section 4) if necessary
|
||||
*/
|
||||
|
||||
#if 1
|
||||
#define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
|
||||
#elif 0
|
||||
#define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#elif 0
|
||||
#define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#else
|
||||
#error The algorithm byte order is not defined
|
||||
#endif
|
||||
|
||||
/* 2. VIA ACE SUPPORT
|
||||
|
||||
Define this option if support for the VIA ACE is required. This uses
|
||||
inline assembler instructions and is only implemented for the Microsoft,
|
||||
Intel and GCC compilers. If VIA ACE is known to be present, then defining
|
||||
ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption
|
||||
code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if
|
||||
it is detected (both present and enabled) but the normal AES code will
|
||||
also be present.
|
||||
|
||||
When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte
|
||||
aligned; other input/output buffers do not need to be 16 byte aligned
|
||||
but there are very large performance gains if this can be arranged.
|
||||
VIA ACE also requires the decryption key schedule to be in reverse
|
||||
order (which later checks below ensure).
|
||||
*/
|
||||
|
||||
#if 0 && !defined( USE_VIA_ACE_IF_PRESENT )
|
||||
# define USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
|
||||
#if 0 && !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# define ASSUME_VIA_ACE_PRESENT
|
||||
# endif
|
||||
|
||||
#if defined ( _WIN64 ) || defined( _WIN32_WCE ) || \
|
||||
defined( _MSC_VER ) && ( _MSC_VER <= 800 )
|
||||
# if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
# undef USE_VIA_ACE_IF_PRESENT
|
||||
# endif
|
||||
# if defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# undef ASSUME_VIA_ACE_PRESENT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* 3. ASSEMBLER SUPPORT
|
||||
|
||||
This define (which can be on the command line) enables the use of the
|
||||
assembler code routines for encryption, decryption and key scheduling
|
||||
as follows:
|
||||
|
||||
ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for
|
||||
encryption, decryption and key scheduling
|
||||
ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
|
||||
Change one 'if 0' below to 'if 1' to select the version or define
|
||||
as a compilation option.
|
||||
*/
|
||||
|
||||
#if 0 && !defined( ASM_X86_V1C )
|
||||
# define ASM_X86_V1C
|
||||
#elif 0 && !defined( ASM_X86_V2 )
|
||||
# define ASM_X86_V2
|
||||
#elif 0 && !defined( ASM_X86_V2C )
|
||||
# define ASM_X86_V2C
|
||||
#elif 0 && !defined( ASM_AMD64_C )
|
||||
# define ASM_AMD64_C
|
||||
#endif
|
||||
|
||||
#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \
|
||||
&& !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 )
|
||||
# error Assembler code is only available for x86 and AMD64 systems
|
||||
#endif
|
||||
|
||||
/* 4. FAST INPUT/OUTPUT OPERATIONS.
|
||||
|
||||
On some machines it is possible to improve speed by transferring the
|
||||
bytes in the input and output arrays to and from the internal 32-bit
|
||||
variables by addressing these arrays as if they are arrays of 32-bit
|
||||
words. On some machines this will always be possible but there may
|
||||
be a large performance penalty if the byte arrays are not aligned on
|
||||
the normal word boundaries. On other machines this technique will
|
||||
lead to memory access errors when such 32-bit word accesses are not
|
||||
properly aligned. The option SAFE_IO avoids such problems but will
|
||||
often be slower on those machines that support misaligned access
|
||||
(especially so if care is taken to align the input and output byte
|
||||
arrays on 32-bit word boundaries). If SAFE_IO is not defined it is
|
||||
assumed that access to byte arrays as if they are arrays of 32-bit
|
||||
words will not cause problems when such accesses are misaligned.
|
||||
*/
|
||||
#if 1 && !defined( _MSC_VER )
|
||||
#define SAFE_IO
|
||||
#endif
|
||||
|
||||
/* 5. LOOP UNROLLING
|
||||
|
||||
The code for encryption and decrytpion cycles through a number of rounds
|
||||
that can be implemented either in a loop or by expanding the code into a
|
||||
long sequence of instructions, the latter producing a larger program but
|
||||
one that will often be much faster. The latter is called loop unrolling.
|
||||
There are also potential speed advantages in expanding two iterations in
|
||||
a loop with half the number of iterations, which is called partial loop
|
||||
unrolling. The following options allow partial or full loop unrolling
|
||||
to be set independently for encryption and decryption
|
||||
*/
|
||||
#if 1
|
||||
#define ENC_UNROLL FULL
|
||||
#elif 0
|
||||
#define ENC_UNROLL PARTIAL
|
||||
#else
|
||||
#define ENC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define DEC_UNROLL FULL
|
||||
#elif 0
|
||||
#define DEC_UNROLL PARTIAL
|
||||
#else
|
||||
#define DEC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
/* 6. FAST FINITE FIELD OPERATIONS
|
||||
|
||||
If this section is included, tables are used to provide faster finite
|
||||
field arithmetic (this has no effect if FIXED_TABLES is defined).
|
||||
*/
|
||||
#if 1
|
||||
#define FF_TABLES
|
||||
#endif
|
||||
|
||||
/* 7. INTERNAL STATE VARIABLE FORMAT
|
||||
|
||||
The internal state of Rijndael is stored in a number of local 32-bit
|
||||
word varaibles which can be defined either as an array or as individual
|
||||
names variables. Include this section if you want to store these local
|
||||
varaibles in arrays. Otherwise individual local variables will be used.
|
||||
*/
|
||||
#if 1
|
||||
#define ARRAYS
|
||||
#endif
|
||||
|
||||
/* 8. FIXED OR DYNAMIC TABLES
|
||||
|
||||
When this section is included the tables used by the code are compiled
|
||||
statically into the binary file. Otherwise the subroutine zrtp_bg_gen_tabs()
|
||||
must be called to compute them before the code is first used.
|
||||
*/
|
||||
#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 ))
|
||||
#define FIXED_TABLES
|
||||
#endif
|
||||
|
||||
/* 9. TABLE ALIGNMENT
|
||||
|
||||
On some sytsems speed will be improved by aligning the AES large lookup
|
||||
tables on particular boundaries. This define should be set to a power of
|
||||
two giving the desired alignment. It can be left undefined if alignment
|
||||
is not needed. This option is specific to the Microsft VC++ compiler -
|
||||
it seems to sometimes cause trouble for the VC++ version 6 compiler.
|
||||
*/
|
||||
|
||||
#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
|
||||
#define TABLE_ALIGN 32
|
||||
#endif
|
||||
|
||||
/* 10. TABLE OPTIONS
|
||||
|
||||
This cipher proceeds by repeating in a number of cycles known as 'rounds'
|
||||
which are implemented by a round function which can optionally be speeded
|
||||
up using tables. The basic tables are each 256 32-bit words, with either
|
||||
one or four tables being required for each round function depending on
|
||||
how much speed is required. The encryption and decryption round functions
|
||||
are different and the last encryption and decrytpion round functions are
|
||||
different again making four different round functions in all.
|
||||
|
||||
This means that:
|
||||
1. Normal encryption and decryption rounds can each use either 0, 1
|
||||
or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
|
||||
2. The last encryption and decryption rounds can also use either 0, 1
|
||||
or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
|
||||
|
||||
Include or exclude the appropriate definitions below to set the number
|
||||
of tables used by this implementation.
|
||||
*/
|
||||
|
||||
#if 1 /* set tables for the normal encryption round */
|
||||
#define ENC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define ENC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define ENC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the last encryption round */
|
||||
#define LAST_ENC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define LAST_ENC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define LAST_ENC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the normal decryption round */
|
||||
#define DEC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define DEC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define DEC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the last decryption round */
|
||||
#define LAST_DEC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define LAST_DEC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define LAST_DEC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
/* The decryption key schedule can be speeded up with tables in the same
|
||||
way that the round functions can. Include or exclude the following
|
||||
defines to set this requirement.
|
||||
*/
|
||||
#if 1
|
||||
#define KEY_SCHED FOUR_TABLES
|
||||
#elif 0
|
||||
#define KEY_SCHED ONE_TABLE
|
||||
#else
|
||||
#define KEY_SCHED NO_TABLES
|
||||
#endif
|
||||
|
||||
/* ---- END OF USER CONFIGURED OPTIONS ---- */
|
||||
|
||||
/* VIA ACE support is only available for VC++ and GCC */
|
||||
|
||||
#if !defined( _MSC_VER ) && !defined( __GNUC__ )
|
||||
# if defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# undef ASSUME_VIA_ACE_PRESENT
|
||||
# endif
|
||||
# if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
# undef USE_VIA_ACE_IF_PRESENT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT )
|
||||
#define USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS )
|
||||
#define AES_REV_DKS
|
||||
#endif
|
||||
|
||||
/* Assembler support requires the use of platform byte order */
|
||||
|
||||
#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \
|
||||
&& (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER)
|
||||
#undef ALGORITHM_BYTE_ORDER
|
||||
#define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
|
||||
#endif
|
||||
|
||||
/* In this implementation the columns of the state array are each held in
|
||||
32-bit words. The state array can be held in various ways: in an array
|
||||
of words, in a number of individual word variables or in a number of
|
||||
processor registers. The following define maps a variable name x and
|
||||
a column number c to the way the state array variable is to be held.
|
||||
The first define below maps the state into an array x[c] whereas the
|
||||
second form maps the state into a number of individual variables x0,
|
||||
x1, etc. Another form could map individual state colums to machine
|
||||
register names.
|
||||
*/
|
||||
|
||||
#if defined( ARRAYS )
|
||||
#define s(x,c) x[c]
|
||||
#else
|
||||
#define s(x,c) x##c
|
||||
#endif
|
||||
|
||||
/* This implementation provides subroutines for encryption, decryption
|
||||
and for setting the three key lengths (separately) for encryption
|
||||
and decryption. Since not all functions are needed, masks are set
|
||||
up here to determine which will be implemented in C
|
||||
*/
|
||||
|
||||
#if !defined( AES_ENCRYPT )
|
||||
# define EFUNCS_IN_C 0
|
||||
#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \
|
||||
|| defined( ASM_X86_V2C ) || defined( ASM_AMD64_C )
|
||||
# define EFUNCS_IN_C ENC_KEYING_IN_C
|
||||
#elif !defined( ASM_X86_V2 )
|
||||
# define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C )
|
||||
#else
|
||||
# define EFUNCS_IN_C 0
|
||||
#endif
|
||||
|
||||
#if !defined( AES_DECRYPT )
|
||||
# define DFUNCS_IN_C 0
|
||||
#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \
|
||||
|| defined( ASM_X86_V2C ) || defined( ASM_AMD64_C )
|
||||
# define DFUNCS_IN_C DEC_KEYING_IN_C
|
||||
#elif !defined( ASM_X86_V2 )
|
||||
# define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C )
|
||||
#else
|
||||
# define DFUNCS_IN_C 0
|
||||
#endif
|
||||
|
||||
#define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C )
|
||||
|
||||
/* END OF CONFIGURATION OPTIONS */
|
||||
|
||||
#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2))
|
||||
|
||||
/* Disable or report errors on some combinations of options */
|
||||
|
||||
#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES
|
||||
#undef LAST_ENC_ROUND
|
||||
#define LAST_ENC_ROUND NO_TABLES
|
||||
#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES
|
||||
#undef LAST_ENC_ROUND
|
||||
#define LAST_ENC_ROUND ONE_TABLE
|
||||
#endif
|
||||
|
||||
#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE
|
||||
#undef ENC_UNROLL
|
||||
#define ENC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES
|
||||
#undef LAST_DEC_ROUND
|
||||
#define LAST_DEC_ROUND NO_TABLES
|
||||
#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES
|
||||
#undef LAST_DEC_ROUND
|
||||
#define LAST_DEC_ROUND ONE_TABLE
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE
|
||||
#undef DEC_UNROLL
|
||||
#define DEC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if defined( bswap32 )
|
||||
#define aes_sw32 bswap32
|
||||
#elif defined( bswap_32 )
|
||||
#define aes_sw32 bswap_32
|
||||
#else
|
||||
#define brot(x,n) (((uint_32t)(x) << n) | ((uint_32t)(x) >> (32 - n)))
|
||||
#define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00))
|
||||
#endif
|
||||
|
||||
/* upr(x,n): rotates bytes within words by n positions, moving bytes to
|
||||
higher index positions with wrap around into low positions
|
||||
ups(x,n): moves bytes by n positions to higher index positions in
|
||||
words but without wrap around
|
||||
bval(x,n): extracts a byte from a word
|
||||
|
||||
WARNING: The definitions given here are intended only for use with
|
||||
unsigned variables and with shift counts that are compile
|
||||
time constants
|
||||
*/
|
||||
|
||||
#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN )
|
||||
#define upr(x,n) (((uint_32t)(x) << (8 * (n))) | ((uint_32t)(x) >> (32 - 8 * (n))))
|
||||
#define ups(x,n) ((uint_32t) (x) << (8 * (n)))
|
||||
#define bval(x,n) ((uint_8t)((x) >> (8 * (n))))
|
||||
#define bytes2word(b0, b1, b2, b3) \
|
||||
(((uint_32t)(b3) << 24) | ((uint_32t)(b2) << 16) | ((uint_32t)(b1) << 8) | (b0))
|
||||
#endif
|
||||
|
||||
#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN )
|
||||
#define upr(x,n) (((uint_32t)(x) >> (8 * (n))) | ((uint_32t)(x) << (32 - 8 * (n))))
|
||||
#define ups(x,n) ((uint_32t) (x) >> (8 * (n)))
|
||||
#define bval(x,n) ((uint_8t)((x) >> (24 - 8 * (n))))
|
||||
#define bytes2word(b0, b1, b2, b3) \
|
||||
(((uint_32t)(b0) << 24) | ((uint_32t)(b1) << 16) | ((uint_32t)(b2) << 8) | (b3))
|
||||
#endif
|
||||
|
||||
#if defined( SAFE_IO )
|
||||
|
||||
#define word_in(x,c) bytes2word(((const uint_8t*)(x)+4*c)[0], ((const uint_8t*)(x)+4*c)[1], \
|
||||
((const uint_8t*)(x)+4*c)[2], ((const uint_8t*)(x)+4*c)[3])
|
||||
#define word_out(x,c,v) { ((uint_8t*)(x)+4*c)[0] = bval(v,0); ((uint_8t*)(x)+4*c)[1] = bval(v,1); \
|
||||
((uint_8t*)(x)+4*c)[2] = bval(v,2); ((uint_8t*)(x)+4*c)[3] = bval(v,3); }
|
||||
|
||||
#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER )
|
||||
|
||||
#define word_in(x,c) (*((uint_32t*)(x)+(c)))
|
||||
#define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = (v))
|
||||
|
||||
#else
|
||||
|
||||
#define word_in(x,c) aes_sw32(*((uint_32t*)(x)+(c)))
|
||||
#define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = aes_sw32(v))
|
||||
|
||||
#endif
|
||||
|
||||
/* the finite field modular polynomial and elements */
|
||||
|
||||
#define WPOLY 0x011b
|
||||
#define BPOLY 0x1b
|
||||
|
||||
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
|
||||
|
||||
#define m1 0x80808080
|
||||
#define m2 0x7f7f7f7f
|
||||
#define gf_mulx(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY))
|
||||
|
||||
/* The following defines provide alternative definitions of gf_mulx that might
|
||||
give improved performance if a fast 32-bit multiply is not available. Note
|
||||
that a temporary variable u needs to be defined where gf_mulx is used.
|
||||
|
||||
#define gf_mulx(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6))
|
||||
#define m4 (0x01010101 * BPOLY)
|
||||
#define gf_mulx(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4)
|
||||
*/
|
||||
|
||||
/* Work out which tables are needed for the different options */
|
||||
|
||||
#if defined( ASM_X86_V1C )
|
||||
#if defined( ENC_ROUND )
|
||||
#undef ENC_ROUND
|
||||
#endif
|
||||
#define ENC_ROUND FOUR_TABLES
|
||||
#if defined( LAST_ENC_ROUND )
|
||||
#undef LAST_ENC_ROUND
|
||||
#endif
|
||||
#define LAST_ENC_ROUND FOUR_TABLES
|
||||
#if defined( DEC_ROUND )
|
||||
#undef DEC_ROUND
|
||||
#endif
|
||||
#define DEC_ROUND FOUR_TABLES
|
||||
#if defined( LAST_DEC_ROUND )
|
||||
#undef LAST_DEC_ROUND
|
||||
#endif
|
||||
#define LAST_DEC_ROUND FOUR_TABLES
|
||||
#if defined( KEY_SCHED )
|
||||
#undef KEY_SCHED
|
||||
#define KEY_SCHED FOUR_TABLES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C )
|
||||
#if ENC_ROUND == ONE_TABLE
|
||||
#define FT1_SET
|
||||
#elif ENC_ROUND == FOUR_TABLES
|
||||
#define FT4_SET
|
||||
#else
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#if LAST_ENC_ROUND == ONE_TABLE
|
||||
#define FL1_SET
|
||||
#elif LAST_ENC_ROUND == FOUR_TABLES
|
||||
#define FL4_SET
|
||||
#elif !defined( SBX_SET )
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C )
|
||||
#if DEC_ROUND == ONE_TABLE
|
||||
#define IT1_SET
|
||||
#elif DEC_ROUND == FOUR_TABLES
|
||||
#define IT4_SET
|
||||
#else
|
||||
#define ISB_SET
|
||||
#endif
|
||||
#if LAST_DEC_ROUND == ONE_TABLE
|
||||
#define IL1_SET
|
||||
#elif LAST_DEC_ROUND == FOUR_TABLES
|
||||
#define IL4_SET
|
||||
#elif !defined(ISB_SET)
|
||||
#define ISB_SET
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)
|
||||
#if KEY_SCHED == ONE_TABLE
|
||||
#define LS1_SET
|
||||
#elif KEY_SCHED == FOUR_TABLES
|
||||
#define LS4_SET
|
||||
#elif !defined( SBX_SET )
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (FUNCS_IN_C & DEC_KEYING_IN_C)
|
||||
#if KEY_SCHED == ONE_TABLE
|
||||
#define IM1_SET
|
||||
#elif KEY_SCHED == FOUR_TABLES
|
||||
#define IM4_SET
|
||||
#elif !defined( SBX_SET )
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* generic definitions of Rijndael macros that use tables */
|
||||
|
||||
#define no_table(x,box,vf,rf,c) bytes2word( \
|
||||
box[bval(vf(x,0,c),rf(0,c))], \
|
||||
box[bval(vf(x,1,c),rf(1,c))], \
|
||||
box[bval(vf(x,2,c),rf(2,c))], \
|
||||
box[bval(vf(x,3,c),rf(3,c))])
|
||||
|
||||
#define one_table(x,op,tab,vf,rf,c) \
|
||||
( tab[bval(vf(x,0,c),rf(0,c))] \
|
||||
^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
|
||||
^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
|
||||
^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
|
||||
|
||||
#define four_tables(x,tab,vf,rf,c) \
|
||||
( tab[0][bval(vf(x,0,c),rf(0,c))] \
|
||||
^ tab[1][bval(vf(x,1,c),rf(1,c))] \
|
||||
^ tab[2][bval(vf(x,2,c),rf(2,c))] \
|
||||
^ tab[3][bval(vf(x,3,c),rf(3,c))])
|
||||
|
||||
#define vf1(x,r,c) (x)
|
||||
#define rf1(r,c) (r)
|
||||
#define rf2(r,c) ((8+r-c)&3)
|
||||
|
||||
/* perform forward and inverse column mix operation on four bytes in long word x in */
|
||||
/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */
|
||||
|
||||
#if defined( FM4_SET ) /* not currently used */
|
||||
#define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0)
|
||||
#elif defined( FM1_SET ) /* not currently used */
|
||||
#define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0)
|
||||
#else
|
||||
#define dec_fmvars uint_32t g2
|
||||
#define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1))
|
||||
#endif
|
||||
|
||||
#if defined( IM4_SET )
|
||||
#define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0)
|
||||
#elif defined( IM1_SET )
|
||||
#define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0)
|
||||
#else
|
||||
#define dec_imvars uint_32t g2, g4, g9
|
||||
#define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \
|
||||
(x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1))
|
||||
#endif
|
||||
|
||||
#if defined( FL4_SET )
|
||||
#define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c)
|
||||
#elif defined( LS4_SET )
|
||||
#define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c)
|
||||
#elif defined( FL1_SET )
|
||||
#define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c)
|
||||
#elif defined( LS1_SET )
|
||||
#define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c)
|
||||
#else
|
||||
#define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c)
|
||||
#endif
|
||||
|
||||
#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET )
|
||||
#define ISB_SET
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+400
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue 09/09/2006
|
||||
*/
|
||||
|
||||
#define DO_TABLES
|
||||
|
||||
#include "aes.h"
|
||||
#include "aesopt.h"
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
//[winfix]
|
||||
#if 0
|
||||
#if ZRTP_PLATFORM != ZP_WIN32 && ZRTP_PLATFORM != ZP_WIN32_KERNEL
|
||||
#ifndef FIXED_TABLES
|
||||
#warning "FIXED_TABLES isn't defined. Use dynamic tables."
|
||||
#else
|
||||
#warning "FIXED_TABLES is defined. Use static tables."
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(FIXED_TABLES)
|
||||
|
||||
#define sb_data(w) {\
|
||||
w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
|
||||
w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
|
||||
w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
|
||||
w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
|
||||
w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
|
||||
w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
|
||||
w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
|
||||
w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
|
||||
w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
|
||||
w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
|
||||
w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
|
||||
w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
|
||||
w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
|
||||
w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
|
||||
w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
|
||||
w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
|
||||
w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
|
||||
w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
|
||||
w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
|
||||
w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
|
||||
w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
|
||||
w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
|
||||
w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
|
||||
w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
|
||||
w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
|
||||
w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
|
||||
w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
|
||||
w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
|
||||
w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
|
||||
w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
|
||||
w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
|
||||
w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
|
||||
|
||||
#define isb_data(w) {\
|
||||
w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
|
||||
w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
|
||||
w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
|
||||
w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
|
||||
w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
|
||||
w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
|
||||
w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
|
||||
w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
|
||||
w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
|
||||
w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
|
||||
w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
|
||||
w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
|
||||
w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
|
||||
w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
|
||||
w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
|
||||
w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
|
||||
w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
|
||||
w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
|
||||
w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
|
||||
w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
|
||||
w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
|
||||
w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
|
||||
w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
|
||||
w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
|
||||
w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
|
||||
w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
|
||||
w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
|
||||
w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
|
||||
w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
|
||||
w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
|
||||
w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
|
||||
w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) }
|
||||
|
||||
#define mm_data(w) {\
|
||||
w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
|
||||
w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
|
||||
w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
|
||||
w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
|
||||
w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
|
||||
w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
|
||||
w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
|
||||
w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
|
||||
w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
|
||||
w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
|
||||
w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
|
||||
w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
|
||||
w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
|
||||
w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
|
||||
w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
|
||||
w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
|
||||
w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
|
||||
w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
|
||||
w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
|
||||
w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
|
||||
w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
|
||||
w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
|
||||
w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
|
||||
w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
|
||||
w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
|
||||
w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
|
||||
w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
|
||||
w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
|
||||
w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
|
||||
w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
|
||||
w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
|
||||
w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) }
|
||||
|
||||
#define rc_data(w) {\
|
||||
w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
|
||||
w(0x1b), w(0x36) }
|
||||
|
||||
#define h0(x) (x)
|
||||
|
||||
#define w0(p) bytes2word(p, 0, 0, 0)
|
||||
#define w1(p) bytes2word(0, p, 0, 0)
|
||||
#define w2(p) bytes2word(0, 0, p, 0)
|
||||
#define w3(p) bytes2word(0, 0, 0, p)
|
||||
|
||||
#define u0(p) bytes2word(f2(p), p, p, f3(p))
|
||||
#define u1(p) bytes2word(f3(p), f2(p), p, p)
|
||||
#define u2(p) bytes2word(p, f3(p), f2(p), p)
|
||||
#define u3(p) bytes2word(p, p, f3(p), f2(p))
|
||||
|
||||
#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p))
|
||||
#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p))
|
||||
#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p))
|
||||
#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p))
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(FIXED_TABLES) || !defined(FF_TABLES)
|
||||
|
||||
#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY))
|
||||
#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
|
||||
#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \
|
||||
^ (((x>>5) & 4) * WPOLY))
|
||||
#define f3(x) (f2(x) ^ x)
|
||||
#define f9(x) (f8(x) ^ x)
|
||||
#define fb(x) (f8(x) ^ f2(x) ^ x)
|
||||
#define fd(x) (f8(x) ^ f4(x) ^ x)
|
||||
#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
|
||||
|
||||
#else
|
||||
|
||||
#define f2(x) ((x) ? pow[log[x] + 0x19] : 0)
|
||||
#define f3(x) ((x) ? pow[log[x] + 0x01] : 0)
|
||||
#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0)
|
||||
#define fb(x) ((x) ? pow[log[x] + 0x68] : 0)
|
||||
#define fd(x) ((x) ? pow[log[x] + 0xee] : 0)
|
||||
#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0)
|
||||
#define fi(x) ((x) ? pow[ 255 - log[x]] : 0)
|
||||
|
||||
#endif
|
||||
|
||||
#include "aestab.h"
|
||||
|
||||
#if defined(FIXED_TABLES)
|
||||
|
||||
/* implemented in case of wrong call for fixed tables */
|
||||
|
||||
AES_RETURN zrtp_bg_gen_tabs(void)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#else /* dynamic table generation */
|
||||
|
||||
#if !defined(FF_TABLES)
|
||||
|
||||
/* Generate the tables for the dynamic table option
|
||||
|
||||
It will generally be sensible to use tables to compute finite
|
||||
field multiplies and inverses but where memory is scarse this
|
||||
code might sometimes be better. But it only has effect during
|
||||
initialisation so its pretty unimportant in overall terms.
|
||||
*/
|
||||
|
||||
/* return 2 ^ (n - 1) where n is the bit number of the highest bit
|
||||
set in x with x in the range 1 < x < 0x00000200. This form is
|
||||
used so that locals within fi can be bytes rather than words
|
||||
*/
|
||||
|
||||
static uint_8t hibit(const uint_32t x)
|
||||
{ uint_8t r = (uint_8t)((x >> 1) | (x >> 2));
|
||||
|
||||
r |= (r >> 2);
|
||||
r |= (r >> 4);
|
||||
return (r + 1) >> 1;
|
||||
}
|
||||
|
||||
/* return the inverse of the finite field element x */
|
||||
|
||||
static uint_8t fi(const uint_8t x)
|
||||
{ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
|
||||
|
||||
if(x < 2) return x;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(!n1) return v1;
|
||||
|
||||
while(n2 >= n1)
|
||||
{
|
||||
n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2);
|
||||
}
|
||||
|
||||
if(!n2) return v2;
|
||||
|
||||
while(n1 >= n2)
|
||||
{
|
||||
n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* The forward and inverse affine transformations used in the S-box */
|
||||
|
||||
#define fwd_affine(x) \
|
||||
(w = (uint_32t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(uint_8t)(w^(w>>8)))
|
||||
|
||||
#define inv_affine(x) \
|
||||
(w = (uint_32t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(uint_8t)(w^(w>>8)))
|
||||
|
||||
static int init = 0;
|
||||
|
||||
AES_RETURN zrtp_bg_gen_tabs(void)
|
||||
{ uint_32t i, w;
|
||||
#if defined(FF_TABLES)
|
||||
|
||||
uint_8t pow[512], log[256];
|
||||
|
||||
if(init)
|
||||
return EXIT_SUCCESS;
|
||||
/* log and power tables for GF(2^8) finite field with
|
||||
WPOLY as modular polynomial - the simplest primitive
|
||||
root is 0x03, used here to generate the tables
|
||||
*/
|
||||
|
||||
i = 0; w = 1;
|
||||
do
|
||||
{
|
||||
pow[i] = (uint_8t)w;
|
||||
pow[i + 255] = (uint_8t)w;
|
||||
log[w] = (uint_8t)i++;
|
||||
w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0);
|
||||
}
|
||||
while (w != 1);
|
||||
|
||||
#else
|
||||
if(init)
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
|
||||
for(i = 0, w = 1; i < RC_LENGTH; ++i)
|
||||
{
|
||||
t_set(r,c)[i] = bytes2word(w, 0, 0, 0);
|
||||
w = f2(w);
|
||||
}
|
||||
|
||||
for(i = 0; i < 256; ++i)
|
||||
{ uint_8t b;
|
||||
|
||||
b = fwd_affine(fi((uint_8t)i));
|
||||
w = bytes2word(f2(b), b, b, f3(b));
|
||||
|
||||
#if defined( SBX_SET )
|
||||
t_set(s,box)[i] = b;
|
||||
#endif
|
||||
|
||||
#if defined( FT1_SET ) /* tables for a normal encryption round */
|
||||
t_set(f,n)[i] = w;
|
||||
#endif
|
||||
#if defined( FT4_SET )
|
||||
t_set(f,n)[0][i] = w;
|
||||
t_set(f,n)[1][i] = upr(w,1);
|
||||
t_set(f,n)[2][i] = upr(w,2);
|
||||
t_set(f,n)[3][i] = upr(w,3);
|
||||
#endif
|
||||
w = bytes2word(b, 0, 0, 0);
|
||||
|
||||
#if defined( FL1_SET ) /* tables for last encryption round (may also */
|
||||
t_set(f,l)[i] = w; /* be used in the key schedule) */
|
||||
#endif
|
||||
#if defined( FL4_SET )
|
||||
t_set(f,l)[0][i] = w;
|
||||
t_set(f,l)[1][i] = upr(w,1);
|
||||
t_set(f,l)[2][i] = upr(w,2);
|
||||
t_set(f,l)[3][i] = upr(w,3);
|
||||
#endif
|
||||
|
||||
#if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is */
|
||||
t_set(l,s)[i] = w; /* not of the required form */
|
||||
#endif
|
||||
#if defined( LS4_SET )
|
||||
t_set(l,s)[0][i] = w;
|
||||
t_set(l,s)[1][i] = upr(w,1);
|
||||
t_set(l,s)[2][i] = upr(w,2);
|
||||
t_set(l,s)[3][i] = upr(w,3);
|
||||
#endif
|
||||
|
||||
b = fi(inv_affine((uint_8t)i));
|
||||
w = bytes2word(fe(b), f9(b), fd(b), fb(b));
|
||||
|
||||
#if defined( IM1_SET ) /* tables for the inverse mix column operation */
|
||||
t_set(i,m)[b] = w;
|
||||
#endif
|
||||
#if defined( IM4_SET )
|
||||
t_set(i,m)[0][b] = w;
|
||||
t_set(i,m)[1][b] = upr(w,1);
|
||||
t_set(i,m)[2][b] = upr(w,2);
|
||||
t_set(i,m)[3][b] = upr(w,3);
|
||||
#endif
|
||||
|
||||
#if defined( ISB_SET )
|
||||
t_set(i,box)[i] = b;
|
||||
#endif
|
||||
#if defined( IT1_SET ) /* tables for a normal decryption round */
|
||||
t_set(i,n)[i] = w;
|
||||
#endif
|
||||
#if defined( IT4_SET )
|
||||
t_set(i,n)[0][i] = w;
|
||||
t_set(i,n)[1][i] = upr(w,1);
|
||||
t_set(i,n)[2][i] = upr(w,2);
|
||||
t_set(i,n)[3][i] = upr(w,3);
|
||||
#endif
|
||||
w = bytes2word(b, 0, 0, 0);
|
||||
#if defined( IL1_SET ) /* tables for last decryption round */
|
||||
t_set(i,l)[i] = w;
|
||||
#endif
|
||||
#if defined( IL4_SET )
|
||||
t_set(i,l)[0][i] = w;
|
||||
t_set(i,l)[1][i] = upr(w,1);
|
||||
t_set(i,l)[2][i] = upr(w,2);
|
||||
t_set(i,l)[3][i] = upr(w,3);
|
||||
#endif
|
||||
}
|
||||
init = 1;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue 09/09/2006
|
||||
|
||||
This file contains the code for declaring the tables needed to implement
|
||||
AES. The file aesopt.h is assumed to be included before this header file.
|
||||
If there are no global variables, the definitions here can be used to put
|
||||
the AES tables in a structure so that a pointer can then be added to the
|
||||
AES context to pass them to the AES routines that need them. If this
|
||||
facility is used, the calling program has to ensure that this pointer is
|
||||
managed appropriately. In particular, the value of the t_dec(in,it) item
|
||||
in the table structure must be set to zero in order to ensure that the
|
||||
tables are initialised. In practice the three code sequences in aeskey.c
|
||||
that control the calls to zrtp_bg_gen_tabs() and the gen_tabs() routine itself will
|
||||
have to be changed for a specific implementation. If global variables are
|
||||
available it will generally be preferable to use them with the precomputed
|
||||
FIXED_TABLES option that uses static global tables.
|
||||
|
||||
The following defines can be used to control the way the tables
|
||||
are defined, initialised and used in embedded environments that
|
||||
require special features for these purposes
|
||||
|
||||
the 't_dec' construction is used to declare fixed table arrays
|
||||
the 't_set' construction is used to set fixed table values
|
||||
the 't_use' construction is used to access fixed table values
|
||||
|
||||
256 byte tables:
|
||||
|
||||
t_xxx(s,box) => forward S box
|
||||
t_xxx(i,box) => inverse S box
|
||||
|
||||
256 32-bit word OR 4 x 256 32-bit word tables:
|
||||
|
||||
t_xxx(f,n) => forward normal round
|
||||
t_xxx(f,l) => forward last round
|
||||
t_xxx(i,n) => inverse normal round
|
||||
t_xxx(i,l) => inverse last round
|
||||
t_xxx(l,s) => key schedule table
|
||||
t_xxx(i,m) => key schedule table
|
||||
|
||||
Other variables and tables:
|
||||
|
||||
t_xxx(r,c) => the rcon table
|
||||
*/
|
||||
|
||||
#if !defined( _AESTAB_H )
|
||||
#define _AESTAB_H
|
||||
|
||||
#define t_dec(m,n) zrtp_bg_t_##m##n
|
||||
#define t_set(m,n) zrtp_bg_t_##m##n
|
||||
#define t_use(m,n) zrtp_bg_t_##m##n
|
||||
|
||||
#if defined(FIXED_TABLES)
|
||||
# if defined( __MSDOS__ ) || defined( __WIN16__ )
|
||||
/* make tables far data to avoid using too much DGROUP space (PG) */
|
||||
# define CONST const far
|
||||
# else
|
||||
# define CONST const
|
||||
# endif
|
||||
#else
|
||||
# define CONST
|
||||
#endif
|
||||
|
||||
#if defined(DO_TABLES)
|
||||
#define EXTERN
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && defined(TABLE_ALIGN)
|
||||
#define ALIGN __declspec(align(TABLE_ALIGN))
|
||||
#else
|
||||
#define ALIGN
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 )
|
||||
# define XP_DIR __cdecl
|
||||
#else
|
||||
# define XP_DIR
|
||||
#endif
|
||||
|
||||
#if defined(DO_TABLES) && defined(FIXED_TABLES)
|
||||
#define d_1(t,n,b,e) ALIGN CONST XP_DIR t n[256] = b(e)
|
||||
#define d_4(t,n,b,e,f,g,h) ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) }
|
||||
EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0);
|
||||
#else
|
||||
#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256]
|
||||
#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256]
|
||||
EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH];
|
||||
#endif
|
||||
|
||||
#if defined( SBX_SET )
|
||||
d_1(uint_8t, t_dec(s,box), sb_data, h0);
|
||||
#endif
|
||||
#if defined( ISB_SET )
|
||||
d_1(uint_8t, t_dec(i,box), isb_data, h0);
|
||||
#endif
|
||||
|
||||
#if defined( FT1_SET )
|
||||
d_1(uint_32t, t_dec(f,n), sb_data, u0);
|
||||
#endif
|
||||
#if defined( FT4_SET )
|
||||
d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3);
|
||||
#endif
|
||||
|
||||
#if defined( FL1_SET )
|
||||
d_1(uint_32t, t_dec(f,l), sb_data, w0);
|
||||
#endif
|
||||
#if defined( FL4_SET )
|
||||
d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
|
||||
#if defined( IT1_SET )
|
||||
d_1(uint_32t, t_dec(i,n), isb_data, v0);
|
||||
#endif
|
||||
#if defined( IT4_SET )
|
||||
d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3);
|
||||
#endif
|
||||
|
||||
#if defined( IL1_SET )
|
||||
d_1(uint_32t, t_dec(i,l), isb_data, w0);
|
||||
#endif
|
||||
#if defined( IL4_SET )
|
||||
d_4(uint_32t, t_dec(i,l), isb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
|
||||
#if defined( LS1_SET )
|
||||
#if defined( FL1_SET )
|
||||
#undef LS1_SET
|
||||
#else
|
||||
d_1(uint_32t, t_dec(l,s), sb_data, w0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined( LS4_SET )
|
||||
#if defined( FL4_SET )
|
||||
#undef LS4_SET
|
||||
#else
|
||||
d_4(uint_32t, t_dec(l,s), sb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined( IM1_SET )
|
||||
d_1(uint_32t, t_dec(i,m), mm_data, v0);
|
||||
#endif
|
||||
#if defined( IM4_SET )
|
||||
d_4(uint_32t, t_dec(i,m), mm_data, v0, v1, v2, v3);
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2008 Philip R. Zimmermann. All rights reserved.
|
||||
* Contact: http://www.philzimmermann.com
|
||||
* For licensing and other legal details, see the file zrtp_legal.c.
|
||||
*
|
||||
* Viktor Krikun <v.krikun@soft-industry.com> <v.krikun@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __BG2ZRTP_H__
|
||||
#define __BG2ZRTP_H__
|
||||
|
||||
/* Define platform byte order for Brian Gladman's AES */
|
||||
#include "zrtp_config.h"
|
||||
|
||||
#define IS_BIG_ENDIAN 4321
|
||||
#define IS_LITTLE_ENDIAN 1234
|
||||
|
||||
|
||||
#if ZRTP_BYTE_ORDER == ZBO_LITTLE_ENDIAN
|
||||
#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#elif ZRTP_BYTE_ORDER == ZBO_BIG_ENDIAN
|
||||
#define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#else
|
||||
#error "Can't define byte order for BG AES. Edit zrtp_system.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* Define integers for Brian Gladman's AES */
|
||||
|
||||
#define BRG_UI8
|
||||
typedef uint8_t uint_8t;
|
||||
|
||||
#define BRG_UI16
|
||||
typedef uint16_t uint_16t;
|
||||
|
||||
#define BRG_UI32
|
||||
//typedef uint32_t uint_32t;
|
||||
typedef unsigned int uint_32t;
|
||||
|
||||
#define BRG_UI64
|
||||
typedef uint64_t uint_64t;
|
||||
|
||||
|
||||
#endif /*__BG2ZRTP_H__*/
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue 09/09/2006
|
||||
|
||||
The unsigned integer types defined here are of the form uint_<nn>t where
|
||||
<nn> is the length of the type; for example, the unsigned 32-bit type is
|
||||
'uint_32t'. These are NOT the same as the 'C99 integer types' that are
|
||||
defined in the inttypes.h and stdint.h headers since attempts to use these
|
||||
types have shown that support for them is still highly variable. However,
|
||||
since the latter are of the form uint<nn>_t, a regular expression search
|
||||
and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t')
|
||||
can be used to convert the types used here to the C99 standard types.
|
||||
*/
|
||||
|
||||
#ifndef BRG_TYPES_H
|
||||
#define BRG_TYPES_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "bg2zrtp.h"
|
||||
//#include <limits.h>
|
||||
|
||||
|
||||
#ifndef BRG_UI8
|
||||
# define BRG_UI8
|
||||
# if UCHAR_MAX == 255u
|
||||
typedef unsigned char uint_8t;
|
||||
# else
|
||||
# error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BRG_UI16
|
||||
# define BRG_UI16
|
||||
# if USHRT_MAX == 65535u
|
||||
typedef unsigned short uint_16t;
|
||||
# else
|
||||
# error Please define uint_16t as a 16-bit unsigned short type in brg_types.h
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BRG_UI32
|
||||
# define BRG_UI32
|
||||
# if UINT_MAX == 4294967295u
|
||||
# define li_32(h) 0x##h##u
|
||||
typedef unsigned int uint_32t;
|
||||
# elif ULONG_MAX == 4294967295u
|
||||
# define li_32(h) 0x##h##ul
|
||||
typedef unsigned long uint_32t;
|
||||
# elif defined( _CRAY )
|
||||
# error This code needs 32-bit data types, which Cray machines do not provide
|
||||
# else
|
||||
# error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BRG_UI64
|
||||
# if defined( __BORLANDC__ ) && !defined( __MSDOS__ )
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
typedef unsigned __int64 uint_64t;
|
||||
# elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ui64
|
||||
typedef unsigned __int64 uint_64t;
|
||||
# elif defined( __sun ) && defined(ULONG_MAX) && ULONG_MAX == 0xfffffffful
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
typedef unsigned long long uint_64t;
|
||||
# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u
|
||||
# if UINT_MAX == 18446744073709551615u
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##u
|
||||
typedef unsigned int uint_64t;
|
||||
# endif
|
||||
# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u
|
||||
# if ULONG_MAX == 18446744073709551615ul
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ul
|
||||
typedef unsigned long uint_64t;
|
||||
# endif
|
||||
# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u
|
||||
# if ULLONG_MAX == 18446744073709551615ull
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
typedef unsigned long long uint_64t;
|
||||
# endif
|
||||
# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u
|
||||
# if ULONG_LONG_MAX == 18446744073709551615ull
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
typedef unsigned long long uint_64t;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined( NEED_UINT_64T ) && !defined( BRG_UI64 )
|
||||
# error Please define uint_64t as an unsigned 64 bit type in brg_types.h
|
||||
#endif
|
||||
|
||||
#ifndef RETURN_VALUES
|
||||
# define RETURN_VALUES
|
||||
# if defined( DLL_EXPORT )
|
||||
# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
|
||||
# define VOID_RETURN __declspec( dllexport ) void __stdcall
|
||||
# define INT_RETURN __declspec( dllexport ) int __stdcall
|
||||
# elif defined( __GNUC__ )
|
||||
# define VOID_RETURN __declspec( __dllexport__ ) void
|
||||
# define INT_RETURN __declspec( __dllexport__ ) int
|
||||
# else
|
||||
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
|
||||
# endif
|
||||
# elif defined( DLL_IMPORT )
|
||||
# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
|
||||
# define VOID_RETURN __declspec( dllimport ) void __stdcall
|
||||
# define INT_RETURN __declspec( dllimport ) int __stdcall
|
||||
# elif defined( __GNUC__ )
|
||||
# define VOID_RETURN __declspec( __dllimport__ ) void
|
||||
# define INT_RETURN __declspec( __dllimport__ ) int
|
||||
# else
|
||||
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
|
||||
# endif
|
||||
# elif defined( __WATCOMC__ )
|
||||
# define VOID_RETURN void __cdecl
|
||||
# define INT_RETURN int __cdecl
|
||||
# else
|
||||
# define VOID_RETURN void
|
||||
# define INT_RETURN int
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* These defines are used to declare buffers in a way that allows
|
||||
faster operations on longer variables to be used. In all these
|
||||
defines 'size' must be a power of 2 and >= 8
|
||||
|
||||
dec_unit_type(size,x) declares a variable 'x' of length
|
||||
'size' bits
|
||||
|
||||
dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize'
|
||||
bytes defined as an array of variables
|
||||
each of 'size' bits (bsize must be a
|
||||
multiple of size / 8)
|
||||
|
||||
ptr_cast(x,size) casts a pointer to a pointer to a
|
||||
varaiable of length 'size' bits
|
||||
*/
|
||||
|
||||
#define ui_type(size) uint_##size##t
|
||||
#define dec_unit_type(size,x) typedef ui_type(size) x
|
||||
#define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)]
|
||||
#define ptr_cast(x,size) ((ui_type(size)*)(x))
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 01/08/2005
|
||||
|
||||
This is a byte oriented version of SHA1 that operates on arrays of bytes
|
||||
stored in memory.
|
||||
*/
|
||||
|
||||
#include <string.h> /* for memcpy() etc. */
|
||||
|
||||
#include "sha1.h"
|
||||
//#include "brg_endian.h"
|
||||
#include "bg2zrtp.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER ) && ( _MSC_VER > 800 )
|
||||
#pragma intrinsic(memcpy)
|
||||
#endif
|
||||
|
||||
#if 0 && defined(_MSC_VER)
|
||||
#define rotl32 _lrotl
|
||||
#define rotr32 _lrotr
|
||||
#else
|
||||
#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
|
||||
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
|
||||
#endif
|
||||
|
||||
#if !defined(bswap_32)
|
||||
#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00))
|
||||
#endif
|
||||
|
||||
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
|
||||
#define SWAP_BYTES
|
||||
#else
|
||||
#undef SWAP_BYTES
|
||||
#endif
|
||||
|
||||
#if defined(SWAP_BYTES)
|
||||
#define bsw_32(p,n) \
|
||||
{ int _i = (n); while(_i--) ((uint_32t*)p)[_i] = bswap_32(((uint_32t*)p)[_i]); }
|
||||
#else
|
||||
#define bsw_32(p,n)
|
||||
#endif
|
||||
|
||||
#define SHA1_MASK (SHA1_BLOCK_SIZE - 1)
|
||||
|
||||
#if 0
|
||||
|
||||
#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define parity(x,y,z) ((x) ^ (y) ^ (z))
|
||||
#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
|
||||
#else /* Discovered by Rich Schroeppel and Colin Plumb */
|
||||
|
||||
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define parity(x,y,z) ((x) ^ (y) ^ (z))
|
||||
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
|
||||
|
||||
#endif
|
||||
|
||||
/* Compile 64 bytes of hash data into SHA1 context. Note */
|
||||
/* that this routine assumes that the byte order in the */
|
||||
/* ctx->wbuf[] at this point is in such an order that low */
|
||||
/* address bytes in the ORIGINAL byte stream will go in */
|
||||
/* this buffer to the high end of 32-bit words on BOTH big */
|
||||
/* and little endian systems */
|
||||
|
||||
#ifdef ARRAY
|
||||
#define q(v,n) v[n]
|
||||
#else
|
||||
#define q(v,n) v##n
|
||||
#endif
|
||||
|
||||
#define one_cycle(v,a,b,c,d,e,f,k,h) \
|
||||
q(v,e) += rotr32(q(v,a),27) + \
|
||||
f(q(v,b),q(v,c),q(v,d)) + k + h; \
|
||||
q(v,b) = rotr32(q(v,b), 2)
|
||||
|
||||
#define five_cycle(v,f,k,i) \
|
||||
one_cycle(v, 0,1,2,3,4, f,k,hf(i )); \
|
||||
one_cycle(v, 4,0,1,2,3, f,k,hf(i+1)); \
|
||||
one_cycle(v, 3,4,0,1,2, f,k,hf(i+2)); \
|
||||
one_cycle(v, 2,3,4,0,1, f,k,hf(i+3)); \
|
||||
one_cycle(v, 1,2,3,4,0, f,k,hf(i+4))
|
||||
|
||||
VOID_RETURN sha1_compile(sha1_ctx ctx[1])
|
||||
{ uint_32t *w = ctx->wbuf;
|
||||
|
||||
#ifdef ARRAY
|
||||
uint_32t v[5];
|
||||
memcpy(v, ctx->hash, 5 * sizeof(uint_32t));
|
||||
#else
|
||||
uint_32t v0, v1, v2, v3, v4;
|
||||
v0 = ctx->hash[0]; v1 = ctx->hash[1];
|
||||
v2 = ctx->hash[2]; v3 = ctx->hash[3];
|
||||
v4 = ctx->hash[4];
|
||||
#endif
|
||||
|
||||
#define hf(i) w[i]
|
||||
|
||||
five_cycle(v, ch, 0x5a827999, 0);
|
||||
five_cycle(v, ch, 0x5a827999, 5);
|
||||
five_cycle(v, ch, 0x5a827999, 10);
|
||||
one_cycle(v,0,1,2,3,4, ch, 0x5a827999, hf(15)); \
|
||||
|
||||
#undef hf
|
||||
#define hf(i) (w[(i) & 15] = rotl32( \
|
||||
w[((i) + 13) & 15] ^ w[((i) + 8) & 15] \
|
||||
^ w[((i) + 2) & 15] ^ w[(i) & 15], 1))
|
||||
|
||||
one_cycle(v,4,0,1,2,3, ch, 0x5a827999, hf(16));
|
||||
one_cycle(v,3,4,0,1,2, ch, 0x5a827999, hf(17));
|
||||
one_cycle(v,2,3,4,0,1, ch, 0x5a827999, hf(18));
|
||||
one_cycle(v,1,2,3,4,0, ch, 0x5a827999, hf(19));
|
||||
|
||||
five_cycle(v, parity, 0x6ed9eba1, 20);
|
||||
five_cycle(v, parity, 0x6ed9eba1, 25);
|
||||
five_cycle(v, parity, 0x6ed9eba1, 30);
|
||||
five_cycle(v, parity, 0x6ed9eba1, 35);
|
||||
|
||||
five_cycle(v, maj, 0x8f1bbcdc, 40);
|
||||
five_cycle(v, maj, 0x8f1bbcdc, 45);
|
||||
five_cycle(v, maj, 0x8f1bbcdc, 50);
|
||||
five_cycle(v, maj, 0x8f1bbcdc, 55);
|
||||
|
||||
five_cycle(v, parity, 0xca62c1d6, 60);
|
||||
five_cycle(v, parity, 0xca62c1d6, 65);
|
||||
five_cycle(v, parity, 0xca62c1d6, 70);
|
||||
five_cycle(v, parity, 0xca62c1d6, 75);
|
||||
|
||||
#ifdef ARRAY
|
||||
ctx->hash[0] += v[0]; ctx->hash[1] += v[1];
|
||||
ctx->hash[2] += v[2]; ctx->hash[3] += v[3];
|
||||
ctx->hash[4] += v[4];
|
||||
#else
|
||||
ctx->hash[0] += v0; ctx->hash[1] += v1;
|
||||
ctx->hash[2] += v2; ctx->hash[3] += v3;
|
||||
ctx->hash[4] += v4;
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID_RETURN sha1_begin(sha1_ctx ctx[1])
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
ctx->hash[0] = 0x67452301;
|
||||
ctx->hash[1] = 0xefcdab89;
|
||||
ctx->hash[2] = 0x98badcfe;
|
||||
ctx->hash[3] = 0x10325476;
|
||||
ctx->hash[4] = 0xc3d2e1f0;
|
||||
}
|
||||
|
||||
/* SHA1 hash data in an array of bytes into hash buffer and */
|
||||
/* call the hash_compile function as required. */
|
||||
|
||||
VOID_RETURN sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1])
|
||||
{
|
||||
uint_32t pos = (uint_32t)(ctx->count[0] & SHA1_MASK),
|
||||
space = SHA1_BLOCK_SIZE - pos;
|
||||
const unsigned char *sp = data;
|
||||
|
||||
if((ctx->count[0] += len) < len)
|
||||
++(ctx->count[1]);
|
||||
|
||||
while(len >= space) /* tranfer whole blocks if possible */
|
||||
{
|
||||
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space);
|
||||
sp += space; len -= space; space = SHA1_BLOCK_SIZE; pos = 0;
|
||||
bsw_32(ctx->wbuf, SHA1_BLOCK_SIZE >> 2);
|
||||
sha1_compile(ctx);
|
||||
}
|
||||
|
||||
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len);
|
||||
}
|
||||
|
||||
/* SHA1 final padding and digest calculation */
|
||||
|
||||
VOID_RETURN sha1_end(unsigned char hval[], sha1_ctx ctx[1])
|
||||
{ uint_32t i = (uint_32t)(ctx->count[0] & SHA1_MASK);
|
||||
|
||||
/* put bytes in the buffer in an order in which references to */
|
||||
/* 32-bit words will put bytes with lower addresses into the */
|
||||
/* top of 32 bit words on BOTH big and little endian machines */
|
||||
bsw_32(ctx->wbuf, (i + 3) >> 2);
|
||||
|
||||
/* we now need to mask valid bytes and add the padding which is */
|
||||
/* a single 1 bit and as many zero bits as necessary. Note that */
|
||||
/* we can always add the first padding byte here because the */
|
||||
/* buffer always has at least one empty slot */
|
||||
ctx->wbuf[i >> 2] &= 0xffffff80 << 8 * (~i & 3);
|
||||
ctx->wbuf[i >> 2] |= 0x00000080 << 8 * (~i & 3);
|
||||
|
||||
/* we need 9 or more empty positions, one for the padding byte */
|
||||
/* (above) and eight for the length count. If there is not */
|
||||
/* enough space, pad and empty the buffer */
|
||||
if(i > SHA1_BLOCK_SIZE - 9)
|
||||
{
|
||||
if(i < 60) ctx->wbuf[15] = 0;
|
||||
sha1_compile(ctx);
|
||||
i = 0;
|
||||
}
|
||||
else /* compute a word index for the empty buffer positions */
|
||||
i = (i >> 2) + 1;
|
||||
|
||||
while(i < 14) /* and zero pad all but last two positions */
|
||||
ctx->wbuf[i++] = 0;
|
||||
|
||||
/* the following 32-bit length fields are assembled in the */
|
||||
/* wrong byte order on little endian machines but this is */
|
||||
/* corrected later since they are only ever used as 32-bit */
|
||||
/* word values. */
|
||||
ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29);
|
||||
ctx->wbuf[15] = ctx->count[0] << 3;
|
||||
sha1_compile(ctx);
|
||||
|
||||
/* extract the hash value as bytes in case the hash buffer is */
|
||||
/* misaligned for 32-bit words */
|
||||
for(i = 0; i < SHA1_DIGEST_SIZE; ++i)
|
||||
hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3)));
|
||||
}
|
||||
|
||||
VOID_RETURN bg_sha1(unsigned char hval[], const unsigned char data[], unsigned long len)
|
||||
{ sha1_ctx cx[1];
|
||||
|
||||
sha1_begin(cx); sha1_hash(data, len, cx); sha1_end(hval, cx);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 01/08/2005
|
||||
*/
|
||||
|
||||
#ifndef _SHA1_H
|
||||
#define _SHA1_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "brg_types.h"
|
||||
|
||||
#define SHA1_BLOCK_SIZE 64
|
||||
#define SHA1_DIGEST_SIZE 20
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* type to hold the SHA256 context */
|
||||
|
||||
typedef struct
|
||||
{ uint_32t count[2];
|
||||
uint_32t hash[5];
|
||||
uint_32t wbuf[16];
|
||||
} sha1_ctx;
|
||||
|
||||
/* Note that these prototypes are the same for both bit and */
|
||||
/* byte oriented implementations. However the length fields */
|
||||
/* are in bytes or bits as appropriate for the version used */
|
||||
/* and bit sequences are input as arrays of bytes in which */
|
||||
/* bit sequences run from the most to the least significant */
|
||||
/* end of each byte */
|
||||
|
||||
VOID_RETURN sha1_compile(sha1_ctx ctx[1]);
|
||||
|
||||
VOID_RETURN sha1_begin(sha1_ctx ctx[1]);
|
||||
VOID_RETURN sha1_hash(const unsigned char data[], unsigned long len, sha1_ctx ctx[1]);
|
||||
VOID_RETURN sha1_end(unsigned char hval[], sha1_ctx ctx[1]);
|
||||
VOID_RETURN sha1(unsigned char hval[], const unsigned char data[], unsigned long len);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+774
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 01/08/2005
|
||||
|
||||
This is a byte oriented version of SHA2 that operates on arrays of bytes
|
||||
stored in memory. This code implements sha256, sha384 and sha512 but the
|
||||
latter two functions rely on efficient 64-bit integer operations that
|
||||
may not be very efficient on 32-bit machines
|
||||
|
||||
The sha256 functions use a type 'sha256_ctx' to hold details of the
|
||||
current hash state and uses the following three calls:
|
||||
|
||||
void sha256_begin(sha256_ctx ctx[1])
|
||||
void sha256_hash(const unsigned char data[],
|
||||
unsigned long len, sha256_ctx ctx[1])
|
||||
void sha_end1(unsigned char hval[], sha256_ctx ctx[1])
|
||||
|
||||
The first subroutine initialises a hash computation by setting up the
|
||||
context in the sha256_ctx context. The second subroutine hashes 8-bit
|
||||
bytes from array data[] into the hash state withinh sha256_ctx context,
|
||||
the number of bytes to be hashed being given by the the unsigned long
|
||||
integer len. The third subroutine completes the hash calculation and
|
||||
places the resulting digest value in the array of 8-bit bytes hval[].
|
||||
|
||||
The sha384 and sha512 functions are similar and use the interfaces:
|
||||
|
||||
void sha384_begin(sha384_ctx ctx[1]);
|
||||
void sha384_hash(const unsigned char data[],
|
||||
unsigned long len, sha384_ctx ctx[1]);
|
||||
void sha384_end(unsigned char hval[], sha384_ctx ctx[1]);
|
||||
|
||||
void sha512_begin(sha512_ctx ctx[1]);
|
||||
void sha512_hash(const unsigned char data[],
|
||||
unsigned long len, sha512_ctx ctx[1]);
|
||||
void sha512_end(unsigned char hval[], sha512_ctx ctx[1]);
|
||||
|
||||
In addition there is a function sha2 that can be used to call all these
|
||||
functions using a call with a hash length parameter as follows:
|
||||
|
||||
int sha2_begin(unsigned long len, sha2_ctx ctx[1]);
|
||||
void sha2_hash(const unsigned char data[],
|
||||
unsigned long len, sha2_ctx ctx[1]);
|
||||
void sha2_end(unsigned char hval[], sha2_ctx ctx[1]);
|
||||
|
||||
My thanks to Erik Andersen <andersen@codepoet.org> for testing this code
|
||||
on big-endian systems and for his assistance with corrections
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#define UNROLL_SHA2 /* for SHA2 loop unroll */
|
||||
#endif
|
||||
|
||||
#include <string.h> /* for memcpy() etc. */
|
||||
|
||||
#include "sha2.h"
|
||||
|
||||
//#include "brg_endian.h"
|
||||
#include "bg2zrtp.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER ) && ( _MSC_VER > 800 )
|
||||
#pragma intrinsic(memcpy)
|
||||
#endif
|
||||
|
||||
#if 0 && defined(_MSC_VER)
|
||||
#define rotl32 _lrotl
|
||||
#define rotr32 _lrotr
|
||||
#else
|
||||
#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
|
||||
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
|
||||
#endif
|
||||
|
||||
#if !defined(bswap_32)
|
||||
#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00))
|
||||
#endif
|
||||
|
||||
#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN)
|
||||
#define SWAP_BYTES
|
||||
#else
|
||||
#undef SWAP_BYTES
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
|
||||
#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
|
||||
#else /* Thanks to Rich Schroeppel and Colin Plumb for the following */
|
||||
|
||||
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
|
||||
|
||||
#endif
|
||||
|
||||
/* round transforms for SHA256 and SHA512 compression functions */
|
||||
|
||||
#define vf(n,i) v[(n - i) & 7]
|
||||
|
||||
#define hf(i) (p[i & 15] += \
|
||||
g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15]))
|
||||
|
||||
#define v_cycle(i,j) \
|
||||
vf(7,i) += (j ? hf(i) : p[i]) + k_0[i+j] \
|
||||
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
|
||||
vf(3,i) += vf(7,i); \
|
||||
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
|
||||
|
||||
#if defined(SHA_224) || defined(SHA_256)
|
||||
|
||||
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1)
|
||||
|
||||
#if defined(SWAP_BYTES)
|
||||
#define bsw_32(p,n) \
|
||||
{ int _i = (n); while(_i--) ((uint_32t*)p)[_i] = bswap_32(((uint_32t*)p)[_i]); }
|
||||
#else
|
||||
#define bsw_32(p,n)
|
||||
#endif
|
||||
|
||||
#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
|
||||
#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
|
||||
#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
|
||||
#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
|
||||
#define k_0 k256
|
||||
|
||||
/* rotated SHA256 round definition. Rather than swapping variables as in */
|
||||
/* FIPS-180, different variables are 'rotated' on each round, returning */
|
||||
/* to their starting positions every eight rounds */
|
||||
|
||||
#define q(n) v##n
|
||||
|
||||
#define one_cycle(a,b,c,d,e,f,g,h,k,w) \
|
||||
q(h) += s_1(q(e)) + ch(q(e), q(f), q(g)) + k + w; \
|
||||
q(d) += q(h); q(h) += s_0(q(a)) + maj(q(a), q(b), q(c))
|
||||
|
||||
/* SHA256 mixing data */
|
||||
|
||||
const uint_32t k256[64] =
|
||||
{ 0x428a2f98ul, 0x71374491ul, 0xb5c0fbcful, 0xe9b5dba5ul,
|
||||
0x3956c25bul, 0x59f111f1ul, 0x923f82a4ul, 0xab1c5ed5ul,
|
||||
0xd807aa98ul, 0x12835b01ul, 0x243185beul, 0x550c7dc3ul,
|
||||
0x72be5d74ul, 0x80deb1feul, 0x9bdc06a7ul, 0xc19bf174ul,
|
||||
0xe49b69c1ul, 0xefbe4786ul, 0x0fc19dc6ul, 0x240ca1ccul,
|
||||
0x2de92c6ful, 0x4a7484aaul, 0x5cb0a9dcul, 0x76f988daul,
|
||||
0x983e5152ul, 0xa831c66dul, 0xb00327c8ul, 0xbf597fc7ul,
|
||||
0xc6e00bf3ul, 0xd5a79147ul, 0x06ca6351ul, 0x14292967ul,
|
||||
0x27b70a85ul, 0x2e1b2138ul, 0x4d2c6dfcul, 0x53380d13ul,
|
||||
0x650a7354ul, 0x766a0abbul, 0x81c2c92eul, 0x92722c85ul,
|
||||
0xa2bfe8a1ul, 0xa81a664bul, 0xc24b8b70ul, 0xc76c51a3ul,
|
||||
0xd192e819ul, 0xd6990624ul, 0xf40e3585ul, 0x106aa070ul,
|
||||
0x19a4c116ul, 0x1e376c08ul, 0x2748774cul, 0x34b0bcb5ul,
|
||||
0x391c0cb3ul, 0x4ed8aa4aul, 0x5b9cca4ful, 0x682e6ff3ul,
|
||||
0x748f82eeul, 0x78a5636ful, 0x84c87814ul, 0x8cc70208ul,
|
||||
0x90befffaul, 0xa4506cebul, 0xbef9a3f7ul, 0xc67178f2ul,
|
||||
};
|
||||
|
||||
/* Compile 64 bytes of hash data into SHA256 digest value */
|
||||
/* NOTE: this routine assumes that the byte order in the */
|
||||
/* ctx->wbuf[] at this point is such that low address bytes */
|
||||
/* in the ORIGINAL byte stream will go into the high end of */
|
||||
/* words on BOTH big and little endian systems */
|
||||
|
||||
VOID_RETURN sha256_compile(sha256_ctx ctx[1])
|
||||
{
|
||||
#if !defined(UNROLL_SHA2)
|
||||
|
||||
uint_32t j, *p = ctx->wbuf, v[8];
|
||||
|
||||
memcpy(v, ctx->hash, 8 * sizeof(uint_32t));
|
||||
|
||||
for(j = 0; j < 64; j += 16)
|
||||
{
|
||||
v_cycle( 0, j); v_cycle( 1, j);
|
||||
v_cycle( 2, j); v_cycle( 3, j);
|
||||
v_cycle( 4, j); v_cycle( 5, j);
|
||||
v_cycle( 6, j); v_cycle( 7, j);
|
||||
v_cycle( 8, j); v_cycle( 9, j);
|
||||
v_cycle(10, j); v_cycle(11, j);
|
||||
v_cycle(12, j); v_cycle(13, j);
|
||||
v_cycle(14, j); v_cycle(15, j);
|
||||
}
|
||||
|
||||
ctx->hash[0] += v[0]; ctx->hash[1] += v[1];
|
||||
ctx->hash[2] += v[2]; ctx->hash[3] += v[3];
|
||||
ctx->hash[4] += v[4]; ctx->hash[5] += v[5];
|
||||
ctx->hash[6] += v[6]; ctx->hash[7] += v[7];
|
||||
|
||||
#else
|
||||
|
||||
uint_32t *p = ctx->wbuf,v0,v1,v2,v3,v4,v5,v6,v7;
|
||||
|
||||
v0 = ctx->hash[0]; v1 = ctx->hash[1];
|
||||
v2 = ctx->hash[2]; v3 = ctx->hash[3];
|
||||
v4 = ctx->hash[4]; v5 = ctx->hash[5];
|
||||
v6 = ctx->hash[6]; v7 = ctx->hash[7];
|
||||
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[ 0],p[ 0]);
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[ 1],p[ 1]);
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[ 2],p[ 2]);
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[ 3],p[ 3]);
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[ 4],p[ 4]);
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[ 5],p[ 5]);
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[ 6],p[ 6]);
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[ 7],p[ 7]);
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[ 8],p[ 8]);
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[ 9],p[ 9]);
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[10],p[10]);
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[11],p[11]);
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[12],p[12]);
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[13],p[13]);
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[14],p[14]);
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[15],p[15]);
|
||||
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[16],hf( 0));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[17],hf( 1));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[18],hf( 2));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[19],hf( 3));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[20],hf( 4));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[21],hf( 5));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[22],hf( 6));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[23],hf( 7));
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[24],hf( 8));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[25],hf( 9));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[26],hf(10));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[27],hf(11));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[28],hf(12));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[29],hf(13));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[30],hf(14));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[31],hf(15));
|
||||
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[32],hf( 0));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[33],hf( 1));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[34],hf( 2));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[35],hf( 3));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[36],hf( 4));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[37],hf( 5));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[38],hf( 6));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[39],hf( 7));
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[40],hf( 8));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[41],hf( 9));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[42],hf(10));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[43],hf(11));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[44],hf(12));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[45],hf(13));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[46],hf(14));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[47],hf(15));
|
||||
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[48],hf( 0));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[49],hf( 1));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[50],hf( 2));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[51],hf( 3));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[52],hf( 4));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[53],hf( 5));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[54],hf( 6));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[55],hf( 7));
|
||||
one_cycle(0,1,2,3,4,5,6,7,k256[56],hf( 8));
|
||||
one_cycle(7,0,1,2,3,4,5,6,k256[57],hf( 9));
|
||||
one_cycle(6,7,0,1,2,3,4,5,k256[58],hf(10));
|
||||
one_cycle(5,6,7,0,1,2,3,4,k256[59],hf(11));
|
||||
one_cycle(4,5,6,7,0,1,2,3,k256[60],hf(12));
|
||||
one_cycle(3,4,5,6,7,0,1,2,k256[61],hf(13));
|
||||
one_cycle(2,3,4,5,6,7,0,1,k256[62],hf(14));
|
||||
one_cycle(1,2,3,4,5,6,7,0,k256[63],hf(15));
|
||||
|
||||
ctx->hash[0] += v0; ctx->hash[1] += v1;
|
||||
ctx->hash[2] += v2; ctx->hash[3] += v3;
|
||||
ctx->hash[4] += v4; ctx->hash[5] += v5;
|
||||
ctx->hash[6] += v6; ctx->hash[7] += v7;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* SHA256 hash data in an array of bytes into hash buffer */
|
||||
/* and call the hash_compile function as required. */
|
||||
|
||||
VOID_RETURN sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1])
|
||||
{ uint_32t pos = (uint_32t)(ctx->count[0] & SHA256_MASK),
|
||||
space = SHA256_BLOCK_SIZE - pos;
|
||||
const unsigned char *sp = data;
|
||||
|
||||
if((ctx->count[0] += len) < len)
|
||||
++(ctx->count[1]);
|
||||
|
||||
while(len >= space) /* tranfer whole blocks while possible */
|
||||
{
|
||||
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space);
|
||||
sp += space; len -= space; space = SHA256_BLOCK_SIZE; pos = 0;
|
||||
bsw_32(ctx->wbuf, SHA256_BLOCK_SIZE >> 2)
|
||||
sha256_compile(ctx);
|
||||
}
|
||||
|
||||
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len);
|
||||
}
|
||||
|
||||
/* SHA256 Final padding and digest calculation */
|
||||
|
||||
static void sha_end1(unsigned char hval[], sha256_ctx ctx[1], const unsigned int hlen)
|
||||
{ uint_32t i = (uint_32t)(ctx->count[0] & SHA256_MASK);
|
||||
|
||||
/* put bytes in the buffer in an order in which references to */
|
||||
/* 32-bit words will put bytes with lower addresses into the */
|
||||
/* top of 32 bit words on BOTH big and little endian machines */
|
||||
bsw_32(ctx->wbuf, (i + 3) >> 2)
|
||||
|
||||
/* we now need to mask valid bytes and add the padding which is */
|
||||
/* a single 1 bit and as many zero bits as necessary. Note that */
|
||||
/* we can always add the first padding byte here because the */
|
||||
/* buffer always has at least one empty slot */
|
||||
ctx->wbuf[i >> 2] &= 0xffffff80 << 8 * (~i & 3);
|
||||
ctx->wbuf[i >> 2] |= 0x00000080 << 8 * (~i & 3);
|
||||
|
||||
/* we need 9 or more empty positions, one for the padding byte */
|
||||
/* (above) and eight for the length count. If there is not */
|
||||
/* enough space pad and empty the buffer */
|
||||
if(i > SHA256_BLOCK_SIZE - 9)
|
||||
{
|
||||
if(i < 60) ctx->wbuf[15] = 0;
|
||||
sha256_compile(ctx);
|
||||
i = 0;
|
||||
}
|
||||
else /* compute a word index for the empty buffer positions */
|
||||
i = (i >> 2) + 1;
|
||||
|
||||
while(i < 14) /* and zero pad all but last two positions */
|
||||
ctx->wbuf[i++] = 0;
|
||||
|
||||
/* the following 32-bit length fields are assembled in the */
|
||||
/* wrong byte order on little endian machines but this is */
|
||||
/* corrected later since they are only ever used as 32-bit */
|
||||
/* word values. */
|
||||
ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29);
|
||||
ctx->wbuf[15] = ctx->count[0] << 3;
|
||||
sha256_compile(ctx);
|
||||
|
||||
/* extract the hash value as bytes in case the hash buffer is */
|
||||
/* mislaigned for 32-bit words */
|
||||
for(i = 0; i < hlen; ++i)
|
||||
hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_224)
|
||||
|
||||
const uint_32t i224[8] =
|
||||
{
|
||||
0xc1059ed8ul, 0x367cd507ul, 0x3070dd17ul, 0xf70e5939ul,
|
||||
0xffc00b31ul, 0x68581511ul, 0x64f98fa7ul, 0xbefa4fa4ul
|
||||
};
|
||||
|
||||
VOID_RETURN sha224_begin(sha224_ctx ctx[1])
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
memcpy(ctx->hash, i224, 8 * sizeof(uint_32t));
|
||||
}
|
||||
|
||||
VOID_RETURN sha224_end(unsigned char hval[], sha224_ctx ctx[1])
|
||||
{
|
||||
sha_end1(hval, ctx, SHA224_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
VOID_RETURN sha224(unsigned char hval[], const unsigned char data[], unsigned long len)
|
||||
{ sha224_ctx cx[1];
|
||||
|
||||
sha224_begin(cx);
|
||||
sha224_hash(data, len, cx);
|
||||
sha_end1(hval, cx, SHA224_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_256)
|
||||
|
||||
const uint_32t i256[8] =
|
||||
{
|
||||
0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul,
|
||||
0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul
|
||||
};
|
||||
|
||||
VOID_RETURN sha256_begin(sha256_ctx ctx[1])
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
memcpy(ctx->hash, i256, 8 * sizeof(uint_32t));
|
||||
}
|
||||
|
||||
VOID_RETURN sha256_end(unsigned char hval[], sha256_ctx ctx[1])
|
||||
{
|
||||
sha_end1(hval, ctx, SHA256_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
VOID_RETURN sha256(unsigned char hval[], const unsigned char data[], unsigned long len)
|
||||
{ sha256_ctx cx[1];
|
||||
|
||||
sha256_begin(cx);
|
||||
sha256_hash(data, len, cx);
|
||||
sha_end1(hval, cx, SHA256_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_384) || defined(SHA_512)
|
||||
|
||||
#define SHA512_MASK (SHA512_BLOCK_SIZE - 1)
|
||||
|
||||
#define rotr64(x,n) (((x) >> n) | ((x) << (64 - n)))
|
||||
|
||||
#if !defined(bswap_64)
|
||||
#define bswap_64(x) (((uint_64t)(bswap_32((uint_32t)(x)))) << 32 | bswap_32((uint_32t)((x) >> 32)))
|
||||
#endif
|
||||
|
||||
#if defined(SWAP_BYTES)
|
||||
#define bsw_64(p,n) \
|
||||
{ int _i = (n); while(_i--) ((uint_64t*)p)[_i] = bswap_64(((uint_64t*)p)[_i]); }
|
||||
#else
|
||||
#define bsw_64(p,n)
|
||||
#endif
|
||||
|
||||
/* SHA512 mixing function definitions */
|
||||
|
||||
#ifdef s_0
|
||||
# undef s_0
|
||||
# undef s_1
|
||||
# undef g_0
|
||||
# undef g_1
|
||||
# undef k_0
|
||||
#endif
|
||||
|
||||
#define s_0(x) (rotr64((x), 28) ^ rotr64((x), 34) ^ rotr64((x), 39))
|
||||
#define s_1(x) (rotr64((x), 14) ^ rotr64((x), 18) ^ rotr64((x), 41))
|
||||
#define g_0(x) (rotr64((x), 1) ^ rotr64((x), 8) ^ ((x) >> 7))
|
||||
#define g_1(x) (rotr64((x), 19) ^ rotr64((x), 61) ^ ((x) >> 6))
|
||||
#define k_0 k512
|
||||
|
||||
/* SHA384/SHA512 mixing data */
|
||||
|
||||
const uint_64t k512[80] =
|
||||
{
|
||||
li_64(428a2f98d728ae22), li_64(7137449123ef65cd),
|
||||
li_64(b5c0fbcfec4d3b2f), li_64(e9b5dba58189dbbc),
|
||||
li_64(3956c25bf348b538), li_64(59f111f1b605d019),
|
||||
li_64(923f82a4af194f9b), li_64(ab1c5ed5da6d8118),
|
||||
li_64(d807aa98a3030242), li_64(12835b0145706fbe),
|
||||
li_64(243185be4ee4b28c), li_64(550c7dc3d5ffb4e2),
|
||||
li_64(72be5d74f27b896f), li_64(80deb1fe3b1696b1),
|
||||
li_64(9bdc06a725c71235), li_64(c19bf174cf692694),
|
||||
li_64(e49b69c19ef14ad2), li_64(efbe4786384f25e3),
|
||||
li_64(0fc19dc68b8cd5b5), li_64(240ca1cc77ac9c65),
|
||||
li_64(2de92c6f592b0275), li_64(4a7484aa6ea6e483),
|
||||
li_64(5cb0a9dcbd41fbd4), li_64(76f988da831153b5),
|
||||
li_64(983e5152ee66dfab), li_64(a831c66d2db43210),
|
||||
li_64(b00327c898fb213f), li_64(bf597fc7beef0ee4),
|
||||
li_64(c6e00bf33da88fc2), li_64(d5a79147930aa725),
|
||||
li_64(06ca6351e003826f), li_64(142929670a0e6e70),
|
||||
li_64(27b70a8546d22ffc), li_64(2e1b21385c26c926),
|
||||
li_64(4d2c6dfc5ac42aed), li_64(53380d139d95b3df),
|
||||
li_64(650a73548baf63de), li_64(766a0abb3c77b2a8),
|
||||
li_64(81c2c92e47edaee6), li_64(92722c851482353b),
|
||||
li_64(a2bfe8a14cf10364), li_64(a81a664bbc423001),
|
||||
li_64(c24b8b70d0f89791), li_64(c76c51a30654be30),
|
||||
li_64(d192e819d6ef5218), li_64(d69906245565a910),
|
||||
li_64(f40e35855771202a), li_64(106aa07032bbd1b8),
|
||||
li_64(19a4c116b8d2d0c8), li_64(1e376c085141ab53),
|
||||
li_64(2748774cdf8eeb99), li_64(34b0bcb5e19b48a8),
|
||||
li_64(391c0cb3c5c95a63), li_64(4ed8aa4ae3418acb),
|
||||
li_64(5b9cca4f7763e373), li_64(682e6ff3d6b2b8a3),
|
||||
li_64(748f82ee5defb2fc), li_64(78a5636f43172f60),
|
||||
li_64(84c87814a1f0ab72), li_64(8cc702081a6439ec),
|
||||
li_64(90befffa23631e28), li_64(a4506cebde82bde9),
|
||||
li_64(bef9a3f7b2c67915), li_64(c67178f2e372532b),
|
||||
li_64(ca273eceea26619c), li_64(d186b8c721c0c207),
|
||||
li_64(eada7dd6cde0eb1e), li_64(f57d4f7fee6ed178),
|
||||
li_64(06f067aa72176fba), li_64(0a637dc5a2c898a6),
|
||||
li_64(113f9804bef90dae), li_64(1b710b35131c471b),
|
||||
li_64(28db77f523047d84), li_64(32caab7b40c72493),
|
||||
li_64(3c9ebe0a15c9bebc), li_64(431d67c49c100d4c),
|
||||
li_64(4cc5d4becb3e42b6), li_64(597f299cfc657e2a),
|
||||
li_64(5fcb6fab3ad6faec), li_64(6c44198c4a475817)
|
||||
};
|
||||
|
||||
/* Compile 128 bytes of hash data into SHA384/512 digest */
|
||||
/* NOTE: this routine assumes that the byte order in the */
|
||||
/* ctx->wbuf[] at this point is such that low address bytes */
|
||||
/* in the ORIGINAL byte stream will go into the high end of */
|
||||
/* words on BOTH big and little endian systems */
|
||||
|
||||
VOID_RETURN sha512_compile(sha512_ctx ctx[1])
|
||||
{ uint_64t v[8], *p = ctx->wbuf;
|
||||
uint_32t j;
|
||||
|
||||
memcpy(v, ctx->hash, 8 * sizeof(uint_64t));
|
||||
|
||||
for(j = 0; j < 80; j += 16)
|
||||
{
|
||||
v_cycle( 0, j); v_cycle( 1, j);
|
||||
v_cycle( 2, j); v_cycle( 3, j);
|
||||
v_cycle( 4, j); v_cycle( 5, j);
|
||||
v_cycle( 6, j); v_cycle( 7, j);
|
||||
v_cycle( 8, j); v_cycle( 9, j);
|
||||
v_cycle(10, j); v_cycle(11, j);
|
||||
v_cycle(12, j); v_cycle(13, j);
|
||||
v_cycle(14, j); v_cycle(15, j);
|
||||
}
|
||||
|
||||
ctx->hash[0] += v[0]; ctx->hash[1] += v[1];
|
||||
ctx->hash[2] += v[2]; ctx->hash[3] += v[3];
|
||||
ctx->hash[4] += v[4]; ctx->hash[5] += v[5];
|
||||
ctx->hash[6] += v[6]; ctx->hash[7] += v[7];
|
||||
}
|
||||
|
||||
/* Compile 128 bytes of hash data into SHA256 digest value */
|
||||
/* NOTE: this routine assumes that the byte order in the */
|
||||
/* ctx->wbuf[] at this point is in such an order that low */
|
||||
/* address bytes in the ORIGINAL byte stream placed in this */
|
||||
/* buffer will now go to the high end of words on BOTH big */
|
||||
/* and little endian systems */
|
||||
|
||||
VOID_RETURN sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1])
|
||||
{ uint_32t pos = (uint_32t)(ctx->count[0] & SHA512_MASK),
|
||||
space = SHA512_BLOCK_SIZE - pos;
|
||||
const unsigned char *sp = data;
|
||||
|
||||
if((ctx->count[0] += len) < len)
|
||||
++(ctx->count[1]);
|
||||
|
||||
while(len >= space) /* tranfer whole blocks while possible */
|
||||
{
|
||||
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space);
|
||||
sp += space; len -= space; space = SHA512_BLOCK_SIZE; pos = 0;
|
||||
bsw_64(ctx->wbuf, SHA512_BLOCK_SIZE >> 3);
|
||||
sha512_compile(ctx);
|
||||
}
|
||||
|
||||
memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len);
|
||||
}
|
||||
|
||||
/* SHA384/512 Final padding and digest calculation */
|
||||
|
||||
static void sha_end2(unsigned char hval[], sha512_ctx ctx[1], const unsigned int hlen)
|
||||
{ uint_32t i = (uint_32t)(ctx->count[0] & SHA512_MASK);
|
||||
|
||||
/* put bytes in the buffer in an order in which references to */
|
||||
/* 32-bit words will put bytes with lower addresses into the */
|
||||
/* top of 32 bit words on BOTH big and little endian machines */
|
||||
bsw_64(ctx->wbuf, (i + 7) >> 3);
|
||||
|
||||
/* we now need to mask valid bytes and add the padding which is */
|
||||
/* a single 1 bit and as many zero bits as necessary. Note that */
|
||||
/* we can always add the first padding byte here because the */
|
||||
/* buffer always has at least one empty slot */
|
||||
ctx->wbuf[i >> 3] &= li_64(ffffffffffffff00) << 8 * (~i & 7);
|
||||
ctx->wbuf[i >> 3] |= li_64(0000000000000080) << 8 * (~i & 7);
|
||||
|
||||
/* we need 17 or more empty byte positions, one for the padding */
|
||||
/* byte (above) and sixteen for the length count. If there is */
|
||||
/* not enough space pad and empty the buffer */
|
||||
if(i > SHA512_BLOCK_SIZE - 17)
|
||||
{
|
||||
if(i < 120) ctx->wbuf[15] = 0;
|
||||
sha512_compile(ctx);
|
||||
i = 0;
|
||||
}
|
||||
else
|
||||
i = (i >> 3) + 1;
|
||||
|
||||
while(i < 14)
|
||||
ctx->wbuf[i++] = 0;
|
||||
|
||||
/* the following 64-bit length fields are assembled in the */
|
||||
/* wrong byte order on little endian machines but this is */
|
||||
/* corrected later since they are only ever used as 64-bit */
|
||||
/* word values. */
|
||||
ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 61);
|
||||
ctx->wbuf[15] = ctx->count[0] << 3;
|
||||
sha512_compile(ctx);
|
||||
|
||||
/* extract the hash value as bytes in case the hash buffer is */
|
||||
/* misaligned for 32-bit words */
|
||||
for(i = 0; i < hlen; ++i)
|
||||
hval[i] = (unsigned char)(ctx->hash[i >> 3] >> (8 * (~i & 7)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_384)
|
||||
|
||||
/* SHA384 initialisation data */
|
||||
|
||||
const uint_64t i384[80] =
|
||||
{
|
||||
li_64(cbbb9d5dc1059ed8), li_64(629a292a367cd507),
|
||||
li_64(9159015a3070dd17), li_64(152fecd8f70e5939),
|
||||
li_64(67332667ffc00b31), li_64(8eb44a8768581511),
|
||||
li_64(db0c2e0d64f98fa7), li_64(47b5481dbefa4fa4)
|
||||
};
|
||||
|
||||
VOID_RETURN sha384_begin(sha384_ctx ctx[1])
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
memcpy(ctx->hash, i384, 8 * sizeof(uint_64t));
|
||||
}
|
||||
|
||||
VOID_RETURN sha384_end(unsigned char hval[], sha384_ctx ctx[1])
|
||||
{
|
||||
sha_end2(hval, ctx, SHA384_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
VOID_RETURN sha384(unsigned char hval[], const unsigned char data[], unsigned long len)
|
||||
{ sha384_ctx cx[1];
|
||||
|
||||
sha384_begin(cx);
|
||||
sha384_hash(data, len, cx);
|
||||
sha_end2(hval, cx, SHA384_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_512)
|
||||
|
||||
/* SHA512 initialisation data */
|
||||
|
||||
const uint_64t i512[80] =
|
||||
{
|
||||
li_64(6a09e667f3bcc908), li_64(bb67ae8584caa73b),
|
||||
li_64(3c6ef372fe94f82b), li_64(a54ff53a5f1d36f1),
|
||||
li_64(510e527fade682d1), li_64(9b05688c2b3e6c1f),
|
||||
li_64(1f83d9abfb41bd6b), li_64(5be0cd19137e2179)
|
||||
};
|
||||
|
||||
VOID_RETURN sha512_begin(sha512_ctx ctx[1])
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
memcpy(ctx->hash, i512, 8 * sizeof(uint_64t));
|
||||
}
|
||||
|
||||
VOID_RETURN sha512_end(unsigned char hval[], sha512_ctx ctx[1])
|
||||
{
|
||||
sha_end2(hval, ctx, SHA512_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
VOID_RETURN sha512(unsigned char hval[], const unsigned char data[], unsigned long len)
|
||||
{ sha512_ctx cx[1];
|
||||
|
||||
sha512_begin(cx);
|
||||
sha512_hash(data, len, cx);
|
||||
sha_end2(hval, cx, SHA512_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SHA_2)
|
||||
|
||||
#define CTX_224(x) ((x)->uu->ctx256)
|
||||
#define CTX_256(x) ((x)->uu->ctx256)
|
||||
#define CTX_384(x) ((x)->uu->ctx512)
|
||||
#define CTX_512(x) ((x)->uu->ctx512)
|
||||
|
||||
/* SHA2 initialisation */
|
||||
|
||||
INT_RETURN sha2_begin(unsigned long len, sha2_ctx ctx[1])
|
||||
{
|
||||
switch(len)
|
||||
{
|
||||
#if defined(SHA_224)
|
||||
case 224:
|
||||
case 28: CTX_256(ctx)->count[0] = CTX_256(ctx)->count[1] = 0;
|
||||
memcpy(CTX_256(ctx)->hash, i224, 32);
|
||||
ctx->sha2_len = 28; return EXIT_SUCCESS;
|
||||
#endif
|
||||
#if defined(SHA_256)
|
||||
case 256:
|
||||
case 32: CTX_256(ctx)->count[0] = CTX_256(ctx)->count[1] = 0;
|
||||
memcpy(CTX_256(ctx)->hash, i256, 32);
|
||||
ctx->sha2_len = 32; return EXIT_SUCCESS;
|
||||
#endif
|
||||
#if defined(SHA_384)
|
||||
case 384:
|
||||
case 48: CTX_384(ctx)->count[0] = CTX_384(ctx)->count[1] = 0;
|
||||
memcpy(CTX_384(ctx)->hash, i384, 64);
|
||||
ctx->sha2_len = 48; return EXIT_SUCCESS;
|
||||
#endif
|
||||
#if defined(SHA_512)
|
||||
case 512:
|
||||
case 64: CTX_512(ctx)->count[0] = CTX_512(ctx)->count[1] = 0;
|
||||
memcpy(CTX_512(ctx)->hash, i512, 64);
|
||||
ctx->sha2_len = 64; return EXIT_SUCCESS;
|
||||
#endif
|
||||
default: return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
VOID_RETURN sha2_hash(const unsigned char data[], unsigned long len, sha2_ctx ctx[1])
|
||||
{
|
||||
switch(ctx->sha2_len)
|
||||
{
|
||||
#if defined(SHA_224)
|
||||
case 28: sha224_hash(data, len, CTX_224(ctx)); return;
|
||||
#endif
|
||||
#if defined(SHA_256)
|
||||
case 32: sha256_hash(data, len, CTX_256(ctx)); return;
|
||||
#endif
|
||||
#if defined(SHA_384)
|
||||
case 48: sha384_hash(data, len, CTX_384(ctx)); return;
|
||||
#endif
|
||||
#if defined(SHA_512)
|
||||
case 64: sha512_hash(data, len, CTX_512(ctx)); return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
VOID_RETURN sha2_end(unsigned char hval[], sha2_ctx ctx[1])
|
||||
{
|
||||
switch(ctx->sha2_len)
|
||||
{
|
||||
#if defined(SHA_224)
|
||||
case 28: sha_end1(hval, CTX_224(ctx), SHA224_DIGEST_SIZE); return;
|
||||
#endif
|
||||
#if defined(SHA_256)
|
||||
case 32: sha_end1(hval, CTX_256(ctx), SHA256_DIGEST_SIZE); return;
|
||||
#endif
|
||||
#if defined(SHA_384)
|
||||
case 48: sha_end2(hval, CTX_384(ctx), SHA384_DIGEST_SIZE); return;
|
||||
#endif
|
||||
#if defined(SHA_512)
|
||||
case 64: sha_end2(hval, CTX_512(ctx), SHA512_DIGEST_SIZE); return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
INT_RETURN sha2(unsigned char hval[], unsigned long size,
|
||||
const unsigned char data[], unsigned long len)
|
||||
{ sha2_ctx cx[1];
|
||||
|
||||
if(sha2_begin(size, cx) == EXIT_SUCCESS)
|
||||
{
|
||||
sha2_hash(data, len, cx); sha2_end(hval, cx); return EXIT_SUCCESS;
|
||||
}
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 01/08/2005
|
||||
*/
|
||||
|
||||
#ifndef _SHA2_H
|
||||
#define _SHA2_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SHA_64BIT
|
||||
|
||||
/* define the hash functions that you need */
|
||||
#define SHA_2 /* for dynamic hash length */
|
||||
#define SHA_224
|
||||
#define SHA_256
|
||||
#ifdef SHA_64BIT
|
||||
# define SHA_384
|
||||
# define SHA_512
|
||||
# define NEED_UINT_64T
|
||||
#endif
|
||||
|
||||
#include "brg_types.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Note that the following function prototypes are the same */
|
||||
/* for both the bit and byte oriented implementations. But */
|
||||
/* the length fields are in bytes or bits as is appropriate */
|
||||
/* for the version used. Bit sequences are arrays of bytes */
|
||||
/* in which bit sequence indexes increase from the most to */
|
||||
/* the least significant end of each byte */
|
||||
|
||||
#define SHA224_DIGEST_SIZE 28
|
||||
#define SHA224_BLOCK_SIZE 64
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
#define SHA256_BLOCK_SIZE 64
|
||||
|
||||
/* type to hold the SHA256 (and SHA224) context */
|
||||
|
||||
typedef struct
|
||||
{ uint_32t count[2];
|
||||
uint_32t hash[8];
|
||||
uint_32t wbuf[16];
|
||||
} sha256_ctx;
|
||||
|
||||
typedef sha256_ctx sha224_ctx;
|
||||
|
||||
VOID_RETURN sha256_compile(sha256_ctx ctx[1]);
|
||||
|
||||
VOID_RETURN sha224_begin(sha224_ctx ctx[1]);
|
||||
#define sha224_hash sha256_hash
|
||||
VOID_RETURN sha224_end(unsigned char hval[], sha224_ctx ctx[1]);
|
||||
VOID_RETURN sha224(unsigned char hval[], const unsigned char data[], unsigned long len);
|
||||
|
||||
VOID_RETURN sha256_begin(sha256_ctx ctx[1]);
|
||||
VOID_RETURN sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1]);
|
||||
VOID_RETURN sha256_end(unsigned char hval[], sha256_ctx ctx[1]);
|
||||
VOID_RETURN sha256(unsigned char hval[], const unsigned char data[], unsigned long len);
|
||||
|
||||
#ifndef SHA_64BIT
|
||||
|
||||
typedef struct
|
||||
{ union
|
||||
{ sha256_ctx ctx256[1];
|
||||
} uu[1];
|
||||
uint_32t sha2_len;
|
||||
} sha2_ctx;
|
||||
|
||||
#define SHA2_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
|
||||
|
||||
#else
|
||||
|
||||
#define SHA384_DIGEST_SIZE 48
|
||||
#define SHA384_BLOCK_SIZE 128
|
||||
#define SHA512_DIGEST_SIZE 64
|
||||
#define SHA512_BLOCK_SIZE 128
|
||||
#define SHA2_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
|
||||
|
||||
/* type to hold the SHA384 (and SHA512) context */
|
||||
|
||||
typedef struct
|
||||
{ uint_64t count[2];
|
||||
uint_64t hash[8];
|
||||
uint_64t wbuf[16];
|
||||
} sha512_ctx;
|
||||
|
||||
typedef sha512_ctx sha384_ctx;
|
||||
|
||||
typedef struct
|
||||
{ union
|
||||
{ sha256_ctx ctx256[1];
|
||||
sha512_ctx ctx512[1];
|
||||
} uu[1];
|
||||
uint_32t sha2_len;
|
||||
} sha2_ctx;
|
||||
|
||||
VOID_RETURN sha512_compile(sha512_ctx ctx[1]);
|
||||
|
||||
VOID_RETURN sha384_begin(sha384_ctx ctx[1]);
|
||||
#define sha384_hash sha512_hash
|
||||
VOID_RETURN sha384_end(unsigned char hval[], sha384_ctx ctx[1]);
|
||||
VOID_RETURN sha384(unsigned char hval[], const unsigned char data[], unsigned long len);
|
||||
|
||||
VOID_RETURN sha512_begin(sha512_ctx ctx[1]);
|
||||
VOID_RETURN sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1]);
|
||||
VOID_RETURN sha512_end(unsigned char hval[], sha512_ctx ctx[1]);
|
||||
VOID_RETURN sha512(unsigned char hval[], const unsigned char data[], unsigned long len);
|
||||
|
||||
INT_RETURN sha2_begin(unsigned long size, sha2_ctx ctx[1]);
|
||||
VOID_RETURN sha2_hash(const unsigned char data[], unsigned long len, sha2_ctx ctx[1]);
|
||||
VOID_RETURN sha2_end(unsigned char hval[], sha2_ctx ctx[1]);
|
||||
INT_RETURN sha2(unsigned char hval[], unsigned long size, const unsigned char data[], unsigned long len);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
1.1.4
|
||||
- Added bnBasePrecompCopy, bnDoubleBasePrecompExpMod, and corresponding
|
||||
lbn* functions.
|
||||
- Fixed some stupid bugs in bnExtractBigBytes and bnExtractLittleBytes
|
||||
when asking for more bytes than the numbers have.
|
||||
|
||||
1.1.3
|
||||
1999-05-09
|
||||
- Added bnBasePrecompBegin, bnBasePrecompEnd and bnBasePrecompExpMod,
|
||||
and corresponding lbn* functions.
|
||||
- Added some rudimentary tests of the above to bntest.
|
||||
- Updated dsatest to use the new functions. Speedup on 1024 bits seems
|
||||
to be about 3x.
|
||||
|
||||
1.1.2:
|
||||
1998-06-22
|
||||
- Added bnReadBit function
|
||||
- Fixed corruption in bnMakeOdd_16
|
||||
- Clarified comments in germain.c
|
||||
- Fixed nasty bug in lbnModQ_16 in lbn80386.asm
|
||||
- renamed rand parameter to randFunc in prime.c to avoid warnings
|
||||
|
||||
1.1.1:
|
||||
- Cleaned up some test directory code
|
||||
|
||||
1.1: Second public release
|
||||
|
||||
- Generalized Sophie Germain primes to variable "orders",
|
||||
which is the number of 2*p+1 levels that are all prime.
|
||||
An order-0 primeis an ordinary prime. An order-1 prime is
|
||||
a Sophie Germain prime. An order-3 prime also has 4*p+3 prime.
|
||||
(Changed hours before release; I wonder if there are bugs?)
|
||||
- Figured out that if p and 2*p+1 are prime, it's p that's called
|
||||
a Sophie Germain prime, not 2*p+1. germain.c and germtest.c
|
||||
updated accordingly. 2*p+1 is called a "strong prime".
|
||||
- Updated to not use 16-bit MSDOS-isms like "cdecl" with GCC under GO32.
|
||||
- Fixed a bug in primeGen() that caused it to do strange things
|
||||
if the first number in the sieve passed.
|
||||
- Fixed a memory leak in lbnExpMod
|
||||
- Fixed bug in lbn80386.asm lbnModQ_32 (was a complete mess)
|
||||
- Fixed bug in bnDoubleExpMod (one-character change; masked a bug in SKIP!)
|
||||
- Fixed a bug in error recovery in lbnInv
|
||||
- Added out-of-memory checking to bntest
|
||||
- Installation documentation improved, especially for non-Unix platforms.
|
||||
- Preprocessor trickery made compatible with some ancient sort-of-ANSI
|
||||
compilers. To be precise:
|
||||
- Not liking "#if FOO" when FOO is not defined (ANSI says FOO is "0")
|
||||
- Not liking long constants without "l" (ANSI says all pp math is long)
|
||||
- bnInit() made redundant; now called automatically by bnBegin().
|
||||
- bnCmpQ(struct BigNum const *, unsigned) added.
|
||||
- Removed copyright disclaimers from some files so as not to confuse lawyers.
|
||||
- Spell-checked, corrected and improved comments in lbn16.c. Especially
|
||||
added a big description of Montgomery representation.
|
||||
- Added parens a few places to shut up compiler warnings.
|
||||
- Added 386 support for Unix and some GCC-specific inline assembler tricks.
|
||||
- Got rid of some warnings in lbn8086.h.
|
||||
- Improved PowerPC inline assembler for CodeWarrior 8.
|
||||
|
||||
1.0: Initial release (unnumbered, retroactively named 1.0)
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
#
|
||||
# This code is pretty well tested, but not optimizing it will have
|
||||
# a *major* effect on speed, so its optimzation flags are separate
|
||||
# from the rest of the release.
|
||||
#
|
||||
# For the SPARC v8, at least, gcc produces a *much* faster library than
|
||||
# the SunPro C compiler. On a 50 MHz TI TMS390Z50 SuperSPARC:
|
||||
# 14.5 vs. 47.2 ms per 256-bit modular exponentiation.
|
||||
# 77.4 vs. 317.8 ms per 512-bit modular exponentiation.
|
||||
# 249.0 vs. 1031.5 ms per 1024-bit modular exponentiation
|
||||
#
|
||||
CC=gcc
|
||||
# for libzrtp support
|
||||
CFLAGS= -Wno-unused-parameter -fno-strict-aliasing -fPIC -DZRTP_AUTOMAKE=1 -DHAVE_CONFIG_H $(DEFINE) -I../../include -I../../include/enterprise -I../../projects/gnu/config -I../../third_party/bgaes
|
||||
srcdir=.
|
||||
|
||||
|
||||
# Extra object files (e.g. lbnalpha.o for Alpha assembly routines)
|
||||
AUXOBJS=
|
||||
# Extra definitions (e.g. -DBNINCLUDE=lbnalpha.h)
|
||||
DEFINE=
|
||||
|
||||
SHELL = /bin/sh
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .h .o .s
|
||||
|
||||
LD =$(CC)
|
||||
LDFLAGS =
|
||||
LIBS=
|
||||
RANLIB=ranlib
|
||||
|
||||
# If you have a machine-specific assembly file, add it to AUXOBJS.
|
||||
OBJS = bn00.o lbn00.o bn.o lbnmem.o sieve.o prime.o \
|
||||
bnprint.o jacobi.o germain.o $(AUXOBJS)
|
||||
|
||||
BNLIB = libbn.a
|
||||
|
||||
# for libzrtp support
|
||||
all: $(BNLIB) bntest32.c bntest64.c
|
||||
# bntest germtest
|
||||
|
||||
# for libzrtp support
|
||||
install: all
|
||||
test -d /usr/local/include/libzrtp || mkdir /usr/local/include/libzrtp
|
||||
cp *.h /usr/local/include/libzrtp
|
||||
cp 'libbn.a' '/usr/local/lib/libbn.a'
|
||||
chmod 644 /usr/local/lib/libbn.a
|
||||
chown 0:0 /usr/local/lib/libbn.a
|
||||
$(RANLIB) '/usr/local/lib/libbn.a'
|
||||
|
||||
# for libzrtp support
|
||||
#check: bntest
|
||||
# ./bntest
|
||||
check:
|
||||
|
||||
bntest: bntest00.o $(BNLIB)
|
||||
$(LD) $(LDFLAGS) -o $@ bntest00.o $(BNLIB) $(LIBS)
|
||||
|
||||
germtest: germtest.o $(BNLIB)
|
||||
$(LD) $(LDFLAGS) -o $@ germtest.o $(BNLIB) $(LIBS)
|
||||
|
||||
$(BNLIB): $(OBJS)
|
||||
$(AR) r $@ $?
|
||||
$(RANLIB) $@
|
||||
|
||||
# Here we get tricky... if we're compiling with GCC, then GCCMAGIC1 and
|
||||
# GCCMAGIC2 are set so that we actually do a link, but with the -r flag
|
||||
# (produce relocatable output) and with -lgcc *only*. This is so that
|
||||
# the result can be linked cleanly with code compiled with another cc,
|
||||
# which doesn't know about -lgcc. Presumably the lbnXX.o file, which
|
||||
# has by far the most math in it, will have a call to every interesting
|
||||
# support-library function.
|
||||
|
||||
lbn00.o: $(srcdir)/lbn00.c $(HDRS) bnconfig.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -I. -I$(srcdir) -o $@ -Wl,-r -nostdlib lbn00.c -lgcc
|
||||
|
||||
lbn16.o: $(srcdir)/lbn16.c $(HDRS) bnconfig.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -I. -I$(srcdir) -o $@ -Wl,-r -nostdlib lbn16.c -lgcc
|
||||
|
||||
lbn32.o: $(srcdir)/lbn32.c $(HDRS) bnconfig.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -I. -I$(srcdir) -o $@ -Wl,-r -nostdlib lbn32.c -lgcc
|
||||
|
||||
lbn64.o: $(srcdir)/lbn64.c $(HDRS) bnconfig.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -I. -I$(srcdir) -o $@ -Wl,-r -nostdlib lbn64.c -lgcc
|
||||
|
||||
# The default .o rule.
|
||||
.c.o: bnconfig.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -I. -I$(srcdir) -o $@ -c $<
|
||||
|
||||
# Extra, non-obvious dependencies. Bnlib can be compiled in three
|
||||
# word sizes, and the *00.c files #include the right .c files based
|
||||
# on <limits.h>, which means that a single compilation will only use a
|
||||
# subset of these files. Duplicated here in case someone regenerates
|
||||
# dependencies with cc -M and they get lost.
|
||||
|
||||
lbn00.o: lbn16.c lbn32.c lbn64.c lbn16.h lbn32.h lbn64.h
|
||||
bn00.o: bn16.c bn32.c bn64.c bn16.h bn32.h bn64.h \
|
||||
bninit16.c bninit32.c bninit64.c
|
||||
bntest00.o: bntest16.c bntest32.c bntest64.c lbn16.h lbn32.h lbn64.h
|
||||
|
||||
# Actual build commented out to prevent confusion by people without autoconf.
|
||||
# Do it manually for now.
|
||||
configure: configure.in
|
||||
@echo "configure script is out of date; run autoconf"
|
||||
# autoconf
|
||||
|
||||
clean:
|
||||
$(RM) -f *.o *32.[ch] *64.[ch]
|
||||
|
||||
distclean: clean
|
||||
-rm -f Makefile
|
||||
|
||||
BNSOURCES = lbn32.c lbn32.h bn32.c bn32.h bninit32.c bntest32.c \
|
||||
lbn64.c lbn64.h bn64.c bn64.h bninit64.c bntest64.c
|
||||
|
||||
# An explicit target that can be made before distribution for
|
||||
# machines that don't have sed.
|
||||
bnsources: $(BNSOURCES)
|
||||
|
||||
# The 16-bit versions of the code are the master versions; all else is
|
||||
# generated from them. This fiddling about makes them unwriteable
|
||||
# to discourage improper edits.
|
||||
|
||||
# (You didn't know that suffixes for suffix rules didn't have to begin
|
||||
# with a period, did you?)
|
||||
.SUFFIXES: 16.c 16.h 32.c 32.h 64.c 64.h
|
||||
16.c32.c:
|
||||
@test ! -f $@ -o -w $@ || chmod u+w $@ && test -w $@ || rm -f $@
|
||||
sed -e s/32/64/g -e s/16/32/g $< > $@
|
||||
@chmod a-w $@
|
||||
|
||||
16.h32.h:
|
||||
@test ! -f $@ -o -w $@ || chmod u+w $@ && test -w $@ || rm -f $@
|
||||
sed -e s/32/64/g -e s/16/32/g $< > $@
|
||||
@chmod a-w $@
|
||||
|
||||
16.c64.c:
|
||||
@test ! -f $@ -o -w $@ || chmod u+w $@ && test -w $@ || rm -f $@
|
||||
sed -e s/32/128/g -e s/16/64/g $< > $@
|
||||
@chmod a-w $@
|
||||
|
||||
16.h64.h:
|
||||
@test ! -f $@ -o -w $@ || chmod u+w $@ && test -w $@ || rm -f $@
|
||||
sed -e s/32/128/g -e s/16/64/g $< > $@
|
||||
@chmod a-w $@
|
||||
|
||||
### Dependencies
|
||||
bn.o: bn.c bn.h
|
||||
bn00.o: bn00.c bnsize00.h lbn.h bn16.c bn32.c bn64.c lbn16.c lbn32.h \
|
||||
lbn64.h lbnmem.h bn16.h bn32.h bn64.h bn.h kludge.h bninit16.c \
|
||||
bninit32.c bninit64.c
|
||||
bn16.o: bn16.c lbn.h lbn16.h lbnmem.h bn16.h bn.h kludge.h
|
||||
bn32.o: bn32.c lbn.h lbn32.h lbnmem.h bn32.h bn.h kludge.h
|
||||
bn64.o: bn64.c lbn.h lbn64.h lbnmem.h bn64.h bn.h kludge.h
|
||||
bn68000.o: bn68000.c lbn.h lbn68000.h bn16.h bn32.h
|
||||
bn8086.o: bn8086.c lbn.h bn64.h lbn8086.h bn32.h
|
||||
bninit16.o: bninit16.c bn.h bn16.h
|
||||
bninit32.o: bninit32.c bn.h bn32.h
|
||||
bninit64.o: bninit64.c bn.h bn64.h
|
||||
bnprint.o: bnprint.c bn.h bnprint.h kludge.h
|
||||
bntest00.o: bntest00.c bnsize00.h lbn.h bntest16.c bntest32.c \
|
||||
bntest64.c cputime.h lbn16.h lbn32.h lbn64.h kludge.h
|
||||
bntest16.o: bntest16.c cputime.h lbn16.h lbn.h kludge.h
|
||||
bntest32.o: bntest32.c cputime.h lbn32.h lbn.h kludge.h
|
||||
bntest64.o: bntest64.c cputime.h lbn64.h lbn.h kludge.h
|
||||
germain.o: germain.c bn.h germain.h jacobi.h lbnmem.h sieve.h kludge.h
|
||||
germtest.o: germtest.c bn.h germain.h sieve.h cputime.h bnprint.h
|
||||
jacobi.o: jacobi.c bn.h jacobi.h
|
||||
lbn00.o: lbn00.c bnsize00.h lbn.h lbn16.c lbn16.h lbn32.c lbn32.h \
|
||||
lbn64.c lbn64.h lbnmem.h kludge.h
|
||||
lbn16.o: lbn16.c lbn.h lbn16.h lbnmem.h kludge.h
|
||||
lbn32.o: lbn32.c lbn.h lbn32.h lbnmem.h kludge.h
|
||||
lbn64.o: lbn64.c lbn.h lbn64.h lbnmem.h kludge.h
|
||||
lbn68000.o: lbn68000.c lbn.h lbn68000.h
|
||||
lbn68020.o: lbn68020.c lbn.h lbn68020.h
|
||||
lbnmem.o: lbnmem.c lbn.h lbnmem.h kludge.h
|
||||
lbnppc.o: lbnppc.c lbnppc.h ppcasm.h
|
||||
prime.o: prime.c bn.h lbnmem.h prime.h sieve.h kludge.h
|
||||
sieve.o: sieve.c bn.h sieve.h kludge.h
|
||||
sizetest.c: bnsize00.h
|
||||
|
||||
distdir:
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
#
|
||||
# This code is pretty well tested, but not optimizing it will have
|
||||
# a *major* effect on speed, so its optimzation flags are separate
|
||||
# from the rest of the release.
|
||||
#
|
||||
# For the SPARC v8, at least, gcc produces a *much* faster library than
|
||||
# the SunPro C compiler. On a 50 MHz TI TMS390Z50 SuperSPARC:
|
||||
# 14.5 vs. 47.2 ms per 256-bit modular exponentiation.
|
||||
# 77.4 vs. 317.8 ms per 512-bit modular exponentiation.
|
||||
# 249.0 vs. 1031.5 ms per 1024-bit modular exponentiation
|
||||
#
|
||||
CC=@CC@
|
||||
# for libzrtp support
|
||||
CFLAGS=@CFLAGS@ @CPPFLAGS@ @WARN@ @TUNE@ @DEFS@ $(DEFINE) -I../../include -I../../include/enterprise -I../../projects/gnu/config -I../../third_party/bgaes
|
||||
srcdir=@srcdir@
|
||||
VPATH=@srcdir@
|
||||
|
||||
# Extra object files (e.g. lbnalpha.o for Alpha assembly routines)
|
||||
AUXOBJS=
|
||||
# Extra definitions (e.g. -DBNINCLUDE=lbnalpha.h)
|
||||
DEFINE=
|
||||
|
||||
SHELL = /bin/sh
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .h .o .s
|
||||
|
||||
LD =$(CC)
|
||||
LDFLAGS =@LDFLAGS@
|
||||
LIBS=@LIBS@
|
||||
RANLIB=@RANLIB@
|
||||
|
||||
# If you have a machine-specific assembly file, add it to AUXOBJS.
|
||||
OBJS = bn00.o lbn00.o bn.o lbnmem.o sieve.o prime.o \
|
||||
bnprint.o jacobi.o germain.o $(AUXOBJS)
|
||||
|
||||
BNLIB = libbn.a
|
||||
|
||||
# for libzrtp support
|
||||
all: $(BNLIB) bntest32.c bntest64.c
|
||||
# bntest germtest
|
||||
|
||||
# for libzrtp support
|
||||
install: all
|
||||
test -d /usr/local/include/libzrtp || mkdir /usr/local/include/libzrtp
|
||||
cp *.h /usr/local/include/libzrtp
|
||||
cp 'libbn.a' '/usr/local/lib/libbn.a'
|
||||
chmod 644 /usr/local/lib/libbn.a
|
||||
chown 0:0 /usr/local/lib/libbn.a
|
||||
$(RANLIB) '/usr/local/lib/libbn.a'
|
||||
|
||||
# for libzrtp support
|
||||
#check: bntest
|
||||
# ./bntest
|
||||
check:
|
||||
|
||||
bntest: bntest00.o $(BNLIB)
|
||||
$(LD) $(LDFLAGS) -o $@ bntest00.o $(BNLIB) $(LIBS)
|
||||
|
||||
germtest: germtest.o $(BNLIB)
|
||||
$(LD) $(LDFLAGS) -o $@ germtest.o $(BNLIB) $(LIBS)
|
||||
|
||||
$(BNLIB): $(OBJS)
|
||||
$(AR) r $@ $?
|
||||
$(RANLIB) $@
|
||||
|
||||
# Here we get tricky... if we're compiling with GCC, then GCCMAGIC1 and
|
||||
# GCCMAGIC2 are set so that we actually do a link, but with the -r flag
|
||||
# (produce relocatable output) and with -lgcc *only*. This is so that
|
||||
# the result can be linked cleanly with code compiled with another cc,
|
||||
# which doesn't know about -lgcc. Presumably the lbnXX.o file, which
|
||||
# has by far the most math in it, will have a call to every interesting
|
||||
# support-library function.
|
||||
|
||||
lbn00.o: $(srcdir)/lbn00.c $(HDRS) bnconfig.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -I. -I$(srcdir) -o $@ @GCCMAGIC1@ lbn00.c @GCCMAGIC2@
|
||||
|
||||
lbn16.o: $(srcdir)/lbn16.c $(HDRS) bnconfig.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -I. -I$(srcdir) -o $@ @GCCMAGIC1@ lbn16.c @GCCMAGIC2@
|
||||
|
||||
lbn32.o: $(srcdir)/lbn32.c $(HDRS) bnconfig.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -I. -I$(srcdir) -o $@ @GCCMAGIC1@ lbn32.c @GCCMAGIC2@
|
||||
|
||||
lbn64.o: $(srcdir)/lbn64.c $(HDRS) bnconfig.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -I. -I$(srcdir) -o $@ @GCCMAGIC1@ lbn64.c @GCCMAGIC2@
|
||||
|
||||
# The default .o rule.
|
||||
.c.o: bnconfig.h
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -I. -I$(srcdir) -o $@ -c $<
|
||||
|
||||
# Extra, non-obvious dependencies. Bnlib can be compiled in three
|
||||
# word sizes, and the *00.c files #include the right .c files based
|
||||
# on <limits.h>, which means that a single compilation will only use a
|
||||
# subset of these files. Duplicated here in case someone regenerates
|
||||
# dependencies with cc -M and they get lost.
|
||||
|
||||
lbn00.o: lbn16.c lbn32.c lbn64.c lbn16.h lbn32.h lbn64.h
|
||||
bn00.o: bn16.c bn32.c bn64.c bn16.h bn32.h bn64.h \
|
||||
bninit16.c bninit32.c bninit64.c
|
||||
bntest00.o: bntest16.c bntest32.c bntest64.c lbn16.h lbn32.h lbn64.h
|
||||
|
||||
# Actual build commented out to prevent confusion by people without autoconf.
|
||||
# Do it manually for now.
|
||||
configure: configure.in
|
||||
@echo "configure script is out of date; run autoconf"
|
||||
# autoconf
|
||||
|
||||
clean:
|
||||
$(RM) -f *.o *32.[ch] *64.[ch]
|
||||
|
||||
distclean: clean
|
||||
-rm -f Makefile
|
||||
|
||||
BNSOURCES = lbn32.c lbn32.h bn32.c bn32.h bninit32.c bntest32.c \
|
||||
lbn64.c lbn64.h bn64.c bn64.h bninit64.c bntest64.c
|
||||
|
||||
# An explicit target that can be made before distribution for
|
||||
# machines that don't have sed.
|
||||
bnsources: $(BNSOURCES)
|
||||
|
||||
# The 16-bit versions of the code are the master versions; all else is
|
||||
# generated from them. This fiddling about makes them unwriteable
|
||||
# to discourage improper edits.
|
||||
|
||||
# (You didn't know that suffixes for suffix rules didn't have to begin
|
||||
# with a period, did you?)
|
||||
.SUFFIXES: 16.c 16.h 32.c 32.h 64.c 64.h
|
||||
16.c32.c:
|
||||
@test ! -f $@ -o -w $@ || chmod u+w $@ && test -w $@ || rm -f $@
|
||||
sed -e s/32/64/g -e s/16/32/g $< > $@
|
||||
@chmod a-w $@
|
||||
|
||||
16.h32.h:
|
||||
@test ! -f $@ -o -w $@ || chmod u+w $@ && test -w $@ || rm -f $@
|
||||
sed -e s/32/64/g -e s/16/32/g $< > $@
|
||||
@chmod a-w $@
|
||||
|
||||
16.c64.c:
|
||||
@test ! -f $@ -o -w $@ || chmod u+w $@ && test -w $@ || rm -f $@
|
||||
sed -e s/32/128/g -e s/16/64/g $< > $@
|
||||
@chmod a-w $@
|
||||
|
||||
16.h64.h:
|
||||
@test ! -f $@ -o -w $@ || chmod u+w $@ && test -w $@ || rm -f $@
|
||||
sed -e s/32/128/g -e s/16/64/g $< > $@
|
||||
@chmod a-w $@
|
||||
|
||||
### Dependencies
|
||||
bn.o: bn.c bn.h
|
||||
bn00.o: bn00.c bnsize00.h lbn.h bn16.c bn32.c bn64.c lbn16.c lbn32.h \
|
||||
lbn64.h lbnmem.h bn16.h bn32.h bn64.h bn.h kludge.h bninit16.c \
|
||||
bninit32.c bninit64.c
|
||||
bn16.o: bn16.c lbn.h lbn16.h lbnmem.h bn16.h bn.h kludge.h
|
||||
bn32.o: bn32.c lbn.h lbn32.h lbnmem.h bn32.h bn.h kludge.h
|
||||
bn64.o: bn64.c lbn.h lbn64.h lbnmem.h bn64.h bn.h kludge.h
|
||||
bn68000.o: bn68000.c lbn.h lbn68000.h bn16.h bn32.h
|
||||
bn8086.o: bn8086.c lbn.h bn64.h lbn8086.h bn32.h
|
||||
bninit16.o: bninit16.c bn.h bn16.h
|
||||
bninit32.o: bninit32.c bn.h bn32.h
|
||||
bninit64.o: bninit64.c bn.h bn64.h
|
||||
bnprint.o: bnprint.c bn.h bnprint.h kludge.h
|
||||
bntest00.o: bntest00.c bnsize00.h lbn.h bntest16.c bntest32.c \
|
||||
bntest64.c cputime.h lbn16.h lbn32.h lbn64.h kludge.h
|
||||
bntest16.o: bntest16.c cputime.h lbn16.h lbn.h kludge.h
|
||||
bntest32.o: bntest32.c cputime.h lbn32.h lbn.h kludge.h
|
||||
bntest64.o: bntest64.c cputime.h lbn64.h lbn.h kludge.h
|
||||
germain.o: germain.c bn.h germain.h jacobi.h lbnmem.h sieve.h kludge.h
|
||||
germtest.o: germtest.c bn.h germain.h sieve.h cputime.h bnprint.h
|
||||
jacobi.o: jacobi.c bn.h jacobi.h
|
||||
lbn00.o: lbn00.c bnsize00.h lbn.h lbn16.c lbn16.h lbn32.c lbn32.h \
|
||||
lbn64.c lbn64.h lbnmem.h kludge.h
|
||||
lbn16.o: lbn16.c lbn.h lbn16.h lbnmem.h kludge.h
|
||||
lbn32.o: lbn32.c lbn.h lbn32.h lbnmem.h kludge.h
|
||||
lbn64.o: lbn64.c lbn.h lbn64.h lbnmem.h kludge.h
|
||||
lbn68000.o: lbn68000.c lbn.h lbn68000.h
|
||||
lbn68020.o: lbn68020.c lbn.h lbn68020.h
|
||||
lbnmem.o: lbnmem.c lbn.h lbnmem.h kludge.h
|
||||
lbnppc.o: lbnppc.c lbnppc.h ppcasm.h
|
||||
prime.o: prime.c bn.h lbnmem.h prime.h sieve.h kludge.h
|
||||
sieve.o: sieve.c bn.h sieve.h kludge.h
|
||||
sizetest.c: bnsize00.h
|
||||
|
||||
distdir:
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
Welcome to my multiprecision math library! I'm a little bit proud
|
||||
of it, particularly its speed. If you have a machine for which
|
||||
assembly-language subroutines are available (you can probably guess
|
||||
from the filename), it will go even faster. Instructions for
|
||||
building the library with assembly subroutines are included later.
|
||||
|
||||
Barring that, on many machines using GCC, the GNU C compiler, helps
|
||||
the speed significantly, because it not only supports "long long"
|
||||
64-bit data types, but it can perform operations on them in line.
|
||||
Some other compilers that support "long long" generate inefficient
|
||||
code for working with them.
|
||||
|
||||
For a description of what the library does, see bn.doc. For a description
|
||||
of how it's organized, see bnintern.doc. For the real nitty-gritty,
|
||||
read the code. I'm very curious what you all think of it. One thing I
|
||||
tried to do was to comment it better than most, although that is more
|
||||
apparent in the lower-level parts of the code (the lbn* files) that I
|
||||
wrote first rather than the higher levels, when I didn't need comments
|
||||
to explain what I was doing to myself.
|
||||
|
||||
I can't put a full number theory course in the comments, so there
|
||||
are some parts that are just going to be confusing unless you
|
||||
have the background. I'd rather not answer questions that elementary.
|
||||
But really, I can't stop you from saying whatever you want. If you'd
|
||||
like to send some comments, good or bad, send me some mail.
|
||||
--
|
||||
-Colin <colin@nyx.net>
|
||||
|
||||
|
||||
** How to build the library
|
||||
|
||||
For the full details of how all the bits go together, see bnintern.doc.
|
||||
If you're on a Unix machine, run the "configure" script (generated from
|
||||
configure.in using GNU autoconf) and it will set up the basic C version
|
||||
automatically. Assembly-language support is still configured by hand.
|
||||
(Just edit the generated Makefile.) If you're on another machine,
|
||||
you'll have to do everything by hand, although it's still not hard.
|
||||
|
||||
This library works in three word sizes: 16, 32 and 64 bits. The limiting
|
||||
factor is that it needs a double-word multiply, so even a 64-bit SPARC
|
||||
must use the 32-bit code, because it only produces a 64-bit multiply
|
||||
result. The DEC Alpha, MIPS R4000 (and up) and the upcoming 64-bit
|
||||
PowerPC, however, can use the 64-bit version, as they provide access to
|
||||
the high 64 bits of an integer multiply result.
|
||||
|
||||
Trying to compile the file "sizetest.c" will produce an error telling
|
||||
you what word size is needed. In the absence of any assembly-language
|
||||
support routines, if your compiler has 64-bit longs or 64-bit long longs,
|
||||
you'll get the 32-bit version. Otherwise, you'll get the 16-bit version.
|
||||
|
||||
The shipped archive contains only the 16-bit version of six important
|
||||
source files: bn16.c, bn16.h, lbn16.c, lbn16.h, bninit16.c and bntest16.c.
|
||||
The 32- and 64-bit versions are produced by a trivial replacement process
|
||||
from those. They are built automatically on demand by the Unix Makefile;
|
||||
other platforms will have to build them by hand if needed.
|
||||
|
||||
If you have the Unix stream editor sed, you can do:
|
||||
sed -e s/32/64/g -e s/16/32/g bn16.c > bn32.c
|
||||
sed -e s/32/64/g -e s/16/32/g bn16.h > bn32.h
|
||||
sed -e s/32/64/g -e s/16/32/g lbn16.c > lbn32.c
|
||||
sed -e s/32/64/g -e s/16/32/g lbn16.h > lbn32.h
|
||||
sed -e s/32/64/g -e s/16/32/g bninit16.c > bninit32.c
|
||||
sed -e s/32/64/g -e s/16/32/g bntest16.c > bntest32.c
|
||||
|
||||
If you don't, you'll have to use your favourite text editor and manually:
|
||||
Copy bn16.c to bn32.c
|
||||
Copy bn16.h to bn32.h
|
||||
Copy lbn16.c to lbn32.c
|
||||
Copy lbn16.h to lbn32.h
|
||||
Copy bninit16.c to bninit32.c
|
||||
Copy bntest16.c to bntest32.c
|
||||
Edit bn32.c, bn32.h, lbn32.c, lbn32.h, bninit32.c and bntest32.c (*32.?)
|
||||
Globally replace all "32" by "64"
|
||||
Globally replace all "16" by "32"
|
||||
|
||||
I don't know of any non-Unix platforms that can use the 64-bit version,
|
||||
so you probably won't need it, but the process is siliar, just replace
|
||||
every "32" with "128" and every "16" with "64".
|
||||
|
||||
Once you have all the word size versions you need you can compile them.
|
||||
If you're compiling a pure C version, or even a simple assembly-language
|
||||
version, there are some special auto-size-detecting files that will
|
||||
figure out (at compile time, using <limits.h> and the C preprocessor)
|
||||
the largest size that it can compile and #include it. To compile that
|
||||
version, you need to compile the following files:
|
||||
|
||||
- bn.c
|
||||
- bn00.c
|
||||
- lbn00.c
|
||||
- lbnmem.c
|
||||
- legal.c
|
||||
|
||||
The file "bntest00.c" (see README.bntest) is a low-level test program
|
||||
that will check the correct operation of the core low-level routines of
|
||||
the library. It needs only lbn00.c, lbnmem.c and legal.c.
|
||||
|
||||
The file "germtest.c" is a simple program to generate Sophie Germain
|
||||
primes which demonstrates the library's use. This uses the full library.
|
||||
|
||||
|
||||
** Adding assembly-language support routines
|
||||
|
||||
It is possible to include some assembly-language primitives in this.
|
||||
For example, for the DEC Alpha primitives, you need to compile everything
|
||||
with the -DBNINCLUDE=lbnalpha.h flag (or somehow get the effect of
|
||||
"#define BNINCLUDE lbnalpha.h" in all of the code), and assemble and
|
||||
link in "lbnalpha.s".
|
||||
|
||||
If you want to compile a specific version of the library, say the
|
||||
32-bit version, you need to compile together the following files:
|
||||
|
||||
- bn.c
|
||||
- bn32.c
|
||||
- bninit32.c
|
||||
- lbn32.c
|
||||
- lbnmem.c
|
||||
- legal.c
|
||||
|
||||
Note the extra "bninit32.c" file. It contains only the function
|
||||
"bnInit()" which does nothing but call "bnInit_32()". This is included in
|
||||
"bn00.c", but is separated out here so that you can compile the library
|
||||
for two word sizes and replace the bnInit() function with one that will
|
||||
select a version to initialize at run time! That's described later.
|
||||
|
||||
To include assembly-language support routines for a given processor
|
||||
(as an example, I'll use the mythical "DLX" processor), compile all the
|
||||
C files with -DBNINCLUDE=lbndlx.h and (or somehow get the effect of
|
||||
"#define BNINCLUDE lbndlx.h" when compiling all the .c files), and
|
||||
assemble and link in the lbndlx.s assembly-language file.
|
||||
|
||||
The fun comes when you compile a version of the library for two
|
||||
word sizes. This is currently only supported for the 680x0 and 80x86
|
||||
processors, which come in 16- and 32-bit versions, but this also makes
|
||||
sense on MIPS and PowerPC processors that have 32- and 64-bit versions.
|
||||
|
||||
To do this, you need to compile the library in two word sizes and include
|
||||
a custom bndlx.c file that defines a smart bnInit() which chooses between
|
||||
the two. For the 80x8 family (or the 680x0 family), you want to compile
|
||||
the following with -DBNINCLUDE=lbn8086.h (or -DBNINCLUDE=lbn68000.h):
|
||||
|
||||
- bn.c
|
||||
- bn16.c
|
||||
- bn32.c
|
||||
- lbn16.c
|
||||
- lbn32.c
|
||||
- lbnmem.c
|
||||
- legal.c
|
||||
- lbn8086.asm (or lbn68000.c and lbn68020.c for the 680x0)
|
||||
- bn8086.c (or bn68000.c for the 680x0)
|
||||
|
||||
The lbn8086.asm file contains the assembly-language subroutines.
|
||||
The lbn8086.h file contains declarations for them and the
|
||||
necessary information to call them instead of the C versions
|
||||
The bn8086.c file contains the single function bnInit(), which
|
||||
determines the word size of the processor when called and calls
|
||||
bnInit_16() or bnInit_32(), as appropriate.
|
||||
|
||||
To summarize:
|
||||
|
||||
To build a (not necessarily optimal) version on any machine, do the following,
|
||||
or get your favourite make(1)-like utility to do it:
|
||||
|
||||
- Compile bn.c, bn00.c, lbn00.c, lbnmem.c and legal.c, with as much
|
||||
optimization as possible.
|
||||
- Link all of the .o files together
|
||||
|
||||
To build an MS-DOS version that will run well on an 8088 and up,
|
||||
compile with -DBNINCLUDE=lbn8086.h:
|
||||
|
||||
- Compile bn.c, bn16.c, bn32.c, lbn16.c, lbn32.c, lbnmem.c, legal.c and
|
||||
bn8086.c, with -DBNINCLUDE=lbn8086.h
|
||||
- Assemble lbn8086.asm
|
||||
- Link all of the .obj files together
|
||||
|
||||
To build an 80x86 WIN16 version (16-bit segmented addressing, 32-bit processor):
|
||||
|
||||
- Compile bn.c, bn00.c (or bn32.c and bninit32.c), lbn00.c (or lbn32.c),
|
||||
lbnmem.c and legal.c, with -DBNINCLUDE=lbn8086.h
|
||||
- Assemble lbn8086.asm
|
||||
- Link all of the .obj files together
|
||||
|
||||
To build an 80x86 WIN32 version (32-bit flat model),
|
||||
|
||||
- Compile bn.c, bn00.c (or bn32.c and bninit32.c), lbn00.c (or lbn32.c),
|
||||
lbnmem.c and legal.c, with -DBNINCLUDE=lbn80386.h
|
||||
- Assemble lbn80386.asm
|
||||
- Link all of the .obj files together
|
||||
|
||||
To build a Mac 68K version that will work well on a 68000 and up,
|
||||
|
||||
- Compile bn.c, bn16.c, bn32.c, lbn16.c, lbn32.c, lbnmem.c, legal.c and
|
||||
bn8086.c, with -DBNINCLUDE=lbn68000.h (On Metrowerks, you may have to
|
||||
build your own precompiled header to achieve this effect.)
|
||||
- Assemble lbn68000.c and lbn68020.c
|
||||
- Link all of the .o files together
|
||||
|
||||
To build a Mac 68K version which will only work on a 68020 or better,
|
||||
|
||||
- Compile bn.c, bn00.c (or bn32.c and bninit32.c), lbn00.c (or lbn32.c),
|
||||
lbnmem.c and legal.c, with -DBNINCLUDE=lbn68020.h (On Metrowerks, you
|
||||
may have to build your own precompiled header to achieve this effect.)
|
||||
- Assemble lbn68020.c
|
||||
- Link all of the .o files together
|
||||
|
||||
To build a Mac PowerPC version,
|
||||
|
||||
- Compile bn.c, bn00.c (or bn32.c and bninit32.c), lbn00.c (or lbn32.c),
|
||||
lbnmem.c and legal.c, with -DBNINCLUDE=lbnppc.h (On Metrowerks, you
|
||||
may have to build your own precompiled header to achieve this effect.)
|
||||
- Assemble lbnppc.c
|
||||
- Link all of the .o files together
|
||||
|
||||
To build a Unix 80x86 version (32-bit flat model, AT&T assembler mnemonics),
|
||||
|
||||
- Compile bn.c, bn00.c (or bn32.c and bninit32.c), lbn00.c (or lbn32.c),
|
||||
lbnmem.c and legal.c, with -DBNINCLUDE=lbn80386.h
|
||||
- Assemble lbn80386.s
|
||||
- Link all of the .o files together
|
||||
|
||||
To build a DEC Alpha version (64-bit math; this *screams*),
|
||||
|
||||
- Compile bn.c, bn00.c (or bn64.c and bninit64.c), lbn00.c (or lbn64.c),
|
||||
lbnmem.c and legal.c, with -DBNINCLUDE=lbnalpha.h
|
||||
- Assemble lbnalpha.s
|
||||
- Link all of the .o files together
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
Test driver for low-level BigNum library correctness.
|
||||
|
||||
In addition to the generic "bntest" program, which picks a size
|
||||
at compile time, there are specific test drivers, bntest16,
|
||||
bntest32 and bntest64 that you can compile specifically, e.g.
|
||||
to test multiple word sizes.
|
||||
|
||||
bntest is different from other programs in that it invokes the
|
||||
low-level BigNum functions directly. It need only be linked with
|
||||
lbnmem.o, lbn32.o and legal.o. This is not normally desirable, but
|
||||
it lets this test driver isolate errors better in the bottom-level
|
||||
primitives.
|
||||
|
||||
It's served very well in tracking down errors. If you write some new
|
||||
assembly primitives and it doesn't find a problem with them, you
|
||||
can have a good deal of confidence that they're correct.
|
||||
|
||||
This program also does timing tests on basic modular exponentiation.
|
||||
It is invoked as bntest [modsize [expsize [expsize2]]].
|
||||
If modsize is not specified, it only runs consistency checks.
|
||||
If expsize is not specified, it defaults to modsize.
|
||||
If expsize2 is not specified, it defaults to expsize.
|
||||
Invalid arguments produce a usage message.
|
||||
|
||||
Example invocation lines:
|
||||
bntest
|
||||
bntest 512
|
||||
bntest 1024 160
|
||||
@@ -0,0 +1,6 @@
|
||||
This directory contains a stripped-down version of Colin Plumb's bnlib bignum package for ARM processors in minimal memory environments, such as embedded Wireless USB controllers. All unnecessary functions have been removed, and code has been reorganized for shrinking the memory footprint. These functions duplicate the functionality of similar functions in the main bnlib package, but with smaller memory footprints. Wireless USB only requires Diffie-Hellman, and little else.
|
||||
|
||||
For more information, see the documentation in the main bnlib package, which is not in this directory. Or contact:
|
||||
|
||||
Philip Zimmermann <prz@mit.edu>
|
||||
October 2007
|
||||
@@ -0,0 +1,803 @@
|
||||
/*
|
||||
* Test driver for low-level bignum library (16-bit version).
|
||||
* This access the low-level library directly. It is NOT an example of
|
||||
* how to program with the library normally! By accessing the library
|
||||
* at a low level, it is possible to exercise the smallest components
|
||||
* and thus localize bugs more accurately. This is especially useful
|
||||
* when writing assembly-language primitives.
|
||||
*
|
||||
* This also does timing tests on modular exponentiation. Modular
|
||||
* exponentiation is so computationally expensive that the fact that this
|
||||
* code omits one level of interface glue has no perceptible effect on
|
||||
* the results.
|
||||
*/
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_STDLIB_H
|
||||
#define NO_STDLIB_H 0
|
||||
#endif
|
||||
#ifndef NO_STRING_H
|
||||
#define NO_STRING_H 0
|
||||
#endif
|
||||
#ifndef HAVE_STRINGS_H
|
||||
#define HAVE_STRINGS_H 0
|
||||
#endif
|
||||
#ifndef NEED_MEMORY_H
|
||||
#define NEED_MEMORY_H 0
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if !NO_STDLIB_H
|
||||
#include <stdlib.h> /* For strtol */
|
||||
#else
|
||||
long strtol(const char *, char **, int);
|
||||
#endif
|
||||
|
||||
#if !NO_STRING_H
|
||||
#include <string.h> /* For memcpy */
|
||||
#elif HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#if NEED_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#include "cputime.h"
|
||||
#include "lbn16.h"
|
||||
|
||||
#include "kludge.h"
|
||||
|
||||
#if BNYIELD
|
||||
int (*bnYield)(void) = 0;
|
||||
#endif
|
||||
|
||||
/* Work with up to 2048-bit numbers */
|
||||
#define MAXBITS 3072
|
||||
#define SIZE (MAXBITS/16 + 1)
|
||||
|
||||
/* Additive congruential random number generator, x[i] = x[i-24] + x[i-55] */
|
||||
static BNWORD16 randp[55];
|
||||
static BNWORD16 *randp1 = randp, *randp2 = randp+24;
|
||||
|
||||
static BNWORD16
|
||||
rand16(void)
|
||||
{
|
||||
if (++randp2 == randp+55) {
|
||||
randp2 = randp;
|
||||
randp1++;
|
||||
} else if (++randp1 == randp+55) {
|
||||
randp1 = randp;
|
||||
}
|
||||
|
||||
return *randp1 += *randp2;
|
||||
}
|
||||
|
||||
/*
|
||||
* CRC-3_2: x^3_2+x^26+x^23+x^22+x^1_6+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
|
||||
*
|
||||
* The additive congruential RNG is seeded with a single integer,
|
||||
* which is shuffled with a CRC polynomial to generate the initial
|
||||
* table values. The Polynomial is the same size as the words being
|
||||
* used.
|
||||
*
|
||||
* Thus, in the various versions of this library, we actually use this
|
||||
* polynomial as-is, this polynomial mod x^17, and this polynomial with
|
||||
* the leading coefficient deleted and replaced with x^6_4. As-is,
|
||||
* it's irreducible, so it has a long period. Modulo x^17, it factors as
|
||||
* (x^4+x^3+x^2+x+1) * (x^12+x^11+x^8+x^7+x^6+x^5+x^4+x^3+1),
|
||||
* which still has a large enough period (4095) for the use it's put to.
|
||||
* With the leading coefficient moved up, it factors as
|
||||
* (x^50+x^49+x^48+x^47+x^46+x^43+x^41+x^40+x^38+x^37+x^36+x^35+x^34+x^33+
|
||||
* x^31+x^30+x^29+x^28+x^27+x^25+x^23+x^18+x^1_6+x^15+x^14+x^13+x^11+x^9+
|
||||
* x^8+x^7+x^6+x^5+x^3+x^2+1)*(x^11+x^10+x^9+x^5+x^4+x^3+1)*(x^3+x+1),
|
||||
* which definitely has a long enough period to serve for initialization.
|
||||
*
|
||||
* The effort put into this PRNG is kind of unwarranted given the trivial
|
||||
* use it's being put to, but oh, well. It does have the nice advantage
|
||||
* of producing numbers that are portable between platforms, so if there's
|
||||
* a problem with one platform, you can compare all the intermediate
|
||||
* results with another platform.
|
||||
*/
|
||||
#define POLY (BNWORD16)0x04c11db7
|
||||
|
||||
static void
|
||||
srand16(BNWORD16 seed)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 55; i++) {
|
||||
for (j = 0; j < 16; j++)
|
||||
if (seed >> (16-1))
|
||||
seed = (seed << 1) ^ POLY;
|
||||
else
|
||||
seed <<= 1;
|
||||
randp[i] = seed;
|
||||
}
|
||||
for (i = 0; i < 3*55; i ++)
|
||||
rand16();
|
||||
}
|
||||
|
||||
static void
|
||||
randnum(BNWORD16 *num, unsigned len)
|
||||
{
|
||||
while (len--)
|
||||
BIGLITTLE(*--num,*num++) = rand16();
|
||||
}
|
||||
|
||||
static void
|
||||
bnprint16(BNWORD16 const *num, unsigned len)
|
||||
{
|
||||
BIGLITTLE(num -= len, num += len);
|
||||
|
||||
while (len--)
|
||||
printf("%0*lX", 16/4, (unsigned long)BIGLITTLE(*num++,*--num));
|
||||
}
|
||||
|
||||
static void
|
||||
bnput16(char const *prompt, BNWORD16 const *num, unsigned len)
|
||||
{
|
||||
fputs(prompt, stdout);
|
||||
bnprint16(num, len);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* One of our tests uses a known prime. The following selections were
|
||||
* taken from the tables at the end of Hans Reisel's "Prime Numbers and
|
||||
* Computer Methods for Factorization", second edition - an excellent book.
|
||||
* (ISBN 0-8176-3743-5 ISBN 3-7323-3743-5)
|
||||
*/
|
||||
#if 0
|
||||
/* P31=1839605 17620282 38179967 87333633 from the factors of 3^256+2^256 */
|
||||
static unsigned char const prime[] = {
|
||||
0x17,0x38,0x15,0xBC,0x8B,0xBB,0xE9,0xEF,0x01,0xA9,0xFD,0x3A,0x01
|
||||
};
|
||||
#elif 0
|
||||
/* P48=40554942 04557502 46193993 36199835 4279613_2 73199617 from the same */
|
||||
static unsigned char const prime[] = {
|
||||
0x47,0x09,0x77,0x07,0xCF,0xFD,0xE1,0x54,0x3E,0x24,
|
||||
0xF7,0xF1,0x7A,0x3E,0x91,0x51,0xCC,0xC7,0xD4,0x01
|
||||
};
|
||||
#elif 0
|
||||
/*
|
||||
* P75 = 450 55287320 97906895 47687014 5808213_2
|
||||
* 05219565 99525911 39967932 66003_258 91979521
|
||||
* from the factors of 4^128+3+128
|
||||
* (The "026" and "062" are to prevent a Bad String from appearing here.)
|
||||
*/
|
||||
static unsigned char const prime[] = {
|
||||
0xFF,0x00,0xFF,0x00,0xFF,0x01,0x06,0x4F,0xF8,0xED,
|
||||
0xA3,0x37,0x23,0x2A,0x04,0xEA,0xF9,0x5F,0x30,0x4C,
|
||||
0xAE,0xCD, 026,0x4E, 062,0x10,0x04,0x7D,0x0D,0x79,
|
||||
0x01
|
||||
};
|
||||
#else
|
||||
/*
|
||||
* P75 = 632 85659796 45277755 9123_2190 67300940
|
||||
* 51844953 78793489 59444670 35675855 57440257
|
||||
* from the factors of 5^128+4^128
|
||||
* (The "026" is to prevent a Bad String from appearing here.)
|
||||
*/
|
||||
static unsigned char const prime[] = {
|
||||
0x01,0x78,0x4B,0xA5,0xD3,0x30,0x03,0xEB,0x73,0xE6,
|
||||
0x0F,0x4E,0x31,0x7D,0xBC,0xE2,0xA0,0xD4, 026,0x3F,
|
||||
0x3C,0xEA,0x1B,0x44,0xAD,0x39,0xE7,0xE5,0xAD,0x19,
|
||||
0x67,0x01
|
||||
};
|
||||
#endif
|
||||
|
||||
static int
|
||||
usage(char const *name)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [modbits [expbits [expbits2]]\n"
|
||||
"With no arguments, just runs test suite. If modbits is given, runs\n"
|
||||
"quick validation test, then runs timing tests of modular exponentiation.\n"
|
||||
"If expbits is given, it is used as an exponent size, otherwise it defaults\n"
|
||||
"to the same as modbits. If expbits2 is given it is used as the second\n"
|
||||
"exponent size in the double-exponentiation tests, otherwise it defaults\n"
|
||||
"to the same as expbits. All are limited to %u bits.\n",
|
||||
name, (unsigned)MAXBITS);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* for libzrtp support */
|
||||
int
|
||||
bntest_main(int argc, char **argv)
|
||||
{
|
||||
unsigned i, j, k, l, m;
|
||||
int z;
|
||||
BNWORD16 t, carry, borrow;
|
||||
BNWORD16 a[SIZE], b[SIZE], c[SIZE], d[SIZE];
|
||||
BNWORD16 e[SIZE], f[SIZE];
|
||||
static BNWORD16 entries[sizeof(prime)*2][(sizeof(prime)-1)/(16/8)+1];
|
||||
BNWORD16 *array[sizeof(prime)*2];
|
||||
unsigned long modbits = 0, expbits = 0, expbits2 = 0;
|
||||
char *p;
|
||||
#define A BIGLITTLE((a+SIZE),a)
|
||||
#define B BIGLITTLE((b+SIZE),b)
|
||||
#define C BIGLITTLE((c+SIZE),c)
|
||||
#define D BIGLITTLE((d+SIZE),d)
|
||||
#define E BIGLITTLE((e+SIZE),e)
|
||||
#define F BIGLITTLE((f+SIZE),f)
|
||||
static unsigned const smallprimes[] = {
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43
|
||||
};
|
||||
|
||||
/* Set up array for precomputed modexp */
|
||||
for (i = 0; i < sizeof(array)/sizeof(*array); i++)
|
||||
array[i] = entries[i] BIG(+ SIZE);
|
||||
|
||||
srand16(1);
|
||||
|
||||
puts(BIGLITTLE("Big-endian machine","Little-endian machine"));
|
||||
|
||||
if (argc >= 2) {
|
||||
modbits = strtoul(argv[1], &p, 0);
|
||||
if (!modbits || *p) {
|
||||
fprintf(stderr, "Invalid modbits: %s\n", argv[1]);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if (argc >= 3) {
|
||||
expbits = strtoul(argv[2], &p, 0);
|
||||
if (!expbits || *p) {
|
||||
fprintf(stderr, "Invalid expbits: %s\n", argv[2]);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
expbits2 = expbits;
|
||||
}
|
||||
if (argc >= 4) {
|
||||
expbits2 = strtoul(argv[3], &p, 0);
|
||||
if (!expbits2 || *p) {
|
||||
fprintf(stderr, "Invalid expbits2: %s\n", argv[3]);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if (argc >= 5) {
|
||||
fprintf(stderr, "Too many arguments: %s\n", argv[4]);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
/* B is a nice not-so-little prime */
|
||||
lbnInsertBigBytes_16(B, prime, 0, sizeof(prime));
|
||||
((unsigned char *)c)[0] = 0;
|
||||
lbnInsertBigBytes_16(B, (unsigned char *)c, sizeof(prime), 1);
|
||||
lbnExtractBigBytes_16(B, (unsigned char *)c, 0, sizeof(prime)+1);
|
||||
i = (sizeof(prime)-1)/(16/8)+1; /* Size of array in words */
|
||||
if (((unsigned char *)c)[0] ||
|
||||
memcmp(prime, (unsigned char *)c+1, sizeof(prime)) != 0)
|
||||
{
|
||||
printf("Input != output!:\n ");
|
||||
for (k = 0; k < sizeof(prime); k++)
|
||||
printf("%02X ", prime[k]);
|
||||
putchar('\n');
|
||||
for (k = 0; k < sizeof(prime)+1; k++)
|
||||
printf("%02X ", ((unsigned char *)c)[k]);
|
||||
putchar('\n');
|
||||
bnput16("p = ", B, i);
|
||||
|
||||
}
|
||||
|
||||
/* Timing test code - only if requested on the command line */
|
||||
if (modbits) {
|
||||
timetype start, stop;
|
||||
unsigned long cursec, expsec, twoexpsec, dblexpsec;
|
||||
unsigned curms, expms, twoexpms, dblexpms;
|
||||
|
||||
expsec = twoexpsec = dblexpsec = 0;
|
||||
expms = twoexpms = dblexpms = 0;
|
||||
|
||||
lbnCopy_16(C,B,i);
|
||||
lbnSub1_16(C,i,1); /* C is exponent: p-1 */
|
||||
|
||||
puts("Testing modexp with a known prime. "
|
||||
"All results should be 1.");
|
||||
bnput16("p = ", B, i);
|
||||
bnput16("p-1 = ", C, i);
|
||||
z = lbnTwoExpMod_16(A, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput16("2^(p-1) mod p = ", A, i);
|
||||
for (j = 0; j < 10; j++) {
|
||||
randnum(A,i);
|
||||
(void)lbnDiv_16(D,A,i,B,i);
|
||||
|
||||
bnput16("a = ", A, i);
|
||||
z = lbnExpMod_16(D, A, i, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput16("a^(p-1) mod p = ", D, i);
|
||||
#if 0
|
||||
z = lbnBasePrecompBegin_16(array, (sizeof(prime)*8+4)/5, 5,
|
||||
A, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
BIGLITTLE(D[-1],D[0]) = -1;
|
||||
z = lbnBasePrecompExp_16(D, (BNWORD16 const * const *)array,
|
||||
5, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput16("a^(p-1) mod p = ", D, i);
|
||||
#endif
|
||||
for (k = 0; k < 5; k++) {
|
||||
randnum(E,i);
|
||||
bnput16("e = ", E, i);
|
||||
z = lbnExpMod_16(D, A, i, E, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput16("a^e mod p = ", D, i);
|
||||
#if 0
|
||||
z = lbnBasePrecompExp_16(D, (BNWORD16 const * const *)array,
|
||||
5, E, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput16("a^e mod p = ", D, i);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n"
|
||||
"Timing exponentiations modulo a %d-bit modulus, i.e.\n"
|
||||
"2^<%d> mod <%d> bits, <%d>^<%d> mod <%d> bits and\n"
|
||||
"<%d>^<%d> * <%d>^<%d> mod <%d> bits\n",
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)modbits, (int)expbits, (int)modbits, (int)expbits2,
|
||||
(int)modbits);
|
||||
|
||||
i = ((int)modbits-1)/16+1;
|
||||
k = ((int)expbits-1)/16+1;
|
||||
l = ((int)expbits2-1)/16+1;
|
||||
for (j = 0; j < 25; j++) {
|
||||
randnum(A,i); /* Base */
|
||||
randnum(B,k); /* Exponent */
|
||||
randnum(C,i); /* Modulus */
|
||||
randnum(D,i); /* Base2 */
|
||||
randnum(E,l); /* Exponent */
|
||||
/* Clip bases and mod to appropriate number of bits */
|
||||
t = ((BNWORD16)2<<((modbits-1)%16)) - 1;
|
||||
*(BIGLITTLE(A-i,A+i-1)) &= t;
|
||||
*(BIGLITTLE(C-i,C+i-1)) &= t;
|
||||
*(BIGLITTLE(D-i,D+i-1)) &= t;
|
||||
/* Make modulus large (msbit set) and odd (lsbit set) */
|
||||
*(BIGLITTLE(C-i,C+i-1)) |= (t >> 1) + 1;
|
||||
BIGLITTLE(C[-1],C[0]) |= 1;
|
||||
|
||||
/* Clip exponent to appropriate number of bits */
|
||||
t = ((BNWORD16)2<<((expbits-1)%16)) - 1;
|
||||
*(BIGLITTLE(B-k,B+k-1)) &= t;
|
||||
/* Make exponent large (msbit set) */
|
||||
*(BIGLITTLE(B-k,B+k-1)) |= (t >> 1) + 1;
|
||||
/* The same for exponent 2 */
|
||||
t = ((BNWORD16)2<<((expbits2-1)%16)) - 1;
|
||||
*(BIGLITTLE(E-l,E+l-1)) &= t;
|
||||
*(BIGLITTLE(E-l,E+l-1)) |= (t >> 1) + 1;
|
||||
|
||||
m = lbnBits_16(A, i);
|
||||
if (m > (unsigned)modbits) {
|
||||
bnput16("a = ", a, i);
|
||||
printf("%u bits, should be <= %d\n",
|
||||
m, (int)modbits);
|
||||
}
|
||||
m = lbnBits_16(B, k);
|
||||
if (m != (unsigned)expbits) {
|
||||
bnput16("b = ", b, i);
|
||||
printf("%u bits, should be %d\n",
|
||||
m, (int)expbits);
|
||||
}
|
||||
m = lbnBits_16(C, i);
|
||||
if (m != (unsigned)modbits) {
|
||||
bnput16("c = ", c, k);
|
||||
printf("%u bits, should be %d\n",
|
||||
m, (int)modbits);
|
||||
}
|
||||
m = lbnBits_16(D, i);
|
||||
if (m > (unsigned)modbits) {
|
||||
bnput16("d = ", d, i);
|
||||
printf("%u bits, should be <= %d\n",
|
||||
m, (int)modbits);
|
||||
}
|
||||
m = lbnBits_16(E, l);
|
||||
if (m != (unsigned)expbits2) {
|
||||
bnput16("e = ", e, i);
|
||||
printf("%u bits, should be %d\n",
|
||||
m, (int)expbits2);
|
||||
}
|
||||
gettime(&start);
|
||||
z = lbnTwoExpMod_16(A, B, k, C, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
twoexpsec += cursec = sec(stop);
|
||||
twoexpms += curms = msec(stop);
|
||||
|
||||
printf("2^<%d>:%4lu.%03u ", (int)expbits, cursec, curms);
|
||||
fflush(stdout);
|
||||
|
||||
gettime(&start);
|
||||
z = lbnExpMod_16(A, A, i, B, k, C, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
expsec += cursec = sec(stop);
|
||||
expms += curms = msec(stop);
|
||||
printf("<%d>^<%d>:%4lu.%03u ",(int)modbits, (int)expbits,
|
||||
cursec, curms);
|
||||
fflush(stdout);
|
||||
|
||||
#if 0
|
||||
gettime(&start);
|
||||
z = lbnDoubleExpMod_16(D, A, i, B, k, D, i, E, l,C,i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
dblexpsec += cursec = sec(stop);
|
||||
dblexpms += curms = msec(stop);
|
||||
printf("<%d>^<%d>*<%d>^<%d>:%4lu.%03u\n",
|
||||
(int)modbits, (int)expbits,
|
||||
(int)modbits, (int)expbits2,
|
||||
cursec, curms);
|
||||
#else
|
||||
putchar('\n');
|
||||
#endif
|
||||
}
|
||||
twoexpms += (twoexpsec % j) * 1000;
|
||||
printf("2^<%d> mod <%d> bits AVERAGE: %4lu.%03u s\n",
|
||||
(int)expbits, (int)modbits, twoexpsec/j, twoexpms/j);
|
||||
expms += (expsec % j) * 1000;
|
||||
printf("<%d>^<%d> mod <%d> bits AVERAGE: %4lu.%03u s\n",
|
||||
(int)modbits, (int)expbits, (int)modbits, expsec/j, expms/j);
|
||||
#if 0
|
||||
dblexpms += (dblexpsec % j) * 1000;
|
||||
printf("<%d>^<%d> * <%d>^<%d> mod <%d> bits AVERAGE:"
|
||||
" %4lu.%03u s\n",
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)expbits2,
|
||||
(int)modbits, dblexpsec/j, dblexpms/j);
|
||||
#endif
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
printf("Beginning 1000 interations of sanity checking.\n");
|
||||
printf("Any output indicates a bug. No output is very strong\n");
|
||||
printf("evidence that all the important low-level bignum routines\n");
|
||||
printf("are working properly.\n");
|
||||
|
||||
/*
|
||||
* If you change this loop to have an iteration 0, all results
|
||||
* are primted on that iteration. Useful to see what's going
|
||||
* on in case of major wierdness, but it produces a *lot* of
|
||||
* output.
|
||||
*/
|
||||
for (j = 1; j <= 1000; j++) {
|
||||
/* Do the tests for lots of different number sizes. */
|
||||
for (i = 1; i <= SIZE/2; i++) {
|
||||
/* Make a random number i words long */
|
||||
do {
|
||||
randnum(A,i);
|
||||
} while (lbnNorm_16(A,i) < i);
|
||||
|
||||
/* Checl lbnCmp - does a == a? */
|
||||
if (lbnCmp_16(A,A,i) || !j) {
|
||||
bnput16("a = ", A, i);
|
||||
printf("(a <=> a) = %d\n", lbnCmp_16(A,A,i));
|
||||
}
|
||||
|
||||
memcpy(c, a, sizeof(a));
|
||||
|
||||
/* Check that the difference, after copy, is good. */
|
||||
if (lbnCmp_16(A,C,i) || !j) {
|
||||
bnput16("a = ", A, i);
|
||||
bnput16("c = ", C, i);
|
||||
printf("(a <=> c) = %d\n", lbnCmp_16(A,C,i));
|
||||
}
|
||||
|
||||
/* Generate a non-zero random t */
|
||||
do {
|
||||
t = rand16();
|
||||
} while (!t);
|
||||
|
||||
/*
|
||||
* Add t to A. Check that:
|
||||
* - lbnCmp works in both directions, and
|
||||
* - A + t is greater than A. If there was a carry,
|
||||
* the result, less the carry, should be *less*
|
||||
* than A.
|
||||
*/
|
||||
carry = lbnAdd1_16(A,i,t);
|
||||
if (lbnCmp_16(A,C,i) + lbnCmp_16(C,A,i) != 0 ||
|
||||
lbnCmp_16(A,C,i) != (carry ? -1 : 1) || !j)
|
||||
{
|
||||
bnput16("c = ", C, i);
|
||||
printf("t = %lX\n", (unsigned long)t);
|
||||
bnput16("a = c+t = ", A, i);
|
||||
printf("carry = %lX\n", (unsigned long)carry);
|
||||
printf("(a <=> c) = %d\n", lbnCmp_16(A,C,i));
|
||||
printf("(c <=> a) = %d\n", lbnCmp_16(C,A,i));
|
||||
}
|
||||
|
||||
/* Subtract t again */
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnSub1_16(A,i,t);
|
||||
|
||||
if (carry != borrow || lbnCmp_16(A,C,i) || !j) {
|
||||
bnput16("a = ", C, i);
|
||||
printf("t = %lX\n", (unsigned long)t);
|
||||
lbnAdd1_16(A,i,t);
|
||||
bnput16("a += t = ", A, i);
|
||||
printf("Carry = %lX\n", (unsigned long)carry);
|
||||
lbnSub1_16(A,i,t);
|
||||
bnput16("a -= t = ", A, i);
|
||||
printf("Borrow = %lX\n", (unsigned long)borrow);
|
||||
printf("(a <=> c) = %d\n", lbnCmp_16(A,C,i));
|
||||
}
|
||||
|
||||
/* Generate a random B */
|
||||
do {
|
||||
randnum(B,i);
|
||||
} while (lbnNorm_16(B,i) < i);
|
||||
|
||||
carry = lbnAddN_16(A,B,i);
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnSubN_16(A,B,i);
|
||||
|
||||
if (carry != borrow || lbnCmp_16(A,C,i) || !j) {
|
||||
bnput16("a = ", C, i);
|
||||
bnput16("b = ", B, i);
|
||||
bnput16("a += b = ", D, i);
|
||||
printf("Carry = %lX\n", (unsigned long)carry);
|
||||
bnput16("a -= b = ", A, i);
|
||||
printf("Borrow = %lX\n", (unsigned long)borrow);
|
||||
printf("(a <=> c) = %d\n", lbnCmp_16(A,C,i));
|
||||
}
|
||||
|
||||
/* D = B * t */
|
||||
lbnMulN1_16(D, B, i, t);
|
||||
memcpy(e, d, sizeof(e));
|
||||
/* D = A + B * t, "carry" is overflow */
|
||||
borrow = *(BIGLITTLE(D-i-1,D+i)) += lbnAddN_16(D,A,i);
|
||||
|
||||
carry = lbnMulAdd1_16(A, B, i, t);
|
||||
|
||||
/* Did MulAdd get the same answer as mul then add? */
|
||||
if (carry != borrow || lbnCmp_16(A, D, i) || !j) {
|
||||
bnput16("a = ", C, i);
|
||||
bnput16("b = ", B, i);
|
||||
printf("t = %lX\n", (unsigned long)t);
|
||||
bnput16("e = b * t = ", E, i+1);
|
||||
bnput16(" a + e = ", D, i+1);
|
||||
bnput16("a + b * t = ", A, i);
|
||||
printf("carry = %lX\n", (unsigned long)carry);
|
||||
}
|
||||
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnMulSub1_16(A, B, i, t);
|
||||
|
||||
/* Did MulSub perform the inverse of MulAdd */
|
||||
if (carry != borrow || lbnCmp_16(A,C,i) || !j) {
|
||||
bnput16(" a = ", C, i);
|
||||
bnput16(" b = ", B, i);
|
||||
bnput16("a += b*t = ", D, i);
|
||||
printf("Carry = %lX\n", (unsigned long)carry);
|
||||
bnput16("a -= b*t = ", A, i);
|
||||
printf("Borrow = %lX\n", (unsigned long)borrow);
|
||||
printf("(a <=> c) = %d\n", lbnCmp_16(A,C,i));
|
||||
bnput16("b*t = ", E, i+1);
|
||||
}
|
||||
/* At this point we're done with t, so it's scratch */
|
||||
#if 0
|
||||
/* Extra debug code */
|
||||
lbnMulN1_16(C, A, i, BIGLITTLE(B[-1],B[0]));
|
||||
bnput16("a * b[0] = ", C, i+1);
|
||||
for (k = 1; k < i; k++) {
|
||||
carry = lbnMulAdd1_16(BIGLITTLE(C-k,C+k), A, i,
|
||||
*(BIGLITTLE(B-1-k,B+k)));
|
||||
*(BIGLITTLE(C-i-k,C+i+k)) = carry;
|
||||
bnput16("a * b[x] = ", C, i+k+1);
|
||||
}
|
||||
|
||||
lbnMulN1_16(D, B, i, BIGLITTLE(A[-1],A[0]));
|
||||
bnput16("b * a[0] = ", D, i+1);
|
||||
for (k = 1; k < i; k++) {
|
||||
carry = lbnMulAdd1_16(BIGLITTLE(D-k,D+k), B, i,
|
||||
*(BIGLITTLE(A-1-k,A+k)));
|
||||
*(BIGLITTLE(D-i-k,D+i+k)) = carry;
|
||||
bnput16("b * a[x] = ", D, i+k+1);
|
||||
}
|
||||
#endif
|
||||
/* Does Mul work both ways symmetrically */
|
||||
lbnMul_16(C,A,i,B,i);
|
||||
lbnMul_16(D,B,i,A,i);
|
||||
if (lbnCmp_16(C,D,i+i) || !j) {
|
||||
bnput16("a = ", A, i);
|
||||
bnput16("b = ", B, i);
|
||||
bnput16("a * b = ", C, i+i);
|
||||
bnput16("b * a = ", D, i+i);
|
||||
printf("(a*b <=> b*a) = %d\n",
|
||||
lbnCmp_16(C,D,i+i));
|
||||
}
|
||||
/* Check multiplication modulo some small things */
|
||||
/* 30030 = 2*3*5*11*13 */
|
||||
k = lbnModQ_16(C, i+i, 30030);
|
||||
for (l = 0;
|
||||
l < sizeof(smallprimes)/sizeof(*smallprimes);
|
||||
l++)
|
||||
{
|
||||
m = smallprimes[l];
|
||||
t = lbnModQ_16(C, i+i, m);
|
||||
carry = lbnModQ_16(A, i, m);
|
||||
borrow = lbnModQ_16(B, i, m);
|
||||
if (t != (carry * borrow) % m) {
|
||||
bnput16("a = ", A, i);
|
||||
printf("a mod %u = %u\n", m,
|
||||
(unsigned)carry);
|
||||
bnput16("b = ", B, i);
|
||||
printf("b mod %u = %u\n", m,
|
||||
(unsigned)borrow);
|
||||
bnput16("a*b = ", C, i+i);
|
||||
printf("a*b mod %u = %u\n", m,
|
||||
(unsigned)t);
|
||||
printf("expected %u\n",
|
||||
(unsigned)((carry*borrow)%m));
|
||||
}
|
||||
/* Verify that (C % 30030) % m == C % m */
|
||||
if (m <= 13 && t != k % m) {
|
||||
printf("c mod 30030 = %u mod %u= %u\n",
|
||||
k, m, k%m);
|
||||
printf("c mod %u = %u\n",
|
||||
m, (unsigned)t);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate an F less than A and B */
|
||||
do {
|
||||
randnum(F,i);
|
||||
} while (lbnCmp_16(F,A,i) >= 0 ||
|
||||
lbnCmp_16(F,B,i) >= 0);
|
||||
|
||||
/* Add F to D (remember, D = A*B) */
|
||||
lbnAdd1_16(BIGLITTLE(D-i,D+i), i, lbnAddN_16(D, F, i));
|
||||
memcpy(c, d, sizeof(d));
|
||||
|
||||
/*
|
||||
* Divide by A and check that quotient and remainder
|
||||
* match (remainder should be F, quotient should be B)
|
||||
*/
|
||||
t = lbnDiv_16(E,C,i+i,A,i);
|
||||
if (t || lbnCmp_16(E,B,i) || lbnCmp_16(C, F, i) || !j) {
|
||||
bnput16("a = ", A, i);
|
||||
bnput16("b = ", B, i);
|
||||
bnput16("f = ", F, i);
|
||||
bnput16("a * b + f = ", D, i+i);
|
||||
printf("qhigh = %lX\n", (unsigned long)t);
|
||||
bnput16("(a*b+f) / a = ", E, i);
|
||||
bnput16("(a*b+f) % a = ", C, i);
|
||||
}
|
||||
|
||||
memcpy(c, d, sizeof(d));
|
||||
|
||||
/* Divide by B and check similarly */
|
||||
t = lbnDiv_16(E,C,i+i,B,i);
|
||||
if (lbnCmp_16(E,A,i) || lbnCmp_16(C, F, i) || !j) {
|
||||
bnput16("a = ", A, i);
|
||||
bnput16("b = ", B, i);
|
||||
bnput16("f = ", F, i);
|
||||
bnput16("a * b + f = ", D, i+i);
|
||||
printf("qhigh = %lX\n", (unsigned long)t);
|
||||
bnput16("(a*b+f) / b = ", E, i);
|
||||
bnput16("(a*b+f) % b = ", C, i);
|
||||
}
|
||||
|
||||
/* Check that A*A == A^2 */
|
||||
lbnMul_16(C,A,i,A,i);
|
||||
lbnSquare_16(D,A,i);
|
||||
if (lbnCmp_16(C,D,i+i) || !j) {
|
||||
bnput16("a*a = ", C, i+i);
|
||||
bnput16("a^2 = ", D, i+i);
|
||||
printf("(a * a == a^2) = %d\n",
|
||||
lbnCmp_16(C,D,i+i));
|
||||
}
|
||||
#if 0
|
||||
/* Compute a GCD */
|
||||
lbnCopy_16(C,A,i);
|
||||
lbnCopy_16(D,B,i);
|
||||
z = lbnGcd_16(C, i, D, i, &k);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
/* z = 1 if GCD in D; z = 0 if GCD in C */
|
||||
|
||||
/* Approximate check that the GCD came out right */
|
||||
for (l = 0;
|
||||
l < sizeof(smallprimes)/sizeof(*smallprimes);
|
||||
l++)
|
||||
{
|
||||
m = smallprimes[l];
|
||||
t = lbnModQ_16(z ? D : C, k, m);
|
||||
carry = lbnModQ_16(A, i, m);
|
||||
borrow = lbnModQ_16(B, i, m);
|
||||
if (!t != (!carry && !borrow)) {
|
||||
bnput16("a = ", A, i);
|
||||
printf("a mod %u = %u\n", m,
|
||||
(unsigned)carry);
|
||||
bnput16("b = ", B, i);
|
||||
printf("b mod %u = %u\n", m,
|
||||
(unsigned)borrow);
|
||||
bnput16("gcd(a,b) = ", z ? D : C, k);
|
||||
printf("gcd(a,b) mod %u = %u\n", m,
|
||||
(unsigned)t);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Do some Montgomery operations
|
||||
* Start with A > B, and also place a copy of B into C.
|
||||
* Then make A odd so it can be a Montgomery modulus.
|
||||
*/
|
||||
if (lbnCmp_16(A, B, i) < 0) {
|
||||
memcpy(c, a, sizeof(c));
|
||||
memcpy(a, b, sizeof(a));
|
||||
memcpy(b, c, sizeof(b));
|
||||
} else {
|
||||
memcpy(c, b, sizeof(c));
|
||||
}
|
||||
BIGLITTLE(A[-1],A[0]) |= 1;
|
||||
|
||||
/* Convert to and from */
|
||||
lbnToMont_16(B, i, A, i);
|
||||
lbnFromMont_16(B, A, i);
|
||||
if (lbnCmp_16(B, C, i)) {
|
||||
memcpy(b, c, sizeof(c));
|
||||
bnput16("mod = ", A, i);
|
||||
bnput16("input = ", B, i);
|
||||
lbnToMont_16(B, i, A, i);
|
||||
bnput16("mont = ", B, i);
|
||||
lbnFromMont_16(B, A, i);
|
||||
bnput16("output = ", B, i);
|
||||
}
|
||||
/* E = B^5 (mod A), no Montgomery ops */
|
||||
lbnSquare_16(E, B, i);
|
||||
(void)lbnDiv_16(BIGLITTLE(E-i,E+i),E,i+i,A,i);
|
||||
lbnSquare_16(D, E, i);
|
||||
(void)lbnDiv_16(BIGLITTLE(D-i,D+i),D,i+i,A,i);
|
||||
lbnMul_16(E, D, i, B, i);
|
||||
(void)lbnDiv_16(BIGLITTLE(E-i,E+i),E,i+i,A,i);
|
||||
|
||||
/* D = B^5, using ExpMod */
|
||||
BIGLITTLE(F[-1],F[0]) = 5;
|
||||
z = lbnExpMod_16(D, B, i, F, 1, A, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
if (lbnCmp_16(D, E, i) || !j) {
|
||||
bnput16("mod = ", A, i);
|
||||
bnput16("input = ", B, i);
|
||||
bnput16("input^5 = ", E, i);
|
||||
bnput16("input^5 = ", D, i);
|
||||
printf("a>b (x <=> y) = %d\n",
|
||||
lbnCmp_16(D,E,i));
|
||||
}
|
||||
/* TODO: Test lbnTwoExpMod, lbnDoubleExpMod */
|
||||
} /* for (i) */
|
||||
printf("\r%d ", j);
|
||||
fflush(stdout);
|
||||
} /* for (j) */
|
||||
printf("%d iterations of up to %d 16-bit words completed.\n",
|
||||
j-1, i-1);
|
||||
return 0;
|
||||
nomem:
|
||||
printf("Out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/* bnconfig.h. Generated automatically by configure. */
|
||||
/*
|
||||
* bnconfig.h -- Configuration file for BigNum library.
|
||||
*
|
||||
* This file is automatically filled in by configure.
|
||||
* Everything must start out turned *off*, because configure
|
||||
* (or, more properly, config.status) only knows how to turn them
|
||||
* *on*.
|
||||
*/
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
/* Define to empty if the compiler does not support 'const' variables. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `unsigned' if <sys/types.h> doesn't define it. */
|
||||
/* #undef size_t */
|
||||
|
||||
/* Checks for the presence and absence of various header files */
|
||||
#define HAVE_ASSERT_H 1
|
||||
#define NO_ASSERT_H !HAVE_ASSERT_H
|
||||
#define HAVE_LIMITS_H 1
|
||||
#define NO_LIMITS_H !HAVE_LIMITS_H
|
||||
#define HAVE_STDLIB_H 1
|
||||
#define NO_STDLIB_H !HAVE_STDLIB_H
|
||||
#define HAVE_STRING_H 1
|
||||
#define NO_STRING_H !HAVE_STRING_H
|
||||
|
||||
#define HAVE_STRINGS_H 0
|
||||
#define NEED_MEMORY_H 0
|
||||
|
||||
/* We go to some trouble to find accurate times... */
|
||||
|
||||
/* Define if you have Posix.4 glock_gettime() */
|
||||
#define HAVE_CLOCK_GETTIME 0
|
||||
/* Define if you have Solaris-style gethrvtime() */
|
||||
#define HAVE_GETHRVTIME 0
|
||||
/* Define if you have getrusage() */
|
||||
#define HAVE_GETRUSAGE 1
|
||||
/* Define if you have clock() */
|
||||
#define HAVE_CLOCK 1
|
||||
/* Define if you have time() */
|
||||
#define HAVE_TIME 1
|
||||
|
||||
/*
|
||||
* Define as 0 if #including <sys/time.h> automatically
|
||||
* #includes <time.h>, and doing so explicitly causes an
|
||||
* error.
|
||||
*/
|
||||
#define TIME_WITH_SYS_TIME 1
|
||||
|
||||
/* Defines for various kinds of library brokenness */
|
||||
|
||||
/* Define if <stdio.h> is missing prototypes (= lots of warnings!) */
|
||||
#define NO_STDIO_PROTOS 0
|
||||
|
||||
/* Define if <assert.h> depends on <stdio.h> and breaks without it */
|
||||
#define ASSERT_NEEDS_STDIO 0
|
||||
/* Define if <assert.h> depends on <stdlib.h> and complains without it */
|
||||
#define ASSERT_NEEDS_STDLIB 0
|
||||
|
||||
/*
|
||||
* Define if <string.h> delcares the mem* functions to take char *
|
||||
* instead of void * parameters (= lots of warnings)
|
||||
*/
|
||||
#define MEM_PROTOS_BROKEN 0
|
||||
|
||||
/* If not available, bcopy() is substituted */
|
||||
#define HAVE_MEMMOVE 1
|
||||
#define NO_MEMMOVE !HAVE_MEMMOVE
|
||||
#define HAVE_MEMCPY 1
|
||||
#define NO_MEMCPY !HAVE_MEMCPY
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
+250
@@ -0,0 +1,250 @@
|
||||
#ifndef CPUTIME_H
|
||||
#define CPUTIME_H
|
||||
|
||||
/*
|
||||
* Figure out what clock to use. Each possibility can be specifically
|
||||
* enabled or disabled by predefining USE_XXX to 1 or 0. For some,
|
||||
* the code attempts to detect availability automatically. If the
|
||||
* Symbols HAVE_XXX are defined, they are used. If not, they are
|
||||
* set to reasonable default assumptions while further conditions
|
||||
* are checked. The choices, and the ways they are auto-detected are:
|
||||
* - gethrvtime(), if HAVE_GETHRVTIME is set to 1.
|
||||
* - clock_gettime(CLOCK_VIRTUAL,...), if CLOCK_VIRTUAL is defined in <time.h>
|
||||
* - getrusage(RUSAGE_SELF,...), if RUSAGE_SELF is defined in <sys/resource.h>
|
||||
* - clock(), if CLOCKS_PER_SEC or CLK_TCK are defined in <time.h>
|
||||
* - time(), unless specifically disabled.
|
||||
*
|
||||
* The symbol CLOCK_AVAIL is given a value of 1 if a clock is found.
|
||||
* The following are then available:
|
||||
* timetype (typedef): the type needed to hold a clock value.
|
||||
* gettime(t) (macro): A function that gets passed a timetype *.
|
||||
* subtime(d,s) (macro): Sets d -= s, essentially.
|
||||
* msec(t) (macro): Given a timetype, return the number of milliseconds
|
||||
* in it, as an unsigned integer between 0 and 999.
|
||||
* sec(t) (macro): Given a timetype, return the number of seconds in it,
|
||||
* as an unsigned long integer.
|
||||
*/
|
||||
|
||||
/* We expect that our caller has already #included "bnconfig.h" if possible. */
|
||||
|
||||
#ifndef unix
|
||||
#define unix 0
|
||||
#endif
|
||||
#ifndef __unix
|
||||
#define __unix 0
|
||||
#endif
|
||||
#ifndef __unix__
|
||||
#define __unix__ 0
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
/* Nothing */
|
||||
#elif unix
|
||||
#define UNIX 1
|
||||
#elif __unix
|
||||
#define UNIX 1
|
||||
#elif __unix__
|
||||
#define UNIX 1
|
||||
#endif
|
||||
|
||||
#ifndef UNIX
|
||||
#define UNIX 0
|
||||
#endif
|
||||
|
||||
#ifndef TIME_WITH_SYS_TIME
|
||||
#define TIME_WITH_SYS_TIME 1 /* Assume true if not told */
|
||||
#endif
|
||||
#ifndef HAVE_SYS_TIME_H
|
||||
#define HAVE_SYS_TIME_H 0 /* Assume true if not told */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Include <time.h> unless that would prevent us from later including
|
||||
* <sys/time.h>, in which case include *that* immediately.
|
||||
*/
|
||||
#if TIME_WITH_SYS_TIME
|
||||
#include <time.h>
|
||||
#elif HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifndef USE_GETHRVTIME
|
||||
#ifdef HAVE_GETHRVTIME
|
||||
#define USE_GETHRVTIME HAVE_GETHRVTIME
|
||||
#else
|
||||
#define USE_GETHRVTIME 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if USE_GETHRVTIME
|
||||
#define CLOCK_AVAIL 1
|
||||
typedef hrtime_t timetype;
|
||||
#define gettime(t) *(t) = gethrvtime()
|
||||
#define subtime(d,s) d -= s
|
||||
#define msec(t) (unsigned)((t/1000000)%1000)
|
||||
#define sec(t) (unsigned long)(t/1000000000)
|
||||
|
||||
#else
|
||||
#ifndef USE_CLOCK_GETTIME
|
||||
#define USE_CLOCK_GETTIME 0
|
||||
#ifndef HAVE_CLOCK_GETTIME
|
||||
#define HAVE_CLOCK_GETTIME 1 /* Assume the CLOCK_VIRTUAL test will catch */
|
||||
#endif
|
||||
/*
|
||||
* It turns out to be non-ANSI to use the apparently simpler construct
|
||||
* "#define USE_CLOCK_GETTIME defined(CLOCK_VIRTUAL)", since
|
||||
* "If the token defined is generated as a result of this replacement
|
||||
* process or use of the defined unary operator does not match one
|
||||
* of the two specified forms prior ro macro replacement, the behaviour
|
||||
* is undefined." (ANSI/ISO 9899-1990 section 6.8.1)
|
||||
* In practice, it breaks the DEC Alpha compiler.
|
||||
*/
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
#ifdef CLOCK_VIRTUAL
|
||||
#ifdef USE_CLOCK_GETTIME
|
||||
#undef USE_CLOCK_GETTIME
|
||||
#endif
|
||||
#define USE_CLOCK_GETTIME 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if USE_CLOCK_GETTIME
|
||||
#define CLOCK_AVAIL 1
|
||||
typedef struct timespec timetype;
|
||||
#define gettime(t) clock_gettime(CLOCK_VIRTUAL, t)
|
||||
#define subtime(d,s) \
|
||||
d.tv_sec -= s.tv_sec + (d.tv_nsec >= s.tv_nsec ? \
|
||||
(d.tv_nsec -= s.tv_nsec, 0) : \
|
||||
(d.tv_nsec += 1000000000-s.tv_nsec, 1))
|
||||
#define msec(t) (unsigned)(t.tv_nsec/1000000)
|
||||
#define sec(t) (unsigned long)(t.tv_sec)
|
||||
|
||||
#else
|
||||
#if UNIX
|
||||
#ifndef HAVE_GETRUSAGE
|
||||
#define HAVE_GETRUSAGE 1
|
||||
#endif
|
||||
#endif /* UNIX */
|
||||
|
||||
#define USE_GETRUSAGE 0
|
||||
|
||||
/* AJR */
|
||||
/*#define HAVE_GETRUSAGE 0*/
|
||||
|
||||
#include <sys/time.h>
|
||||
#if HAVE_GETRUSAGE
|
||||
#if TIME_WITH_SYS_TIME
|
||||
#ifndef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#elif HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#endif /* TIME_WITH_SYS_TIME */
|
||||
#include <sys/resource.h>
|
||||
|
||||
#ifdef RUSAGE_SELF
|
||||
#undef USE_GETRUSAGE
|
||||
#define USE_GETRUSAGE 1
|
||||
#endif
|
||||
#endif /* HAVE_GETRUSAGE */
|
||||
|
||||
#if USE_GETRUSAGE
|
||||
#define CLOCK_AVAIL 1
|
||||
typedef struct rusage timetype;
|
||||
#define gettime(t) getrusage(RUSAGE_SELF, t);
|
||||
#define subtime(d, s) \
|
||||
d.ru_utime.tv_sec -= s.ru_utime.tv_sec + \
|
||||
(d.ru_utime.tv_usec >= s.ru_utime.tv_usec ? \
|
||||
(d.ru_utime.tv_usec -= s.ru_utime.tv_usec, 0) : \
|
||||
(d.ru_utime.tv_usec += 1000000-s.ru_utime.tv_usec, 1))
|
||||
#define msec(t) (unsigned)(t.ru_utime.tv_usec/1000)
|
||||
#define sec(t) (unsigned long)(t.ru_utime.tv_sec)
|
||||
|
||||
#else
|
||||
|
||||
#ifndef HAVE_CLOCK
|
||||
#define HAVE_CLOCK 1
|
||||
#endif
|
||||
|
||||
#define USE_CLOCK 0
|
||||
#define USE_TIME 0
|
||||
|
||||
#if HAVE_CLOCK
|
||||
#ifndef CLOCKS_PER_SEC
|
||||
#ifdef CLK_TCK
|
||||
#define CLOCKS_PER_SEC CLK_TCK
|
||||
#endif
|
||||
#endif /* !defined(CLOCKS_PER_SEC) */
|
||||
|
||||
#ifndef USE_CLOCK
|
||||
#ifdef CLOCKS_PER_SEC
|
||||
#define USE_CLOCK 1
|
||||
#endif
|
||||
#endif /* !defined(USE_CLOCK) */
|
||||
#endif /* HAVE_CLOCK */
|
||||
|
||||
#if USE_CLOCK
|
||||
#define CLOCK_AVAIL 1
|
||||
typedef clock_t timetype;
|
||||
#define gettime(t) *(t) = clock()
|
||||
#define subtime(d, s) d -= s
|
||||
/*
|
||||
* I don't like having to do floating point math. CLOCKS_PER_SEC is
|
||||
* almost always an integer, and the most common non-integral case is
|
||||
* the MS-DOS wierdness of 18.2. We have to be a bit careful with the
|
||||
* casts, because ANSI C doesn't provide % with non-integral operands,
|
||||
* but just to be extra annoying, some implementations define it as an
|
||||
* integral-valued float. (E.g. Borland C++ 4.5 with 1000.0)
|
||||
*/
|
||||
/* AJR #if ((unsigned)CLOCKS_PER_SEC == CLOCKS_PER_SEC)*/
|
||||
#if 1
|
||||
/* Integer CLOCKS_PER_SEC */
|
||||
|
||||
#define sec(t) (unsigned long)(t/CLOCKS_PER_SEC)
|
||||
#define msec(t) (unsigned)(t % (unsigned)CLOCKS_PER_SEC * 1000 / \
|
||||
(unsigned)CLOCKS_PER_SEC)
|
||||
/* AJR #elif (CLOCKS_PER_SEC == 18.2)*/
|
||||
#elif 0
|
||||
/* MS-DOS-ism */
|
||||
|
||||
#define sec(t) (unsigned long)(t*5 / 91)
|
||||
#define msec(t) (unsigned)(t*5 % 91 * 1000 / 91)
|
||||
|
||||
#else /* We are forced to muck with floating point.... */
|
||||
|
||||
#include <math.h> /* For floor() */
|
||||
#define sec(t) (unsigned long)(t/CLOCKS_PER_SEC)
|
||||
#define msec(t) (unsigned)((t - sec(t)*CLOCKS_PER_SEC) * 1000 / CLOCKS_PER_SEC)
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifndef HAVE_TIME
|
||||
#define HAVE_TIME 1
|
||||
#endif
|
||||
|
||||
#if HAVE_TIME
|
||||
#ifndef USE_TIME
|
||||
#define USE_TIME 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if USE_TIME
|
||||
#define CLOCK_AVAIL 1
|
||||
typedef time_t timetype;
|
||||
#define gettime(t) time(t)
|
||||
#define subtime(d, s) d -= s
|
||||
#define msec(t) (unsigned)0
|
||||
#define sec(t) (unsigned long)t
|
||||
|
||||
#endif /* USE_TIME */
|
||||
#endif /* USE_CLOCK */
|
||||
#endif /* USE_GETRUSAGE */
|
||||
#endif /* USE_CLOCK_GETTIME */
|
||||
#endif /* USE_GETHRVTIME */
|
||||
|
||||
#endif /*CPUTIME_H*/
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
#ifndef KLUDGE_H
|
||||
#define KLUDGE_H
|
||||
|
||||
/*
|
||||
* Kludges for not-quite-ANSI systems.
|
||||
* This should always be the last file included, because it may
|
||||
* mess up some system header files.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef ASSERT_NEEDS_STDIO
|
||||
#define ASSERT_NEEDS_STDIO 0
|
||||
#endif
|
||||
#ifndef ASSERT_NEEDS_STDLIB
|
||||
#define ASSERT_NEEDS_STDLIB 0
|
||||
#endif
|
||||
#ifndef NO_STDLIB_H
|
||||
#define NO_STDLIB_H 0
|
||||
#endif
|
||||
|
||||
/* SunOS 4.1.x <assert.h> needs "stderr" defined, and "exit" declared... */
|
||||
#ifdef assert
|
||||
#if ASSERT_NEEDS_STDIO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#if ASSERT_NEEDS_STDLIB
|
||||
#if !NO_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NO_MEMMOVE
|
||||
#define NO_MEMMOVE 0
|
||||
#endif
|
||||
#if NO_MEMMOVE /* memove() not in libraries */
|
||||
#define memmove(dest,src,len) bcopy(src,dest,len)
|
||||
#endif
|
||||
|
||||
#ifndef NO_MEMCPY
|
||||
#define NO_MEMCPY 0
|
||||
#endif
|
||||
#if NO_MEMCPY /* memcpy() not in libraries */
|
||||
#define memcpy(dest,src,len) bcopy(src,dest,len)
|
||||
#endif
|
||||
|
||||
#ifndef MEM_PROTOS_BROKEN
|
||||
#define MEM_PROTOS_BROKEN 0
|
||||
#endif
|
||||
#if MEM_PROTOS_BROKEN
|
||||
#define memcpy(d,s,l) memcpy((void *)(d), (void const *)(s), l)
|
||||
#define memmove(d,s,l) memmove((void *)(d), (void const *)(s), l)
|
||||
#define memcmp(d,s,l) memcmp((void const *)(d), (void const *)(s), l)
|
||||
#define memset(d,v,l) memset((void *)(d), v, l)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If there are no prototypes for the stdio functions, use these to
|
||||
* reduce compiler warnings. Uses EOF as a giveaway to indicate
|
||||
* that <stdio.h> was #included.
|
||||
*/
|
||||
#ifndef NO_STDIO_PROTOS
|
||||
#define NO_STDIO_PROTOS 0
|
||||
#endif
|
||||
#if NO_STDIO_PROTOS /* Missing prototypes for "simple" functions */
|
||||
#ifdef EOF
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int (puts)(char const *);
|
||||
int (fputs)(char const *, FILE *);
|
||||
int (fflush)(FILE *);
|
||||
int (printf)(char const *, ...);
|
||||
int (fprintf)(FILE *, char const *, ...);
|
||||
/* If we have a sufficiently old-fashioned stdio, it probably uses these... */
|
||||
int (_flsbuf)(int, FILE *);
|
||||
int (_filbuf)(FILE *);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* EOF */
|
||||
#endif /* NO_STDIO_PROTOS */
|
||||
|
||||
/*
|
||||
* Borland C seems to think that it's a bad idea to decleare a
|
||||
* structure tag and not declare the contents. I happen to think
|
||||
* it's a *good* idea to use such "opaque" structures wherever
|
||||
* possible. So shut up.
|
||||
*/
|
||||
#ifdef __BORLANDC__
|
||||
#pragma warn -stu
|
||||
#ifndef MSDOS
|
||||
#define MSDOS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Turn off warning about negation of unsigned values */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4146)
|
||||
#endif
|
||||
|
||||
/* Cope with people forgetting to define the OS, if possible... */
|
||||
#ifndef MSDOS
|
||||
#ifdef __MSDOS
|
||||
#define MSDOS 1
|
||||
#endif
|
||||
#endif
|
||||
#ifndef MSDOS
|
||||
#ifdef __MSDOS__
|
||||
#define MSDOS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* By MS-DOS, we mean 16-bit brain-dead MS-DOS. Not GCC & GO32 */
|
||||
#ifdef __GO32
|
||||
#undef MSDOS
|
||||
#endif
|
||||
#ifdef __GO32__
|
||||
#undef MSDOS
|
||||
#endif
|
||||
|
||||
#endif /* KLUDGE_H */
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* lbn.h - Low-level bignum header.
|
||||
* Defines various word sizes and useful macros.
|
||||
*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
*/
|
||||
#ifndef LBN_H
|
||||
#define LBN_H
|
||||
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_LIMITS_H
|
||||
#define NO_LIMITS_H 0
|
||||
#endif
|
||||
|
||||
/* Make sure we have 8-bit bytes */
|
||||
#if !NO_LIMITS_H
|
||||
#include <limits.h>
|
||||
#if UCHAR_MAX != 0xff || CHAR_BIT != 8
|
||||
#error The bignum library requires 8-bit unsigned characters.
|
||||
#endif
|
||||
#endif /* !NO_LIMITS_H */
|
||||
|
||||
#ifdef BNINCLUDE /* If this is defined as, say, foo.h */
|
||||
#define STR(x) #x /* STR(BNINCLUDE) -> "BNINCLUDE" */
|
||||
#define XSTR(x) STR(x) /* XSTR(BNINCLUDE) -> STR(foo.h) -> "foo.h" */
|
||||
#include XSTR(BNINCLUDE) /* #include "foo.h" */
|
||||
#undef XSTR
|
||||
#undef STR
|
||||
#endif
|
||||
|
||||
/* Do we want bnYield()? */
|
||||
#ifndef BNYIELD
|
||||
#define BNYIELD 0
|
||||
#endif
|
||||
|
||||
/* Figure out the endianness */
|
||||
/* Error if more than one is defined */
|
||||
#if defined(BN_BIG_ENDIAN) && defined(BN_LITTLE_ENDIAN)
|
||||
#error Only one of BN_BIG_ENDIAN or BN_LITTLE_ENDIAN may be defined
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If no preference is stated, little-endian C code is slightly more
|
||||
* efficient, so prefer that. (The endianness here does NOT have to
|
||||
* match the machine's native byte sex; the library's C code will work
|
||||
* either way. The flexibility is allowed for assembly routines
|
||||
* that do care.
|
||||
*/
|
||||
#if !defined(BN_BIG_ENDIAN) && !defined(BN_LITTLE_ENDIAN)
|
||||
#define BN_LITTLE_ENDIAN 1
|
||||
#endif /* !BN_BIG_ENDIAN && !BN_LITTLE_ENDIAN */
|
||||
|
||||
/* Macros to choose between big and little endian */
|
||||
#if defined(BN_BIG_ENDIAN)
|
||||
#define BIG(b) b
|
||||
#define LITTLE(l) /*nothing*/
|
||||
#define BIGLITTLE(b,l) b
|
||||
#elif BN_LITTLE_ENDIAN
|
||||
#define BIG(b) /*nothing*/
|
||||
#define LITTLE(l) l
|
||||
#define BIGLITTLE(b,l) l
|
||||
#else
|
||||
#error One of BN_BIG_ENDIAN or BN_LITTLE_ENDIAN must be defined as 1
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Find a 16-bit unsigned type.
|
||||
* Unsigned short is preferred over unsigned int to make the type chosen
|
||||
* by this file more stable on platforms (such as many 68000 compilers)
|
||||
* which support both 16- and 32-bit ints.
|
||||
*/
|
||||
#ifndef BNWORD16
|
||||
#ifndef USHRT_MAX /* No <limits.h> available - guess */
|
||||
typedef unsigned short bnword16;
|
||||
#define BNWORD16 bnword16
|
||||
#elif USHRT_MAX == 0xffff
|
||||
typedef unsigned short bnword16;
|
||||
#define BNWORD16 bnword16
|
||||
#elif UINT_MAX == 0xffff
|
||||
typedef unsigned bnword16;
|
||||
#define BNWORD16 bnword16
|
||||
#endif
|
||||
#endif /* BNWORD16 */
|
||||
|
||||
/*
|
||||
* Find a 32-bit unsigned type.
|
||||
* Unsigned long is preferred over unsigned int to make the type chosen
|
||||
* by this file more stable on platforms (such as many 68000 compilers)
|
||||
* which support both 16- and 32-bit ints.
|
||||
*/
|
||||
#ifndef BNWORD32
|
||||
#ifndef ULONG_MAX /* No <limits.h> available - guess */
|
||||
typedef unsigned long bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
#elif ULONG_MAX == 0xfffffffful
|
||||
typedef unsigned long bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
#elif UINT_MAX == 0xffffffff
|
||||
typedef unsigned bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
#elif USHRT_MAX == 0xffffffff
|
||||
typedef unsigned short bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
#endif
|
||||
#endif /* BNWORD16 */
|
||||
|
||||
/*
|
||||
* Find a 64-bit unsigned type.
|
||||
* The conditions here are more complicated to avoid using numbers that
|
||||
* will choke lesser preprocessors (like 0xffffffffffffffff) unless
|
||||
* we're reasonably certain that they'll be acceptable.
|
||||
*/
|
||||
#if !defined(BNWORD64) && ULONG_MAX > 0xfffffffful
|
||||
#if ULONG_MAX == 0xffffffffffffffff
|
||||
typedef unsigned long bnword64;
|
||||
#define BNWORD64 bnword64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* I would test the value of unsigned long long, but some *preprocessors*
|
||||
* don't constants that long even if the compiler can accept them, so it
|
||||
* doesn't work reliably. So cross our fingers and hope that it's a 64-bit
|
||||
* type.
|
||||
*
|
||||
* GCC uses ULONG_LONG_MAX. Solaris uses ULLONG_MAX. IRIX uses ULONGLONG_MAX.
|
||||
* Are there any other names for this?
|
||||
*/
|
||||
#if !defined(BNWORD64) && \
|
||||
(defined(ULONG_LONG_MAX) || defined (ULLONG_MAX) || defined(ULONGLONG_MAX))
|
||||
typedef unsigned long long bnword64;
|
||||
#define BNWORD64 bnword64
|
||||
#else
|
||||
typedef unsigned long long bnword64;
|
||||
#define BNWORD64 bnword64
|
||||
#endif
|
||||
|
||||
/* We don't even try to find a 128-bit type at the moment */
|
||||
|
||||
#endif /* !LBN_H */
|
||||
+4076
File diff suppressed because it is too large.
Load diff
+156
@@ -0,0 +1,156 @@
|
||||
#ifndef LBN16_H
|
||||
#define LBN16_H
|
||||
|
||||
#include "lbn.h"
|
||||
|
||||
#ifndef BNWORD16
|
||||
#error 16-bit bignum library requires a 16-bit data type
|
||||
#endif
|
||||
|
||||
#ifndef lbnCopy_16
|
||||
void lbnCopy_16(BNWORD16 *dest, BNWORD16 const *src, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnZero_16
|
||||
void lbnZero_16(BNWORD16 *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnNeg_16
|
||||
void lbnNeg_16(BNWORD16 *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnAdd1_16
|
||||
BNWORD16 lbnAdd1_16(BNWORD16 *num, unsigned len, BNWORD16 carry);
|
||||
#endif
|
||||
#ifndef lbnSub1_16
|
||||
BNWORD16 lbnSub1_16(BNWORD16 *num, unsigned len, BNWORD16 borrow);
|
||||
#endif
|
||||
|
||||
#ifndef lbnAddN_16
|
||||
BNWORD16 lbnAddN_16(BNWORD16 *num1, BNWORD16 const *num2, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnSubN_16
|
||||
BNWORD16 lbnSubN_16(BNWORD16 *num1, BNWORD16 const *num2, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnCmp_16
|
||||
int lbnCmp_16(BNWORD16 const *num1, BNWORD16 const *num2, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMulN1_16
|
||||
void lbnMulN1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k);
|
||||
#endif
|
||||
#ifndef lbnMulAdd1_16
|
||||
BNWORD16
|
||||
lbnMulAdd1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k);
|
||||
#endif
|
||||
#ifndef lbnMulSub1_16
|
||||
BNWORD16 lbnMulSub1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k);
|
||||
#endif
|
||||
|
||||
#ifndef lbnLshift_16
|
||||
BNWORD16 lbnLshift_16(BNWORD16 *num, unsigned len, unsigned shift);
|
||||
#endif
|
||||
#ifndef lbnDouble_16
|
||||
BNWORD16 lbnDouble_16(BNWORD16 *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnRshift_16
|
||||
BNWORD16 lbnRshift_16(BNWORD16 *num, unsigned len, unsigned shift);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMul_16
|
||||
void lbnMul_16(BNWORD16 *prod, BNWORD16 const *num1, unsigned len1,
|
||||
BNWORD16 const *num2, unsigned len2);
|
||||
#endif
|
||||
#ifndef lbnSquare_16
|
||||
void lbnSquare_16(BNWORD16 *prod, BNWORD16 const *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnNorm_16
|
||||
unsigned lbnNorm_16(BNWORD16 const *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnBits_16
|
||||
unsigned lbnBits_16(BNWORD16 const *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnExtractBigBytes_16
|
||||
void lbnExtractBigBytes_16(BNWORD16 const *bn, unsigned char *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnInsertBigytes_16
|
||||
void lbnInsertBigBytes_16(BNWORD16 *n, unsigned char const *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnExtractLittleBytes_16
|
||||
void lbnExtractLittleBytes_16(BNWORD16 const *bn, unsigned char *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnInsertLittleBytes_16
|
||||
void lbnInsertLittleBytes_16(BNWORD16 *n, unsigned char const *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
|
||||
#ifndef lbnDiv21_16
|
||||
BNWORD16 lbnDiv21_16(BNWORD16 *q, BNWORD16 nh, BNWORD16 nl, BNWORD16 d);
|
||||
#endif
|
||||
#ifndef lbnDiv1_16
|
||||
BNWORD16 lbnDiv1_16(BNWORD16 *q, BNWORD16 *rem,
|
||||
BNWORD16 const *n, unsigned len, BNWORD16 d);
|
||||
#endif
|
||||
#ifndef lbnModQ_16
|
||||
unsigned lbnModQ_16(BNWORD16 const *n, unsigned len, unsigned d);
|
||||
#endif
|
||||
#ifndef lbnDiv_16
|
||||
BNWORD16
|
||||
lbnDiv_16(BNWORD16 *q, BNWORD16 *n, unsigned nlen, BNWORD16 *d, unsigned dlen);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMontInv1_16
|
||||
BNWORD16 lbnMontInv1_16(BNWORD16 const x);
|
||||
#endif
|
||||
#ifndef lbnMontReduce_16
|
||||
void lbnMontReduce_16(BNWORD16 *n, BNWORD16 const *mod, unsigned const mlen,
|
||||
BNWORD16 inv);
|
||||
#endif
|
||||
#ifndef lbnToMont_16
|
||||
void lbnToMont_16(BNWORD16 *n, unsigned nlen, BNWORD16 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnFromMont_16
|
||||
void lbnFromMont_16(BNWORD16 *n, BNWORD16 *mod, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnExpMod_16
|
||||
int lbnExpMod_16(BNWORD16 *result, BNWORD16 const *n, unsigned nlen,
|
||||
BNWORD16 const *exp, unsigned elen, BNWORD16 *mod, unsigned mlen);
|
||||
#endif
|
||||
#if 0
|
||||
#ifndef lbnDoubleExpMod_16
|
||||
int lbnDoubleExpMod_16(BNWORD16 *result,
|
||||
BNWORD16 const *n1, unsigned n1len, BNWORD16 const *e1, unsigned e1len,
|
||||
BNWORD16 const *n2, unsigned n2len, BNWORD16 const *e2, unsigned e2len,
|
||||
BNWORD16 *mod, unsigned mlen);
|
||||
#endif
|
||||
#endif
|
||||
#ifndef lbnTwoExpMod_16
|
||||
int lbnTwoExpMod_16(BNWORD16 *n, BNWORD16 const *exp, unsigned elen,
|
||||
BNWORD16 *mod, unsigned mlen);
|
||||
#endif
|
||||
#if 0
|
||||
#ifndef lbnGcd_16
|
||||
int lbnGcd_16(BNWORD16 *a, unsigned alen, BNWORD16 *b, unsigned blen,
|
||||
unsigned *rlen);
|
||||
#endif
|
||||
#ifndef lbnInv_16
|
||||
int lbnInv_16(BNWORD16 *a, unsigned alen, BNWORD16 const *mod, unsigned mlen);
|
||||
#endif
|
||||
|
||||
int lbnBasePrecompBegin_16(BNWORD16 **array, unsigned n, unsigned bits,
|
||||
BNWORD16 const *g, unsigned glen, BNWORD16 *mod, unsigned mlen);
|
||||
int lbnBasePrecompExp_16(BNWORD16 *result, BNWORD16 const * const *array,
|
||||
unsigned bits, BNWORD16 const *exp, unsigned elen,
|
||||
BNWORD16 const *mod, unsigned mlen);
|
||||
int lbnDoubleBasePrecompExp_16(BNWORD16 *result, unsigned bits,
|
||||
BNWORD16 const * const *array1, BNWORD16 const *exp1, unsigned elen1,
|
||||
BNWORD16 const * const *array2, BNWORD16 const *exp2,
|
||||
unsigned elen2, BNWORD16 const *mod, unsigned mlen);
|
||||
#endif
|
||||
|
||||
#endif /* LBN16_H */
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* lbnarm.h - This file defines the interfaces to the ARM
|
||||
* assembly primitives. It is intended to be included in "lbn.h"
|
||||
* via the "#include BNINCLUDE" mechanism.
|
||||
*/
|
||||
|
||||
#define BN_LITTLE_ENDIAN 1
|
||||
|
||||
typedef unsigned bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
|
||||
/* Function prototypes for the asm routines */
|
||||
void
|
||||
lbnMulN1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
#define lbnMulN1_32 lbnMulN1_32
|
||||
|
||||
bnword32
|
||||
lbnMulAdd1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
#define lbnMulAdd1_32 lbnMulAdd1_32
|
||||
|
||||
/* Not implemented yet */
|
||||
bnword32
|
||||
lbnMulSub1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
#define lbnMulSub1_32 lbnMulSub1_32
|
||||
|
||||
#if __GNUC__ && 0
|
||||
/*
|
||||
* Use the (massively cool) GNU inline-assembler extension to define
|
||||
* inline expansions for various operations.
|
||||
*
|
||||
* The massively cool part is that the assembler can have inputs
|
||||
* and outputs, and you specify the operands and which effective
|
||||
* addresses are legal and they get substituted into the code.
|
||||
* (For example, some of the code requires a zero. Rather than
|
||||
* specify an immediate constant, the expansion specifies an operand
|
||||
* of zero which can be in various places. This lets GCC use an
|
||||
* immediate zero, or a register which contains zero if it's available.)
|
||||
*
|
||||
* The syntax is asm("asm_code" : outputs : inputs : trashed)
|
||||
* %0, %1 and so on in the asm code are substituted by the operands
|
||||
* in left-to-right order (outputs, then inputs).
|
||||
* The operands contain constraint strings and values to use.
|
||||
* Outputs must be lvalues, inputs may be rvalues. In the constraints:
|
||||
* "r" means that the operand may be in a register.
|
||||
* "=" means that the operand is assigned to.
|
||||
* "%" means that this operand and the following one may be
|
||||
* interchanged if desirable.
|
||||
* "&" means that this output operand is written before the input operands
|
||||
* are read, so it may NOT overlap with any input operands.
|
||||
* "0" and "1" mean that this operand may be in the same place as the
|
||||
* given operand.
|
||||
* Multiple sets of constraints may be listed, separated by commas.
|
||||
*
|
||||
* Note that ARM multi-precision multiply syntax lists destLo before destHi.
|
||||
* Also, the first source (%2) may not be the same as %0 or %1.
|
||||
* The second source, however, may be.
|
||||
*/
|
||||
|
||||
/* (ph<<32) + pl = x*y */
|
||||
#define mul32_ppmm(ph,pl,x,y) \
|
||||
__asm__("umull %1,%0,%2,%3" : "=&r,&r"(ph), "=&r,&r"(pl) \
|
||||
: "%r,%r"(x), "r0,r1"(y))
|
||||
|
||||
/* (ph<<32) + pl = x*y + a */
|
||||
#define mul32_ppmma(ph,pl,x,y,a) \
|
||||
__asm__("umlal %1,%0,%2,%3" : "=&r"(ph), "=&r"(pl) \
|
||||
: "%r"(x), "r"(y), "0"(0), "1"(a))
|
||||
|
||||
/* (ph<<32) + pl = x*y + a + b */
|
||||
/* %4 (a) may share a register with %0, but nothing else may. */
|
||||
#define mul32_ppmmaa(ph,pl,x,y,a,b) \
|
||||
__asm__("adds %1, %4, %5\n\t" \
|
||||
"movcc %0, #0\n\t" \
|
||||
"movcs %0, #1\n\t" \
|
||||
"umlal %1,%0,%2,%3" \
|
||||
: "=&r"(ph), "=&r"(pl) \
|
||||
: "%r"(x), "r"(y), "%r"(a), "r1"(b))
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
@ lbnarm.s - 32-bit bignum primitives for ARM processors with 32x32-bit multiply
|
||||
@
|
||||
@ This uses the standard ARM calling convetion, which is that arguments
|
||||
@ are passed, and results returned, in r0..r3. r0..r3, r12 (IP) and r14 (LR)
|
||||
@ are volatile across the function; all others are callee-save.
|
||||
@ However, note that r14 (LR) is the return address, so it would be
|
||||
@ wise to save it somewhere before trashing it. Fortunately, there is
|
||||
@ a neat trick possible, in that you can pop LR from the stack straight
|
||||
@ into r15 (PC), effecting a return at the same time.
|
||||
@
|
||||
@ Also, r13 (SP) is probably best left alone, and r15 (PC) is obviously
|
||||
@ reserved by hardware. Temps should use lr, then r4..r9 in order.
|
||||
|
||||
.text
|
||||
.align 2
|
||||
|
||||
@ out[0..len] = in[0..len-1] * k
|
||||
@ void lbnMulN1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
.global lbnMulN1_32
|
||||
.type lbnMulN1_32, %function
|
||||
lbnMulN1_32:
|
||||
stmfd sp!, {r4, r5, lr}
|
||||
ldr lr, [r1], #4 @ lr = *in++
|
||||
umull r5, r4, lr, r3 @ (r4,r5) = lr * r3
|
||||
str r5, [r0], #4 @ *out++ = r5
|
||||
movs r2, r2, lsr #1
|
||||
bcc m32_even
|
||||
mov r5, r4 @ Get carry in the right register
|
||||
beq m32_done
|
||||
m32_loop:
|
||||
@ carry is in r5
|
||||
ldr lr, [r1], #4 @ lr = *in++
|
||||
mov r4, #0
|
||||
umlal r5, r4, lr, r3 @ (r4,r5) += lr * r3
|
||||
str r5, [r0], #4 @ *out++ = r5
|
||||
m32_even:
|
||||
@ carry is in r4
|
||||
ldr lr, [r1], #4 @ lr = *in++
|
||||
mov r5, #0
|
||||
umlal r4, r5, lr, r3 @ (r5,r4) += lr * r3
|
||||
subs r2, r2, #1
|
||||
str r4, [r0], #4 @ *out++ = r4
|
||||
|
||||
bne m32_loop
|
||||
m32_done:
|
||||
str r5, [r0, #0] @ store carry
|
||||
ldmfd sp!, {r4, r5, pc}
|
||||
.size lbnMulN1_32, .-lbnMulN1_32
|
||||
|
||||
@ out[0..len-1] += in[0..len-1] * k, return carry
|
||||
@ BNWORD32
|
||||
@ lbnMulAdd1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
|
||||
.global lbnMulAdd1_32
|
||||
.type lbnMulAdd1_32, %function
|
||||
lbnMulAdd1_32:
|
||||
stmfd sp!, {r4, r5, lr}
|
||||
|
||||
mov r4, #0
|
||||
ldr lr, [r1], #4 @ lr = *in++
|
||||
ldr r5, [r0, #0] @ r5 = *out
|
||||
mov r4, #0
|
||||
umlal r5, r4, lr, r3 @ (r4,r5) += lr * r3
|
||||
str r5, [r0], #4 @ *out++ = r5
|
||||
movs r2, r2, lsr #1
|
||||
bcc ma32_even
|
||||
beq ma32_done
|
||||
ma32_loop:
|
||||
@ carry is in r4
|
||||
ldr lr, [r1], #4 @ lr = *in++
|
||||
mov r5, #0
|
||||
umlal r4, r5, lr, r3 @ (r5,r4) += lr * r3
|
||||
ldr lr, [r0, #0] @ lr = *out
|
||||
adds lr, lr, r4 @ lr += product.low
|
||||
str lr, [r0], #4 @ *out++ = lr
|
||||
adc r4, r5, #0 @ Compute carry and move back to r4
|
||||
ma32_even:
|
||||
@ another unrolled copy
|
||||
ldr lr, [r1], #4 @ lr = *in++
|
||||
mov r5, #0
|
||||
umlal r4, r5, lr, r3 @ (r5,r4) += lr * r3
|
||||
ldr lr, [r0, #0] @ lr = *out
|
||||
adds lr, lr, r4 @ lr += product.low
|
||||
adc r4, r5, #0 @ Compute carry and move back to r4
|
||||
str lr, [r0], #4 @ *out++ = lr
|
||||
subs r2, r2, #1
|
||||
|
||||
bne ma32_loop
|
||||
ma32_done:
|
||||
mov r0, r4
|
||||
ldmfd sp!, {r4, r5, pc}
|
||||
.size lbnMulAdd1_32, .-lbnMulAdd1_32
|
||||
|
||||
@@@ This is a bit messy... punt for now...
|
||||
@ out[0..len-1] -= in[0..len-1] * k, return carry (borrow)
|
||||
@ BNWORD32
|
||||
@ lbnMulSub1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
.global lbnMulSub1_32
|
||||
.type lbnMulSub1_32, %function
|
||||
lbnMulSub1_32:
|
||||
stmfd sp!, {r4, r5, lr}
|
||||
|
||||
mov r4, #0
|
||||
mov r5, #0
|
||||
ldr lr, [r1], #4 @ lr = *in++
|
||||
umull r4, r5, lr, r3 @ (r5,r4) = lr * r3
|
||||
ldr lr, [r0, #0] @ lr = *out
|
||||
subs lr, lr, r4 @ lr -= product.low
|
||||
str lr, [r0], #4 @ *out++ = lr
|
||||
addcc r5, r5, #1 @ propagate carry
|
||||
|
||||
movs r2, r2, lsr #1
|
||||
bcc ms32_even
|
||||
mov r4, r5
|
||||
beq ms32_done
|
||||
ms32_loop:
|
||||
@ carry is in r4
|
||||
ldr lr, [r1], #4 @ lr = *in++
|
||||
mov r5, #0
|
||||
umlal r4, r5, lr, r3 @ (r5,r4) += lr * r3
|
||||
ldr lr, [r0, #0] @ lr = *out
|
||||
subs lr, lr, r4 @ lr -= product.low
|
||||
str lr, [r0], #4 @ *out++ = lr
|
||||
addcc r5, r5, #1 @ propagate carry
|
||||
ms32_even:
|
||||
@ carry is in r5
|
||||
ldr lr, [r1], #4 @ lr = *in++
|
||||
mov r4, #0
|
||||
umlal r5, r4, lr, r3 @ (r4,r5) += lr * r3
|
||||
ldr lr, [r0, #0] @ lr = *out
|
||||
subs lr, lr, r5 @ lr -= product.low
|
||||
str lr, [r0], #4 @ *out++ = lr
|
||||
addcc r4, r4, #1 @ Propagate carry
|
||||
|
||||
subs r2, r2, #1
|
||||
bne ms32_loop
|
||||
ms32_done:
|
||||
mov r0, r4
|
||||
ldmfd sp!, {r4, r5, pc}
|
||||
|
||||
.size lbnMulSub1_32, .-lbnMulSub1_32
|
||||
|
||||
@@
|
||||
@@ It's possible to eliminate the store traffic by doing the multiplies
|
||||
@@ in a different order, forming all the partial products in one column
|
||||
@@ at a time. But it requires 32x32 + 64 -> 65-bit MAC. The
|
||||
@@ ARM has the MAC, but no carry out.
|
||||
@@
|
||||
@@ The question is, is it faster to do the add directly (3 instructions),
|
||||
@@ or can we compute the carry out in 1 instruction (+1 to do the add)?
|
||||
@@ Well... it takes at least 1 instruction to copy the original accumulator,
|
||||
@@ out of the way, and 1 to do a compare, so no.
|
||||
@@
|
||||
@@ Now, the overall loop... this is an nxn->2n multiply. For i=0..n-1,
|
||||
@@ we sum i+1 multiplies in each (plus the carry in from the
|
||||
@@ previous one). For i = n..2*n-1 we sum 2*n-1-i, plus the previous
|
||||
@@ carry.
|
||||
@@
|
||||
@@ This "non-square" structure makes things more complicated.
|
||||
@@
|
||||
@@ void
|
||||
@@ lbnMulX_32(BNWORD32 *prod, BNWORD32 const *num1, BNWORD32 const *num2,
|
||||
@@ unsigned len)
|
||||
@ .global lbnMulX_32
|
||||
@ .type lbnMulX_32, %function
|
||||
@lbnMulX_32:
|
||||
@ stmfd sp!, {r4, r5, r6, r7, lr}
|
||||
@
|
||||
@ mov r4, #0
|
||||
@ mov r5, #0
|
||||
@ mov r0, r4
|
||||
@ ldmfd sp!, {r4, r5, pc}
|
||||
@ .size lbnMulX_32, .-lbnMulX_32
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* lbnmem.c - low-level bignum memory handling.
|
||||
*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
*
|
||||
* Note that in all cases, the pointers passed around
|
||||
* are pointers to the *least* significant end of the word.
|
||||
* On big-endian machines, these are pointers to the *end*
|
||||
* of the allocated range.
|
||||
*
|
||||
* BNSECURE is a simple level of security; for more security
|
||||
* change these function to use locked unswappable memory.
|
||||
*/
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_STDLIB_H
|
||||
#define NO_STDLIB_H 0
|
||||
#endif
|
||||
#ifndef NO_STRING_H
|
||||
#define NO_STRING_H 0
|
||||
#endif
|
||||
#ifndef HAVE_STRINGS_H
|
||||
#define HAVE_STRINGS_H 0
|
||||
#endif
|
||||
#ifndef NEED_MEMORY_H
|
||||
#define NEED_MEMORY_H 0
|
||||
#endif
|
||||
|
||||
#if !NO_STDLIB_H
|
||||
#include <stdlib.h> /* For malloc() & co. */
|
||||
#else
|
||||
void *malloc();
|
||||
void *realloc();
|
||||
void free();
|
||||
#endif
|
||||
|
||||
#if !NO_STRING_H
|
||||
#include <string.h> /* For memset */
|
||||
#elif HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#if NEED_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#ifndef DBMALLOC
|
||||
#define DBMALLOC 0
|
||||
#endif
|
||||
#if DBMALLOC
|
||||
/* Development debugging */
|
||||
#include "../dbmalloc/malloc.h"
|
||||
#endif
|
||||
|
||||
#include "lbn.h"
|
||||
#include "lbnmem.h"
|
||||
|
||||
#include "kludge.h"
|
||||
|
||||
#ifndef lbnMemWipe
|
||||
void
|
||||
lbnMemWipe(void *ptr, unsigned bytes)
|
||||
{
|
||||
memset(ptr, 0, bytes);
|
||||
}
|
||||
#define lbnMemWipe(ptr, bytes) memset(ptr, 0, bytes)
|
||||
#endif
|
||||
|
||||
#ifndef lbnMemAlloc
|
||||
void *
|
||||
lbnMemAlloc(unsigned bytes)
|
||||
{
|
||||
return malloc(bytes);
|
||||
}
|
||||
#define lbnMemAlloc(bytes) malloc(bytes)
|
||||
#endif
|
||||
|
||||
#ifndef lbnMemFree
|
||||
void
|
||||
lbnMemFree(void *ptr, unsigned bytes)
|
||||
{
|
||||
lbnMemWipe(ptr, bytes);
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifndef lbnRealloc
|
||||
#if defined(lbnMemRealloc) || !BNSECURE
|
||||
void *
|
||||
lbnRealloc(void *ptr, unsigned oldbytes, unsigned newbytes)
|
||||
{
|
||||
if (ptr) {
|
||||
BIG(ptr = (char *)ptr - oldbytes;)
|
||||
if (newbytes < oldbytes)
|
||||
memmove(ptr, (char *)ptr + oldbytes-newbytes, oldbytes);
|
||||
}
|
||||
#ifdef lbnMemRealloc
|
||||
ptr = lbnMemRealloc(ptr, oldbytes, newbytes);
|
||||
#else
|
||||
ptr = realloc(ptr, newbytes);
|
||||
#endif
|
||||
if (ptr) {
|
||||
if (newbytes > oldbytes)
|
||||
memmove((char *)ptr + newbytes-oldbytes, ptr, oldbytes);
|
||||
BIG(ptr = (char *)ptr + newbytes;)
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#else /* BNSECURE */
|
||||
|
||||
void *
|
||||
lbnRealloc(void *oldptr, unsigned oldbytes, unsigned newbytes)
|
||||
{
|
||||
void *newptr = lbnMemAlloc(newbytes);
|
||||
|
||||
if (!newptr)
|
||||
return newptr;
|
||||
if (!oldptr)
|
||||
return BIGLITTLE((char *)newptr+newbytes, newptr);
|
||||
|
||||
/*
|
||||
* The following copies are a bit non-obvious in the big-endian case
|
||||
* because one of the pointers points to the *end* of allocated memory.
|
||||
*/
|
||||
if (newbytes > oldbytes) { /* Copy all of old into part of new */
|
||||
BIG(newptr = (char *)newptr + newbytes;)
|
||||
BIG(oldptr = (char *)oldptr - oldbytes;)
|
||||
memcpy(BIGLITTLE((char *)newptr-oldbytes, newptr), oldptr,
|
||||
oldbytes);
|
||||
} else { /* Copy part of old into all of new */
|
||||
memcpy(newptr, BIGLITTLE((char *)oldptr-newbytes, oldptr),
|
||||
newbytes);
|
||||
BIG(newptr = (char *)newptr + newbytes;)
|
||||
BIG(oldptr = (char *)oldptr - oldbytes;)
|
||||
}
|
||||
|
||||
lbnMemFree(oldptr, oldbytes);
|
||||
|
||||
return newptr;
|
||||
}
|
||||
#endif /* BNSECURE */
|
||||
#endif /* !lbnRealloc */
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Operations on the usual buffers of bytes
|
||||
*/
|
||||
#ifndef BNSECURE
|
||||
#define BNSECURE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These operations act on buffers of memory, just like malloc & free.
|
||||
* One exception: it is not legal to pass a NULL pointer to lbnMemFree.
|
||||
*/
|
||||
|
||||
#ifndef lbnMemAlloc
|
||||
void *lbnMemAlloc(unsigned bytes);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMemFree
|
||||
void lbnMemFree(void *ptr, unsigned bytes);
|
||||
#endif
|
||||
|
||||
/* This wipes out a buffer of bytes if necessary needed. */
|
||||
|
||||
#ifndef lbnMemWipe
|
||||
#if BNSECURE
|
||||
void lbnMemWipe(void *ptr, unsigned bytes);
|
||||
#else
|
||||
#define lbnMemWipe(ptr, bytes) (void)(ptr,bytes)
|
||||
#endif
|
||||
#endif /* !lbnMemWipe */
|
||||
|
||||
/*
|
||||
* lbnRealloc is NOT like realloc(); it's endian-sensitive!
|
||||
* If lbnMemRealloc is #defined, lbnRealloc will be defined in terms of it.
|
||||
* It is legal to pass a NULL pointer to lbnRealloc, although oldbytes
|
||||
* will always be sero.
|
||||
*/
|
||||
#ifndef lbnRealloc
|
||||
void *lbnRealloc(void *ptr, unsigned oldbytes, unsigned newbytes);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* These macros are the ones actually used most often in the math library.
|
||||
* They take and return pointers to the *end* of the given buffer, and
|
||||
* take sizes in terms of words, not bytes.
|
||||
*
|
||||
* Note that LBNALLOC takes the pointer as an argument instead of returning
|
||||
* the value.
|
||||
*
|
||||
* Note also that these macros are only useable if you have included
|
||||
* lbn.h (for the BIG and BIGLITTLE macros), which this file does NOT include.
|
||||
*/
|
||||
|
||||
#define LBNALLOC(p,type,words) BIGLITTLE( \
|
||||
if ( ((p) = (type *)lbnMemAlloc((words)*sizeof*(p))) != 0) \
|
||||
(p) += (words), \
|
||||
(p) = (type *)lbnMemAlloc((words) * sizeof*(p)) \
|
||||
)
|
||||
#define LBNFREE(p,words) lbnMemFree((p) BIG(-(words)), (words) * sizeof*(p))
|
||||
#define LBNREALLOC(p,old,new) \
|
||||
lbnRealloc(p, (old) * sizeof*(p), (new) * sizeof*(p))
|
||||
#define LBNWIPE(p,words) lbnMemWipe((p) BIG(-(words)), (words) * sizeof*(p))
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
/*
|
||||
* For code size reasons, this doesn't even try to support
|
||||
* input sizes >= 2^32 bits = 2^29 bytes
|
||||
*/
|
||||
struct sha256_state {
|
||||
uint32_t iv[8]; /* a, b, c, d, e, f, g, h */
|
||||
uint32_t w[64]; /* Fill in first 16 with ntohl(input) */
|
||||
uint32_t bytes;
|
||||
};
|
||||
|
||||
/* Rotate right macro. GCC can usually get this right. */
|
||||
#define ROTR(x,s) ((x)>>(s) | (x)<<(32-(s)))
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* An implementation of SHA-256 for register-starved architectures like
|
||||
* x86 or perhaps the MSP430. (Although the latter's lack of a multi-bit
|
||||
* shifter will doom its performance no matter what.)
|
||||
* This code is also quite small.
|
||||
*
|
||||
* If you have 12 32-bit registers to work with, loading the 8 state
|
||||
* variables into registers is probably faster. If you have 28 registers
|
||||
* or so, you can put the input block into registers as well.
|
||||
*
|
||||
* The key idea is to notice that each round consumes one word from the
|
||||
* key schedule w[i], computes a new a, and shifts all the other state
|
||||
* variables down one position, discarding the old h.
|
||||
*
|
||||
* So if we store the state vector in reverse order h..a, immediately
|
||||
* before w[i], then a single base pointer can be incremented to advance
|
||||
* to the next round.
|
||||
*/
|
||||
void
|
||||
sha256_transform(uint32_t p[76])
|
||||
{
|
||||
static uint32_t const k[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,
|
||||
0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,
|
||||
0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
|
||||
0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,
|
||||
0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
||||
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
|
||||
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
|
||||
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
|
||||
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
/*
|
||||
* Look, ma, only 6 local variables including p!
|
||||
* Too bad they're so overloaded it's impossible to give them
|
||||
* meaningful names.
|
||||
*/
|
||||
register uint32_t const *kp;
|
||||
register uint32_t a, s, t, u;
|
||||
|
||||
/* Step 1: Expand the 16 words of w[], at p[8..23] into 64 words */
|
||||
for (u = 8; u < 8+64-16; u++) {
|
||||
/* w[i] = s1(w[i-2]) + w[i-7] + s0(w[i-15]) + w[i-16] */
|
||||
/* Form s0(x) = (x >>> 7) ^ (x >>> 18) ^ (x >> 3) */
|
||||
s = t = p[u+1];
|
||||
s = ROTR(s, 18-7);
|
||||
s ^= t;
|
||||
s = ROTR(s, 7);
|
||||
s ^= t >> 3;
|
||||
/* Form s1(x) = (x >>> 17) ^ (x >>> 19) ^ (x >> 10) */
|
||||
a = t = p[u+14];
|
||||
a = ROTR(a, 19-17);
|
||||
a ^= t;
|
||||
a = ROTR(a, 17);
|
||||
a ^= t >> 10;
|
||||
|
||||
p[u+16] = s + a + p[u] + p[u+9];
|
||||
}
|
||||
|
||||
/* Step 2: Copy the initial values of d, c, b, a out of the way */
|
||||
p[72] = p[4];
|
||||
p[73] = p[5];
|
||||
p[74] = p[6];
|
||||
p[75] = a = p[7];
|
||||
|
||||
/*
|
||||
* Step 3: The big loop.
|
||||
* We maintain p[0..7] = h..a, and p[8] is w[i]
|
||||
*/
|
||||
kp = k;
|
||||
|
||||
do {
|
||||
/* T1 = h + S1(e) + Ch(e,f,g) + k[i] + w[i] */
|
||||
/* Form Ch(e,f,g) = g ^ (e & (f ^ g)) */
|
||||
s = t = p[1]; /* g */
|
||||
s ^= p[2]; /* f ^ g */
|
||||
s &= u = p[3]; /* e & (f ^ g) */
|
||||
s ^= t;
|
||||
/* Form S1(e) = (e >>> 6) ^ (e >>> 11) ^ (e >>> 25) */
|
||||
t = u;
|
||||
u = ROTR(u, 25-11);
|
||||
u ^= t;
|
||||
u = ROTR(u, 11-6);
|
||||
u ^= t;
|
||||
u = ROTR(u, 6);
|
||||
s += u;
|
||||
/* Now add other things to t1 */
|
||||
s += p[0] + p[8] + *kp; /* h + w[i] + kp[i] */
|
||||
/* Round function: e = d + T1 */
|
||||
p[4] += s;
|
||||
/* a = t1 + (t2 = S0(a) + Maj(a,b,c) */
|
||||
/* Form S0(a) = (a >>> 2) ^ (a >>> 13) ^ (a >>> 22) */
|
||||
t = a;
|
||||
t = ROTR(t, 22-13);
|
||||
t ^= a;
|
||||
t = ROTR(t, 13-2);
|
||||
t ^= a;
|
||||
t = ROTR(t, 2);
|
||||
s += t;
|
||||
/* Form Maj(a,b,c) = (a & b) + (c & (a ^ b)) */
|
||||
t = a;
|
||||
u = p[6]; /* b */
|
||||
a ^= u; /* a ^ b */
|
||||
u &= t; /* a & b */
|
||||
a &= p[5]; /* c & (a + b) */
|
||||
s += u;
|
||||
a += s; /* Sum final result into a */
|
||||
|
||||
/* Now store new a on top of w[i] and shift... */
|
||||
p[8] = a;
|
||||
p++;
|
||||
#if DEBUG
|
||||
/* If debugging, print out the state variables each round */
|
||||
printf("%2u:", kp-k);
|
||||
for (t = 8; t--; )
|
||||
printf(" %08x", p[t]);
|
||||
putchar('\n');
|
||||
#endif
|
||||
} while (++kp != k+64);
|
||||
|
||||
/* Now, do the final summation. */
|
||||
p -= 64;
|
||||
/*
|
||||
* Now, the final h..a are in p[64..71], and the initial values
|
||||
* are in p[0..7]. Except that p[4..7] got trashed in the loop
|
||||
* above, so use the copies we made.
|
||||
*/
|
||||
p[0] += p[64];
|
||||
p[1] += p[65];
|
||||
p[2] += p[66];
|
||||
p[3] += p[67];
|
||||
p[4] = p[68] + p[72];
|
||||
p[5] = p[69] + p[73];
|
||||
p[6] = p[70] + p[74];
|
||||
p[7] = a + p[75];
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* A space-optimized ARM assembly implementation */
|
||||
void sha256_transform(uint32_t p[8+64]);
|
||||
|
||||
#endif
|
||||
|
||||
/* Initial values H0..H7 for SHA-256, and SHA-224. */
|
||||
static uint32_t const sha256_iv[8] = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
#if 0
|
||||
static uint32_t const sha224_iv[8] = {
|
||||
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
|
||||
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
|
||||
};
|
||||
#endif
|
||||
|
||||
void
|
||||
sha256_begin(struct sha256_state *s)
|
||||
{
|
||||
memcpy(s->iv, sha256_iv, sizeof sha256_iv);
|
||||
s->bytes = 0;
|
||||
}
|
||||
|
||||
#include <netinet/in.h> /* For ntohl, htonl */
|
||||
|
||||
void
|
||||
sha256_hash(unsigned char const *data, size_t len, struct sha256_state *s)
|
||||
{
|
||||
unsigned space = 64 - (unsigned)s->bytes % 64;
|
||||
unsigned i;
|
||||
|
||||
s->bytes += len;
|
||||
|
||||
while (len >= space) {
|
||||
memcpy((unsigned char *)s->w + 64 - space, data, space);
|
||||
len -= space;
|
||||
space = 64;
|
||||
for (i = 0; i < 16; i++)
|
||||
s->w[i] = ntohl(s->w[i]);
|
||||
sha256_transform(s->iv);
|
||||
}
|
||||
memcpy((unsigned char *)s->w + 64 - space, data, len);
|
||||
}
|
||||
|
||||
void
|
||||
sha256_end(unsigned char hash[32], struct sha256_state *s)
|
||||
{
|
||||
static unsigned char const padding[64] = { 0x80, 0, 0 /* ,... */ };
|
||||
uint32_t bytes = s->bytes;
|
||||
unsigned i;
|
||||
|
||||
/* Add trailing bit padding. */
|
||||
sha256_hash(padding, 64 - ((bytes+8) & 63), s);
|
||||
assert(s->bytes % 64 == 56);
|
||||
|
||||
/* Byte-swap and hash final block */
|
||||
for (i = 0; i < 14; i++)
|
||||
s->w[i] = ntohl(s->w[i]);
|
||||
s->w[14] = 0; /* We don't even try */
|
||||
s->w[15] = s->bytes << 3;
|
||||
sha256_transform(s->iv);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
s->iv[i] = htonl(s->iv[i]);
|
||||
memcpy(hash, s->iv, sizeof s->iv);
|
||||
memset(s, 0, sizeof *s); /* Good cryptographic hygiene */
|
||||
}
|
||||
|
||||
void
|
||||
sha256(unsigned char hash[32], const unsigned char *data, size_t len)
|
||||
{
|
||||
struct sha256_state s;
|
||||
sha256_begin(&s);
|
||||
sha256_hash(data, len, &s);
|
||||
sha256_end(hash, &s);
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
@ ARM procedure call convention:
|
||||
@ r0..r3, r12 (ip) and r14 (lr) are volatile. Args are passed in r0..r3,
|
||||
@ and the return address in r14.
|
||||
@
|
||||
@ All other registers must be preserved by the callee. r13 (sp) and r15 (pc)
|
||||
@ are as expected.
|
||||
@
|
||||
@ The usual convention is to push all the needed registers, including r14,
|
||||
@ on the stack, and the restore them at the end, but to r15 rather than r14.
|
||||
@ This, however, WILL NOT WORK for Thumb code. You have to use the "bx"
|
||||
@ instruction for that, so you need one more trailing instruction.
|
||||
|
||||
.text
|
||||
.align 2
|
||||
.type k_table, %object
|
||||
k_table:
|
||||
.word 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b
|
||||
.word 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01
|
||||
.word 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7
|
||||
.word 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc
|
||||
.word 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152
|
||||
.word 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147
|
||||
.word 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc
|
||||
.word 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85
|
||||
.word 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819
|
||||
.word 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08
|
||||
.word 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f
|
||||
.word 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208
|
||||
.word 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
.size k_table, .-k_table
|
||||
|
||||
@ We use 13 local variables:
|
||||
pp .req r0 @ The argument, points to the IV and w[] space
|
||||
aa .req r1 @ Working variable.
|
||||
bb .req r2
|
||||
cc .req r3
|
||||
dd .req r4
|
||||
ee .req r5
|
||||
ff .req r6
|
||||
gg .req r7
|
||||
hh .req r8
|
||||
ii .req r9 @ Loop index
|
||||
tt .req r10 @ General purpose temp
|
||||
kk .req r11 @ k+64 (k_table+256)
|
||||
ww .req r12 @ Actually, w+64 much of the time
|
||||
@ We could use r14 as well, but don't need to.
|
||||
@ (The names are doubled because a sigle b is "branch"!
|
||||
@
|
||||
@ This function takes a pointer to an array of 72 32-bit words:
|
||||
@ The first 8 are the state vector a..h
|
||||
@ The next 16 are the input data words w[0..15], in native byte order.
|
||||
@ The next 48 are used to hold the rest of the key schedule w[16..63].
|
||||
|
||||
.global sha256_transform
|
||||
.type sha256_transform, %function
|
||||
sha256_transform:
|
||||
stmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11}
|
||||
add ww, pp, #4*(8+16) @ w + 16 = p + 8 + 16
|
||||
mov ii, #64-16 @ loop counter
|
||||
|
||||
@ Fill in words 16..63 of the w[] array, at p+24..p+71
|
||||
1:
|
||||
@ ww[i] = w[i-16] + s0(w[i-15]) + w[i-7] + s1(w[i-2])
|
||||
ldr aa, [ww, #-64] @ a = w[i-16]
|
||||
ldr bb, [ww, #-60] @ b = w[i-15]
|
||||
ldr cc, [ww, #-28] @ c = w[i-7]
|
||||
add aa, aa, cc @ a += c (= w[i-7])
|
||||
|
||||
@ s0(x) = (x >>> 7) ^ (x >>> 18) ^ (x >> 3)
|
||||
mov cc, bb, ror #18 @ c = b>>>18
|
||||
eor cc, cc, bb, ror #7 @ c ^= b>>>7
|
||||
eor cc, cc, bb, lsr #3 @ c ^= b>>3
|
||||
ldr bb, [ww, #-8] @ b = w[i-2]
|
||||
add aa, aa, cc @ a += c (= s0(w[i-15]))
|
||||
@ s1(x) = (x >>> 17) ^ (x >>> 19) ^ (x >> 10)
|
||||
mov cc, bb, ror #19 @ c = b>>>19
|
||||
eor cc, cc, bb, ror #17 @ c ^= b>>>17
|
||||
eor cc, cc, bb, lsr #10 @ c ^= b>>10
|
||||
add aa, aa, cc @ a += c (= s1(w[i-2]))
|
||||
|
||||
subs ii, ii, #1 @ --i
|
||||
str aa, [ww], #4 @ w[i++] = a
|
||||
bne 1b
|
||||
|
||||
|
||||
@ The main loop. Arrays are indexed with i, which starts at -256
|
||||
@ and counts up to 0. In addition to t, we use h as a working
|
||||
@ variable for the first part of the loop, until doing the
|
||||
@ big register rotation, then a as a temp for the last part.
|
||||
|
||||
ldmia pp, {aa,bb,cc,dd,ee,ff,gg,hh} @ Load a..h
|
||||
mov ii, #-256 @ i = -64 (*4 strength-reduced)
|
||||
adr kk, k_table+256 @ Load up r12 to the END of k
|
||||
2:
|
||||
@ t = h + S1(e) + Ch(e,f,g) + k[i] + w[i]
|
||||
@ Form t = Ch(e,f,g) = (g ^ (e & (f ^ g))
|
||||
eor tt, ff, gg @ t = f^g
|
||||
and tt, tt, ee @ t &= e
|
||||
eor tt, tt, gg @ t ^= g
|
||||
|
||||
add tt, tt, hh @ t += h
|
||||
|
||||
@ Form t += S1(e) = (e >>> 6) ^ (e >>> 11) ^ (e >>> 25)
|
||||
eor hh, ee, ee, ror #25-6 @ h = e ^ e>>>(25-6)
|
||||
eor hh, hh, ee, ror #11-6 @ h = h ^ e>>>(11-6)
|
||||
add tt, tt, hh, ror #6 @ t += h>>>6
|
||||
|
||||
@ Add k[i] and w[i]. Note that -64 <= i < 0.
|
||||
ldr hh, [ww, ii] @ h = w[64+i]
|
||||
add tt, tt, hh
|
||||
ldr hh, [kk, ii] @ h = k[64+i]
|
||||
add tt, tt, hh
|
||||
adds ii, ii, #4 @ ++i (*4 strength-reduced)
|
||||
|
||||
@ Copy (h,g,f,e,d,c,b) = (g,f,e,d+t1,c,b,a)
|
||||
@ This could be shrunk with aa big stm/ldm pair, but that
|
||||
@ seems terribly wasteful...
|
||||
mov hh, gg @ h = g
|
||||
mov gg, ff @ g = f
|
||||
mov ff, ee @ f = e
|
||||
add ee, dd, tt @ e = d + t
|
||||
mov dd, cc @ d = c
|
||||
mov cc, bb @ c = b
|
||||
mov bb, aa @ b = a
|
||||
|
||||
@ a = t + S0(b) + Maj(b,c,d)
|
||||
@ Form t += S0(b) = (b >>> 2) ^ (b >>> 13) ^ (b >>> 22) */
|
||||
eor aa, bb, bb, ror #22-2 @ a = b ^ b>>>(22-2)
|
||||
eor aa, aa, bb, ror #13-2 @ a = a ^ b>>>(13-2)
|
||||
add tt, tt, aa, ror #2 @ t += a>>>2
|
||||
|
||||
@ Form a = t + Maj(b,c,d) = (c & d) + (b & (c ^ d))
|
||||
and aa, cc, dd @ a = c & d
|
||||
add tt, tt, aa @ t += a
|
||||
eor aa, cc, dd @ a = c ^ d
|
||||
and aa, aa, bb @ a &= b
|
||||
add aa, aa, tt @ a += t
|
||||
|
||||
bne 2b @ while (i != 0)
|
||||
|
||||
@ Now, the final summation. Minimum code size is tricky...
|
||||
ldmia pp!, {ii,tt,kk,ww} @ Load old iv[0..3]
|
||||
add aa, aa, ii @ a += iv[0]
|
||||
add bb, bb, tt @ b += iv[1]
|
||||
add cc, cc, kk @ c += iv[2]
|
||||
add dd, dd, ww @ d += iv[3]
|
||||
ldmia pp!, {ii,tt,kk,ww} @ Load old iv[4..7]
|
||||
add ee, ee, ii @ e += iv[4]
|
||||
add ff, ff, tt @ f += iv[5]
|
||||
add gg, gg, kk @ g += iv[6]
|
||||
add hh, hh, ww @ h += iv[7]
|
||||
stmfd pp, {aa,bb,cc,dd,ee,ff,gg,hh} @ Store new iv[0..7]
|
||||
|
||||
ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11}
|
||||
bx lr
|
||||
|
||||
.size sha256_transform, .-sha256_transform
|
||||
Vendored
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bn.c - the high-level bignum interface
|
||||
*/
|
||||
|
||||
#include "bn.h"
|
||||
|
||||
/* Functions */
|
||||
void
|
||||
bnBegin(struct BigNum *bn)
|
||||
{
|
||||
static int bninit = 0;
|
||||
|
||||
if (!bninit) {
|
||||
bnInit();
|
||||
bninit = 1;
|
||||
}
|
||||
|
||||
bn->ptr = 0;
|
||||
bn->size = 0;
|
||||
bn->allocated = 0;
|
||||
}
|
||||
|
||||
void
|
||||
bnSwap(struct BigNum *a, struct BigNum *b)
|
||||
{
|
||||
void *p;
|
||||
unsigned t;
|
||||
|
||||
p = a->ptr;
|
||||
a->ptr = b->ptr;
|
||||
b->ptr = p;
|
||||
|
||||
t = a->size;
|
||||
a->size = b->size;
|
||||
b->size = t;
|
||||
|
||||
t = a->allocated;
|
||||
a->allocated = b->allocated;
|
||||
b->allocated = t;
|
||||
}
|
||||
|
||||
int (*bnYield)(void);
|
||||
|
||||
void (*bnEnd)(struct BigNum *bn);
|
||||
int (*bnPrealloc)(struct BigNum *bn, unsigned bits);
|
||||
int (*bnCopy)(struct BigNum *dest, struct BigNum const *src);
|
||||
void (*bnNorm)(struct BigNum *bn);
|
||||
void (*bnExtractBigBytes)(struct BigNum const *bn, unsigned char *dest,
|
||||
unsigned lsbyte, unsigned len);
|
||||
int (*bnInsertBigBytes)(struct BigNum *bn, unsigned char const *src,
|
||||
unsigned lsbyte, unsigned len);
|
||||
void (*bnExtractLittleBytes)(struct BigNum const *bn, unsigned char *dest,
|
||||
unsigned lsbyte, unsigned len);
|
||||
int (*bnInsertLittleBytes)(struct BigNum *bn, unsigned char const *src,
|
||||
unsigned lsbyte, unsigned len);
|
||||
unsigned (*bnLSWord)(struct BigNum const *src);
|
||||
int (*bnReadBit)(struct BigNum const *bn, unsigned bit);
|
||||
unsigned (*bnBits)(struct BigNum const *src);
|
||||
int (*bnAdd)(struct BigNum *dest, struct BigNum const *src);
|
||||
int (*bnSub)(struct BigNum *dest, struct BigNum const *src);
|
||||
int (*bnCmpQ)(struct BigNum const *a, unsigned b);
|
||||
int (*bnSetQ)(struct BigNum *dest, unsigned src);
|
||||
int (*bnAddQ)(struct BigNum *dest, unsigned src);
|
||||
int (*bnSubQ)(struct BigNum *dest, unsigned src);
|
||||
int (*bnCmp)(struct BigNum const *a, struct BigNum const *b);
|
||||
int (*bnSquare)(struct BigNum *dest, struct BigNum const *src);
|
||||
int (*bnMul)(struct BigNum *dest, struct BigNum const *a,
|
||||
struct BigNum const *b);
|
||||
int (*bnMulQ)(struct BigNum *dest, struct BigNum const *a, unsigned b);
|
||||
int (*bnDivMod)(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
|
||||
struct BigNum const *d);
|
||||
int (*bnMod)(struct BigNum *dest, struct BigNum const *src,
|
||||
struct BigNum const *d);
|
||||
unsigned (*bnModQ)(struct BigNum const *src, unsigned d);
|
||||
int (*bnExpMod)(struct BigNum *result, struct BigNum const *n,
|
||||
struct BigNum const *exp, struct BigNum const *mod);
|
||||
int (*bnDoubleExpMod)(struct BigNum *dest,
|
||||
struct BigNum const *n1, struct BigNum const *e1,
|
||||
struct BigNum const *n2, struct BigNum const *e2,
|
||||
struct BigNum const *mod);
|
||||
int (*bnTwoExpMod)(struct BigNum *n, struct BigNum const *exp,
|
||||
struct BigNum const *mod);
|
||||
int (*bnGcd)(struct BigNum *dest, struct BigNum const *a,
|
||||
struct BigNum const *b);
|
||||
int (*bnInv)(struct BigNum *dest, struct BigNum const *src,
|
||||
struct BigNum const *mod);
|
||||
int (*bnLShift)(struct BigNum *dest, unsigned amt);
|
||||
void (*bnRShift)(struct BigNum *dest, unsigned amt);
|
||||
unsigned (*bnMakeOdd)(struct BigNum *n);
|
||||
int (*bnBasePrecompBegin)(struct BnBasePrecomp *pre, struct BigNum const *base,
|
||||
struct BigNum const *mod, unsigned maxebits);
|
||||
int (*bnBasePrecompCopy)(struct BnBasePrecomp *dst,
|
||||
struct BnBasePrecomp const *src);
|
||||
void (*bnBasePrecompEnd)(struct BnBasePrecomp *pre);
|
||||
int (*bnBasePrecompExpMod)(struct BigNum *dest,
|
||||
struct BnBasePrecomp const *pre, struct BigNum const *exp,
|
||||
struct BigNum const *mod);
|
||||
int (*bnDoubleBasePrecompExpMod)(struct BigNum *dest,
|
||||
struct BnBasePrecomp const *pre1, struct BigNum const *exp1,
|
||||
struct BnBasePrecomp const *pre2, struct BigNum const *exp2,
|
||||
struct BigNum const *mod);
|
||||
+541
@@ -0,0 +1,541 @@
|
||||
* The BigNum multi-precision integer math library
|
||||
|
||||
This is a multi-precision math library designed to be very portable,
|
||||
reasonably clean and easy to use, have very liberal bounds on the sizes
|
||||
of numbers that can be represented, but above all to perform extremely
|
||||
fast modular exponentiation. It has some limitations, such as
|
||||
representing positive numbers only, and supporting only odd moduli,
|
||||
which simplify it without impairing this ability.
|
||||
|
||||
A second speed goal which has had considerable effort applied to it is
|
||||
prime number generation.
|
||||
|
||||
Finally, while there is probably a long way to go in this direction,
|
||||
some effort has gone into commenting the code a lot more than seems to
|
||||
be fashionable among mathematicians.
|
||||
|
||||
It is written in C, and should compile on any platform with an ANSI C
|
||||
compiler and 16 and 32-bit unsigned data types, but various primitives
|
||||
can be replaced with assembly versions in a great variety of ways for
|
||||
greater speedup. See "bnintern.doc" for a description.
|
||||
|
||||
In case you're wondering, yes C++ would produce a much nicer syntax
|
||||
for working with these numbers, but there are a lot of compilers out
|
||||
there that actually implement ANSI C, and get it almost right. I have
|
||||
a few kludges to deal with some that get little things wrong, but
|
||||
overall it's not too difficult to write code that I can be sure
|
||||
will work on lots of machines. And porting it to a K&R C compiler,
|
||||
if it ever becomes necessary, shouldn't be all *that* difficult.
|
||||
|
||||
The C++ compiler world is a less friendly place. First of all, C++
|
||||
compilers are still not as common as C compilers, so that hurts
|
||||
portability right there, and I don't need the extra power to write my
|
||||
code. C++ compilers all seem to have important bugs, and different
|
||||
bugs for each compiler. First I have to learn all the foibles of a
|
||||
whole lot of C++ compilers, and then I have write code that uses only
|
||||
the features that work in all of them. This is a language not a whole
|
||||
heck of a lot bigger than C.
|
||||
|
||||
(The fact that it drives me *batty* the way that C++ drags *everything*
|
||||
into the same name space is also a contributing factor. I *like*
|
||||
writing "struct" (or "class") before structure names. I *like* putting
|
||||
"this->" in front of member references. It makes it clear to me, when
|
||||
reading a single line of code, roughly what is being affected by it and
|
||||
where I can find the relevant source code to find out more. I've seen
|
||||
people develop complicated naming conventions to make all this clear,
|
||||
but the conventions are still very much in flux.)
|
||||
|
||||
Anyway...
|
||||
|
||||
The main public interface is contained in the file bn.h. This is
|
||||
mostly a bunch of pointers to functions which start out uninitialized,
|
||||
but are set by bnInit() (which is called by bnBegin()).
|
||||
|
||||
All of the public routines have names of the bnFunction variety.
|
||||
Some internal routines are lbnFunction, but you should never have to
|
||||
worry about those unless you're hacking with the code.
|
||||
|
||||
The code uses the assert() macro a lot internally. If you do something
|
||||
you're not supposed to, you'll generally notice because an assert()
|
||||
will fail. The library does not have special error codes for division
|
||||
by zero or the like - it assert fails instead. Just don't do that.
|
||||
|
||||
A BigNum is represented by a struct BigNum, which really doesn't
|
||||
need to be understood, but it often makes me feel better to understand
|
||||
what's going on, so here it is:
|
||||
|
||||
#> struct BigNum {
|
||||
#> void *ptr;
|
||||
#> unsigned size; /* Note: in (variable-sized) words */
|
||||
#> unsigned allocated;
|
||||
#> };
|
||||
|
||||
The pointer points to the least-significant end of an array of words which
|
||||
hold the number. The array contains "allocated" words, but only "size"
|
||||
of them are actually meaningful. The others may have any value.
|
||||
This is all of limited use because the size of a word is not specified.
|
||||
In fact, it can change at run time - if you run on an 8086 one day and an
|
||||
80386 the next, you may find the word size different.
|
||||
|
||||
* Initialization
|
||||
|
||||
The user of the library is responsible for allocating and freeing each
|
||||
struct BigNum. Usually they're just local variables. All the library
|
||||
functions take pointers to them. The first thing you need to do is
|
||||
initialize all the fields to empty, a zero-valued BigNum. This is done
|
||||
with the function bnBegin:
|
||||
#> void bnBegin(struct BigNum *bn);
|
||||
|
||||
When you're done with a BigNum, call bnEnd to deallocate the data storage
|
||||
in preparation for deallocating the structure:
|
||||
#> void bnEnd(struct BigNum *bn);
|
||||
|
||||
This resets the number to the 0 state. You can actually start using the
|
||||
number right away again, or call bnEnd again, so if you're really
|
||||
memory-conscious you might want to use this to free a large
|
||||
number you're done with this way before going on to use the buffer
|
||||
for smaller things.
|
||||
|
||||
A simple assignment can be done with bnCopy.
|
||||
#> int bnCopy(struct BigNum *dest, struct BigNum const *src);
|
||||
|
||||
This sets dest = src, and returns an error code. Most functions in the
|
||||
library do this, and return 0 on success and -1 if they were unable to
|
||||
allocate needed memory. If you're lazy and sure you'll never run out
|
||||
of memory, you can avoid checking this, but it's better to be
|
||||
paranoid. If a function returns -1, the what has happened to the
|
||||
destination values is undefined. They're usually unmodified, and
|
||||
they're always still valid BigNum numbers, but their values might be
|
||||
strange.
|
||||
|
||||
In general, anywhere that follows, unless otherwise documented, assume
|
||||
that an "int" return value is 0 for success or -1 for error.
|
||||
|
||||
A trivial little function which is sometimes handy, and quite cheap to
|
||||
execute (it just swaps the pointers) is:
|
||||
#> void bnSwap(struct BigNum *a, struct BigNum *b);
|
||||
|
||||
* Input and output
|
||||
|
||||
For now, the library only works with numbers in binary form - there's
|
||||
no way to get decimal numbers into or out of it. But it's pretty
|
||||
flexible on how it does that.
|
||||
|
||||
The first function just sets a BigNum to have a small value. There are
|
||||
several such "quick" forms which work with "small" second operads.
|
||||
"Small" is defined as less than 65536, the minimum 16-bit word size
|
||||
supported by the library. The limit applies even if unsigned is larger
|
||||
or the library is compiled for a larger word size.
|
||||
#> int bnSetQ(struct BigNum *dest, unsigned src);
|
||||
|
||||
This returns the usual -1 error if it couldn't allocate memory.
|
||||
|
||||
There's also a function to determine the size of a BigNum, in bits.
|
||||
The size is the number of bits required to represent the number,
|
||||
0 if the number is 0, and floor(log2(src)) + 1 otherwise. E.g. 1 is
|
||||
the only 1-bit number, 2 and 3 are 2-bit numbers, etc.
|
||||
#> unsigned bnBits(struct BigNum const *src);
|
||||
|
||||
If bnBits(src) <= 16, you can get the whole number with this function.
|
||||
If it's larger, you get the low k bits, where k is at least 16.
|
||||
(This doesn't bother masking if it's easy to return more, but you
|
||||
shouldn't rely on it.) Even that is useful for many things, like
|
||||
deciding if a number is even or odd.
|
||||
#> unsigned bnLSWord(struct BigNum const *src);
|
||||
|
||||
For larger numbers, the format used by the library is an array of
|
||||
unsigned 8-bit bytes. These bytes may be in big-endian or little-endian
|
||||
order, and it's possible to examine or change just part of a number.
|
||||
The functions are:
|
||||
#> void bnExtractBigBytes(struct BigNum const *bn, unsigned char *dest,
|
||||
#> unsigned lsbyte, unsigned len);
|
||||
#> int bnInsertBigBytes(struct BigNum *bn, unsigned char const *src,
|
||||
#> unsigned lsbyte, unsigned len);
|
||||
#> void bnExtractLittleBytes(struct BigNum const *bn, unsigned char *dest,
|
||||
#> unsigned lsbyte, unsigned len);
|
||||
#> int bnInsertLittleBytes(struct BigNum *bn, unsigned char const *src,
|
||||
#> unsigned lsbyte, unsigned len);
|
||||
|
||||
These move bytes between the BigNum and the buffer of 8-bit bytes. The
|
||||
Insert functions can allocate memory, so return an error code. The
|
||||
Extract functions always succeed.
|
||||
|
||||
The buffer is encoded in base 256, with either the most significant
|
||||
byte (the Big functions) or the least significant byte (the Little
|
||||
functions) coming first. "len" is the length of the buffer, so the
|
||||
buffer always encodes a value between 0 and 256^len. (That's
|
||||
"to the power of", not "xor".)
|
||||
|
||||
"lsbyte" gives the offset into the BigNum which is being worked with.
|
||||
This is usually zero, but you can, for example, read out a large
|
||||
BigNum in 32-byte chunks, using a len of 32 and an lsbyte of 0, 32,
|
||||
64, 96, etc.
|
||||
|
||||
After these complete, the number encoded in the buffer will be
|
||||
equal to (bn / 256^lsbyte) % 256^len. The only difference between
|
||||
Insert and Extract is which is changed to match the other.
|
||||
|
||||
* Simple math
|
||||
|
||||
#> int bnAdd(struct BigNum *dest, struct BigNum const *src);
|
||||
#> int bnAddQ(struct BigNum *dest, unsigned src);
|
||||
|
||||
These add dest += src. In the Q form, as mentioned above with bnSetQ,
|
||||
src must be < 65536. In either case, the functions can fail and return
|
||||
-1, as usual.
|
||||
|
||||
#> int bnSub(struct BigNum *dest, struct BigNum const *src);
|
||||
#> int bnSubQ(struct BigNum *dest, unsigned src);
|
||||
|
||||
These subtract dest -= src. If this would make the result negative,
|
||||
dest is set to (src-dest) and a value of 1 is returned, so you can
|
||||
keep track of a separate sign if you need to. Otherwise, they return
|
||||
0 on success and -1 if they were unable to allocate needed memory.
|
||||
|
||||
To make your life simpler if you are error checking, these four functions
|
||||
are guaranteed not to allocate memory unnecessarily. So if you know
|
||||
that the addition or subtraction you're doing won't produce a result
|
||||
larger than the input, and won't underflow either (like subtracting 1
|
||||
from an odd number or adding 1 to an even number), you can skip checking
|
||||
the error code.
|
||||
|
||||
#> extern int (*bnCmp)(struct BigNum const *a, struct BigNum const *b);
|
||||
#> extern int (*bnCmpQ)(struct BigNum const *a, unsigned b);
|
||||
|
||||
This returns the sign (-1, 0 or +1) of a-b. Another way of saying
|
||||
this is that a <=> b is the same as bnCmp(a, b) <=> 0, where "<=>"
|
||||
stands for one of <, <=, =, !=, >= or >. The bnCmpQ form is the same,
|
||||
but (as in all the Q functions) the second argument is a number < 65536.
|
||||
|
||||
#> int bnSquare(struct BigNum *dest, struct BigNum const *src);
|
||||
|
||||
This computes dest = src^2, returning an error if it ran out of memory.
|
||||
If you care about performance tuning, this slows down when dest and
|
||||
src are the same BigNum, since it needs to allocate a temporary buffer
|
||||
to do the work in. It does work, however.
|
||||
|
||||
#> int bnMul(struct BigNum *dest, struct BigNum const *a,
|
||||
#> struct BigNum const *b);
|
||||
#> int bnMulQ(struct BigNum *dest, struct BigNum const *a, unsigned b);
|
||||
|
||||
These compute dest = a * b, and work in the same way as bnSquare.
|
||||
(Including the fact that it's faster if dest is not the same as any of
|
||||
the inputs.) bnSquare is faster if a and b are the same. The second
|
||||
input operand to bnMulQ must be < 65536, like all the "Q" functions.
|
||||
|
||||
#> int bnDivMod(struct BigNum *q, struct BigNum *r,
|
||||
#> struct BigNum const *n, struct BigNum const *d);
|
||||
|
||||
This computes division with remainder, q = n/d and r = n%d. Don't
|
||||
pass in a zero d; it will blow up. In general, all of the values
|
||||
must be different (it will blow up if you try), but r and n may be the
|
||||
same.
|
||||
|
||||
RE-ENTRANCY NOTE: This temporarily modifies the BigNum "d" internally,
|
||||
although it restores it before returning. If you're doing something
|
||||
multi-threaded, you can't share the d value between threads, even though
|
||||
it says "const". That's a safe assumption elsewhere, but this is an
|
||||
exception.
|
||||
|
||||
That note also means that it's not safe to let n be the same as d,
|
||||
although that's such a stupid way to set q to 1 and r to 0 that
|
||||
I don't think it's worth worrying about. (I hope you understand that
|
||||
this doesn't mean that n and d can't have the same numerical value,
|
||||
just that they can't both point to the same struct BigNum.)
|
||||
|
||||
#> int bnMod(struct BigNum *dest, struct BigNum const *src,
|
||||
#> struct BigNum const *d);
|
||||
|
||||
This works just the same as the above, but doesn't bother you with the
|
||||
quotient. (No, there's no function that doesn't bother you with the
|
||||
remainder.) Again, dest and src may be the same (it's actually
|
||||
more efficient if they are), but d may not be the same as either.
|
||||
|
||||
#> unsigned int bnModQ(struct BigNum const *src, unsigned d);
|
||||
|
||||
This also computes src % d, but does so for small (up to 65535,
|
||||
the usual limit on "Q" functions) values of d. It returns the
|
||||
remainder. (No error is possible.)
|
||||
|
||||
* Advanced math
|
||||
|
||||
#> int bnLShift(struct BigNum *dest, unsigned amt);
|
||||
#> void bnRShift(struct BigNum *dest, unsigned amt);
|
||||
|
||||
These shift the given bignum left or right by "amt" bit positions.
|
||||
Left shifts multiply by 2^amt, and may have to allocate memory
|
||||
(and thus fail). Right shifts divide by 2^amt, throwing away the
|
||||
remainder, and can never fail.
|
||||
|
||||
#> unsigned bnMakeOdd(struct BigNum *n);
|
||||
|
||||
This right shifts the input number as many places as possible without
|
||||
throwing anything away, and returns the number of bits shifted.
|
||||
If you see "let n = s * 2^t, where s is odd" in an algorithm,
|
||||
this is the function to call. It modifies n in place to produce s
|
||||
and returns t.
|
||||
|
||||
This returns 0 if you pass it 0.
|
||||
|
||||
#> int bnExpMod(struct BigNum *result, struct BigNum const *n,
|
||||
#> struct BigNum const *exp, struct BigNum const *mod);
|
||||
|
||||
Ah, now we get to the heart of the library - probably the most heavily
|
||||
optimized function in it. This computes result = n^exp, modulo "mod".
|
||||
result may be the same as n, but not the same as exp or mod. For large
|
||||
exponents and moduli, it can try to allocate quite a bit of working
|
||||
storage, although it will manage to finish its work (just slower)
|
||||
if some of those allocations fail. (Not all, though - the first few
|
||||
are essential.)
|
||||
|
||||
"mod" must be odd. It will blow up if not. Also, n must be less than
|
||||
mod. If you're not sure if it is, use bnMod first. The return value
|
||||
is always between 0 and mod-1.
|
||||
|
||||
#> int bnTwoExpMod(struct BigNum *result, struct BigNum const *exp,
|
||||
#> struct BigNum const *mod);
|
||||
|
||||
This computes result = 2^exp, modulo "mod". It's faster than the general
|
||||
bnExpMod function, although that function checks to see if n = 2 and calls
|
||||
this one internally, so you don't need to check yourself if you're not
|
||||
sure. The main reason to mention this is that if you're doing something
|
||||
like a pseudoprimality test, using a base of 2 first can save some time.
|
||||
|
||||
#> int bnDoubleExpMod(struct BigNum *result,
|
||||
#> struct BigNum const *n1, struct BigNum const *e1,
|
||||
#> struct BigNum const *n2, struct BigNum const *e2,
|
||||
#> struct BigNum const *mod);
|
||||
|
||||
This computes dest = n1^e1 * n2^e2, modulo "mod". It does it quite
|
||||
a bit faster than doing two separate bnExpMod operations; in fact,
|
||||
it's not that much more expensive than one. "result" may be the
|
||||
same BigNum as n1 or n2, but it may not be the same as the exponents
|
||||
or the modulus. All of the other caveats about bnExpMod apply.
|
||||
|
||||
#> int bnGcd(struct BigNum *dest, struct BigNum const *a,
|
||||
#> struct BigNum const *b);
|
||||
|
||||
This returns dest = gcd(a,b). dest may be the same as either input.
|
||||
|
||||
/* dest = src^-1, modulo "mod". dest may be the same as src. */
|
||||
#> int bnInv(struct BigNum *dest, struct BigNum const *src,
|
||||
#> struct BigNum const *mod);
|
||||
|
||||
This requires that gcd(src, mod) = 1, and returns dest = src^-1, modulo
|
||||
"mod". That is, 0 < dest < mod and dest*src = 1, modulo "mod".
|
||||
dest and src may be the same, but mod must be different.
|
||||
|
||||
This will probably get extended at some point to find dest such that
|
||||
dest * src = gcd(src, mod), modulo "mod", but that isn't implemented
|
||||
yet.
|
||||
|
||||
* Auxiliary functions
|
||||
|
||||
These mostly-internal functions aren't very useful to call directly,
|
||||
and might even get removed, but for now they're there in the unusual
|
||||
case where you might want them.
|
||||
|
||||
#> void bnInit(void);
|
||||
|
||||
This does global library initialization. It is called by the first
|
||||
call to bnBegin(), so you shouldn't need to call it explicitly. It is
|
||||
idempotent, so you can call it multiple times if you like. The only
|
||||
thing it does right now is set up the function pointers to the rest of
|
||||
the library. If a program crashes and the debugger tells you that
|
||||
it's trying to execute at address 0, bnInit never got called.
|
||||
|
||||
#> int bnPrealloc(struct BigNum *bn, unsigned bits);
|
||||
|
||||
This preallocates space in bn to make sure that it can hold "bits" bits.
|
||||
If the overflow characteristics of various algorithms get documented
|
||||
better, this might allow even more error-checking to be avoided, but
|
||||
for now it's only to reduce memory fragmentation.
|
||||
|
||||
#> void bnNorm(struct BigNum *bn);
|
||||
|
||||
This decreases the "size" field of the given bignum until it has no leading
|
||||
zero words in its internal representation. Given that almost everything
|
||||
in the library does the equivalent of this on input and output, the utility
|
||||
of this function is a bit dubious. It's kind of a legacy.
|
||||
|
||||
* Extra libraries
|
||||
|
||||
There are a number of utilities built on top of the basic library.
|
||||
They are built on top of the interfaces just described, and can be used
|
||||
if you like.
|
||||
|
||||
* jacobi.h
|
||||
|
||||
#> int bnJacobiQ(unsigned p, struct BigNum const *bn);
|
||||
|
||||
This returns the Jacobi symbol J(p,bn), where p is a small number.
|
||||
The Jacobi symbol is always -1, 0, or +1. You'll note that p may
|
||||
only be positive, even though the Jacobi symbol is defined for
|
||||
negative p. If you want to worry about negative p, do it yourself.
|
||||
J(-p,bn) = (bnLSWord(bn) & 2 ? -1 : +1) * bnJacobiQ(p, bn).
|
||||
|
||||
A function to compute the Jacobi symbol for large p would be nice.
|
||||
|
||||
* prime.h
|
||||
|
||||
#> int primeGen(struct BigNum *bn, unsigned (*rand)(unsigned),
|
||||
#> int (*f)(void *arg, int c), void *arg, unsigned exponent, ...);
|
||||
|
||||
This finds the next prime p >= bn, and sets bn to equal it.
|
||||
Well, sort of.
|
||||
|
||||
It always leaves bn at least as large as when it started (unless it
|
||||
runs out of memory and returns -1), and if you pass a 0 for the rand
|
||||
function, it will be the next prime >= bn.
|
||||
|
||||
Except:
|
||||
- It doesn't bother coping with small primes. If it's divisible by any
|
||||
prime up to 65521, it's considered non-prime. Even if the quotient is 0.
|
||||
If you pass in "1", expecting to get "2" back, you'll get 65537. Maybe
|
||||
it would be nice to fix that.
|
||||
- It actually only does a few strong pseudoprimality tests to fixed
|
||||
bases to determine if the candidate number is prime. For random input,
|
||||
this is fine; the chance of error is so infinitesimal that it is
|
||||
absolutely not worth worrying about. But if you give it numbers carefully
|
||||
chosen to be strong pseudoprimes, it will think they're primes and not
|
||||
complain. For example, 341550071728321 = 10670053 * 32010157 will
|
||||
pass the primality test quite handily. So will
|
||||
68528663395046912244223605902738356719751082784386681071.
|
||||
- If you supply a rand() function, which returns 0 <= rand(n) < n
|
||||
(n never gets very large - currently, at most 256), this shuffles the
|
||||
candidates before testing and accepting one. If you want a "random"
|
||||
prime, this produces a more uniformly distributed prime, while
|
||||
retaining all of the speed advantages of a sequential search from a
|
||||
random starting point, which would otherwise produce a bias towards
|
||||
primes which were not closely preceded by other primes. So, for
|
||||
example, the second of a pair of twin primes would be very unlikely to
|
||||
be chosen. rand() doesn't totally flatten the distribution, but it
|
||||
comes very close.
|
||||
|
||||
The "f" function is called periodically during the progress of the
|
||||
search (which can take a while) with the supplied argument (for private
|
||||
context) and a character c, which sort of tells you what it's doing.
|
||||
c is either '.' or '*' (if it's found something and is confirming that
|
||||
it's really prime) or '/' (if it's having a really hard time finding
|
||||
something). Also, if f returns < 0, primeGen immediately returns that
|
||||
value. This can form the basis for a user interface which can show some
|
||||
life occasionally and abort the computation if desired.
|
||||
|
||||
If you just print these characters to the screen, don't forget to
|
||||
fflush() after printing them.
|
||||
|
||||
Finally, "exponent, ..." is a zero-terminated list of small numbers
|
||||
which must not divide p-1 when the function returns. If the numbers
|
||||
are chosen to be the prime factors of n, then gcd(n, p-1) will be
|
||||
1, so the map f(x) -> x^n is invertible modulo p.
|
||||
|
||||
#> int primeGenStrong(struct BigNum *bn, struct BigNum const *step,
|
||||
#> int (*f)(void *arg, int c), void *arg);
|
||||
|
||||
This is similar, but searches in steps of "step", rather than 1, from the
|
||||
given starting value. The starting value must be odd and the step
|
||||
size must be even! If you start with bn == 1 (mod step), and step
|
||||
is 2*q, where q is a large prime, then this generates "strong" primes,
|
||||
p-1 having a large prime factor q. There are other uses, too.
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
* germain.h
|
||||
|
||||
#> int germainPrimeGen(struct BigNum *bn, int (*f)(void *arg, int c),
|
||||
#> void *arg);
|
||||
|
||||
This increases bn until it is a Sophie Germain prime, that is, a number p
|
||||
such that p and (p-1)/2 are both prime. These numbers are rarer than
|
||||
ordinary primes and the search takes correspondingly longer.
|
||||
|
||||
It omits the randomization portion of primeGen, and the exponent list,
|
||||
since the factors of bn-1 are known already. The f function for
|
||||
progress is the same, but it is also sometimes passed a '+' or '-'
|
||||
character when it's found a (p-1)/2 that's prime. This is just to lend
|
||||
some interest to an otherwise very boring row of dots. Finding large
|
||||
primes with this function, even though it's pretty optimized, takes a
|
||||
*while*, and otherwise once the screen filled with dots (one every few
|
||||
seconds) it would be hard to keep track of the scroll.
|
||||
|
||||
It varies a lot, depending on luck of the starting value and the speed
|
||||
of your machine, but if your starting number is over 1024 bits, plan on
|
||||
over an hour of run time, and if it's over 2048 bits, plan on a day.
|
||||
At 4096 bits, start thinking about a week.
|
||||
|
||||
Past that, supporting checkpoint/restart is a good idea. Every time
|
||||
the progress function gets a '/' is probably a good interval, and when
|
||||
it happens have f return a distinct error value like -2. When
|
||||
germainPrimeGen returns with that value, save the value in bn to a file
|
||||
somewhere and call it again with the same bn to continue searching.
|
||||
|
||||
* sieve.h
|
||||
|
||||
This is the sieving code that the other prime-finding functions call
|
||||
to do trial division. You might use it if you are doing some magic
|
||||
prime-finding of your own. A sieve is an array of bits, stored
|
||||
little-endian in an array of bytes (i.e. the lsb of byte 0 is bit 0).
|
||||
Sieves are indexed with the "unsigned" data type, so should not, for
|
||||
portability, be larger than 65536/8 = 8192 bytes long.
|
||||
|
||||
A 1 bit is considered "in" the sieve, it has passed all the sieving.
|
||||
A 0 bit has been removed by some step.
|
||||
|
||||
The functions are:
|
||||
|
||||
#> void sieveSingle(unsigned char *array, unsigned size, unsigned start,
|
||||
#> unsigned step);
|
||||
|
||||
This (efficiently) clears the bits at positions start, start+step,
|
||||
start+2*step, etc. in the sieve given by array and size. This is the
|
||||
elementary sieve-building step. Start with a sieve of all 1s, and
|
||||
apply this as required.
|
||||
|
||||
#> unsigned sieveSearch(unsigned char const *array, unsigned size,
|
||||
#> unsigned start);
|
||||
|
||||
This returns the next bit position *greater than* start which is set
|
||||
in the indicated sieve, or 0 on failure. NOTE that this means that
|
||||
you have to look at the bit at position 0 (array[0] & 1) by yourself
|
||||
if you want to pay attention to it, because there's no way to tell
|
||||
sieveSearch to start searching at 0 - it starts at start+1.
|
||||
|
||||
#> int sieveBuild(unsigned char *array, unsigned size, struct BigNum const *bn,
|
||||
#> unsigned step, unsigned dbl);
|
||||
|
||||
This initializes a sieve where, if bit i is set, then bn+step*i is not
|
||||
divisible by any small primes. (Small is from 2 through 65521, the
|
||||
largest prime less that 65536.) If "dbl" is > 0, then bits are also
|
||||
cleared if 2*(bn+step*i)+1 is divisible. If dbl > 1, then
|
||||
4*(bn+step*i)+3 is also checked, and so on. This feature is used when
|
||||
generating Sohpie Germain primes.
|
||||
|
||||
Usually, you use a step of 2.
|
||||
|
||||
#> int sieveBuildBig(unsigned char *array, unsigned size,
|
||||
#> struct BigNum const *bn, struct BigNum const *step, unsigned dbl);
|
||||
|
||||
This is just the same, but accepts a BigNum step size, and is correspondingly
|
||||
slower.
|
||||
|
||||
* bnprint.h
|
||||
|
||||
#> int bnPrint(FILE *f, char const *prefix, struct BigNum const *bn,
|
||||
#> char const *suffix);
|
||||
|
||||
This prints a nicely-formatted BigNum in hexadecimal form to the given
|
||||
FILE *. The "prefix" is printed before it, as a prompt, and the
|
||||
"suffix" is printed afterwards. The BigNum itself is printed in
|
||||
64-character lines, broken with a trailing backslash if necessary.
|
||||
Continuation lines are indented by the length of the prefix.
|
||||
|
||||
E.g. a 2^512-1, printed with the call bnPrint(stdout, "a = (", bn, ")\n")
|
||||
would result in:
|
||||
|
||||
a = (FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\
|
||||
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
|
||||
|
||||
Hex digits are printed in upper case to facilitate cutting and pasting into
|
||||
the Unix "dc" utility.
|
||||
Vendored
+228
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bn.h - the interface to the bignum routines.
|
||||
* All functions which return ints can potentially allocate memory
|
||||
* and return -1 if they are unable to. All "const" arguments
|
||||
* are unmodified.
|
||||
*
|
||||
* This is not particularly asymmetric, as some operations are of the
|
||||
* form a = b @ c, while others do a @= b. In general, outputs may not
|
||||
* point to the same struct BigNums as inputs, except as specified
|
||||
* below. This relationship is referred to as "being the same as".
|
||||
* This is not numerical equivalence.
|
||||
*
|
||||
* The "Q" operations take "unsigned" inputs. Higher values of the
|
||||
* extra input may work on some implementations, but 65535 is the
|
||||
* highest portable value. Just because UNSIGNED_MAX is larger than
|
||||
* that, or you know that the word size of the library is larger than that,
|
||||
* that, does *not* mean it's allowed.
|
||||
*/
|
||||
#ifndef BN_H
|
||||
#define BN_H
|
||||
|
||||
struct BigNum {
|
||||
void *ptr;
|
||||
unsigned size; /* Note: in (variable-sized) words */
|
||||
unsigned allocated;
|
||||
};
|
||||
|
||||
/*
|
||||
* User-supplied function: if non-NULL, this is called during long-running
|
||||
* computations. You may put Yield() calls in here to give CPU time to
|
||||
* other processes. You may also force the computation to be aborted,
|
||||
* by returning a value < 0, which will be the return value of the
|
||||
* bnXXX call. (You probably want the value to be someting other than
|
||||
* -1, to distinguish it from a n out-of-memory error.)
|
||||
*
|
||||
* The functions that this is called from, and the intervals at which it
|
||||
* is called, are not well defined, just "reasonably often". (Currently,
|
||||
* once per exponent bit in nodular exponentiation, and once per two
|
||||
* divisions in GCD and inverse computation.)
|
||||
*/
|
||||
extern int (*bnYield)(void);
|
||||
|
||||
/* Functions */
|
||||
|
||||
/*
|
||||
* You usually never have to call this function explicitly, as
|
||||
* bnBegin() takes care of it. If the program jumps to address 0,
|
||||
* this function has bot been called.
|
||||
*/
|
||||
void bnInit(void);
|
||||
|
||||
/*
|
||||
* This initializes an empty struct BigNum to a zero value.
|
||||
* Do not use this on a BigNum which has had a value stored in it!
|
||||
*/
|
||||
void bnBegin(struct BigNum *bn);
|
||||
|
||||
/* Swap two BigNums. Cheap. */
|
||||
void bnSwap(struct BigNum *a, struct BigNum *b);
|
||||
|
||||
/* Reset an initialized bigNum to empty, pending deallocation. */
|
||||
extern void (*bnEnd)(struct BigNum *bn);
|
||||
|
||||
/*
|
||||
* If you know you'll need space in the number soon, you can use this function
|
||||
* to ensure that there is room for at least "bits" bits. Optional.
|
||||
* Returns <0 on out of memory, but the value is unaffected.
|
||||
*/
|
||||
extern int (*bnPrealloc)(struct BigNum *bn, unsigned bits);
|
||||
|
||||
/* Hopefully obvious. dest = src. dest may be the same as src. */
|
||||
extern int (*bnCopy)(struct BigNum *dest, struct BigNum const *src);
|
||||
|
||||
/*
|
||||
* Mostly done automatically, but this removes leading zero words from
|
||||
* the internal representation of the BigNum. Use is unclear.
|
||||
*/
|
||||
extern void (*bnNorm)(struct BigNum *bn);
|
||||
|
||||
/*
|
||||
* Move bytes between the given buffer and the given BigNum encoded in
|
||||
* base 256. I.e. after either of these, the buffer will be equal to
|
||||
* (bn / 256^lsbyte) % 256^len. The difference is which is altered to
|
||||
* match the other!
|
||||
*/
|
||||
extern void (*bnExtractBigBytes)(struct BigNum const *bn,
|
||||
unsigned char *dest, unsigned lsbyte, unsigned len);
|
||||
extern int (*bnInsertBigBytes)(struct BigNum *bn, unsigned char const *src,
|
||||
unsigned lsbyte, unsigned len);
|
||||
|
||||
/* The same, but the buffer is little-endian. */
|
||||
extern void (*bnExtractLittleBytes)(struct BigNum const *bn,
|
||||
unsigned char *dest, unsigned lsbyte, unsigned len);
|
||||
extern int (*bnInsertLittleBytes)(struct BigNum *bn, unsigned char const *src,
|
||||
unsigned lsbyte, unsigned len);
|
||||
|
||||
/* Return the least-significant bits (at least 16) of the BigNum */
|
||||
extern unsigned (*bnLSWord)(struct BigNum const *src);
|
||||
|
||||
/* Return the selected bit of the BigNum (bit 0 is bn mod 2) */
|
||||
extern int (*bnReadBit)(struct BigNum const *bn, unsigned bit);
|
||||
|
||||
/*
|
||||
* Return the number of significant bits in the BigNum.
|
||||
* 0 or 1+floor(log2(src))
|
||||
*/
|
||||
extern unsigned (*bnBits)(struct BigNum const *src);
|
||||
#define bnBytes(bn) ((bnBits(bn)+7)/8)
|
||||
|
||||
/*
|
||||
* dest += src. dest and src may be the same. Guaranteed not to
|
||||
* allocate memory unnecessarily, so if you're sure bnBits(dest)
|
||||
* won't change, you don't need to check the return value.
|
||||
*/
|
||||
extern int (*bnAdd)(struct BigNum *dest, struct BigNum const *src);
|
||||
|
||||
/*
|
||||
* dest -= src. dest and src may be the same, but bnSetQ(dest, 0) is faster.
|
||||
* if dest < src, returns +1 and sets dest = src-dest.
|
||||
*/
|
||||
extern int (*bnSub)(struct BigNum *dest, struct BigNum const *src);
|
||||
|
||||
/* Return sign (-1, 0, +1) of a-b. a <=> b --> bnCmpQ(a, b) <=> 0 */
|
||||
extern int (*bnCmpQ)(struct BigNum const *a, unsigned b);
|
||||
|
||||
/* dest = src, where 0 <= src < 2^16. */
|
||||
extern int (*bnSetQ)(struct BigNum *dest, unsigned src);
|
||||
|
||||
/* dest += src, where 0 <= src < 2^16 */
|
||||
extern int (*bnAddQ)(struct BigNum *dest, unsigned src);
|
||||
|
||||
/* dest -= src, where 0 <= src < 2^16 */
|
||||
extern int (*bnSubQ)(struct BigNum *dest, unsigned src);
|
||||
|
||||
/* Return sign (-1, 0, +1) of a-b. a <=> b --> bnCmp(a, b) <=> 0 */
|
||||
extern int (*bnCmp)(struct BigNum const *a, struct BigNum const *b);
|
||||
|
||||
/* dest = src^2. dest may be the same as src, but it costs time. */
|
||||
extern int (*bnSquare)(struct BigNum *dest, struct BigNum const *src);
|
||||
|
||||
/* dest = a * b. dest may be the same as a or b, but it costs time. */
|
||||
extern int (*bnMul)(struct BigNum *dest, struct BigNum const *a,
|
||||
struct BigNum const *b);
|
||||
|
||||
/* dest = a * b, where 0 <= b < 2^16. dest and a may be the same. */
|
||||
extern int (*bnMulQ)(struct BigNum *dest, struct BigNum const *a, unsigned b);
|
||||
|
||||
/*
|
||||
* q = n/d, r = n%d. r may be the same as n, but not d,
|
||||
* and q may not be the same as n or d.
|
||||
* re-entrancy issue: this temporarily modifies d, but restores
|
||||
* it for return.
|
||||
*/
|
||||
extern int (*bnDivMod)(struct BigNum *q, struct BigNum *r,
|
||||
struct BigNum const *n, struct BigNum const *d);
|
||||
/*
|
||||
* dest = src % d. dest and src may be the same, but not dest and d.
|
||||
* re-entrancy issue: this temporarily modifies d, but restores
|
||||
* it for return.
|
||||
*/
|
||||
extern int (*bnMod)(struct BigNum *dest, struct BigNum const *src,
|
||||
struct BigNum const *d);
|
||||
|
||||
/* return src % d, where 0 <= d < 2^16. */
|
||||
extern unsigned int (*bnModQ)(struct BigNum const *src, unsigned d);
|
||||
|
||||
/* n = n^exp, modulo "mod" "mod" *must* be odd */
|
||||
extern int (*bnExpMod)(struct BigNum *result, struct BigNum const *n,
|
||||
struct BigNum const *exp, struct BigNum const *mod);
|
||||
|
||||
/*
|
||||
* dest = n1^e1 * n2^e2, modulo "mod". "mod" *must* be odd.
|
||||
* dest may be the same as n1 or n2.
|
||||
*/
|
||||
extern int (*bnDoubleExpMod)(struct BigNum *dest,
|
||||
struct BigNum const *n1, struct BigNum const *e1,
|
||||
struct BigNum const *n2, struct BigNum const *e2,
|
||||
struct BigNum const *mod);
|
||||
|
||||
/* n = 2^exp, modulo "mod" "mod" *must* be odd */
|
||||
extern int (*bnTwoExpMod)(struct BigNum *n, struct BigNum const *exp,
|
||||
struct BigNum const *mod);
|
||||
|
||||
/* dest = gcd(a, b). The inputs may overlap arbitrarily. */
|
||||
extern int (*bnGcd)(struct BigNum *dest, struct BigNum const *a,
|
||||
struct BigNum const *b);
|
||||
|
||||
/* dest = src^-1, modulo "mod". dest may be the same as src. */
|
||||
extern int (*bnInv)(struct BigNum *dest, struct BigNum const *src,
|
||||
struct BigNum const *mod);
|
||||
|
||||
/* Shift dest left "amt" places */
|
||||
extern int (*bnLShift)(struct BigNum *dest, unsigned amt);
|
||||
/* Shift dest right "amt" places, discarding low-order bits */
|
||||
extern void (*bnRShift)(struct BigNum *dest, unsigned amt);
|
||||
|
||||
/* For the largest 2^k that divides n, divide n by it and return k. */
|
||||
extern unsigned (*bnMakeOdd)(struct BigNum *n);
|
||||
|
||||
/*
|
||||
* Precomputed data for rapid base^exp (mod mod) computation with fixed
|
||||
* base and mod.
|
||||
*/
|
||||
struct BnBasePrecomp {
|
||||
void *array; /* Ponter to array of pointers to words */
|
||||
unsigned msize; /* Words in modulis (normalized) */
|
||||
unsigned bits; /* Bits per array element */
|
||||
unsigned maxebits; /* Maximum exponent bits */
|
||||
unsigned entries; /* Number of entries */
|
||||
unsigned arraysize;
|
||||
};
|
||||
|
||||
extern int (*bnBasePrecompBegin)(struct BnBasePrecomp *pre,
|
||||
struct BigNum const *base, struct BigNum const *mod,
|
||||
unsigned maxebits);
|
||||
extern void (*bnBasePrecompEnd)(struct BnBasePrecomp *pre);
|
||||
extern int (*bnBasePrecompExpMod)(struct BigNum *dest,
|
||||
struct BnBasePrecomp const *pre, struct BigNum const *exp,
|
||||
struct BigNum const *mod);
|
||||
extern int (*bnDoubleBasePrecompExpMod)(struct BigNum *dest,
|
||||
struct BnBasePrecomp const *pre1, struct BigNum const *exp1,
|
||||
struct BnBasePrecomp const *pre2, struct BigNum const *exp2,
|
||||
struct BigNum const *mod);
|
||||
|
||||
#endif/* !BN_H */
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bn00.c - auto-size-detecting bn??.c file.
|
||||
*
|
||||
* Written in 1995 by Colin Plumb.
|
||||
*/
|
||||
|
||||
#include "bnsize00.h"
|
||||
|
||||
#if BNSIZE64
|
||||
|
||||
/* Include all of the C source file by reference */
|
||||
#include "bn64.c"
|
||||
#include "bninit64.c"
|
||||
|
||||
#elif BNSIZE32
|
||||
|
||||
/* Include all of the C source file by reference */
|
||||
#include "bn32.c"
|
||||
#include "bninit32.c"
|
||||
|
||||
#else /* BNSIZE16 */
|
||||
|
||||
/* Include all of the C source file by reference */
|
||||
#include "bn16.c"
|
||||
#include "bninit16.c"
|
||||
|
||||
#endif
|
||||
+1188
File diff suppressed because it is too large.
Load diff
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bn16.h - interface to 16-bit bignum routines.
|
||||
*/
|
||||
struct BigNum;
|
||||
struct BnBasePrecomp;
|
||||
|
||||
void bnInit_16(void);
|
||||
void bnEnd_16(struct BigNum *bn);
|
||||
int bnPrealloc_16(struct BigNum *bn, unsigned bits);
|
||||
int bnCopy_16(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnSwap_16(struct BigNum *a, struct BigNum *b);
|
||||
void bnNorm_16(struct BigNum *bn);
|
||||
void bnExtractBigBytes_16(struct BigNum const *bn, unsigned char *dest,
|
||||
unsigned lsbyte, unsigned dlen);
|
||||
int bnInsertBigBytes_16(struct BigNum *bn, unsigned char const *src,
|
||||
unsigned lsbyte, unsigned len);
|
||||
void bnExtractLittleBytes_16(struct BigNum const *bn, unsigned char *dest,
|
||||
unsigned lsbyte, unsigned dlen);
|
||||
int bnInsertLittleBytes_16(struct BigNum *bn, unsigned char const *src,
|
||||
unsigned lsbyte, unsigned len);
|
||||
unsigned bnLSWord_16(struct BigNum const *src);
|
||||
int bnReadBit_16(struct BigNum const *bn, unsigned bit);
|
||||
unsigned bnBits_16(struct BigNum const *src);
|
||||
int bnAdd_16(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnSub_16(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnCmpQ_16(struct BigNum const *a, unsigned b);
|
||||
int bnSetQ_16(struct BigNum *dest, unsigned src);
|
||||
int bnAddQ_16(struct BigNum *dest, unsigned src);
|
||||
int bnSubQ_16(struct BigNum *dest, unsigned src);
|
||||
int bnCmp_16(struct BigNum const *a, struct BigNum const *b);
|
||||
int bnSquare_16(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnMul_16(struct BigNum *dest, struct BigNum const *a,
|
||||
struct BigNum const *b);
|
||||
int bnMulQ_16(struct BigNum *dest, struct BigNum const *a, unsigned b);
|
||||
int bnDivMod_16(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
|
||||
struct BigNum const *d);
|
||||
int bnMod_16(struct BigNum *dest, struct BigNum const *src,
|
||||
struct BigNum const *d);
|
||||
unsigned bnModQ_16(struct BigNum const *src, unsigned d);
|
||||
int bnExpMod_16(struct BigNum *dest, struct BigNum const *n,
|
||||
struct BigNum const *exp, struct BigNum const *mod);
|
||||
int bnDoubleExpMod_16(struct BigNum *dest,
|
||||
struct BigNum const *n1, struct BigNum const *e1,
|
||||
struct BigNum const *n2, struct BigNum const *e2,
|
||||
struct BigNum const *mod);
|
||||
int bnTwoExpMod_16(struct BigNum *n, struct BigNum const *exp,
|
||||
struct BigNum const *mod);
|
||||
int bnGcd_16(struct BigNum *dest, struct BigNum const *a,
|
||||
struct BigNum const *b);
|
||||
int bnInv_16(struct BigNum *dest, struct BigNum const *src,
|
||||
struct BigNum const *mod);
|
||||
int bnLShift_16(struct BigNum *dest, unsigned amt);
|
||||
void bnRShift_16(struct BigNum *dest, unsigned amt);
|
||||
unsigned bnMakeOdd_16(struct BigNum *n);
|
||||
int bnBasePrecompBegin_16(struct BnBasePrecomp *pre, struct BigNum const *base,
|
||||
struct BigNum const *mod, unsigned maxebits);
|
||||
void bnBasePrecompEnd_16(struct BnBasePrecomp *pre);
|
||||
int bnBasePrecompExpMod_16(struct BigNum *dest, struct BnBasePrecomp const *pre,
|
||||
struct BigNum const *exp, struct BigNum const *mod);
|
||||
int bnDoubleBasePrecompExpMod_16(struct BigNum *dest,
|
||||
struct BnBasePrecomp const *pre1, struct BigNum const *exp1,
|
||||
struct BnBasePrecomp const *pre2, struct BigNum const *exp2,
|
||||
struct BigNum const *mod);
|
||||
+1188
File diff suppressed because it is too large.
Load diff
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bn32.h - interface to 32-bit bignum routines.
|
||||
*/
|
||||
struct BigNum;
|
||||
struct BnBasePrecomp;
|
||||
|
||||
void bnInit_32(void);
|
||||
void bnEnd_32(struct BigNum *bn);
|
||||
int bnPrealloc_32(struct BigNum *bn, unsigned bits);
|
||||
int bnCopy_32(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnSwap_32(struct BigNum *a, struct BigNum *b);
|
||||
void bnNorm_32(struct BigNum *bn);
|
||||
void bnExtractBigBytes_32(struct BigNum const *bn, unsigned char *dest,
|
||||
unsigned lsbyte, unsigned dlen);
|
||||
int bnInsertBigBytes_32(struct BigNum *bn, unsigned char const *src,
|
||||
unsigned lsbyte, unsigned len);
|
||||
void bnExtractLittleBytes_32(struct BigNum const *bn, unsigned char *dest,
|
||||
unsigned lsbyte, unsigned dlen);
|
||||
int bnInsertLittleBytes_32(struct BigNum *bn, unsigned char const *src,
|
||||
unsigned lsbyte, unsigned len);
|
||||
unsigned bnLSWord_32(struct BigNum const *src);
|
||||
int bnReadBit_32(struct BigNum const *bn, unsigned bit);
|
||||
unsigned bnBits_32(struct BigNum const *src);
|
||||
int bnAdd_32(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnSub_32(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnCmpQ_32(struct BigNum const *a, unsigned b);
|
||||
int bnSetQ_32(struct BigNum *dest, unsigned src);
|
||||
int bnAddQ_32(struct BigNum *dest, unsigned src);
|
||||
int bnSubQ_32(struct BigNum *dest, unsigned src);
|
||||
int bnCmp_32(struct BigNum const *a, struct BigNum const *b);
|
||||
int bnSquare_32(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnMul_32(struct BigNum *dest, struct BigNum const *a,
|
||||
struct BigNum const *b);
|
||||
int bnMulQ_32(struct BigNum *dest, struct BigNum const *a, unsigned b);
|
||||
int bnDivMod_32(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
|
||||
struct BigNum const *d);
|
||||
int bnMod_32(struct BigNum *dest, struct BigNum const *src,
|
||||
struct BigNum const *d);
|
||||
unsigned bnModQ_32(struct BigNum const *src, unsigned d);
|
||||
int bnExpMod_32(struct BigNum *dest, struct BigNum const *n,
|
||||
struct BigNum const *exp, struct BigNum const *mod);
|
||||
int bnDoubleExpMod_32(struct BigNum *dest,
|
||||
struct BigNum const *n1, struct BigNum const *e1,
|
||||
struct BigNum const *n2, struct BigNum const *e2,
|
||||
struct BigNum const *mod);
|
||||
int bnTwoExpMod_32(struct BigNum *n, struct BigNum const *exp,
|
||||
struct BigNum const *mod);
|
||||
int bnGcd_32(struct BigNum *dest, struct BigNum const *a,
|
||||
struct BigNum const *b);
|
||||
int bnInv_32(struct BigNum *dest, struct BigNum const *src,
|
||||
struct BigNum const *mod);
|
||||
int bnLShift_32(struct BigNum *dest, unsigned amt);
|
||||
void bnRShift_32(struct BigNum *dest, unsigned amt);
|
||||
unsigned bnMakeOdd_32(struct BigNum *n);
|
||||
int bnBasePrecompBegin_32(struct BnBasePrecomp *pre, struct BigNum const *base,
|
||||
struct BigNum const *mod, unsigned maxebits);
|
||||
void bnBasePrecompEnd_32(struct BnBasePrecomp *pre);
|
||||
int bnBasePrecompExpMod_32(struct BigNum *dest, struct BnBasePrecomp const *pre,
|
||||
struct BigNum const *exp, struct BigNum const *mod);
|
||||
int bnDoubleBasePrecompExpMod_32(struct BigNum *dest,
|
||||
struct BnBasePrecomp const *pre1, struct BigNum const *exp1,
|
||||
struct BnBasePrecomp const *pre2, struct BigNum const *exp2,
|
||||
struct BigNum const *mod);
|
||||
+1188
File diff suppressed because it is too large.
Load diff
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bn64.h - interface to 64-bit bignum routines.
|
||||
*/
|
||||
struct BigNum;
|
||||
struct BnBasePrecomp;
|
||||
|
||||
void bnInit_64(void);
|
||||
void bnEnd_64(struct BigNum *bn);
|
||||
int bnPrealloc_64(struct BigNum *bn, unsigned bits);
|
||||
int bnCopy_64(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnSwap_64(struct BigNum *a, struct BigNum *b);
|
||||
void bnNorm_64(struct BigNum *bn);
|
||||
void bnExtractBigBytes_64(struct BigNum const *bn, unsigned char *dest,
|
||||
unsigned lsbyte, unsigned dlen);
|
||||
int bnInsertBigBytes_64(struct BigNum *bn, unsigned char const *src,
|
||||
unsigned lsbyte, unsigned len);
|
||||
void bnExtractLittleBytes_64(struct BigNum const *bn, unsigned char *dest,
|
||||
unsigned lsbyte, unsigned dlen);
|
||||
int bnInsertLittleBytes_64(struct BigNum *bn, unsigned char const *src,
|
||||
unsigned lsbyte, unsigned len);
|
||||
unsigned bnLSWord_64(struct BigNum const *src);
|
||||
int bnReadBit_64(struct BigNum const *bn, unsigned bit);
|
||||
unsigned bnBits_64(struct BigNum const *src);
|
||||
int bnAdd_64(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnSub_64(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnCmpQ_64(struct BigNum const *a, unsigned b);
|
||||
int bnSetQ_64(struct BigNum *dest, unsigned src);
|
||||
int bnAddQ_64(struct BigNum *dest, unsigned src);
|
||||
int bnSubQ_64(struct BigNum *dest, unsigned src);
|
||||
int bnCmp_64(struct BigNum const *a, struct BigNum const *b);
|
||||
int bnSquare_64(struct BigNum *dest, struct BigNum const *src);
|
||||
int bnMul_64(struct BigNum *dest, struct BigNum const *a,
|
||||
struct BigNum const *b);
|
||||
int bnMulQ_64(struct BigNum *dest, struct BigNum const *a, unsigned b);
|
||||
int bnDivMod_64(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
|
||||
struct BigNum const *d);
|
||||
int bnMod_64(struct BigNum *dest, struct BigNum const *src,
|
||||
struct BigNum const *d);
|
||||
unsigned bnModQ_64(struct BigNum const *src, unsigned d);
|
||||
int bnExpMod_64(struct BigNum *dest, struct BigNum const *n,
|
||||
struct BigNum const *exp, struct BigNum const *mod);
|
||||
int bnDoubleExpMod_64(struct BigNum *dest,
|
||||
struct BigNum const *n1, struct BigNum const *e1,
|
||||
struct BigNum const *n2, struct BigNum const *e2,
|
||||
struct BigNum const *mod);
|
||||
int bnTwoExpMod_64(struct BigNum *n, struct BigNum const *exp,
|
||||
struct BigNum const *mod);
|
||||
int bnGcd_64(struct BigNum *dest, struct BigNum const *a,
|
||||
struct BigNum const *b);
|
||||
int bnInv_64(struct BigNum *dest, struct BigNum const *src,
|
||||
struct BigNum const *mod);
|
||||
int bnLShift_64(struct BigNum *dest, unsigned amt);
|
||||
void bnRShift_64(struct BigNum *dest, unsigned amt);
|
||||
unsigned bnMakeOdd_64(struct BigNum *n);
|
||||
int bnBasePrecompBegin_64(struct BnBasePrecomp *pre, struct BigNum const *base,
|
||||
struct BigNum const *mod, unsigned maxebits);
|
||||
void bnBasePrecompEnd_64(struct BnBasePrecomp *pre);
|
||||
int bnBasePrecompExpMod_64(struct BigNum *dest, struct BnBasePrecomp const *pre,
|
||||
struct BigNum const *exp, struct BigNum const *mod);
|
||||
int bnDoubleBasePrecompExpMod_64(struct BigNum *dest,
|
||||
struct BnBasePrecomp const *pre1, struct BigNum const *exp1,
|
||||
struct BnBasePrecomp const *pre2, struct BigNum const *exp2,
|
||||
struct BigNum const *mod);
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bn68000.c - bnInit() for Motorola 680x0 family, 16 or 32-bit.
|
||||
*
|
||||
* Written in 1995 by Colin Plumb.
|
||||
*/
|
||||
|
||||
#include "lbn.h"
|
||||
#include "bn16.h"
|
||||
#include "bn32.h"
|
||||
|
||||
#ifndef BNINCLUDE
|
||||
#error You must define BNINCLUDE to lbn68000.h to use assembly primitives.
|
||||
#endif
|
||||
|
||||
void
|
||||
bnInit(void)
|
||||
{
|
||||
if (is68020())
|
||||
bnInit_32();
|
||||
else
|
||||
bnInit_16();
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bn8086.c - bnInit() for Intel x86 family in 16-bit mode.
|
||||
*
|
||||
* Written in 1995 by Colin Plumb.
|
||||
*/
|
||||
|
||||
#include "lbn.h"
|
||||
#include "bn16.h"
|
||||
#include "bn32.h"
|
||||
|
||||
#ifndef BNINCLUDE
|
||||
#error You must define BNINCLUDE to lbn8086.h to use assembly primitives.
|
||||
#endif
|
||||
|
||||
void
|
||||
bnInit(void)
|
||||
{
|
||||
if (not386())
|
||||
bnInit_16();
|
||||
else
|
||||
bnInit_32();
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bnconfig.h -- Configuration file for BigNum library.
|
||||
*
|
||||
* This file is automatically filled in by configure.
|
||||
* Everything must start out turned *off*, because configure
|
||||
* (or, more properly, config.status) only knows how to turn them
|
||||
* *on*.
|
||||
*/
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
/* Define to empty if the compiler does not support 'const' variables. */
|
||||
#undef const
|
||||
|
||||
/* Define to `unsigned' if <sys/types.h> doesn't define it. */
|
||||
#undef size_t
|
||||
|
||||
/* Checks for the presence and absence of various header files */
|
||||
#define HAVE_ASSERT_H 0
|
||||
#define NO_ASSERT_H !HAVE_ASSERT_H
|
||||
#define HAVE_LIMITS_H 0
|
||||
#define NO_LIMITS_H !HAVE_LIMITS_H
|
||||
#define HAVE_STDLIB_H 0
|
||||
#define NO_STDLIB_H !HAVE_STDLIB_H
|
||||
#define HAVE_STRING_H 0
|
||||
#define NO_STRING_H !HAVE_STRING_H
|
||||
|
||||
#define HAVE_STRINGS_H 0
|
||||
#define NEED_MEMORY_H 0
|
||||
|
||||
/* We go to some trouble to find accurate times... */
|
||||
|
||||
/* Define if you have Posix.4 glock_gettime() */
|
||||
#define HAVE_CLOCK_GETTIME 0
|
||||
/* Define if you have Solaris-style gethrvtime() */
|
||||
#define HAVE_GETHRVTIME 0
|
||||
/* Define if you have getrusage() */
|
||||
#define HAVE_GETRUSAGE 0
|
||||
/* Define if you have clock() */
|
||||
#define HAVE_CLOCK 0
|
||||
/* Define if you have time() */
|
||||
#define HAVE_TIME 0
|
||||
|
||||
/*
|
||||
* Define as 0 if #including <sys/time.h> automatically
|
||||
* #includes <time.h>, and doing so explicitly causes an
|
||||
* error.
|
||||
*/
|
||||
#define TIME_WITH_SYS_TIME 0
|
||||
|
||||
/* Defines for various kinds of library brokenness */
|
||||
|
||||
/* Define if <stdio.h> is missing prototypes (= lots of warnings!) */
|
||||
#define NO_STDIO_PROTOS 0
|
||||
|
||||
/* Define if <assert.h> depends on <stdio.h> and breaks without it */
|
||||
#define ASSERT_NEEDS_STDIO 0
|
||||
/* Define if <assert.h> depends on <stdlib.h> and complains without it */
|
||||
#define ASSERT_NEEDS_STDLIB 0
|
||||
|
||||
/*
|
||||
* Define if <string.h> delcares the mem* functions to take char *
|
||||
* instead of void * parameters (= lots of warnings)
|
||||
*/
|
||||
#define MEM_PROTOS_BROKEN 0
|
||||
|
||||
/* If not available, bcopy() is substituted */
|
||||
#define HAVE_MEMMOVE 0
|
||||
#define NO_MEMMOVE !HAVE_MEMMOVE
|
||||
#define HAVE_MEMCPY 0
|
||||
#define NO_MEMCPY !HAVE_MEMCPY
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bninit16.c - Provide an init function that sets things up for 16-bit
|
||||
* operation. This is a seaparate tiny file so you can compile two bn
|
||||
* packages into the library and write a custom init routine.
|
||||
*
|
||||
* Written in 1995 by Colin Plumb.
|
||||
*/
|
||||
|
||||
#include "bn.h"
|
||||
#include "bn16.h"
|
||||
|
||||
void
|
||||
bnInit(void)
|
||||
{
|
||||
bnInit_16();
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bninit32.c - Provide an init function that sets things up for 32-bit
|
||||
* operation. This is a seaparate tiny file so you can compile two bn
|
||||
* packages into the library and write a custom init routine.
|
||||
*
|
||||
* Written in 1995 by Colin Plumb.
|
||||
*/
|
||||
|
||||
#include "bn.h"
|
||||
#include "bn32.h"
|
||||
|
||||
void
|
||||
bnInit(void)
|
||||
{
|
||||
bnInit_32();
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bninit64.c - Provide an init function that sets things up for 64-bit
|
||||
* operation. This is a seaparate tiny file so you can compile two bn
|
||||
* packages into the library and write a custom init routine.
|
||||
*
|
||||
* Written in 1995 by Colin Plumb.
|
||||
*/
|
||||
|
||||
#include "bn.h"
|
||||
#include "bn64.h"
|
||||
|
||||
void
|
||||
bnInit(void)
|
||||
{
|
||||
bnInit_64();
|
||||
}
|
||||
+304
@@ -0,0 +1,304 @@
|
||||
* The organization of the BigNum Library
|
||||
|
||||
As mentioned in bn.doc, the library should compile on anything with an
|
||||
ANSI C compiler and 16 and 32-bit data types. (Non-power-of-2 word
|
||||
lengths probably wouldn't be *too* hard, but the matter is likely to
|
||||
remain academic.) However, assembly subroutines can be added in a
|
||||
great variety of ways to speed up computations.
|
||||
|
||||
It's even possible to vary the word length dynamically at run time.
|
||||
Currently, 80x86 and 680x0 assembly primitives have been written in 16
|
||||
and 32-bit forms, as not all members of these families support 32x32->64
|
||||
bit multiply. In future, 32/64 bit routines may be nice for the MIPS
|
||||
and PowerPC processors. (The SPARC has a 64-bit extension, but it still
|
||||
only produces a maximum 64-bit multiply result. The MIPS, PowerPC and
|
||||
Alpha give access to 128 bits of product.)
|
||||
|
||||
The way that this works is that the file bn.c declares a big pile of
|
||||
function pointers, and the first bnInit() call figures out which set
|
||||
of functions to point these to. The functions are named so that
|
||||
it is possible to link several sets into the same executable without
|
||||
collisions.
|
||||
|
||||
The library can store numbers in big-endian or little-endian word order,
|
||||
although the order of bytes within a word is always the platform native
|
||||
order. As long as you're using the pure C version, you can compile
|
||||
independent of the native byte ordering, but the flexibility is available
|
||||
in case assembly primitives are easier to write one way or the other.
|
||||
(In the absence of other considerations, little-endian is somewhat more
|
||||
efficient, and is the default. This is controlled by BN_XXX_ENDIAN.)
|
||||
|
||||
In fact, it would be possible to change the word order at run time,
|
||||
except that there is no naming convention to support linking in
|
||||
functions that differ only in endianness. (Which is because the
|
||||
point of doing so is unclear.)
|
||||
|
||||
The core of the library is in the files lbn??.c and bn??.c, where "??"
|
||||
is 16, 32, or 64. The 32 and 64-bit files are generated from the 16-bit
|
||||
version by a simple textual substitution. The 16-bit files are generally
|
||||
considered the master source, and the others generated from it with sed.
|
||||
|
||||
Usually, only one set of these files is used on any given platform,
|
||||
but if you want multiple word sizes, you include one for each supported
|
||||
word size. The files bninit??.c define a bnInit function for a given
|
||||
word size, which calls bnInit_??() internally. Only one of these may
|
||||
be included at a time, and multiple word sizes are handled by a more
|
||||
complex bnInit function such as the ones in bn8086.c and bn68000.c,
|
||||
which determine the word size of the processor they're running on and
|
||||
call the appropriate bnInit_??() function.
|
||||
|
||||
The file lbn.h uses <limits.h> to find the platform's available data
|
||||
types. The types are defined both as macros (BNWORD32) and as typedefs
|
||||
(bnword32) which aren't used anywhere but can come in very handy when
|
||||
using a debugger (which doesn't know about macros). Any of these may
|
||||
be overridden either on the compiler command line (cc -DBN_BIG_ENDIAN
|
||||
-DBNWORD32="unsigned long"), or from an extra include file BNINCLUDE
|
||||
defined on the command line. (cc -DBNINCLUDE=lbnmagic.h) This is the
|
||||
preferred way to specify assembly primitives.
|
||||
|
||||
So, for example, to build a 68020 version of the library, compile the
|
||||
32-bit library with -DBNINCLUDE=lbn68020.h, and compile and link in
|
||||
lbn68020.c (which is actually an assembly source file, if you look).
|
||||
|
||||
Both 16- and 32-bit 80x86 code is included in lbn8086.h and .asm. That
|
||||
code uses 16-bit large-model addressing. lbn80386.h and .asm use 32-bit
|
||||
flat-model addressing.
|
||||
|
||||
Three particularly heavily used macros defined by lbn.h are BIG(x),
|
||||
LITTLE(y) and BIGLITTLE(x,y). These expand to x (or nothing) on
|
||||
a big-endian system, and y (or nothing) on a little-endian system.
|
||||
These are used to conditionalize the rest of the code without taking
|
||||
up entire lines to say "#ifdef BN_BIG_ENDIAN", "#else" and "#endif".
|
||||
|
||||
* The lbn??.c files
|
||||
|
||||
The lbn?? file contains the low-level bignum functions. These universally
|
||||
expect their numbers to be passed to them in (buffer, length) form and
|
||||
do not attempt to extend the buffers. (In some cases, they do allocate
|
||||
temporary buffers.) The buffer pointer points to the least-significant
|
||||
end of the buffer. If the machine uses big-endian word ordering, that
|
||||
is a pointer to the end of the buffer. This is motivated by considering
|
||||
pointers to point to the boundaries between words (or bytes). If you
|
||||
consider a pointer to point to a word rather than between words, the
|
||||
pointer in the big-endian case points to the first word past the end of the
|
||||
buffer.
|
||||
|
||||
All of the primitives have names of the form lbnAddN_16, where the
|
||||
_16 is the word size. All are surrounded by "#ifndef lbnAddN_16".
|
||||
If you #define lbnAddN_16 previously (either on the command like or
|
||||
in the BNINCLUDE file), the C code will neither define *nor declare* the
|
||||
corresponding function. The declaration must be suppressed in case you
|
||||
declare it in a magic way with special calling attributes or define it as
|
||||
a macro.
|
||||
|
||||
If you wish to write an assembly primitive, lbnMulAdd1_??, which
|
||||
multiplies N words by 1 word and adds the result to N words, returning
|
||||
the carry word, is by FAR the most important function - almost all of
|
||||
the time spent performing a modular exponentiation is spent in this
|
||||
function. lbnMulSub1_??, which does the same but subtracts the product
|
||||
and returns a word of borrow, is used heavily in the division routine
|
||||
and thus by GCD and modular inverse computation.
|
||||
|
||||
These two functions are the only functions which *require* some sort
|
||||
of double-word data type, so if you define them in assembly language,
|
||||
the ?? may be the widest word your C compiler supports; otherwise, you
|
||||
must limit your implementation to half of the maximum word size. Other
|
||||
functions will, however, use a double-word data type if available.
|
||||
|
||||
Actually, there are some even simpler primitives which you can provide
|
||||
to allow double-width multiplication: mul??_ppmm, mul??_ppmma and
|
||||
mul??_ppmmaa These are expected to be defined as macros (all arguments
|
||||
are always side-effect-free lvalues), and must return two words of result
|
||||
of the computation m1*m2 + a1 + a2. It is best to define all three,
|
||||
although any that are not defined will be generated from the others in
|
||||
the obvious way. GCC's inline assembler can be used to define these.
|
||||
(The names are borrowed from the GNU MP package.)
|
||||
|
||||
There is also lbnMulN1_??, which stores the result rather than adding or
|
||||
subtracting it, but it is less critical. If it is not provided, but
|
||||
lbnMulAdd1_?? is, it will be implemented in terms of lbnMulAdd1_?? in the
|
||||
obvious way.
|
||||
|
||||
lbnDiv21_??, which divides two words by one word and returns a quotient
|
||||
and remainder, is greatly sped up by a double-word data type, macro
|
||||
definition, or assembly implementation, but has a version which will run
|
||||
without one. If your platform has a double/single divide with remainder,
|
||||
it would help to define this, and it's quite simple.
|
||||
|
||||
lbnModQ_?? (return a multi-precision number reduced modulo a "quick"
|
||||
(< 65536) modulus is used heavily by prime generation for trial division,
|
||||
but is otherwise little used.
|
||||
|
||||
Other primitives may be implemented depending on the expected usage mix.
|
||||
It is generally not worth implementing lbnAddN_?? and lbnSubN_?? unless
|
||||
you want to start learning to write assembly primitives on something
|
||||
simple; they just aren't used very much. (Of course, if you do, you'll
|
||||
probably get some improvements, in both speed and object code size, so
|
||||
it's worth keeping them in, once written.)
|
||||
|
||||
* The bn??.c files
|
||||
|
||||
While the lbn??.c files deal in words, the bn??.c files provide the
|
||||
public interface to the library and deal in bignum structures. These
|
||||
contain a buffer pointer, an allocated length, and a used length.
|
||||
The lengths are specified in words, but as long as the user doesn't go
|
||||
prying into such innards, all of the different word-size libraries
|
||||
provide the same interface; they may be exchanged at link time, or even
|
||||
at run time.
|
||||
|
||||
The bn.c file defines a large collection of function pointers and one
|
||||
function, bnInit. bnInit is responsible for setting the function pointers
|
||||
to point to the appropriate bn??.c functions. Each bn??.c file
|
||||
provides a bnInit_?? function which sets itself up; it is the job
|
||||
of bnInit to figure out which word size to use and call the appropriate
|
||||
bnInit_?? function.
|
||||
|
||||
If only one word size is in use, you may link in the file bninit??.c,
|
||||
which provides a trivial bnInit function. If multiple word sizes are
|
||||
in use, you must provide the appropriate bnInit function. See
|
||||
bn8086.c as an example.
|
||||
|
||||
For maximum portability, you may just compile and link in the files
|
||||
lbn00.c, bn00.c and bninit00.c, which determine, using the preprocessor
|
||||
at compile time, the best word size to use. (The logic is actually
|
||||
located in the file bnsize00.h, so that the three .c files cannot get out
|
||||
of sync.)
|
||||
|
||||
The bignum buffers are allocated using the memory management routines in
|
||||
lbnmem.c. These are word-size independent; they expect byte counts and
|
||||
expect the system malloc() to return suitably aligned buffers. The
|
||||
main reason for this wrapper layer is to support any customized allocators
|
||||
that the user might want to provide.
|
||||
|
||||
* Other bn*.c files
|
||||
|
||||
bnprint.c is a simple routine for printing a bignum in hex. It is
|
||||
provided in a separate file so that its calls to stdio can be eliminated
|
||||
from the link process if the capability is not needed.
|
||||
|
||||
bntest??.c is a very useful regression test if you're implementing
|
||||
assembly primitives. If it doesn't complain, you've probably
|
||||
got it right. It also does timing tests so you can see the effects
|
||||
of any changes.
|
||||
|
||||
* Other files
|
||||
|
||||
sieve.c contains some primitives which use the bignum library to perform
|
||||
sieving (trial division) of ranges of numbers looking for candidate primes.
|
||||
This involves two steps: using a sieve of Eratosthenes to generate the
|
||||
primes up to 65536, and using that to do trial division on a range of
|
||||
numbers following a larger input number. Note that this is designed
|
||||
for large numbers, greater than 65536, since there is no check to see
|
||||
if the input is one of the small primes; if it is divisible, it is assumed
|
||||
composite.
|
||||
|
||||
prime.c uses sieve.c to generate primes. It uses sieve.c to eliminate
|
||||
numbers with trivial divisors, then does strong pseudoprimality tests
|
||||
with some small bases. (Actually, the first test, to the base 2, is
|
||||
optimized a bit to be faster when it fails, which is the common case,
|
||||
but 1/8 of the time it's not a strong pseudoprimality test, so an extra,
|
||||
strong, test is done in that case.)
|
||||
|
||||
It prints progress indicators as it searches. The algorithm
|
||||
searches a range of numbers starting at a given prime, but it does
|
||||
so in a "shuffled" order, inspired by algorithm M from Knuth. (The
|
||||
random number generator to use for this is passed in; if no function
|
||||
is given, the numbers are searched in sequential order and the
|
||||
returns value will be the next prime >= the input value.)
|
||||
|
||||
germain.c operates similarly, but generates Sophie Germain primes;
|
||||
that is, primes p such that (p-1)/2 is also prime. It lacks the
|
||||
shuffling feature - searching is always sequential.
|
||||
|
||||
jacobi.c computes the Jacobi symbol between a small integer and a BigNum.
|
||||
It's currently only ever used in germain.c.
|
||||
|
||||
* Sources
|
||||
|
||||
Obviously, a key source of information was Knuth, Volume 2,
|
||||
particularly on division algorithms.
|
||||
|
||||
The greatest inspiration, however, was Arjen Lenstra's LIP
|
||||
(Large Integer Package), distributed with the RSA-129 effort.
|
||||
While very difficult to read (there is no internal documentation on
|
||||
sometimes very subtle algorithms), it showed me many useful tricks,
|
||||
notably the windowed exponentiation algorithm that saves so many
|
||||
multiplies. If you need a more general-purpose large-integer package,
|
||||
with only a minor speed penalty, the LIP package is almost certainly
|
||||
the best available. It implements a great range of efficient
|
||||
algorithms.
|
||||
|
||||
The second most important source was Torbjorn Granlund's gmp
|
||||
(GNU multi-precision) library. A number of C coding tricks were
|
||||
adapted from there. I'd like to thank Torbjorn for some useful
|
||||
discussions and letting me see his development work on GMP 2.0.
|
||||
|
||||
Antoon Bosselaers, Rene' Govaerts and Joos Vandewalle, in their CRYPTO
|
||||
'93 paper, "Comparison of three modular reduction functions", brought
|
||||
Montgomery reduction to my attention, for which I am grateful.
|
||||
|
||||
Burt Kaliski's article in the September 1993 Dr. Dobb's Journal,
|
||||
"The Z80180 and Big-number Arithmetic" pointed out the advantages (and
|
||||
terminology) of product scanning to me, although the limited
|
||||
experiments I've done have shown no improvement from trying it in C.
|
||||
|
||||
Hans Reisel's book, "Prime Numbers and Computer Methods for Factorization"
|
||||
was of great help in designing the prime testing, although some of
|
||||
the code in the book, notably the Jacobi function in Appendix 3,
|
||||
is an impressive example of why GOTO should be considered harmful.
|
||||
Papers by R. G. E. Pinch and others in Mathematics of Computation were
|
||||
also very useful.
|
||||
|
||||
Keith Geddes, Stephen Czapor and George Labahn's book "Algorithms
|
||||
for Computer Algebra", although it's mostly about polynomials,
|
||||
has some useful multi-precision math examples.
|
||||
|
||||
Philip Zimmermann's mpi (multi-precision integer) library suggested
|
||||
storing the numbers in native byte order to facilitate assembly
|
||||
subroutines, although the core modular multiplication algorithms are
|
||||
so confusing that I still don't understand them. His boasting about
|
||||
the speed of his library (albeit in 1986, before any of the above were
|
||||
available for study) also inspired me to particular effort to soundly
|
||||
beat it. It also provoked a strong reaction from me against fixed
|
||||
buffer sizes, and complaints about its implementation from Paul Leyland
|
||||
(interface) and Robert Silverman (prime searching) contributed usefully
|
||||
to the design of this current library.
|
||||
|
||||
I'd like to credit all of the above, plus the Berkeley MP package, with
|
||||
giving me difficulty finding a short, unique distinguishing prefix for
|
||||
my library's functions. (I have just, sigh, discovered that Eric Young
|
||||
is using the same prefix for *his* library, although with the
|
||||
bn_function_name convention as opposed to the bnFunctionName one.)
|
||||
|
||||
I'd like to thank the original implementor of Unix "dc" and "factor"
|
||||
for providing useful tools for verifying the correct operation of
|
||||
my library.
|
||||
|
||||
* Future
|
||||
|
||||
- Obviously, assembly-language subroutines for more platforms would
|
||||
always be nice.
|
||||
- There's a special case in the division for a two-word denominator
|
||||
which should be completed.
|
||||
- When the quotient of a division is big enough, compute an inverse of
|
||||
the high word of the denominator and use multiplication by that
|
||||
to do the divide.
|
||||
- A more efficient GCD algorithm would be nice to have.
|
||||
- More efficient modular inversion is possible. Do it.
|
||||
- Extend modular inversion to deal with non-relatively-prime
|
||||
inputs. Produce y = inv(x,m) with y * x == gcd(x,m) mod m.
|
||||
- Try some product scanning in assembly.
|
||||
- Karatsuba's multiplication and squaring speedups would be nice.
|
||||
- I *don't* think that FFT-based algorithms are worth implementing yet,
|
||||
but it's worth a little bit of study to make sure.
|
||||
- More general support for numbers in Montgomery form, so they can
|
||||
be used by more than the bowels of lbnExpMod.
|
||||
- Provide an lbnExpMod optimized for small arguments > 2, using
|
||||
conventional (or even Barrett) reduction of the multiplies, and
|
||||
Montgomery reduction of the squarings.
|
||||
- Adding a Lucas-based prime test would be a real coup, although it's
|
||||
hard to give rational reasons why it's necessary. I have a number of
|
||||
ideas on this already. Find out if norm-1 (which is faster to
|
||||
compute) suffices.
|
||||
- Split up the source code more to support linking with smaller subsets
|
||||
of the library.
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bnprint.c - Print a bignum, for debugging purposes.
|
||||
*/
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_STRING_H
|
||||
#define NO_STRING_H 0
|
||||
#endif
|
||||
#ifndef HAVE_STRINGS_H
|
||||
#define HAVE_STRINGS_H 0
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if !NO_STRING_H
|
||||
#include <string.h>
|
||||
#elif HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "bn.h"
|
||||
#include "bnprint.h"
|
||||
|
||||
#include "kludge.h"
|
||||
|
||||
int
|
||||
bnPrint(FILE *f, char const *prefix, struct BigNum const *bn,
|
||||
char const *suffix)
|
||||
{
|
||||
unsigned char temp[32]; /* How much to print on one line */
|
||||
unsigned len;
|
||||
size_t i;
|
||||
|
||||
if (prefix && fputs(prefix, f) < 0)
|
||||
return EOF;
|
||||
|
||||
len = (bnBits(bn) + 7)/ 8;
|
||||
|
||||
if (!len) {
|
||||
if (putc('0', f) < 0)
|
||||
return EOF;
|
||||
} else {
|
||||
while (len > sizeof(temp)) {
|
||||
len -= sizeof(temp);
|
||||
bnExtractBigBytes(bn, temp, len, sizeof(temp));
|
||||
for (i = 0; i < sizeof(temp); i++)
|
||||
if (fprintf(f, "%02X", temp[i]) < 0)
|
||||
return EOF;
|
||||
if (putc('\\', f) < 0 || putc('\n', f) < 0)
|
||||
return EOF;
|
||||
if (prefix) {
|
||||
i = strlen(prefix);
|
||||
while (i--)
|
||||
if (putc(' ', f) < 0)
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
bnExtractBigBytes(bn, temp, 0, len);
|
||||
for (i = 0; i < len; i++)
|
||||
if (fprintf(f, "%02X", temp[i]) < 0)
|
||||
return EOF;
|
||||
}
|
||||
return suffix ? fputs(suffix, f) : 0;
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
#ifndef BNPRINT_H
|
||||
#define BNPRINT_H
|
||||
|
||||
#include <stdio.h>
|
||||
struct BigNum;
|
||||
|
||||
int bnPrint(FILE *f, char const *prefix, struct BigNum const *bn,
|
||||
char const *suffix);
|
||||
|
||||
#endif /* BNPRINT_H */
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bnsize00.h - pick the correct machine word size to use.
|
||||
*/
|
||||
#include "lbn.h" /* Get basic information */
|
||||
|
||||
#if !BNSIZE64 && !BNSIZE32 && !BNSIZE16 && defined(BNWORD64)
|
||||
# if defined(BNWORD128) || (defined(lbnMulAdd1_64) && defined(lbnMulSub1_64))
|
||||
# define BNSIZE64 1
|
||||
# elif defined(mul64_ppmm) || defined(mul64_ppmma) || defined(mul64_ppmmaa)
|
||||
# define BNSIZE64 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !BNSIZE64 && !BNSIZE32 && !BNSIZE16 && defined(BNWORD32)
|
||||
# if defined(BNWORD64) || (defined(lbnMulAdd1_32) && defined(lbnMulSub1_32))
|
||||
# define BNSIZE32 1
|
||||
# elif defined(mul32_ppmm) || defined(mul32_ppmma) || defined(mul32_ppmmaa)
|
||||
# define BNSIZE32 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !BNSIZE64 && !BNSIZE32 && !BNSIZE16 && defined(BNWORD16)
|
||||
# if defined(BNWORD32) || (defined(lbnMulAdd1_16) && defined(lbnMulSub1_16))
|
||||
# define BNSIZE16 1
|
||||
# elif defined(mul16_ppmm) || defined(mul16_ppmma) || defined(mul16_ppmmaa)
|
||||
# define BNSIZE16 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !BNSIZE64 && !BNSIZE32 && !BNSIZE16
|
||||
#error Unable to find a viable word size to compile bignum library.
|
||||
#endif
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* bntest00.c - auto-size-detecting bntest??.c file.
|
||||
*
|
||||
* Written in 1995 by Colin Plumb.
|
||||
*/
|
||||
|
||||
#include "bnsize00.h"
|
||||
|
||||
#if BNSIZE64
|
||||
|
||||
#include "bntest64.c"
|
||||
|
||||
#elif BNSIZE32
|
||||
|
||||
#include "bntest32.c"
|
||||
|
||||
#else /* BNSIZE16 */
|
||||
|
||||
#include "bntest16.c"
|
||||
|
||||
#endif
|
||||
+804
@@ -0,0 +1,804 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* Test driver for low-level bignum library (16-bit version).
|
||||
* This access the low-level library directly. It is NOT an example of
|
||||
* how to program with the library normally! By accessing the library
|
||||
* at a low level, it is possible to exercise the smallest components
|
||||
* and thus localize bugs more accurately. This is especially useful
|
||||
* when writing assembly-language primitives.
|
||||
*
|
||||
* This also does timing tests on modular exponentiation. Modular
|
||||
* exponentiation is so computationally expensive that the fact that this
|
||||
* code omits one level of interface glue has no perceptible effect on
|
||||
* the results.
|
||||
*/
|
||||
#include "zrtp.h"
|
||||
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
#define _ZTU_ "bntest"
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_STDLIB_H
|
||||
#define NO_STDLIB_H 0
|
||||
#endif
|
||||
#ifndef NO_STRING_H
|
||||
#define NO_STRING_H 0
|
||||
#endif
|
||||
#ifndef HAVE_STRINGS_H
|
||||
#define HAVE_STRINGS_H 0
|
||||
#endif
|
||||
#ifndef NEED_MEMORY_H
|
||||
#define NEED_MEMORY_H 0
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if !NO_STDLIB_H
|
||||
#include <stdlib.h> /* For strtol */
|
||||
#else
|
||||
long strtol(const char *, char **, int);
|
||||
#endif
|
||||
|
||||
#if !NO_STRING_H
|
||||
#include <string.h> /* For memcpy */
|
||||
#elif HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#if NEED_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#include "lbn16.h"
|
||||
#include "kludge.h"
|
||||
|
||||
#if BNYIELD
|
||||
int (*bnYield)(void) = 0;
|
||||
#endif
|
||||
|
||||
/* Work with up to 2048-bit numbers */
|
||||
#define MAXBITS 3072
|
||||
#define SIZE (MAXBITS/16 + 1)
|
||||
|
||||
/* Additive congruential random number generator, x[i] = x[i-24] + x[i-55] */
|
||||
static BNWORD16 randp[55];
|
||||
static BNWORD16 *randp1 = randp, *randp2 = randp+24;
|
||||
|
||||
static BNWORD16
|
||||
rand16(void)
|
||||
{
|
||||
if (++randp2 == randp+55) {
|
||||
randp2 = randp;
|
||||
randp1++;
|
||||
} else if (++randp1 == randp+55) {
|
||||
randp1 = randp;
|
||||
}
|
||||
|
||||
return *randp1 += *randp2;
|
||||
}
|
||||
|
||||
/*
|
||||
* CRC-3_2: x^3_2+x^26+x^23+x^22+x^1_6+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
|
||||
*
|
||||
* The additive congruential RNG is seeded with a single integer,
|
||||
* which is shuffled with a CRC polynomial to generate the initial
|
||||
* table values. The Polynomial is the same size as the words being
|
||||
* used.
|
||||
*
|
||||
* Thus, in the various versions of this library, we actually use this
|
||||
* polynomial as-is, this polynomial mod x^17, and this polynomial with
|
||||
* the leading coefficient deleted and replaced with x^6_4. As-is,
|
||||
* it's irreducible, so it has a long period. Modulo x^17, it factors as
|
||||
* (x^4+x^3+x^2+x+1) * (x^12+x^11+x^8+x^7+x^6+x^5+x^4+x^3+1),
|
||||
* which still has a large enough period (4095) for the use it's put to.
|
||||
* With the leading coefficient moved up, it factors as
|
||||
* (x^50+x^49+x^48+x^47+x^46+x^43+x^41+x^40+x^38+x^37+x^36+x^35+x^34+x^33+
|
||||
* x^31+x^30+x^29+x^28+x^27+x^25+x^23+x^18+x^1_6+x^15+x^14+x^13+x^11+x^9+
|
||||
* x^8+x^7+x^6+x^5+x^3+x^2+1)*(x^11+x^10+x^9+x^5+x^4+x^3+1)*(x^3+x+1),
|
||||
* which definitely has a long enough period to serve for initialization.
|
||||
*
|
||||
* The effort put into this PRNG is kind of unwarranted given the trivial
|
||||
* use it's being put to, but oh, well. It does have the nice advantage
|
||||
* of producing numbers that are portable between platforms, so if there's
|
||||
* a problem with one platform, you can compare all the intermediate
|
||||
* results with another platform.
|
||||
*/
|
||||
#define POLY (BNWORD16)0x04c11db7
|
||||
|
||||
static void
|
||||
srand16(BNWORD16 seed)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 55; i++) {
|
||||
for (j = 0; j < 16; j++)
|
||||
if (seed >> (16-1))
|
||||
seed = (seed << 1) ^ POLY;
|
||||
else
|
||||
seed <<= 1;
|
||||
randp[i] = seed;
|
||||
}
|
||||
for (i = 0; i < 3*55; i ++)
|
||||
rand16();
|
||||
}
|
||||
|
||||
static void
|
||||
randnum(BNWORD16 *num, unsigned len)
|
||||
{
|
||||
while (len--)
|
||||
BIGLITTLE(*--num,*num++) = rand16();
|
||||
}
|
||||
|
||||
static void
|
||||
bnprint16(BNWORD16 const *num, unsigned len)
|
||||
{
|
||||
BIGLITTLE(num -= len, num += len);
|
||||
|
||||
while (len--)
|
||||
ZRTP_LOG(3, (_ZTU_, "%0*lX", 16/4, (unsigned long)BIGLITTLE(*num++,*--num)));
|
||||
}
|
||||
|
||||
static void
|
||||
bnput16(char const *prompt, BNWORD16 const *num, unsigned len)
|
||||
{
|
||||
fputs(prompt, stdout);
|
||||
bnprint16(num, len);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* One of our tests uses a known prime. The following selections were
|
||||
* taken from the tables at the end of Hans Reisel's "Prime Numbers and
|
||||
* Computer Methods for Factorization", second edition - an excellent book.
|
||||
* (ISBN 0-8176-3743-5 ISBN 3-7323-3743-5)
|
||||
*/
|
||||
#if 0
|
||||
/* P31=1839605 17620282 38179967 87333633 from the factors of 3^256+2^256 */
|
||||
static unsigned char const prime[] = {
|
||||
0x17,0x38,0x15,0xBC,0x8B,0xBB,0xE9,0xEF,0x01,0xA9,0xFD,0x3A,0x01
|
||||
};
|
||||
#elif 0
|
||||
/* P48=40554942 04557502 46193993 36199835 4279613_2 73199617 from the same */
|
||||
static unsigned char const prime[] = {
|
||||
0x47,0x09,0x77,0x07,0xCF,0xFD,0xE1,0x54,0x3E,0x24,
|
||||
0xF7,0xF1,0x7A,0x3E,0x91,0x51,0xCC,0xC7,0xD4,0x01
|
||||
};
|
||||
#elif 0
|
||||
/*
|
||||
* P75 = 450 55287320 97906895 47687014 5808213_2
|
||||
* 05219565 99525911 39967932 66003_258 91979521
|
||||
* from the factors of 4^128+3+128
|
||||
* (The "026" and "062" are to prevent a Bad String from appearing here.)
|
||||
*/
|
||||
static unsigned char const prime[] = {
|
||||
0xFF,0x00,0xFF,0x00,0xFF,0x01,0x06,0x4F,0xF8,0xED,
|
||||
0xA3,0x37,0x23,0x2A,0x04,0xEA,0xF9,0x5F,0x30,0x4C,
|
||||
0xAE,0xCD, 026,0x4E, 062,0x10,0x04,0x7D,0x0D,0x79,
|
||||
0x01
|
||||
};
|
||||
#else
|
||||
/*
|
||||
* P75 = 632 85659796 45277755 9123_2190 67300940
|
||||
* 51844953 78793489 59444670 35675855 57440257
|
||||
* from the factors of 5^128+4^128
|
||||
* (The "026" is to prevent a Bad String from appearing here.)
|
||||
*/
|
||||
static unsigned char const prime[] = {
|
||||
0x01,0x78,0x4B,0xA5,0xD3,0x30,0x03,0xEB,0x73,0xE6,
|
||||
0x0F,0x4E,0x31,0x7D,0xBC,0xE2,0xA0,0xD4, 026,0x3F,
|
||||
0x3C,0xEA,0x1B,0x44,0xAD,0x39,0xE7,0xE5,0xAD,0x19,
|
||||
0x67,0x01
|
||||
};
|
||||
#endif
|
||||
|
||||
static int
|
||||
usage(char const *name)
|
||||
{
|
||||
ZRTP_LOG(3, (_ZTU_, "Usage: %s [modbits [expbits [expbits2]]"
|
||||
"With no arguments, just runs test suite. If modbits is given, runs\n"
|
||||
"quick validation test, then runs timing tests of modular exponentiation.\n"
|
||||
"If expbits is given, it is used as an exponent size, otherwise it defaults\n"
|
||||
"to the same as modbits. If expbits2 is given it is used as the second\n"
|
||||
"exponent size in the double-exponentiation tests, otherwise it defaults\n"
|
||||
"to the same as expbits. All are limited to %u bits.\n",
|
||||
name, (unsigned)MAXBITS));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* for libzrtp support */
|
||||
int
|
||||
bntest_main(int argc, char **argv)
|
||||
{
|
||||
unsigned i, j, k, l, m;
|
||||
int z;
|
||||
BNWORD16 t, carry, borrow;
|
||||
BNWORD16 a[SIZE], b[SIZE], c[SIZE], d[SIZE];
|
||||
BNWORD16 e[SIZE], f[SIZE];
|
||||
static BNWORD16 entries[sizeof(prime)*2][(sizeof(prime)-1)/(16/8)+1];
|
||||
BNWORD16 *array[sizeof(prime)*2];
|
||||
unsigned long modbits = 0, expbits = 0, expbits2 = 0;
|
||||
char *p;
|
||||
#define A BIGLITTLE((a+SIZE),a)
|
||||
#define B BIGLITTLE((b+SIZE),b)
|
||||
#define C BIGLITTLE((c+SIZE),c)
|
||||
#define D BIGLITTLE((d+SIZE),d)
|
||||
#define E BIGLITTLE((e+SIZE),e)
|
||||
#define F BIGLITTLE((f+SIZE),f)
|
||||
static unsigned const smallprimes[] = {
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43
|
||||
};
|
||||
|
||||
/* Set up array for precomputed modexp */
|
||||
for (i = 0; i < sizeof(array)/sizeof(*array); i++)
|
||||
array[i] = entries[i] BIG(+ SIZE);
|
||||
|
||||
srand16(1);
|
||||
|
||||
puts(BIGLITTLE("Big-endian machine","Little-endian machine"));
|
||||
|
||||
if (argc >= 2) {
|
||||
modbits = strtoul(argv[1], &p, 0);
|
||||
if (!modbits || *p) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Invalid modbits: %s", argv[1]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if (argc >= 3) {
|
||||
expbits = strtoul(argv[2], &p, 0);
|
||||
if (!expbits || *p) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Invalid expbits: %s", argv[2]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
expbits2 = expbits;
|
||||
}
|
||||
if (argc >= 4) {
|
||||
expbits2 = strtoul(argv[3], &p, 0);
|
||||
if (!expbits2 || *p) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Invalid expbits2: %s", argv[3]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if (argc >= 5) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Too many arguments: %s", argv[4]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
/* B is a nice not-so-little prime */
|
||||
lbnInsertBigBytes_16(B, prime, 0, sizeof(prime));
|
||||
((unsigned char *)c)[0] = 0;
|
||||
lbnInsertBigBytes_16(B, (unsigned char *)c, sizeof(prime), 1);
|
||||
lbnExtractBigBytes_16(B, (unsigned char *)c, 0, sizeof(prime)+1);
|
||||
i = (sizeof(prime)-1)/(16/8)+1; /* Size of array in words */
|
||||
if (((unsigned char *)c)[0] ||
|
||||
memcmp(prime, (unsigned char *)c+1, sizeof(prime)) != 0)
|
||||
{
|
||||
ZRTP_LOG(3, (_ZTU_, "Input != output!: "));
|
||||
for (k = 0; k < sizeof(prime); k++)
|
||||
ZRTP_LOG(3, (_ZTU_, "%02X ", prime[k]));
|
||||
putchar('\n');
|
||||
for (k = 0; k < sizeof(prime)+1; k++)
|
||||
ZRTP_LOG(3, (_ZTU_, "%02X ", ((unsigned char *)c)[k]));
|
||||
putchar('\n');
|
||||
bnput16("p = ", B, i);
|
||||
|
||||
}
|
||||
|
||||
/* Timing test code - only if requested on the command line */
|
||||
if (modbits) {
|
||||
#if CLOCK_AVAIL
|
||||
timetype start, stop;
|
||||
unsigned long cursec, expsec, twoexpsec, dblexpsec;
|
||||
unsigned curms, expms, twoexpms, dblexpms;
|
||||
|
||||
expsec = twoexpsec = dblexpsec = 0;
|
||||
expms = twoexpms = dblexpms = 0;
|
||||
#endif
|
||||
|
||||
lbnCopy_16(C,B,i);
|
||||
lbnSub1_16(C,i,1); /* C is exponent: p-1 */
|
||||
|
||||
puts("Testing modexp with a known prime. "
|
||||
"All results should be 1.");
|
||||
bnput16("p = ", B, i);
|
||||
bnput16("p-1 = ", C, i);
|
||||
z = lbnTwoExpMod_16(A, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput16("2^(p-1) mod p = ", A, i);
|
||||
for (j = 0; j < 10; j++) {
|
||||
randnum(A,i);
|
||||
(void)lbnDiv_16(D,A,i,B,i);
|
||||
|
||||
bnput16("a = ", A, i);
|
||||
z = lbnExpMod_16(D, A, i, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput16("a^(p-1) mod p = ", D, i);
|
||||
|
||||
z = lbnBasePrecompBegin_16(array, (sizeof(prime)*8+4)/5, 5,
|
||||
A, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
BIGLITTLE(D[-1],D[0]) = -1;
|
||||
z = lbnBasePrecompExp_16(D, (BNWORD16 const * const *)array,
|
||||
5, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput16("a^(p-1) mod p = ", D, i);
|
||||
|
||||
for (k = 0; k < 5; k++) {
|
||||
randnum(E,i);
|
||||
bnput16("e = ", E, i);
|
||||
z = lbnExpMod_16(D, A, i, E, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput16("a^e mod p = ", D, i);
|
||||
z = lbnBasePrecompExp_16(D, (BNWORD16 const * const *)array,
|
||||
5, E, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput16("a^e mod p = ", D, i);
|
||||
}
|
||||
}
|
||||
|
||||
ZRTP_LOG(3, (_ZTU_, "\n"
|
||||
"Timing exponentiations modulo a %d-bit modulus, i.e.\n"
|
||||
"2^<%d> mod <%d> bits, <%d>^<%d> mod <%d> bits and\n"
|
||||
"<%d>^<%d> * <%d>^<%d> mod <%d> bits",
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)modbits, (int)expbits, (int)modbits, (int)expbits2,
|
||||
(int)modbits));
|
||||
|
||||
i = ((int)modbits-1)/16+1;
|
||||
k = ((int)expbits-1)/16+1;
|
||||
l = ((int)expbits2-1)/16+1;
|
||||
for (j = 0; j < 25; j++) {
|
||||
randnum(A,i); /* Base */
|
||||
randnum(B,k); /* Exponent */
|
||||
randnum(C,i); /* Modulus */
|
||||
randnum(D,i); /* Base2 */
|
||||
randnum(E,l); /* Exponent */
|
||||
/* Clip bases and mod to appropriate number of bits */
|
||||
t = ((BNWORD16)2<<((modbits-1)%16)) - 1;
|
||||
*(BIGLITTLE(A-i,A+i-1)) &= t;
|
||||
*(BIGLITTLE(C-i,C+i-1)) &= t;
|
||||
*(BIGLITTLE(D-i,D+i-1)) &= t;
|
||||
/* Make modulus large (msbit set) and odd (lsbit set) */
|
||||
*(BIGLITTLE(C-i,C+i-1)) |= (t >> 1) + 1;
|
||||
BIGLITTLE(C[-1],C[0]) |= 1;
|
||||
|
||||
/* Clip exponent to appropriate number of bits */
|
||||
t = ((BNWORD16)2<<((expbits-1)%16)) - 1;
|
||||
*(BIGLITTLE(B-k,B+k-1)) &= t;
|
||||
/* Make exponent large (msbit set) */
|
||||
*(BIGLITTLE(B-k,B+k-1)) |= (t >> 1) + 1;
|
||||
/* The same for exponent 2 */
|
||||
t = ((BNWORD16)2<<((expbits2-1)%16)) - 1;
|
||||
*(BIGLITTLE(E-l,E+l-1)) &= t;
|
||||
*(BIGLITTLE(E-l,E+l-1)) |= (t >> 1) + 1;
|
||||
|
||||
m = lbnBits_16(A, i);
|
||||
if (m > (unsigned)modbits) {
|
||||
bnput16("a = ", a, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be <= %d", m, (int)modbits));
|
||||
}
|
||||
m = lbnBits_16(B, k);
|
||||
if (m != (unsigned)expbits) {
|
||||
bnput16("b = ", b, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be %d", m, (int)expbits));
|
||||
}
|
||||
m = lbnBits_16(C, i);
|
||||
if (m != (unsigned)modbits) {
|
||||
bnput16("c = ", c, k);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be %d", m, (int)modbits));
|
||||
}
|
||||
m = lbnBits_16(D, i);
|
||||
if (m > (unsigned)modbits) {
|
||||
bnput16("d = ", d, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be <= %d", m, (int)modbits));
|
||||
}
|
||||
m = lbnBits_16(E, l);
|
||||
if (m != (unsigned)expbits2) {
|
||||
bnput16("e = ", e, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be %d", m, (int)expbits2));
|
||||
}
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&start);
|
||||
#endif
|
||||
z = lbnTwoExpMod_16(A, B, k, C, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
twoexpsec += cursec = sec(stop);
|
||||
twoexpms += curms = msec(stop);
|
||||
|
||||
ZRTP_LOG(3, (_ZTU_, "2^<%d>:%4lu.%03u ", (int)expbits, cursec, curms));
|
||||
#else
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d> ", (int)modbits, (int)expbits));
|
||||
#endif
|
||||
fflush(stdout);
|
||||
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&start);
|
||||
#endif
|
||||
z = lbnExpMod_16(A, A, i, B, k, C, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
expsec += cursec = sec(stop);
|
||||
expms += curms = msec(stop);
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d>:%4lu.%03u ",(int)modbits, (int)expbits, cursec, curms));
|
||||
fflush(stdout);
|
||||
|
||||
gettime(&start);
|
||||
z = lbnDoubleExpMod_16(D, A, i, B, k, D, i, E, l,C,i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
dblexpsec += cursec = sec(stop);
|
||||
dblexpms += curms = msec(stop);
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d>*<%d>^<%d>:%4lu.%03u",
|
||||
(int)modbits, (int)expbits,
|
||||
(int)modbits, (int)expbits2,
|
||||
cursec, curms));
|
||||
#else
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d>*<%d>^<%d>",
|
||||
(int)modbits, (int)expbits,
|
||||
(int)modbits, (int)expbits2));
|
||||
#endif
|
||||
}
|
||||
#if CLOCK_AVAIL
|
||||
twoexpms += (twoexpsec % j) * 1000;
|
||||
ZRTP_LOG(3, (_ZTU_, "2^<%d> mod <%d> bits AVERAGE: %4lu.%03u s",
|
||||
(int)expbits, (int)modbits, twoexpsec/j, twoexpms/j));
|
||||
expms += (expsec % j) * 1000;
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d> mod <%d> bits AVERAGE: %4lu.%03u s",
|
||||
(int)modbits, (int)expbits, (int)modbits, expsec/j, expms/j));
|
||||
dblexpms += (dblexpsec % j) * 1000;
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d> * <%d>^<%d> mod <%d> bits AVERAGE:"
|
||||
" %4lu.%03u s",
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)expbits2,
|
||||
(int)modbits, dblexpsec/j, dblexpms/j));
|
||||
|
||||
putchar('\n');
|
||||
#endif
|
||||
}
|
||||
|
||||
puts("Beginning 1000 interations of sanity checking.\n"
|
||||
"Any output indicates a bug. No output is very strong\n"
|
||||
"evidence that all the important low-level bignum routines\n"
|
||||
"are working properly.\n");
|
||||
|
||||
/*
|
||||
* If you change this loop to have an iteration 0, all results
|
||||
* are primted on that iteration. Useful to see what's going
|
||||
* on in case of major wierdness, but it produces a *lot* of
|
||||
* output.
|
||||
*/
|
||||
#if (ZRTP_PLATFORM == ZP_WINCE) || (ZRTP_PLATFORM == ZP_SYMBIAN)
|
||||
for (j = 1; j <= 20; j++) {
|
||||
#else
|
||||
for (j = 1; j <= 1000; j++) {
|
||||
#endif
|
||||
/* Do the tests for lots of different number sizes. */
|
||||
for (i = 1; i <= SIZE/2; i++) {
|
||||
/* Make a random number i words long */
|
||||
do {
|
||||
randnum(A,i);
|
||||
} while (lbnNorm_16(A,i) < i);
|
||||
|
||||
/* Checl lbnCmp - does a == a? */
|
||||
if (lbnCmp_16(A,A,i) || !j) {
|
||||
bnput16("a = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> a) = %d", lbnCmp_16(A,A,i)));
|
||||
}
|
||||
|
||||
memcpy(c, a, sizeof(a));
|
||||
|
||||
/* Check that the difference, after copy, is good. */
|
||||
if (lbnCmp_16(A,C,i) || !j) {
|
||||
bnput16("a = ", A, i);
|
||||
bnput16("c = ", C, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_16(A,C,i)));
|
||||
}
|
||||
|
||||
/* Generate a non-zero random t */
|
||||
do {
|
||||
t = rand16();
|
||||
} while (!t);
|
||||
|
||||
/*
|
||||
* Add t to A. Check that:
|
||||
* - lbnCmp works in both directions, and
|
||||
* - A + t is greater than A. If there was a carry,
|
||||
* the result, less the carry, should be *less*
|
||||
* than A.
|
||||
*/
|
||||
carry = lbnAdd1_16(A,i,t);
|
||||
if (lbnCmp_16(A,C,i) + lbnCmp_16(C,A,i) != 0 ||
|
||||
lbnCmp_16(A,C,i) != (carry ? -1 : 1) || !j)
|
||||
{
|
||||
bnput16("c = ", C, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "t = %lX", (unsigned long)t));
|
||||
bnput16("a = c+t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "carry = %lX", (unsigned long)carry));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_16(A,C,i)));
|
||||
ZRTP_LOG(3, (_ZTU_, "(c <=> a) = %d", lbnCmp_16(C,A,i)));
|
||||
}
|
||||
|
||||
/* Subtract t again */
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnSub1_16(A,i,t);
|
||||
|
||||
if (carry != borrow || lbnCmp_16(A,C,i) || !j) {
|
||||
bnput16("a = ", C, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "t = %lX", (unsigned long)t));
|
||||
lbnAdd1_16(A,i,t);
|
||||
bnput16("a += t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Carry = %lX", (unsigned long)carry));
|
||||
lbnSub1_16(A,i,t);
|
||||
bnput16("a -= t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Borrow = %lX", (unsigned long)borrow));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_16(A,C,i)));
|
||||
}
|
||||
|
||||
/* Generate a random B */
|
||||
do {
|
||||
randnum(B,i);
|
||||
} while (lbnNorm_16(B,i) < i);
|
||||
|
||||
carry = lbnAddN_16(A,B,i);
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnSubN_16(A,B,i);
|
||||
|
||||
if (carry != borrow || lbnCmp_16(A,C,i) || !j) {
|
||||
bnput16("a = ", C, i);
|
||||
bnput16("b = ", B, i);
|
||||
bnput16("a += b = ", D, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Carry = %lX", (unsigned long)carry));
|
||||
bnput16("a -= b = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Borrow = %lX", (unsigned long)borrow));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_16(A,C,i)));
|
||||
}
|
||||
|
||||
/* D = B * t */
|
||||
lbnMulN1_16(D, B, i, t);
|
||||
memcpy(e, d, sizeof(e));
|
||||
/* D = A + B * t, "carry" is overflow */
|
||||
borrow = *(BIGLITTLE(D-i-1,D+i)) += lbnAddN_16(D,A,i);
|
||||
|
||||
carry = lbnMulAdd1_16(A, B, i, t);
|
||||
|
||||
/* Did MulAdd get the same answer as mul then add? */
|
||||
if (carry != borrow || lbnCmp_16(A, D, i) || !j) {
|
||||
bnput16("a = ", C, i);
|
||||
bnput16("b = ", B, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "t = %lX", (unsigned long)t));
|
||||
bnput16("e = b * t = ", E, i+1);
|
||||
bnput16(" a + e = ", D, i+1);
|
||||
bnput16("a + b * t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "carry = %lX", (unsigned long)carry));
|
||||
}
|
||||
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnMulSub1_16(A, B, i, t);
|
||||
|
||||
/* Did MulSub perform the inverse of MulAdd */
|
||||
if (carry != borrow || lbnCmp_16(A,C,i) || !j) {
|
||||
bnput16(" a = ", C, i);
|
||||
bnput16(" b = ", B, i);
|
||||
bnput16("a += b*t = ", D, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Carry = %lX", (unsigned long)carry));
|
||||
bnput16("a -= b*t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Borrow = %lX", (unsigned long)borrow));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_16(A,C,i)));
|
||||
bnput16("b*t = ", E, i+1);
|
||||
}
|
||||
/* At this point we're done with t, so it's scratch */
|
||||
#if 0
|
||||
/* Extra debug code */
|
||||
lbnMulN1_16(C, A, i, BIGLITTLE(B[-1],B[0]));
|
||||
bnput16("a * b[0] = ", C, i+1);
|
||||
for (k = 1; k < i; k++) {
|
||||
carry = lbnMulAdd1_16(BIGLITTLE(C-k,C+k), A, i,
|
||||
*(BIGLITTLE(B-1-k,B+k)));
|
||||
*(BIGLITTLE(C-i-k,C+i+k)) = carry;
|
||||
bnput16("a * b[x] = ", C, i+k+1);
|
||||
}
|
||||
|
||||
lbnMulN1_16(D, B, i, BIGLITTLE(A[-1],A[0]));
|
||||
bnput16("b * a[0] = ", D, i+1);
|
||||
for (k = 1; k < i; k++) {
|
||||
carry = lbnMulAdd1_16(BIGLITTLE(D-k,D+k), B, i,
|
||||
*(BIGLITTLE(A-1-k,A+k)));
|
||||
*(BIGLITTLE(D-i-k,D+i+k)) = carry;
|
||||
bnput16("b * a[x] = ", D, i+k+1);
|
||||
}
|
||||
#endif
|
||||
/* Does Mul work both ways symmetrically */
|
||||
lbnMul_16(C,A,i,B,i);
|
||||
lbnMul_16(D,B,i,A,i);
|
||||
if (lbnCmp_16(C,D,i+i) || !j) {
|
||||
bnput16("a = ", A, i);
|
||||
bnput16("b = ", B, i);
|
||||
bnput16("a * b = ", C, i+i);
|
||||
bnput16("b * a = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a*b <=> b*a) = %d", lbnCmp_16(C,D,i+i)));
|
||||
}
|
||||
/* Check multiplication modulo some small things */
|
||||
/* 30030 = 2*3*5*11*13 */
|
||||
k = lbnModQ_16(C, i+i, 30030);
|
||||
for (l = 0;
|
||||
l < sizeof(smallprimes)/sizeof(*smallprimes);
|
||||
l++)
|
||||
{
|
||||
m = smallprimes[l];
|
||||
t = lbnModQ_16(C, i+i, m);
|
||||
carry = lbnModQ_16(A, i, m);
|
||||
borrow = lbnModQ_16(B, i, m);
|
||||
if (t != (carry * borrow) % m) {
|
||||
bnput16("a = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a mod %u = %u", m, (unsigned)carry));
|
||||
bnput16("b = ", B, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "b mod %u = %u", m, (unsigned)borrow));
|
||||
bnput16("a*b = ", C, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a*b mod %u = %u", m, (unsigned)t));
|
||||
ZRTP_LOG(3, (_ZTU_, "expected %u", (unsigned)((carry*borrow)%m)));
|
||||
}
|
||||
/* Verify that (C % 30030) % m == C % m */
|
||||
if (m <= 13 && t != k % m) {
|
||||
ZRTP_LOG(3, (_ZTU_, "c mod 30030 = %u mod %u= %u", k, m, k%m));
|
||||
ZRTP_LOG(3, (_ZTU_, "c mod %u = %u", m, (unsigned)t));
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate an F less than A and B */
|
||||
do {
|
||||
randnum(F,i);
|
||||
} while (lbnCmp_16(F,A,i) >= 0 ||
|
||||
lbnCmp_16(F,B,i) >= 0);
|
||||
|
||||
/* Add F to D (remember, D = A*B) */
|
||||
lbnAdd1_16(BIGLITTLE(D-i,D+i), i, lbnAddN_16(D, F, i));
|
||||
memcpy(c, d, sizeof(d));
|
||||
|
||||
/*
|
||||
* Divide by A and check that quotient and remainder
|
||||
* match (remainder should be F, quotient should be B)
|
||||
*/
|
||||
t = lbnDiv_16(E,C,i+i,A,i);
|
||||
if (t || lbnCmp_16(E,B,i) || lbnCmp_16(C, F, i) || !j) {
|
||||
bnput16("a = ", A, i);
|
||||
bnput16("b = ", B, i);
|
||||
bnput16("f = ", F, i);
|
||||
bnput16("a * b + f = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "qhigh = %lX", (unsigned long)t));
|
||||
bnput16("(a*b+f) / a = ", E, i);
|
||||
bnput16("(a*b+f) % a = ", C, i);
|
||||
}
|
||||
|
||||
memcpy(c, d, sizeof(d));
|
||||
|
||||
/* Divide by B and check similarly */
|
||||
t = lbnDiv_16(E,C,i+i,B,i);
|
||||
if (lbnCmp_16(E,A,i) || lbnCmp_16(C, F, i) || !j) {
|
||||
bnput16("a = ", A, i);
|
||||
bnput16("b = ", B, i);
|
||||
bnput16("f = ", F, i);
|
||||
bnput16("a * b + f = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "qhigh = %lX", (unsigned long)t));
|
||||
bnput16("(a*b+f) / b = ", E, i);
|
||||
bnput16("(a*b+f) % b = ", C, i);
|
||||
}
|
||||
|
||||
/* Check that A*A == A^2 */
|
||||
lbnMul_16(C,A,i,A,i);
|
||||
lbnSquare_16(D,A,i);
|
||||
if (lbnCmp_16(C,D,i+i) || !j) {
|
||||
bnput16("a*a = ", C, i+i);
|
||||
bnput16("a^2 = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a * a == a^2) = %d", lbnCmp_16(C,D,i+i)));
|
||||
}
|
||||
|
||||
/* Compute a GCD */
|
||||
lbnCopy_16(C,A,i);
|
||||
lbnCopy_16(D,B,i);
|
||||
z = lbnGcd_16(C, i, D, i, &k);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
/* z = 1 if GCD in D; z = 0 if GCD in C */
|
||||
|
||||
/* Approximate check that the GCD came out right */
|
||||
for (l = 0;
|
||||
l < sizeof(smallprimes)/sizeof(*smallprimes);
|
||||
l++)
|
||||
{
|
||||
m = smallprimes[l];
|
||||
t = lbnModQ_16(z ? D : C, k, m);
|
||||
carry = lbnModQ_16(A, i, m);
|
||||
borrow = lbnModQ_16(B, i, m);
|
||||
if (!t != (!carry && !borrow)) {
|
||||
bnput16("a = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a mod %u = %u", m, (unsigned)carry));
|
||||
bnput16("b = ", B, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "b mod %u = %u", m, (unsigned)borrow));
|
||||
bnput16("gcd(a,b) = ", z ? D : C, k);
|
||||
ZRTP_LOG(3, (_ZTU_, "gcd(a,b) mod %u = %u", m, (unsigned)t));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Do some Montgomery operations
|
||||
* Start with A > B, and also place a copy of B into C.
|
||||
* Then make A odd so it can be a Montgomery modulus.
|
||||
*/
|
||||
if (lbnCmp_16(A, B, i) < 0) {
|
||||
memcpy(c, a, sizeof(c));
|
||||
memcpy(a, b, sizeof(a));
|
||||
memcpy(b, c, sizeof(b));
|
||||
} else {
|
||||
memcpy(c, b, sizeof(c));
|
||||
}
|
||||
BIGLITTLE(A[-1],A[0]) |= 1;
|
||||
|
||||
/* Convert to and from */
|
||||
lbnToMont_16(B, i, A, i);
|
||||
lbnFromMont_16(B, A, i);
|
||||
if (lbnCmp_16(B, C, i)) {
|
||||
memcpy(b, c, sizeof(c));
|
||||
bnput16("mod = ", A, i);
|
||||
bnput16("input = ", B, i);
|
||||
lbnToMont_16(B, i, A, i);
|
||||
bnput16("mont = ", B, i);
|
||||
lbnFromMont_16(B, A, i);
|
||||
bnput16("output = ", B, i);
|
||||
}
|
||||
/* E = B^5 (mod A), no Montgomery ops */
|
||||
lbnSquare_16(E, B, i);
|
||||
(void)lbnDiv_16(BIGLITTLE(E-i,E+i),E,i+i,A,i);
|
||||
lbnSquare_16(D, E, i);
|
||||
(void)lbnDiv_16(BIGLITTLE(D-i,D+i),D,i+i,A,i);
|
||||
lbnMul_16(E, D, i, B, i);
|
||||
(void)lbnDiv_16(BIGLITTLE(E-i,E+i),E,i+i,A,i);
|
||||
|
||||
/* D = B^5, using ExpMod */
|
||||
BIGLITTLE(F[-1],F[0]) = 5;
|
||||
z = lbnExpMod_16(D, B, i, F, 1, A, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
if (lbnCmp_16(D, E, i) || !j) {
|
||||
bnput16("mod = ", A, i);
|
||||
bnput16("input = ", B, i);
|
||||
bnput16("input^5 = ", E, i);
|
||||
bnput16("input^5 = ", D, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a>b (x <=> y) = %d", lbnCmp_16(D,E,i)));
|
||||
}
|
||||
/* TODO: Test lbnTwoExpMod, lbnDoubleExpMod */
|
||||
} /* for (i) */
|
||||
ZRTP_LOG(3, (_ZTU_, "\r%d ", j));
|
||||
fflush(stdout);
|
||||
} /* for (j) */
|
||||
ZRTP_LOG(3, (_ZTU_, "%d iterations of up to %d 16-bit words completed.", j-1, i-1));
|
||||
return 0;
|
||||
nomem:
|
||||
ZRTP_LOG(3, (_ZTU_, "Out of memory"));
|
||||
return 1;
|
||||
}
|
||||
+804
@@ -0,0 +1,804 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* Test driver for low-level bignum library (32-bit version).
|
||||
* This access the low-level library directly. It is NOT an example of
|
||||
* how to program with the library normally! By accessing the library
|
||||
* at a low level, it is possible to exercise the smallest components
|
||||
* and thus localize bugs more accurately. This is especially useful
|
||||
* when writing assembly-language primitives.
|
||||
*
|
||||
* This also does timing tests on modular exponentiation. Modular
|
||||
* exponentiation is so computationally expensive that the fact that this
|
||||
* code omits one level of interface glue has no perceptible effect on
|
||||
* the results.
|
||||
*/
|
||||
#include "zrtp.h"
|
||||
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
#define _ZTU_ "bntest"
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_STDLIB_H
|
||||
#define NO_STDLIB_H 0
|
||||
#endif
|
||||
#ifndef NO_STRING_H
|
||||
#define NO_STRING_H 0
|
||||
#endif
|
||||
#ifndef HAVE_STRINGS_H
|
||||
#define HAVE_STRINGS_H 0
|
||||
#endif
|
||||
#ifndef NEED_MEMORY_H
|
||||
#define NEED_MEMORY_H 0
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if !NO_STDLIB_H
|
||||
#include <stdlib.h> /* For strtol */
|
||||
#else
|
||||
long strtol(const char *, char **, int);
|
||||
#endif
|
||||
|
||||
#if !NO_STRING_H
|
||||
#include <string.h> /* For memcpy */
|
||||
#elif HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#if NEED_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#include "lbn32.h"
|
||||
#include "kludge.h"
|
||||
|
||||
#if BNYIELD
|
||||
int (*bnYield)(void) = 0;
|
||||
#endif
|
||||
|
||||
/* Work with up to 2048-bit numbers */
|
||||
#define MAXBITS 3072
|
||||
#define SIZE (MAXBITS/32 + 1)
|
||||
|
||||
/* Additive congruential random number generator, x[i] = x[i-24] + x[i-55] */
|
||||
static BNWORD32 randp[55];
|
||||
static BNWORD32 *randp1 = randp, *randp2 = randp+24;
|
||||
|
||||
static BNWORD32
|
||||
rand32(void)
|
||||
{
|
||||
if (++randp2 == randp+55) {
|
||||
randp2 = randp;
|
||||
randp1++;
|
||||
} else if (++randp1 == randp+55) {
|
||||
randp1 = randp;
|
||||
}
|
||||
|
||||
return *randp1 += *randp2;
|
||||
}
|
||||
|
||||
/*
|
||||
* CRC-3_2: x^3_2+x^26+x^23+x^22+x^1_6+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
|
||||
*
|
||||
* The additive congruential RNG is seeded with a single integer,
|
||||
* which is shuffled with a CRC polynomial to generate the initial
|
||||
* table values. The Polynomial is the same size as the words being
|
||||
* used.
|
||||
*
|
||||
* Thus, in the various versions of this library, we actually use this
|
||||
* polynomial as-is, this polynomial mod x^17, and this polynomial with
|
||||
* the leading coefficient deleted and replaced with x^6_4. As-is,
|
||||
* it's irreducible, so it has a long period. Modulo x^17, it factors as
|
||||
* (x^4+x^3+x^2+x+1) * (x^12+x^11+x^8+x^7+x^6+x^5+x^4+x^3+1),
|
||||
* which still has a large enough period (4095) for the use it's put to.
|
||||
* With the leading coefficient moved up, it factors as
|
||||
* (x^50+x^49+x^48+x^47+x^46+x^43+x^41+x^40+x^38+x^37+x^36+x^35+x^34+x^33+
|
||||
* x^31+x^30+x^29+x^28+x^27+x^25+x^23+x^18+x^1_6+x^15+x^14+x^13+x^11+x^9+
|
||||
* x^8+x^7+x^6+x^5+x^3+x^2+1)*(x^11+x^10+x^9+x^5+x^4+x^3+1)*(x^3+x+1),
|
||||
* which definitely has a long enough period to serve for initialization.
|
||||
*
|
||||
* The effort put into this PRNG is kind of unwarranted given the trivial
|
||||
* use it's being put to, but oh, well. It does have the nice advantage
|
||||
* of producing numbers that are portable between platforms, so if there's
|
||||
* a problem with one platform, you can compare all the intermediate
|
||||
* results with another platform.
|
||||
*/
|
||||
#define POLY (BNWORD32)0x04c11db7
|
||||
|
||||
static void
|
||||
srand32(BNWORD32 seed)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 55; i++) {
|
||||
for (j = 0; j < 32; j++)
|
||||
if (seed >> (32-1))
|
||||
seed = (seed << 1) ^ POLY;
|
||||
else
|
||||
seed <<= 1;
|
||||
randp[i] = seed;
|
||||
}
|
||||
for (i = 0; i < 3*55; i ++)
|
||||
rand32();
|
||||
}
|
||||
|
||||
static void
|
||||
randnum(BNWORD32 *num, unsigned len)
|
||||
{
|
||||
while (len--)
|
||||
BIGLITTLE(*--num,*num++) = rand32();
|
||||
}
|
||||
|
||||
static void
|
||||
bnprint32(BNWORD32 const *num, unsigned len)
|
||||
{
|
||||
BIGLITTLE(num -= len, num += len);
|
||||
|
||||
while (len--)
|
||||
ZRTP_LOG(3, (_ZTU_, "%0*lX", 32/4, (unsigned long)BIGLITTLE(*num++,*--num)));
|
||||
}
|
||||
|
||||
static void
|
||||
bnput32(char const *prompt, BNWORD32 const *num, unsigned len)
|
||||
{
|
||||
fputs(prompt, stdout);
|
||||
bnprint32(num, len);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* One of our tests uses a known prime. The following selections were
|
||||
* taken from the tables at the end of Hans Reisel's "Prime Numbers and
|
||||
* Computer Methods for Factorization", second edition - an excellent book.
|
||||
* (ISBN 0-8176-3743-5 ISBN 3-7643-3743-5)
|
||||
*/
|
||||
#if 0
|
||||
/* P31=1839605 17620282 38179967 87333633 from the factors of 3^256+2^256 */
|
||||
static unsigned char const prime[] = {
|
||||
0x17,0x38,0x15,0xBC,0x8B,0xBB,0xE9,0xEF,0x01,0xA9,0xFD,0x3A,0x01
|
||||
};
|
||||
#elif 0
|
||||
/* P48=40554942 04557502 46193993 36199835 4279613_2 73199617 from the same */
|
||||
static unsigned char const prime[] = {
|
||||
0x47,0x09,0x77,0x07,0xCF,0xFD,0xE1,0x54,0x3E,0x24,
|
||||
0xF7,0xF1,0x7A,0x3E,0x91,0x51,0xCC,0xC7,0xD4,0x01
|
||||
};
|
||||
#elif 0
|
||||
/*
|
||||
* P75 = 450 55287640 97906895 47687014 5808213_2
|
||||
* 05219565 99525911 39967964 66003_258 91979521
|
||||
* from the factors of 4^128+3+128
|
||||
* (The "026" and "062" are to prevent a Bad String from appearing here.)
|
||||
*/
|
||||
static unsigned char const prime[] = {
|
||||
0xFF,0x00,0xFF,0x00,0xFF,0x01,0x06,0x4F,0xF8,0xED,
|
||||
0xA3,0x37,0x23,0x2A,0x04,0xEA,0xF9,0x5F,0x30,0x4C,
|
||||
0xAE,0xCD, 026,0x4E, 062,0x10,0x04,0x7D,0x0D,0x79,
|
||||
0x01
|
||||
};
|
||||
#else
|
||||
/*
|
||||
* P75 = 664 85659796 45277755 9123_2190 67300940
|
||||
* 51844953 78793489 59444670 35675855 57440257
|
||||
* from the factors of 5^128+4^128
|
||||
* (The "026" is to prevent a Bad String from appearing here.)
|
||||
*/
|
||||
static unsigned char const prime[] = {
|
||||
0x01,0x78,0x4B,0xA5,0xD3,0x30,0x03,0xEB,0x73,0xE6,
|
||||
0x0F,0x4E,0x31,0x7D,0xBC,0xE2,0xA0,0xD4, 026,0x3F,
|
||||
0x3C,0xEA,0x1B,0x44,0xAD,0x39,0xE7,0xE5,0xAD,0x19,
|
||||
0x67,0x01
|
||||
};
|
||||
#endif
|
||||
|
||||
static int
|
||||
usage(char const *name)
|
||||
{
|
||||
ZRTP_LOG(3, (_ZTU_, "Usage: %s [modbits [expbits [expbits2]]"
|
||||
"With no arguments, just runs test suite. If modbits is given, runs\n"
|
||||
"quick validation test, then runs timing tests of modular exponentiation.\n"
|
||||
"If expbits is given, it is used as an exponent size, otherwise it defaults\n"
|
||||
"to the same as modbits. If expbits2 is given it is used as the second\n"
|
||||
"exponent size in the double-exponentiation tests, otherwise it defaults\n"
|
||||
"to the same as expbits. All are limited to %u bits.\n",
|
||||
name, (unsigned)MAXBITS));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* for libzrtp support */
|
||||
int
|
||||
bntest_main(int argc, char **argv)
|
||||
{
|
||||
unsigned i, j, k, l, m;
|
||||
int z;
|
||||
BNWORD32 t, carry, borrow;
|
||||
BNWORD32 a[SIZE], b[SIZE], c[SIZE], d[SIZE];
|
||||
BNWORD32 e[SIZE], f[SIZE];
|
||||
static BNWORD32 entries[sizeof(prime)*2][(sizeof(prime)-1)/(32/8)+1];
|
||||
BNWORD32 *array[sizeof(prime)*2];
|
||||
unsigned long modbits = 0, expbits = 0, expbits2 = 0;
|
||||
char *p;
|
||||
#define A BIGLITTLE((a+SIZE),a)
|
||||
#define B BIGLITTLE((b+SIZE),b)
|
||||
#define C BIGLITTLE((c+SIZE),c)
|
||||
#define D BIGLITTLE((d+SIZE),d)
|
||||
#define E BIGLITTLE((e+SIZE),e)
|
||||
#define F BIGLITTLE((f+SIZE),f)
|
||||
static unsigned const smallprimes[] = {
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43
|
||||
};
|
||||
|
||||
/* Set up array for precomputed modexp */
|
||||
for (i = 0; i < sizeof(array)/sizeof(*array); i++)
|
||||
array[i] = entries[i] BIG(+ SIZE);
|
||||
|
||||
srand32(1);
|
||||
|
||||
puts(BIGLITTLE("Big-endian machine","Little-endian machine"));
|
||||
|
||||
if (argc >= 2) {
|
||||
modbits = strtoul(argv[1], &p, 0);
|
||||
if (!modbits || *p) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Invalid modbits: %s", argv[1]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if (argc >= 3) {
|
||||
expbits = strtoul(argv[2], &p, 0);
|
||||
if (!expbits || *p) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Invalid expbits: %s", argv[2]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
expbits2 = expbits;
|
||||
}
|
||||
if (argc >= 4) {
|
||||
expbits2 = strtoul(argv[3], &p, 0);
|
||||
if (!expbits2 || *p) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Invalid expbits2: %s", argv[3]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if (argc >= 5) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Too many arguments: %s", argv[4]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
/* B is a nice not-so-little prime */
|
||||
lbnInsertBigBytes_32(B, prime, 0, sizeof(prime));
|
||||
((unsigned char *)c)[0] = 0;
|
||||
lbnInsertBigBytes_32(B, (unsigned char *)c, sizeof(prime), 1);
|
||||
lbnExtractBigBytes_32(B, (unsigned char *)c, 0, sizeof(prime)+1);
|
||||
i = (sizeof(prime)-1)/(32/8)+1; /* Size of array in words */
|
||||
if (((unsigned char *)c)[0] ||
|
||||
memcmp(prime, (unsigned char *)c+1, sizeof(prime)) != 0)
|
||||
{
|
||||
ZRTP_LOG(3, (_ZTU_, "Input != output!: "));
|
||||
for (k = 0; k < sizeof(prime); k++)
|
||||
ZRTP_LOG(3, (_ZTU_, "%02X ", prime[k]));
|
||||
putchar('\n');
|
||||
for (k = 0; k < sizeof(prime)+1; k++)
|
||||
ZRTP_LOG(3, (_ZTU_, "%02X ", ((unsigned char *)c)[k]));
|
||||
putchar('\n');
|
||||
bnput32("p = ", B, i);
|
||||
|
||||
}
|
||||
|
||||
/* Timing test code - only if requested on the command line */
|
||||
if (modbits) {
|
||||
#if CLOCK_AVAIL
|
||||
timetype start, stop;
|
||||
unsigned long cursec, expsec, twoexpsec, dblexpsec;
|
||||
unsigned curms, expms, twoexpms, dblexpms;
|
||||
|
||||
expsec = twoexpsec = dblexpsec = 0;
|
||||
expms = twoexpms = dblexpms = 0;
|
||||
#endif
|
||||
|
||||
lbnCopy_32(C,B,i);
|
||||
lbnSub1_32(C,i,1); /* C is exponent: p-1 */
|
||||
|
||||
puts("Testing modexp with a known prime. "
|
||||
"All results should be 1.");
|
||||
bnput32("p = ", B, i);
|
||||
bnput32("p-1 = ", C, i);
|
||||
z = lbnTwoExpMod_32(A, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput32("2^(p-1) mod p = ", A, i);
|
||||
for (j = 0; j < 10; j++) {
|
||||
randnum(A,i);
|
||||
(void)lbnDiv_32(D,A,i,B,i);
|
||||
|
||||
bnput32("a = ", A, i);
|
||||
z = lbnExpMod_32(D, A, i, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput32("a^(p-1) mod p = ", D, i);
|
||||
|
||||
z = lbnBasePrecompBegin_32(array, (sizeof(prime)*8+4)/5, 5,
|
||||
A, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
BIGLITTLE(D[-1],D[0]) = -1;
|
||||
z = lbnBasePrecompExp_32(D, (BNWORD32 const * const *)array,
|
||||
5, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput32("a^(p-1) mod p = ", D, i);
|
||||
|
||||
for (k = 0; k < 5; k++) {
|
||||
randnum(E,i);
|
||||
bnput32("e = ", E, i);
|
||||
z = lbnExpMod_32(D, A, i, E, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput32("a^e mod p = ", D, i);
|
||||
z = lbnBasePrecompExp_32(D, (BNWORD32 const * const *)array,
|
||||
5, E, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput32("a^e mod p = ", D, i);
|
||||
}
|
||||
}
|
||||
|
||||
ZRTP_LOG(3, (_ZTU_, "\n"
|
||||
"Timing exponentiations modulo a %d-bit modulus, i.e.\n"
|
||||
"2^<%d> mod <%d> bits, <%d>^<%d> mod <%d> bits and\n"
|
||||
"<%d>^<%d> * <%d>^<%d> mod <%d> bits",
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)modbits, (int)expbits, (int)modbits, (int)expbits2,
|
||||
(int)modbits));
|
||||
|
||||
i = ((int)modbits-1)/32+1;
|
||||
k = ((int)expbits-1)/32+1;
|
||||
l = ((int)expbits2-1)/32+1;
|
||||
for (j = 0; j < 25; j++) {
|
||||
randnum(A,i); /* Base */
|
||||
randnum(B,k); /* Exponent */
|
||||
randnum(C,i); /* Modulus */
|
||||
randnum(D,i); /* Base2 */
|
||||
randnum(E,l); /* Exponent */
|
||||
/* Clip bases and mod to appropriate number of bits */
|
||||
t = ((BNWORD32)2<<((modbits-1)%32)) - 1;
|
||||
*(BIGLITTLE(A-i,A+i-1)) &= t;
|
||||
*(BIGLITTLE(C-i,C+i-1)) &= t;
|
||||
*(BIGLITTLE(D-i,D+i-1)) &= t;
|
||||
/* Make modulus large (msbit set) and odd (lsbit set) */
|
||||
*(BIGLITTLE(C-i,C+i-1)) |= (t >> 1) + 1;
|
||||
BIGLITTLE(C[-1],C[0]) |= 1;
|
||||
|
||||
/* Clip exponent to appropriate number of bits */
|
||||
t = ((BNWORD32)2<<((expbits-1)%32)) - 1;
|
||||
*(BIGLITTLE(B-k,B+k-1)) &= t;
|
||||
/* Make exponent large (msbit set) */
|
||||
*(BIGLITTLE(B-k,B+k-1)) |= (t >> 1) + 1;
|
||||
/* The same for exponent 2 */
|
||||
t = ((BNWORD32)2<<((expbits2-1)%32)) - 1;
|
||||
*(BIGLITTLE(E-l,E+l-1)) &= t;
|
||||
*(BIGLITTLE(E-l,E+l-1)) |= (t >> 1) + 1;
|
||||
|
||||
m = lbnBits_32(A, i);
|
||||
if (m > (unsigned)modbits) {
|
||||
bnput32("a = ", a, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be <= %d", m, (int)modbits));
|
||||
}
|
||||
m = lbnBits_32(B, k);
|
||||
if (m != (unsigned)expbits) {
|
||||
bnput32("b = ", b, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be %d", m, (int)expbits));
|
||||
}
|
||||
m = lbnBits_32(C, i);
|
||||
if (m != (unsigned)modbits) {
|
||||
bnput32("c = ", c, k);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be %d", m, (int)modbits));
|
||||
}
|
||||
m = lbnBits_32(D, i);
|
||||
if (m > (unsigned)modbits) {
|
||||
bnput32("d = ", d, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be <= %d", m, (int)modbits));
|
||||
}
|
||||
m = lbnBits_32(E, l);
|
||||
if (m != (unsigned)expbits2) {
|
||||
bnput32("e = ", e, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be %d", m, (int)expbits2));
|
||||
}
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&start);
|
||||
#endif
|
||||
z = lbnTwoExpMod_32(A, B, k, C, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
twoexpsec += cursec = sec(stop);
|
||||
twoexpms += curms = msec(stop);
|
||||
|
||||
ZRTP_LOG(3, (_ZTU_, "2^<%d>:%4lu.%03u ", (int)expbits, cursec, curms));
|
||||
#else
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d> ", (int)modbits, (int)expbits));
|
||||
#endif
|
||||
fflush(stdout);
|
||||
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&start);
|
||||
#endif
|
||||
z = lbnExpMod_32(A, A, i, B, k, C, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
expsec += cursec = sec(stop);
|
||||
expms += curms = msec(stop);
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d>:%4lu.%03u ",(int)modbits, (int)expbits, cursec, curms));
|
||||
fflush(stdout);
|
||||
|
||||
gettime(&start);
|
||||
z = lbnDoubleExpMod_32(D, A, i, B, k, D, i, E, l,C,i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
dblexpsec += cursec = sec(stop);
|
||||
dblexpms += curms = msec(stop);
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d>*<%d>^<%d>:%4lu.%03u",
|
||||
(int)modbits, (int)expbits,
|
||||
(int)modbits, (int)expbits2,
|
||||
cursec, curms));
|
||||
#else
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d>*<%d>^<%d>",
|
||||
(int)modbits, (int)expbits,
|
||||
(int)modbits, (int)expbits2));
|
||||
#endif
|
||||
}
|
||||
#if CLOCK_AVAIL
|
||||
twoexpms += (twoexpsec % j) * 1000;
|
||||
ZRTP_LOG(3, (_ZTU_, "2^<%d> mod <%d> bits AVERAGE: %4lu.%03u s",
|
||||
(int)expbits, (int)modbits, twoexpsec/j, twoexpms/j));
|
||||
expms += (expsec % j) * 1000;
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d> mod <%d> bits AVERAGE: %4lu.%03u s",
|
||||
(int)modbits, (int)expbits, (int)modbits, expsec/j, expms/j));
|
||||
dblexpms += (dblexpsec % j) * 1000;
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d> * <%d>^<%d> mod <%d> bits AVERAGE:"
|
||||
" %4lu.%03u s",
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)expbits2,
|
||||
(int)modbits, dblexpsec/j, dblexpms/j));
|
||||
|
||||
putchar('\n');
|
||||
#endif
|
||||
}
|
||||
|
||||
puts("Beginning 1000 interations of sanity checking.\n"
|
||||
"Any output indicates a bug. No output is very strong\n"
|
||||
"evidence that all the important low-level bignum routines\n"
|
||||
"are working properly.\n");
|
||||
|
||||
/*
|
||||
* If you change this loop to have an iteration 0, all results
|
||||
* are primted on that iteration. Useful to see what's going
|
||||
* on in case of major wierdness, but it produces a *lot* of
|
||||
* output.
|
||||
*/
|
||||
#if (ZRTP_PLATFORM == ZP_WINCE) || (ZRTP_PLATFORM == ZP_SYMBIAN)
|
||||
for (j = 1; j <= 20; j++) {
|
||||
#else
|
||||
for (j = 1; j <= 1000; j++) {
|
||||
#endif
|
||||
/* Do the tests for lots of different number sizes. */
|
||||
for (i = 1; i <= SIZE/2; i++) {
|
||||
/* Make a random number i words long */
|
||||
do {
|
||||
randnum(A,i);
|
||||
} while (lbnNorm_32(A,i) < i);
|
||||
|
||||
/* Checl lbnCmp - does a == a? */
|
||||
if (lbnCmp_32(A,A,i) || !j) {
|
||||
bnput32("a = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> a) = %d", lbnCmp_32(A,A,i)));
|
||||
}
|
||||
|
||||
memcpy(c, a, sizeof(a));
|
||||
|
||||
/* Check that the difference, after copy, is good. */
|
||||
if (lbnCmp_32(A,C,i) || !j) {
|
||||
bnput32("a = ", A, i);
|
||||
bnput32("c = ", C, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_32(A,C,i)));
|
||||
}
|
||||
|
||||
/* Generate a non-zero random t */
|
||||
do {
|
||||
t = rand32();
|
||||
} while (!t);
|
||||
|
||||
/*
|
||||
* Add t to A. Check that:
|
||||
* - lbnCmp works in both directions, and
|
||||
* - A + t is greater than A. If there was a carry,
|
||||
* the result, less the carry, should be *less*
|
||||
* than A.
|
||||
*/
|
||||
carry = lbnAdd1_32(A,i,t);
|
||||
if (lbnCmp_32(A,C,i) + lbnCmp_32(C,A,i) != 0 ||
|
||||
lbnCmp_32(A,C,i) != (carry ? -1 : 1) || !j)
|
||||
{
|
||||
bnput32("c = ", C, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "t = %lX", (unsigned long)t));
|
||||
bnput32("a = c+t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "carry = %lX", (unsigned long)carry));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_32(A,C,i)));
|
||||
ZRTP_LOG(3, (_ZTU_, "(c <=> a) = %d", lbnCmp_32(C,A,i)));
|
||||
}
|
||||
|
||||
/* Subtract t again */
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnSub1_32(A,i,t);
|
||||
|
||||
if (carry != borrow || lbnCmp_32(A,C,i) || !j) {
|
||||
bnput32("a = ", C, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "t = %lX", (unsigned long)t));
|
||||
lbnAdd1_32(A,i,t);
|
||||
bnput32("a += t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Carry = %lX", (unsigned long)carry));
|
||||
lbnSub1_32(A,i,t);
|
||||
bnput32("a -= t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Borrow = %lX", (unsigned long)borrow));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_32(A,C,i)));
|
||||
}
|
||||
|
||||
/* Generate a random B */
|
||||
do {
|
||||
randnum(B,i);
|
||||
} while (lbnNorm_32(B,i) < i);
|
||||
|
||||
carry = lbnAddN_32(A,B,i);
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnSubN_32(A,B,i);
|
||||
|
||||
if (carry != borrow || lbnCmp_32(A,C,i) || !j) {
|
||||
bnput32("a = ", C, i);
|
||||
bnput32("b = ", B, i);
|
||||
bnput32("a += b = ", D, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Carry = %lX", (unsigned long)carry));
|
||||
bnput32("a -= b = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Borrow = %lX", (unsigned long)borrow));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_32(A,C,i)));
|
||||
}
|
||||
|
||||
/* D = B * t */
|
||||
lbnMulN1_32(D, B, i, t);
|
||||
memcpy(e, d, sizeof(e));
|
||||
/* D = A + B * t, "carry" is overflow */
|
||||
borrow = *(BIGLITTLE(D-i-1,D+i)) += lbnAddN_32(D,A,i);
|
||||
|
||||
carry = lbnMulAdd1_32(A, B, i, t);
|
||||
|
||||
/* Did MulAdd get the same answer as mul then add? */
|
||||
if (carry != borrow || lbnCmp_32(A, D, i) || !j) {
|
||||
bnput32("a = ", C, i);
|
||||
bnput32("b = ", B, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "t = %lX", (unsigned long)t));
|
||||
bnput32("e = b * t = ", E, i+1);
|
||||
bnput32(" a + e = ", D, i+1);
|
||||
bnput32("a + b * t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "carry = %lX", (unsigned long)carry));
|
||||
}
|
||||
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnMulSub1_32(A, B, i, t);
|
||||
|
||||
/* Did MulSub perform the inverse of MulAdd */
|
||||
if (carry != borrow || lbnCmp_32(A,C,i) || !j) {
|
||||
bnput32(" a = ", C, i);
|
||||
bnput32(" b = ", B, i);
|
||||
bnput32("a += b*t = ", D, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Carry = %lX", (unsigned long)carry));
|
||||
bnput32("a -= b*t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Borrow = %lX", (unsigned long)borrow));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_32(A,C,i)));
|
||||
bnput32("b*t = ", E, i+1);
|
||||
}
|
||||
/* At this point we're done with t, so it's scratch */
|
||||
#if 0
|
||||
/* Extra debug code */
|
||||
lbnMulN1_32(C, A, i, BIGLITTLE(B[-1],B[0]));
|
||||
bnput32("a * b[0] = ", C, i+1);
|
||||
for (k = 1; k < i; k++) {
|
||||
carry = lbnMulAdd1_32(BIGLITTLE(C-k,C+k), A, i,
|
||||
*(BIGLITTLE(B-1-k,B+k)));
|
||||
*(BIGLITTLE(C-i-k,C+i+k)) = carry;
|
||||
bnput32("a * b[x] = ", C, i+k+1);
|
||||
}
|
||||
|
||||
lbnMulN1_32(D, B, i, BIGLITTLE(A[-1],A[0]));
|
||||
bnput32("b * a[0] = ", D, i+1);
|
||||
for (k = 1; k < i; k++) {
|
||||
carry = lbnMulAdd1_32(BIGLITTLE(D-k,D+k), B, i,
|
||||
*(BIGLITTLE(A-1-k,A+k)));
|
||||
*(BIGLITTLE(D-i-k,D+i+k)) = carry;
|
||||
bnput32("b * a[x] = ", D, i+k+1);
|
||||
}
|
||||
#endif
|
||||
/* Does Mul work both ways symmetrically */
|
||||
lbnMul_32(C,A,i,B,i);
|
||||
lbnMul_32(D,B,i,A,i);
|
||||
if (lbnCmp_32(C,D,i+i) || !j) {
|
||||
bnput32("a = ", A, i);
|
||||
bnput32("b = ", B, i);
|
||||
bnput32("a * b = ", C, i+i);
|
||||
bnput32("b * a = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a*b <=> b*a) = %d", lbnCmp_32(C,D,i+i)));
|
||||
}
|
||||
/* Check multiplication modulo some small things */
|
||||
/* 30030 = 2*3*5*11*13 */
|
||||
k = lbnModQ_32(C, i+i, 30030);
|
||||
for (l = 0;
|
||||
l < sizeof(smallprimes)/sizeof(*smallprimes);
|
||||
l++)
|
||||
{
|
||||
m = smallprimes[l];
|
||||
t = lbnModQ_32(C, i+i, m);
|
||||
carry = lbnModQ_32(A, i, m);
|
||||
borrow = lbnModQ_32(B, i, m);
|
||||
if (t != (carry * borrow) % m) {
|
||||
bnput32("a = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a mod %u = %u", m, (unsigned)carry));
|
||||
bnput32("b = ", B, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "b mod %u = %u", m, (unsigned)borrow));
|
||||
bnput32("a*b = ", C, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a*b mod %u = %u", m, (unsigned)t));
|
||||
ZRTP_LOG(3, (_ZTU_, "expected %u", (unsigned)((carry*borrow)%m)));
|
||||
}
|
||||
/* Verify that (C % 30030) % m == C % m */
|
||||
if (m <= 13 && t != k % m) {
|
||||
ZRTP_LOG(3, (_ZTU_, "c mod 30030 = %u mod %u= %u", k, m, k%m));
|
||||
ZRTP_LOG(3, (_ZTU_, "c mod %u = %u", m, (unsigned)t));
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate an F less than A and B */
|
||||
do {
|
||||
randnum(F,i);
|
||||
} while (lbnCmp_32(F,A,i) >= 0 ||
|
||||
lbnCmp_32(F,B,i) >= 0);
|
||||
|
||||
/* Add F to D (remember, D = A*B) */
|
||||
lbnAdd1_32(BIGLITTLE(D-i,D+i), i, lbnAddN_32(D, F, i));
|
||||
memcpy(c, d, sizeof(d));
|
||||
|
||||
/*
|
||||
* Divide by A and check that quotient and remainder
|
||||
* match (remainder should be F, quotient should be B)
|
||||
*/
|
||||
t = lbnDiv_32(E,C,i+i,A,i);
|
||||
if (t || lbnCmp_32(E,B,i) || lbnCmp_32(C, F, i) || !j) {
|
||||
bnput32("a = ", A, i);
|
||||
bnput32("b = ", B, i);
|
||||
bnput32("f = ", F, i);
|
||||
bnput32("a * b + f = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "qhigh = %lX", (unsigned long)t));
|
||||
bnput32("(a*b+f) / a = ", E, i);
|
||||
bnput32("(a*b+f) % a = ", C, i);
|
||||
}
|
||||
|
||||
memcpy(c, d, sizeof(d));
|
||||
|
||||
/* Divide by B and check similarly */
|
||||
t = lbnDiv_32(E,C,i+i,B,i);
|
||||
if (lbnCmp_32(E,A,i) || lbnCmp_32(C, F, i) || !j) {
|
||||
bnput32("a = ", A, i);
|
||||
bnput32("b = ", B, i);
|
||||
bnput32("f = ", F, i);
|
||||
bnput32("a * b + f = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "qhigh = %lX", (unsigned long)t));
|
||||
bnput32("(a*b+f) / b = ", E, i);
|
||||
bnput32("(a*b+f) % b = ", C, i);
|
||||
}
|
||||
|
||||
/* Check that A*A == A^2 */
|
||||
lbnMul_32(C,A,i,A,i);
|
||||
lbnSquare_32(D,A,i);
|
||||
if (lbnCmp_32(C,D,i+i) || !j) {
|
||||
bnput32("a*a = ", C, i+i);
|
||||
bnput32("a^2 = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a * a == a^2) = %d", lbnCmp_32(C,D,i+i)));
|
||||
}
|
||||
|
||||
/* Compute a GCD */
|
||||
lbnCopy_32(C,A,i);
|
||||
lbnCopy_32(D,B,i);
|
||||
z = lbnGcd_32(C, i, D, i, &k);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
/* z = 1 if GCD in D; z = 0 if GCD in C */
|
||||
|
||||
/* Approximate check that the GCD came out right */
|
||||
for (l = 0;
|
||||
l < sizeof(smallprimes)/sizeof(*smallprimes);
|
||||
l++)
|
||||
{
|
||||
m = smallprimes[l];
|
||||
t = lbnModQ_32(z ? D : C, k, m);
|
||||
carry = lbnModQ_32(A, i, m);
|
||||
borrow = lbnModQ_32(B, i, m);
|
||||
if (!t != (!carry && !borrow)) {
|
||||
bnput32("a = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a mod %u = %u", m, (unsigned)carry));
|
||||
bnput32("b = ", B, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "b mod %u = %u", m, (unsigned)borrow));
|
||||
bnput32("gcd(a,b) = ", z ? D : C, k);
|
||||
ZRTP_LOG(3, (_ZTU_, "gcd(a,b) mod %u = %u", m, (unsigned)t));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Do some Montgomery operations
|
||||
* Start with A > B, and also place a copy of B into C.
|
||||
* Then make A odd so it can be a Montgomery modulus.
|
||||
*/
|
||||
if (lbnCmp_32(A, B, i) < 0) {
|
||||
memcpy(c, a, sizeof(c));
|
||||
memcpy(a, b, sizeof(a));
|
||||
memcpy(b, c, sizeof(b));
|
||||
} else {
|
||||
memcpy(c, b, sizeof(c));
|
||||
}
|
||||
BIGLITTLE(A[-1],A[0]) |= 1;
|
||||
|
||||
/* Convert to and from */
|
||||
lbnToMont_32(B, i, A, i);
|
||||
lbnFromMont_32(B, A, i);
|
||||
if (lbnCmp_32(B, C, i)) {
|
||||
memcpy(b, c, sizeof(c));
|
||||
bnput32("mod = ", A, i);
|
||||
bnput32("input = ", B, i);
|
||||
lbnToMont_32(B, i, A, i);
|
||||
bnput32("mont = ", B, i);
|
||||
lbnFromMont_32(B, A, i);
|
||||
bnput32("output = ", B, i);
|
||||
}
|
||||
/* E = B^5 (mod A), no Montgomery ops */
|
||||
lbnSquare_32(E, B, i);
|
||||
(void)lbnDiv_32(BIGLITTLE(E-i,E+i),E,i+i,A,i);
|
||||
lbnSquare_32(D, E, i);
|
||||
(void)lbnDiv_32(BIGLITTLE(D-i,D+i),D,i+i,A,i);
|
||||
lbnMul_32(E, D, i, B, i);
|
||||
(void)lbnDiv_32(BIGLITTLE(E-i,E+i),E,i+i,A,i);
|
||||
|
||||
/* D = B^5, using ExpMod */
|
||||
BIGLITTLE(F[-1],F[0]) = 5;
|
||||
z = lbnExpMod_32(D, B, i, F, 1, A, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
if (lbnCmp_32(D, E, i) || !j) {
|
||||
bnput32("mod = ", A, i);
|
||||
bnput32("input = ", B, i);
|
||||
bnput32("input^5 = ", E, i);
|
||||
bnput32("input^5 = ", D, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a>b (x <=> y) = %d", lbnCmp_32(D,E,i)));
|
||||
}
|
||||
/* TODO: Test lbnTwoExpMod, lbnDoubleExpMod */
|
||||
} /* for (i) */
|
||||
ZRTP_LOG(3, (_ZTU_, "\r%d ", j));
|
||||
fflush(stdout);
|
||||
} /* for (j) */
|
||||
ZRTP_LOG(3, (_ZTU_, "%d iterations of up to %d 32-bit words completed.", j-1, i-1));
|
||||
return 0;
|
||||
nomem:
|
||||
ZRTP_LOG(3, (_ZTU_, "Out of memory"));
|
||||
return 1;
|
||||
}
|
||||
+804
@@ -0,0 +1,804 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* Test driver for low-level bignum library (64-bit version).
|
||||
* This access the low-level library directly. It is NOT an example of
|
||||
* how to program with the library normally! By accessing the library
|
||||
* at a low level, it is possible to exercise the smallest components
|
||||
* and thus localize bugs more accurately. This is especially useful
|
||||
* when writing assembly-language primitives.
|
||||
*
|
||||
* This also does timing tests on modular exponentiation. Modular
|
||||
* exponentiation is so computationally expensive that the fact that this
|
||||
* code omits one level of interface glue has no perceptible effect on
|
||||
* the results.
|
||||
*/
|
||||
#include "zrtp.h"
|
||||
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
#define _ZTU_ "bntest"
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_STDLIB_H
|
||||
#define NO_STDLIB_H 0
|
||||
#endif
|
||||
#ifndef NO_STRING_H
|
||||
#define NO_STRING_H 0
|
||||
#endif
|
||||
#ifndef HAVE_STRINGS_H
|
||||
#define HAVE_STRINGS_H 0
|
||||
#endif
|
||||
#ifndef NEED_MEMORY_H
|
||||
#define NEED_MEMORY_H 0
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if !NO_STDLIB_H
|
||||
#include <stdlib.h> /* For strtol */
|
||||
#else
|
||||
long strtol(const char *, char **, int);
|
||||
#endif
|
||||
|
||||
#if !NO_STRING_H
|
||||
#include <string.h> /* For memcpy */
|
||||
#elif HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#if NEED_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#include "lbn64.h"
|
||||
#include "kludge.h"
|
||||
|
||||
#if BNYIELD
|
||||
int (*bnYield)(void) = 0;
|
||||
#endif
|
||||
|
||||
/* Work with up to 2048-bit numbers */
|
||||
#define MAXBITS 3072
|
||||
#define SIZE (MAXBITS/64 + 1)
|
||||
|
||||
/* Additive congruential random number generator, x[i] = x[i-24] + x[i-55] */
|
||||
static BNWORD64 randp[55];
|
||||
static BNWORD64 *randp1 = randp, *randp2 = randp+24;
|
||||
|
||||
static BNWORD64
|
||||
rand64(void)
|
||||
{
|
||||
if (++randp2 == randp+55) {
|
||||
randp2 = randp;
|
||||
randp1++;
|
||||
} else if (++randp1 == randp+55) {
|
||||
randp1 = randp;
|
||||
}
|
||||
|
||||
return *randp1 += *randp2;
|
||||
}
|
||||
|
||||
/*
|
||||
* CRC-3_2: x^3_2+x^26+x^23+x^22+x^1_6+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1
|
||||
*
|
||||
* The additive congruential RNG is seeded with a single integer,
|
||||
* which is shuffled with a CRC polynomial to generate the initial
|
||||
* table values. The Polynomial is the same size as the words being
|
||||
* used.
|
||||
*
|
||||
* Thus, in the various versions of this library, we actually use this
|
||||
* polynomial as-is, this polynomial mod x^17, and this polynomial with
|
||||
* the leading coefficient deleted and replaced with x^6_4. As-is,
|
||||
* it's irreducible, so it has a long period. Modulo x^17, it factors as
|
||||
* (x^4+x^3+x^2+x+1) * (x^12+x^11+x^8+x^7+x^6+x^5+x^4+x^3+1),
|
||||
* which still has a large enough period (4095) for the use it's put to.
|
||||
* With the leading coefficient moved up, it factors as
|
||||
* (x^50+x^49+x^48+x^47+x^46+x^43+x^41+x^40+x^38+x^37+x^36+x^35+x^34+x^33+
|
||||
* x^31+x^30+x^29+x^28+x^27+x^25+x^23+x^18+x^1_6+x^15+x^14+x^13+x^11+x^9+
|
||||
* x^8+x^7+x^6+x^5+x^3+x^2+1)*(x^11+x^10+x^9+x^5+x^4+x^3+1)*(x^3+x+1),
|
||||
* which definitely has a long enough period to serve for initialization.
|
||||
*
|
||||
* The effort put into this PRNG is kind of unwarranted given the trivial
|
||||
* use it's being put to, but oh, well. It does have the nice advantage
|
||||
* of producing numbers that are portable between platforms, so if there's
|
||||
* a problem with one platform, you can compare all the intermediate
|
||||
* results with another platform.
|
||||
*/
|
||||
#define POLY (BNWORD64)0x04c11db7
|
||||
|
||||
static void
|
||||
srand64(BNWORD64 seed)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 55; i++) {
|
||||
for (j = 0; j < 64; j++)
|
||||
if (seed >> (64-1))
|
||||
seed = (seed << 1) ^ POLY;
|
||||
else
|
||||
seed <<= 1;
|
||||
randp[i] = seed;
|
||||
}
|
||||
for (i = 0; i < 3*55; i ++)
|
||||
rand64();
|
||||
}
|
||||
|
||||
static void
|
||||
randnum(BNWORD64 *num, unsigned len)
|
||||
{
|
||||
while (len--)
|
||||
BIGLITTLE(*--num,*num++) = rand64();
|
||||
}
|
||||
|
||||
static void
|
||||
bnprint64(BNWORD64 const *num, unsigned len)
|
||||
{
|
||||
BIGLITTLE(num -= len, num += len);
|
||||
|
||||
while (len--)
|
||||
ZRTP_LOG(3, (_ZTU_, "%0*lX", 64/4, (unsigned long)BIGLITTLE(*num++,*--num)));
|
||||
}
|
||||
|
||||
static void
|
||||
bnput64(char const *prompt, BNWORD64 const *num, unsigned len)
|
||||
{
|
||||
fputs(prompt, stdout);
|
||||
bnprint64(num, len);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* One of our tests uses a known prime. The following selections were
|
||||
* taken from the tables at the end of Hans Reisel's "Prime Numbers and
|
||||
* Computer Methods for Factorization", second edition - an excellent book.
|
||||
* (ISBN 0-8176-3743-5 ISBN 3-71283-3743-5)
|
||||
*/
|
||||
#if 0
|
||||
/* P31=1839605 17620282 38179967 87333633 from the factors of 3^256+2^256 */
|
||||
static unsigned char const prime[] = {
|
||||
0x17,0x38,0x15,0xBC,0x8B,0xBB,0xE9,0xEF,0x01,0xA9,0xFD,0x3A,0x01
|
||||
};
|
||||
#elif 0
|
||||
/* P48=40554942 04557502 46193993 36199835 4279613_2 73199617 from the same */
|
||||
static unsigned char const prime[] = {
|
||||
0x47,0x09,0x77,0x07,0xCF,0xFD,0xE1,0x54,0x3E,0x24,
|
||||
0xF7,0xF1,0x7A,0x3E,0x91,0x51,0xCC,0xC7,0xD4,0x01
|
||||
};
|
||||
#elif 0
|
||||
/*
|
||||
* P75 = 450 552871280 97906895 47687014 5808213_2
|
||||
* 05219565 99525911 399679128 66003_258 91979521
|
||||
* from the factors of 4^128+3+128
|
||||
* (The "026" and "062" are to prevent a Bad String from appearing here.)
|
||||
*/
|
||||
static unsigned char const prime[] = {
|
||||
0xFF,0x00,0xFF,0x00,0xFF,0x01,0x06,0x4F,0xF8,0xED,
|
||||
0xA3,0x37,0x23,0x2A,0x04,0xEA,0xF9,0x5F,0x30,0x4C,
|
||||
0xAE,0xCD, 026,0x4E, 062,0x10,0x04,0x7D,0x0D,0x79,
|
||||
0x01
|
||||
};
|
||||
#else
|
||||
/*
|
||||
* P75 = 6128 85659796 45277755 9123_2190 67300940
|
||||
* 51844953 78793489 59444670 35675855 57440257
|
||||
* from the factors of 5^128+4^128
|
||||
* (The "026" is to prevent a Bad String from appearing here.)
|
||||
*/
|
||||
static unsigned char const prime[] = {
|
||||
0x01,0x78,0x4B,0xA5,0xD3,0x30,0x03,0xEB,0x73,0xE6,
|
||||
0x0F,0x4E,0x31,0x7D,0xBC,0xE2,0xA0,0xD4, 026,0x3F,
|
||||
0x3C,0xEA,0x1B,0x44,0xAD,0x39,0xE7,0xE5,0xAD,0x19,
|
||||
0x67,0x01
|
||||
};
|
||||
#endif
|
||||
|
||||
static int
|
||||
usage(char const *name)
|
||||
{
|
||||
ZRTP_LOG(3, (_ZTU_, "Usage: %s [modbits [expbits [expbits2]]"
|
||||
"With no arguments, just runs test suite. If modbits is given, runs\n"
|
||||
"quick validation test, then runs timing tests of modular exponentiation.\n"
|
||||
"If expbits is given, it is used as an exponent size, otherwise it defaults\n"
|
||||
"to the same as modbits. If expbits2 is given it is used as the second\n"
|
||||
"exponent size in the double-exponentiation tests, otherwise it defaults\n"
|
||||
"to the same as expbits. All are limited to %u bits.\n",
|
||||
name, (unsigned)MAXBITS));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* for libzrtp support */
|
||||
int
|
||||
bntest_main(int argc, char **argv)
|
||||
{
|
||||
unsigned i, j, k, l, m;
|
||||
int z;
|
||||
BNWORD64 t, carry, borrow;
|
||||
BNWORD64 a[SIZE], b[SIZE], c[SIZE], d[SIZE];
|
||||
BNWORD64 e[SIZE], f[SIZE];
|
||||
static BNWORD64 entries[sizeof(prime)*2][(sizeof(prime)-1)/(64/8)+1];
|
||||
BNWORD64 *array[sizeof(prime)*2];
|
||||
unsigned long modbits = 0, expbits = 0, expbits2 = 0;
|
||||
char *p;
|
||||
#define A BIGLITTLE((a+SIZE),a)
|
||||
#define B BIGLITTLE((b+SIZE),b)
|
||||
#define C BIGLITTLE((c+SIZE),c)
|
||||
#define D BIGLITTLE((d+SIZE),d)
|
||||
#define E BIGLITTLE((e+SIZE),e)
|
||||
#define F BIGLITTLE((f+SIZE),f)
|
||||
static unsigned const smallprimes[] = {
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43
|
||||
};
|
||||
|
||||
/* Set up array for precomputed modexp */
|
||||
for (i = 0; i < sizeof(array)/sizeof(*array); i++)
|
||||
array[i] = entries[i] BIG(+ SIZE);
|
||||
|
||||
srand64(1);
|
||||
|
||||
puts(BIGLITTLE("Big-endian machine","Little-endian machine"));
|
||||
|
||||
if (argc >= 2) {
|
||||
modbits = strtoul(argv[1], &p, 0);
|
||||
if (!modbits || *p) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Invalid modbits: %s", argv[1]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if (argc >= 3) {
|
||||
expbits = strtoul(argv[2], &p, 0);
|
||||
if (!expbits || *p) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Invalid expbits: %s", argv[2]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
expbits2 = expbits;
|
||||
}
|
||||
if (argc >= 4) {
|
||||
expbits2 = strtoul(argv[3], &p, 0);
|
||||
if (!expbits2 || *p) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Invalid expbits2: %s", argv[3]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
if (argc >= 5) {
|
||||
ZRTP_LOG(1, (_ZTU_, "Too many arguments: %s", argv[4]));
|
||||
return usage(argv[0]);
|
||||
}
|
||||
|
||||
/* B is a nice not-so-little prime */
|
||||
lbnInsertBigBytes_64(B, prime, 0, sizeof(prime));
|
||||
((unsigned char *)c)[0] = 0;
|
||||
lbnInsertBigBytes_64(B, (unsigned char *)c, sizeof(prime), 1);
|
||||
lbnExtractBigBytes_64(B, (unsigned char *)c, 0, sizeof(prime)+1);
|
||||
i = (sizeof(prime)-1)/(64/8)+1; /* Size of array in words */
|
||||
if (((unsigned char *)c)[0] ||
|
||||
memcmp(prime, (unsigned char *)c+1, sizeof(prime)) != 0)
|
||||
{
|
||||
ZRTP_LOG(3, (_ZTU_, "Input != output!: "));
|
||||
for (k = 0; k < sizeof(prime); k++)
|
||||
ZRTP_LOG(3, (_ZTU_, "%02X ", prime[k]));
|
||||
putchar('\n');
|
||||
for (k = 0; k < sizeof(prime)+1; k++)
|
||||
ZRTP_LOG(3, (_ZTU_, "%02X ", ((unsigned char *)c)[k]));
|
||||
putchar('\n');
|
||||
bnput64("p = ", B, i);
|
||||
|
||||
}
|
||||
|
||||
/* Timing test code - only if requested on the command line */
|
||||
if (modbits) {
|
||||
#if CLOCK_AVAIL
|
||||
timetype start, stop;
|
||||
unsigned long cursec, expsec, twoexpsec, dblexpsec;
|
||||
unsigned curms, expms, twoexpms, dblexpms;
|
||||
|
||||
expsec = twoexpsec = dblexpsec = 0;
|
||||
expms = twoexpms = dblexpms = 0;
|
||||
#endif
|
||||
|
||||
lbnCopy_64(C,B,i);
|
||||
lbnSub1_64(C,i,1); /* C is exponent: p-1 */
|
||||
|
||||
puts("Testing modexp with a known prime. "
|
||||
"All results should be 1.");
|
||||
bnput64("p = ", B, i);
|
||||
bnput64("p-1 = ", C, i);
|
||||
z = lbnTwoExpMod_64(A, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput64("2^(p-1) mod p = ", A, i);
|
||||
for (j = 0; j < 10; j++) {
|
||||
randnum(A,i);
|
||||
(void)lbnDiv_64(D,A,i,B,i);
|
||||
|
||||
bnput64("a = ", A, i);
|
||||
z = lbnExpMod_64(D, A, i, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput64("a^(p-1) mod p = ", D, i);
|
||||
|
||||
z = lbnBasePrecompBegin_64(array, (sizeof(prime)*8+4)/5, 5,
|
||||
A, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
BIGLITTLE(D[-1],D[0]) = -1;
|
||||
z = lbnBasePrecompExp_64(D, (BNWORD64 const * const *)array,
|
||||
5, C, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput64("a^(p-1) mod p = ", D, i);
|
||||
|
||||
for (k = 0; k < 5; k++) {
|
||||
randnum(E,i);
|
||||
bnput64("e = ", E, i);
|
||||
z = lbnExpMod_64(D, A, i, E, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput64("a^e mod p = ", D, i);
|
||||
z = lbnBasePrecompExp_64(D, (BNWORD64 const * const *)array,
|
||||
5, E, i, B, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
bnput64("a^e mod p = ", D, i);
|
||||
}
|
||||
}
|
||||
|
||||
ZRTP_LOG(3, (_ZTU_, "\n"
|
||||
"Timing exponentiations modulo a %d-bit modulus, i.e.\n"
|
||||
"2^<%d> mod <%d> bits, <%d>^<%d> mod <%d> bits and\n"
|
||||
"<%d>^<%d> * <%d>^<%d> mod <%d> bits",
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)modbits, (int)expbits, (int)modbits, (int)expbits2,
|
||||
(int)modbits));
|
||||
|
||||
i = ((int)modbits-1)/64+1;
|
||||
k = ((int)expbits-1)/64+1;
|
||||
l = ((int)expbits2-1)/64+1;
|
||||
for (j = 0; j < 25; j++) {
|
||||
randnum(A,i); /* Base */
|
||||
randnum(B,k); /* Exponent */
|
||||
randnum(C,i); /* Modulus */
|
||||
randnum(D,i); /* Base2 */
|
||||
randnum(E,l); /* Exponent */
|
||||
/* Clip bases and mod to appropriate number of bits */
|
||||
t = ((BNWORD64)2<<((modbits-1)%64)) - 1;
|
||||
*(BIGLITTLE(A-i,A+i-1)) &= t;
|
||||
*(BIGLITTLE(C-i,C+i-1)) &= t;
|
||||
*(BIGLITTLE(D-i,D+i-1)) &= t;
|
||||
/* Make modulus large (msbit set) and odd (lsbit set) */
|
||||
*(BIGLITTLE(C-i,C+i-1)) |= (t >> 1) + 1;
|
||||
BIGLITTLE(C[-1],C[0]) |= 1;
|
||||
|
||||
/* Clip exponent to appropriate number of bits */
|
||||
t = ((BNWORD64)2<<((expbits-1)%64)) - 1;
|
||||
*(BIGLITTLE(B-k,B+k-1)) &= t;
|
||||
/* Make exponent large (msbit set) */
|
||||
*(BIGLITTLE(B-k,B+k-1)) |= (t >> 1) + 1;
|
||||
/* The same for exponent 2 */
|
||||
t = ((BNWORD64)2<<((expbits2-1)%64)) - 1;
|
||||
*(BIGLITTLE(E-l,E+l-1)) &= t;
|
||||
*(BIGLITTLE(E-l,E+l-1)) |= (t >> 1) + 1;
|
||||
|
||||
m = lbnBits_64(A, i);
|
||||
if (m > (unsigned)modbits) {
|
||||
bnput64("a = ", a, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be <= %d", m, (int)modbits));
|
||||
}
|
||||
m = lbnBits_64(B, k);
|
||||
if (m != (unsigned)expbits) {
|
||||
bnput64("b = ", b, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be %d", m, (int)expbits));
|
||||
}
|
||||
m = lbnBits_64(C, i);
|
||||
if (m != (unsigned)modbits) {
|
||||
bnput64("c = ", c, k);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be %d", m, (int)modbits));
|
||||
}
|
||||
m = lbnBits_64(D, i);
|
||||
if (m > (unsigned)modbits) {
|
||||
bnput64("d = ", d, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be <= %d", m, (int)modbits));
|
||||
}
|
||||
m = lbnBits_64(E, l);
|
||||
if (m != (unsigned)expbits2) {
|
||||
bnput64("e = ", e, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "%u bits, should be %d", m, (int)expbits2));
|
||||
}
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&start);
|
||||
#endif
|
||||
z = lbnTwoExpMod_64(A, B, k, C, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
twoexpsec += cursec = sec(stop);
|
||||
twoexpms += curms = msec(stop);
|
||||
|
||||
ZRTP_LOG(3, (_ZTU_, "2^<%d>:%4lu.%03u ", (int)expbits, cursec, curms));
|
||||
#else
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d> ", (int)modbits, (int)expbits));
|
||||
#endif
|
||||
fflush(stdout);
|
||||
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&start);
|
||||
#endif
|
||||
z = lbnExpMod_64(A, A, i, B, k, C, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
expsec += cursec = sec(stop);
|
||||
expms += curms = msec(stop);
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d>:%4lu.%03u ",(int)modbits, (int)expbits, cursec, curms));
|
||||
fflush(stdout);
|
||||
|
||||
gettime(&start);
|
||||
z = lbnDoubleExpMod_64(D, A, i, B, k, D, i, E, l,C,i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
gettime(&stop);
|
||||
subtime(stop, start);
|
||||
dblexpsec += cursec = sec(stop);
|
||||
dblexpms += curms = msec(stop);
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d>*<%d>^<%d>:%4lu.%03u",
|
||||
(int)modbits, (int)expbits,
|
||||
(int)modbits, (int)expbits2,
|
||||
cursec, curms));
|
||||
#else
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d>*<%d>^<%d>",
|
||||
(int)modbits, (int)expbits,
|
||||
(int)modbits, (int)expbits2));
|
||||
#endif
|
||||
}
|
||||
#if CLOCK_AVAIL
|
||||
twoexpms += (twoexpsec % j) * 1000;
|
||||
ZRTP_LOG(3, (_ZTU_, "2^<%d> mod <%d> bits AVERAGE: %4lu.%03u s",
|
||||
(int)expbits, (int)modbits, twoexpsec/j, twoexpms/j));
|
||||
expms += (expsec % j) * 1000;
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d> mod <%d> bits AVERAGE: %4lu.%03u s",
|
||||
(int)modbits, (int)expbits, (int)modbits, expsec/j, expms/j));
|
||||
dblexpms += (dblexpsec % j) * 1000;
|
||||
ZRTP_LOG(3, (_ZTU_, "<%d>^<%d> * <%d>^<%d> mod <%d> bits AVERAGE:"
|
||||
" %4lu.%03u s",
|
||||
(int)modbits, (int)expbits, (int)modbits,
|
||||
(int)expbits2,
|
||||
(int)modbits, dblexpsec/j, dblexpms/j));
|
||||
|
||||
putchar('\n');
|
||||
#endif
|
||||
}
|
||||
|
||||
puts("Beginning 1000 interations of sanity checking.\n"
|
||||
"Any output indicates a bug. No output is very strong\n"
|
||||
"evidence that all the important low-level bignum routines\n"
|
||||
"are working properly.\n");
|
||||
|
||||
/*
|
||||
* If you change this loop to have an iteration 0, all results
|
||||
* are primted on that iteration. Useful to see what's going
|
||||
* on in case of major wierdness, but it produces a *lot* of
|
||||
* output.
|
||||
*/
|
||||
#if (ZRTP_PLATFORM == ZP_WINCE) || (ZRTP_PLATFORM == ZP_SYMBIAN)
|
||||
for (j = 1; j <= 20; j++) {
|
||||
#else
|
||||
for (j = 1; j <= 1000; j++) {
|
||||
#endif
|
||||
/* Do the tests for lots of different number sizes. */
|
||||
for (i = 1; i <= SIZE/2; i++) {
|
||||
/* Make a random number i words long */
|
||||
do {
|
||||
randnum(A,i);
|
||||
} while (lbnNorm_64(A,i) < i);
|
||||
|
||||
/* Checl lbnCmp - does a == a? */
|
||||
if (lbnCmp_64(A,A,i) || !j) {
|
||||
bnput64("a = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> a) = %d", lbnCmp_64(A,A,i)));
|
||||
}
|
||||
|
||||
memcpy(c, a, sizeof(a));
|
||||
|
||||
/* Check that the difference, after copy, is good. */
|
||||
if (lbnCmp_64(A,C,i) || !j) {
|
||||
bnput64("a = ", A, i);
|
||||
bnput64("c = ", C, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_64(A,C,i)));
|
||||
}
|
||||
|
||||
/* Generate a non-zero random t */
|
||||
do {
|
||||
t = rand64();
|
||||
} while (!t);
|
||||
|
||||
/*
|
||||
* Add t to A. Check that:
|
||||
* - lbnCmp works in both directions, and
|
||||
* - A + t is greater than A. If there was a carry,
|
||||
* the result, less the carry, should be *less*
|
||||
* than A.
|
||||
*/
|
||||
carry = lbnAdd1_64(A,i,t);
|
||||
if (lbnCmp_64(A,C,i) + lbnCmp_64(C,A,i) != 0 ||
|
||||
lbnCmp_64(A,C,i) != (carry ? -1 : 1) || !j)
|
||||
{
|
||||
bnput64("c = ", C, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "t = %lX", (unsigned long)t));
|
||||
bnput64("a = c+t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "carry = %lX", (unsigned long)carry));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_64(A,C,i)));
|
||||
ZRTP_LOG(3, (_ZTU_, "(c <=> a) = %d", lbnCmp_64(C,A,i)));
|
||||
}
|
||||
|
||||
/* Subtract t again */
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnSub1_64(A,i,t);
|
||||
|
||||
if (carry != borrow || lbnCmp_64(A,C,i) || !j) {
|
||||
bnput64("a = ", C, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "t = %lX", (unsigned long)t));
|
||||
lbnAdd1_64(A,i,t);
|
||||
bnput64("a += t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Carry = %lX", (unsigned long)carry));
|
||||
lbnSub1_64(A,i,t);
|
||||
bnput64("a -= t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Borrow = %lX", (unsigned long)borrow));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_64(A,C,i)));
|
||||
}
|
||||
|
||||
/* Generate a random B */
|
||||
do {
|
||||
randnum(B,i);
|
||||
} while (lbnNorm_64(B,i) < i);
|
||||
|
||||
carry = lbnAddN_64(A,B,i);
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnSubN_64(A,B,i);
|
||||
|
||||
if (carry != borrow || lbnCmp_64(A,C,i) || !j) {
|
||||
bnput64("a = ", C, i);
|
||||
bnput64("b = ", B, i);
|
||||
bnput64("a += b = ", D, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Carry = %lX", (unsigned long)carry));
|
||||
bnput64("a -= b = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Borrow = %lX", (unsigned long)borrow));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_64(A,C,i)));
|
||||
}
|
||||
|
||||
/* D = B * t */
|
||||
lbnMulN1_64(D, B, i, t);
|
||||
memcpy(e, d, sizeof(e));
|
||||
/* D = A + B * t, "carry" is overflow */
|
||||
borrow = *(BIGLITTLE(D-i-1,D+i)) += lbnAddN_64(D,A,i);
|
||||
|
||||
carry = lbnMulAdd1_64(A, B, i, t);
|
||||
|
||||
/* Did MulAdd get the same answer as mul then add? */
|
||||
if (carry != borrow || lbnCmp_64(A, D, i) || !j) {
|
||||
bnput64("a = ", C, i);
|
||||
bnput64("b = ", B, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "t = %lX", (unsigned long)t));
|
||||
bnput64("e = b * t = ", E, i+1);
|
||||
bnput64(" a + e = ", D, i+1);
|
||||
bnput64("a + b * t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "carry = %lX", (unsigned long)carry));
|
||||
}
|
||||
|
||||
memcpy(d, a, sizeof(a));
|
||||
borrow = lbnMulSub1_64(A, B, i, t);
|
||||
|
||||
/* Did MulSub perform the inverse of MulAdd */
|
||||
if (carry != borrow || lbnCmp_64(A,C,i) || !j) {
|
||||
bnput64(" a = ", C, i);
|
||||
bnput64(" b = ", B, i);
|
||||
bnput64("a += b*t = ", D, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Carry = %lX", (unsigned long)carry));
|
||||
bnput64("a -= b*t = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "Borrow = %lX", (unsigned long)borrow));
|
||||
ZRTP_LOG(3, (_ZTU_, "(a <=> c) = %d", lbnCmp_64(A,C,i)));
|
||||
bnput64("b*t = ", E, i+1);
|
||||
}
|
||||
/* At this point we're done with t, so it's scratch */
|
||||
#if 0
|
||||
/* Extra debug code */
|
||||
lbnMulN1_64(C, A, i, BIGLITTLE(B[-1],B[0]));
|
||||
bnput64("a * b[0] = ", C, i+1);
|
||||
for (k = 1; k < i; k++) {
|
||||
carry = lbnMulAdd1_64(BIGLITTLE(C-k,C+k), A, i,
|
||||
*(BIGLITTLE(B-1-k,B+k)));
|
||||
*(BIGLITTLE(C-i-k,C+i+k)) = carry;
|
||||
bnput64("a * b[x] = ", C, i+k+1);
|
||||
}
|
||||
|
||||
lbnMulN1_64(D, B, i, BIGLITTLE(A[-1],A[0]));
|
||||
bnput64("b * a[0] = ", D, i+1);
|
||||
for (k = 1; k < i; k++) {
|
||||
carry = lbnMulAdd1_64(BIGLITTLE(D-k,D+k), B, i,
|
||||
*(BIGLITTLE(A-1-k,A+k)));
|
||||
*(BIGLITTLE(D-i-k,D+i+k)) = carry;
|
||||
bnput64("b * a[x] = ", D, i+k+1);
|
||||
}
|
||||
#endif
|
||||
/* Does Mul work both ways symmetrically */
|
||||
lbnMul_64(C,A,i,B,i);
|
||||
lbnMul_64(D,B,i,A,i);
|
||||
if (lbnCmp_64(C,D,i+i) || !j) {
|
||||
bnput64("a = ", A, i);
|
||||
bnput64("b = ", B, i);
|
||||
bnput64("a * b = ", C, i+i);
|
||||
bnput64("b * a = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a*b <=> b*a) = %d", lbnCmp_64(C,D,i+i)));
|
||||
}
|
||||
/* Check multiplication modulo some small things */
|
||||
/* 30030 = 2*3*5*11*13 */
|
||||
k = lbnModQ_64(C, i+i, 30030);
|
||||
for (l = 0;
|
||||
l < sizeof(smallprimes)/sizeof(*smallprimes);
|
||||
l++)
|
||||
{
|
||||
m = smallprimes[l];
|
||||
t = lbnModQ_64(C, i+i, m);
|
||||
carry = lbnModQ_64(A, i, m);
|
||||
borrow = lbnModQ_64(B, i, m);
|
||||
if (t != (carry * borrow) % m) {
|
||||
bnput64("a = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a mod %u = %u", m, (unsigned)carry));
|
||||
bnput64("b = ", B, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "b mod %u = %u", m, (unsigned)borrow));
|
||||
bnput64("a*b = ", C, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a*b mod %u = %u", m, (unsigned)t));
|
||||
ZRTP_LOG(3, (_ZTU_, "expected %u", (unsigned)((carry*borrow)%m)));
|
||||
}
|
||||
/* Verify that (C % 30030) % m == C % m */
|
||||
if (m <= 13 && t != k % m) {
|
||||
ZRTP_LOG(3, (_ZTU_, "c mod 30030 = %u mod %u= %u", k, m, k%m));
|
||||
ZRTP_LOG(3, (_ZTU_, "c mod %u = %u", m, (unsigned)t));
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate an F less than A and B */
|
||||
do {
|
||||
randnum(F,i);
|
||||
} while (lbnCmp_64(F,A,i) >= 0 ||
|
||||
lbnCmp_64(F,B,i) >= 0);
|
||||
|
||||
/* Add F to D (remember, D = A*B) */
|
||||
lbnAdd1_64(BIGLITTLE(D-i,D+i), i, lbnAddN_64(D, F, i));
|
||||
memcpy(c, d, sizeof(d));
|
||||
|
||||
/*
|
||||
* Divide by A and check that quotient and remainder
|
||||
* match (remainder should be F, quotient should be B)
|
||||
*/
|
||||
t = lbnDiv_64(E,C,i+i,A,i);
|
||||
if (t || lbnCmp_64(E,B,i) || lbnCmp_64(C, F, i) || !j) {
|
||||
bnput64("a = ", A, i);
|
||||
bnput64("b = ", B, i);
|
||||
bnput64("f = ", F, i);
|
||||
bnput64("a * b + f = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "qhigh = %lX", (unsigned long)t));
|
||||
bnput64("(a*b+f) / a = ", E, i);
|
||||
bnput64("(a*b+f) % a = ", C, i);
|
||||
}
|
||||
|
||||
memcpy(c, d, sizeof(d));
|
||||
|
||||
/* Divide by B and check similarly */
|
||||
t = lbnDiv_64(E,C,i+i,B,i);
|
||||
if (lbnCmp_64(E,A,i) || lbnCmp_64(C, F, i) || !j) {
|
||||
bnput64("a = ", A, i);
|
||||
bnput64("b = ", B, i);
|
||||
bnput64("f = ", F, i);
|
||||
bnput64("a * b + f = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "qhigh = %lX", (unsigned long)t));
|
||||
bnput64("(a*b+f) / b = ", E, i);
|
||||
bnput64("(a*b+f) % b = ", C, i);
|
||||
}
|
||||
|
||||
/* Check that A*A == A^2 */
|
||||
lbnMul_64(C,A,i,A,i);
|
||||
lbnSquare_64(D,A,i);
|
||||
if (lbnCmp_64(C,D,i+i) || !j) {
|
||||
bnput64("a*a = ", C, i+i);
|
||||
bnput64("a^2 = ", D, i+i);
|
||||
ZRTP_LOG(3, (_ZTU_, "(a * a == a^2) = %d", lbnCmp_64(C,D,i+i)));
|
||||
}
|
||||
|
||||
/* Compute a GCD */
|
||||
lbnCopy_64(C,A,i);
|
||||
lbnCopy_64(D,B,i);
|
||||
z = lbnGcd_64(C, i, D, i, &k);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
/* z = 1 if GCD in D; z = 0 if GCD in C */
|
||||
|
||||
/* Approximate check that the GCD came out right */
|
||||
for (l = 0;
|
||||
l < sizeof(smallprimes)/sizeof(*smallprimes);
|
||||
l++)
|
||||
{
|
||||
m = smallprimes[l];
|
||||
t = lbnModQ_64(z ? D : C, k, m);
|
||||
carry = lbnModQ_64(A, i, m);
|
||||
borrow = lbnModQ_64(B, i, m);
|
||||
if (!t != (!carry && !borrow)) {
|
||||
bnput64("a = ", A, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a mod %u = %u", m, (unsigned)carry));
|
||||
bnput64("b = ", B, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "b mod %u = %u", m, (unsigned)borrow));
|
||||
bnput64("gcd(a,b) = ", z ? D : C, k);
|
||||
ZRTP_LOG(3, (_ZTU_, "gcd(a,b) mod %u = %u", m, (unsigned)t));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Do some Montgomery operations
|
||||
* Start with A > B, and also place a copy of B into C.
|
||||
* Then make A odd so it can be a Montgomery modulus.
|
||||
*/
|
||||
if (lbnCmp_64(A, B, i) < 0) {
|
||||
memcpy(c, a, sizeof(c));
|
||||
memcpy(a, b, sizeof(a));
|
||||
memcpy(b, c, sizeof(b));
|
||||
} else {
|
||||
memcpy(c, b, sizeof(c));
|
||||
}
|
||||
BIGLITTLE(A[-1],A[0]) |= 1;
|
||||
|
||||
/* Convert to and from */
|
||||
lbnToMont_64(B, i, A, i);
|
||||
lbnFromMont_64(B, A, i);
|
||||
if (lbnCmp_64(B, C, i)) {
|
||||
memcpy(b, c, sizeof(c));
|
||||
bnput64("mod = ", A, i);
|
||||
bnput64("input = ", B, i);
|
||||
lbnToMont_64(B, i, A, i);
|
||||
bnput64("mont = ", B, i);
|
||||
lbnFromMont_64(B, A, i);
|
||||
bnput64("output = ", B, i);
|
||||
}
|
||||
/* E = B^5 (mod A), no Montgomery ops */
|
||||
lbnSquare_64(E, B, i);
|
||||
(void)lbnDiv_64(BIGLITTLE(E-i,E+i),E,i+i,A,i);
|
||||
lbnSquare_64(D, E, i);
|
||||
(void)lbnDiv_64(BIGLITTLE(D-i,D+i),D,i+i,A,i);
|
||||
lbnMul_64(E, D, i, B, i);
|
||||
(void)lbnDiv_64(BIGLITTLE(E-i,E+i),E,i+i,A,i);
|
||||
|
||||
/* D = B^5, using ExpMod */
|
||||
BIGLITTLE(F[-1],F[0]) = 5;
|
||||
z = lbnExpMod_64(D, B, i, F, 1, A, i);
|
||||
if (z < 0)
|
||||
goto nomem;
|
||||
if (lbnCmp_64(D, E, i) || !j) {
|
||||
bnput64("mod = ", A, i);
|
||||
bnput64("input = ", B, i);
|
||||
bnput64("input^5 = ", E, i);
|
||||
bnput64("input^5 = ", D, i);
|
||||
ZRTP_LOG(3, (_ZTU_, "a>b (x <=> y) = %d", lbnCmp_64(D,E,i)));
|
||||
}
|
||||
/* TODO: Test lbnTwoExpMod, lbnDoubleExpMod */
|
||||
} /* for (i) */
|
||||
ZRTP_LOG(3, (_ZTU_, "\r%d ", j));
|
||||
fflush(stdout);
|
||||
} /* for (j) */
|
||||
ZRTP_LOG(3, (_ZTU_, "%d iterations of up to %d 64-bit words completed.", j-1, i-1));
|
||||
return 0;
|
||||
nomem:
|
||||
ZRTP_LOG(3, (_ZTU_, "Out of memory"));
|
||||
return 1;
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
# Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
# For licensing and other legal details, see the file legal.c.
|
||||
#
|
||||
./configure CFLAGS="$CFLAGS -O3 -g0 -W -Wall"
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
# Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
# For licensing and other legal details, see the file legal.c.
|
||||
#
|
||||
./configure CFLAGS="$CFLAGS -O0 -g3"
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
dnl Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
dnl For licensing and other legal details, see the file legal.c.
|
||||
dnl
|
||||
dnl This file in input to autoconf. It consists of a series of m4
|
||||
dnl macros which expand to produce the shell script "configure".
|
||||
dnl Anything which is not an m4 macro is copied directly to the output.
|
||||
dnl
|
||||
dnl Start things up. If the specified file doesn't exist, configure
|
||||
dnl will complain.
|
||||
AC_INIT(lbn16.c)
|
||||
|
||||
dnl The following tests need to know that we intend to produce a config.h
|
||||
dnl file, even though this won't expand to any shell script code until
|
||||
dnl AC_OUTPUT time. Name it bnconfig.hin to avoid MS-LOSS.
|
||||
AC_CONFIG_HEADER(bnconfig.h:bnconfig.hin)
|
||||
|
||||
dnl Checks for programs.
|
||||
|
||||
# Find a compiler to use.
|
||||
# Check 1) The $CC environment varaible, 2) egcc, 3) gcc, 4) acc, and 5) cc.
|
||||
dnl This used to be just AC-CHECK-PROGS(CC, gcc acc, cc), but...
|
||||
# This deals with brain-damaged Sun systems that place a bogus cc or
|
||||
# acc executable in the $PATH, which just prints an error and exit.
|
||||
# We deal with this by actually trying to compile a trivial test program.
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
|
||||
AC_MSG_CHECKING(For C compiler (cached))
|
||||
CC="$ac_cv_prog_CC"
|
||||
AC_MSG_RESULT($CC)
|
||||
elif test -n "$CC"; then
|
||||
ac_cv_prog_CC="$CC" # Let the user override the test.
|
||||
AC_MSG_CHECKING(For C compiler)
|
||||
AC_MSG_RESULT($CC)
|
||||
else
|
||||
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
|
||||
echo 'main(){return 0;}' > conftest.$ac_ext
|
||||
for ac_prog in egcc gcc acc cc; do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
AC_MSG_CHECKING(for $ac_word)
|
||||
for ac_dir in $PATH; do
|
||||
test -z "$ac_dir" && ac_dir=.
|
||||
if test -x "$ac_dir/$ac_word"; then
|
||||
CC="$ac_prog"
|
||||
if eval $ac_compile; then
|
||||
ac_cv_prog_CC="$ac_prog"
|
||||
fi
|
||||
break
|
||||
fi
|
||||
done
|
||||
CC="$ac_cv_prog_CC"
|
||||
if test -n "$CC"; then
|
||||
AC_MSG_RESULT($ac_dir/$CC)
|
||||
break;
|
||||
fi
|
||||
AC_MSG_RESULT(no)
|
||||
done
|
||||
if test ! -n "$CC"; then
|
||||
AC_MSG_ERROR(no C compiler found)
|
||||
fi
|
||||
IFS="$ac_save_ifs"
|
||||
rm -f conftest*
|
||||
fi
|
||||
AC_SUBST(CC)
|
||||
|
||||
AC_CACHE_CHECK(whether we are using GNU CC, ac_cv_prog_gcc,
|
||||
[dnl The semicolon is to pacify NeXT's syntax-checking cpp.
|
||||
cat > conftest.c <<EOF
|
||||
#ifdef __GNUC__
|
||||
yes;
|
||||
#endif
|
||||
EOF
|
||||
if ${CC-cc} -E conftest.c 2>&AC_FD_CC | egrep yes >/dev/null 2>&1; then
|
||||
ac_cv_prog_gcc=yes
|
||||
else
|
||||
ac_cv_prog_gcc=no
|
||||
fi])
|
||||
|
||||
if test $ac_cv_prog_gcc = yes; then
|
||||
if test "${CFLAGS+set}" != set; then
|
||||
AC_CACHE_CHECK(whether ${CC-cc} accepts -g, ac_cv_prog_gcc_g,
|
||||
[echo 'void f(){}' > conftest.c
|
||||
if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
|
||||
ac_cv_prog_gcc_g=yes
|
||||
else
|
||||
ac_cv_prog_gcc_g=no
|
||||
fi
|
||||
rm -f conftest*
|
||||
])
|
||||
fi
|
||||
|
||||
# If we're using GCC, perform some Deep Magic to enable the result to
|
||||
# link cleanly with code compiled with a compiler that doesn't understand
|
||||
# GCC's support library (-lgcc). Do a link, to relocatable object form,
|
||||
# with just -lgcc. If it's not GCC, do the normal -c thing.
|
||||
# These substitutions are used in the Makefile to force that behaviour.
|
||||
GCCMAGIC1='-Wl,-r -nostdlib'
|
||||
GCCMAGIC2=-lgcc
|
||||
else
|
||||
GCCMAGIC1=-c
|
||||
GCCMAGIC2=
|
||||
fi
|
||||
AC_SUBST(GCCMAGIC1)
|
||||
AC_SUBST(GCCMAGIC2)
|
||||
|
||||
# Now, figure out the CFLAGS we want. If the user didn't *ask*
|
||||
# for CFLAGS, we're going to use some ideas of our own.
|
||||
if test "${CFLAGS+set}" != set; then
|
||||
|
||||
# First, remember one useful thing that was just figured out,
|
||||
# namely whether the compiler can take -g with -O. (Most compilers
|
||||
# seem to do the opposite of what I want here - if you give both, -g
|
||||
# overrides and disables optimization.) This is only done for
|
||||
# gcc at the moment, and the no/yes combination is possible but
|
||||
# misleading
|
||||
if test $ac_cv_prog_gcc$ac_cv_prog_gcc_g = yesyes; then
|
||||
CFLAGS=-g
|
||||
else
|
||||
CFLAGS=""
|
||||
fi
|
||||
|
||||
# Now, the whole raison d'e^tre of this library is that it's *fast*.
|
||||
# So we are *not* happy with autoconf's normal conservative compilation
|
||||
# flags. Try to figure out what kind the compiler we're using and soup
|
||||
# things up a bit. Also turn on warnings if possible.
|
||||
# If it's GCC, crank up optimization to -O6, and try to add some
|
||||
# -m options, too.
|
||||
# Otherwise, it gets even more ad-hoc, but the test below works for the
|
||||
# SunPro C compiler and cranks it up to maximum optimization.
|
||||
dnl
|
||||
dnl Note that the situation here is actually *worse* than the usual
|
||||
dnl CPU-COMPANY-SYSTEM system type can detect, because it depends on
|
||||
dnl the C compiler. For example, all of the options below (as of the
|
||||
dnl time this is written) are available on a single machine!
|
||||
dnl Using compiler-specific checks rather than config.guess seems
|
||||
dnl entirely appropriate here.
|
||||
AC_MSG_CHECKING(for useful tuning options (\$TUNE))
|
||||
if test $ac_cv_prog_gcc = yes; then
|
||||
: ${WARN="-Wall -W -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings"}
|
||||
if test "${TUNE+set}" != set; then
|
||||
TUNE=-O6
|
||||
case `$CC -v 2>&1` in
|
||||
*gcc-lib/sparc-*)
|
||||
# Try to use the architecture-detecting tool with SunPro CC.
|
||||
if bn_tune=`(fpversion -foption) 2>/dev/null`; then
|
||||
if test "$bn_tune" = xcg92 || test "$bn_tune" = cg92; then
|
||||
TUNE="$TUNE -mv8"
|
||||
elif test "$bn_tune" != xcg89 && test "$bn_tune" != cg89; then
|
||||
TUNE="$TUNE -mv8"
|
||||
bn_tune_guess=yes
|
||||
fi
|
||||
else
|
||||
TUNE="$TUNE -mv8"
|
||||
bn_tune_guess=yes
|
||||
fi
|
||||
esac
|
||||
fi
|
||||
elif $CC -flags 2>&1 | grep SunSoft >/dev/null 2>&1; then
|
||||
if test "${WARN+set}" != set; then
|
||||
if $CC -flags 2>&1 | grep 'checking' | grep '^-vc' > /dev/null 2>&1; then
|
||||
WARN=-vc
|
||||
elif $CC -flags 2>&1 | grep 'checking' | grep '^-v ' > /dev/null 2>&1; then
|
||||
WARN=-v
|
||||
fi
|
||||
if $CC -flags 2>&1 | grep '^-xstrconst' > /dev/null 2>&1; then
|
||||
WARN="${WARN}${WARN+ }-xstrconst"
|
||||
fi
|
||||
fi
|
||||
# SunPro C compiler - now grok version and platform
|
||||
if test "${TUNE+set}" != set; then
|
||||
if $CC -flags 2>&1 | grep '^-xO.*5' >/dev/null 2>&1; then
|
||||
TUNE=-xO5
|
||||
else
|
||||
TUNE=-xO4
|
||||
fi
|
||||
# Architecture: -native iv avail., else as fpversion says, else guess -mv8
|
||||
if $CC -flags 2>&1 | grep '^-native' >/dev/null 2>&1; then
|
||||
TUNE="$TUNE -native"
|
||||
elif bn_tune=`(fpversion -foption) 2>/dev/null`; then
|
||||
TUNE="$TUNE -$bn_tune"
|
||||
elif $CC -flags 2>&1 | grep '^-xcg92' >/dev/null 2>&1; then
|
||||
TUNE="$TUNE -xcg92"
|
||||
bn_tune_guess=yes
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
bn_tune_set=${TUNE+set}
|
||||
# If nothing better is available, turn on -O
|
||||
: ${TUNE=-O}
|
||||
AC_MSG_RESULT(${TUNE-none})
|
||||
if test "$bn_tune_set" != set; then
|
||||
AC_MSG_WARN(not optimizing heavily - try setting \$CFLAGS)
|
||||
elif test "$bn_tune_guess" = yes; then
|
||||
AC_MSG_WARN([architecture guessed. If incorrect, use explicit \$TUNE.])
|
||||
fi
|
||||
AC_MSG_CHECKING(for useful warning options (\$WARN))
|
||||
AC_MSG_RESULT(${WARN-none})
|
||||
fi
|
||||
# ^^ End of "$(CFLAGS+set)" != set condition
|
||||
AC_SUBST(TUNE)
|
||||
AC_SUBST(WARN)
|
||||
|
||||
# Find "ranlib". Sone systems don't have or need ranlib. If so,
|
||||
# ":" (do nothing) is used instead.
|
||||
AC_PROG_RANLIB
|
||||
|
||||
dnl Checks for libraries.
|
||||
dnl (we don't have any)
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
|
||||
if test $ac_cv_header_stdc = yes; then
|
||||
AC_DEFINE(HAVE_ASSERT_H)
|
||||
AC_DEFINE(HAVE_LIMITS_H)
|
||||
AC_DEFINE(HAVE_STDLIB_H)
|
||||
AC_DEFINE(HAVE_STRING_H)
|
||||
|
||||
else # If non-ANSI, check for other brokenness.
|
||||
|
||||
AC_CHECK_HEADERS(assert.h limits.h stdlib.h string.h)
|
||||
|
||||
# Do we want to include memory.h?
|
||||
if test $ac_cv_header_string_h = no; then
|
||||
AC_CHECK_HEADERS(strings.h)
|
||||
ac_found=no
|
||||
else
|
||||
AC_MSG_CHECKING(whether string.h declares mem functions)
|
||||
AC_EGREP_HEADER(memset, string.h, ac_found=yes, ac_found=no)
|
||||
AC_MSG_RESULT($ac_found)
|
||||
fi
|
||||
# ac_found is now "yes" if string.h exists and declares the mem*
|
||||
# functions. If not, see if memory.h exists and include that
|
||||
# as well.
|
||||
if test $ac_found = no; then
|
||||
AC_CHECK_HEADER(memory,h. [AC_DEFINE(NEED_MEMORY_H)])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(whether <stdio.h> provides prototypes,
|
||||
bn_cv_header_stdio_protos,
|
||||
[AC_EGREP_HEADER(printf, stdio.h, bn_cv_header_stdio_protos=yes, bn_cv_header_stdio_protos=no)
|
||||
])
|
||||
if test $bn_cv_header_stdio_protos = no; then
|
||||
AC_DEFINE(NO_STDIO_PROTOS)
|
||||
fi
|
||||
|
||||
fi
|
||||
# ^^ End of non-ANSI header brokenness tests (first part)
|
||||
|
||||
AC_CACHE_CHECK(whether <string.h> declares mem* wrong.,
|
||||
bn_cv_header_mem_broken,
|
||||
[AC_EGREP_HEADER(memcpy.*char, string.h, bn_cv_header_mem_broken=yes, bn_cv_header_mem_broken=no)
|
||||
])
|
||||
if test $bn_cv_header_mem_broken = yes; then
|
||||
AC_DEFINE(MEM_PROTOS_BROKEN)
|
||||
fi
|
||||
|
||||
# SunOS 4.1.x acc's <assert.h> is broken
|
||||
AC_CACHE_CHECK(whether <assert.h> is broken and needs <stdio.h>,
|
||||
bn_cv_header_assert_needs_stdio,
|
||||
[AC_EGREP_CPP(stderr,
|
||||
[#include <assert.h>
|
||||
assert(foo)
|
||||
], bn_cv_header_assert_needs_stdio=yes, bn_cv_header_assert_needs_stdio=no)
|
||||
])
|
||||
if test $bn_cv_header_assert_needs_stdio = yes; then
|
||||
AC_DEFINE(ASSERT_NEEDS_STDIO)
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(whether <assert.h> is broken and needs <stdlib.h>,
|
||||
bn_cv_header_assert_needs_stdlib,
|
||||
[AC_EGREP_CPP(exit,
|
||||
[#include <assert.h>
|
||||
assert(foo)
|
||||
], bn_cv_header_assert_needs_stdlib=yes, bn_cv_header_assert_needs_stdlib=no)
|
||||
])
|
||||
if test $bn_cv_header_assert_needs_stdlib = yes; then
|
||||
AC_DEFINE(ASSERT_NEEDS_STDLIB)
|
||||
fi
|
||||
|
||||
# Check that we have <sys/time.h> explicitly.
|
||||
AC_CHECK_HEADERS(sys/time.h)
|
||||
AC_HEADER_TIME
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
# Verify that the compiler supports const, and that it works.
|
||||
# A number of compilers sort of support const, but they have bugs
|
||||
# that will prevent valid programs from compiling.
|
||||
AC_C_CONST
|
||||
|
||||
# See if we have size_t. (If not, define it as unsigned.)
|
||||
AC_TYPE_SIZE_T
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_CHECK_FUNCS(clock_gettime gethrvtime getrusage)
|
||||
dnl The following are for real-time clocks only as of yet.
|
||||
dnl AC_CHECK_FUNCS(clock_getres gethrtime gettimeofday getitimer setitimer ftime)
|
||||
|
||||
# If we don't have ANSI C, see if a few functions are missing that
|
||||
# we've noticed the lack of before.
|
||||
if test $ac_cv_header_stdc = yes; then
|
||||
AC_DEFINE(HAVE_CLOCK)
|
||||
AC_DEFINE(HAVE_TIME)
|
||||
AC_DEFINE(HAVE_MEMMOVE)
|
||||
AC_DEFINE(HAVE_MEMCPY)
|
||||
else
|
||||
AC_CHECK_FUNCS(clock time memmove memcpy)
|
||||
fi
|
||||
# ^^ End of non-ANSI header brokenness tests (second part)
|
||||
|
||||
# libzrtp - fix it back
|
||||
#AC_OUTPUT_SUBDIRS(test)
|
||||
|
||||
# The big bang! Produce the output files. This is config.cache, and
|
||||
# config.status, which builds the config.h file and a long list of
|
||||
# Makefiles.
|
||||
dnl The value specified to AC_CONFIG_HEADER at the top if the file is
|
||||
dnl used here to produce bnconfig.h.
|
||||
AC_OUTPUT(Makefile)
|
||||
|
||||
echo
|
||||
echo bnlib is now configured for a generic installation.
|
||||
echo If you with assembly-language support, edit the Makefile according
|
||||
echo to the instructions in README.bn.
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
#ifndef CPUTIME_H
|
||||
#define CPUTIME_H
|
||||
|
||||
/*
|
||||
* Figure out what clock to use. Each possibility can be specifically
|
||||
* enabled or disabled by predefining USE_XXX to 1 or 0. For some,
|
||||
* the code attempts to detect availability automatically. If the
|
||||
* Symbols HAVE_XXX are defined, they are used. If not, they are
|
||||
* set to reasonable default assumptions while further conditions
|
||||
* are checked. The choices, and the ways they are auto-detected are:
|
||||
* - gethrvtime(), if HAVE_GETHRVTIME is set to 1.
|
||||
* - clock_gettime(CLOCK_VIRTUAL,...), if CLOCK_VIRTUAL is defined in <time.h>
|
||||
* - getrusage(RUSAGE_SELF,...), if RUSAGE_SELF is defined in <sys/resource.h>
|
||||
* - clock(), if CLOCKS_PER_SEC or CLK_TCK are defined in <time.h>
|
||||
* - time(), unless specifically disabled.
|
||||
*
|
||||
* The symbol CLOCK_AVAIL is given a value of 1 if a clock is found.
|
||||
* The following are then available:
|
||||
* timetype (typedef): the type needed to hold a clock value.
|
||||
* gettime(t) (macro): A function that gets passed a timetype *.
|
||||
* subtime(d,s) (macro): Sets d -= s, essentially.
|
||||
* msec(t) (macro): Given a timetype, return the number of milliseconds
|
||||
* in it, as an unsigned integer between 0 and 999.
|
||||
* sec(t) (macro): Given a timetype, return the number of seconds in it,
|
||||
* as an unsigned long integer.
|
||||
*
|
||||
* This is written to accomocate a number of crufy old preprocessors that:
|
||||
* - Emit annoying warnings if you use "#if NOT_DEFINED".
|
||||
* (Workaround: #ifndef FOO / #define FOO 0 / #endif)
|
||||
* - Emit annoying warnings if you #undef something not defined.
|
||||
* (Workaround: #ifdef FOO / #undef FOO / #endif)
|
||||
* - Don't like spaces in "# define" and the like.
|
||||
* (Workaround: harder-to-read code with no indentation.)
|
||||
*/
|
||||
|
||||
/* We expect that our caller has already #included "bnconfig.h" if possible. */
|
||||
|
||||
#ifndef unix
|
||||
#define unix 0
|
||||
#endif
|
||||
#ifndef __unix
|
||||
#define __unix 0
|
||||
#endif
|
||||
#ifndef __unix__
|
||||
#define __unix__ 0
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
/* Nothing */
|
||||
#elif unix
|
||||
#define UNIX 1
|
||||
#elif __unix
|
||||
#define UNIX 1
|
||||
#elif __unix__
|
||||
#define UNIX 1
|
||||
#endif
|
||||
|
||||
#ifndef UNIX
|
||||
#define UNIX 0
|
||||
#endif
|
||||
|
||||
#ifndef TIME_WITH_SYS_TIME
|
||||
#define TIME_WITH_SYS_TIME 1 /* Assume true if not told */
|
||||
#endif
|
||||
#ifndef HAVE_SYS_TIME_H
|
||||
#define HAVE_SYS_TIME_H 1 /* Assume true if not told */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Include <time.h> unless that would prevent us from later including
|
||||
* <sys/time.h>, in which case include *that* immediately.
|
||||
*/
|
||||
#if TIME_WITH_SYS_TIME
|
||||
#include <time.h>
|
||||
#elif HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
/* Do we want to use gethrvtime() (a Solaris special?) */
|
||||
#ifndef USE_GETHRVTIME
|
||||
#ifdef HAVE_GETHRVTIME
|
||||
#define USE_GETHRVTIME HAVE_GETHRVTIME
|
||||
#else
|
||||
#define USE_GETHRVTIME 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* If we do want to use gethrvtime(), define the functions */
|
||||
#if USE_GETHRVTIME
|
||||
#define CLOCK_AVAIL 1
|
||||
typedef hrtime_t timetype;
|
||||
#define gettime(t) *(t) = gethrvtime()
|
||||
#define subtime(d,s) d -= s
|
||||
#define msec(t) (unsigned)((t/1000000)%1000)
|
||||
#define sec(t) (unsigned long)(t/1000000000)
|
||||
|
||||
#else /* !USE_GETHRVTIME, extends to end of file */
|
||||
|
||||
/* Do we want to use clock_gettime()? */
|
||||
#ifndef USE_CLOCK_GETTIME
|
||||
#ifndef HAVE_CLOCK_GETTIME
|
||||
#define HAVE_CLOCK_GETTIME 1 /* Assume the CLOCK_VIRTUAL test will catch */
|
||||
#endif
|
||||
/*
|
||||
* It turns out to be non-ANSI to use the apparently simpler construct
|
||||
* "#define USE_CLOCK_GETTIME defined(CLOCK_VIRTUAL)", since
|
||||
* "If the token defined is generated as a result of this replacement
|
||||
* process or use of the defined unary operator does not match one
|
||||
* of the two specified forms prior ro macro replacement, the behaviour
|
||||
* is undefined." (ANSI/ISO 9899-1990 section 6.8.1)
|
||||
* In practice, it breaks the DEC Alpha compiler.
|
||||
*/
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
#ifdef CLOCK_VIRTUAL
|
||||
#define USE_CLOCK_GETTIME 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* If we do want to use clock_gettime(), define the necessary functions */
|
||||
#if USE_CLOCK_GETTIME
|
||||
#define CLOCK_AVAIL 1
|
||||
typedef struct timespec timetype;
|
||||
#define gettime(t) clock_gettime(CLOCK_VIRTUAL, t)
|
||||
#define subtime(d,s) \
|
||||
d.tv_sec -= s.tv_sec + (d.tv_nsec >= s.tv_nsec ? \
|
||||
(d.tv_nsec -= s.tv_nsec, 0) : \
|
||||
(d.tv_nsec += 1000000000-s.tv_nsec, 1))
|
||||
#define msec(t) (unsigned)(t.tv_nsec/1000000)
|
||||
#define sec(t) (unsigned long)(t.tv_sec)
|
||||
|
||||
#else /* !USE_CLOCK_GETTIME, extends to end of file */
|
||||
|
||||
#if UNIX
|
||||
#ifndef HAVE_GETRUSAGE
|
||||
#define HAVE_GETRUSAGE 1
|
||||
#endif
|
||||
#endif /* UNIX */
|
||||
|
||||
/* Do we want to use getrusage()? */
|
||||
#if HAVE_GETRUSAGE
|
||||
#if TIME_WITH_SYS_TIME
|
||||
#ifndef HAVE_SYS_TIME_H /* If it's not defined */
|
||||
#include <sys/time.h>
|
||||
#elif HAVE_SYS_TIME_H /* Or it's defined true */
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#endif /* TIME_WITH_SYS_TIME */
|
||||
#include <sys/resource.h>
|
||||
|
||||
#ifdef RUSAGE_SELF
|
||||
#undef USE_GETRUSAGE
|
||||
#define USE_GETRUSAGE 1
|
||||
#endif
|
||||
#endif /* HAVE_GETRUSAGE */
|
||||
|
||||
/* If we do want to use getrusage(), define the necessary functions */
|
||||
#if USE_GETRUSAGE
|
||||
#define CLOCK_AVAIL 1
|
||||
typedef struct rusage timetype;
|
||||
#define gettime(t) getrusage(RUSAGE_SELF, t);
|
||||
#define subtime(d, s) \
|
||||
d.ru_utime.tv_sec -= s.ru_utime.tv_sec + \
|
||||
(d.ru_utime.tv_usec >= s.ru_utime.tv_usec ? \
|
||||
(d.ru_utime.tv_usec -= s.ru_utime.tv_usec, 0) : \
|
||||
(d.ru_utime.tv_usec += 1000000-s.ru_utime.tv_usec, 1))
|
||||
#define msec(t) (unsigned)(t.ru_utime.tv_usec/1000)
|
||||
#define sec(t) (unsigned long)(t.ru_utime.tv_sec)
|
||||
|
||||
#else /* !USE_GETRUSAGE, extends to end of file */
|
||||
|
||||
#ifndef HAVE_CLOCK
|
||||
#define HAVE_CLOCK 1
|
||||
#endif
|
||||
|
||||
#if HAVE_CLOCK
|
||||
#ifndef CLOCKS_PER_SEC
|
||||
#ifdef CLK_TCK
|
||||
#define CLOCKS_PER_SEC CLK_TCK
|
||||
#endif
|
||||
#endif /* !defined(CLOCKS_PER_SEC) */
|
||||
|
||||
#ifndef USE_CLOCK
|
||||
#ifdef CLOCKS_PER_SEC
|
||||
#define USE_CLOCK 1
|
||||
#endif
|
||||
#endif /* !defined(USE_CLOCK) */
|
||||
#endif /* HAVE_CLOCK */
|
||||
|
||||
/* If we want to use clock(), define the necessary functions */
|
||||
#if USE_CLOCK
|
||||
#define CLOCK_AVAIL 1
|
||||
typedef clock_t timetype;
|
||||
#define gettime(t) *(t) = clock()
|
||||
#define subtime(d, s) d -= s
|
||||
/*
|
||||
* I don't like having to do floating point math. CLOCKS_PER_SEC is
|
||||
* almost always an integer, and the most common non-integral case is
|
||||
* the MS-DOS wierdness of 18.2. We have to be a bit careful with the
|
||||
* casts, because ANSI C doesn't provide % with non-integral operands,
|
||||
* but just to be extra annoying, some implementations define it as an
|
||||
* integral-valued float. (E.g. Borland C++ 4.5 with 1000.0)
|
||||
*/
|
||||
#if ((unsigned)CLOCKS_PER_SEC == CLOCKS_PER_SEC)
|
||||
/* Integer CLOCKS_PER_SEC */
|
||||
|
||||
#define sec(t) (unsigned long)(t/CLOCKS_PER_SEC)
|
||||
#define msec(t) (unsigned)(t % (unsigned)CLOCKS_PER_SEC * 1000 / \
|
||||
(unsigned)CLOCKS_PER_SEC)
|
||||
#elif (CLOCKS_PER_SEC == 18.2)
|
||||
/* MS-DOS-ism */
|
||||
|
||||
#define sec(t) (unsigned long)(t*5 / 91)
|
||||
#define msec(t) (unsigned)(t*5 % 91 * 1000 / 91)
|
||||
|
||||
#else /* We are forced to muck with floating point.... */
|
||||
|
||||
#include <math.h> /* For floor() */
|
||||
#define sec(t) (unsigned long)(t/CLOCKS_PER_SEC)
|
||||
#define msec(t) (unsigned)((t - sec(t)*CLOCKS_PER_SEC) * 1000 / CLOCKS_PER_SEC)
|
||||
|
||||
#endif
|
||||
|
||||
#else /* !USE_CLOCK, extends to end of file */
|
||||
|
||||
#ifndef HAVE_TIME
|
||||
#define HAVE_TIME 1
|
||||
#endif
|
||||
|
||||
#if HAVE_TIME
|
||||
#ifndef USE_TIME
|
||||
#define USE_TIME 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if USE_TIME
|
||||
#define CLOCK_AVAIL 1
|
||||
typedef time_t timetype;
|
||||
#define gettime(t) time(t)
|
||||
#define subtime(d, s) d -= s
|
||||
#define msec(t) (unsigned)0
|
||||
#define sec(t) (unsigned long)t
|
||||
|
||||
#else /* !USE_TIME, extends to end of file */
|
||||
|
||||
#error No clock available.
|
||||
|
||||
#endif /* USE_TIME */
|
||||
#endif /* USE_CLOCK */
|
||||
#endif /* USE_GETRUSAGE */
|
||||
#endif /* USE_CLOCK_GETTIME */
|
||||
#endif /* USE_GETHRVTIME */
|
||||
|
||||
#endif /*CPUTIME_H*/
|
||||
+608
@@ -0,0 +1,608 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* Sophie Germain prime generation using the bignum library and sieving.
|
||||
*/
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_ASSERT_H
|
||||
#define NO_ASSERT_H 0
|
||||
#endif
|
||||
#if !NO_ASSERT_H
|
||||
#include <assert.h>
|
||||
#else
|
||||
#define assert(x) (void)0
|
||||
#endif
|
||||
|
||||
#define BNDEBUG 1
|
||||
#ifndef BNDEBUG
|
||||
#define BNDEBUG 0
|
||||
#endif
|
||||
#if BNDEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "bn.h"
|
||||
#include "germain.h"
|
||||
#include "jacobi.h"
|
||||
#include "lbnmem.h" /* For lbnMemWipe */
|
||||
#include "sieve.h"
|
||||
|
||||
#include "kludge.h"
|
||||
|
||||
/* Size of the sieve area (can be up to 65536/8 = 8192) */
|
||||
#define SIEVE 8192
|
||||
|
||||
static unsigned const confirm[] = {2, 3, 5, 7, 11, 13, 17};
|
||||
#define CONFIRMTESTS (sizeof(confirm)/sizeof(*confirm))
|
||||
|
||||
#if BNDEBUG
|
||||
/*
|
||||
* For sanity checking the sieve, we check for small divisors of the numbers
|
||||
* we get back. This takes "rem", a partially reduced form of the prime,
|
||||
* "div" a divisor to check for, and "order", a parameter of the "order"
|
||||
* of Sophie Germain primes (0 = normal primes, 1 = Sophie Germain primes,
|
||||
* 2 = 4*p+3 is also prime, etc.) and does the check. It just complains
|
||||
* to stdout if the check fails.
|
||||
*/
|
||||
static void
|
||||
germainSanity(unsigned rem, unsigned div, unsigned order)
|
||||
{
|
||||
unsigned mul = 1;
|
||||
|
||||
rem %= div;
|
||||
if (!rem)
|
||||
printf("bn div by %u!\n", div);
|
||||
while (order--) {
|
||||
rem += rem+1;
|
||||
if (rem >= div)
|
||||
rem -= div;
|
||||
mul += mul;
|
||||
if (!rem)
|
||||
printf("%u*bn+%u div by %u!\n", mul, mul-1, div);
|
||||
}
|
||||
}
|
||||
#endif /* BNDEBUG */
|
||||
|
||||
/*
|
||||
* Helper function that does the slow primality test.
|
||||
* bn is the input bignum; a, e and bn2 are temporary buffers that are
|
||||
* allocated by the caller to save overhead. bn2 is filled with
|
||||
* a copy of 2^order*bn+2^order-1 if bn is found to be prime.
|
||||
*
|
||||
* Returns 0 if both bn and bn2 are prime, >0 if not prime, and -1 on
|
||||
* error (out of memory). If not prime, the return value is the number
|
||||
* of modular exponentiations performed. Prints a '+' or '-' on the
|
||||
* given FILE (if any) for each test that is passed by bn, and a '*'
|
||||
* for each test that is passed by bn2.
|
||||
*
|
||||
* The testing consists of strong pseudoprimality tests, to the bases given
|
||||
* in the confirm[] array above. (Also called Miller-Rabin, although that's
|
||||
* not technically correct if we're using fixed bases.) Some people worry
|
||||
* that this might not be enough. Number theorists may wish to generate
|
||||
* primality proofs, but for random inputs, this returns non-primes with
|
||||
* a probability which is quite negligible, which is good enough.
|
||||
*
|
||||
* It has been proved (see Carl Pomerance, "On the Distribution of
|
||||
* Pseudoprimes", Math. Comp. v.37 (1981) pp. 587-593) that the number of
|
||||
* pseudoprimes (composite numbers that pass a Fermat test to the base 2)
|
||||
* less than x is bounded by:
|
||||
* exp(ln(x)^(5/14)) <= P_2(x) ### CHECK THIS FORMULA - it looks wrong! ###
|
||||
* P_2(x) <= x * exp(-1/2 * ln(x) * ln(ln(ln(x))) / ln(ln(x))).
|
||||
* Thus, the local density of Pseudoprimes near x is at most
|
||||
* exp(-1/2 * ln(x) * ln(ln(ln(x))) / ln(ln(x))), and at least
|
||||
* exp(ln(x)^(5/14) - ln(x)). Here are some values of this function
|
||||
* for various k-bit numbers x = 2^k:
|
||||
* Bits Density <= Bit equivalent Density >= Bit equivalent
|
||||
* 128 3.577869e-07 21.414396 4.202213e-37 120.840190
|
||||
* 192 4.175629e-10 31.157288 4.936250e-56 183.724558
|
||||
* 256 5.804314e-13 40.647940 4.977813e-75 246.829095
|
||||
* 384 1.578039e-18 59.136573 3.938861e-113 373.400096
|
||||
* 512 5.858255e-24 77.175803 2.563353e-151 500.253110
|
||||
* 768 1.489276e-34 112.370944 7.872825e-228 754.422724
|
||||
* 1024 6.633188e-45 146.757062 1.882404e-304 1008.953565
|
||||
*
|
||||
* As you can see, there's quite a bit of slop between these estimates.
|
||||
* In fact, the density of pseudoprimes is conjectured to be closer to the
|
||||
* square of that upper bound. E.g. the density of pseudoprimes of size
|
||||
* 256 is around 3 * 10^-27. The density of primes is very high, from
|
||||
* 0.005636 at 256 bits to 0.001409 at 1024 bits, i.e. more than 10^-3.
|
||||
*
|
||||
* For those people used to cryptographic levels of security where the
|
||||
* 56 bits of DES key space is too small because it's exhaustible with
|
||||
* custom hardware searching engines, note that you are not generating
|
||||
* 50,000,000 primes per second on each of 56,000 custom hardware chips
|
||||
* for several hours. The chances that another Dinosaur Killer asteroid
|
||||
* will land today is about 10^-11 or 2^-36, so it would be better to
|
||||
* spend your time worrying about *that*. Well, okay, there should be
|
||||
* some derating for the chance that astronomers haven't seen it yet,
|
||||
* but I think you get the idea. For a good feel about the probability
|
||||
* of various events, I have heard that a good book is by E'mile Borel,
|
||||
* "Les Probabilite's et la vie". (The 's are accents, not apostrophes.)
|
||||
*
|
||||
* For more on the subject, try "Finding Four Million Large Random Primes",
|
||||
* by Ronald Rivest, in Advancess in Cryptology: Proceedings of Crypto
|
||||
* '90. He used a small-divisor test, then a Fermat test to the base 2,
|
||||
* and then 8 iterations of a Miller-Rabin test. About 718 million random
|
||||
* 256-bit integers were generated, 43,741,404 passed the small divisor
|
||||
* test, 4,058,000 passed the Fermat test, and all 4,058,000 passed all
|
||||
* 8 iterations of the Miller-Rabin test, proving their primality beyond
|
||||
* most reasonable doubts.
|
||||
*
|
||||
* If the probability of getting a pseudoprime is some small p, then the
|
||||
* probability of not getting it in t trials is (1-p)^t. Remember that,
|
||||
* for small p, (1-p)^(1/p) ~ 1/e, the base of natural logarithms.
|
||||
* (This is more commonly expressed as e = lim_{x\to\infty} (1+1/x)^x.)
|
||||
* Thus, (1-p)^t ~ e^(-p*t) = exp(-p*t). So the odds of being able to
|
||||
* do this many tests without seeing a pseudoprime if you assume that
|
||||
* p = 10^-6 (one in a million) is one in 57.86. If you assume that
|
||||
* p = 2*10^-6, it's one in 3347.6. So it's implausible that the density
|
||||
* of pseudoprimes is much more than one millionth the density of primes.
|
||||
*
|
||||
* He also gives a theoretical argument that the chance of finding a
|
||||
* 256-bit non-prime which satisfies one Fermat test to the base 2 is
|
||||
* less than 10^-22. The small divisor test improves this number, and
|
||||
* if the numbers are 512 bits (as needed for a 1024-bit key) the odds
|
||||
* of failure shrink to about 10^-44. Thus, he concludes, for practical
|
||||
* purposes *one* Fermat test to the base 2 is sufficient.
|
||||
*/
|
||||
static int
|
||||
germainPrimeTest(struct BigNum const *bn, struct BigNum *bn2, struct BigNum *e,
|
||||
struct BigNum *a, unsigned order, int (*f)(void *arg, int c), void *arg)
|
||||
{
|
||||
int err;
|
||||
unsigned i;
|
||||
int j;
|
||||
unsigned k, l, n;
|
||||
|
||||
#if BNDEBUG /* Debugging */
|
||||
/*
|
||||
* This is debugging code to test the sieving stage.
|
||||
* If the sieving is wrong, it will let past numbers with
|
||||
* small divisors. The prime test here will still work, and
|
||||
* weed them out, but you'll be doing a lot more slow tests,
|
||||
* and presumably excluding from consideration some other numbers
|
||||
* which might be prime. This check just verifies that none
|
||||
* of the candidates have any small divisors. If this
|
||||
* code is enabled and never triggers, you can feel quite
|
||||
* confident that the sieving is doing its job.
|
||||
*/
|
||||
i = bnLSWord(bn);
|
||||
if (!(i % 2)) printf("bn div by 2!");
|
||||
i = bnModQ(bn, 51051); /* 51051 = 3 * 7 * 11 * 13 * 17 */
|
||||
germainSanity(i, 3, order);
|
||||
germainSanity(i, 7, order);
|
||||
germainSanity(i, 11, order);
|
||||
germainSanity(i, 13, order);
|
||||
germainSanity(i, 17, order);
|
||||
i = bnModQ(bn, 63365); /* 63365 = 5 * 19 * 23 * 29 */
|
||||
germainSanity(i, 5, order);
|
||||
germainSanity(i, 19, order);
|
||||
germainSanity(i, 23, order);
|
||||
germainSanity(i, 29, order);
|
||||
i = bnModQ(bn, 47027); /* 47027 = 31 * 37 * 41 */
|
||||
germainSanity(i, 31, order);
|
||||
germainSanity(i, 37, order);
|
||||
germainSanity(i, 41, order);
|
||||
#endif
|
||||
/*
|
||||
* First, check whether bn is prime. This uses a fast primality
|
||||
* test which usually obviates the need to do one of the
|
||||
* confirmation tests later. See prime.c for a full explanation.
|
||||
* We check bn first because it's one bit smaller, saving one
|
||||
* modular squaring, and because we might be able to save another
|
||||
* when testing it. (1/4 of the time.) A small speed hack,
|
||||
* but finding big Sophie Germain primes is *slow*.
|
||||
*/
|
||||
if (bnCopy(e, bn) < 0)
|
||||
return -1;
|
||||
(void)bnSubQ(e, 1);
|
||||
l = bnLSWord(e);
|
||||
|
||||
j = 1; /* Where to start in prime array for strong prime tests */
|
||||
|
||||
if (l & 7) {
|
||||
bnRShift(e, 1);
|
||||
if (bnTwoExpMod(a, e, bn) < 0)
|
||||
return -1;
|
||||
if ((l & 7) == 6) {
|
||||
/* bn == 7 mod 8, expect +1 */
|
||||
if (bnBits(a) != 1)
|
||||
return 1; /* Not prime */
|
||||
k = 1;
|
||||
} else {
|
||||
/* bn == 3 or 5 mod 8, expect -1 == bn-1 */
|
||||
if (bnAddQ(a, 1) < 0)
|
||||
return -1;
|
||||
if (bnCmp(a, bn) != 0)
|
||||
return 1; /* Not prime */
|
||||
k = 1;
|
||||
if (l & 4) {
|
||||
/* bn == 5 mod 8, make odd for strong tests */
|
||||
bnRShift(e, 1);
|
||||
k = 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* bn == 1 mod 8, expect 2^((bn-1)/4) == +/-1 mod bn */
|
||||
bnRShift(e, 2);
|
||||
if (bnTwoExpMod(a, e, bn) < 0)
|
||||
return -1;
|
||||
if (bnBits(a) == 1) {
|
||||
j = 0; /* Re-do strong prime test to base 2 */
|
||||
} else {
|
||||
if (bnAddQ(a, 1) < 0)
|
||||
return -1;
|
||||
if (bnCmp(a, bn) != 0)
|
||||
return 1; /* Not prime */
|
||||
}
|
||||
k = 2 + bnMakeOdd(e);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* It's prime! Now check higher-order forms bn2 = 2*bn+1, 4*bn+3,
|
||||
* etc. Since bn2 == 3 mod 4, a strong pseudoprimality test boils
|
||||
* down to looking at a^((bn2-1)/2) mod bn and seeing if it's +/-1.
|
||||
* (+1 if bn2 is == 7 mod 8, -1 if it's == 3)
|
||||
* Of course, that exponent is just the previous bn2 or bn...
|
||||
*/
|
||||
if (bnCopy(bn2, bn) < 0)
|
||||
return -1;
|
||||
for (n = 0; n < order; n++) {
|
||||
/*
|
||||
* Print a success indicator: the sign of Jacobi(2,bn2),
|
||||
* which is available to us in l. bn2 = 2*bn + 1. Since bn
|
||||
* is odd, bn2 must be == 3 mod 4, so the options modulo 8
|
||||
* are 3 and 7. 3 if l == 1 mod 4, 7 if l == 3 mod 4.
|
||||
* The sign of the Jacobi symbol is - and + for these cases,
|
||||
* respectively.
|
||||
*/
|
||||
if (f && (err = f(arg, "-+"[(l >> 1) & 1])) < 0)
|
||||
return err;
|
||||
/* Exponent is previous bn2 */
|
||||
if (bnCopy(e, bn2) < 0 || bnLShift(bn2, 1) < 0)
|
||||
return -1;
|
||||
(void)bnAddQ(bn2, 1); /* Can't overflow */
|
||||
if (bnTwoExpMod(a, e, bn2) < 0)
|
||||
return -1;
|
||||
if (n | l) { /* Expect + */
|
||||
if (bnBits(a) != 1)
|
||||
return 2+n; /* Not prime */
|
||||
} else {
|
||||
if (bnAddQ(a, 1) < 0)
|
||||
return -1;
|
||||
if (bnCmp(a, bn2) != 0)
|
||||
return 2+n; /* Not prime */
|
||||
}
|
||||
l = bnLSWord(bn2);
|
||||
}
|
||||
|
||||
/* Final success indicator - it's in the bag. */
|
||||
if (f && (err = f(arg, '*')) < 0)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Success! We have found a prime! Now go on to confirmation
|
||||
* tests... k is an amount by which we know it's safe to shift
|
||||
* down e. j = 1 unless the test to the base 2 could stand to be
|
||||
* re-done (it wasn't *quite* a strong test), in which case it's 0.
|
||||
*
|
||||
* Here, we do the full strong pseudoprimality test. This proves
|
||||
* that a number is composite, or says that it's probably prime.
|
||||
*
|
||||
* For the given base a, find bn-1 = 2^k * e, then find
|
||||
* x == a^e (mod bn).
|
||||
* If x == +1 -> strong pseudoprime to base a
|
||||
* Otherwise, repeat k times:
|
||||
* If x == -1, -> strong pseudoprime
|
||||
* x = x^2 (mod bn)
|
||||
* If x = +1 -> composite
|
||||
* If we reach the end of the iteration and x is *not* +1, at the
|
||||
* end, it is composite. But it's also composite if the result
|
||||
* *is* +1. Which means that the squaring actually only has to
|
||||
* proceed k-1 times. If x is not -1 by then, it's composite
|
||||
* no matter what the result of the squaring is.
|
||||
*
|
||||
* For the multiples 2*bn+1, 4*bn+3, etc. then k = 1 (and e is
|
||||
* the previous multiple of bn) so the squaring loop is never
|
||||
* actually executed at all.
|
||||
*/
|
||||
for (i = j; i < CONFIRMTESTS; i++) {
|
||||
if (bnCopy(e, bn) < 0)
|
||||
return -1;
|
||||
bnRShift(e, k);
|
||||
k += bnMakeOdd(e);
|
||||
(void)bnSetQ(a, confirm[i]);
|
||||
if (bnExpMod(a, a, e, bn) < 0)
|
||||
return -1;
|
||||
|
||||
if (bnBits(a) != 1) {
|
||||
l = k;
|
||||
for (;;) {
|
||||
if (bnAddQ(a, 1) < 0)
|
||||
return -1;
|
||||
if (bnCmp(a, bn) == 0) /* Was result bn-1? */
|
||||
break; /* Prime */
|
||||
if (!--l)
|
||||
return (1+order)*i+2; /* Fail */
|
||||
/* This part is executed once, on average. */
|
||||
(void)bnSubQ(a, 1); /* Restore a */
|
||||
if (bnSquare(a, a) < 0 || bnMod(a, a, bn) < 0)
|
||||
return -1;
|
||||
if (bnBits(a) == 1)
|
||||
return (1+order)*i+1; /* Fail */
|
||||
}
|
||||
}
|
||||
|
||||
if (bnCopy(bn2, bn) < 0)
|
||||
return -1;
|
||||
|
||||
/* Only do the following if we're not re-doing base 2 */
|
||||
if (i) for (n = 0; n < order; n++) {
|
||||
if (bnCopy(e, bn2) < 0 || bnLShift(bn2, 1) < 0)
|
||||
return -1;
|
||||
(void)bnAddQ(bn2, 1);
|
||||
|
||||
/* Print success indicator for previous test */
|
||||
j = bnJacobiQ(confirm[i], bn2);
|
||||
if (f && (err = f(arg, j < 0 ? '-' : '+')) < 0)
|
||||
return err;
|
||||
|
||||
/* Check that p^e == Jacobi(p,bn2) (mod bn2) */
|
||||
(void)bnSetQ(a, confirm[i]);
|
||||
if (bnExpMod(a, a, e, bn2) < 0)
|
||||
return -1;
|
||||
/*
|
||||
* FIXME: Actually, we don't need to compute the
|
||||
* Jacobi symbol externally... it never happens that
|
||||
* a = +/-1 but it's the wrong one. So we can just
|
||||
* look at a and use its sign. Find a proof somewhere.
|
||||
*/
|
||||
if (j < 0) {
|
||||
/* Not a Q.R., should have a = bn2-1 */
|
||||
if (bnAddQ(a, 1) < 0)
|
||||
return -1;
|
||||
if (bnCmp(a, bn2) != 0) /* Was result bn2-1? */
|
||||
return (1+order)*i+n+2; /* Fail */
|
||||
} else {
|
||||
/* Quadratic residue, should have a = 1 */
|
||||
if (bnBits(a) != 1)
|
||||
return (1+order)*i+n+2; /* Fail */
|
||||
}
|
||||
}
|
||||
/* Final success indicator for the base confirm[i]. */
|
||||
if (f && (err = f(arg, '*')) < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0; /* Prime! */
|
||||
}
|
||||
|
||||
/*
|
||||
* Add x*y to bn, which is usually (but not always) < 65536.
|
||||
* Do it in a simple linear manner.
|
||||
*/
|
||||
static int
|
||||
bnAddMult(struct BigNum *bn, unsigned long x, unsigned y)
|
||||
{
|
||||
unsigned long z = (unsigned long)x * y;
|
||||
|
||||
while (z > 65535) {
|
||||
if (bnAddQ(bn, 65535) < 0)
|
||||
return -1;
|
||||
z -= 65535;
|
||||
}
|
||||
return bnAddQ(bn, (unsigned)z);
|
||||
}
|
||||
|
||||
/*
|
||||
* Modifies the bignum to return the next Sophie Germain prime >= the
|
||||
* input value. Sohpie Germain primes are number such that p is
|
||||
* prime and 2*p+1 is also prime.
|
||||
*
|
||||
* This is actually parameterized: it generates primes p such that "order"
|
||||
* multiples-plus-two are also prime, 2*p+1, 2*(2*p+1)+1 = 4*p+3, etc.
|
||||
*
|
||||
* Returns >=0 on success or -1 on failure (out of memory). On success,
|
||||
* the return value is the number of modular exponentiations performed
|
||||
* (excluding the final confirmations). This never gives up searching.
|
||||
*
|
||||
* The FILE *f argument, if non-NULL, has progress indicators written
|
||||
* to it. A dot (.) is written every time a primeality test is failed,
|
||||
* a plus (+) or minus (-) when the smaller prime of the pair passes a
|
||||
* test, and a star (*) when the larger one does. Finally, a slash (/)
|
||||
* is printed when the sieve was emptied without finding a prime and is
|
||||
* being refilled.
|
||||
*
|
||||
* Apologies to structured programmers for all the GOTOs.
|
||||
*/
|
||||
int
|
||||
germainPrimeGen(struct BigNum *bn, unsigned order,
|
||||
int (*f)(void *arg, int c), void *arg)
|
||||
{
|
||||
int retval;
|
||||
unsigned p, prev;
|
||||
unsigned inc;
|
||||
struct BigNum a, e, bn2;
|
||||
int modexps = 0;
|
||||
#ifdef MSDOS
|
||||
unsigned char *sieve;
|
||||
#else
|
||||
unsigned char sieve[SIEVE];
|
||||
#endif
|
||||
|
||||
#ifdef MSDOS
|
||||
sieve = lbnMemAlloc(SIEVE);
|
||||
if (!sieve)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
bnBegin(&a);
|
||||
bnBegin(&e);
|
||||
bnBegin(&bn2);
|
||||
|
||||
/*
|
||||
* Obviously, the prime we find must be odd. Further, if 2*p+1
|
||||
* is also to be prime (order > 0) then p != 1 (mod 3), lest
|
||||
* 2*p+1 == 3 (mod 3). Added to p != 3 (mod 3), p == 2 (mod 3)
|
||||
* and p == 5 (mod 6).
|
||||
* If order > 2 and we care about 4*p+3 and 8*p+7, then similarly
|
||||
* p == 4 (mod 5), so p == 29 (mod 30).
|
||||
* So pick the step size for searching based on the order
|
||||
* and increse bn until it's == -1 (mod inc).
|
||||
*
|
||||
* mod 7 doesn't have a unique value for p because 2 -> 5 -> 4 -> 2,
|
||||
* nor does mod 11, and I don't want to think about things past
|
||||
* that. The required order would be impractically high, in any case.
|
||||
*/
|
||||
inc = order ? ((order > 2) ? 30 : 6) : 2;
|
||||
if (bnAddQ(bn, inc-1 - bnModQ(bn, inc)) < 0)
|
||||
goto failed;
|
||||
|
||||
for (;;) {
|
||||
if (sieveBuild(sieve, SIEVE, bn, inc, order) < 0)
|
||||
goto failed;
|
||||
|
||||
p = prev = 0;
|
||||
if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) {
|
||||
do {
|
||||
/* Adjust bn to have the right value. */
|
||||
assert(p >= prev);
|
||||
if (bnAddMult(bn, p-prev, inc) < 0)
|
||||
goto failed;
|
||||
prev = p;
|
||||
|
||||
/* Okay, do the strong tests. */
|
||||
retval = germainPrimeTest(bn, &bn2, &e, &a,
|
||||
order, f, arg);
|
||||
if (retval <= 0)
|
||||
goto done;
|
||||
modexps += retval;
|
||||
if (f && (retval = f(arg, '.')) < 0)
|
||||
goto done;
|
||||
|
||||
/* And try again */
|
||||
p = sieveSearch(sieve, SIEVE, p);
|
||||
} while (p);
|
||||
}
|
||||
|
||||
/* Ran out of sieve space - increase bn and keep trying. */
|
||||
if (bnAddMult(bn, (unsigned long)SIEVE*8-prev, inc) < 0)
|
||||
goto failed;
|
||||
if (f && (retval = f(arg, '/')) < 0)
|
||||
goto done;
|
||||
} /* for (;;) */
|
||||
|
||||
failed:
|
||||
retval = -1;
|
||||
done:
|
||||
bnEnd(&bn2);
|
||||
bnEnd(&e);
|
||||
bnEnd(&a);
|
||||
#ifdef MSDOS
|
||||
lbnMemFree(sieve, SIEVE);
|
||||
#else
|
||||
lbnMemWipe(sieve, sizeof(sieve));
|
||||
#endif
|
||||
return retval < 0 ? retval : modexps+(order+1)*CONFIRMTESTS;
|
||||
}
|
||||
|
||||
int
|
||||
germainPrimeGenStrong(struct BigNum *bn, struct BigNum const *step,
|
||||
unsigned order, int (*f)(void *arg, int c), void *arg)
|
||||
{
|
||||
int retval;
|
||||
unsigned p, prev;
|
||||
struct BigNum a, e, bn2;
|
||||
int modexps = 0;
|
||||
#ifdef MSDOS
|
||||
unsigned char *sieve;
|
||||
#else
|
||||
unsigned char sieve[SIEVE];
|
||||
#endif
|
||||
|
||||
#ifdef MSDOS
|
||||
sieve = lbnMemAlloc(SIEVE);
|
||||
if (!sieve)
|
||||
return -1;
|
||||
#endif
|
||||
bnBegin(&a);
|
||||
bnBegin(&e);
|
||||
bnBegin(&bn2);
|
||||
|
||||
for (;;) {
|
||||
if (sieveBuildBig(sieve, SIEVE, bn, step, order) < 0)
|
||||
goto failed;
|
||||
|
||||
p = prev = 0;
|
||||
if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) {
|
||||
do {
|
||||
/*
|
||||
* Adjust bn to have the right value,
|
||||
* adding (p-prev) * 2*step.
|
||||
*/
|
||||
assert(p >= prev);
|
||||
/* Compute delta into a */
|
||||
if (bnMulQ(&a, step, p-prev) < 0)
|
||||
goto failed;
|
||||
if (bnAdd(bn, &a) < 0)
|
||||
goto failed;
|
||||
prev = p;
|
||||
|
||||
/* Okay, do the strong tests. */
|
||||
retval = germainPrimeTest(bn, &bn2, &e, &a,
|
||||
order, f, arg);
|
||||
if (retval <= 0)
|
||||
goto done;
|
||||
modexps += retval;
|
||||
if (f && (retval = f(arg, '.')) < 0)
|
||||
goto done;
|
||||
|
||||
/* And try again */
|
||||
p = sieveSearch(sieve, SIEVE, p);
|
||||
} while (p);
|
||||
}
|
||||
|
||||
/* Ran out of sieve space - increase bn and keep trying. */
|
||||
#if SIEVE*8 == 65536
|
||||
/* Corner case that will never actually happen */
|
||||
if (!prev) {
|
||||
if (bnAdd(bn, step) < 0)
|
||||
goto failed;
|
||||
p = 65535;
|
||||
} else {
|
||||
p = (unsigned)(SIEVE*8 - prev);
|
||||
}
|
||||
#else
|
||||
p = SIEVE*8 - prev;
|
||||
#endif
|
||||
if (bnMulQ(&a, step, p) < 0 || bnAdd(bn, &a) < 0)
|
||||
goto failed;
|
||||
if (f && (retval = f(arg, '/')) < 0)
|
||||
goto done;
|
||||
} /* for (;;) */
|
||||
|
||||
failed:
|
||||
retval = -1;
|
||||
done:
|
||||
bnEnd(&bn2);
|
||||
bnEnd(&e);
|
||||
bnEnd(&a);
|
||||
#ifdef MSDOS
|
||||
lbnMemFree(sieve, SIEVE);
|
||||
#else
|
||||
lbnMemWipe(sieve, sizeof(sieve));
|
||||
#endif
|
||||
return retval < 0 ? retval : modexps+(order+1)*CONFIRMTESTS;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
struct BigNum;
|
||||
|
||||
/* Generate a Sophie Germain prime */
|
||||
int germainPrimeGen(struct BigNum *bn, unsigned order,
|
||||
int (*f)(void *arg, int c), void *arg);
|
||||
/* The same, but search for using the given step size */
|
||||
int germainPrimeGenStrong(struct BigNum *bn, struct BigNum const *step,
|
||||
unsigned order, int (*f)(void *arg, int c), void *arg);
|
||||
+339
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* germtest.c - Random Sophie Germain prime generator.
|
||||
*
|
||||
* This generates random Sophie Germain primes using the command line
|
||||
* as a seed value. It uses George Marsaglia's "mother of all random
|
||||
* number generators" to (using the command line as a seed) to pick the
|
||||
* starting search value and then searches sequentially for the next
|
||||
* Sophie Germain prime p (a prime such that 2*p+1 is also prime).
|
||||
*
|
||||
* This is a really good way to burn a lot of CPU cycles.
|
||||
*/
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#if !NO_STRING_H
|
||||
#include <string.h>
|
||||
#elif HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#if NEED_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> /* For malloc() */
|
||||
|
||||
#include "bn.h"
|
||||
#include "germain.h"
|
||||
#include "sieve.h"
|
||||
|
||||
#include "cputime.h"
|
||||
|
||||
#define BNDEBUG 1
|
||||
|
||||
#include "bnprint.h"
|
||||
#define bnPut(prompt, bn) bnPrint(stdout, prompt, bn, "\n")
|
||||
|
||||
/*
|
||||
* Generate random numbers according to George Marsaglia's
|
||||
* Mother Of All Random Number Generators. This has a
|
||||
* period of 0x17768215025F82EA0378038A03A203CA7FFF,
|
||||
* or decimal 2043908804452974490458343567652678881935359.
|
||||
*/
|
||||
static unsigned mstate[8];
|
||||
static unsigned mcarry;
|
||||
static unsigned mindex;
|
||||
|
||||
static unsigned
|
||||
mRandom_16(void)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
t = mcarry +
|
||||
mstate[ mindex ] * 1941ul +
|
||||
mstate[(mindex+1)&7] * 1860ul +
|
||||
mstate[(mindex+2)&7] * 1812ul +
|
||||
mstate[(mindex+3)&7] * 1776ul +
|
||||
mstate[(mindex+4)&7] * 1492ul +
|
||||
mstate[(mindex+5)&7] * 1215ul +
|
||||
mstate[(mindex+6)&7] * 1066ul +
|
||||
mstate[(mindex+7)&7] * 12013ul;
|
||||
mcarry = (unsigned)(t >> 16); /* 0 <= mcarry <= 0x5a87 */
|
||||
mindex = (mindex-1) & 7;
|
||||
return mstate[mindex] = (unsigned)(t & 0xffff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the RNG based on the given seed.
|
||||
* A zero-length seed will produce pretty lousy numbers,
|
||||
* but it will work.
|
||||
*/
|
||||
static void
|
||||
mSeed(unsigned char const *seed, unsigned len)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
mstate[i] = 0;
|
||||
mcarry = 1;
|
||||
while (len--) {
|
||||
mcarry += *seed++;
|
||||
(void)mRandom_16();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate a bignum of a specified length, with the given
|
||||
* high and low 8 bits. "High" is merged into the high 8 bits of the
|
||||
* number. For example, set it to 0x80 to ensure that the number is
|
||||
* exactly "bits" bits long (i.e. 2^(bits-1) <= bn < 2^bits).
|
||||
* "Low" is merged into the low 8 bits. For example, set it to
|
||||
* 1 to ensure that you generate an odd number. "High" is merged
|
||||
* into the high bits; set it to 0x80 to ensure that the high bit
|
||||
* is set in the returned value.
|
||||
*/
|
||||
static int
|
||||
genRandBn(struct BigNum *bn, unsigned bits, unsigned char high,
|
||||
unsigned char low, unsigned char const *seed, unsigned len)
|
||||
{
|
||||
unsigned char buf[64];
|
||||
unsigned bytes;
|
||||
unsigned l = 0; /* Current position */
|
||||
unsigned t, i;
|
||||
|
||||
bnSetQ(bn, 0);
|
||||
if (bnPrealloc(bn, bits) < 0)
|
||||
return -1;
|
||||
mSeed(seed, len);
|
||||
|
||||
bytes = (bits+7) / 8; /* Number of bytes to use */
|
||||
|
||||
for (i = 0; i < sizeof(buf); i += 2) {
|
||||
t = mRandom_16();
|
||||
buf[i] = (unsigned char)(t >> 8);
|
||||
buf[i+1] = (unsigned char)t;
|
||||
}
|
||||
buf[sizeof(buf)-1] |= low;
|
||||
|
||||
while (bytes > sizeof(buf)) {
|
||||
bytes -= sizeof(buf);
|
||||
/* Merge in low half of high bits, if necessary */
|
||||
if (bytes == 1 && (bits & 7))
|
||||
buf[0] |= high << (bits & 7);
|
||||
if (bnInsertBigBytes(bn, buf, l, sizeof(buf)) < 0)
|
||||
return -1;
|
||||
l += sizeof(buf);
|
||||
for (i = 0; i < sizeof(buf); i += 2) {
|
||||
t = mRandom_16();
|
||||
buf[i] = (unsigned char)t;
|
||||
buf[i+1] = (unsigned char)(t >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the final "bytes"-long section, using the tail bytes in buf */
|
||||
/* Mask off excess high bits */
|
||||
buf[sizeof(buf)-bytes] &= 255 >> (-bits & 7);
|
||||
/* Merge in specified high bits */
|
||||
buf[sizeof(buf)-bytes] |= high >> (-bits & 7);
|
||||
if (bytes > 1 && (bits & 7))
|
||||
buf[sizeof(buf)-bytes+1] |= high << (bits & 7);
|
||||
/* Merge in the appropriate bytes of the buffer */
|
||||
if (bnInsertBigBytes(bn, buf+sizeof(buf)-bytes, l, bytes) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct Progress {
|
||||
FILE *f;
|
||||
unsigned column;
|
||||
unsigned wrap;
|
||||
};
|
||||
|
||||
/* Print a progress indicator, with line-wrap */
|
||||
static int
|
||||
genProgress(void *arg, int c)
|
||||
{
|
||||
struct Progress *p = arg;
|
||||
if (++p->column > p->wrap) {
|
||||
putc('\n', p->f);
|
||||
p->column = 1;
|
||||
}
|
||||
putc(c, p->f);
|
||||
fflush(p->f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
genSophieGermain(struct BigNum *bn, unsigned bits, unsigned order,
|
||||
unsigned char const *seed, unsigned len, FILE *f)
|
||||
{
|
||||
#if CLOCK_AVAIL
|
||||
timetype start, stop;
|
||||
unsigned long s;
|
||||
#endif
|
||||
int i;
|
||||
#if BNDEBUG
|
||||
unsigned char s1[1024], s2[1024];
|
||||
#endif
|
||||
char buf[40];
|
||||
unsigned p1, p2;
|
||||
struct BigNum step;
|
||||
struct Progress progress;
|
||||
|
||||
if (f)
|
||||
fprintf(f, "Generating a %u-bit order-%u Sophie Germain prime with \"%.*s\"\n",
|
||||
bits, order, (int)len, (char *)seed);
|
||||
progress.f = f;
|
||||
progress.column = 0;
|
||||
progress.wrap = 78;
|
||||
|
||||
/* Find p - choose a starting place */
|
||||
if (genRandBn(bn, bits, 0xC0, 3, seed, len) < 0)
|
||||
return -1;
|
||||
#if BNDEBUG /* DEBUG - check that sieve works properly */
|
||||
bnBegin(&step);
|
||||
bnSetQ(&step, 2);
|
||||
sieveBuild(s1, 1024, bn, 2, order);
|
||||
sieveBuildBig(s2, 1024, bn, &step, order);
|
||||
p1 = p2 = 0;
|
||||
if (s1[0] != s2[0])
|
||||
printf("Difference: s1[0] = %x s2[0] = %x\n", s1[0], s2[0]);
|
||||
do {
|
||||
p1 = sieveSearch(s1, 1024, p1);
|
||||
p2 = sieveSearch(s2, 1024, p2);
|
||||
|
||||
if (p1 != p2)
|
||||
printf("Difference: p1 = %u p2 = %u\n", p1, p2);
|
||||
} while (p1 && p2);
|
||||
|
||||
bnEnd(&step);
|
||||
#endif
|
||||
/* And search for a prime */
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&start);
|
||||
#endif
|
||||
i = germainPrimeGen(bn, order, f ? genProgress : 0, (void *)&progress);
|
||||
if (i < 0)
|
||||
return -1;
|
||||
#if CLOCK_AVAIL
|
||||
gettime(&stop);
|
||||
#endif
|
||||
if (f) {
|
||||
putc('\n', f);
|
||||
fprintf(f, "%d modular exponentiations performed.\n", i);
|
||||
}
|
||||
#if CLOCK_AVAIL
|
||||
subtime(stop, start);
|
||||
s = sec(stop);
|
||||
printf("%u-bit time = %lu.%03u sec.", bits, s, msec(stop));
|
||||
if (s > 60) {
|
||||
putchar(' ');
|
||||
putchar('(');
|
||||
if (s > 3600)
|
||||
printf("%u:%02u", (unsigned)(s/3600),
|
||||
(unsigned)(s/60%60));
|
||||
else
|
||||
printf("%u", (unsigned)(s/60));
|
||||
printf(":%02u)", (unsigned)(s%60));
|
||||
}
|
||||
putchar('\n');
|
||||
#endif
|
||||
|
||||
bnPut(" p = ", bn);
|
||||
for (p1 = 0; p1 < order; p1++) {
|
||||
if (bnLShift(bn, 1) <0)
|
||||
return -1;
|
||||
(void)bnAddQ(bn, 1);
|
||||
sprintf(buf, "%u*p+%u = ", 2u<<p1, (2u<<p1) - 1);
|
||||
bnPut(buf, bn);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the command line to the buffer. */
|
||||
static unsigned char *
|
||||
copy(int argc, char **argv, size_t *lenp)
|
||||
{
|
||||
size_t len;
|
||||
int i;
|
||||
unsigned char *buf, *p;
|
||||
|
||||
len = argc > 2 ? (size_t)(argc-2) : 0;
|
||||
for (i = 1; i < argc; i++)
|
||||
len += strlen(argv[i]);
|
||||
*lenp = len;
|
||||
buf = malloc(len+!len); /* Can't malloc 0 bytes... */
|
||||
if (buf) {
|
||||
p = buf;
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (i > 1)
|
||||
*p++ = ' ';
|
||||
len = strlen(argv[i]);
|
||||
memcpy(p, argv[i], len);
|
||||
p += len;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
unsigned len;
|
||||
struct BigNum bn;
|
||||
unsigned char *buf;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s <seed>\n", argv[0]);
|
||||
fputs("\
|
||||
<seed> should be a a string of bytes to be hashed to seed the prime\n\
|
||||
generator. Note that unquoted whitespace between words will be counted\n\
|
||||
as a single space. To include multiple spaces, quote them.\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
buf = copy(argc, argv, &len);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bnBegin(&bn);
|
||||
|
||||
genSophieGermain(&bn, 0x100, 0, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x100, 1, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x100, 2, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x100, 3, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x200, 0, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x200, 1, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x200, 2, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x300, 0, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x300, 1, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x400, 0, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x400, 1, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x500, 0, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x500, 1, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x600, 0, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x600, 1, buf, len, stdout);
|
||||
#if 0
|
||||
/* These get *really* slow */
|
||||
genSophieGermain(&bn, 0x800, 0, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x800, 1, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0xc00, 0, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0xc00, 1, buf, len, stdout);
|
||||
/* Like, plan on a *week* or more for this one. */
|
||||
genSophieGermain(&bn, 0x1000, 0, buf, len, stdout);
|
||||
genSophieGermain(&bn, 0x1000, 1, buf, len, stdout);
|
||||
#endif
|
||||
|
||||
bnEnd(&bn);
|
||||
free(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* Compute the Jacobi symbol (small prime case only).
|
||||
*/
|
||||
#include "bn.h"
|
||||
#include "jacobi.h"
|
||||
|
||||
/*
|
||||
* For a small (usually prime, but not necessarily) prime p,
|
||||
* compute Jacobi(p,bn), which is -1, 0 or +1, using the following rules:
|
||||
* Jacobi(x, y) = Jacobi(x mod y, y)
|
||||
* Jacobi(0, y) = 0
|
||||
* Jacobi(1, y) = 1
|
||||
* Jacobi(2, y) = 0 if y is even, +1 if y is +/-1 mod 8, -1 if y = +/-3 mod 8
|
||||
* Jacobi(x1*x2, y) = Jacobi(x1, y) * Jacobi(x2, y) (used with x1 = 2 & x1 = 4)
|
||||
* If x and y are both odd, then
|
||||
* Jacobi(x, y) = Jacobi(y, x) * (-1 if x = y = 3 mod 4, +1 otherwise)
|
||||
*/
|
||||
int
|
||||
bnJacobiQ(unsigned p, struct BigNum const *bn)
|
||||
{
|
||||
int j = 1;
|
||||
unsigned u = bnLSWord(bn);
|
||||
|
||||
if (!(u & 1))
|
||||
return 0; /* Don't *do* that */
|
||||
|
||||
/* First, get rid of factors of 2 in p */
|
||||
while ((p & 3) == 0)
|
||||
p >>= 2;
|
||||
if ((p & 1) == 0) {
|
||||
p >>= 1;
|
||||
if ((u ^ u>>1) & 2)
|
||||
j = -j; /* 3 (011) or 5 (101) mod 8 */
|
||||
}
|
||||
if (p == 1)
|
||||
return j;
|
||||
/* Then, apply quadratic reciprocity */
|
||||
if (p & u & 2) /* p = u = 3 (mod 4? */
|
||||
j = -j;
|
||||
/* And reduce u mod p */
|
||||
u = bnModQ(bn, p);
|
||||
|
||||
/* Now compute Jacobi(u,p), u < p */
|
||||
while (u) {
|
||||
while ((u & 3) == 0)
|
||||
u >>= 2;
|
||||
if ((u & 1) == 0) {
|
||||
u >>= 1;
|
||||
if ((p ^ p>>1) & 2)
|
||||
j = -j; /* 3 (011) or 5 (101) mod 8 */
|
||||
}
|
||||
if (u == 1)
|
||||
return j;
|
||||
/* Now both u and p are odd, so use quadratic reciprocity */
|
||||
if (u < p) {
|
||||
unsigned t = u; u = p; p = t;
|
||||
if (u & p & 2) /* u = p = 3 (mod 4? */
|
||||
j = -j;
|
||||
}
|
||||
/* Now u >= p, so it can be reduced */
|
||||
u %= p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* For a small (usually prime, but not necessarily) prime p,
|
||||
* Return Jacobi(p,bn), which is -1, 0 or +1.
|
||||
* bn must be odd.
|
||||
*/
|
||||
struct BigNum;
|
||||
int bnJacobiQ(unsigned p, struct BigNum const *bn);
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
#ifndef KLUDGE_H
|
||||
#define KLUDGE_H
|
||||
|
||||
/*
|
||||
* Kludges for not-quite-ANSI systems.
|
||||
* This should always be the last file included, because it may
|
||||
* mess up some system header files.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef ASSERT_NEEDS_STDIO
|
||||
#define ASSERT_NEEDS_STDIO 0
|
||||
#endif
|
||||
#ifndef ASSERT_NEEDS_STDLIB
|
||||
#define ASSERT_NEEDS_STDLIB 0
|
||||
#endif
|
||||
#ifndef NO_STDLIB_H
|
||||
#define NO_STDLIB_H 0
|
||||
#endif
|
||||
|
||||
/* SunOS 4.1.x <assert.h> needs "stderr" defined, and "exit" declared... */
|
||||
#ifdef assert
|
||||
#if ASSERT_NEEDS_STDIO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#if ASSERT_NEEDS_STDLIB
|
||||
#if !NO_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NO_MEMMOVE
|
||||
#define NO_MEMMOVE 0
|
||||
#endif
|
||||
#if NO_MEMMOVE /* memove() not in libraries */
|
||||
#define memmove(dest,src,len) bcopy(src,dest,len)
|
||||
#endif
|
||||
|
||||
#ifndef NO_MEMCPY
|
||||
#define NO_MEMCPY 0
|
||||
#endif
|
||||
#if NO_MEMCPY /* memcpy() not in libraries */
|
||||
#define memcpy(dest,src,len) bcopy(src,dest,len)
|
||||
#endif
|
||||
|
||||
#ifndef MEM_PROTOS_BROKEN
|
||||
#define MEM_PROTOS_BROKEN 0
|
||||
#endif
|
||||
#if MEM_PROTOS_BROKEN
|
||||
#define memcpy(d,s,l) memcpy((void *)(d), (void const *)(s), l)
|
||||
#define memmove(d,s,l) memmove((void *)(d), (void const *)(s), l)
|
||||
#define memcmp(d,s,l) memcmp((void const *)(d), (void const *)(s), l)
|
||||
#define memset(d,v,l) memset((void *)(d), v, l)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If there are no prototypes for the stdio functions, use these to
|
||||
* reduce compiler warnings. Uses EOF as a giveaway to indicate
|
||||
* that <stdio.h> was #included.
|
||||
*/
|
||||
#ifndef NO_STDIO_PROTOS
|
||||
#define NO_STDIO_PROTOS 0
|
||||
#endif
|
||||
#if NO_STDIO_PROTOS /* Missing prototypes for "simple" functions */
|
||||
#ifdef EOF
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int (puts)(char const *);
|
||||
int (fputs)(char const *, FILE *);
|
||||
int (fflush)(FILE *);
|
||||
int (printf)(char const *, ...);
|
||||
int (fprintf)(FILE *, char const *, ...);
|
||||
/* If we have a sufficiently old-fashioned stdio, it probably uses these... */
|
||||
int (_flsbuf)(int, FILE *);
|
||||
int (_filbuf)(FILE *);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* EOF */
|
||||
#endif /* NO_STDIO_PROTOS */
|
||||
|
||||
/*
|
||||
* Borland C seems to think that it's a bad idea to decleare a
|
||||
* structure tag and not declare the contents. I happen to think
|
||||
* it's a *good* idea to use such "opaque" structures wherever
|
||||
* possible. So shut up.
|
||||
*/
|
||||
#ifdef __BORLANDC__
|
||||
#pragma warn -stu
|
||||
#ifndef MSDOS
|
||||
#define MSDOS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Turn off warning about negation of unsigned values */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4146)
|
||||
#endif
|
||||
|
||||
/* Cope with people forgetting to define the OS, if possible... */
|
||||
#ifndef MSDOS
|
||||
#ifdef __MSDOS
|
||||
#define MSDOS 1
|
||||
#endif
|
||||
#endif
|
||||
#ifndef MSDOS
|
||||
#ifdef __MSDOS__
|
||||
#define MSDOS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* By MS-DOS, we mean 16-bit brain-dead MS-DOS. Not GCC & GO32 */
|
||||
#ifdef __GO32
|
||||
#undef MSDOS
|
||||
#endif
|
||||
#ifdef __GO32__
|
||||
#undef MSDOS
|
||||
#endif
|
||||
|
||||
#endif /* KLUDGE_H */
|
||||
Vendored
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbn.h - Low-level bignum header.
|
||||
* Defines various word sizes and useful macros.
|
||||
* TODO: Rewrite this to use <stdint.h> and/or <inttypes.h>
|
||||
*/
|
||||
#ifndef LBN_H
|
||||
#define LBN_H
|
||||
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_LIMITS_H
|
||||
#define NO_LIMITS_H 0
|
||||
#endif
|
||||
|
||||
/* Make sure we have 8-bit bytes */
|
||||
#if !NO_LIMITS_H
|
||||
#include <limits.h>
|
||||
#if UCHAR_MAX != 0xff || CHAR_BIT != 8
|
||||
#error The bignum library requires 8-bit unsigned characters.
|
||||
#endif
|
||||
#endif /* !NO_LIMITS_H */
|
||||
|
||||
#ifdef BNINCLUDE /* If this is defined as, say, foo.h */
|
||||
#define STR(x) #x /* STR(BNINCLUDE) -> "BNINCLUDE" */
|
||||
#define XSTR(x) STR(x) /* XSTR(BNINCLUDE) -> STR(foo.h) -> "foo.h" */
|
||||
#include XSTR(BNINCLUDE) /* #include "foo.h" */
|
||||
#undef XSTR
|
||||
#undef STR
|
||||
#endif
|
||||
|
||||
/* Do we want bnYield()? */
|
||||
#ifndef BNYIELD
|
||||
#define BNYIELD 0
|
||||
#endif
|
||||
|
||||
/* Figure out the endianness */
|
||||
/* Error if more than one is defined */
|
||||
#if defined(BN_BIG_ENDIAN) && defined(BN_LITTLE_ENDIAN)
|
||||
#error Only one of BN_BIG_ENDIAN or BN_LITTLE_ENDIAN may be defined
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If no preference is stated, little-endian C code is slightly more
|
||||
* efficient, so prefer that. (The endianness here does NOT have to
|
||||
* match the machine's native byte sex; the library's C code will work
|
||||
* either way. The flexibility is allowed for assembly routines
|
||||
* that do care.
|
||||
*/
|
||||
#if !defined(BN_BIG_ENDIAN) && !defined(BN_LITTLE_ENDIAN)
|
||||
#define BN_LITTLE_ENDIAN 1
|
||||
#endif /* !BN_BIG_ENDIAN && !BN_LITTLE_ENDIAN */
|
||||
|
||||
/* Macros to choose between big and little endian */
|
||||
#if defined(BN_BIG_ENDIAN)
|
||||
#define BIG(b) b
|
||||
#define LITTLE(l) /*nothing*/
|
||||
#define BIGLITTLE(b,l) b
|
||||
#elif BN_LITTLE_ENDIAN
|
||||
#define BIG(b) /*nothing*/
|
||||
#define LITTLE(l) l
|
||||
#define BIGLITTLE(b,l) l
|
||||
#else
|
||||
#error One of BN_BIG_ENDIAN or BN_LITTLE_ENDIAN must be defined as 1
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Find a 16-bit unsigned type.
|
||||
* Unsigned short is preferred over unsigned int to make the type chosen
|
||||
* by this file more stable on platforms (such as many 68000 compilers)
|
||||
* which support both 16- and 32-bit ints.
|
||||
*/
|
||||
#ifndef BNWORD16
|
||||
#ifndef USHRT_MAX /* No <limits.h> available - guess */
|
||||
typedef unsigned short bnword16;
|
||||
#define BNWORD16 bnword16
|
||||
#elif USHRT_MAX == 0xffff
|
||||
typedef unsigned short bnword16;
|
||||
#define BNWORD16 bnword16
|
||||
#elif UINT_MAX == 0xffff
|
||||
typedef unsigned bnword16;
|
||||
#define BNWORD16 bnword16
|
||||
#endif
|
||||
#endif /* BNWORD16 */
|
||||
|
||||
/*
|
||||
* Find a 32-bit unsigned type.
|
||||
* Unsigned long is preferred over unsigned int to make the type chosen
|
||||
* by this file more stable on platforms (such as many 68000 compilers)
|
||||
* which support both 16- and 32-bit ints.
|
||||
*/
|
||||
#ifndef BNWORD32
|
||||
#ifndef ULONG_MAX /* No <limits.h> available - guess */
|
||||
typedef unsigned long bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
#elif ULONG_MAX == 0xfffffffful
|
||||
typedef unsigned long bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
#elif UINT_MAX == 0xffffffff
|
||||
typedef unsigned bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
#elif USHRT_MAX == 0xffffffff
|
||||
typedef unsigned short bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
#endif
|
||||
#endif /* BNWORD16 */
|
||||
|
||||
/*
|
||||
* Find a 64-bit unsigned type.
|
||||
* The conditions here are more complicated to avoid using numbers that
|
||||
* will choke lesser preprocessors (like 0xffffffffffffffff) unless
|
||||
* we're reasonably certain that they'll be acceptable.
|
||||
*/
|
||||
#if !defined(BNWORD64) && ULONG_MAX > 0xfffffffful
|
||||
#if ULONG_MAX == 0xffffffffffffffff
|
||||
typedef unsigned long bnword64;
|
||||
#define BNWORD64 bnword64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* I would test the value of unsigned long long, but some *preprocessors*
|
||||
* don't constants that long even if the compiler can accept them, so it
|
||||
* doesn't work reliably. So cross our fingers and hope that it's a 64-bit
|
||||
* type.
|
||||
*
|
||||
* GCC uses ULONG_LONG_MAX. Solaris uses ULLONG_MAX. IRIX uses ULONGLONG_MAX.
|
||||
* Are there any other names for this?
|
||||
*/
|
||||
#if !defined(BNWORD64) && \
|
||||
(defined(ULONG_LONG_MAX) || defined (ULLONG_MAX) || defined(ULONGLONG_MAX) || defined(ULONG_MAX))
|
||||
typedef unsigned long long bnword64;
|
||||
#define BNWORD64 bnword64
|
||||
#endif
|
||||
|
||||
/* We don't even try to find a 128-bit type at the moment */
|
||||
|
||||
#endif /* !LBN_H */
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbn00.c - auto-size-detecting lbn??.c file.
|
||||
*
|
||||
* Written in 1995 by Colin Plumb.
|
||||
*/
|
||||
|
||||
#include "bnsize00.h"
|
||||
|
||||
#if BNSIZE64
|
||||
|
||||
/* Include all of the C source file by reference */
|
||||
#include "lbn64.c"
|
||||
|
||||
#elif BNSIZE32
|
||||
|
||||
/* Include all of the C source file by reference */
|
||||
#include "lbn32.c"
|
||||
|
||||
#else /* BNSIZE16 */
|
||||
|
||||
/* Include all of the C source file by reference */
|
||||
#include "lbn16.c"
|
||||
|
||||
#endif
|
||||
+4073
File diff suppressed because it is too large.
Load diff
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
#ifndef LBN16_H
|
||||
#define LBN16_H
|
||||
|
||||
#include "lbn.h"
|
||||
|
||||
#ifndef BNWORD16
|
||||
#error 16-bit bignum library requires a 16-bit data type
|
||||
#endif
|
||||
|
||||
#ifndef lbnCopy_16
|
||||
void lbnCopy_16(BNWORD16 *dest, BNWORD16 const *src, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnZero_16
|
||||
void lbnZero_16(BNWORD16 *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnNeg_16
|
||||
void lbnNeg_16(BNWORD16 *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnAdd1_16
|
||||
BNWORD16 lbnAdd1_16(BNWORD16 *num, unsigned len, BNWORD16 carry);
|
||||
#endif
|
||||
#ifndef lbnSub1_16
|
||||
BNWORD16 lbnSub1_16(BNWORD16 *num, unsigned len, BNWORD16 borrow);
|
||||
#endif
|
||||
|
||||
#ifndef lbnAddN_16
|
||||
BNWORD16 lbnAddN_16(BNWORD16 *num1, BNWORD16 const *num2, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnSubN_16
|
||||
BNWORD16 lbnSubN_16(BNWORD16 *num1, BNWORD16 const *num2, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnCmp_16
|
||||
int lbnCmp_16(BNWORD16 const *num1, BNWORD16 const *num2, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMulN1_16
|
||||
void lbnMulN1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k);
|
||||
#endif
|
||||
#ifndef lbnMulAdd1_16
|
||||
BNWORD16
|
||||
lbnMulAdd1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k);
|
||||
#endif
|
||||
#ifndef lbnMulSub1_16
|
||||
BNWORD16 lbnMulSub1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k);
|
||||
#endif
|
||||
|
||||
#ifndef lbnLshift_16
|
||||
BNWORD16 lbnLshift_16(BNWORD16 *num, unsigned len, unsigned shift);
|
||||
#endif
|
||||
#ifndef lbnDouble_16
|
||||
BNWORD16 lbnDouble_16(BNWORD16 *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnRshift_16
|
||||
BNWORD16 lbnRshift_16(BNWORD16 *num, unsigned len, unsigned shift);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMul_16
|
||||
void lbnMul_16(BNWORD16 *prod, BNWORD16 const *num1, unsigned len1,
|
||||
BNWORD16 const *num2, unsigned len2);
|
||||
#endif
|
||||
#ifndef lbnSquare_16
|
||||
void lbnSquare_16(BNWORD16 *prod, BNWORD16 const *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnNorm_16
|
||||
unsigned lbnNorm_16(BNWORD16 const *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnBits_16
|
||||
unsigned lbnBits_16(BNWORD16 const *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnExtractBigBytes_16
|
||||
void lbnExtractBigBytes_16(BNWORD16 const *bn, unsigned char *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnInsertBigytes_16
|
||||
void lbnInsertBigBytes_16(BNWORD16 *n, unsigned char const *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnExtractLittleBytes_16
|
||||
void lbnExtractLittleBytes_16(BNWORD16 const *bn, unsigned char *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnInsertLittleBytes_16
|
||||
void lbnInsertLittleBytes_16(BNWORD16 *n, unsigned char const *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
|
||||
#ifndef lbnDiv21_16
|
||||
BNWORD16 lbnDiv21_16(BNWORD16 *q, BNWORD16 nh, BNWORD16 nl, BNWORD16 d);
|
||||
#endif
|
||||
#ifndef lbnDiv1_16
|
||||
BNWORD16 lbnDiv1_16(BNWORD16 *q, BNWORD16 *rem,
|
||||
BNWORD16 const *n, unsigned len, BNWORD16 d);
|
||||
#endif
|
||||
#ifndef lbnModQ_16
|
||||
unsigned lbnModQ_16(BNWORD16 const *n, unsigned len, unsigned d);
|
||||
#endif
|
||||
#ifndef lbnDiv_16
|
||||
BNWORD16
|
||||
lbnDiv_16(BNWORD16 *q, BNWORD16 *n, unsigned nlen, BNWORD16 *d, unsigned dlen);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMontInv1_16
|
||||
BNWORD16 lbnMontInv1_16(BNWORD16 const x);
|
||||
#endif
|
||||
#ifndef lbnMontReduce_16
|
||||
void lbnMontReduce_16(BNWORD16 *n, BNWORD16 const *mod, unsigned const mlen,
|
||||
BNWORD16 inv);
|
||||
#endif
|
||||
#ifndef lbnToMont_16
|
||||
void lbnToMont_16(BNWORD16 *n, unsigned nlen, BNWORD16 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnFromMont_16
|
||||
void lbnFromMont_16(BNWORD16 *n, BNWORD16 *mod, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnExpMod_16
|
||||
int lbnExpMod_16(BNWORD16 *result, BNWORD16 const *n, unsigned nlen,
|
||||
BNWORD16 const *exp, unsigned elen, BNWORD16 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnDoubleExpMod_16
|
||||
int lbnDoubleExpMod_16(BNWORD16 *result,
|
||||
BNWORD16 const *n1, unsigned n1len, BNWORD16 const *e1, unsigned e1len,
|
||||
BNWORD16 const *n2, unsigned n2len, BNWORD16 const *e2, unsigned e2len,
|
||||
BNWORD16 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnTwoExpMod_16
|
||||
int lbnTwoExpMod_16(BNWORD16 *n, BNWORD16 const *exp, unsigned elen,
|
||||
BNWORD16 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnGcd_16
|
||||
int lbnGcd_16(BNWORD16 *a, unsigned alen, BNWORD16 *b, unsigned blen,
|
||||
unsigned *rlen);
|
||||
#endif
|
||||
#ifndef lbnInv_16
|
||||
int lbnInv_16(BNWORD16 *a, unsigned alen, BNWORD16 const *mod, unsigned mlen);
|
||||
#endif
|
||||
|
||||
int lbnBasePrecompBegin_16(BNWORD16 **array, unsigned n, unsigned bits,
|
||||
BNWORD16 const *g, unsigned glen, BNWORD16 *mod, unsigned mlen);
|
||||
int lbnBasePrecompExp_16(BNWORD16 *result, BNWORD16 const * const *array,
|
||||
unsigned bits, BNWORD16 const *exp, unsigned elen,
|
||||
BNWORD16 const *mod, unsigned mlen);
|
||||
int lbnDoubleBasePrecompExp_16(BNWORD16 *result, unsigned bits,
|
||||
BNWORD16 const * const *array1, BNWORD16 const *exp1, unsigned elen1,
|
||||
BNWORD16 const * const *array2, BNWORD16 const *exp2,
|
||||
unsigned elen2, BNWORD16 const *mod, unsigned mlen);
|
||||
|
||||
#endif /* LBN16_H */
|
||||
+4073
File diff suppressed because it is too large.
Load diff
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
#ifndef LBN32_H
|
||||
#define LBN32_H
|
||||
|
||||
#include "lbn.h"
|
||||
|
||||
#ifndef BNWORD32
|
||||
#error 32-bit bignum library requires a 32-bit data type
|
||||
#endif
|
||||
|
||||
#ifndef lbnCopy_32
|
||||
void lbnCopy_32(BNWORD32 *dest, BNWORD32 const *src, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnZero_32
|
||||
void lbnZero_32(BNWORD32 *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnNeg_32
|
||||
void lbnNeg_32(BNWORD32 *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnAdd1_32
|
||||
BNWORD32 lbnAdd1_32(BNWORD32 *num, unsigned len, BNWORD32 carry);
|
||||
#endif
|
||||
#ifndef lbnSub1_32
|
||||
BNWORD32 lbnSub1_32(BNWORD32 *num, unsigned len, BNWORD32 borrow);
|
||||
#endif
|
||||
|
||||
#ifndef lbnAddN_32
|
||||
BNWORD32 lbnAddN_32(BNWORD32 *num1, BNWORD32 const *num2, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnSubN_32
|
||||
BNWORD32 lbnSubN_32(BNWORD32 *num1, BNWORD32 const *num2, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnCmp_32
|
||||
int lbnCmp_32(BNWORD32 const *num1, BNWORD32 const *num2, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMulN1_32
|
||||
void lbnMulN1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k);
|
||||
#endif
|
||||
#ifndef lbnMulAdd1_32
|
||||
BNWORD32
|
||||
lbnMulAdd1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k);
|
||||
#endif
|
||||
#ifndef lbnMulSub1_32
|
||||
BNWORD32 lbnMulSub1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k);
|
||||
#endif
|
||||
|
||||
#ifndef lbnLshift_32
|
||||
BNWORD32 lbnLshift_32(BNWORD32 *num, unsigned len, unsigned shift);
|
||||
#endif
|
||||
#ifndef lbnDouble_32
|
||||
BNWORD32 lbnDouble_32(BNWORD32 *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnRshift_32
|
||||
BNWORD32 lbnRshift_32(BNWORD32 *num, unsigned len, unsigned shift);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMul_32
|
||||
void lbnMul_32(BNWORD32 *prod, BNWORD32 const *num1, unsigned len1,
|
||||
BNWORD32 const *num2, unsigned len2);
|
||||
#endif
|
||||
#ifndef lbnSquare_32
|
||||
void lbnSquare_32(BNWORD32 *prod, BNWORD32 const *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnNorm_32
|
||||
unsigned lbnNorm_32(BNWORD32 const *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnBits_32
|
||||
unsigned lbnBits_32(BNWORD32 const *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnExtractBigBytes_32
|
||||
void lbnExtractBigBytes_32(BNWORD32 const *bn, unsigned char *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnInsertBigytes_32
|
||||
void lbnInsertBigBytes_32(BNWORD32 *n, unsigned char const *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnExtractLittleBytes_32
|
||||
void lbnExtractLittleBytes_32(BNWORD32 const *bn, unsigned char *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnInsertLittleBytes_32
|
||||
void lbnInsertLittleBytes_32(BNWORD32 *n, unsigned char const *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
|
||||
#ifndef lbnDiv21_32
|
||||
BNWORD32 lbnDiv21_32(BNWORD32 *q, BNWORD32 nh, BNWORD32 nl, BNWORD32 d);
|
||||
#endif
|
||||
#ifndef lbnDiv1_32
|
||||
BNWORD32 lbnDiv1_32(BNWORD32 *q, BNWORD32 *rem,
|
||||
BNWORD32 const *n, unsigned len, BNWORD32 d);
|
||||
#endif
|
||||
#ifndef lbnModQ_32
|
||||
unsigned lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d);
|
||||
#endif
|
||||
#ifndef lbnDiv_32
|
||||
BNWORD32
|
||||
lbnDiv_32(BNWORD32 *q, BNWORD32 *n, unsigned nlen, BNWORD32 *d, unsigned dlen);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMontInv1_32
|
||||
BNWORD32 lbnMontInv1_32(BNWORD32 const x);
|
||||
#endif
|
||||
#ifndef lbnMontReduce_32
|
||||
void lbnMontReduce_32(BNWORD32 *n, BNWORD32 const *mod, unsigned const mlen,
|
||||
BNWORD32 inv);
|
||||
#endif
|
||||
#ifndef lbnToMont_32
|
||||
void lbnToMont_32(BNWORD32 *n, unsigned nlen, BNWORD32 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnFromMont_32
|
||||
void lbnFromMont_32(BNWORD32 *n, BNWORD32 *mod, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnExpMod_32
|
||||
int lbnExpMod_32(BNWORD32 *result, BNWORD32 const *n, unsigned nlen,
|
||||
BNWORD32 const *exp, unsigned elen, BNWORD32 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnDoubleExpMod_32
|
||||
int lbnDoubleExpMod_32(BNWORD32 *result,
|
||||
BNWORD32 const *n1, unsigned n1len, BNWORD32 const *e1, unsigned e1len,
|
||||
BNWORD32 const *n2, unsigned n2len, BNWORD32 const *e2, unsigned e2len,
|
||||
BNWORD32 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnTwoExpMod_32
|
||||
int lbnTwoExpMod_32(BNWORD32 *n, BNWORD32 const *exp, unsigned elen,
|
||||
BNWORD32 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnGcd_32
|
||||
int lbnGcd_32(BNWORD32 *a, unsigned alen, BNWORD32 *b, unsigned blen,
|
||||
unsigned *rlen);
|
||||
#endif
|
||||
#ifndef lbnInv_32
|
||||
int lbnInv_32(BNWORD32 *a, unsigned alen, BNWORD32 const *mod, unsigned mlen);
|
||||
#endif
|
||||
|
||||
int lbnBasePrecompBegin_32(BNWORD32 **array, unsigned n, unsigned bits,
|
||||
BNWORD32 const *g, unsigned glen, BNWORD32 *mod, unsigned mlen);
|
||||
int lbnBasePrecompExp_32(BNWORD32 *result, BNWORD32 const * const *array,
|
||||
unsigned bits, BNWORD32 const *exp, unsigned elen,
|
||||
BNWORD32 const *mod, unsigned mlen);
|
||||
int lbnDoubleBasePrecompExp_32(BNWORD32 *result, unsigned bits,
|
||||
BNWORD32 const * const *array1, BNWORD32 const *exp1, unsigned elen1,
|
||||
BNWORD32 const * const *array2, BNWORD32 const *exp2,
|
||||
unsigned elen2, BNWORD32 const *mod, unsigned mlen);
|
||||
|
||||
#endif /* LBN32_H */
|
||||
+4073
File diff suppressed because it is too large.
Load diff
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
#ifndef LBN64_H
|
||||
#define LBN64_H
|
||||
|
||||
#include "lbn.h"
|
||||
|
||||
#ifndef BNWORD64
|
||||
#error 64-bit bignum library requires a 64-bit data type
|
||||
#endif
|
||||
|
||||
#ifndef lbnCopy_64
|
||||
void lbnCopy_64(BNWORD64 *dest, BNWORD64 const *src, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnZero_64
|
||||
void lbnZero_64(BNWORD64 *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnNeg_64
|
||||
void lbnNeg_64(BNWORD64 *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnAdd1_64
|
||||
BNWORD64 lbnAdd1_64(BNWORD64 *num, unsigned len, BNWORD64 carry);
|
||||
#endif
|
||||
#ifndef lbnSub1_64
|
||||
BNWORD64 lbnSub1_64(BNWORD64 *num, unsigned len, BNWORD64 borrow);
|
||||
#endif
|
||||
|
||||
#ifndef lbnAddN_64
|
||||
BNWORD64 lbnAddN_64(BNWORD64 *num1, BNWORD64 const *num2, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnSubN_64
|
||||
BNWORD64 lbnSubN_64(BNWORD64 *num1, BNWORD64 const *num2, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnCmp_64
|
||||
int lbnCmp_64(BNWORD64 const *num1, BNWORD64 const *num2, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMulN1_64
|
||||
void lbnMulN1_64(BNWORD64 *out, BNWORD64 const *in, unsigned len, BNWORD64 k);
|
||||
#endif
|
||||
#ifndef lbnMulAdd1_64
|
||||
BNWORD64
|
||||
lbnMulAdd1_64(BNWORD64 *out, BNWORD64 const *in, unsigned len, BNWORD64 k);
|
||||
#endif
|
||||
#ifndef lbnMulSub1_64
|
||||
BNWORD64 lbnMulSub1_64(BNWORD64 *out, BNWORD64 const *in, unsigned len, BNWORD64 k);
|
||||
#endif
|
||||
|
||||
#ifndef lbnLshift_64
|
||||
BNWORD64 lbnLshift_64(BNWORD64 *num, unsigned len, unsigned shift);
|
||||
#endif
|
||||
#ifndef lbnDouble_64
|
||||
BNWORD64 lbnDouble_64(BNWORD64 *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnRshift_64
|
||||
BNWORD64 lbnRshift_64(BNWORD64 *num, unsigned len, unsigned shift);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMul_64
|
||||
void lbnMul_64(BNWORD64 *prod, BNWORD64 const *num1, unsigned len1,
|
||||
BNWORD64 const *num2, unsigned len2);
|
||||
#endif
|
||||
#ifndef lbnSquare_64
|
||||
void lbnSquare_64(BNWORD64 *prod, BNWORD64 const *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnNorm_64
|
||||
unsigned lbnNorm_64(BNWORD64 const *num, unsigned len);
|
||||
#endif
|
||||
#ifndef lbnBits_64
|
||||
unsigned lbnBits_64(BNWORD64 const *num, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnExtractBigBytes_64
|
||||
void lbnExtractBigBytes_64(BNWORD64 const *bn, unsigned char *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnInsertBigytes_64
|
||||
void lbnInsertBigBytes_64(BNWORD64 *n, unsigned char const *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnExtractLittleBytes_64
|
||||
void lbnExtractLittleBytes_64(BNWORD64 const *bn, unsigned char *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
#ifndef lbnInsertLittleBytes_64
|
||||
void lbnInsertLittleBytes_64(BNWORD64 *n, unsigned char const *buf,
|
||||
unsigned lsbyte, unsigned buflen);
|
||||
#endif
|
||||
|
||||
#ifndef lbnDiv21_64
|
||||
BNWORD64 lbnDiv21_64(BNWORD64 *q, BNWORD64 nh, BNWORD64 nl, BNWORD64 d);
|
||||
#endif
|
||||
#ifndef lbnDiv1_64
|
||||
BNWORD64 lbnDiv1_64(BNWORD64 *q, BNWORD64 *rem,
|
||||
BNWORD64 const *n, unsigned len, BNWORD64 d);
|
||||
#endif
|
||||
#ifndef lbnModQ_64
|
||||
unsigned lbnModQ_64(BNWORD64 const *n, unsigned len, unsigned d);
|
||||
#endif
|
||||
#ifndef lbnDiv_64
|
||||
BNWORD64
|
||||
lbnDiv_64(BNWORD64 *q, BNWORD64 *n, unsigned nlen, BNWORD64 *d, unsigned dlen);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMontInv1_64
|
||||
BNWORD64 lbnMontInv1_64(BNWORD64 const x);
|
||||
#endif
|
||||
#ifndef lbnMontReduce_64
|
||||
void lbnMontReduce_64(BNWORD64 *n, BNWORD64 const *mod, unsigned const mlen,
|
||||
BNWORD64 inv);
|
||||
#endif
|
||||
#ifndef lbnToMont_64
|
||||
void lbnToMont_64(BNWORD64 *n, unsigned nlen, BNWORD64 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnFromMont_64
|
||||
void lbnFromMont_64(BNWORD64 *n, BNWORD64 *mod, unsigned len);
|
||||
#endif
|
||||
|
||||
#ifndef lbnExpMod_64
|
||||
int lbnExpMod_64(BNWORD64 *result, BNWORD64 const *n, unsigned nlen,
|
||||
BNWORD64 const *exp, unsigned elen, BNWORD64 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnDoubleExpMod_64
|
||||
int lbnDoubleExpMod_64(BNWORD64 *result,
|
||||
BNWORD64 const *n1, unsigned n1len, BNWORD64 const *e1, unsigned e1len,
|
||||
BNWORD64 const *n2, unsigned n2len, BNWORD64 const *e2, unsigned e2len,
|
||||
BNWORD64 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnTwoExpMod_64
|
||||
int lbnTwoExpMod_64(BNWORD64 *n, BNWORD64 const *exp, unsigned elen,
|
||||
BNWORD64 *mod, unsigned mlen);
|
||||
#endif
|
||||
#ifndef lbnGcd_64
|
||||
int lbnGcd_64(BNWORD64 *a, unsigned alen, BNWORD64 *b, unsigned blen,
|
||||
unsigned *rlen);
|
||||
#endif
|
||||
#ifndef lbnInv_64
|
||||
int lbnInv_64(BNWORD64 *a, unsigned alen, BNWORD64 const *mod, unsigned mlen);
|
||||
#endif
|
||||
|
||||
int lbnBasePrecompBegin_64(BNWORD64 **array, unsigned n, unsigned bits,
|
||||
BNWORD64 const *g, unsigned glen, BNWORD64 *mod, unsigned mlen);
|
||||
int lbnBasePrecompExp_64(BNWORD64 *result, BNWORD64 const * const *array,
|
||||
unsigned bits, BNWORD64 const *exp, unsigned elen,
|
||||
BNWORD64 const *mod, unsigned mlen);
|
||||
int lbnDoubleBasePrecompExp_64(BNWORD64 *result, unsigned bits,
|
||||
BNWORD64 const * const *array1, BNWORD64 const *exp1, unsigned elen1,
|
||||
BNWORD64 const * const *array2, BNWORD64 const *exp2,
|
||||
unsigned elen2, BNWORD64 const *mod, unsigned mlen);
|
||||
|
||||
#endif /* LBN64_H */
|
||||
+460
@@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbn68000.c - 16-bit bignum primitives for the 68000 (or 68010) processors.
|
||||
*
|
||||
* This was written for Metrowerks C, and while it should be reasonably
|
||||
* portable, NOTE that Metrowerks lets a callee trash a0, a1, d0, d1, and d2.
|
||||
* Some 680x0 compilers make d2 callee-save, so instructions to save it
|
||||
* will have to be added.
|
||||
*
|
||||
* This code supports 16 or 32-bit ints, based on UINT_MAX.
|
||||
* Regardless of UINT_MAX, only bignums up to 64K words (1 million bits)
|
||||
* are supported. (68k hackers will recognize this as a consequence of
|
||||
* using dbra.)
|
||||
*
|
||||
* These primitives use little-endian word order.
|
||||
* (The order of bytes within words is irrelevant to this issue.)
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "lbn.h" /* Should include lbn68000.h */
|
||||
|
||||
/*
|
||||
* The Metrowerks C compiler (1.2.2) produces bad 68k code for the
|
||||
* following input, which happens to be the inner loop of lbnSub1,
|
||||
* so a few less than critical routines have been recoded in assembly
|
||||
* to avoid the bug. (Optimizer on or off does not matter.)
|
||||
*
|
||||
* unsigned
|
||||
* decrement(unsigned *num, unsigned len)
|
||||
* {
|
||||
* do {
|
||||
* if ((*num++)-- != 0)
|
||||
* return 0;
|
||||
* } while (--len);
|
||||
* return 1;
|
||||
* }
|
||||
*/
|
||||
asm BNWORD16
|
||||
lbnSub1_16(BNWORD16 *num, unsigned len, BNWORD16 borrow)
|
||||
{
|
||||
movea.l 4(sp),a0 /* num */
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 10(sp),d0 /* borrow */
|
||||
#else
|
||||
move.w 12(sp),d0 /* borrow */
|
||||
#endif
|
||||
sub.w d0,(a0)+
|
||||
bcc done
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 8(sp),d0 /* len */
|
||||
#else
|
||||
move.w 10(sp),d0 /* len */
|
||||
#endif
|
||||
subq.w #2,d0
|
||||
bcs done
|
||||
loop:
|
||||
subq.w #1,(a0)+
|
||||
dbcc d0,loop
|
||||
done:
|
||||
moveq.l #0,d0
|
||||
addx.w d0,d0
|
||||
rts
|
||||
}
|
||||
|
||||
asm BNWORD16
|
||||
lbnAdd1_16(BNWORD16 *num, unsigned len, BNWORD16 carry)
|
||||
{
|
||||
movea.l 4(sp),a0 /* num */
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 10(sp),d0 /* carry */
|
||||
#else
|
||||
move.w 12(sp),d0 /* carry */
|
||||
#endif
|
||||
add.w d0,(a0)+
|
||||
bcc done
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 8(sp),d0 /* len */
|
||||
#else
|
||||
move.w 10(sp),d0 /* len */
|
||||
#endif
|
||||
subq.w #2,d0
|
||||
bcs done
|
||||
loop:
|
||||
addq.w #1,(a0)+
|
||||
dbcc d0,loop
|
||||
done:
|
||||
moveq.l #0,d0
|
||||
addx.w d0,d0
|
||||
rts
|
||||
}
|
||||
|
||||
asm void
|
||||
lbnMulN1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
|
||||
{
|
||||
move.w d3,-(sp) /* 2 bytes of stack frame */
|
||||
move.l 2+4(sp),a1 /* out */
|
||||
move.l 2+8(sp),a0 /* in */
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 2+12(sp),d3 /* len */
|
||||
move.w 2+14(sp),d2 /* k */
|
||||
#else
|
||||
move.w 2+14(sp),d3 /* len (low 16 bits) */
|
||||
move.w 2+16(sp),d2 /* k */
|
||||
#endif
|
||||
|
||||
move.w (a0)+,d1 /* First multiply */
|
||||
mulu.w d2,d1
|
||||
move.w d1,(a1)+
|
||||
clr.w d1
|
||||
swap d1
|
||||
|
||||
subq.w #1,d3 /* Setup for loop unrolling */
|
||||
lsr.w #1,d3
|
||||
bcs.s m16_even
|
||||
beq.s m16_short
|
||||
|
||||
subq.w #1,d3 /* Set up software pipeline properly */
|
||||
move.l d1,d0
|
||||
|
||||
m16_loop:
|
||||
move.w (a0)+,d1
|
||||
mulu.w d2,d1
|
||||
add.l d0,d1
|
||||
move.w d1,(a1)+
|
||||
clr.w d1
|
||||
swap d1
|
||||
m16_even:
|
||||
|
||||
move.w (a0)+,d0
|
||||
mulu.w d2,d0
|
||||
add.l d1,d0
|
||||
move.w d0,(a1)+
|
||||
clr.w d0
|
||||
swap d0
|
||||
|
||||
dbra d3,m16_loop
|
||||
|
||||
move.w d0,(a1)
|
||||
move.w (sp)+,d3
|
||||
rts
|
||||
m16_short:
|
||||
move.w d1,(a1)
|
||||
move.w (sp)+,d3
|
||||
rts
|
||||
}
|
||||
|
||||
|
||||
asm BNWORD16
|
||||
lbnMulAdd1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
|
||||
{
|
||||
move.w d4,-(sp)
|
||||
clr.w d4
|
||||
move.w d3,-(sp) /* 4 bytes of stack frame */
|
||||
move.l 4+4(sp),a1 /* out */
|
||||
move.l 4+8(sp),a0 /* in */
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 4+12(sp),d3 /* len */
|
||||
move.w 4+14(sp),d2 /* k */
|
||||
#else
|
||||
move.w 4+14(sp),d3 /* len (low 16 bits) */
|
||||
move.w 4+16(sp),d2 /* k */
|
||||
#endif
|
||||
|
||||
move.w (a0)+,d1 /* First multiply */
|
||||
mulu.w d2,d1
|
||||
add.w d1,(a1)+
|
||||
clr.w d1
|
||||
swap d1
|
||||
addx.w d4,d1
|
||||
|
||||
subq.w #1,d3 /* Setup for loop unrolling */
|
||||
lsr.w #1,d3
|
||||
bcs.s ma16_even
|
||||
beq.s ma16_short
|
||||
|
||||
subq.w #1,d3 /* Set up software pipeline properly */
|
||||
move.l d1,d0
|
||||
|
||||
ma16_loop:
|
||||
move.w (a0)+,d1
|
||||
mulu.w d2,d1
|
||||
add.l d0,d1
|
||||
add.w d1,(a1)+
|
||||
clr.w d1
|
||||
swap d1
|
||||
addx.w d4,d1
|
||||
ma16_even:
|
||||
|
||||
move.w (a0)+,d0
|
||||
mulu.w d2,d0
|
||||
add.l d1,d0
|
||||
add.w d0,(a1)+
|
||||
clr.w d0
|
||||
swap d0
|
||||
addx.w d4,d0
|
||||
|
||||
dbra d3,ma16_loop
|
||||
|
||||
move.w (sp)+,d3
|
||||
move.w (sp)+,d4
|
||||
rts
|
||||
ma16_short:
|
||||
move.w (sp)+,d3
|
||||
move.l d1,d0
|
||||
move.w (sp)+,d4
|
||||
rts
|
||||
}
|
||||
|
||||
|
||||
|
||||
asm BNWORD16
|
||||
lbnMulSub1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
|
||||
{
|
||||
move.w d4,-(sp)
|
||||
clr.w d4
|
||||
move.w d3,-(sp) /* 4 bytes of stack frame */
|
||||
move.l 4+4(sp),a1 /* out */
|
||||
move.l 4+8(sp),a0 /* in */
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 4+12(sp),d3 /* len */
|
||||
move.w 4+14(sp),d2 /* k */
|
||||
#else
|
||||
move.w 4+14(sp),d3 /* len (low 16 bits) */
|
||||
move.w 4+16(sp),d2 /* k */
|
||||
#endif
|
||||
|
||||
move.w (a0)+,d1 /* First multiply */
|
||||
mulu.w d2,d1
|
||||
sub.w d1,(a1)+
|
||||
clr.w d1
|
||||
swap d1
|
||||
addx.w d4,d1
|
||||
|
||||
subq.w #1,d3 /* Setup for loop unrolling */
|
||||
lsr.w #1,d3
|
||||
bcs.s ms16_even
|
||||
beq.s ms16_short
|
||||
|
||||
subq.w #1,d3 /* Set up software pipeline properly */
|
||||
move.l d1,d0
|
||||
|
||||
ms16_loop:
|
||||
move.w (a0)+,d1
|
||||
mulu.w d2,d1
|
||||
add.l d0,d1
|
||||
sub.w d1,(a1)+
|
||||
clr.w d1
|
||||
swap d1
|
||||
addx.w d4,d1
|
||||
ms16_even:
|
||||
|
||||
move.w (a0)+,d0
|
||||
mulu.w d2,d0
|
||||
add.l d1,d0
|
||||
sub.w d0,(a1)+
|
||||
clr.w d0
|
||||
swap d0
|
||||
addx.w d4,d0
|
||||
|
||||
dbra d3,ms16_loop
|
||||
|
||||
move.w (sp)+,d3
|
||||
move.w (sp)+,d4
|
||||
rts
|
||||
ms16_short:
|
||||
move.w (sp)+,d3
|
||||
move.l d1,d0
|
||||
move.w (sp)+,d4
|
||||
rts
|
||||
}
|
||||
|
||||
/* The generic long/short divide doesn't know that nh < d */
|
||||
asm BNWORD16
|
||||
lbnDiv21_16(BNWORD16 *q, BNWORD16 nh, BNWORD16 nl, BNWORD16 d)
|
||||
{
|
||||
move.l 8(sp),d0 /* nh *and* nl */
|
||||
divu.w 12(sp),d0
|
||||
move.l 4(sp),a0
|
||||
move.w d0,(a0)
|
||||
clr.w d0
|
||||
swap d0
|
||||
rts
|
||||
}
|
||||
|
||||
asm unsigned
|
||||
lbnModQ_16(BNWORD16 const *n, unsigned len, BNWORD16 d)
|
||||
{
|
||||
move.l 4(sp),a0 /* n */
|
||||
moveq.l #0,d1
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 8(sp),d1 /* len */
|
||||
move.w 10(sp),d2 /* d */
|
||||
#else
|
||||
move.w 10(sp),d1 /* len (low 16 bits) */
|
||||
move.w 12(sp),d2 /* d */
|
||||
#endif
|
||||
|
||||
add.l d1,a0
|
||||
add.l d1,a0 /* n += len */
|
||||
moveq.l #0,d0
|
||||
subq.w #1,d1
|
||||
|
||||
mq16_loop:
|
||||
move.w -(a0),d0 /* Assemble remainder and new word */
|
||||
divu.w d2,d0 /* Put remainder in high half of d0 */
|
||||
dbra d1,mq16_loop
|
||||
|
||||
mq16_done:
|
||||
clr.w d0
|
||||
swap d0
|
||||
rts
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect if this is a 32-bit processor (68020+ *or* CPU32).
|
||||
* Both the 68020+ and CPU32 processors (which have 32x32->64-bit
|
||||
* multiply, what the 32-bit math library wants) support scaled indexed
|
||||
* addressing. The 68000 and 68010 ignore the scale selection
|
||||
* bits, treating it as *1 all the time. So a 32-bit processor
|
||||
* will evaluate -2(a0,a0.w*2) as 1+1*2-2 = 1.
|
||||
* A 16-bit processor will compute 1+1-2 = 0.
|
||||
*
|
||||
* Thus, the return value will indicate whether the chip this is
|
||||
* running on supports 32x32->64-bit multiply (mulu.l).
|
||||
*/
|
||||
asm int
|
||||
is68020(void)
|
||||
{
|
||||
machine 68020
|
||||
lea 1,a0
|
||||
#if 0
|
||||
lea -2(a0,a0.w*2),a0 /* Metrowerks won't assemble this, arrgh */
|
||||
#else
|
||||
dc.w 0x41f0, 0x82fe
|
||||
#endif
|
||||
move.l a0,d0
|
||||
rts
|
||||
}
|
||||
/*
|
||||
* Since I had to hand-assemble that fancy addressing mode, I had to study
|
||||
* up on 680x0 addressing modes.
|
||||
* A summary of 680x0 addressing modes.
|
||||
* A 68000 effective address specifies an operand on an instruction, which
|
||||
* may be a register or in memory. It is made up of a 3-bit mode and a
|
||||
* 3-bit register specifier. The meanings of the various modes are:
|
||||
*
|
||||
* 000 reg - Dn, n specified by "reg"
|
||||
* 001 reg - An, n specified by "reg"
|
||||
* 010 reg - (An)
|
||||
* 011 reg - (An)+
|
||||
* 100 reg - -(An)
|
||||
* 101 reg - d16(An), one 16-bit displacement word follows, sign-extended
|
||||
* 110 reg - Fancy addressing mode off of An, see extension word below
|
||||
* 111 000 - abs.W, one 16-bit signed absolute address follows
|
||||
* 111 001 - abs.L, one 32-bit absolute address follows
|
||||
* 111 010 - d16(PC), one 16-bit displacemnt word follows, sign-extended
|
||||
* 111 011 - Fancy addressing mode off of PC, see extension word below
|
||||
* 111 100 - #immediate, followed by 16 or 32 bits of immediate value
|
||||
* 111 101 - unused, reserved
|
||||
* 111 110 - unused, reserved
|
||||
* 111 111 - unused, reserved
|
||||
*
|
||||
* Memory references are to data space, except that PC-relative references
|
||||
* are to program space, and are read-only.
|
||||
*
|
||||
* Fancy addressing modes are followed by a 16-bit extension word, and come
|
||||
* in "brief" and "full" forms.
|
||||
* The "brief" form looks like this. Bit 8 is 0 to indicate this form:
|
||||
*
|
||||
* 1 1 1 1 1 1 1
|
||||
* 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |A/D| register |L/W| scale | 0 | 8-bit signed displacement |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* The basic effective address specifies a 32-bit base register - A0 through
|
||||
* A7 or PC (the address of the following instruction).
|
||||
* The A/D and register fields specify an index register. A/D is 1 for
|
||||
* address registers, and 0 for data registers. L/W specifies the length
|
||||
* of the index register, 1 for 32 bits, and 0 for 16 bits (sign-extended).
|
||||
* The scale field is a left shift amount (0 to 3 bits) to apply to the
|
||||
* sign-extended index register. The final address is d8(An,Rn.X*SCALE),
|
||||
* also written (d8,An,Rn.X*SCALE). X is "W" or "L", SCALE is 1, 2, 4 or 8.
|
||||
* "*1" may be omitted, as may a d8 of 0.
|
||||
*
|
||||
* The 68000 supports this form, but only with a scale field of 0.
|
||||
* It does NOT (says the MC68030 User's Manual MC68030UM/AD, section 2.7)
|
||||
* decode the scale field and the following format bit. They are treated
|
||||
* as 0.
|
||||
* I recall (I don't have the data book handy) that the CPU32 processor
|
||||
* core used in the 683xx series processors supports variable scales,
|
||||
* but only the brief extension word form. I suspect it decodes the
|
||||
* format bit and traps if it is not zero, but I don't recall.
|
||||
*
|
||||
* The "full" form (680x0, x >= 2 processors only) looks like this:
|
||||
*
|
||||
* 1 1 1 1 1 1 1
|
||||
* 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |A/D| register |L/W| scale | 1 | BS| IS|BD size| 0 | P |OD size|
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* The first 8 bits are interpreted the same way as in the brief form,
|
||||
* except that bit 8 is set to 1 to indicate the full form.
|
||||
* BS, Base Suppress, if set, causes a value of 0 to be used in place of
|
||||
* the base register value. If this is set, the base register
|
||||
* specified is irrelevant, except that if it is the PC, the fetch is
|
||||
* still done from program space. The specifier "ZPC" can be used in
|
||||
* place of "PC" in the effective address mnemonic to represent this
|
||||
* case.
|
||||
* IS, Index Suppress, if set, causes a value of 0 to be used in place
|
||||
* of the scaled index register. In this case, the first 7 bits of the
|
||||
* extension word are irrelevant.
|
||||
* BD size specifies the base displacement size. A value of 00
|
||||
* in this field is illegal, while 01, 10 and 11 indicate that the
|
||||
* extension word is followed by 0, 1 or 2 16-bit words of base displacement
|
||||
* (zero, sign-extended to 32 bits, and most-significant word first,
|
||||
* respectively) to add to the base register value.
|
||||
* Bit 3 is unused.
|
||||
* The P bit is the pre/post indexing bit, and only applies if an outer
|
||||
* displacement is used. This is explained later.
|
||||
* OD size specifies the size of an outer displacement. In the simple
|
||||
* case, this field is set to 00 and the effective address is
|
||||
* (disp,An,Rn.X*SCALE) or (disp,PC,Rn.X*SCALE).
|
||||
* In this case the P bit must be 0. Any of those compnents may be
|
||||
* suppressed, with a BD size of 01, the BS bit, or the IS bit.
|
||||
* If the OD size is not 00, it encodes an outer displacement in the same
|
||||
* manner as the BD size, and 0, 1 or 2 16-bit words of outer displacement
|
||||
* follow the base displacement in the instruction stream. In this case,
|
||||
* this is a double-indirect addressing mode. The base, base displacement,
|
||||
* and possibly the index, specify a 32-bit memory word which holds a value
|
||||
* which is fetched, and the outer displacement and possibly the index are
|
||||
* added to produce the address of the operand.
|
||||
* If the P bit is 0, this is pre-indexed, and the index value is added
|
||||
* before the fetch of the indirect word, producing an effective address
|
||||
* of ([disp,An,Rn.X*SCALE],disp). If the P bit is 1, the post-indexed case,
|
||||
* the memory word is fectched from base+base displacement, then the index
|
||||
* and outer displacement are added to compute the address of the operand.
|
||||
* This effective address is written ([disp,An],Rn.X*SCALE,disp).
|
||||
* (In both cases, "An" may also be "PC" or "ZPC".)
|
||||
* Any of the components may be omitted. If the index is omitted (using the
|
||||
* IS bit), the P bit is irrelevant, but must be written as 0.
|
||||
* Thus, legal combinations of IS, P and OD size are:
|
||||
* 0 0 00 - (disp,An,Rn.X*SCALE), also written disp(An,Rn.X*SCALE)
|
||||
* 0 0 01 - ([disp,An,Rn.X*SCALE])
|
||||
* 0 0 10 - ([disp,An,Rn.X*SCALE],d16)
|
||||
* 0 0 11 - ([disp,An,Rn.X*SCALE],d32)
|
||||
* 0 1 01 - ([disp,An],Rn.X*SCALE)
|
||||
* 0 1 10 - ([disp,An],Rn.X*SCALE,d16)
|
||||
* 0 1 11 - ([disp,An],Rn.X*SCALE,d32)
|
||||
* 1 0 00 - (disp,An), also written disp(An)
|
||||
* 1 0 01 - ([disp,An])
|
||||
* 1 0 10 - ([disp,An],d16)
|
||||
* 1 0 11 - ([disp,An],d32)
|
||||
*/
|
||||
|
||||
/* 45678901234567890123456789012345678901234567890123456789012345678901234567 */
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbn68000.h - 16-bit bignum primitives for the 68000 (or 68010) processors.
|
||||
*
|
||||
* These primitives use little-endian word order.
|
||||
* (The order of bytes within words is irrelevant.)
|
||||
*/
|
||||
#define BN_LITTLE_ENDIAN 1
|
||||
|
||||
typedef unsigned short bnword16
|
||||
#define BNWORD16 bnword16
|
||||
|
||||
bnword16 lbnSub1_16(bnword16 *num, unsigned len, bnword16 borrow);
|
||||
bnword16 lbnAdd1_16(bnword16 *num, unsigned len, bnword16 carry);
|
||||
void lbnMulN1_16(bnword16 *out, bnword16 const *in, unsigned len, bnword16 k);
|
||||
bnword16
|
||||
lbnMulAdd1_16(bnword16 *out, bnword16 const *in, unsigned len, bnword16 k);
|
||||
bnword16
|
||||
lbnMulSub1_16(bnword16 *out, bnword16 const *in, unsigned len, bnword16 k);
|
||||
bnword16 lbnDiv21_16(bnword16 *q, bnword16 nh, bnword16 nl, bnword16 d);
|
||||
unsigned lbnModQ_16(bnword16 const *n, unsigned len, bnword16 d);
|
||||
|
||||
int is68020(void);
|
||||
|
||||
/* #define the values to exclude the C versions */
|
||||
#define lbnSub1_16 lbnSub1_16
|
||||
#define lbnAdd1_16 lbnAdd1_16
|
||||
#define lbnMulN1_16 lbnMulN1_16
|
||||
#define lbnMulAdd1_16 lbnMulAdd1_16
|
||||
#define lbnMulSub1_16 lbnMulSub1_16
|
||||
#define lbnDiv21_16 lbnDiv21_16
|
||||
#define lbnModQ_16 lbnModQ_16
|
||||
|
||||
/* Also include the 68020 definitions for 16/32 bit switching versions. */
|
||||
#include <lbn68020.h>
|
||||
+309
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbn68020.c - 32-bit bignum primitives for the 68020+ (0r 683xx) processors.
|
||||
*
|
||||
* This was written for Metrowerks C, and while it should be reasonably
|
||||
* portable, NOTE that Metrowerks lets a callee trash a0, a1, d0, d1, and d2.
|
||||
* Some 680x0 compilers make d2 callee-save, so instructions to save it
|
||||
* will have to be added.
|
||||
*
|
||||
* This code supports 16 or 32-bit ints, based on UINT_MAX.
|
||||
* Regardless of UINT_MAX, only bignums up to 64K words (2 million bits)
|
||||
* are supported. (68k hackers will recognize this as a consequence of
|
||||
* using dbra.)
|
||||
*
|
||||
* These primitives use little-endian word order.
|
||||
* (The order of bytes within words is irrelevant to this issue.)
|
||||
*
|
||||
* TODO: Schedule this for the 68040's pipeline. (When I get a 68040 manual.)
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "lbn.h" /* Should include lbn68020.h */
|
||||
|
||||
/*
|
||||
* The Metrowerks C compiler (1.2.2) produces bad 68k code for the
|
||||
* following input, which happens to be the inner loop of lbnSub1,
|
||||
* so a few less than critical routines have been recoded in assembly
|
||||
* to avoid the bug. (Optimizer on or off does not matter.)
|
||||
*
|
||||
* unsigned
|
||||
* decrement(unsigned *num, unsigned len)
|
||||
* {
|
||||
* do {
|
||||
* if ((*num++)-- != 0)
|
||||
* return 0;
|
||||
* } while (--len);
|
||||
* return 1;
|
||||
* }
|
||||
*/
|
||||
asm BNWORD32
|
||||
lbnSub1_32(BNWORD32 *num, unsigned len, BNWORD32 borrow)
|
||||
{
|
||||
movea.l 4(sp),a0 /* num */
|
||||
#if UINT_MAX == 0xffff
|
||||
move.l 10(sp),d0 /* borrow */
|
||||
#else
|
||||
move.l 12(sp),d0 /* borrow */
|
||||
#endif
|
||||
sub.l d0,(a0)+
|
||||
bcc done
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 8(sp),d0 /* len */
|
||||
#else
|
||||
move.w 10(sp),d0 /* len */
|
||||
#endif
|
||||
subq.w #2,d0
|
||||
bcs done
|
||||
loop:
|
||||
subq.l #1,(a0)+
|
||||
dbcc d0,loop
|
||||
done:
|
||||
moveq.l #0,d0
|
||||
addx.w d0,d0
|
||||
rts
|
||||
}
|
||||
|
||||
asm BNWORD32
|
||||
lbnAdd1_32(BNWORD32 *num, unsigned len, BNWORD32 carry)
|
||||
{
|
||||
movea.l 4(sp),a0 /* num */
|
||||
#if UINT_MAX == 0xffff
|
||||
move.l 10(sp),d0 /* carry */
|
||||
#else
|
||||
move.l 12(sp),d0 /* carry */
|
||||
#endif
|
||||
add.l d0,(a0)+
|
||||
bcc done
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 8(sp),d0 /* len */
|
||||
#else
|
||||
move.w 10(sp),d0 /* len */
|
||||
#endif
|
||||
subq.w #2,d0
|
||||
bcs done
|
||||
loop:
|
||||
addq.l #1,(a0)+
|
||||
dbcc d0,loop
|
||||
done:
|
||||
moveq.l #0,d0
|
||||
addx.w d0,d0
|
||||
rts
|
||||
}
|
||||
|
||||
asm void
|
||||
lbnMulN1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
{
|
||||
machine 68020
|
||||
|
||||
movem.l d3-d5,-(sp) /* 12 bytes of extra data */
|
||||
moveq.l #0,d4
|
||||
move.l 16(sp),a1 /* out */
|
||||
move.l 20(sp),a0 /* in */
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 24(sp),d5 /* len */
|
||||
move.l 26(sp),d2 /* k */
|
||||
#else
|
||||
move.w 26(sp),d5 /* len */
|
||||
move.l 28(sp),d2 /* k */
|
||||
#endif
|
||||
|
||||
move.l (a0)+,d3 /* First multiply */
|
||||
mulu.l d2,d1:d3 /* dc.w 0x4c02, 0x3401 */
|
||||
move.l d3,(a1)+
|
||||
|
||||
subq.w #1,d5 /* Setup for loop unrolling */
|
||||
lsr.w #1,d5
|
||||
bcs.s m32_even
|
||||
beq.s m32_short
|
||||
|
||||
subq.w #1,d5 /* Set up software pipeline properly */
|
||||
move.l d1,d0
|
||||
|
||||
m32_loop:
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d1:d3 /* dc.w 0x4c02, 0x3401 */
|
||||
add.l d0,d3
|
||||
addx.l d4,d1
|
||||
move.l d3,(a1)+
|
||||
m32_even:
|
||||
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d0:d3 /* dc.w 0x4c02, 0x3400 */
|
||||
add.l d1,d3
|
||||
addx.l d4,d0
|
||||
move.l d3,(a1)+
|
||||
|
||||
dbra d5,m32_loop
|
||||
|
||||
move.l d0,(a1)
|
||||
movem.l (sp)+,d3-d5
|
||||
rts
|
||||
m32_short:
|
||||
move.l d1,(a1)
|
||||
movem.l (sp)+,d3-d5
|
||||
rts
|
||||
}
|
||||
|
||||
|
||||
asm BNWORD32
|
||||
lbnMulAdd1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
{
|
||||
machine 68020
|
||||
movem.l d3-d5,-(sp) /* 12 bytes of extra data */
|
||||
moveq.l #0,d4
|
||||
move.l 16(sp),a1 /* out */
|
||||
move.l 20(sp),a0 /* in */
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 24(sp),d5 /* len */
|
||||
move.l 26(sp),d2 /* k */
|
||||
#else
|
||||
move.w 26(sp),d5 /* len */
|
||||
move.l 28(sp),d2 /* k */
|
||||
#endif
|
||||
|
||||
move.l (a0)+,d3 /* First multiply */
|
||||
mulu.l d2,d1:d3 /* dc.w 0x4c02, 0x3401 */
|
||||
add.l d3,(a1)+
|
||||
addx.l d4,d1
|
||||
|
||||
subq.w #1,d5 /* Setup for loop unrolling */
|
||||
lsr.w #1,d5
|
||||
bcs.s ma32_even
|
||||
beq.s ma32_short
|
||||
|
||||
subq.w #1,d5 /* Set up software pipeline properly */
|
||||
move.l d1,d0
|
||||
|
||||
ma32_loop:
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d1:d3 /* dc.w 0x4c02, 0x3401 */
|
||||
add.l d0,d3
|
||||
addx.l d4,d1
|
||||
add.l d3,(a1)+
|
||||
addx.l d4,d1
|
||||
ma32_even:
|
||||
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d0:d3 /* dc.w 0x4c02, 0x3400 */
|
||||
add.l d1,d3
|
||||
addx.l d4,d0
|
||||
add.l d3,(a1)+
|
||||
addx.l d4,d0
|
||||
|
||||
dbra d5,ma32_loop
|
||||
|
||||
movem.l (sp)+,d3-d5
|
||||
rts
|
||||
ma32_short:
|
||||
move.l d1,d0
|
||||
movem.l (sp)+,d3-d5
|
||||
rts
|
||||
}
|
||||
|
||||
|
||||
asm BNWORD32
|
||||
lbnMulSub1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
{
|
||||
machine 68020
|
||||
movem.l d3-d5,-(sp) /* 12 bytes of extra data */
|
||||
moveq.l #0,d4
|
||||
move.l 16(sp),a1 /* out */
|
||||
move.l 20(sp),a0 /* in */
|
||||
#if UINT_MAX == 0xffff
|
||||
move.w 24(sp),d5 /* len */
|
||||
move.l 26(sp),d2 /* k */
|
||||
#else
|
||||
move.w 26(sp),d5 /* len */
|
||||
move.l 28(sp),d2 /* k */
|
||||
#endif
|
||||
|
||||
move.l (a0)+,d3 /* First multiply */
|
||||
mulu.l d2,d1:d3 /* dc.w 0x4c02, 0x3401 */
|
||||
sub.l d3,(a1)+
|
||||
addx.l d4,d1
|
||||
|
||||
subq.w #1,d5 /* Setup for loop unrolling */
|
||||
lsr.w #1,d5
|
||||
bcs.s ms32_even
|
||||
beq.s ms32_short
|
||||
|
||||
subq.w #1,d5 /* Set up software pipeline properly */
|
||||
move.l d1,d0
|
||||
|
||||
ms32_loop:
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d1:d3 /* dc.w 0x4c02, 0x3401 */
|
||||
add.l d0,d3
|
||||
addx.l d4,d1
|
||||
sub.l d3,(a1)+
|
||||
addx.l d4,d1
|
||||
ms32_even:
|
||||
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d0:d3 /* dc.w 0x4c02, 0x3400 */
|
||||
add.l d1,d3
|
||||
addx.l d4,d0
|
||||
sub.l d3,(a1)+
|
||||
addx.l d4,d0
|
||||
|
||||
dbra d5,ms32_loop
|
||||
|
||||
movem.l (sp)+,d3-d5
|
||||
rts
|
||||
|
||||
ms32_short:
|
||||
move.l d1,d0
|
||||
movem.l (sp)+,d3-d5
|
||||
rts
|
||||
}
|
||||
|
||||
|
||||
asm BNWORD32
|
||||
lbnDiv21_32(BNWORD32 *q, BNWORD32 nh, BNWORD32 nl, BNWORD32 d)
|
||||
{
|
||||
machine 68020
|
||||
move.l 8(sp),d0
|
||||
move.l 12(sp),d1
|
||||
move.l 4(sp),a0
|
||||
divu.l 16(sp),d0:d1 /* dc.w 0x4c6f, 0x1400, 16 */
|
||||
move.l d1,(a0)
|
||||
rts
|
||||
}
|
||||
|
||||
asm unsigned
|
||||
lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d)
|
||||
{
|
||||
machine 68020
|
||||
move.l 4(sp),a0 /* n */
|
||||
move.l d3,a1
|
||||
#if UINT_MAX == 0xffff
|
||||
moveq.l #0,d2
|
||||
move.w 8(sp),d1 /* len */
|
||||
move.w 10(sp),d2 /* d */
|
||||
#else
|
||||
move.w 10(sp),d1 /* len */
|
||||
move.l 12(sp),d2 /* d */
|
||||
#endif
|
||||
dc.w 0x41f0, 0x1cfc /* lea -4(a0,d1.L*4),a0 */
|
||||
|
||||
/* First time, divide 32/32 - may be faster than 64/32 */
|
||||
move.l (a0),d3
|
||||
divul.l d2,d0:d3 /* dc.w 0x4c02, 0x3000 */
|
||||
subq.w #2,d1
|
||||
bmi mq32_done
|
||||
|
||||
mq32_loop:
|
||||
move.l -(a0),d3
|
||||
divu.l d2,d0:d3 /* dc.w 0x4c02,0x3400 */
|
||||
dbra d1,mq32_loop
|
||||
|
||||
mq32_done:
|
||||
move.l a1,d3
|
||||
rts
|
||||
}
|
||||
|
||||
/* 45678901234567890123456789012345678901234567890123456789012345678901234567 */
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbn68020.h - 32-bit bignum primitives for the 68020 (or 683xx) processors.
|
||||
*
|
||||
* These primitives use little-endian word order.
|
||||
* (The order of bytes within words is irrelevant.)
|
||||
*/
|
||||
#define BN_LITTLE_ENDIAN 1
|
||||
|
||||
typedef unsigned long bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
|
||||
bnword32 lbnSub1_32(bnword32 *num, unsigned len, bnword32 borrow);
|
||||
bnword32 lbnAdd1_32(bnword32 *num, unsigned len, bnword32 carry);
|
||||
void lbnMulN1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
bnword32
|
||||
lbnMulAdd1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
bnword32
|
||||
lbnMulSub1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
bnword32 lbnDiv21_32(bnword32 *q, bnword32 nh, bnword32 nl, bnword32 d);
|
||||
unsigned lbnModQ_32(bnword32 const *n, unsigned len, unsigned d);
|
||||
|
||||
/* #define the values to exclude the C versions */
|
||||
#define lbnSub1_32 lbnSub1_32
|
||||
#define lbnAdd1_32 lbnAdd1_32
|
||||
#define lbnMulN1_32 lbnMulN1_32
|
||||
#define lbnMulAdd1_32 lbnMulAdd1_32
|
||||
#define lbnMulSub1_32 lbnMulSub1_32
|
||||
#define lbnDiv21_32 lbnDiv21_32
|
||||
#define lbnModQ_32 lbnModQ_32
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbn68360.c - 32-bit bignum primitives for 683xx processors.
|
||||
*
|
||||
* This code is using InterTools calling convention, which is a bit odd.
|
||||
* One minor note is that the default variable sizes are
|
||||
* char = unsigned 8, short = 8 (in violation of ANSI!),
|
||||
* int = 16, long = 32. Longs (including on the stack) are 16-bit aligned.
|
||||
* Arguments are apdded to 16 bits.
|
||||
* A6 is used as a frame pointer, and globals are indexed off A5.
|
||||
* Return valies are passes id D0 or A0 (or FP0), depending on type.
|
||||
* D0, D1, A0 and A4 (!) are volatile across function calls. A1
|
||||
* must be preserved!
|
||||
*
|
||||
* This code assumes 16-bit ints. Code for 32-bit ints is commented out
|
||||
* with "**".
|
||||
*
|
||||
* Regardless of UINT_MAX, only bignums up to 64K words (2 million bits)
|
||||
* are supported. (68k hackers will recognize this as a consequence of
|
||||
* using dbra.) This could be extended easily if anyone cares.
|
||||
*
|
||||
* These primitives use little-endian word order.
|
||||
* (The order of bytes within words is irrelevant to this issue.)
|
||||
|
||||
* The Metrowerks C compiler (1.2.2) produces bad 68k code for the
|
||||
* following input, which happens to be the inner loop of lbnSub1,
|
||||
* so it has been rewritees in assembly, even though it is not terribly
|
||||
* speed-critical. (Optimizer on or off does not matter.)
|
||||
*
|
||||
* unsigned
|
||||
* decrement(unsigned *num, unsigned len)
|
||||
* {
|
||||
* do {
|
||||
* if ((*num++)-- != 0)
|
||||
* return 0;
|
||||
* } while (--len);
|
||||
* return 1;
|
||||
* }
|
||||
|
||||
* BNWORD32 lbnSub1_32(BNWORD32 *num, unsigned len, BNWORD32 borrow)
|
||||
SECTION S_lbnSub1_32,,"code"
|
||||
XDEF _lbnSub1_32
|
||||
_lbnSub1_32:
|
||||
movea.l 4(sp),a0 * num
|
||||
move.l 10(sp),d0 * borrow
|
||||
** move.l 12(sp),d0 * borrow
|
||||
sub.l d0,(a0)+
|
||||
bcc sub_done
|
||||
move.w 8(sp),d0 * len
|
||||
** move.w 10(sp),d0 * len
|
||||
subq.w #2,d0
|
||||
bcs sub_done
|
||||
sub_loop:
|
||||
subq.l #1,(a0)+
|
||||
dbcc d0,sub_loop
|
||||
sub_done:
|
||||
moveq.l #0,d0
|
||||
addx.w d0,d0
|
||||
rts
|
||||
|
||||
* BNWORD32 lbnAdd1_32(BNWORD32 *num, unsigned len, BNWORD32 carry)
|
||||
SECTION S_lbnAdd1_32,,"code"
|
||||
XDEF _lbnAdd1_32
|
||||
_lbnAdd1_32:
|
||||
movea.l 4(sp),a0 * num
|
||||
move.l 10(sp),d0 * carry
|
||||
** move.l 12(sp),d0 * carry
|
||||
add.l d0,(a0)+
|
||||
bcc add_done
|
||||
move.w 8(sp),d0 * len
|
||||
** move.w 10(sp),d0 * len
|
||||
subq.w #2,d0
|
||||
bcs add_done
|
||||
add_loop:
|
||||
addq.l #1,(a0)+
|
||||
dbcc d0,add_loop
|
||||
add_done:
|
||||
moveq.l #0,d0
|
||||
addx.w d0,d0
|
||||
rts
|
||||
|
||||
* void lbnMulN1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
SECTION S_lbnMulN1_32,,"code"
|
||||
XDEF _lbnMulN1_32
|
||||
_lbnMulN1_32:
|
||||
movem.l d2-d5,-(sp) * 16 bytes of extra data
|
||||
moveq.l #0,d4
|
||||
move.l 20(sp),a4 * out
|
||||
move.l 24(sp),a0 * in
|
||||
move.w 28(sp),d5 * len
|
||||
move.l 30(sp),d2 * k
|
||||
** move.w 30(sp),d5 * len
|
||||
** move.l 32(sp),d2 * k
|
||||
|
||||
move.l (a0)+,d3 * First multiply
|
||||
mulu.l d2,d1:d3 * dc.w 0x4c02, 0x3401
|
||||
move.l d3,(a4)+
|
||||
|
||||
subq.w #1,d5 * Setup for loop unrolling
|
||||
lsr.w #1,d5
|
||||
bcs.s m32_even
|
||||
beq.s m32_short
|
||||
|
||||
subq.w #1,d5 * Set up software pipeline properly
|
||||
move.l d1,d0
|
||||
|
||||
m32_loop:
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d1:d3 * dc.w 0x4c02, 0x3401
|
||||
add.l d0,d3
|
||||
addx.l d4,d1
|
||||
move.l d3,(a4)+
|
||||
m32_even:
|
||||
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d0:d3 * dc.w 0x4c02, 0x3400
|
||||
add.l d1,d3
|
||||
addx.l d4,d0
|
||||
move.l d3,(a4)+
|
||||
|
||||
dbra d5,m32_loop
|
||||
|
||||
move.l d0,(a4)
|
||||
movem.l (sp)+,d2-d5
|
||||
rts
|
||||
m32_short:
|
||||
move.l d1,(a4)
|
||||
movem.l (sp)+,d2-d5
|
||||
rts
|
||||
|
||||
* BNWORD32
|
||||
* lbnMulAdd1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
SECTION S_lbnMulAdd1_32,,"code"
|
||||
XDEF _lbnMulAdd1_32
|
||||
_lbnMulAdd1_32:
|
||||
movem.l d2-d5,-(sp) * 16 bytes of extra data
|
||||
moveq.l #0,d4
|
||||
move.l 20(sp),a4 * out
|
||||
move.l 24(sp),a0 * in
|
||||
move.w 28(sp),d5 * len
|
||||
move.l 30(sp),d2 * k
|
||||
** move.w 30(sp),d5 * len
|
||||
** move.l 32(sp),d2 * k
|
||||
|
||||
move.l (a0)+,d3 * First multiply
|
||||
mulu.l d2,d1:d3 * dc.w 0x4c02, 0x3401
|
||||
add.l d3,(a4)+
|
||||
addx.l d4,d1
|
||||
|
||||
subq.w #1,d5 * Setup for loop unrolling
|
||||
lsr.w #1,d5
|
||||
bcs.s ma32_even
|
||||
beq.s ma32_short
|
||||
|
||||
subq.w #1,d5 * Set up software pipeline properly
|
||||
move.l d1,d0
|
||||
|
||||
ma32_loop:
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d1:d3 * dc.w 0x4c02, 0x3401
|
||||
add.l d0,d3
|
||||
addx.l d4,d1
|
||||
add.l d3,(a4)+
|
||||
addx.l d4,d1
|
||||
ma32_even:
|
||||
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d0:d3 * dc.w 0x4c02, 0x3400
|
||||
add.l d1,d3
|
||||
addx.l d4,d0
|
||||
add.l d3,(a4)+
|
||||
addx.l d4,d0
|
||||
|
||||
dbra d5,ma32_loop
|
||||
|
||||
movem.l (sp)+,d2-d5
|
||||
rts
|
||||
ma32_short:
|
||||
move.l d1,d0
|
||||
movem.l (sp)+,d2-d5
|
||||
rts
|
||||
|
||||
* BNWORD32
|
||||
* lbnMulSub1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
SECTION S_lbnMulSub1_32,,"code"
|
||||
XDEF _lbnMulSub1_32
|
||||
_lbnMulSub1_32:
|
||||
movem.l d2-d5,-(sp) * 16 bytes of extra data
|
||||
moveq.l #0,d4
|
||||
move.l 20(sp),a4 * out
|
||||
move.l 24(sp),a0 * in
|
||||
move.w 28(sp),d5 * len
|
||||
move.l 30(sp),d2 * k
|
||||
** move.w 30(sp),d5 * len
|
||||
** move.l 32(sp),d2 * k
|
||||
|
||||
move.l (a0)+,d3 * First multiply
|
||||
mulu.l d2,d1:d3 * dc.w 0x4c02, 0x3401
|
||||
sub.l d3,(a4)+
|
||||
addx.l d4,d1
|
||||
|
||||
subq.w #1,d5 * Setup for loop unrolling
|
||||
lsr.w #1,d5
|
||||
bcs.s ms32_even
|
||||
beq.s ms32_short
|
||||
|
||||
subq.w #1,d5 * Set up software pipeline properly
|
||||
move.l d1,d0
|
||||
|
||||
ms32_loop:
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d1:d3 * dc.w 0x4c02, 0x3401
|
||||
add.l d0,d3
|
||||
addx.l d4,d1
|
||||
sub.l d3,(a4)+
|
||||
addx.l d4,d1
|
||||
ms32_even:
|
||||
|
||||
move.l (a0)+,d3
|
||||
mulu.l d2,d0:d3 * dc.w 0x4c02, 0x3400
|
||||
add.l d1,d3
|
||||
addx.l d4,d0
|
||||
sub.l d3,(a4)+
|
||||
addx.l d4,d0
|
||||
|
||||
dbra d5,ms32_loop
|
||||
|
||||
movem.l (sp)+,d2-d5
|
||||
rts
|
||||
|
||||
ms32_short:
|
||||
move.l d1,d0
|
||||
movem.l (sp)+,d2-d5
|
||||
rts
|
||||
|
||||
|
||||
* BNWORD32 lbnDiv21_32(BNWORD32 *q, BNWORD32 nh, BNWORD32 nl, BNWORD32 d)
|
||||
SECTION S_lbnDiv21_32,,"code"
|
||||
XDEF _lbnDiv21_32
|
||||
_lbnDiv21_32:
|
||||
move.l 8(sp),d0
|
||||
move.l 12(sp),d1
|
||||
move.l 4(sp),a0
|
||||
divu.l 16(sp),d0:d1 * dc.w 0x4c6f, 0x1400, 16
|
||||
move.l d1,(a0)
|
||||
rts
|
||||
|
||||
* unsigned lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d)
|
||||
SECTION S_lbnModQ_32,,"code"
|
||||
XDEF _lbnModQ_32
|
||||
_lbnModQ_32:
|
||||
move.l 4(sp),a0 * n
|
||||
move.l d2,-(sp)
|
||||
move.l d3,a4
|
||||
moveq.l #0,d1
|
||||
moveq.l #0,d2
|
||||
move.w 12(sp),d1 * len
|
||||
move.w 14(sp),d2 * d
|
||||
** move.l 12(sp),d1 * len
|
||||
** move.l 16(sp),d2 * d
|
||||
lea -4(a0,d1.L*4),a0 * dc.w 0x41f0, 0x1cfc
|
||||
|
||||
* First time, divide 32/32 - may be faster than 64/32
|
||||
move.l (a0),d3
|
||||
divul.l d2,d0:d3 * dc.w 0x4c02, 0x3000
|
||||
subq.w #2,d1
|
||||
bmi mq32_done
|
||||
|
||||
mq32_loop:
|
||||
move.l -(a0),d3
|
||||
divu.l d2,d0:d3 * dc.w 0x4c02,0x3400
|
||||
dbra d1,mq32_loop
|
||||
|
||||
mq32_done:
|
||||
move.l (sp)+,d2
|
||||
move.l a4,d3
|
||||
rts
|
||||
|
||||
end
|
||||
+414
@@ -0,0 +1,414 @@
|
||||
;;; Copyright (c) 1995, Colin Plumb.
|
||||
;;; For licensing and other legal details, see the file legal.c.
|
||||
;;;
|
||||
;;; Assembly primitives for bignum library, 80386 family, 32-bit code.
|
||||
;;;
|
||||
;;; Several primitives are included here. Only lbnMulAdd1 is *really*
|
||||
;;; critical, but once that's written, lnmMulN1 and lbnMulSub1 are quite
|
||||
;;; easy to write as well, so they are included here as well.
|
||||
;;; lbnDiv21 and lbnModQ are so easy to write that they're included, too.
|
||||
;;;
|
||||
;;; All functions here are for 32-bit flat mode. I.e. near code and
|
||||
;;; near data, although the near offsets are 32 bits.
|
||||
;;;
|
||||
;;; The usual 80x86 calling conventions have AX, BX, CX and DX
|
||||
;;; volatile, and SI, DI, SP and BP preserved across calls.
|
||||
;;; This includes the "E"xtended forms of all of those registers
|
||||
;;;
|
||||
;;; However, just to be confusing, recent 32-bit DOS compilers have
|
||||
;;; quietly changed that to require EBX preserved across calls, too.
|
||||
;;; Joy.
|
||||
|
||||
.386
|
||||
;_TEXT segment para public use32 'CODE' ; 16-byte aligned because 486 cares
|
||||
;_TEXT ends
|
||||
|
||||
ifdef @Version
|
||||
if @Version le 510
|
||||
FLAT group _TEXT
|
||||
endif
|
||||
else
|
||||
FLAT group _TEXT
|
||||
endif
|
||||
assume cs:FLAT, ds:FLAT, ss:FLAT
|
||||
_TEXT segment para public use32 'CODE' ; 16-byte aligned because 486 cares
|
||||
|
||||
public _lbnMulN1_32
|
||||
public _lbnMulAdd1_32
|
||||
public _lbnMulSub1_32
|
||||
public _lbnDiv21_32
|
||||
public _lbnModQ_32
|
||||
|
||||
;; Register usage:
|
||||
;; eax - low half of product
|
||||
;; ebx - carry to next iteration
|
||||
;; ecx - multiplier (k)
|
||||
;; edx - high half of product
|
||||
;; esi - source pointer
|
||||
;; edi - dest pointer
|
||||
;; ebp - loop counter
|
||||
;;
|
||||
;; Stack frame:
|
||||
;; +--------+ esp+20 esp+24 esp+28 esp+32 esp+36
|
||||
;; | k |
|
||||
;; +--------+ esp+16 esp+20 esp+24 esp+28 esp+32
|
||||
;; | len |
|
||||
;; +--------+ esp+12 esp+16 esp+20 esp+24 esp+28
|
||||
;; | in |
|
||||
;; +--------+ esp+8 esp+12 esp+16 esp+20 esp+24
|
||||
;; | out |
|
||||
;; +--------+ esp+4 esp+8 esp+12 esp+16 esp+20
|
||||
;; | return |
|
||||
;; +--------+ esp esp+4 esp+8 esp+12 esp+16
|
||||
;; | esi |
|
||||
;; +--------+ esp esp+4 esp+8 esp+12
|
||||
;; | ebp |
|
||||
;; +--------+ esp esp+4 esp+8
|
||||
;; | ebx |
|
||||
;; +--------+ esp esp+4
|
||||
;; | edi |
|
||||
;; +--------+ esp
|
||||
|
||||
align 16
|
||||
_lbnMulN1_32 proc near
|
||||
|
||||
push esi ; U
|
||||
mov esi,[esp+12] ; V load in
|
||||
push ebp ; U
|
||||
mov ebp,[esp+20] ; V load len
|
||||
push ebx ; U
|
||||
mov ecx,[esp+28] ; V load k
|
||||
push edi ; U
|
||||
mov edi,[esp+20] ; V load out
|
||||
|
||||
;; First multiply step has no carry in.
|
||||
mov eax,[esi] ; U
|
||||
lea ebx,[ebp*4-4] ; V loop unrolling
|
||||
mul ecx ; NP first multiply
|
||||
mov [edi],eax ; U
|
||||
and ebx,12 ; V loop unrolling
|
||||
|
||||
add esi,ebx ; U loop unrolling
|
||||
add edi,ebx ; V loop unrolling
|
||||
|
||||
jmp DWORD PTR m32_jumptable[ebx] ; NP loop unrolling
|
||||
|
||||
align 4
|
||||
m32_jumptable:
|
||||
dd m32_case0
|
||||
dd m32_case1
|
||||
dd m32_case2
|
||||
dd m32_case3
|
||||
|
||||
nop
|
||||
align 8
|
||||
nop
|
||||
nop
|
||||
nop ; Get loop nicely aligned
|
||||
|
||||
m32_case0:
|
||||
sub ebp,4 ; U
|
||||
jbe SHORT m32_done ; V
|
||||
|
||||
m32_loop:
|
||||
mov eax,[esi+4] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
add esi,16 ; U
|
||||
add edi,16 ; V
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
adc edx,0 ; U
|
||||
mov [edi-12],eax ; V
|
||||
m32_case3:
|
||||
mov eax,[esi-8] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
adc edx,0 ; U
|
||||
mov [edi-8],eax ; V
|
||||
m32_case2:
|
||||
mov eax,[esi-4] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
adc edx,0 ; U
|
||||
mov [edi-4],eax ; V
|
||||
m32_case1:
|
||||
mov eax,[esi] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
adc edx,0 ; U
|
||||
mov [edi],eax ; V
|
||||
|
||||
sub ebp,4 ; U
|
||||
ja SHORT m32_loop ; V
|
||||
|
||||
m32_done:
|
||||
mov [edi+4],edx ; U
|
||||
pop edi ; V
|
||||
pop ebx ; U
|
||||
pop ebp ; V
|
||||
pop esi ; U
|
||||
ret ; NP
|
||||
_lbnMulN1_32 endp
|
||||
|
||||
|
||||
align 16
|
||||
_lbnMulAdd1_32 proc near
|
||||
|
||||
push esi ; U
|
||||
mov esi,[esp+12] ; V load in
|
||||
push edi ; U
|
||||
mov edi,[esp+12] ; V load out
|
||||
push ebp ; U
|
||||
mov ebp,[esp+24] ; V load len
|
||||
push ebx ; U
|
||||
mov ecx,[esp+32] ; V load k
|
||||
|
||||
;; First multiply step has no carry in.
|
||||
mov eax,[esi] ; U
|
||||
mov ebx,[edi] ; V
|
||||
mul ecx ; NP first multiply
|
||||
add ebx,eax ; U
|
||||
lea eax,[ebp*4-4] ; V loop unrolling
|
||||
adc edx,0 ; U
|
||||
and eax,12 ; V loop unrolling
|
||||
mov [edi],ebx ; U
|
||||
|
||||
add esi,eax ; V loop unrolling
|
||||
add edi,eax ; U loop unrolling
|
||||
|
||||
jmp DWORD PTR ma32_jumptable[eax] ; NP loop unrolling
|
||||
|
||||
align 4
|
||||
ma32_jumptable:
|
||||
dd ma32_case0
|
||||
dd ma32_case1
|
||||
dd ma32_case2
|
||||
dd ma32_case3
|
||||
|
||||
nop
|
||||
align 8
|
||||
nop
|
||||
nop
|
||||
nop ; To align loop properly
|
||||
|
||||
|
||||
ma32_case0:
|
||||
sub ebp,4 ; U
|
||||
jbe SHORT ma32_done ; V
|
||||
|
||||
ma32_loop:
|
||||
mov eax,[esi+4] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
add esi,16 ; U
|
||||
add edi,16 ; V
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
mov ebx,[edi-12] ; V
|
||||
adc edx,0 ; U
|
||||
add ebx,eax ; V
|
||||
adc edx,0 ; U
|
||||
mov [edi-12],ebx ; V
|
||||
ma32_case3:
|
||||
mov eax,[esi-8] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
mov ebx,[edi-8] ; V
|
||||
adc edx,0 ; U
|
||||
add ebx,eax ; V
|
||||
adc edx,0 ; U
|
||||
mov [edi-8],ebx ; V
|
||||
ma32_case2:
|
||||
mov eax,[esi-4] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
mov ebx,[edi-4] ; V
|
||||
adc edx,0 ; U
|
||||
add ebx,eax ; V
|
||||
adc edx,0 ; U
|
||||
mov [edi-4],ebx ; V
|
||||
ma32_case1:
|
||||
mov eax,[esi] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
mov ebx,[edi] ; V
|
||||
adc edx,0 ; U
|
||||
add ebx,eax ; V
|
||||
adc edx,0 ; U
|
||||
mov [edi],ebx ; V
|
||||
|
||||
sub ebp,4 ; U
|
||||
ja SHORT ma32_loop ; V
|
||||
|
||||
ma32_done:
|
||||
pop ebx ; U
|
||||
pop ebp ; V
|
||||
mov eax,edx ; U
|
||||
pop edi ; V
|
||||
pop esi ; U
|
||||
ret ; NP
|
||||
_lbnMulAdd1_32 endp
|
||||
|
||||
|
||||
align 16
|
||||
_lbnMulSub1_32 proc near
|
||||
push esi ; U
|
||||
mov esi,[esp+12] ; V load in
|
||||
push edi ; U
|
||||
mov edi,[esp+12] ; V load out
|
||||
push ebp ; U
|
||||
mov ebp,[esp+24] ; V load len
|
||||
push ebx ; U
|
||||
mov ecx,[esp+32] ; V load k
|
||||
|
||||
;; First multiply step has no carry in.
|
||||
push esi ; U
|
||||
mov esi,[esp+12] ; V load in
|
||||
push edi ; U
|
||||
mov edi,[esp+12] ; V load out
|
||||
push ebp ; U
|
||||
mov ebp,[esp+24] ; V load len
|
||||
mov ecx,[esp+28] ; U load k
|
||||
|
||||
;; First multiply step has no carry in.
|
||||
mov eax,[esi] ; V
|
||||
mov ebx,[edi] ; U
|
||||
mul ecx ; NP first multiply
|
||||
sub ebx,eax ; U
|
||||
lea eax,[ebp*4-4] ; V loop unrolling
|
||||
adc edx,0 ; U
|
||||
and eax,12 ; V loop unrolling
|
||||
mov [edi],ebx ; U
|
||||
|
||||
add esi,eax ; V loop unrolling
|
||||
add edi,eax ; U loop unrolling
|
||||
|
||||
jmp DWORD PTR ms32_jumptable[eax] ; NP loop unrolling
|
||||
|
||||
align 4
|
||||
ms32_jumptable:
|
||||
dd ms32_case0
|
||||
dd ms32_case1
|
||||
dd ms32_case2
|
||||
dd ms32_case3
|
||||
|
||||
nop
|
||||
align 8
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
ms32_case0:
|
||||
sub ebp,4 ; U
|
||||
jbe SHORT ms32_done ; V
|
||||
|
||||
ms32_loop:
|
||||
mov eax,[esi+4] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
add esi,16 ; U
|
||||
add edi,16 ; V
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
mov ebx,[edi-12] ; V
|
||||
adc edx,0 ; U
|
||||
sub ebx,eax ; V
|
||||
adc edx,0 ; U
|
||||
mov [edi-12],ebx ; V
|
||||
ms32_case3:
|
||||
mov eax,[esi-8] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
mov ebx,[edi-8] ; V
|
||||
adc edx,0 ; U
|
||||
sub ebx,eax ; V
|
||||
adc edx,0 ; U
|
||||
mov [edi-8],ebx ; V
|
||||
ms32_case2:
|
||||
mov eax,[esi-4] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
mov ebx,[edi-4] ; V
|
||||
adc edx,0 ; U
|
||||
sub ebx,eax ; V
|
||||
adc edx,0 ; U
|
||||
mov [edi-4],ebx ; V
|
||||
ms32_case1:
|
||||
mov eax,[esi] ; U
|
||||
mov ebx,edx ; V Remember carry for later
|
||||
mul ecx ; NP
|
||||
add eax,ebx ; U Add carry in from previous word
|
||||
mov ebx,[edi] ; V
|
||||
adc edx,0 ; U
|
||||
sub ebx,eax ; V
|
||||
adc edx,0 ; U
|
||||
mov [edi],ebx ; V
|
||||
|
||||
sub ebp,4 ; U
|
||||
ja SHORT ms32_loop ; V
|
||||
|
||||
ms32_done:
|
||||
pop ebx ; U
|
||||
pop ebp ; V
|
||||
mov eax,edx ; U
|
||||
pop edi ; V
|
||||
pop esi ; U
|
||||
ret ; NP
|
||||
_lbnMulSub1_32 endp
|
||||
|
||||
|
||||
|
||||
;; Two-word by one-word divide. Stores quotient, returns remainder.
|
||||
;; BNWORD32 lbnDiv21_32(BNWORD32 *q, BNWORD32 nh, BNWORD32 nl, BNWORD32 d)
|
||||
;; 4 8 12 16
|
||||
align 4
|
||||
_lbnDiv21_32 proc near
|
||||
mov edx,[esp+8] ; U Load nh
|
||||
mov eax,[esp+12] ; V Load nl
|
||||
mov ecx,[esp+4] ; U Load q
|
||||
div DWORD PTR [esp+16] ; NP
|
||||
mov [ecx],eax ; U Store quotient
|
||||
mov eax,edx ; V Return remainder
|
||||
ret
|
||||
_lbnDiv21_32 endp
|
||||
|
||||
;; Multi-word by one-word remainder.
|
||||
;; This speeds up key generation. It's not worth unrolling and so on;
|
||||
;; using 32-bit divides is enough of a speedup.
|
||||
;;
|
||||
;; The modulus (in ebp) is often 16 bits. Given that the dividend is 32
|
||||
;; bits, the chances of saving the first divide because the high word of the
|
||||
;; dividend is less than the modulus are low enough it's not worth taking
|
||||
;; the cycles to test for it.
|
||||
;;
|
||||
;; unsigned lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d)
|
||||
;; 4 8 12
|
||||
align 4
|
||||
_lbnModQ_32 proc near
|
||||
mov eax,[esp+4] ; U Load n
|
||||
push ebp ; V
|
||||
mov ebp,[esp+12] ; U Load len
|
||||
push esi ; V
|
||||
lea esi,[ebp*4+eax-4] ; U
|
||||
mov ecx,[esp+20] ; V Load d
|
||||
xor edx,edx ; U Clear edx for first iteration
|
||||
modq32_loop:
|
||||
mov eax,[esi] ; U Load new low word for divide
|
||||
sub esi,4 ; V
|
||||
div ecx ; NP edx = edx:eax % ecx
|
||||
dec ebp ; U
|
||||
jnz SHORT modq32_loop ; V
|
||||
|
||||
pop esi ; U
|
||||
mov eax,edx ; V Return remainder in eax
|
||||
pop ebp ; U
|
||||
ret ; NP
|
||||
_lbnModQ_32 endp
|
||||
|
||||
end
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbn80386.h - This file defines the interfaces to the 80386
|
||||
* assembly primitives. It is intended to be included in "lbn.h"
|
||||
* via the "#include BNINCLUDE" mechanism.
|
||||
*/
|
||||
|
||||
#define BN_LITTLE_ENDIAN 1
|
||||
|
||||
typedef unsigned long bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
|
||||
/* MS-DOS needs the calling convention described to it. */
|
||||
#ifndef MSDOS
|
||||
#ifdef __MSDOS
|
||||
#define MSDOS 1
|
||||
#endif
|
||||
#endif
|
||||
#ifndef MSDOS
|
||||
#ifdef __MSDOS__
|
||||
#define MSDOS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* By MS-DOS, we mean 16-bit brain-dead MS-DOS. Not 32-bit good things. */
|
||||
#ifdef __GO32
|
||||
#undef MSDOS
|
||||
#endif
|
||||
#ifdef __GO32__
|
||||
#undef MSDOS
|
||||
#endif
|
||||
|
||||
#ifdef MSDOS
|
||||
#define CDECL __cdecl
|
||||
#else
|
||||
#define CDECL /*nothing*/
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* These assembly-language primitives use C names */
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Function prototypes for the asm routines */
|
||||
void CDECL
|
||||
lbnMulN1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
#define lbnMulN1_32 lbnMulN1_32
|
||||
|
||||
bnword32 CDECL
|
||||
lbnMulAdd1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
#define lbnMulAdd1_32 lbnMulAdd1_32
|
||||
|
||||
bnword32 CDECL
|
||||
lbnMulSub1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
#define lbnMulSub1_32 lbnMulSub1_32
|
||||
|
||||
bnword32 CDECL
|
||||
lbnDiv21_32(bnword32 *q, bnword32 nh, bnword32 nl, bnword32 d);
|
||||
#define lbnDiv21_32 lbnDiv21_32
|
||||
|
||||
unsigned CDECL
|
||||
lbnModQ_32(bnword32 const *n, unsigned len, bnword32 d);
|
||||
#define lbnModQ_32 lbnModQ_32
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if __GNUC__
|
||||
/*
|
||||
* Use the (massively cool) GNU inline-assembler extension to define
|
||||
* inline expansions for various operations.
|
||||
*
|
||||
* The massively cool part is that the assembler can have inputs
|
||||
* and outputs, and you specify the operands and which effective
|
||||
* addresses are legal and they get substituted into the code.
|
||||
* (For example, some of the code requires a zero. Rather than
|
||||
* specify an immediate constant, the expansion specifies an operand
|
||||
* of zero which can be in various places. This lets GCC use an
|
||||
* immediate zero, or a register which contains zero if it's available.)
|
||||
*
|
||||
* The syntax is asm("asm_code" : outputs : inputs : trashed)
|
||||
* %0, %1 and so on in the asm code are substituted by the operands
|
||||
* in left-to-right order (outputs, then inputs).
|
||||
* The operands contain constraint strings and values to use.
|
||||
* Outputs must be lvalues, inputs may be rvalues. In the constraints:
|
||||
* "a" means that the operand must be in eax.
|
||||
* "d" means that the operand must be in edx.
|
||||
* "g" means that the operand may be any effective address.
|
||||
* "=" means that the operand is assigned to.
|
||||
* "%" means that this operand and the following one may be
|
||||
* interchanged if desirable.
|
||||
* "bcDSmn" means that the operand must be in ebx, ecx, esi, edi, memory,
|
||||
* or an immediate constant. (This is almost the same as "g"
|
||||
* but allowing it in eax wouldn't help because x is already
|
||||
* assigned there, and it must not be in edx, since edx is
|
||||
* overwritten by the multiply before a and b are read.)
|
||||
*
|
||||
* Note that GCC uses AT&T assembler syntax, which is rather
|
||||
* different from Intel syntax. The length (b, w or l) of the
|
||||
* operation is appended to the opcode, and the *second* operand
|
||||
* is the destination, not the first. Finally, the register names
|
||||
* are all preceded with "%". (Doubled here because % is a
|
||||
* magic character.)
|
||||
*/
|
||||
|
||||
/* (ph<<32) + pl = x*y */
|
||||
#define mul32_ppmm(ph,pl,x,y) \
|
||||
__asm__("mull %3" : "=d"(ph), "=a"(pl) : "%a"(x), "g"(y))
|
||||
|
||||
/* (ph<<32) + pl = x*y + a */
|
||||
#define mul32_ppmma(ph,pl,x,y,a) \
|
||||
__asm__("mull %3\n\t" \
|
||||
"addl %4,%%eax\n\t" \
|
||||
"adcl %5,%%edx" \
|
||||
: "=&d"(ph), "=a"(pl) \
|
||||
: "%a"(x), "g"(y), "bcDSmn"(a), "bcDSmn"(0))
|
||||
|
||||
/* (ph<<32) + pl = x*y + a + b */
|
||||
#define mul32_ppmmaa(ph,pl,x,y,a,b) \
|
||||
__asm__("mull %3\n\t" \
|
||||
"addl %4,%%eax\n\t" \
|
||||
"adcl %6,%%edx\n\t" \
|
||||
"addl %5,%%eax\n\t" \
|
||||
"adcl %6,%%edx" \
|
||||
: "=&d"(ph), "=a"(pl) \
|
||||
: "%a"(x), "g"(y), "%bcDSmn"(a), "bcDSmn"(b), "bcDSmn"(0))
|
||||
|
||||
/* q = ((nh<<32) + nl) / d, return remainder. nh guaranteed < d. */
|
||||
#undef lbnDiv21_32
|
||||
#define lbnDiv21_32(q,nh,nl,d) \
|
||||
({unsigned _; \
|
||||
__asm__("divl %4" : "=d"(_), "=a"(*q) : "d"(nh), "a"(nl), "g"(d)); \
|
||||
_;})
|
||||
|
||||
/* No quotient, just return remainder ((nh<<32) + nl) % d */
|
||||
#define lbnMod21_32(nh,nl,d) \
|
||||
({unsigned _; \
|
||||
__asm__("divl %3" : "=d"(_) : "d"(nh), "a"(nl), "g"(d) : "ax"); \
|
||||
_;})
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
+394
@@ -0,0 +1,394 @@
|
||||
### Copyright (c) 1995, Colin Plumb.
|
||||
### For licensing and other legal details, see the file legal.c.
|
||||
###
|
||||
### Assembly primitives for bignum library, 80386 family, 32-bit code.
|
||||
###
|
||||
### Several primitives are included here. Only lbnMulAdd1 is *really*
|
||||
### critical, but once that's written, lnmMulN1 and lbnMulSub1 are quite
|
||||
### easy to write as well, so they are included here as well.
|
||||
### lbnDiv21 and lbnModQ are so easy to write that they're included, too.
|
||||
###
|
||||
### All functions here are for 32-bit flat mode. I.e. near code and
|
||||
### near data, although the near offsets are 32 bits.
|
||||
### Preserved registers are esp, ebp, esi, edi and ebx. That last
|
||||
### is needed by ELF for PIC, and differs from the IBM PC calling
|
||||
### convention.
|
||||
|
||||
# Different assemblers have different conventions here
|
||||
align4=4 # could be 2 or 4
|
||||
align8=8 # could be 3 or 8
|
||||
align16=16 # cound be 4 or 16
|
||||
|
||||
|
||||
.text
|
||||
|
||||
# We declare each symbol with two names, to deal with ELF/a.out variances.
|
||||
.globl lbnMulN1_32
|
||||
.globl _lbnMulN1_32
|
||||
.globl lbnMulAdd1_32
|
||||
.globl _lbnMulAdd1_32
|
||||
.globl lbnMulSub1_32
|
||||
.globl _lbnMulSub1_32
|
||||
.globl lbnDiv21_32
|
||||
.globl _lbnDiv21_32
|
||||
.globl lbnModQ_32
|
||||
.globl _lbnModQ_32
|
||||
|
||||
## Register usage:
|
||||
## %eax - low half of product
|
||||
## %ebx - carry to next iteration
|
||||
## %ecx - multiplier (k)
|
||||
## %edx - high half of product
|
||||
## %esi - source pointer
|
||||
## %edi - dest pointer
|
||||
## %ebp - loop counter
|
||||
##
|
||||
## Stack frame:
|
||||
## +--------+ %esp+20 %esp+24 %esp+28 %esp+32 %esp+36
|
||||
## | k |
|
||||
## +--------+ %esp+16 %esp+20 %esp+24 %esp+28 %esp+32
|
||||
## | len |
|
||||
## +--------+ %esp+12 %esp+16 %esp+20 %esp+24 %esp+28
|
||||
## | in |
|
||||
## +--------+ %esp+8 %esp+12 %esp+16 %esp+20 %esp+24
|
||||
## | out |
|
||||
## +--------+ %esp+4 %esp+8 %esp+12 %esp+16 %esp+20
|
||||
## | return |
|
||||
## +--------+ %esp %esp+4 %esp+8 %esp+12 %esp+16
|
||||
## | %esi |
|
||||
## +--------+ %esp %esp+4 %esp+8 %esp+12
|
||||
## | %ebp |
|
||||
## +--------+ %esp %esp+4 %esp+8
|
||||
## | %ebx |
|
||||
## +--------+ %esp %esp+4
|
||||
## | %edi |
|
||||
## +--------+ %esp
|
||||
|
||||
.align align16
|
||||
lbnMulN1_32:
|
||||
_lbnMulN1_32:
|
||||
pushl %esi # U
|
||||
movl 12(%esp),%esi # V load in
|
||||
pushl %ebp # U
|
||||
movl 20(%esp),%ebp # V load len
|
||||
pushl %ebx # U
|
||||
movl 28(%esp),%ecx # V load k
|
||||
pushl %edi # U
|
||||
movl 20(%esp),%edi # V load out
|
||||
|
||||
## First multiply step has no carry in.
|
||||
movl (%esi),%eax # V
|
||||
leal -4(,%ebp,4),%ebx # U loop unrolling
|
||||
mull %ecx # NP first multiply
|
||||
movl %eax,(%edi) # U
|
||||
andl $12,%ebx # V loop unrolling
|
||||
|
||||
addl %ebx,%esi # U loop unrolling
|
||||
addl %ebx,%edi # V loop unrolling
|
||||
|
||||
jmp *m32_jumptable(%ebx) # NP loop unrolling
|
||||
|
||||
.align align4
|
||||
m32_jumptable:
|
||||
.long m32_case0
|
||||
.long m32_case1
|
||||
.long m32_case2
|
||||
.long m32_case3
|
||||
|
||||
nop
|
||||
.align align8
|
||||
nop
|
||||
nop
|
||||
nop # Get loop nicely aligned
|
||||
|
||||
m32_case0:
|
||||
subl $4,%ebp # U
|
||||
jbe m32_done # V
|
||||
|
||||
m32_loop:
|
||||
movl 4(%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
addl $16,%esi # U
|
||||
addl $16,%edi # V
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
adcl $0,%edx # U
|
||||
movl %eax,-12(%edi) # V
|
||||
m32_case3:
|
||||
movl -8(%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
adcl $0,%edx # U
|
||||
movl %eax,-8(%edi) # V
|
||||
m32_case2:
|
||||
movl -4(%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
adcl $0,%edx # U
|
||||
movl %eax,-4(%edi) # V
|
||||
m32_case1:
|
||||
movl (%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
adcl $0,%edx # U
|
||||
movl %eax,(%edi) # V
|
||||
|
||||
subl $4,%ebp # U
|
||||
ja m32_loop # V
|
||||
|
||||
m32_done:
|
||||
movl %edx,4(%edi) # U
|
||||
popl %edi # V
|
||||
popl %ebx # U
|
||||
popl %ebp # V
|
||||
popl %esi # U
|
||||
ret # NP
|
||||
|
||||
|
||||
.align align16
|
||||
lbnMulAdd1_32:
|
||||
_lbnMulAdd1_32:
|
||||
|
||||
pushl %esi # U
|
||||
movl 12(%esp),%esi # V load in
|
||||
pushl %edi # U
|
||||
movl 12(%esp),%edi # V load out
|
||||
pushl %ebp # U
|
||||
movl 24(%esp),%ebp # V load len
|
||||
pushl %ebx # U
|
||||
movl 32(%esp),%ecx # V load k
|
||||
|
||||
## First multiply step has no carry in.
|
||||
movl (%esi),%eax # V
|
||||
movl (%edi),%ebx # U
|
||||
mull %ecx # NP first multiply
|
||||
addl %eax,%ebx # U
|
||||
leal -4(,%ebp,4),%eax # V loop unrolling
|
||||
adcl $0,%edx # U
|
||||
andl $12,%eax # V loop unrolling
|
||||
movl %ebx,(%edi) # U
|
||||
|
||||
addl %eax,%esi # V loop unrolling
|
||||
addl %eax,%edi # U loop unrolling
|
||||
|
||||
jmp *ma32_jumptable(%eax) # NP loop unrolling
|
||||
|
||||
.align align4
|
||||
ma32_jumptable:
|
||||
.long ma32_case0
|
||||
.long ma32_case1
|
||||
.long ma32_case2
|
||||
.long ma32_case3
|
||||
|
||||
.align align8
|
||||
nop
|
||||
nop
|
||||
nop # To align loop properly
|
||||
|
||||
|
||||
ma32_case0:
|
||||
subl $4,%ebp # U
|
||||
jbe ma32_done # V
|
||||
|
||||
ma32_loop:
|
||||
movl 4(%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
addl $16,%esi # U
|
||||
addl $16,%edi # V
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
movl -12(%edi),%ebx # V
|
||||
adcl $0,%edx # U
|
||||
addl %eax,%ebx # V
|
||||
adcl $0,%edx # U
|
||||
movl %ebx,-12(%edi) # V
|
||||
ma32_case3:
|
||||
movl -8(%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
movl -8(%edi),%ebx # V
|
||||
adcl $0,%edx # U
|
||||
addl %eax,%ebx # V
|
||||
adcl $0,%edx # U
|
||||
movl %ebx,-8(%edi) # V
|
||||
ma32_case2:
|
||||
movl -4(%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
movl -4(%edi),%ebx # V
|
||||
adcl $0,%edx # U
|
||||
addl %eax,%ebx # V
|
||||
adcl $0,%edx # U
|
||||
movl %ebx,-4(%edi) # V
|
||||
ma32_case1:
|
||||
movl (%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
movl (%edi),%ebx # V
|
||||
adcl $0,%edx # U
|
||||
addl %eax,%ebx # V
|
||||
adcl $0,%edx # U
|
||||
movl %ebx,(%edi) # V
|
||||
|
||||
subl $4,%ebp # U
|
||||
ja ma32_loop # V
|
||||
|
||||
ma32_done:
|
||||
popl %ebx # U
|
||||
popl %ebp # V
|
||||
movl %edx,%eax # U
|
||||
popl %edi # V
|
||||
popl %esi # U
|
||||
ret # NP
|
||||
|
||||
|
||||
.align align16
|
||||
lbnMulSub1_32:
|
||||
_lbnMulSub1_32:
|
||||
pushl %esi # U
|
||||
movl 12(%esp),%esi # V load in
|
||||
pushl %edi # U
|
||||
movl 12(%esp),%edi # V load out
|
||||
pushl %ebp # U
|
||||
movl 24(%esp),%ebp # V load len
|
||||
pushl %ebx # U
|
||||
movl 32(%esp),%ecx # V load k
|
||||
|
||||
/* First multiply step has no carry in. */
|
||||
movl (%esi),%eax # V
|
||||
movl (%edi),%ebx # U
|
||||
mull %ecx # NP first multiply
|
||||
subl %eax,%ebx # U
|
||||
leal -4(,%ebp,4),%eax # V loop unrolling
|
||||
adcl $0,%edx # U
|
||||
andl $12,%eax # V loop unrolling
|
||||
movl %ebx,(%edi) # U
|
||||
|
||||
addl %eax,%esi # V loop unrolling
|
||||
addl %eax,%edi # U loop unrolling
|
||||
|
||||
jmp *ms32_jumptable(%eax) # NP loop unrolling
|
||||
|
||||
.align align4
|
||||
ms32_jumptable:
|
||||
.long ms32_case0
|
||||
.long ms32_case1
|
||||
.long ms32_case2
|
||||
.long ms32_case3
|
||||
|
||||
.align align8
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
ms32_case0:
|
||||
subl $4,%ebp # U
|
||||
jbe ms32_done # V
|
||||
|
||||
ms32_loop:
|
||||
movl 4(%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
addl $16,%esi # U
|
||||
addl $16,%edi # V
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
movl -12(%edi),%ebx # V
|
||||
adcl $0,%edx # U
|
||||
subl %eax,%ebx # V
|
||||
adcl $0,%edx # U
|
||||
movl %ebx,-12(%edi) # V
|
||||
ms32_case3:
|
||||
movl -8(%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
movl -8(%edi),%ebx # V
|
||||
adcl $0,%edx # U
|
||||
subl %eax,%ebx # V
|
||||
adcl $0,%edx # U
|
||||
movl %ebx,-8(%edi) # V
|
||||
ms32_case2:
|
||||
movl -4(%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
movl -4(%edi),%ebx # V
|
||||
adcl $0,%edx # U
|
||||
subl %eax,%ebx # V
|
||||
adcl $0,%edx # U
|
||||
movl %ebx,-4(%edi) # V
|
||||
ms32_case1:
|
||||
movl (%esi),%eax # U
|
||||
movl %edx,%ebx # V Remember carry for later
|
||||
mull %ecx # NP
|
||||
addl %ebx,%eax # U Add carry in from previous word
|
||||
movl (%edi),%ebx # V
|
||||
adcl $0,%edx # U
|
||||
subl %eax,%ebx # V
|
||||
adcl $0,%edx # U
|
||||
movl %ebx,(%edi) # V
|
||||
|
||||
subl $4,%ebp # U
|
||||
ja ms32_loop # V
|
||||
|
||||
ms32_done:
|
||||
popl %ebx # U
|
||||
popl %ebp # V
|
||||
movl %edx,%eax # U
|
||||
popl %edi # V
|
||||
popl %esi # U
|
||||
ret # NP
|
||||
|
||||
## Two-word by one-word divide. Stores quotient, returns remainder.
|
||||
## BNWORD32 lbnDiv21_32(BNWORD32 *q, BNWORD32 nh, BNWORD32 nl, BNWORD32 d)
|
||||
## 4 8 12 16
|
||||
|
||||
.align align16
|
||||
lbnDiv21_32:
|
||||
_lbnDiv21_32:
|
||||
movl 8(%esp),%edx # U Load nh
|
||||
movl 12(%esp),%eax # V Load nl
|
||||
movl 4(%esp),%ecx # U Load q
|
||||
divl 16(%esp) # NP
|
||||
movl %eax,(%ecx) # U Store quotient
|
||||
movl %edx,%eax # V Return remainder
|
||||
ret
|
||||
|
||||
## Multi-word by one-word remainder.
|
||||
## This speeds up key generation. It's not worth unrolling and so on;
|
||||
## using 32-bit divides is enough of a speedup.
|
||||
##
|
||||
## The modulus (in %ebp) is often 16 bits. Given that the dividend is 32
|
||||
## bits, the chances of saving the first divide because the high word of the
|
||||
## dividend is less than the modulus are low enough it's not worth taking
|
||||
## the cycles to test for it.
|
||||
##
|
||||
## unsigned lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d)
|
||||
## 4 8 12
|
||||
.align align16
|
||||
lbnModQ_32:
|
||||
_lbnModQ_32:
|
||||
movl 4(%esp),%eax # U Load n
|
||||
pushl %ebp # V
|
||||
movl 12(%esp),%ebp # U Load len
|
||||
pushl %esi # V
|
||||
leal -4(%eax,%ebp,4),%esi # U
|
||||
movl 20(%esp),%ecx # V Load d
|
||||
xorl %edx,%edx # U Clear MSW for first divide
|
||||
modq32_loop:
|
||||
movl (%esi),%eax # U
|
||||
subl $4,%esi # V
|
||||
divl %ecx # NP
|
||||
decl %ebp # U
|
||||
jnz modq32_loop # V
|
||||
|
||||
popl %esi # U
|
||||
movl %edx,%eax # V
|
||||
popl %ebp # U
|
||||
ret # NP
|
||||
+1038
File diff suppressed because it is too large.
Load diff
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbn8086.h - This file defines the interfaces to the 8086
|
||||
* assembly primitives for 16-bit MS-DOS environments.
|
||||
* It is intended to be included in "lbn.h"
|
||||
* via the "#include BNINCLUDE" mechanism.
|
||||
*/
|
||||
|
||||
#define BN_LITTLE_ENDIAN 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* These assembly-language primitives use C names */
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Set up the appropriate types */
|
||||
typedef unsigned short bnword16;
|
||||
#define BNWORD16 bnword16
|
||||
typedef unsigned long bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
|
||||
void __cdecl __far
|
||||
lbnMulN1_16(bnword16 __far *out, bnword16 const __far *in,
|
||||
unsigned len, bnword16 k);
|
||||
#define lbnMulN1_16 lbnMulN1_16
|
||||
|
||||
bnword16 __cdecl __far
|
||||
lbnMulAdd1_16(bnword16 __far *out, bnword16 const __far *in,
|
||||
unsigned len, bnword16 k);
|
||||
#define lbnMulAdd1_16 lbnMulAdd1_16
|
||||
|
||||
bnword16 __cdecl __far
|
||||
lbnMulSub1_16(bnword16 __far *out, bnword16 const __far *in,
|
||||
unsigned len, bnword16 k);
|
||||
#define lbnMulSub1_16 lbnMulSub1_16
|
||||
|
||||
bnword16 __cdecl __far
|
||||
lbnDiv21_16(bnword16 __far *q, bnword16 nh, bnword16 nl, bnword16 d);
|
||||
#define lbnDiv21_16 lbnDiv21_16
|
||||
|
||||
bnword16 __cdecl __far
|
||||
lbnModQ_16(bnword16 const __far *n, unsigned len, bnword16 d);
|
||||
#define lbnModQ_16 lbnModQ_16
|
||||
|
||||
|
||||
|
||||
void __cdecl __far
|
||||
lbnMulN1_32(bnword32 __far *out, bnword32 const __far *in,
|
||||
unsigned len, bnword32 k);
|
||||
#define lbnMulN1_32 lbnMulN1_32
|
||||
|
||||
bnword32 __cdecl __far
|
||||
lbnMulAdd1_32(bnword32 __far *out, bnword32 const __far *in,
|
||||
unsigned len, bnword32 k);
|
||||
#define lbnMulAdd1_32 lbnMulAdd1_32
|
||||
|
||||
bnword32 __cdecl __far
|
||||
lbnMulSub1_32(bnword32 __far *out, bnword32 const __far *in,
|
||||
unsigned len, bnword32 k);
|
||||
#define lbnMulSub1_32 lbnMulSub1_32
|
||||
|
||||
bnword32 __cdecl __far
|
||||
lbnDiv21_32(bnword32 __far *q, bnword32 nh, bnword32 nl, bnword32 d);
|
||||
#define lbnDiv21_32 lbnDiv21_32
|
||||
|
||||
bnword16 __cdecl __far
|
||||
lbnModQ_32(bnword32 const __far *n, unsigned len, bnword32 d);
|
||||
#define lbnModQ_32 lbnModQ_32
|
||||
|
||||
int __cdecl __far not386(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbn960jx.h - This file defines the interfaces to assembly primitives
|
||||
* for the the Intel i960Jx series of processors. In fact, these thould
|
||||
* work on any i960 series processor, but haven't been tested.
|
||||
* It is intended to be included in "lbn.h"
|
||||
* via the "#include BNINCLUDE" mechanism.
|
||||
*/
|
||||
|
||||
#define BN_LITTLE_ENDIAN 1
|
||||
|
||||
typedef unsigned long bnword32;
|
||||
#define BNWORD32 bnword32;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* These assembly-language primitives use C names */
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Function prototypes for the asm routines */
|
||||
void
|
||||
lbnMulN1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
#define lbnMulN1_32 lbnMulN1_32
|
||||
|
||||
bnword32
|
||||
lbnMulAdd1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
#define lbnMulAdd1_32 lbnMulAdd1_32
|
||||
|
||||
bnword32
|
||||
lbnMulSub1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
|
||||
#define lbnMulSub1_32 lbnMulSub1_32
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
# Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
# For licensing and other legal details, see the file legal.c.
|
||||
#
|
||||
# Assembly-language bignum primitives for the i960 Jx series.
|
||||
#
|
||||
# The Jx series is fairly straightforward single-instruction-issue
|
||||
# implementation, with a 1-cycle-issue 4-cycle-latency non-pipelined
|
||||
# multiplier that we can use. Note also that loads which hit in the
|
||||
# cache have 2 cycles of latency and stores stall until all pending
|
||||
# loads are done.
|
||||
#
|
||||
# What is intensely annoying about the i960 is that it uses the same
|
||||
# flags for all conditional branches (even compare-and-branch sets the
|
||||
# flags) AND for the carry bit. Further, it is hard to manipulate
|
||||
# that bit.
|
||||
#
|
||||
# Calling conventions:
|
||||
# The r registers are all local, if you set them up. There's an alternative
|
||||
# calling convention that uses bal (branch and link) and doesn't set them up.
|
||||
# Currently, all of these functions are designed to work that way.
|
||||
# g0-g7 are argument registers and volatile across calls. return in g0-g3.
|
||||
# g8-g11 are extra argument registers, and volatile if used, but
|
||||
# preserved if not. Here, they are not.
|
||||
# g12 is used for PIC, and is preserved.
|
||||
# g13 is a pointer to a structure return value, if used, and is volatile.
|
||||
# g14 is magic, and is used as a return address in the branch-and-link
|
||||
# convention, and as a pointer to an argument block if the arguments
|
||||
# won't fit in registers, but is usually hardwired 0 and must be
|
||||
# returned set to zero (0).
|
||||
# g15 is the frame pointer, and shouldn't be messed with.
|
||||
# The AC (condition codes) are all volatile.
|
||||
# The fp registers are all volatile, but irrelevant.
|
||||
#
|
||||
|
||||
# BNWORD32
|
||||
# lbnMultAdd1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
# This adds "k" * "in" to "len" words of "out" and returns the word of
|
||||
# carry.
|
||||
#
|
||||
# For doing multiply-add, the 960 is a bit annoying because it uses
|
||||
# the same status bits for the carry flag and for the loop indexing
|
||||
# computation, and doesn't have an "add with carry out but not carry in"
|
||||
# instruction. Fortunately, we can arrange to have the loop indexing
|
||||
# leave the carry bit clear most of the time.
|
||||
#
|
||||
# The basic sequence of the loop is:
|
||||
# 1. Multiply k * *in++ -> high, low
|
||||
# 2. Addc carry word and carry bit to low
|
||||
# 3. Addc carry bit to high, producing carry word (note: cannot generate carry!)
|
||||
# 4. Addc low to *out++
|
||||
#
|
||||
# Note that the carry bit set in step 4 is used in step 2. The only place
|
||||
# in this loop that the carry flag isn't in use is between steps 3 and 4,
|
||||
# so we have to rotate the loop to place the loop indexing operations here.
|
||||
# (Which consist of a compare-and-decrement and a conditional branch.)
|
||||
# The loop above ignores the details of when to do loads and stores, which
|
||||
# have some flexibility, but must be carefully scheduled to avoid stalls.
|
||||
#
|
||||
# The first iteration has no carry word in, so it requires only steps 1 and 4,
|
||||
# and since we begin the loop with step 4, it boils down to just step 1
|
||||
# followed by the loop indexing (which clears the carry bit in preparation
|
||||
# for step 4).
|
||||
#
|
||||
# Arguments are passed as follows:
|
||||
# g0 - out pointer
|
||||
# g1 - in pointer
|
||||
# g2 - length
|
||||
# g3 - k
|
||||
# The other registers are used as follows.
|
||||
# g4 - low word of product
|
||||
# g5 - high word of product
|
||||
# g6 - current word of "out"
|
||||
# g7 - carry word
|
||||
# g13 - current word of "in"
|
||||
|
||||
.globl _lbnMulAdd1_32
|
||||
_lbnMulAdd1_32:
|
||||
ld (g1),g13 # Fetch *in
|
||||
addo g1,4,g1 # Increment in
|
||||
emul g13,g3,g4 # Do multiply (step 1)
|
||||
ld (g0),g6 # Fetch *out
|
||||
chkbit 0,g2 # Check if loop counter was odd
|
||||
shro 1,g2,g2 # Divide loop counter by 2
|
||||
mov g5,g7 # Move high word to carry
|
||||
bno ma_loop1 # If even, jump to ma_loop1
|
||||
cmpo 0,g2 # If odd, was it 1 (now 0)?
|
||||
be ma_done # If equal (carry set), jump to ending code
|
||||
|
||||
# Entered with carry bit clear
|
||||
ma_loop:
|
||||
ld (g1),g13 # Fetch *in
|
||||
addc g4,g6,g6 # Add low to *out (step 4), generate carry
|
||||
emul g13,g3,g4 # Do multiply (step 1)
|
||||
st g6,(g0) # Write out *out
|
||||
addo g0,4,g0 # Increment out
|
||||
addo g1,4,g1 # Increment in
|
||||
ld (g0),g6 # Fetch next *out
|
||||
addc g7,g4,g4 # Add carries to low (step 2)
|
||||
addc g5,0,g7 # Add carry bit to high (step 3) & clear carry
|
||||
ma_loop1:
|
||||
ld (g1),g13 # Fetch *in
|
||||
addc g4,g6,g6 # Add low to *out (step 4), generate carry
|
||||
emul g13,g3,g4 # Do multiply (step 1)
|
||||
st g6,(g0) # Write out *out
|
||||
addo g0,4,g0 # Increment out
|
||||
addo g1,4,g1 # Increment in
|
||||
ld (g0),g6 # Fetch next *out
|
||||
addc g7,g4,g4 # Add carries to low (step 2)
|
||||
addc g5,0,g7 # Add carry bit to high (step 3) & clear carry
|
||||
|
||||
cmpdeco 1,g2,g2
|
||||
bne ma_loop
|
||||
# When we come here, carry is *set*, and we stil have to do step 4
|
||||
ma_done:
|
||||
cmpi 0,1 # Clear carry (equal flag)
|
||||
addc g4,g6,g6 # Add low to *out (step 4), generate carry
|
||||
st g6,(g0) # Write out *out
|
||||
addc g7,0,g0 # Add carry bit and word to produce return value
|
||||
ret
|
||||
|
||||
# Now, multiply N by 1 is similarly annoying. We only have one add in the
|
||||
# whole loop, which should just be able to leave its carry output in the
|
||||
# carry flag for the next iteration, but we need the condition codes to do
|
||||
# loop testing. *Sigh*.
|
||||
#
|
||||
# void
|
||||
# lbnMultN1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
# This stores len+1 words of "k" * len words of "in" and stores the result
|
||||
# in "out".
|
||||
#
|
||||
# To avoid having to do a move after the first iteration, for the first
|
||||
# step, g4/g5 is the product. For second step, g6/g7 is used for product
|
||||
# storage and g5 is the carry in. It alternates from then on.
|
||||
.globl _lbnMulN1_32
|
||||
_lbnMulN1_32:
|
||||
ld (g1),g13 # Fetch *in
|
||||
addo g1,4,g1 # Increment in
|
||||
emul g13,g3,g4 # Do multiply (step 1)
|
||||
chkbit 0,g2 # Check if loop counter was odd
|
||||
shro 1,g2,g2 # Divide loop counter by 2
|
||||
bno m_loop1 # If even, jump to ma_loop1
|
||||
mov g4,g6
|
||||
cmpo 0,g2 # If counter was odd, was it 1 (now 0)?
|
||||
mov g5,g7
|
||||
be m_done # If equal (carry set), jump to ending code
|
||||
|
||||
# Entered with carry bit clear
|
||||
m_loop:
|
||||
# Result in g6, carry word in g7
|
||||
ld (g1),g13 # Fetch *in
|
||||
addo g1,4,g1 # Increment in
|
||||
emul g13,g3,g4 # Do multiply (step 1)
|
||||
st g6,(g0) # Write out *out
|
||||
addo g0,4,g0 # Increment out
|
||||
addc g7,g4,g4 # Add carries to low (step 2)
|
||||
# No need to add carry bit here, because it'll get remembered until next addc.
|
||||
# addc g5,0,g5 # Add carry bit to high (step 3)
|
||||
m_loop1:
|
||||
# Carry word in g5
|
||||
ld (g1),g13 # Fetch *in
|
||||
addo g1,4,g1 # Increment in
|
||||
emul g13,g3,g6 # Do multiply (step 1)
|
||||
st g4,(g0) # Write out *out
|
||||
addo g0,4,g0 # Increment out
|
||||
addc g5,g6,g6 # Add carries to low (step 2)
|
||||
addc g7,0,g7 # Add carry bit to high (step 3)
|
||||
|
||||
cmpdeco 1,g2,g2
|
||||
bne m_loop
|
||||
|
||||
# When we come here, we have to store g6 and the carry word in g7.
|
||||
m_done:
|
||||
st g6,(g0) # Write out *out
|
||||
st g7,4(g0) # Write out *out
|
||||
ret
|
||||
|
||||
# BNWORD32
|
||||
# lbnMultSub1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
|
||||
# This subtracts "k" * "in" from "len" words of "out" and returns the word of
|
||||
# borrow.
|
||||
#
|
||||
# This is similar to multiply-add, but actually a bit more obnoxious,
|
||||
# because of the carry situation. The 960 uses a carry (rather than a borrow)
|
||||
# bit on subtracts, so the carry bit should be 1 for a subc to do the
|
||||
# same thing as an ordinary subo. So we use two carry chains: one from
|
||||
# the add of the low-order words to the high-order carry word, and a second,
|
||||
# which uses an extra register, to connect the subtracts. This avoids
|
||||
# the need to fiddle with inverting the bit in the usual case.
|
||||
#
|
||||
# Arguments are passed as follows:
|
||||
# g0 - out pointer
|
||||
# g1 - in pointer
|
||||
# g2 - length
|
||||
# g3 - k
|
||||
# The other registers are used as follows.
|
||||
# g4 - low word of product
|
||||
# g5 - high word of product
|
||||
# g6 - current word of "out"
|
||||
# g7 - carry word
|
||||
# g13 - current word of "in"
|
||||
# g14 - remembered carry bit
|
||||
|
||||
.globl _lbnMulSub1_32
|
||||
_lbnMulSub1_32:
|
||||
ld (g1),g13 # Fetch *in
|
||||
addo g1,4,g1 # Increment in
|
||||
emul g13,g3,g4 # Do multiply (step 1)
|
||||
ld (g0),g6 # Fetch *out
|
||||
chkbit 0,g2 # Check if loop counter was odd
|
||||
mov 1,g14 # Set remembered carry for first iteration
|
||||
shro 1,g2,g2 # Divide loop counter by 2
|
||||
mov g5,g7 # Move high word to carry
|
||||
bno ms_loop1 # If even, jump to ma_loop1
|
||||
cmpo 0,g2 # If odd, was it 1 (now 0)?
|
||||
be ms_done # If equal (carry set), jump to ending code
|
||||
|
||||
# Entered with carry bit clear
|
||||
ms_loop:
|
||||
ld (g1),g13 # Fetch *in
|
||||
cmpi g14,1 # Set carry flag
|
||||
subc g4,g6,g6 # Subtract low from *out (step 4), gen. carry
|
||||
emul g13,g3,g4 # Do multiply (step 1)
|
||||
addc 0,0,g14 # g14 = carry, then clear carry
|
||||
st g6,(g0) # Write out *out
|
||||
addo g0,4,g0 # Increment out
|
||||
addo g1,4,g1 # Increment in
|
||||
ld (g0),g6 # Fetch next *out
|
||||
addc g7,g4,g4 # Add carries to low (step 2)
|
||||
addc g5,0,g7 # Add carry bit to high (step 3)
|
||||
ms_loop1:
|
||||
ld (g1),g13 # Fetch *in
|
||||
cmpi g14,1 # Set carry flag for subtrsct
|
||||
subc g4,g6,g6 # Subtract low from *out (step 4), gen. carry
|
||||
emul g13,g3,g4 # Do multiply (step 1)
|
||||
addc 0,0,g14 # g14 = carry, then clear carry
|
||||
st g6,(g0) # Write out *out
|
||||
addo g0,4,g0 # Increment out
|
||||
addo g1,4,g1 # Increment in
|
||||
ld (g0),g6 # Fetch next *out
|
||||
addc g7,g4,g4 # Add carries to low (step 2)
|
||||
addc g5,0,g7 # Add carry bit to high (step 3)
|
||||
|
||||
cmpdeco 1,g2,g2
|
||||
bne ms_loop
|
||||
# When we come here, carry is *set*, and we stil have to do step 4
|
||||
ms_done:
|
||||
cmpi g14,1 # set carry (equal flag)
|
||||
subc g4,g6,g6 # Add low to *out (step 4), generate carry
|
||||
st g6,(g0) # Write out *out
|
||||
subc 0,0,g14 # g14 = -1 if no carry (borrow), 0 if carry
|
||||
subo g14,g7,g0 # Add borrow bit to produce return value
|
||||
mov 0,g14 # Restore g14 to 0 for return
|
||||
ret
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbnalpha.h - header file that declares the Alpha assembly-language
|
||||
* subroutines. It is intended to be included via the BNINCLUDE
|
||||
* mechanism.
|
||||
*/
|
||||
|
||||
#define BN_LITTLE_ENDIAN 1
|
||||
|
||||
typedef unsigned long bnword64;
|
||||
#define BNWORD64 bnword64
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* These assembly-language primitives use C names */
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void lbnMulN1_64(bnword64 *out, bnword64 const *in, unsigned len, bnword64 k);
|
||||
#define lbnMulN1_64 lbnMulN1_64
|
||||
|
||||
bnword64
|
||||
lbnMulAdd1_64(bnword64 *out, bnword64 const *in, unsigned len, bnword64 k);
|
||||
#define lbnMulAdd1_64 lbnMulAdd1_64
|
||||
|
||||
bnword64
|
||||
lbnMulSub1_64(bnword64 *out, bnword64 const *in, unsigned len, bnword64 k);
|
||||
#define lbnMulSub1_64 lbnMulSub1_64
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* DEC Alpha 64-bit math primitives. These use 64-bit words
|
||||
* unless otherwise noted.
|
||||
*
|
||||
* The DEC assembler apparently does some instruction scheduling,
|
||||
* but I tried to do some of my own, and tries to spread things
|
||||
* out over the register file to give the assembler more room
|
||||
* to schedule things.
|
||||
*
|
||||
* Alpha OSF/1 register usage conventions:
|
||||
* r0 - v0 - Temp, holds integer return value
|
||||
* r1..r8 - t0..t7 - Temp, trashed by procedure call
|
||||
* r9..r14 - s0..s5 - Saved across procedure calls
|
||||
* r15 - s6/FP - Frame pointer, saved across procedure calls
|
||||
* r16..r21 - a0..a5 - Argument registers, all trashed by procedure call
|
||||
* r22..r25 - t8..t11 - Temp, trashed by procedure call
|
||||
* r26 - ra - Return address
|
||||
* r27 - t12/pv - Procedure value, trashed by procedure call
|
||||
* r28 - at - Assembler temp, trashed by procedure call
|
||||
* r29 - gp - Global pointer
|
||||
* r30 - sp - Stack pointer
|
||||
* r31 - zero - hardwired to zero
|
||||
*/
|
||||
.text
|
||||
.align 4
|
||||
.globl lbnMulN1_64
|
||||
/* I have no idea what the '2' at the end of the .ent line means. */
|
||||
.ent lbnMulN1_64 2
|
||||
/*
|
||||
* Arguments: $16 = out, $17 = in, $18 = len<32>, $19 = k
|
||||
* Other registers: $0 = carry word, $1 = product low,
|
||||
* $2 = product high, $3 = input word
|
||||
*/
|
||||
lbnMulN1_64:
|
||||
ldq $3,0($17) /* Load first word of input */
|
||||
subl $18,1,$18
|
||||
mulq $3,$19,$1 /* Do low half of first multiply */
|
||||
umulh $3,$19,$0 /* Do second half of first multiply */
|
||||
stq $1,0($16)
|
||||
beq $18,m64_done
|
||||
m64_loop:
|
||||
ldq $3,8($17)
|
||||
addq $17,8,$17
|
||||
mulq $3,$19,$1 /* Do bottom half of multiply */
|
||||
subl $18,1,$18
|
||||
umulh $3,$19,$2 /* Do top half of multiply */
|
||||
addq $0,$1,$1 /* Add carry word from previous multiply */
|
||||
stq $1,8($16)
|
||||
cmpult $1,$0,$0 /* Compute carry bit from add */
|
||||
addq $16,8,$16
|
||||
addq $2,$0,$0 /* Add carry bit to carry word */
|
||||
|
||||
beq $18,m64_done
|
||||
|
||||
ldq $3,8($17)
|
||||
addq $17,8,$17
|
||||
mulq $3,$19,$1 /* Do bottom half of multiply */
|
||||
subl $18,1,$18
|
||||
umulh $3,$19,$2 /* Do top half of multiply */
|
||||
addq $0,$1,$1 /* Add carry word from previous multiply */
|
||||
stq $1,8($16)
|
||||
cmpult $1,$0,$0 /* Compute carry bit from add */
|
||||
addq $16,8,$16
|
||||
addq $2,$0,$0 /* Add carry bit to carry word */
|
||||
|
||||
bne $18,m64_loop
|
||||
m64_done:
|
||||
stq $0,8($16) /* Store last word of result */
|
||||
ret $31,($26),1
|
||||
/* The '1' in the hint field means procedure return - software convention */
|
||||
.end lbnMulN1_64
|
||||
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.globl lbnMulAdd1_64
|
||||
.ent lbnMulAdd1_64 2
|
||||
/*
|
||||
* Arguments: $16 = out, $17 = in, $18 = len<32>, $19 = k
|
||||
* Other registers: $0 = product high, $1 = product low,
|
||||
* $2 = product high temp, $3 = input word, $4 = output word
|
||||
* $5 = carry bit from add to out
|
||||
*/
|
||||
lbnMulAdd1_64:
|
||||
ldq $3,0($17) /* Load first word of input */
|
||||
subl $18,1,$18
|
||||
mulq $3,$19,$1 /* Do low half of first multiply */
|
||||
ldq $4,0($16) /* Load first word of output */
|
||||
umulh $3,$19,$2 /* Do second half of first multiply */
|
||||
addq $4,$1,$4
|
||||
cmpult $4,$1,$5 /* Compute borrow bit from subtract */
|
||||
stq $4,0($16)
|
||||
addq $5,$2,$0 /* Add carry bit to high word */
|
||||
beq $18,ma64_done
|
||||
ma64_loop:
|
||||
ldq $3,8($17) /* Load next word of input */
|
||||
addq $17,8,$17
|
||||
ldq $4,8($16) /* Load next word of output */
|
||||
mulq $3,$19,$1 /* Do bottom half of multiply */
|
||||
subl $18,1,$18
|
||||
addq $0,$1,$1 /* Add carry word from previous multiply */
|
||||
umulh $3,$19,$2 /* Do top half of multiply */
|
||||
cmpult $1,$0,$0 /* Compute carry bit from add */
|
||||
addq $4,$1,$4 /* Add product to loaded word */
|
||||
cmpult $4,$1,$5 /* Compute carry bit from add */
|
||||
stq $4,8($16)
|
||||
addq $5,$0,$5 /* Add carry bits together */
|
||||
addq $16,8,$16
|
||||
addq $5,$2,$0 /* Add carry bits to carry word */
|
||||
|
||||
beq $18,ma64_done
|
||||
|
||||
ldq $3,8($17) /* Load next word of input */
|
||||
addq $17,8,$17
|
||||
ldq $4,8($16) /* Load next word of output */
|
||||
mulq $3,$19,$1 /* Do bottom half of multiply */
|
||||
subl $18,1,$18
|
||||
addq $0,$1,$1 /* Add carry word from previous multiply */
|
||||
umulh $3,$19,$2 /* Do top half of multiply */
|
||||
cmpult $1,$0,$0 /* Compute carry bit from add */
|
||||
addq $4,$1,$4 /* Add product to loaded word */
|
||||
cmpult $4,$1,$5 /* Compute carry bit from add */
|
||||
stq $4,8($16)
|
||||
addq $5,$0,$5 /* Add carry bits together */
|
||||
addq $16,8,$16
|
||||
addq $5,$2,$0 /* Add carry bits to carry word */
|
||||
|
||||
bne $18,ma64_loop
|
||||
ma64_done:
|
||||
ret $31,($26),1
|
||||
.end lbnMulAdd1_64
|
||||
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.globl lbnMulSub1_64
|
||||
.ent lbnMulSub1_64 2
|
||||
/*
|
||||
* Arguments: $16 = out, $17 = in, $18 = len<32>, $19 = k
|
||||
* Other registers: $0 = carry word, $1 = product low,
|
||||
* $2 = product high temp, $3 = input word, $4 = output word
|
||||
* $5 = borrow bit from subtract
|
||||
*/
|
||||
lbnMulSub1_64:
|
||||
ldq $3,0($17) /* Load first word of input */
|
||||
subl $18,1,$18
|
||||
mulq $3,$19,$1 /* Do low half of first multiply */
|
||||
ldq $4,0($16) /* Load first word of output */
|
||||
umulh $3,$19,$2 /* Do second half of first multiply */
|
||||
cmpult $4,$1,$5 /* Compute borrow bit from subtract */
|
||||
subq $4,$1,$4
|
||||
addq $5,$2,$0 /* Add carry bit to high word */
|
||||
stq $4,0($16)
|
||||
beq $18,ms64_done
|
||||
ms64_loop:
|
||||
ldq $3,8($17) /* Load next word of input */
|
||||
addq $17,8,$17
|
||||
ldq $4,8($16) /* Load next word of output */
|
||||
mulq $3,$19,$1 /* Do bottom half of multiply */
|
||||
subl $18,1,$18
|
||||
addq $0,$1,$1 /* Add carry word from previous multiply */
|
||||
umulh $3,$19,$2 /* Do top half of multiply */
|
||||
cmpult $1,$0,$0 /* Compute carry bit from add */
|
||||
cmpult $4,$1,$5 /* Compute borrow bit from subtract */
|
||||
subq $4,$1,$4
|
||||
addq $5,$0,$5 /* Add carry bits together */
|
||||
stq $4,8($16)
|
||||
addq $5,$2,$0 /* Add carry bits to carry word */
|
||||
addq $16,8,$16
|
||||
|
||||
beq $18,ms64_done
|
||||
|
||||
ldq $3,8($17) /* Load next word of input */
|
||||
addq $17,8,$17
|
||||
ldq $4,8($16) /* Load next word of output */
|
||||
mulq $3,$19,$1 /* Do bottom half of multiply */
|
||||
subl $18,1,$18
|
||||
addq $0,$1,$1 /* Add carry word from previous multiply */
|
||||
umulh $3,$19,$2 /* Do top half of multiply */
|
||||
cmpult $1,$0,$0 /* Compute carry bit from add */
|
||||
cmpult $4,$1,$5 /* Compute borrow bit from subtract */
|
||||
subq $4,$1,$4
|
||||
addq $5,$0,$5 /* Add carry bits together */
|
||||
stq $4,8($16)
|
||||
addq $5,$2,$0 /* Add carry bits to carry word */
|
||||
addq $16,8,$16
|
||||
|
||||
bne $18,ms64_loop
|
||||
ms64_done:
|
||||
ret $31,($26),1
|
||||
.end lbnMulSub1_64
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* lbnmem.c - low-level bignum memory handling.
|
||||
*
|
||||
* Note that in all cases, the pointers passed around
|
||||
* are pointers to the *least* significant end of the word.
|
||||
* On big-endian machines, these are pointers to the *end*
|
||||
* of the allocated range.
|
||||
*
|
||||
* BNSECURE is a simple level of security; for more security
|
||||
* change these function to use locked unswappable memory.
|
||||
*/
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_STDLIB_H
|
||||
#define NO_STDLIB_H 0
|
||||
#endif
|
||||
#ifndef NO_STRING_H
|
||||
#define NO_STRING_H 0
|
||||
#endif
|
||||
#ifndef HAVE_STRINGS_H
|
||||
#define HAVE_STRINGS_H 0
|
||||
#endif
|
||||
#ifndef NEED_MEMORY_H
|
||||
#define NEED_MEMORY_H 0
|
||||
#endif
|
||||
|
||||
#if !NO_STDLIB_H
|
||||
#include <stdlib.h> /* For malloc() & co. */
|
||||
#else
|
||||
void *malloc();
|
||||
void *realloc();
|
||||
void free();
|
||||
#endif
|
||||
|
||||
#if !NO_STRING_H
|
||||
#include <string.h> /* For memset */
|
||||
#elif HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#if NEED_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#ifndef DBMALLOC
|
||||
#define DBMALLOC 0
|
||||
#endif
|
||||
#if DBMALLOC
|
||||
/* Development debugging */
|
||||
#include "../dbmalloc/malloc.h"
|
||||
#endif
|
||||
|
||||
#include "lbn.h"
|
||||
#include "lbnmem.h"
|
||||
|
||||
#include "kludge.h"
|
||||
|
||||
#include "zrtp.h"
|
||||
|
||||
#ifndef lbnMemWipe
|
||||
void
|
||||
lbnMemWipe(void *ptr, unsigned bytes)
|
||||
{
|
||||
zrtp_memset(ptr, 0, bytes);
|
||||
}
|
||||
#define lbnMemWipe(ptr, bytes) memset(ptr, 0, bytes)
|
||||
#endif
|
||||
|
||||
#ifndef lbnMemAlloc
|
||||
void *
|
||||
lbnMemAlloc(unsigned bytes)
|
||||
{
|
||||
return zrtp_sys_alloc(bytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef lbnMemFree
|
||||
void
|
||||
lbnMemFree(void *ptr, unsigned bytes)
|
||||
{
|
||||
lbnMemWipe(ptr, bytes);
|
||||
zrtp_sys_free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef lbnRealloc
|
||||
#if defined(lbnMemRealloc) || !BNSECURE
|
||||
void *
|
||||
lbnRealloc(void *ptr, unsigned oldbytes, unsigned newbytes)
|
||||
{
|
||||
if (ptr) {
|
||||
BIG(ptr = (char *)ptr - oldbytes;)
|
||||
if (newbytes < oldbytes)
|
||||
memmove(ptr, (char *)ptr + oldbytes-newbytes, oldbytes);
|
||||
}
|
||||
#ifdef lbnMemRealloc
|
||||
ptr = lbnMemRealloc(ptr, oldbytes, newbytes);
|
||||
#else
|
||||
ptr = realloc(ptr, newbytes);
|
||||
#endif
|
||||
if (ptr) {
|
||||
if (newbytes > oldbytes)
|
||||
memmove((char *)ptr + newbytes-oldbytes, ptr, oldbytes);
|
||||
BIG(ptr = (char *)ptr + newbytes;)
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#else /* BNSECURE */
|
||||
|
||||
void *
|
||||
lbnRealloc(void *oldptr, unsigned oldbytes, unsigned newbytes)
|
||||
{
|
||||
void *newptr = lbnMemAlloc(newbytes);
|
||||
|
||||
if (!newptr)
|
||||
return newptr;
|
||||
if (!oldptr)
|
||||
return BIGLITTLE((char *)newptr+newbytes, newptr);
|
||||
|
||||
/*
|
||||
* The following copies are a bit non-obvious in the big-endian case
|
||||
* because one of the pointers points to the *end* of allocated memory.
|
||||
*/
|
||||
if (newbytes > oldbytes) { /* Copy all of old into part of new */
|
||||
BIG(newptr = (char *)newptr + newbytes;)
|
||||
BIG(oldptr = (char *)oldptr - oldbytes;)
|
||||
memcpy(BIGLITTLE((char *)newptr-oldbytes, newptr), oldptr,
|
||||
oldbytes);
|
||||
} else { /* Copy part of old into all of new */
|
||||
memcpy(newptr, BIGLITTLE((char *)oldptr-newbytes, oldptr),
|
||||
newbytes);
|
||||
BIG(newptr = (char *)newptr + newbytes;)
|
||||
BIG(oldptr = (char *)oldptr - oldbytes;)
|
||||
}
|
||||
|
||||
lbnMemFree(oldptr, oldbytes);
|
||||
|
||||
return newptr;
|
||||
}
|
||||
#endif /* BNSECURE */
|
||||
#endif /* !lbnRealloc */
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* Operations on the usual buffers of bytes
|
||||
*/
|
||||
#ifndef BNSECURE
|
||||
#define BNSECURE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These operations act on buffers of memory, just like malloc & free.
|
||||
* One exception: it is not legal to pass a NULL pointer to lbnMemFree.
|
||||
*/
|
||||
|
||||
#ifndef lbnMemAlloc
|
||||
void *lbnMemAlloc(unsigned bytes);
|
||||
#endif
|
||||
|
||||
#ifndef lbnMemFree
|
||||
void lbnMemFree(void *ptr, unsigned bytes);
|
||||
#endif
|
||||
|
||||
/* This wipes out a buffer of bytes if necessary needed. */
|
||||
|
||||
#ifndef lbnMemWipe
|
||||
#if BNSECURE
|
||||
void lbnMemWipe(void *ptr, unsigned bytes);
|
||||
#else
|
||||
#define lbnMemWipe(ptr, bytes) (void)(ptr,bytes)
|
||||
#endif
|
||||
#endif /* !lbnMemWipe */
|
||||
|
||||
/*
|
||||
* lbnRealloc is NOT like realloc(); it's endian-sensitive!
|
||||
* If lbnMemRealloc is #defined, lbnRealloc will be defined in terms of it.
|
||||
* It is legal to pass a NULL pointer to lbnRealloc, although oldbytes
|
||||
* will always be sero.
|
||||
*/
|
||||
#ifndef lbnRealloc
|
||||
void *lbnRealloc(void *ptr, unsigned oldbytes, unsigned newbytes);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* These macros are the ones actually used most often in the math library.
|
||||
* They take and return pointers to the *end* of the given buffer, and
|
||||
* take sizes in terms of words, not bytes.
|
||||
*
|
||||
* Note that LBNALLOC takes the pointer as an argument instead of returning
|
||||
* the value.
|
||||
*
|
||||
* Note also that these macros are only useable if you have included
|
||||
* lbn.h (for the BIG and BIGLITTLE macros), which this file does NOT include.
|
||||
*/
|
||||
|
||||
#define LBNALLOC(p,type,words) BIGLITTLE( \
|
||||
if ( ((p) = (type *)lbnMemAlloc((words)*sizeof*(p))) != 0) \
|
||||
(p) += (words), \
|
||||
(p) = (type *)lbnMemAlloc((words) * sizeof*(p)) \
|
||||
)
|
||||
#define LBNFREE(p,words) lbnMemFree((p) BIG(-(words)), (words) * sizeof*(p))
|
||||
#define LBNREALLOC(p,old,new) \
|
||||
lbnRealloc(p, (old) * sizeof*(p), (new) * sizeof*(p))
|
||||
#define LBNWIPE(p,words) lbnMemWipe((p) BIG(-(words)), (words) * sizeof*(p))
|
||||
|
||||
+322
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
#include "lbnppc.h"
|
||||
|
||||
/*
|
||||
* lbnppc.c - Assembly primitives for the bignum library, PowerPC version.
|
||||
*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* Register usage during function calls is:
|
||||
* r0 - volatile
|
||||
* r1 - stack pointer, preserved
|
||||
* r2 - TOC pointer, preserved
|
||||
* r3 - First argument and return value register
|
||||
* r4-r10 - More argument registers, volatile
|
||||
* r11-r12 - Volatile
|
||||
* r13-r31 - Preserved
|
||||
* LR, CTR, XER and MQ are all volatile.
|
||||
* LR holds return address on entry.
|
||||
*
|
||||
* On the PPC 601, unrolling the loops more doesn't seem to speed things
|
||||
* up at all. I'd be curious if other chips differed.
|
||||
*/
|
||||
#if __MWERKS__ < 0x800
|
||||
|
||||
#include "ppcasm.h" /* PowerPC assembler */
|
||||
|
||||
/*
|
||||
* MulN1 expects (*out, *in, len, k), count >= 1
|
||||
* r3 r4 r5 r6
|
||||
*/
|
||||
static const unsigned mulN1[] = {
|
||||
PPC_LWZ(7,4,0), /* Load first word of in in r7 */
|
||||
PPC_MULLW(8,7,6), /* Low half of multiply in r8 */
|
||||
PPC_MTCTR(5), /* Move len into CTR */
|
||||
PPC_ADDIC(0,0,0), /* Clear carry bit for loop */
|
||||
PPC_MULHWU(5,7,6), /* High half of multiply in r5 */
|
||||
PPC_STW(8,3,0),
|
||||
PPC_BC(18,31,7), /* Branch to Label if --ctr == 0 */
|
||||
/* Loop: */
|
||||
PPC_LWZU(7,4,4), /* r7 = *++in */
|
||||
PPC_MULLW(8,7,6), /* r8 = low word of product */
|
||||
PPC_ADDE(8,8,5), /* Add carry word r5 and bit CF to r8 */
|
||||
PPC_STWU(8,3,4), /* *++out = r8 */
|
||||
PPC_MULHWU(5,7,6), /* r5 is high word of product, for carry word */
|
||||
PPC_BC(16,31,-5), /* Branch to Loop if --ctr != 0 */
|
||||
/* Label: */
|
||||
PPC_ADDZE(5,5), /* Add carry flag to r5 */
|
||||
PPC_STW(5,3,4), /* out[1] = r5 */
|
||||
PPC_BLR()
|
||||
};
|
||||
|
||||
/*
|
||||
* MulAdd1 expects (*out, *in, len, k), count >= 1
|
||||
* r3 r4 r5 r6
|
||||
*/
|
||||
static unsigned const mulAdd1[] = {
|
||||
PPC_LWZ(7,4,0), /* Load first word of in in r7 */
|
||||
PPC_LWZ(0,3,0), /* Load first word of out into r0 */
|
||||
PPC_MULLW(8,7,6), /* Low half of multiply in r8 */
|
||||
PPC_MTCTR(5), /* Move len into CTR */
|
||||
PPC_MULHWU(5,7,6), /* High half of multiply in r5 */
|
||||
PPC_ADDC(8,8,0), /* r8 = r8 + r0 */
|
||||
PPC_STW(8,3,0), /* Store result to memory */
|
||||
PPC_BC(18,31,10), /* Branch to Label if --ctr == 0 */
|
||||
/* Loop: */
|
||||
PPC_LWZU(7,4,4), /* r7 = *++in */
|
||||
PPC_LWZU(0,3,4), /* r0 = *++out */
|
||||
PPC_MULLW(8,7,6), /* r8 = low word of product */
|
||||
PPC_ADDE(8,8,5), /* Add carry word r5 and carry bit CF to r8 */
|
||||
PPC_MULHWU(5,7,6), /* r5 is high word of product, for carry word */
|
||||
PPC_ADDZE(5,5), /* Add carry bit from low add to r5 */
|
||||
PPC_ADDC(8,8,0), /* r8 = r8 + r0 */
|
||||
PPC_STW(8,3,0), /* *out = r8 */
|
||||
PPC_BC(16,31,-8), /* Branch to Loop if --ctr != 0 */
|
||||
/* Label: */
|
||||
PPC_ADDZE(3,5), /* Add carry flag to r5 and move to r3 */
|
||||
PPC_BLR()
|
||||
};
|
||||
|
||||
/*
|
||||
* MulSub1 expects (*out, *in, len, k), count >= 1
|
||||
* r3 r4 r5 r6
|
||||
*
|
||||
* Multiply and subtract is rather a pain. If the subtract of the
|
||||
* low word of the product from out[i] generates a borrow, we want to
|
||||
* increment the carry word (initially in the range 0..0xfffffffe).
|
||||
* However, the PPC's carry bit CF is *clear* after a subtract, so
|
||||
* we want to add (1-CF) to the carry word. This is done using two
|
||||
* instructions:
|
||||
*
|
||||
* SUBFME, subtract from minus one extended. This computes
|
||||
* rD = ~rS + 0xffffffff + CF. Since rS is from 0 to 0xfffffffe,
|
||||
* ~rS is from 1 through 0xffffffff, and the sum with 0xffffffff+CF is
|
||||
* from 0 through 0xfffffffff, setting the carry flag unconditionally, and
|
||||
* NOR, which is used as a bitwise invert NOT instruction.
|
||||
*
|
||||
* The SUBFME performs the computation rD = ~rS + 0xffffffff + CF,
|
||||
* = (-rS - 1) + (CF - 1) = -(rS - CF + 1) - 1 = ~(rS + 1-CF),
|
||||
* which is the bitwise complement of the value we want.
|
||||
* We want to add the complement of that result to the low word of the
|
||||
* product, which is just what a subtract would do, if only we could get
|
||||
* the carry flag clear. But it's always set, except for SUBFE, and the
|
||||
* operation we just performed unconditionally *sets* the carry flag. Ugh.
|
||||
* So find the complement in a separate instruction.
|
||||
*/
|
||||
static unsigned const mulSub1[] = {
|
||||
PPC_LWZ(7,4,0), /* Load first word of in in r7 */
|
||||
PPC_LWZ(0,3,0), /* Load first word of out into r0 */
|
||||
PPC_MTCTR(5), /* Move len into CTR */
|
||||
PPC_MULLW(8,7,6), /* Low half of multiply in r8 */
|
||||
PPC_MULHWU(5,7,6), /* High half of multiply in r5 */
|
||||
PPC_SUBFC(8,8,0), /* r8 = r0 - r8, setting CF */
|
||||
PPC_STW(8,3,0), /* Store result to memory */
|
||||
PPC_SUBFME(5,5), /* First of two insns to add (1-CF) to r5 */
|
||||
PPC_BC(18,31,12), /* Branch to Label if --ctr == 0 */
|
||||
/* Loop: */
|
||||
PPC_LWZU(7,4,4), /* r7 = *++in */
|
||||
PPC_LWZU(0,3,4), /* r0 = *++out */
|
||||
PPC_NOR(5,5,5), /* Second of two insns to add (1-CF) to r5 */
|
||||
PPC_MULLW(8,7,6), /* r8 = low word of product */
|
||||
PPC_ADDC(8,8,5), /* Add carry word r5 to r8 */
|
||||
PPC_MULHWU(5,7,6), /* r5 is high word of product, for carry word */
|
||||
PPC_ADDZE(5,5), /* Add carry bit from low add to r5 */
|
||||
PPC_SUBFC(8,8,0), /* r8 = r0 - r8, setting CF */
|
||||
PPC_STW(8,3,0), /* *out = r8 */
|
||||
PPC_SUBFME(5,5), /* First of two insns to add (1-CF) to r5 */
|
||||
PPC_BC(16,31,-10), /* Branch to Loop if --ctr != 0 */
|
||||
/* Label: */
|
||||
PPC_NOR(3,5,5), /* Finish adding (1-CF) to r5, store in r3 */
|
||||
PPC_BLR()
|
||||
};
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Args: BNWORD32 *n, BNWORD32 const *mod, unsigned mlen, BNWORD32 inv)
|
||||
* r3 r4 r5 r6
|
||||
* r7, r8 and r9 are the triple-width accumulator.
|
||||
* r0 and r10 are temporary registers.
|
||||
* r11 and r12 are temporary pointers into n and mod, respectively.
|
||||
* r2 (!) is another temporary register.
|
||||
*/
|
||||
static unsigned const montReduce[] = {
|
||||
PPC_MTCTR(5), /* ??? */
|
||||
PPC_LWZ(7,3,0), /* Load low word of n into r7 */
|
||||
PPC_LWZ(10,4,0), /* Fetch low word of mod */
|
||||
PPC_MULLW(0,7,6), /* Invert r7 into r0 */
|
||||
PPC_STW(0,3,0), /* Store back for future use */
|
||||
PPC_MULHWU(8,10,7), /* Get high word of whatnot */
|
||||
PPC_MULLW(10,10,7), /* Get low word of it */
|
||||
PPC_ADDC(7,7,10), /* Add low word of product to r7 */
|
||||
PPC_ADDZE(8,8), /* Add carry to high word */
|
||||
PPC_
|
||||
|
||||
|
||||
PPC_MULHW(8,7,6),
|
||||
PPC_ADDC(7,7,0), /* Add inverse back to r7 */
|
||||
PPC_ADDZE(8,8),
|
||||
PPC_
|
||||
|
||||
PPC_LWZU(
|
||||
/* Loop: */
|
||||
PPC_LWZU(0,11,4),
|
||||
PPC_LWZU(10,23,-4),
|
||||
PPC_MULLW(2,0,10),
|
||||
PPC_ADDC(7,7,2),
|
||||
PPC_MULHWU(0,0,10),
|
||||
PPC_ADDE(8,8,0),
|
||||
PPC_ADDZE(9,9),
|
||||
PPC_BC(16,31,-7), /* Branch to Loop if --ctr != 0 */
|
||||
|
||||
PPC_ADDIC_(count,-1),
|
||||
PPC_LWZU(0,x,4),
|
||||
PPC_ADDC(0,7,0),
|
||||
PPC_STW(0,x,0),
|
||||
PPC_ADDZE(7,8),
|
||||
PPC_ADDZE(8,9),
|
||||
PPC_LI(9,0),
|
||||
PPC_BC(xx,2,yy),
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Three overlapped transition vectors for three functions.
|
||||
* A PowerPC transition vector for a (potentially) inter-module
|
||||
* jump or call consists of two words, an instruction address
|
||||
* and a Table Of Contents (TOC) pointer, which is loaded into
|
||||
* r1. Since none of the routines here have global variables,
|
||||
* they don't need a TOC pointer, so the value is unimportant.
|
||||
* This array places an unintersting 32-bit value after each address.
|
||||
*/
|
||||
unsigned const * const lbnPPC_tv[] = {
|
||||
mulN1,
|
||||
mulAdd1,
|
||||
mulSub1,
|
||||
0
|
||||
};
|
||||
|
||||
#else /* __MWERKS >= 0x800 */
|
||||
|
||||
/*
|
||||
* MulN1 expects (*out, *in, len, k), count >= 1
|
||||
* r3 r4 r5 r6
|
||||
*/
|
||||
asm void
|
||||
lbnMulN1_32(register unsigned *out, register unsigned const *in,
|
||||
register unsigned len, register unsigned k)
|
||||
{
|
||||
lwz r7,0(in) /* Load first word of in in r7 */
|
||||
mtctr len /* Move len into CTR */
|
||||
mullw r8,r7,k /* Low half of multiply in r8 */
|
||||
addic r0,r0,0 /* Clear carry bit for loop */
|
||||
mulhwu len,r7,k /* High half of multiply in len */
|
||||
stw r8,0(out) /* *out = r8 */
|
||||
mulhwu len,r7,k /* len is high word of product, for carry */
|
||||
bdz- label /* Branch to Label if --ctr == 0 */
|
||||
loop:
|
||||
lwzu r7,4(in) /* r7 = *++in */
|
||||
mullw r8,r7,k /* Low half of multiply in r8 */
|
||||
adde r8,r8,len /* Add carry word len and bit CF to r8 */
|
||||
stwu r8,4(out) /* *++out = r8 */
|
||||
mulhwu len,r7,k /* len is high word of product, for carry */
|
||||
bdnz+ loop /* Branch to Loop if --ctr != 0 */
|
||||
label:
|
||||
addze len,len /* Add carry flag to carry word */
|
||||
stw len,4(out)
|
||||
blr
|
||||
}
|
||||
|
||||
/*
|
||||
* MulAdd1 expects (*out, *in, len, k), count >= 1
|
||||
* r3 r4 r5 r6
|
||||
*/
|
||||
asm unsigned
|
||||
lbnMulAdd1_32(register unsigned *out, register unsigned const *in,
|
||||
register unsigned len, register unsigned k)
|
||||
{
|
||||
lwz r7,0(in) /* Load first word of in in r7 */
|
||||
lwz r0,0(out) /* Load first word of out into r0 */
|
||||
mullw r8,r7,k /* Low half of multiply in r8 */
|
||||
mtctr len /* Move len into CTR */
|
||||
mulhwu len,r7,k /* High half of multiply in len */
|
||||
addc r8,r8,r0 /* r8 = r8 + r0 */
|
||||
stw r8,0(out) /* Store result to memory */
|
||||
bdz- label /* Branch to Label if --ctr == 0 */
|
||||
loop:
|
||||
lwzu r7,4(in) /* r7 = *++in */
|
||||
lwzu r0,4(out) /* r0 = *++out */
|
||||
mullw r8,r7,k /* r8 = low word of product */
|
||||
adde r8,r8,len /* Add carry word len and carry bit CF to r8 */
|
||||
mulhwu len,r7,k /* len is high word of product, for carry */
|
||||
addze len,len /* Add carry bit from low add to r5 */
|
||||
addc r8,r8,r0 /* r8 = r8 + r0 */
|
||||
stw r8,0(out) /* *out = r8 */
|
||||
bdnz+ loop /* Branch to Loop if --ctr != 0 */
|
||||
label:
|
||||
addze r3,r5 /* Add carry flag to r5 and move to r3 */
|
||||
blr
|
||||
}
|
||||
|
||||
/*
|
||||
* MulSub1 expects (*out, *in, len, k), count >= 1
|
||||
* r3 r4 r5 r6
|
||||
*
|
||||
* Multiply and subtract is rather a pain. If the subtract of the
|
||||
* low word of the product from out[i] generates a borrow, we want to
|
||||
* increment the carry word (initially in the range 0..0xfffffffe).
|
||||
* However, the PPC's carry bit CF is *clear* after a subtract, so
|
||||
* we want to add (1-CF) to the carry word. This is done using two
|
||||
* instructions:
|
||||
*
|
||||
* SUBFME, subtract from minus one extended. This computes
|
||||
* rD = ~rS + 0xffffffff + CF. Since rS is from 0 to 0xfffffffe,
|
||||
* ~rS is from 1 through 0xffffffff, and the sum with 0xffffffff+CF is
|
||||
* from 0 through 0xfffffffff, setting the carry flag unconditionally, and
|
||||
* NOR, which is used as a bitwise invert NOT instruction.
|
||||
*
|
||||
* The SUBFME performs the computation rD = ~rS + 0xffffffff + CF,
|
||||
* = (-rS - 1) + (CF - 1) = -(rS - CF + 1) - 1 = ~(rS + 1-CF),
|
||||
* which is the bitwise complement of the value we want.
|
||||
* We want to add the complement of that result to the low word of the
|
||||
* product, which is just what a subtract would do, if only we could get
|
||||
* the carry flag clear. But it's always set, except for SUBFE, and the
|
||||
* operation we just performed unconditionally *sets* the carry flag. Ugh.
|
||||
* So find the complement in a separate instruction.
|
||||
*/
|
||||
asm unsigned
|
||||
lbnMulSub1_32(register unsigned *out, register unsigned const *in,
|
||||
register unsigned len, register unsigned k)
|
||||
{
|
||||
lwz r7,0(in) /* Load first word of in in r7 */
|
||||
lwz r0,0(out) /* Load first word of out into r0 */
|
||||
mtctr len /* Move len into CTR */
|
||||
mullw r8,r7,k /* Low half of multiply in r8 */
|
||||
mulhwu len,r7,k /* High half of multiply in len */
|
||||
subfc r8,r8,r0 /* r8 = r0 - r8, setting CF */
|
||||
stw r8,0(out) /* Store result to memory */
|
||||
subfme len,len /* First of two insns to add (1-CF) to len */
|
||||
bdz- label /* Branch to Label if --ctr == 0 */
|
||||
loop:
|
||||
lwzu r7,4(in) /* r7 = *++in */
|
||||
lwzu r0,4(out) /* r0 = *++out */
|
||||
nor len,len,len /* Second of two insns to add (1-CF) to len */
|
||||
mullw r8,r7,k /* r8 = low word of product */
|
||||
addc r8,r8,len /* Add carry word len to r8 */
|
||||
mulhwu len,r7,k /* len is high word of product, for carry */
|
||||
addze len,len /* Add carry bit from low add to len */
|
||||
subfc r8,r8,r0 /* r8 = r0 - r8 */
|
||||
stw r8,0(out) /* *out = r8 */
|
||||
subfme len,len /* First of two insns to add (1-CF) to len */
|
||||
bdnz+ loop /* Branch to Loop if --ctr != 0 */
|
||||
label:
|
||||
nor r3,r5,r5 /* Finish adding (1-CF) to len, store in r3 */
|
||||
blr
|
||||
}
|
||||
|
||||
#endif /* __MWERKS >= 0x800 */
|
||||
/* 45678901234567890123456789012345678901234567890123456789012345678901234567 */
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
#ifndef LBNPPC_H
|
||||
#define LBNPPC_H
|
||||
|
||||
/*
|
||||
* Assembly-language routines for the Power PC processor.
|
||||
* Annoyingly, the Power PC does not have 64/32->32 bit divide,
|
||||
* so the C code should be reasonably fast. But it does have
|
||||
* 32x32->64-bit multiplies, and these routines provide access
|
||||
* to that.
|
||||
*
|
||||
* In versions of CodeWarrior before 8.0, there was no PPC assembler,
|
||||
* so a kludged-up one in CPP is used. This requires casting an
|
||||
* array of unsigneds to function pointer type, and a function pointer
|
||||
* is not a pointer to the code, but rather a pointer to a (code,TOC)
|
||||
* pointer pair which we fake up.
|
||||
*
|
||||
* CodeWarrior 8.0 supports PCC assembly, which is used directly.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bignums are stored in arrays of 32-bit words, and the least
|
||||
* significant 32-bit word has the lowest address, thus "little-endian".
|
||||
* The C code is slightly more efficient this way, so unless the
|
||||
* processor cares (the PowerPC, like most RISCs, doesn't), it is
|
||||
* best to use BN_LITTLE_ENDIAN.
|
||||
* Note that this has NOTHING to do with the order of bytes within a 32-bit
|
||||
* word; the math library is insensitive to that.
|
||||
*/
|
||||
#define BN_LITTLE_ENDIAN 1
|
||||
|
||||
typedef unsigned bnword32;
|
||||
#define BNWORD32 bnword32
|
||||
|
||||
#if __MWERKS__ < 0x800
|
||||
|
||||
/* Shared transition vector array */
|
||||
extern unsigned const * const lbnPPC_tv[];
|
||||
|
||||
/* A function pointer on the PowerPC is a pointer to a transition vector */
|
||||
#define lbnMulN1_32 \
|
||||
((void (*)(bnword32 *, bnword32 const *, unsigned, bnword32))(lbnPPC_tv+0))
|
||||
#define lbnMulAdd1_32 \
|
||||
((bnword32 (*)(bnword32 *, bnword32 const *, unsigned, bnword32))(lbnPPC_tv+1))
|
||||
#define lbnMulSub1_32 \
|
||||
((bnword32 (*)(bnword32 *, bnword32 const *, unsigned, bnword32))(lbnPPC_tv+2))
|
||||
|
||||
#else /* __MWERKS__ >= 0x800 */
|
||||
|
||||
void lbnMulN1_32(bnword32 *, bnword32 const *, unsigned, bnword32);
|
||||
#define lbnMulN1_32 lbnMulN1_32
|
||||
bnword32 lbnMulAdd1_32(bnword32 *, bnword32 const *, unsigned, bnword32);
|
||||
#define lbnMulAdd1_32 lbnMulAdd1_32
|
||||
bnword32 lbnMulSub1_32(bnword32 *, bnword32 const *, unsigned, bnword32);
|
||||
#define lbnMulSub1_32 lbnMulSub1_32
|
||||
|
||||
#endif /* __MWERKS__ >= 0x800 */
|
||||
|
||||
#endif /* LBNPPC_H */
|
||||
+1100
File diff suppressed because it is too large.
Load diff
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* We want the copyright string to be accessable to the unix strings command
|
||||
* in the final linked binary, and we don't want the linker to remove it if
|
||||
* it's not referenced, so we do that by using the volatile qualifier.
|
||||
*
|
||||
* ANSI C standard, section 3.5.3: "An object that has volatile-qualified
|
||||
* type may be modified in ways unknown to the implementation or have
|
||||
* other unknown side effects." Yes, we can't expect a compiler to
|
||||
* understand law...
|
||||
*/
|
||||
extern volatile const char bnCopyright[];
|
||||
+539
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
#ifndef PPCASM_H
|
||||
#define PPCASM_H
|
||||
/*
|
||||
* A PowerPC assembler in the C preprocessor.
|
||||
* This assumes that ints are 32 bits, and uses them for the values.
|
||||
*
|
||||
* An assembly-language routine is simply an array of unsigned ints,
|
||||
* initialized with the macros defined here.
|
||||
*
|
||||
* In the PowerPC, a generic function pointer does *not* point to the
|
||||
* first word of code, but to a two (or possibly more) word "transition
|
||||
* vector." The first word of the TV points to the function's code.
|
||||
* The second word is the function's TOC (Table Of Contents) pointer,
|
||||
* which is loaded into r2. The function's global variables are
|
||||
* accessed via the TOC pointed to by r2. TOC pointers are changed,
|
||||
* for example, when a dynamically linked library is called, so the
|
||||
* library can have private global variables.
|
||||
*
|
||||
* Saving r2 and reloading r2 each function call is a hassle that
|
||||
* I'd really rather avoid, since a lot of useful assembly language routines
|
||||
* can be written without global variables at all, so they don't need a TOC
|
||||
* pointer. But I haven't figured out how to persuade CodeWarrior 7 to
|
||||
* generate an intra-TOC call to an array. (CodeWarrior 8 supports
|
||||
* PowerPC asm, which obviates the need to do the cast-to-function-pointer
|
||||
* trick, which obviates the need for cross-TOC calls.)
|
||||
*
|
||||
* The basic PowerPC calling conventions for integers are:
|
||||
* r0 - scratch. May be modified by function calls.
|
||||
* r1 - stack pointer. Must be preserved across function calls.
|
||||
* See IMPORTANT notes on stack frame format below.
|
||||
* This must *ALWAYS*, at every instruction boundary, be 16-byte
|
||||
* aligned and point to a valid stack frame. If a procedure
|
||||
* needs to create a stack frame, the recommended way is to do:
|
||||
* stwu r1,-frame_size(r1)
|
||||
* and on exit, recover with one of:
|
||||
* addi r1,r1,frame_size, OR
|
||||
* lwz r1,0(r1)
|
||||
* r2 - TOC pointer. Points to the current table of contents.
|
||||
* Must be preserved across function calls.
|
||||
* r3 - First argument register and return value register.
|
||||
* Arguments are passed in r3 through r10, and values returned in
|
||||
* r3 through r6, as needed. (Usually only r3 for single word.)
|
||||
* r4-r10 - More argument registers
|
||||
* r11 - Scratch, may be modified by function calls.
|
||||
* On entry to indirect function calls, this points to the
|
||||
* transition vector, and additional words may be loaded
|
||||
* at offsets from it. Some conventions use r12 instead.
|
||||
* r12 - Scratch, may be modified by function calls.
|
||||
* r13-r31 - Callee-save registers, may not be modified by function
|
||||
* calls.
|
||||
* The LR, CTR and XER may be modified by function calls, as may the MQ
|
||||
* register, on those processors for which it is implemented.
|
||||
* CR fields 0, 1, 5, 6 and 7 are scratch and may be modified by function
|
||||
* calls. CR fields 2, 3 and 4 must be preserved across function calls.
|
||||
*
|
||||
* Stack frame format - READ
|
||||
*
|
||||
* r1 points to a stack frame, which must *ALWAYS*, meaning after each and
|
||||
* every instruction, without excpetion, point to a valid 16-byte-aligned
|
||||
* stack frame, defined as follows:
|
||||
* - The 296 bytes below r1 (from -296(r1) to -1(r1)) are the so-called Red
|
||||
* Zone reserved for leaf procedures, which may use it without allocating
|
||||
* a stack frame and without decrementing r1. The size comes from the room
|
||||
* needed to store all the callee-save registers: 19 64-bit integer registers
|
||||
* and 18 64-bit floating-point registers. (18+19)*8 = 296. So any
|
||||
* procedure can save all the registers it needs to save before creating
|
||||
* a stack frame and moving r1.
|
||||
* The bytes at -297(r1) and below may be used by interrupt and exception
|
||||
* handlers *at any time*. Anything placed there may disappear before
|
||||
* the next instruction.
|
||||
* The word at 0(r1) is the previous r1, and so on in a linked list.
|
||||
* This is the minimum needed to be a valid stack frame, but some other
|
||||
* offsets from r1 are preallocated by the calling procedure for the called
|
||||
* procedure's use. These are:
|
||||
* Offset 0: Link to previous stack frame - saved r1, if the called
|
||||
* procedure alters it.
|
||||
* Offset 4: Saved CR, if the called procedure alters the callee-save
|
||||
* fields. There's no important reason to save it here,
|
||||
* but the space is reserved and you might as well use it
|
||||
* for its intended purpose unless you have good reason to
|
||||
* do otherwise. (This may help some debuggers.)
|
||||
* Offset 8: Saved LR, if the called procedure needs to save it for
|
||||
* later function return. Saving the LR here helps a debugger
|
||||
* track the chain of return addresses on the stack.
|
||||
* Note that a called procedure does not need to preserve the
|
||||
* LR for it's caller's sake, but it uually wants to preserve
|
||||
* the value for its own sake until it finishes and it's
|
||||
* time to return. At that point, this is usually loaded
|
||||
* back into the LR and the branch accomplished with BLR.
|
||||
* However, if you want to be preverse, you could load it
|
||||
* into the CTR and use BCTR instead.
|
||||
* Offset 12: Reserved to compiler. I can't find what this is for.
|
||||
* Offset 16: Reserved to compiler. I can't find what this is for.
|
||||
* Offset 20: Saved TOC pointer. In a cross-TOC call, the old TOC (r2)
|
||||
* is saved here before r2 is loaded with the new TOC value.
|
||||
* Again, it's not important to use this slot for this, but
|
||||
* you might as well.
|
||||
* Beginning at offset 24 is the argument area. This area is at least 8 words
|
||||
* (32 bytes; I don't know what happens with 64 bits) long, and may be longer,
|
||||
* up to the length of the longest argument list in a function called by
|
||||
* the function which allocated this stack frame. Generally, arguments
|
||||
* to functions are passed in registers, but if those functions notice
|
||||
* the address of the arguments being taken, the registers are stored
|
||||
* into the space reserved for them in this area and then used from memory.
|
||||
* Additional arguments that will not fit into registers are also stored
|
||||
* here. Variadic functions (like printf) generally start by saving
|
||||
* all the integer argument registers from the "..." onwards to this space.
|
||||
* For that reason, the space must be large enough to store all the argument
|
||||
* registers, even if they're never used.
|
||||
* (It could probably be safely shrunk if you're not calling any variadic
|
||||
* functions, but be careful!)
|
||||
*
|
||||
* Offsets above that are private to the calling function and shouldn't
|
||||
* be messed with. Generally, what appears there is locals, then saved
|
||||
* registers.
|
||||
*
|
||||
*
|
||||
* The floating-point instruction set isn't implemented yet (I'm too
|
||||
* lazy, as I don't need it yet), but for when it is, the register
|
||||
* usage convention is:
|
||||
* FPSCR - Scratch, except for floating point exception enable fields,
|
||||
* which should only be modified by functions defined to do so.
|
||||
* fr0 - scratch
|
||||
* fr1 - first floating point parameter and return value, scratch
|
||||
* fr2 - second floating point parameter and return value (if needed), scratch
|
||||
* fr3 - third floating point parameter and return value (if needed), scratch
|
||||
* fr4 - fourth floating point parameter and return value (if needed), scratch
|
||||
* fr5-fr13 - More floating point argument registers, scratch
|
||||
* fr14-fr31 - Callee-save registers, may not be modified across a function call
|
||||
*
|
||||
* Complex values store the real part in the lower-numberd register of a pair.
|
||||
* When mixing floating-point and integer arguments, reserve space (one register
|
||||
* for single-precision, two for double-precision values) in the integer
|
||||
* argument list for the floating-point values. Those integer registers
|
||||
* generally have undefined values, UNLESS there is no prototype for the call,
|
||||
* in which case they should contain a copy of the floating-point value's
|
||||
* bit pattern to cope with wierd software.
|
||||
* If the floating point arguments go past the end of the integer registers,
|
||||
* they are stored in the argument area as well as being passed in here.
|
||||
*
|
||||
* After the argument area comes the calling function's private storage.
|
||||
* Typically, there are locals, followed by saved GP rgisters, followed
|
||||
* by saved FP registers.
|
||||
*
|
||||
* Suggested instruction for allocating a stack frame:
|
||||
* stwu r1,-frame_size(r1)
|
||||
* Suggested instructions for deallocating a stack frame:
|
||||
* addi r1,r1,frame_size
|
||||
* or
|
||||
* lwz r1,0(r1)
|
||||
* If frame_size is too big, you'll have to load the offset into a temp
|
||||
* register, but be sure that r1 is updated atomically.
|
||||
*
|
||||
*
|
||||
* Basic PowerPC instructions look like this:
|
||||
*
|
||||
* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Opcode | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* Branch instructions look like this:
|
||||
*
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Opcode | Branch offset |A|L|
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* The L, or LK, or Link bit indicates that the return address for the
|
||||
* branch should be copied to the link register (LR).
|
||||
* The A, or AA, or absolute address bit, indicates that the address
|
||||
* of the current instruction (NOTE: not next instruction!) should NOT
|
||||
* be added to the branch offset; it is relative to address 0.
|
||||
*
|
||||
* Conditional branches looks like this:
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Opcode | BO | BI | Branch offset |A|L|
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* The BI field specifies the condition bit of interest (from the CR).
|
||||
* The BO field specifies what's interesting. You can branch on a
|
||||
* combination of a bit of the condition register and --ctr, the CTR
|
||||
* register. Two bits encode the branch condition to use:
|
||||
* BRANCH IF
|
||||
* 00--- = Bit BI is 0
|
||||
* 01--- = Bit BI is 1
|
||||
* 1z--- = don't care about bit BI (always true)
|
||||
* AND
|
||||
* --00- = --ctr != 0
|
||||
* --01- = --ctr == 0
|
||||
* --1z- = don't decrement ctr (always true)
|
||||
* The last bit us used as a branch prediction bit. If set, it reverses
|
||||
* the usual backward-branch-taken heuristic.
|
||||
*
|
||||
* y = branch prediction bit. z = unused, must be 0
|
||||
* 0000y - branch if --ctr != 0 && BI == 0
|
||||
* don't branch if --ctr == 0 || BI != 0
|
||||
* 0001y - branch if --ctr == 0 && BI == 0
|
||||
* don't branch if --ctr != 0 || BI != 0
|
||||
* 001zy - branch if BI == 0
|
||||
* don't branch if BI != 0
|
||||
* 0100y - branch if --ctr != 0 && BI != 0
|
||||
* don't branch if --ctr == 0 || BI == 0
|
||||
* 0101y - branch if --ctr == 0 && BI != 0
|
||||
* don't branch if --ctr != 0 || BI == 0
|
||||
* 011zy - branch if BI != 0
|
||||
* don't branch if BI == 0
|
||||
* 1z00y - branch if --ctr != 0
|
||||
* don't branch if --ctr == 0
|
||||
* 1z01y - branch if --ctr == 0
|
||||
* don't branch if --ctr != 0
|
||||
* 1z1zz - branch always
|
||||
* If y is 1, the usual branch prediction (usually not taken, taken for
|
||||
* backwards branches with immediate offsets) is reversed.
|
||||
*
|
||||
* Instructions with 2 operands and a 16-bit immediate field look like this:
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Opcode | D | A | 16-bit immediate value |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* Now, there are three variations of note. In some instructions, the 16-bit
|
||||
* value is sign-extended. In others, it's zero-extended. These are noted
|
||||
* below as "simm" (signed immediate) and "uimm", respectively. Also, which
|
||||
* field is the destination and which is the source sometimes switches.
|
||||
* Sometimes it's d = a OP imm, and sometimes it's a = s OP imm. In the
|
||||
* latter cases, the "d" field is referred to as "s" ("source" instead of
|
||||
* "destination". These are logical and shift instructions. (Store also
|
||||
* refers to the s register, but that's the source of the value to be stored.)
|
||||
* The assembly mnemonics, however, always lists the destination first,
|
||||
* swapping the order in the instruction if necessary.
|
||||
* Third, quite often, if r0 is specified for the source a, then the constant
|
||||
* value 0 is used instead. Thus, r0 is of limited use - it can be used for
|
||||
* some things, but not all.
|
||||
*
|
||||
* Instructions with three register operands look like this:
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Opcode | D | A | B | Subopcode |C|
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* For most of the instructions of interest the Opcode is 31 and the subopcode
|
||||
* determines what the instruction does. For a few instructions (mostly loads
|
||||
* and stores), if the A field is 0, the constant 0 is used. The "C"
|
||||
* bit (also known as the "RC" bit) controls whether or not the condition
|
||||
* codes are updated. If it is set (indicated by a "." suffix on the official
|
||||
* PowerPC opcodes, and a "_" suffix on these macros), condition code register
|
||||
* field 0 (for integer instructions; field 1 for floating point) is updated
|
||||
* to reflect the result of the operation.
|
||||
* Some arithmetic instructions use the most significant bit of the subopcode
|
||||
* field as an overflow enable bit (o suffix).
|
||||
*
|
||||
* Then there are the rotate and mask instructions, which have 5 operands, and
|
||||
* fill the subopcode field with 2 more 5-bit fields. See below for them.
|
||||
*
|
||||
* NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
|
||||
* These macros fully parenthesize their arguments, but are not themselves
|
||||
* fully parenthesized. They are intended to be used for initializer lists,
|
||||
* and if you want to do tricks with their numeric values, wrap them in
|
||||
* parentheses.
|
||||
*/
|
||||
|
||||
#define PPC_MAJOR(x) ((x)<<26) /* Major opcode (0..63) */
|
||||
#define PPC_MINOR(x) ((x)<<1) /* Minor opcode (0..1023) */
|
||||
#define PPC_RC 1 /* Record carry (. suffix, represented as _) */
|
||||
#define PPC_OE 1024 /* Overflow enable (o suffix) */
|
||||
#define PPC_DEST(reg) ((reg)<<21) /* Dest register field */
|
||||
#define PPC_SRCA(reg) ((reg)<<16) /* First source register field */
|
||||
#define PPC_SRCB(reg) ((reg)<<11) /* Second source register field */
|
||||
#define PPC_AA 2 /* Branch is absolute, relative to address 0 */
|
||||
#define PPC_LK 1 /* Branch with link (L suffix) */
|
||||
|
||||
/* Unconditional branch (dest is 26 bits, +/- 2^25 bytes) */
|
||||
#define PPC_B(dest) PPC_MAJOR(18)|(((dest)<<2) & 0x03fffffc)
|
||||
#define PPC_BA(dest) PPC_B(dest)|PPC_AA
|
||||
#define PPC_BL(dest) PPC_B(dest)|PPC_LK
|
||||
#define PPC_BLA(dest) PPC_B(dest)|PPC_AA|PPC_LK
|
||||
|
||||
/* Three-operand instructions */
|
||||
#define PPC_TYPE31(minor,d,a,b) \
|
||||
PPC_MAJOR(31)|PPC_DEST(d)|PPC_SRCA(a)|PPC_SRCB(b)|PPC_MINOR(minor)
|
||||
#define PPC_ADD(d,a,b) PPC_TYPE31(266,d,a,b)
|
||||
#define PPC_ADD_(d,a,b) PPC_TYPE31(266,d,a,b)|PPC_RC
|
||||
#define PPC_ADDO(d,a,b) PPC_TYPE31(266,d,a,b)|PPC_OE
|
||||
#define PPC_ADDO_(d,a,b) PPC_TYPE31(266,d,a,b)|PPC_OE|PPC_RC
|
||||
#define PPC_ADDC(d,a,b) PPC_TYPE31(10,d,a,b)
|
||||
#define PPC_ADDC_(d,a,b) PPC_TYPE31(10,d,a,b)|PPC_RC
|
||||
#define PPC_ADDCO(d,a,b) PPC_TYPE31(10,d,a,b)|PPC_OE
|
||||
#define PPC_ADDCO_(d,a,b) PPC_TYPE31(10,d,a,b)|PPC_OE|PPC_RC
|
||||
#define PPC_ADDE(d,a,b) PPC_TYPE31(138,d,a,b)
|
||||
#define PPC_ADDE_(d,a,b) PPC_TYPE31(138,d,a,b)|PPC_RC
|
||||
#define PPC_ADDEO(d,a,b) PPC_TYPE31(138,d,a,b)|PPC_OE
|
||||
#define PPC_ADDEO_(d,a,b) PPC_TYPE31(138,d,a,b)|PPC_OE|PPC_RC
|
||||
#define PPC_ADDME(d,a) PPC_TYPE31(234,d,a,0)
|
||||
#define PPC_ADDME_(d,a) PPC_TYPE31(234,d,a,0)|PPC_RC
|
||||
#define PPC_ADDMEO(d,a) PPC_TYPE31(234,d,a,0)|PPC_OE
|
||||
#define PPC_ADDMEO_(d,a) PPC_TYPE31(234,d,a,0)|PPC_OE|PPC_RC
|
||||
#define PPC_ADDZE(d,a) PPC_TYPE31(202,d,a,0)
|
||||
#define PPC_ADDZE_(d,a) PPC_TYPE31(202,d,a,0)|PPC_RC
|
||||
#define PPC_ADDZEO(d,a) PPC_TYPE31(202,d,a,0)|PPC_OE
|
||||
#define PPC_ADDZEO_(d,a) PPC_TYPE31(202,d,a,0)|PPC_OE|PPC_RC
|
||||
#define PPC_AND(a,s,b) PPC_TYPE31(28,s,a,b)
|
||||
#define PPC_AND_(a,s,b) PPC_TYPE31(28,s,a,b)|PPC_RC
|
||||
#define PPC_ANDC(a,s,b) PPC_TYPE31(60,s,a,b)
|
||||
#define PPC_ANDC_(a,s,b) PPC_TYPE31(60,s,a,b)|PPC_RC
|
||||
#define PPC_CMP(cr,a,b) PPC_TYPE31(0,(cr)<<2,a,b)
|
||||
#define PPC_CMPL(cr,a,b) PPC_TYPE31(32,(cr)<<2,a,b)
|
||||
#define PPC_CNTLZW(a,s) PPC_TYPE31(26,s,a,0)
|
||||
#define PPC_CNTLZW_(a,s) PPC_TYPE31(26,s,a,0)|PPC_RC
|
||||
#define PPC_DCBF(a,b) PPC_TYPE31(86,0,a,b)
|
||||
#define PPC_DCBI(a,b) PPC_TYPE31(470,0,a,b)
|
||||
#define PPC_DCBST(a,b) PPC_TYPE31(54,0,a,b)
|
||||
#define PPC_DCBT(a,b) PPC_TYPE31(278,0,a,b)
|
||||
#define PPC_DCBTST(a,b) PPC_TYPE31(246,0,a,b)
|
||||
#define PPC_DCBZ(a,b) PPC_TYPE31(1014,0,a,b)
|
||||
#define PPC_DIVW(d,a,b) PPC_TYPE31(491,d,a,b)
|
||||
#define PPC_DIVW_(d,a,b) PPC_TYPE31(491,d,a,b)|PPC_RC
|
||||
#define PPC_DIVWO(d,a,b) PPC_TYPE31(491,d,a,b)|PPC_OE
|
||||
#define PPC_DIVWO_(d,a,b) PPC_TYPE31(491,d,a,b)|PPC_OE|PPC_RC
|
||||
#define PPC_DIVWU(d,a,b) PPC_TYPE31(459,d,a,b)
|
||||
#define PPC_DIVWU_(d,a,b) PPC_TYPE31(459,d,a,b)|PPC_RC
|
||||
#define PPC_DIVWUO(d,a,b) PPC_TYPE31(459,d,a,b)|PPC_OE
|
||||
#define PPC_DIVWUO_(d,a,b) PPC_TYPE31(459,d,a,b)|PPC_OE|PPC_RC
|
||||
#define PPC_EIEIO() PPC_TYPE31(854,0,0,0)
|
||||
#define PPC_EQV(a,s,b) PPC_TYPE31(284,s,a,b)
|
||||
#define PPC_EQV_(a,s,b) PPC_TYPE31(284,s,a,b)|PPC_RC
|
||||
#define PPC_EXTSB(a,s,b) PPC_TYPE31(954,s,a,b)
|
||||
#define PPC_EXTSB_(a,s,b) PPC_TYPE31(954,s,a,b)|PPC_RC
|
||||
#define PPC_EXTSH(a,s,b) PPC_TYPE31(922,s,a,b)
|
||||
#define PPC_EXTSH_(a,s,b) PPC_TYPE31(922,s,a,b)|PPC_RC
|
||||
#define PPC_ICBI(a,b) PPC_TYPE31(982,0,a,b)
|
||||
#define PPC_ISYNC() PPC_TYPE31(150,0,0,0)
|
||||
#define PPC_LBZUX(d,a,b) PPC_TYPE31(119,d,a,b)
|
||||
#define PPC_LBZX(d,a,b) PPC_TYPE31(87,d,a,b)
|
||||
#define PPC_LHAUX(d,a,b) PPC_TYPE31(375,d,a,b)
|
||||
#define PPC_LHAX(d,a,b) PPC_TYPE31(343,d,a,b)
|
||||
#define PPC_LHBRX(d,a,b) PPC_TYPE31(790,d,a,b)
|
||||
#define PPC_LHZUX(d,a,b) PPC_TYPE31(311,d,a,b)
|
||||
#define PPC_LHZX(d,a,b) PPC_TYPE31(279,d,a,b)
|
||||
#define PPC_LSWI(d,a,nb) PPC_TYPE31(597,d,a,nb)
|
||||
#define PPC_LSWX(d,a,b) PPC_TYPE31(533,d,a,b)
|
||||
#define PPC_LSARX(d,a,b) PPC_TYPE31(20,d,a,b)
|
||||
#define PPC_LSBRX(d,a,b) PPC_TYPE31(534,d,a,b)
|
||||
#define PPC_MCRXR(crd) PPC_TYPE31(512,(crd)<<2,0,0)
|
||||
#define PPC_MFCR(d) PPC_TYPE31(19,d,0,0)
|
||||
#define PPC_MFSPR(d,spr) PPC_TYPE31(339,d,(spr)&31,(spr)>>5)
|
||||
#define PPC_MFTB(d) PPC_TYPE31(371,d,12,8)
|
||||
#define PPC_MFTBU(d) PPC_TYPE31(371,d,13,8)
|
||||
#define PPC_MTCRF(mask,s) PPC_TYPE31(144,s,0,(mask)&0xff)
|
||||
#define PPC_MTSPR(s,spr) PPC_TYPE31(467,s,(spr)&31,(spr)>>5)
|
||||
#define PPC_MULHW(d,a,b) PPC_TYPE31(75,d,a,b)
|
||||
#define PPC_MULHW_(d,a,b) PPC_TYPE31(75,d,a,b)|PPC_RC
|
||||
#define PPC_MULHWU(d,a,b) PPC_TYPE31(11,d,a,b)
|
||||
#define PPC_MULHWU_(d,a,b) PPC_TYPE31(11,d,a,b)|PPC_RC
|
||||
#define PPC_MULLW(d,a,b) PPC_TYPE31(235,d,a,b)
|
||||
#define PPC_MULLW_(d,a,b) PPC_TYPE31(235,d,a,b)|PPC_RC
|
||||
#define PPC_MULLWO(d,a,b) PPC_TYPE31(235,d,a,b)|PPC_OE
|
||||
#define PPC_MULLWO_(d,a,b) PPC_TYPE31(235,d,a,b)|PPC_OE|PPC_RC
|
||||
#define PPC_NAND(a,s,b) PPC_TYPE31(476,s,a,b)
|
||||
#define PPC_NAND_(a,s,b) PPC_TYPE31(476,s,a,b)|PPC_RC
|
||||
#define PPC_NEG(d,a) PPC_TYPE31(104,d,a,b)
|
||||
#define PPC_NEG_(d,a) PPC_TYPE31(104,d,a,b)|PPC_RC
|
||||
#define PPC_NEGO(d,a) PPC_TYPE31(104,d,a,b)|PPC_OE
|
||||
#define PPC_NEGO_(d,a) PPC_TYPE31(104,d,a,b)|PPC_OE|PPC_RC
|
||||
#define PPC_NOR(a,s,b) PPC_TYPE31(124,s,a,b)
|
||||
#define PPC_NOR_(a,s,b) PPC_TYPE31(124,s,a,b)|PPC_RC
|
||||
#define PPC_OR(a,s,b) PPC_TYPE31(444,s,a,b)
|
||||
#define PPC_OR_(a,s,b) PPC_TYPE31(444,s,a,b)|PPC_RC
|
||||
#define PPC_ORC(a,s,b) PPC_TYPE31(412,s,a,b)
|
||||
#define PPC_ORC_(a,s,b) PPC_TYPE31(412,s,a,b)|PPC_RC
|
||||
#define PPC_SLW(a,s,b) PPC_TYPE31(24,s,a,b)
|
||||
#define PPC_SLW_(a,s,b) PPC_TYPE31(24,s,a,b)|PPC_RC
|
||||
#define PPC_SRAW(a,s,b) PPC_TYPE31(792,s,a,b)
|
||||
#define PPC_SRAW_(a,s,b) PPC_TYPE31(792,s,a,b)|PPC_RC
|
||||
#define PPC_SRAWI(a,s,sh) PPC_TYPE31(824,s,a,sh)
|
||||
#define PPC_SRAWI_(a,s,sh) PPC_TYPE31(824,s,a,sh)|PPC_RC
|
||||
#define PPC_SRW(a,s,b) PPC_TYPE31(536,s,a,b)
|
||||
#define PPC_SRW_(a,s,b) PPC_TYPE31(536,s,a,b)|PPC_RC
|
||||
#define PPC_STBUX(s,a,b) PPC_TYPE31(247,s,a,b)
|
||||
#define PPC_STBX(s,a,b) PPC_TYPE31(215,s,a,b)
|
||||
#define PPC_STHBRX(s,a,b) PPC_TYPE31(918,s,a,b)
|
||||
#define PPC_STHUX(s,a,b) PPC_TYPE31(439,s,a,b)
|
||||
#define PPC_STHX(s,a,b) PPC_TYPE31(407,s,a,b)
|
||||
#define PPC_STSWI(s,a,nb) PPC_TYPE31(725,s,a,nb)
|
||||
#define PPC_STSWX(s,a,b) PPC_TYPE31(661,s,a,b)
|
||||
#define PPC_STWBRX(s,a,b) PPC_TYPE31(662,s,a,b)
|
||||
#define PPC_STWCX_(s,a,b) PPC_TYPE31(150,s,a,b)|PPC_RC
|
||||
#define PPC_STWUX(s,a,b) PPC_TYPE31(183,s,a,b)
|
||||
#define PPC_STWX(s,a,b) PPC_TYPE31(151,s,a,b)
|
||||
#define PPC_SUBF(d,a,b) PPC_TYPE31(40,d,a,b)
|
||||
#define PPC_SUBF_(d,a,b) PPC_TYPE31(40,d,a,b)|PPC_RC
|
||||
#define PPC_SUBFO(d,a,b) PPC_TYPE31(40,d,a,b)|PPC_OE
|
||||
#define PPC_SUBFO_(d,a,b) PPC_TYPE31(40,d,a,b)|PPC_OE|PPC_RC
|
||||
#define PPC_SUB(d,b,a) PPC_SUBF(d,a,b)
|
||||
#define PPC_SUB_(d,b,a) PPC_SUBF_(d,a,b)
|
||||
#define PPC_SUBO(d,b,a) PPC_SUBFO(d,a,b)
|
||||
#define PPC_SUBO_(d,b,a) PPC_SUBFO_(d,a,b)
|
||||
#define PPC_SUBFC(d,a,b) PPC_TYPE31(8,d,a,b)
|
||||
#define PPC_SUBFC_(d,a,b) PPC_TYPE31(8,d,a,b)|PPC_RC
|
||||
#define PPC_SUBFCO(d,a,b) PPC_TYPE31(8,d,a,b)|PPC_OE
|
||||
#define PPC_SUBFCO_(d,a,b) PPC_TYPE31(8,d,a,b)|PPC_OE|PPC_RC
|
||||
#define PPC_SUBFE(d,a,b) PPC_TYPE31(136,d,a,b)
|
||||
#define PPC_SUBFE_(d,a,b) PPC_TYPE31(136,d,a,b)|PPC_RC
|
||||
#define PPC_SUBFEO(d,a,b) PPC_TYPE31(136,d,a,b)|PPC_OE
|
||||
#define PPC_SUBFEO_(d,a,b) PPC_TYPE31(136,d,a,b)|PPC_OE|PPC_RC
|
||||
#define PPC_SUBFME(d,a) PPC_TYPE31(232,d,a,0)
|
||||
#define PPC_SUBFME_(d,a) PPC_TYPE31(232,d,a,0)|PPC_RC
|
||||
#define PPC_SUBFMEO(d,a) PPC_TYPE31(232,d,a,0)|PPC_OE
|
||||
#define PPC_SUBFMEO_(d,a) PPC_TYPE31(232,d,a,0)|PPC_OE|PPC_RC
|
||||
#define PPC_SUBFZE(d,a) PPC_TYPE31(200,d,a,0)
|
||||
#define PPC_SUBFZE_(d,a) PPC_TYPE31(200,d,a,0)|PPC_RC
|
||||
#define PPC_SUBFZEO(d,a) PPC_TYPE31(200,d,a,0)|PPC_OE
|
||||
#define PPC_SUBFZEO_(d,a) PPC_TYPE31(200,d,a,0)|PPC_OE|PPC_RC
|
||||
#define PPC_SYNC() PPC_TYPE31(598,0,0,0)
|
||||
#define PPC_TW(to,a,b) PPC_TYPE31(4,to,a,b)
|
||||
#define PPC_XOR(a,s,b) PPC_TYPE31(316,s,a,b)
|
||||
|
||||
/* Immediate-operand instructions. Take a 16-bit immediate operand */
|
||||
#define PPC_IMM(major,d,a,imm) \
|
||||
PPC_MAJOR(major)|PPC_DEST(d)|PPC_SRCA(a)|((imm)&0xffff)
|
||||
/* Trap word immediate */
|
||||
#define PPV_TWI(to,a,simm) PPC_IMM(3,to,a,simm)
|
||||
/* Integer arithmetic */
|
||||
#define PPC_MULLI(d,a,simm) PPC_IMM(7,d,a,simm)
|
||||
#define PPC_SUBFIC(s,a,simm) PPC_IMM(8,s,a,simm)
|
||||
#define PPC_CMPLI(cr,a,uimm) PPC_IMM(10,(cr)<<2,a,uimm)
|
||||
#define PPC_CMPI(cr,a,simm) PPC_IMM(11,(cr)<<2,a,simm)
|
||||
#define PPC_ADDIC(d,a,simm) PPC_IMM(12,d,a,simm)
|
||||
#define PPC_ADDIC_(d,a,simm) PPC_IMM(13,d,a,simm)
|
||||
#define PPC_ADDI(d,a,simm) PPC_IMM(14,d,a,simm)
|
||||
#define PPC_ADDIS(d,a,simm) PPC_IMM(15,d,a,simm)
|
||||
|
||||
/* Conditional branch (dest is 16 bits, +/- 2^15 bytes) */
|
||||
#define PPC_BC(bo,bi,dest) PPC_IMM(16,bo,bi,((dest)<<2)&0xfffc)
|
||||
#define PPC_BCA(bo,bi,dest) PPC_BC(bo,bi,dest)|PPC_AA
|
||||
#define PPC_BCL(bo,bi,dest) PPC_BC(bo,bi,dest)|PPC_LK
|
||||
#define PPC_BCLA(bo,bi,dest) PPC_BC(bo,bi,dest)|PPC_AA|PPC_LK
|
||||
|
||||
/* Logical operations */
|
||||
#define PPC_ORI(a,s,uimm) PPC_IMM(24,s,a,uimm)
|
||||
#define PPC_ORIS(a,s,uimm) PPC_IMM(25,s,a,uimm)
|
||||
#define PPC_XORI(a,s,uimm) PPC_IMM(26,s,a,uimm)
|
||||
#define PPC_XORIS(a,s,uimm) PPC_IMM(27,s,a,uimm)
|
||||
#define PPC_ANDI_(a,s,uimm) PPC_IMM(28,s,a,uimm)
|
||||
#define PPC_ANDIS(a,s,uimm) PPC_IMM(29,s,a,uimm)
|
||||
|
||||
/* Load/store */
|
||||
#define PPC_LWZ(d,a,simm) PPC_IMM(32,d,a,simm)
|
||||
#define PPC_LWZU(d,a,simm) PPC_IMM(33,d,a,simm)
|
||||
#define PPC_LBZ(d,a,simm) PPC_IMM(34,d,a,simm)
|
||||
#define PPC_LBZU(d,a,simm) PPC_IMM(35,d,a,simm)
|
||||
#define PPC_STW(s,a,simm) PPC_IMM(36,s,a,simm)
|
||||
#define PPC_STWU(s,a,simm) PPC_IMM(37,s,a,simm)
|
||||
#define PPC_STB(s,a,simm) PPC_IMM(38,s,a,simm)
|
||||
#define PPC_STBU(s,a,simm) PPC_IMM(39,s,a,simm)
|
||||
#define PPC_LHZ(d,a,simm) PPC_IMM(40,d,a,simm)
|
||||
#define PPC_LHZU(d,a,simm) PPC_IMM(41,d,a,simm)
|
||||
#define PPC_LHA(d,a,simm) PPC_IMM(42,d,a,simm)
|
||||
#define PPC_STH(s,a,simm) PPC_IMM(44,s,a,simm)
|
||||
#define PPC_STHU(s,a,simm) PPC_IMM(45,s,a,simm)
|
||||
#define PPC_LHAU(d,a,simm) PPC_IMM(43,d,a,simm)
|
||||
#define PPC_LMW(d,a,simm) PPC_IMM(46,d,a,simm)
|
||||
#define PPC_STMW(s,a,simm) PPC_IMM(47,s,a,simm)
|
||||
|
||||
/* Major number = 19 - condition register operations. d, a and b are CR bits */
|
||||
#define PPC_TYPE19(minor,d,a,b) \
|
||||
PPC_MAJOR(19)|PPC_DEST(d)|PPC_SRCA(a)|PPC_SRCB(b)|PPC_MINOR(minor)
|
||||
#define PPC_MCRF(d,s) PPC_TYPE19(0,(d)<<2,(s)<<2,0)
|
||||
#define PPC_CRNOR(d,a,b) PPC_TYPE19(33,d,a,b)
|
||||
#define PPC_CRANDC(d,a,b) PPC_TYPE19(129,d,a,b)
|
||||
#define PPC_CRXOR(d,a,b) PPC_TYPE19(193,d,a,b)
|
||||
#define PPC_CRNAND(d,a,b) PPC_TYPE19(225,d,a,b)
|
||||
#define PPC_CRAND(d,a,b) PPC_TYPE19(257,d,a,b)
|
||||
#define PPC_CREQV(d,a,b) PPC_TYPE19(289,d,a,b)
|
||||
#define PPC_CRORC(d,a,b) PPC_TYPE19(417,d,a,b)
|
||||
#define PPC_CROR(d,a,b) PPC_TYPE19(449,d,a,b)
|
||||
|
||||
/* Indirect conditional branch */
|
||||
#define PPC_BCLR(bo,bi) PPC_TYPE19(16,bo,bi,0)
|
||||
#define PPC_BCLRL(bo,bi) PPC_TYPE19(16,bo,bi,0)|PPC_LK
|
||||
#define PPC_BCCTR(bo,bi) PPC_TYPE19(528,bo,bi,0)
|
||||
#define PPC_BCCTRL(bo,bi) PPC_TYPE19(528,bo,bi,0)|PPC_LK
|
||||
#define PPC_BLR() PPC_BCLR(20,31)
|
||||
#define PPC_BCTR() PPC_BCCTR(20,31)
|
||||
|
||||
/* Other */
|
||||
#define PPC_RLWIMI(a,s,sh,mb,me) \
|
||||
PPC_MAJOR(20)|PPC_DEST(s)|PPC_SRCA(A)|PPC_SRCB(sh)|(mb)<<6|(me)<<1
|
||||
#define PPC_RLWIMI_(a,s,sh,mb,me) PPC_RLWIMI(a,s,sh,mb,me)|PPC_RC
|
||||
#define PPC_RLWINM(a,s,sh,mb,me) \
|
||||
PPC_MAJOR(21)|PPC_DEST(s)|PPC_SRCA(A)|PPC_SRCB(sh)|(mb)<<6|(me)<<1
|
||||
#define PPC_RLWINM_(a,s,sh,mb,me) PPC_RLWINM(a,s,sh,mb,me)|PPC_RC
|
||||
#define PPC_RLWNM(a,s,b,mb,me) \
|
||||
PPC_MAJOR(23)|PPC_DEST(s)|PPC_SRCA(A)|PPC_SRCB(b)|(mb)<<6|(me)<<1
|
||||
#define PPC_RLWNM_(a,s,b,mb,me) PPC_RLWNM(a,s,b,mb,me)|PPC_RC
|
||||
|
||||
#define PPC_SC() PPC_MAJOR(17)|2
|
||||
/* Major number = 63 Floating-point operations (not implemented for now) */
|
||||
|
||||
/* Simplified Mnemonics */
|
||||
/* Fabricate immediate subtract out of add negative */
|
||||
#define PPC_SUBI(d,a,simm) PPC_ADDI(d,a,-(simm))
|
||||
#define PPC_SUBIS(d,a,simm) PPC_ADDIS(d,a,-(simm))
|
||||
#define PPC_SUBIC(d,a,simm) PPC_ADDIC(d,a,-(simm))
|
||||
#define PPC_SUBIC_(d,a,simm) PPC_ADDIC_(d,a,-(simm))
|
||||
/* Fabricate subtract out of subtract from */
|
||||
#define PPC_SUBC(d,b,a) PPC_SUBFC(d,a,b)
|
||||
#define PPC_SUBC_(d,b,a) PPC_SUBFC_(d,a,b)
|
||||
#define PPC_SUBCO(d,b,a) PPC_SUBFCO(d,a,b)
|
||||
#define PPC_SUBCO_(d,b,a) PPC_SUBFCO_(d,a,b)
|
||||
/* Messy compare bits omitted */
|
||||
/* Shift and rotate omitted */
|
||||
/* Branch coding omitted */
|
||||
#define PPC_CRSET(d) PPC_CREQV(d,d,d)
|
||||
#define PPC_CRCLR(d) PPC_CRXOR(d,d,d)
|
||||
#define PPC_CRMOVE(d,s) PPC_CROR(d,s,s)
|
||||
#define PPC_CRNOT(d,s) PPC_CRNOR(d,s,s)
|
||||
/* Trap menmonics omitted */
|
||||
/* Menmonics for user-accessible SPRs */
|
||||
#define PPC_MFXER(d) PPC_MFSPR(d,1)
|
||||
#define PPC_MFLR(d) PPC_MFSPR(d,8)
|
||||
#define PPC_MFCTR(d) PPC_MFSPR(d,9)
|
||||
#define PPC_MTXER(s) PPC_MTSPR(s,1)
|
||||
#define PPC_MTLR(s) PPC_MTSPR(s,8)
|
||||
#define PPC_MTCTR(s) PPC_MTSPR(s,9)
|
||||
/* Recommended mnemonics */
|
||||
#define PPC_NOP() PPC_ORI(0,0,0)
|
||||
#define PPC_LI(d,simm) PPC_ADDI(d,0,simm)
|
||||
#define PPC_LIS(d,simm) PPC_ADDIS(d,0,simm)
|
||||
#define PPC_LA(d,a,simm) PPC_ADDI(d,a,simm)
|
||||
#define PPC_MR(d,s) PPC_OR(d,s,s)
|
||||
#define PPC_NOT(d,s) PPC_NOR(d,s,s)
|
||||
#define PPC_MTCR(s) PPC_MTCRF(0xff,s)
|
||||
|
||||
#endif /* PPCASM_H */
|
||||
|
||||
/* 45678901234567890123456789012345678901234567890123456789012345678901234567 */
|
||||
+679
@@ -0,0 +1,679 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* Prime generation using the bignum library and sieving.
|
||||
*/
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_ASSERT_H
|
||||
#define NO_ASSERT_H 0
|
||||
#endif
|
||||
#if !NO_ASSERT_H
|
||||
#include <assert.h>
|
||||
#else
|
||||
#define assert(x) (void)0
|
||||
#endif
|
||||
|
||||
#include <stdarg.h> /* We just can't live without this... */
|
||||
|
||||
#ifndef BNDEBUG
|
||||
#define BNDEBUG 1
|
||||
#endif
|
||||
#if BNDEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "bn.h"
|
||||
#include "lbnmem.h"
|
||||
#include "prime.h"
|
||||
#include "sieve.h"
|
||||
|
||||
#include "kludge.h"
|
||||
|
||||
/* Size of the shuffle table */
|
||||
#define SHUFFLE 256
|
||||
/* Size of the sieve area */
|
||||
#define SIEVE 32768u/16
|
||||
|
||||
/* Confirmation tests. The first one *must* be 2 */
|
||||
static unsigned const confirm[] = {2, 3, 5, 7, 11, 13, 17};
|
||||
#define CONFIRMTESTS (sizeof(confirm)/sizeof(*confirm))
|
||||
|
||||
/*
|
||||
* Helper function that does the slow primality test.
|
||||
* bn is the input bignum; a and e are temporary buffers that are
|
||||
* allocated by the caller to save overhead.
|
||||
*
|
||||
* Returns 0 if prime, >0 if not prime, and -1 on error (out of memory).
|
||||
* If not prime, returns the number of modular exponentiations performed.
|
||||
* Calls the given progress function with a '*' for each primality test
|
||||
* that is passed.
|
||||
*
|
||||
* The testing consists of strong pseudoprimality tests, to the bases given
|
||||
* in the confirm[] array above. (Also called Miller-Rabin, although that's
|
||||
* not technically correct if we're using fixed bases.) Some people worry
|
||||
* that this might not be enough. Number theorists may wish to generate
|
||||
* primality proofs, but for random inputs, this returns non-primes with
|
||||
* a probability which is quite negligible, which is good enough.
|
||||
*
|
||||
* It has been proved (see Carl Pomerance, "On the Distribution of
|
||||
* Pseudoprimes", Math. Comp. v.37 (1981) pp. 587-593) that the number of
|
||||
* pseudoprimes (composite numbers that pass a Fermat test to the base 2)
|
||||
* less than x is bounded by:
|
||||
* exp(ln(x)^(5/14)) <= P_2(x) ### CHECK THIS FORMULA - it looks wrong! ###
|
||||
* P_2(x) <= x * exp(-1/2 * ln(x) * ln(ln(ln(x))) / ln(ln(x))).
|
||||
* Thus, the local density of Pseudoprimes near x is at most
|
||||
* exp(-1/2 * ln(x) * ln(ln(ln(x))) / ln(ln(x))), and at least
|
||||
* exp(ln(x)^(5/14) - ln(x)). Here are some values of this function
|
||||
* for various k-bit numbers x = 2^k:
|
||||
* Bits Density <= Bit equivalent Density >= Bit equivalent
|
||||
* 128 3.577869e-07 21.414396 4.202213e-37 120.840190
|
||||
* 192 4.175629e-10 31.157288 4.936250e-56 183.724558
|
||||
* 256 5.804314e-13 40.647940 4.977813e-75 246.829095
|
||||
* 384 1.578039e-18 59.136573 3.938861e-113 373.400096
|
||||
* 512 5.858255e-24 77.175803 2.563353e-151 500.253110
|
||||
* 768 1.489276e-34 112.370944 7.872825e-228 754.422724
|
||||
* 1024 6.633188e-45 146.757062 1.882404e-304 1008.953565
|
||||
*
|
||||
* As you can see, there's quite a bit of slop between these estimates.
|
||||
* In fact, the density of pseudoprimes is conjectured to be closer to the
|
||||
* square of that upper bound. E.g. the density of pseudoprimes of size
|
||||
* 256 is around 3 * 10^-27. The density of primes is very high, from
|
||||
* 0.005636 at 256 bits to 0.001409 at 1024 bits, i.e. more than 10^-3.
|
||||
*
|
||||
* For those people used to cryptographic levels of security where the
|
||||
* 56 bits of DES key space is too small because it's exhaustible with
|
||||
* custom hardware searching engines, note that you are not generating
|
||||
* 50,000,000 primes per second on each of 56,000 custom hardware chips
|
||||
* for several hours. The chances that another Dinosaur Killer asteroid
|
||||
* will land today is about 10^-11 or 2^-36, so it would be better to
|
||||
* spend your time worrying about *that*. Well, okay, there should be
|
||||
* some derating for the chance that astronomers haven't seen it yet,
|
||||
* but I think you get the idea. For a good feel about the probability
|
||||
* of various events, I have heard that a good book is by E'mile Borel,
|
||||
* "Les Probabilite's et la vie". (The 's are accents, not apostrophes.)
|
||||
*
|
||||
* For more on the subject, try "Finding Four Million Large Random Primes",
|
||||
* by Ronald Rivest, in Advancess in Cryptology: Proceedings of Crypto
|
||||
* '90. He used a small-divisor test, then a Fermat test to the base 2,
|
||||
* and then 8 iterations of a Miller-Rabin test. About 718 million random
|
||||
* 256-bit integers were generated, 43,741,404 passed the small divisor
|
||||
* test, 4,058,000 passed the Fermat test, and all 4,058,000 passed all
|
||||
* 8 iterations of the Miller-Rabin test, proving their primality beyond
|
||||
* most reasonable doubts.
|
||||
*
|
||||
* If the probability of getting a pseudoprime is some small p, then the
|
||||
* probability of not getting it in t trials is (1-p)^t. Remember that,
|
||||
* for small p, (1-p)^(1/p) ~ 1/e, the base of natural logarithms.
|
||||
* (This is more commonly expressed as e = lim_{x\to\infty} (1+1/x)^x.)
|
||||
* Thus, (1-p)^t ~ e^(-p*t) = exp(-p*t). So the odds of being able to
|
||||
* do this many tests without seeing a pseudoprime if you assume that
|
||||
* p = 10^-6 (one in a million) is one in 57.86. If you assume that
|
||||
* p = 2*10^-6, it's one in 3347.6. So it's implausible that the density
|
||||
* of pseudoprimes is much more than one millionth the density of primes.
|
||||
*
|
||||
* He also gives a theoretical argument that the chance of finding a
|
||||
* 256-bit non-prime which satisfies one Fermat test to the base 2 is
|
||||
* less than 10^-22. The small divisor test improves this number, and
|
||||
* if the numbers are 512 bits (as needed for a 1024-bit key) the odds
|
||||
* of failure shrink to about 10^-44. Thus, he concludes, for practical
|
||||
* purposes *one* Fermat test to the base 2 is sufficient.
|
||||
*/
|
||||
static int
|
||||
primeTest(struct BigNum const *bn, struct BigNum *e, struct BigNum *a,
|
||||
int (*f)(void *arg, int c), void *arg)
|
||||
{
|
||||
unsigned i, j;
|
||||
unsigned k, l;
|
||||
int err;
|
||||
|
||||
#if BNDEBUG /* Debugging */
|
||||
/*
|
||||
* This is debugging code to test the sieving stage.
|
||||
* If the sieving is wrong, it will let past numbers with
|
||||
* small divisors. The prime test here will still work, and
|
||||
* weed them out, but you'll be doing a lot more slow tests,
|
||||
* and presumably excluding from consideration some other numbers
|
||||
* which might be prime. This check just verifies that none
|
||||
* of the candidates have any small divisors. If this
|
||||
* code is enabled and never triggers, you can feel quite
|
||||
* confident that the sieving is doing its job.
|
||||
*/
|
||||
i = bnLSWord(bn);
|
||||
if (!(i % 2)) printf("bn div by 2!");
|
||||
i = bnModQ(bn, 51051); /* 51051 = 3 * 7 * 11 * 13 * 17 */
|
||||
if (!(i % 3)) printf("bn div by 3!");
|
||||
if (!(i % 7)) printf("bn div by 7!");
|
||||
if (!(i % 11)) printf("bn div by 11!");
|
||||
if (!(i % 13)) printf("bn div by 13!");
|
||||
if (!(i % 17)) printf("bn div by 17!");
|
||||
i = bnModQ(bn, 63365); /* 63365 = 5 * 19 * 23 * 29 */
|
||||
if (!(i % 5)) printf("bn div by 5!");
|
||||
if (!(i % 19)) printf("bn div by 19!");
|
||||
if (!(i % 23)) printf("bn div by 23!");
|
||||
if (!(i % 29)) printf("bn div by 29!");
|
||||
i = bnModQ(bn, 47027); /* 47027 = 31 * 37 * 41 */
|
||||
if (!(i % 31)) printf("bn div by 31!");
|
||||
if (!(i % 37)) printf("bn div by 37!");
|
||||
if (!(i % 41)) printf("bn div by 41!");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now, check that bn is prime. If it passes to the base 2,
|
||||
* it's prime beyond all reasonable doubt, and everything else
|
||||
* is just gravy, but it gives people warm fuzzies to do it.
|
||||
*
|
||||
* This starts with verifying Euler's criterion for a base of 2.
|
||||
* This is the fastest pseudoprimality test that I know of,
|
||||
* saving a modular squaring over a Fermat test, as well as
|
||||
* being stronger. 7/8 of the time, it's as strong as a strong
|
||||
* pseudoprimality test, too. (The exception being when bn ==
|
||||
* 1 mod 8 and 2 is a quartic residue, i.e. bn is of the form
|
||||
* a^2 + (8*b)^2.) The precise series of tricks used here is
|
||||
* not documented anywhere, so here's an explanation.
|
||||
* Euler's criterion states that if p is prime then a^((p-1)/2)
|
||||
* is congruent to Jacobi(a,p), modulo p. Jacobi(a,p) is
|
||||
* a function which is +1 if a is a square modulo p, and -1 if
|
||||
* it is not. For a = 2, this is particularly simple. It's
|
||||
* +1 if p == +/-1 (mod 8), and -1 if m == +/-3 (mod 8).
|
||||
* If p == 3 mod 4, then all a strong test does is compute
|
||||
* 2^((p-1)/2). and see if it's +1 or -1. (Euler's criterion
|
||||
* says *which* it should be.) If p == 5 (mod 8), then
|
||||
* 2^((p-1)/2) is -1, so the initial step in a strong test,
|
||||
* looking at 2^((p-1)/4), is wasted - you're not going to
|
||||
* find a +/-1 before then if it *is* prime, and it shouldn't
|
||||
* have either of those values if it isn't. So don't bother.
|
||||
*
|
||||
* The remaining case is p == 1 (mod 8). In this case, we
|
||||
* expect 2^((p-1)/2) == 1 (mod p), so we expect that the
|
||||
* square root of this, 2^((p-1)/4), will be +/-1 (mod p).
|
||||
* Evaluating this saves us a modular squaring 1/4 of the time.
|
||||
* If it's -1, a strong pseudoprimality test would call p
|
||||
* prime as well. Only if the result is +1, indicating that
|
||||
* 2 is not only a quadratic residue, but a quartic one as well,
|
||||
* does a strong pseudoprimality test verify more things than
|
||||
* this test does. Good enough.
|
||||
*
|
||||
* We could back that down another step, looking at 2^((p-1)/8)
|
||||
* if there was a cheap way to determine if 2 were expected to
|
||||
* be a quartic residue or not. Dirichlet proved that 2 is
|
||||
* a quartic residue iff p is of the form a^2 + (8*b^2).
|
||||
* All primes == 1 (mod 4) can be expressed as a^2 + (2*b)^2,
|
||||
* but I see no cheap way to evaluate this condition.
|
||||
*/
|
||||
if (bnCopy(e, bn) < 0)
|
||||
return -1;
|
||||
(void)bnSubQ(e, 1);
|
||||
l = bnLSWord(e);
|
||||
|
||||
j = 1; /* Where to start in prime array for strong prime tests */
|
||||
|
||||
if (l & 7) {
|
||||
bnRShift(e, 1);
|
||||
if (bnTwoExpMod(a, e, bn) < 0)
|
||||
return -1;
|
||||
if ((l & 7) == 6) {
|
||||
/* bn == 7 mod 8, expect +1 */
|
||||
if (bnBits(a) != 1)
|
||||
return 1; /* Not prime */
|
||||
k = 1;
|
||||
} else {
|
||||
/* bn == 3 or 5 mod 8, expect -1 == bn-1 */
|
||||
if (bnAddQ(a, 1) < 0)
|
||||
return -1;
|
||||
if (bnCmp(a, bn) != 0)
|
||||
return 1; /* Not prime */
|
||||
k = 1;
|
||||
if (l & 4) {
|
||||
/* bn == 5 mod 8, make odd for strong tests */
|
||||
bnRShift(e, 1);
|
||||
k = 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* bn == 1 mod 8, expect 2^((bn-1)/4) == +/-1 mod bn */
|
||||
bnRShift(e, 2);
|
||||
if (bnTwoExpMod(a, e, bn) < 0)
|
||||
return -1;
|
||||
if (bnBits(a) == 1) {
|
||||
j = 0; /* Re-do strong prime test to base 2 */
|
||||
} else {
|
||||
if (bnAddQ(a, 1) < 0)
|
||||
return -1;
|
||||
if (bnCmp(a, bn) != 0)
|
||||
return 1; /* Not prime */
|
||||
}
|
||||
k = 2 + bnMakeOdd(e);
|
||||
}
|
||||
/* It's prime! Now go on to confirmation tests */
|
||||
|
||||
/*
|
||||
* Now, e = (bn-1)/2^k is odd. k >= 1, and has a given value
|
||||
* with probability 2^-k, so its expected value is 2.
|
||||
* j = 1 in the usual case when the previous test was as good as
|
||||
* a strong prime test, but 1/8 of the time, j = 0 because
|
||||
* the strong prime test to the base 2 needs to be re-done.
|
||||
*/
|
||||
for (i = j; i < CONFIRMTESTS; i++) {
|
||||
if (f && (err = f(arg, '*')) < 0)
|
||||
return err;
|
||||
(void)bnSetQ(a, confirm[i]);
|
||||
if (bnExpMod(a, a, e, bn) < 0)
|
||||
return -1;
|
||||
if (bnBits(a) == 1)
|
||||
continue; /* Passed this test */
|
||||
|
||||
l = k;
|
||||
for (;;) {
|
||||
if (bnAddQ(a, 1) < 0)
|
||||
return -1;
|
||||
if (bnCmp(a, bn) == 0) /* Was result bn-1? */
|
||||
break; /* Prime */
|
||||
if (!--l) /* Reached end, not -1? luck? */
|
||||
return i+2-j; /* Failed, not prime */
|
||||
/* This portion is executed, on average, once. */
|
||||
(void)bnSubQ(a, 1); /* Put a back where it was. */
|
||||
if (bnSquare(a, a) < 0 || bnMod(a, a, bn) < 0)
|
||||
return -1;
|
||||
if (bnBits(a) == 1)
|
||||
return i+2-j; /* Failed, not prime */
|
||||
}
|
||||
/* It worked (to the base confirm[i]) */
|
||||
}
|
||||
|
||||
/* Yes, we've decided that it's prime. */
|
||||
if (f && (err = f(arg, '*')) < 0)
|
||||
return err;
|
||||
return 0; /* Prime! */
|
||||
}
|
||||
|
||||
/*
|
||||
* Add x*y to bn, which is usually (but not always) < 65536.
|
||||
* Do it in a simple linear manner.
|
||||
*/
|
||||
static int
|
||||
bnAddMult(struct BigNum *bn, unsigned x, unsigned y)
|
||||
{
|
||||
unsigned long z = (unsigned long)x * y;
|
||||
|
||||
while (z > 65535) {
|
||||
if (bnAddQ(bn, 65535) < 0)
|
||||
return -1;
|
||||
z -= 65535;
|
||||
}
|
||||
return bnAddQ(bn, (unsigned)z);
|
||||
}
|
||||
|
||||
static int
|
||||
bnSubMult(struct BigNum *bn, unsigned x, unsigned y)
|
||||
{
|
||||
unsigned long z = (unsigned long)x * y;
|
||||
|
||||
while (z > 65535) {
|
||||
if (bnSubQ(bn, 65535) < 0)
|
||||
return -1;
|
||||
z -= 65535;
|
||||
}
|
||||
return bnSubQ(bn, (unsigned)z);
|
||||
}
|
||||
|
||||
/*
|
||||
* Modifies the bignum to return a nearby (slightly larger) number which
|
||||
* is a probable prime. Returns >=0 on success or -1 on failure (out of
|
||||
* memory). The return value is the number of unsuccessful modular
|
||||
* exponentiations performed. This never gives up searching.
|
||||
*
|
||||
* All other arguments are optional. They may be NULL. They are:
|
||||
*
|
||||
* unsigned (*rand)(unsigned limit)
|
||||
* For better distributed numbers, supply a non-null pointer to a
|
||||
* function which returns a random x, 0 <= x < limit. (It may make it
|
||||
* simpler to know that 0 < limit <= SHUFFLE, so you need at most a byte.)
|
||||
* The program generates a large window of sieve data and then does
|
||||
* pseudoprimality tests on the data. If a rand function is supplied,
|
||||
* the candidates which survive sieving are shuffled with a window of
|
||||
* size SHUFFLE before testing to increase the uniformity of the prime
|
||||
* selection. This isn't perfect, but it reduces the correlation between
|
||||
* the size of the prime-free gap before a prime and the probability
|
||||
* that that prime will be found by a sequential search.
|
||||
*
|
||||
* If rand is NULL, sequential search is used. If you want sequential
|
||||
* search, note that the search begins with the given number; if you're
|
||||
* trying to generate consecutive primes, you must increment the previous
|
||||
* one by two before calling this again.
|
||||
*
|
||||
* int (*f)(void *arg, int c), void *arg
|
||||
* The function f argument, if non-NULL, is called with progress indicator
|
||||
* characters for printing. A dot (.) is written every time a primality test
|
||||
* is failed, a star (*) every time one is passed, and a slash (/) in the
|
||||
* (very rare) case that the sieve was emptied without finding a prime
|
||||
* and is being refilled. f is also passed the void *arg argument for
|
||||
* private context storage. If f returns < 0, the test aborts and returns
|
||||
* that value immediately. (bn is set to the last value tested, so you
|
||||
* can increment bn and continue.)
|
||||
*
|
||||
* The "exponent" argument, and following unsigned numbers, are exponents
|
||||
* for which an inverse is desired, modulo p. For a d to exist such that
|
||||
* (x^e)^d == x (mod p), then d*e == 1 (mod p-1), so gcd(e,p-1) must be 1.
|
||||
* The prime returned is constrained to not be congruent to 1 modulo
|
||||
* any of the zero-terminated list of 16-bit numbers. Note that this list
|
||||
* should contain all the small prime factors of e. (You'll have to test
|
||||
* for large prime factors of e elsewhere, but the chances of needing to
|
||||
* generate another prime are low.)
|
||||
*
|
||||
* The list is terminated by a 0, and may be empty.
|
||||
*/
|
||||
int
|
||||
primeGen(struct BigNum *bn, unsigned (*rand)(unsigned),
|
||||
int (*f)(void *arg, int c), void *arg, unsigned exponent, ...)
|
||||
{
|
||||
int retval;
|
||||
int modexps = 0;
|
||||
unsigned short offsets[SHUFFLE];
|
||||
unsigned i, j;
|
||||
unsigned p, q, prev;
|
||||
struct BigNum a, e;
|
||||
#ifdef MSDOS
|
||||
unsigned char *sieve;
|
||||
#else
|
||||
unsigned char sieve[SIEVE];
|
||||
#endif
|
||||
|
||||
#ifdef MSDOS
|
||||
sieve = lbnMemAlloc(SIEVE);
|
||||
if (!sieve)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
bnBegin(&a);
|
||||
bnBegin(&e);
|
||||
|
||||
#if 0 /* Self-test (not used for production) */
|
||||
{
|
||||
struct BigNum t;
|
||||
static unsigned char const prime1[] = {5};
|
||||
static unsigned char const prime2[] = {7};
|
||||
static unsigned char const prime3[] = {11};
|
||||
static unsigned char const prime4[] = {1, 1}; /* 257 */
|
||||
static unsigned char const prime5[] = {0xFF, 0xF1}; /* 65521 */
|
||||
static unsigned char const prime6[] = {1, 0, 1}; /* 65537 */
|
||||
static unsigned char const prime7[] = {1, 0, 3}; /* 65539 */
|
||||
/* A small prime: 1234567891 */
|
||||
static unsigned char const prime8[] = {0x49, 0x96, 0x02, 0xD3};
|
||||
/* A slightly larger prime: 12345678901234567891 */
|
||||
static unsigned char const prime9[] = {
|
||||
0xAB, 0x54, 0xA9, 0x8C, 0xEB, 0x1F, 0x0A, 0xD3 };
|
||||
/*
|
||||
* No, 123456789012345678901234567891 isn't prime; it's just a
|
||||
* lucky, easy-to-remember conicidence. (You have to go to
|
||||
* ...4567907 for a prime.)
|
||||
*/
|
||||
static struct {
|
||||
unsigned char const *prime;
|
||||
unsigned size;
|
||||
} const primelist[] = {
|
||||
{ prime1, sizeof(prime1) },
|
||||
{ prime2, sizeof(prime2) },
|
||||
{ prime3, sizeof(prime3) },
|
||||
{ prime4, sizeof(prime4) },
|
||||
{ prime5, sizeof(prime5) },
|
||||
{ prime6, sizeof(prime6) },
|
||||
{ prime7, sizeof(prime7) },
|
||||
{ prime8, sizeof(prime8) },
|
||||
{ prime9, sizeof(prime9) } };
|
||||
|
||||
bnBegin(&t);
|
||||
|
||||
for (i = 0; i < sizeof(primelist)/sizeof(primelist[0]); i++) {
|
||||
bnInsertBytes(&t, primelist[i].prime, 0,
|
||||
primelist[i].size);
|
||||
bnCopy(&e, &t);
|
||||
(void)bnSubQ(&e, 1);
|
||||
bnTwoExpMod(&a, &e, &t);
|
||||
p = bnBits(&a);
|
||||
if (p != 1) {
|
||||
printf(
|
||||
"Bug: Fermat(2) %u-bit output (1 expected)\n", p);
|
||||
fputs("Prime = 0x", stdout);
|
||||
for (j = 0; j < primelist[i].size; j++)
|
||||
printf("%02X", primelist[i].prime[j]);
|
||||
putchar('\n');
|
||||
}
|
||||
bnSetQ(&a, 3);
|
||||
bnExpMod(&a, &a, &e, &t);
|
||||
p = bnBits(&a);
|
||||
if (p != 1) {
|
||||
printf(
|
||||
"Bug: Fermat(3) %u-bit output (1 expected)\n", p);
|
||||
fputs("Prime = 0x", stdout);
|
||||
for (j = 0; j < primelist[i].size; j++)
|
||||
printf("%02X", primelist[i].prime[j]);
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
bnEnd(&t);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* First, make sure that bn is odd. */
|
||||
if ((bnLSWord(bn) & 1) == 0)
|
||||
(void)bnAddQ(bn, 1);
|
||||
|
||||
retry:
|
||||
/* Then build a sieve starting at bn. */
|
||||
sieveBuild(sieve, SIEVE, bn, 2, 0);
|
||||
|
||||
/* Do the extra exponent sieving */
|
||||
if (exponent) {
|
||||
va_list ap;
|
||||
unsigned t = exponent;
|
||||
|
||||
va_start(ap, exponent);
|
||||
|
||||
do {
|
||||
/* The exponent had better be odd! */
|
||||
assert(t & 1);
|
||||
|
||||
i = bnModQ(bn, t);
|
||||
/* Find 1-i */
|
||||
if (i == 0)
|
||||
i = 1;
|
||||
else if (--i)
|
||||
i = t - i;
|
||||
|
||||
/* Divide by 2, modulo the exponent */
|
||||
i = (i & 1) ? i/2 + t/2 + 1 : i/2;
|
||||
|
||||
/* Remove all following multiples from the sieve. */
|
||||
sieveSingle(sieve, SIEVE, i, t);
|
||||
|
||||
/* Get the next exponent value */
|
||||
t = va_arg(ap, unsigned);
|
||||
} while (t);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Fill up the offsets array with the first SHUFFLE candidates */
|
||||
i = p = 0;
|
||||
/* Get first prime */
|
||||
if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) {
|
||||
offsets[i++] = p;
|
||||
p = sieveSearch(sieve, SIEVE, p);
|
||||
}
|
||||
/*
|
||||
* Okay, from this point onwards, p is always the next entry
|
||||
* from the sieve, that has not been added to the shuffle table,
|
||||
* and is 0 iff the sieve has been exhausted.
|
||||
*
|
||||
* If we want to shuffle, then fill the shuffle table until the
|
||||
* sieve is exhausted or the table is full.
|
||||
*/
|
||||
if (rand && p) {
|
||||
do {
|
||||
offsets[i++] = p;
|
||||
p = sieveSearch(sieve, SIEVE, p);
|
||||
} while (p && i < SHUFFLE);
|
||||
}
|
||||
|
||||
/* Choose a random candidate for experimentation */
|
||||
prev = 0;
|
||||
while (i) {
|
||||
/* Pick a random entry from the shuffle table */
|
||||
j = rand ? rand(i) : 0;
|
||||
q = offsets[j]; /* The entry to use */
|
||||
|
||||
/* Replace the entry with some more data, if possible */
|
||||
if (p) {
|
||||
offsets[j] = p;
|
||||
p = sieveSearch(sieve, SIEVE, p);
|
||||
} else {
|
||||
offsets[j] = offsets[--i];
|
||||
offsets[i] = 0;
|
||||
}
|
||||
|
||||
/* Adjust bn to have the right value */
|
||||
if ((q > prev ? bnAddMult(bn, q-prev, 2)
|
||||
: bnSubMult(bn, prev-q, 2)) < 0)
|
||||
goto failed;
|
||||
prev = q;
|
||||
|
||||
/* Now do the Fermat tests */
|
||||
retval = primeTest(bn, &e, &a, f, arg);
|
||||
if (retval <= 0)
|
||||
goto done; /* Success or error */
|
||||
modexps += retval;
|
||||
if (f && (retval = f(arg, '.')) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Ran out of sieve space - increase bn and keep trying. */
|
||||
if (bnAddMult(bn, SIEVE*8-prev, 2) < 0)
|
||||
goto failed;
|
||||
if (f && (retval = f(arg, '/')) < 0)
|
||||
goto done;
|
||||
goto retry;
|
||||
|
||||
failed:
|
||||
retval = -1;
|
||||
done:
|
||||
bnEnd(&e);
|
||||
bnEnd(&a);
|
||||
lbnMemWipe(offsets, sizeof(offsets));
|
||||
#ifdef MSDOS
|
||||
lbnMemFree(sieve, SIEVE);
|
||||
#else
|
||||
lbnMemWipe(sieve, sizeof(sieve));
|
||||
#endif
|
||||
|
||||
return retval < 0 ? retval : modexps + CONFIRMTESTS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Similar, but searches forward from the given starting value in steps of
|
||||
* "step" rather than 1. The step size must be even, and bn must be odd.
|
||||
* Among other possibilities, this can be used to generate "strong"
|
||||
* primes, where p-1 has a large prime factor.
|
||||
*/
|
||||
int
|
||||
primeGenStrong(struct BigNum *bn, struct BigNum const *step,
|
||||
int (*f)(void *arg, int c), void *arg)
|
||||
{
|
||||
int retval;
|
||||
unsigned p, prev;
|
||||
struct BigNum a, e;
|
||||
int modexps = 0;
|
||||
#ifdef MSDOS
|
||||
unsigned char *sieve;
|
||||
#else
|
||||
unsigned char sieve[SIEVE];
|
||||
#endif
|
||||
|
||||
#ifdef MSDOS
|
||||
sieve = lbnMemAlloc(SIEVE);
|
||||
if (!sieve)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
/* Step must be even and bn must be odd */
|
||||
assert((bnLSWord(step) & 1) == 0);
|
||||
assert((bnLSWord(bn) & 1) == 1);
|
||||
|
||||
bnBegin(&a);
|
||||
bnBegin(&e);
|
||||
|
||||
for (;;) {
|
||||
if (sieveBuildBig(sieve, SIEVE, bn, step, 0) < 0)
|
||||
goto failed;
|
||||
|
||||
p = prev = 0;
|
||||
if (sieve[0] & 1 || (p = sieveSearch(sieve, SIEVE, p)) != 0) {
|
||||
do {
|
||||
/*
|
||||
* Adjust bn to have the right value,
|
||||
* adding (p-prev) * 2*step.
|
||||
*/
|
||||
assert(p >= prev);
|
||||
/* Compute delta into a */
|
||||
if (bnMulQ(&a, step, p-prev) < 0)
|
||||
goto failed;
|
||||
if (bnAdd(bn, &a) < 0)
|
||||
goto failed;
|
||||
prev = p;
|
||||
|
||||
retval = primeTest(bn, &e, &a, f, arg);
|
||||
if (retval <= 0)
|
||||
goto done; /* Success! */
|
||||
modexps += retval;
|
||||
if (f && (retval = f(arg, '.')) < 0)
|
||||
goto done;
|
||||
|
||||
/* And try again */
|
||||
p = sieveSearch(sieve, SIEVE, p);
|
||||
} while (p);
|
||||
}
|
||||
|
||||
/* Ran out of sieve space - increase bn and keep trying. */
|
||||
#if SIEVE*8 == 65536
|
||||
/* Corner case that will never actually happen */
|
||||
if (!prev) {
|
||||
if (bnAdd(bn, step) < 0)
|
||||
goto failed;
|
||||
p = 65535;
|
||||
} else {
|
||||
p = (unsigned)(SIEVE*8 - prev);
|
||||
}
|
||||
#else
|
||||
p = SIEVE*8 - prev;
|
||||
#endif
|
||||
if (bnMulQ(&a, step, p) < 0 || bnAdd(bn, &a) < 0)
|
||||
goto failed;
|
||||
if (f && (retval = f(arg, '/')) < 0)
|
||||
goto done;
|
||||
} /* for (;;) */
|
||||
|
||||
failed:
|
||||
retval = -1;
|
||||
|
||||
done:
|
||||
|
||||
bnEnd(&e);
|
||||
bnEnd(&a);
|
||||
#ifdef MSDOS
|
||||
lbnMemFree(sieve, SIEVE);
|
||||
#else
|
||||
lbnMemWipe(sieve, sizeof(sieve));
|
||||
#endif
|
||||
return retval < 0 ? retval : modexps + CONFIRMTESTS;
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
struct BigNum;
|
||||
|
||||
/* Generate a prime >= bn. leaving the result in bn. */
|
||||
int primeGen(struct BigNum *bn, unsigned (*randfunc)(unsigned),
|
||||
int (*f)(void *arg, int c), void *arg, unsigned exponent, ...);
|
||||
|
||||
/*
|
||||
* Generate a prime of the form bn + k*step. Step must be even and
|
||||
* bn must be odd.
|
||||
*/
|
||||
int primeGenStrong(struct BigNum *bn, struct BigNum const *step,
|
||||
int (*f)(void *arg, int c), void *arg);
|
||||
+685
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* sieve.c - Trial division for prime finding.
|
||||
*
|
||||
* Finding primes:
|
||||
* - Sieve 1 to find the small primes for
|
||||
* - Sieve 2 to find the candidate large primes, then
|
||||
* - Pseudo-primality test.
|
||||
*
|
||||
* An important question is how much trial division by small primes
|
||||
* should we do? The answer is a LOT. Even a heavily optimized
|
||||
* Fermat test to the base 2 (the simplest pseudoprimality test)
|
||||
* is much more expensive than a division.
|
||||
*
|
||||
* For an prime of n k-bit words, a Fermat test to the base 2 requires n*k
|
||||
* modular squarings, each of which involves n*(n+1)/2 signle-word multiplies
|
||||
* in the squaring and n*(n+1) multiplies in the modular reduction, plus
|
||||
* some overhead to get into and out of Montgomery form. This is a total
|
||||
* of 3/2 * k * n^2 * (n+1). Equivalently, if n*k = b bits, it's
|
||||
* 3/2 * (b/k+1) * b^2 / k.
|
||||
*
|
||||
* A modulo operation requires n single-word divides. Let's assume that
|
||||
* a divide is 4 times the cost of a multiply. That's 4*n multiplies.
|
||||
* However, you only have to do the division once for your entire
|
||||
* search. It can be amortized over 10-15 primes. So it's
|
||||
* really more like n/3 multiplies. This is b/3k.
|
||||
*
|
||||
* Now, let's suppose you have a candidate prime t. Your options
|
||||
* are to a) do trial division by a prime p, then do a Fermat test,
|
||||
* or to do the Fermat test directly. Doing the trial division
|
||||
* costs b/3k multiplies, but a certain fraction of the time (1/p), it
|
||||
* saves you 3/2 b^3 / k^2 multiplies. Thus, it's worth it doing the
|
||||
* division as long as b/3k < 3/2 * (b/k+1) * b^2 / k / p.
|
||||
* I.e. p < 9/2 * (b/k + 1) * b = 9/2 * (b^2/k + b).
|
||||
* E.g. for k=16 and b=256, p < 9/2 * 17 * 256 = 19584.
|
||||
* Solving for k=16 and k=32 at a few interesting value of b:
|
||||
*
|
||||
* k=16, b=256: p < 19584 k=32, b=256: p < 10368
|
||||
* k=16, b=384: p < 43200 k=32, b=384; p < 22464
|
||||
* k=16, b=512: p < 76032 k=32, b=512: p < 39168
|
||||
* k=16, b=640: p < 118080 k=32, b=640: p < 60480
|
||||
*
|
||||
* H'm... before using the highly-optimized Fermat test, I got much larger
|
||||
* numbers (64K to 256K), and designed the sieve for that. Maybe it needs
|
||||
* to be reduced. It *is* true that the desirable sieve size increases
|
||||
* rapidly with increasing prime size, and it's the larger primes that are
|
||||
* worrisome in any case. I'll leave it as is (64K) for now while I
|
||||
* think about it.
|
||||
*
|
||||
* A bit of tweaking the division (we can compute a reciprocal and do
|
||||
* multiplies instead, turning 4*n into 4 + 2*n) would increase all the
|
||||
* numbers by a factor of 2 or so.
|
||||
*
|
||||
*
|
||||
* Bit k in a sieve corresponds to the number a + k*b.
|
||||
* For a given a and b, the sieve's job is to find the values of
|
||||
* k for which a + k*b == 0 (mod p). Multiplying by b^-1 and
|
||||
* isolating k, you get k == -a*b^-1 (mod p). So the values of
|
||||
* k which should be worked on are k = (-a*b^-1 mod p) + i * p,
|
||||
* for i = 0, 1, 2,...
|
||||
*
|
||||
* Note how this is still easy to use with very large b, if you need it.
|
||||
* It just requires computing (b mod p) and then finding the multiplicative
|
||||
* inverse of that.
|
||||
*
|
||||
*
|
||||
* How large a space to search to ensure that one will hit a prime?
|
||||
* The average density is known, but the primes behave oddly, and sometimes
|
||||
* there are large gaps. It is conjectured by shanks that the first gap
|
||||
* of size "delta" will occur at approximately exp(sqrt(delta)), so a delta
|
||||
* of 65536 is conjectured to be to contain a prime up to e^256.
|
||||
* Remembering the handy 2<->e conversion ratios:
|
||||
* ln(2) = 0.693147 log2(e) = 1.442695
|
||||
* This covers up to 369 bits. Damn, not enough! Still, it'll have to do.
|
||||
*
|
||||
* Cramer's conjecture (he proved it for "most" cases) is that in the limit,
|
||||
* as p goes to infinity, the largest gap after a prime p tends to (ln(p))^2.
|
||||
* So, for a 1024-bit p, the interval to the next prime is expected to be
|
||||
* about 709.78^2, or 503791. We'd need to enlarge our space by a factor of
|
||||
* 8 to be sure. It isn't worth the hassle.
|
||||
*
|
||||
* Note that a span of this size is expected to contain 92 primes even
|
||||
* in the vicinity of 2^1024 (it's 369 at 256 bits and 492 at 192 bits).
|
||||
* So the probability of failure is pretty low.
|
||||
*/
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#define HAVE_CONFIG_H 0
|
||||
#endif
|
||||
#if HAVE_CONFIG_H
|
||||
#include "bnconfig.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some compilers complain about #if FOO if FOO isn't defined,
|
||||
* so do the ANSI-mandated thing explicitly...
|
||||
*/
|
||||
#ifndef NO_ASSERT_H
|
||||
#define NO_ASSERT_H 0
|
||||
#endif
|
||||
#ifndef NO_LIMITS_H
|
||||
#define NO_LIMITS_H 0
|
||||
#endif
|
||||
#ifndef NO_STRING_H
|
||||
#define NO_STRING_H 0
|
||||
#endif
|
||||
#ifndef HAVE_STRINGS_H
|
||||
#define HAVE_STRINGS_H 0
|
||||
#endif
|
||||
#ifndef NEED_MEMORY_H
|
||||
#define NEED_MEMORY_H 0
|
||||
#endif
|
||||
|
||||
#if !NO_ASSERT_H
|
||||
#include <assert.h>
|
||||
#else
|
||||
#define assert(x) (void)0
|
||||
#endif
|
||||
|
||||
#if !NO_LIMITS_H
|
||||
#include <limits.h> /* For UINT_MAX */
|
||||
#endif /* If not avail, default value of 0 is safe */
|
||||
|
||||
#if !NO_STRING_H
|
||||
#include <string.h> /* for memset() */
|
||||
#elif HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#if NEED_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#include "bn.h"
|
||||
#include "sieve.h"
|
||||
#ifdef MSDOS
|
||||
#include "lbnmem.h"
|
||||
#endif
|
||||
|
||||
#include "kludge.h"
|
||||
|
||||
/*
|
||||
* Each array stores potential primes as 1 bits in little-endian bytes.
|
||||
* Bit k in an array represents a + k*b, for some parameters a and b
|
||||
* of the sieve. Currently, b is hardcoded to 2.
|
||||
*
|
||||
* Various factors of 16 arise because these are all *byte* sizes, and
|
||||
* skipping even numbers, 16 numbers fit into a byte's worth of bitmap.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The first number in the small prime sieve. This could be raised to
|
||||
* 3 if you want to squeeze bytes out aggressively for a smaller SMALL
|
||||
* table, and doing so would let one more prime into the end of the array,
|
||||
* but there is no sense making it larger if you're generating small
|
||||
* primes up to the limit if 2^16, since it doesn't save any memory and
|
||||
* would require extra code to ignore 65537 in the last byte, which is
|
||||
* over the 16-bit limit.
|
||||
*/
|
||||
#define SMALLSTART 1
|
||||
|
||||
/*
|
||||
* Size of sieve used to find large primes, in bytes. For compatibility
|
||||
* with 16-bit-int systems, the largest prime that can appear in it,
|
||||
* SMALL * 16 + SMALLSTART - 2, must be < 65536. Since 65537 is a prime,
|
||||
* this is the absolute maximum table size.
|
||||
*/
|
||||
#define SMALL (65536/16)
|
||||
|
||||
/*
|
||||
* Compute the multiplicative inverse of x, modulo mod, using the extended
|
||||
* Euclidean algorithm. The classical EEA returns two results, traditionally
|
||||
* named s and t, but only one (t) is needed or computed here.
|
||||
* It is unrolled twice to avoid some variable-swapping, and because negating
|
||||
* t every other round makes all the number positive and less than the
|
||||
* modulus, which makes fixed-length arithmetic easier.
|
||||
*
|
||||
* If gcd(x, mod) != 1, then this will return 0.
|
||||
*/
|
||||
static unsigned
|
||||
sieveModInvert(unsigned x, unsigned mod)
|
||||
{
|
||||
unsigned y;
|
||||
unsigned t0, t1;
|
||||
unsigned q;
|
||||
|
||||
if (x <= 1)
|
||||
return x; /* 0 and 1 are self-inverse */
|
||||
/*
|
||||
* The first round is simplified based on the
|
||||
* initial conditions t0 = 1 and t1 = 0.
|
||||
*/
|
||||
t1 = mod / x;
|
||||
y = mod % x;
|
||||
if (y <= 1)
|
||||
return y ? mod - t1 : 0;
|
||||
t0 = 1;
|
||||
|
||||
do {
|
||||
q = x / y;
|
||||
x = x % y;
|
||||
t0 += q * t1;
|
||||
if (x <= 1)
|
||||
return x ? t0 : 0;
|
||||
q = y / x;
|
||||
y = y % x;
|
||||
t1 += q * t0;
|
||||
} while (y > 1);
|
||||
return y ? mod - t1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Perform a single sieving operation on an array. Clear bits "start",
|
||||
* "start+step", "start+2*step", etc. from the array, up to the size
|
||||
* limit (in BYTES) "size". All of the arguments must fit into 16 bits
|
||||
* for portability.
|
||||
*
|
||||
* This is the core of the sieving operation. In addition to being
|
||||
* called from the sieving functions, it is useful to call directly if,
|
||||
* say, you want to exclude primes congruent to 1 mod 3, or whatever.
|
||||
* (Although in that case, it would be better to change the sieving to
|
||||
* use a step size of 6 and start == 5 (mod 6).)
|
||||
*
|
||||
* Originally, this was inlined in the code below (with various checks
|
||||
* turned off where they could be inferred from the environment), but it
|
||||
* turns out that all the sieving is so fast that it makes a negligible
|
||||
* speed difference and smaller, cleaner code was preferred.
|
||||
*
|
||||
* Rather than increment a bit index through the array and clear
|
||||
* the corresponding bit, this code takes advantage of the fact that
|
||||
* every eighth increment must use the same bit position in a byte.
|
||||
* I.e. start + k*step == start + (k+8)*step (mod 8). Thus, a bitmask
|
||||
* can be computed only eight times and used for all multiples. Thus, the
|
||||
* outer loop is over (k mod 8) while the inner loop is over (k div 8).
|
||||
*
|
||||
* The only further trickiness is that this code is designed to accept
|
||||
* start, step, and size up to 65535 on 16-bit machines. On such a
|
||||
* machine, the computation "start+step" can overflow, so we need to
|
||||
* insert an extra check for that situation.
|
||||
*/
|
||||
void
|
||||
sieveSingle(unsigned char *array, unsigned size, unsigned start, unsigned step)
|
||||
{
|
||||
unsigned bit;
|
||||
unsigned char mask;
|
||||
unsigned i;
|
||||
|
||||
#if UINT_MAX < 0x1ffff
|
||||
/* Unsigned is small; add checks for wrap */
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
i = start/8;
|
||||
if (i >= size)
|
||||
break;
|
||||
mask = ~(1 << (start & 7));
|
||||
do {
|
||||
array[i] &= mask;
|
||||
i += step;
|
||||
} while (i >= step && i < size);
|
||||
start += step;
|
||||
if (start < step) /* Overflow test */
|
||||
break;
|
||||
}
|
||||
#else
|
||||
/* Unsigned has the range - no overflow possible */
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
i = start/8;
|
||||
if (i >= size)
|
||||
break;
|
||||
mask = ~(1 << (start & 7));
|
||||
do {
|
||||
array[i] &= mask;
|
||||
i += step;
|
||||
} while (i < size);
|
||||
start += step;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the index of the next bit set in the given array. The search
|
||||
* begins after the specified bit, so if you care about bit 0, you need
|
||||
* to check it explicitly yourself. This returns 0 if no bits are found.
|
||||
*
|
||||
* Note that the size is in bytes, and that it takes and returns BIT
|
||||
* positions. If the array represents odd numbers only, as usual, the
|
||||
* returned values must be doubled to turn them into offsets from the
|
||||
* initial number.
|
||||
*/
|
||||
unsigned
|
||||
sieveSearch(unsigned char const *array, unsigned size, unsigned start)
|
||||
{
|
||||
unsigned i; /* Loop index */
|
||||
unsigned char t; /* Temp */
|
||||
|
||||
if (!++start)
|
||||
return 0;
|
||||
i = start/8;
|
||||
if (i >= size)
|
||||
return 0; /* Done! */
|
||||
|
||||
/* Deal with odd-bit beginnings => search the first byte */
|
||||
if (start & 7) {
|
||||
t = array[i++] >> (start & 7);
|
||||
if (t) {
|
||||
if (!(t & 15)) {
|
||||
t >>= 4;
|
||||
start += 4;
|
||||
}
|
||||
if (!(t & 3)) {
|
||||
t >>= 2;
|
||||
start += 2;
|
||||
}
|
||||
if (!(t & 1))
|
||||
start += 1;
|
||||
return start;
|
||||
} else if (i == size) {
|
||||
return 0; /* Done */
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the main search loop */
|
||||
|
||||
do {
|
||||
if ((t = array[i]) != 0) {
|
||||
start = 8*i;
|
||||
if (!(t & 15)) {
|
||||
t >>= 4;
|
||||
start += 4;
|
||||
}
|
||||
if (!(t & 3)) {
|
||||
t >>= 2;
|
||||
start += 2;
|
||||
}
|
||||
if (!(t & 1))
|
||||
start += 1;
|
||||
return start;
|
||||
}
|
||||
} while (++i < size);
|
||||
|
||||
/* Failed */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a table of small primes for sieving larger primes with. This
|
||||
* could be cached between calls to sieveBuild, but it's so fast that
|
||||
* it's really not worth it. This code takes a few milliseconds to run.
|
||||
*/
|
||||
static void
|
||||
sieveSmall(unsigned char *array, unsigned size)
|
||||
{
|
||||
unsigned i; /* Loop index */
|
||||
unsigned p; /* The current prime */
|
||||
|
||||
/* Initialize to all 1s */
|
||||
memset(array, 0xFF, size);
|
||||
|
||||
#if SMALLSTART == 1
|
||||
/* Mark 1 as NOT prime */
|
||||
array[0] = 0xfe;
|
||||
i = 1; /* Index of first prime */
|
||||
#else
|
||||
i = 0; /* Index of first prime */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Okay, now sieve via the primes up to 256, obtained from the
|
||||
* table itself. We know the maximum possible table size is
|
||||
* 65536, and sieveSingle() can cope with out-of-range inputs
|
||||
* safely, and the time required is trivial, so it isn't adaptive
|
||||
* based on the array size.
|
||||
*
|
||||
* Convert each bit position into a prime, compute a starting
|
||||
* sieve position (the square of the prime), and remove multiples
|
||||
* from the table, using sieveSingle(). I used to have that
|
||||
* code in line here, but the speed difference was so small it
|
||||
* wasn't worth it. If a compiler really wants to waste memory,
|
||||
* it can inline it.
|
||||
*/
|
||||
do {
|
||||
p = 2 * i + SMALLSTART;
|
||||
if (p > 256)
|
||||
break;
|
||||
/* Start at square of p */
|
||||
sieveSingle(array, size, (p*p-SMALLSTART)/2, p);
|
||||
|
||||
/* And find the next prime */
|
||||
i = sieveSearch(array, 16, i);
|
||||
} while (i);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is the primary sieving function. It fills in the array with
|
||||
* a sieve (multiples of small primes removed) beginning at bn and
|
||||
* proceeding in steps of "step".
|
||||
*
|
||||
* It generates a small array to get the primes to sieve by. It's
|
||||
* generated on the fly - sieveSmall is fast enough to make that
|
||||
* perfectly acceptable.
|
||||
*
|
||||
* The caller should take the array, walk it with sieveSearch, and
|
||||
* apply a stronger primality test to the numbers that are returned.
|
||||
*
|
||||
* If the "dbl" flag non-zero (at least 1), this also sieves 2*bn+1, in
|
||||
* steps of 2*step. If dbl is 2 or more, this also sieve 4*bn+3,
|
||||
* in steps of 4*step, and so on for arbitrarily high values of "dbl".
|
||||
* This is convenient for finding primes such that (p-1)/2 is also prime.
|
||||
* This is particularly efficient because sieveSingle is controlled by the
|
||||
* parameter s = -n/step (mod p). (In fact, we find t = -1/step (mod p)
|
||||
* and multiply that by n (mod p).) If you have -n/step (mod p), then
|
||||
* finding -(2*n+1)/(2*step) (mod p), which is -n/step - 1/(2*step) (mod p),
|
||||
* reduces to finding -1/(2*step) (mod p), or t/2 (mod p), and adding that
|
||||
* to s = -n/step (mod p). Dividing by 2 modulo an odd p is easy -
|
||||
* if even, divide directly. Otherwise, add p (which produces an even
|
||||
* sum), and divide by 2. Very simple. And this produces s' and t'
|
||||
* for step' = 2*step. It can be repeated for step'' = 4*step and so on.
|
||||
*
|
||||
* Note that some of the math is complicated by the fact that 2*p might
|
||||
* not fit into an unsigned, so rather than if (odd(x)) x = (x+p)/2,
|
||||
* we do if (odd(x)) x = x/2 + p/2 + 1;
|
||||
*
|
||||
* TODO: Do the double-sieving by sieving the larger number, and then
|
||||
* just subtract one from the remainder to get the other parameter.
|
||||
* (bn-1)/2 is divisible by an odd p iff bn-1 is divisible, which is
|
||||
* true iff bn == 1 mod p. This requires using a step size of 4.
|
||||
*/
|
||||
int
|
||||
sieveBuild(unsigned char *array, unsigned size, struct BigNum const *bn,
|
||||
unsigned step, unsigned dbl)
|
||||
{
|
||||
unsigned i, j; /* Loop index */
|
||||
unsigned p; /* Current small prime */
|
||||
unsigned s; /* Where to start operations in the big sieve */
|
||||
unsigned t; /* Step modulo p, the current prime */
|
||||
#ifdef MSDOS /* Use dynamic allocation rather than on the stack */
|
||||
unsigned char *small;
|
||||
#else
|
||||
unsigned char small[SMALL];
|
||||
#endif
|
||||
|
||||
assert(array);
|
||||
|
||||
#ifdef MSDOS
|
||||
small = lbnMemAlloc(SMALL); /* Which allocator? Not secure. */
|
||||
if (!small)
|
||||
return -1; /* Failed */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* An odd step is a special case, since we must sieve by 2,
|
||||
* which isn't in the small prime array and has a few other
|
||||
* special properties. These are:
|
||||
* - Since the numbers are stored in binary, we don't need to
|
||||
* use bnModQ to find the remainder.
|
||||
* - If step is odd, then t = step % 2 is 1, which allows
|
||||
* the elimination of a lot of math. Inverting and negating
|
||||
* t don't change it, and multiplying s by 1 is a no-op,
|
||||
* so t isn't actually mentioned.
|
||||
* - Since this is the first sieving, instead of calling
|
||||
* sieveSingle, we can just use memset to fill the array
|
||||
* with 0x55 or 0xAA. Since a 1 bit means possible prime
|
||||
* (i.e. NOT divisible by 2), and the least significant bit
|
||||
* is first, if bn % 2 == 0, we use 0xAA (bit 0 = bn is NOT
|
||||
* prime), while if bn % 2 == 1, use 0x55.
|
||||
* (If step is even, bn must be odd, so fill the array with 0xFF.)
|
||||
* - Any doublings need not be considered, since 2*bn+1 is odd, and
|
||||
* 2*step is even, so none of these numbers are divisible by 2.
|
||||
*/
|
||||
if (step & 1) {
|
||||
s = bnLSWord(bn) & 1;
|
||||
memset(array, 0xAA >> s, size);
|
||||
} else {
|
||||
/* Initialize the array to all 1's */
|
||||
memset(array, 255, size);
|
||||
assert(bnLSWord(bn) & 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This could be cached between calls to sieveBuild, but
|
||||
* it's really not worth it; sieveSmall is *very* fast.
|
||||
* sieveSmall returns a sieve of odd primes.
|
||||
*/
|
||||
sieveSmall(small, SMALL);
|
||||
|
||||
/*
|
||||
* Okay, now sieve via the primes up to ssize*16+SMALLSTART-1,
|
||||
* obtained from the small table.
|
||||
*/
|
||||
i = (small[0] & 1) ? 0 : sieveSearch(small, SMALL, 0);
|
||||
do {
|
||||
p = 2 * i + SMALLSTART;
|
||||
|
||||
/*
|
||||
* Modulo is usually very expensive, but step is usually
|
||||
* small, so this conditional is worth it.
|
||||
*/
|
||||
t = (step < p) ? step : step % p;
|
||||
if (!t) {
|
||||
/*
|
||||
* Instead of assert failing, returning all zero
|
||||
* bits is the "correct" thing to do, but I think
|
||||
* that the caller should take care of that
|
||||
* themselves before starting.
|
||||
*/
|
||||
assert(bnModQ(bn, p) != 0);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Get inverse of step mod p. 0 < t < p, and p is prime,
|
||||
* so it has an inverse and sieveModInvert can't return 0.
|
||||
*/
|
||||
t = sieveModInvert(t, p);
|
||||
assert(t);
|
||||
/* Negate t, so now t == -1/step (mod p) */
|
||||
t = p - t;
|
||||
|
||||
/* Now get the bignum modulo the prime. */
|
||||
s = bnModQ(bn, p);
|
||||
|
||||
/* Multiply by t, the negative inverse of step size */
|
||||
#if UINT_MAX/0xffff < 0xffff
|
||||
s = (unsigned)(((unsigned long)s * t) % p);
|
||||
#else
|
||||
s = (s * t) % p;
|
||||
#endif
|
||||
|
||||
/* s is now the starting bit position, so sieve */
|
||||
sieveSingle(array, size, s, p);
|
||||
|
||||
/* Now do the double sieves as desired. */
|
||||
for (j = 0; j < dbl; j++) {
|
||||
/* Halve t modulo p */
|
||||
#if UINT_MAX < 0x1ffff
|
||||
t = (t & 1) ? p/2 + t/2 + 1 : t/2;
|
||||
/* Add t to s, modulo p with overflow checks. */
|
||||
s += t;
|
||||
if (s >= p || s < t)
|
||||
s -= p;
|
||||
#else
|
||||
if (t & 1)
|
||||
t += p;
|
||||
t /= 2;
|
||||
/* Add t to s, modulo p */
|
||||
s += t;
|
||||
if (s >= p)
|
||||
s -= p;
|
||||
#endif
|
||||
sieveSingle(array, size, s, p);
|
||||
}
|
||||
|
||||
/* And find the next prime */
|
||||
} while ((i = sieveSearch(small, SMALL, i)) != 0);
|
||||
|
||||
#ifdef MSDOS
|
||||
lbnMemFree(small, SMALL);
|
||||
#endif
|
||||
return 0; /* Success */
|
||||
}
|
||||
|
||||
/*
|
||||
* Similar to the above, but use "step" (which must be even) as a step
|
||||
* size rather than a fixed value of 2. If "step" has any small divisors
|
||||
* other than 2, this will blow up.
|
||||
*
|
||||
* Returns -1 on out of memory (MSDOS only, actually), and -2
|
||||
* if step is found to be non-prime.
|
||||
*/
|
||||
int
|
||||
sieveBuildBig(unsigned char *array, unsigned size, struct BigNum const *bn,
|
||||
struct BigNum const *step, unsigned dbl)
|
||||
{
|
||||
unsigned i, j; /* Loop index */
|
||||
unsigned p; /* Current small prime */
|
||||
unsigned s; /* Where to start operations in the big sieve */
|
||||
unsigned t; /* step modulo p, the current prime */
|
||||
#ifdef MSDOS /* Use dynamic allocation rather than on the stack */
|
||||
unsigned char *small;
|
||||
#else
|
||||
unsigned char small[SMALL];
|
||||
#endif
|
||||
|
||||
assert(array);
|
||||
|
||||
#ifdef MSDOS
|
||||
small = lbnMemAlloc(SMALL); /* Which allocator? Not secure. */
|
||||
if (!small)
|
||||
return -1; /* Failed */
|
||||
#endif
|
||||
/*
|
||||
* An odd step is a special case, since we must sieve by 2,
|
||||
* which isn't in the small prime array and has a few other
|
||||
* special properties. These are:
|
||||
* - Since the numbers are stored in binary, we don't need to
|
||||
* use bnModQ to find the remainder.
|
||||
* - If step is odd, then t = step % 2 is 1, which allows
|
||||
* the elimination of a lot of math. Inverting and negating
|
||||
* t don't change it, and multiplying s by 1 is a no-op,
|
||||
* so t isn't actually mentioned.
|
||||
* - Since this is the first sieving, instead of calling
|
||||
* sieveSingle, we can just use memset to fill the array
|
||||
* with 0x55 or 0xAA. Since a 1 bit means possible prime
|
||||
* (i.e. NOT divisible by 2), and the least significant bit
|
||||
* is first, if bn % 2 == 0, we use 0xAA (bit 0 = bn is NOT
|
||||
* prime), while if bn % 2 == 1, use 0x55.
|
||||
* (If step is even, bn must be odd, so fill the array with 0xFF.)
|
||||
* - Any doublings need not be considered, since 2*bn+1 is odd, and
|
||||
* 2*step is even, so none of these numbers are divisible by 2.
|
||||
*/
|
||||
if (bnLSWord(step) & 1) {
|
||||
s = bnLSWord(bn) & 1;
|
||||
memset(array, 0xAA >> s, size);
|
||||
} else {
|
||||
/* Initialize the array to all 1's */
|
||||
memset(array, 255, size);
|
||||
assert(bnLSWord(bn) & 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This could be cached between calls to sieveBuild, but
|
||||
* it's really not worth it; sieveSmall is *very* fast.
|
||||
* sieveSmall returns a sieve of the odd primes.
|
||||
*/
|
||||
sieveSmall(small, SMALL);
|
||||
|
||||
/*
|
||||
* Okay, now sieve via the primes up to ssize*16+SMALLSTART-1,
|
||||
* obtained from the small table.
|
||||
*/
|
||||
i = (small[0] & 1) ? 0 : sieveSearch(small, SMALL, 0);
|
||||
do {
|
||||
p = 2 * i + SMALLSTART;
|
||||
|
||||
t = bnModQ(step, p);
|
||||
if (!t) {
|
||||
assert(bnModQ(bn, p) != 0);
|
||||
continue;
|
||||
}
|
||||
/* Get negative inverse of step */
|
||||
t = sieveModInvert(bnModQ(step, p), p);
|
||||
assert(t);
|
||||
t = p-t;
|
||||
|
||||
/* Okay, we have a prime - get the remainder */
|
||||
s = bnModQ(bn, p);
|
||||
|
||||
/* Now multiply s by the negative inverse of step (mod p) */
|
||||
#if UINT_MAX/0xffff < 0xffff
|
||||
s = (unsigned)(((unsigned long)s * t) % p);
|
||||
#else
|
||||
s = (s * t) % p;
|
||||
#endif
|
||||
/* We now have the starting bit pos */
|
||||
sieveSingle(array, size, s, p);
|
||||
|
||||
/* Now do the double sieves as desired. */
|
||||
for (j = 0; j < dbl; j++) {
|
||||
/* Halve t modulo p */
|
||||
#if UINT_MAX < 0x1ffff
|
||||
t = (t & 1) ? p/2 + t/2 + 1 : t/2;
|
||||
/* Add t to s, modulo p with overflow checks. */
|
||||
s += t;
|
||||
if (s >= p || s < t)
|
||||
s -= p;
|
||||
#else
|
||||
if (t & 1)
|
||||
t += p;
|
||||
t /= 2;
|
||||
/* Add t to s, modulo p */
|
||||
s += t;
|
||||
if (s >= p)
|
||||
s -= p;
|
||||
#endif
|
||||
sieveSingle(array, size, s, p);
|
||||
}
|
||||
|
||||
/* And find the next prime */
|
||||
} while ((i = sieveSearch(small, SMALL, i)) != 0);
|
||||
|
||||
#ifdef MSDOS
|
||||
lbnMemFree(small, SMALL);
|
||||
#endif
|
||||
return 0; /* Success */
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*
|
||||
* sieve.h - Trial division for prime finding.
|
||||
*
|
||||
* This is generally not intended for direct use by a user of the library;
|
||||
* the prime.c and dhprime.c functions. are more likely to be used.
|
||||
* However, a special application may need these.
|
||||
*/
|
||||
struct BigNum;
|
||||
|
||||
/* Remove multiples of a single number from the sieve */
|
||||
void
|
||||
sieveSingle(unsigned char *array, unsigned size, unsigned start, unsigned step);
|
||||
|
||||
/* Build a sieve starting at the number and incrementing by "step". */
|
||||
int sieveBuild(unsigned char *array, unsigned size, struct BigNum const *bn,
|
||||
unsigned step, unsigned dbl);
|
||||
|
||||
/* Similar, but uses a >16-bit step size */
|
||||
int sieveBuildBig(unsigned char *array, unsigned size, struct BigNum const *bn,
|
||||
struct BigNum const *step, unsigned dbl);
|
||||
|
||||
/* Return the next bit set in the sieve (or 0 on failure) */
|
||||
unsigned sieveSearch(unsigned char const *array, unsigned size, unsigned start);
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Colin Plumb. All rights reserved.
|
||||
* For licensing and other legal details, see the file legal.c.
|
||||
*/
|
||||
#include "bnsize00.h"
|
||||
|
||||
#if BNSIZE16
|
||||
#error Using 16-bit math library
|
||||
#elif BNSIZE32
|
||||
#error Using 32-bit math library
|
||||
#elif BNSIZE64
|
||||
#error Using 64-bit math library
|
||||
#else
|
||||
#error No math library size defined
|
||||
#endif
|
||||
Loaded 100 of 261 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user