Projects : gbw-signer : gbw-signer_usrbin

gbw-signer/library/bignum.scm

Dir - Raw

1;;;; bignum.scm: A user-level unsigned bignum arithmetic library
2;;; J. Welsh, August 2017
3;;; Trimmed for gbw, March 2020
4
5;; A bignum is a list of words, least significant first. It must not have trailing zeros. Thus each number has a unique representation, and zero is the empty list.
6
7(lambda ()
8
9 ;;; Constants
10 (define base-nibbles (quotient *fixnum-width* 8))
11 (define base-bits (delay (fx*/wrap base-nibbles 4)))
12 (define base/2 (delay (expt 2 (- base-bits 1))))
13 (define base (delay (* 2 base/2))) ;; must be <= sqrt of largest fixnum
14 (define base-1 (delay (- base 1)))
15 (define neg-base-bits (delay (- base-bits)))
16
17 (define - fx-/wrap)
18 (define + fx+/wrap)
19 (define * fx*/wrap)
20 (define (zero? x) (fx= x 0))
21 (define (even? x) (fx= (fxand x 1) 0))
22 (define = fx=)
23 (define < fx<)
24 (define <= fx<=)
25 (define hex "0123456789abcdef")
26 (define char0 (char->integer #\0))
27 (define char10-A (fx-/wrap 10 (char->integer #\A)))
28 (define bn0 '())
29 (define bn1 '(1))
30
31 ;;; Helpers
32
33 (define (fix->hex n) ;; note 0 -> empty string
34 (do ((n n (fxshift n -4))
35 (acc '() (cons (string-ref hex (fxand n 15)) acc)))
36 ((zero? n) (list->string acc))))
37
38 (define (hexdigit->fix c)
39 (if (char-numeric? c) (- (char->integer c) char0)
40 (let ((i (+ (char->integer (char-upcase c)) char10-A)))
41 (if (and (<= 10 i) (< i 16)) i
42 (error "bad hex digit:" c)))))
43
44 (define (decdigit->fix c)
45 (if (char-numeric? c) (- (char->integer c) char0)
46 (error "bad decimal digit:" c)))
47
48 (define (left-pad s len char)
49 (string-append (make-string (- len (string-length s)) char) s))
50
51 (define (bn-pad-word->hex w)
52 (left-pad (fix->hex w) base-nibbles #\0))
53
54 (define (word->bn w)
55 (if (zero? w) '() (list w)))
56
57 ;; Construct bignum from big-endian, vector-like sequence of nibbles. Ugly, but linear time.
58 (define (nibbles->bn nibble-ref len)
59 (define (loop-words start acc)
60 (if (= start len) acc
61 (let* ((next (+ start base-nibbles))
62 (word (get-word start (- next 1))))
63 (loop-words next (if (and (null? acc) (zero? word)) acc
64 (cons word acc))))))
65 (define (get-word start stop)
66 (define (loop start acc)
67 (if (< stop start) acc
68 (loop (+ start 1) (+ (* 16 acc) (nibble-ref start)))))
69 (loop (+ start 1) (nibble-ref start)))
70 (if (zero? len) '()
71 (let* ((msw-end (remainder (- len 1) base-nibbles))
72 (msw (get-word 0 msw-end)))
73 (loop-words (+ msw-end 1) (word->bn msw)))))
74
75 ;; Rather than "shift left/right", which unnecessarily invoke endianness, I'm using "shift" for multiplications and "unshift" for divisions.
76 (define (shift-words a k)
77 (if (null? a) a (shift-words-nz a k)))
78
79 (define (shift-words-nz a k)
80 (if (zero? k) a
81 (shift-words-nz (cons 0 a) (- k 1))))
82
83 (define (unshift-words a k)
84 (if (or (zero? k) (null? a)) a
85 (unshift-words (cdr a) (- k 1))))
86
87 ;;; Type conversion
88
89 (define (bn->hex n)
90 (let ((n (reverse n)))
91 (if (null? n) "0"
92 (apply string-append (fix->hex (car n)) ;; optimize?
93 (map bn-pad-word->hex (cdr n))))))
94
95 (define (hex->bn s)
96 (nibbles->bn (lambda (k) (hexdigit->fix (string-ref s k)))
97 (string-length s)))
98
99 (define (bytes->bn v)
100 (nibbles->bn (lambda (k)
101 (let ((byte (vector-ref v (fxshift k -1))))
102 (if (even? k)
103 (fxshift byte -4) ;; big-endian
104 (fxand byte 15))))
105 (* 2 (vector-length v))))
106
107 ;; ~Cubic algorithm!
108 (define (bn->dec n)
109 (let loop ((n n) (acc '()))
110 (if (null? n) (list->string acc)
111 (bn-divrem n '(10)
112 (lambda (q r)
113 (loop q (cons (string-ref hex (bn->fix r)) acc)))))))
114
115 ;; Quadratic algorithm!
116 (define (dec->bn s)
117 (do ((i 0 (+ i 1))
118 (acc bn0 (bn+fix (bn*fix acc 10)
119 (decdigit->fix (string-ref s i)))))
120 ((= i (string-length s)) acc)))
121
122 ;; Can overflow (obviously)
123 (define (bn->fix n)
124 (do ((n (reverse n) (cdr n))
125 (acc 0 (+ (* acc base) (car n))))
126 ((null? n) acc)))
127
128 (define (fix->bn n)
129 (do ((n n (fxshift n neg-base-bits))
130 (acc '() (cons (fxand n base-1) acc)))
131 ((zero? n) (reverse acc))))
132
133 ;;; Predicates
134
135 (define bn-zero? null?)
136
137 (define (bn-even? a) (or (null? a) (even? (car a))))
138 (define (bn-odd? a) (not (bn-even? a)))
139
140 (define (cmp a b)
141 (cond ((< a b) -1)
142 ((< b a) 1)
143 (else 0)))
144
145 (define (bn-cmp a b)
146 (cond ((null? a) (if (null? b) 0 -1))
147 ((null? b) 1)
148 (else (let ((c (bn-cmp (cdr a) (cdr b))))
149 (if (zero? c) (cmp (car a) (car b))
150 c)))))
151
152 (define bn= equal?)
153 (define (bn< a b) (< (bn-cmp a b) 0))
154 (define (bn> a b) (< 0 (bn-cmp a b)))
155 (define (bn<= a b) (<= (bn-cmp a b) 0))
156 (define (bn>= a b) (<= 0 (bn-cmp a b)))
157
158 ;;; Addition
159
160 (define (bn+1 a)
161 (if (null? a) bn1
162 (let ((head (car a)))
163 (if (= head base-1)
164 (cons 0 (bn+1 (cdr a)))
165 (cons (+ head 1) (cdr a))))))
166
167 (define (bn+ a b)
168 (cond ((null? a) b)
169 ((null? b) a)
170 (else (let ((sum (+ (car a) (car b))))
171 (if (< sum base)
172 (cons sum (bn+ (cdr a) (cdr b)))
173 (cons (- sum base) (bn+carry (cdr a) (cdr b))))))))
174
175 (define (bn+carry a b)
176 (cond ((null? a) (bn+1 b))
177 ((null? b) (bn+1 a))
178 (else (let ((sum (+ (car a) (car b) 1)))
179 (if (< sum base)
180 (cons sum (bn+ (cdr a) (cdr b)))
181 (cons (- sum base) (bn+carry (cdr a) (cdr b))))))))
182
183 ;; CAUTION: assumes 0 <= b < base
184 (define (bn+fix a b)
185 (cond ((zero? b) a)
186 ((null? a) (list b))
187 (else (let ((sum (+ (car a) b)))
188 (if (< sum base)
189 (cons sum (cdr a))
190 (cons (- sum base) (bn+1 (cdr a))))))))
191
192 ;;; Subtraction
193
194 (define (bn-1 a)
195 (if (null? a) (error "bn-1: subtract from zero"))
196 (let ((head (car a)) (tail (cdr a)))
197 (cond ((zero? head) (cons base-1 (bn-1 tail)))
198 ((and (= head 1) (null? tail)) '())
199 (else (cons (- head 1) tail)))))
200
201 (define (bn- a b)
202 (cond ((null? a) (if (null? b) b (error "bn-: subtract from zero")))
203 ((null? b) a)
204 (else (let ((diff (- (car a) (car b))))
205 (if (< diff 0)
206 (cons (+ diff base) (bn-sub-borrow (cdr a) (cdr b)))
207 (let ((tail (bn- (cdr a) (cdr b))))
208 (if (and (= diff 0) (null? tail)) '()
209 (cons diff tail))))))))
210
211 (define (bn-sub-borrow a b)
212 (cond ((null? a) (error "bn-: subtract from zero"))
213 ((null? b) (bn-1 a))
214 (else (let ((diff (- (car a) (car b) 1)))
215 (if (< diff 0)
216 (let ((tail (bn-sub-borrow (cdr a) (cdr b)))
217 (diff (+ diff base)))
218 (if (and (= diff 0) (null? tail)) '()
219 (cons diff tail)))
220 (let ((tail (bn- (cdr a) (cdr b))))
221 (if (and (= diff 0) (null? tail)) '()
222 (cons diff tail))))))))
223
224 ;;; Multiplication
225
226 (define (bn*2 a)
227 (if (null? a) '()
228 (let ((product (* (car a) 2)))
229 (if (< product base)
230 (cons product (bn*2 (cdr a)))
231 (cons (- product base) (bn*2+carry (cdr a)))))))
232
233 (define (bn*2+carry a)
234 (if (null? a) bn1
235 (let ((product (+ (* (car a) 2) 1)))
236 (if (< product base)
237 (cons product (bn*2 (cdr a)))
238 (cons (- product base) (bn*2+carry (cdr a)))))))
239
240 ;; CAUTION: assumes 0 <= scale < base
241 (define (bn*fix a scale)
242 (if (or (null? a) (zero? scale)) '()
243 (let ((product (* (car a) scale)))
244 (if (< product base)
245 (cons product (bn*fix (cdr a) scale))
246 (cons (fxand product base-1)
247 (bn*fix+carry (cdr a) scale
248 (fxshift product neg-base-bits)))))))
249
250 (define (bn*fix+carry a scale carry)
251 (if (or (null? a) (zero? scale)) (list carry)
252 (let ((product (+ (* (car a) scale) carry)))
253 (if (< product base)
254 (cons product (bn*fix (cdr a) scale))
255 (cons (fxand product base-1)
256 (bn*fix+carry (cdr a) scale
257 (fxshift product neg-base-bits)))))))
258
259 (define (bn-shift a bits)
260 (cond ((< bits 0) (error "bn-shift: negative bits"))
261 ((null? a) a)
262 (else (bn*fix (shift-words-nz a (quotient bits base-bits))
263 (expt 2 (remainder bits base-bits))))))
264
265 (define (bn* a b)
266 (define (a* b)
267 (if (null? b) b
268 (bn+ (bn*fix a (car b))
269 (shift-words (a* (cdr b)) 1))))
270 (if (null? a) a (a* b)))
271
272 ;; Still quadratic, but ~30% faster than generic multiplication
273 (define (bn^2 a)
274 (if (null? a) '()
275 (let* ((hd (car a))
276 (tl (cdr a))
277 (hd^2 (* hd hd))
278 (hd^2 (if (< hd^2 base) (word->bn hd^2)
279 (list (fxand hd^2 base-1)
280 (fxshift hd^2 neg-base-bits)))))
281 (if (null? tl) hd^2
282 (bn+ hd^2
283 (cons 0 (bn+ (cons 0 (bn^2 tl))
284 (bn*fix (bn*2 tl) hd))))))))
285
286 (define (strip-leading-zeros l)
287 (cond ((null? l) l)
288 ((zero? (car l)) (strip-leading-zeros (cdr l)))
289 (else l)))
290
291 (define (bn-split a k cont)
292 (do ((head '() (cons (car tail) head))
293 (tail a (cdr tail))
294 (k k (- k 1)))
295 ((or (null? tail) (zero? k))
296 (cont (reverse (strip-leading-zeros head)) tail))))
297
298 ;;; Division
299
300 (define (bn/2 a)
301 (if (null? a) a
302 (cdr (bn*fix a base/2))))
303
304 (define (bn-unshift a bits)
305 (if (< bits 0) (error "bn-unshift: negative bits"))
306 (let* ((full-words (quotient bits base-bits))
307 (extra-bits (remainder bits base-bits))
308 (a (unshift-words a full-words)))
309 (if (or (null? a) (zero? extra-bits)) a
310 (cdr (bn*fix a (expt 2 (- base-bits extra-bits)))))))
311
312 (define (num-bit-shifts start target) ;; optimize?
313 (define (loop start n)
314 (if (<= target start) n
315 (loop (* start 2) (+ n 1))))
316 (loop start 0))
317
318 (define (last l)
319 (if (null? (cdr l)) (car l)
320 (last (cdr l))))
321
322 (define (bn-divrem a b return)
323 (if (null? b) (error "division by zero"))
324 ;; Normalize: most sig. bit of most sig. word of divisor must be 1
325 (let ((msw (last b)))
326 (if (<= base/2 msw) (div-normalized a b return)
327 (let ((s (expt 2 (num-bit-shifts msw base/2))))
328 (div-normalized
329 (bn*fix a s) (bn*fix b s) ;; optimize
330 (lambda (q r)
331 (return q (if (null? r) r
332 (cdr (bn*fix r (quotient base s)))))))))))
333
334 (define (divrem-q q r) q)
335 (define (divrem-r q r) r)
336 (define (bn-quotient a b) (bn-divrem a b divrem-q)) ;; optimize?
337 (define (bn-remainder a b) (bn-divrem a b divrem-r))
338
339 (define (slice-2 a k)
340 (if (null? a) 0
341 (let ((tail (cdr a)))
342 (if (zero? k)
343 (if (null? tail) (car a)
344 (+ (car a) (* (car tail) base)))
345 (slice-2 tail (- k 1))))))
346
347 (define (most-sig-word a) ;; assumes not null
348 (define (loop a tail)
349 (if (null? tail) (car a)
350 (loop tail (cdr tail))))
351 (loop a (cdr a)))
352
353 (define (div-normalized A B return)
354 (let* ((n (length B))
355 (m (- (length A) n)))
356 (if (< m 0) (return '() A)
357 (let ((n-1 (- n 1))
358 (B-msw (most-sig-word B)))
359 (define (get-qi i Q A)
360 (define (try-qi qi)
361 (let ((prod (shift-words (bn*fix B qi) i)))
362 (if (bn< A prod)
363 (try-qi (- qi 1))
364 (get-qi (- i 1) (cons qi Q) (bn- A prod)))))
365 (if (< i 0) (return Q A)
366 (try-qi (min base-1 (quotient (slice-2 A (+ n-1 i))
367 B-msw)))))
368 (let ((B-shift (shift-words B m)))
369 (if (bn< A B-shift)
370 (get-qi (- m 1) '() A)
371 (get-qi (- m 1) '(1) (bn- A B-shift))))))))
372
373 ;; Multiplicative inverse of a mod n:
374 ;; (bn-remainder (bn* a (bn-mod-inverse a n)) n) -> bn1
375 ;; Assumes reduced input (0 < a < n)
376 (define (bn-mod-inverse a n)
377 ;; Extended Euclidean algorithm: find x where ax + by = gcd(a, b)
378 ;; If the gcd is 1, it follows that ax == 1 mod b
379 ;; See [HAC] Algorithm 2.142 / 2.107
380 ;; Simplified / adjusted for unsigned bignums
381 ;; Invariants:
382 ;; [1] 0 <= r < b (loop terminates when b would reach 0)
383 ;; [2] 0 < b < a (by [1], as b is last r and a is last b)
384 ;; [3] q > 0 (by [2])
385 ;; [4] If x > 0, then last x <= 0 and next x < 0
386 ;; If x < 0, then last x > 0 and next x > 0
387 ;; (by [3], as next x is last x - qx)
388 ;; Full proofs (mostly by induction) left as an exercise to the reader.
389 (define (loop a b x neg last-x)
390 (bn-divrem a b
391 (lambda (q r)
392 (if (bn-zero? r)
393 (if (bn= b bn1) (if neg (bn- n x) x)
394 (error "not invertible (modulus not prime?)"))
395 (loop b r (bn+ last-x (bn* q x)) (not neg) x)))))
396 (loop n a bn1 #f bn0))
397
398 ;;; Misc
399
400 ;; Number of significant bits
401 ;; = least integer b such that 2^b > a
402 ;; = ceil(log_2(a+1))
403 (define (bn-bits a)
404 (if (null? a) 0
405 (+ (num-bit-shifts 1 (+ (last a) 1))
406 (* (- (length a) 1) base-bits))))
407
408 (define (read-bytes n port)
409 (let ((v (make-vector n)))
410 (do ((k 0 (+ k 1))) ((= k n) v)
411 (vector-set! v k (char->integer (read-char port))))))
412
413 (define (ceil-quotient a b)
414 (quotient (+ a b -1) b))
415
416 ; Unbiased random integer generator in the interval [0, n)
417 (define (rand-bn n)
418 (if (bn-zero? n) (error "rand-bn: zero range"))
419 ;; Collecting one more byte than strictly necessary avoids cases where a large part of the range is invalid (e.g. n=130)
420 (let* ((nbytes (+ (ceil-quotient (bn-bits (bn-1 n)) 8) 1))
421 (rand-range (bn-shift bn1 (* nbytes 8)))
422 (unbiased-range (bn- rand-range (bn-remainder rand-range n))))
423 (lambda (rng-port)
424 (define (retry)
425 (let ((r (bytes->bn (read-bytes nbytes rng-port))))
426 (if (bn< r unbiased-range)
427 (bn-remainder r n)
428 (retry))))
429 (retry))))
430
431 ;; Deferred initializations
432 (set! base-bits (force base-bits))
433 (set! base/2 (force base/2))
434 (set! base (force base))
435 (set! base-1 (force base-1))
436 (set! neg-base-bits (force neg-base-bits))
437
438 (export
439 bn0 bn1
440 hexdigit->fix decdigit->fix ;; not strictly bignum ops, but handy
441 bn->hex hex->bn bytes->bn
442 bn->dec dec->bn
443 bn->fix fix->bn
444 bn-zero? bn-even? bn-odd? bn= bn< bn> bn<= bn>=
445 bn+1 bn+ bn-1 bn-
446 bn*2 bn-shift bn*fix bn* bn^2
447 bn/2 bn-unshift bn-divrem bn-quotient bn-remainder
448 bn-mod-inverse
449 bn-bits
450 rand-bn))