[Pkg-privacy-commits] [golang-ed25519-dev] 01/11: Initial import.

Ximin Luo infinity0 at moszumanska.debian.org
Sat Aug 22 12:55:25 UTC 2015


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch master
in repository golang-ed25519-dev.

commit 4117a04a6c31fb858e7341e1736ab2baf564c401
Author: Adam Langley <agl at chromium.org>
Date:   Sat Oct 6 19:57:32 2012 -0400

    Initial import.
---
 ed25519_ref.go         | 377 +++++++++++++++++++++++++++++++++++++++++++++++++
 ed25519_test.go        | 106 ++++++++++++++
 testdata/sign.input.gz | Bin 0 -> 50330 bytes
 3 files changed, 483 insertions(+)

diff --git a/ed25519_ref.go b/ed25519_ref.go
new file mode 100644
index 0000000..ef4dcdf
--- /dev/null
+++ b/ed25519_ref.go
@@ -0,0 +1,377 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ed25519 implements the Ed25519 signature algorithm. See
+// http://ed25519.cr.yp.to/.
+package ed25519
+
+import (
+	"bytes"
+	"crypto/sha512"
+	"io"
+	"math/big"
+)
+
+const (
+	PublicKeySize = 32
+	PrivateKeySize = 64
+	SignatureSize = 64
+)
+
+var (
+	// p25519 is 2**255-19, a prime number.
+	p25519 *big.Int
+	// n25521 is p-2 = 2**255-21.
+	n25521 *big.Int
+	// n2523 is (p-5)/8 = 2**252-3
+	n2523 *big.Int
+	// sqrtm1 is sqrt(-1) mod p
+	sqrtm1 *big.Int
+	// order is the order of the Twisted Edward's group: 2**252 + 27742317777372353535851937790883648493.
+	order *big.Int
+	// d is -121665/121666 mod 2**255-19, a parameter of the Twisted Edward's curve.
+	d *big.Int
+	// k is 2*d mod 2**255-19
+	k *big.Int
+	// (bX, bY) is the base point of the curve.
+	bX, bY *big.Int
+	bigOne *big.Int
+)
+
+func init() {
+	p25519, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 16)
+	n25521, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb", 16)
+	n2523, _ = new(big.Int).SetString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", 16)
+	sqrtm1, _ = new(big.Int).SetString("2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0", 16)
+	d, _ = new(big.Int).SetString("52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3", 16)
+	k, _ = new(big.Int).SetString("2406d9dc56dffce7198e80f2eef3d13000e0149a8283b156ebd69b9426b2f159", 16)
+	bX, _ = new(big.Int).SetString("216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a", 16)
+	bY, _ = new(big.Int).SetString("6666666666666666666666666666666666666666666666666666666666666658", 16)
+	order, _ = new(big.Int).SetString("7237005577332262213973186563042994240857116359379907606001950938285454250989", 10)
+	bigOne = big.NewInt(1)
+}
+
+// invert sets out = a^{-1} mod 2**255-19 by raising to the power of p-2 (see
+// Fermat's Little Theorem).
+func invert(out, a *big.Int) {
+	out.Exp(a, n25521, p25519)
+}
+
+// context is used to provide a pool of allocated big.Int's for use during
+// scalar multiplication.
+type context struct {
+	t1, t2, t3, t4, t5, t6, t7, t8 *big.Int
+}
+
+func newContext() *context {
+	return &context{
+		t1: new(big.Int),
+		t2: new(big.Int),
+		t3: new(big.Int),
+		t4: new(big.Int),
+		t5: new(big.Int),
+		t6: new(big.Int),
+		t7: new(big.Int),
+		t8: new(big.Int),
+	}
+}
+
+// GenerateKey generates a public/private key pair using randomness from rand.
+func GenerateKey(rand io.Reader) (publicKey *[PublicKeySize]byte, privateKey *[PrivateKeySize]byte, err error) {
+	privateKey = new([64]byte)
+	publicKey = new([32]byte)
+	_, err = io.ReadFull(rand, privateKey[:32])
+	if err != nil {
+		return nil, nil, err
+	}
+
+	h := sha512.New()
+	h.Write(privateKey[:32])
+	digest := h.Sum(nil)
+
+	digest[0] &= 248
+	digest[31] &= 127
+	digest[31] |= 64
+	a := scalarFrom32Bytes(digest[:32])
+	Ax, Ay := newContext().scalarMult(a, bX, bY).toAffine()
+	encodePoint(publicKey, Ax, Ay)
+
+	copy(privateKey[32:], publicKey[:])
+	return
+}
+
+// a fieldElement is a point on the Twisted Edward's curve represented in
+// extended coordinates. An affine point (x', y') is encoded as x = x'/z,
+// y = y'/z, t = x'y'/z.
+type fieldElement struct {
+	x, y, z, t *big.Int
+}
+
+func newFieldElement() *fieldElement {
+	return &fieldElement{
+		x: new(big.Int),
+		y: new(big.Int),
+		z: new(big.Int),
+		t: new(big.Int),
+	}
+}
+
+// toAffine converts from extended coordinates to affine coordinates.
+func (fe *fieldElement) toAffine() (x, y *big.Int) {
+	zInv := new(big.Int)
+	invert(zInv, fe.z)
+	x = new(big.Int).Mul(zInv, fe.x)
+	x.Mod(x, p25519)
+	y = new(big.Int).Mul(zInv, fe.y)
+	y.Mod(y, p25519)
+	return
+}
+
+// pointAdd adds two curve points, a and b, and puts a+b into out.
+// See http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
+func (c *context) pointAdd(out, a, b *fieldElement) {
+	c.t1.Sub(a.y, a.x)
+	if c.t1.Sign() < 0 {
+		c.t1.Add(c.t1, p25519)
+	}
+	c.t2.Sub(b.y, b.x)
+	if c.t2.Sign() < 0 {
+		c.t2.Add(c.t2, p25519)
+	}
+	c.t1.Mul(c.t1, c.t2) // A
+
+	c.t2.Add(a.y, a.x)
+	c.t3.Add(b.y, b.x)
+	c.t2.Mul(c.t2, c.t3) // B
+
+	c.t3.Mul(a.t, b.t)
+	c.t3.Mul(c.t3, k) // C
+
+	c.t4.Mul(a.z, b.z)
+	c.t4.Lsh(c.t4, 1) // D
+
+	c.t5.Sub(c.t2, c.t1) // E
+	if c.t5.Sign() < 0 {
+		c.t5.Add(c.t5, p25519)
+	}
+
+	c.t6.Sub(c.t4, c.t3) // F
+	if c.t6.Sign() < 0 {
+		c.t6.Add(c.t6, p25519)
+	}
+
+	c.t7.Add(c.t4, c.t3) // G
+	c.t8.Add(c.t1, c.t2) // H
+
+	out.x.Mul(c.t5, c.t6)
+	out.x.Mod(out.x, p25519)
+	out.y.Mul(c.t7, c.t8)
+	out.y.Mod(out.y, p25519)
+	out.t.Mul(c.t5, c.t8)
+	out.t.Mod(out.t, p25519)
+	out.z.Mul(c.t6, c.t7)
+	out.z.Mod(out.z, p25519)
+}
+
+// scalarMult calculates scalar*(px, py) and returns the result in extended
+// coordinates.
+func (c *context) scalarMult(scalar, px, py *big.Int) *fieldElement {
+	scalarBytes := scalar.Bytes()
+	n := newFieldElement()
+	p := newFieldElement()
+	p.x.Set(px)
+	p.y.Set(py)
+	p.z.SetInt64(1)
+	p.t.Mul(p.x, p.y)
+	n.x.SetInt64(0)
+	n.y.SetInt64(1)
+	n.z.SetInt64(1)
+	n.t.SetInt64(0)
+
+	for _, x := range scalarBytes {
+		for bit := 0; bit < 8; bit++ {
+			c.pointAdd(n, n, n)
+			if x&0x80 != 0 {
+				c.pointAdd(n, n, p)
+			}
+			x <<= 1
+		}
+	}
+
+	return n
+}
+
+// encodePoint encodes a point on the curve into 32 bytes by encoding the y
+// coordinate in the first 255 bits, followed by the parity of the
+// x-coordinate.
+func encodePoint(out *[32]byte, px, py *big.Int) {
+	b := py.Bytes()
+	for i := range b {
+		out[i] = b[len(b)-(1+i)]
+	}
+	if px.Bit(0) == 1 {
+		out[31] |= 0x80
+	}
+}
+
+// scalarFrom64Bytes interprets v as a 64-byte, little-endian number and
+// returns an element of the scalar field.
+func scalarFrom64Bytes(v []byte) *big.Int {
+	// math.big takes bytes in big-endian form so we have to reverse the
+	// bytes.
+	var reversedBytes [64]byte
+	for i := 0; i < 64; i++ {
+		reversedBytes[i] = v[63-i]
+	}
+	r := new(big.Int).SetBytes(reversedBytes[:])
+	r.Mod(r, order)
+	return r
+}
+
+// scalarFrom32Bytes interprets v as a 32-byte, little-endian number and
+// returns an element of the scalar field.
+func scalarFrom32Bytes(v []byte) *big.Int {
+	// math.big takes bytes in big-endian form so we have to reverse the
+	// bytes.
+	var reversedBytes [32]byte
+	for i := 0; i < 32; i++ {
+		reversedBytes[i] = v[31-i]
+	}
+	n := new(big.Int).SetBytes(reversedBytes[:])
+	n.Mod(n, order)
+	return n
+}
+
+// encodeScalar encodes s in to out as a 32-byte, little-endian number.
+func encodeScalar(out []byte, s *big.Int) {
+	b := s.Bytes()
+	for i := 0; i < len(b); i++ {
+		out[i] = b[len(b)-(1+i)]
+	}
+}
+
+// Sign signs the message with privateKey and returns a signature.
+func Sign(privateKey *[PrivateKeySize]byte, message []byte) *[SignatureSize]byte {
+	h := sha512.New()
+	h.Write(privateKey[:32])
+	var digestBytes1, digestBytes2, digestBytes3 [64]byte
+	expandedSecretKey := h.Sum(digestBytes1[:0])
+
+	expandedSecretKey[0] &= 248
+	expandedSecretKey[31] &= 127
+	expandedSecretKey[31] |= 64
+	a := scalarFrom32Bytes(expandedSecretKey[:32])
+
+	h.Reset()
+	h.Write(expandedSecretKey[32:])
+	h.Write(message)
+	messageDigest := h.Sum(digestBytes2[:0])
+
+	r := scalarFrom64Bytes(messageDigest)
+	Rx, Ry := newContext().scalarMult(r, bX, bY).toAffine()
+	var encodedR [32]byte
+	encodePoint(&encodedR, Rx, Ry)
+
+	h.Reset()
+	h.Write(encodedR[:])
+	h.Write(privateKey[32:])
+	h.Write(message)
+	hramDigest := h.Sum(digestBytes3[:0])
+	s := scalarFrom64Bytes(hramDigest)
+	s.Mul(s, a)
+	s.Add(s, r)
+	s.Mod(s, order)
+
+	signature := new([64]byte)
+	copy(signature[:32], encodedR[:])
+	encodeScalar(signature[32:], s)
+	return signature
+}
+
+// decodePoint unpacks a curve point, as encoded by encodePoint, and returns
+// its affine coordinates.
+func decodePoint(in *[32]byte) (x, y *big.Int, ok bool) {
+	var bigEndian [32]byte
+	for i := 0; i < 32; i++ {
+		bigEndian[i] = in[31-i]
+	}
+	bigEndian[0] &= 0x7f
+	y = new(big.Int).SetBytes(bigEndian[:])
+
+	u := new(big.Int).Mul(y, y)
+	u.Mod(u, p25519)
+	v := new(big.Int).Set(u)
+	u.Sub(u, bigOne)
+	if u.Sign() < 0 {
+		u.Add(u, p25519)
+	}
+	v.Mul(v, d)
+	v.Add(v, bigOne)
+	v.Mod(v, p25519)
+
+	v2 := new(big.Int).Mul(v, v)
+	v3 := new(big.Int).Mul(v2, v)
+	v3.Mod(v3, p25519)
+	v4 := new(big.Int).Mul(v2, v2)
+	v7 := v4.Mul(v4, v3)
+	b := v7.Mul(v7, u)
+	b.Mod(b, p25519)
+	b.Exp(b, n2523, p25519)
+	b.Mul(b, v3)
+	b.Mul(b, u)
+	b.Mod(b, p25519)
+
+	check := v2.Mul(b, b)
+	check.Mul(check, v)
+	check.Mod(check, p25519)
+	if check.Cmp(u) != 0 {
+		b.Mul(b, sqrtm1)
+		b.Mod(b, p25519)
+		check.Mul(b, b)
+		check.Mul(check, v)
+		check.Mod(check, p25519)
+	}
+
+	if check.Cmp(u) != 0 {
+		return nil, nil, false
+	}
+
+	if b.Bit(0) != uint(in[31]>>7) {
+		b.Neg(b)
+		b.Add(b, p25519)
+	}
+
+	return b, y, true
+}
+
+// Verify returns true iff sig is a valid signature of message by publicKey.
+func Verify(publicKey *[PublicKeySize]byte, message []byte, sig *[SignatureSize]byte) bool {
+	h := sha512.New()
+	h.Write(sig[:32])
+	h.Write(publicKey[:])
+	h.Write(message)
+	digest := h.Sum(nil)
+	H := scalarFrom64Bytes(digest)
+	S := scalarFrom32Bytes(sig[32:])
+
+	Ax, Ay, ok := decodePoint(publicKey)
+	if !ok {
+		return false
+	}
+
+	c := newContext()
+	SB := c.scalarMult(S, bX, bY)
+	HRAMA := c.scalarMult(H, Ax, Ay)
+	HRAMA.x.Neg(HRAMA.x)
+	HRAMA.x.Add(HRAMA.x, p25519)
+	HRAMA.t.Neg(HRAMA.t)
+	HRAMA.t.Add(HRAMA.t, p25519)
+	out := newFieldElement()
+	c.pointAdd(out, SB, HRAMA)
+	Px, Py := out.toAffine()
+
+	var rPrime [32]byte
+	encodePoint(&rPrime, Px, Py)
+	return bytes.Equal(sig[:32], rPrime[:])
+}
diff --git a/ed25519_test.go b/ed25519_test.go
new file mode 100644
index 0000000..b9580f5
--- /dev/null
+++ b/ed25519_test.go
@@ -0,0 +1,106 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ed25519
+
+import (
+	"bufio"
+	"bytes"
+	"compress/gzip"
+	"encoding/hex"
+	"io"
+	"os"
+	"strings"
+	"testing"
+)
+
+type zeroReader struct{}
+
+func (zeroReader) Read(buf []byte) (int, error) {
+	for i := range buf {
+		buf[i] = 0
+	}
+	return len(buf), nil
+}
+
+func TestSignVerify(t *testing.T) {
+	return
+	var zero zeroReader
+	public, private, _ := GenerateKey(zero)
+
+	message := []byte("test message")
+	sig := Sign(private, message)
+	if !Verify(public, message, sig) {
+		t.Errorf("valid signature rejected")
+	}
+
+	wrongMessage := []byte("wrong message")
+	if Verify(public, wrongMessage, sig) {
+		t.Errorf("signature of different message accepted")
+	}
+}
+
+func TestGolden(t *testing.T) {
+	// sign.input.gz is a selection of test cases from
+	// http://ed25519.cr.yp.to/python/sign.input
+	testDataZ, err := os.Open("testdata/sign.input.gz")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer testDataZ.Close()
+	testData, err := gzip.NewReader(testDataZ)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer testData.Close()
+
+	in := bufio.NewReaderSize(testData, 1<<12)
+	lineNo := 0
+	for {
+		lineNo++
+		lineBytes, isPrefix, err := in.ReadLine()
+		if isPrefix {
+			t.Fatal("bufio buffer too small")
+		}
+		if err != nil {
+			if err == io.EOF {
+				break
+			}
+			t.Fatalf("error reading test data: %s", err)
+		}
+
+		line := string(lineBytes)
+		parts := strings.Split(line, ":")
+		if len(parts) != 5 {
+			t.Fatalf("bad number of parts on line %d", lineNo)
+		}
+
+		privBytes, _ := hex.DecodeString(parts[0])
+		pubKeyBytes, _ := hex.DecodeString(parts[1])
+		msg, _ := hex.DecodeString(parts[2])
+		sig, _ := hex.DecodeString(parts[3])
+		// The signatures in the test vectors also include the message
+		// at the end, but we just want R and S.
+		sig = sig[:SignatureSize]
+
+		if l := len(pubKeyBytes); l != PublicKeySize {
+			t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
+		}
+
+		var priv [PrivateKeySize]byte
+		copy(priv[:], privBytes)
+		copy(priv[32:], pubKeyBytes)
+
+		sig2 := Sign(&priv, msg)
+		if !bytes.Equal(sig, sig2[:]) {
+			t.Errorf("different signature result on line %d", lineNo)
+		}
+
+		var pubKey [PublicKeySize]byte
+		copy(pubKey[:], pubKeyBytes)
+		if !Verify(&pubKey, msg, sig2) {
+			t.Errorf("signature failed to verify on line %d", lineNo)
+		}
+	}
+}
diff --git a/testdata/sign.input.gz b/testdata/sign.input.gz
new file mode 100644
index 0000000..4103069
Binary files /dev/null and b/testdata/sign.input.gz differ

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/golang-ed25519-dev.git



More information about the Pkg-privacy-commits mailing list