DataHoarder
e258da67dd
All checks were successful
continuous-integration/drone/push Build is passing
122 lines
3.8 KiB
Go
122 lines
3.8 KiB
Go
package ed25519
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto"
|
|
goEd25519 "crypto/ed25519"
|
|
"crypto/sha512"
|
|
"errors"
|
|
"filippo.io/edwards25519"
|
|
"io"
|
|
"strconv"
|
|
)
|
|
|
|
type PrivateKey []byte
|
|
type PublicKey goEd25519.PublicKey
|
|
|
|
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 = PrivateKeyFormSize + PublicKeySize
|
|
PrivateKeyFormSize = 64
|
|
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
|
SignatureSize = 64
|
|
)
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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 (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
|
|
if opts.HashFunc() != crypto.Hash(0) {
|
|
return nil, errors.New("ed25519: cannot sign hashed message")
|
|
}
|
|
|
|
return Sign(priv, message), nil
|
|
}
|
|
|
|
func sign(signature, privateKey, message []byte) {
|
|
if l := len(privateKey); l != PrivateKeySize {
|
|
panic("ed25519: bad private key length: " + strconv.Itoa(l))
|
|
}
|
|
privateKey, publicKey := privateKey[:PrivateKeyFormSize], privateKey[PrivateKeyFormSize:]
|
|
|
|
s, _ := edwards25519.NewScalar().SetBytesWithClamping(privateKey[:32])
|
|
prefix := privateKey[32:]
|
|
|
|
mh := sha512.New()
|
|
mh.Write(prefix)
|
|
mh.Write(message)
|
|
messageDigest := make([]byte, 0, sha512.Size)
|
|
messageDigest = mh.Sum(messageDigest)
|
|
r, _ := edwards25519.NewScalar().SetUniformBytes(messageDigest)
|
|
|
|
R := (&edwards25519.Point{}).ScalarBaseMult(r)
|
|
|
|
kh := sha512.New()
|
|
kh.Write(R.Bytes())
|
|
kh.Write(publicKey)
|
|
kh.Write(message)
|
|
hramDigest := make([]byte, 0, sha512.Size)
|
|
hramDigest = kh.Sum(hramDigest)
|
|
k, _ := edwards25519.NewScalar().SetUniformBytes(hramDigest)
|
|
|
|
S := edwards25519.NewScalar().MultiplyAdd(k, s, r)
|
|
|
|
copy(signature[:32], R.Bytes())
|
|
copy(signature[32:], S.Bytes())
|
|
}
|
|
|
|
// 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 goEd25519.Verify(goEd25519.PublicKey(publicKey), message, sig)
|
|
}
|
|
|
|
// NewKeyFromSeed calculates a private key from a seed. It will panic if
|
|
// len(seed) is not SeedSize. This function is provided for interoperability
|
|
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
|
|
// package.
|
|
func NewKeyFromSeed(seed []byte) PrivateKey {
|
|
return NewKeyFromStandard(goEd25519.NewKeyFromSeed(seed))
|
|
}
|
|
|
|
// GenerateKey generates a public/private key pair using entropy from rand.
|
|
// If rand is nil, crypto/rand.Reader will be used.
|
|
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
|
|
publicKey, privateKey, err := goEd25519.GenerateKey(rand)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return PublicKey(publicKey), NewKeyFromStandard(privateKey), nil
|
|
}
|
|
|
|
// Public returns the PublicKey corresponding to priv.
|
|
func (priv PrivateKey) Public() crypto.PublicKey {
|
|
publicKey := make([]byte, PublicKeySize)
|
|
copy(publicKey, priv[PrivateKeyFormSize:])
|
|
return PublicKey(publicKey)
|
|
}
|
|
|
|
// Equal reports whether priv and x have the same value.
|
|
func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
|
|
xx, ok := x.(PrivateKey)
|
|
if !ok {
|
|
return false
|
|
}
|
|
return bytes.Equal(priv, xx)
|
|
}
|