Initial commit.
[BoarSSL] / ZInt / ZInt.cs
1 /*
2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 using System;
26 using System.Security.Cryptography;
27 using System.Text;
28
29 /*
30 * A custom "big integer" implementation. It internally uses an array
31 * of 32-bit integers, that encode the integer in little-endian convention,
32 * using two's complement for negative integers.
33 *
34 * Apart from the array, a single 32-bit field is also present, which
35 * encodes the sign. When the value is small (it fits on 32 bits), then
36 * the array pointer is null, and the value is in the 32-bit field.
37 * Since ZInt is a struct, this means that computations using ZInt do
38 * not entail any dynamic (GC-based) memory allocation as long as the
39 * value fits on 32 bits. This makes it substantially faster than usual
40 * "big integer" implementations (including .NET's implementation, since
41 * version 4.0) when values are small.
42 *
43 * Instances are immutable, and thus can be used as if they were
44 * "plain integers".
45 *
46 * None of this code is "constant-time". As such, ZInt should be
47 * considered unsuitable to implementations of cryptographic algorithms.
48 */
49
50 public struct ZInt : IComparable, IComparable<ZInt>, IEquatable<ZInt> {
51
52 /*
53 * CONVENTIONS:
54 *
55 * If varray == null, then "small" contains the integer value.
56 *
57 * If varray != null, then it contains the value, in little-endian
58 * convention (least significant word comes first) and of
59 * minimal encoded length (i.e. "trimmed"). Two's complement is
60 * used for negative values. "small" is then -1 or 0, depending
61 * on whether the value is negative or not.
62 *
63 * Note that the trimmed value does not always include the sign
64 * bit.
65 *
66 * If the integer value is in the range of values which can be
67 * represented in an "int", then magn is null. There is no allowed
68 * overlap between the two kinds of encodings.
69 *
70 * Default value thus encodes the integer zero.
71 */
72
73 readonly int small;
74 readonly uint[] varray;
75
76 /*
77 * The value -1.
78 */
79 public static ZInt MinusOne {
80 get { return new ZInt(-1, null); }
81 }
82
83 /*
84 * The value 0.
85 */
86 public static ZInt Zero {
87 get { return new ZInt(0, null); }
88 }
89
90 /*
91 * The value 1.
92 */
93 public static ZInt One {
94 get { return new ZInt(1, null); }
95 }
96
97 /*
98 * The value 2.
99 */
100 public static ZInt Two {
101 get { return new ZInt(2, null); }
102 }
103
104 /*
105 * Internal constructor which assumes that the provided values are
106 * correct and normalized.
107 */
108 private ZInt(int small, uint[] varray)
109 {
110 this.small = small;
111 this.varray = varray;
112 #if DEBUG
113 if (varray != null) {
114 if (small != -1 && small != 0) {
115 throw new Exception(
116 "Bad sign encoding: " + small);
117 }
118 if (varray.Length == 0) {
119 throw new Exception("Empty varray");
120 }
121 if (Length(small, varray) != varray.Length) {
122 throw new Exception("Untrimmed varray");
123 }
124 if (varray.Length == 1) {
125 /*
126 * If there was room for a sign bit, then
127 * the "small" encoding should have been used.
128 */
129 if (((varray[0] ^ (uint)small) >> 31) == 0) {
130 throw new Exception(
131 "suboptimal encoding");
132 }
133 }
134 }
135 #endif
136 }
137
138 /*
139 * Main internal build method. This method normalizes the encoding
140 * ("small" encoding is used when possible; otherwise, the varray
141 * is trimmed and the sign is normalized to -1 or 0).
142 *
143 * If "varray" is null, then the small value is used. Otherwise,
144 * only the sign bit (most significant bit) of "small" is used,
145 * and that value is normalized; the array is trimmed. If the
146 * small encoding then becomes applicable, then it is used.
147 */
148 private static ZInt Make(int small, uint[] varray)
149 {
150 if (varray == null) {
151 return new ZInt(small, null);
152 }
153 small >>= 31;
154 int n = Length(small, varray);
155 if (n == 1 && (((varray[0] ^ (uint)small) >> 31) == 0)) {
156 small = (int)varray[0];
157 varray = null;
158 } else {
159 /*
160 * Note: if n == 0 then the value is -1 or 0, and
161 * "small" already contains the correct value;
162 * Trim() will then return null, which is appropriate.
163 */
164 varray = Trim(small, varray, n);
165 }
166 return new ZInt(small, varray);
167 }
168
169 /*
170 * Create an instance from a signed 32-bit integer.
171 */
172 public ZInt(int val)
173 {
174 small = val;
175 varray = null;
176 }
177
178 /*
179 * Create an instance from an unsigned 32-bit integer.
180 */
181 public ZInt(uint val)
182 {
183 small = (int)val;
184 if (small < 0) {
185 small = 0;
186 varray = new uint[1] { val };
187 } else {
188 varray = null;
189 }
190 }
191
192 /*
193 * Create an instance from a signed 64-bit integer.
194 */
195 public ZInt(long val)
196 {
197 small = (int)val;
198 if ((long)small == val) {
199 varray = null;
200 } else {
201 ulong uval = (ulong)val;
202 uint w0 = (uint)uval;
203 uint w1 = (uint)(uval >> 32);
204 if (w1 == 0) {
205 small = 0;
206 varray = new uint[1] { w0 };
207 } else if (w1 == 0xFFFFFFFF) {
208 small = -1;
209 varray = new uint[1] { w0 };
210 } else {
211 small = (int)w1 >> 31;
212 varray = new uint[2] { w0, w1 };
213 }
214 }
215 }
216
217 /*
218 * Create an instance from an unsigned 64-bit integer.
219 */
220 public ZInt(ulong val)
221 {
222 if (val <= 0x7FFFFFFF) {
223 small = (int)val;
224 varray = null;
225 } else {
226 small = 0;
227 uint w0 = (uint)val;
228 uint w1 = (uint)(val >> 32);
229 if (w1 == 0) {
230 varray = new uint[1] { w0 };
231 } else {
232 varray = new uint[2] { w0, w1 };
233 }
234 }
235 }
236
237 /*
238 * Create a ZInt instance for an integer expressed as an array
239 * of 32-bit integers (unsigned little-endian convention), with
240 * a specific number of value bits.
241 */
242 public static ZInt Make(uint[] words, int numBits)
243 {
244 if (numBits == 0) {
245 return Zero;
246 }
247 int n = (numBits + 31) >> 5;
248 int kb = numBits & 31;
249 uint[] m = new uint[n];
250 Array.Copy(words, 0, m, 0, n);
251 if (kb > 0) {
252 m[n - 1] &= ~((uint)0xFFFFFFFF << kb);
253 }
254 return Make(0, m);
255 }
256
257 /*
258 * Create a ZInt instance for an integer expressed as an array
259 * of 64-bit integers (unsigned little-endian convention), with
260 * a specific number of value bits.
261 */
262 public static ZInt Make(ulong[] words, int numBits)
263 {
264 if (numBits == 0) {
265 return Zero;
266 }
267 int kw = (numBits + 63) >> 6;
268 int kb = numBits & 63;
269 int n = kw * 2;
270 uint[] m = new uint[n];
271 if (kb != 0) {
272 ulong z = words[kw - 1]
273 & ~((ulong)0xFFFFFFFFFFFFFFFF << kb);
274 m[n - 1] = (uint)(z >> 32);
275 m[n - 2] = (uint)z;
276 kw --;
277 n -= 2;
278 }
279 for (int i = kw - 1, j = n - 2; i >= 0; i --, j -= 2) {
280 ulong z = words[i];
281 m[j + 0] = (uint)z;
282 m[j + 1] = (uint)(z >> 32);
283 }
284 return Make(0, m);
285 }
286
287 /*
288 * Test whether this value is 0.
289 */
290 public bool IsZero {
291 get {
292 return small == 0 && varray == null;
293 }
294 }
295
296 /*
297 * Test whether this value is 1.
298 */
299 public bool IsOne {
300 get {
301 return small == 1;
302 }
303 }
304
305 /*
306 * Test whether this value is even.
307 */
308 public bool IsEven {
309 get {
310 uint w = (varray == null) ? (uint)small : varray[0];
311 return (w & 1) == 0;
312 }
313 }
314
315 /*
316 * Test whether this value is a power of 2. Note that 1 is a power
317 * of 2 (but 0 is not). For negative values, false is returned.
318 */
319 public bool IsPowerOfTwo {
320 get {
321 if (small < 0) {
322 return false;
323 }
324 if (varray == null) {
325 return small != 0 && (small & -small) == small;
326 }
327 int n = varray.Length;
328 int z = (int)varray[n - 1];
329 if ((z & -z) != z) {
330 return false;
331 }
332 for (int i = n - 2; i >= 0; i --) {
333 if (varray[i] != 0) {
334 return false;
335 }
336 }
337 return true;
338 }
339 }
340
341 /*
342 * Get the sign of this value as an integer (-1 for negative
343 * values, 1 for positive, 0 for zero).
344 */
345 public int Sign {
346 get {
347 if (varray == null) {
348 if (small < 0) {
349 return -1;
350 } else if (small == 0) {
351 return 0;
352 } else {
353 return 1;
354 }
355 } else {
356 return small | 1;
357 }
358 }
359 }
360
361 /*
362 * Test whether this value would fit in an 'int'.
363 */
364 public bool IsInt {
365 get {
366 return varray == null;
367 }
368 }
369
370 /*
371 * Test whether this value would fit in a "long".
372 */
373 public bool IsLong {
374 get {
375 if (varray == null) {
376 return true;
377 }
378 int n = varray.Length;
379 if (n == 1) {
380 return true;
381 } else if (n == 2) {
382 return ((int)varray[1] >> 31) == small;
383 } else {
384 return false;
385 }
386 }
387 }
388
389 /*
390 * Get the length of the value in bits. This is the minimal number
391 * of bits of the two's complement representation of the value,
392 * excluding the sign bit; thus, both 0 and -1 have bit length 0.
393 */
394 public int BitLength {
395 get {
396 if (varray == null) {
397 if (small < 0) {
398 return 32 - LeadingZeros(~(uint)small);
399 } else {
400 return 32 - LeadingZeros((uint)small);
401 }
402 } else {
403 int n = varray.Length;
404 int bl = n << 5;
405 uint w = varray[n - 1];
406 if (small < 0) {
407 return bl - LeadingZeros(~w);
408 } else {
409 return bl - LeadingZeros(w);
410 }
411 }
412 }
413 }
414
415 /*
416 * Test whether the specified bit has value 1 or 0 ("true" is
417 * returned if the bit has value 1). Note that for negative values,
418 * two's complement representation is assumed.
419 */
420 public bool TestBit(int n)
421 {
422 if (n < 0) {
423 throw new ArgumentOutOfRangeException();
424 }
425 if (varray == null) {
426 if (n >= 32) {
427 return small < 0;
428 } else {
429 return (((uint)small >> n) & (uint)1) != 0;
430 }
431 } else {
432 int nw = n >> 5;
433 if (nw >= varray.Length) {
434 return small != 0;
435 }
436 int nb = n & 31;
437 return ((varray[nw] >> nb) & (uint)1) != 0;
438 }
439 }
440
441 /*
442 * Copy some bits from this instance to the provided array. Bits
443 * are copied in little-endian order. First bit to be copied is
444 * bit at index "off", and exactly "num" bits are copied. This
445 * method modifies only the minimum number of destination words
446 * (i.e. the first "(num+31)/32" words, exactly). Remaining bits
447 * in the last touched word are set to 0.
448 */
449 public void CopyBits(int off, int num, uint[] dest)
450 {
451 CopyBits(off, num, dest, 0);
452 }
453
454 public void CopyBits(int off, int num, uint[] dest, int destOff)
455 {
456 if (off < 0 || num < 0) {
457 throw new ArgumentOutOfRangeException();
458 }
459 if (num == 0) {
460 return;
461 }
462 ZInt x = this;
463 if (off > 0) {
464 x >>= off;
465 }
466 int kw = num >> 5;
467 int kb = num & 31;
468 uint hmask = ~((uint)0xFFFFFFFF << kb);
469 if (x.varray == null) {
470 if (kw == 0) {
471 dest[destOff] = (uint)x.small & hmask;
472 } else {
473 uint iw = (uint)(x.small >> 31);
474 dest[destOff] = (uint)x.small;
475 for (int i = 1; i < kw; i ++) {
476 dest[destOff + i] = iw;
477 }
478 if (kb > 0) {
479 dest[destOff + kw] = iw & hmask;
480 }
481 }
482 } else {
483 int n = x.varray.Length;
484 if (kw <= n) {
485 Array.Copy(x.varray, 0, dest, destOff, kw);
486 } else {
487 Array.Copy(x.varray, 0, dest, destOff, n);
488 for (int i = n; i < kw; i ++) {
489 dest[destOff + i] = (uint)x.small;
490 }
491 }
492 if (kb > 0) {
493 uint last;
494 if (kw < n) {
495 last = x.varray[kw] & hmask;
496 } else {
497 last = (uint)x.small & hmask;
498 }
499 dest[destOff + kw] = last;
500 }
501 }
502 }
503
504 /*
505 * Copy some bits from this instance to the provided array. Bits
506 * are copied in little-endian order. First bit to be copied is
507 * bit at index "off", and exactly "num" bits are copied. This
508 * method modifies only the minimum number of destination words
509 * (i.e. the first "(num+63)/64" words, exactly). Remaining bits
510 * in the last touched word are set to 0.
511 */
512 public void CopyBits(int off, int num, ulong[] dest)
513 {
514 CopyBits(off, num, dest, 0);
515 }
516
517 public void CopyBits(int off, int num, ulong[] dest, int destOff)
518 {
519 if (off < 0 || num < 0) {
520 throw new ArgumentOutOfRangeException();
521 }
522 if (num == 0) {
523 return;
524 }
525 ZInt x = this;
526 if (off > 0) {
527 x >>= off;
528 }
529 int kw = num >> 6;
530 int kb = num & 63;
531 ulong hmask = ~((ulong)0xFFFFFFFFFFFFFFFF << kb);
532 long xs = (long)x.small;
533 if (x.varray == null) {
534 if (kw == 0) {
535 dest[destOff] = (ulong)xs & hmask;
536 } else {
537 ulong iw = (ulong)(xs >> 31);
538 dest[destOff] = (ulong)xs;
539 for (int i = 1; i < kw; i ++) {
540 dest[destOff + i] = iw;
541 }
542 if (kb > 0) {
543 dest[destOff + kw] = iw & hmask;
544 }
545 }
546 } else {
547 int n = x.varray.Length;
548 uint iw = (uint)x.small;
549 int j = 0;
550 for (int i = 0; i < kw; i ++, j += 2) {
551 uint w0 = (j < n) ? x.varray[j] : iw;
552 uint w1 = ((j + 1) < n) ? x.varray[j + 1] : iw;
553 dest[destOff + i] =
554 (ulong)w0 | ((ulong)w1 << 32);
555 }
556 if (kb > 0) {
557 uint w0 = (j < n) ? x.varray[j] : iw;
558 uint w1 = ((j + 1) < n) ? x.varray[j + 1] : iw;
559 ulong last = (ulong)w0 | ((ulong)w1 << 32);
560 dest[destOff + kw] = last & hmask;
561 }
562 }
563 }
564
565 /*
566 * Extract a 32-bit word at a given offset (counted in bits).
567 * This function is equivalent to right-shifting the value by
568 * "off" bits, then returning the low 32 bits (however, this
569 * function may be more efficient).
570 */
571 public uint GetWord(int off)
572 {
573 if (off < 0) {
574 throw new ArgumentOutOfRangeException();
575 }
576 if (varray == null) {
577 int x = small;
578 if (off >= 32) {
579 off = 31;
580 }
581 return (uint)(x >> off);
582 }
583 int n = varray.Length;
584 int kw = off >> 5;
585 if (kw >= n) {
586 return (uint)small;
587 }
588 int kb = off & 31;
589 if (kb == 0) {
590 return varray[kw];
591 } else {
592 uint hi;
593 if (kw == n - 1) {
594 hi = (uint)small;
595 } else {
596 hi = varray[kw + 1];
597 }
598 uint lo = varray[kw];
599 return (lo >> kb) | (hi << (32 - kb));
600 }
601 }
602
603 /*
604 * Extract a 64-bit word at a given offset (counted in bits).
605 * This function is equivalent to right-shifting the value by
606 * "off" bits, then returning the low 64 bits (however, this
607 * function may be more efficient).
608 */
609 public ulong GetWord64(int off)
610 {
611 if (off < 0) {
612 throw new ArgumentOutOfRangeException();
613 }
614 if (varray == null) {
615 int x = small;
616 if (off >= 32) {
617 off = 31;
618 }
619 return (ulong)(x >> off);
620 }
621 int n = varray.Length;
622 int kw = off >> 5;
623 if (kw >= n) {
624 return (ulong)small;
625 }
626 int kb = off & 31;
627 if (kb == 0) {
628 if (kw == (n - 1)) {
629 return (ulong)varray[kw]
630 | ((ulong)small << 32);
631 } else {
632 return (ulong)varray[kw]
633 | ((ulong)varray[kw + 1] << 32);
634 }
635 } else {
636 uint v0, v1, v2;
637 if (kw == (n - 1)) {
638 v0 = varray[kw];
639 v1 = (uint)small;
640 v2 = (uint)small;
641 } else if (kw == (n - 2)) {
642 v0 = varray[kw];
643 v1 = varray[kw + 1];
644 v2 = (uint)small;
645 } else {
646 v0 = varray[kw];
647 v1 = varray[kw + 1];
648 v2 = varray[kw + 2];
649 }
650 uint lo = (v0 >> kb) | (v1 << (32 - kb));
651 uint hi = (v1 >> kb) | (v2 << (32 - kb));
652 return (ulong)lo | ((ulong)hi << 32);
653 }
654 }
655
656 /*
657 * Convert this value to an 'int', using silent truncation if
658 * the value does not fit.
659 */
660 public int ToInt {
661 get {
662 return (varray == null) ? small : (int)varray[0];
663 }
664 }
665
666 /*
667 * Convert this value to an 'uint', using silent truncation if
668 * the value does not fit.
669 */
670 public uint ToUInt {
671 get {
672 return (varray == null) ? (uint)small : varray[0];
673 }
674 }
675
676 /*
677 * Convert this value to a 'long', using silent truncation if
678 * the value does not fit.
679 */
680 public long ToLong {
681 get {
682 return (long)ToULong;
683 }
684 }
685
686 /*
687 * Convert this value to an 'ulong', using silent truncation if
688 * the value does not fit.
689 */
690 public ulong ToULong {
691 get {
692 if (varray == null) {
693 return (ulong)small;
694 } else if (varray.Length == 1) {
695 uint iw = (uint)small;
696 return (ulong)varray[0] | ((ulong)iw << 32);
697 } else {
698 return (ulong)varray[0]
699 | ((ulong)varray[1] << 32);
700 }
701 }
702 }
703
704 /*
705 * Get the actual length of a varray encoding: this is the minimal
706 * length, in words, needed to encode the value. The value sign
707 * is provided as a negative or non-negative integer, and the
708 * encoding of minimal length does not necessarily include a
709 * sign bit. The value 0 is returned when the array encodes 0
710 * or -1 (depending on sign).
711 */
712 static int Length(int sign, uint[] m)
713 {
714 if (m == null) {
715 return 0;
716 }
717 uint sw = (uint)(sign >> 31);
718 int n = m.Length;
719 while (n > 0 && m[n - 1] == sw) {
720 n --;
721 }
722 return n;
723 }
724
725 /*
726 * Trim an encoding to its minimal encoded length. If the provided
727 * array is already of minimal length, it is returned unchanged.
728 */
729 static uint[] Trim(int sign, uint[] m)
730 {
731 int n = Length(sign, m);
732 if (n == 0) {
733 return null;
734 } else if (n < m.Length) {
735 uint[] mt = new uint[n];
736 Array.Copy(m, 0, mt, 0, n);
737 return mt;
738 } else {
739 return m;
740 }
741 }
742
743 /*
744 * Trim or extend a value to the provided length. The returned
745 * array will have the length specified as "n" (if n == 0, then
746 * null is returned). If the source array already has the right
747 * size, then it is returned unchanged.
748 */
749 static uint[] Trim(int sign, uint[] m, int n)
750 {
751 if (n == 0) {
752 return null;
753 } else if (m == null) {
754 m = new uint[n];
755 if (sign < 0) {
756 Fill(0xFFFFFFFF, m);
757 }
758 return m;
759 }
760 int ct = m.Length;
761 if (ct < n) {
762 uint[] r = new uint[n];
763 Array.Copy(m, 0, r, 0, ct);
764 return r;
765 } else if (ct == n) {
766 return m;
767 } else {
768 uint[] r = new uint[n];
769 Array.Copy(m, 0, r, 0, n);
770 if (sign < 0) {
771 Fill(0xFFFFFFFF, r, ct, n - ct);
772 }
773 return r;
774 }
775 }
776
777 static void Fill(uint val, uint[] buf)
778 {
779 Fill(val, buf, 0, buf.Length);
780 }
781
782 static void Fill(uint val, uint[] buf, int off, int len)
783 {
784 while (len -- > 0) {
785 buf[off ++] = val;
786 }
787 }
788
789 // =================================================================
790 /*
791 * Utility methods.
792 *
793 * The methods whose name begins with "Mutate" modify the array
794 * they are given as first parameter; the other methods instantiate
795 * a new array.
796 *
797 * As a rule, untrimmed arrays are accepted as input, and output
798 * may be untrimmed as well.
799 */
800
801 /*
802 * Count the number of leading zeros for a 32-bit value (number of
803 * consecutive zeros, starting with the most significant bit). This
804 * value is between 0 (for a value equal to 2^31 or greater) and
805 * 32 (for zero).
806 */
807 static int LeadingZeros(uint v)
808 {
809 if (v == 0) {
810 return 32;
811 }
812 int n = 0;
813 if (v > 0xFFFF) { v >>= 16; } else { n += 16; }
814 if (v > 0x00FF) { v >>= 8; } else { n += 8; }
815 if (v > 0x000F) { v >>= 4; } else { n += 4; }
816 if (v > 0x0003) { v >>= 2; } else { n += 2; }
817 if (v <= 0x0001) { n ++; }
818 return n;
819 }
820
821 /*
822 * Duplicate the provided magnitude array. No attempt is made at
823 * trimming. The source array MUST NOT be null.
824 */
825 static uint[] Dup(uint[] m)
826 {
827 uint[] r = new uint[m.Length];
828 Array.Copy(m, 0, r, 0, m.Length);
829 return r;
830 }
831
832 /*
833 * Increment the provided array. If there is a resulting carry,
834 * then "true" is returned, "false" otherwise. The array MUST
835 * NOT be null.
836 */
837 static bool MutateIncr(uint[] x)
838 {
839 int n = x.Length;
840 for (int i = 0; i < n; i ++) {
841 uint w = x[i] + 1;
842 x[i] = w;
843 if (w != 0) {
844 return false;
845 }
846 }
847 return true;
848 }
849
850 /*
851 * Decrement the provided array. If there is a resulting carry,
852 * then "true" is returned, "false" otherwise. The array MUST
853 * NOT be null.
854 */
855 static bool MutateDecr(uint[] x)
856 {
857 int n = x.Length;
858 for (int i = 0; i < n; i ++) {
859 uint w = x[i];
860 x[i] = w - 1;
861 if (w != 0) {
862 return false;
863 }
864 }
865 return true;
866 }
867
868 /*
869 * Multiply a[] with b[] (unsigned multiplication).
870 */
871 static uint[] Mul(uint[] a, uint[] b)
872 {
873 // TODO: use Karatsuba when operands are large.
874 int na = Length(0, a);
875 int nb = Length(0, b);
876 if (na == 0 || nb == 0) {
877 return null;
878 }
879 uint[] r = new uint[na + nb];
880 for (int i = 0; i < na; i ++) {
881 ulong ma = a[i];
882 ulong carry = 0;
883 for (int j = 0; j < nb; j ++) {
884 ulong mb = (ulong)b[j];
885 ulong mr = (ulong)r[i + j];
886 ulong w = ma * mb + mr + carry;
887 r[i + j] = (uint)w;
888 carry = w >> 32;
889 }
890 r[i + nb] = (uint)carry;
891 }
892 return r;
893 }
894
895 /*
896 * Get the sign and magnitude of an integer. The sign is
897 * normalized to -1 (negative) or 0 (positive or zero). The
898 * magnitude is an array of length at least 1, containing the
899 * absolute value of this integer; if possible, the varray
900 * is reused (hence, the magnitude array MUST NOT be altered).
901 */
902 static void ToAbs(ZInt x, out int sign, out uint[] magn)
903 {
904 if (x.small < 0) {
905 sign = -1;
906 x = -x;
907 } else {
908 sign = 0;
909 }
910 magn = x.varray;
911 if (magn == null) {
912 magn = new uint[1] { (uint)x.small };
913 }
914 }
915
916 /*
917 * Compare two integers, yielding -1, 0 or 1.
918 */
919 static int Compare(int a, int b)
920 {
921 if (a < b) {
922 return -1;
923 } else if (a == b) {
924 return 0;
925 } else {
926 return 1;
927 }
928 }
929
930 /*
931 * Compare a[] with b[] (unsigned). Returned value is 1 if a[]
932 * is greater than b[], 0 if they are equal, -1 otherwise.
933 */
934 static int Compare(uint[] a, uint[] b)
935 {
936 int ka = Length(0, a);
937 int kb = Length(0, b);
938 if (ka < kb) {
939 return -1;
940 } else if (ka == kb) {
941 while (ka > 0) {
942 ka --;
943 uint wa = a[ka];
944 uint wb = b[ka];
945 if (wa < wb) {
946 return -1;
947 } else if (wa > wb) {
948 return 1;
949 }
950 }
951 return 0;
952 } else {
953 return 1;
954 }
955 }
956
957 /*
958 * Add b[] to a[] (unsigned). a[] is modified "in place". Only
959 * n words of a[] are modified. Moreover, the value of
960 * b[] which is added is left-shifted: words b[0]...b[n-1] are
961 * added to a[k]...a[k+n-1]. The final carry is returned ("true"
962 * for 1, "false" for 0). Neither a nor b may be null.
963 */
964 static bool MutateAdd(uint[] a, int n, uint[] b, int k)
965 {
966 bool carry = false;
967 for (int i = 0; i < n; i ++) {
968 uint wa = a[i + k];
969 uint wb = b[i];
970 uint wc = wa + wb;
971 if (carry) {
972 wc ++;
973 carry = wa >= wc;
974 } else {
975 carry = wa > wc;
976 }
977 a[i + k] = wc;
978 }
979 return carry;
980 }
981
982 /*
983 * Substract b[] from a[] (unsigned). a[] is modified "in
984 * place". Only n words of a[] are modified. Words
985 * b[0]...b[n-1] are subtracted from a[k]...a[k+n-1]. The final
986 * carry is returned ("true" for -1, "false" for 0). Neither a
987 * nor b may be null.
988 */
989 static bool MutateSub(uint[] a, int n, uint[] b, int k)
990 {
991 bool carry = false;
992 for (int i = 0; i < n; i ++) {
993 uint wa = a[i + k];
994 uint wb = b[i];
995 uint wc = wa - wb;
996 if (carry) {
997 wc --;
998 carry = wa <= wc;
999 } else {
1000 carry = wa < wc;
1001 }
1002 a[i + k] = wc;
1003 }
1004 return carry;
1005 }
1006
1007 /*
1008 * Get the length (in words) of the result of a left-shift of
1009 * the provided integer by k bits. If k < 0, then the value is
1010 * computed for a right-shift by -k bits.
1011 */
1012 static int GetLengthForLeftShift(ZInt x, int k)
1013 {
1014 if (k < 0) {
1015 if (k == Int32.MinValue) {
1016 return 0;
1017 }
1018 return GetLengthForRightShift(x, -k);
1019 }
1020 uint bl = (uint)x.BitLength + (uint)k;
1021 return (int)((bl + 31) >> 5);
1022 }
1023
1024 /*
1025 * Get the length (in words) of the result of a right-shift of
1026 * the provided integer by k bits. If k < 0, then the value is
1027 * computed for a left-shift by -k bits.
1028 */
1029 static int GetLengthForRightShift(ZInt x, int k)
1030 {
1031 if (k < 0) {
1032 if (k == Int32.MinValue) {
1033 throw new OverflowException();
1034 }
1035 return GetLengthForLeftShift(x, -k);
1036 }
1037 uint bl = (uint)x.BitLength;
1038 if (bl <= (uint)k) {
1039 return 0;
1040 } else {
1041 return (int)((bl - k + 31) >> 5);
1042 }
1043 }
1044
1045 /*
1046 * Left-shift a[] (unsigned) by k bits. If k < 0, then this becomes
1047 * a right-shift.
1048 */
1049 static uint[] ShiftLeft(uint[] a, int k)
1050 {
1051 if (k < 0) {
1052 return ShiftRight(a, -k);
1053 } else if (k == 0) {
1054 return a;
1055 }
1056 int n = Length(0, a);
1057 if (n == 0) {
1058 return null;
1059 }
1060
1061 /*
1062 * Allocate the result array, with the exact proper size.
1063 */
1064 int bl = ((n << 5) - LeadingZeros(a[n - 1])) + k;
1065 uint[] r = new uint[(bl + 31) >> 5];
1066
1067 int kb = k & 31;
1068 int kw = k >> 5;
1069
1070 /*
1071 * Special case: shift by an integral amount of words.
1072 */
1073 if (kb == 0) {
1074 Array.Copy(a, 0, r, kw, n);
1075 return r;
1076 }
1077
1078 /*
1079 * Copy the bits. This loop handles one source word at
1080 * a time, and writes one destination word at a time.
1081 * Some unhandled bits may remain at the end.
1082 */
1083 uint bits = 0;
1084 int zkb = 32 - kb;
1085 for (int i = 0; i < n; i ++) {
1086 uint w = a[i];
1087 r[i + kw] = bits | (w << kb);
1088 bits = w >> zkb;
1089 }
1090 if (bits != 0) {
1091 r[n + kw] = bits;
1092 }
1093 return r;
1094 }
1095
1096 /*
1097 * Right-shift a[] by k bits. If k < 0, then this becomes
1098 * a left-shift.
1099 */
1100 static uint[] ShiftRight(uint[] a, int k)
1101 {
1102 if (k < 0) {
1103 return ShiftLeft(a, -k);
1104 } else if (k == 0) {
1105 return a;
1106 }
1107 int n = Length(0, a);
1108 if (n == 0) {
1109 return null;
1110 }
1111 int bl = (n << 5) - LeadingZeros(a[n - 1]) - k;
1112 if (bl <= 0) {
1113 return null;
1114 }
1115 uint[] r = new uint[(bl + 31) >> 5];
1116
1117 int kb = k & 31;
1118 int kw = k >> 5;
1119
1120 /*
1121 * Special case: shift by an integral amount of words.
1122 */
1123 if (kb == 0) {
1124 Array.Copy(a, kw, r, 0, r.Length);
1125 return r;
1126 }
1127
1128 /*
1129 * Copy the bits. This loop handles one source word at
1130 * a time, and writes one destination word at a time.
1131 * Some unhandled bits may remain at the end.
1132 */
1133 uint bits = a[kw] >> kb;
1134 int zkb = 32 - kb;
1135 for (int i = kw + 1; i < n; i ++) {
1136 uint w = a[i];
1137 r[i - kw - 1] = bits | (w << zkb);
1138 bits = w >> kb;
1139 }
1140 if (bits != 0) {
1141 r[n - kw - 1] = bits;
1142 }
1143 return r;
1144 }
1145
1146 /*
1147 * Euclidian division of a[] (unsigned) by b (single word). This
1148 * method assumes that b is not 0.
1149 */
1150 static void DivRem(uint[] a, uint b, out uint[] q, out uint r)
1151 {
1152 int n = Length(0, a);
1153 if (n == 0) {
1154 q = null;
1155 r = 0;
1156 return;
1157 }
1158 q = new uint[n];
1159 ulong carry = 0;
1160 for (int i = n - 1; i >= 0; i --) {
1161 /*
1162 * Performance: we strongly hope that the JIT
1163 * compiler will notice that the "/" and "%"
1164 * can be combined into a single operation.
1165 * TODO: test whether we should replace the
1166 * carry computation with:
1167 * carry = w - (ulong)q[i] * b;
1168 */
1169 ulong w = (ulong)a[i] + (carry << 32);
1170 q[i] = (uint)(w / b);
1171 carry = w % b;
1172 }
1173 r = (uint)carry;
1174 }
1175
1176 /*
1177 * Euclidian division of a[] (unsigned) by b (single word). This
1178 * method assumes that b is not 0. a[] is modified in place. The
1179 * remainder (in the 0..b-1 range) is returned.
1180 */
1181 static uint MutateDivRem(uint[] a, uint b)
1182 {
1183 int n = Length(0, a);
1184 if (n == 0) {
1185 return 0;
1186 }
1187 ulong carry = 0;
1188 for (int i = n - 1; i >= 0; i --) {
1189 /*
1190 * Performance: we strongly hope that the JIT
1191 * compiler will notice that the "/" and "%"
1192 * can be combined into a single operation.
1193 * TODO: test whether we should replace the
1194 * carry computation with:
1195 * carry = w - (ulong)q[i] * b;
1196 */
1197 ulong w = (ulong)a[i] + (carry << 32);
1198 a[i] = (uint)(w / b);
1199 carry = w % b;
1200 }
1201 return (uint)carry;
1202 }
1203
1204 /*
1205 * Euclidian division of a[] by b[] (unsigned). This method
1206 * assumes that b[] is neither 0 or 1, and a[] is not smaller
1207 * than b[] (this implies that the quotient won't be zero).
1208 */
1209 static void DivRem(uint[] a, uint[] b, out uint[] q, out uint[] r)
1210 {
1211 int nb = Length(0, b);
1212
1213 /*
1214 * Special case when the divisor fits on one word.
1215 */
1216 if (nb == 1) {
1217 r = new uint[1];
1218 DivRem(a, b[0], out q, out r[0]);
1219 return;
1220 }
1221
1222 /*
1223 * General case.
1224 *
1225 * We first normalize divisor and dividend such that the
1226 * most significant bit of the most significant word of
1227 * the divisor is set. We can then compute the quotient
1228 * word by word. In details:
1229 *
1230 * Let:
1231 * w = 2^32 (one word)
1232 * a = (w*a0 + a1) * w^N + a2
1233 * b = b0 * w^N + b2
1234 * such that:
1235 * 0 <= a0 < w
1236 * 0 <= a1 < w
1237 * 0 <= a2 < w^N
1238 * w/2 <= b0 < w
1239 * 0 <= b2 < w^N
1240 * a < w*b
1241 * In other words, a0 and a1 are the two upper words of a[],
1242 * b0 is the upper word of b[] and has length 32 bits exactly,
1243 * and the quotient of a by b fits in one word.
1244 *
1245 * Under these conditions, define q and r such that:
1246 * a = b * q + r
1247 * q >= 0
1248 * 0 <= r < b
1249 * We can then compute a value u this way:
1250 * if a0 = b0, then let u = w-1
1251 * otherwise, let u be such that
1252 * (w*a0 + a1) = u*b0 + v, where 0 <= v < b0
1253 * It can then be shown that all these inequations hold:
1254 * 0 <= u < w
1255 * u-2 <= q <= u
1256 *
1257 * In plain words, this allows us to compute an almost-exact
1258 * estimate of the upper word of the quotient, with only
1259 * one 64-bit division.
1260 */
1261
1262 /*
1263 * Normalize dividend and divisor. The normalized dividend
1264 * will become the temporary array for the remainder, and
1265 * we will modify it, so we make sure we have a copy.
1266 */
1267 int norm = LeadingZeros(b[nb - 1]);
1268 r = ShiftLeft(a, norm);
1269 if (r == a) {
1270 r = new uint[a.Length];
1271 Array.Copy(a, 0, r, 0, a.Length);
1272 }
1273 uint[] b2 = ShiftLeft(b, norm);
1274 int nr = Length(0, r);
1275 #if DEBUG
1276 if (Length(0, b2) != nb) {
1277 throw new Exception("normalize error 1");
1278 }
1279 if (b2[nb - 1] < 0x80000000) {
1280 throw new Exception("normalize error 2");
1281 }
1282 {
1283 uint[] ta = ShiftRight(r, norm);
1284 if (Compare(a, ta) != 0) {
1285 throw new Exception("normalize error 3");
1286 }
1287 uint[] tb = ShiftRight(b2, norm);
1288 if (Compare(b, tb) != 0) {
1289 throw new Exception("normalize error 4");
1290 }
1291 }
1292 #endif
1293 b = b2;
1294
1295 /*
1296 * Length of the quotient will be (at most) k words. This
1297 * is the number of iterations in the loop below.
1298 */
1299 int k = (nr - nb) + 1;
1300 #if DEBUG
1301 if (k <= 0) {
1302 throw new Exception("wrong iteration count: " + k);
1303 }
1304 #endif
1305 q = new uint[k];
1306
1307 /*
1308 * The upper word of a[] (the one we modify, i.e. currently
1309 * stored in r[]) is in a0; it is carried over from the
1310 * previous loop iteration. Initially, it is zero.
1311 */
1312 uint a0 = 0;
1313 uint b0 = b[nb - 1];
1314 int j = nr;
1315 while (k -- > 0) {
1316 uint a1 = r[-- j];
1317 uint u;
1318 if (a0 == b0) {
1319 u = 0xFFFFFFFF;
1320 } else {
1321 ulong ah = ((ulong)a0 << 32) | (ulong)a1;
1322 u = (uint)(ah / b0);
1323 }
1324
1325 /*
1326 * Candidate word for the quotient:
1327 * -- if u = 0 then qw is necessarily 0, and the
1328 * rest of this iteration is trivial;
1329 * -- if u = 1 then we try qw = 1;
1330 * -- otherwise, we try qw = u-1.
1331 */
1332 uint qw;
1333 if (u == 0) {
1334 q[k] = 0;
1335 a0 = a1;
1336 continue;
1337 } else if (u == 1) {
1338 qw = 1;
1339 } else {
1340 qw = u - 1;
1341 }
1342
1343 /*
1344 * "Trying" a candidate word means subtracting from
1345 * r[] the product qw*b (b[] being shifted by k words).
1346 * The result may be negative, in which case we
1347 * overestimated qw; it may be greater than b or
1348 * equal to b, in which case we underestimated qw;
1349 * or it may be just fine.
1350 */
1351 ulong carry = 0;
1352 bool tooBig = true;
1353 for (int i = 0; i < nb; i ++) {
1354 uint wb = b[i];
1355 ulong z = (ulong)wb * (ulong)qw + carry;
1356 carry = z >> 32;
1357 uint wa = r[i + k];
1358 uint wc = wa - (uint)z;
1359 if (wc > wa) {
1360 carry ++;
1361 }
1362 r[i + k] = wc;
1363 if (wc != wb) {
1364 tooBig = wc > wb;
1365 }
1366 }
1367
1368 /*
1369 * Once we have adjusted everything, the upper word
1370 * of r[] will be nullified; wo do it now. Note that
1371 * for the first loop iteration, that upper word
1372 * may be absent (so already zero, but also "virtual").
1373 */
1374 if (nb + k < nr) {
1375 r[nb + k] = 0;
1376 }
1377
1378 /*
1379 * At that point, "carry" should be equal to a0
1380 * if we estimated right.
1381 */
1382 if (carry < (ulong)a0) {
1383 /*
1384 * Underestimate.
1385 */
1386 qw ++;
1387 #if DEBUG
1388 if (carry + 1 != (ulong)a0) {
1389 throw new Exception("div error 1");
1390 }
1391 if (!MutateSub(r, nb, b, k)) {
1392 throw new Exception("div error 2");
1393 }
1394 #else
1395 MutateSub(r, nb, b, k);
1396 #endif
1397 } else if (carry > (ulong)a0) {
1398 /*
1399 * Overestimate.
1400 */
1401 qw --;
1402 #if DEBUG
1403 if (carry - 1 != (ulong)a0) {
1404 throw new Exception("div error 3");
1405 }
1406 if (!MutateAdd(r, nb, b, k)) {
1407 throw new Exception("div error 4");
1408 }
1409 #else
1410 MutateAdd(r, nb, b, k);
1411 #endif
1412 } else if (tooBig) {
1413 /*
1414 * Underestimate, but no expected carry.
1415 */
1416 qw ++;
1417 #if DEBUG
1418 if (MutateSub(r, nb, b, k)) {
1419 throw new Exception("div error 5");
1420 }
1421 #else
1422 MutateSub(r, nb, b, k);
1423 #endif
1424 }
1425
1426 q[k] = qw;
1427 a0 = r[j];
1428 }
1429
1430 /*
1431 * At that point, r[] contains the remainder but needs
1432 * to be shifted back, to account for the normalization
1433 * performed before. q[] is correct (but possibly
1434 * untrimmed).
1435 */
1436 r = ShiftRight(r, norm);
1437 }
1438
1439 // =================================================================
1440
1441 /*
1442 * Conversion to sbyte; an OverflowException is thrown if the
1443 * value does not fit. Use ToInt to get a truncating conversion.
1444 */
1445 public static explicit operator sbyte(ZInt val)
1446 {
1447 int x = (int)val;
1448 if (x < SByte.MinValue || x > SByte.MaxValue) {
1449 throw new OverflowException();
1450 }
1451 return (sbyte)x;
1452 }
1453
1454 /*
1455 * Conversion to byte; an OverflowException is thrown if the
1456 * value does not fit. Use ToInt to get a truncating conversion.
1457 */
1458 public static explicit operator byte(ZInt val)
1459 {
1460 int x = (int)val;
1461 if (x > Byte.MaxValue) {
1462 throw new OverflowException();
1463 }
1464 return (byte)x;
1465 }
1466
1467 /*
1468 * Conversion to short; an OverflowException is thrown if the
1469 * value does not fit. Use ToInt to get a truncating conversion.
1470 */
1471 public static explicit operator short(ZInt val)
1472 {
1473 int x = (int)val;
1474 if (x < Int16.MinValue || x > Int16.MaxValue) {
1475 throw new OverflowException();
1476 }
1477 return (short)x;
1478 }
1479
1480 /*
1481 * Conversion to ushort; an OverflowException is thrown if the
1482 * value does not fit. Use ToInt to get a truncating conversion.
1483 */
1484 public static explicit operator ushort(ZInt val)
1485 {
1486 int x = (int)val;
1487 if (x > UInt16.MaxValue) {
1488 throw new OverflowException();
1489 }
1490 return (ushort)x;
1491 }
1492
1493 /*
1494 * Conversion to int; an OverflowException is thrown if the
1495 * value does not fit. Use ToInt to get a truncating conversion.
1496 */
1497 public static explicit operator int(ZInt val)
1498 {
1499 if (val.varray != null) {
1500 throw new OverflowException();
1501 }
1502 return val.small;
1503 }
1504
1505 /*
1506 * Conversion to uint; an OverflowException is thrown if the
1507 * value does not fit. Use ToUInt to get a truncating conversion.
1508 */
1509 public static explicit operator uint(ZInt val)
1510 {
1511 int s = val.small;
1512 if (s < 0) {
1513 throw new OverflowException();
1514 }
1515 uint[] m = val.varray;
1516 if (m == null) {
1517 return (uint)s;
1518 } else if (m.Length > 1) {
1519 throw new OverflowException();
1520 } else {
1521 return m[0];
1522 }
1523 }
1524
1525 /*
1526 * Conversion to long; an OverflowException is thrown if the
1527 * value does not fit. Use ToLong to get a truncating conversion.
1528 */
1529 public static explicit operator long(ZInt val)
1530 {
1531 int s = val.small;
1532 uint[] m = val.varray;
1533 if (m == null) {
1534 return (long)s;
1535 } else if (m.Length == 1) {
1536 return (long)m[0] | ((long)s << 32);
1537 } else if (m.Length == 2) {
1538 uint w0 = m[0];
1539 uint w1 = m[1];
1540 if (((w1 ^ (uint)s) >> 31) != 0) {
1541 throw new OverflowException();
1542 }
1543 return (long)w0 | ((long)w1 << 32);
1544 } else {
1545 throw new OverflowException();
1546 }
1547 }
1548
1549 /*
1550 * Conversion to ulong; an OverflowException is thrown if the
1551 * value does not fit. Use ToULong to get a truncating conversion.
1552 */
1553 public static explicit operator ulong(ZInt val)
1554 {
1555 int s = val.small;
1556 if (s < 0) {
1557 throw new OverflowException();
1558 }
1559 uint[] m = val.varray;
1560 if (m == null) {
1561 return (ulong)s;
1562 } else if (m.Length == 1) {
1563 return (ulong)m[0];
1564 } else if (m.Length == 2) {
1565 return (ulong)m[0] | ((ulong)m[1] << 32);
1566 } else {
1567 throw new OverflowException();
1568 }
1569 }
1570
1571 /*
1572 * By definition, conversion from sbyte conserves the value.
1573 */
1574 public static implicit operator ZInt(sbyte val)
1575 {
1576 return new ZInt((int)val);
1577 }
1578
1579 /*
1580 * By definition, conversion from byte conserves the value.
1581 */
1582 public static implicit operator ZInt(byte val)
1583 {
1584 return new ZInt((uint)val);
1585 }
1586
1587 /*
1588 * By definition, conversion from short conserves the value.
1589 */
1590 public static implicit operator ZInt(short val)
1591 {
1592 return new ZInt((int)val);
1593 }
1594
1595 /*
1596 * By definition, conversion from ushort conserves the value.
1597 */
1598 public static implicit operator ZInt(ushort val)
1599 {
1600 return new ZInt((uint)val);
1601 }
1602
1603 /*
1604 * By definition, conversion from int conserves the value.
1605 */
1606 public static implicit operator ZInt(int val)
1607 {
1608 return new ZInt(val);
1609 }
1610
1611 /*
1612 * By definition, conversion from uint conserves the value.
1613 */
1614 public static implicit operator ZInt(uint val)
1615 {
1616 return new ZInt(val);
1617 }
1618
1619 /*
1620 * By definition, conversion from long conserves the value.
1621 */
1622 public static implicit operator ZInt(long val)
1623 {
1624 return new ZInt(val);
1625 }
1626
1627 /*
1628 * By definition, conversion from ulong conserves the value.
1629 */
1630 public static implicit operator ZInt(ulong val)
1631 {
1632 return new ZInt(val);
1633 }
1634
1635 /*
1636 * Unary '+' operator is a no-operation.
1637 */
1638 public static ZInt operator +(ZInt a)
1639 {
1640 return a;
1641 }
1642
1643 /*
1644 * Unary negation.
1645 */
1646 public static ZInt operator -(ZInt a)
1647 {
1648 int s = a.small;
1649 uint[] m = a.varray;
1650 if (m == null) {
1651 if (s == Int32.MinValue) {
1652 return new ZInt(0, new uint[1] { 0x80000000 });
1653 } else {
1654 return new ZInt(-s, null);
1655 }
1656 }
1657
1658 /*
1659 * Two's complement: invert all bits, then add 1. The
1660 * result array will usually have the same size, but may
1661 * be one word longer or one word shorter.
1662 */
1663 int n = Length(s, m);
1664 uint[] bm = new uint[n];
1665 for (int i = 0; i < n; i ++) {
1666 bm[i] = ~m[i];
1667 }
1668 if (MutateIncr(bm)) {
1669 /*
1670 * Extra carry. This may happen only if the source
1671 * array contained only zeros, which may happen only
1672 * for a source value -2^(32*k) for some integer k
1673 * (k > 0).
1674 */
1675 bm = new uint[n + 1];
1676 bm[n] = 1;
1677 return new ZInt(0, bm);
1678 } else {
1679 /*
1680 * The resulting array might be too big by one word,
1681 * so we must not assume that it is trimmed.
1682 */
1683 return Make((int)~(uint)s, bm);
1684 }
1685 }
1686
1687 /*
1688 * Addition operator.
1689 */
1690 public static ZInt operator +(ZInt a, ZInt b)
1691 {
1692 int sa = a.small;
1693 int sb = b.small;
1694 uint[] ma = a.varray;
1695 uint[] mb = b.varray;
1696 if (ma == null) {
1697 if (sa == 0) {
1698 return b;
1699 }
1700 if (mb == null) {
1701 if (sb == 0) {
1702 return a;
1703 }
1704 return new ZInt((long)sa + (long)sb);
1705 }
1706 ma = new uint[1] { (uint)sa };
1707 sa >>= 31;
1708 } else if (mb == null) {
1709 if (sb == 0) {
1710 return a;
1711 }
1712 mb = new uint[1] { (uint)sb };
1713 sb >>= 31;
1714 }
1715 int na = ma.Length;
1716 int nb = mb.Length;
1717 int n = Math.Max(na, nb) + 1;
1718 uint[] mc = new uint[n];
1719 ulong carry = 0;
1720 for (int i = 0; i < n; i ++) {
1721 uint wa = i < na ? ma[i] : (uint)sa;
1722 uint wb = i < nb ? mb[i] : (uint)sb;
1723 ulong z = (ulong)wa + (ulong)wb + carry;
1724 mc[i] = (uint)z;
1725 carry = z >> 32;
1726 }
1727 return Make((-(int)carry) ^ sa ^ sb, mc);
1728 }
1729
1730 /*
1731 * Subtraction operator.
1732 */
1733 public static ZInt operator -(ZInt a, ZInt b)
1734 {
1735 int sa = a.small;
1736 int sb = b.small;
1737 uint[] ma = a.varray;
1738 uint[] mb = b.varray;
1739 if (ma == null) {
1740 if (sa == 0) {
1741 return -b;
1742 }
1743 if (mb == null) {
1744 if (sb == 0) {
1745 return a;
1746 }
1747 return new ZInt((long)sa - (long)sb);
1748 }
1749 ma = new uint[1] { (uint)sa };
1750 sa >>= 31;
1751 } else if (mb == null) {
1752 if (sb == 0) {
1753 return a;
1754 }
1755 mb = new uint[1] { (uint)sb };
1756 sb >>= 31;
1757 }
1758 int na = ma.Length;
1759 int nb = mb.Length;
1760 int n = Math.Max(na, nb) + 1;
1761 uint[] mc = new uint[n];
1762 long carry = 0;
1763 for (int i = 0; i < n; i ++) {
1764 uint wa = i < na ? ma[i] : (uint)sa;
1765 uint wb = i < nb ? mb[i] : (uint)sb;
1766 long z = (long)wa - (long)wb + carry;
1767 mc[i] = (uint)z;
1768 carry = z >> 32;
1769 }
1770 return Make((int)carry ^ sa ^ sb, mc);
1771 }
1772
1773 /*
1774 * Increment operator.
1775 */
1776 public static ZInt operator ++(ZInt a)
1777 {
1778 int s = a.small;
1779 uint[] ma = a.varray;
1780 if (ma == null) {
1781 return new ZInt((long)s + 1);
1782 }
1783 uint[] mb = Dup(ma);
1784 if (MutateIncr(mb)) {
1785 int n = ma.Length;
1786 mb = new uint[n + 1];
1787 mb[n] = 1;
1788 return new ZInt(0, mb);
1789 } else {
1790 return Make(s, mb);
1791 }
1792 }
1793
1794 /*
1795 * Decrement operator.
1796 */
1797 public static ZInt operator --(ZInt a)
1798 {
1799 int s = a.small;
1800 uint[] ma = a.varray;
1801 if (ma == null) {
1802 return new ZInt((long)s - 1);
1803 }
1804
1805 /*
1806 * MutateDecr() will report a carry only if the varray
1807 * contained only zeros; since this value was not small,
1808 * then it must have been negative.
1809 */
1810 uint[] mb = Dup(ma);
1811 if (MutateDecr(mb)) {
1812 int n = mb.Length;
1813 uint[] mc = new uint[n + 1];
1814 Array.Copy(mb, 0, mc, 0, n);
1815 mc[n] = 0xFFFFFFFE;
1816 return new ZInt(-1, mc);
1817 } else {
1818 return Make(s, mb);
1819 }
1820 }
1821
1822 /*
1823 * Multiplication operator.
1824 */
1825 public static ZInt operator *(ZInt a, ZInt b)
1826 {
1827 int sa = a.small;
1828 int sb = b.small;
1829 uint[] ma = a.varray;
1830 uint[] mb = b.varray;
1831
1832 /*
1833 * Special cases:
1834 * -- one of the operands is zero
1835 * -- both operands are small
1836 */
1837 if (ma == null) {
1838 if (sa == 0) {
1839 return Zero;
1840 }
1841 if (mb == null) {
1842 if (sb == 0) {
1843 return Zero;
1844 }
1845 return new ZInt((long)sa * (long)sb);
1846 }
1847 } else if (mb == null) {
1848 if (sb == 0) {
1849 return Zero;
1850 }
1851 }
1852
1853 /*
1854 * Get both values in sign+magnitude representation.
1855 */
1856 ToAbs(a, out sa, out ma);
1857 ToAbs(b, out sb, out mb);
1858
1859 /*
1860 * Compute the product. Set the sign.
1861 */
1862 ZInt r = Make(0, Mul(ma, mb));
1863 if ((sa ^ sb) < 0) {
1864 r = -r;
1865 }
1866 return r;
1867 }
1868
1869 /*
1870 * Integer division: the quotient is returned, and the remainder
1871 * is written in 'r'.
1872 *
1873 * This operation follows the C# rules for integer division:
1874 * -- rounding is towards 0
1875 * -- quotient is positive if dividend and divisor have the same
1876 * sign, negative otherwise
1877 * -- remainder has the sign of the dividend
1878 *
1879 * Attempt at dividing by zero triggers a DivideByZeroException.
1880 */
1881 public static ZInt DivRem(ZInt a, ZInt b, out ZInt r)
1882 {
1883 ZInt q;
1884 DivRem(a, b, out q, out r);
1885 return q;
1886 }
1887
1888 static void DivRem(ZInt a, ZInt b,
1889 out ZInt q, out ZInt r)
1890 {
1891 int sa = a.small;
1892 int sb = b.small;
1893 uint[] ma = a.varray;
1894 uint[] mb = b.varray;
1895
1896 /*
1897 * Division by zero triggers an exception.
1898 */
1899 if (mb == null && sb == 0) {
1900 throw new DivideByZeroException();
1901 }
1902
1903 /*
1904 * If the dividend is zero, then both quotient and
1905 * remainder are zero.
1906 */
1907 if (ma == null && sa == 0) {
1908 q = Zero;
1909 r = Zero;
1910 return;
1911 }
1912
1913 /*
1914 * If both dividend and divisor are small, then we
1915 * use the native 64-bit integer types. If only the
1916 * divisor is small, then we have a special fast case
1917 * for division by 1 or -1.
1918 */
1919 if (ma == null && mb == null) {
1920 q = new ZInt((long)sa / (long)sb);
1921 r = new ZInt((long)sa % (long)sb);
1922 return;
1923 }
1924 if (mb == null) {
1925 if (sb == 1) {
1926 q = a;
1927 r = Zero;
1928 return;
1929 } else if (sb == -1) {
1930 q = -a;
1931 r = Zero;
1932 return;
1933 }
1934 }
1935
1936 /*
1937 * We know that the dividend is not 0, and the divisor
1938 * is not -1, 0 or 1. We now want the sign+magnitude
1939 * representations of both operands.
1940 */
1941 ToAbs(a, out sa, out ma);
1942 ToAbs(b, out sb, out mb);
1943
1944 /*
1945 * If the divisor is greater (in magnitude) than the
1946 * dividend, then the quotient is zero and the remainder
1947 * is equal to the dividend. If the divisor and dividend
1948 * are equal in magnitude, then the remainder is zero and
1949 * the quotient is 1 if divisor and dividend have the same
1950 * sign, -1 otherwise.
1951 */
1952 int cc = Compare(ma, mb);
1953 if (cc < 0) {
1954 q = Zero;
1955 r = a;
1956 return;
1957 } else if (cc == 0) {
1958 q = (sa == sb) ? One : MinusOne;
1959 r = Zero;
1960 return;
1961 }
1962
1963 /*
1964 * At that point, we know that the divisor is not -1, 0
1965 * or 1, and that the quotient will not be 0. We perform
1966 * the unsigned division (with the magnitudes), then
1967 * we adjust the signs.
1968 */
1969
1970 uint[] mq, mr;
1971 DivRem(ma, mb, out mq, out mr);
1972
1973 /*
1974 * Quotient is positive if divisor and dividend have the
1975 * same sign, negative otherwise. Remainder always has
1976 * the sign of the dividend, but it may be zero.
1977 */
1978 q = Make(0, mq);
1979 if (sa != sb) {
1980 q = -q;
1981 }
1982 r = Make(0, mr);
1983 if (sa < 0) {
1984 r = -r;
1985 }
1986 #if DEBUG
1987 if (q * b + r != a) {
1988 throw new Exception("division error");
1989 }
1990 #endif
1991 }
1992
1993 /*
1994 * Division operator: see DivRem() for details.
1995 */
1996 public static ZInt operator /(ZInt a, ZInt b)
1997 {
1998 ZInt q, r;
1999 DivRem(a, b, out q, out r);
2000 return q;
2001 }
2002
2003 /*
2004 * Remainder operator: see DivRem() for details.
2005 */
2006 public static ZInt operator %(ZInt a, ZInt b)
2007 {
2008 ZInt q, r;
2009 DivRem(a, b, out q, out r);
2010 return r;
2011 }
2012
2013 /*
2014 * Reduce this value modulo the provided m. This differs from
2015 * '%' in that the returned value is always in the 0 to abs(m)-1
2016 * range.
2017 */
2018 public ZInt Mod(ZInt m)
2019 {
2020 ZInt r = this % m;
2021 if (r.small < 0) {
2022 if (m.small < 0) {
2023 m = -m;
2024 }
2025 r += m;
2026 }
2027 return r;
2028 }
2029
2030 /*
2031 * Left-shift operator.
2032 */
2033 public static ZInt operator <<(ZInt a, int n)
2034 {
2035 if (n < 0) {
2036 if (n == Int32.MinValue) {
2037 return Zero;
2038 }
2039 return a >> (-n);
2040 }
2041 int sa = a.small;
2042 uint[] ma = a.varray;
2043 if (ma == null) {
2044 if (n <= 32) {
2045 return new ZInt((long)sa << n);
2046 }
2047 if (sa == 0) {
2048 return Zero;
2049 }
2050 }
2051 uint[] mr = new uint[GetLengthForLeftShift(a, n)];
2052
2053 /*
2054 * Special case when the shift is a multiple of 32.
2055 */
2056 int kw = n >> 5;
2057 int kb = n & 31;
2058 if (kb == 0) {
2059 if (ma == null) {
2060 mr[kw] = (uint)sa;
2061 return new ZInt(sa >> 31, mr);
2062 } else {
2063 Array.Copy(ma, 0, mr, kw, ma.Length);
2064 return new ZInt(sa, mr);
2065 }
2066 }
2067
2068 /*
2069 * At that point, we know that the source integer does
2070 * not fit in a signed "int", or is shifted by more than
2071 * 32 bits, or both. Either way, the result will not fit
2072 * in an "int".
2073 *
2074 * We process all input words one by one.
2075 */
2076 uint rem = 0;
2077 int ikb = 32 - kb;
2078 int j;
2079 if (ma == null) {
2080 j = 1;
2081 uint wa = (uint)sa;
2082 mr[kw] = wa << kb;
2083 rem = wa >> ikb;
2084 } else {
2085 j = ma.Length;
2086 for (int i = 0; i < j; i ++) {
2087 uint wa = ma[i];
2088 mr[i + kw] = rem | (wa << kb);
2089 rem = wa >> ikb;
2090 }
2091 }
2092 sa >>= 31;
2093 #if DEBUG
2094 if ((j + kw) == mr.Length - 1) {
2095 if (rem == ((uint)sa >> ikb)) {
2096 throw new Exception(
2097 "Wrong left-shift: untrimmed");
2098 }
2099 } else if ((j + kw) == mr.Length) {
2100 if (rem != ((uint)sa >> ikb)) {
2101 throw new Exception(
2102 "Wrong left-shift: dropped bits");
2103 }
2104 } else {
2105 throw new Exception(
2106 "Wrong left-shift: oversized output length");
2107 }
2108 #endif
2109 if ((j + kw) < mr.Length) {
2110 mr[j + kw] = rem | ((uint)sa << kb);
2111 }
2112 return new ZInt(sa, mr);
2113 }
2114
2115 /*
2116 * Right-shift operator.
2117 */
2118 public static ZInt operator >>(ZInt a, int n)
2119 {
2120 if (n < 0) {
2121 if (n == Int32.MinValue) {
2122 throw new OverflowException();
2123 }
2124 return a << (-n);
2125 }
2126 int sa = a.small;
2127 uint[] ma = a.varray;
2128 if (ma == null) {
2129 /*
2130 * If right-shifting a "small" value, then we can
2131 * do the computation with the native ">>" operator
2132 * on "int" values, unless the shift count is 32
2133 * or more, in which case we get either 0 or -1,
2134 * depending on the source value sign.
2135 */
2136 if (n < 32) {
2137 return new ZInt(sa >> n, null);
2138 } else {
2139 return new ZInt(sa >> 31, null);
2140 }
2141 }
2142
2143 /*
2144 * At that point, we know that the source value uses
2145 * a non-null varray. We compute the bit length of the
2146 * result. If the result would fit in an "int" (bit length
2147 * of 31 or less) then we handle it as a special case.
2148 */
2149 int kw = n >> 5;
2150 int kb = n & 31;
2151 int bl = a.BitLength - n;
2152 if (bl <= 0) {
2153 return new ZInt(sa, null);
2154 } else if (bl <= 31) {
2155 if (kb == 0) {
2156 return new ZInt((int)ma[kw], null);
2157 } else {
2158 int p = ma.Length;
2159 uint w0 = ma[kw];
2160 uint w1 = (kw + 1) < p ? ma[kw + 1] : (uint)sa;
2161 return new ZInt((int)((w0 >> kb)
2162 | (w1 << (32 - kb))), null);
2163 }
2164 }
2165
2166 /*
2167 * Result will require an array. Let's allocate it.
2168 */
2169 uint[] mr = new uint[(bl + 31) >> 5];
2170
2171 /*
2172 * Special case when the shift is a multiple of 32.
2173 */
2174 if (kb == 0) {
2175 #if DEBUG
2176 if (mr.Length != (ma.Length - kw)) {
2177 throw new Exception(
2178 "Wrong right-shift: output length");
2179 }
2180 #endif
2181 Array.Copy(ma, kw, mr, 0, ma.Length - kw);
2182 return new ZInt(sa, mr);
2183 }
2184
2185 /*
2186 * We process all input words one by one.
2187 */
2188 int ikb = 32 - kb;
2189 uint rem = ma[kw] >> kb;
2190 int j = ma.Length;
2191 for (int i = kw + 1; i < j; i ++) {
2192 uint wa = ma[i];
2193 mr[i - kw - 1] = rem | (wa << ikb);
2194 rem = wa >> kb;
2195 }
2196 #if DEBUG
2197 if ((j - kw - 1) == mr.Length - 1) {
2198 if (rem == ((uint)sa >> kb)) {
2199 throw new Exception(
2200 "Wrong right-shift: untrimmed");
2201 }
2202 } else if ((j - kw - 1) == mr.Length) {
2203 if (rem != ((uint)sa >> kb)) {
2204 throw new Exception(
2205 "Wrong right-shift: dropped bits");
2206 }
2207 } else {
2208 throw new Exception(
2209 "Wrong right-shift: oversized output length");
2210 }
2211 #endif
2212 if ((j - kw - 1) < mr.Length) {
2213 mr[j - kw - 1] = rem | ((uint)sa << ikb);
2214 }
2215 return new ZInt(sa, mr);
2216 }
2217
2218 /*
2219 * NOTES ON BITWISE BOOLEAN OPERATIONS
2220 *
2221 * When both operands are "small" then the result is necessarily
2222 * small: in "small" encoding, all bits beyond bit 31 of the
2223 * two's complement encoding are equal to bit 31, so the result
2224 * of computing the operation on bits 31 will also be valid for
2225 * all subsequent bits. Therefore, when the two operands are
2226 * small, we can just do the operation on the "int" values and the
2227 * result is guaranteed "small" as well.
2228 */
2229
2230 /*
2231 * Compute the bitwise AND between a "big" and a "small" values.
2232 */
2233 static ZInt AndSmall(int s, uint[] m, int x)
2234 {
2235 if (x < 0) {
2236 uint[] r = Dup(m);
2237 r[0] &= (uint)x;
2238 return new ZInt(s, r);
2239 } else {
2240 return new ZInt(x & (int)m[0], null);
2241 }
2242 }
2243
2244 /*
2245 * Bitwise AND operator.
2246 */
2247 public static ZInt operator &(ZInt a, ZInt b)
2248 {
2249 int sa = a.small;
2250 int sb = b.small;
2251 uint[] ma = a.varray;
2252 uint[] mb = b.varray;
2253 if (ma == null) {
2254 if (mb == null) {
2255 return new ZInt(sa & sb, null);
2256 } else {
2257 return AndSmall(sb, mb, sa);
2258 }
2259 } else if (mb == null) {
2260 return AndSmall(sa, ma, sb);
2261 }
2262
2263 /*
2264 * Both values are big. Since upper zero bits force the
2265 * result to contain zeros, the result size is that of the
2266 * positive operand (the smallest of the two if both are
2267 * positive). If both operands are negative, then the
2268 * result magnitude may be as large as the largest of the
2269 * two source magnitudes.
2270 *
2271 * Result is negative if and only if both operands are
2272 * negative.
2273 */
2274 int na = ma.Length;
2275 int nb = mb.Length;
2276 int nr;
2277 if (sa >= 0) {
2278 if (sb >= 0) {
2279 nr = Math.Min(na, nb);
2280 } else {
2281 nr = na;
2282 }
2283 } else {
2284 if (sb >= 0) {
2285 nr = nb;
2286 } else {
2287 nr = Math.Max(na, nb);
2288 }
2289 }
2290 uint[] mr = new uint[nr];
2291 for (int i = 0; i < nr; i ++) {
2292 uint wa = i < na ? ma[i] : (uint)sa;
2293 uint wb = i < nb ? mb[i] : (uint)sb;
2294 mr[i] = wa & wb;
2295 }
2296 return Make(sa & sb, mr);
2297 }
2298
2299 /*
2300 * Compute the bitwise OR between a "big" value (sign and
2301 * magnitude, already normalized/trimmed), and a small value
2302 * (which can be positive or negative).
2303 */
2304 static ZInt OrSmall(int s, uint[] m, int x)
2305 {
2306 if (x < 0) {
2307 return new ZInt(x | (int)m[0], null);
2308 } else {
2309 uint[] r = Dup(m);
2310 r[0] |= (uint)x;
2311 return new ZInt(s, r);
2312 }
2313 }
2314
2315 /*
2316 * Bitwise OR operator.
2317 */
2318 public static ZInt operator |(ZInt a, ZInt b)
2319 {
2320 int sa = a.small;
2321 int sb = b.small;
2322 uint[] ma = a.varray;
2323 uint[] mb = b.varray;
2324 if (ma == null) {
2325 if (mb == null) {
2326 return new ZInt(sa | sb, null);
2327 } else {
2328 return OrSmall(sb, mb, sa);
2329 }
2330 } else if (mb == null) {
2331 return OrSmall(sa, ma, sb);
2332 }
2333
2334 /*
2335 * Both values are big. Since upper one bits force the
2336 * result to contain ones, the result size is that of
2337 * the negative operand (the greater, i.e. "smallest" of
2338 * the two if both are negative). If both operands are
2339 * positive, then the result magnitude may be as large
2340 * as the largest of the two source magnitudes.
2341 *
2342 * Result is positive if and only if both operands are
2343 * positive.
2344 */
2345 int na = ma.Length;
2346 int nb = mb.Length;
2347 int nr;
2348 if (sa >= 0) {
2349 if (sb >= 0) {
2350 nr = Math.Max(na, nb);
2351 } else {
2352 nr = nb;
2353 }
2354 } else {
2355 if (sb >= 0) {
2356 nr = na;
2357 } else {
2358 nr = Math.Min(na, nb);
2359 }
2360 }
2361 uint[] mr = new uint[nr];
2362 for (int i = 0; i < nr; i ++) {
2363 uint wa = i < na ? ma[i] : (uint)sa;
2364 uint wb = i < nb ? mb[i] : (uint)sb;
2365 mr[i] = wa | wb;
2366 }
2367 return Make(sa | sb, mr);
2368 }
2369
2370 /*
2371 * Bitwise XOR operator.
2372 */
2373 public static ZInt operator ^(ZInt a, ZInt b)
2374 {
2375 int sa = a.small;
2376 int sb = b.small;
2377 uint[] ma = a.varray;
2378 uint[] mb = b.varray;
2379 if (ma == null && mb == null) {
2380 return new ZInt(sa ^ sb, null);
2381 }
2382 if (ma == null) {
2383 int st = sa;
2384 sa = sb;
2385 sb = st;
2386 uint[] mt = ma;
2387 ma = mb;
2388 mb = mt;
2389 }
2390 if (mb == null) {
2391 int nx = ma.Length;
2392 uint[] mx = new uint[nx];
2393 mx[0] = ma[0] ^ (uint)sb;
2394 if (nx > 1) {
2395 if (sb < 0) {
2396 for (int i = 1; i < nx; i ++) {
2397 mx[i] = ~ma[i];
2398 }
2399 } else {
2400 Array.Copy(ma, 1, mx, 1, nx - 1);
2401 }
2402 }
2403 return Make(sa ^ (sb >> 31), mx);
2404 }
2405
2406 /*
2407 * Both operands use varrays.
2408 * Result can be as big as the bigger of the two operands
2409 * (it _will_ be that big, necessarily, if the two operands
2410 * have distinct sizes).
2411 */
2412 int na = ma.Length;
2413 int nb = mb.Length;
2414 int nr = Math.Max(na, nb);
2415 uint[] mr = new uint[nr];
2416 for (int i = 0; i < nr; i ++) {
2417 uint wa = i < na ? ma[i] : (uint)sa;
2418 uint wb = i < nb ? mb[i] : (uint)sb;
2419 mr[i] = wa ^ wb;
2420 }
2421 return Make((sa ^ sb) >> 31, mr);
2422 }
2423
2424 /*
2425 * Bitwise inversion operator.
2426 */
2427 public static ZInt operator ~(ZInt a)
2428 {
2429 int s = a.small;
2430 uint[] m = a.varray;
2431 if (m == null) {
2432 return new ZInt(~s, null);
2433 } else {
2434 int n = m.Length;
2435 uint[] r = new uint[n];
2436 for (int i = 0; i < n; i ++) {
2437 r[i] = ~m[i];
2438 }
2439 return new ZInt(~s, r);
2440 }
2441 }
2442
2443 /*
2444 * Basic comparison; returned value is -1, 0 or 1 depending on
2445 * whether this instance is to be considered lower then, equal
2446 * to, or greater than the provided object.
2447 *
2448 * All ZInt instances are considered greater than 'null', and
2449 * lower than any non-null object that is not a ZInt.
2450 */
2451 public int CompareTo(object obj)
2452 {
2453 if (obj == null) {
2454 return 1;
2455 }
2456 if (!(obj is ZInt)) {
2457 return -1;
2458 }
2459 return CompareTo((ZInt)obj);
2460 }
2461
2462 /*
2463 * Basic comparison; returned value is -1, 0 or 1 depending on
2464 * whether this instance is to be considered lower then, equal
2465 * to, or greater than the provided value.
2466 */
2467 public int CompareTo(ZInt v)
2468 {
2469 int sv = v.small;
2470 uint[] mv = v.varray;
2471 int sign1 = small >> 31;
2472 int sign2 = sv >> 31;
2473 if (sign1 != sign2) {
2474 /*
2475 * One of the sign* values is -1, the other is 0.
2476 */
2477 return sign1 - sign2;
2478 }
2479
2480 /*
2481 * Both values have the same sign. Since the varrays are
2482 * trimmed, we can use their presence and length to
2483 * quickly resolve most cases.
2484 */
2485 if (small < 0) {
2486 if (varray == null) {
2487 if (mv == null) {
2488 return Compare(small, sv);
2489 } else {
2490 return 1;
2491 }
2492 } else {
2493 if (mv == null) {
2494 return -1;
2495 } else {
2496 int n1 = varray.Length;
2497 int n2 = mv.Length;
2498 if (n1 < n2) {
2499 return 1;
2500 } else if (n1 == n2) {
2501 return Compare(varray, mv);
2502 } else {
2503 return -1;
2504 }
2505 }
2506 }
2507 } else {
2508 if (varray == null) {
2509 if (mv == null) {
2510 return Compare(small, sv);
2511 } else {
2512 return -1;
2513 }
2514 } else {
2515 if (mv == null) {
2516 return 1;
2517 } else {
2518 return Compare(varray, mv);
2519 }
2520 }
2521 }
2522 }
2523
2524 /*
2525 * Equality comparison: a ZInt instance is equal only to another
2526 * ZInt instance that encodes the same integer value.
2527 */
2528 public override bool Equals(object obj)
2529 {
2530 if (obj == null) {
2531 return false;
2532 }
2533 if (!(obj is ZInt)) {
2534 return false;
2535 }
2536 return CompareTo((ZInt)obj) == 0;
2537 }
2538
2539 /*
2540 * Equality comparison: a ZInt instance is equal only to another
2541 * ZInt instance that encodes the same integer value.
2542 */
2543 public bool Equals(ZInt v)
2544 {
2545 return CompareTo(v) == 0;
2546 }
2547
2548 /*
2549 * The hash code for a ZInt is equal to its lower 32 bits.
2550 */
2551 public override int GetHashCode()
2552 {
2553 if (varray == null) {
2554 return small;
2555 } else {
2556 return (int)varray[0];
2557 }
2558 }
2559
2560 /*
2561 * Equality operator.
2562 */
2563 public static bool operator ==(ZInt a, ZInt b)
2564 {
2565 return a.CompareTo(b) == 0;
2566 }
2567
2568 /*
2569 * Inequality operator.
2570 */
2571 public static bool operator !=(ZInt a, ZInt b)
2572 {
2573 return a.CompareTo(b) != 0;
2574 }
2575
2576 /*
2577 * Lower-than operator.
2578 */
2579 public static bool operator <(ZInt a, ZInt b)
2580 {
2581 return a.CompareTo(b) < 0;
2582 }
2583
2584 /*
2585 * Lower-or-equal operator.
2586 */
2587 public static bool operator <=(ZInt a, ZInt b)
2588 {
2589 return a.CompareTo(b) <= 0;
2590 }
2591
2592 /*
2593 * Greater-than operator.
2594 */
2595 public static bool operator >(ZInt a, ZInt b)
2596 {
2597 return a.CompareTo(b) > 0;
2598 }
2599
2600 /*
2601 * Greater-or-equal operator.
2602 */
2603 public static bool operator >=(ZInt a, ZInt b)
2604 {
2605 return a.CompareTo(b) >= 0;
2606 }
2607
2608 /*
2609 * Power function: this raises x to the power e. The exponent e
2610 * MUST NOT be negative. If x and e are both zero, then 1 is
2611 * returned.
2612 */
2613 public static ZInt Pow(ZInt x, int e)
2614 {
2615 if (e < 0) {
2616 throw new ArgumentOutOfRangeException();
2617 }
2618 if (e == 0) {
2619 return One;
2620 }
2621 if (e == 1 || x.IsZero || x.IsOne) {
2622 return x;
2623 }
2624 bool neg = false;
2625 if (x.Sign < 0) {
2626 x = -x;
2627 neg = (e & 1) != 0;
2628 }
2629 if (x.IsPowerOfTwo) {
2630 int t = x.BitLength - 1;
2631 long u = (long)t * (long)e;
2632 if (u > (long)Int32.MaxValue) {
2633 throw new OverflowException();
2634 }
2635 x = One << (int)u;
2636 } else {
2637 ZInt y = One;
2638 for (;;) {
2639 if ((e & 1) != 0) {
2640 y *= x;
2641 }
2642 e >>= 1;
2643 if (e == 0) {
2644 break;
2645 }
2646 x *= x;
2647 }
2648 x = y;
2649 }
2650 return neg ? -x : x;
2651 }
2652
2653 /*
2654 * Modular exponentation: this function raises v to the power e
2655 * modulo m. The returned value is reduced modulo m: it will be
2656 * in the 0 to abs(m)-1 range.
2657 *
2658 * The modulus m must be positive. If m is 1, then the result is
2659 * 0 (regardless of the values of v and e).
2660 *
2661 * The exponent e must be nonnegative (this function does not
2662 * compute modular inverses). If e is zero, then the result is 1
2663 * (except if m is 1).
2664 */
2665 public static ZInt ModPow(ZInt v, ZInt e, ZInt m)
2666 {
2667 int se = e.Sign;
2668 if (se < 0) {
2669 throw new ArgumentOutOfRangeException();
2670 }
2671 int sm = m.Sign;
2672 if (sm < 0) {
2673 m = -m;
2674 } else if (sm == 0) {
2675 throw new DivideByZeroException();
2676 }
2677 if (m.varray == null && m.small == 1) {
2678 return Zero;
2679 }
2680 if (se == 0) {
2681 return One;
2682 }
2683 if (v.IsZero) {
2684 return Zero;
2685 }
2686
2687 // TODO: use Montgomery's multiplication when the exponent
2688 // is large.
2689 ZInt x = v.Mod(m);
2690 for (int n = e.BitLength - 2; n >= 0; n --) {
2691 x = (x * x).Mod(m);
2692 if (e.TestBit(n)) {
2693 x = (x * v).Mod(m);
2694 }
2695 }
2696 return x;
2697 }
2698
2699 /*
2700 * Get the absolute value of a ZInt.
2701 */
2702 public static ZInt Abs(ZInt x)
2703 {
2704 return (x.Sign < 0) ? -x : x;
2705 }
2706
2707 private static void AppendHex(StringBuilder sb, uint w, bool trim)
2708 {
2709 int i = 28;
2710 if (trim) {
2711 for (; i >= 0 && (w >> i) == 0; i -= 4);
2712 if (i < 0) {
2713 sb.Append("0");
2714 return;
2715 }
2716 }
2717 for (; i >= 0; i -= 4) {
2718 sb.Append("0123456789ABCDEF"[(int)((w >> i) & 0x0F)]);
2719 }
2720 }
2721
2722 /*
2723 * Convert this value to hexadecimal. If this instance is zero,
2724 * then "0" is returned. Otherwise, the number of digits is
2725 * minimal (no leading '0'). A leading '-' is used for negative
2726 * values. Hexadecimal digits are uppercase.
2727 */
2728 public string ToHexString()
2729 {
2730 if (varray == null && small == 0) {
2731 return "0";
2732 }
2733 StringBuilder sb = new StringBuilder();
2734 ZInt x = this;
2735 if (x.small < 0) {
2736 sb.Append('-');
2737 x = -x;
2738 }
2739 if (x.varray == null) {
2740 AppendHex(sb, (uint)x.small, true);
2741 } else {
2742 int n = x.varray.Length;
2743 AppendHex(sb, x.varray[n - 1], true);
2744 for (int j = n - 2; j >= 0; j --) {
2745 AppendHex(sb, x.varray[j], false);
2746 }
2747 }
2748 return sb.ToString();
2749 }
2750
2751 /*
2752 * Convert this value to decimal. A leading '-' sign is used for
2753 * negative value. The number of digits is minimal (no leading '0',
2754 * except for zero, which is returned as "0").
2755 */
2756 public override string ToString()
2757 {
2758 return ToString(10);
2759 }
2760
2761 private static int[] NDIGITS32 = {
2762 0, 0, 31, 20, 15, 13, 12, 11, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7,
2763 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
2764 };
2765
2766 private static uint[] RADIXPP32 = {
2767 0, 0, 2147483648, 3486784401, 1073741824, 1220703125,
2768 2176782336, 1977326743, 1073741824, 3486784401, 1000000000,
2769 2357947691, 429981696, 815730721, 1475789056, 2562890625,
2770 268435456, 410338673, 612220032, 893871739, 1280000000,
2771 1801088541, 2494357888, 3404825447, 191102976, 244140625,
2772 308915776, 387420489, 481890304, 594823321, 729000000,
2773 887503681, 1073741824, 1291467969, 1544804416, 1838265625,
2774 2176782336
2775 };
2776
2777 private static char[] DCHAR =
2778 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
2779
2780 static void AppendDigits(StringBuilder sb, uint v, int radix, int num)
2781 {
2782 while (num -- > 0) {
2783 sb.Append(DCHAR[v % (uint)radix]);
2784 v = v / (uint)radix;
2785 }
2786 }
2787
2788 static void AppendDigits(StringBuilder sb, uint v, int radix)
2789 {
2790 while (v > 0) {
2791 sb.Append(DCHAR[v % (uint)radix]);
2792 v = v / (uint)radix;
2793 }
2794 }
2795
2796 /*
2797 * Convert this value to a string, in the provided radix. The
2798 * radix must be in the 2 to 36 range (inclusive); uppercase
2799 * letters 'A' to 'Z' are used for digits of value 10 to 35.
2800 * If the value is zero, then "0" is returned; otherwise, leading
2801 * '0' digits are removed. A leading '-' sign is added for negative
2802 * values.
2803 */
2804 public string ToString(int radix)
2805 {
2806 if (radix < 2 || radix > 36) {
2807 throw new ArgumentOutOfRangeException();
2808 }
2809
2810 /*
2811 * Special optimized case for base 16.
2812 */
2813 if (radix == 16) {
2814 return ToHexString();
2815 }
2816
2817 if (IsZero) {
2818 return "0";
2819 }
2820
2821 ZInt x = this;
2822 if (x.Sign < 0) {
2823 x = -x;
2824 }
2825 StringBuilder sb = new StringBuilder();
2826 if (x.varray == null) {
2827 AppendDigits(sb, (uint)x.small, radix);
2828 } else {
2829 uint[] m = new uint[x.varray.Length];
2830 Array.Copy(x.varray, 0, m, 0, m.Length);
2831 uint prad = RADIXPP32[radix];
2832 int dnum = NDIGITS32[radix];
2833 for (;;) {
2834 uint v = MutateDivRem(m, prad);
2835 bool qz = Length(0, m) == 0;
2836 if (qz) {
2837 AppendDigits(sb, v, radix);
2838 break;
2839 } else {
2840 AppendDigits(sb, v, radix, dnum);
2841 }
2842 }
2843 }
2844 if (Sign < 0) {
2845 sb.Append('-');
2846 }
2847 return Reverse(sb);
2848 }
2849
2850 static string Reverse(StringBuilder sb)
2851 {
2852 int n = sb.Length;
2853 char[] tc = new char[n];
2854 sb.CopyTo(0, tc, 0, n);
2855 for (int i = 0, j = n - 1; i < j; i ++, j --) {
2856 char c = tc[i];
2857 tc[i] = tc[j];
2858 tc[j] = c;
2859 }
2860 return new string(tc);
2861 }
2862
2863 static uint DigitValue(char c, int radix)
2864 {
2865 int d;
2866 if (c >= '0' && c <= '9') {
2867 d = c - '0';
2868 } else if (c >= 'a' && c <= 'z') {
2869 d = (c - 'a') + 10;
2870 } else if (c >= 'A' && c <= 'Z') {
2871 d = (c - 'A') + 10;
2872 } else {
2873 d = -1;
2874 }
2875 if (d < 0 || d >= radix) {
2876 throw new ArgumentException();
2877 }
2878 return (uint)d;
2879 }
2880
2881 static ZInt ParseUnsigned(string s, int radix)
2882 {
2883 if (s.Length == 0) {
2884 throw new ArgumentException();
2885 }
2886 ZInt x = Zero;
2887 uint acc = 0;
2888 int accNum = 0;
2889 uint prad = RADIXPP32[radix];
2890 int dnum = NDIGITS32[radix];
2891 foreach (char c in s) {
2892 uint d = DigitValue(c, radix);
2893 acc = acc * (uint)radix + d;
2894 if (++ accNum == dnum) {
2895 x = x * (ZInt)prad + (ZInt)acc;
2896 acc = 0;
2897 accNum = 0;
2898 }
2899 }
2900 if (accNum > 0) {
2901 uint p = 1;
2902 while (accNum -- > 0) {
2903 p *= (uint)radix;
2904 }
2905 x = x * (ZInt)p + (ZInt)acc;
2906 }
2907 return x;
2908 }
2909
2910 /*
2911 * Parse a string:
2912 * -- A leading '-' is allowed, to denote a negative value.
2913 * -- If there is a "0b" or "0B" header (after any '-' sign),
2914 * then the value is interpreted in base 2.
2915 * -- If there is a "0x" or "0X" header (after any '-' sign),
2916 * then the value is interpreted in base 16 (hexadecimal).
2917 * Both uppercase and lowercase letters are accepted.
2918 * -- If there is no header, then decimal interpretation is used.
2919 *
2920 * Unexpected characters (including spaces) trigger exceptions.
2921 * There must be at least one digit.
2922 */
2923 public static ZInt Parse(string s)
2924 {
2925 s = s.Trim();
2926 bool neg = false;
2927 if (s.StartsWith("-")) {
2928 neg = true;
2929 s = s.Substring(1);
2930 }
2931 int radix;
2932 if (s.StartsWith("0b") || s.StartsWith("0B")) {
2933 radix = 2;
2934 s = s.Substring(2);
2935 } else if (s.StartsWith("0x") || s.StartsWith("0X")) {
2936 radix = 16;
2937 s = s.Substring(2);
2938 } else {
2939 radix = 10;
2940 }
2941 ZInt x = ParseUnsigned(s, radix);
2942 return neg ? -x : x;
2943 }
2944
2945 /*
2946 * Parse a string in the specified radix. The radix must be in
2947 * the 2 to 36 range (inclusive). Uppercase and lowercase letters
2948 * are accepted for digits in the 10 to 35 range.
2949 *
2950 * A leading '-' sign is allowed, to denote a negative value.
2951 * Otherwise, only digits (acceptable with regards to the radix)
2952 * may appear. There must be at least one digit.
2953 */
2954 public static ZInt Parse(string s, int radix)
2955 {
2956 if (radix < 2 || radix > 36) {
2957 throw new ArgumentOutOfRangeException();
2958 }
2959 s = s.Trim();
2960 bool neg = false;
2961 if (s.StartsWith("-")) {
2962 neg = true;
2963 s = s.Substring(1);
2964 }
2965 ZInt x = ParseUnsigned(s, radix);
2966 return neg ? -x : x;
2967 }
2968
2969 static uint DecU32BE(byte[] buf, int off, int len)
2970 {
2971 switch (len) {
2972 case 0:
2973 return 0;
2974 case 1:
2975 return buf[off];
2976 case 2:
2977 return ((uint)buf[off] << 8)
2978 | (uint)buf[off + 1];
2979 case 3:
2980 return ((uint)buf[off] << 16)
2981 | ((uint)buf[off + 1] << 8)
2982 | (uint)buf[off + 2];
2983 default:
2984 return ((uint)buf[off] << 24)
2985 | ((uint)buf[off + 1] << 16)
2986 | ((uint)buf[off + 2] << 8)
2987 | (uint)buf[off + 3];
2988 }
2989 }
2990
2991 /*
2992 * Decode an integer, assuming unsigned big-endian encoding.
2993 * An empty array is decoded as 0.
2994 */
2995 public static ZInt DecodeUnsignedBE(byte[] buf)
2996 {
2997 return DecodeUnsignedBE(buf, 0, buf.Length);
2998 }
2999
3000 /*
3001 * Decode an integer, assuming unsigned big-endian encoding.
3002 * An empty array is decoded as 0.
3003 */
3004 public static ZInt DecodeUnsignedBE(byte[] buf, int off, int len)
3005 {
3006 while (len > 0 && buf[off] == 0) {
3007 off ++;
3008 len --;
3009 }
3010 if (len == 0) {
3011 return Zero;
3012 } else if (len <= 4) {
3013 return new ZInt(DecU32BE(buf, off, len));
3014 }
3015 uint[] m = new uint[(len + 3) >> 2];
3016 int i = 0;
3017 for (int j = len; j > 0; j -= 4) {
3018 int k = j - 4;
3019 uint w;
3020 if (k < 0) {
3021 w = DecU32BE(buf, off, j);
3022 } else {
3023 w = DecU32BE(buf, off + k, 4);
3024 }
3025 m[i ++] = w;
3026 }
3027 return new ZInt(0, m);
3028 }
3029
3030 static RNGCryptoServiceProvider RNG = new RNGCryptoServiceProvider();
3031
3032 /*
3033 * Create a random integer of the provided size. Returned value
3034 * is in the 0 (inclusive) to 2^size (exclusive) range. A
3035 * cryptographically strong RNG is used to ensure uniform selection.
3036 */
3037 public static ZInt MakeRand(int size)
3038 {
3039 if (size <= 0) {
3040 throw new ArgumentOutOfRangeException();
3041 }
3042 byte[] buf = new byte[(size + 7) >> 3];
3043 RNG.GetBytes(buf);
3044 int kb = size & 7;
3045 if (kb != 0) {
3046 buf[0] &= (byte)(0xFF >> (8 - kb));
3047 }
3048 return DecodeUnsignedBE(buf);
3049 }
3050
3051 /*
3052 * Create a random integer in the 0 (inclusive) to max (exclusive)
3053 * range. 'max' must be positive. A cryptographically strong RNG
3054 * is used to ensure uniform selection.
3055 */
3056 public static ZInt MakeRand(ZInt max)
3057 {
3058 if (max.Sign <= 0) {
3059 throw new ArgumentOutOfRangeException();
3060 }
3061 int bl = max.BitLength;
3062 for (;;) {
3063 ZInt x = MakeRand(bl);
3064 if (x < max) {
3065 return x;
3066 }
3067 }
3068 }
3069
3070 /*
3071 * Create a random integer in the min (inclusive) to max (exclusive)
3072 * range. 'max' must be greater than min. A cryptographically
3073 * strong RNG is used to ensure uniform selection.
3074 */
3075 public static ZInt MakeRand(ZInt min, ZInt max)
3076 {
3077 if (max <= min) {
3078 throw new ArgumentOutOfRangeException();
3079 }
3080 return min + MakeRand(max - min);
3081 }
3082
3083 /*
3084 * Check whether this integer is prime. A probabilistic algorithm
3085 * is used, that theoretically ensures that a non-prime won't be
3086 * declared prime with probability greater than 2^(-100). Note that
3087 * this holds regardless of how the integer was generated (this
3088 * method does not assume that uniform random selection was used).
3089 *
3090 * (Realistically, the probability of a computer hardware
3091 * malfunction is way greater than 2^(-100), so this property
3092 * returns the primality status with as much certainty as can be
3093 * achieved with a computer.)
3094 */
3095 public bool IsPrime {
3096 get {
3097 return IsProbablePrime(50);
3098 }
3099 }
3100
3101 static uint[] PRIMES_BF = new uint[] {
3102 0xA08A28AC, 0x28208A20, 0x02088288, 0x800228A2,
3103 0x20A00A08, 0x80282088, 0x800800A2, 0x08028228,
3104 0x0A20A082, 0x22880020, 0x28020800, 0x88208082,
3105 0x02022020, 0x08828028, 0x8008A202, 0x20880880
3106 };
3107
3108 private bool IsProbablePrime(int rounds)
3109 {
3110 ZInt x = this;
3111 int cc = x.Sign;
3112 if (cc == 0) {
3113 return false;
3114 } else if (cc < 0) {
3115 x = -x;
3116 }
3117 if (x.varray == null) {
3118 if (x.small < (PRIMES_BF.Length << 5)) {
3119 return (PRIMES_BF[x.small >> 5]
3120 & ((uint)1 << (x.small & 31))) != 0;
3121 }
3122 }
3123 if (!x.TestBit(0)) {
3124 return false;
3125 }
3126
3127 ZInt xm1 = x;
3128 xm1 --;
3129 ZInt m = xm1;
3130 int a;
3131 for (a = 0; !m.TestBit(a); a ++);
3132 m >>= a;
3133 while (rounds -- > 0) {
3134 ZInt b = MakeRand(Two, x);
3135 ZInt z = ModPow(b, m, x);
3136 for (int j = 0; j < a; j ++) {
3137 if (z == One) {
3138 if (j > 0) {
3139 return false;
3140 }
3141 break;
3142 }
3143 if (z == xm1) {
3144 break;
3145 }
3146 if ((j + 1) < a) {
3147 z = (z * z) % x;
3148 } else {
3149 return false;
3150 }
3151 }
3152 }
3153 return true;
3154 }
3155
3156 /*
3157 * Encode this integer as bytes (signed big-endian convention).
3158 * Encoding is of minimal length that still contains a sign bit
3159 * (compatible with ASN.1 DER encoding).
3160 */
3161 public byte[] ToBytesBE()
3162 {
3163 byte[] r = new byte[(BitLength + 8) >> 3];
3164 ToBytesBE(r, 0, r.Length);
3165 return r;
3166 }
3167
3168 /*
3169 * Encode this integer as bytes (signed little-endian convention).
3170 * Encoding is of minimal length that still contains a sign bit.
3171 */
3172 public byte[] ToBytesLE()
3173 {
3174 byte[] r = new byte[(BitLength + 8) >> 3];
3175 ToBytesLE(r, 0, r.Length);
3176 return r;
3177 }
3178
3179 /*
3180 * Encode this integer as bytes (signed big-endian convention).
3181 * Output length is provided; exactly that many bytes will be
3182 * written. The value is sign-extended or truncated if needed.
3183 */
3184 public void ToBytesBE(byte[] buf, int off, int len)
3185 {
3186 ToBytes(true, buf, off, len);
3187 }
3188
3189 /*
3190 * Encode this integer as bytes (signed little-endian convention).
3191 * Output length is provided; exactly that many bytes will be
3192 * written. The value is sign-extended or truncated if needed.
3193 */
3194 public void ToBytesLE(byte[] buf, int off, int len)
3195 {
3196 ToBytes(false, buf, off, len);
3197 }
3198
3199 /*
3200 * Encode this integer as bytes (unsigned big-endian convention).
3201 * Encoding is of minimal length, possibly without a sign bit. If
3202 * this value is zero, then an empty array is returned. If this
3203 * value is negative, then an ArgumentOutOfRangeException is thrown.
3204 */
3205 public byte[] ToBytesUnsignedBE()
3206 {
3207 if (Sign < 0) {
3208 throw new ArgumentOutOfRangeException();
3209 }
3210 byte[] r = new byte[(BitLength + 7) >> 3];
3211 ToBytesBE(r, 0, r.Length);
3212 return r;
3213 }
3214
3215 /*
3216 * Encode this integer as bytes (unsigned little-endian convention).
3217 * Encoding is of minimal length, possibly without a sign bit. If
3218 * this value is zero, then an empty array is returned. If this
3219 * value is negative, then an ArgumentOutOfRangeException is thrown.
3220 */
3221 public byte[] ToBytesUnsignedLE()
3222 {
3223 if (Sign < 0) {
3224 throw new ArgumentOutOfRangeException();
3225 }
3226 byte[] r = new byte[(BitLength + 7) >> 3];
3227 ToBytesLE(r, 0, r.Length);
3228 return r;
3229 }
3230
3231 void ToBytes(bool be, byte[] buf, int off, int len)
3232 {
3233 uint iw = (uint)small >> 31;
3234 for (int i = 0; i < len; i ++) {
3235 int j = i >> 2;
3236 uint w;
3237 if (varray == null) {
3238 w = (j == 0) ? (uint)small : iw;
3239 } else {
3240 w = (j < varray.Length) ? varray[j] : iw;
3241 }
3242 byte v = (byte)(w >> ((i & 3) << 3));
3243 if (be) {
3244 buf[off + len - 1 - i] = v;
3245 } else {
3246 buf[off + i] = v;
3247 }
3248 }
3249 }
3250 }