MANIPULATION TRÈS RAPIDE DE TRÈS GRANDS NOMBRES ENTIERS + FONCTIONS DE BASE DE L'ARITHMÉTIQUE MODULAIRE, NOMBRES PREMIERS ...
Description
Dans cette librairie, un type Hugint est défini pour la manipulation de nombres entiers trés grands, avec les fonctions correspondantes (addition, soustraction, multiplication et division). En plus les fonctions mathématiques de base sont implémentées : arithmétique modulaire, génération de nombres premiers trés grands, exponentionation modulaire (Montgomery), résolution d'équations diophantiennes et de congruence, factorisation, ... Le code est très optimisé, la division utilise l'algorithme le plus rapide de Knuth !
Développé par Faraoun Kamel Mohamed. UDL-SBA
Pour toute remarque ou suggestion : Kamel_mh@yahoo.fr
Conclusion
L'application ci-jointe est une démonstration utilisant cette bibliothèque.
Source / Exemple :
unit HugIntegers;
{********************************************************************************************}
{ Développer par Faraoun Kamel Mohamed }
{ Université Djilali Liabes -Sidi Bel Abbes - Algérie }
{ kamel_mh@yahoo.fr }
{********************************************************************************************}
interface
uses windows,Sysutils,StdCtrls,forms,Dialogs;
Const MaxLen=4096; {must be in the form 2^^n}
MaxPrimSteps=2629;
Type
{ Define a signed Hug integer structure : -2^^(Maxlen*32)...+2^^(Maxlen*32)}
Hugint=record case integer of
0:(i32:packed array [-1..MaxLen] of Dword);
1:(i16:packed array [-2..MaxLen*2] of word);
2:(i8:packed array [-4..MaxLen*4] of Byte);
end;
HugintArray=Array of Hugint;
PHugintArray=^HugintArray;
MontgomeryStruct=Record
modu,r,v,invr:Hugint;
nbits:Dword;
end;
SafeStruct=Record
Q:Hugint;
k:Dword;
end;
PSafeStruct=^SafeStruct;
Procedure AddHug(const t1,t2,Result:Hugint);
Procedure SubHug(const t1,t2,Result:Hugint);
Procedure MulHug(const t1,t2,Result:Hugint);
Procedure DivideModHug(a,b:Hugint;var Q,res:hugint);
Procedure ModuloHug(a,b:Hugint;var res:hugint);
procedure ShlHug(a:Hugint;count:word);
procedure ShrHug(const a:Hugint;const count:word);
Procedure SqrHug(const a,result:Hugint);
Procedure PowerHug(a:hugint;var Result:hugint ;p:longword);
Procedure ModPowerHug(a,b,modulo:hugint;var Result:hugint);
Function CompareHug(const t1,t2:Hugint):Smallint;
function IsNull(a:Hugint):boolean;
Function IsNeg(a:Hugint):boolean;
Function StrToHug(s:string):Hugint;
Function HugToStr(a:Hugint):String;
Function HugToHex(a:Hugint):String;
Function NumOfBits(a:Hugint):longint;
Function NumOfDecimalDigits(a:Hugint):Word;
Procedure HCopy(a,b:Hugint);
Function HexToHug(s:string):Hugint;
Function Hugtobin(a :Hugint):string;
Function BintoHug (s:string):Hugint;
Function OctaltoHug(S:string):Hugint;
Function HugtoOctal(a:Hugint):string;
Procedure IncHug(Var a:Hugint;p:Dword);
Procedure DecHug(Var a:Hugint;p:Dword);
Procedure AndHug(a,b:Hugint;Var Result:Hugint);
Procedure OrHug(a,b:Hugint;Var Result:Hugint);
Procedure XorHug(a,b:Hugint;Var Result:Hugint);
Procedure NotHug(a:Hugint;Var Result:Hugint);
Function AreHugsRelativlyPrimes(a,b:Hugint):Boolean;
Procedure ExtendedEuclid(a,b:HugInt;Var s,t:HugInt);
Function ResolveDiopantiene(a,b,c:Hugint;var x,y:Hugint):Boolean;
Function ResolveLinearCongruenceEquation(a,b,c:Hugint;Var Sol:PHugintArray;All:boolean):integer;
Procedure InvModHug(const a,modulo:Hugint;Var Result:Hugint);
Procedure GetRandomHugOnBits(Var Result:Hugint;Numbits:Integer);
Procedure GetRandomHugLowerThan(var Result:Hugint;Limit:Hugint);
Procedure InitMontgomeryStruct(Modulo:Hugint);
Procedure MgModPowerHug(a,b,n:Hugint;var Result:Hugint);
Function IsHugPrime(Number:Hugint;Prob:Extended=0.99):Boolean;
Procedure GetHugPrimeOnBits(Numbit:integer;Var Result:Hugint;SkipStep:integer=MaxPrimSteps);
Procedure GetHug4Kp3PrimeOnBits(Numbit:integer;Var Result:Hugint;SkipStep:integer=MaxPrimSteps);
Procedure GetStrongHugPrimeOnBits(Numbit:integer;Var Result:Hugint);
Procedure SqrtHug(Number:Hugint;Var Result:Hugint);
Procedure ModSquareHug(a,modulo:Hugint;Var Result:Hugint);
Procedure ResolveMultiLinearCongSystems(Resid,Modu:HugintArray;WithoutVerif:Boolean;Var Result:HugintArray);
Procedure ResolveQuadraticCongruenceEquation(a,b,c:Hugint;ModuloFactors:HugintArray;var n:Hugint;Var Result:HugintArray);
Procedure MonteCarloFactorizeHug(a:Hugint;var factors:HugintArray;Memo:Tmemo=nil);
Procedure PollardFactorizeHug(a:hugint;var Factors:HugintArray;Memo:Tmemo=nil);
Function BinaryGCDHug(a,b:HugInt):HugInt;
Function EuclidGCDHug(a,b:HugInt):HugInt;
Procedure GetPrime1(Numbit:integer;init:Hugint;Var Result:Hugint;var nbmont,nbitr:integer);
Procedure GetPrime2(Numbit:integer;init:Hugint;Var Result:Hugint;var nbmont,nbitr:integer);
Procedure GetPrime3(Numbit:integer;init:Hugint;Var Result:Hugint;var nbmont,nbitr:integer);
Procedure GetSafePrimeOnBits(Numbit:integer;Var Result:Hugint);
Procedure GetMulSafePrimeOnBits(Numbit:integer;Var Res:Hugint;facts:PSafeStruct=nil);
Procedure GetSafeWithGenerator(Numbit:integer;Var Result,Generator:Hugint);
Var Zero,One,Two,Three,Four,ProdFirstPrimes:Hugint;
MgStruct:MontgomeryStruct;
implementation
uses Unit1,FirstPrimesTable,PrimesDemo;
Var ind:Integer;
{***************************************************************************************}
{ Addition of two signed Hug integeres }
{***************************************************************************************}
Procedure AddHug(const t1,t2,result:Hugint);
var carr,indic,zer:Dword;
sizeA,sizeB:Word;
asm
push ebx
push esi
push edi
mov zer,0
mov bx,Word ptr[edx]
mov sizeB,bx
mov bx,Word ptr [eax] { Compare the size }
mov sizeA,bx
shl sizeA,2
shl sizeB,2
cmp bx,Word ptr [edx] { of the two numbers }
jg @@1 { and set the size }
mov bx,Word ptr [edx] { of the result to }
@@1: mov Word ptr[ecx],bx { the maximum one. }
cmp bx,0
je @@fin2
mov esi,ecx { Save the result adress (ecx).}
mov carr,0
mov indic,0
mov bx,word ptr [eax+2]{ }
cmp bx,Word ptr[edx+2] { Compare the signe of the two numbers}
je @@same { jump if same sign. }
{--------------------------------------------------------}
cmp bx,0 { put the negatif }
je @@t2 { number adr in edx }
xchg eax,edx { }
push ecx
mov cx,sizeA
mov bx,sizeB
mov sizeA,bx
mov sizeB,cx
pop ecx
@@t2: mov esi,ecx { Save ecx. }
inc carr
dec indic
{--------------------------------------------------------}
@@same: mov word ptr[ecx+2],bx {set the sign of the result (will be modified if diffrent signes))}
xor ecx,ecx { Here start the addition with carry. }
mov cx,word ptr [esi]
xor ebx,ebx
@@lp: add ebx,4
mov edi,0
cmp bx,sizeB
jg @@001
mov edi,Dword ptr [edx+ebx]
@@001: xor edi,indic {perform the 2 complement }
add edi,carr
mov carr,0
adc carr,0
cmp bx,sizeA
jg @@002
add edi,Dword ptr[eax+ebx]
adc carr,0
@@002: mov Dword ptr[esi+ebx],edi { esi contain the initial ecx value (@t3)}
or zer,edi
loop @@lp
mov ecx,carr
cmp indic,0
jne @@cmpRes {Jump if the two numbers are with diffrents signs}
add word ptr[esi],cx
mov Dword ptr[esi+ebx+4],ecx
or zer,ecx
jmp @@fin
{--------------------------------------------------------}
@@cmpRes:dec ecx
mov word ptr[esi+2],cx
cmp ecx,0
je @@fin
xor ecx,ecx
mov cx,word ptr[esi]
inc carr
xor ebx,ebx
@@lp3: add ebx,4
mov edi,Dword ptr[esi+ebx]
not edi
add edi,carr
mov Dword ptr[esi+ebx],edi
mov carr,0
adc carr,0
loop @@lp3
{--------------------------------------------------------}
@@fin: cmp zer,0
jne @@lll
mov word ptr[esi],0
jmp @@fin2
@@lll: xor ecx,ecx
mov cx,word ptr [esi]
shl ecx,2
add ecx,esi
@loop: cmp dword ptr[ecx],0
jne @@fin2
dec Word ptr[esi]
sub ecx,4
jmp @loop
@@fin2: mov ecx,esi
pop edi
pop esi
pop ebx
end;
{***************************************************************************************}
{ Substraction of two signed Hug integeres }
{***************************************************************************************}
Procedure SubHug(const t1,t2,Result:Hugint);
asm
push esi
mov esi,edx
cmp eax,edx
je @@zero {compare if t1 and t2 are same }
not word ptr[edx+2] {invesre signe of t2}
call addHug {and perform an addition }
cmp esi,ecx {in the case of t2=Result don't inverse the result sign}
je @@ret
not word ptr[edx+2]
@@ret: pop esi
Ret
{--------------------------------------------------------}
@@zero: push esi { if t1 and t2 are same then return 0}
mov esi,ecx
mov ecx,DWord ptr[ecx]
and ecx,$FFFFFFFF
jz @@fin
@@lp: mov Dword ptr[esi+ecx*4],0
loop @@lp
mov word ptr[esi],0
{--------------------------------------------------------}
@@fin: mov ecx,esi
pop esi
end;
{***************************************************************************************}
{ Faster Substraction of two signed Hug integeres }
{ Work only if t1,t2>=0, and t1>t2 }
{***************************************************************************************}
Procedure FastSub(const t1,t2:Hugint);
var borr:Dword;
asm
push ebx
push esi
mov borr,0
xor esi,esi
xor ecx,ecx
mov cx,word ptr[edx]
inc cx
@lp: add esi,4
mov ebx,Dword ptr[eax+esi]
sub ebx,borr
mov borr,0
sbb ebx,Dword ptr[edx+esi]
adc borr,0
Mov Dword ptr[eax+esi],ebx
loop @lp
xor ecx,ecx
Mov CX,word ptr[eax]
shl ecx,2
@ll: cmp dWord ptr[eax+ecx],0
jne @fin
dec Word ptr[eax]
sub ecx,4
jz @fin
jmp @ll
@fin: pop esi
pop ebx
end;
{***************************************************************************************}
{ Multiplication of two signed Hug integeres based on standard grade school algorithm }
{***************************************************************************************}
Procedure MulHug(const t1,t2,Result:Hugint);
{t1, t2 and Result Must be diffrent }
var carr:Dword;
sizet1,sizet2:Dword;
asm
push ebx
push esi
push edi
mov bx,word ptr[eax+2]
xor bx,word ptr[edx+2]
mov word ptr[ecx+2],bx
mov esi,1
xor ebx,ebx
mov bx,word ptr[eax]
mov sizet1,ebx
mov bx,word ptr[edx]
mov sizet2,ebx
cmp ebx,0
jz @@isnull
cmp sizet1,0
jnz @@loop1
@@isnull:mov Dword ptr[ecx],0 {one of the operand is null}
jmp @@end4
@@loop1:cmp esi,sizet1
jg @@end1
mov edi,1
mov carr,0
@@loop2:cmp edi,sizet2
jg @@end2
mov ebx,esi
add ebx,edi
dec ebx
cmp esi,1
jg @@next
mov Dword ptr[ecx+ebx*4],0
@@next: push eax
push edx
mov eax,Dword ptr[eax+esi*4]
mul Dword ptr [edx+edi*4]
add eax,carr
adc edx,0
add eax,Dword ptr[ecx+ebx*4]
adc edx,0
mov carr,edx
mov Dword ptr[ecx+ebx*4],eax
pop edx
pop eax
inc edi
jmp @@loop2
@@end2: mov ebx,carr
add edi,esi
dec edi
mov Dword ptr[ecx+edi*4],ebx
inc esi
jmp @@loop1
@@end1: mov bx,word ptr [eax]
add bx,word ptr [edx]
@@end3: mov word ptr[ecx],bx
{--------------------------------------------------------}
mov esi,ecx
xor ecx,ecx
mov cx,word ptr [esi]
shl ecx,2
add ecx,esi
@loop: cmp dword ptr[ecx],0
jne @@end4
cmp ecx,esi
je @@end4
dec Word ptr[esi]
sub ecx,4
jmp @loop
{--------------------------------------------------------}
@@end4: pop edi
pop esi
pop ebx
end;
{***************************************************************************************}
{ Compute the Square of a hug integer }
{***************************************************************************************}
Procedure SqrHug(const a,result:Hugint);
var carr:Dword;
sizet1,sizet2:Dword;
asm
push ebx
push esi
push edi
mov word ptr[edx+2],0
mov ecx,edx
mov esi,1
xor ebx,ebx
mov bx,word ptr[eax]
mov sizet1,ebx
cmp ebx,0
jnz @@loop1
jmp @@end3
@@loop1:cmp esi,sizet1
jg @@end1
mov edi,1
mov carr,0
@@loop2:cmp edi,sizet1
jg @@end2
mov ebx,esi
add ebx,edi
dec ebx
cmp esi,1
jg @@next
mov Dword ptr[ecx+ebx*4],0
@@next: push eax
push edx
mov edx,eax
mov eax,Dword ptr[eax+esi*4]
mul Dword ptr [edx+edi*4]
add eax,carr
adc edx,0
add eax,Dword ptr[ecx+ebx*4]
adc edx,0
mov carr,edx
mov Dword ptr[ecx+ebx*4],eax
pop edx
pop eax
inc edi
jmp @@loop2
@@end2: mov ebx,carr
add edi,esi
dec edi
mov Dword ptr[ecx+edi*4],ebx
inc esi
jmp @@loop1
@@end1: mov bx,word ptr [eax]
shl bx,1
@@end3: mov word ptr[ecx],bx
@@end4: pop edi
pop esi
pop ebx
end;
{***************************************************************************************}
{ Fast division function based on Knuth division algorithm }
{***************************************************************************************}
Procedure DivideModHug(a,b:Hugint;var Q,res:hugint);
Const basediv2=32768;
base=65536;
base_1=65535;
basearray:array [false..true] of dword=(base_1,base);
var d,inv_d:Byte;
bn,bn_1,ri,ri_1,ri_2:Word;
i,j,hb,ha,hr,ptr:integer;
rv,rhat,qhat,right,left,borrow,carry:Dword;
sigA,sigB:Word;
begin
if isnull(b) then begin
Raise ERangeError.Create( 'Illegal Division by 0.');
exit;
end;
{Determination of Q and Res signes}
q.i16[-1]:=a.i16[-1] and not(b.i16[-1]);
Res.i16[-1]:=a.i16[-1] or b.i16[-1];
{a and b comparison }
sigA:=a.i16[-1];
sigB:=b.i16[-1]; {save the signes of a and b}
a.i16[-1]:=0;
b.i16[-1]:=0; {take the absolute value of a and b}
i:=CompareHug(a,b);
a.i16[-1]:=sigA;
b.i16[-1]:=sigB; {restore the signes of a and b}
if i<=0 then begin
if i=0 then begin
res.i16[-2]:=0;
q.i16[-2]:=1;
q.i32[0]:=1;
exit;
end
else begin
for i:=-1 to a.i16[-2]-1 do res.i32[i]:=a.i32[i];
q.i16[-2]:=0;
q.i32[0]:=0;
exit;
end;
end;
ha:=a.i16[-2]shl 1-1;
if a.i16[ha]=0 then dec(ha);
for i:=-1 to a.i16[-2]-1 do res.i32[i]:=a.i32[i];
Res.i32[res.i16[-2]]:=0;
{ We can make a short division }
if (b.i16[-2]=1)and(b.i16[1]=0) then begin
rv:=0;
bn:=b.i16[0];
for i:=ha downto 0 do begin
rhat:=(rv shl 16)+res.i16[i];
Q.i16[i]:=rhat div bn;
rv:=rhat mod bn;
end;
Q.i16[ha+1]:=0;
Q.i16[-2]:=res.i16[-2];
while (Q.i32[Q.i16[-2]-1]=0)and(Q.i16[-2]>0) do dec(Q.i16[-2]);
if rv=0 then Res.i16[-2]:=0
else begin
Res.i16[-2]:=1;
Res.i32[0]:=rv;
end;
exit;
end;
{ Structures initialization }
hb:=b.i16[-2]shl 1-1;
if b.i16[hb]=0 then dec(hb);
ptr:=ha-hb;
hr:=ha+1;
Q.i16[-2]:=ptr shr 1+3;
for i:=0 to Q.i16[-2] do Q.i32[i]:=0;
{Camputation of the scaling factor d >[Base/Bn] }
bn:=b.i16[hb];
bn_1:=b.i16[hb-1];
d:=0;
while (bn<basediv2) do begin
bn:=bn shl 1;
inc(d);
end;
inv_d:=16-d;
{Initialization of the divisor most signifients digits Bn and Bn-1 }
if d>0 then begin
bn:=bn or(b.i16[hb-1] shr (inv_d));
if hb>2 then bn_1:=(bn_1 shl d)or(b.i16[hb-2] shr(inv_d))
else bn_1:=(bn_1 shl d);
end;
{ The main Loop}
for i:=ptr downto 0 do begin
{computation of the divident's most significant digits ri, ri_1 and ri_2 }
ri:=res.i16[hr];
ri_1:=res.i16[hr-1];
ri_2:=res.i16[hr-2];
if d>0 then begin
ri:=(ri shl d)or(ri_1 shr(inv_d));
ri_1:=(ri_1 shl d)or(ri_2 shr (inv_d));
if (hr-3)<0 then ri_2:=ri_2 shl d
else ri_2:=(ri_2 shl d)or(res.i16[hr-3] shr(inv_d));
end;
{Estimation of the quotion digit qhat }
if ri<>bn then begin
rhat:=(ri shl 16)or ri_1;
qhat:=rhat div bn;
rhat:=rhat mod bn;
right:=(rhat shl 16) or ri_2;
left:=bn_1*qhat;
if left>right then begin
dec(qhat);
if (rhat+bn<base) and(left-bn_1>right+(bn shl 16)) then dec(qhat);
end;
end
else begin
qhat:=base_1;
rhat:=ri_1+bn;
right:=(rhat shl 16)or ri_2;
if rhat<base then begin
left:=bn_1*qhat;
if left>right then begin
dec(qhat);
if (rhat+bn<base) and(left-bn_1>right+(bn shl 16)) then dec(qhat);
end;
end;
end;
{multiplication and substration (aiai-1......ai-n):=(aiai-1......ai-n)-qhat*b }
borrow:=base;
carry:=0;
for j:=i to i+hb do begin
carry:=b.i16[j-i]*qhat+(carry shr 16);
borrow:=res.i16[j]+basearray[borrow>=base]-(carry and base_1);
res.i16[j]:=borrow;
end;
borrow:=res.i16[i+hb+1]+basearray[borrow>=base]-(carry shr 16);
res.i16[i+hb+1]:=borrow;
{the quotion digit is stored }
Q.i16[i]:=qhat;
if (borrow<base) then begin
carry:=0;
for j:=i to i+hb do begin
carry:=res.i16[j]+b.i16[j-i]+(carry shr 16);
res.i16[j]:=carry;
end;
res.i16[i+hb+1]:=res.i16[j+1]+(carry shr 16);
dec(Q.i16[i]);
end;
hr:=hr-1;
end;
Res.i16[-2]:=b.i16[-2];
if hb mod 2=0 then Res.i16[hb+1]:=0;
while (res.i32[res.i16[-2]-1]=0)and(Res.i16[-2]>0) do dec(Res.i16[-2]);
while (Q.i32[Q.i16[-2]-1]=0)and(Q.i16[-2]>0) do dec(Q.i16[-2]);
end;
{***************************************************************************************}
{ Fast modulo function based on Knuth division algorithm }
{***************************************************************************************}
Procedure ModuloHug(a,b:Hugint;var res:hugint);
Const basediv2=32768;
base=65536;
base_1=65535;
basearray:array [false..true] of dword=(base_1,base);
var d,inv_d:Byte;
bn,bn_1,ri,ri_1,ri_2:Word;
i,j,hb,ha,hr,ptr:integer;
rv,rhat,qhat,right,left,borrow,carry:Dword;
sigA,sigB:Word;
begin
if isnull(b) then begin
Raise ERangeError.Create( 'Illegal Division by 0.');
exit;
end;
{Determination of Res signes}
Res.i16[-1]:=a.i16[-1] or b.i16[-1];
{a and b comparison }
sigA:=a.i16[-1];
sigB:=b.i16[-1]; {save the signes of a and b}
a.i16[-1]:=0;
b.i16[-1]:=0; {take the absolute value of a and b}
i:=CompareHug(a,b);
a.i16[-1]:=sigA;
b.i16[-1]:=sigB; {restore the signes of a and b}
if i<=0 then begin
if i=0 then begin
res.i16[-2]:=0;
exit;
end
else begin
for i:=-1 to a.i16[-2]-1 do res.i32[i]:=a.i32[i];
exit;
end;
end;
ha:=a.i16[-2]shl 1-1;
if a.i16[ha]=0 then dec(ha);
for i:=-1 to a.i16[-2]-1 do res.i32[i]:=a.i32[i];
Res.i32[res.i16[-2]]:=0;
{ We can make a short division }
if (b.i16[-2]=1)and(b.i16[1]=0) then begin
rv:=0;
bn:=b.i16[0];
for i:=ha downto 0 do begin
rhat:=(rv shl 16)+res.i16[i];
rv:=rhat mod bn;
end;
if rv=0 then Res.i16[-2]:=0
else begin
Res.i16[-2]:=1;
Res.i32[0]:=rv;
end;
exit;
end;
{ Structures initialization }
hb:=b.i16[-2]shl 1-1;
if b.i16[hb]=0 then dec(hb);
ptr:=ha-hb;
hr:=ha+1;
{Camputation of the scaling factor d >[Base/Bn] }
bn:=b.i16[hb];
bn_1:=b.i16[hb-1];
d:=0;
while (bn<basediv2) do begin
bn:=bn shl 1;
inc(d);
end;
inv_d:=16-d;
{Initialization of the divisor most signifients digits Bn and Bn-1 }
if d>0 then begin
bn:=bn or(b.i16[hb-1] shr (inv_d));
if hb>2 then bn_1:=(bn_1 shl d)or(b.i16[hb-2] shr(inv_d))
else bn_1:=(bn_1 shl d);
end;
{ The main Loop}
for i:=ptr downto 0 do begin
{computation of the divident's most significant digits ri, ri_1 and ri_2 }
ri:=res.i16[hr];
ri_1:=res.i16[hr-1];
ri_2:=res.i16[hr-2];
if d>0 then begin
ri:=(ri shl d)or(ri_1 shr(inv_d));
ri_1:=(ri_1 shl d)or(ri_2 shr (inv_d));
if (hr-3)<0 then ri_2:=ri_2 shl d
else ri_2:=(ri_2 shl d)or(res.i16[hr-3] shr(inv_d));
end;
{Estimation of the quotion digit qhat }
if ri<>bn then begin
rhat:=(ri shl 16)or ri_1;
qhat:=rhat div bn;
rhat:=rhat mod bn;
right:=(rhat shl 16) or ri_2;
left:=bn_1*qhat;
if left>right then begin
dec(qhat);
if (rhat+bn<base) and(left-bn_1>right+(bn shl 16)) then dec(qhat);
end;
end
else begin
qhat:=base_1;
rhat:=ri_1+bn;
right:=(rhat shl 16)or ri_2;
if rhat<base then begin
left:=bn_1*qhat;
if left>right then begin
dec(qhat);
if (rhat+bn<base) and(left-bn_1>right+(bn shl 16)) then dec(qhat);
end;
end;
end;
{multiplication and substration (aiai-1......ai-n):=(aiai-1......ai-n)-qhat*b }
borrow:=base;
carry:=0;
for j:=i to i+hb do begin
carry:=b.i16[j-i]*qhat+(carry shr 16);
borrow:=res.i16[j]+basearray[borrow>=base]-(carry and base_1);
res.i16[j]:=borrow;
end;
borrow:=res.i16[i+hb+1]+basearray[borrow>=base]-(carry shr 16);
res.i16[i+hb+1]:=borrow;
if (borrow<base) then begin
carry:=0;
for j:=i to i+hb do begin
carry:=res.i16[j]+b.i16[j-i]+(carry shr 16);
res.i16[j]:=carry;
end;
res.i16[i+hb+1]:=res.i16[j+1]+(carry shr 16);
end;
hr:=hr-1;
end;
Res.i16[-2]:=b.i16[-2];
if hb mod 2=0 then Res.i16[hb+1]:=0;
while (res.i32[res.i16[-2]-1]=0)and(Res.i16[-2]>0) do dec(Res.i16[-2]);
end;
{***************************************************************************************}
{ Comparison of two signed Hug integeres }
{***************************************************************************************}
Function CompareHug(const t1,t2:Hugint):Smallint;
{Result = 0:equal; 1:t1>t2; -1:t1<t2}
asm
push ebx
push edi
xor ebx,ebx
xor cx,cx
mov bx,word ptr[eax+2] { Compare the sign }
cmp bx,Word ptr[edx+2] { jump if the same }
je @@samesig
or bx,1 {0 or 1=1; FFFF or 1 =FFFF=-1; }
mov cx,bx
jmp @@end
@@samesig:xor cx,cx
mov bx,word ptr[eax] {Compare the size}
cmp bx,word ptr[edx]
je @@samsize
sub bx,word ptr[edx]
sets cl
dec cx
not cx
or cx,1
jmp @@end
@@samsize:cmp bx,0
je @@end
@@samsize1:mov edi,Dword ptr[eax+ebx*4]
cmp edi,Dword ptr[edx+ebx*4]
jne @@result
dec bx
jz @@end
jmp @@samsize1
@@Result: setbe cl
dec cx
not cx
or cx,1
@@end: mov result,cx
pop edi
pop ebx
end;
{***************************************************************************************}
{ Right shift of a Hug integer }
{***************************************************************************************}
procedure ShrHug(const a:Hugint;const count:word);
var c:word;
asm
push esi
push edi
cmp Word ptr[eax],0
je @@fin2
{--------------------------------------------------------}
xor ecx,ecx
mov cx,Word ptr[eax]
inc cx
shl cx,2
mov Dword ptr[eax+ecx],0
{--------------------------------------------------------}
xor ecx,ecx
mov cx,count
shr cx,5
mov edi,eax
jz @small
add edi,4
mov esi,edi
//--------------- move bytes
cmp cx,Word ptr[eax]
jl @@lower
mov cx,Word ptr[eax]
@@lower:sub Word ptr[eax],cx
shl cx,2
add esi,ecx
mov cx,Word ptr[eax]
rep movsd
//----------------{rz with zeros}
mov cx,Word ptr[eax]
inc cx
shl cx,2
mov edi,eax
add edi,ecx
mov cx,count
shr cx,5
push eax
xor eax,eax
rep stosd
pop eax
mov edi,eax
//---------------
@small:mov cx,count
and cx,$1f
jz @@fin2
xor edx,edx
mov dx,Word ptr[eax]
shl edx,2
add edx,eax
@@loop:cmp eax,edx
jg @@fin
add eax,4
mov esi,Dword ptr[eax+4]
shrd Dword ptr[eax],esi,cl
mov esi,Dword ptr[eax]
jmp @@loop
@@fin: cmp Dword ptr[eax-4],0
jne @@fin2
dec word ptr[edi]
@@fin2:pop edi
pop esi
end;
{***************************************************************************************}
{ Left shift of a Hug integer }
{***************************************************************************************}
procedure ShlHug(a:Hugint;count:word);
var c:word;
asm
push esi
push ebx
push edi
mov edi,eax
{--------------------------------------------------------}
xor ecx,ecx
mov cx,Word ptr[eax]
inc cx
shl cx,2
mov Dword ptr[eax+ecx],0
{--------------------------------------------------------}
xor ecx,ecx
mov cx,count
shr cx,5
jz @@small
add edi,4
mov esi,edi
//--------------- move bytes
mov bx,cx
mov cx,Word ptr[eax]
shl cx,2
add esi,ecx
shr cx,2
add cx,bx
mov Word ptr[eax],cx
shl cx,2
add edi,ecx
shr cx,2
std
rep movsd
cld
//----------------{rz with zeros}
mov cx,count
shr cx,5
push eax
xor eax,eax
rep stosd
pop eax
mov edi,eax
//---------------
@@small:mov cx,count
and cx,$1f
jz @@fin2
xor edx,edx
mov dx,Word ptr[eax]
and edx,maxlen-1
shl edx,2
add eax,edx
@@loop: cmp eax,edi
je @@fin
mov esi,Dword ptr[eax]
shld Dword ptr[eax+4],esi,cl
sub eax,4
jmp @@loop
@@fin: shl Dword ptr[edi+4],cl
cmp Dword ptr[eax+edx+4],0
je @@fin2
inc Word ptr[edi]
@@fin2: pop edi
pop ebx
pop esi
end;
{***************************************************************************************}
{ Test if a Hug integer is Null }
{***************************************************************************************}
function IsNull(a:Hugint):boolean;
asm
mov ax,word ptr[eax]
or ax,ax
setz al
end;
{***************************************************************************************}
{ Test if a Hug integer is Negative }
{***************************************************************************************}
Function IsNeg(a:Hugint):boolean;
asm
mov ax,word ptr[eax+2]
end;
{***************************************************************************************}
{ Increment a Hug Integer }
{***************************************************************************************}
Procedure IncHug(Var a:Hugint;p:Dword);
asm
cmp word ptr[eax+2],0
je @@start
not word ptr[eax+2]
call DecHug
not word ptr[eax+2]
Ret
@@start:push ebx
xor ebx,ebx
mov ecx,eax
add ecx,4
mov bx, word ptr[eax]
cmp bx,0
je @@endlp
@@non0: add Dword ptr[ecx],edx
jnc @@end
mov edx,1
inc ebx
shl ebx,2
add ebx,eax
@@loop: add ecx,4
cmp ecx,ebx
je @@endlp
add Dword ptr[ecx],1
jnc @@end
jmp @@loop
@@endlp:mov Dword ptr[ecx],edx
inc word ptr[eax]
@@end: pop ebx
end;
{***************************************************************************************}
{ Decrement a Hug Integer }
{***************************************************************************************}
Procedure DecHug(Var a:Hugint;p:Dword);
asm
cmp word ptr[eax+2],0
je @@Start
not word ptr[eax+2]
call IncHug
not word ptr[eax+2]
Ret
@@start:push ebx
push esi
xor ebx,ebx
mov ecx,eax
add ecx,4
mov bx, word ptr[eax]
cmp bx,0
je @@endlp
@@non0: mov esi,Dword ptr[ecx]
sub esi,edx
sub Dword ptr[ecx],edx
jnb @@end
mov edx,1
inc ebx
shl ebx,2
add ebx,eax
@@loop: add ecx,4
cmp ecx,ebx
je @@endlp
sub Dword ptr[ecx],1
jnb @@end
jmp @@loop
@@endlp:not Dword ptr[ecx-4]
mov word ptr[eax+2],$ffff
@@end: cmp Word ptr[eax],1
jne @@fin1
cmp DWord ptr[eax+4],0
jne @@fin1
mov Word ptr[eax],0
@@fin1: cmp Word ptr[eax],2
jne @@fin
cmp DWord ptr[eax+8],0
jne @@fin
mov Word ptr[eax],1
@@fin: pop esi
pop ebx
end;
{***************************************************************************************}
{ Perform a logical "And" between two hug integers }
{***************************************************************************************}
Procedure AndHug(a,b:Hugint;Var Result:Hugint);
asm
push ebx
push esi
xor ebx,ebx
mov bx,word ptr[eax] {eax must represent alwayse the lowest hugint size}
cmp bx,word ptr[edx]
jl @@start
xchg eax,edx
@@start:mov ebx,1
@@loop1:mov esi,Dword ptr[eax+ebx*4]
and esi,Dword ptr[edx+ebx*4]
mov Dword ptr[ecx+ebx*4],esi
inc bx
cmp bx,Word ptr[eax]
jle @@loop1
@@loop2:cmp bx,Word ptr[edx]
jg @@end
mov Dword ptr[ecx+ebx*4],0
inc bx
jmp @@loop2
@@end: mov bx,word ptr[edx]
mov word ptr[ecx],bx
pop esi
pop ebx
end;
{***************************************************************************************}
{ Perform a logical "Or" between two hug integers }
{***************************************************************************************}
Procedure OrHug(a,b:Hugint;Var Result:Hugint);
asm
push ebx
push esi
xor ebx,ebx
mov bx,word ptr[eax] {eax must represent alwayse the lowest hugint size}
cmp bx,word ptr[edx]
jl @@start
xchg eax,edx
@@start:mov ebx,1
@@loop1:mov esi,Dword ptr[eax+ebx*4]
or esi,Dword ptr[edx+ebx*4]
mov Dword ptr[ecx+ebx*4],esi
inc bx
cmp bx,Word ptr[eax]
jle @@loop1
@@loop2:cmp bx,Word ptr[edx]
jg @@end
mov esi,Dword ptr[edx+ebx*4]
mov Dword ptr[ecx+ebx*4],esi
inc bx
jmp @@loop2
@@end: mov bx,word ptr[edx]
mov word ptr[ecx],bx
pop esi
pop ebx
end;
{***************************************************************************************}
{ Perform a logical "Xor" between two hug integers }
{***************************************************************************************}
Procedure XorHug(a,b:Hugint;Var Result:Hugint);
asm
push ebx
push esi
xor ebx,ebx
mov bx,word ptr[eax] {eax must represent alwayse the lowest hugint size}
cmp bx,word ptr[edx]
jl @@start
xchg eax,edx
@@start:mov ebx,1
@@loop1:mov esi,Dword ptr[eax+ebx*4]
xor esi,Dword ptr[edx+ebx*4]
mov Dword ptr[ecx+ebx*4],esi
inc bx
cmp bx,Word ptr[eax]
jle @@loop1
@@loop2:cmp bx,Word ptr[edx]
jg @@end
mov esi,Dword ptr[edx+ebx*4]
mov Dword ptr[ecx+ebx*4],esi
inc bx
jmp @@loop2
@@end: mov bx,word ptr[edx]
mov word ptr[ecx],bx
pop esi
pop ebx
end;
{***************************************************************************************}
{ Perform a logical "Not" between two hug integers }
{***************************************************************************************}
Procedure NotHug(a:Hugint;Var Result:Hugint);
asm
push ebx
push esi
xor ebx,ebx
@@loop: cmp bx,word ptr[eax]
jnl @@end
inc ebx
mov esi,Dword ptr[eax+ebx*4]
not esi
mov Dword ptr[edx+ebx*4],esi
jmp @@loop
@@end: mov bx,word ptr[eax]
mov word ptr[edx],bx
pop esi
pop ebx
end;
{***************************************************************************************}
{ Affect a Hug integer to another }
{***************************************************************************************}
Procedure HCopy(a,b:Hugint);
asm
push esi
push edi
mov esi,eax
mov edi,edx
xor ecx,ecx
mov cx,word ptr[eax]
inc cx
// shl cx,2
rep movsd
pop edi
pop esi
end;
{***************************************************************************************}
{ Compute the Power of a Hug integer to a longword value }
{***************************************************************************************}
Procedure PowerHug(a:hugint;var Result:hugint ;p:longword);
var i:byte;
tmp:hugint;
begin
Result.i32[-1]:=1;
Result.i32[0]:=1;
for i:=31 downto 0 do begin
Mulhug(result,result,tmp);
Hcopy(tmp,result);
if (p and(1 shl i)<>0)then begin
MulHug(Result,a,tmp);
Hcopy(tmp,Result);
end;
end;
end;
{***************************************************************************************}
{ Compute the Moular Power of a Hug integer to a Hug integer }
{***************************************************************************************}
Procedure ModPowerHug(a,b,modulo:hugint;var Result:hugint);
var i:Word;
tmp:hugint;
nbits:Longint;
begin
Result.i32[-1]:=1;
Result.i32[0]:=1;
nbits:=numofbits(b);
for i:=nbits-1 downto 0 do begin
Mulhug(result,result,tmp);
ModuloHug(tmp,modulo,Result);
if (b.i32[i shr 5] and (1 shl (i and 31))<>0) then begin
Mulhug(result,a,tmp);
ModuloHug(tmp,modulo,Result);
end;
end;
end;
{***************************************************************************************}
{ Return the number of bits of a Hug integer }
{***************************************************************************************}
Function NumOfBits(a:Hugint):longint;
var l:longint;
begin
if a.i16[-2]=0 then Result:=0
else begin
l:=(a.i16[-2]-1)shl 5;
l:=l+Trunc(Ln(a.i32[a.i16[-2]-1])/ln(2)+1);
Result:=l;
end;
end;
{***************************************************************************************}
{ Return the number of decimal digits of a Hug integer }
{***************************************************************************************}
Function NumOfDecimalDigits(a:Hugint):Word;
begin
Result:=Length(Hugtostr(a));
end;
{***************************************************************************************}
{ Determine if two Hug integers are relativly prime }
{***************************************************************************************}
Function AreHugsRelativlyPrimes(a,b:Hugint):Boolean;
begin
Result:=(CompareHug(BinaryGCDHug(a,b),One)=0);
end;
{***************************************************************************************}
{ Applay the exetended Euclid Algorithm to find s and t such That as+bt=gcd(a,b) }
{***************************************************************************************}
Procedure ExtendedEuclid(a,b:HugInt;Var s,t:HugInt);
var s0,s1,t0,t1,r,q,aa,bb,tmp:Hugint;
z:string;
begin
Hcopy(a,aa);
Hcopy(b,bb);
Hcopy(One,s0);
s1.i32[-1]:=0;
t0.i32[-1]:=0;
Hcopy(One,t1);
DivideModHug(aa,bb,q,r);
While not IsNull(r) do begin
MulHug(q,s1,tmp);
SubHug(s0,tmp,s);
MulHug(q,t1,tmp);
Subhug(t0,tmp,t);
Hcopy(s1,s0);
Hcopy(s,s1);
Hcopy(t1,t0);
Hcopy(t,t1);
Hcopy(bb,aa);
Hcopy(r,bb);
DivideModHug(aa,bb,q,r);
end;
end;
{***************************************************************************************}
{ Resolve the linear Diopantiene Equation ax+by=c }
{***************************************************************************************}
Function ResolveDiopantiene(a,b,c:Hugint;var x,y:Hugint):Boolean;
var g,r,q,tmp:Hugint;
begin
g:=BinaryGCDHug(a,b);
DivideModHug(c,g,q,r);
if IsNull(r) then begin
ExtendedEuclid(a,b,x,y);
Mulhug(x,q,tmp);
Hcopy(tmp,x);
MulHug(y,q,tmp);
Hcopy(tmp,y);
Result:=True;
end
else begin
Result:=False;
Raise ERangeError.Create( 'No integer solution for this equation ')
end;
end;
{***************************************************************************************}
{ Resolve the linear congurence ax # b[c] and return the number of solutions as result }
{***************************************************************************************}
Function ResolveLinearCongruenceEquation(a,b,c:Hugint;Var Sol:PHugintArray;All:boolean):integer;
var g,q,qq,qqq,r,x,y,tmp,aa,cc,s0,s1:Hugint;
i:integer;
NumSol:Dword;
begin
g:=BinaryGCDHug(a,c);
DivideModHug(b,g,q,r);
Hcopy(a,aa);
if IsNull(r) then begin
ModuloHug(aa,c,aa);
ModuloHug(b,c,b);
{********** ResolveDiopantiene(aa,c,b,x,y) ****}
g:=BinaryGCDHug(aa,c);
DivideModHug(b,g,qq,r);
if IsNull(r) then begin
{*********** ExtendedEuclid(aa,c,x,y) ****************}
Hcopy(c,cc);
Hcopy(One,s0);
s1.i32[-1]:=0;
DivideModHug(aa,cc,qqq,r);
While not IsNull(r) do begin
MulHug(qqq,s1,tmp);
SubHug(s0,tmp,x);
Hcopy(s1,s0);
Hcopy(x,s1);
Hcopy(cc,aa);
Hcopy(r,cc);
DivideModHug(aa,cc,qqq,r);
end;
{********************************************}
Mulhug(x,qq,tmp);
Hcopy(tmp,x);
end
else begin
Result:=-1;
Raise ERangeError.Create( 'No solution for this congruence equation ')
end;
{********************************************}
Numsol:=g.i16[0];
Setlength(Sol^,Numsol);
Hcopy(x,Sol^[0]);
if IsNeg(Sol^[0]) then AddHug(x,c,Sol^[0]);
ModuloHug(Sol^[0],c,Sol^[0]);
if All then begin
Tmp.i32[-1]:=1;
for i:=1 to NumSol-1 do begin
Tmp.i32[0]:=i;
MulHug(c,tmp,aa);
DivideModHug(aa,g,q,r);
AddHug(Sol^[0],q,Sol^[i]);
if IsNeg(Sol^[i]) then AddHug(Sol^[i],c,Sol^[i]);
ModuloHug(Sol^[i],c,Sol^[i]);
end;
end;
Result:=Numsol;
end
else begin
Result:=-1;
Raise ERangeError.Create( 'No solution for this congruence equation ')
end;
end;
{***************************************************************************************}
{ Compute the modular inverse of a Hug integer }
{***************************************************************************************}
Procedure InvModHug(const a,modulo:Hugint;Var Result:Hugint);
var g:Hugint;
Sol:PHugintArray;
begin
new(Sol);
if ResolveLinearCongruenceEquation(a,one,modulo,sol,false)=-1 then Raise ERangeError.Create( 'No inverse for the number with respect to the specified modulo ')
else Hcopy(sol^[0],Result);
end;
{***************************************************************************************}
{ Generate a random binary Hug integer on Numbit Bits }
{***************************************************************************************}
Procedure GetRandomHugOnBits(Var Result:Hugint;Numbits:Integer);
var b,i:integer;
x:Dword;
begin;
b:=Numbits shr 5;
Result.i32[-1]:=b;
For i:=0 to b-1 do Result.i32[i]:=Random($ffffffff);
if Numbits and 31=0 then Result.i32[b-1]:=Result.i32[b-1] or $80000000
else begin
inc(Result.i32[-1]);
x:=(1 shl (Numbits and 31)-1);
Result.i32[b]:=Random(x)or (1 shl ((Numbits and 31)-1));
end;
end;
{***************************************************************************************}
{ Generate a random binary block Lower than Limit }
{***************************************************************************************}
Procedure GetRandomHugLowerThan(var Result:Hugint;Limit:Hugint);
var b,i:integer;
begin
Result.i32[-1]:=Limit.i32[-1];
For i:=0 to Result.i32[-1]-1 do Result.i32[i]:=Random($FFFFFFFF);
ModuloHug(Result,Limit,Result);
while (Result.i32[Result.i16[-2]-1]=0)and(Result.i16[-2]>0) do dec(Result.i16[-2]);
end;
{***************************************************************************************}
{ Initialization of a montgomery strcutur with repect to a modulo (must be odd) }
{***************************************************************************************}
Procedure InitMontgomeryStruct(Modulo:Hugint);
var tmp,Head:DWord;
i:integer;
begin
if (Modulo.i32[0] and 1=0) then begin
Raise ERangeError.Create( 'Montgomery exponentiation can operate on odd modulo only ');
exit;
end;
with MgStruct do begin
r.i32[-1]:=Modulo.i32[-1];
for i:=0 to r.i16[-2]-1 do r.i32[i]:=0;
Head:=Modulo.i32[Modulo.i16[-2]-1];
if Head>$80000000 then begin
nbits:=r.i16[-2]shl 5;
inc(r.i16[-2]);
r.i32[r.i16[-2]-1]:=1;
end
else begin
tmp:=1;
nbits:=0;
while (tmp<=Head) do begin
tmp:=tmp shl 1;
inc(nbits);
end;
r.i32[r.i16[-2]-1]:=tmp;
nbits:=nbits+(r.i16[-2]-1) shl 5;
end;
ResolveDiopantiene(r,modulo,one,Invr,v);
if IsNeg(Invr) then AddHug(Invr,Modulo,Invr);
v.i16[-1]:=not(v.i16[-1]);
if IsNeg(v) then AddHug(v,r,v);
Hcopy(Modulo,Modu);
end;
end;
{***************************************************************************************}
{ Compute a^^b (mod n) using montgomery algorithm (n must be odd number) }
{ the montgomery approache is faster for very big numbers }
{***************************************************************************************}
Procedure MgModPowerHug(a,b,n:Hugint;var Result:Hugint);
var s,r0,m,t,fia:Hugint;
i:integer;
nbits:Longint;
begin
Hcopy(a,fia);
ShlHug(fia,MgStruct.nbits);
ModuloHug(fia,n,fia);
Hcopy(MgStruct.r,r0);
nbits:=NumOfBits(b);
For i:=nbits-1 downto 0 do begin
MulHug(r0,r0,s);
MulHug(s,MgStruct.v,t);
if t.i16[-2]>=MgStruct.r.i16[-2] then begin
t.i16[-2]:=MgStruct.r.i16[-2];
t.i32[t.i16[-2]-1]:=t.i32[t.i16[-2]-1] and (MgStruct.r.i32[MgStruct.r.i16[-2]-1]-1);
end;
while (t.i32[t.i16[-2]-1]=0)and(t.i16[-2]>0)do dec(t.i16[-2]);
MulHug(t,n,m);
AddHug(s,m,r0);
ShrHug(r0,MgStruct.nbits);
if CompareHug(r0,n)<>-1 then SubHug(r0,n,r0);
if (b.i32[i shr 5])and(1 shl (i and 31))<>0 then begin
MulHug(r0,fia,s);
MulHug(s,MgStruct.v,t);
if t.i16[-2]>=MgStruct.r.i16[-2] then begin
t.i16[-2]:=MgStruct.r.i16[-2];
t.i32[t.i16[-2]-1]:=t.i32[t.i16[-2]-1] and (MgStruct.r.i32[MgStruct.r.i16[-2]-1]-1);
end;
while (t.i32[t.i16[-2]-1]=0)and(t.i16[-2]>0)do dec(t.i16[-2]);
MulHug(t,n,m);
AddHug(s,m,r0);
ShrHug(r0,MgStruct.nbits);
if CompareHug(r0,n)<>-1 then SubHug(r0,n,r0);
end;
end;
MulHug(r0,MgStruct.invr,Result);
ModuloHug(Result,n,Result);
end;
{***************************************************************************************}
{ Test If a Hug Integer is a prime number Using the Rabin-Miller Test }
{***************************************************************************************}
Function IsHugPrime(Number:Hugint;Prob:Extended=0.99):Boolean;
Var SminusOne,Base,x,Q,minusOne:Hugint;
nbItr,Rest:Byte;
i:integer;
nbits:Longint;
Prim:Boolean;
begin
Randomize;
if (Number.i16[-2]=1)and(Number.i32[0]=2) then begin
{The number is 2}
Result:=True;
exit;
end;
if (Number.i32[0] and 1=0) then begin
{The number is Even}
Result:=False;
exit;
end;
SubHug(Number,One,minusOne);
ModPowerHug(Two,MinusOne,Number,x);
if CompareHug(x,One)<>0 then begin
Result:=false;
exit;
end;
Hcopy(MinusOne,SMinusOne);
ShrHug(SminusOne,1);
nbItr:=Round((-Ln(1-Prob)/(2*ln(2))));
i:=0;
Prim:=True;
nbits:=Numofbits(Number);
InitMontgomeryStruct(Number);
while (i<=nbItr-1)and(Prim) do begin
GetRandomHugOnBits(Base,12-1);
MgModPowerHug(Base,minusOne,Number,x);
if (x.i16[-2]<>1)or(x.i32[0]<>1) then
Prim:=false
else begin
Hcopy(SMinusOne,Q);
Rest:=0;
While (Rest=0)and Prim do begin
MgModPowerHug(Base,Q,Number,x);
if CompareHug(x,minusOne)=0 then Rest:=1
else begin
if (x.i16[-2]<>1)or(x.i32[0]<>1) then Prim:=False
else begin
Rest:=Q.i32[0] and 1;
ShrHug(Q,1);
end;
end;
end;
end;
i:=i+1;
end;
Result:=Prim;
end;
{***************************************************************************************}
{ Generate a Prime Number using Rabin-Miller Test }
{***************************************************************************************}
Procedure GetHugPrimeOnBits(Numbit:integer;Var Result:Hugint;SkipStep:integer=MaxPrimSteps);
var i,j,k:integer;
b,bb:boolean;
Begin
Randomize;
GetRandomHugOnBits(Result,Numbit);
Result.i32[0]:=Result.i32[0] or 1;
//i:=1;
Repeat
IncHug(Result,2);
bb:=(CompareHug(BinaryGCDHug(ProdFirstPrimes,Result),One)=0);
b:=bb and IsHugPrime(Result,0.99);
// i:=i+1;
// Form11.Edit1.Text:=inttostr(i);
// Application.ProcessMessages;
Until(b);
end;
Procedure GetPrime1(Numbit:integer;init:Hugint;Var Result:Hugint;var nbmont,nbitr:integer);
var i,j,k:integer;
b,bb:boolean;
Begin
Randomize;
Hcopy(init,Result);
Result.i32[0]:=Result.i32[0] or 1;
nbitr:=1;
nbmont:=0;
Repeat
IncHug(Result,2);
bb:=(CompareHug(BinaryGCDHug(ProdFirstPrimes,Result),One)=0);
b:=bb and IsHugPrime(Result,0.99);
if bb then inc(nbmont);
nbitr:=nbitr+1;
Until(b);
end;
Procedure GetPrime2(Numbit:integer;init:Hugint;Var Result:Hugint;var nbmont,nbitr:integer);
var i,j,k,step,Nstep:integer;
b,bb:boolean;
First,Small,x:Hugint;
R:Array[0..2629] of Dword;
Begin
Small.i32[-1]:=1;
Randomize;
Hcopy(init,Result);
Result.i32[0]:=Result.i32[0] or 1;
repeat
i:=1;
b:=true;
while (i<=2629)and b do begin
Small.i32[0]:=firstPrimes[i];
ModuloHug(Result,Small,x);
R[i]:=x.I32[0]*x.I16[-2];
b:=R[i]<>0;
i:=i+1;
end;
if not b then IncHug(Result,2);
until(b);
b:=IsHugPrime(Result,0.99);
NStep:=2;
nbitr:=1;
nbmont:=1;
While not b do begin
j:=1;
b:=true;
Step:=Nstep;
Nstep:=2;
IncHug(Result,Step);
while (j<=2629)do begin
R[j]:=(R[j]+step) mod FirstPrimes[j];
if (R[j]+Nstep)Mod FirstPrimes[j]=0 then Nstep:=Nstep+2;
b:=b and (R[j]<>0);
j:=j+1;
end;
if b then inc(nbmont);
b:=b and IsHugPrime(Result,0.99);
nbitr:=nbitr+1;
end;
end;
Procedure GetPrime3(Numbit:integer;init:Hugint;Var Result:Hugint;var nbmont,nbitr:integer);
var i,j,k,step,Nstep,Pas:integer;
z:Dword;
b,bb:boolean;
First,Small,x:Hugint;
R:Array[0..2629] of Dword;
Begin
Small.i32[-1]:=1;
Randomize;
Hcopy(init,Result);
Result.i32[0]:=Result.i32[0] or 1;
repeat
i:=1;
b:=true;
while (i<=2629)and b do begin
Small.i32[0]:=firstPrimes[i];
ModuloHug(Result,Small,x);
R[i]:=x.I32[0]*x.I16[-2];
b:=R[i]<>0;
i:=i+1;
end;
if not b then IncHug(Result,2);
until(b);
b:=IsHugPrime(Result,0.99);
NStep:=2;
Pas:=0;
nbitr:=1;
nbmont:=1;
While not b do begin
j:=1;
b:=true;
Pas:=Pas+NStep;
IncHug(Result,NStep);
Nstep:=2;
while (j<=2629) and b do begin
b:= b and ((R[j]+Pas) mod FirstPrimes[j]<>0);
if (R[j]+pas+Nstep)Mod FirstPrimes[j]=0 then Nstep:=Nstep+2;
j:=j+1;
end;
if b then inc(nbmont);
b:=b and IsHugPrime(Result,0.99);
nbitr:=nbitr+1;
end;
end;
{***************************************************************************************}
{ Generate a Prime Number on the form 4k+3 to be used for Blum-Glodwasser Cipher }
{***************************************************************************************}
Procedure GetHug4Kp3PrimeOnBits(Numbit:integer;Var Result:Hugint;SkipStep:integer=MaxPrimSteps);
var i,j,k:integer;
Two,Four,Small,Res:Hugint;
b:boolean;
Begin
Randomize;
Small.i16[-2]:=1;
Small.i16[-1]:=0;
GetRandomHugOnBits(Result,Numbit);
Result.i32[0]:=Result.i32[0] or 1;
if (Result.i32[0] and 3<>3) then Result.i32[0]:=Result.i32[0]+2;
k:=SkipStep;
Repeat
IncHug(Result,4);
j:=1;
b:=True;
While(j<=k)and b do begin
Small.i32[0]:=FirstPrimes[j];
ModuloHug(Result,Small,Res);
b:=b and not Isnull(Res);
j:=j+1;
end;
b:=b and IsHugPrime(Result,0.99);
Until(b);
end;
{***************************************************************************************}
{ Generate a Strong Prime Number using Gordon Algorithm }
{***************************************************************************************}
Procedure GetStrongHugPrimeOnBits(Numbit:integer;Var Result:Hugint);
var s,t,r,z,ps,p:Hugint;
tmp,i:Hugint;
bb:boolean;
Begin
GetRandomHugOnBits(s,Numbit div 2-8);
GetRandomHugOnBits(t,Numbit div 2-8);
Hcopy(one,i);
Repeat
Mulhug(t,i,tmp);
ShlHug(tmp,1);
AddHug(tmp,One,r);
IncHug(i,1);
until (IsHugPrime(r,0.99));
Subhug(r,two,tmp);
ModPowerHug(s,tmp,r,z);
MulHug(z,s,tmp);
ShlHug(tmp,1);
SubHug(tmp,One,ps);
Hcopy(One,i);
Repeat
Mulhug(r,s,tmp);
shlhug(tmp,1);
Mulhug(tmp,i,p);
addhug(p,ps,p);
shlhug(i,1);
until(NumOfBits(p)>Numbit);
bb:=IsHugPrime(p,0.999) ;
while not bb do begin
IncHug(i,1);
Mulhug(r,s,tmp);
shlhug(tmp,1);
mulhug(tmp,i,p);
addhug(ps,p,p);
bb:=IsHugPrime(p,0.99) ;
end;
Result:=p;
end;
{***************************************************************************************}
{ Generate a Safe Prime Number (2p+1) }
{***************************************************************************************}
Procedure GetSafePrimeOnBits(Numbit:integer;Var Result:Hugint);
var i,j,k,step,Nstep:integer;
b,p1,p2:boolean;
Q,Q_1,Small,x:Hugint;
R:Array[0..2629] of Dword;
Begin
Small.i32[-1]:=1;
GetRandomHugOnBits(Q,Numbit-1);
Q.i32[0]:=Q.i32[0] or 1;
k:=0;
Repeat
repeat
i:=1;
b:=(Q.i32[0] and 3=1);
while (i<=2629)and b do begin
Small.i32[0]:=firstPrimes[i];
ModuloHug(Q,Small,x);
R[i]:=x.I32[0]*x.I16[-2];
b:=(R[i]<>0)and(R[i]<>(firstPrimes[i]-1)div 2);
i:=i+1;
end;
if not b then IncHug(Q,2);
until(b);
b:=IsHugPrime(Q,0.99);
NStep:=2;
While not b do begin
j:=1;
b:=(Q.i32[0] and 3=1);
Step:=Nstep;
Nstep:=2;
IncHug(Q,Step);
while (j<=2629)do begin
R[j]:=(R[j]+step) mod FirstPrimes[j];
if (R[j]+Nstep)Mod FirstPrimes[j]=0 then Nstep:=Nstep+2;
b:=b and (R[j]<>0) and (R[j]<>(FirstPrimes[j]-1) div 2);
j:=j+1;
end;
b:=b and IsHugPrime(Q,0.99);
end;
Hcopy(Q,Result);
Hcopy(Q,Q_1);
ShlHug(Result,1);
IncHug(Result,1);
DecHug(Q_1,1);
ShrHug(Q_1,1);
inchug(Q,2);
j:=1;
b:=true;
while (j<=2629)do begin
R[j]:=(2*R[j]+1) mod FirstPrimes[j];
b:=b and (R[j]<>0);
j:=j+1;
end;
p1:=b and IsHugPrime(Result,0.99);
j:=1;
b:=true;
while (j<=2629)do begin
R[j]:=(2*R[j]-1) mod FirstPrimes[j];
b:=b and (R[j]<>0);
j:=j+1;
end;
p2:=p1 or (b and IsHugPrime(Q_1,0.99));
k:=k+1;
// Form1.Edit1.Text:=inttostr(k);
// Application.ProcessMessages;
Until(p1 or p2);
if p2 and not(p1)then Hcopy(Q_1,Result);
end;
{***************************************************************************************}
{ Generate a multiple Safe Prime Number (2*k*p+1) }
{***************************************************************************************}
Procedure GetMulSafePrimeOnBits(Numbit:integer;Var Res:Hugint;facts:PSafeStruct=nil);
var i,j,k,step,Nstep:Word;
fac:Dword;
b,p1,p2:boolean;
Q,Q2,Small,x:Hugint;
R,RQ:Array[0..2629] of Dword;
begin
Small.i32[-1]:=1;
GetRandomHugOnBits(Q,Numbit-16);
Q.i32[0]:=Q.i32[0] or 1;
k:=0;
Repeat
repeat
i:=1;
b:=True;
while (i<=2629)and b do begin
Small.i32[0]:=firstPrimes[i];
ModuloHug(Q,Small,x);
R[i]:=x.I32[0]*x.I16[-2];
b:=(R[i]<>0);
i:=i+1;
end;
if not b then IncHug(Q,2);
until(b);
b:=IsHugPrime(Q,0.99);
NStep:=2;
While not b do begin
j:=1;
b:=True;
Step:=Nstep;
Nstep:=2;
IncHug(Q,Step);
while (j<=2629)do begin
R[j]:=(R[j]+step) mod FirstPrimes[j];
if (R[j]+Nstep)Mod FirstPrimes[j]=0 then Nstep:=Nstep+2;
b:=b and (R[j]<>0);
j:=j+1;
end;
b:=b and IsHugPrime(Q,0.99);
end;
Hcopy(Q,Res);
ShlHug(Res,1);
Hcopy(Res,Q2);
ShlHug(Res,15);
incHug(Res,1);
fac:=65536;
j:=1;
b:=true;
while (j<=2629)do begin
Small.i32[0]:=firstPrimes[j];
ModuloHug(Res,Small,x);
R[j]:=x.I32[0]*x.I16[-2];
ModuloHug(Q2,Small,x);
RQ[j]:=x.I32[0]*x.I16[-2];
b:=b and (R[j]<>0);
j:=j+1;
end;
p1:=b and IsHugPrime(Res,0.99);
While(Not p1)and(fac<4294967296) do begin
AddHug(Res,Q2,Res);
fac:=fac+1;
j:=1;
b:=true;
while (j<=2629)do begin
R[j]:=(R[j]+RQ[j]) mod FirstPrimes[j];
b:=b and (R[j]<>0);
j:=j+1;
end;
P1:=b and IsHugPrime(Res);
//Form1.Edit2.Text:=inttostr(fac);
//Application.ProcessMessages;
end;
inchug(Q,2);
Until(p1);
if Facts<>Nil then begin
Facts^.k:=fac;
ShrHug(Q2,1);
Hcopy(Q2,Facts^.Q);
end;
end;
{***************************************************************************************}
{ Generate a multiple Safe Prime Number (2*k*p+1) With the corresponding Generator }
{***************************************************************************************}
Procedure GetSafeWithGenerator(Numbit:integer;Var Result,Generator:Hugint);
var k:DWORD;
Factors:Array of Dword;
sq,i:Dword;
Fstruct:PSafeStruct;
Q,res,pow,Small:Hugint;
isgen:boolean;
begin
New(Fstruct);
GetMulSafePrimeOnBits(Numbit,Result,Fstruct);
k:=Fstruct^.k;
sq:=Round(sqrt(k))+1;
Setlength(Factors,1);
Factors[0]:=2;
For i:=3 to sq do begin
if k mod i=0 then begin
Setlength(Factors,Length(Factors)+1);
Factors[Length(Factors)-1]:=i;
end;
end;
InitMontgomeryStruct(Result);
Repeat
GetRandomHugLowerThan(Generator,Result);
DecHug(Generator,1);
DivideModHug(Result,Fstruct^.Q,Q,Res);
MgModPowerHug(Generator,Q,Result,pow);
isgen:=not (CompareHug(Pow,One)=0);
i:=0;
Small.i32[-1]:=1;
while (isgen)and(i<=Length(Factors)-1) do begin
Small.i32[0]:=factors[i];
DivideModHug(Result,Small,Q,Res);
MgModPowerHug(Generator,Q,Result,pow);
isgen:=not (CompareHug(Pow,One)=0);
i:=i+1;
end;
until isgen;
end;
{***************************************************************************************}
{ Find the Integer Square root of a positive Hug Integer }
{***************************************************************************************}
Procedure SqrtHug(Number:Hugint;Var Result:Hugint);
var a,a_plus1,b,tmp:Hugint;
nbit:Longint;
stop:boolean;
begin
if IsNull(Number) then begin
Result.i32[-1]:=0;
exit;
end
else if IsNeg(Number) then begin
Raise ERangeError.Create( 'Can''t compute the square root of a negative number');
exit;
end;
nbit:=NumOfBits(Number) shr 1;
a.i32[-1]:=nbit shr 5+1;
a.i32[a.i32[-1]-1]:=1 shl (nbit and 31);
Stop:=false;
while not Stop do begin
DivideModHug(Number,a,b,tmp);
AddHug(a,b,b);
ShrHug(b,1);
SubHug(b,a,tmp);
tmp.i16[-1]:=0;
if CompareHug(Tmp,Two)=-1 then begin
MulHug(a,a,tmp);
if CompareHug(tmp,Number)<1 then begin
AddHug(a,One,a_plus1);
MulHug(a_plus1,a_plus1,tmp);
if CompareHug(tmp,Number)=1
then begin
Hcopy(a,Result);
Stop:=true;
end;
end;
end;
Hcopy(b,a);
end;
end;
{***************************************************************************************}
{ Find the Square of a hug integer "a" modulo "modulo" (Result^2==a[Modulo]) }
{***************************************************************************************}
Procedure ModSquareHug(a,modulo:Hugint;Var Result:Hugint);
var e1,e2,g,MinusOne,MinusOneDiv2,tmp,tmp2,tmp3:Hugint;
begin
{First we test if Modu is a Prime numbre}
if not IsHugPrime(modulo) then begin
Raise ERangeError.Create( 'The modulo must be a prime number ');
exit;
end;
{Then we test if a is a quadratic Residu modulo modu using Euler's Criterion}
SubHug(Modulo,One,tmp);
ShrHug(tmp,1);
ModPowerHug(a,tmp,modulo,g);
if (CompareHug(a,Modulo)<>0)and(CompareHug(g,One)<>0) then begin
Raise ERangeError.Create( Hugtostr(a)+' is not a Quadratic residu Modulo '+Hugtostr(modulo));
exit;
end;
if (Modulo.i32[0] and 3)=3 then begin
{The modulo is in the form 4k+3 so direct computation...}
AddHug(Modulo,One,Tmp);
ShrHug(Tmp,2);
ModPowerHug(a,tmp,modulo,Result);
end
else begin
{The Modulo is in the form 4k+1 so we use the Tonelli-Shanks Algorithm}
SubHug(modulo,One,MinusOne);
Hcopy(MinusOne,MinusOneDiv2);
ShrHug(Minusonediv2,1);
Hcopy(Two,g);
ModPowerHug(g,Minusonediv2,Modulo,tmp);
while CompareHug(tmp,MinusOne)<>0 do begin
incHug(g,1);
ModPowerHug(g,Minusonediv2,Modulo,tmp);
end;
Hcopy(MinusOneDiv2,e1);
e2.i32[-1]:=0;
While(e1.i32[0] and 1=0) do begin
ShrHug(e1,1);
ModPowerHug(a,e1,Modulo,tmp);
ModPowerHug(g,e2,Modulo,tmp2);
MulHug(tmp,tmp2,tmp3);
ModuloHug(tmp3,Modulo,tmp);
if CompareHug(tmp,MinusOne)=0 then begin
Addhug(e2,MinusOneDiv2,e2);
ShrHug(e2,1);
end;
end;
incHug(e1,1);
ShrHug(e1,1);
ModPowerHug(a,e1,Modulo,tmp2);
ShrHug(e2,1);
ModPowerHug(g,e2,Modulo,tmp3);
MulHug(tmp2,tmp3,tmp);
ModuloHug(tmp,Modulo,Result);
end;
end;
{***************************************************************************************}
{ Convert a Hug integer to a decimal string }
{***************************************************************************************}
Function HugToStr(a:Hugint):String;
var s,sig:string;
i:integer;
rem,bilion:Hugint;
SaveSig:Word;
begin
bilion.i32[-1]:=1;
bilion.i32[0]:=1000000000;
result:='';
SaveSig:=a.i16[-1];
if SaveSig<>0 then sig:='-' else sig:='';
a.i16[-1]:=0;
repeat
dividemodhug(a,bilion,a,rem);
if rem.i16[-2]<>0 then s:=inttostr(rem.i32[0])
else s:='0';
while length(s)<9 do s:='0'+s;
Result:=s+Result;
until(a.i32[-1]and $ffff=1)or(a.i32[-1]and $ffff=0)and(a.i32[0]<=999999999);
Result:=inttostr(a.i32[0])+result;
while (result[1]='0')and(length(Result)>1) do result:=copy(result,2,length(result));
result:=sig+result;
a.i16[-1]:=SaveSig;
end;
{***************************************************************************************}
{ Convert a Hug integer to a Hexadecimal string }
{***************************************************************************************}
Function HugToHex(a:Hugint):String;
var i:integer;
s:string;
begin
Result:='';
for i:=0 to a.i16[-2]-1 do begin
s:=inttohex(a.i32[i],8);
Result:=s+Result;
end;
if result<>'' then While (Result[1]='0')and (length(Result)>1) do
Result:=Copy(Result,2,length(Result))
else Result:='0';
end;
{***************************************************************************************}
{ Convert a Hexadecimal string to a Hug integer }
{***************************************************************************************}
Function HexToHug(s:string):Hugint;
var i,len:word;
tmp:Hugint;
begin
Hcopy(Zero,Result);
tmp.i16[-1]:=0;
len:=length(s);
for i:=len downto 1 do begin
tmp.i16[-2]:=1;
if s[i] in ['0'..'9'] then tmp.i32[0]:=Ord(s[i])-ord('0')
else if s[i]in ['A','B','C','D','E','F'] then tmp.i32[0]:=Ord(s[i])-ord('A')+10
else if s[i]in ['a','b','c','d','e','f'] then tmp.i32[0]:=Ord(s[i])-ord('a')+10
else tmp.i32[0]:=0;
ShlHug(tmp,(len-i)*4);
AddHug(Result,tmp,Result);
end;
end;
{***************************************************************************************}
{ Convert a binary string to a Hug integer }
{***************************************************************************************}
Function Hugtobin(a :Hugint):string;
var i,j:integer;
begin
Result:='';
for i:=0 to a.i16[-2] do begin
for j:=0 to 31 do if (a.i32[i] and (1 shl j))=0 then result:='0'+result
else result:='1'+result;
end;
if result<>'' then While (Result[1]='0')and (length(Result)>1) do Result:=Copy(Result,2,length(Result))
else Result:='0';
end;
{***************************************************************************************}
{ Convert a Hug integer to a binary string }
{***************************************************************************************}
Function BintoHug (s:string):Hugint;
var i:integer;
begin
Hcopy(Zero,Result);
for i:=0 to length(s) do begin
shlhug(Result,1);
if s[i]='1' then orhug(Result,One,Result);
end;
end;
{***************************************************************************************}
{ Convert a Hug integer to an Octal string }
{***************************************************************************************}
Function HugtoOctal(a:Hugint):string;
var i,j:integer;
w:word;
begin
Result:='';
While not(IsNull(a)) do begin
w:=a.i32[0] and 7;
Result:=inttostr(w)+Result;
ShrHug(a,3);
end;
if Result<>'' then While (Result[1]='0')and (length(Result)>1) do Result:=Copy(Result,2,length(Result))
else result:='0';
end;
{***************************************************************************************}
{ Convert an octal string to a Hug integer }
{***************************************************************************************}
Function OctaltoHug(S:string):Hugint;
var i,len:integer;
tmp:Hugint;
begin
Hcopy(Zero,Result);
tmp.i16[-1]:=0;
len:=length(s);
for i:=len downto 1 do begin
tmp.i16[-2]:=1;
if s[i] in ['0'..'7'] then tmp.i32[0]:=Ord(s[i])-ord('0')
else tmp.i32[0]:=0;
ShlHug(tmp,(len-i)*3);
AddHug(Result,tmp,Result);
end;
end;
{***************************************************************************************}
{ Convert decimal string to a Hug integer }
{***************************************************************************************}
Function StrToHug(s:string):Hugint;
var str:string;
i:integer;
signe:Dword;
million,tmp,t,z,h:Hugint;
begin
signe:=0;
if s[1]='-' then begin
s:=copy(S,2,length(s));
signe:=$ffff0000;
end;
Million.i32[-1]:=1;
t.i32[-1]:=1;
tmp.i32[-1]:=1;
t.i32[0]:=1;
Million.i32[0]:=1000000;
if length(s)<=7 then begin
Result.i32[0]:=strtoint(s);
if Result.i32[0]<>0 then Result.i32[-1]:=1
else Result.i32[-1]:=0;
end
else begin
str:=s;
Result.i32[-1]:=1;
Result.i32[0]:=0;
repeat
tmp.i32[0]:=strtoint(copy(str,length(str)-5,length(str)));
str:=copy(str,1,length(str)-6);
MulHug(tmp,t,z);
Addhug(Result,z,Result);
mulhug(t,million,h);
Hcopy(h,t);
until(str='');
end;
Result.i32[-1]:=Result.i32[-1] or signe;
end;
{***************************************************************************************}
{ Compute the GCD of two Hug integers using classical Euclid Algo }
{***************************************************************************************}
Function EuclidGCDHug(a,b:HugInt):HugInt;
var Qtmp:Hugint;
Swap:array[0..1]of HugInt;
i,j,k :Byte;
id:integer;
begin
Result.i32[-1]:=0;
if (IsNull(a))or (IsNull(b)) then exit
else begin
Hcopy(a,Swap[0]);
Hcopy(b,Swap[1]);
i:=0;
j:=1;
Repeat
DivideModhug(Swap[i],Swap[j],Qtmp,Swap[i]);
if not IsNull(Swap[i]) then begin
k:=i;
i:=j;
j:=k;
end;
until IsNull(Swap[i]);
for id:=-1 to Swap[j].i16[-2] do Result.i32[id]:=Swap[j].i32[id];
end;
end;
{***************************************************************************************}
{ Compute the GCD of two Hug integers using Binary Algo }
{***************************************************************************************}
Function BinaryGCDHug(a,b:HugInt):HugInt;
var u,v,g,t,z:Hugint;
n1,n2:Longint;
begin
Result.i32[-1]:=0;
if (IsNull(a))or (IsNull(b)) then exit
else begin
Hcopy(a,u);
Hcopy(b,v);
Hcopy(One,g);
While(u.i32[0] and 1=0)and(v.i32[0] and 1=0) do begin
ShrHug(u,1);
ShrHug(v,1);
ShlHug(g,1);
end;
While not(isNull(v)) do begin
if (u.i32[0] and 1=0) then ShrHug(u,1)
else if (v.i32[0] and 1=0) then ShrHug(v,1)
else begin
SubHug(u,v,t);
t.i16[-1]:=0;
ShrHug(t,1);
if CompareHug(u,v)<=0 then Hcopy(t,v) else Hcopy(t,u);
end;
end;
MulHug(u,g,Result);
end;
end;
{***************************************************************************************}
{ Resolve a multi-modulo linear congruences system using the "Chinees Remainder Theorem"}
{ The Result is given by the value:Result[0] and the modulo:Result[1] }
{***************************************************************************************}
Procedure ResolveMultiLinearCongSystems(Resid,Modu:HugintArray;WithoutVerif:Boolean;Var Result:HugintArray);
var i,j:integer;
prim:boolean;
m,tmp,tmp1:Hugint;
begin
if (Length(Resid)<>Length(Modu))or(Length(Resid)=0)or(length(Modu)=0) then
Raise ERangeError.Create( 'Invalid linear congruences system parametres ');
if Not WithoutVerif then begin
i:=0;
j:=0;
prim:=true;
while (i<=length(Modu)-1)and prim do begin
while (j<=Length(Modu)-1) and prim do begin
if i<>j then
Prim:=Prim and AreHugsRelativlyPrimes(Modu[i],Modu[j]);
j:=j+1;
end;
i:=i+1;
end;
if not prim then Raise ERangeError.Create( 'Modulus are not pirwise relativly primes');
end;
Setlength(Result,2);
Result[1].i32[-1]:=1;
Result[1].i32[0]:=1;
For i:=0 to Length(Modu)-1 do begin
MulHug(Result[1],Modu[i],tmp);
Hcopy(tmp,Result[1]);
end;
Result[0].i32[0]:=0;
for i:=0 to length(Modu)-1 do begin
DivideModHug(Result[1],Modu[i],m,tmp);
InvModHug(m,Modu[i],tmp);
MulHug(tmp,m,tmp1);
MulHug(tmp1,Resid[i],tmp);
AddHug(Result[0],tmp,Result[0]);
end;
ModuloHug(Result[0],Result[1],Result[0]);
end;
{***************************************************************************************}
{ Resolve a quadratic Congruence of the Form ax²+bx+c # 0[Mod p1*p2*...*pn] }
{ The Result is given by the modulo:n and the solution values: Result[] }
{***************************************************************************************}
Procedure ResolveQuadraticCongruenceEquation(a,b,c:Hugint;ModuloFactors:HugintArray;var n:Hugint;Var Result:HugintArray);
var i,j:Integer;
Prime:Boolean;
IndivSolutions,TmpArray,TmpRes:HugintArray;
aa,bb,inva,inv2,tmp:Hugint;
NbSol:Word;
begin
if Length(ModuloFactors)=0 then Raise ERangeError.Create( 'Invalid Quadratic congruence parametres');
i:=0;
j:=0;
Prime:=True;
{p1,p2,....,pn must be distincts primes }
While (i<=Length(ModuloFactors)-1) and (Prime) do begin
While (j<=Length(ModuloFactors)-1) and Prime do begin
if i<>j then Prime:=Prime and AreHugsRelativlyPrimes(ModuloFactors[i],ModuloFactors[j]);
j:=j+1;
end;
i:=i+1;
end;
if not Prime then Raise ERangeError.Create( 'Factors are not pirewise relativly primes...');
n.i32[-1]:=1;
n.i32[0]:=1;
For i:=0 to length(moduloFactors)-1 do begin
MulHug(n,ModuloFactors[i],tmp);
Hcopy(tmp,n);
end;
InvModHug(a,n,Inva);
InvModHug(Two,n,Inv2);
MulHug(inv2,b,tmp);
MulHug(tmp,tmp,aa);
MulHug(aa,inva,tmp);
SubHug(tmp,c,tmp);
MulHug(inva,tmp,aa);
ModuloHug(aa,n,aa);
MulHug(inv2,inva,tmp);
MulHug(tmp,b,bb);
ModuloHug(bb,n,bb);
SetLength(IndivSolutions,0);
For i:=0 to Length(ModuloFactors)-1 do begin
SetLength(IndivSolutions,Length(IndivSolutions)+1);
ModSquareHug(aa,ModuloFactors[i],IndivSolutions[High(IndivSolutions)]);
end;
NbSol:=Round(Exp(Length(IndivSolutions)*Ln(2)));
Setlength(Tmparray,Length(IndivSolutions));
Setlength(Result,NbSol);
Setlength(TmpRes,2);
For i:=0 to NbSol-1 do begin
For j:=0 to Length(TmpArray)-1 do begin
Hcopy(IndivSolutions[j],TmpArray[j]);
if (i and (1 shl j))<>0 then
SubHug(ModuloFactors[j],TmpArray[j],TmpArray[j]);
end;
ResolveMultiLinearCongSystems(TmpArray,ModuloFactors,True,TmpRes);
Hcopy(TmpRes[0],Result[i]);
SubHug(Result[i],bb,Result[i]);
while IsNeg(Result[i]) do AddHug(Result[i],n,Result[i]);
end;
end;
{***************************************************************************************}
{ Factorize a Hug integer to the product of it's prime factores }
{ using the probabilistic Monte-Carlo Algorithm }
{***************************************************************************************}
Procedure MonteCarloFactorizeHug(a:Hugint;var factors:HugintArray;Memo:Tmemo=nil);
var mi,m2i,tmp,g,Q:Hugint;
i:Dword;
begin
if IsHugPrime(a) then begin
Setlength(Factors,Length(Factors)+1);
Hcopy(a,Factors[Length(Factors)-1]);
end
else begin
GetRandomHugOnBits(mi,NumOfBits(a));
Hcopy(mi,m2i);
i:=0;
Repeat
MulHug(mi,mi,tmp);
IncHug(tmp,1);
ModuloHug(tmp,a,mi);
MulHug(m2i,m2i,tmp);
IncHug(tmp,1);
ModuloHug(tmp,a,m2i);
MulHug(m2i,m2i,tmp);
IncHug(tmp,1);
ModuloHug(tmp,a,m2i);
SubHug(m2i,mi,tmp);
tmp.i16[-1]:=0;
i:=i+1;
if (IsNull(tmp)) then begin
GetRandomHugLowerThan(mi,a);
Hcopy(mi,m2i);
Hcopy(one,g);
end
else g:=BinaryGCDHug(a,tmp);
if (i>100000000) and(CompareHug(g,one)=0) then begin
GetRandomHugLowerThan(mi,a);
Hcopy(mi,m2i);
i:=0;
end;
until(CompareHug(g,One)<>0)and(CompareHug(g,a)<>0);
DivideModHug(a,g,Q,tmp);
if not IsHugPrime(g) then MonteCarloFactorizeHug(g,factors)
else begin
Setlength(Factors,Length(Factors)+1);
Hcopy(g,Factors[Length(Factors)-1]);
if Memo<>nil then begin
Memo.Lines.Add(Hugtostr(g)+' is a prime factor');
Memo.Lines.Add('Now factorizing :'+hugtostr(Q));
end;
end;
if not IsHugPrime(Q) then MonteCarloFactorizeHug(Q,factors)
else begin
Setlength(Factors,Length(Factors)+1);
Hcopy(g,Factors[Length(Factors)-1]);
if Memo<>nil then Memo.Lines.Add(Hugtostr(Q)+' is a prime factor');
end;
end;
end;
{***************************************************************************************}
{ Factorize a Hug integer to the product of it's prime factores }
{ using the Pollard P-1 Algorithm }
{***************************************************************************************}
Procedure PollardFactorizeHug(a:hugint;var Factors:HugintArray;Memo:Tmemo=nil);
var r,tmp,i,g:Hugint;
begin
if IsHugPrime(a) then begin
Setlength(Factors,Length(Factors)+1);
Hcopy(a,Factors[Length(Factors)-1]);
if Memo<>nil then Memo.Lines.Add(Hugtostr(a)+' is a prime factor');
end
else begin
repeat
GetRandomHugOnBits(r,NumOfBits(a));
until (CompareHug(BinaryGCDHug(a,r),One)=0);
Hcopy(One,i);
repeat
ModPowerHug(r,i,a,tmp);
IncHug(i,1);
Hcopy(tmp,r);
DecHug(tmp,1);
if IsNull(tmp) then begin
repeat
GetRandomHugOnBits(r,NumOfBits(a));
until (CompareHug(BinaryGCDHug(a,r),One)=0);
Hcopy(One,i);
HCopy(One,g);
end
else g:=BinaryGCDHug(tmp,a);
until(CompareHug(g,One)<>0);
DivideModHug(a,g,r,tmp);
if not IsHugPrime(g) then PollardFactorizeHug(g,Factors)
else begin
Setlength(Factors,Length(Factors)+1);
Hcopy(g,Factors[Length(Factors)-1]);
if Memo<>nil then begin
Memo.Lines.Add(Hugtostr(g)+' is a prime factor');
Memo.Lines.Add('Now factorizing :'+hugtostr(r));
end;
end;
if not IsHugPrime(r) then PollardFactorizeHug(r,Factors)
else begin
Setlength(Factors,Length(Factors)+1);
Hcopy(g,Factors[Length(Factors)-1]);
if Memo<>nil then Memo.Lines.Add(Hugtostr(r)+' is a prime factor');
end;
end;
end;
Begin
Zero:=Strtohug('0');
One:=Strtohug('1');
Two:=Strtohug('2');
Three:=Strtohug('3');
Four:=Strtohug('4');
ProdFirstPrimes.i32[-1]:=1059;
For ind:=0 to 1058 do ProdFirstPrimes.i32[ind]:=_ProdFirstPrimes[ind];
end.
Conclusion :
L'application en jointe est une démonstration utilisant cette bibliothèque. J'ai attacher un fichier Zip Avec le source qui contien deux démonstrations, s'il n'est pas téléchargable alors mail me at kamel_mh@yahoo.fr.
Merci.
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.