commit bbca46bf0b29d8109811eaa02984c4647968134d Author: Lyanis Souidi Date: Sat Apr 6 14:13:39 2024 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..69acf1a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.vscode/ +/.build/ +/bin/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..81db447 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +LIB_DIR=lib +SRC_DIR=src +BUILD_DIR=.build +BIN_DIR=bin + +CC=gcc + +build: key_gen crypt_rsa crypt_rsa_file + +key_gen: $(BIN_DIR)/key_gen + +crypt_rsa: $(BIN_DIR)/crypt_rsa + +crypt_rsa_file: $(BIN_DIR)/crypt_rsa_file + +clean: + rm -r $(BUILD_DIR) $(BIN_DIR) + +.PHONY: build key_gen crypt_rsa crypt_rsa_file clean + +$(BIN_DIR)/key_gen: $(BUILD_DIR)/key_gen.o $(BUILD_DIR)/key_utils.o $(BUILD_DIR)/crypt_utils.o $(BUILD_DIR)/big.o + mkdir -p $(BIN_DIR) + $(CC) -o $@ $^ + +$(BIN_DIR)/crypt_rsa: $(BUILD_DIR)/crypt_rsa.o $(BUILD_DIR)/key_utils.o $(BUILD_DIR)/crypt_utils.o $(BUILD_DIR)/big.o + mkdir -p $(BIN_DIR) + $(CC) -o $@ $^ + +$(BIN_DIR)/crypt_rsa_file: $(BUILD_DIR)/crypt_rsa_file.o $(BUILD_DIR)/key_utils.o $(BUILD_DIR)/crypt_utils.o $(BUILD_DIR)/big.o + mkdir -p $(BIN_DIR) + $(CC) -o $@ $^ + +$(BUILD_DIR)/key_gen.o: $(SRC_DIR)/key_gen.c + mkdir -p $(BUILD_DIR) + $(CC) -c -o $@ $< + +$(BUILD_DIR)/crypt_rsa.o: $(SRC_DIR)/crypt_rsa.c + mkdir -p $(BUILD_DIR) + $(CC) -c -o $@ $< + +$(BUILD_DIR)/crypt_rsa_file.o: $(SRC_DIR)/crypt_rsa_file.c + mkdir -p $(BUILD_DIR) + $(CC) -c -o $@ $< + +$(BUILD_DIR)/crypt_utils.o: $(SRC_DIR)/crypt_utils.c + mkdir -p $(BUILD_DIR) + $(CC) -c -o $@ $< + +$(BUILD_DIR)/key_utils.o: $(SRC_DIR)/key_utils.c + mkdir -p $(BUILD_DIR) + $(CC) -c -o $@ $< + +$(BUILD_DIR)/big.o: $(LIB_DIR)/big.c + mkdir -p $(BUILD_DIR) + $(CC) -c -o $@ $< diff --git a/README.md b/README.md new file mode 100644 index 0000000..7c75aae --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# Cryptographie RSA + +Programme de cryptographie RSA utilisant la bibliothéque [bign](https://sourceforge.net/projects/bignlibacbignum/) afin de générer des clés, chiffrer et déchiffrer des entiers en hexadécimal et des fichiers. + +## Build + +```bash +make build +``` + +Les exécutables se trouvent dans le dossier `bin`. + +## Utilisation + +### Génération de clé + +```bash +./key_gen rsa.key rsa.key.pub +``` + +### Chiffrement d'un entier + +```bash +./crypt_rsa -e rsa.key.pub entier.txt entier.txt.rsa +``` + +### Déchiffrement d'un entier + +```bash +./crypt_rsa -d rsa.key entier.txt.rsa entier.txt +``` + +### Chiffrement d'un ficher + +```bash +./crypt_rsa -e rsa.key.pub fichier.txt fichier.txt.rsa +``` + +### Déchiffrement d'un ficher + +```bash +./crypt_rsa -d rsa.key fichier.txt.rsa fichier.txt +``` + +## Auteurs + +- Hugo Dimitijevic +- Lyanis Souidi diff --git a/inc/crypt_utils.h b/inc/crypt_utils.h new file mode 100644 index 0000000..212980a --- /dev/null +++ b/inc/crypt_utils.h @@ -0,0 +1,11 @@ +#ifndef CRYPT_UTILS_H +#define CRYPT_UTILS_H + +#include "../lib/big.h" +#include "key_utils.h" + +void big_pow_mod(big_n a, big_n b, big_n n, big_n result); +void encrypt(public_key pub_key, big_n input, big_n output); +void decrypt(private_key priv_key, big_n input, big_n output); + +#endif diff --git a/inc/key_utils.h b/inc/key_utils.h new file mode 100644 index 0000000..e41f6dd --- /dev/null +++ b/inc/key_utils.h @@ -0,0 +1,20 @@ +#ifndef KEY_UTILS_H +#define KEY_UTILS_H + +#include "../lib/big.h" + +typedef struct { + big_n n; + big_n e; + big_n d; +} private_key; + +typedef struct { + big_n n; + big_n e; +} public_key; + +private_key private_key_read(const char *file); +public_key public_key_read(const char *file); + +#endif diff --git a/lib/big.c b/lib/big.c new file mode 100644 index 0000000..7e3fc7b --- /dev/null +++ b/lib/big.c @@ -0,0 +1,2036 @@ +#include "big.h" +#include + +#if ! ( defined BN_LIB_GOT || defined NO_BIG_BODY ) +#define BN_LIB_GOT + + +void read_hex(FILE* stream,bele* x) +{ + char buffer[4096]; + fgets(buffer, sizeof buffer, stream); + buffer[strcspn(buffer, "\n")] = 0; + num_here(buffer,x); +} + + +void write_hex(FILE* stream,bele* x,int cend) +{ + blong limit = mssb(x); + blong nb_words = limit / B_P_E; + + if (x[PREC] == 1) + fprintf(stream,"-"); + + fprintf(stream,"0x%0X",x[nb_words]); + for (int i = nb_words - 1; i >= 0; i--) + fprintf(stream,"%08X",x[i]); + fprintf(stream,"%c",cend); +} + +/* physical */ + +void zero_big ( bele * w ) /* set w = 0 */ +{ BN_TRAC( '0' ) ; bnflen ( w , S_LEN , ( bele ) 0 ) ; } + +void bnflen ( bele * w , unsigned sz , bele u ) +{ while ( sz -- ) w [ sz ] = u ; } + +void copy_big ( bele * w , bele * x ) +{ BN_TRAC( 'c' ) ; bnclen ( w , x , S_LEN ) ; } + +void bnclen ( bele * w , bele * x , unsigned m ) +{ while ( m -- ) x [ m ] = w [ m ] ; } + +/* big on big mathematics */ + +/** add_big sub_big + | | + raw_add_big raw_sub_big + | \/ | depending on signs & add or sub + | /\ | + bnaddub bns_ub */ + +R_D add_big ( bele * w , bele * x , bele * y ) /* y = w + x */ +#if ( ERROR_MODE > 1 ) || ( defined BIG_TRACE ) +{ BN_TRAC( '+' ) ; + BN_ERR( if ) ( rawadd_big ( w , x , y ) ) BNE_FUN( "overflow in add_big" ) ; + BN0 ; } + +BN_E rawadd_big ( bele * w , bele * x , bele * y ) +#endif +#if SIGNED +{ if ( w [ S_PREC ] != x [ S_PREC ] ) + { ( bns_ub ( w , x , y ) ) ; BN_ERR( return ( 0 ) ) ; } + else + BN_ERR( return ) ( bnaddub ( w , x , y ) ) ; } /* returns 1 or 0 */ + +BN_E bnaddub ( bele * w , bele * x , bele * y ) /* y = w + x */ +#endif +{ ublong ul = L2( 0 ) ; + int m = 0 ; + while ( m < S_PREC ) + { y [ m ] = ( bele ) + ( ul = ( ublong ) ( ul > BNFUL ) + w [ m ] + x [ m ] ) ; + ++ m ; + BN_SIG( y [ S_PREC ] = x [ S_PREC ] ; ) } + BN_ERR( return ( ( int ) ( ul >> B_P_E ) ) ; ) } /* returns carry */ + +R_D sub_big ( bele * w , bele * x , bele * y ) /* y = x - w */ +#if ( ERROR_MODE > 1 ) || ( defined BIG_TRACE ) +{ BN_TRAC( '-' ) ; + BN_ERR( if ) ( rawsub_big ( w , x , y ) ) BNE_FUN( "overflow in sub_big" ) ; + BN0 ; } + +BN_E rawsub_big ( bele * w , bele * x , bele * y ) +#endif +{ +#if SIGNED + if ( w [ S_PREC ] != x [ S_PREC ] ) + BN_ERR( return ) ( bnaddub ( w , x , y ) ) ; + else +#endif + bns_ub ( w , x , y ) ; + BN_ERR( return ( 0 ) ) ; } + +void bns_ub ( bele * w , bele * x , bele * y ) +{ blong li = L2( 0 ) ; bele * e_ptr ; + int m = 0 ; + if ( cp_abs ( w , x ) == - 1 ) /* abs w > abs x */ + { BN_SIG( y [ S_PREC ] = x [ S_PREC ] ^ 1 ; ) /* carry through zero */ + e_ptr = w ; w = x ; x = e_ptr ; } /* swap pointers */ + BN_SIG( else y [ S_PREC ] = x [ S_PREC ] ; ) /* no change */ + while ( m < S_PREC ) + y [ m ++ ] = ( bele ) ( li = ( blong ) * x ++ - * w ++ - ( li < 0 ) ) ; } + +R_D mult_big ( bele * w , bele * x , bele * y ) /* y = x * w */ +#if ( ERROR_MODE > 1 ) || ( defined BIG_TRACE ) +{ BN_TRAC( '*' ) ; + BN_ERR( if ) ( rawmult_big ( w , x , y ) ) + BNE_FUN( "overflow in mult_big" ) ; + BN0 ; } + + /** multiply two big numbers w * x to y + w [ m ] * x [ d + m - S_FRAC ] accumulates into y [ d ] and a carry + the outer loop increments each element of the destination in turn + starting at w [ 0 ] * x [ 0 ] to provide y [ - S_FRAC ] + during each sweep the multiple is accumulated in two ublong + if the destination has an index less than 0 then the answer is discarded + the carry always starts the next run + the inner loops are an oblique sweep, like these : + + outer loop starts at w [ 0 ] + each sweep start at x [ 0 ] + v + x [ ] 0 1 2 3 4 + + w [ 3 ] o o o o o > y [i] i = highest element affected + \ \ \ \ + w [ 2 ] o o o o o > y [h] + \ \ \ \ + w [ 1 ] o o o o o > y [g] + \ \ \ \ + w [ 0 ] o o o o o > y [f] + v v v v v + to y [ ] a b c d e + a = - S_FRAC and increments to b, c, ... */ + + +BN_E rawmult_big ( bele * w , bele * x , bele * y ) +#endif +{ ublong ul , lucy ; + int tw , tx , ty , sw = 0 , sx = 0 , iw , ix , iy ; + /* ^ tops starts indices */ + bele * swap ; +#if B_ROUND > 1 + unsigned underrun = 0 , up ; +#endif + DEF_BN_( z ) ; + tw = ( int ) ( blong ) mssb ( w ) >> BNSHIFT ; + tx = ( int ) ( blong ) mssb ( x ) >> BNSHIFT ; + if ( ( ty = tw + tx BN_FRAC( - S_FRAC ) ) >= S_PREC ) BNE1 ; + if ( tw > tx ) + { swap = w ; w = x ; x = swap ; iw = tw ; tw = tx ; tx = iw ; } + BN_HEAP_( z ) ; + BN_NHEAP( bnflen ( z , S_LEN , ( bele ) 0 ) ; ) + BN_SIG( z [ S_PREC ] = w [ S_PREC ] ^ x [ S_PREC ] ; ) + ul = lucy = L2( 0 ) ; /* initialise */ + iy = ( BNUF( ( unsigned ) muluf < S_FRAC ? - muluf : ) - S_FRAC - 1 ) ; + BNUF( sw = S_FRAC + iy + 1 ; ) + /* outer loop */ + while ( iy ++ < ty ) + { iw = sw ; ix = sx ; /* active starts */ + /* inner loop */ + do + { ul += ( ublong ) w [ iw ] * x [ ix ++ ] ; /* accumulate * */ + lucy += ( ul >> B_P_E ) ; /* accumulate carry */ + ul = ( bele ) ul ; } /* no hi carry in ul */ + while ( iw -- ) ; /* while effective */ + /* ^ end inner loop ^ */ +#if B_ROUND > 1 + if ( iy < - 1 ) underrun = underrun | ul ; + if ( iy == - 1 ) + { underrun = underrun | ( ul & E_SZ( 0x7FFF , 0x7FFFFFFF ) ) ; + up = ul & E_SZ( 0x8000UL , L2( 0x80000000U ) ) ; } + if ( ( ! iy ) && up && ( underrun || ( ( ul ^ B_ROUND ) & 1 ) ) ) + if ( ! ( bele ) ++ ul ) ++ lucy ; /* round up, & carry */ +#elif B_ROUND == 1 + if ( ( iy == - 1 ) && ( ul & E_SZ( 0x8000UL , L2( 0x80000000U ) ) ) ) + ++ lucy ; +#endif + BN_FRAC( if ( iy > - 1 ) ) /* if valid place */ + z [ iy ] = ( bele ) ul ; /* take accumulation */ + ul = lucy & E_SZ( 0xFFFF , 0xFFFFFFFF ) ; /* low carry for next */ + lucy = lucy >> B_P_E ; /* high to low carry */ + if ( sw < tw ) ++ sw ; + else + { ++ sx ; + if ( ix > tx ) + { -- sw ; -- tw ; ++ w ; -- tx ; } } } /* ugly , fast */ + /* ^ end outer loop ^ */ + if ( iy < S_PREC ) z [ iy ] = ( bele ) ul ; + bnclen ( z , y , S_LEN ) ; + FREE_BN_( z ) ; + BN_ERR( return ( ( int ) ( ( blong ) ( ( int ) iy == S_PREC ) && ul ) ) ) ; } + + /** there is one engine bn_divide + these functions for a user pass to it : + div_big , mod_big , i_div_big & div_big_4 + and these definitions, in the header, call to it : + rawdiv_big_ , bndo0_ , rawmod_big_ , rawi_div_ & rawdiv_4_ + + definitions for the divide below */ + +#if FRAC +#define BNZ_0 , 0 +#ifndef SOFT_SIZE +#define BNZ_F , s_frac +#else +#define BNZ_F , 1 +#endif +#else +#define BNZ_0 +#define BNZ_F +#define bnend 0 +#endif + +R_D div_big ( bele * w , bele * x , bele * y ) /* y = w / x */ +{ BN_TRAC( '/' ) ; + BN_ERR( if ) ( rawdiv_big_( w , x , y ) ) + BNE_FUN( "overflow or divide by zero in div_big" ) ; + BN0 ; } + +R_D mod_big ( bele * w , bele * x , bele * z ) /* z = x % w */ +{ BN_TRAC( '%' ) ; + BN_ERR( if ) ( rawmod_big_( w , x , z ) ) + BNE_FUN( "divide by zero in mod_big" ) ; + BN0 ; } + +#if FRAC +R_D i_div_big ( bele * w , bele * x , bele * y ) /* y = w \ x */ +{ BN_TRAC( '\\' ) ; + BN_ERR( if ) ( rawi_div_( w , x , y ) ) + BNE_FUN( "overflow or divide by zero in i_div" ) ; + BN0 ; } +#endif + +R_D div_big_4 ( bele * w , bele * x , bele * y , bele * z ) +{ BN_TRAC( '4' ) ; + BN_ERR( if ) ( rawdiv_4_( w , x , y , z ) ) + BNE_FUN( "overflow or divide by zero in div_big_4" ) ; + BN0 ; } + +#undef BNZ_0 +#undef BNZ_F + + /** set the residue to the dividend + bn_divide takes the active ( ( top bele length of the divisor ) + 1 ) + the outer loop comprises + new top answer is = + ( active residue top ) divided by ( divisor top + 1 ) (1) + shift up the residue to the top or ( top - 1 ) bit + add new top answer into the answer at the correct bit place + inner loop runs up the numbers : + residue = residue - ( top answer * dividend ) + if the top answer was 1 short then this is corrected by the next loop + and finally test if the answer is 1 short and fix + round + + (1) division of the ( top of divisor + 1 ) into the residue top ublong length + consider a ublong as two bele here : bele,bele , and ... continues the same + the top answer ranges from 0,80...0 to 1,F...FC, ratio of nearly 1 to 4 + and if the top multiplier is greater than 0,F...F + then the residue shift is to one bit less than the top + + bit places w_p divider, then divider shift + y_p dividend + z_p residue + + shifts z_s residue + z_st accumulation of shift for answer shift + + top two elements w_t divider , after assignment does not change + z_t local residue */ + +BN_E bn_divide ( bele * w , bele * x , bele * y , bele * z +#if FRAC + , int iend +#endif +#ifdef MDUF + , int bnuf +#endif + ) +{ DEF_BN_( w2 ) ; + blong w_p , y_p , z_p , z_s , z_st = - B_P_E ; /* bit places and shift */ + ublong w_t , z_t , lj , lcy ; + /* bit positions are w_p divider, then divider shift + y_p dividend + z_p residue + shifts z_s residue + z_st accumulation of shift for answer shift + top two elements w_t divider , after assignment does not change + z_t local residue */ + int k , m , n ; + bele * z1 ; +#if FRAC + int bnend ; +#if B_ROUND + int j ; +#endif + blong bnlend ; +#else +#define bnend 0 +#define bnlend L2( 0 ) +#endif + +#ifdef MDUF + int mv , bnact , nbot = 0 ; /* move , active length , shift place */ + bele * bnzx ; +#else +#define bnuf S_PREC +#define bnact S_PREC +#define bnzx zx +#endif +#ifndef USE_HEAP + bele zx [ PREC + 1 ] ; /* 4 args is only ! FRAC */ +#else + bele * zx ; +#endif +#if FRAC + bnend = iend & INT_MAX ; +#endif + /* set y = NULL if no division required */ + if ( y == z ) y = NULL ; /* no division */ + /* initialise top bit controls , divisor and residue */ + if ( ( w_p = bn_msx ( w , S_PREC ) ) == - L2( 1 ) ) + BNE1 ; /* return if / 0 */ + if ( ( z_p = bn_msx ( x , S_PREC ) ) == - L2( 1 ) ) /* divide into 0 */ + { if ( y != NULL ) bnflen ( y , S_LEN , 0 ) ; /* returns to 0 */ + if ( z != NULL ) bnflen ( z , S_LEN , 0 ) ; + BNE0 ; } /* return */ + y_p = z_p - w_p + BN_FRAC( + ( ( blong ) S_FRAC << BNSHIFT ) ) ; /* top answer place */ + z_s = ( ( blong ) S_PREC + L2( 1 ) ) * B_P_E - L2( 1 ) - z_p ; + /* first zx shift */ +#ifdef USE_HEAP + /* take w2 , zx [ LEN + 1 ] and set * z1 */ + BN_HEAP_( w2 ) ; + zx = ( bele * ) bn_h ( S_PREC + 1 , BY_P_E ) ; +#endif + z1 = & zx [ 1 ] ; /* for 1 u-f int */ +#ifdef MDUF + bnuf = ( unsigned ) bnuf > S_PREC ? S_PREC : bnuf ; + bnact = S_PREC ; + bnzx = zx ; +#endif + /* prepare registers */ + BN_FRAC( bnlend = ( blong ) bnend << BNSHIFT ; ) + k = ( int ) ( ( blong ) ( w_p = + ( ( blong ) S_PREC << BNSHIFT ) - L2( 1 ) - w_p ) >> BNSHIFT ) ; + bns_up ( w_p , w , w2 , S_PREC ) ; /* divisor to top of w2 */ + bnclen ( x , zx , S_PREC ) ; /* dividend to residue low */ + zx [ S_PREC ] = 0 ; /* extra to be empty */ + if ( y != NULL ) + bnflen ( y , S_PREC , 0 ) ; /* to collect answer */ + /* take divisor top + 1 */ + w_t = ( ublong ) w2 [ S_PREC - 1 ] + L2( 1 ) ; + /* outer loop */ + while ( 1 ) + { /* bit and element top zx places */ + lj = z_p & BNMASK ; /* mod top bit place */ + m = ( int ) ( ( ublong ) z_p >> BNSHIFT ) ; /* zx element place */ + /* take residue top and divide into */ + z_t = ( ublong ) ( ( ( ublong ) zx [ m ] ) << ( B_P_E + BNMASK - lj ) ) | + ( ( m > 0 ) ? ( ublong ) zx [ m - 1 ] << ( BNMASK - lj ) : L2( 0 ) ) | + ( ( m > 1 ) ? ( ublong ) zx [ m - 2 ] >> ( L2( 1 ) + lj ) : L2( 0 ) ) ; + if ( ( z_t /= w_t ) > BNFUL ) /* top divide */ + { z_t >>= L2( 1 ) ; -- z_s ; ++ y_p ; } /* if larger */ + z_st += z_s ; + /* shift zx to top */ + bns_up ( z_s , bnzx , bnzx , bnact + 1 ) ; /* residue to top */ + /* test if done */ + if ( y_p <= bnlend ) break ; + /* MDUF business */ +#ifdef MDUF + if ( ( ( unsigned ) bnuf < S_PREC ) && + ( ( mv = bnact - ( y_p >> BNSHIFT ) - 1 - bnuf ) > 0 ) ) + { bnact -= mv ; bnzx += mv ; nbot += mv ; } +#endif + /* set m to top answer element place, curtail and add */ + m = y_p >> BNSHIFT ; lj = y_p & BNMASK ; + if ( m == bnend ) z_t &= ( BNFUL << ( B_P_E - lj ) ) ; /* mask ans */ + /* add top answer at bit place, ? o-f */ + if ( y != NULL ) /* if collecting */ + { BN_FRAC( if ) /* o-f only if FRAC */ + ( bnadd_ul + ( z_t << ( y_p & BNMASK ) , y , m - 1 ) ) /* m cont */ + BN_FRAC( { FREE_BN_( zx ) ; FREE_BN_( w2 ) ; BNE1 ; } ) + ; } /* return if o-f */ + /* run up zx subtracting multiple */ + BNUF( if ( k < nbot ) k = nbot ; ) + n = k ; + lcy = L2( 0 ) ; /* initialise run */ + do + { lcy += z_t * ( ublong ) w2 [ n ] ; + if ( ( bele ) lcy > zx [ n ] ) + lcy += E_SZ( 0x10000UL , L2( 0x100000000U ) ) ; + zx [ n ] -= ( bele ) lcy ; lcy >>= B_P_E ; + } while ( ++ n < S_PREC ) ; + zx [ S_PREC ] -= ( bele ) lcy ; /* top element */ + /* set new top bit places and zx shift */ + z_s = ( ( ( blong ) S_PREC + L2( 1 ) ) * B_P_E - L2( 1 ) ) - + ( z_p = bn_msx ( zx , S_PREC + 1 ) ) ; /* residue top place */ +#ifdef MDUF + if ( z_p == - L2( 1 ) ) break ; +#endif + /* adopt new answer top place from residue shift */ + y_p -= z_s ; /* new ans top place */ + } /* end of outer loop */ + /* test 1 short, add 1, sub from residue */ + if /* if dreg >= divisor */ + ( ( y_p == bnlend ) && ( BNCPABS( w2 , z1 ) > - 1 ) ) + { if ( ( y != NULL ) && ( bnadd_ul ( L2( 1 ) , y , bnend ) ) ) /* + 1 */ + { FREE_BN_( zx ) ; FREE_BN_( w2 ) ; BNE1 ; } ; /* return if o-f */ + bns_ub ( w2 , z1 , z1 ) ; /* reduce dreg */ + -- y_p ; } + /* in case mod goes to source */ + BN_SIG( n = w [ S_PREC ] ^ x [ S_PREC ] ; ) /* hold div sign */ + /* align residue for return */ + if ( z != NULL ) /* for mod */ + { bns_down ( z_st , bnzx , bnzx , bnact + 1 ) ; + bnclen ( z1 , z , bnact ) ; /* out */ + BN_SIG( z [ S_PREC ] = x [ S_PREC ] ; ) } /* mod sign */ +#if B_ROUND + /* or round answer */ + else + { if ( ( y != NULL ) && ( iend < 0 ) ) + { j = 0 ; + if ( ! y_p ) + { j = zx [ S_PREC ] & E_SZ( 0x8000 , 0x80000000 ) ; /* save top bit */ + bns_up ( L2( 1 ) , bnzx , bnzx , bnact + 1 ) ; + -- y_p ; } + if ( y_p == - L2( 1 ) ) + { +#if B_ROUND == 1 + if ( ( j || ( BNCPABS( w2 , z1 ) > - L2( 1 ) ) ) && + ( bnadd_ul ( L2( 1 ) , y , 0 ) ) ) + { +#else + if ( j || ( m = BNCPABS( w2 , z1 ) ) > - L2( 1 ) ) + { if ( bnadd_ul ( ( blong ) + ( ( ( y [ 0 ] ^ B_ROUND ) & 1 ) || ( m > 0 ) ) , + y , 0 ) ) +#endif + { FREE_BN_( zx ) ; FREE_BN_( w2 ) ; BNE1 ; } } } } } /* o/f exit */ +#endif + BN_SIG( if ( y != NULL ) y [ S_PREC ] = n ; ) /* div sign */ + FREE_BN_( zx ) ; FREE_BN_( w2 ) ; + BNE0 ; } + +#ifdef MDUF +#undef BNUF +#else +#undef bnact +#undef bnz +#undef bnufl +#endif + + /* maths, int on big */ + + /** div_bintoi and rawdivbintoi + + div_bintoi handles error and trace + it calls rawdivbintoi + if error and trace code are not needed by definition, + the two functions merge and are defined to the same */ + + R_D div_bintoi ( bele * x , int i , bele * y ) +#if ( ERROR_MODE > 1 ) || ( defined BIG_TRACE ) + { BN_TRAC( 'u' ) ; + BN_ERR( if ) ( rawdivbintoi ( x , i , y ) ) + BNE_FUN( "overflow or divide by zero in div_bintoi" ) ; + BN0 ; } + + BN_E rawdivbintoi ( bele * x , int i , bele * y ) +#endif + { DEF_BN_( z ) ; +#ifdef USE_HEAP + BN_ERR( int r ; ) BN_HEAP_( z ) ; +#endif + bnflen ( z , S_LEN , ( bele ) 0 ) ; + if ( i < 0 ) + { z [ S_FRAC ] = ( bele ) - i ; + BN_SIG( z [ S_PREC ] = 1 ; ) } /* i becomes */ + else z [ S_FRAC ] = i ; /* +/- z */ + BN_ERR( BN_NHEAP( return ) BN_HEAP( r = ) ) + ( rawdiv_big_( x , z , y ) ) + BN_HEAP( ; free ( z ) ; BN_ERR( return ( r ) ) ) ; } + + /** maths of int and blong on big */ + + /** the small add and subtract nest are here : + + add_int sub_int add and sub ints + | | + add_li | | add from a blong + \ | | + add_li_place add from a blong to elements + / \ + | | choose on signs same or different + | | + bnadd_ul bnsub_ul unsigned add + or subtract with reversal if needed + + bnadd_ul requires a ublong value to be any up to 0x F...F,0 + bn_divide uses this to add an element length at any bit place + bnsub_ul requires a ublong value to be any up to 0x 1,0 */ + + R_D add_int ( int i , bele * x , bele * y ) + { BN_TRAC( 'a' ) ; + if ( x != y ) bnclen ( x , y , S_LEN ) ; + BN_ERR( if ) ( add_li_place ( ( blong ) i , y , S_FRAC ) ) + BNE_FUN( "overflow in add_int" ) ; + BN0 ; } + + R_D sub_int ( int i , bele * x , bele * y ) + { BN_TRAC( 's' ) ; + if ( x != y ) bnclen ( x , y , S_LEN ) ; + BN_ERR( if ) ( add_li_place ( ( blong ) - i , y , S_FRAC ) ) + BNE_FUN( "overflow in sub_int" ) ; + BN0 ; } + + BN_E add_li ( blong li , bele * x ) + { BN_ERR( return ) ( add_li_place ( li , x , S_FRAC ) ) ; } + + BN_E add_li_place ( blong li , bele * x , int m ) + { int j = 0 ; +#if SIGNED + j = x [ S_PREC ] ^ ( li < 0 ) ; +#else + j = ( li < 0 ) ; +#endif + if ( li < 0 ) li = - li ; /* treat negative li */ + if ( m >= ( S_PREC + j ) ) + return BN_ERR( ( ( int ) ( li != L2( 0 ) ) ) ) ; /* too high to count */ + if ( ! j ) + /* preprocess and call add */ + { if ( m < - 1 ) return BN_ERR( ( 0 ) ) ; /* u-f return */ + BN_ERR( return ) ( bnadd_ul ( ( ublong ) li , x , m ) ) ; + BNDV ; } + /* preprocess and call sub */ + { if ( li == ( E_SZ( 0x10000UL , L2( 0x100000000U ) ) ) ) + { ++ m ; li = L2( 1 ) ; } + if ( m < 0 ) BNE0 ; + if ( ( m == S_PREC ) && ( bn_msx ( x , S_PREC ) == - 1 ) ) BNE0 ; + bnsub_ul ( ( ublong ) li , x , m ) ; BNE0 ; } } + + /** rawadd_ul adds ul to x at element place m + sign of x is ignored + blong must accomodate, not carry up, a carry from adding lower int + so max value in ul is [ 1...1 ] [ 0...0 ] + accepts m == -1 , it then ignores the u-f + returns 0 on success or u-f, 1 on o-f */ + + int bnadd_ul ( ublong ul , bele * x , int m ) + { if ( m >= S_PREC ) return ( 1 ) ; + if ( m > - 1 ) /* low ul useable */ + { ul += ( ublong ) x [ m ] ; + x [ m ] = ( bele ) ul ; } + ul >>= B_P_E ; + if ( ++ m < S_PREC ) + { ul += ( ublong ) x [ m ] ; + x [ m ] = ( bele ) ul ; } + else return ( ( int ) ( ( ublong ) ul != L2( 0 ) ) ) ; + if ( ul > BNFUL ) /* if carry */ + while ( ( ++ m < S_PREC ) && ( ! ( ++ x [ m ] ) ) ) ; + return ( m == S_PREC ) ; } + + /* rawsub_ul subtracts ul from abs x at element place m + ul max is [ 1 ] [ 0...0 ] + sign of x changed by through zero */ + void bnsub_ul ( ublong ul , bele * x , int m ) + { bele cy = 0 ; + int n ; + n = m ; + if ( x [ m ] < ul ) /* if to carry */ + while ( ( ++ n < S_PREC ) && ! x [ n ] ) ; /* test up */ + if ( n < S_PREC ) /* if number is there */ + bns_lipos ( ul , x , m ) ; /* simple subtract */ + else /* through zero */ + { n = 0 ; + while ( ! x [ n ] && ( n < m ) ) ++ n ; /* pass lower zeroes */ + if ( n < m ) + { x [ n ] = 0 - x [ n ] ; cy = E_SZ( 0xFFFF , 0xFFFFFFFF ) ; + while ( ++ n < m ) /* complement ints */ + x [ n ] = ~ x [ n ] ; } /* through active */ + x [ m ] = ( bele ) + ( ( ublong ) ul - x [ m ] + cy ) ; /* subtract with cy */ + BN_SIG( x [ S_PREC ] = ! x [ S_PREC ] ; ) } } /* through zero */ + + /* bns_lipos subtracts ul at m when result will not pass through zero + used by bnsub_ul and bn_readyx */ + void bns_lipos ( ublong ul , bele * x , int m ) + { x [ m ] = ( bele ) ( ul = ( ublong ) x [ m ] - ul ) ; + if ( ul > E_SZ( 0xFFFFUL , L2( 0xFFFFFFFFU ) ) ) + while ( ( x [ ++ m ] -- == ( bele ) 0 ) && + ( m < ( S_PREC - 1 ) ) ) ; } /* cy */ + + /** mult_int + | + mult_li + | + bnmulul */ + + R_D mult_int ( int i , bele * x , bele * y ) /* x = x * n */ + { BN_TRAC( 'm' ) ; + BN_ERR( if ) + ( mult_li ( ( blong ) i , x , y ) ) + BNE_FUN( "overflow in mult_int" ) ; + BN0 ; } + + BN_E mult_li ( blong li , bele * x , bele * y ) + { BN_ERR( if ) + ( bnmulul ( ( ublong ) ( li < L2( 0 ) ? - li : li ) , + x , y , S_PREC ) ) + BN_ERR( return ( 1 ) ) ; + BN_SIG( y [ S_PREC ] = x [ S_PREC ] ^ ( li < L2( 0 ) ) ; ) + BNE0 ; } + + unsigned bnmulul ( ublong ul , bele * x , bele * y , int sz ) + { ublong cy = L2( 0 ) ; + while ( sz -- ) + * ( y ++ ) = ( bele ) + ( ( ublong ) ( cy = ( cy >> B_P_E ) + * ( x ++ ) * ul ) ) ; + return ( ( unsigned int ) + ( ( ublong ) cy >> B_P_E ) ) ; } /* return the overflow */ + + /** int and blong divides + + div_int div_i_4 + | | + div_li div_li_4 + \ / + bndivul */ + + R_D div_int ( int i , bele * x , bele * y ) + { BN_TRAC( 'd' ) ; + BN_ERR( if ) ( div_li ( ( blong ) i , x , y ) ) + BNE_FUN( "divide by zero in div_int" ) ; + BN0 ; } + +#if ! ( FRAC ) + R_D div_i_4 ( int i , bele * x , bele * y , int * rem ) + { blong lr ; + BN_TRAC( 'j' ) ; + BN_ERR( if ) ( div_li_4 ( ( blong ) i , x , y , & lr ) ) + BNE_FUN( "divide by zero in div_i_4" ) ; + * rem = ( int ) lr ; + BN0 ; } +#endif + + BN_E div_li ( blong li , bele * x , bele * y ) + { +#if ! ( FRAC ) + blong dummy ; + BN_ERR( return ) ( div_li_4 ( li , x , y , & dummy ) ) ; } + + BN_E div_li_4 ( blong li , bele * x , bele * y , blong * li_rem ) + { +#endif + ublong u ; +#if ! ( FRAC ) || B_ROUND + ublong r ; +#endif + if ( ! li ) { BN_NFRAC( * li_rem = L2( 0 ) ; ) BNE1 ; } + u = li < L2( 0 ) ? - li : li ; +#if ! ( FRAC ) || B_ROUND + r = +#endif + bndivul ( L2( 0 ) , u , x , y , S_PREC ) ; +#if B_ROUND + bnadd_ul ( +#if B_ROUND == 1 + ( r << L2( 1 ) ) >= ( blong ) u +#elif B_ROUND > 1 + ( ( r = r << L2( 1 ) ) > u ) || + ( ( r == u ) && ( y [ 0 ] ^ B_ROUND ) & 1 ) +#endif + , y , 0 ) ; +#endif + BN_NFRAC( * li_rem = ( int ) ( BN_SIG( x [ S_PREC ] ? - r : ) r ) ) ; + BN_SIG( y [ S_PREC ] = x [ S_PREC ] ^ ( li < L2( 0 ) ) ; ) + BNE0 ; } + + /** bndivul does all datum divides and is used for decimal converions + ul is the divisor + cy is the carry in, this is divided into the number by ul + the function returns the final residue */ + + unsigned int bndivul + ( ublong cy, ublong ul, bele * x, bele * y, int sz) + { while ( sz -- ) + { y [ sz ] = ( bele ) + ( ( ublong ) ( cy = ( cy << B_P_E ) + x [ sz ] ) / ul ) ; + cy = cy % ul ; } + return ( ( unsigned int ) cy ) ; } /* return residue */ + + /** shifts + + big_shift + / \ + bns_up bns_down + + bns_up is called by bndivul, bn_divide ( 3 calls ) + bns_down bndivul, bn_divide & bnin2 */ + + R_D big_shift ( blong shift , bele * x , bele * y ) + { blong li ; +#if B_ROUND + ublong lh ; +#if B_ROUND > 1 + ublong lj ; bele mask = ( unsigned ) - 1 ; int m ; +#endif +#endif + BN_TRAC( 'z' ) ; + li = bn_msx ( x , S_PREC ) + L2( 1 ) ; + if ( shift < L2( 0 ) ) + { /* shift down */ + if ( ( shift = - shift ) <= li ) /* shift to 0 then round */ + { +#if B_ROUND + lh = shift - L2( 1 ) ; /* to first u-f */ + lh = ( blong ) ( ( bele ) + x [ ( int ) ( ( blong ) lh >> BNSHIFT ) ] >> + ( ( bele ) lh & BNMASK ) ) & L2( 1 ) ; +#if B_ROUND > 1 + /* set lj = 1 if rounding is certain */ + if ( ( shift > L2( 1 ) ) && lh ) /* if rounding is possible */ + { lj = shift - L2( 1 ) ; + mask >>= ( B_P_E - ( lj & BNMASK ) ) ; + lj = ( blong ) ( ( bele ) + x [ m = ( unsigned int ) ( ( blong ) lj >> BNSHIFT ) ] + & mask ) ; + if ( ! lj ) + while ( m -- && ! x [ m ] ) ; lj = ( m > - 1 ) ; } /* l to r */ + else lj = L2( 0 ) ; +#endif +#endif + bns_down ( shift , x , y , S_PREC ) ; +#if B_ROUND + bnadd_ul ( +#if B_ROUND > 1 + ( ( ( y [ 0 ] ^ B_ROUND ) & 1 ) || lj ) && +#endif + lh , y , 0 ) ; /* cannot o-f */ +#endif + } + else bnflen ( y , S_LEN , ( bele ) 0 ) ; } /* end of shift down */ + else + { /* shift up */ + if ( shift <= ( ( blong ) S_PREC * B_P_E ) - li ) + bns_up ( shift , x , y , S_PREC ) ; + else + { if ( ! li ) bnflen ( y , S_LEN , ( bele ) 0 ) ; + BN_ERR( else ) BNE_FUN( "overflow in big_shift" ) ; } } + BN_SIG( y [ S_PREC ] = x [ S_PREC ] ; ) + BN0 ; } + + /** bns_up and bns_down + will crash the application if shift or m exceed S_PREC * B_P_E + shift , source , dest , size */ + + void bns_up ( ublong shift , bele * x , bele * y , int m ) + { unsigned u , d ; int n , p ; bele * z ; + d = B_P_E - ( u = ( unsigned int ) shift & BNMASK ) ; /* bits : up down */ + n = ( int ) ( ( ublong ) shift >> BNSHIFT ) ; /* n ints */ + z = y + n ; /* dest offset */ + p = m - n ; /* active shift */ + if ( u ) /* if bit shift */ + { while ( -- p ) + z [ p ] = ( x [ p ] << u ) + ( x [ p - 1 ] >> d ) ; + * z = * x << u ; } + else /* element shift */ + { while ( p -- ) z [ p ] = x [ p ] ; } + while ( n -- ) y [ n ] = 0 ; } /* fill low */ + + void bns_down ( ublong shift , bele * x , bele * y , int m ) + { int p = - 1 , n , d , q , u ; bele * z ; + u = B_P_E - ( d = ( unsigned int ) shift & BNMASK ) ; /* bits : down up */ + n = ( int ) ( ( ublong ) shift >> BNSHIFT ) ; /* n ints */ + q = m - ( int ) ( ( ublong ) shift >> BNSHIFT ) - 1 ; + z = x + n ; /* source offset */ + if ( d ) + { while ( ++ p < q ) + y [ p ] = ( z [ p ] >> d ) + ( z [ p + 1 ] << u ) ; + y [ p ] = z [ p ] >> d ; } + else + { ++ q ; while ( ++ p < q ) y [ p ] = z [ p ] ; -- p ; } + while ( ++ p < m ) y [ p ] = 0 ; } + + /** maths auxiliaries */ + + /** bit size + primary tech + mssb _ + overbit _\_ bn_msx if ! ( FRAC ) ntop is defined as mssb + ntop _/ + + bit comparisons + _ bn_ubsum + obitdif _/ + \_ bn_ubdif + a_obitdif _/ */ + + blong overbit ( bele * x ) +#if SIGNED + { blong li ; + BN_NSIG( return ) ( li = bn_msx ( x , S_PREC ) + 1 ) ; + BN_SIG( return ( x [ S_PREC ] ? - li : li ) ) ; } + + blong bnbn_uobit ( bele * x ) +#endif + { return ( bn_msx ( x , S_PREC ) + 1 ) ; } + + /* a_obitdiff ( x , y ) returns the absolute value of the unsigned + over bit difference of x and y */ + blong a_obitdif ( bele * x , bele * y ) + { blong li ; + li = bn_ubdif ( x , y ) ; + return ( li < 0 ? - li : li ) ; } + + blong obitdif ( bele * x , bele * y ) +#if SIGNED + { blong li ; + li = ( x [ S_PREC ] == y [ S_PREC ] ) ? + bn_ubdif ( x , y ) : bn_ubsum ( x , y ) ; + return ( y [ S_PREC ] ? - li : li ) ; } + + /** finds overbit of ( x - y ) when these have different signs */ + + blong bn_ubdif ( bele * x , bele * y ) +#endif + { blong k , li , mask ; int m = S_PREC - 1 ; + unsigned sig ; bele * gt , * lt ; + while ( ( x [ m ] == y [ m ] ) && ( m > - 1 ) ) -- m ; /* while ints == */ + if ( m == - 1 ) return ( L2( 0 ) ) ; /* return if equal */ + if ( x [ m ] > y [ m ] ) { gt = x ; lt = y ; sig = 1 ; } /* set pointers */ + else { gt = y ; lt = x ; sig = 0 ; } + /* find end of carry down */ + if ( ( li = gt [ m ] - lt [ m ] ) == 1 ) /* test & set li */ + { -- m ; + while ( ( gt [ m ] == 0 ) && + ( lt [ m ] == E_SZ( 0xFFFF , 0xFFFFFFFF ) ) && ( m > - 1 ) ) -- m ; + if ( m == - 1 ) return ( sig ? - L2( 1 ) : L2( 1 ) ) ; + li = E_SZ( 0x10000UL , L2( 0x100000000U ) ) + /* set li */ + gt [ m ] - lt [ m ] ; } + k = ( blong ) B_P_E * ( m + 1 ) ; + mask = E_SZ( 0xFFFF8000UL , L2( 0xFFFFFFFF80000000U ) ) ; + while ( ! ( li & mask ) ) { mask = mask >> 1 ; -- k ; } + /* under the carry, is lt > gt */ + if ( ( mask | ( blong ) gt [ m ] ) == ( mask | ( blong ) lt [ m ] ) ) + { -- m ; + while ( ( gt [ m ] == lt [ m ] ) && ( m > - 1 ) ) -- m ; } + k = k - ( ( lt [ m ] > gt [ m ] ) && ( m > - 1 ) ) ; /* adjust */ + return ( sig ? - k : k ) ; } + +#if SIGNED + + /** a_obitsum enables obitdiff to return the overbit of a difference when + the argument values are of different signs + it measures the overbit of the sum + as it is called only by obitdiff it should be within there + but I am not going to fix that */ + + blong bn_ubsum ( bele * x , bele * y ) + { blong li ; ublong k ; int j , m ; + m = S_PREC - 1 ; + while ( ! ( x [ m ] || y [ m ] ) && ( m > - 1 ) ) -- m ; /* find topmost */ + k = ( blong ) x [ m ] + y [ m ] ; + li = ( blong ) m << E_SZ( 4 , 5 ) ; j = 0 ; /* save int place */ + while ( k && ( k & 1 ) ) { k = k >> 1 ; ++ j ; } + if ( k ) /* cannot carry */ + { while ( k ) { k = k >> 1 ; ++ j ; } } + else + { -- m ; + while ( ( ( k = ( x [ m ] + y [ m ] ) ) == + E_SZ( 0xFFFF , ( int ) 0xFFFFFFFF ) ) && ( m > - 1 ) ) + -- m ; /* while may carry */ + if ( k > E_SZ( 0xFFFF , ( int ) 0xFFFFFFFF ) ) k = 1 ; else k = 0 ; } + return ( li + j + k ) ; } +#endif + + /** mssb ( x ) returns the bit place of the most significant set bit + of the absolute value of x + and + if the compilation is signed, if x == 0 the sign is set positive + + mssb + | + bn_msx */ + + /* mssb is called by rawmult_big (2), kb_2_big_2, bnnum_here & bn_s_out */ + blong mssb ( bele * x ) + { +#if SIGNED + blong lh ; + if ( ( lh = bn_msx ( x , S_PREC ) ) == - L2( 1 ) ) + x [ S_PREC ] = 0 ; return ( lh ) ; } /* correct - 0 , ret */ +#else + return ( bn_msx ( x , S_PREC ) ) ; } +#endif + + /* bn_msx is called by bn_divide (3), add_li+place, big_shift, overbit, + bnbn_uobit, mssx, ntop & bn_m_00 */ +blong bn_msx ( bele * x , int sz ) +{ bele be ; blong ul = - L2( 1 ) ; + -- sz ; + while ( ( sz > - 1 ) && ( ! x [ sz ] ) ) -- sz ; + if ( sz == - 1 ) return ( - L2( 1 ) ) ; + be = x [ sz ] ; + while ( be ) { be = be >> 1 ; ++ ul ; } /* find top bit */ + return ( ( blong ) ( ( ublong ) sz << BNSHIFT ) + ul ) ; } + +#if FRAC +blong ntop ( bele * x ) +{ return ( bn_msx ( x , S_PREC ) - ( blong ) S_FRAC * B_P_E ) ; } +#endif + +int cp_abs ( bele * w , bele * x ) +{ /* returns ( abs ( x ) - abs ( w ) ) as - 1 , 0 , 1 */ +#ifndef MDUF + int m = S_PREC ; +#else + return ( bncp_abs ( w , x , S_PREC ) ) ; } + +int bncp_abs ( bele * w , bele * x , int m ) +{ +#endif + while ( ( -- m > - 1 ) && ( w [ m ] == x [ m ] ) ) ; + return ( ( int ) m == - 1 ? 0 : w [ m ] > x [ m ] ? - 1 : 1 ) ; } + + /** input and output */ + + /** bnin1 permits loading to a length of S_PREC + 1 , + needed for pix.txt + + bnin1 finds the mark and sign then finds if decimal or hex + provides error response + copies the arguments into a structure + | \ + | for decimal to bn_dec_in which makes a buffer for the f-p + | / + bnin2, which processes its way through the input stream + collecting each next character from bn2i + hex input is planted into the top of the destination + until o-f or end of i-p + then shifted down to place + and the f-p is collected and planted + see comments for i-p and f-p of decimal input below + inserting into i-p and f-p uses max power of 10 within an element + + bn_dec_in_ip and bn_dec_in_fp serve big_in and bnnum_here */ + + +R_D big_in ( FILE * sm , int mark , bele * x , int base , int b_end ) +#if ( ERROR_MODE > 1 ) || ( FRAC && SIGNED ) +{ BN_ERR( if ) ( bnin1 ( sm , mark , x , base , b_end +#if ( FRAC && SIGNED ) + , 0 +#endif + ) ) + BNE_FUN( "fault in file input to big_in" ) ; +BN0 ; } + +BN_E bnin1 ( FILE * sm , int mark , bele * x , int base , int b_end +#if ( FRAC && SIGNED ) + , int xtra /* xtra adds to the length of the target */ +#endif + ) +#endif +{ int ich = 256 , bnerr ; + BN_SIG( int sig = 0 ; ) + BN_DEC( struct bn_in sc ; sc.ulbuff = L2( 0 ) ; ) + if ( sm == NULL ) BNE1 ; + /* find mark */ + if ( mark ) + while ( ( ( ich = fgetc ( sm ) ) != mark ) && ( ich != EOF ) ) +#ifdef SHO_LEAD_IN + if ( ich > 31 ) putc( ich , FILE_SM ) +#endif + ; + if ( ich == EOF ) BNE1 ; + /* read start of number */ + ich = bn2i ( sm , b_end ) ; + /* take sign */ + if ( ( ich == '+' ) || ( ich == '-' ) ) + { BN_SIG( if ( ich == '-' ) sig = 1 ; ) /* nor end yet */ + ich = bn2i ( sm , b_end ) ; } + /* try to find 0x */ + bnflen ( x , S_LEN , ( bele ) 0 ) ; + if ( ich == '0' ) + { if ( ( ich = bn2i ( sm , b_end ) ) == 'x' ) + { base = 16 ; ich = '0' ; } + else + if ( ich < 0 ) return BN_ERR( ( ich != - 2 ) ) ; } /* EOF or terminator */ + bnerr = ( ! base ) ; /* not lost here */ + + /* call bn_dec_in or bnin & error response */ + if ( ( +#ifndef NO_DEC + base == 10 ? + + bn_dec_in ( sm , x , ich , b_end ) : +#endif + bnin2 ( sm , x , 16 , ich , b_end +#if ( FRAC && SIGNED ) + , xtra +#endif +#ifndef NO_DEC + , & sc +#endif + ) + ) | bnerr ) BNE1 ; + BN_SIG( x [ S_PREC BN_FRAC( + xtra ) ] = sig ; ) BNE0 ; } + +#ifndef NO_DEC + + /** make a decimal buffer to collect extra length of f-p, + this is 3 / 16 length of f-p + 2 + call bnin2, convert from buffer */ + +int bn_dec_in ( FILE * sm , bele * x , int ich , int b_end ) +{ struct bn_in sc ; +#ifdef USE_HEAP + int bnerr = 0 ; +#if FRAC + bele * d_hold ; + if ( ( d_hold = ( bele * ) bn_h ( ( int ) ( ( blong ) + ( L2( 3 ) * FRAC_CHAR ) / L2( 16 ) ) + L2( 2 ) , BY_P_E ) ) + == NULL ) return ( 1 ) ; +#endif +#else +#if FRAC + bele d_hold [ ( int ) ( ( blong ) ( L2( 3 ) * BNASZ( FRAC ) ) / + L2( 16 ) + L2( 2 ) ) ] ; +#endif +#endif + sc.x = x ; BN_FRAC( sc.h = d_hold ; ) sc.ulbuff = L2( 0 ) ; sc.n = L2( 0 ) ; + sc.m = 1 ; + BN_HEAP( bnerr = ) BN_NHEAP( return ) + ( bnin2 ( sm , x , 10 , ich , b_end , +#if ( FRAC && SIGNED ) + 0 , +#endif + & sc ) ) ; + BN_FRAC( FREE_BN_( d_hold ) ; ) + BN_HEAP( return ( bnerr ) ) ; } + /* vv endif # if NO_DEC */ +#endif + + /* ich contains first character taken, or point */ +int bnin2 ( FILE * sm , bele * x , int base , int ich , int b_end +#if ( FRAC && SIGNED ) + , int xtra +#endif +#ifndef NO_DEC + , struct bn_in * sc +#endif + ) +{ blong li ; + int bnerr = 0 ; int got_n = 0 ; /* bnerr is used */ + BN_DEC( int base_b ; ) + /* pass leading zeros */ + while ( ich == '0' ) + { got_n = 1 ; ich = bn2i ( sm , b_end ) ; } + /* initialise */ +#ifndef NO_DEC + base_b = ( base == 16 ) ; /* 1 for hex */ + if ( base == 10 ) li = INT_CHAR ; + else +#endif + li = BNXICH ; /* integer digits */ + /* take values of integer part */ + while ( ( bn_n_( ich ) < base ) && li -- ) + { got_n = 1 ; + BN_DEC( if ( base_b ) ) + bnplant ( ( unsigned ) ich , + & x [ S_FRAC BN_FRAC( BN_SIG( + xtra ) ) ] , li ) ; +#ifndef NO_DEC + else + bnerr |= ( bn_dec_in_ip ( ich , sc ) ) ; +#endif + ich = bn2i ( sm , b_end ) ; } /* li is -1 at full end or too blong */ +#ifndef NO_DEC + if ( ! base_b ) + { if ( bn_decip_end ( sc ) ) return ( 1 ) ; } /* return on i-p o-f */ + else +#endif + if ( li != BNXICH ) + bns_down ( li << L2( 2 ) , x + S_FRAC BN_SIG( BN_FRAC( + xtra ) ) , + x + S_FRAC BN_SIG( BN_FRAC( + xtra ) ) , S_PREC BN_FRAC( - S_FRAC ) ) ; + if ( ich == '.' ) + { ich = bn2i ( sm , b_end ) ; + /* take fraction part */ +#if FRAC +#ifndef NO_DEC + if ( ! base_b ) + { sc->ulbuff = sc->n = L2( 0 ) ; sc->m = S_FRAC ; + li = FRAC_CHAR ; } + else +#endif + li = ( blong ) ( S_FRAC BN_SIG( BN_FRAC( + xtra ) ) ) * BNXPE ; + /* fraction digits */ + while ( ( bn_n_( ich ) < base ) && li -- ) /* number and wanted */ + { BN_ERR( got_n = 1 ; ) + BN_DEC( if ( base_b ) ) bnplant ( ( unsigned ) ich , x , li ) ; + BN_DEC( else bn_dec_in_fp ( ich , sc ) ; ) + ich = bn2i ( sm , b_end ) ; } + BN_DEC( if ( ! base_b ) bn_decfp_end ( sc ) ; ) +#endif + } /* o-f or fraction u-f */ + while ( bn_n_( ich ) < base ) ich = bn2i ( sm , b_end ) ; + BN_ERR( if ( ich != -2 ) bnerr = 1 ; ) + /* finish */ + return ( ( bnerr && b_end ) | -- got_n ) ; } /* DO I NEED bnerr ? */ + + /** i_end is to equal one of : ascii terminator + EOF terminator + 0 , which requires 10 10 + 10 , which requires 10 10 + in the same block of white space + 13 one 10 as terminator + 256 as impossible value to prevent termination + + terminator values : + + 0 non parsing terminates + 10 10 ( white space ignored ) 10 + 13 10 + etc accurately */ + +int bn2i ( FILE * sm , int i_end ) /* function for big_in */ +{ int ich , rct ; + if ( ! i_end ) i_end = 10 ; + rct = ( i_end != 10 ) ; + if ( i_end == 13 ) i_end = 10 ; + do + { ich = fgetc ( sm ) ; + if ( ( ich == i_end ) && rct ++ ) return ( - 2 ) ; } + while ( ( ich == ' ' ) || ( ( unsigned ) ( ich - 9 ) < 5 ) ) ; + return ( ich ) ; } + +void bnplant ( unsigned ich , bele * x , blong li ) +{ ich = bn_n_( ich ) ; + x [ ( int ) ( ( blong ) li / BNXPE ) ] |= + ( bele ) ( ich << + ( ( ( unsigned int ) li & E_SZ( 3L , L2( 7 ) ) ) * L2( 4 ) ) ) ; } + +#ifndef NO_DEC + /** conversion is based upon the struct bn_in + bn_dec_in_ip ( ich , & sc ) accumulates inserts digital values + bn_decip_end ( & sc ) inserts any residue + + this and bn_dec_in_fp are for use by big_in , kb_2_big , num_here */ + +int bn_dec_in_ip ( int ich , struct bn_in * sc ) /* OK */ +{ sc->ulbuff = sc->ulbuff * L2( 10 ) + ich - L2( 48 ) ; + if ( ( ++ sc->n ) % E_SZ( 4 , 9 ) ) return ( 0 ) ; + if ( ( bnmulul ( E_SZ( 10000UL , L2( 1000000000U ) ) , + sc->x + S_FRAC , sc->x + S_FRAC , sc->m ) ? 1 : /* I know */ + bnadd_ul ( sc->ulbuff , sc->x , S_FRAC ) ) ) return ( 1 ) ; + if ( sc->x [ S_FRAC + sc->m - 1 ] && + ( sc->m < ( S_PREC BN_FRAC( - S_FRAC ) ) ) ) + ++ sc->m ; + sc->ulbuff = L2( 0 ) ; return ( 0 ) ; } + +int bn_decip_end ( struct bn_in * sc ) /* OK */ +{ ublong li = L2( 1 ) ; + if ( ( sc->n % E_SZ( 4 , 9 ) ) ) + { while ( ( sc->n -- ) % E_SZ( 4 , 9 ) ) li *= L2( 10 ) ; + if ( ( bnmulul ( li , sc->x + S_FRAC , + sc->x + S_FRAC , sc->m ) ? 1 : + + bnadd_ul ( sc->ulbuff , sc->x , S_FRAC ) ) ) return ( 1 ) ; } + return ( 0 ) ; } + + /** fraction collection from an incoming stream of decimal digits + bn_dec_in_fp ( ich , sc ) saves digital values into an int buffer + E_SZ ( four , nine ) digits are saved + one int is saved in tail of x for every three saved into sc->h + bn_decfp_end ( sc ) saves any residue then inserts all */ +#if FRAC +void bn_dec_in_fp ( int ich , struct bn_in * sc ) +{ sc->ulbuff = sc->ulbuff * L2( 10 ) + ich - L2( 48 ) ; + if ( ++ sc->n % E_SZ( 4 , 9 ) ) return ; + if ( sc->n % E_SZ( 16 , 36 ) ) + * sc->h ++ = ( bele ) sc->ulbuff ; /* store 3 in hold */ + else + { * sc->x ++ = ( bele ) sc->ulbuff ; -- sc->m ; } /* store 1 in x */ + sc->ulbuff = L2( 0 ) ; } + +void bn_decfp_end ( struct bn_in * sc ) +{ ublong ul ; +#if BIG_DAJ == 1 + unsigned int rem = 0 ; +#endif + while ( sc->n % E_SZ( 4L , L2( 9 ) ) ) bn_dec_in_fp ( '0' , sc ) ; + /* stuff until int is full */ + sc->n /= E_SZ( 4L , L2( 9 ) ) ; + while ( sc->n ) + { if ( sc->n -- % L2( 4 ) ) { -- sc->h ; ul = * sc->h ; } + else + { -- sc->x ; ++ sc->m ; ul = ( blong ) * sc->x ; * sc->x = 0 ; } +#if BIG_DAJ == 1 + rem |= +#endif + bndivul ( ul , E_SZ( 10000UL , L2( 1000000000U ) ) , + sc->x , sc->x , sc->m ) ; } +#if BIG_DAJ == 1 + bnadd_ul ( ( blong ) ( rem != 0 ) , sc->x , 0 ) ; +#endif +} +/* v end # if FRAC */ +#endif +/* v end # ifndef NO_DEC */ +#endif + +/* kb_2_big_2 + this accepts kb input + if a console interface has been included + non parsing keys are refused + on i-p count it calls bnnum_here to test for overflow + if no console interface + text is collected in a buffer + then converted by num_here */ + +int kb_2_big ( bele * dest ) +{ return ( kb_2_big_2 ( dest , 10 ) ) ; } + +int kb_2_big_2 ( bele * dest , int base ) +#if ( defined GET_C_POS ) && ( defined GET_CHE ) +{ int ich , k = 0 , ok_char = 0 , sigot = 0 , gotx = 0 , base2 , ypos ; + /* count , valid = 1 , got sign , got 0x = 2 , base pos in y */ + /* longs for comparisons */ + blong digs = L2( 0 ) ; /* digits */ + BN_FRAC( blong p_got = 0 ; ) /* got point flag */ + DEF_BN_( hold ) ; /* permits [ Esc ] */ + char * q ; +#ifdef USE_HEAP + char * asc_in ; + BN_HEAP_( hold ) ; + asc_in = ( char * ) bn_h ( ( int ) BNKB_CH + 1 , 1 ) ; +#else + char asc_in [ BNKB_CH + 1 ] ; /* assemble ascii */ +#endif + q = asc_in ; base2 = ! base ? 16 : base ; + ypos = READ_LINE( GET_C_POS ) ; + * q = 0 ; + while ( 1 ) /* keystrokes */ + { q [ 1 ] = 0 ; + * q = ( ich = GET_CH ) ; /* get and plant */ + if ( ( ich > 31 ) && ( ich < 127 ) ) putchar( ich ) ; + ok_char = ( k < BNKB_CH ) ; /* prevent buffer o-f */ + if ( ok_char && + ! ( base || gotx ) ) /* test if 0x forced by call */ + { switch ( ich ) + { BN_FRAC( case '-' : ) + case '+' : break ; + case '0' : if ( k != sigot ) ok_char = 0 ; break ; + case 'X' : + case 'x' : if ( k != ( sigot + 1 ) ) ok_char = 0 ; break ; + default : ok_char = 0 ; } } + if ( ok_char || ( ich < 32 ) ) + { if ( bn_n_( ich ) < base2 ) /* if a digit */ + ok_char = /* o-f or u-f */ +#if FRAC + p_got ? p_got < ( ( /* f-p underflow */ +#ifndef NO_DEC + base2 == 10 ? FRAC_CHAR : +#endif + S_FRAC * E_SZ( 4 , 8 ) ) + 2 ) : +#endif + ( /* i-p overflow */ +#ifndef NO_DEC + base2 == 10 ? + ( digs < ( INT_CHAR - 1 ) ) || + ! bnnum_here ( asc_in , base2 , hold BNA_1 ) : +#endif + digs < ( ( S_PREC - S_FRAC ) * E_SZ( 4 , 8 ) ) ) ; + else /* not a digit */ + { switch ( ich ) + { case 'X' : + case 'x' : if ( ( k == 1 + sigot ) && + ( asc_in [ sigot ] == '0' ) ) + { base2 = 16 ; gotx = 2 ; digs = - 1 ; } /* !!!! */ + else ok_char = 0 ; break ; + /* base2 offset into string */ + BN_SIG( case '-' : ) + case '+' : if ( ! k ) sigot = 1 ; else ok_char = 0 ; break ; + BN_FRAC( + case '.' : if ( ! p_got ) p_got = 1 ; else ok_char = 0 ; break ; ) + case ENTER_K : + if ( k > ( sigot BN_FRAC( + ( p_got > 0 ) ) + gotx ) ) + { bnnum_here /* convert & issue */ + ( asc_in + sigot + gotx , base2 , hold BNA_1 ) ; + bnclen ( hold , dest , S_LEN ) ; + BN_SIG( dest [ S_PREC ] = ( * asc_in == '-' ) ; ) + BN_SIG( mssb ( dest ) ; ) + FREE_BN_( hold ) ; FREE_BN_( asc_in ) ; + putchar( '\n' ) ; return ( 0 ) ; } + break ; + case 27 : FREE_BN_( hold ) ; FREE_BN_( asc_in ) ; return ( - 1 ) ; + case BACK_SP : if ( k ) + { -- k ; -- q ; + switch ( * q ) + + { case 'X' : + case 'x' : digs = 1 ; gotx = 0 ; base2 = base ; + break ; + BN_FRAC( case '.' : p_got = 0 ; break ; ) + BN_SIG( case '-' : ) + case '+' : sigot = 0 ; break ; + default : BN_FRAC( if ( p_got ) -- p_got ; else ) + if ( digs ) -- digs ; /* digit */ + } } /* end switch * q , if ( k ) */ + ok_char = - 1 ; break ; /* - 1 to supress bell */ + default : ok_char = 0 ; } } } /* else , switch , if */ + /* actions */ + if ( ok_char < 1 ) + { +#ifndef NO_BELL + if ( ! ok_char ) putchar( '\a' ) ; +#endif + * q = 0 ; + SET_C_POS_( ypos , 1 ) ; printf( "%s " , asc_in ) ; + SET_C_POS_( ypos , 1 ) ; printf( "%s" , asc_in ) ; } + else + { BN_FRAC( if ( p_got ) ++ p_got ; else ) ++ digs ; + ++ q ; ++ k ; } + } } /* end of while ( 1 ) , fn */ +#else +{ char asc_in [ 81 ] ; /* alternative fn */ + printf ( "\t80 characters maximum\n" ) ; + scanf( "%80s" , asc_in ) ; + bnnum_here ( asc_in , base , dest BNA_1 ) ; + return ( 1 ) ; } +#endif + + /** num_here converts a decimal text string to a big number, + terminates ok on any character that does not parse for the conversion + num_here responds to overflow or no number as an error + num_here calls bnnum_here setting base 10 */ + + R_D num_here ( char * sg , bele * x ) /* put a value into x */ +{ BN_ERR( if ) + ( bnnum_here ( sg , + ( ( sg [ 1 ] | 32 ) == 'x' ) || ( ( sg [ 2 ] | 32 ) == 'x' ) ? + 12 : 10 , x BNA_1 ) ) + BNE_FUN( "num_here " ) ; + BN0 ; } + + /** to provide a routine that tests and converts a string number to binary + it returns 0 if it finds a number or 1 if overflow or no number + bnnum_here advances a pointer through : + leading spaces - ignored + if SIGNED , a sign - adopted + spaces - ignored + optional 0x - set base to 16 + spaces - ignored + leading zeros - noted as a number, otherwise ignored + if base is 16 a direct hex conversion to base 16 is used is made + the integer of the number is measured to find point or low end + the hex digits are converted into their places + below the point the hex digits are converted to their places + if base is 10 + if FRAC it : + tests for a decimal point, if yes + saves & x { S_FRAC ] + runs to the end of the ascii + steps back along ascii ch by ch repeatedly until decimal point + puts value from ch in x [ S_FRAC ] + divides the unit.fraction by base + restores x [ S_FRAC ] + tests if wanted and appropriate and increments number */ + +int bnnum_here ( char * sg , int base , bele * x +#if ( BIG_DAJ == 1 ) && ( ! defined NO_DEC ) + , int asc_inc +#endif + ) +{ int pos = 0 ; char * s2 ; bele * x2 ; + BN_FRAC( BN_DEC( blong j = 0 ; ) unsigned int n ; ) + /* characters ; digit value */ + BN_SIG( int sig = 0 ; ) /* sign */ +#if ( BIG_DAJ == 1 ) && ( ! defined NO_DEC ) + int rem = 0 ; +#endif +#ifndef NO_DEC + struct bn_in sc ; + sc.x = x ; BN_FRAC( sc.h = NULL ; ) sc.ulbuff = L2( 0 ) ; + sc.n = L2( 0 ) ; sc.m = 1 ; +#endif + bnflen ( x , S_LEN , ( bele ) 0 ) ; x2 = x ; + while ( * sg == ' ' ) ++ sg ; /* tolerate leading spaces */ + BN_SIG( if ( * sg == '-' ) { ++ sg ; sig = 1 ; } else ) + if ( * sg == '+' ) ++ sg ; + while ( * sg == ' ' ) ++ sg ; /* tolerate leading spaces */ + if ( ( * sg == '0' ) && ( ( sg [ 1 ] | 32 ) == 'x' ) ) + { base = 16 ; sg = sg + 2 ; while ( * sg == ' ' ) ++ sg ; } + if ( ! base ) return ( 1 ) ; + while ( * sg == '0' ) ++ sg ; /* leading zeroes */ +#ifndef NO_DEC + if ( base == 10 ) + /* convert from decimal */ + /* integer part */ + { while ( ( bn_n_( * sg ) ) < 10 ) /* step down digits */ + { if ( bn_dec_in_ip ( * sg , & sc ) ) /* insert digits */ + return ( 1 ) ; ++ sg ; } + if ( bn_decip_end ( & sc ) ) return ( 1 ) ; /* convert */ +#if FRAC + /* prepare fraction part */ + if ( * sg == '.' ) /* if found frac */ + { ++ sg ; + while ( bn_n_( * sg ) < 10 ) { ++ j ; ++ sg ; } + -- sg ; /* at end */ + /* fraction part conversion */ + while ( * sg != '.' ) + { +#if BIG_DAJ == 1 + rem = rem | /* keep underflow */ +#endif + bndivul ( ( ublong ) * ( sg -- ) - '0' , + L2( 10 ) , x , x , S_FRAC ) ; } +#if BIG_DAJ == 1 + bnadd_ul ( ( blong ) ( asc_inc && rem && ( j == FRAC_CHAR ) ) , x , 0 ) ; +#endif + } /* end '.' */ +#endif + } /* end decimal */ + else +#endif + /* convert from hex */ + { if ( ! ( * sg == '.' ) ) + { s2 = sg ; + while ( bn_n_( * s2 ) < 16 ) { ++ s2 ; ++ pos ; } /* digits in integer */ + if ( pos > ( ( S_PREC - S_FRAC ) * E_SZ( 4 , 8 ) ) ) return ( 1 ) ; + x2 = x2 + BN_FRAC( S_FRAC + ) ( ( pos - 1 ) >> E_SZ( 2 , 3 ) ) ; + /* hex integer part */ + while ( pos -- ) /* down integer */ + { * x2 = * x2 | + ( bn_n_( * sg ) << ( ( pos & E_SZ( 3 , 7 ) ) * 4 ) ) ; + ++ sg ; + if ( ! ( pos & E_SZ( 3 , 7 ) ) ) -- x2 ; } } +#if FRAC + if ( * sg == '.' ) /* maybe end */ + /* hex fraction part */ + { ++ sg ; x2 = x + S_FRAC - 1 ; pos = S_FRAC * E_SZ( 4 , 8 ) ; + while ( ( ( n = bn_n_( * sg ) ) < 16 ) && + ( ( pos >> E_SZ( 2 , 3 ) ) > - 1 ) ) + { -- pos ; * x2 = * x2 | ( n << ( ( pos & E_SZ( 3 , 7 ) ) * 4 ) ) ; + ++ sg ; + if ( ! ( pos & E_SZ( 3 , 7 ) ) ) -- x2 ; } } +#endif + } + BN_SIG( x [ S_PREC ] = sig ; mssb ( x ) ; ) + return ( 0 ) ; } /* sc AT EM = 0 IS NOT USED */ + + /** output to a stream */ + + /** bn_out + if hex / \ if decimal + / \ + bn_m_00 readyx these initialise as needed + makes buffer | + \ / + bn_s_out does the work */ + + R_D big_out ( int name_len , char * sg , bele * x , FILE * sm , int mark , + /* ^^^ ch length string big number stream begin mark */ + int b_end , int group , unsigned line_len , blong chip , + /* ^^^ end mark group line length integer-part characters */ +#if FRAC + int fmode , /* mode for chfp */ + blong chfp , /* fraction-part characters */ +#endif + int leadz , int base ) + /* ^^^ to replace leading 0 base */ + +{ struct bnout ctrl ; + ctrl.nam_len = name_len ; ctrl.sg = sg ; + ctrl.mark = mark ; ctrl.x = x ; ctrl.b_end = b_end ; + ctrl.group = ( blong ) group ; ctrl.line_len = ( blong ) line_len ; + ctrl.base = base ; + ctrl.sm = sm ; BN_DEC( ctrl.achip = ) ctrl.chip = chip ; + ctrl.leadz = ctrl.lead1 = leadz ; +#if FRAC + ctrl.ofm = fmode & 1 ; ctrl.fpnl = fmode & 2 ; ctrl.frnd = ! ( fmode & 4 ) ; + ctrl.chfp = chfp ; +#endif +#if ERROR_MODE + if ( ( sm == NULL ) ? 1 : + ( BN_DEC( base == 10 ? bn_m_00 ( & ctrl ) : ) bn_readyx ( & ctrl ) ) ) + BNE_FUN( "writing ascii " ) ; BN0 ; } +#else +if ( sm != NULL ) + BN_DEC( if ( base == 10 ) bn_m_00 ( & ctrl ) ; else ) + bn_readyx ( & ctrl ) ; } +#endif + + /** bn_readyx and bn_m_00 have to prepare the control values in the + struct ctrl + arrival use + ctrl->chip i-p request i-p characters + ctrl->ofm f-p mode +0 : ctrl->chfp as a dock +1 : ctrl->chfp as length +ctrl-chfp f-p length request neg of f-p characters +ctrl->n number of i-p n000 +ctrl->achip dec i-p min places i-p places +at arrival out of range values arriving produce the natural length + +has to set +ctrl->n the top hex digit +lead1 lead ch for o-f position +*/ +BN_E bn_readyx ( struct bnout * ctrl ) +{ blong len ; BN_FRAC( blong add_8 ; int pl ; BN_ERR( int bnerr ; ) ) + ctrl->fcall = bn2x ; + + /* set ctrl->achip */ + ctrl->lead1 = ( int ) ( ( blong ) ctrl->chip == BNXICH ) ; + /* horrible patch, elegance has competitors */ + if ( ! ctrl->chip || ( ( ublong ) ctrl->chip >= BNXICH ) ) + ctrl->achip = BNXICH ; + /* set achip for integer-part natural length */ + else + if ( ctrl->chip < ( len = ( ntop ( ctrl->x ) / L2( 4 ) + L2( 1 ) ) ) ) + /* characters in i-p , not counting o-f */ + ctrl->achip = len ; +#if FRAC + /* set ctrl->chfp */ + if ( ( ublong ) ctrl->chfp > ( S_FRAC * BNXPE ) ) + { ctrl->ofm = 0 ; ctrl->chfp = L2( 0 ) ; } + ctrl->chfp = ctrl->ofm ? - ctrl->chfp : + ctrl->chfp - S_FRAC * BNXPE ; /* set chfp to minus length */ + /* rounding and possible consequent o-f */ + if ( ( ctrl->chfp + S_FRAC * BNXPE ) ) /* if chfp + cut */ + { ctrl->ofm = bnadd_ul ( add_8 = ( blong ) ( L2( 8 ) << /* ofm is o-f */ + ( ( ( S_FRAC * BNXPE + + ctrl->chfp - L2( 1 ) ) & E_SZ( 3L , L2( 7 ) ) ) * L2( 4 ) ) ) + * ctrl->frnd , /* add_8 is the 8 positioned in int */ + ctrl->x , + pl = ( unsigned int ) ( ( blong ) ( S_FRAC * BNXPE + + ctrl->chfp - L2( 1 ) ) >> E_SZ( 2L , L2( 3 ) ) ) ) ; + ctrl->lead1 = ctrl->lead1 ? ' ' : ctrl->leadz ; } + else { ctrl->ofm = 0 ; add_8 = L2( 0 ) ; ctrl->lead1 = ctrl->leadz ; } + /* ofm to bn_s_out, add_8 to below */ + ctrl->achip += ( ( add_8 > 0 ) && ( ctrl->achip == BNXICH ) ) * ctrl->frnd ; + /* 1 more if add_8 and full length i-p */ +#endif + ctrl->n = ctrl->achip +#if FRAC + + ( blong ) S_FRAC * E_SZ( 4L , L2( 8 ) ) ; + BN_ERR( bnerr = ) bn_s_out ( ctrl ) ; + if ( add_8 ) bns_lipos ( add_8 , ctrl->x , pl ) ; /* restore */ + BN_ERR( return ( bnerr ) ) ; } +#else + ; /* not an accident */ +BN_ERR( return ) ( bn_s_out ( ctrl ) ) ; } +#endif + +#ifndef NO_DEC +#define BNZ( A ) (int) ((ublong) BNASZ( A )/E_SZ(4L,L2(9))+L2(1)) +#define BN00MX BNZ( BNHOP ) +#if ( defined USE_HEAP && defined SOFT_SIZE ) || ( PREC > BNHOP ) +#ifdef SOFT_SIZE +#define BN_UP( A ) if( A ++ == ctrl->n00top && (S_PREC>BNHOP)) A = ctrl->n002 +#define BN_DO( A ) if( A -- == ctrl->n002 && (S_PREC>BNHOP)) A = ctrl->n00top +#else +#define BN_UP( A ) if ( A ++ == ctrl->n00top ) A = ctrl->n002 +#define BN_DO( A ) if ( A -- == ctrl->n002 ) A = ctrl->n00top +#endif +#else +#define BN_UP( A ) ++ A +#define BN_DO( A ) -- A +#endif + +/** for decimal output + makes a buffer and, if needed an overflow buffer + load this with clusters of decimal places + then call bn_s_out + + written as a number, least significant to the right : + + [ ] ... [ ] . [ ] ... [ ] + ^ ^ + numb n00 + + when the n00s have to be broken because there are too many + numb pointing to the 0 int place may be in either array : + + [ ] ... [ ] [ ] ... [ ] + ^ ^ + n002 n00top n00 + + test pointer going + up against n00top after incrementing + down against n002 before decrementing */ + +BN_E bn_m_00 ( struct bnout * ctrl ) +{ BN_FRAC( bele * n00fp ; ) + unsigned m ; blong len ; + int bn2 ; +#if FRAC + bele * numb , noddy = 0 ; +#endif + BN_HEAP( BN_ERR( int bnerr = 1 ; ) ) /* set to zero by success */ +#ifndef USE_HEAP + /* take stack */ +#ifndef SOFT_SIZE + bele numb0 [ ( ( PREC - FRAC ) > FRAC ? PREC - FRAC : FRAC ) ] ; + /* fraction-part , integer-part */ +#else + big_n numb0 ; +#endif +#if ( PREC > BNHOP ) + bele n00 [ BNZ( BNHOP ) ] , n002 [ BNZ( PREC - BNHOP ) + 1 ] ; + ctrl->n002 = n002 ; +#else + bele n00 [ BNZ( PREC ) + 1 ] ; /* + 1 for 2 roundings up */ +#endif + BN_FRAC( numb = numb0 ; ) +#else + bele * n00 , * numb0 ; +#endif + if ( ! ctrl->chip || ( ( ublong ) ctrl->chip > INT_CHAR ) ) + len = ctrl->achip = INT_CHAR ; /* natural length */ + else + len = BNBSZ( bn_msx ( & ctrl->x [ S_FRAC ] , S_PREC - S_FRAC ) ) ; + ctrl->n = ( len + E_SZ( 3L , L2( 8 ) ) ) / E_SZ( 4L , L2( 9 ) ) ; + if ( len > ctrl->achip ) ctrl->achip = len ; +#if FRAC + /* ofm determines how chfp will be used, see above + then when that is resolved, signals f-p to o/p shorter than naturally + chfp of 0 or outside the natural length gives the natural length + chfp is used as a negative */ +#ifdef SOFT_SIZE + if ( ! S_FRAC ) { ctrl->ofm = 1 ; ctrl->chfp = L2( 0 ) ; } +#endif + if ( ( ublong ) ctrl->chfp > FRAC_CHAR ) + { ctrl->ofm = 0 ; ctrl->chfp = L2( 0 ) ; } /* natural length */ + ctrl->chfp = ctrl->ofm ? - ctrl->chfp : ctrl->chfp - FRAC_CHAR ; + /* control - given dok */ + ctrl->ofm = ( ( - ctrl->chfp ) != FRAC_CHAR ) ; + /* reuse */ +#endif +#ifdef USE_HEAP + /* take heap memory */ + + + BN_FRAC( numb = ) numb0 = ( bele * ) bn_h ( +#if FRAC + ( S_PREC - S_FRAC ) > S_FRAC ? S_PREC - S_FRAC : S_FRAC +#else + S_PREC +#endif + , BY_P_E ) ; + + n00 = ( bele * ) + bn_h ( S_PREC > BNHOP ? BN00MX : BNZ( S_PREC ) + 1 , BY_P_E ) ; + /* initialise n00ip, save point */ +#if ( defined USE_HEAP && defined SOFT_SIZE ) || ( PREC > BNHOP ) + ctrl->n00top = n00 + BNZ( S_PREC > BNHOP ? BNHOP : s_prec ) - 1 ; +#endif +#if defined USE_HEAP && ( ( defined SOFT_SIZE ) || ( PREC > BNHOP ) ) + ctrl->n002 = ( bele * ) bn_h ( +#ifdef SOFT_SIZE + ( S_PREC <= BNHOP ) ? 1 : +#endif + BNZ( S_PREC - BNHOP ) + 1 , BY_P_E ) ; +#endif +#endif + ctrl->n00ip = /* n00 place 0 */ +#if FRAC + n00fp = +#if defined USE_HEAP && ( ( defined SOFT_SIZE ) || ( PREC > BNHOP ) ) + ( S_FRAC > BNHOP ) ? ctrl->n002 + BNZ( S_FRAC - BNHOP ) : +#endif + BNZ( S_FRAC ) + /* n00fp start at the unit place */ +#endif + n00 ; + /* these fills can be slightly accelerated, is it worth it ? */ + /* fill n00s, integer-part */ + bnclen ( & ctrl->x [ S_FRAC ] , numb0 , m = S_PREC - S_FRAC ) ; + ctrl->n = ( ( blong ) ( ctrl->achip + + E_SZ( 3L , L2( 8 ) ) ) / E_SZ( 4L , L2( 9 ) ) ) ; + while ( ctrl->n -- ) + { * ctrl->n00ip = bndivul ( L2( 0 ) , E_SZ( 10000UL , L2( 1000000000U ) ) , + numb0 , numb0 , m ) ; + m -= ( ! numb0 [ m - 1 ] ) && ( m > 0 ) ; /* shorten i-p */ + BN_UP( ctrl->n00ip ) ; } +#if FRAC + /* fill n00s, fraction-part */ + bnclen ( ctrl->x , numb , bn2 = S_FRAC ) ; /* big fraction-part */ + ctrl->n = /* number of n00s to load in f-p */ + ( - ctrl->chfp + E_SZ( 3L , L2( 8 ) ) + ctrl->ofm ) + / E_SZ( 4L , L2( 9 ) ) ; /* number of f-p n00s to fill */ + while ( ctrl->n -- ) + { BN_DO( n00fp ) ; + * n00fp = bnmulul ( E_SZ( 10000UL , L2( 1000000000U ) ) , + numb , numb , bn2 ) ; + if ( ( ! * numb ) && bn2 ) { -- bn2 ; ++ numb ; } } /* shorten f-p */ + /* n00fp points to last n00 filled */ + /* dock tail and round for dock or BIG_DAJ */ + /* will hold 10 * 10 ^ N or 5 * 10 ^ N , to add */ + m = ( ctrl->ofm ? E_SZ( 5000UL , L2( 500000000U ) ) : ( +#if BIG_DAJ == 2 + bn_msx ( numb , bn2 ) != - L2( 1 ) ? + E_SZ( 10000UL , L2( 1000000000U ) ) : +#endif + L2( 0 ) ) ) * ctrl->frnd ; + noddy = ( int ) ( ( blong ) + ( - L2( 0 ) - ctrl->chfp ) % E_SZ( 4L , L2( 9 ) ) ) ; + while ( noddy -- ) m /= 10 ; /* position the 5 */ + /* add and test for excess + 5 or + 1 at required place */ + if ( ( * n00fp += m ) > E_SZ( 9999U , 999999999U ) ) /* but cast 64 bit */ + { * ( n00fp ++ ) = 0 ; + while ( ++ * n00fp == E_SZ( 10000 , 1000000000 ) ) + { * n00fp = 0 ; /* carry up the n000s */ + BN_UP( n00fp ) ; } } /* will never o-f */ +#else +#undef bn2 + /* V end if FRAC */ +#endif + /* prepare for function bn210 */ + -- ctrl->n00ip ; + ctrl->bebuff = * ctrl->n00ip ; + if ( ( m = ( int ) ( ( ctrl->n = ctrl->achip ) % E_SZ( 4 , 9 ) ) ) != 0 ) + { m = E_SZ( 4 , 9 ) - m ; + while ( m -- ) ctrl->bebuff *= 10 ; } + /* if needed by ctrl->chip , lose top 0 */ + if ( ctrl->chip && ( ctrl->achip > ctrl->chip ) && + ! ( ctrl->bebuff / E_SZ( ( bele ) 1000 , 100000000 ) ) ) + { -- ctrl->achip ; bn210 ( ctrl ) ; } + /* set call */ + ctrl->fcall = bn210 ; + /* send */ + BN_ERR( BN_NHEAP( return ) BN_HEAP( bnerr = ) ) + bn_s_out ( ctrl ) ; +#ifdef USE_HEAP +#if ( defined SOFT_SIZE ) || ( PREC > BNHOP ) + FREE_BN_( ctrl->n002 ) ; +#endif + FREE_BN_( n00 ) ; FREE_BN_( numb0 ) ; + BN_ERR( return ( bnerr ) ) ; +#endif +} +#endif + +BN_E bn_s_out ( struct bnout * ctrl ) +{ BN_ERR( int bnerr = 0 ; ) unsigned u , program ; + ublong lu , pos ; + int i = 0 , activ = '0' , tokens ; + char mark_sg [ 3 ] = " " ; +#if SIGNED + mssb ( ctrl->x ) ; /* mend -0 */ +#endif + if ( ctrl->mark == 10 ) mark_sg [ 1 ] = 0 ; /* equals one space */ + else mark_sg [ 0 ] = ctrl->mark ; + /* 0 or 10 give no string length */ + /* line length and group */ + ctrl->line_len = ctrl->line_len > L2( 2 ) ? + ctrl->line_len - L2( 2 ) : ( unsigned ) ( - L2( 1 ) ) ; + + if ( ctrl->group >= ctrl->line_len ) ctrl->group = ctrl->line_len ; + /* print label */ + tokens = ( ( ( ctrl->mark && ( ctrl->mark != 10 ) ) ? 2 : 1 ) + + ( ctrl->base ? 0 : 3 ) + SIGNED + SIGNED ) ; + /* send label */ + if ( ctrl->sg ) /* NULL gives no label */ + { while ( * ctrl->sg ) /* step through sg */ + { if ( ( * ctrl->sg > 31 ) BN_NERR ) /* ignore non printable */ + { BN_ERR( bnerr = ) ( BNEEOF putc( * ctrl->sg , ctrl->sm ) ) ; /* o/p */ + ++ i ; } + ++ ctrl->sg ; } } + /* position cursor and send tokens */ + if ( ( ctrl->mark != 10 ) && ( i <= ctrl->nam_len ) ) + { pos = ctrl->nam_len + ( ctrl->nam_len > 0 ) + tokens ; + i += tokens ; + program = 0451 + /* adjust , pad , tokens */ + ! ctrl->group ; } /* set for group = 0 */ + else + { pos = ( i = tokens ) + 1 ; + program = 04531 - ! ctrl->group ; } /* adjust , \n , pad , tokens */ + + while ( program ) + { switch ( program & 7 ) + { case 0 : /* group == 0 , mark == 10 */ + program = 05437 ; /* >> , \n , tokens , */ + break ; + case 1 : /* calculate adjustment */ + lu = ctrl->achip % ctrl->group ; + if ( ! lu ) lu = ctrl->group ; + if ( pos > + ( u = ( int ) ( ( blong ) ctrl->line_len - + ( ctrl->line_len + L2( 1 ) ) % ( ctrl->group + L2( 1 ) ) - lu ) ) ) + { pos = i = tokens ; + program = 04537 ; /* >> , \n , pad , tokens */ + if ( pos > u ) + { pos = i = 0 ; + program = ( ctrl->mark == 10 ) ? + 053437 : /* >> , \n , tokens , \n , pad */ + 05347 ; } } /* >> , tokens , \n , pad */ + if ( ( u = ( ctrl->group - + ( int ) ( ( blong ) ctrl->achip % ctrl->group + pos ) % + ( ctrl->group + 1 ) ) % ( ctrl->group + 1 ) ) != ctrl->group ) + pos += u ; + else + { if ( pos ) -- pos ; + else program = ( ctrl->mark == 10 ) ? + 0437 : /* >> , \n , tokens */ + 047 ; } /* >> , tokens */ + break ; + case 2 : /* group == 0 */ + pos = ctrl->nam_len + tokens ; + program = 0457 ; /* >> , pad , tokens */ + break ; + case 3 : /* newline */ +#ifdef CLEOL + if ( ctrl->sm == stdout ) CLEOL ; +#endif + BN_ERR( if ( ! bnerr ) bnerr = ) ( BNEEOF putc( '\n' , ctrl->sm ) ) ; +#ifdef CLEOL + if ( ctrl->sm == stdout ) CLEOL ; +#endif + break ; + case 4 : /* put tokens */ + BN_ERR( if ( ! bnerr ) bnerr = ) + ( BNEEOF fprintf( ctrl->sm , "%s" /* mark */ +#if SIGNED + "%c " /* sign */ +#endif + "%s" , mark_sg /* 0x */ +#if SIGNED + , ctrl->x [ S_PREC ] ? '-' : '+' +#endif + , ctrl->base ? "" : X_x ) ) ; /* allow 0X */ +#ifdef CLEOL + if ( ctrl->sm == stdout ) CLEOL ; +#endif + break ; + case 5 : /* pad before tokens */ + i = pos - i + 1 ; + while ( i -- BN_NERR ) + BN_ERR( bnerr = ) ( BNEEOF putc( ' ' , ctrl->sm ) ) ; + break ; } + program >>= 3 ; } ; + /* send the body */ + while ( ( ctrl->achip BN_FRAC( > ctrl->chfp ) ) BN_NERR ) + /* character due && ! error */ + { ++ pos ; /* this is this character increment */ + if ( ( ctrl->group && ( blong ) ! ( ctrl->achip % ctrl->group ) ) || + ! ctrl->achip || ( pos > ctrl->line_len ) ) + /* group break */ + { ++ pos ; + if ( ( ( pos >= ( ctrl->line_len - ctrl->group - ! ctrl->group ) ) && + ctrl->line_len ) +#if FRAC + || ( ! ctrl->achip && ctrl->fpnl ) +#endif + ) /* line end */ + { BN_ERR( if ( ! bnerr ) bnerr = ) + ( BNEEOF putc( '\n' , ctrl->sm ) ) ; +#ifdef CLEOL + if ( ctrl->sm == stdout ) CLEOL ; +#endif + pos = 1 ; } /* turn & then space */ +#if FRAC + BN_ERR( if ( ! bnerr ) bnerr = ) + ( BNEEOF putc( ctrl->achip ? ' ' : '.' , ctrl->sm ) ) ; +#else + BN_ERR( if ( ! bnerr ) bnerr = ) + ( BNEEOF putc( ' ' , ctrl->sm ) ) ; +#endif + } /* end group break */ + BN_ERR( if ( ! bnerr ) ) + { -- ctrl->achip ; + /* get the character from the function assigned to ctrl->fcall */ + u = ( * ctrl->fcall ) ( ctrl ) ; /* 000 suppress */ + activ |= ( u | ( ctrl->achip == 0 ) ) ; + BN_ERR( bnerr = ) + ( BNEEOF putc( activ == '0' ? ctrl->lead1 : u , ctrl->sm ) ) ; + ctrl->lead1 = ctrl->leadz ; + } } /* end of : while , if ! bnerr */ + /* terminator, \n, error call, return */ + if ( ctrl->b_end && ( ctrl->b_end != 13 ) BN_NERR ) BN_ERR( bnerr = ) + ( BNEEOF putc( ( char ) ctrl->b_end , ctrl->sm ) ) ; +#ifdef CLEOL + if ( ctrl->sm == stdout ) CLEOL ; +#endif + /* final newline */ +#ifndef BNNONL + BN_ERR( if ( ! bnerr ) bnerr = ) ( BNEEOF ( putc( '\n' , ctrl->sm ) ) ) ; +#endif + return BN_ERR( ( bnerr ) ) ; } + +#ifndef NO_DEC +int bn210 ( struct bnout * ctrl ) +{ int u ; + u = ( int ) ( ( bele ) ctrl->bebuff / E_SZ( 1000 , 100000000 ) ) ; /* take */ + ctrl->bebuff = ( ctrl->bebuff - E_SZ( 1000 , 100000000 ) * u ) * 10 ; + if ( ! ( -- ctrl->n % E_SZ( 4L , L2( 9 ) ) ) ) + { BN_DO( ctrl->n00ip ) ; + ctrl->bebuff = * ctrl->n00ip ; } + return ( u + '0' ) ; } + +#undef BN00MX +#undef NSZ +#undef BNHOP +#undef BN_UP +#undef BN_DO +#endif + + /* bn2x decrements ctrl->n and returns the indicated ascii hex */ +int bn2x ( struct bnout * ctrl ) +{ int ich ; + -- ctrl->n ; +#if FRAC + if ( ctrl->n == ( ( blong ) ( S_PREC ) * E_SZ( 4 , 8 ) ) ) + return ( ctrl->ofm ? '1' : ' ' ) ; +#endif + ich = ( ( unsigned ) + ctrl->x [ ( int ) ( ( blong ) ctrl->n >> E_SZ( 2L , L2( 3 ) ) ) ] >> + ( ( ctrl->n & E_SZ( 3L , L2( 7 ) ) ) * L2( 4 ) ) ) & L2( 15 ) ; + return ( ich + ( ich > 9 ? ( X_ten - 10 ) : '0' ) ) ; } + + /** output a big number as bits + + bit_show outputs to the console + | + bits_out to any stream + | + bn_bits2sm one element to stream */ + +void bit_show ( bele * w ) /* display w as bits */ +{ bits_out ( w , S_LEN , stdout ) ; } + +R_D bits_out ( bele * w , int m , FILE * sm ) +{ BN_ERR( int bnerr = 0 ; ) int mm ; + mm = m ; + while ( m -- BN_ERR( && ! bnerr ) ) /* all elements */ + { BN_ERR( bnerr = ) ( BNEEOF fprintf( sm , + BN_FRAC( m == ( S_FRAC - 1 ) ? BIG_B_POINT : ) " " ) ) ; + BN_ERR( if ( ! bnerr ) bnerr = ) bn_bits2sm ( w [ m ] , sm ) ; + if ( ! m || ! ( ( mm - m ) % ( ( LINE_LEN - 2 ) / E_SZ( 19 , 35 ) ) ) ) + /* if end or EOL */ + { +#ifdef CLEOL + if ( sm == stdout ) CLEOL ; +#endif + BN_ERR( bnerr = ) ( BNEEOF putc( '\n' , sm ) ) ; } } /* end all loop */ + BN_ERR( if ( bnerr ) ) BNE_FUN( "in bits_out" ) ; + BN0 ; } + +BN_E bn_bits2sm ( bele be , FILE * sm ) +{ unsigned o = E_SZ( 0x8000 , 0x80000000 ) ; + do + { if ( putc( ( be & o ) ? '1' : BIG_B_0 , sm ) == EOF ) BNE1 ; } + while ( ( o = o >> 1 ) != 0 ) ; + BNE0 ; } + + /** error function */ + +#if ( ( ERROR_MODE > 1 ) && ( ERROR_MODE < 64 ) ) +void error_function ( char * sg ) +{ +#ifndef NO_BELL + putchar( '\a' ) ; +#endif + + fprintf( ERR_SM , "\nerror : %s\n" +#if ! ( ERROR_MODE & 8 ) + "press a key " +#endif + , sg ) ; +#if ! ( ERROR_MODE & 8 ) +#if ( ERROR_MODE & 63 ) == 2 + fprintf( ERR_SM , +#ifdef GET_CH + "to continue\n" ) ; + GET_CH ; +#else + "to continue, and then press cr or enter\n" ) ; + fflush ( stdin ) ; getchar ( ) ; fflush ( stdin ) ; +#endif +#elif ( ERROR_MODE & 63 ) == 3 + fprintf( ERR_SM , +#ifdef GET_CHE + "or press q to quit\n" ) ; + if ( ( GET_CH | 32 ) != 'q' ) return ; +#else + "or enter q to quit\n" ) ; + fflush ( stdin ) ; + if ( ( getchar ( ) | 32 ) != 'q' ) return ; +#endif +#elif ( ERROR_MODE & 63 ) == 4 + fprintf( ERR_SM , "to quit\n" ) ; +#ifdef GET_CH + GET_CH ; +#else + fflush ( stdin ) ; getchar ( ) ; fflush ( stdin ) ; +#endif +#endif +#endif +#if ( ERROR_MODE & 7 ) > 2 + fprintf( ERR_SM , "process inactive\n" ) ; +#ifdef ICLOSE + ICLOSE ; +#endif + exit ERR_EX ; +#endif +} +#endif + +#ifdef USE_HEAP +#ifndef BN_TAKE_GOT +#define BN_TAKE_GOT + +/** take heap + + argument i of j bytes, return to pointer */ + +void * bn_h ( int i , int j ) +{ void * z ; + if ( ( z = ( void * ) calloc ( i , j ) ) == NULL ) + { fprintf( ERR_SM , "\tno heap memory left\n" ) ; +#ifdef ICLOSE + ICLOSE ; +#endif + exit ERR_EX ; } + return ( z ) ; } + +#endif +#endif + +#endif + diff --git a/lib/big.h b/lib/big.h new file mode 100644 index 0000000..2b3c34d --- /dev/null +++ b/lib/big.h @@ -0,0 +1,669 @@ +/* bign.lib v 1.05.03 April 2013 copyright Alan Firminger + + a library for large number mathematics + described in buserdoc.htm */ + +/* to separate bign.h, copy out lines 7 to 660 8<...........................*/ +/* bign.h */ + +/* delete this comment and use these blank lines for any standing defines + that you desire without changing the line numbers */ + + + + + + + + +#ifndef BN_H_GOT +#define BN_H_GOT + +#include +#include +#include + +void write_hex(); +void read_hex(); + +#define PREC 128 +#define FRAC 0 +#define WORD_SIZE 4 +//#define NO_DEC +#define BN_VER 10503 + + /* settle BNLONG and L2( ) */ +#if ( defined LLONG_MAX ) && ( ! defined NO_LL ) +#if LLONG_MAX == 0x7FFFFFFFFFFFFFFFLL +#define BN_LL 1 +#define L2( A ) A ## LL +#define BNLONG long long +#define DTYP 2 +#define QLQ "ll" +#endif +#endif +#ifndef BN_LL +#define BN_LL 0 +#define L2( A ) A ## L +#define BNLONG long +#define QLQ "l" +#endif +#define BNULONG unsigned BNLONG +#define BNELE unsigned int + /* int size definitions */ +#if BN_LL || ( LONG_MAX == 0x7FFFFFFFFFFFFFFFL ) && ( INT_MAX == 0x7FFFFFFF ) +#define E_SZ( A , B ) ( B ) +#define BY_P_E 4 +#define BNXPE L2( 8 ) +#define QWQ "8" +#define BNFUL L2( 0xFFFFFFFFU ) +#define BNSHIFT L2( 5 ) +#define BNMASK L2( 31 ) +#define B_P_E L2( 32 ) +#ifndef NO_DEC +#define BNASZ( A ) ((L2(24394249U)*( A ))/L2(38539962U)+L2(9U)*( A )+L2(1U)) +/* below, fraction is > log_10 ( 2 ) in 15th decimal place */ +#define BNBSZ( A ) ((L2(7647217U)*( A +L2(1U)))/L2(25403505U)+L2(1U)) +#define BNHOP 1003188697 +#endif +#else +#if LONG_MAX == 0x7FFFFFFFL +#define E_SZ( A , B ) ( A ) +#define BY_P_E 2 +#define BNXPE 4L +#define QWQ "4" +#define BNFUL 0xFFFFUL +#define BNSHIFT 4L +#define BNMASK 15L +#define B_P_E 16L +#ifndef NO_DEC +#define BNASZ( A ) ((52031UL*( A ))/63726UL+4UL*( A )+1UL) +/* below, fraction is > * log_10 ( 2 ) in 9th decimal place */ +#define BNBSZ( A ) ((4004UL*( A +1UL))/13301UL+1UL) +#define BNHOP 27208 +#endif +#if INT_MAX == 0x7FFF +#else +#if SHRT_MAX == 0x7FFF +#undef BNELE +#define BNELE unsigned short +#define DTYP 1 +#else +#error cannot compile with your compiler +#endif +#undef BN_LL +#endif + +#else +#error cannot compile with your compiler +#endif +#endif +#ifndef DTYP +#define DTYP 0 +#endif + /* default definitions */ +#ifndef PREC +#define PREC 4 +#endif +#ifndef FRAC +#define FRAC 0 +#endif +#ifndef SIGNED +#define SIGNED 1 +#endif + + /* tests to stop compilation */ +#if (PREC<4)||(FRAC<0)||(FRAC>=PREC)||(PREC>E_SZ(0x7FFB,0x7FFFFFFB)) +#error stop in bign.h : PREC or FRAC are incompatible or out of range +#endif + +#define LEN ( PREC + SIGNED ) +#define S_LEN ( S_PREC + SIGNED ) + + /* type defines */ +typedef BNELE big_n [ LEN ] ; +typedef BNELE bele ; +typedef BNLONG blong ; +typedef BNULONG ublong ; +#undef BNELE +#undef BNLONG +#undef BNULONG + + + + + /* consequent definitions */ +#ifndef BIG_B_0 +#define BIG_B_0 ( char ) '.' +#endif + +#if FRAC +#ifndef BIG_B_POINT +#define BIG_B_POINT " . " +#endif +#else +#ifdef B_ROUND +#undef B_ROUND +#ifdef B_ROUND +#error B_ROUND defined with ! FRAC +#endif +#endif +#ifdef BIG_DAJ +#undef BIG_DAJ +#ifdef BIG_DAJ +#error BIG_DAJ defined with ! FRAC +#endif +#endif +#endif + +#ifdef NO_DEC +#define BN_DEC( A ) +#else +#define BN_DEC( A ) A +#endif + + /* global variables or macro constants for soft size */ +#ifndef NO_DEC +#if FRAC +#define FRAC_CHAR BNASZ( S_FRAC ) +#endif +#define INT_CHAR BNASZ( S_PREC - S_FRAC ) +#endif + +#ifndef SOFT_SIZE +#define S_PREC PREC +#define s_prec PREC +#define S_FRAC FRAC +#define s_frac FRAC +#else +int s_prec = PREC ; +#define S_PREC s_prec +#define S_FRAC s_frac +#if FRAC +int s_frac = FRAC ; +#else +#define s_frac 0 +#endif +#endif + /* coding definitions */ +#if SIGNED +#define BN_SIG( A ) A +#define BN_NSIG( A ) +#else +#define BN_SIG( A ) +#define BN_NSIG( A ) A +#endif +#if FRAC +#define BN_FRAC( A ) A +#define BN_NFRAC( A ) +#else +#define BN_FRAC( A ) +#define BN_NFRAC( A ) A +#endif + +#ifndef ERROR_MODE +#define ERROR_MODE 3 +#endif + +#if ( ERROR_MODE & 3 ) +#define R_D int +#define BN_ERR3( A ) A +#define BN_RN return +#else +#define R_D void +#define BN_ERR3( A ) +#define BN_RN +#endif + +#if ERROR_MODE +#define BN_ERR( A ) A +#define BNEEOF EOF == +#define BN_NERR && ! bnerr +#define BN_E int +#define BNE1 return ( 1 ) +#define BNE0 return ( 0 ) +#define BNDV +#else +#define BN_ERR( A ) +#define BNEEOF +#define BN_NERR +#define BN_E void +#define BNE1 return +#define BNE0 return +#define BNDV return +#endif + +#ifndef ERR_SM +#define ERR_SM stdout +#endif +#ifndef ERR_EX +#define ERR_EX ( - 1 ) +#endif + +#if ( ERROR_MODE & 4 ) +#define BNE_FUN( sg ) error_function ( sg ) +#define BN0 +#elif ( ERROR_MODE & 2 ) +#define BNE_FUN( sg ) { error_function ( sg ) ; return ( 1 ) ; } +#define BN0 return ( 0 ) +#elif ( ERROR_MODE == 1 ) +#define BNE_FUN( sg ) return ( 1 ) +#define BN0 return ( 0 ) +#elif ! ERROR_MODE +#define BNE_FUN( sg ) +#define BN0 +#endif + +#ifdef USE_HEAP +#define BN_HEAP( A ) A +#define BN_NHEAP( A ) +#define FREE_BN_( x ) free ( x ) +#define DEF_BN_( x ) bele * x +#define BN_HEAP_( x ) x = ( bele * ) bn_h ( S_LEN , BY_P_E ) +#else +#define BN_HEAP( A ) +#define BN_NHEAP( A ) A +#define FREE_BN_( x ) +#define DEF_BN_( x ) big_n x +#define BN_HEAP_( x ) +#endif + +#ifdef BIG_TRACE +#ifndef TR_SM +#define TR_SM stdout +#define BN_TRIN( A ) A ; fflush( stdout ) ; +#define BN_TRAC( A ) putc( A , stdout ) ; fflush( stdout ) ; +#else +#define BN_TRIN( A ) +#define BN_TRAC( A ) putc( A , TR_SM ) ; +#endif +#define BN_TROUT( A ) A ; +#define BN_NTR( A ) +#else +#define BN_TRIN( A ) +#define BN_TROUT( A ) +#define BN_TRAC( A ) +#define BN_NTR( A ) A +#endif + +#ifndef FILE_SM +#define FILE_SM stdout +#endif + +#if ( defined MDUF ) && ! FRAC +#undef MDUF +#ifdef MDUF +#error MDUF defined with ! FRAC +#endif +#endif + +#ifdef MDUF +int muluf = MDUF , divuf = MDUF ; +#define BNCUF , divuf +#define BNUF( A ) A +#define BNCPABS( A , B ) bncp_abs ( A + nbot , B + nbot , bnact ) +#else +#define muluf S_FRAC +#define divuf S_PREC +#define BNCUF +#define BNUF( A ) +#define BNCPABS( A , B ) cp_abs ( A , B ) +#endif + + /* check and convert from ascii digits */ +/* bn_n_( c ) c yields + < 0 255 + 0 to 47 255 + 48 to 57 x - 48 + 58 to 64 255 + > 64 x - 55 */ + +#define bn_n_( c ) ((unsigned)(c-48)<10?c-48:c>64?c>96?c-87:c-55:255) + +#ifndef B_ROUND +#define B_ROUND 0 +#endif + /* i/o definitions */ +#ifndef BIG_DAJ +#define BIG_DAJ ( FRAC > 0 ) +#endif +#if ( BIG_DAJ == 1 ) && ( ! defined NO_DEC ) +#define BNA_1 , 1 +#define BNA_0 , 0 +#else +#define BNA_1 +#define BNA_0 +#endif +#ifndef NAME_LEN +#define NAME_LEN 10 +#endif +#ifndef BIG_MARK +#define BIG_MARK '#' +#endif +#ifndef BIG_END +#define BIG_END ',' +#endif +#ifndef LINE_LEN +#define LINE_LEN 80 +#endif +#ifndef CON_ROWS +#define CON_ROWS 25 +#endif +#ifndef BIG_GROUP +#define BIG_GROUP 10 +#endif +#ifndef X_x +#define X_x "0x " +#endif +#ifndef X_ten +#define X_ten 'A' +#endif + + /* read stream to big number */ +#define sm_2_big_( sm , x ) big_in ( sm , BIG_MARK , x , 10 , BIG_END ) +#define smx_2_big_( sm , x ) big_in ( sm , BIG_MARK , x , 16 , BIG_END ) + +#define BNXICH ( ( blong ) ( ( S_PREC - S_FRAC ) * BNXPE ) ) + + /* V chip mode chfp leadz base V */ +#ifndef NO_DEC +#ifndef OUT_DEF +#if FRAC +#define OUT_DEF L2( 0 ) , 0 , L2( 0 ) , ' ' , 10 +#else +#define OUT_DEF L2( 0 ) , ' ' , 10 +#endif +#endif +#endif +#ifndef HEX_DEF +#if FRAC +#define HEX_DEF BNXICH , 0 , L2( 0 ) , '0' , 0 +#else +#define HEX_DEF BNXICH , '0' , 0 +#endif +#endif + /* mark end group line */ +#ifndef BOD_DEF +#define BOD_DEF ' ' , 0 , BIG_GROUP , LINE_LEN +#endif +#ifndef MC_DEF +#define MC_DEF BIG_MARK , BIG_END , BIG_GROUP , LINE_LEN +#endif + + /* convenient i/o defines */ +/* x decimal to screen */ +#define cn_( x ) big_out ( 0 , NULL , x , stdout , BOD_DEF , OUT_DEF ) +/* x decimal to printer */ +#define pr_( x ) big_out ( 0 , NULL , x , stdprn , BOD_DEF , OUT_DEF ) +/* x decimal to stream for humans */ +#define ob_( x , sm ) big_out ( 0 , NULL , x , sm , BOD_DEF , OUT_DEF ) +/* x decimal to stream for m/c */ +#define om_( x , sm ) big_out ( 0 , NULL , x , sm , MC_DEF , OUT_DEF ) + +/* string then x decimal to screen */ +#define c2_( sg , x ) big_out ( NAME_LEN , sg , x , stdout , BOD_DEF , OUT_DEF ) +/* string then x decimal to printer */ +#define p2_( sg , x ) big_out ( NAME_LEN , sg , x , stdprn , BOD_DEF , OUT_DEF ) +/* string then x decimal to stream for humans */ +#define ob2_( sg , x , sm ) big_out ( NAME_LEN, sg, x, sm, BOD_DEF, OUT_DEF ) +/* string then x decimal to stream for m/c */ +#define om2_( sg , x , sm ) big_out ( NAME_LEN, sg, x, sm, MC_DEF, OUT_DEF ) + +/* x hex to screen */ +#define cx_( x ) big_out ( 0 , NULL , x , stdout , BOD_DEF , HEX_DEF ) +/* x hex to printer */ +#define px_( x ) big_out ( 0 , NULL , x , stdprn , BOD_DEF , HEX_DEF ) +/* x hex to stream for humans */ +#define obx_( x , sm ) big_out ( 0 , NULL , x , sm , BOD_DEF , HEX_DEF ) +/* x hex to stream for m/c */ +#define omx_( x , sm ) big_out ( 0 , NULL , x , sm , MC_DEF , HEX_DEF ) +/* string then x hex to screen */ +#define cx2_( sg , x ) big_out ( NAME_LEN, sg, x, stdout, BOD_DEF, HEX_DEF ) +/* string then x hex to printer */ +#define px2_( sg , x ) big_out ( NAME_LEN, sg, x, stdprn, BOD_DEF, HEX_DEF ) +/* string then x hex to stream for humans */ +#define obx2_( sg , x , sm ) big_out ( NAME_LEN, sg, x, sm, BOD_DEF, HEX_DEF) +/* string then x hex to stream for m/c */ +#define omx2_( sg , x , sm ) big_out ( NAME_LEN, sg, x, sm, MC_DEF, HEX_DEF ) +#define tr_pr_( A , B ) big_out ( 5 , A , B , TR_SM , MC_DEF , HEX_DEF ) + +#ifndef USE_HEAP +#ifndef NO_DEC +#define BN_NEED ( BNASZ( PREC ) + SIGNED + ( FRAC > 0 ) * 2 ) +#else +#define BN_NEED ( PREC * BY_P_E * 2 + SIGNED + ( FRAC > 0 ) + 2 ) +#endif +#else +#ifndef NO_DEC +#define BN_NEED ( SIGNED + BNASZ( S_PREC ) + ( FRAC > 0 ) * 2 ) +#else +#define BN_NEED ( S_PREC * BY_P_E * 2 + SIGNED + ( FRAC > 0 ) + 2 ) +#endif +#endif + +#ifndef BNKB_MAX +#ifdef GET_C_POS +#define BNKB_MAX ( LINE_LEN * 5 ) +#else +#define BNKB_MAX ( 80 ) +#endif +#endif + +#define BNKB_CH ( BN_NEED > BNKB_MAX ? BNKB_MAX : BN_NEED ) + + /* structures for decimal conversion control */ +#ifndef NO_DEC +struct bn_in { bele * x ; BN_FRAC( bele * h ; ) + ublong ulbuff ; blong n ; int m ; } ; +#endif +struct bnout { int nam_len ; char * sg ; int mark ; bele * x ; int b_end ; + blong group , line_len ; int base ; FILE * sm ; + blong n ; blong chip , achip ; + BN_FRAC( int ofm ; int frnd ; int fpnl ; blong chfp ; ) + int leadz , lead1 ; +#ifndef NO_DEC + bele * n00ip ; +#if ( defined USE_HEAP && defined SOFT_SIZE ) || ( PREC > BNHOP ) + bele * n00top ; bele * n002 ; +#endif +#endif + bele bebuff ; int ( * fcall ) ( struct bnout * ctrl ) ; } ; + + /* function prototypes */ +/* utilities */ +void zero_big ( bele * w ) ; +void bnflen ( bele * w , unsigned sz , bele u ) ; +void copy_big ( bele * w , bele * x ) ; +void bnclen ( bele * w , bele * x , unsigned m ) ; + +/* maths, big on big */ +R_D add_big ( bele * w , bele * x , bele * y ) ; +#if SIGNED +BN_E bnaddub ( bele * w , bele * x , bele * y ) ; +#else +#define bnaddub rawadd_big +#endif +R_D sub_big ( bele * w , bele * x , bele * y ) ; +void bns_ub ( bele * w , bele * x , bele * y ) ; +R_D mult_big ( bele * w , bele * x , bele * y ) ; +R_D div_big ( bele * w , bele * x , bele * y ) ; +R_D mod_big ( bele * w , bele * x , bele * z ) ; +R_D div_big_4 ( bele * w , bele * x , bele * y , bele * z ) ; +#if FRAC +#if B_ROUND +#define BN_ROUND | INT_MIN +#else +#define BN_ROUND +#endif +#ifdef MDUF +#define rawdiv_big_( W , X , Y ) bn_divide ( W,X,Y , NULL , 0 BN_ROUND , divuf ) +#define bndo0_( W , X , Y ) bn_divide ( W , X , Y , NULL , 0 , divuf ) +#define rawmod_big_( W , X , Y ) bn_divide( W , X , NULL , Y , S_FRAC , S_PREC ) +#define rawi_div_( W , X , Y ) bn_divide ( W , X , Y , NULL , S_FRAC , S_PREC ) +#define rawdiv_4_( W , X , Y , Z ) bn_divide ( W , X , Y , Z , S_FRAC , S_PREC ) +#else +#define rawdiv_big_( W , X , Y ) bn_divide ( W , X , Y , NULL , 0 BN_ROUND ) +#define bndo0_( W , X , Y ) bn_divide ( W , X , Y , NULL , 0 ) +#define rawmod_big_( W , X , Z ) bn_divide ( W , X , NULL , Z , S_FRAC ) +#define rawi_div_( W , X , Y ) bn_divide ( W , X , Y , NULL , S_FRAC ) +#define rawdiv_4_( W , X , Y , Z ) bn_divide ( W , X , Y , Z , S_FRAC ) +#endif + +BN_E bn_divide ( bele * w , bele * x , bele * y , bele * z , int iend +#ifdef MDUF + , int bnuf +#endif + ) ; +R_D i_div_big ( bele * w , bele * x , bele * y ) ; +#else +#define rawdiv_big_( W , X , Y ) bn_divide ( W , X , Y , NULL ) + //#define rawmod_big_( W , X , Y ) rawdiv_big_( W , X , Y ) +#define rawmod_big_( W , X , Y ) bn_divide ( W , X , NULL,Y ) +#define rawi_div_( W , X , Y ) bn_divide ( W , X , Y , NULL ) +#define rawdiv_4_( W , X , Y , Z ) bn_divide ( W , X , Y , Z ) +#define bndo0_( W , X , Y ) bn_divide ( W , X , Y , NULL ) +BN_E bn_divide ( bele * w , bele * x , bele * y , bele * z ) ; +#define i_div_big div_big +#endif + +#if ( ERROR_MODE > 1 ) || ( defined BIG_TRACE ) +BN_E rawadd_big ( bele * w , bele * x , bele * y ) ; +BN_E rawsub_big ( bele * w , bele * x , bele * y ) ; +BN_E rawmult_big ( bele * w , bele * x , bele * y ) ; +#else +#define rawadd_big add_big +#define rawsub_big sub_big +#define rawmult_big mult_big +#endif + +R_D big_shift ( blong shift , bele * x , bele * y ) ; +void bns_up ( ublong shift , bele * x , bele * y , int m ) ; +void bns_down ( ublong shift , bele * x , bele * y , int m ) ; + +/* maths, big on int */ +R_D div_bintoi ( bele * x , int i , bele * y ) ; +#if ( ERROR_MODE > 1 ) || ( defined BIG_TRACE ) +BN_E rawdivbintoi ( bele * x , int i , bele * y ) ; +#else +#define rawdivbintoi div_bintoi +#endif + +/* maths, int value on big */ +R_D add_int ( int i , bele * x , bele * y ) ; +R_D sub_int ( int i , bele * x , bele * y ) ; +BN_E add_li ( blong li , bele * x ) ; +BN_E add_li_place ( blong li , bele * x , int m ) ; +int bnadd_ul ( ublong ul , bele * x , int m ) ; +void bnsub_ul ( ublong ul , bele * x , int m ) ; +void bns_lipos ( ublong li , bele * x , int m ) ; +R_D mult_int ( int i , bele * x , bele * y ) ; +BN_E mult_li ( blong li , bele * x , bele * y ) ; +unsigned bnmulul ( ublong ul , bele * x , bele * y , int sz ) ; +R_D div_int ( int i , bele * x , bele * y ) ; +#if ! ( FRAC ) +R_D div_i_4 ( int i , bele * x , bele * y , int * rem ) ; +BN_E div_li_4 ( blong li , bele * x , bele * y , blong * rem ) ; +#endif +BN_E div_li ( blong li , bele * x , bele * y ) ; +unsigned bndivul ( ublong lucy , ublong li , bele * x , bele * y , int m ) ; + +/* number testing */ +blong overbit ( bele * x ) ; +blong a_obitdif ( bele * x , bele * y ) ; +blong obitdif ( bele * x , bele * y ) ; +#if SIGNED +blong bnbn_uobit ( bele * cp_absx ) ; +blong bn_ubdif ( bele * x , bele * y ) ; +blong bn_ubsum ( bele * x , bele * y ) ; +#else +#define bn_ubdif obitdif +#endif +blong mssb ( bele * x ) ; +blong bn_msx ( bele * x , int sz ) ; +#if FRAC +blong ntop ( bele * x ) ; +#else +#define ntop mssb +#endif +int cp_abs ( bele * x , bele * y ) ; +#ifdef MDUF +int bncp_abs ( bele * w , bele * x , int m ) ; +#else +#define bncp_abs cp_abs +#endif + +/* conversion, input & output and auxiliaries */ +R_D big_in ( FILE * sm , int mark , bele * x , int base , int b_end ) ; +#if ( ERROR_MODE > 1 ) || ( FRAC && SIGNED ) +BN_E bnin1 ( FILE * sm , int mark , bele * x , int base , + int b_end +#if ( FRAC && SIGNED ) + , int xtra +#endif + ) ; +#else +#define bnin1 big_in +#endif +int bnin2 ( FILE * sm , bele * z , int base , int ich , int b_end +#if ( FRAC && SIGNED ) + , int xtra +#endif +#ifndef NO_DEC + , struct bn_in * sc ) ; +int bn_dec_in ( FILE * sm , bele * x , int ich , int b_end +#endif + ) ; + +int bn2i ( FILE * sm , int i_end ) ; +void bnplant ( unsigned ich , bele * x , blong i ) ; +#ifndef NO_DEC +int bn_dec_in_ip ( int ich , struct bn_in * sc ) ; +int bn_decip_end ( struct bn_in * sc ) ; +BN_FRAC( void bn_dec_in_fp ( int ich , struct bn_in * sc ) ; ) +BN_FRAC( void bn_decfp_end ( struct bn_in * sc ) ; ) +#endif + +int kb_2_big ( bele * x ) ; +int kb_2_big_2 ( bele * x , int base ) ; + +R_D num_here ( char * sg , bele * x ) ; +int bnnum_here ( char * sg , int base , bele * x +#if ( BIG_DAJ == 1 ) && ( ! defined NO_DEC ) + , int asc_inc +#endif + ) ; + + + + +R_D big_out ( int name_len , char * sg , bele * x , FILE * sm , + int mark , int b_end , int group , unsigned line_len , blong chip , +#if FRAC + int fmode , blong chfp , +#endif + int leadz , int base ) ; +BN_E bn_readyx ( struct bnout * ctrl ) ; +#ifndef NO_DEC +BN_E bn_m_00 ( struct bnout * ) ; +#endif +BN_E bn_s_out ( struct bnout * ) ; +#ifndef NO_DEC +void bni10i ( struct bnout * ) ; +int bn210 ( struct bnout * ) ; +#endif +int bn2x ( struct bnout * ) ; + +void bit_show ( bele * w ) ; +R_D bits_out ( bele * w , int m , FILE * sm ) ; +BN_E bn_bits2sm ( bele be , FILE * sm ) ; + +/* error function */ +#if ( ( ERROR_MODE & 63 ) > 1 ) +void error_function ( char * sg ) ; +#endif +#ifdef USE_HEAP +void * bn_h ( int i , int j ) ; +#endif + +#endif + diff --git a/src/crypt_rsa.c b/src/crypt_rsa.c new file mode 100644 index 0000000..8328f08 --- /dev/null +++ b/src/crypt_rsa.c @@ -0,0 +1,48 @@ +#include +#include +#include + +#include "../lib/big.h" +#include "../inc/crypt_utils.h" +#include "../inc/key_utils.h" + +int main(int argc, char *argv[]) { + public_key pub_key; + private_key priv_key; + big_n input_big, output_big; + FILE *input_file, *output_file; + + if (argc != 5) { + fprintf(stderr, "Usage : %s <-e|-d> \n", argv[0]); + return EXIT_FAILURE; + } + + input_file = fopen(argv[3], "r"); + if (!input_file) { + fprintf(stderr, "Une erreur est survenue lors de la lecture du fichier \"%s\".\n", argv[3]); + return EXIT_FAILURE; + } + read_hex(input_file, input_big); + fclose(input_file); + + if (strcmp(argv[1], "-e") == 0) { + pub_key = public_key_read(argv[2]); + encrypt(pub_key, input_big, output_big); + } else if (strcmp(argv[1], "-d") == 0) { + priv_key = private_key_read(argv[2]); + decrypt(priv_key, input_big, output_big); + } else { + fprintf(stderr, "Commande \"%s\" invalide. Commandes disponibles :\n\t-e pour crypter\n\t-d pour décrypter\n", argv[2]); + return EXIT_FAILURE; + } + + output_file = fopen(argv[4], "w"); + if (!output_file) { + fprintf(stderr, "Une erreur est survenue lors de l'écriture du fichier \"%s\".\n", argv[4]); + return EXIT_FAILURE; + } + write_hex(output_file, output_big, '\n'); + fclose(output_file); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/src/crypt_rsa_file.c b/src/crypt_rsa_file.c new file mode 100644 index 0000000..7c36271 --- /dev/null +++ b/src/crypt_rsa_file.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include + +#include "../lib/big.h" +#include "../inc/crypt_utils.h" +#include "../inc/key_utils.h" + +void encrypt_file(public_key pub_key, const char *input_filepath, const char *output_filepath) { + FILE *input_file, *output_file; + size_t total_size, bits, encrypted_size, input_data_size; + big_n input_data, encrypted_data; + + input_file = fopen(input_filepath, "r"); + if (!input_file) { + fprintf(stderr, "Une erreur est survenue lors de la lecture du fichier \"%s\".\n", input_filepath); + exit(EXIT_FAILURE); + } + + output_file = fopen(output_filepath, "w"); + if (!output_file) { + fprintf(stderr, "Une erreur est survenue lors de l'ecriture du fichier \"%s\".\n", output_filepath); + exit(EXIT_FAILURE); + } + + fseek(input_file, 0, SEEK_END); + total_size = ftell(input_file); + fseek(input_file, 0, SEEK_SET); + + fwrite(&total_size, sizeof(total_size), 1, output_file); + + bits = mssb(pub_key.n); + encrypted_size = (bits + 7) / 8; + input_data_size = (bits - 1) / 8; + + zero_big(input_data); + while (fread(input_data, 1, input_data_size, input_file) > 0) { + encrypt(pub_key, input_data, encrypted_data); + fwrite(encrypted_data, 1, encrypted_size, output_file); + zero_big(input_data); + } + + fclose(input_file); + fclose(output_file); +} + +void decrypt_file(private_key priv_key, const char *input_filepath, const char *output_filepath) { + FILE *input_file, *output_file; + size_t total_size, bits, encrypted_size, output_data_size, total_written; + big_n encrypted_data, output_data; + + input_file = fopen(input_filepath, "r"); + if (!input_file) { + fprintf(stderr, "Une erreur est survenue lors de la lecture du fichier \"%s\".\n", input_filepath); + exit(EXIT_FAILURE); + } + + output_file = fopen(output_filepath, "w"); + if (!output_file) { + fprintf(stderr, "Une erreur est survenue lors de l'ecriture du fichier \"%s\".\n", output_filepath); + exit(EXIT_FAILURE); + } + + fread(&total_size, sizeof(total_size), 1, input_file); + + bits = mssb(priv_key.n); + encrypted_size = (bits + 7) / 8; + output_data_size = (bits - 1) / 8; + + total_written = 0; + + zero_big(encrypted_data); + while (fread(encrypted_data, 1, encrypted_size, input_file) > 0) { + decrypt(priv_key, encrypted_data, output_data); + fwrite(output_data, 1, (total_written + output_data_size > total_size) ? total_size - total_written : output_data_size, output_file); + total_written += output_data_size; + zero_big(encrypted_data); + } + + fclose(input_file); + fclose(output_file); +} + +int main(int argc, char *argv[]) { + private_key priv_key; + public_key pub_key; + + if (argc != 5) { + fprintf(stderr, "Usage : %s <-e|-d> \n", argv[0]); + return EXIT_FAILURE; + } + + if (strcmp(argv[1], "-e") == 0) { + pub_key = public_key_read(argv[2]); + encrypt_file(pub_key, argv[3], argv[4]); + } else if (strcmp(argv[1], "-d") == 0) { + priv_key = private_key_read(argv[2]); + decrypt_file(priv_key, argv[3], argv[4]); + } else { + fprintf(stderr, "Commande \"%s\" invalide. Commandes disponibles :\n\t-e pour crypter\n\t-d pour décrypter\n", argv[2]); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/crypt_utils.c b/src/crypt_utils.c new file mode 100644 index 0000000..87376aa --- /dev/null +++ b/src/crypt_utils.c @@ -0,0 +1,44 @@ +#include + +#include "../lib/big.h" +#include "../inc/key_utils.h" +#include "../inc/crypt_utils.h" + +void big_pow_mod(big_n a, big_n b, big_n n, big_n result) { + big_n a_mod, b_mod, zero; + + mod_big(n, a, a_mod); + mod_big(n, b, b_mod); + zero_big(zero); + zero_big(result); + result[0] = 1; + + while (cp_abs(b_mod, zero) != 0) { + if (b_mod[0] % 2 == 1) { + mult_big(result, a_mod, result); + mod_big(n, result, result); + } + + big_shift(-1, b_mod, b_mod); + mult_big(a_mod, a_mod, a_mod); + mod_big(n, a_mod, a_mod); + } +} + +void encrypt(public_key pub_key, big_n input, big_n output) { + if (cp_abs(input, pub_key.n) < 0) { + fprintf(stderr, "Le nombre à crypter doit être inférieur au module de chiffrement.\n"); + exit(EXIT_FAILURE); + } + + big_pow_mod(input, pub_key.e, pub_key.n, output); +} + +void decrypt(private_key priv_key, big_n input, big_n output) { + if (cp_abs(input, priv_key.n) < 0) { + fprintf(stderr, "Le nombre à décrypter doit être inférieur au module de chiffrement.\n"); + exit(EXIT_FAILURE); + } + + big_pow_mod(input, priv_key.d, priv_key.n, output); +} diff --git a/src/key_gen.c b/src/key_gen.c new file mode 100644 index 0000000..5ae6178 --- /dev/null +++ b/src/key_gen.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include + +#include "../lib/big.h" +#include "../inc/key_utils.h" +#include "../inc/crypt_utils.h" + +#define RM_ITERATIONS 100 +#define RSA_KEY_SIZE 2048 + + +void big_random_bits(size_t bits, big_n result) { + size_t i, size, index, offset; + uint8_t byte; + + zero_big(result); + + for (i = 0; i < bits; i++) { + byte = rand() % 256; + + size = 8; + if (bits - i < 8) size = bits - i; + + byte &= (1 << size) - 1; + index = i / 32; + offset = i % 32; + result[index] |= (uint32_t)byte << offset; + i += 8; + } +} + +void big_random(big_n min, big_n max, big_n result) { + big_n range; + + sub_big(min, max, range); + big_random_bits(mssb(range), result); + mod_big(range, result, result); + add_big(min, result, result); +} + +void big_rmod(big_n a, big_n n, big_n result) { + big_n one, x, y, A, N, quotient, temp; + + zero_big(one); + one[0] = 1; + + if (cp_abs(n, one) == 0) { + zero_big(result); + return; + } + + zero_big(x); + x[0] = 1; + + zero_big(y); + copy_big(a, A); + copy_big(n, N); + + while (cp_abs(A, one) < 0) { + div_big(N, A, quotient); + copy_big(N, temp); + mod_big(N, A, N); + copy_big(temp, A); + copy_big(y, temp); + mult_big(quotient, y, y); + sub_big(y, x, y); + copy_big(temp, x); + } + + if (x[PREC] != 0) add_big(n, x, x); + + copy_big(x, result); +} + +void big_gcd(big_n a, big_n b, big_n result) { + big_n zero, a_mod, b_mod, mod; + + zero_big(zero); + copy_big(a, a_mod); + copy_big(b, b_mod); + + while (cp_abs(b_mod, zero) != 0) { + mod_big(b_mod, a_mod, mod); + + copy_big(b_mod, a_mod); + copy_big(mod, b_mod); + } + + copy_big(a_mod, result); +} + + +void private_key_write(private_key priv_key, const char *filepath) { + FILE *file = fopen(filepath, "w"); + if (!file) { + fprintf(stderr, "Une erreur est survenue lors de l'ecriture du fichier \"%s\"*.\n", filepath); + exit(EXIT_FAILURE); + } + + write_hex(file, priv_key.n, '\n'); + write_hex(file, priv_key.e, '\n'); + write_hex(file, priv_key.d, '\n'); + + fclose(file); +} + +void public_key_write(public_key pub_key, const char *filepath) { + FILE *file = fopen(filepath, "w"); + if (!file) { + fprintf(stderr, "Une erreur est survenue lors de l'ecriture du fichier \"%s\".\n", filepath); + exit(EXIT_FAILURE); + } + + write_hex(file, pub_key.n, '\n'); + write_hex(file, pub_key.e, '\n'); + + fclose(file); +} + +bool is_prime(big_n n, int k) { + big_n zero, prime, mod, one, min, max, n1, d, a, x; + uint32_t firsts_primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101}; + size_t i, r, j; + bool rm_prime_witness; + + if (n[0] % 2 == 0) + return false; + + if (n[0] < 2) + return false; + + zero_big(zero); + + zero_big(prime); + + for (i = 0; i < sizeof(firsts_primes) / sizeof(uint32_t); i++) { + prime[0] = firsts_primes[i]; + + mod_big(prime, n, mod); + + if (cp_abs(mod, zero) == 0) + return false; + } + + zero_big(one); + one[0] = 1; + + zero_big(min); + min[0] = 2; + + copy_big(n, max); + sub_int(2, max, max); + + copy_big(n, n1); + sub_int(1, n1, n1); + + copy_big(n1, d); + + r = 0; + while (d[0] % 2 == 0) { + r++; + big_shift(-1, d, d); + } + + for (int i = 0; i < k; i++) { + big_random(min, max, a); + + big_pow_mod(a, d, n, x); + + if (cp_abs(x, one) == 0 || cp_abs(x, n1) == 0) continue; + + rm_prime_witness = false; + + for (j = 0; j < r; j++) { + mult_big(x, x, x); + mod_big(n, x, x); + + if (cp_abs(x, one) == 0) return false; + + if (cp_abs(x, n1) == 0) { + rm_prime_witness = true; + break; + } + } + + if (!rm_prime_witness) return false; + } + + return true; +} + +void prime_gen(size_t bits, int k, big_n prime) { + big_random_bits(bits, prime); + prime[(bits - 1) / 32] |= 1 << ((bits - 1) % 32); + prime[0] |= 1; + while (!is_prime(prime, k)) add_int(2, prime, prime); +} + +private_key private_key_gen() { + private_key priv_key; + big_n p, q, p1, q1, phi, one, cd; + + prime_gen(RSA_KEY_SIZE / 2, RM_ITERATIONS, p); + prime_gen(RSA_KEY_SIZE / 2, RM_ITERATIONS, q); + + mult_big(p, q, priv_key.n); + + copy_big(p, p1); + sub_int(1, p1, p1); + + copy_big(q, q1); + sub_int(1, q1, q1); + + mult_big(p1, q1, phi); + + zero_big(one); + one[0] = 1; + + do { + big_random(one, phi, priv_key.e); + big_gcd(priv_key.e, phi, cd); + } while (cp_abs(cd, one) != 0); + + big_rmod(priv_key.e, phi, priv_key.d); + + return priv_key; +} + +public_key public_key_gen(private_key priv_key) { + public_key pub_key; + copy_big(priv_key.n, pub_key.n); + copy_big(priv_key.e, pub_key.e); + return pub_key; +} + +int main(int argc, char *argv[]) { + srand(time(NULL)); + + private_key priv_key; + public_key pub_key; + + if (argc != 3) { + fprintf(stderr, "Usage : %s \n", argv[0]); + return EXIT_FAILURE; + } + + priv_key = private_key_gen(); + pub_key = public_key_gen(priv_key); + + private_key_write(priv_key, argv[1]); + public_key_write(pub_key, argv[2]); + + return EXIT_SUCCESS; +} diff --git a/src/key_utils.c b/src/key_utils.c new file mode 100644 index 0000000..2dd554a --- /dev/null +++ b/src/key_utils.c @@ -0,0 +1,78 @@ +#include "../lib/big.h" +#include "../inc/key_utils.h" + +private_key private_key_read(const char *filepath) { + FILE *file; + private_key priv_key; + big_n zero; + + file = fopen(filepath, "r"); + if (!file) { + fprintf(stderr, "Une erreur est survenue lors de la lecture du fichier \"%s\".\n", filepath); + exit(EXIT_FAILURE); + } + + read_hex(file, priv_key.n); + if (feof(file)) { + fprintf(stderr, "Clé privée \"%s\" invalide.\n", filepath); + exit(EXIT_FAILURE); + } + + read_hex(file, priv_key.e); + if (feof(file)) { + fprintf(stderr, "Clé privée \"%s\" invalide.\n", filepath); + exit(EXIT_FAILURE); + } + + read_hex(file, priv_key.d); + if (feof(file)) { + fprintf(stderr, "Clé privée \"%s\" invalide.\n", filepath); + exit(EXIT_FAILURE); + } + + fclose(file); + + zero_big(zero); + + if (cp_abs(priv_key.n, zero) == 0 || cp_abs(priv_key.e, zero) == 0 || cp_abs(priv_key.d, zero) == 0) { + fprintf(stderr, "Clé privée \"%s\" invalide.\n", filepath); + exit(EXIT_FAILURE); + } + + return priv_key; +} + +public_key public_key_read(const char *filepath) { + FILE *file; + public_key pub_key; + big_n zero; + + file = fopen(filepath, "r"); + if (!file) { + fprintf(stderr, "Une erreur est survenue lors de la lecture du fichier \"%s\".\n", filepath); + exit(EXIT_FAILURE); + } + + read_hex(file, pub_key.n); + if (feof(file)) { + fprintf(stderr, "Clé publique \"%s\" invalide.\n", filepath); + exit(EXIT_FAILURE); + } + + read_hex(file, pub_key.e); + if (feof(file)) { + fprintf(stderr, "Clé publique \"%s\" invalide.\n", filepath); + exit(EXIT_FAILURE); + } + + fclose(file); + + zero_big(zero); + + if (cp_abs(pub_key.n, zero) == 0 || cp_abs(pub_key.e, zero) == 0) { + fprintf(stderr, "Clé publique \"%s\" invalide.\n", filepath); + exit(EXIT_FAILURE); + } + + return pub_key; +}