@@ -23,18 +23,22 @@ interface
2323uses
2424 ClpISecureRandom,
2525 ClpBigInteger,
26- ClpBigIntegerUtilities,
2726 ClpWNafUtilities,
2827 ClpBitOperations,
2928 ClpCryptoLibTypes;
3029
30+ resourcestring
31+ SSizeTooSmall = ' size < 64' ;
32+
3133type
3234 TDHParametersHelper = class sealed(TObject)
3335
3436 strict private
3537 class var
3638
37- FSix: TBigInteger;
39+ FTwo: TBigInteger;
40+ FTwelve: TBigInteger;
41+ FTwentyFour: TBigInteger;
3842 FPrimeProducts: TCryptoLibInt32Array;
3943 FPrimeLists: TCryptoLibMatrixInt32Array;
4044 FBigPrimeProducts: TCryptoLibGenericArray<TBigInteger>;
@@ -43,34 +47,24 @@ TDHParametersHelper = class sealed(TObject)
4347 class function ConstructBigPrimeProducts (const APrimeProducts
4448 : TCryptoLibInt32Array): TCryptoLibGenericArray<TBigInteger>; static;
4549
50+ class function HasAnySmallFactorsSafe (const X: TBigInteger): Boolean; static;
51+
4652 class procedure Boot (); static;
4753
4854 class constructor DHParametersHelper();
4955
5056 public
5157
5258 // / <summary>
53- // / <para>
54- // / Finds a pair of prime BigInteger's {p, q: p = 2q + 1}
55- // / </para>
56- // / <para>
57- // / (see: Handbook of Applied Cryptography 4.86)
58- // / </para>
59- // / </summary>
60- class function GenerateSafePrimes (ASize, ACertainty: Int32;
61- const ARandom: ISecureRandom): TCryptoLibGenericArray<TBigInteger>; static;
62-
63- // / <summary>
64- // / <para>
65- // / Select a high order element of the multiplicative group Zp*
66- // / </para>
67- // / <para>
68- // / p and q must be s.t. p = 2*q + 1, where p and q are prime (see
69- // / generateSafePrimes)
70- // / </para>
59+ // / Finds a pair of prime BigInteger's {p, q: p = 2q + 1}.
7160 // / </summary>
72- class function SelectGenerator (const AP, AQ: TBigInteger;
73- const ARandom: ISecureRandom): TBigInteger; static;
61+ // / <remarks>
62+ // / See: Handbook of Applied Cryptography 4.86. If AForGenerator2 is true, the
63+ // / returned p will also have 2 as a quadratic residue (p === 7 mod 8).
64+ // / </remarks>
65+ class function GenerateSafePrimes (ABitLength, ACertainty: Int32;
66+ const ARandom: ISecureRandom; AForGenerator2: Boolean)
67+ : TCryptoLibGenericArray<TBigInteger>; static;
7468 end ;
7569
7670implementation
@@ -81,7 +75,9 @@ class procedure TDHParametersHelper.Boot;
8175begin
8276 if not FIsBooted then
8377 begin
84- FSix := TBigInteger.ValueOf(6 );
78+ FTwo := TBigInteger.Two;
79+ FTwelve := TBigInteger.ValueOf(12 );
80+ FTwentyFour := TBigInteger.ValueOf(24 );
8581
8682 FPrimeLists := TBigInteger.primeLists;
8783 FPrimeProducts := TBigInteger.primeProducts;
@@ -112,105 +108,103 @@ class function TDHParametersHelper.ConstructBigPrimeProducts(const APrimeProduct
112108 Result := LBpp;
113109end ;
114110
115- class function TDHParametersHelper.GenerateSafePrimes (ASize, ACertainty: Int32;
116- const ARandom: ISecureRandom): TCryptoLibGenericArray<TBigInteger>;
111+ class function TDHParametersHelper.HasAnySmallFactorsSafe (const X: TBigInteger): Boolean;
117112var
118- LP, LQ: TBigInteger;
119- LQLength, LMinWeight, LI, LTest, LRem3, LDiff, LJ, LPrime, LQRem: Int32;
120- LRetryFlag: Boolean;
113+ LI, LJ, LR, LPrime: Int32;
121114 LPrimeList: TCryptoLibInt32Array;
122115begin
123- LRetryFlag := False;
124- LQLength := ASize - 1 ;
125- LMinWeight := TBitOperations.Asr32(ASize, 2 );
126-
127- if ASize <= 32 then
116+ for LI := 0 to System.Pred(System.Length(FPrimeLists)) do
128117 begin
129- while True do
118+ LR := X.Remainder(FBigPrimeProducts[LI]).Int32ValueExact;
119+
120+ LPrimeList := FPrimeLists[LI];
121+ for LJ := 0 to System.Pred(System.Length(LPrimeList)) do
130122 begin
131- LQ := TBigInteger.Create(LQLength, 2 , ARandom);
123+ LPrime := LPrimeList[LJ];
124+ if (LR mod LPrime) < 2 then
125+ Exit(True);
126+ end ;
127+ end ;
132128
133- LP := LQ.ShiftLeft(1 ).Add(TBigInteger.One);
129+ Result := False;
130+ end ;
134131
135- if not LP.IsProbablePrime(ACertainty, True) then
136- Continue;
132+ class function TDHParametersHelper.GenerateSafePrimes (ABitLength, ACertainty: Int32;
133+ const ARandom: ISecureRandom; AForGenerator2: Boolean)
134+ : TCryptoLibGenericArray<TBigInteger>;
135+ var
136+ LP, LQ, LStep: TBigInteger;
137+ LLowBitsSet, LInc3, LMinWeight, LByteLength, LExtraBits, LCount, LPMod3: Int32;
138+ LBytes: TCryptoLibByteArray;
139+ begin
140+ if ABitLength < 64 then
141+ raise EArgumentCryptoLibException.CreateRes(@SSizeTooSmall);
137142
138- if (ACertainty > 2 ) and (not LQ.IsProbablePrime(ACertainty, True)) then
139- Continue;
143+ LLowBitsSet := $03 ;
144+ LInc3 := 4 ;
145+ LStep := FTwelve;
140146
141- Break;
142- end ;
143- end
144- else
147+ if AForGenerator2 then
145148 begin
146- while True do
147- begin
148- LQ := TBigInteger.Create(LQLength, 0 , ARandom);
149+ LLowBitsSet := $07 ;
150+ LInc3 := -8 ;
151+ LStep := FTwentyFour;
152+ end ;
149153
150- LI := 0 ;
151- while LI < System.Length(FPrimeLists) do
152- begin
153- LTest := LQ.Remainder(FBigPrimeProducts[LI]).Int32Value;
154+ LMinWeight := TBitOperations.Asr32(ABitLength, 2 );
155+ LByteLength := (ABitLength + 7 ) div 8 ;
156+ LExtraBits := LByteLength * 8 - ABitLength;
154157
155- if LI = 0 then
156- begin
157- LRem3 := LTest mod 3 ;
158- if LRem3 <> 2 then
159- begin
160- LDiff := (2 * LRem3) + 2 ;
161- LQ := LQ.Add(TBigInteger.ValueOf(LDiff));
162- LTest := (LTest + LDiff) mod FPrimeProducts[LI];
163- end ;
164- end ;
158+ System.SetLength(LBytes, LByteLength);
165159
166- LPrimeList := FPrimeLists[LI];
167- for LJ := 0 to System.Pred(System.Length(LPrimeList)) do
168- begin
169- LPrime := LPrimeList[LJ];
170- LQRem := LTest mod LPrime;
171- if (LQRem = 0 ) or (LQRem = TBitOperations.Asr32(LPrime, 1 )) then
172- begin
173- LQ := LQ.Add(FSix);
174- LRetryFlag := True;
175- Break;
176- end ;
177- end ;
178-
179- if LRetryFlag then
180- begin
181- LI := 0 ;
182- LRetryFlag := False;
183- end
184- else
185- System.Inc(LI);
186- end ;
160+ while True do
161+ begin
162+ ARandom.NextBytes(LBytes);
187163
188- if LQ.BitLength <> LQLength then
189- Continue ;
164+ LBytes[ 0 ] := (LBytes[ 0 ] and Byte($FF shr LExtraBits)) or Byte($ 80 shr LExtraBits);
165+ LBytes[System.Pred(LByteLength)] := LBytes[System.Pred(LByteLength)] or Byte(LLowBitsSet) ;
190166
191- if not LQ.RabinMillerTest(2 , ARandom, True) then
192- Continue;
167+ LP := TBigInteger.Create(1 , LBytes);
193168
194- LP := LQ.ShiftLeft(1 ).Add(TBigInteger.One);
169+ LPMod3 := LP.&Mod (TBigInteger.Three).Int32ValueExact;
170+ if LPMod3 <> 2 then
171+ LP := LP.Add(TBigInteger.ValueOf((2 - LPMod3) * LInc3));
195172
196- if not LP.RabinMillerTest(ACertainty, ARandom, True) then
197- Continue;
173+ LCount := 0 ;
174+ while LCount < 256 do
175+ begin
176+ System.Inc(LCount);
177+ if LP.BitLength <> ABitLength then
178+ Break;
198179
199- if (ACertainty > 2 ) and (not LQ.RabinMillerTest(ACertainty - 2 , ARandom, True)) then
200- Continue;
180+ if not HasAnySmallFactorsSafe(LP) then
181+ begin
182+ // NOTE: Pocklington criterion: Fermat test suffices to prove p prime given q is prime
183+ if FTwo.ModPow(LP, LP).Equals(FTwo) then
184+ begin
185+ LQ := LP.ShiftRight(1 );
186+ if LQ.RabinMillerTest(ACertainty, ARandom, True) then
187+ begin
188+ if TWNafUtilities.GetNafWeight(LP) >= LMinWeight then
189+ begin
190+ Result := TCryptoLibGenericArray<TBigInteger>.Create(LP, LQ);
191+ Exit;
192+ end ;
193+ end ;
194+ end ;
201195
202- if TWNafUtilities.GetNafWeight(LP) < LMinWeight then
203- Continue ;
196+ Break;
197+ end ;
204198
205- Break ;
199+ LP := LP.Add(LStep) ;
206200 end ;
207201 end ;
208-
209- Result := TCryptoLibGenericArray<TBigInteger>.Create(LP, LQ);
210202end ;
211203
212- { $IFNDEF _FIXINSIGHT_}
213-
204+ {
205+ // Select a high order element of the multiplicative group Zp*
206+ // (see generateSafePrimes). Superseded by fixed generator g = 2 when
207+ // GenerateSafePrimes is called with AForGenerator2 = true.
214208class function TDHParametersHelper.SelectGenerator(const AP, AQ: TBigInteger;
215209 const ARandom: ISecureRandom): TBigInteger;
216210var
@@ -225,6 +219,6 @@ class function TDHParametersHelper.SelectGenerator(const AP, AQ: TBigInteger;
225219
226220 Result := LG;
227221end;
228- { $ENDIF }
222+ }
229223
230224end .
0 commit comments