Support precomputed ed25519 public keys
This commit is contained in:
parent
c11e3bb90d
commit
00909b144c
|
@ -99,22 +99,22 @@ func (r *RSAKey) Blob() string {
|
|||
}
|
||||
|
||||
// ED25519Key is a Key for AddOnion that is a ed25519 key (i.e. v3).
|
||||
type ED25519Key ed25519.PrivateKey
|
||||
type ED25519Key struct{ ed25519.KeyPair }
|
||||
|
||||
// ED25519KeyFromBlob creates a ED25519Key for the given response blob.
|
||||
func ED25519KeyFromBlob(blob string) (ED25519Key, error) {
|
||||
func ED25519KeyFromBlob(blob string) (*ED25519Key, error) {
|
||||
byts, err := base64.StdEncoding.DecodeString(blob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ED25519Key(ed25519.PrivateKey(byts)), nil
|
||||
return &ED25519Key{ed25519.PrivateKey(byts).KeyPair()}, nil
|
||||
}
|
||||
|
||||
// Type implements Key.Type.
|
||||
func (ED25519Key) Type() KeyType { return KeyTypeED25519V3 }
|
||||
func (*ED25519Key) Type() KeyType { return KeyTypeED25519V3 }
|
||||
|
||||
// Blob implements Key.Blob.
|
||||
func (e ED25519Key) Blob() string { return base64.StdEncoding.EncodeToString(e) }
|
||||
func (e *ED25519Key) Blob() string { return base64.StdEncoding.EncodeToString(e.PrivateKey()) }
|
||||
|
||||
// AddOnionRequest is a set of request params for AddOnion.
|
||||
type AddOnionRequest struct {
|
||||
|
|
|
@ -11,12 +11,14 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var torEnabled bool
|
||||
var torExePath string
|
||||
var torVerbose bool
|
||||
var torIncludeNetworkTests bool
|
||||
var globalEnabledNetworkContext *TestContext
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
flag.BoolVar(&torEnabled, "tor", false, "Whether any of the integration tests are enabled")
|
||||
flag.StringVar(&torExePath, "tor.path", "tor", "The Tor exe path")
|
||||
flag.BoolVar(&torVerbose, "tor.verbose", false, "Show verbose test info")
|
||||
flag.BoolVar(&torIncludeNetworkTests, "tor.network", false, "Include network tests")
|
||||
|
@ -29,14 +31,10 @@ func TestMain(m *testing.M) {
|
|||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
func SkipIfExcludingNetworkTests(t *testing.T) {
|
||||
if !torIncludeNetworkTests {
|
||||
t.Skip("Only runs if -tor.network is set")
|
||||
}
|
||||
}
|
||||
|
||||
func GlobalEnabledNetworkContext(t *testing.T) *TestContext {
|
||||
SkipIfExcludingNetworkTests(t)
|
||||
if !torEnabled || !torIncludeNetworkTests {
|
||||
t.Skip("Only runs if -tor and -tor.network is set")
|
||||
}
|
||||
if globalEnabledNetworkContext == nil {
|
||||
ctx := NewTestContext(t, nil)
|
||||
ctx.CloseTorOnClose = false
|
||||
|
@ -61,6 +59,9 @@ type TestContext struct {
|
|||
}
|
||||
|
||||
func NewTestContext(t *testing.T, conf *tor.StartConf) *TestContext {
|
||||
if !torEnabled {
|
||||
t.Skip("Only runs if -tor is set")
|
||||
}
|
||||
// Build start conf
|
||||
if conf == nil {
|
||||
conf = &tor.StartConf{}
|
||||
|
|
|
@ -21,7 +21,7 @@ type OnionService struct {
|
|||
// Key is the private key for this service. It is either the set key, the
|
||||
// generated key, or nil if asked to discard the key. If present, it is
|
||||
// *crypto/rsa.PrivateKey (1024 bit) when Version3 is false or
|
||||
// github.com/cretz/bine/torutil/ed25519.PrivateKey when Version3 is true.
|
||||
// github.com/cretz/bine/torutil/ed25519.KeyPair when Version3 is true.
|
||||
Key crypto.PrivateKey
|
||||
|
||||
// Version3 says whether or not this service is a V3 service.
|
||||
|
@ -66,7 +66,7 @@ type ListenConf struct {
|
|||
// Key is the private key to use. If not present, a key is generated based
|
||||
// on whether Version3 is true or false. If present, it must be a
|
||||
// *crypto/rsa.PrivateKey (1024 bit), a
|
||||
// github.com/cretz/bine/torutil/ed25519.PrivateKey, a
|
||||
// github.com/cretz/bine/torutil/ed25519.KeyPair, a
|
||||
// golang.org/x/crypto/ed25519.PrivateKey, or a
|
||||
// github.com/cretz/bine/control.Key.
|
||||
Key crypto.PrivateKey
|
||||
|
@ -179,17 +179,17 @@ func (t *Tor) Listen(ctx context.Context, conf *ListenConf) (*OnionService, erro
|
|||
} else {
|
||||
req.Key = key
|
||||
}
|
||||
case ed25519.PrivateKey:
|
||||
case ed25519.KeyPair:
|
||||
svc.Key = key
|
||||
svc.Version3 = true
|
||||
req.Key = control.ED25519Key(key)
|
||||
req.Key = &control.ED25519Key{key}
|
||||
case othered25519.PrivateKey:
|
||||
properKey := ed25519.FromCryptoPrivateKey(key)
|
||||
svc.Key = properKey
|
||||
svc.Version3 = true
|
||||
req.Key = control.ED25519Key(properKey)
|
||||
case control.ED25519Key:
|
||||
svc.Key = ed25519.PrivateKey(key)
|
||||
req.Key = &control.ED25519Key{properKey}
|
||||
case *control.ED25519Key:
|
||||
svc.Key = key.KeyPair
|
||||
svc.Version3 = true
|
||||
req.Key = key
|
||||
default:
|
||||
|
@ -235,8 +235,8 @@ func (t *Tor) Listen(ctx context.Context, conf *ListenConf) (*OnionService, erro
|
|||
// Do nothing
|
||||
case *control.RSAKey:
|
||||
svc.Key = key.PrivateKey
|
||||
case control.ED25519Key:
|
||||
svc.Key = ed25519.PrivateKey(key)
|
||||
case *control.ED25519Key:
|
||||
svc.Key = key.KeyPair
|
||||
default:
|
||||
err = fmt.Errorf("Unrecognized result key type: %T", key)
|
||||
}
|
||||
|
|
|
@ -16,21 +16,31 @@ import (
|
|||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
// Ref: https://stackoverflow.com/questions/44810708/ed25519-public-result-is-different
|
||||
const (
|
||||
// PublicKeySize is the size, in bytes, of public keys as used in this package.
|
||||
PublicKeySize = 32
|
||||
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
|
||||
PrivateKeySize = 64
|
||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||
SignatureSize = 64
|
||||
)
|
||||
|
||||
// PrivateKey is a 64-byte Ed25519 private key.
|
||||
// PrivateKey is a 64-byte Ed25519 private key. Unlike
|
||||
// golang.org/x/crypto/ed25519, this is just the digest and does not contain
|
||||
// the public key within it. Instead call PublicKey() or better, call KeyPair()
|
||||
// which stores the precomputed public key.
|
||||
type PrivateKey []byte
|
||||
|
||||
// PublicKey is a 32-byte Ed25519 public key.
|
||||
type PublicKey []byte
|
||||
|
||||
// FromCryptoPrivateKey converts a Go private key to the one in this package.
|
||||
func FromCryptoPrivateKey(key ed25519.PrivateKey) PrivateKey {
|
||||
func FromCryptoPrivateKey(key ed25519.PrivateKey) KeyPair {
|
||||
digest := sha512.Sum512(key[:32])
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
return digest[:]
|
||||
return &precomputedKeyPair{PrivateKeyBytes: digest[:], PublicKeyBytes: PublicKey(key[32:])}
|
||||
}
|
||||
|
||||
// FromCryptoPublicKey converts a Go public key to the one in this package.
|
||||
|
@ -38,16 +48,24 @@ func FromCryptoPublicKey(key ed25519.PublicKey) PublicKey {
|
|||
return PublicKey(key)
|
||||
}
|
||||
|
||||
// KeyPair returns a new key pair with the public key precomputed.
|
||||
func (p PrivateKey) KeyPair() KeyPair {
|
||||
return &precomputedKeyPair{PrivateKeyBytes: p, PublicKeyBytes: p.PublicKey()}
|
||||
}
|
||||
|
||||
// PrivateKey simply returns itself. Implements KeyPair.PrivateKey.
|
||||
func (p PrivateKey) PrivateKey() PrivateKey { return p }
|
||||
|
||||
// Public simply delegates to PublicKey() to satisfy crypto.Signer. This method
|
||||
// does a bit more work than the traditional Go ed25519's private key's Public()
|
||||
// method so developers are encouraged to reuse the result.
|
||||
func (p PrivateKey) Public() crypto.PublicKey {
|
||||
return p.PublicKey()
|
||||
}
|
||||
// method so developers are encouraged to reuse the result or use KeyPair()
|
||||
// which stores this value.
|
||||
func (p PrivateKey) Public() crypto.PublicKey { return p.PublicKey() }
|
||||
|
||||
// PublicKey generates a public key for this private key. This method does a bit
|
||||
// more work than the traditional Go ed25519's private key's Public() method so
|
||||
// developers are encouraged to reuse the result.
|
||||
// developers are encouraged to reuse the result or use KeyPair() which stores
|
||||
// this value. Implements KeyPair.PublicKey.
|
||||
func (p PrivateKey) PublicKey() PublicKey {
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
var hBytes [32]byte
|
||||
|
@ -58,28 +76,114 @@ func (p PrivateKey) PublicKey() PublicKey {
|
|||
return publicKeyBytes[:]
|
||||
}
|
||||
|
||||
// Sign is not yet implemented.
|
||||
func (p PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
|
||||
// Sign signs the given message with priv. Ed25519 performs two passes over
|
||||
// messages to be signed and therefore cannot handle pre-hashed messages. Thus
|
||||
// opts.HashFunc() must return zero to indicate the message hasn't been hashed.
|
||||
// This can be achieved by passing crypto.Hash(0) as the value for opts.
|
||||
func (p PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
if opts.HashFunc() != crypto.Hash(0) {
|
||||
return nil, errors.New("ed25519: cannot sign hashed message")
|
||||
}
|
||||
panic("TODO")
|
||||
return Sign(p, message), nil
|
||||
}
|
||||
|
||||
// Verify simply calls PublicKey().Verify(). Callers are encouraged to instead
|
||||
// store a precomputed KeyPair (via KeyPair() or GenerateKey()) and call Verify
|
||||
// on that.
|
||||
func (p PrivateKey) Verify(message []byte, sig []byte) bool {
|
||||
return p.PublicKey().Verify(message, sig)
|
||||
}
|
||||
|
||||
// Verify simply calls the package-level function Verify().
|
||||
func (p PublicKey) Verify(message []byte, sig []byte) bool {
|
||||
return Verify(p, message, sig)
|
||||
}
|
||||
|
||||
// KeyPair is an interface for types with both keys. While PrivateKey does
|
||||
// implement this, it generates the PublicKey on demand. For better performance,
|
||||
// use the result of GenerateKey directly or call PrivateKey.KeyPair().
|
||||
type KeyPair interface {
|
||||
crypto.Signer
|
||||
PrivateKey() PrivateKey
|
||||
PublicKey() PublicKey
|
||||
Verify(message []byte, sig []byte) bool
|
||||
}
|
||||
|
||||
type precomputedKeyPair struct {
|
||||
PrivateKeyBytes PrivateKey
|
||||
PublicKeyBytes PublicKey
|
||||
}
|
||||
|
||||
func (p *precomputedKeyPair) PrivateKey() PrivateKey { return p.PrivateKeyBytes }
|
||||
func (p *precomputedKeyPair) PublicKey() PublicKey { return p.PublicKeyBytes }
|
||||
func (p *precomputedKeyPair) Public() crypto.PublicKey { return p.PublicKey() }
|
||||
func (p *precomputedKeyPair) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
if opts.HashFunc() != crypto.Hash(0) {
|
||||
return nil, errors.New("ed25519: cannot sign hashed message")
|
||||
}
|
||||
return Sign(p, message), nil
|
||||
}
|
||||
func (p *precomputedKeyPair) Verify(message []byte, sig []byte) bool {
|
||||
return p.PublicKeyBytes.Verify(message, sig)
|
||||
}
|
||||
|
||||
// GenerateKey generates a public/private key pair using entropy from rand.
|
||||
// If rand is nil, crypto/rand.Reader will be used.
|
||||
func GenerateKey(rnd io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) {
|
||||
func GenerateKey(rnd io.Reader) (KeyPair, error) {
|
||||
if rnd == nil {
|
||||
rnd = rand.Reader
|
||||
}
|
||||
_, err = io.ReadFull(rnd, privateKey[:32])
|
||||
if err == nil {
|
||||
digest := sha512.Sum512(privateKey[:32])
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
privateKey = digest[:]
|
||||
publicKey = privateKey.PublicKey()
|
||||
rndByts := make([]byte, 32)
|
||||
if _, err := io.ReadFull(rnd, rndByts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
digest := sha512.Sum512(rndByts)
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
return PrivateKey(digest[:]).KeyPair(), nil
|
||||
}
|
||||
|
||||
// Sign signs the message with the given key pair.
|
||||
func Sign(keyPair KeyPair, message []byte) []byte {
|
||||
// Ref: https://stackoverflow.com/questions/44810708/ed25519-public-result-is-different
|
||||
|
||||
var privateKeyA [32]byte
|
||||
copy(privateKeyA[:], keyPair.PrivateKey()) // we need this in an array later
|
||||
var messageDigest, hramDigest [64]byte
|
||||
|
||||
h := sha512.New()
|
||||
h.Write(keyPair.PrivateKey()[32:])
|
||||
h.Write(message)
|
||||
h.Sum(messageDigest[:0])
|
||||
|
||||
var messageDigestReduced [32]byte
|
||||
edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
|
||||
var R edwards25519.ExtendedGroupElement
|
||||
edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
|
||||
|
||||
var encodedR [32]byte
|
||||
R.ToBytes(&encodedR)
|
||||
|
||||
h.Reset()
|
||||
h.Write(encodedR[:])
|
||||
h.Write(keyPair.PublicKey())
|
||||
h.Write(message)
|
||||
h.Sum(hramDigest[:0])
|
||||
var hramDigestReduced [32]byte
|
||||
edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
|
||||
|
||||
var s [32]byte
|
||||
edwards25519.ScMulAdd(&s, &hramDigestReduced, &privateKeyA, &messageDigestReduced)
|
||||
|
||||
signature := make([]byte, 64)
|
||||
copy(signature[:], encodedR[:])
|
||||
copy(signature[32:], s[:])
|
||||
|
||||
return signature
|
||||
}
|
||||
|
||||
// Verify verifies a signed message.
|
||||
func Verify(p PublicKey, message []byte, sig []byte) bool {
|
||||
return ed25519.Verify(ed25519.PublicKey(p), message, sig)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
package ed25519
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cretz/bine/torutil/ed25519/internal/edwards25519"
|
||||
)
|
||||
|
||||
// Taken from https://github.com/golang/crypto/blob/1a580b3eff7814fc9b40602fd35256c63b50f491/ed25519/ed25519_test.go
|
||||
|
||||
type zeroReader struct{}
|
||||
|
||||
func (zeroReader) Read(buf []byte) (int, error) {
|
||||
for i := range buf {
|
||||
buf[i] = 0
|
||||
}
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func TestUnmarshalMarshal(t *testing.T) {
|
||||
pair, _ := GenerateKey(rand.Reader)
|
||||
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
var pubBytes [32]byte
|
||||
copy(pubBytes[:], pair.PublicKey())
|
||||
if !A.FromBytes(&pubBytes) {
|
||||
t.Fatalf("ExtendedGroupElement.FromBytes failed")
|
||||
}
|
||||
|
||||
var pub2 [32]byte
|
||||
A.ToBytes(&pub2)
|
||||
|
||||
if pubBytes != pub2 {
|
||||
t.Errorf("FromBytes(%v)->ToBytes does not round-trip, got %x\n", pubBytes, pub2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignVerify(t *testing.T) {
|
||||
var zero zeroReader
|
||||
pair, _ := GenerateKey(zero)
|
||||
|
||||
message := []byte("test message")
|
||||
sig := Sign(pair, message)
|
||||
if !Verify(pair.PublicKey(), message, sig) {
|
||||
t.Errorf("valid signature rejected")
|
||||
}
|
||||
|
||||
wrongMessage := []byte("wrong message")
|
||||
if Verify(pair.PublicKey(), wrongMessage, sig) {
|
||||
t.Errorf("signature of different message accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCryptoSigner(t *testing.T) {
|
||||
var zero zeroReader
|
||||
pair, _ := GenerateKey(zero)
|
||||
|
||||
signer := crypto.Signer(pair)
|
||||
|
||||
publicInterface := signer.Public()
|
||||
public2, ok := publicInterface.(PublicKey)
|
||||
if !ok {
|
||||
t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
|
||||
}
|
||||
|
||||
if !bytes.Equal(pair.PublicKey(), public2) {
|
||||
t.Errorf("public keys do not match: original:%x vs Public():%x", pair.PublicKey(), public2)
|
||||
}
|
||||
|
||||
message := []byte("message")
|
||||
var noHash crypto.Hash
|
||||
signature, err := signer.Sign(zero, message, noHash)
|
||||
if err != nil {
|
||||
t.Fatalf("error from Sign(): %s", err)
|
||||
}
|
||||
|
||||
if !Verify(pair.PublicKey(), message, signature) {
|
||||
t.Errorf("Verify failed on signature from Sign()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGolden(t *testing.T) {
|
||||
// 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")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer testDataZ.Close()
|
||||
testData, err := gzip.NewReader(testDataZ)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer testData.Close()
|
||||
|
||||
scanner := bufio.NewScanner(testData)
|
||||
lineNo := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
lineNo++
|
||||
|
||||
line := scanner.Text()
|
||||
parts := strings.Split(line, ":")
|
||||
if len(parts) != 5 {
|
||||
t.Fatalf("bad number of parts on line %d", lineNo)
|
||||
}
|
||||
|
||||
privBytes, _ := hex.DecodeString(parts[0])
|
||||
pubKey, _ := 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(pubKey); l != PublicKeySize {
|
||||
t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
|
||||
}
|
||||
|
||||
var otherPriv [PrivateKeySize]byte
|
||||
copy(otherPriv[:], privBytes)
|
||||
copy(otherPriv[32:], pubKey)
|
||||
priv := FromCryptoPrivateKey(otherPriv[:])
|
||||
|
||||
sig2 := Sign(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) {
|
||||
t.Errorf("signature failed to verify on line %d", lineNo)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
t.Fatalf("error reading test data: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMalleability(t *testing.T) {
|
||||
// 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.
|
||||
msg := []byte{0x54, 0x65, 0x73, 0x74}
|
||||
sig := []byte{
|
||||
0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
|
||||
0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
|
||||
0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
|
||||
0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
|
||||
0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
|
||||
0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
|
||||
}
|
||||
publicKey := []byte{
|
||||
0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
|
||||
0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
|
||||
0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
|
||||
}
|
||||
|
||||
if Verify(publicKey, msg, sig) {
|
||||
t.Fatal("non-canonical signature accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKeyGeneration(b *testing.B) {
|
||||
var zero zeroReader
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := GenerateKey(zero); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSigning(b *testing.B) {
|
||||
var zero zeroReader
|
||||
pair, err := GenerateKey(zero)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
message := []byte("Hello, world!")
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sign(pair, message)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkVerification(b *testing.B) {
|
||||
var zero zeroReader
|
||||
pair, err := GenerateKey(zero)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
message := []byte("Hello, world!")
|
||||
signature := Sign(pair, message)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Verify(pair.PublicKey(), message, signature)
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -17,12 +17,12 @@ var serviceIDEncoding = base32.StdEncoding.WithPadding(base32.NoPadding)
|
|||
|
||||
// OnionServiceIDFromPrivateKey generates the onion service ID from the given
|
||||
// private key. This panics if the private key is not a crypto/*rsa.PrivateKey
|
||||
// or github.com/cretz/bine/torutil/ed25519.PrivateKey.
|
||||
// or github.com/cretz/bine/torutil/ed25519.KeyPair.
|
||||
func OnionServiceIDFromPrivateKey(key crypto.PrivateKey) string {
|
||||
switch k := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return OnionServiceIDFromV2PublicKey(&k.PublicKey)
|
||||
case ed25519.PrivateKey:
|
||||
case ed25519.KeyPair:
|
||||
return OnionServiceIDFromV3PublicKey(k.PublicKey())
|
||||
}
|
||||
panic(fmt.Sprintf("Unrecognized private key type: %T", key))
|
||||
|
|
Loading…
Reference in New Issue