blob: 877bc98112b3ad8e79fa0a7c83292d2cbc5ef626 [file] [log] [blame]
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -07001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// This file contains operations on unsigned multi-precision integers.
6// These are the building blocks for the operations on signed integers
7// and rationals.
8
Adam Langley19418552009-11-11 13:21:37 -08009// This package implements multi-precision arithmetic (big numbers).
Robert Griesemer08a209f2009-08-26 12:55:54 -070010// The following numeric types are supported:
11//
12// - Int signed integers
13//
14// All methods on Int take the result as the receiver; if it is one
15// of the operands it may be overwritten (and its memory reused).
16// To enable chaining of operations, the result is also returned.
17//
Adam Langley19418552009-11-11 13:21:37 -080018// If possible, one should use big over bignum as the latter is headed for
19// deprecation.
20//
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070021package big
22
Adam Langley19418552009-11-11 13:21:37 -080023import "rand"
24
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070025// An unsigned integer x of the form
26//
27// x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
28//
29// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
30// with the digits x[i] as the slice elements.
31//
32// A number is normalized if the slice contains no leading 0 digits.
33// During arithmetic operations, denormalized values may occur but are
34// always normalized before returning the final result. The normalized
35// representation of 0 is the empty or nil slice (length = 0).
36
Robert Griesemere5874222009-08-15 11:43:54 -070037// TODO(gri) - convert these routines into methods for type 'nat'
38// - decide if type 'nat' should be exported
39
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070040func normN(z []Word) []Word {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080041 i := len(z)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070042 for i > 0 && z[i-1] == 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -080043 i--
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070044 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -080045 z = z[0:i]
46 return z
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070047}
48
49
Robert Griesemer88742ef2009-08-18 10:06:15 -070050func makeN(z []Word, m int, clear bool) []Word {
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070051 if len(z) > m {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080052 z = z[0:m] // reuse z - has at least one extra word for a carry, if any
Robert Griesemer116b52d2009-08-18 11:48:47 -070053 if clear {
54 for i := range z {
Robert Griesemer40621d52009-11-09 12:07:39 -080055 z[i] = 0
Robert Griesemer116b52d2009-08-18 11:48:47 -070056 }
Robert Griesemer88742ef2009-08-18 10:06:15 -070057 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -080058 return z
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070059 }
Robert Griesemer116b52d2009-08-18 11:48:47 -070060
Robert Griesemer5a1d3322009-12-15 15:33:31 -080061 c := 4 // minimum capacity
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070062 if m > c {
Robert Griesemer40621d52009-11-09 12:07:39 -080063 c = m
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070064 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -080065 return make([]Word, m, c+1) // +1: extra word for a carry, if any
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070066}
67
68
69func newN(z []Word, x uint64) []Word {
70 if x == 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -080071 return makeN(z, 0, false)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070072 }
73
74 // single-digit values
75 if x == uint64(Word(x)) {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080076 z = makeN(z, 1, false)
77 z[0] = Word(x)
78 return z
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070079 }
80
81 // compute number of words n required to represent x
Robert Griesemer5a1d3322009-12-15 15:33:31 -080082 n := 0
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070083 for t := x; t > 0; t >>= _W {
Robert Griesemer40621d52009-11-09 12:07:39 -080084 n++
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070085 }
86
87 // split x into n words
Robert Griesemer5a1d3322009-12-15 15:33:31 -080088 z = makeN(z, n, false)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070089 for i := 0; i < n; i++ {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080090 z[i] = Word(x & _M)
91 x >>= _W
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070092 }
93
Robert Griesemer5a1d3322009-12-15 15:33:31 -080094 return z
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -070095}
96
97
98func setN(z, x []Word) []Word {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080099 z = makeN(z, len(x), false)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700100 for i, d := range x {
Robert Griesemer40621d52009-11-09 12:07:39 -0800101 z[i] = d
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700102 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800103 return z
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700104}
105
106
107func addNN(z, x, y []Word) []Word {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800108 m := len(x)
109 n := len(y)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700110
111 switch {
112 case m < n:
Robert Griesemer40621d52009-11-09 12:07:39 -0800113 return addNN(z, y, x)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700114 case m == 0:
115 // n == 0 because m >= n; result is 0
Robert Griesemer40621d52009-11-09 12:07:39 -0800116 return makeN(z, 0, false)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700117 case n == 0:
118 // result is x
Robert Griesemer40621d52009-11-09 12:07:39 -0800119 return setN(z, x)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700120 }
Robert Griesemere5874222009-08-15 11:43:54 -0700121 // m > 0
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700122
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800123 z = makeN(z, m, false)
124 c := addVV(&z[0], &x[0], &y[0], n)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700125 if m > n {
Robert Griesemer40621d52009-11-09 12:07:39 -0800126 c = addVW(&z[n], &x[n], c, m-n)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700127 }
128 if c > 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800129 z = z[0 : m+1]
130 z[m] = c
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700131 }
132
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800133 return z
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700134}
135
136
137func subNN(z, x, y []Word) []Word {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800138 m := len(x)
139 n := len(y)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700140
141 switch {
142 case m < n:
Robert Griesemer40621d52009-11-09 12:07:39 -0800143 panic("underflow")
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700144 case m == 0:
145 // n == 0 because m >= n; result is 0
Robert Griesemer40621d52009-11-09 12:07:39 -0800146 return makeN(z, 0, false)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700147 case n == 0:
148 // result is x
Robert Griesemer40621d52009-11-09 12:07:39 -0800149 return setN(z, x)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700150 }
Robert Griesemere5874222009-08-15 11:43:54 -0700151 // m > 0
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700152
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800153 z = makeN(z, m, false)
154 c := subVV(&z[0], &x[0], &y[0], n)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700155 if m > n {
Robert Griesemer40621d52009-11-09 12:07:39 -0800156 c = subVW(&z[n], &x[n], c, m-n)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700157 }
158 if c != 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800159 panic("underflow")
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700160 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800161 z = normN(z)
Robert Griesemere5874222009-08-15 11:43:54 -0700162
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800163 return z
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700164}
165
166
Robert Griesemer88742ef2009-08-18 10:06:15 -0700167func cmpNN(x, y []Word) (r int) {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800168 m := len(x)
169 n := len(y)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700170 if m != n || m == 0 {
Robert Griesemer88742ef2009-08-18 10:06:15 -0700171 switch {
Russ Coxc62b3262009-10-06 11:42:55 -0700172 case m < n:
Robert Griesemer40621d52009-11-09 12:07:39 -0800173 r = -1
Russ Coxc62b3262009-10-06 11:42:55 -0700174 case m > n:
Robert Griesemer40621d52009-11-09 12:07:39 -0800175 r = 1
Robert Griesemer88742ef2009-08-18 10:06:15 -0700176 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800177 return
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700178 }
179
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800180 i := m - 1
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700181 for i > 0 && x[i] == y[i] {
Robert Griesemer40621d52009-11-09 12:07:39 -0800182 i--
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700183 }
184
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700185 switch {
Russ Coxc62b3262009-10-06 11:42:55 -0700186 case x[i] < y[i]:
Robert Griesemer40621d52009-11-09 12:07:39 -0800187 r = -1
Russ Coxc62b3262009-10-06 11:42:55 -0700188 case x[i] > y[i]:
Robert Griesemer40621d52009-11-09 12:07:39 -0800189 r = 1
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700190 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800191 return
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700192}
193
194
Robert Griesemere5874222009-08-15 11:43:54 -0700195func mulAddNWW(z, x []Word, y, r Word) []Word {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800196 m := len(x)
Robert Griesemere5874222009-08-15 11:43:54 -0700197 if m == 0 || y == 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800198 return newN(z, uint64(r)) // result is r
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700199 }
200 // m > 0
Robert Griesemere5874222009-08-15 11:43:54 -0700201
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800202 z = makeN(z, m, false)
203 c := mulAddVWW(&z[0], &x[0], y, r, m)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700204 if c > 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800205 z = z[0 : m+1]
206 z[m] = c
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700207 }
Robert Griesemere5874222009-08-15 11:43:54 -0700208
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800209 return z
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700210}
211
212
213func mulNN(z, x, y []Word) []Word {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800214 m := len(x)
215 n := len(y)
Robert Griesemere5874222009-08-15 11:43:54 -0700216
217 switch {
218 case m < n:
Robert Griesemer40621d52009-11-09 12:07:39 -0800219 return mulNN(z, y, x)
Robert Griesemere5874222009-08-15 11:43:54 -0700220 case m == 0 || n == 0:
Robert Griesemer40621d52009-11-09 12:07:39 -0800221 return makeN(z, 0, false)
Robert Griesemer88742ef2009-08-18 10:06:15 -0700222 case n == 1:
Robert Griesemer40621d52009-11-09 12:07:39 -0800223 return mulAddNWW(z, x, y[0], 0)
Robert Griesemere5874222009-08-15 11:43:54 -0700224 }
Robert Griesemer88742ef2009-08-18 10:06:15 -0700225 // m >= n && m > 1 && n > 1
Robert Griesemere5874222009-08-15 11:43:54 -0700226
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800227 z = makeN(z, m+n, true)
Robert Griesemer88742ef2009-08-18 10:06:15 -0700228 if &z[0] == &x[0] || &z[0] == &y[0] {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800229 z = makeN(nil, m+n, true) // z is an alias for x or y - cannot reuse
Robert Griesemer88742ef2009-08-18 10:06:15 -0700230 }
231 for i := 0; i < n; i++ {
232 if f := y[i]; f != 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800233 z[m+i] = addMulVVW(&z[i], &x[0], f, m)
Robert Griesemer88742ef2009-08-18 10:06:15 -0700234 }
235 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800236 z = normN(z)
Robert Griesemere5874222009-08-15 11:43:54 -0700237
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800238 return z
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700239}
240
241
242// q = (x-r)/y, with 0 <= r < y
243func divNW(z, x []Word, y Word) (q []Word, r Word) {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800244 m := len(x)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700245 switch {
246 case y == 0:
Robert Griesemer40621d52009-11-09 12:07:39 -0800247 panic("division by zero")
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700248 case y == 1:
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800249 q = setN(z, x) // result is x
250 return
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700251 case m == 0:
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800252 q = setN(z, nil) // result is 0
253 return
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700254 }
255 // m > 0
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800256 z = makeN(z, m, false)
257 r = divWVW(&z[0], 0, &x[0], y, m)
258 q = normN(z)
259 return
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700260}
261
262
Adam Langley19418552009-11-11 13:21:37 -0800263func divNN(z, z2, u, v []Word) (q, r []Word) {
264 if len(v) == 0 {
265 panic("Divide by zero undefined")
266 }
267
268 if cmpNN(u, v) < 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800269 q = makeN(z, 0, false)
270 r = setN(z2, u)
271 return
Adam Langley19418552009-11-11 13:21:37 -0800272 }
273
274 if len(v) == 1 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800275 var rprime Word
276 q, rprime = divNW(z, u, v[0])
Adam Langley19418552009-11-11 13:21:37 -0800277 if rprime > 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800278 r = makeN(z2, 1, false)
279 r[0] = rprime
Adam Langley19418552009-11-11 13:21:37 -0800280 } else {
281 r = makeN(z2, 0, false)
282 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800283 return
Adam Langley19418552009-11-11 13:21:37 -0800284 }
285
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800286 q, r = divLargeNN(z, z2, u, v)
287 return
Adam Langley19418552009-11-11 13:21:37 -0800288}
289
290
Adam Langley65063bc2009-11-05 15:55:41 -0800291// q = (uIn-r)/v, with 0 <= r < y
292// See Knuth, Volume 2, section 4.3.1, Algorithm D.
293// Preconditions:
294// len(v) >= 2
Adam Langley19418552009-11-11 13:21:37 -0800295// len(uIn) >= len(v)
296func divLargeNN(z, z2, uIn, v []Word) (q, r []Word) {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800297 n := len(v)
298 m := len(uIn) - len(v)
Adam Langley65063bc2009-11-05 15:55:41 -0800299
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800300 u := makeN(z2, len(uIn)+1, false)
301 qhatv := make([]Word, len(v)+1)
302 q = makeN(z, m+1, false)
Adam Langley65063bc2009-11-05 15:55:41 -0800303
304 // D1.
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800305 shift := leadingZeroBits(v[n-1])
306 shiftLeft(v, v, shift)
307 shiftLeft(u, uIn, shift)
308 u[len(uIn)] = uIn[len(uIn)-1] >> (_W - uint(shift))
Adam Langley65063bc2009-11-05 15:55:41 -0800309
310 // D2.
311 for j := m; j >= 0; j-- {
312 // D3.
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800313 var qhat Word
Adam Langleybf1f63a2009-11-18 19:26:12 -0800314 if u[j+n] == v[n-1] {
315 qhat = _B - 1
316 } else {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800317 var rhat Word
318 qhat, rhat = divWW_g(u[j+n], u[j+n-1], v[n-1])
Adam Langley65063bc2009-11-05 15:55:41 -0800319
Adam Langleybf1f63a2009-11-18 19:26:12 -0800320 // x1 | x2 = q̂v_{n-2}
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800321 x1, x2 := mulWW_g(qhat, v[n-2])
Adam Langleybf1f63a2009-11-18 19:26:12 -0800322 // test if q̂v_{n-2} > br̂ + u_{j+n-2}
323 for greaterThan(x1, x2, rhat, u[j+n-2]) {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800324 qhat--
325 prevRhat := rhat
326 rhat += v[n-1]
Adam Langleybf1f63a2009-11-18 19:26:12 -0800327 // v[n-1] >= 0, so this tests for overflow.
328 if rhat < prevRhat {
329 break
330 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800331 x1, x2 = mulWW_g(qhat, v[n-2])
Adam Langley65063bc2009-11-05 15:55:41 -0800332 }
Adam Langley65063bc2009-11-05 15:55:41 -0800333 }
334
335 // D4.
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800336 qhatv[len(v)] = mulAddVWW(&qhatv[0], &v[0], qhat, 0, len(v))
Adam Langley65063bc2009-11-05 15:55:41 -0800337
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800338 c := subVV(&u[j], &u[j], &qhatv[0], len(qhatv))
Adam Langley65063bc2009-11-05 15:55:41 -0800339 if c != 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800340 c := addVV(&u[j], &u[j], &v[0], len(v))
341 u[j+len(v)] += c
342 qhat--
Adam Langley65063bc2009-11-05 15:55:41 -0800343 }
344
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800345 q[j] = qhat
Adam Langley65063bc2009-11-05 15:55:41 -0800346 }
347
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800348 q = normN(q)
349 shiftRight(u, u, shift)
350 shiftRight(v, v, shift)
351 r = normN(u)
Adam Langley65063bc2009-11-05 15:55:41 -0800352
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800353 return q, r
Adam Langley65063bc2009-11-05 15:55:41 -0800354}
355
356
Robert Griesemer08a209f2009-08-26 12:55:54 -0700357// log2 computes the integer binary logarithm of x.
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700358// The result is the integer n for which 2^n <= x < 2^(n+1).
Robert Griesemer08a209f2009-08-26 12:55:54 -0700359// If x == 0, the result is -1.
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700360func log2(x Word) int {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800361 n := 0
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700362 for ; x > 0; x >>= 1 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800363 n++
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700364 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800365 return n - 1
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700366}
367
368
Robert Griesemer08a209f2009-08-26 12:55:54 -0700369// log2N computes the integer binary logarithm of x.
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700370// The result is the integer n for which 2^n <= x < 2^(n+1).
Robert Griesemer08a209f2009-08-26 12:55:54 -0700371// If x == 0, the result is -1.
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700372func log2N(x []Word) int {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800373 m := len(x)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700374 if m > 0 {
Adam Langley19418552009-11-11 13:21:37 -0800375 return (m-1)*_W + log2(x[m-1])
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700376 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800377 return -1
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700378}
379
380
381func hexValue(ch byte) int {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800382 var d byte
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700383 switch {
Russ Coxc62b3262009-10-06 11:42:55 -0700384 case '0' <= ch && ch <= '9':
Robert Griesemer16989342009-11-09 21:09:34 -0800385 d = ch - '0'
Russ Coxc62b3262009-10-06 11:42:55 -0700386 case 'a' <= ch && ch <= 'f':
Robert Griesemer16989342009-11-09 21:09:34 -0800387 d = ch - 'a' + 10
Russ Coxc62b3262009-10-06 11:42:55 -0700388 case 'A' <= ch && ch <= 'F':
Robert Griesemer16989342009-11-09 21:09:34 -0800389 d = ch - 'A' + 10
Russ Coxc62b3262009-10-06 11:42:55 -0700390 default:
Robert Griesemer40621d52009-11-09 12:07:39 -0800391 return -1
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700392 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800393 return int(d)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700394}
395
396
397// scanN returns the natural number corresponding to the
398// longest possible prefix of s representing a natural number in a
399// given conversion base, the actual conversion base used, and the
400// prefix length. The syntax of natural numbers follows the syntax
401// of unsigned integer literals in Go.
402//
403// If the base argument is 0, the string prefix determines the actual
404// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
405// ``0'' prefix selects base 8. Otherwise the selected base is 10.
406//
407func scanN(z []Word, s string, base int) ([]Word, int, int) {
408 // determine base if necessary
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800409 i, n := 0, len(s)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700410 if base == 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800411 base = 10
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700412 if n > 0 && s[0] == '0' {
413 if n > 1 && (s[1] == 'x' || s[1] == 'X') {
Adam Langley65063bc2009-11-05 15:55:41 -0800414 if n == 2 {
415 // Reject a string which is just '0x' as nonsense.
Robert Griesemer40621d52009-11-09 12:07:39 -0800416 return nil, 0, 0
Adam Langley65063bc2009-11-05 15:55:41 -0800417 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800418 base, i = 16, 2
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700419 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800420 base, i = 8, 1
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700421 }
422 }
423 }
424 if base < 2 || 16 < base {
Robert Griesemer40621d52009-11-09 12:07:39 -0800425 panic("illegal base")
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700426 }
427
428 // convert string
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800429 z = makeN(z, len(z), false)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700430 for ; i < n; i++ {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800431 d := hexValue(s[i])
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700432 if 0 <= d && d < base {
Robert Griesemer40621d52009-11-09 12:07:39 -0800433 z = mulAddNWW(z, z, Word(base), Word(d))
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700434 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800435 break
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700436 }
437 }
438
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800439 return z, base, i
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700440}
441
442
443// string converts x to a string for a given base, with 2 <= base <= 16.
444// TODO(gri) in the style of the other routines, perhaps this should take
445// a []byte buffer and return it
446func stringN(x []Word, base int) string {
447 if base < 2 || 16 < base {
Robert Griesemer40621d52009-11-09 12:07:39 -0800448 panic("illegal base")
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700449 }
450
451 if len(x) == 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800452 return "0"
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700453 }
454
455 // allocate buffer for conversion
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800456 i := (log2N(x)+1)/log2(Word(base)) + 1 // +1: round up
457 s := make([]byte, i)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700458
459 // don't destroy x
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800460 q := setN(nil, x)
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700461
462 // convert
463 for len(q) > 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800464 i--
465 var r Word
466 q, r = divNW(q, q, Word(base))
467 s[i] = "0123456789abcdef"[r]
Russ Coxc62b3262009-10-06 11:42:55 -0700468 }
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700469
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800470 return string(s[i:])
Robert Griesemerdb3bf9c2009-08-14 11:53:27 -0700471}
Adam Langley65063bc2009-11-05 15:55:41 -0800472
473
474// leadingZeroBits returns the number of leading zero bits in x.
475func leadingZeroBits(x Word) int {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800476 c := 0
Robert Griesemer48b31562009-11-05 18:25:23 -0800477 if x < 1<<(_W/2) {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800478 x <<= _W / 2
479 c = _W / 2
Adam Langley65063bc2009-11-05 15:55:41 -0800480 }
481
482 for i := 0; x != 0; i++ {
483 if x&(1<<(_W-1)) != 0 {
Robert Griesemer16989342009-11-09 21:09:34 -0800484 return i + c
Adam Langley65063bc2009-11-05 15:55:41 -0800485 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800486 x <<= 1
Adam Langley65063bc2009-11-05 15:55:41 -0800487 }
488
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800489 return _W
Adam Langley19418552009-11-11 13:21:37 -0800490}
491
492const deBruijn32 = 0x077CB531
493
494var deBruijn32Lookup = []byte{
495 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
496 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
497}
498
499const deBruijn64 = 0x03f79d71b4ca8b09
500
501var deBruijn64Lookup = []byte{
502 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
503 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
504 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
505 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
506}
507
508// trailingZeroBits returns the number of consecutive zero bits on the right
509// side of the given Word.
510// See Knuth, volume 4, section 7.3.1
511func trailingZeroBits(x Word) int {
512 // x & -x leaves only the right-most bit set in the word. Let k be the
513 // index of that bit. Since only a single bit is set, the value is two
514 // to the power of k. Multipling by a power of two is equivalent to
515 // left shifting, in this case by k bits. The de Bruijn constant is
516 // such that all six bit, consecutive substrings are distinct.
517 // Therefore, if we have a left shifted version of this constant we can
518 // find by how many bits it was shifted by looking at which six bit
519 // substring ended up at the top of the word.
520 switch _W {
521 case 32:
522 return int(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
523 case 64:
524 return int(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
525 default:
526 panic("Unknown word size")
527 }
528
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800529 return 0
Adam Langley65063bc2009-11-05 15:55:41 -0800530}
531
532
533func shiftLeft(dst, src []Word, n int) {
534 if len(src) == 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800535 return
Adam Langley65063bc2009-11-05 15:55:41 -0800536 }
537
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800538 ñ := _W - uint(n)
Robert Griesemer16989342009-11-09 21:09:34 -0800539 for i := len(src) - 1; i >= 1; i-- {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800540 dst[i] = src[i] << uint(n)
541 dst[i] |= src[i-1] >> ñ
Adam Langley65063bc2009-11-05 15:55:41 -0800542 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800543 dst[0] = src[0] << uint(n)
Adam Langley65063bc2009-11-05 15:55:41 -0800544}
545
546
547func shiftRight(dst, src []Word, n int) {
548 if len(src) == 0 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800549 return
Adam Langley65063bc2009-11-05 15:55:41 -0800550 }
551
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800552 ñ := _W - uint(n)
Adam Langley65063bc2009-11-05 15:55:41 -0800553 for i := 0; i < len(src)-1; i++ {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800554 dst[i] = src[i] >> uint(n)
555 dst[i] |= src[i+1] << ñ
Adam Langley65063bc2009-11-05 15:55:41 -0800556 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800557 dst[len(src)-1] = src[len(src)-1] >> uint(n)
Adam Langley65063bc2009-11-05 15:55:41 -0800558}
559
560
561// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800562func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 }
Adam Langley19418552009-11-11 13:21:37 -0800563
564
565// modNW returns x % d.
566func modNW(x []Word, d Word) (r Word) {
567 // TODO(agl): we don't actually need to store the q value.
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800568 q := makeN(nil, len(x), false)
569 return divWVW(&q[0], 0, &x[0], d, len(x))
Adam Langley19418552009-11-11 13:21:37 -0800570}
571
572
573// powersOfTwoDecompose finds q and k such that q * 1<<k = n and q is odd.
574func powersOfTwoDecompose(n []Word) (q []Word, k Word) {
575 if len(n) == 0 {
576 return n, 0
577 }
578
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800579 zeroWords := 0
Adam Langley19418552009-11-11 13:21:37 -0800580 for n[zeroWords] == 0 {
581 zeroWords++
582 }
583 // One of the words must be non-zero by invariant, therefore
584 // zeroWords < len(n).
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800585 x := trailingZeroBits(n[zeroWords])
Adam Langley19418552009-11-11 13:21:37 -0800586
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800587 q = makeN(nil, len(n)-zeroWords, false)
588 shiftRight(q, n[zeroWords:], x)
Adam Langley19418552009-11-11 13:21:37 -0800589
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800590 k = Word(_W*zeroWords + x)
591 return
Adam Langley19418552009-11-11 13:21:37 -0800592}
593
594
595// randomN creates a random integer in [0..limit), using the space in z if
596// possible. n is the bit length of limit.
597func randomN(z []Word, rand *rand.Rand, limit []Word, n int) []Word {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800598 bitLengthOfMSW := uint(n % _W)
599 mask := Word((1 << bitLengthOfMSW) - 1)
600 z = makeN(z, len(limit), false)
Adam Langley19418552009-11-11 13:21:37 -0800601
602 for {
603 for i := range z {
604 switch _W {
605 case 32:
606 z[i] = Word(rand.Uint32())
607 case 64:
608 z[i] = Word(rand.Uint32()) | Word(rand.Uint32())<<32
609 }
610 }
611
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800612 z[len(limit)-1] &= mask
Adam Langley19418552009-11-11 13:21:37 -0800613
614 if cmpNN(z, limit) < 0 {
615 break
616 }
617 }
618
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800619 return z
Adam Langley19418552009-11-11 13:21:37 -0800620}
621
622
623// If m != nil, expNNN calculates x**y mod m. Otherwise it calculates x**y. It
624// reuses the storage of z if possible.
625func expNNN(z, x, y, m []Word) []Word {
626 if len(y) == 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800627 z = makeN(z, 1, false)
628 z[0] = 1
629 return z
Adam Langley19418552009-11-11 13:21:37 -0800630 }
631
632 if m != nil {
633 // We likely end up being as long as the modulus.
634 z = makeN(z, len(m), false)
635 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800636 z = setN(z, x)
637 v := y[len(y)-1]
Adam Langley19418552009-11-11 13:21:37 -0800638 // It's invalid for the most significant word to be zero, therefore we
639 // will find a one bit.
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800640 shift := leadingZeros(v) + 1
641 v <<= shift
642 var q []Word
Adam Langley19418552009-11-11 13:21:37 -0800643
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800644 const mask = 1 << (_W - 1)
Adam Langley19418552009-11-11 13:21:37 -0800645
646 // We walk through the bits of the exponent one by one. Each time we
647 // see a bit, we square, thus doubling the power. If the bit is a one,
648 // we also multiply by x, thus adding one to the power.
649
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800650 w := _W - int(shift)
Adam Langley19418552009-11-11 13:21:37 -0800651 for j := 0; j < w; j++ {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800652 z = mulNN(z, z, z)
Adam Langley19418552009-11-11 13:21:37 -0800653
654 if v&mask != 0 {
655 z = mulNN(z, z, x)
656 }
657
658 if m != nil {
659 q, z = divNN(q, z, z, m)
660 }
661
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800662 v <<= 1
Adam Langley19418552009-11-11 13:21:37 -0800663 }
664
665 for i := len(y) - 2; i >= 0; i-- {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800666 v = y[i]
Adam Langley19418552009-11-11 13:21:37 -0800667
668 for j := 0; j < _W; j++ {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800669 z = mulNN(z, z, z)
Adam Langley19418552009-11-11 13:21:37 -0800670
671 if v&mask != 0 {
672 z = mulNN(z, z, x)
673 }
674
675 if m != nil {
676 q, z = divNN(q, z, z, m)
677 }
678
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800679 v <<= 1
Adam Langley19418552009-11-11 13:21:37 -0800680 }
681 }
682
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800683 return z
Adam Langley19418552009-11-11 13:21:37 -0800684}
685
686
687// lenN returns the bit length of z.
688func lenN(z []Word) int {
689 if len(z) == 0 {
690 return 0
691 }
692
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800693 return (len(z)-1)*_W + (_W - leadingZeroBits(z[len(z)-1]))
Adam Langley19418552009-11-11 13:21:37 -0800694}
695
696
697const (
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800698 primesProduct32 = 0xC0CFD797 // Π {p ∈ primes, 2 < p <= 29}
699 primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
Adam Langley19418552009-11-11 13:21:37 -0800700)
701
702var bigOne = []Word{1}
703var bigTwo = []Word{2}
704
705// ProbablyPrime performs n Miller-Rabin tests to check whether n is prime.
706// If it returns true, n is prime with probability 1 - 1/4^n.
707// If it returns false, n is not prime.
708func probablyPrime(n []Word, reps int) bool {
709 if len(n) == 0 {
710 return false
711 }
712
713 if len(n) == 1 {
714 if n[0]%2 == 0 {
715 return n[0] == 2
716 }
717
718 // We have to exclude these cases because we reject all
719 // multiples of these numbers below.
720 if n[0] == 3 || n[0] == 5 || n[0] == 7 || n[0] == 11 ||
721 n[0] == 13 || n[0] == 17 || n[0] == 19 || n[0] == 23 ||
722 n[0] == 29 || n[0] == 31 || n[0] == 37 || n[0] == 41 ||
723 n[0] == 43 || n[0] == 47 || n[0] == 53 {
724 return true
725 }
726 }
727
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800728 var r Word
Adam Langley19418552009-11-11 13:21:37 -0800729 switch _W {
730 case 32:
731 r = modNW(n, primesProduct32)
732 case 64:
733 r = modNW(n, primesProduct64&_M)
734 default:
735 panic("Unknown word size")
736 }
737
738 if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
739 r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
740 return false
741 }
742
743 if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
744 r%43 == 0 || r%47 == 0 || r%53 == 0) {
745 return false
746 }
747
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800748 nm1 := subNN(nil, n, bigOne)
Adam Langley19418552009-11-11 13:21:37 -0800749 // 1<<k * q = nm1;
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800750 q, k := powersOfTwoDecompose(nm1)
Adam Langley19418552009-11-11 13:21:37 -0800751
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800752 nm3 := subNN(nil, nm1, bigTwo)
753 rand := rand.New(rand.NewSource(int64(n[0])))
Adam Langley19418552009-11-11 13:21:37 -0800754
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800755 var x, y, quotient []Word
756 nm3Len := lenN(nm3)
Adam Langley19418552009-11-11 13:21:37 -0800757
758NextRandom:
759 for i := 0; i < reps; i++ {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800760 x = randomN(x, rand, nm3, nm3Len)
761 addNN(x, x, bigTwo)
762 y = expNNN(y, x, q, n)
Adam Langley19418552009-11-11 13:21:37 -0800763 if cmpNN(y, bigOne) == 0 || cmpNN(y, nm1) == 0 {
764 continue
765 }
766 for j := Word(1); j < k; j++ {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800767 y = mulNN(y, y, y)
768 quotient, y = divNN(quotient, y, y, n)
Adam Langley19418552009-11-11 13:21:37 -0800769 if cmpNN(y, nm1) == 0 {
770 continue NextRandom
771 }
772 if cmpNN(y, bigOne) == 0 {
773 return false
774 }
775 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800776 return false
Adam Langley19418552009-11-11 13:21:37 -0800777 }
778
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800779 return true
Adam Langley19418552009-11-11 13:21:37 -0800780}