Commit 1e3b9524 authored by Adam Langley's avatar Adam Langley

crypto/elliptic: add serialisation and key pair generation.

        This is a prerequisite to ECDHE support in crypto/tls.

R=r, rsc
CC=golang-dev
https://golang.org/cl/3685043
parent b3e8fdce
......@@ -15,15 +15,18 @@ package elliptic
import (
"big"
"io"
"os"
"sync"
)
// A Curve represents a short-form Weierstrass curve with a=-3.
// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
type Curve struct {
P *big.Int // the order of the underlying field
B *big.Int // the constant of the curve equation
Gx, Gy *big.Int // (x,y) of the base point
P *big.Int // the order of the underlying field
B *big.Int // the constant of the curve equation
Gx, Gy *big.Int // (x,y) of the base point
BitSize int // the size of the underlying field
}
// IsOnCurve returns true if the given (x,y) lies on the curve.
......@@ -241,6 +244,60 @@ func (curve *Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
return curve.ScalarMult(curve.Gx, curve.Gy, k)
}
var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
// GenerateKey returns a public/private key pair. The private key is generated
// using the given reader, which must return random data.
func (curve *Curve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err os.Error) {
byteLen := (curve.BitSize + 7) >> 3
priv = make([]byte, byteLen)
for x == nil {
_, err = io.ReadFull(rand, priv)
if err != nil {
return
}
// We have to mask off any excess bits in the case that the size of the
// underlying field is not a whole number of bytes.
priv[0] &= mask[curve.BitSize%8]
// This is because, in tests, rand will return all zeros and we don't
// want to get the point at infinity and loop forever.
priv[1] ^= 0x42
x, y = curve.ScalarBaseMult(priv)
}
return
}
// Marshal converts a point into the form specified in section 4.3.6 of ANSI
// X9.62.
func (curve *Curve) Marshal(x, y *big.Int) []byte {
byteLen := (curve.BitSize + 7) >> 3
ret := make([]byte, 1+2*byteLen)
ret[0] = 4 // uncompressed point
xBytes := x.Bytes()
copy(ret[1+byteLen-len(xBytes):], xBytes)
yBytes := y.Bytes()
copy(ret[1+2*byteLen-len(yBytes):], yBytes)
return ret
}
// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
// error, x = nil.
func (curve *Curve) Unmarshal(data []byte) (x, y *big.Int) {
byteLen := (curve.BitSize + 7) >> 3
if len(data) != 1+2*byteLen {
return
}
if data[0] != 4 { // uncompressed form
return
}
x = new(big.Int).SetBytes(data[1 : 1+byteLen])
y = new(big.Int).SetBytes(data[1+byteLen:])
return
}
var initonce sync.Once
var p224 *Curve
var p256 *Curve
......@@ -261,6 +318,7 @@ func initP224() {
p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)
p224.Gx, _ = new(big.Int).SetString("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16)
p224.Gy, _ = new(big.Int).SetString("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16)
p224.BitSize = 224
}
func initP256() {
......@@ -270,6 +328,7 @@ func initP256() {
p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
p256.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
p256.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
p256.BitSize = 256
}
func initP384() {
......@@ -279,6 +338,7 @@ func initP384() {
p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16)
p384.Gx, _ = new(big.Int).SetString("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", 16)
p384.Gy, _ = new(big.Int).SetString("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", 16)
p384.BitSize = 384
}
func initP521() {
......@@ -288,6 +348,7 @@ func initP521() {
p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16)
p521.Gx, _ = new(big.Int).SetString("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16)
p521.Gy, _ = new(big.Int).SetString("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16)
p521.BitSize = 521
}
// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2)
......
......@@ -6,6 +6,7 @@ package elliptic
import (
"big"
"crypto/rand"
"fmt"
"testing"
)
......@@ -309,3 +310,22 @@ func BenchmarkBaseMult(b *testing.B) {
p224.ScalarBaseMult(k.Bytes())
}
}
func TestMarshal(t *testing.T) {
p224 := P224()
_, x, y, err := p224.GenerateKey(rand.Reader)
if err != nil {
t.Error(err)
return
}
serialised := p224.Marshal(x, y)
xx, yy := p224.Unmarshal(serialised)
if xx == nil {
t.Error("failed to unmarshal")
return
}
if xx.Cmp(x) != 0 || yy.Cmp(y) != 0 {
t.Error("unmarshal returned different values")
return
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment