Skip to content

Commit

Permalink
Add functions to convert to curve25519 keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
agl committed Dec 22, 2013
1 parent 5613cf0 commit 8f60da0
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
41 changes: 41 additions & 0 deletions ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -2240,3 +2240,44 @@ func Verify(publicKey *[PublicKeySize]byte, message []byte, sig *[SignatureSize]
R.ToBytes(&checkR)
return bytes.Equal(sig[:32], checkR[:])
}

// PrivateKeyToCurve25519 converts an ed25519 private key into a corresponding
// curve25519 private key such that the resulting curve25519 public key will
// equal the result from PublicKeyToCurve25519.
func PrivateKeyToCurve25519(curve25519Private *[32]byte, privateKey *[PrivateKeySize]byte) {
h := sha512.New()
h.Write(privateKey[:32])
digest := h.Sum(nil)

digest[0] &= 248
digest[31] &= 127
digest[31] |= 64

copy(curve25519Private[:], digest)
}

// PublicKeyToCurve25519 converts an Ed25519 public key into the curve25519
// public key that would be generated from the same private key.
func PublicKeyToCurve25519(curve25519Public *[32]byte, publicKey *[PublicKeySize]byte) bool {
// We only need the x-coordinate of the curve25519 point, which I'll call u.
// The isomorphism is u=(y+1)/(1-y), since y=Y/Z, this gives u=(Y+Z)/(Z-Y).

var A extendedGroupElement
if !A.FromBytes(publicKey) {
return false
}

// Z=1 since we have just unpacked the public key. Thus u=(Y+1)/(1-Y).
var oneMinusY fieldElement
feOne(&oneMinusY)
feSub(&oneMinusY, &oneMinusY, &A.Y)
feInvert(&oneMinusY, &oneMinusY)

var yPlusOne fieldElement
feOne(&yPlusOne)
feAdd(&yPlusOne, &yPlusOne, &A.Y)

feMul(&yPlusOne, &yPlusOne, &oneMinusY)
feToBytes(curve25519Public, &yPlusOne)
return true
}
19 changes: 19 additions & 0 deletions ed25519_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ import (
"bufio"
"bytes"
"compress/gzip"
"crypto/rand"
"encoding/hex"
"io"
"os"
"strings"
"testing"

"code.google.com/p/go.crypto/curve25519"
)

type zeroReader struct{}
Expand Down Expand Up @@ -103,3 +106,19 @@ func TestGolden(t *testing.T) {
}
}
}

func TestCurve25519Conversion(t *testing.T) {
public, private, _ := GenerateKey(rand.Reader)

var curve25519Public, curve25519Public2, curve25519Private [32]byte
PrivateKeyToCurve25519(&curve25519Private, private)
curve25519.ScalarBaseMult(&curve25519Public, &curve25519Private)

if !PublicKeyToCurve25519(&curve25519Public2, public) {
t.Fatalf("PublicKeyToCurve25519 failed")
}

if !bytes.Equal(curve25519Public[:], curve25519Public2[:]) {
t.Errorf("Values didn't match: curve25519 produced %x, conversion produced %x", curve25519Public[:], curve25519Public2[:])
}
}

0 comments on commit 8f60da0

Please sign in to comment.