CryptoBigNumbers.Mod 26 KB

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