]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/ed25519: outline NewKeyFromSeed and Sign
authorlukechampine <luke.champine@gmail.com>
Fri, 20 Sep 2019 17:25:07 +0000 (17:25 +0000)
committerDaniel Martí <mvdan@mvdan.cc>
Tue, 24 Sep 2019 10:23:40 +0000 (10:23 +0000)
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/+/195980
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/crypto/ed25519/ed25519.go
src/crypto/ed25519/ed25519_test.go

index dc47e5585d6ae27efef6041629265faf3951faff..dcb4f9544f918320e110b8cc690862c9dba79728 100644 (file)
@@ -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
 // package.
 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 {
                panic("ed25519: bad seed length: " + strconv.Itoa(l))
        }
@@ -112,16 +119,21 @@ func NewKeyFromSeed(seed []byte) PrivateKey {
        var publicKeyBytes [32]byte
        A.ToBytes(&publicKeyBytes)
 
-       privateKey := make([]byte, PrivateKeySize)
        copy(privateKey, seed)
        copy(privateKey[32:], publicKeyBytes[:])
-
-       return privateKey
 }
 
 // Sign signs the message with privateKey and returns a signature. It will
 // panic if len(privateKey) is not PrivateKeySize.
 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 {
                panic("ed25519: bad private key length: " + strconv.Itoa(l))
        }
@@ -161,11 +173,8 @@ func Sign(privateKey PrivateKey, message []byte) []byte {
        var s [32]byte
        edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)
 
-       signature := make([]byte, SignatureSize)
        copy(signature[:], encodedR[:])
        copy(signature[32:], s[:])
-
-       return signature
 }
 
 // Verify reports whether sig is a valid signature of message by publicKey. It
index 9c980fceff3f1b782503b91f0417b5e78520ff7a..cacd281f1cc62b9568ed3cd7f508274b8126833b 100644 (file)
@@ -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) {
        var zero zeroReader
        _, priv, err := GenerateKey(zero)
@@ -198,6 +206,7 @@ func BenchmarkSigning(b *testing.B) {
                b.Fatal(err)
        }
        message := []byte("Hello, world!")
+       b.ReportAllocs()
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
                Sign(priv, message)