summaryrefslogtreecommitdiff
path: root/vendor/github.com/cretz/bine/torutil/ed25519/ed25519.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/cretz/bine/torutil/ed25519/ed25519.go')
-rw-r--r--vendor/github.com/cretz/bine/torutil/ed25519/ed25519.go189
1 files changed, 189 insertions, 0 deletions
diff --git a/vendor/github.com/cretz/bine/torutil/ed25519/ed25519.go b/vendor/github.com/cretz/bine/torutil/ed25519/ed25519.go
new file mode 100644
index 0000000..c27378f
--- /dev/null
+++ b/vendor/github.com/cretz/bine/torutil/ed25519/ed25519.go
@@ -0,0 +1,189 @@
+// Package ed25519 implements Tor/BitTorrent-like ed25519 keys.
+//
+// See the following stack overflow post for details on why
+// golang.org/x/crypto/ed25519 can't be used:
+// https://stackoverflow.com/questions/44810708/ed25519-public-result-is-different
+package ed25519
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/sha512"
+ "errors"
+ "io"
+
+ "github.com/cretz/bine/torutil/ed25519/internal/edwards25519"
+ "golang.org/x/crypto/ed25519"
+)
+
+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. 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) KeyPair {
+ digest := sha512.Sum512(key[:32])
+ digest[0] &= 248
+ digest[31] &= 127
+ digest[31] |= 64
+ return &precomputedKeyPair{PrivateKeyBytes: digest[:], PublicKeyBytes: PublicKey(key[32:])}
+}
+
+// FromCryptoPublicKey converts a Go public key to the one in this package.
+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 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 or use KeyPair() which stores
+// this value. Implements KeyPair.PublicKey.
+func (p PrivateKey) PublicKey() PublicKey {
+ var A edwards25519.ExtendedGroupElement
+ var hBytes [32]byte
+ copy(hBytes[:], p[:])
+ edwards25519.GeScalarMultBase(&A, &hBytes)
+ var publicKeyBytes [32]byte
+ A.ToBytes(&publicKeyBytes)
+ return publicKeyBytes[:]
+}
+
+// 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")
+ }
+ 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) (KeyPair, error) {
+ if rnd == nil {
+ rnd = rand.Reader
+ }
+ rndByts := make([]byte, 32)
+ if _, err := io.ReadFull(rnd, rndByts); err != nil {
+ return nil, err
+ }
+ 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)
+}