CryptoPrimes.Mod 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. MODULE CryptoPrimes;
  2. (* 2002.9.11 g.f. based on 'bn_prime.c'
  3. Copyright of the original: <-- middle click here
  4. *)
  5. IMPORT B := CryptoBigNumbers, Out := KernelLog;
  6. CONST
  7. N = 2048;
  8. TYPE
  9. BigNumber = B.BigNumber;
  10. VAR
  11. one: BigNumber;
  12. primes: ARRAY N OF LONGINT;
  13. PROCEDURE NewPrime*( bits: INTEGER; safe: BOOLEAN ): BigNumber;
  14. VAR checks, i: INTEGER; t, p: BigNumber;
  15. BEGIN
  16. checks := Checks( bits ); i := 1;
  17. LOOP
  18. p := ProbablePrime( bits );
  19. Out.Char( '.' );
  20. IF IsPrime( p, checks, FALSE ) THEN
  21. Out.Char( 'P' );
  22. IF ~safe THEN Out.Ln; RETURN p
  23. ELSE
  24. Out.Int( i, 0 ); INC( i );
  25. (* for "safe prime" generation, check that (p-1)/2 is prime. *)
  26. B.Copy( p, t ); t.Shift( -1 );
  27. IF IsPrime( t, checks, FALSE ) THEN
  28. Out.String( " (safe prime)" ); Out.Ln;
  29. RETURN p
  30. END;
  31. Out.String( " (not safe)" ); Out.Ln;
  32. END
  33. END;
  34. END
  35. END NewPrime;
  36. PROCEDURE NewDHPrime*( bits: INTEGER; safe: BOOLEAN; add, rem: BigNumber ): BigNumber;
  37. VAR checks: INTEGER; t, p: BigNumber;
  38. BEGIN
  39. checks := Checks( bits );
  40. LOOP
  41. IF safe THEN p := ProbableDHPrimeSafe( bits, add, rem )
  42. ELSE p := ProbableDHPrime( bits, add, rem )
  43. END;
  44. IF IsPrime( p, checks, FALSE ) THEN
  45. IF ~safe THEN RETURN p
  46. ELSE (* for "safe prime" generation, check that (p-1)/2 is prime. *)
  47. B.Copy( p, t ); t.Shift( -1 );
  48. IF IsPrime( t, checks, FALSE ) THEN RETURN p END
  49. END
  50. END
  51. END
  52. END NewDHPrime;
  53. PROCEDURE Checks( b: LONGINT ): INTEGER;
  54. (* number of Miller-Rabin iterations for an error rate of less than 2^-80
  55. for random 'b'-bit input, b >= 100 (taken from table 4.4 in the Handbook
  56. of Applied Cryptography [Menezes, van Oorschot, Vanstone; CRC Press 1996]
  57. *)
  58. VAR t: INTEGER;
  59. BEGIN
  60. ASSERT( b >= 100 );
  61. IF b >= 1300 THEN t := 2
  62. ELSIF b >= 850 THEN t := 3
  63. ELSIF b >= 650 THEN t := 4
  64. ELSIF b >= 550 THEN t := 5
  65. ELSIF b >= 450 THEN t := 6
  66. ELSIF b >= 400 THEN t := 7
  67. ELSIF b >= 350 THEN t := 8
  68. ELSIF b >= 300 THEN t := 9
  69. ELSIF b >= 250 THEN t := 12
  70. ELSIF b >= 200 THEN t := 15
  71. ELSIF b >= 150 THEN t := 18
  72. ELSE t := 27
  73. END;
  74. RETURN t
  75. END Checks;
  76. PROCEDURE ProbablePrime( bits: INTEGER ): BigNumber;
  77. VAR t: BigNumber; delta, i: LONGINT; p: BigNumber;
  78. mods: ARRAY N OF LONGINT;
  79. BEGIN
  80. LOOP
  81. p := B.NewRand( bits, 1, 1 );
  82. FOR i := 0 TO N - 1 DO mods[i] := B.ModWord( p, primes[i] ) END;
  83. (* check that p is not a prime and also that gcd( p-1, primes) = 1 (except for 2) *)
  84. i := 0; delta := 0;
  85. LOOP
  86. INC( i );
  87. IF i >= N THEN
  88. B.AssignInt( t, delta ); p := B.Add( p, t );
  89. RETURN p
  90. END;
  91. IF (mods[i] + delta) MOD primes[i] <= 1 THEN
  92. INC( delta, 2 ); i := 0;
  93. IF delta < 0 THEN (* overfow! try new random *) EXIT END;
  94. END;
  95. END
  96. END
  97. END ProbablePrime;
  98. PROCEDURE ProbableDHPrime( bits: INTEGER; add, rem: BigNumber ): BigNumber;
  99. VAR d, r, p: BigNumber; i: LONGINT;
  100. BEGIN
  101. p := B.NewRand( bits, 0, 1 );
  102. (* we need (p - rem) mod add = 0 *)
  103. r := B.Mod( p, add ); p := B.Sub( p, r );
  104. IF rem.IsZero( ) THEN p.Inc ELSE p := B.Add( p, rem ) END;
  105. (* we now have a random number 'p' to test. *)
  106. i := 0;
  107. LOOP
  108. INC( i );
  109. IF i >= N THEN RETURN p END;
  110. B.AssignInt( d, primes[i] ); r := B.Mod( p, d );
  111. IF r.IsZero( ) THEN p := B.Add( p, add ); i := 0 END;
  112. END
  113. END ProbableDHPrime;
  114. PROCEDURE ProbableDHPrimeSafe( bits: INTEGER; padd, rem: BigNumber ): BigNumber;
  115. VAR d, q, r, qr, qadd, p: BigNumber; i: LONGINT;
  116. BEGIN
  117. B.Copy( padd, qadd ); qadd.Shift( -1 );
  118. q := B.NewRand( bits, 0, 1 );
  119. r := B.Mod( q, qadd ); q := B.Sub( q, r );
  120. IF rem.IsZero( ) THEN q.Inc
  121. ELSE B.Copy( rem, r ); r.Shift( -1 ); q := B.Add( q, r )
  122. END;
  123. (* we now have a random number to test. *)
  124. B.Copy( q, p ); p.Shift( 1 ); p.Inc;
  125. i := 0;
  126. LOOP
  127. INC( i );
  128. IF i >= N THEN RETURN p END;
  129. B.AssignInt( d, primes[i] ); r := B.Mod( p, d ); qr := B.Mod( q, d );
  130. IF r.IsZero( ) OR qr.IsZero( ) THEN
  131. p := B.Add( p, padd ); q := B.Add( q, qadd ); i := 0
  132. END;
  133. END
  134. END ProbableDHPrimeSafe;
  135. PROCEDURE IsPrime*( a: BigNumber; checks: INTEGER; doTrialDiv: BOOLEAN ): BOOLEAN;
  136. VAR i, k: INTEGER; A, A1, A1odd, check: BigNumber;
  137. BEGIN
  138. IF checks = 0 THEN checks := Checks( a.BitSize( ) ) END;
  139. IF ~ODD( a.d[0] ) THEN RETURN FALSE END;
  140. IF doTrialDiv THEN
  141. FOR i := 1 TO N - 1 DO
  142. IF B.ModWord( a, primes[i] ) = 0 THEN RETURN FALSE END
  143. END
  144. END;
  145. B.Copy( a, A );
  146. IF A.neg THEN A.Negate END;
  147. B.Copy( A, A1 ); A1.Dec;
  148. IF A1.IsZero( ) THEN RETURN FALSE END;
  149. (* write A1 as A1odd * 2^k *)
  150. k := 1; WHILE ~A1.BitSet( k ) DO INC( k ) END;
  151. B.Copy( A1, A1odd ); A1odd.Shift( -k );
  152. FOR i := 1 TO checks DO
  153. check := B.NewRand( A1.BitSize( ), 0, 0 );
  154. IF check.GEQ( A1 ) THEN check := B.Sub( check, A1 ) END;
  155. check.Inc;
  156. (* now 1 <= check < A *)
  157. IF ~witness( check, A, A1, A1odd, k ) THEN RETURN FALSE END;
  158. END;
  159. RETURN TRUE
  160. END IsPrime;
  161. PROCEDURE witness( W, a, a1, a1odd: BigNumber; k: INTEGER): BOOLEAN;
  162. VAR w: BigNumber;
  163. BEGIN
  164. w := B.ModExp( W, a1odd, a );
  165. IF w.EQ( one ) THEN (* probably prime *) RETURN TRUE END;
  166. IF w.EQ( a1 ) THEN RETURN TRUE END;
  167. (* w = -1 (mod a), a is probably prime *)
  168. WHILE k > 0 DO
  169. w := B.ModMul( w, w, a ); (* w = w^2 mod a *)
  170. IF w.EQ( one ) THEN RETURN FALSE END;
  171. (* a is composite, otherwise a previous w would have been = -1 (mod a) *)
  172. IF w.EQ( a1 ) THEN RETURN TRUE END;
  173. (* w = -1 (mod a), a is probably prime *)
  174. DEC( k )
  175. END;
  176. (* If we get here, w is the (a-1)/2-th power of the original w, *)
  177. (* and it is neither -1 nor +1 -- so a cannot be prime *)
  178. RETURN FALSE
  179. END witness;
  180. PROCEDURE Init;
  181. VAR sieve: ARRAY N OF SET; i, j, p, n: LONGINT;
  182. BEGIN
  183. (* compute the first N small primes *)
  184. FOR i := 0 TO N - 1 DO sieve[i] := {0..31} END;
  185. primes[0] := 2; n := 1; i := 1;
  186. WHILE n < N DO
  187. IF i MOD 32 IN sieve[i DIV 32] THEN
  188. p := 2*i + 1; primes[n] := p; INC( n ); j := i;
  189. WHILE j DIV 32 < N DO EXCL( sieve[j DIV 32], j MOD 32 ); INC( j, p ) END;
  190. END;
  191. INC( i )
  192. END;
  193. END Init;
  194. BEGIN
  195. Init; B.AssignInt( one, 1 );
  196. END CryptoPrimes.