CryptoBigNumbers.Mod 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. MODULE CryptoBigNumbers; (* g.f. 2001.10.07 *)
  2. (* 2002.08.12 g.f. added neg. numbers, GCD and ModInverse *)
  3. (* 2002.09.24 g.f. inceased digit size from 8 bit to 32 bit *)
  4. (* 2002.10.04 g.f. faster version of ModExp (uses montgomery multiplications now) *)
  5. (* 2005.07.07 g.f. Fabian Nart's enhancements incorporated *)
  6. (* 2010.01.12 g.f. interface cleanup, most procedures got funtions *)
  7. IMPORT S := SYSTEM, Streams, Random, Kernel, Out := KernelLog;
  8. CONST
  9. BufferPoolSize = 16;
  10. TYPE
  11. BNdigit = UNSIGNED32;
  12. digits = POINTER TO ARRAY OF BNdigit;
  13. BigNumber* = OBJECT
  14. VAR
  15. len-: LONGINT; (** number of significant 'digits' *)
  16. neg-: BOOLEAN;
  17. d-: digits;
  18. PROCEDURE & Init( bitsize: LONGINT );
  19. VAR n: LONGINT;
  20. BEGIN
  21. IF bitsize # 0 THEN
  22. n := (bitsize + 31) DIV 32;
  23. INC( n, (-n) MOD 16 );
  24. NEW( d, n );
  25. END;
  26. len := 0; neg := FALSE
  27. END Init;
  28. PROCEDURE Mask*( bits: LONGINT );
  29. VAR w, b: LONGINT;
  30. BEGIN
  31. w := bits DIV 32; b := bits MOD 32; len := w;
  32. IF b # 0 THEN INC( len );
  33. d[w] := S.VAL( UNSIGNED32, S.VAL( SET32, d[w] ) * {0..b} )
  34. END
  35. END Mask;
  36. PROCEDURE IsZero*( ): BOOLEAN;
  37. BEGIN
  38. RETURN (len = 0) OR ((len = 1) & (d[0] = 0))
  39. END IsZero;
  40. PROCEDURE EQ* ( b: BigNumber ): BOOLEAN;
  41. BEGIN
  42. RETURN Cmp( SELF, b ) = 0
  43. END EQ;
  44. PROCEDURE NEQ* ( b: BigNumber ): BOOLEAN;
  45. BEGIN
  46. RETURN Cmp( SELF, b ) # 0
  47. END NEQ;
  48. PROCEDURE GT* ( b: BigNumber ): BOOLEAN;
  49. BEGIN
  50. RETURN Cmp( SELF, b ) > 0
  51. END GT;
  52. PROCEDURE GEQ* ( b: BigNumber ): BOOLEAN;
  53. BEGIN
  54. RETURN Cmp( SELF, b ) >= 0
  55. END GEQ;
  56. PROCEDURE Shift*( n: LONGINT );
  57. VAR right: BOOLEAN; w, bits, i, l: LONGINT; a, b: BNdigit;
  58. BEGIN
  59. IF len = 0 THEN RETURN END;
  60. IF n < 0 THEN right := TRUE; n := ABS( n ) ELSE right := FALSE END;
  61. w := n DIV 32; bits := n MOD 32;
  62. IF ~right THEN
  63. adjust( len + w + 1 );
  64. IF w > 0 THEN
  65. FOR i := len - 1 TO 0 BY -1 DO d[i + w] := d[i] END;
  66. FOR i := 0 TO w - 1 DO d[i] := 0 END;
  67. INC( len, w )
  68. END;
  69. IF bits > 0 THEN
  70. d[len] := 0;
  71. FOR i := len TO 0 BY -1 DO
  72. a := d[i];
  73. IF i > 0 THEN b := d[i - 1] ELSE b := 0 END;
  74. d[i] := LSH( a, bits ) + LSH( b, -32 + bits )
  75. END;
  76. IF d[len] # 0 THEN INC( len ) END;
  77. END
  78. ELSE
  79. IF w > 0 THEN
  80. FOR i := 0 TO len - w - 1 DO d[i] := d[i + w] END;
  81. DEC( len, w )
  82. END;
  83. IF bits > 0 THEN
  84. l := len;
  85. FOR i := 0 TO l - 1 DO a := d[i];
  86. IF i < l - 1 THEN b := d[i + 1] ELSE b := 0 END;
  87. d[i] := LSH( a, -bits ) + LSH( b, 32 - bits )
  88. END;
  89. IF d[l - 1] = 0 THEN DEC( len ) END;
  90. END
  91. END;
  92. END Shift;
  93. PROCEDURE Dec*;
  94. VAR i: LONGINT;
  95. BEGIN
  96. i := 0;
  97. IF IsZero( ) THEN len := 1; neg := TRUE; d[0] := 1
  98. ELSIF neg THEN
  99. WHILE (d[i] = -1) & (i < len) DO d[i] := 0; INC( i ) END;
  100. IF i = len THEN d[i] := 1; INC( len ) ELSE INC( d[i] ) END
  101. ELSE
  102. WHILE d[i] = 0 DO d[i] := -1; INC( i ) END;
  103. DEC( d[i] ); fixlen( d, len )
  104. END
  105. END Dec;
  106. PROCEDURE Inc*;
  107. VAR i: LONGINT;
  108. BEGIN
  109. i := 0;
  110. IF ~neg THEN
  111. WHILE (d[i] = -1) & (i < len) DO d[i] := 0; INC( i ) END;
  112. IF i = len THEN d[i] := 1; INC( len ) ELSE INC( d[i] ) END
  113. ELSE
  114. WHILE d[i] = 0 DO d[i] := -1; INC( i ) END;
  115. DEC( d[i] ); fixlen( d, len );
  116. IF len = 0 THEN neg := FALSE END
  117. END
  118. END Inc;
  119. PROCEDURE Negate*;
  120. BEGIN
  121. IF ~IsZero( ) THEN neg := ~neg END
  122. END Negate;
  123. PROCEDURE BitSize*( ): LONGINT;
  124. VAR n: LONGINT; t: BNdigit;
  125. BEGIN
  126. IF len = 0 THEN RETURN 0
  127. ELSE n := (len - 1) * 32
  128. END;
  129. t := d[len - 1];
  130. WHILE t # 0 DO INC( n ); t := LSH( t, -1 ) END;
  131. RETURN n
  132. END BitSize;
  133. PROCEDURE BitSet*( n: LONGINT ): BOOLEAN;
  134. VAR w, bit: LONGINT;
  135. BEGIN
  136. w := n DIV 32; bit := n MOD 32;
  137. IF w >= len THEN RETURN FALSE
  138. ELSE RETURN bit IN S.VAL( SET32, d[w] )
  139. END
  140. END BitSet;
  141. PROCEDURE adjust( newlen: LONGINT );
  142. VAR n, i: LONGINT; nd: digits;
  143. BEGIN
  144. n := 16;
  145. WHILE n < newlen DO INC( n, 16 ) END;
  146. IF LEN( d ) < n THEN
  147. NEW( nd, n );
  148. FOR i := 0 TO LEN( d^ ) - 1 DO nd[i] := d[i] END;
  149. d := nd
  150. END;
  151. END adjust;
  152. END BigNumber;
  153. dig2 = ARRAY 2 OF BNdigit;
  154. dig3 = ARRAY 3 OF BNdigit;
  155. Montgomery = OBJECT
  156. VAR
  157. bits: LONGINT; (* of R *)
  158. r, n, t1, t2: BigNumber;
  159. PROCEDURE & Init( x: BigNumber );
  160. BEGIN
  161. Copy( x, n ); bits := x.len*32;
  162. AssignInt( r, 1 ); r.Shift( bits ); (* r := R *)
  163. r := Sub( r, ModInverse( n, r ) ); (* r := R - (1/n) (mod R) *)
  164. n.adjust( 2*x.len ); r.adjust( 2*x.len );
  165. NEW( t1, 2*bits ); NEW( t2, 2*bits );
  166. END Init;
  167. PROCEDURE Convert( VAR val: BigNumber ); (* val := val ^ R mod n *)
  168. VAR i: LONGINT;
  169. BEGIN
  170. FOR i := 0 TO bits - 1 DO
  171. val.Shift( 1 );
  172. IF ucmp( val, n ) >= 0 THEN val := Sub( val, n ) END
  173. END
  174. END Convert;
  175. PROCEDURE Reduce( VAR val: BigNumber ); (* val := val ^ (1/R) mod n *)
  176. BEGIN
  177. Copy( val, t1 ); t1.Mask( bits - 1 ); (* val mod R *)
  178. mul( t1.d, r.d, t2.d, t1.len, r.len, t2.len ); t2.Mask( bits - 1 ); (* mod R *)
  179. mul( t2.d, n.d, t1.d, t2.len, n.len, t1.len );
  180. add( t1.d, val.d, val.d, t1.len, val.len, val.len ); val.Shift( -bits ); (* div R *)
  181. IF ucmp( val, n ) >= 0 THEN sub( val.d, n.d, val.d, val.len, n.len, val.len ) END;
  182. END Reduce;
  183. PROCEDURE Mult( a, b: BigNumber ): BigNumber;
  184. VAR c: BigNumber;
  185. BEGIN
  186. NEW( c, 0 );
  187. mul( a.d, b.d, c.d, a.len, b.len, c.len );
  188. Reduce( c );
  189. RETURN c
  190. END Mult;
  191. END Montgomery;
  192. VAR
  193. bufferPool: ARRAY BufferPoolSize OF digits;
  194. nextFreeBuffer: LONGINT;
  195. randomgenerator: Random.Generator;
  196. PROCEDURE RandomBytes*( VAR buf: ARRAY OF CHAR; p: LONGINT; n: LONGINT );
  197. VAR i: LONGINT;
  198. BEGIN
  199. FOR i := 0 TO n - 1 DO buf[p + i] := CHR( ENTIER( randomgenerator.Uniform()*256 ) ) END
  200. END RandomBytes;
  201. PROCEDURE adjust( VAR d: digits; dl, len: LONGINT );
  202. VAR n, i: LONGINT; nd: digits;
  203. BEGIN
  204. ASSERT( d # NIL );
  205. n := 16;
  206. WHILE n < len DO INC( n, 16) END;
  207. IF LEN( d ) < n THEN
  208. NEW( nd, n );
  209. FOR i := 0 TO dl - 1 DO nd[i] := d[i] END;
  210. d := nd
  211. END;
  212. END adjust;
  213. (** random number with len 'bits' *)
  214. PROCEDURE NewRand*( bits: LONGINT; top, bottom: SHORTINT ): BigNumber;
  215. VAR n, len, i, topbit: LONGINT; topword: SET32; b: BigNumber;
  216. BEGIN
  217. len := bits; INC( len, (-len) MOD 32 );
  218. NEW( b, len );
  219. n := len DIV 32;
  220. FOR i := 0 TO n -1 DO
  221. b.d[i] := randomgenerator.Integer()
  222. END;
  223. b.len := (bits + 31) DIV 32;
  224. topbit := (bits - 1) MOD 32;
  225. topword := SET32( S.VAL( SET32, b.d[b.len - 1] ) * {0..topbit} );
  226. IF top > 0 THEN INCL( topword, topbit ) END;
  227. b.d[b.len - 1] := S.VAL( LONGINT, topword );
  228. IF (bottom > 0) & ~ODD( b.d[0] ) THEN INC( b.d[0] ) END;
  229. RETURN b
  230. END NewRand;
  231. PROCEDURE NewRandRange*( range: BigNumber ): BigNumber; (** 0 < b < range DIV 2 - 1*)
  232. VAR b: BigNumber;
  233. BEGIN
  234. b := NewRand( range.BitSize( ) - 1, 0, 0 );
  235. b.Dec;
  236. RETURN b
  237. END NewRandRange;
  238. PROCEDURE fixlen( VAR d: digits; VAR len: LONGINT );
  239. BEGIN
  240. WHILE (len > 0) & (d[len - 1] = 0) DO DEC( len ) END;
  241. END fixlen;
  242. PROCEDURE h2i( c: CHAR ): LONGINT;
  243. VAR v: LONGINT;
  244. BEGIN
  245. CASE c OF
  246. | '0'..'9': v := ORD( c ) - ORD( '0' )
  247. | 'a'..'f': v := ORD( c ) - ORD( 'a' ) + 10
  248. | 'A'..'F': v := ORD( c ) - ORD( 'A' ) + 10
  249. ELSE HALT( 99 )
  250. END;
  251. RETURN v
  252. END h2i;
  253. PROCEDURE AssignHex*( VAR b: BigNumber; CONST hex: ARRAY OF CHAR; len: LONGINT );
  254. VAR n, w, pos: LONGINT;
  255. BEGIN
  256. ASSERT( len <= LEN( hex ) - 1);
  257. NEW( b, 4*len ); b.len := (4*len + 31) DIV 32;
  258. n := b.len - 1; w := 0; pos := 0;
  259. WHILE len > 0 DO
  260. w := w*16 + h2i( hex[pos] ); INC( pos ); DEC( len );
  261. IF len MOD 8 = 0 THEN b.d[n] := w; w := 0; DEC( n ) END;
  262. END;
  263. fixlen( b.d, b.len )
  264. END AssignHex;
  265. PROCEDURE AssignBin*( VAR b: BigNumber; CONST buf: ARRAY OF CHAR; pos, len: LONGINT );
  266. VAR n, w: LONGINT;
  267. BEGIN
  268. ASSERT( (pos + len) <= LEN( buf ) );
  269. NEW( b, 8*len ); b.len := SHORT( (8*len + 31) DIV 32 );
  270. n := b.len - 1; w := 0;
  271. WHILE len > 0 DO
  272. w := w*256 + ORD( buf[pos] ); INC( pos ); DEC( len );
  273. IF len MOD 4 = 0 THEN b.d[n] := w; w := 0; DEC( n ) END;
  274. END;
  275. fixlen( b.d, b.len )
  276. END AssignBin;
  277. (** Returns the value of b as a binary string 'data' starting at ofs.
  278. The Length of 'data' must be longer or equal to 4*b.len + ofs. *)
  279. PROCEDURE GetBinaryValue*( VAR b: BigNumber; VAR data: ARRAY OF CHAR; ofs: LONGINT );
  280. VAR j, n: LONGINT; tmp: BNdigit;
  281. BEGIN
  282. ASSERT( LEN( data ) >= 4 * b.len + ofs );
  283. FOR n := b.len-1 TO 0 BY -1 DO
  284. tmp := b.d[n];
  285. FOR j := 3 TO 0 BY - 1 DO
  286. data[ ofs + j ] := CHR( tmp MOD 256 );
  287. tmp := tmp DIV 256
  288. END;
  289. INC( ofs, 4 )
  290. END
  291. END GetBinaryValue;
  292. PROCEDURE AssignInt*( VAR b: BigNumber; val: LONGINT );
  293. BEGIN
  294. NEW( b, 64 );
  295. IF val < 0 THEN b.neg := TRUE; val := ABS( val ) END;
  296. IF val # 0 THEN b.len := 1; b.d[0] := val ELSE b.len := 0 END
  297. END AssignInt;
  298. PROCEDURE cmpd( VAR a, b: digits; len: LONGINT ): SHORTINT;
  299. VAR i: LONGINT;
  300. BEGIN
  301. i := len - 1;
  302. WHILE (i >= 0) & (a[i] = b[i]) DO DEC( i ) END;
  303. IF i < 0 THEN RETURN 0
  304. ELSE
  305. IF b[i] < a[i] THEN RETURN 1 ELSE RETURN -1 END
  306. END
  307. END cmpd;
  308. PROCEDURE ucmp( VAR a, b: BigNumber ): SHORTINT; (* 1: |a| > |b|; 0: a = b; -1: |a| < |b| *)
  309. BEGIN
  310. IF a.len > b.len THEN RETURN 1
  311. ELSIF a.len < b.len THEN RETURN -1
  312. ELSE RETURN cmpd( a.d, b.d, a.len )
  313. END
  314. END ucmp;
  315. PROCEDURE Cmp*( a, b: BigNumber ): SHORTINT; (** 1: a > b; 0: a = b; -1: a < b *)
  316. BEGIN
  317. IF a.neg # b.neg THEN
  318. IF a.neg THEN RETURN -1 ELSE RETURN 1 END
  319. ELSIF a.neg THEN RETURN ucmp( a, b ) * (-1)
  320. ELSE RETURN ucmp( a, b )
  321. END
  322. END Cmp;
  323. PROCEDURE copy( a, b: digits; len: LONGINT );
  324. VAR i: LONGINT;
  325. BEGIN
  326. FOR i := 0 TO len - 1 DO b[i] := a[i] END
  327. END copy;
  328. PROCEDURE Copy*( VAR a, b: BigNumber ); (** b := a *)
  329. BEGIN
  330. ASSERT( (a # NIL) & (ADDRESSOF( a ) # ADDRESSOF( b )) );
  331. IF (b = NIL) OR (LEN( b.d^ ) < a.len) THEN NEW( b, a.len*32 ) END;
  332. copy( a.d, b.d, a.len ); b.len := a.len
  333. END Copy;
  334. PROCEDURE Invert( x: BNdigit ): BNdigit;
  335. BEGIN
  336. RETURN S.VAL( BNdigit, -S.VAL( SET32, x ) )
  337. END Invert;
  338. PROCEDURE add( a, b: digits; VAR c: digits; al, bl: LONGINT; VAR cl: LONGINT );
  339. VAR i, n: LONGINT; A, B, x: BNdigit; carry: BOOLEAN;
  340. BEGIN
  341. n := MAX( al, bl ); carry := FALSE;
  342. IF LEN( c^ ) < (n + 1) THEN adjust( c, cl, n + 1 ) END;
  343. FOR i := 0 TO n - 1 DO
  344. IF i >= al THEN A := 0 ELSE A := a[i] END;
  345. IF i >= bl THEN B := 0 ELSE B := b[i] END;
  346. x := A + B;
  347. IF carry THEN INC( x ); carry := Invert(A) <= B ELSE carry := x < B END;
  348. c[i]:= x
  349. END;
  350. IF carry THEN c[n] := 1; INC( n ) END;
  351. cl := n
  352. END add;
  353. PROCEDURE sub( a, b: digits; VAR c: digits; al, bl: LONGINT; VAR cl: LONGINT );
  354. VAR i, n: LONGINT; A, B, x: BNdigit; borrow: BOOLEAN;
  355. BEGIN
  356. n := MAX( al, bl ); borrow := FALSE;
  357. IF LEN( c^ ) < n THEN adjust( c, cl, n ) END;
  358. FOR i := 0 TO n - 1 DO
  359. IF i >= al THEN A := 0 ELSE A := a[i] END;
  360. IF i >= bl THEN B := 0 ELSE B := b[i] END;
  361. x := A - B;
  362. IF borrow THEN DEC( x ); borrow := A <= B ELSE borrow := A < B END;
  363. c[i]:= x
  364. END;
  365. ASSERT( ~borrow );
  366. WHILE (n > 0) & (c[n - 1] = 0) DO DEC( n ) END;
  367. cl := n
  368. END sub;
  369. PROCEDURE Add*( a, b: BigNumber ): BigNumber; (** a + b *)
  370. VAR sd: digits; l, sl: LONGINT; c: BigNumber;
  371. BEGIN
  372. ASSERT( (a # NIL) & (b # NIL) );
  373. l := MAX( a.len, b.len ) + 1;
  374. NEW( c, l*32 ); sd := c.d;
  375. IF a.neg = b.neg THEN add( a.d, b.d, sd, a.len, b.len, sl ); c.neg := a.neg
  376. ELSE
  377. IF ucmp( a, b ) >= 0 THEN sub( a.d, b.d, sd, a.len, b.len, sl ); c.neg := a.neg
  378. ELSE sub( b.d, a.d, sd, b.len, a.len, sl ); c.neg := ~a.neg
  379. END
  380. END;
  381. IF sd # c.d THEN adjust( c.d, 0, sl ); copy( sd, c.d, sl ) END;
  382. c.len := sl;
  383. IF c.IsZero( ) THEN c.neg := FALSE END;
  384. RETURN c
  385. END Add;
  386. PROCEDURE Sub*( a, b: BigNumber ): BigNumber; (** a - b *)
  387. VAR sd: digits; l, sl: LONGINT; c: BigNumber;
  388. BEGIN
  389. ASSERT( (a # NIL) & (b # NIL) );
  390. l := MAX( a.len, b.len ) + 1;
  391. NEW( c, l*32 ); sd := c.d;
  392. IF a.neg # b.neg THEN add( a.d, b.d, sd, a.len, b.len, sl ); c.neg := a.neg
  393. ELSE
  394. IF ucmp( a, b ) >= 0 THEN sub( a.d, b.d, sd, a.len, b.len, sl ); c.neg := a.neg
  395. ELSE sub( b.d, a.d, sd, b.len, a.len, sl ); c.neg := ~a.neg
  396. END
  397. END;
  398. IF sd # c.d THEN adjust( c.d, 0, sl ); copy( sd, c.d, sl ) END;
  399. c.len := sl;
  400. IF c.IsZero( ) THEN c.neg := FALSE END;
  401. RETURN c
  402. END Sub;
  403. PROCEDURE mul( a, b: digits; VAR c: digits; al, bl: LONGINT; VAR cl: LONGINT ); (* c = a*b *)
  404. VAR
  405. prod, sum, tmp, mulc: BNdigit; addc: BOOLEAN; i, j: LONGINT; pl: LONGINT;
  406. p: digits; tmp64: UNSIGNED64;
  407. BEGIN
  408. pl := 0; NEW( p, al + bl + 2 );
  409. FOR i := 0 TO al + bl + 1 DO p[i] := 0 END; (* clear acc *)
  410. FOR i := 0 TO bl - 1 DO
  411. mulc := 0; addc := FALSE; pl := i;
  412. FOR j := 0 TO al - 1 DO
  413. tmp := p[pl];
  414. tmp64 := UNSIGNED64( a[j] )*b[i] + mulc;
  415. prod := BNdigit( tmp64 MOD 100000000H );
  416. mulc := BNdigit( tmp64 DIV 100000000H );
  417. sum := prod + tmp;
  418. IF addc THEN INC( sum ); addc := Invert(prod) <= tmp
  419. ELSE addc := sum < tmp
  420. END;
  421. p[pl] := sum; INC( pl );
  422. END;
  423. IF addc OR (mulc # 0) THEN
  424. IF addc THEN INC( mulc ) END;
  425. p[pl] := mulc; INC( pl )
  426. END;
  427. END;
  428. c := p; cl := pl; fixlen( c, cl );
  429. END mul;
  430. PROCEDURE muls( a: digits; b: BNdigit; c: digits; al: LONGINT; VAR cl: LONGINT ); (* c = a*b *)
  431. VAR carry: BNdigit; tmp64: UNSIGNED64; i: LONGINT;
  432. BEGIN
  433. carry := 0; cl := al;
  434. FOR i := 0 TO al - 1 DO
  435. tmp64 := UNSIGNED64( a[i] )*b + carry;
  436. c[i] := BNdigit( tmp64 MOD 100000000H );
  437. carry := BNdigit( tmp64 DIV 100000000H );
  438. END;
  439. IF carry # 0 THEN c[cl] := carry; INC( cl ) END
  440. END muls;
  441. PROCEDURE Mul*( a, b: BigNumber ): BigNumber; (** a * b *)
  442. VAR pd: digits; pl: LONGINT; c: BigNumber;
  443. BEGIN
  444. ASSERT( (a # NIL) & (b # NIL) );
  445. IF (a.len = 0) OR (b.len = 0) THEN AssignInt( c, 0 ); RETURN c END;
  446. NEW( c, 32 );
  447. IF a.len >= b.len THEN
  448. mul( a.d, b.d, pd, a.len, b.len, pl )
  449. ELSE
  450. mul( b.d, a.d, pd, b.len, a.len, pl )
  451. END;
  452. c.d := pd; c.len := pl; c.neg := a.neg # b.neg;
  453. RETURN c
  454. END Mul;
  455. PROCEDURE div64( CONST a: dig2; VAR b: BNdigit ): LONGINT; (* a div b *)
  456. VAR bit, q: LONGINT; r: BNdigit; overflow: BOOLEAN;
  457. BEGIN
  458. IF a[1] = 0 THEN
  459. IF (a[0] < 80000000H) & (b < 80000000H ) THEN RETURN LONGINT( a[0] DIV b )
  460. ELSIF a[0] < b THEN RETURN 0
  461. ELSIF a[0] = b THEN RETURN 1
  462. END;
  463. bit := 31
  464. ELSIF a[1] = b THEN RETURN -1
  465. ELSE bit := 63
  466. END;
  467. q := 0; r := 0;
  468. WHILE (bit >= 0) & ~(bit MOD 32 IN S.VAL( SET32, a[bit DIV 32]) ) DO DEC( bit ) END;
  469. WHILE bit >= 0 DO
  470. overflow := 31 IN S.VAL( SET32, r ); r := ASH( r, 1 );
  471. IF bit MOD 32 IN S.VAL( SET32, a[bit DIV 32] ) THEN INC( r ) END;
  472. IF overflow OR (b <= r) THEN r := r - b;
  473. IF bit < 32 THEN INCL( S.VAL( SET32, q ), bit ) ELSE q := -1 END;
  474. END;
  475. DEC( bit )
  476. END;
  477. RETURN q
  478. END div64;
  479. PROCEDURE div96( CONST a: dig3; CONST b: dig2 ): LONGINT; (* a div b *)
  480. VAR bit: LONGINT; r: dig2; q: LONGINT; overflow, borrow: BOOLEAN;
  481. PROCEDURE ge( CONST a, b: dig2 ): BOOLEAN;
  482. BEGIN
  483. IF a[1] = b[1] THEN RETURN a[0] >= b[0]
  484. ELSE RETURN a[1] >= b[1]
  485. END
  486. END ge;
  487. PROCEDURE shift( VAR x: dig2 );
  488. BEGIN
  489. overflow := 31 IN S.VAL( SET32, x[1] ); x[1] := ASH( x[1], 1 );
  490. IF 31 IN S.VAL( SET32, x[0] ) THEN INC( x[1] ) END;
  491. x[0] := ASH( x[0], 1 );
  492. END shift;
  493. BEGIN
  494. IF a[2] = 0 THEN
  495. IF a[1] < b[1] THEN RETURN 0 END;
  496. bit := 63
  497. ELSE bit := 95
  498. END;
  499. q := 0; r[0] := 0; r[1] := 0;
  500. WHILE (bit >= 0) & ~(bit MOD 32 IN S.VAL( SET32, a[bit DIV 32]) ) DO DEC( bit ) END;
  501. WHILE bit >= 0 DO
  502. shift( r ); (* r := r*2 *)
  503. IF bit MOD 32 IN S.VAL( SET32, a[bit DIV 32] ) THEN INC( r[0] ) END;
  504. IF overflow OR ge( r, b ) THEN
  505. borrow := r[0] <= b[0]; r[0] := r[0] - b[0]; r[1] := r[1] - b[1];
  506. IF borrow THEN DEC( r[1] ) END;
  507. IF bit < 32 THEN INCL( S.VAL( SET32, q ), bit ) ELSE q := -1 END;
  508. END;
  509. DEC( bit )
  510. END;
  511. RETURN q
  512. END div96;
  513. PROCEDURE Div2*( a, b: BigNumber; VAR q, r: BigNumber ); (** q = a div b; r = a mod b *)
  514. VAR td, sd, bd, qd: digits; x, i, tail, bl, tl, sl, ql, qi: LONGINT;
  515. t3: dig3; t2, d0: dig2;
  516. aq, ar: ADDRESS;
  517. BEGIN
  518. aq := ADDRESSOF( q ); ar := ADDRESSOF( r );
  519. ASSERT( (a # NIL) & (b # NIL) & ~b.IsZero( ) & ~b.neg & (aq # ar) );
  520. NEW( q, a.len*32 ); qd := q.d;
  521. x := ucmp( a, b );
  522. IF x < 0 THEN AssignInt( q, 0 ); Copy( a, r )
  523. ELSIF x = 0 THEN AssignInt( q, 1 ); AssignInt( r, 0 )
  524. ELSE
  525. td := GetBuffer();
  526. sd := GetBuffer();
  527. bd := b.d; bl := b.len; d0[1] := bd[bl - 1];
  528. IF bl > 1 THEN d0[0] := bd[bl - 2] ELSE d0[0] := 0 END;
  529. FOR i := 1 TO bl DO td[bl - i] := a.d[a.len - i] END;
  530. tl := bl; tail := a.len - bl; ql := tail + 1; qi := ql;
  531. LOOP
  532. IF tl < bl THEN x := 0;
  533. ELSE i := tl - 1;
  534. IF d0[0] = 0 THEN
  535. IF tl > bl THEN t2[1] := td[i]; DEC( i ) ELSE t2[1] := 0 END;
  536. t2[0] := td[i];
  537. x := div64( t2, d0[1] );
  538. ELSE
  539. IF tl > bl THEN t3[2] := td[i]; DEC( i ) ELSE t3[2] := 0 END;
  540. t3[1] := td[i];
  541. IF i > 0 THEN t3[0] := td[i - 1] ELSE t3[0] := 0 END;
  542. x := div96( t3, d0 );
  543. END
  544. END;
  545. IF x # 0 THEN muls( bd, x, sd, bl, sl );
  546. WHILE (sl > tl) OR ((sl = tl) & (cmpd( sd, td, sl ) > 0)) DO
  547. sub( sd, bd, sd, sl, bl, sl ); DEC( x );
  548. END;
  549. sub( td, sd, td, tl, sl, tl );
  550. END;
  551. IF (qi = ql) & (x = 0) THEN DEC( ql ); DEC( qi ) ELSE DEC( qi ); qd[qi] := x END;
  552. IF tail = 0 THEN EXIT END;
  553. DEC( tail );
  554. FOR i := tl TO 1 BY -1 DO td[i] := td[i - 1] END;
  555. td[0] := a.d[tail]; INC( tl );
  556. END;
  557. q.len := ql;
  558. NEW( r, tl*32 ); copy( td, r.d, tl ); r.len := tl;
  559. RecycleBuffer( td );
  560. RecycleBuffer( sd )
  561. END;
  562. IF q.len = 0 THEN q.neg := FALSE ELSE q.neg := a.neg END;
  563. IF (r.len # 0) & a.neg THEN q.Dec; r := Sub( b, r ) END;
  564. END Div2;
  565. PROCEDURE ModWord*( VAR a: BigNumber; b: BNdigit ): BNdigit; (** a mod b *)
  566. VAR x: BNdigit; td, sd, bd: digits; tail, tl, sl, bl: LONGINT; t2: dig2;
  567. BEGIN
  568. ASSERT( a # NIL );
  569. td := GetBuffer();
  570. sd := GetBuffer();
  571. bd := GetBuffer();
  572. bd[0] := b; bl := 1; td[0] := a.d[a.len - 1]; tl := 1; tail := a.len - 1;
  573. LOOP
  574. IF tl > 1 THEN t2[1] := td[1] ELSE t2[1] := 0 END;
  575. t2[0] := td[0];
  576. x := div64( t2, b );
  577. IF x # 0 THEN muls( bd, x, sd, bl, sl );
  578. WHILE (sl > tl) OR ((sl = tl) & (cmpd( sd, td, sl ) > 0)) DO
  579. sub( sd, bd, sd, sl, bl, sl ); DEC( x );
  580. END;
  581. sub( td, sd, td, tl, sl, tl );
  582. END;
  583. IF tail <= 0 THEN EXIT END;
  584. DEC( tail );
  585. IF td[0] = 0 THEN tl := 1 ELSE td[1] := td[0]; tl := 2 END;
  586. td[0] := a.d[tail];
  587. END;
  588. x := td[0];
  589. RecycleBuffer( td );
  590. RecycleBuffer( sd );
  591. RecycleBuffer( bd );
  592. RETURN x
  593. END ModWord;
  594. PROCEDURE Div*( a, b: BigNumber ): BigNumber; (** a DIV b *)
  595. VAR dummy, q: BigNumber;
  596. BEGIN
  597. Div2( a, b, q, dummy );
  598. RETURN q
  599. END Div;
  600. PROCEDURE Mod*( a, b: BigNumber ): BigNumber; (** a MOD b *)
  601. VAR dummy, r: BigNumber;
  602. BEGIN
  603. Div2( a, b, dummy, r );
  604. RETURN r
  605. END Mod;
  606. PROCEDURE Exp*( a, b: BigNumber ): BigNumber; (** a ^ b *)
  607. VAR v: digits; i: LONGINT; vl: LONGINT; e: BigNumber;
  608. BEGIN
  609. NEW( e, 8192 );
  610. NEW( v, 256 );
  611. copy( a.d, v, a.len ); vl := a.len;
  612. IF ODD( b.d[0] ) THEN copy( a.d, e.d, a.len ); e.len := a.len ELSE e.len := 1; e.d[0] := 1 END;
  613. FOR i := 1 TO b.BitSize( ) - 1 DO
  614. mul( v, v, v, vl, vl, vl );
  615. IF b.BitSet( i ) THEN mul( v, e.d, e.d, vl, e.len, e.len ) END;
  616. END;
  617. fixlen( e.d, e.len );
  618. RETURN e
  619. END Exp;
  620. PROCEDURE ModMul*( a, b, m: BigNumber ): BigNumber; (** (a*b) mod m *)
  621. VAR p, r: BigNumber;
  622. BEGIN
  623. p := Mul( a, b ); r := Mod( p, m );
  624. RETURN r
  625. END ModMul;
  626. PROCEDURE wbits( exp: BigNumber ): LONGINT;
  627. VAR b, w: LONGINT;
  628. BEGIN
  629. (* window bits for exponent size, for sliding window ModExp functions *)
  630. b := exp.BitSize( );
  631. IF b <= 23 THEN w := 1
  632. ELSIF b <= 79 THEN w := 3
  633. ELSIF b <= 239 THEN w := 4
  634. ELSIF b <= 671 THEN w := 5
  635. ELSE w := 6
  636. END;
  637. RETURN w
  638. END wbits;
  639. PROCEDURE ModExp*( a, b, m: BigNumber ): BigNumber; (** a ^ b mod m *)
  640. VAR
  641. a0: ARRAY 32 OF BigNumber; res, d: BigNumber;
  642. wsize, v, wstart, e, i, j: LONGINT;
  643. mg: Montgomery;
  644. BEGIN
  645. ASSERT( (a # NIL) & (b # NIL) & (m # NIL) );
  646. IF b.IsZero( ) THEN
  647. IF a.IsZero( ) THEN HALT( 100 ) END;
  648. AssignInt( res, 1 ); RETURN res
  649. END;
  650. IF m.IsZero( ) THEN HALT( 101 ) END;
  651. IF m.neg THEN HALT( 102 ) END;
  652. NEW( mg, m );
  653. a0[0] := Mod( a, m ); mg.Convert( a0[0] );
  654. wsize := wbits( b );
  655. IF wsize > 1 THEN (* precompute window multipliers *)
  656. d := mg.Mult( a0[0], a0[0] ); j := ASH( 1, wsize - 1 );
  657. FOR i := 1 TO j - 1 DO a0[i] := mg.Mult( a0[i - 1], d ) END;
  658. END;
  659. Copy( a0[0], res ); wstart := b.BitSize( ) - 2;
  660. WHILE wstart >= 0 DO res := mg.Mult( res, res );
  661. IF b.BitSet( wstart ) THEN
  662. v := 1; e := 0; i := 1;
  663. WHILE (i < wsize) & (wstart - i >= 0) DO
  664. IF b.BitSet( wstart - i ) THEN v := ASH( v, i - e ) + 1; e := i END;
  665. INC( i )
  666. END;
  667. FOR i := 1 TO e DO res := mg.Mult( res, res ) END;
  668. res := mg.Mult( res, a0[v DIV 2] ); (* v will be an odd number < 2^wsize *)
  669. DEC( wstart, e + 1 );
  670. ELSE DEC( wstart )
  671. END
  672. END;
  673. mg.Reduce( res );
  674. RETURN res
  675. END ModExp;
  676. PROCEDURE GCD*( a, b: BigNumber ): BigNumber; (** gcd( a, b ) *)
  677. VAR x, y, r: BigNumber;
  678. BEGIN
  679. ASSERT( ~a.neg & ~b.neg );
  680. Copy( a, x ); Copy( b, y );
  681. LOOP
  682. IF Cmp( x, y ) > 0 THEN x := Mod( x, y );
  683. IF x.IsZero( ) THEN Copy( y, r ); EXIT END
  684. ELSE y := Mod( y, x ) ;
  685. IF y.IsZero( ) THEN Copy( x, r ); EXIT END
  686. END;
  687. END;
  688. RETURN r
  689. END GCD;
  690. PROCEDURE ModInverse*( a, m: BigNumber ): BigNumber; (** Return x so that (x * a) mod m = 1 *)
  691. VAR
  692. q, t, x: BigNumber; g, v: ARRAY 3 OF BigNumber; p, i, s, tmp, n: LONGINT;
  693. BEGIN
  694. FOR i := 0 TO 2 DO AssignInt( g[i], 0 ); AssignInt( v[i], 0 ) END;
  695. Copy( a, g[0] ); Copy( m, g[1] ); AssignInt( v[0], 1 ); AssignInt( v[1], 0 );
  696. p := 0; i := 1; s := 2; n := 0;
  697. LOOP
  698. Div2( g[p], g[i], q, g[s] ); t := Mul( q, v[i] ); v[s] := Add( v[p], t ); INC( n );
  699. IF g[s].IsZero( ) THEN EXIT END;
  700. tmp := p; p := i; i := s; s := tmp;
  701. END;
  702. IF (g[i].len = 1) & (g[i].d[0] = 1) THEN
  703. IF ODD( n ) THEN v[i] := Sub( m, v[i] ) END;
  704. x := Mod( v[i], m )
  705. ELSE AssignInt( x, 0 )
  706. END;
  707. RETURN x
  708. END ModInverse;
  709. (*--------------------------- Text I/O ---------------------------------*)
  710. PROCEDURE TextWrite*( w: Streams.Writer; b: BigNumber );
  711. VAR i: LONGINT;
  712. BEGIN
  713. IF b.neg THEN w.String( "-" ) END;
  714. IF b.len = 0 THEN w.String( " 00000000" )
  715. ELSE i := b.len;
  716. WHILE i > 0 DO
  717. DEC( i ); w.Hex( b.d[i], -8 );
  718. IF i > 0 THEN
  719. IF i MOD 6 = 0 THEN w.Ln
  720. ELSE w.String( " " )
  721. END
  722. END
  723. END
  724. END;
  725. w.Char( '.' );
  726. END TextWrite;
  727. (** writes a hexadecimal representation of b to the standard output *)
  728. PROCEDURE Print*( b: BigNumber );
  729. VAR i: LONGINT;
  730. BEGIN
  731. IF b.neg THEN Out.String( "-" ) END;
  732. IF b.len = 0 THEN Out.String( "00000000" )
  733. ELSE i := b.len;
  734. WHILE i > 0 DO
  735. DEC( i ); Out.Hex( b.d[i], -8 );
  736. IF i > 0 THEN
  737. IF i MOD 6 = 0 THEN Out.Ln
  738. ELSE Out.String( " " )
  739. END
  740. END
  741. END
  742. END;
  743. Out.Char( '.' ); Out.Ln
  744. END Print;
  745. PROCEDURE nibble( r: Streams.Reader ): CHAR;
  746. VAR c: CHAR;
  747. BEGIN
  748. REPEAT
  749. REPEAT r.Char( c ) UNTIL (c > ' ') OR (r.Available() = 0);
  750. UNTIL (r.Available() = 0) OR
  751. (c >= '0') & (c <= '9') OR
  752. (c >= 'A') & (c <= 'F') OR
  753. (c >= 'a') & (c <= 'f') OR (c = '.');
  754. RETURN c
  755. END nibble;
  756. PROCEDURE TextRead*( r: Streams.Reader; VAR b: BigNumber );
  757. VAR buf: ARRAY 2048 OF CHAR; i: LONGINT; n: CHAR;
  758. BEGIN
  759. i := 0; n := nibble( r );
  760. WHILE n # '.' DO buf[i] := n; INC( i ); n := nibble( r ) END;
  761. AssignHex( b, buf, i );
  762. END TextRead;
  763. (*--------------------------- File I/O ---------------------------------*)
  764. PROCEDURE FileRead*( r: Streams.Reader; VAR b: BigNumber );
  765. VAR i, j, v: LONGINT;
  766. BEGIN
  767. r.RawLInt( j );
  768. NEW( b, 32 * j );
  769. b.len := j;
  770. FOR i := 0 TO j - 1 DO r.RawLInt( v ); b.d[ i ] := v END
  771. END FileRead;
  772. PROCEDURE FileWrite*( w: Streams.Writer; b: BigNumber );
  773. VAR i, j, v: LONGINT;
  774. BEGIN
  775. j := b.len;
  776. w.RawLInt( j );
  777. FOR i := 0 TO j - 1 DO w.RawLInt( v ); b.d[ i ] := v END
  778. END FileWrite;
  779. (* ------------ buffer pooling to make this module thread-save (F.N.) -----------------------*)
  780. PROCEDURE GetBuffer( ): digits;
  781. VAR d: digits;
  782. BEGIN {EXCLUSIVE}
  783. IF nextFreeBuffer > -1 THEN
  784. d := bufferPool[ nextFreeBuffer ];
  785. DEC( nextFreeBuffer )
  786. ELSE
  787. NEW( d, 256 )
  788. END;
  789. RETURN d
  790. END GetBuffer;
  791. PROCEDURE RecycleBuffer( d: digits );
  792. BEGIN {EXCLUSIVE}
  793. IF nextFreeBuffer < BufferPoolSize - 1 THEN
  794. INC( nextFreeBuffer );
  795. bufferPool[ nextFreeBuffer ] := d
  796. END
  797. END RecycleBuffer;
  798. PROCEDURE InitRandomgenerator;
  799. BEGIN
  800. NEW( randomgenerator );
  801. randomgenerator.InitSeed( Kernel.GetTicks() );
  802. END InitRandomgenerator;
  803. BEGIN
  804. ASSERT( S.VAL( LONGINT, {0}) = 1 ); (* little endian SETs! *)
  805. FOR nextFreeBuffer := 0 TO BufferPoolSize - 1 DO
  806. NEW( bufferPool[nextFreeBuffer], 256 )
  807. END;
  808. nextFreeBuffer := BufferPoolSize-1;
  809. InitRandomgenerator();
  810. END CryptoBigNumbers.