return signature
}
-func sign(signature, privateKey, message []byte) {
+func signGeneric(signature, privateKey, message []byte) {
if l := len(privateKey); l != PrivateKeySize {
panic("ed25519: bad private key length: " + strconv.Itoa(l))
}
// Verify reports whether sig is a valid signature of message by publicKey. It
// will panic if len(publicKey) is not PublicKeySize.
func Verify(publicKey PublicKey, message, sig []byte) bool {
+ return verify(publicKey, message, sig)
+}
+
+func verifyGeneric(publicKey PublicKey, message, sig []byte) bool {
if l := len(publicKey); l != PublicKeySize {
panic("ed25519: bad public key length: " + strconv.Itoa(l))
}
--- /dev/null
+// Copyright 2020 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.
+
+// +build !s390x purego
+
+package ed25519
+
+func sign(signature, privateKey, message []byte) {
+ signGeneric(signature, privateKey, message)
+}
+
+func verify(publicKey PublicKey, message, sig []byte) bool {
+ return verifyGeneric(publicKey, message, sig)
+}
--- /dev/null
+// Copyright 2020 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.
+
+// +build !purego
+
+package ed25519
+
+import (
+ "internal/cpu"
+ "strconv"
+)
+
+//go:noescape
+func kdsaSign(message, signature, privateKey []byte) bool
+
+//go:noescape
+func kdsaVerify(message, signature, publicKey []byte) bool
+
+// sign does a check to see if hardware has Edwards Curve instruction available.
+// If it does, use the hardware implementation. Otherwise, use the generic version.
+func sign(signature, privateKey, message []byte) {
+ if cpu.S390X.HasEDDSA {
+ if l := len(privateKey); l != PrivateKeySize {
+ panic("ed25519: bad private key length: " + strconv.Itoa(l))
+ }
+
+ ret := kdsaSign(message, signature, privateKey[:32])
+ if !ret {
+ panic("ed25519: kdsa sign has a failure")
+ }
+ return
+ }
+ signGeneric(signature, privateKey, message)
+}
+
+// verify does a check to see if hardware has Edwards Curve instruction available.
+// If it does, use the hardware implementation for eddsa verfication. Otherwise, the generic
+// version is used
+func verify(publicKey PublicKey, message, sig []byte) bool {
+ if cpu.S390X.HasEDDSA {
+ if l := len(publicKey); l != PublicKeySize {
+ panic("ed25519: bad public key length: " + strconv.Itoa(l))
+ }
+
+ if len(sig) != SignatureSize || sig[63]&224 != 0 {
+ return false
+ }
+
+ return kdsaVerify(message, sig, publicKey)
+ }
+ return verifyGeneric(publicKey, message, sig)
+}
--- /dev/null
+// Copyright 2020 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.
+
+// +build !purego
+
+#include "textflag.h"
+
+// func kdsaSign(message, signature, privateKey []byte) bool
+TEXT ·kdsaSign(SB), $4096-73
+ // The kdsa instruction takes function code,
+ // buffer's location, message's location and message len
+ // as parameters. Out of those, the function code and buffer's location
+ // should be placed in R0 and R1 respectively. The message's location
+ // and message length should be placed in an even-odd register pair. (e.g: R2 and R3)
+
+ // The content of parameter block(buffer) looks like the following:
+ // Signature R, Signature S and Private Key all take 32 bytes.
+ // In the signing case, the signatures(R and S) will be generated by
+ // the signing instruction and get placed in the locations shown in the parameter block.
+ // 0 +---------------+
+ // | Signature(R) |
+ // 32 +---------------+
+ // | Signature(S) |
+ // 64 +---------------+
+ // | Private Key |
+ // 96 +---------------+
+ // | Reserved |
+ // 112+---------------+
+ // | |
+ // | ... |
+ // | |
+ // 4088 +---------------+
+
+ // The following code section setups the buffer from stack:
+ // Get the address of the buffer stack variable.
+ MOVD $buffer-4096(SP), R1
+
+ // Zero the buffer.
+ MOVD R1, R2
+ MOVD $(4096/256), R0 // number of 256 byte chunks to clear
+
+clear:
+ XC $256, (R2), (R2)
+ MOVD $256(R2), R2
+ BRCTG R0, clear
+
+ MOVD $40, R0 // EDDSA-25519 sign has a function code of 40
+ LMG message+0(FP), R2, R3 // R2=base R3=len
+ LMG signature+24(FP), R4, R5 // R4=base R5=len
+ LMG privateKey+48(FP), R6, R7 // R6=base R7=len
+
+ // Checks the length of signature and private key
+ CMPBNE R5, $64, panic
+ CMPBNE R7, $32, panic
+
+ // The instruction uses RFC 8032's private key, which is the first 32 bytes
+ // of the private key in this package. So we copy that into the buffer.
+ MVC $32, (R6), 64(R1)
+
+loop:
+ WORD $0xB93A0002 // The KDSA instruction
+ BVS loop // The instruction is exectued by hardware and can be interrupted. This does a retry when that happens.
+ BNE error
+
+success:
+ // The signatures generated are in big-endian form, so we
+ // need to reverse the bytes of Signature(R) and Signature(S) in the buffers to transform
+ // them from big-endian to little-endian.
+
+ // Transform Signature(R) from big endian to little endian and copy into the signature
+ MVCIN $32, 31(R1), (R4)
+
+ // Transform Signature(S) from big endian to little endian and copy into the signature
+ MVCIN $32, 63(R1), 32(R4)
+
+ MOVB $1, ret+72(FP)
+ RET
+
+error:
+ // return false
+ MOVB $0, ret+72(FP)
+ RET
+
+panic:
+ UNDEF
+
+// func kdsaVerify(message, signature, publicKey []byte) bool
+TEXT ·kdsaVerify(SB), $4096-73
+ // The kdsa instruction takes function code,
+ // buffer's location, message's location and message len
+ // as parameters. Out of those, the function code and buffer's location
+ // should be placed in R0 and R1 respectively. The message's location
+ // and message length should be placed in an even-odd register pair. (e.g: R2 and R3)
+
+ // The parameter block(buffer) is similar to that of signing, except that
+ // we use public key for verification, and Signatures(R and S) are provided
+ // as input parameters to the parameter block.
+ // 0 +---------------+
+ // | Signature(R) |
+ // 32 +---------------+
+ // | Signature(S) |
+ // 64 +---------------+
+ // | Public Key |
+ // 96 +---------------+
+ // | Reserved |
+ // 112+---------------+
+ // | |
+ // | ... |
+ // | |
+ // 4088 +---------------+
+
+ // The following code section setups the buffer from stack:
+ // Get the address of the buffer stack variable.
+ MOVD $buffer-4096(SP), R1
+
+ // Zero the buffer.
+ MOVD R1, R2
+ MOVD $(4096/256), R0 // number of 256 byte chunks to clear
+
+clear:
+ XC $256, (R2), (R2)
+ MOVD $256(R2), R2
+ BRCTG R0, clear
+
+ MOVD $32, R0 // EDDSA-25519 verify has a function code of 32
+ LMG message+0(FP), R2, R3 // R2=base R3=len
+ LMG signature+24(FP), R4, R5 // R4=base R5=len
+ LMG publicKey+48(FP), R6, R7 // R6=base R7=len
+
+ // Checks the length of public key and signature
+ CMPBNE R5, $64, panic
+ CMPBNE R7, $32, panic
+
+verify:
+ // The instruction needs Signature(R), Signature(S) and public key
+ // to be in big-endian form during computation. Therefore,
+ // we do the transformation (from little endian to big endian) and copy those into the buffer.
+
+ // Transform Signature(R) from little endian to big endian and copy into the buffer
+ MVCIN $32, 31(R4), (R1)
+
+ // Transform Signature(S) from little endian to big endian and copy into the buffer
+ MVCIN $32, 63(R4), 32(R1)
+
+ // Transform Public Key from little endian to big endian and copy into the buffer
+ MVCIN $32, 31(R6), 64(R1)
+
+verifyLoop:
+ WORD $0xB93A0002 // KDSA instruction
+ BVS verifyLoop // Retry upon hardware interrupt
+ BNE error
+
+success:
+ MOVB $1, ret+72(FP)
+ RET
+
+error:
+ MOVB $0, ret+72(FP)
+ RET
+
+panic:
+ UNDEF
return len(buf), nil
}
+// signGenericWrapper is identical to Sign except that it unconditionally calls signGeneric directly
+// rather than going through the sign function that might call assembly code.
+func signGenericWrapper(privateKey PrivateKey, msg []byte) []byte {
+ sig := make([]byte, SignatureSize)
+ signGeneric(sig, privateKey, msg)
+ return sig
+}
+
func TestUnmarshalMarshal(t *testing.T) {
pub, _, _ := GenerateKey(rand.Reader)
}
func TestSignVerify(t *testing.T) {
+ t.Run("Generic", func(t *testing.T) { testSignVerify(t, signGenericWrapper, verifyGeneric) })
+ t.Run("Native", func(t *testing.T) { testSignVerify(t, Sign, Verify) })
+}
+
+func testSignVerify(t *testing.T, signImpl func(privateKey PrivateKey, message []byte) []byte,
+ verifyImpl func(publicKey PublicKey, message, sig []byte) bool) {
var zero zeroReader
public, private, _ := GenerateKey(zero)
message := []byte("test message")
- sig := Sign(private, message)
- if !Verify(public, message, sig) {
+ sig := signImpl(private, message)
+ if !verifyImpl(public, message, sig) {
t.Errorf("valid signature rejected")
}
wrongMessage := []byte("wrong message")
- if Verify(public, wrongMessage, sig) {
+ if verifyImpl(public, wrongMessage, sig) {
t.Errorf("signature of different message accepted")
}
}
func TestCryptoSigner(t *testing.T) {
+ t.Run("Generic", func(t *testing.T) { testCryptoSigner(t, verifyGeneric) })
+ t.Run("Native", func(t *testing.T) { testCryptoSigner(t, Verify) })
+}
+
+func testCryptoSigner(t *testing.T, verifyImpl func(publicKey PublicKey, message, sig []byte) bool) {
var zero zeroReader
public, private, _ := GenerateKey(zero)
t.Fatalf("error from Sign(): %s", err)
}
- if !Verify(public, message, signature) {
+ if !verifyImpl(public, message, signature) {
t.Errorf("Verify failed on signature from Sign()")
}
}
}
func TestGolden(t *testing.T) {
+ t.Run("Generic", func(t *testing.T) { testGolden(t, signGenericWrapper, verifyGeneric) })
+ t.Run("Native", func(t *testing.T) { testGolden(t, Sign, Verify) })
+}
+
+func testGolden(t *testing.T, signImpl func(privateKey PrivateKey, message []byte) []byte,
+ verifyImpl func(publicKey PublicKey, message, sig []byte) bool) {
// sign.input.gz is a selection of test cases from
// https://ed25519.cr.yp.to/python/sign.input
testDataZ, err := os.Open("testdata/sign.input.gz")
copy(priv[:], privBytes)
copy(priv[32:], pubKey)
- sig2 := Sign(priv[:], msg)
+ sig2 := signImpl(priv[:], msg)
if !bytes.Equal(sig, sig2[:]) {
t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
}
- if !Verify(pubKey, msg, sig2) {
+ if !verifyImpl(pubKey, msg, sig2) {
t.Errorf("signature failed to verify on line %d", lineNo)
}
}
func TestMalleability(t *testing.T) {
+ t.Run("Generic", func(t *testing.T) { testMalleability(t, verifyGeneric) })
+ t.Run("Native", func(t *testing.T) { testMalleability(t, Verify) })
+}
+
+func testMalleability(t *testing.T, verifyImpl func(publicKey PublicKey, message, sig []byte) bool) {
// https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test
// that s be in [0, order). This prevents someone from adding a multiple of
// order to s and obtaining a second valid signature for the same message.
0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
}
- if Verify(publicKey, msg, sig) {
+ if verifyImpl(publicKey, msg, sig) {
t.Fatal("non-canonical signature accepted")
}
}