#include "big.h" #include #include #include #include #include #define CAPACITY 10 #define BASE 0x100000000 void bign_create_empty(struct bign *self) { //initializing an empty bign self->data=NULL; self->capacity= 0; self->size=0; } void bign_create_from_value(struct bign *self, uint32_t val) { //creating a bign out of a value self->capacity=CAPACITY; self->size=1; self->data=malloc(self->capacity*sizeof(uint32_t)); self->data[0]=val; } //function that doubles the maximum capacity of a bign void extend_capacity(struct bign *self){ self->capacity=self->capacity*2; //temp points to the curr array to keep the location uint32_t *temp=self->data; self->data=NULL; // allocating another mem segment to self->data self->data=calloc(self->capacity,sizeof(uint32_t)); for(size_t i=0;isize;i++){ self->data[i]=temp[i]; } //freeing the previous array to avoid memory leaks free(temp); } //function that converts a hex char into an integer uint32_t hex_char_to_int(char val){ //--------------------------------converting every char to an int //case '0'='0' && val<='9'){ return (int)(val-'0'); //case 'A'='A' && val<='Z'){ return (int)(val-'0'-('A'-'9'-1)); //case 'a'='a' && val<='z'){ return (int)(val-'0'-('a'-'9'-1)); } return -1; } void bign_create_from_string(struct bign *self, const char *str) { //getting the index of the first digit that s not a 0 size_t length=strlen(str); size_t i=0; while(str[i]=='0'&& isize=0; self->capacity=CAPACITY; self->data=calloc(self->capacity,sizeof(uint32_t)); int pow_16=1; size_t index_curr=length-1; //index_curr is the index of the current char we re treating size_t digit_bign=0; // index of the uint32_t we re working on uint32_t tmp=0; //tmp is a temporary uint32_t used to add the char*pow16s together size_t count=1; while(index_curr>first_digit ){ //ading up the hex digits with the powers of 16 tmp+=hex_char_to_int(str[index_curr])*pow_16; pow_16=pow_16*16; //incrementing the power of 16 index_curr--; //every 8 hex chars assining the uint32 digit the value of tmp and giving every variable their default value if(count%8==0){ self->size++; //checking if we need to extend the capacity if(self->size>=self->capacity){ extend_capacity(self); } self->data[digit_bign]=tmp; digit_bign++; pow_16=1; tmp=0; count=0; } count ++; } // case when the initial str size%8!=0 or if the the size of the bign is still 0 // which can occur if the index of the first non 0 diigt is 0 if(count!=0 || self->size==0){ self->size++; self->data[digit_bign]=tmp+hex_char_to_int(str[index_curr])*pow_16; } } void bign_copy_from_other(struct bign *self, const struct bign *other) { //if data was already allocated we re freeing it if (self->data!=NULL){ free(self->data); } //allocating a new array to self->data self->capacity=other->capacity; self->data=calloc(self->capacity,sizeof(uint32_t)); self->size=other->size; //copying every digit for(size_t i=0;isize;i++){ self->data[i]=other->data[i]; } } void bign_move_from_other(struct bign *self, struct bign *other) { //if data was already allocated we re freeing it if (self->data!=NULL){ free(self->data); } //giving every value of other to self self->capacity=other->capacity; self->size=other->size; self->data=other->data; //not freeing other->data cause it would erase the array that s also pointed by self->data other->data=NULL; other->capacity=0; other->size=0; } void bign_destroy(struct bign *self) { //if data was already allocated we re freeing it if(self->data!=NULL){ free(self->data); } self->size=0; self->capacity=0; } void bign_print(const struct bign *self) { if(self->size>0){ //we re printing the number backwords for(size_t i=self->size-1;i>0;i--){ printf("%08X_",self->data[i]); //%08x prints a uint32_t with the non significant 0s included } // and printing data[0] separately to avoid having an underscore after the number printf("%08X",self->data[0]); printf("\n"); } } int bign_cmp(const struct bign *lhs, const struct bign *rhs) { // comparing sizes if(lhs->sizesize){ return -1; }else if(lhs->size>rhs->size){ return 1; } else { //if sizes are equal comparing every digit for(size_t i =lhs->size;i>0;i--){ if(lhs->data[i-1]>rhs->data[i-1]){ return 1; }else if(lhs->data[i-1]data[i-1]){ return -1; } } } return 0; } int bign_cmp_zero(const struct bign *self) { if(self->data[0]==0 && self->size==1){ return 0; } return 1; } /* *Les fonctions complémentaires * */ uint32_t bign_get(const struct bign *self,size_t i){ if(isize){ return self->data[i]; } return 0; } void bign_normalize(struct bign *self){ size_t i = self->size-1; while(self->data[i]==0 && i>0){ self->size--; i--; } } //function that returns the bigger size out of 2 bigns size_t max(size_t nb1, size_t nb2){ if(nb1>nb2){ return nb1; } return nb2; } void bign_add(struct bign *self, const struct bign *lhs, const struct bign *rhs) { //if self is empty we create it from 0 if(self->data==NULL){ bign_create_from_value(self, 0); } //initializing every local variable needed to calculate size_t n = max(lhs->size,rhs->size); uint64_t c=0; uint64_t sum = 0; uint64_t digit1=0; uint64_t digit2=0; //extending self's size/capacity to n+1 size_t size=n+1; while(size>self->capacity){ extend_capacity(self); } self->size=size; self->data[n]=0; //setting data[n]to 0 because it s the only value that we might not change (if c= 0 at the end) for(size_t i=0;i=lhs->size){ digit1=0; }else{digit1 = lhs->data[i]; } if(i>=rhs->size){ digit2=0; }else{ digit2 = rhs->data[i]; } //add algorithm application sum = digit1+digit2+c; self->data[i]=sum%BASE; c=sum/BASE; } //adding c to data[n] self->data[n]+=c; bign_normalize(self); } void bign_sub(struct bign *self, const struct bign *lhs, const struct bign *rhs) { //if self is empty we create it from 0 if(self->data==NULL){ bign_create_from_value(self, 0); } //checking if the first number is bigger or equal to he second if(bign_cmp(lhs,rhs)>=0){ uint32_t b=0; uint64_t diff=0; uint64_t digit2=0; //extending self's size/capacity to n+1 size_t n = lhs->size; size_t size=n+1; while(size>self->capacity){ extend_capacity(self); } self->size=size; self->data[n]=0; for(size_t i=0;i=rhs->size){ digit2=0; }else{ digit2 = rhs->data[i]; } //main algorithm diff= lhs->data[i]-digit2-b; self->data[i]=diff%BASE; //making sure b(orrow) is [0;1] if(diff/BASE>0){ b=1; } else { b=0; } } bign_normalize(self); } } void bign_mul(struct bign *self, const struct bign *lhs, const struct bign *rhs) { if(self->data==NULL){ bign_create_from_value(self, 0); } uint32_t c=0; uint64_t tmp=0; size_t n = lhs->size; size_t m = rhs->size; size_t size=n+m+1; //temporary array that holds the result uint32_t *tmp_data=calloc(size+1,sizeof(uint32_t)); for (size_t i = 0; i < n; i++){ c=0; for (size_t j = 0; j < m; j++){ //casting the sum of uint32_t tmp= (uint64_t)lhs->data[i]*rhs->data[j]+ tmp_data[i+j]+c; tmp_data[i+j]= tmp%BASE; c= tmp/BASE; } if(c>0){ tmp_data[i+m]=c; } } //creating self out of the temporary array we allocated right above free(self->data); self->size=size; self->data=tmp_data; self->capacity=size+1; bign_normalize(self); } void bign_mul_karatsuba(struct bign *self, const struct bign *lhs, const struct bign *rhs) { } void bign_mul_short(struct bign *self, const struct bign *lhs, uint32_t rhs) { //making a bign out of the initial uint32_t to be able to use the mul functions struct bign tmp_big; bign_create_from_value(&tmp_big,rhs); bign_mul(self,lhs,&tmp_big); bign_destroy(&tmp_big); } // https://janmr.com/blog/2012/11/basic-multiple-precision-short-division/ void bign_div_short(struct bign *quo, uint32_t *rem, const struct bign *lhs, uint32_t rhs) { if(rhs !=0){ uint64_t temp=0; for(size_t k =lhs->size; k>0; k--){ temp=(uint64_t)(*rem*BASE+lhs->data[k-1]); quo->data[k-1]=temp/rhs; *rem=temp%rhs; } } } // https://janmr.com/blog/2014/04/basic-multiple-precision-long-division/ void bign_div(struct bign *quo, struct bign *rem, const struct bign *lhs, const struct bign *rhs) { //initializing quo and rem at 0x0 if(quo->data!=NULL){ bign_destroy(quo); } if(rem->data!=NULL){ bign_destroy(rem); } bign_create_from_value(quo, 0); bign_create_from_value(rem, 0); //case when rhs is a one digit bign if(rhs->size==1){ while(lhs->size>=quo->capacity){ extend_capacity(quo); } quo->size=lhs->size; bign_div_short(quo, rem->data, lhs, rhs->data[0]); } //normalizing the bigns bign_normalize(quo); bign_normalize(rem); } void expo(struct bign *lhs, struct bign *rhs, struct bign *self){ //the bign that s going to be returned struct bign tmp; bign_create_from_value(&tmp, 1); uint32_t r=0; //case when n = 0 if(bign_cmp_zero(rhs)== 0){ bign_move_from_other(self, &tmp); //case when n=1 }else if(bign_cmp(rhs,&tmp)==0 ){ bign_move_from_other(self, lhs); }else{ //dividing the n by 2 bign_div_short(&tmp, &r, rhs, 2); //n is even if(r==0){ // rhs = rhs/2 bign_move_from_other(rhs, &tmp); //lhs = lhs² bign_mul(lhs,lhs,lhs); expo(lhs,rhs,self); //n is odd } else { // rhs = (rhs-1)/2 bign_move_from_other(rhs, &tmp); //keeping in memory the value of lhs bign_copy_from_other(&tmp, lhs); //lhs = lhs² bign_mul(lhs,lhs,lhs); expo(lhs,rhs,self); bign_mul(lhs, lhs, &tmp); //multiplication by lhs } } bign_destroy(&tmp); } void bign_exp(struct bign *self, const struct bign *lhs, const struct bign *rhs) { bign_destroy(self); //copies of lhs and rhs struct bign big_l; bign_create_empty(&big_l); bign_copy_from_other(&big_l, lhs); struct bign big_r; bign_create_empty(&big_r); bign_copy_from_other(&big_r, rhs); //isolating the case when lhs ==0 if(bign_cmp_zero(lhs)==0){ bign_create_from_value(self, 0); } else { expo(&big_l, &big_r, self); } //destroying the copies bign_destroy(&big_l); bign_destroy(&big_r); bign_normalize(self); } /* * * bigz * */ void bigz_create_empty(struct bigz *self) { self->positive=true; bign_create_empty(&self->n); } void bigz_create_from_value(struct bigz *self, int32_t val) { if(val<0){ self->positive=false; val=-val; }else{ self->positive=true; } bign_create_from_value(&self->n,val); } void bigz_create_from_string(struct bigz *self, const char *str, unsigned base) { size_t i=1; //checking if the number is >=0 or <0 if(str[0]=='-'){ bigz_create_from_value(self,hex_char_to_int(str[1])); self->positive=false; i=2; } else { bigz_create_from_value(self,hex_char_to_int(str[0])); } struct bign tmp_big; //using the algorithm to transform a str to an int while(str[i]!='\0'){ bign_create_from_value(&tmp_big,hex_char_to_int(str[i])); bign_mul_short(&self->n,&self->n,base); //multiply the number by base bign_add(&self->n,&self->n,&tmp_big); //add the next digit bign_destroy(&tmp_big); i++; } } void bigz_copy_from_other(struct bigz *self, const struct bigz *other) { bigz_destroy(self); //assigning the values of other to self self->n.capacity=other->n.capacity; self->n.size=other->n.size; self->positive=other->positive; //copying every digit to self self->n.data=calloc(self->n.capacity, sizeof(uint32_t)); for (size_t i = 0; i < self->n.size; i++) { self->n.data[i]=other->n.data[i]; } } void bigz_move_from_other(struct bigz *self, struct bigz *other) { bigz_destroy(self); //assigning the values of other to self self->n.capacity=other->n.capacity; self->n.size=other->n.size; self->positive=other->positive; //self->data points the same array as other->data self->n.data=other->n.data; //other points to NULL to make other destroyable other->n.data=NULL; bigz_destroy(other); } void bigz_destroy(struct bigz *self) { bign_destroy(&self->n); self->positive=true; } void bigz_print(const struct bigz *self) { if(!self->positive){ printf("-"); } bign_print(&self->n); } int bigz_cmp(const struct bigz *lhs, const struct bigz *rhs) { if(bigz_cmp_zero(lhs)==0 && bigz_cmp_zero(rhs)==0){ return 0; } if(lhs->positive && !rhs->positive){ return 1; } if(!lhs->positive && rhs->positive){ return -1; } if(!lhs->positive && !rhs->positive){ return -bign_cmp(&lhs->n, &rhs->n); } return bign_cmp(&lhs->n, &rhs->n); } int bigz_cmp_zero(const struct bigz *self) { if(self->n.size==1 && self->n.data[0]==0){ return 0; } if(!self->positive){ return -1; } return 1; } void bigz_add(struct bigz *self, const struct bigz *lhs, const struct bigz *rhs) { if(self->n.data==NULL){ bigz_create_from_value(self, 0); } // if same sign if(lhs->positive==rhs->positive){ self->positive=lhs->positive; bign_add(&self->n,&lhs->n,&rhs->n); // if rhs <0 } else if(lhs->positive && !rhs->positive){ //if lhs value greater than rhs value if(bign_cmp(&lhs->n,&rhs->n)>=0){ self->positive=true; bign_sub(&self->n, &lhs->n, &rhs->n); //if rhs value greater than lhs value } else { self->positive=false; bign_sub (&self->n, &rhs->n, &lhs->n); } //if lhs<0 }else { //if lhs value greater than rhs value if(bign_cmp(&lhs->n,&rhs->n)>=0){ self->positive=false; bign_sub(&self->n, &lhs->n, &rhs->n); //if rhs value greater than lhs value } else { self->positive=true; bign_sub (&self->n, &rhs->n, &lhs->n); } } } void bigz_sub(struct bigz *self, const struct bigz *lhs, const struct bigz *rhs) { if(self->n.data==NULL){ bigz_create_from_value(self, 0); } //lhs=>0 && rhs<0 if(lhs->positive && !rhs->positive){ self->positive=true; bign_add(&self->n, &lhs->n, &rhs->n); //lhs<0 && rhs>=0 } else if(!lhs->positive && rhs->positive){ self->positive=false; bign_add(&self->n, &lhs->n, &rhs->n); //lhs>=0 && rhs>=0 } else if(lhs->positive && rhs->positive){ if(bign_cmp(&lhs->n,&rhs->n)>=0){ self->positive=true; bign_sub(&self->n, &lhs->n, &rhs->n); } else { self->positive=false; bign_sub(&self->n, &rhs->n, &lhs->n); } //lhs<0 && rhs<0 } else { if(bign_cmp(&lhs->n,&rhs->n)>=0){ self->positive=false; bign_sub(&self->n, &lhs->n, &rhs->n); } else { self->positive=true; bign_sub(&self->n, &rhs->n, &lhs->n); } } } void bigz_mul(struct bigz *self, const struct bigz *lhs, const struct bigz *rhs) { if(self->n.data==NULL){ bigz_create_from_value(self, 0); } bign_mul(&self->n, &lhs->n, &rhs->n); //case when same sign if(lhs->positive==rhs->positive){ self->positive=true; //case when different signs } else { self->positive=false; } } void bigz_div(struct bigz *quo, struct bigz *rem, const struct bigz *lhs, const struct bigz *rhs) { } void bigz_gcd(struct bigz *self, const struct bigz *lhs, const struct bigz *rhs) { }