summaryrefslogtreecommitdiff
path: root/src/pkg/big
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/big')
-rwxr-xr-xsrc/pkg/big/int.go93
-rwxr-xr-xsrc/pkg/big/int_test.go50
-rwxr-xr-xsrc/pkg/big/nat.go47
3 files changed, 138 insertions, 52 deletions
diff --git a/src/pkg/big/int.go b/src/pkg/big/int.go
index 46e008734..f1ea7b1c2 100755
--- a/src/pkg/big/int.go
+++ b/src/pkg/big/int.go
@@ -8,6 +8,7 @@ package big
import (
"fmt"
+ "os"
"rand"
)
@@ -336,6 +337,10 @@ func fmtbase(ch int) int {
// 'x' (hexadecimal).
//
func (x *Int) Format(s fmt.State, ch int) {
+ if x == nil {
+ fmt.Fprint(s, "<nil>")
+ return
+ }
if x.neg {
fmt.Fprint(s, "-")
}
@@ -393,62 +398,19 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
}
-// SetBytes interprets b as the bytes of a big-endian, unsigned integer and
-// sets z to that value.
-func (z *Int) SetBytes(b []byte) *Int {
- const s = _S
- z.abs = z.abs.make((len(b) + s - 1) / s)
-
- j := 0
- for len(b) >= s {
- var w Word
-
- for i := s; i > 0; i-- {
- w <<= 8
- w |= Word(b[len(b)-i])
- }
-
- z.abs[j] = w
- j++
- b = b[0 : len(b)-s]
- }
-
- if len(b) > 0 {
- var w Word
-
- for i := len(b); i > 0; i-- {
- w <<= 8
- w |= Word(b[len(b)-i])
- }
-
- z.abs[j] = w
- }
-
- z.abs = z.abs.norm()
+// SetBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z *Int) SetBytes(buf []byte) *Int {
+ z.abs = z.abs.setBytes(buf)
z.neg = false
return z
}
-// Bytes returns the absolute value of x as a big-endian byte array.
+// Bytes returns the absolute value of z as a big-endian byte slice.
func (z *Int) Bytes() []byte {
- const s = _S
- b := make([]byte, len(z.abs)*s)
-
- for i, w := range z.abs {
- wordBytes := b[(len(z.abs)-i-1)*s : (len(z.abs)-i)*s]
- for j := s - 1; j >= 0; j-- {
- wordBytes[j] = byte(w)
- w >>= 8
- }
- }
-
- i := 0
- for i < len(b) && b[i] == 0 {
- i++
- }
-
- return b[i:]
+ buf := make([]byte, len(z.abs)*_S)
+ return buf[z.abs.bytes(buf):]
}
@@ -739,3 +701,34 @@ func (z *Int) Not(x *Int) *Int {
z.neg = true // z cannot be zero if x is positive
return z
}
+
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const version byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (z *Int) GobEncode() ([]byte, os.Error) {
+ buf := make([]byte, len(z.abs)*_S+1) // extra byte for version and sign bit
+ i := z.abs.bytes(buf) - 1 // i >= 0
+ b := version << 1 // make space for sign bit
+ if z.neg {
+ b |= 1
+ }
+ buf[i] = b
+ return buf[i:], nil
+}
+
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Int) GobDecode(buf []byte) os.Error {
+ if len(buf) == 0 {
+ return os.NewError("Int.GobDecode: no data")
+ }
+ b := buf[0]
+ if b>>1 != version {
+ return os.NewError(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
+ }
+ z.neg = b&1 != 0
+ z.abs = z.abs.setBytes(buf[1:])
+ return nil
+}
diff --git a/src/pkg/big/int_test.go b/src/pkg/big/int_test.go
index fc981e1da..9c19dd5da 100755
--- a/src/pkg/big/int_test.go
+++ b/src/pkg/big/int_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"encoding/hex"
"fmt"
+ "gob"
"testing"
"testing/quick"
)
@@ -715,18 +716,25 @@ var composites = []string{
func TestProbablyPrime(t *testing.T) {
+ nreps := 20
+ if testing.Short() {
+ nreps = 1
+ }
for i, s := range primes {
p, _ := new(Int).SetString(s, 10)
- if !ProbablyPrime(p, 20) {
+ if !ProbablyPrime(p, nreps) {
t.Errorf("#%d prime found to be non-prime (%s)", i, s)
}
}
for i, s := range composites {
c, _ := new(Int).SetString(s, 10)
- if ProbablyPrime(c, 20) {
+ if ProbablyPrime(c, nreps) {
t.Errorf("#%d composite found to be prime (%s)", i, s)
}
+ if testing.Short() {
+ break
+ }
}
}
@@ -1053,3 +1061,41 @@ func TestModInverse(t *testing.T) {
}
}
}
+
+
+var gobEncodingTests = []string{
+ "0",
+ "1",
+ "2",
+ "10",
+ "42",
+ "1234567890",
+ "298472983472983471903246121093472394872319615612417471234712061",
+}
+
+func TestGobEncoding(t *testing.T) {
+ var medium bytes.Buffer
+ enc := gob.NewEncoder(&medium)
+ dec := gob.NewDecoder(&medium)
+ for i, test := range gobEncodingTests {
+ for j := 0; j < 2; j++ {
+ medium.Reset() // empty buffer for each test case (in case of failures)
+ stest := test
+ if j == 0 {
+ stest = "-" + test
+ }
+ var tx Int
+ tx.SetString(stest, 10)
+ if err := enc.Encode(&tx); err != nil {
+ t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
+ }
+ var rx Int
+ if err := dec.Decode(&rx); err != nil {
+ t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err)
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx)
+ }
+ }
+ }
+}
diff --git a/src/pkg/big/nat.go b/src/pkg/big/nat.go
index a308f69e8..a04d3b1d9 100755
--- a/src/pkg/big/nat.go
+++ b/src/pkg/big/nat.go
@@ -1065,3 +1065,50 @@ NextRandom:
return true
}
+
+
+// bytes writes the value of z into buf using big-endian encoding.
+// len(buf) must be >= len(z)*_S. The value of z is encoded in the
+// slice buf[i:]. The number i of unused bytes at the beginning of
+// buf is returned as result.
+func (z nat) bytes(buf []byte) (i int) {
+ i = len(buf)
+ for _, d := range z {
+ for j := 0; j < _S; j++ {
+ i--
+ buf[i] = byte(d)
+ d >>= 8
+ }
+ }
+
+ for i < len(buf) && buf[i] == 0 {
+ i++
+ }
+
+ return
+}
+
+
+// setBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z nat) setBytes(buf []byte) nat {
+ z = z.make((len(buf) + _S - 1) / _S)
+
+ k := 0
+ s := uint(0)
+ var d Word
+ for i := len(buf); i > 0; i-- {
+ d |= Word(buf[i-1]) << s
+ if s += 8; s == _S*8 {
+ z[k] = d
+ k++
+ s = 0
+ d = 0
+ }
+ }
+ if k < len(z) {
+ z[k] = d
+ }
+
+ return z.norm()
+}