Accueil > > > CODAGE RSA SUR 1024 BITS
CODAGE RSA SUR 1024 BITS
Information sur la source
Description
Génère un couple de clés privée/publique puis génère un message clair au hasard, le crypte puis le décrypte, en utilisant l'algorithme RSA. Utilise 3 classes gérant des nombres de 512, 1024 ou 2048 bits ( pour simplifier le code, on pourrait en faire qu'une mais je crain que le code devienne plus lent). Ne marche que sur une machine 64bits.
Source
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <string.h>
-
- class Nb512;
- class Nb1024;
-
- unsigned long long NbHasard;
- void InitHasard(){ NbHasard=time(NULL); }
-
- class Nb2048{
- public:
- union {
- unsigned D[64];
- unsigned long long Q[32];
- struct {
- unsigned long long Lo;
- unsigned long long Hi;
- } O[16];
- } Nb __attribute__ ((aligned(16)));
- bool carry;
- bool ChercheQuotient;
- void DecaleAdd (const Nb1024 &terme, unsigned char decal); //Permet d'ajouter à un nombre de 1024 bits un nombre de 512 bits, en le décalant d'un nombre entier de qword
- Nb1024 operator% (const Nb1024 &Mod)const;
- Nb2048 operator+ (const Nb2048 &Terme)const;
- Nb2048 operator- (const Nb2048 &Terme)const;
- Nb2048& operator= (unsigned long long Nb);
- Nb2048& operator= (const Nb1024 &Nb);
- bool operator== (const Nb2048 &Nb)const;
- Nb2048() : ChercheQuotient(false){};
- };
-
- class Nb1024{
- public:
- union {
- unsigned char B[128];
- unsigned D[32];
- unsigned long long Q[16];
- struct {
- unsigned long long Lo;
- unsigned long long Hi;
- } O[8];
- } Nb __attribute__ ((aligned(16)));
- bool carry;
- Nb2048* Quotient;
- bool ChercheQuotient;
- void DecaleAdd (const Nb512 &terme, unsigned char decal); //Permet d'ajouter à un nombre de 1024 bits un nombre de 512 bits, en le décalant d'un nombre entier de qword
- Nb1024& operator= (unsigned long long Nb);
- Nb1024& operator= (const Nb512 &Nb);
- Nb1024& operator= (const Nb1024 &Nb);
- Nb1024& operator= (const Nb2048 &Nb);
- Nb512 operator% (const Nb512 &Mod)const;
- Nb1024 operator+ (const Nb1024 &Terme)const;
- Nb1024 operator- (const Nb1024 &Terme)const;
- Nb2048 operator* (unsigned long long fact)const;
- Nb2048 operator* (const Nb1024 &fact)const;
- bool operator== (const Nb1024 &Nb)const;
- Nb1024 Nb1024::Puissance (const Nb1024 &Exp, const Nb1024 &Mod)const;
- Nb1024() : ChercheQuotient(false),Quotient(NULL){}
- Nb1024(const Nb1024& c){
- for(int i=0; i<16; i++) Nb.Q[i]=c.Nb.Q[i];
- carry=c.carry;
- ChercheQuotient=c.ChercheQuotient;
- if(c.Quotient!=NULL){
- Quotient=new Nb2048;
- *Quotient=*c.Quotient;
- } else Quotient=NULL;
- }
- ~Nb1024(){if(Quotient!=NULL) delete Quotient;}
- Nb1024 Inverse(const Nb1024 &Mod)const;
- };
-
- class Nb512{
- public:
- union {
- unsigned char B[64];
- unsigned D[16];
- unsigned long long Q[8];
- struct {
- unsigned long long Lo;
- unsigned long long Hi;
- } O[4];
- } Nb __attribute__ ((aligned(16)));
- bool carry;
- Nb1024* Quotient;
- Nb512 operator+ (const Nb512 &Terme)const;
- Nb512 operator- (const Nb512 &Terme)const;
- Nb512& operator= (unsigned long long Nb);
- Nb512& operator= (const Nb512 &Nb);
- Nb512& operator= (const Nb1024 &Nb);
- Nb1024 operator* (const Nb512 &Fact)const; //Il est plus rapide de mettre les plus petits nombres en premier opérande avec cet opérateur( si possible)
- Nb1024 operator* (unsigned long long fact)const;
- bool operator== (const Nb512 &Nb)const;
- Nb512 Puissance (const Nb512 &Exp, const Nb512 &Mod)const;
- void Hasard (); //Crée un nombre aléatoire non-sécurisé ( pour les tests et le test de Miller-Rabin)
- bool MillerRabin(unsigned int Boucles)const;
- void Premier();
- Nb512():Quotient(NULL){}
- Nb512(const Nb512& c){
- for(int i=0; i<8; i++) Nb.Q[i]=c.Nb.Q[i];
- carry=c.carry;
- if(c.Quotient!=NULL){
- Quotient=new Nb1024;
- *Quotient=*c.Quotient;
- }else Quotient=NULL;
- }
- ~Nb512(){if(Quotient!=NULL) delete Quotient;}
- };
-
- inline void Nb1024::DecaleAdd(const Nb512 &terme, unsigned char decal){
- asm ("add %8, %0\n\t"
- "adc %9, %1\n\t"
- "adc %10,%2\n\t"
- "adc %11,%3\n\t"
- "adc %12,%4\n\t"
- "adc %13,%5\n\t"
- "adc %14,%6\n\t"
- "adc %15,%7\n\t"
-
- /*FIXME : mettre la derniere retenue dans la variable carry*/
- "jnc 1f\n\t"
- "lea %7,%%R8\n\t"
- "0:\n\t" //gestion de la retenue : si elle persiste, on la fait remonter tout le nombre (pas de gestion de dépassement de la fin du nombre -> peut provoquer des bugs)
- "jnc 1f\n\t"
- "add $8,%%R8\n\t"
- "add $1,(%%R8)\n\t"
- "jmp 0b\n\t"
- "1:\n\t"
- :
- "=m" (Nb.Q[decal+0]), "=m" (Nb.Q[decal+1]), "=m" (Nb.Q[decal+2]), "=m" (Nb.Q[decal+3]),
- "=m" (Nb.Q[decal+4]), "=m" (Nb.Q[decal+5]), "=m" (Nb.Q[decal+6]), "=m" (Nb.Q[decal+7])
- :
- "r" (terme.Nb.Q[0]), "r" (terme.Nb.Q[1]), "r" (terme.Nb.Q[2]), "r" (terme.Nb.Q[3]),
- "r" (terme.Nb.Q[4]), "r" (terme.Nb.Q[5]), "r" (terme.Nb.Q[6]), "r" (terme.Nb.Q[7])
- );
- }
-
- inline void Nb2048::DecaleAdd(const Nb1024 &terme, unsigned char decal){
- bool c;
- asm ("add %9, %0\n\t"
- "adc %10,%1\n\t"
- "adc %11,%2\n\t"
- "adc %12,%3\n\t"
- "adc %13,%4\n\t"
- "adc %14,%5\n\t"
- "adc %15,%6\n\t"
- "adc %16,%7\n\t"
-
- "setc %8\n\t"
- :
- "=m" (Nb.Q[decal+0]), "=m" (Nb.Q[decal+1]), "=m" (Nb.Q[decal+2]), "=m" (Nb.Q[decal+3]),
- "=m" (Nb.Q[decal+4]), "=m" (Nb.Q[decal+5]), "=m" (Nb.Q[decal+6]), "=m" (Nb.Q[decal+7]),
-
- "=g" (c)
- :
- "r" (terme.Nb.Q[0]), "r" (terme.Nb.Q[1]), "r" (terme.Nb.Q[2]), "r" (terme.Nb.Q[3]),
- "r" (terme.Nb.Q[4]), "r" (terme.Nb.Q[5]), "r" (terme.Nb.Q[6]), "r" (terme.Nb.Q[7])
- );
- asm ("test $1,%8\n\t"
- "clc\n\t"
- "jz 1f\n\t"
- "stc\n\t"
- "1:\n\t"
-
- "adc %9, %0\n\t"
- "adc %10,%1\n\t"
- "adc %11,%2\n\t"
- "adc %12,%3\n\t"
- "adc %13,%4\n\t"
- "adc %14,%5\n\t"
- "adc %15,%6\n\t"
- "adc %16,%7\n\t"
-
- /*FIXME : mettre la derniere retenue dans la variable carry*/
- "jnc 1f\n\t"
- "lea %7,%%R8\n\t"
- "0:\n\t" //gestion de la retenue : si elle persiste, on la fait remonter tout le nombre (pas de gestion de dépassement de la fin du nombre -> peut provoquer des bugs)
- "jnc 1f\n\t"
- "add $8,%%R8\n\t"
- "add $1,(%%R8)\n\t"
- "jmp 0b\n\t"
- "1:\n\t"
- :
- "=m" (Nb.Q[decal+8]), "=m" (Nb.Q[decal+9]), "=m" (Nb.Q[decal+10]),"=m" (Nb.Q[decal+11]),
- "=m" (Nb.Q[decal+12]),"=m" (Nb.Q[decal+13]),"=m" (Nb.Q[decal+14]),"=m" (Nb.Q[decal+15])
- :
- "g" (c),
-
- "r" (terme.Nb.Q[8]), "r" (terme.Nb.Q[9]), "r" (terme.Nb.Q[10]),"r" (terme.Nb.Q[11]),
- "r" (terme.Nb.Q[12]),"r" (terme.Nb.Q[13]),"r" (terme.Nb.Q[14]),"r" (terme.Nb.Q[15])
- );
- }
-
- inline Nb512& Nb512::operator= (unsigned long long Nb){
- memset(&this->Nb,0,sizeof(this->Nb));
- this->Nb.Q[0]=Nb;
- return *this;
- }
-
- inline Nb1024& Nb1024::operator= (unsigned long long Nb){
- memset(&this->Nb,0,sizeof(this->Nb));
- this->Nb.Q[0]=Nb;
- return *this;
- }
-
- inline Nb2048& Nb2048::operator= (unsigned long long Nb){
- memset(&this->Nb,0,sizeof(this->Nb));
- this->Nb.Q[0]=Nb;
- return *this;
- }
-
- inline Nb512& Nb512::operator= (const Nb1024 &Nb){
- memcpy(&this->Nb,&Nb.Nb,sizeof(this->Nb));
- return *this;
- }
-
- inline Nb1024& Nb1024::operator= (const Nb2048 &Nb){
- memcpy(&this->Nb,&Nb.Nb,sizeof(this->Nb));
- return *this;
- }
-
- inline Nb2048& Nb2048::operator= (const Nb1024 &Nb){
- memcpy(&this->Nb, &Nb.Nb, sizeof(Nb.Nb));
- memset((char*)&this->Nb + sizeof(Nb.Nb), 0, sizeof(this->Nb)-sizeof(Nb.Nb));
- return *this;
- }
-
- inline Nb1024& Nb1024::operator= (const Nb512 &Nb){
- memcpy(&this->Nb, &Nb.Nb, sizeof(Nb.Nb));
- memset((char*)&this->Nb + sizeof(Nb.Nb), 0, sizeof(this->Nb)-sizeof(Nb.Nb));
- return *this;
- }
-
- inline Nb1024& Nb1024::operator= (const Nb1024 &Nb){
- memcpy(this, &Nb,sizeof(Nb));
- if(Nb.Quotient!=NULL){
- Quotient=new Nb2048;
- *Quotient=*Nb.Quotient;
- } else Quotient=NULL;
- return *this;
- }
-
- inline Nb512& Nb512::operator= (const Nb512 &Nb){
- memcpy(this, &Nb,sizeof(Nb));
- if(Nb.Quotient!=NULL){
- Quotient=new Nb1024;
- *Quotient=*Nb.Quotient;
- } else Quotient=NULL;
- return *this;
- }
-
- inline Nb512 Nb512::operator+ (const Nb512 &Terme)const{
- Nb512 Res;
- asm ("add %17, %9\n\t"
- "adc %18, %10\n\t"
- "adc %19, %11\n\t"
- "adc %20, %12\n\t"
- "adc %21, %13\n\t"
- "adc %22, %14\n\t"
- "adc %23, %15\n\t"
- "adc %24, %16\n\t"
-
- "mov %9, %0\n\t"
- "mov %10,%1\n\t"
- "mov %11,%2\n\t"
- "mov %12,%3\n\t"
- "mov %13,%4\n\t"
- "mov %14,%5\n\t"
- "mov %15,%6\n\t"
- "mov %16,%7\n\t"
-
- "setc %8\n\t"
- :
- "=m" (Res.Nb.Q[0]), "=m" (Res.Nb.Q[1]), "=m" (Res.Nb.Q[2]), "=m" (Res.Nb.Q[3]),
- "=m" (Res.Nb.Q[4]), "=m" (Res.Nb.Q[5]), "=m" (Res.Nb.Q[6]), "=m" (Res.Nb.Q[7]),
-
- "=g" (Res.carry)
- :
- "r" (Terme.Nb.Q[0]), "r" (Terme.Nb.Q[1]), "r" (Terme.Nb.Q[2]), "r" (Terme.Nb.Q[3]),
- "r" (Terme.Nb.Q[4]), "r" (Terme.Nb.Q[5]), "r" (Terme.Nb.Q[6]), "r" (Terme.Nb.Q[7]),
-
- "g" (Nb.Q[0]), "g" (Nb.Q[1]), "g" (Nb.Q[2]), "g" (Nb.Q[3]),
- "g" (Nb.Q[4]), "g" (Nb.Q[5]), "g" (Nb.Q[6]), "g" (Nb.Q[7])
- );
- return Res;
- }
-
- inline Nb1024 Nb1024::operator+ (const Nb1024 &Terme)const{
- Nb1024 Res;
- asm ("add %17, %9\n\t"
- "adc %18, %10\n\t"
- "adc %19, %11\n\t"
- "adc %20, %12\n\t"
- "adc %21, %13\n\t"
- "adc %22, %14\n\t"
- "adc %23, %15\n\t"
- "adc %24, %16\n\t"
-
- "mov %9, %0\n\t"
- "mov %10,%1\n\t"
- "mov %11,%2\n\t"
- "mov %12,%3\n\t"
- "mov %13,%4\n\t"
- "mov %14,%5\n\t"
- "mov %15,%6\n\t"
- "mov %16,%7\n\t"
-
- "setc %8\n\t"
- :
- "=m" (Res.Nb.Q[0]), "=m" (Res.Nb.Q[1]), "=m" (Res.Nb.Q[2]), "=m" (Res.Nb.Q[3]),
- "=m" (Res.Nb.Q[4]), "=m" (Res.Nb.Q[5]), "=m" (Res.Nb.Q[6]), "=m" (Res.Nb.Q[7]),
-
- "=g" (Res.carry)
- :
- "r" (Terme.Nb.Q[0]), "r" (Terme.Nb.Q[1]), "r" (Terme.Nb.Q[2]), "r" (Terme.Nb.Q[3]),
- "r" (Terme.Nb.Q[4]), "r" (Terme.Nb.Q[5]), "r" (Terme.Nb.Q[6]), "r" (Terme.Nb.Q[7]),
-
- "g" (Nb.Q[0]), "g" (Nb.Q[1]), "g" (Nb.Q[2]), "g" (Nb.Q[3]),
- "g" (Nb.Q[4]), "g" (Nb.Q[5]), "g" (Nb.Q[6]), "g" (Nb.Q[7])
- );
- asm ("testl $1,%8\n\t"
- "clc\n\t"
- "jz 1f\n\t"
- "stc\n\t"
- "1:\n\t"
-
- "adc %17, %9\n\t"
- "adc %18, %10\n\t"
- "adc %19, %11\n\t"
- "adc %20, %12\n\t"
- "adc %21, %13\n\t"
- "adc %22, %14\n\t"
- "adc %23, %15\n\t"
- "adc %24, %16\n\t"
-
- "mov %9, %0\n\t"
- "mov %10,%1\n\t"
- "mov %11,%2\n\t"
- "mov %12,%3\n\t"
- "mov %13,%4\n\t"
- "mov %14,%5\n\t"
- "mov %15,%6\n\t"
- "mov %16,%7\n\t"
-
- "setc %8\n\t"
- :
- "=m" (Res.Nb.Q[8]), "=m" (Res.Nb.Q[9]), "=m" (Res.Nb.Q[10]),"=m" (Res.Nb.Q[11]),
- "=m" (Res.Nb.Q[12]),"=m" (Res.Nb.Q[13]),"=m" (Res.Nb.Q[14]),"=m" (Res.Nb.Q[15]),
-
- "+g" (Res.carry)
- :
- "r" (Terme.Nb.Q[8]), "r" (Terme.Nb.Q[9]), "r" (Terme.Nb.Q[10]),"r" (Terme.Nb.Q[11]),
- "r" (Terme.Nb.Q[12]),"r" (Terme.Nb.Q[13]),"r" (Terme.Nb.Q[14]),"r" (Terme.Nb.Q[15]),
-
- "g" (Nb.Q[8]), "g" (Nb.Q[9]), "g" (Nb.Q[10]), "g" (Nb.Q[11]),
- "g" (Nb.Q[12]),"g" (Nb.Q[13]),"g" (Nb.Q[14]), "g" (Nb.Q[15])
- );
- return Res;
- }
-
- inline Nb512 Nb512::operator- (const Nb512 &Terme)const{
- Nb512 Res;
- asm ("sub %17, %9\n\t"
- "sbb %18, %10\n\t"
- "sbb %19, %11\n\t"
- "sbb %20, %12\n\t"
- "sbb %21, %13\n\t"
- "sbb %22, %14\n\t"
- "sbb %23, %15\n\t"
- "sbb %24, %16\n\t"
-
- "mov %9, %0\n\t"
- "mov %10,%1\n\t"
- "mov %11,%2\n\t"
- "mov %12,%3\n\t"
- "mov %13,%4\n\t"
- "mov %14,%5\n\t"
- "mov %15,%6\n\t"
- "mov %16,%7\n\t"
-
- "setc %8\n\t"
- :
- "=m" (Res.Nb.Q[0]), "=m" (Res.Nb.Q[1]), "=m" (Res.Nb.Q[2]), "=m" (Res.Nb.Q[3]),
- "=m" (Res.Nb.Q[4]), "=m" (Res.Nb.Q[5]), "=m" (Res.Nb.Q[6]), "=m" (Res.Nb.Q[7]),
-
- "=g" (Res.carry)
- :
- "r" (Nb.Q[0]), "r" (Nb.Q[1]), "r" (Nb.Q[2]), "r" (Nb.Q[3]),
- "r" (Nb.Q[4]), "r" (Nb.Q[5]), "r" (Nb.Q[6]), "r" (Nb.Q[7]),
-
- "g" (Terme.Nb.Q[0]), "g" (Terme.Nb.Q[1]), "g" (Terme.Nb.Q[2]), "g" (Terme.Nb.Q[3]),
- "g" (Terme.Nb.Q[4]), "g" (Terme.Nb.Q[5]), "g" (Terme.Nb.Q[6]), "g" (Terme.Nb.Q[7])
- );
- return Res;
- }
-
- inline Nb1024 Nb1024::operator- (const Nb1024 &Terme)const{
- Nb1024 Res;
- asm ("sub %17, %9\n\t"
- "sbb %18, %10\n\t"
- "sbb %19, %11\n\t"
- "sbb %20, %12\n\t"
- "sbb %21, %13\n\t"
- "sbb %22, %14\n\t"
- "sbb %23, %15\n\t"
- "sbb %24, %16\n\t"
-
- "mov %9, %0\n\t"
- "mov %10,%1\n\t"
- "mov %11,%2\n\t"
- "mov %12,%3\n\t"
- "mov %13,%4\n\t"
- "mov %14,%5\n\t"
- "mov %15,%6\n\t"
- "mov %16,%7\n\t"
-
- "setc %8\n\t"
- :
- "=m" (Res.Nb.Q[0]), "=m" (Res.Nb.Q[1]), "=m" (Res.Nb.Q[2]), "=m" (Res.Nb.Q[3]),
- "=m" (Res.Nb.Q[4]), "=m" (Res.Nb.Q[5]), "=m" (Res.Nb.Q[6]), "=m" (Res.Nb.Q[7]),
-
- "=g" (Res.carry)
- :
- "r" (Nb.Q[0]), "r" (Nb.Q[1]), "r" (Nb.Q[2]), "r" (Nb.Q[3]),
- "r" (Nb.Q[4]), "r" (Nb.Q[5]), "r" (Nb.Q[6]), "r" (Nb.Q[7]),
-
- "g" (Terme.Nb.Q[0]), "g" (Terme.Nb.Q[1]), "g" (Terme.Nb.Q[2]), "g" (Terme.Nb.Q[3]),
- "g" (Terme.Nb.Q[4]), "g" (Terme.Nb.Q[5]), "g" (Terme.Nb.Q[6]), "g" (Terme.Nb.Q[7])
- );
- asm ("testl $1,%8\n\t"
- "clc\n\t"
- "jz 1f\n\t"
- "stc\n\t"
- "1:\n\t"
-
- "sbb %17, %9\n\t"
- "sbb %18, %10\n\t"
- "sbb %19, %11\n\t"
- "sbb %20, %12\n\t"
- "sbb %21, %13\n\t"
- "sbb %22, %14\n\t"
- "sbb %23, %15\n\t"
- "sbb %24, %16\n\t"
-
- "mov %9, %0\n\t"
- "mov %10,%1\n\t"
- "mov %11,%2\n\t"
- "mov %12,%3\n\t"
- "mov %13,%4\n\t"
- "mov %14,%5\n\t"
- "mov %15,%6\n\t"
- "mov %16,%7\n\t"
-
- "setc %8\n\t"
- :
- "=m" (Res.Nb.Q[8]), "=m" (Res.Nb.Q[9]), "=m" (Res.Nb.Q[10]),"=m" (Res.Nb.Q[11]),
- "=m" (Res.Nb.Q[12]),"=m" (Res.Nb.Q[13]),"=m" (Res.Nb.Q[14]),"=m" (Res.Nb.Q[15]),
-
- "+g" (Res.carry)
- :
- "r" (Nb.Q[8]), "r" (Nb.Q[9]), "r" (Nb.Q[10]), "r" (Nb.Q[11]),
- "r" (Nb.Q[12]),"r" (Nb.Q[13]),"r" (Nb.Q[14]), "r" (Nb.Q[15]),
-
- "g" (Terme.Nb.Q[8]), "g" (Terme.Nb.Q[9]), "g" (Terme.Nb.Q[10]),"g" (Terme.Nb.Q[11]),
- "g" (Terme.Nb.Q[12]),"g" (Terme.Nb.Q[13]),"g" (Terme.Nb.Q[14]),"g" (Terme.Nb.Q[15])
- );
- return Res;
- }
-
- inline Nb2048 Nb2048::operator- (const Nb2048 &Terme)const{
- Nb2048 Res;
- Res.carry=false;
- for(int i=0; i<32; i+=8)
- asm ("test $1,%8\n\t"
- "clc\n\t"
- "jz 1f\n\t"
- "stc\n\t"
- "1:\n\t"
-
- "sbb %17, %9\n\t"
- "sbb %18, %10\n\t"
- "sbb %19, %11\n\t"
- "sbb %20, %12\n\t"
- "sbb %21, %13\n\t"
- "sbb %22, %14\n\t"
- "sbb %23, %15\n\t"
- "sbb %24, %16\n\t"
-
- "mov %9, %0\n\t"
- "mov %10,%1\n\t"
- "mov %11,%2\n\t"
- "mov %12,%3\n\t"
- "mov %13,%4\n\t"
- "mov %14,%5\n\t"
- "mov %15,%6\n\t"
- "mov %16,%7\n\t"
-
- "setc %8\n\t"
- :
- "=m" (Res.Nb.Q[i+0]), "=m" (Res.Nb.Q[i+1]), "=m" (Res.Nb.Q[i+2]), "=m" (Res.Nb.Q[i+3]),
- "=m" (Res.Nb.Q[i+4]), "=m" (Res.Nb.Q[i+5]), "=m" (Res.Nb.Q[i+6]), "=m" (Res.Nb.Q[i+7]),
-
- "+g" (Res.carry)
- :
- "r" (Nb.Q[i+0]), "r" (Nb.Q[i+1]), "r" (Nb.Q[i+2]), "r" (Nb.Q[i+3]),
- "r" (Nb.Q[i+4]), "r" (Nb.Q[i+5]), "r" (Nb.Q[i+6]), "r" (Nb.Q[i+7]),
-
- "g" (Terme.Nb.Q[i+0]), "g" (Terme.Nb.Q[i+1]), "g" (Terme.Nb.Q[i+2]), "g" (Terme.Nb.Q[i+3]),
- "g" (Terme.Nb.Q[i+4]), "g" (Terme.Nb.Q[i+5]), "g" (Terme.Nb.Q[i+6]), "g" (Terme.Nb.Q[i+7])
- );
- return Res;
- }
-
- Nb1024 Nb512::operator* (const Nb512 &fact)const{
- Nb512 TamponPair[8];
- Nb512 TamponImpair[8];
- bool Zero[8];
- for(int i=0; i<8; i++){
- if(Nb.Q[i]==0){
- Zero[i]=true;
- continue;
- }
- Zero[i]=false;
-
- register unsigned long long ChiffreThis asm("%rcx")=Nb.Q[i];
- for(int j=0; j<8; j+=2){
- asm("mul %3"
- :"=a" (TamponPair[i].Nb.Q[j & 0xE]), "=d" (TamponPair[i].Nb.Q[(j & 0xE)+1])
- :"a" (fact.Nb.Q[j]), "r" (ChiffreThis)
- );
- asm("mul %3"
- :"=a" (TamponImpair[i].Nb.Q[j & 0xE]), "=d" (TamponImpair[i].Nb.Q[(j & 0xE)+1])
- :"a" (fact.Nb.Q[j+1]), "r" (ChiffreThis)
- );
- }
- }
-
- Nb1024 Retour;
- Retour=0;
- for(int i=0; i<8; i++) {
- if(Zero[i]==false){
- Retour.DecaleAdd(TamponPair[i],i);
- Retour.DecaleAdd(TamponImpair[i],i+1);
- }
- }
-
- return Retour;
- }
-
- Nb2048 Nb1024::operator* (const Nb1024 &fact)const{
- Nb1024 TamponPair[16];
- Nb1024 TamponImpair[16];
- bool Zero[16];
- for(int i=0; i<16; i++){
- if(Nb.Q[i]==0){
- Zero[i]=true;
- continue;
- }
- Zero[i]=false;
-
- register unsigned long long ChiffreThis asm("%rcx")=Nb.Q[i];
- for(int j=0; j<16; j+=2){
- asm("mul %3"
- :"=a" (TamponPair[i].Nb.Q[j & 0xE]), "=d" (TamponPair[i].Nb.Q[(j & 0xE)+1])
- :"a" (fact.Nb.Q[j]), "r" (ChiffreThis)
- );
- asm("mul %3"
- :"=a" (TamponImpair[i].Nb.Q[j & 0xE]), "=d" (TamponImpair[i].Nb.Q[(j & 0xE)+1])
- :"a" (fact.Nb.Q[j+1]), "r" (ChiffreThis)
- );
- }
- }
-
- Nb2048 Retour;
- Retour=0;
- for(int i=0; i<16; i++) {
- if(Zero[i]==false){
- Retour.DecaleAdd(TamponPair[i],i);
- Retour.DecaleAdd(TamponImpair[i],i+1);
- }
- }
-
- return Retour;
- }
-
- inline Nb1024 Nb512::operator* (unsigned long long fact)const{
- Nb512 Tampon;
-
- Nb1024 Res;
- if(fact==0) return Res=0;
-
- Res=0;
-
- for(int i=0; i<8; i+=2){
- asm("mul %3"
- :"=a" (Res.Nb.Q[i & 0xE]), "=d" (Res.Nb.Q[(i & 0xE)+1])
- :"a" (Nb.Q[i]), "r" (fact)
- );
- asm("mul %3"
- :"=a" (Tampon.Nb.Q[i & 0xE]), "=d" (Tampon.Nb.Q[(i & 0xE)+1])
- :"a" (Nb.Q[i+1]), "r" (fact)
- );
- }
-
- Res.DecaleAdd(Tampon,1);
-
- return Res;
- }
-
- inline Nb2048 Nb1024::operator* (unsigned long long fact)const{
- Nb1024 Tampon;
-
- Nb2048 Res;
- if(fact==0) return Res=0;
-
- Res=0;
-
- for(int i=0; i<16; i+=2){
- asm("mul %3"
- :"=a" (Res.Nb.Q[i & 0xE]), "=d" (Res.Nb.Q[(i & 0xE)+1])
- :"a" (Nb.Q[i]), "r" (fact)
- );
- asm("mul %3"
- :"=a" (Tampon.Nb.Q[i & 0xE]), "=d" (Tampon.Nb.Q[(i & 0xE)+1])
- :"a" (Nb.Q[i+1]), "r" (fact)
- );
- }
-
- Res.DecaleAdd(Tampon,1);
-
- return Res;
- }
-
- //Un chiffre = un DWORD
- Nb512 Nb1024::operator% (const Nb512 &Mod)const{
- Nb512 Res;
-
- if(ChercheQuotient) {
- if(Res.Quotient!=NULL) delete Res.Quotient;
- Res.Quotient=new Nb1024;
- *Res.Quotient=0;
- }
-
- //ChiffreBase : contient l'index du chiffre dans Dividende que l'on va utiliser pour faire la premiere approche de Quotient
- signed char IndexThis, ChiffreBase;
- for(IndexThis=31; this->Nb.D[IndexThis]==0; IndexThis--) if (IndexThis==0) return Res=0;
- for(ChiffreBase=15; Mod.Nb.D[ChiffreBase]==0; ChiffreBase--) if(ChiffreBase==0) exit(-1); //division par 0
- if(IndexThis<ChiffreBase) return Res=*this;
-
- Nb1024 Dividende; //Dividende partiel traité à une itération de la boucle
- Dividende=0;
- for(int i=ChiffreBase-1; i>=0; i--, IndexThis--) Dividende.Nb.D[i]=this->Nb.D[IndexThis];
-
- for(; IndexThis>=0; IndexThis--){
- // TODO : A faire en Asm (SSE ou non, selon le mieux)
- for(int i=15; i>=0; i--) Dividende.Nb.D[i+1]=Dividende.Nb.D[i];
- Dividende.Nb.D[0]=this->Nb.D[IndexThis];
-
- unsigned long long Quotient, RestePart;
- asm ("divq %4" //Premiere estimation de Quotient
- :"=a" (Quotient), "=d" (RestePart)
- :"a" ( Dividende.Nb.D[ChiffreBase] + ((unsigned long long)Dividende.Nb.D[ChiffreBase+1]<<32)), "d" (0), "g" ( (unsigned long long)Mod.Nb.D[ChiffreBase])
- );
- bool QuotientOK=false;
- if(Quotient > 0xFFFFFFFF) {
- Quotient=0xFFFFFFFF;
- //RestePart = Dividende.Nb.D[ChiffreBase+1]:Dividende.Nb.D[ChiffreBase] - 0xFFFFFFFF * Md.Nb.D[ChiffreBase]
- RestePart= Dividende.Nb.D[ChiffreBase] + ((unsigned long long)Dividende.Nb.D[ChiffreBase+1]<<32) - ((unsigned long long)Mod.Nb.D[ChiffreBase]<<32) + Mod.Nb.D[ChiffreBase]<<32;
- if(RestePart & 0xFFFFFFFF00000000) QuotientOK=true;
- }
- //Ensuite, le but est de rajouter des chiffres et de calculer l'erreur que l'on commet : on multiplie l'estimation du quotient déjà faite par les chiffres
- //de Mod déja pris en compte puis on soustrait les chiffres de dividende déjà pris en compte. Si le résultat est négatif ou nul, pas de problème,
- //Quotient n'est pas trop grand (il ne peut pas être trop petit). Dans ce cas, l'opposé du résultat correspond au reste de la division. S'il est positif,
- //on le divise par les chiffres de Mod déjà pris en compte : on obtient un nombre qu'il faut soustraire à Quotient. Sans optimisation, cette méthode est
- //impossible : on se retrouve a faire des divisions avec un dénominateur énorme et tout un tas de multiplications...
- //Pour simplifier, on se rend compte que ce nombre est calculable a partir du reste de la division précédente (calculé lors de la derniere estimation de
- //Quotient: on supprime donc beaucoup de multiplications inutiles. De plus, seules la premiere itération de cette boucle est utiles : les autres ne pourront
- //Faire descendre Quotient que de 1 : on remplace donc toutes ces itérations par une comparaison entre Quotient*Mod et Diviseur, qui nous dira s'il faut
- //décrémenter Quotient ou non.
-
- //Petite vérification.. histoire de pas faire des opérations pour rien
- if(Quotient == 0) continue;
-
- if(ChiffreBase == 0) QuotientOK=true;
-
- if(!QuotientOK){
- unsigned long long Tmp=Quotient*Mod.Nb.D[ChiffreBase-1];
- if(Tmp > ((unsigned long long)RestePart<<32) + Dividende.Nb.D[ChiffreBase-1])
- //Le nombre dont on parle dans le § de commentaires plus haut est positif : on réajuste Quotient
- //Diviseion en arrondissant par au dessus : d'où le 1 + et le -1
- Quotient-=1 + (Tmp - ((unsigned long long)RestePart<<32) - Dividende.Nb.D[ChiffreBase-1] - 1) / ( ((unsigned long long)Mod.Nb.D[ChiffreBase]<<32) + Mod.Nb.D[ChiffreBase-1] );
- }
-
- Dividende=Dividende-Mod*Quotient;
- if(Dividende.carry) {
- Dividende.DecaleAdd(Mod,0);
- Quotient--;
- }
- if(ChercheQuotient)
- Res.Quotient->Nb.D[IndexThis]=Quotient;
- }
-
- return Res=Dividende;
- }
-
- Nb1024 Nb2048::operator% (const Nb1024 &Mod)const{
- Nb1024 Res;
-
- if(ChercheQuotient) {
- if(Res.Quotient!=NULL) delete Res.Quotient;
- Res.Quotient=new Nb2048;
- *Res.Quotient=0;
- }
-
- //ChiffreBase : contient l'index du chiffre dans Dividende que l'on va utiliser pour faire la premiere approche de Quotient
- signed char IndexThis, ChiffreBase;
- for(IndexThis=63; this->Nb.D[IndexThis]==0; IndexThis--) if (IndexThis==0) return Res=0;
- for(ChiffreBase=31; Mod.Nb.D[ChiffreBase]==0; ChiffreBase--) if(ChiffreBase==0) exit(-1); //division par 0
- if(IndexThis<ChiffreBase) return Res=*this;
-
- Nb2048 Dividende; //Dividende partiel traité à une itération de la boucle
- Dividende=0;
- for(int i=ChiffreBase-1; i>=0; i--, IndexThis--) Dividende.Nb.D[i]=this->Nb.D[IndexThis];
-
- for(; IndexThis>=0; IndexThis--){
- // TODO : A faire en Asm (SSE ou non, selon le mieux)
- for(int i=31; i>=0; i--) Dividende.Nb.D[i+1]=Dividende.Nb.D[i];
- Dividende.Nb.D[0]=this->Nb.D[IndexThis];
-
- unsigned long long Quotient, RestePart;
- asm ("divq %4" //Premiere estimation de Quotient
- :"=a" (Quotient), "=d" (RestePart)
- :"a" ( Dividende.Nb.D[ChiffreBase] + ((unsigned long long)Dividende.Nb.D[ChiffreBase+1]<<32)), "d" (0), "g" ( (unsigned long long)Mod.Nb.D[ChiffreBase])
- );
- bool QuotientOK=false;
- if(Quotient > 0xFFFFFFFF) {
- Quotient=0xFFFFFFFF;
- //RestePart = Dividende.Nb.D[ChiffreBase+1]:Dividende.Nb.D[ChiffreBase] - 0xFFFFFFFF * Md.Nb.D[ChiffreBase]
- RestePart= Dividende.Nb.D[ChiffreBase] + ((unsigned long long)Dividende.Nb.D[ChiffreBase+1]<<32) - ((unsigned long long)Mod.Nb.D[ChiffreBase]<<32) + Mod.Nb.D[ChiffreBase]<<32;
- if(RestePart & 0xFFFFFFFF00000000) QuotientOK=true;
- }
- //Ensuite, le but est de rajouter des chiffres et de calculer l'erreur que l'on commet : on multiplie l'estimation du quotient déjà faite par les chiffres
- //de Mod déja pris en compte puis on soustrait les chiffres de dividende déjà pris en compte. Si le résultat est négatif ou nul, pas de problème,
- //Quotient n'est pas trop grand (il ne peut pas être trop petit). Dans ce cas, l'opposé du résultat correspond au reste de la division. S'il est positif,
- //on le divise par les chiffres de Mod déjà pris en compte : on obtient un nombre qu'il faut soustraire à Quotient. Sans optimisation, cette méthode est
- //impossible : on se retrouve a faire des divisions avec un dénominateur énorme et tout un tas de multiplications...
- //Pour simplifier, on se rend compte que ce nombre est calculable a partir du reste de la division précédente (calculé lors de la derniere estimation de
- //Quotient: on supprime donc beaucoup de multiplications inutiles. De plus, seules la premiere itération de cette boucle est utiles : les autres ne pourront
- //Faire descendre Quotient que de 1 : on remplace donc toutes ces itérations par une comparaison entre Quotient*Mod et Diviseur, qui nous dira s'il faut
- //décrémenter Quotient ou non.
-
- //Petite vérification.. histoire de pas faire des opérations pour rien
- if(Quotient == 0) continue;
-
- if(ChiffreBase == 0) QuotientOK=true;
-
- if(!QuotientOK){
- unsigned long long Tmp=Quotient*Mod.Nb.D[ChiffreBase-1];
- if(Tmp > ((unsigned long long)RestePart<<32) + Dividende.Nb.D[ChiffreBase-1])
- //Le nombre dont on parle dans le § de commentaires plus haut est positif : on réajuste Quotient
- //Diviseion en arrondissant par au dessus : d'où le 1 + et le -1
- Quotient-=1 + (Tmp - ((unsigned long long)RestePart<<32) - Dividende.Nb.D[ChiffreBase-1] - 1) / ( ((unsigned long long)Mod.Nb.D[ChiffreBase]<<32) + Mod.Nb.D[ChiffreBase-1] );
- }
-
- //On fait la grande multiplcation et soustraction
- Dividende=Dividende-Mod*Quotient;
- if(Dividende.carry) {
- Dividende.DecaleAdd(Mod,0);
- Quotient--;
- }
- if(ChercheQuotient)
- Res.Quotient->Nb.D[IndexThis]=Quotient;
- }
-
- return Res=Dividende;
- }
-
- inline bool Nb512::operator== (const Nb512 &Nb)const{
- return !memcmp(&this->Nb,&Nb.Nb,sizeof(Nb.Nb));
- }
-
- inline bool Nb1024::operator== (const Nb1024 &Nb)const{
- return !memcmp(&this->Nb,&Nb.Nb,sizeof(Nb.Nb));
- }
-
- inline bool Nb2048::operator== (const Nb2048 &Nb)const{
- return !memcmp(&this->Nb,&Nb.Nb,sizeof(Nb.Nb));
- }
-
- Nb512 Nb512::Puissance (const Nb512 &Exp, const Nb512 &Mod)const{
- Nb512 Res;
- Res=1;
- //TODO ne pas faire les premiers octets vides
- for(int i=63; i>=0; i--)
- for(int j=128; j>0; j>>=1){
- Res=Res*Res % Mod;
- if(Exp.Nb.B[i] & j){
- Res=Res* *this % Mod;
- }
- }
- return Res;
- }
-
- Nb1024 Nb1024::Puissance (const Nb1024 &Exp, const Nb1024 &Mod)const{
- Nb1024 Res;
- Res=1;
- //TODO ne pas faire les premiers octets vides
- for(int i=127; i>=0; i--)
- for(int j=128; j>0; j>>=1){
- Res=Res*Res % Mod;
- if(Exp.Nb.B[i] & j){
- Res=Res* *this % Mod;
- }
- }
- return Res;
- }
-
- void Nb512::Hasard (){
- for(int i=0; i<8; i++){
- NbHasard*=6364136223846793005; //Générateur de Haynes
- NbHasard++;
-
- this->Nb.Q[i]=NbHasard;
- }
- while ((Nb.Q[7] & ((unsigned long long)1<<63)) == 0){ //Pour avoir un VRAI nombre de 512 bits
- NbHasard*=6364136223846793005; //Générateur de Haynes
- NbHasard++;
-
- this->Nb.Q[7]=NbHasard;
- }
- }
-
- //http://cryptosec.lautre.net/article.php3?id_article=12
- bool Nb512::MillerRabin(unsigned int Boucles)const{
- unsigned int b;
- Nb512 thism1,un;
- un=1; thism1=*this -un;
-
- //calcul de b
- for(b=0;b<512; b+=64)
- if(thism1.Nb.Q[b>>6]!=0) break;
-
- if(b==512) return false; // *this==1
-
- for(; b<512; b++)
- if( (thism1.Nb.Q[b>>6] & ( 1 << (b&63)) )!=0) break;
-
- //calcul de r
- Nb512 r; int i;
- for(i=0; i<7 - (b>>6); i++)
- r.Nb.Q[i]=(thism1.Nb.Q[i + (b>>6) + 1]<<(64-(b&63))) | (thism1.Nb.Q[i + (b>>6)]>>(b&63));
- r.Nb.Q[i]=thism1.Nb.Q[i + (b>>6)]>>(b&63);
- for(i++; i<8; i++) r.Nb.Q[i]=0;
-
-
- for(i=0; i<Boucles; i++){
- Nb512 a;
- a.Hasard();
- //On s'assure que a<this* en mettant a 0 1 octet de plus dans a que dans this
- for(int j=63; j>=0; j--){
- a.Nb.B[i]=0;
- if(this->Nb.B[i] != 0) break;
- }
-
- //y est représenté ici par a :
- a=a.Puissance(r,*this);
- if(a==un) continue;
- for( int j=0; j<b; j++){
- if(a==un) return false;
- if(a==thism1) break;
- a=a*a % *this;
- }
- if(!(a==thism1)) return false;
- }
- return true;
- }
-
- void Nb512::Premier(){
- do{
- Hasard(); /*FIXME : utiliser un meilleur générateur aléatoire*/
- Nb.B[0]|=1;
- } while (!MillerRabin(5));
- }
-
- //trouve le nombre a tel que this*a = PGCD(this;Mod) modulo Mod
- //En fait, ici on l'appele avec this et Mod premiers entres eux.. donc PGCD=1 donc a*this = 1 modulo Mod donc a est bine l'inverse de this modulo Mod
- //On utilise pour ceci l'algoritme d'euclide étendu
- Nb1024 Nb1024::Inverse(const Nb1024 &Mod)const{
- Nb1024 Tmp1024;
-
- struct sListeQuotients{
- struct sListeQuotients* q;
- Nb1024 t;
- } *ListeQuotients=new struct sListeQuotients,*TmpListeQuotients;
-
-
- //On commence par appliquer l'algoritme d'euclide et on retient tous les quotients
- Nb1024 Nb2,Zero;
- Nb2048 Nb1;
- ListeQuotients->q=NULL;
- Zero=0;
- Nb1=Mod;
- Nb2=*this;
- do{
- Nb1.ChercheQuotient=true;
- Tmp1024=Nb1 % Nb2;
- ListeQuotients->t=*Tmp1024.Quotient;
- Nb1=Nb2;
- Nb2=Tmp1024;
- TmpListeQuotients=new struct sListeQuotients;
- TmpListeQuotients->q=ListeQuotients;
- ListeQuotients=TmpListeQuotients;
- }while(!(Nb2==Zero));
-
- //On enlève deux éléments de la liste : le premier car il est vide et le deuxième car on se fiche du dernier quotient obtenu
- TmpListeQuotients=ListeQuotients;
- ListeQuotients=ListeQuotients->q;
- delete TmpListeQuotients;
- TmpListeQuotients=ListeQuotients;
- ListeQuotients=ListeQuotients->q;
- delete TmpListeQuotients;
-
- //Et on le remonte pour finalement trouver les deux coefficients de Bezout, dont l'un est le nombre cherché
- //On calcule la suite : U(n-2)=U(n)-q(n-2)*U(n-1) où q(n) est le n-ième quotient calculé plus haut
- //Pour simplifier, on fait tous ces calculs modulo Mod. Si on se retrouve avec un U(n-2) négatif, on lui ajoute Mod
- Nb1024 Unm1,Un;
- Unm1=1;
- Un=0;
- while(ListeQuotients!=NULL){
- Tmp1024=Un- ((ListeQuotients->t * Unm1) % Mod);
- if(Tmp1024.carry) Tmp1024=Tmp1024+Mod;
-
- Un=Unm1;
- Unm1=Tmp1024;
-
- TmpListeQuotients=ListeQuotients;
- ListeQuotients=ListeQuotients->q;
- delete TmpListeQuotients;
- }
- return Unm1;
- }
-
- int main(){
- Nb512 p,q,un,clair512;
- un=1;
- Nb1024 n,e,d,phi,clair,chiffre,dechiffre;
- Nb2048 Verif;
- InitHasard();
-
- p.Premier();
- q.Premier();
-
- n=p*q;
- printf("\n\nModulo commun aux deux clées :\n");
- for(int i=31; i>=0; i--) printf("%.8X ",n.Nb.D[i]);
-
- phi=(p-un)*(q-un);
-
- e=0x10001;
- printf("\n\nExposant public e:(Par défaut, 0x10001)");
- //for(int i=31; i>=0; i--) printf("%.8X ",e.Nb.D[i]);
-
- d=e.Inverse(phi);
- printf("\n\nExposant privé d :\n");
- for(int i=31; i>=0; i--) printf("%.8X ",d.Nb.D[i]);
-
- printf("\n\nPour vérification, d*e mod phi(n)=(p-1)*(q-1): (doit être 1)\n");
- Verif=d*e;
- Verif=Verif % phi;
- for(int i=31; i>=0; i--) printf("%.8X ",Verif.Nb.D[i]);
-
- printf("\n\n\nTest: Bloc de départ (non chiffré) :\n");
- clair512.Hasard();
- clair=clair512;
- clair512.Hasard();
- clair.DecaleAdd(clair512,8);
- clair.Nb.B[127]&=0xf;
- for(int i=31; i>=0; i--) printf("%.8X ",clair.Nb.D[i]);
-
- printf("\n\nTest: Bloc chiffré :\n");
- chiffre=clair.Puissance(e,n);
- for(int i=31; i>=0; i--) printf("%.8X ",chiffre.Nb.D[i]);
-
- printf("\n\nTest: Bloc déchiffré :\n");
- dechiffre=chiffre.Puissance(d,n);
- for(int i=31; i>=0; i--) printf("%.8X ",dechiffre.Nb.D[i]);
-
- printf("\n");
- }
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
class Nb512;
class Nb1024;
unsigned long long NbHasard;
void InitHasard(){ NbHasard=time(NULL); }
class Nb2048{
public:
union {
unsigned D[64];
unsigned long long Q[32];
struct {
unsigned long long Lo;
unsigned long long Hi;
} O[16];
} Nb __attribute__ ((aligned(16)));
bool carry;
bool ChercheQuotient;
void DecaleAdd (const Nb1024 &terme, unsigned char decal); //Permet d'ajouter à un nombre de 1024 bits un nombre de 512 bits, en le décalant d'un nombre entier de qword
Nb1024 operator% (const Nb1024 &Mod)const;
Nb2048 operator+ (const Nb2048 &Terme)const;
Nb2048 operator- (const Nb2048 &Terme)const;
Nb2048& operator= (unsigned long long Nb);
Nb2048& operator= (const Nb1024 &Nb);
bool operator== (const Nb2048 &Nb)const;
Nb2048() : ChercheQuotient(false){};
};
class Nb1024{
public:
union {
unsigned char B[128];
unsigned D[32];
unsigned long long Q[16];
struct {
unsigned long long Lo;
unsigned long long Hi;
} O[8];
} Nb __attribute__ ((aligned(16)));
bool carry;
Nb2048* Quotient;
bool ChercheQuotient;
void DecaleAdd (const Nb512 &terme, unsigned char decal); //Permet d'ajouter à un nombre de 1024 bits un nombre de 512 bits, en le décalant d'un nombre entier de qword
Nb1024& operator= (unsigned long long Nb);
Nb1024& operator= (const Nb512 &Nb);
Nb1024& operator= (const Nb1024 &Nb);
Nb1024& operator= (const Nb2048 &Nb);
Nb512 operator% (const Nb512 &Mod)const;
Nb1024 operator+ (const Nb1024 &Terme)const;
Nb1024 operator- (const Nb1024 &Terme)const;
Nb2048 operator* (unsigned long long fact)const;
Nb2048 operator* (const Nb1024 &fact)const;
bool operator== (const Nb1024 &Nb)const;
Nb1024 Nb1024::Puissance (const Nb1024 &Exp, const Nb1024 &Mod)const;
Nb1024() : ChercheQuotient(false),Quotient(NULL){}
Nb1024(const Nb1024& c){
for(int i=0; i<16; i++) Nb.Q[i]=c.Nb.Q[i];
carry=c.carry;
ChercheQuotient=c.ChercheQuotient;
if(c.Quotient!=NULL){
Quotient=new Nb2048;
*Quotient=*c.Quotient;
} else Quotient=NULL;
}
~Nb1024(){if(Quotient!=NULL) delete Quotient;}
Nb1024 Inverse(const Nb1024 &Mod)const;
};
class Nb512{
public:
union {
unsigned char B[64];
unsigned D[16];
unsigned long long Q[8];
struct {
unsigned long long Lo;
unsigned long long Hi;
} O[4];
} Nb __attribute__ ((aligned(16)));
bool carry;
Nb1024* Quotient;
Nb512 operator+ (const Nb512 &Terme)const;
Nb512 operator- (const Nb512 &Terme)const;
Nb512& operator= (unsigned long long Nb);
Nb512& operator= (const Nb512 &Nb);
Nb512& operator= (const Nb1024 &Nb);
Nb1024 operator* (const Nb512 &Fact)const; //Il est plus rapide de mettre les plus petits nombres en premier opérande avec cet opérateur( si possible)
Nb1024 operator* (unsigned long long fact)const;
bool operator== (const Nb512 &Nb)const;
Nb512 Puissance (const Nb512 &Exp, const Nb512 &Mod)const;
void Hasard (); //Crée un nombre aléatoire non-sécurisé ( pour les tests et le test de Miller-Rabin)
bool MillerRabin(unsigned int Boucles)const;
void Premier();
Nb512():Quotient(NULL){}
Nb512(const Nb512& c){
for(int i=0; i<8; i++) Nb.Q[i]=c.Nb.Q[i];
carry=c.carry;
if(c.Quotient!=NULL){
Quotient=new Nb1024;
*Quotient=*c.Quotient;
}else Quotient=NULL;
}
~Nb512(){if(Quotient!=NULL) delete Quotient;}
};
inline void Nb1024::DecaleAdd(const Nb512 &terme, unsigned char decal){
asm ("add %8, %0\n\t"
"adc %9, %1\n\t"
"adc %10,%2\n\t"
"adc %11,%3\n\t"
"adc %12,%4\n\t"
"adc %13,%5\n\t"
"adc %14,%6\n\t"
"adc %15,%7\n\t"
/*FIXME : mettre la derniere retenue dans la variable carry*/
"jnc 1f\n\t"
"lea %7,%%R8\n\t"
"0:\n\t" //gestion de la retenue : si elle persiste, on la fait remonter tout le nombre (pas de gestion de dépassement de la fin du nombre -> peut provoquer des bugs)
"jnc 1f\n\t"
"add $8,%%R8\n\t"
"add $1,(%%R8)\n\t"
"jmp 0b\n\t"
"1:\n\t"
:
"=m" (Nb.Q[decal+0]), "=m" (Nb.Q[decal+1]), "=m" (Nb.Q[decal+2]), "=m" (Nb.Q[decal+3]),
"=m" (Nb.Q[decal+4]), "=m" (Nb.Q[decal+5]), "=m" (Nb.Q[decal+6]), "=m" (Nb.Q[decal+7])
:
"r" (terme.Nb.Q[0]), "r" (terme.Nb.Q[1]), "r" (terme.Nb.Q[2]), "r" (terme.Nb.Q[3]),
"r" (terme.Nb.Q[4]), "r" (terme.Nb.Q[5]), "r" (terme.Nb.Q[6]), "r" (terme.Nb.Q[7])
);
}
inline void Nb2048::DecaleAdd(const Nb1024 &terme, unsigned char decal){
bool c;
asm ("add %9, %0\n\t"
"adc %10,%1\n\t"
"adc %11,%2\n\t"
"adc %12,%3\n\t"
"adc %13,%4\n\t"
"adc %14,%5\n\t"
"adc %15,%6\n\t"
"adc %16,%7\n\t"
"setc %8\n\t"
:
"=m" (Nb.Q[decal+0]), "=m" (Nb.Q[decal+1]), "=m" (Nb.Q[decal+2]), "=m" (Nb.Q[decal+3]),
"=m" (Nb.Q[decal+4]), "=m" (Nb.Q[decal+5]), "=m" (Nb.Q[decal+6]), "=m" (Nb.Q[decal+7]),
"=g" (c)
:
"r" (terme.Nb.Q[0]), "r" (terme.Nb.Q[1]), "r" (terme.Nb.Q[2]), "r" (terme.Nb.Q[3]),
"r" (terme.Nb.Q[4]), "r" (terme.Nb.Q[5]), "r" (terme.Nb.Q[6]), "r" (terme.Nb.Q[7])
);
asm ("test $1,%8\n\t"
"clc\n\t"
"jz 1f\n\t"
"stc\n\t"
"1:\n\t"
"adc %9, %0\n\t"
"adc %10,%1\n\t"
"adc %11,%2\n\t"
"adc %12,%3\n\t"
"adc %13,%4\n\t"
"adc %14,%5\n\t"
"adc %15,%6\n\t"
"adc %16,%7\n\t"
/*FIXME : mettre la derniere retenue dans la variable carry*/
"jnc 1f\n\t"
"lea %7,%%R8\n\t"
"0:\n\t" //gestion de la retenue : si elle persiste, on la fait remonter tout le nombre (pas de gestion de dépassement de la fin du nombre -> peut provoquer des bugs)
"jnc 1f\n\t"
"add $8,%%R8\n\t"
"add $1,(%%R8)\n\t"
"jmp 0b\n\t"
"1:\n\t"
:
"=m" (Nb.Q[decal+8]), "=m" (Nb.Q[decal+9]), "=m" (Nb.Q[decal+10]),"=m" (Nb.Q[decal+11]),
"=m" (Nb.Q[decal+12]),"=m" (Nb.Q[decal+13]),"=m" (Nb.Q[decal+14]),"=m" (Nb.Q[decal+15])
:
"g" (c),
"r" (terme.Nb.Q[8]), "r" (terme.Nb.Q[9]), "r" (terme.Nb.Q[10]),"r" (terme.Nb.Q[11]),
"r" (terme.Nb.Q[12]),"r" (terme.Nb.Q[13]),"r" (terme.Nb.Q[14]),"r" (terme.Nb.Q[15])
);
}
inline Nb512& Nb512::operator= (unsigned long long Nb){
memset(&this->Nb,0,sizeof(this->Nb));
this->Nb.Q[0]=Nb;
return *this;
}
inline Nb1024& Nb1024::operator= (unsigned long long Nb){
memset(&this->Nb,0,sizeof(this->Nb));
this->Nb.Q[0]=Nb;
return *this;
}
inline Nb2048& Nb2048::operator= (unsigned long long Nb){
memset(&this->Nb,0,sizeof(this->Nb));
this->Nb.Q[0]=Nb;
return *this;
}
inline Nb512& Nb512::operator= (const Nb1024 &Nb){
memcpy(&this->Nb,&Nb.Nb,sizeof(this->Nb));
return *this;
}
inline Nb1024& Nb1024::operator= (const Nb2048 &Nb){
memcpy(&this->Nb,&Nb.Nb,sizeof(this->Nb));
return *this;
}
inline Nb2048& Nb2048::operator= (const Nb1024 &Nb){
memcpy(&this->Nb, &Nb.Nb, sizeof(Nb.Nb));
memset((char*)&this->Nb + sizeof(Nb.Nb), 0, sizeof(this->Nb)-sizeof(Nb.Nb));
return *this;
}
inline Nb1024& Nb1024::operator= (const Nb512 &Nb){
memcpy(&this->Nb, &Nb.Nb, sizeof(Nb.Nb));
memset((char*)&this->Nb + sizeof(Nb.Nb), 0, sizeof(this->Nb)-sizeof(Nb.Nb));
return *this;
}
inline Nb1024& Nb1024::operator= (const Nb1024 &Nb){
memcpy(this, &Nb,sizeof(Nb));
if(Nb.Quotient!=NULL){
Quotient=new Nb2048;
*Quotient=*Nb.Quotient;
} else Quotient=NULL;
return *this;
}
inline Nb512& Nb512::operator= (const Nb512 &Nb){
memcpy(this, &Nb,sizeof(Nb));
if(Nb.Quotient!=NULL){
Quotient=new Nb1024;
*Quotient=*Nb.Quotient;
} else Quotient=NULL;
return *this;
}
inline Nb512 Nb512::operator+ (const Nb512 &Terme)const{
Nb512 Res;
asm ("add %17, %9\n\t"
"adc %18, %10\n\t"
"adc %19, %11\n\t"
"adc %20, %12\n\t"
"adc %21, %13\n\t"
"adc %22, %14\n\t"
"adc %23, %15\n\t"
"adc %24, %16\n\t"
"mov %9, %0\n\t"
"mov %10,%1\n\t"
"mov %11,%2\n\t"
"mov %12,%3\n\t"
"mov %13,%4\n\t"
"mov %14,%5\n\t"
"mov %15,%6\n\t"
"mov %16,%7\n\t"
"setc %8\n\t"
:
"=m" (Res.Nb.Q[0]), "=m" (Res.Nb.Q[1]), "=m" (Res.Nb.Q[2]), "=m" (Res.Nb.Q[3]),
"=m" (Res.Nb.Q[4]), "=m" (Res.Nb.Q[5]), "=m" (Res.Nb.Q[6]), "=m" (Res.Nb.Q[7]),
"=g" (Res.carry)
:
"r" (Terme.Nb.Q[0]), "r" (Terme.Nb.Q[1]), "r" (Terme.Nb.Q[2]), "r" (Terme.Nb.Q[3]),
"r" (Terme.Nb.Q[4]), "r" (Terme.Nb.Q[5]), "r" (Terme.Nb.Q[6]), "r" (Terme.Nb.Q[7]),
"g" (Nb.Q[0]), "g" (Nb.Q[1]), "g" (Nb.Q[2]), "g" (Nb.Q[3]),
"g" (Nb.Q[4]), "g" (Nb.Q[5]), "g" (Nb.Q[6]), "g" (Nb.Q[7])
);
return Res;
}
inline Nb1024 Nb1024::operator+ (const Nb1024 &Terme)const{
Nb1024 Res;
asm ("add %17, %9\n\t"
"adc %18, %10\n\t"
"adc %19, %11\n\t"
"adc %20, %12\n\t"
"adc %21, %13\n\t"
"adc %22, %14\n\t"
"adc %23, %15\n\t"
"adc %24, %16\n\t"
"mov %9, %0\n\t"
"mov %10,%1\n\t"
"mov %11,%2\n\t"
"mov %12,%3\n\t"
"mov %13,%4\n\t"
"mov %14,%5\n\t"
"mov %15,%6\n\t"
"mov %16,%7\n\t"
"setc %8\n\t"
:
"=m" (Res.Nb.Q[0]), "=m" (Res.Nb.Q[1]), "=m" (Res.Nb.Q[2]), "=m" (Res.Nb.Q[3]),
"=m" (Res.Nb.Q[4]), "=m" (Res.Nb.Q[5]), "=m" (Res.Nb.Q[6]), "=m" (Res.Nb.Q[7]),
"=g" (Res.carry)
:
"r" (Terme.Nb.Q[0]), "r" (Terme.Nb.Q[1]), "r" (Terme.Nb.Q[2]), "r" (Terme.Nb.Q[3]),
"r" (Terme.Nb.Q[4]), "r" (Terme.Nb.Q[5]), "r" (Terme.Nb.Q[6]), "r" (Terme.Nb.Q[7]),
"g" (Nb.Q[0]), "g" (Nb.Q[1]), "g" (Nb.Q[2]), "g" (Nb.Q[3]),
"g" (Nb.Q[4]), "g" (Nb.Q[5]), "g" (Nb.Q[6]), "g" (Nb.Q[7])
);
asm ("testl $1,%8\n\t"
"clc\n\t"
"jz 1f\n\t"
"stc\n\t"
"1:\n\t"
"adc %17, %9\n\t"
"adc %18, %10\n\t"
"adc %19, %11\n\t"
"adc %20, %12\n\t"
"adc %21, %13\n\t"
"adc %22, %14\n\t"
"adc %23, %15\n\t"
"adc %24, %16\n\t"
"mov %9, %0\n\t"
"mov %10,%1\n\t"
"mov %11,%2\n\t"
"mov %12,%3\n\t"
"mov %13,%4\n\t"
"mov %14,%5\n\t"
"mov %15,%6\n\t"
"mov %16,%7\n\t"
"setc %8\n\t"
:
"=m" (Res.Nb.Q[8]), "=m" (Res.Nb.Q[9]), "=m" (Res.Nb.Q[10]),"=m" (Res.Nb.Q[11]),
"=m" (Res.Nb.Q[12]),"=m" (Res.Nb.Q[13]),"=m" (Res.Nb.Q[14]),"=m" (Res.Nb.Q[15]),
"+g" (Res.carry)
:
"r" (Terme.Nb.Q[8]), "r" (Terme.Nb.Q[9]), "r" (Terme.Nb.Q[10]),"r" (Terme.Nb.Q[11]),
"r" (Terme.Nb.Q[12]),"r" (Terme.Nb.Q[13]),"r" (Terme.Nb.Q[14]),"r" (Terme.Nb.Q[15]),
"g" (Nb.Q[8]), "g" (Nb.Q[9]), "g" (Nb.Q[10]), "g" (Nb.Q[11]),
"g" (Nb.Q[12]),"g" (Nb.Q[13]),"g" (Nb.Q[14]), "g" (Nb.Q[15])
);
return Res;
}
inline Nb512 Nb512::operator- (const Nb512 &Terme)const{
Nb512 Res;
asm ("sub %17, %9\n\t"
"sbb %18, %10\n\t"
"sbb %19, %11\n\t"
"sbb %20, %12\n\t"
"sbb %21, %13\n\t"
"sbb %22, %14\n\t"
"sbb %23, %15\n\t"
"sbb %24, %16\n\t"
"mov %9, %0\n\t"
"mov %10,%1\n\t"
"mov %11,%2\n\t"
"mov %12,%3\n\t"
"mov %13,%4\n\t"
"mov %14,%5\n\t"
"mov %15,%6\n\t"
"mov %16,%7\n\t"
"setc %8\n\t"
:
"=m" (Res.Nb.Q[0]), "=m" (Res.Nb.Q[1]), "=m" (Res.Nb.Q[2]), "=m" (Res.Nb.Q[3]),
"=m" (Res.Nb.Q[4]), "=m" (Res.Nb.Q[5]), "=m" (Res.Nb.Q[6]), "=m" (Res.Nb.Q[7]),
"=g" (Res.carry)
:
"r" (Nb.Q[0]), "r" (Nb.Q[1]), "r" (Nb.Q[2]), "r" (Nb.Q[3]),
"r" (Nb.Q[4]), "r" (Nb.Q[5]), "r" (Nb.Q[6]), "r" (Nb.Q[7]),
"g" (Terme.Nb.Q[0]), "g" (Terme.Nb.Q[1]), "g" (Terme.Nb.Q[2]), "g" (Terme.Nb.Q[3]),
"g" (Terme.Nb.Q[4]), "g" (Terme.Nb.Q[5]), "g" (Terme.Nb.Q[6]), "g" (Terme.Nb.Q[7])
);
return Res;
}
inline Nb1024 Nb1024::operator- (const Nb1024 &Terme)const{
Nb1024 Res;
asm ("sub %17, %9\n\t"
"sbb %18, %10\n\t"
"sbb %19, %11\n\t"
"sbb %20, %12\n\t"
"sbb %21, %13\n\t"
"sbb %22, %14\n\t"
"sbb %23, %15\n\t"
"sbb %24, %16\n\t"
"mov %9, %0\n\t"
"mov %10,%1\n\t"
"mov %11,%2\n\t"
"mov %12,%3\n\t"
"mov %13,%4\n\t"
"mov %14,%5\n\t"
"mov %15,%6\n\t"
"mov %16,%7\n\t"
"setc %8\n\t"
:
"=m" (Res.Nb.Q[0]), "=m" (Res.Nb.Q[1]), "=m" (Res.Nb.Q[2]), "=m" (Res.Nb.Q[3]),
"=m" (Res.Nb.Q[4]), "=m" (Res.Nb.Q[5]), "=m" (Res.Nb.Q[6]), "=m" (Res.Nb.Q[7]),
"=g" (Res.carry)
:
"r" (Nb.Q[0]), "r" (Nb.Q[1]), "r" (Nb.Q[2]), "r" (Nb.Q[3]),
"r" (Nb.Q[4]), "r" (Nb.Q[5]), "r" (Nb.Q[6]), "r" (Nb.Q[7]),
"g" (Terme.Nb.Q[0]), "g" (Terme.Nb.Q[1]), "g" (Terme.Nb.Q[2]), "g" (Terme.Nb.Q[3]),
"g" (Terme.Nb.Q[4]), "g" (Terme.Nb.Q[5]), "g" (Terme.Nb.Q[6]), "g" (Terme.Nb.Q[7])
);
asm ("testl $1,%8\n\t"
"clc\n\t"
"jz 1f\n\t"
"stc\n\t"
"1:\n\t"
"sbb %17, %9\n\t"
"sbb %18, %10\n\t"
"sbb %19, %11\n\t"
"sbb %20, %12\n\t"
"sbb %21, %13\n\t"
"sbb %22, %14\n\t"
"sbb %23, %15\n\t"
"sbb %24, %16\n\t"
"mov %9, %0\n\t"
"mov %10,%1\n\t"
"mov %11,%2\n\t"
"mov %12,%3\n\t"
"mov %13,%4\n\t"
"mov %14,%5\n\t"
"mov %15,%6\n\t"
"mov %16,%7\n\t"
"setc %8\n\t"
:
"=m" (Res.Nb.Q[8]), "=m" (Res.Nb.Q[9]), "=m" (Res.Nb.Q[10]),"=m" (Res.Nb.Q[11]),
"=m" (Res.Nb.Q[12]),"=m" (Res.Nb.Q[13]),"=m" (Res.Nb.Q[14]),"=m" (Res.Nb.Q[15]),
"+g" (Res.carry)
:
"r" (Nb.Q[8]), "r" (Nb.Q[9]), "r" (Nb.Q[10]), "r" (Nb.Q[11]),
"r" (Nb.Q[12]),"r" (Nb.Q[13]),"r" (Nb.Q[14]), "r" (Nb.Q[15]),
"g" (Terme.Nb.Q[8]), "g" (Terme.Nb.Q[9]), "g" (Terme.Nb.Q[10]),"g" (Terme.Nb.Q[11]),
"g" (Terme.Nb.Q[12]),"g" (Terme.Nb.Q[13]),"g" (Terme.Nb.Q[14]),"g" (Terme.Nb.Q[15])
);
return Res;
}
inline Nb2048 Nb2048::operator- (const Nb2048 &Terme)const{
Nb2048 Res;
Res.carry=false;
for(int i=0; i<32; i+=8)
asm ("test $1,%8\n\t"
"clc\n\t"
"jz 1f\n\t"
"stc\n\t"
"1:\n\t"
"sbb %17, %9\n\t"
"sbb %18, %10\n\t"
"sbb %19, %11\n\t"
"sbb %20, %12\n\t"
"sbb %21, %13\n\t"
"sbb %22, %14\n\t"
"sbb %23, %15\n\t"
"sbb %24, %16\n\t"
"mov %9, %0\n\t"
"mov %10,%1\n\t"
"mov %11,%2\n\t"
"mov %12,%3\n\t"
"mov %13,%4\n\t"
"mov %14,%5\n\t"
"mov %15,%6\n\t"
"mov %16,%7\n\t"
"setc %8\n\t"
:
"=m" (Res.Nb.Q[i+0]), "=m" (Res.Nb.Q[i+1]), "=m" (Res.Nb.Q[i+2]), "=m" (Res.Nb.Q[i+3]),
"=m" (Res.Nb.Q[i+4]), "=m" (Res.Nb.Q[i+5]), "=m" (Res.Nb.Q[i+6]), "=m" (Res.Nb.Q[i+7]),
"+g" (Res.carry)
:
"r" (Nb.Q[i+0]), "r" (Nb.Q[i+1]), "r" (Nb.Q[i+2]), "r" (Nb.Q[i+3]),
"r" (Nb.Q[i+4]), "r" (Nb.Q[i+5]), "r" (Nb.Q[i+6]), "r" (Nb.Q[i+7]),
"g" (Terme.Nb.Q[i+0]), "g" (Terme.Nb.Q[i+1]), "g" (Terme.Nb.Q[i+2]), "g" (Terme.Nb.Q[i+3]),
"g" (Terme.Nb.Q[i+4]), "g" (Terme.Nb.Q[i+5]), "g" (Terme.Nb.Q[i+6]), "g" (Terme.Nb.Q[i+7])
);
return Res;
}
Nb1024 Nb512::operator* (const Nb512 &fact)const{
Nb512 TamponPair[8];
Nb512 TamponImpair[8];
bool Zero[8];
for(int i=0; i<8; i++){
if(Nb.Q[i]==0){
Zero[i]=true;
continue;
}
Zero[i]=false;
register unsigned long long ChiffreThis asm("%rcx")=Nb.Q[i];
for(int j=0; j<8; j+=2){
asm("mul %3"
:"=a" (TamponPair[i].Nb.Q[j & 0xE]), "=d" (TamponPair[i].Nb.Q[(j & 0xE)+1])
:"a" (fact.Nb.Q[j]), "r" (ChiffreThis)
);
asm("mul %3"
:"=a" (TamponImpair[i].Nb.Q[j & 0xE]), "=d" (TamponImpair[i].Nb.Q[(j & 0xE)+1])
:"a" (fact.Nb.Q[j+1]), "r" (ChiffreThis)
);
}
}
Nb1024 Retour;
Retour=0;
for(int i=0; i<8; i++) {
if(Zero[i]==false){
Retour.DecaleAdd(TamponPair[i],i);
Retour.DecaleAdd(TamponImpair[i],i+1);
}
}
return Retour;
}
Nb2048 Nb1024::operator* (const Nb1024 &fact)const{
Nb1024 TamponPair[16];
Nb1024 TamponImpair[16];
bool Zero[16];
for(int i=0; i<16; i++){
if(Nb.Q[i]==0){
Zero[i]=true;
continue;
}
Zero[i]=false;
register unsigned long long ChiffreThis asm("%rcx")=Nb.Q[i];
for(int j=0; j<16; j+=2){
asm("mul %3"
:"=a" (TamponPair[i].Nb.Q[j & 0xE]), "=d" (TamponPair[i].Nb.Q[(j & 0xE)+1])
:"a" (fact.Nb.Q[j]), "r" (ChiffreThis)
);
asm("mul %3"
:"=a" (TamponImpair[i].Nb.Q[j & 0xE]), "=d" (TamponImpair[i].Nb.Q[(j & 0xE)+1])
:"a" (fact.Nb.Q[j+1]), "r" (ChiffreThis)
);
}
}
Nb2048 Retour;
Retour=0;
for(int i=0; i<16; i++) {
if(Zero[i]==false){
Retour.DecaleAdd(TamponPair[i],i);
Retour.DecaleAdd(TamponImpair[i],i+1);
}
}
return Retour;
}
inline Nb1024 Nb512::operator* (unsigned long long fact)const{
Nb512 Tampon;
Nb1024 Res;
if(fact==0) return Res=0;
Res=0;
for(int i=0; i<8; i+=2){
asm("mul %3"
:"=a" (Res.Nb.Q[i & 0xE]), "=d" (Res.Nb.Q[(i & 0xE)+1])
:"a" (Nb.Q[i]), "r" (fact)
);
asm("mul %3"
:"=a" (Tampon.Nb.Q[i & 0xE]), "=d" (Tampon.Nb.Q[(i & 0xE)+1])
:"a" (Nb.Q[i+1]), "r" (fact)
);
}
Res.DecaleAdd(Tampon,1);
return Res;
}
inline Nb2048 Nb1024::operator* (unsigned long long fact)const{
Nb1024 Tampon;
Nb2048 Res;
if(fact==0) return Res=0;
Res=0;
for(int i=0; i<16; i+=2){
asm("mul %3"
:"=a" (Res.Nb.Q[i & 0xE]), "=d" (Res.Nb.Q[(i & 0xE)+1])
:"a" (Nb.Q[i]), "r" (fact)
);
asm("mul %3"
:"=a" (Tampon.Nb.Q[i & 0xE]), "=d" (Tampon.Nb.Q[(i & 0xE)+1])
:"a" (Nb.Q[i+1]), "r" (fact)
);
}
Res.DecaleAdd(Tampon,1);
return Res;
}
//Un chiffre = un DWORD
Nb512 Nb1024::operator% (const Nb512 &Mod)const{
Nb512 Res;
if(ChercheQuotient) {
if(Res.Quotient!=NULL) delete Res.Quotient;
Res.Quotient=new Nb1024;
*Res.Quotient=0;
}
//ChiffreBase : contient l'index du chiffre dans Dividende que l'on va utiliser pour faire la premiere approche de Quotient
signed char IndexThis, ChiffreBase;
for(IndexThis=31; this->Nb.D[IndexThis]==0; IndexThis--) if (IndexThis==0) return Res=0;
for(ChiffreBase=15; Mod.Nb.D[ChiffreBase]==0; ChiffreBase--) if(ChiffreBase==0) exit(-1); //division par 0
if(IndexThis<ChiffreBase) return Res=*this;
Nb1024 Dividende; //Dividende partiel traité à une itération de la boucle
Dividende=0;
for(int i=ChiffreBase-1; i>=0; i--, IndexThis--) Dividende.Nb.D[i]=this->Nb.D[IndexThis];
for(; IndexThis>=0; IndexThis--){
// TODO : A faire en Asm (SSE ou non, selon le mieux)
for(int i=15; i>=0; i--) Dividende.Nb.D[i+1]=Dividende.Nb.D[i];
Dividende.Nb.D[0]=this->Nb.D[IndexThis];
unsigned long long Quotient, RestePart;
asm ("divq %4" //Premiere estimation de Quotient
:"=a" (Quotient), "=d" (RestePart)
:"a" ( Dividende.Nb.D[ChiffreBase] + ((unsigned long long)Dividende.Nb.D[ChiffreBase+1]<<32)), "d" (0), "g" ( (unsigned long long)Mod.Nb.D[ChiffreBase])
);
bool QuotientOK=false;
if(Quotient > 0xFFFFFFFF) {
Quotient=0xFFFFFFFF;
//RestePart = Dividende.Nb.D[ChiffreBase+1]:Dividende.Nb.D[ChiffreBase] - 0xFFFFFFFF * Md.Nb.D[ChiffreBase]
RestePart= Dividende.Nb.D[ChiffreBase] + ((unsigned long long)Dividende.Nb.D[ChiffreBase+1]<<32) - ((unsigned long long)Mod.Nb.D[ChiffreBase]<<32) + Mod.Nb.D[ChiffreBase]<<32;
if(RestePart & 0xFFFFFFFF00000000) QuotientOK=true;
}
//Ensuite, le but est de rajouter des chiffres et de calculer l'erreur que l'on commet : on multiplie l'estimation du quotient déjà faite par les chiffres
//de Mod déja pris en compte puis on soustrait les chiffres de dividende déjà pris en compte. Si le résultat est négatif ou nul, pas de problème,
//Quotient n'est pas trop grand (il ne peut pas être trop petit). Dans ce cas, l'opposé du résultat correspond au reste de la division. S'il est positif,
//on le divise par les chiffres de Mod déjà pris en compte : on obtient un nombre qu'il faut soustraire à Quotient. Sans optimisation, cette méthode est
//impossible : on se retrouve a faire des divisions avec un dénominateur énorme et tout un tas de multiplications...
//Pour simplifier, on se rend compte que ce nombre est calculable a partir du reste de la division précédente (calculé lors de la derniere estimation de
//Quotient: on supprime donc beaucoup de multiplications inutiles. De plus, seules la premiere itération de cette boucle est utiles : les autres ne pourront
//Faire descendre Quotient que de 1 : on remplace donc toutes ces itérations par une comparaison entre Quotient*Mod et Diviseur, qui nous dira s'il faut
//décrémenter Quotient ou non.
//Petite vérification.. histoire de pas faire des opérations pour rien
if(Quotient == 0) continue;
if(ChiffreBase == 0) QuotientOK=true;
if(!QuotientOK){
unsigned long long Tmp=Quotient*Mod.Nb.D[ChiffreBase-1];
if(Tmp > ((unsigned long long)RestePart<<32) + Dividende.Nb.D[ChiffreBase-1])
//Le nombre dont on parle dans le § de commentaires plus haut est positif : on réajuste Quotient
//Diviseion en arrondissant par au dessus : d'où le 1 + et le -1
Quotient-=1 + (Tmp - ((unsigned long long)RestePart<<32) - Dividende.Nb.D[ChiffreBase-1] - 1) / ( ((unsigned long long)Mod.Nb.D[ChiffreBase]<<32) + Mod.Nb.D[ChiffreBase-1] );
}
Dividende=Dividende-Mod*Quotient;
if(Dividende.carry) {
Dividende.DecaleAdd(Mod,0);
Quotient--;
}
if(ChercheQuotient)
Res.Quotient->Nb.D[IndexThis]=Quotient;
}
return Res=Dividende;
}
Nb1024 Nb2048::operator% (const Nb1024 &Mod)const{
Nb1024 Res;
if(ChercheQuotient) {
if(Res.Quotient!=NULL) delete Res.Quotient;
Res.Quotient=new Nb2048;
*Res.Quotient=0;
}
//ChiffreBase : contient l'index du chiffre dans Dividende que l'on va utiliser pour faire la premiere approche de Quotient
signed char IndexThis, ChiffreBase;
for(IndexThis=63; this->Nb.D[IndexThis]==0; IndexThis--) if (IndexThis==0) return Res=0;
for(ChiffreBase=31; Mod.Nb.D[ChiffreBase]==0; ChiffreBase--) if(ChiffreBase==0) exit(-1); //division par 0
if(IndexThis<ChiffreBase) return Res=*this;
Nb2048 Dividende; //Dividende partiel traité à une itération de la boucle
Dividende=0;
for(int i=ChiffreBase-1; i>=0; i--, IndexThis--) Dividende.Nb.D[i]=this->Nb.D[IndexThis];
for(; IndexThis>=0; IndexThis--){
// TODO : A faire en Asm (SSE ou non, selon le mieux)
for(int i=31; i>=0; i--) Dividende.Nb.D[i+1]=Dividende.Nb.D[i];
Dividende.Nb.D[0]=this->Nb.D[IndexThis];
unsigned long long Quotient, RestePart;
asm ("divq %4" //Premiere estimation de Quotient
:"=a" (Quotient), "=d" (RestePart)
:"a" ( Dividende.Nb.D[ChiffreBase] + ((unsigned long long)Dividende.Nb.D[ChiffreBase+1]<<32)), "d" (0), "g" ( (unsigned long long)Mod.Nb.D[ChiffreBase])
);
bool QuotientOK=false;
if(Quotient > 0xFFFFFFFF) {
Quotient=0xFFFFFFFF;
//RestePart = Dividende.Nb.D[ChiffreBase+1]:Dividende.Nb.D[ChiffreBase] - 0xFFFFFFFF * Md.Nb.D[ChiffreBase]
RestePart= Dividende.Nb.D[ChiffreBase] + ((unsigned long long)Dividende.Nb.D[ChiffreBase+1]<<32) - ((unsigned long long)Mod.Nb.D[ChiffreBase]<<32) + Mod.Nb.D[ChiffreBase]<<32;
if(RestePart & 0xFFFFFFFF00000000) QuotientOK=true;
}
//Ensuite, le but est de rajouter des chiffres et de calculer l'erreur que l'on commet : on multiplie l'estimation du quotient déjà faite par les chiffres
//de Mod déja pris en compte puis on soustrait les chiffres de dividende déjà pris en compte. Si le résultat est négatif ou nul, pas de problème,
//Quotient n'est pas trop grand (il ne peut pas être trop petit). Dans ce cas, l'opposé du résultat correspond au reste de la division. S'il est positif,
//on le divise par les chiffres de Mod déjà pris en compte : on obtient un nombre qu'il faut soustraire à Quotient. Sans optimisation, cette méthode est
//impossible : on se retrouve a faire des divisions avec un dénominateur énorme et tout un tas de multiplications...
//Pour simplifier, on se rend compte que ce nombre est calculable a partir du reste de la division précédente (calculé lors de la derniere estimation de
//Quotient: on supprime donc beaucoup de multiplications inutiles. De plus, seules la premiere itération de cette boucle est utiles : les autres ne pourront
//Faire descendre Quotient que de 1 : on remplace donc toutes ces itérations par une comparaison entre Quotient*Mod et Diviseur, qui nous dira s'il faut
//décrémenter Quotient ou non.
//Petite vérification.. histoire de pas faire des opérations pour rien
if(Quotient == 0) continue;
if(ChiffreBase == 0) QuotientOK=true;
if(!QuotientOK){
unsigned long long Tmp=Quotient*Mod.Nb.D[ChiffreBase-1];
if(Tmp > ((unsigned long long)RestePart<<32) + Dividende.Nb.D[ChiffreBase-1])
//Le nombre dont on parle dans le § de commentaires plus haut est positif : on réajuste Quotient
//Diviseion en arrondissant par au dessus : d'où le 1 + et le -1
Quotient-=1 + (Tmp - ((unsigned long long)RestePart<<32) - Dividende.Nb.D[ChiffreBase-1] - 1) / ( ((unsigned long long)Mod.Nb.D[ChiffreBase]<<32) + Mod.Nb.D[ChiffreBase-1] );
}
//On fait la grande multiplcation et soustraction
Dividende=Dividende-Mod*Quotient;
if(Dividende.carry) {
Dividende.DecaleAdd(Mod,0);
Quotient--;
}
if(ChercheQuotient)
Res.Quotient->Nb.D[IndexThis]=Quotient;
}
return Res=Dividende;
}
inline bool Nb512::operator== (const Nb512 &Nb)const{
return !memcmp(&this->Nb,&Nb.Nb,sizeof(Nb.Nb));
}
inline bool Nb1024::operator== (const Nb1024 &Nb)const{
return !memcmp(&this->Nb,&Nb.Nb,sizeof(Nb.Nb));
}
inline bool Nb2048::operator== (const Nb2048 &Nb)const{
return !memcmp(&this->Nb,&Nb.Nb,sizeof(Nb.Nb));
}
Nb512 Nb512::Puissance (const Nb512 &Exp, const Nb512 &Mod)const{
Nb512 Res;
Res=1;
//TODO ne pas faire les premiers octets vides
for(int i=63; i>=0; i--)
for(int j=128; j>0; j>>=1){
Res=Res*Res % Mod;
if(Exp.Nb.B[i] & j){
Res=Res* *this % Mod;
}
}
return Res;
}
Nb1024 Nb1024::Puissance (const Nb1024 &Exp, const Nb1024 &Mod)const{
Nb1024 Res;
Res=1;
//TODO ne pas faire les premiers octets vides
for(int i=127; i>=0; i--)
for(int j=128; j>0; j>>=1){
Res=Res*Res % Mod;
if(Exp.Nb.B[i] & j){
Res=Res* *this % Mod;
}
}
return Res;
}
void Nb512::Hasard (){
for(int i=0; i<8; i++){
NbHasard*=6364136223846793005; //Générateur de Haynes
NbHasard++;
this->Nb.Q[i]=NbHasard;
}
while ((Nb.Q[7] & ((unsigned long long)1<<63)) == 0){ //Pour avoir un VRAI nombre de 512 bits
NbHasard*=6364136223846793005; //Générateur de Haynes
NbHasard++;
this->Nb.Q[7]=NbHasard;
}
}
//http://cryptosec.lautre.net/article.php3?id_article=12
bool Nb512::MillerRabin(unsigned int Boucles)const{
unsigned int b;
Nb512 thism1,un;
un=1; thism1=*this -un;
//calcul de b
for(b=0;b<512; b+=64)
if(thism1.Nb.Q[b>>6]!=0) break;
if(b==512) return false; // *this==1
for(; b<512; b++)
if( (thism1.Nb.Q[b>>6] & ( 1 << (b&63)) )!=0) break;
//calcul de r
Nb512 r; int i;
for(i=0; i<7 - (b>>6); i++)
r.Nb.Q[i]=(thism1.Nb.Q[i + (b>>6) + 1]<<(64-(b&63))) | (thism1.Nb.Q[i + (b>>6)]>>(b&63));
r.Nb.Q[i]=thism1.Nb.Q[i + (b>>6)]>>(b&63);
for(i++; i<8; i++) r.Nb.Q[i]=0;
for(i=0; i<Boucles; i++){
Nb512 a;
a.Hasard();
//On s'assure que a<this* en mettant a 0 1 octet de plus dans a que dans this
for(int j=63; j>=0; j--){
a.Nb.B[i]=0;
if(this->Nb.B[i] != 0) break;
}
//y est représenté ici par a :
a=a.Puissance(r,*this);
if(a==un) continue;
for( int j=0; j<b; j++){
if(a==un) return false;
if(a==thism1) break;
a=a*a % *this;
}
if(!(a==thism1)) return false;
}
return true;
}
void Nb512::Premier(){
do{
Hasard(); /*FIXME : utiliser un meilleur générateur aléatoire*/
Nb.B[0]|=1;
} while (!MillerRabin(5));
}
//trouve le nombre a tel que this*a = PGCD(this;Mod) modulo Mod
//En fait, ici on l'appele avec this et Mod premiers entres eux.. donc PGCD=1 donc a*this = 1 modulo Mod donc a est bine l'inverse de this modulo Mod
//On utilise pour ceci l'algoritme d'euclide étendu
Nb1024 Nb1024::Inverse(const Nb1024 &Mod)const{
Nb1024 Tmp1024;
struct sListeQuotients{
struct sListeQuotients* q;
Nb1024 t;
} *ListeQuotients=new struct sListeQuotients,*TmpListeQuotients;
//On commence par appliquer l'algoritme d'euclide et on retient tous les quotients
Nb1024 Nb2,Zero;
Nb2048 Nb1;
ListeQuotients->q=NULL;
Zero=0;
Nb1=Mod;
Nb2=*this;
do{
Nb1.ChercheQuotient=true;
Tmp1024=Nb1 % Nb2;
ListeQuotients->t=*Tmp1024.Quotient;
Nb1=Nb2;
Nb2=Tmp1024;
TmpListeQuotients=new struct sListeQuotients;
TmpListeQuotients->q=ListeQuotients;
ListeQuotients=TmpListeQuotients;
}while(!(Nb2==Zero));
//On enlève deux éléments de la liste : le premier car il est vide et le deuxième car on se fiche du dernier quotient obtenu
TmpListeQuotients=ListeQuotients;
ListeQuotients=ListeQuotients->q;
delete TmpListeQuotients;
TmpListeQuotients=ListeQuotients;
ListeQuotients=ListeQuotients->q;
delete TmpListeQuotients;
//Et on le remonte pour finalement trouver les deux coefficients de Bezout, dont l'un est le nombre cherché
//On calcule la suite : U(n-2)=U(n)-q(n-2)*U(n-1) où q(n) est le n-ième quotient calculé plus haut
//Pour simplifier, on fait tous ces calculs modulo Mod. Si on se retrouve avec un U(n-2) négatif, on lui ajoute Mod
Nb1024 Unm1,Un;
Unm1=1;
Un=0;
while(ListeQuotients!=NULL){
Tmp1024=Un- ((ListeQuotients->t * Unm1) % Mod);
if(Tmp1024.carry) Tmp1024=Tmp1024+Mod;
Un=Unm1;
Unm1=Tmp1024;
TmpListeQuotients=ListeQuotients;
ListeQuotients=ListeQuotients->q;
delete TmpListeQuotients;
}
return Unm1;
}
int main(){
Nb512 p,q,un,clair512;
un=1;
Nb1024 n,e,d,phi,clair,chiffre,dechiffre;
Nb2048 Verif;
InitHasard();
p.Premier();
q.Premier();
n=p*q;
printf("\n\nModulo commun aux deux clées :\n");
for(int i=31; i>=0; i--) printf("%.8X ",n.Nb.D[i]);
phi=(p-un)*(q-un);
e=0x10001;
printf("\n\nExposant public e:(Par défaut, 0x10001)");
//for(int i=31; i>=0; i--) printf("%.8X ",e.Nb.D[i]);
d=e.Inverse(phi);
printf("\n\nExposant privé d :\n");
for(int i=31; i>=0; i--) printf("%.8X ",d.Nb.D[i]);
printf("\n\nPour vérification, d*e mod phi(n)=(p-1)*(q-1): (doit être 1)\n");
Verif=d*e;
Verif=Verif % phi;
for(int i=31; i>=0; i--) printf("%.8X ",Verif.Nb.D[i]);
printf("\n\n\nTest: Bloc de départ (non chiffré) :\n");
clair512.Hasard();
clair=clair512;
clair512.Hasard();
clair.DecaleAdd(clair512,8);
clair.Nb.B[127]&=0xf;
for(int i=31; i>=0; i--) printf("%.8X ",clair.Nb.D[i]);
printf("\n\nTest: Bloc chiffré :\n");
chiffre=clair.Puissance(e,n);
for(int i=31; i>=0; i--) printf("%.8X ",chiffre.Nb.D[i]);
printf("\n\nTest: Bloc déchiffré :\n");
dechiffre=chiffre.Puissance(d,n);
for(int i=31; i>=0; i--) printf("%.8X ",dechiffre.Nb.D[i]);
printf("\n");
}
Conclusion
Se compile avec gcc ( soit la version Unix 64 bits, soit une version sous windows, toujours 64bits).
Un petit bug à la compilation, du à gcc : il faut compiler avec l'option -O (sinon il refuse de compiler).
Pas de bugs connus, mais quelques précisions : le message à coder ne doit pas être supèrieur ou égal à n.
Historique
- 03 mars 2005 20:34:31 :
- 29 novembre 2005 17:11:48 :
- Ajout de mots-cles
- 05 mai 2009 00:01:46 :
- corrections de typos.
Sources du même auteur
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
cryptage RSA [ par moicmoi ]
Bon je me doute que je vais passer pour un boulet mais j'aurai besoin avant jeudi d'un code source du cryptage RSA en LANGAGE C. Mais un code tout si
Cryptage RSA [ par ritchie00 ]
Salut,Qqun saurait où je peux trouver une API C++ de chiffrement/dechiffrement RSA, qui marcherait avec des certificats et des tailles de clés paramét
Debugage assembleur [ par crocejf2000 ]
Salut,Qq'un pourrai il peut etre m'aider, j'ai une méchante érreur et jmy connais pas trop en assembleur, Borland c++ 5 me renvoi ceci : Il s'arrete a
mettre de l'assembleur en ligne sous Visual C++ [ par alain34270 ]
alainBonjour,Voilà. J'ai un problème avec mon disque dur. je voudrais lire les secteurs physiques de mon disque dur, si possible à partir de visual C+
récupérer code assembleur [ par none77 ]
Bonjour,j'aimerai savoir si lorsque je programme en C il m'est possible de récupérer le code assembleur automatiquement.Je demande ca car je dois util
Macro assembleur pour microcontroleur [ par Tyozhebes ]
Bonjour à tous ! Je suis actuellement sur la programmation d'un 68HC11 et, pour des raisons de mémoire (seulement 2ko), il me faut le programmer en
[Asm][Devc++] [ par Gonath ]
Bon voilà, je programme sur devc++ depuis peu. Je voudrais y insérer des codes en assembleur vu que je connais l'assembleur. Mais le prob, c qu'il n'a
Le cryptage par MD5 de RSA [ par LSRS ]
Salut tout le monde...J'ai un très grand problème avec l'algorithme de hachage MD5 qui réprésente le squelette de mon stage d'été... Je n'arrive pas à
interruprion assembleur [ par seito ]
SVP est ce que quelqu'un sait comment éxecuter les interuptions assembleurs dans Visual Cmerci
Pb avec l'assembleur dev-cpp [ par 6co ]
Voici une source vue sur cppfrance et corrigée pour l'assembleur de Dev-Cpp#include <iostream>#include <stdlib.h>#include <conio.c>#
|
Derniers Blogs
IMAGINE CUP 2012, MAKE A SIGN EN FINALEIMAGINE CUP 2012, MAKE A SIGN EN FINALE par junarnoalg
Voilà qui est fait, la nouvelle est officielle ! L'équipe belge "Make a Sign" va au pays des kangourous défendre son projet dans la catégorie Software Design. http://www.imaginecup.com/CompetitionsContent/Competition/WorldwideFinalists.aspx V...
Cliquez pour lire la suite de l'article par junarnoalg KINECT 1.5 IS OUT !KINECT 1.5 IS OUT ! par Vko
La version 1.5 du Kinect For Microsoft vient tout juste de sortir ! Plein de nouveautés: Tracking de squelette en Near Mode Détection en position assise Détection faciale avec un SDK dédié Documentation et des guideline (enfin) Un out...
Cliquez pour lire la suite de l'article par Vko LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) par richardc
Mise à jour des Web API du 14 Mai
Réservez dès maintenant votre journée du 20 juin pour le Windows Azure Dev Camp 2012 à Paris
Mise à jour de Team Foundation Service
MechCommander 2 sur Windows 8
Entity Framework 5 Release Candidate e...
Cliquez pour lire la suite de l'article par richardc REACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITERREACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITER par Groc
Une mauvaise utilisation de rx lors de l'écriture d'une couche d'accès à des services peut conduire à des cas embarassants avec des erreurs mal gérées, des appels qui ne partent lorsqu'ils le devraient, et même des résultats incorrects . le tout nuis...
Cliquez pour lire la suite de l'article par Groc SHAREPOINT BLOG SITE, PROBLèME D'ARCHIVESSHAREPOINT BLOG SITE, PROBLèME D'ARCHIVES par junarnoalg
Dernièrement, nous avons migré le site
myTIC
vers un nouveau serveur SharePoint 2010. Dans les contenus que nous vouloins récupérer, nous avions un certain nombre de blogs.
Nous avons utilisé les commandes Power...
Cliquez pour lire la suite de l'article par junarnoalg
Forum
MATRICE TEMPLATEMATRICE TEMPLATE par hjr2610
Cliquez pour lire la suite par hjr2610 RE : SAC A DOS RE : SAC A DOS par hadjkaddour
Cliquez pour lire la suite par hadjkaddour
Logiciels
sDEVIS-FACTURES vlPRO (8.1.0.3)SDEVIS-FACTURES VLPRO (8.1.0.3)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO 974 Application Server (12.2.4.6)974 APPLICATION SERVER (12.2.4.6)Développez de puissantes applications dans un environnement de 'cloud computing', clusterisé, séc... Cliquez pour télécharger 974 Application Server vPicture (1.4.2.1)VPICTURE (1.4.2.1)Avec vPicture, hébergez vos images facilement et rapidement.
vPicture est un utilitaire simple, ... Cliquez pour télécharger vPicture Easy-Planning (2.2.1.6)EASY-PLANNING (2.2.1.6)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté au... Cliquez pour télécharger Easy-Planning COM-BACKUP (2.0)COM-BACKUP (2.0)
COM-BACKUP est un logiciel de sauvegarde qui permet de planifier les sauvegardes de vos dossiers ...
Cliquez pour télécharger COM-BACKUP
|