Commit 2dfff363 authored by lukechampine's avatar lukechampine Committed by Daniel Martí

crypto/ed25519: outline NewKeyFromSeed and Sign

This allows the returned key/signature to be stack-allocated where possible.

name              old time/op    new time/op    delta
NewKeyFromSeed-4    61.8µs ± 8%    57.2µs ±11%      ~     (p=0.056 n=5+5)
Signing-4           56.6µs ± 3%    67.8µs ±38%      ~     (p=1.000 n=5+5)

name              old alloc/op   new alloc/op   delta
NewKeyFromSeed-4     64.0B ± 0%      0.0B       -100.00%  (p=0.008 n=5+5)
Signing-4             512B ± 0%      448B ± 0%   -12.50%  (p=0.008 n=5+5)

name              old allocs/op  new allocs/op  delta
NewKeyFromSeed-4      1.00 ± 0%      0.00       -100.00%  (p=0.008 n=5+5)
Signing-4             6.00 ± 0%      5.00 ± 0%   -16.67%  (p=0.008 n=5+5)

Change-Id: I7dc6a1b8a483c4b213f380ac7c30cefc5caca0f9
GitHub-Last-Rev: 0dd2e0f93e9cd1410760544be638238f18fa5cd4
GitHub-Pull-Request: golang/go#34357
Reviewed-on: https://go-review.googlesource.com/c/go/+/195980Reviewed-by: default avatarFilippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 39ab8db9
...@@ -96,6 +96,13 @@ func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { ...@@ -96,6 +96,13 @@ func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
// with RFC 8032. RFC 8032's private keys correspond to seeds in this // with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package. // package.
func NewKeyFromSeed(seed []byte) PrivateKey { func NewKeyFromSeed(seed []byte) PrivateKey {
// Outline the function body so that the returned key can be stack-allocated.
privateKey := make([]byte, PrivateKeySize)
newKeyFromSeed(privateKey, seed)
return privateKey
}
func newKeyFromSeed(privateKey, seed []byte) {
if l := len(seed); l != SeedSize { if l := len(seed); l != SeedSize {
panic("ed25519: bad seed length: " + strconv.Itoa(l)) panic("ed25519: bad seed length: " + strconv.Itoa(l))
} }
...@@ -112,16 +119,21 @@ func NewKeyFromSeed(seed []byte) PrivateKey { ...@@ -112,16 +119,21 @@ func NewKeyFromSeed(seed []byte) PrivateKey {
var publicKeyBytes [32]byte var publicKeyBytes [32]byte
A.ToBytes(&publicKeyBytes) A.ToBytes(&publicKeyBytes)
privateKey := make([]byte, PrivateKeySize)
copy(privateKey, seed) copy(privateKey, seed)
copy(privateKey[32:], publicKeyBytes[:]) copy(privateKey[32:], publicKeyBytes[:])
return privateKey
} }
// Sign signs the message with privateKey and returns a signature. It will // Sign signs the message with privateKey and returns a signature. It will
// panic if len(privateKey) is not PrivateKeySize. // panic if len(privateKey) is not PrivateKeySize.
func Sign(privateKey PrivateKey, message []byte) []byte { func Sign(privateKey PrivateKey, message []byte) []byte {
// Outline the function body so that the returned signature can be
// stack-allocated.
signature := make([]byte, SignatureSize)
sign(signature, privateKey, message)
return signature
}
func sign(signature, privateKey, message []byte) {
if l := len(privateKey); l != PrivateKeySize { if l := len(privateKey); l != PrivateKeySize {
panic("ed25519: bad private key length: " + strconv.Itoa(l)) panic("ed25519: bad private key length: " + strconv.Itoa(l))
} }
...@@ -161,11 +173,8 @@ func Sign(privateKey PrivateKey, message []byte) []byte { ...@@ -161,11 +173,8 @@ func Sign(privateKey PrivateKey, message []byte) []byte {
var s [32]byte var s [32]byte
edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced) edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)
signature := make([]byte, SignatureSize)
copy(signature[:], encodedR[:]) copy(signature[:], encodedR[:])
copy(signature[32:], s[:]) copy(signature[32:], s[:])
return signature
} }
// Verify reports whether sig is a valid signature of message by publicKey. It // Verify reports whether sig is a valid signature of message by publicKey. It
......
...@@ -191,6 +191,14 @@ func BenchmarkKeyGeneration(b *testing.B) { ...@@ -191,6 +191,14 @@ func BenchmarkKeyGeneration(b *testing.B) {
} }
} }
func BenchmarkNewKeyFromSeed(b *testing.B) {
seed := make([]byte, SeedSize)
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = NewKeyFromSeed(seed)
}
}
func BenchmarkSigning(b *testing.B) { func BenchmarkSigning(b *testing.B) {
var zero zeroReader var zero zeroReader
_, priv, err := GenerateKey(zero) _, priv, err := GenerateKey(zero)
...@@ -198,6 +206,7 @@ func BenchmarkSigning(b *testing.B) { ...@@ -198,6 +206,7 @@ func BenchmarkSigning(b *testing.B) {
b.Fatal(err) b.Fatal(err)
} }
message := []byte("Hello, world!") message := []byte("Hello, world!")
b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
Sign(priv, message) Sign(priv, message)
......
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