Projects : gbw-signer : gbw-signer_genesis
| 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)) |