97 lines
3.1 KiB
Go
97 lines
3.1 KiB
Go
package crypto
|
|
|
|
import (
|
|
"git.gammaspectra.live/P2Pool/consensus/v3/types"
|
|
"git.gammaspectra.live/P2Pool/edwards25519"
|
|
)
|
|
|
|
// Signature Schnorr signature
|
|
type Signature struct {
|
|
// C hash of data in signature, also called e
|
|
C *edwards25519.Scalar
|
|
// R result of the signature, also called s
|
|
R *edwards25519.Scalar
|
|
}
|
|
|
|
// SignatureSigningHandler receives k, inserts it or a pubkey into its data, and produces a []byte buffer for Signing/Verifying
|
|
type SignatureSigningHandler func(r PrivateKey) []byte
|
|
|
|
// SignatureVerificationHandler receives r = pubkey(k), inserts it into its data, and produces a []byte buffer for Signing/Verifying
|
|
type SignatureVerificationHandler func(r PublicKey) []byte
|
|
|
|
func NewSignatureFromBytes(buf []byte) *Signature {
|
|
if len(buf) != types.HashSize*2 {
|
|
return nil
|
|
}
|
|
signature := &Signature{}
|
|
var err error
|
|
if signature.C, err = GetEdwards25519Scalar().SetCanonicalBytes(buf[:32]); err != nil {
|
|
return nil
|
|
} else if signature.R, err = GetEdwards25519Scalar().SetCanonicalBytes(buf[32:]); err != nil {
|
|
return nil
|
|
} else {
|
|
return signature
|
|
}
|
|
}
|
|
|
|
func (s *Signature) Bytes() []byte {
|
|
buf := make([]byte, 0, types.HashSize*2)
|
|
buf = append(buf, s.C.Bytes()...)
|
|
buf = append(buf, s.R.Bytes()...)
|
|
return buf
|
|
}
|
|
|
|
// Verify checks a Schnorr Signature using H = keccak
|
|
func (s *Signature) Verify(handler SignatureVerificationHandler, publicKey PublicKey) (ok bool, r *PublicKeyPoint) {
|
|
//s = C * k, R * G
|
|
sp := GetEdwards25519Point().VarTimeDoubleScalarBaseMult(s.C, publicKey.AsPoint().Point(), s.R)
|
|
if sp.Equal(infinityPoint) == 1 {
|
|
return false, nil
|
|
}
|
|
r = PublicKeyFromPoint(sp)
|
|
return s.C.Equal(HashToScalar(handler(r))) == 1, r
|
|
}
|
|
|
|
// CreateSignature produces a Schnorr Signature using H = keccak
|
|
func CreateSignature(handler SignatureSigningHandler, privateKey PrivateKey) *Signature {
|
|
k := PrivateKeyFromScalar(RandomScalar())
|
|
|
|
signature := &Signature{
|
|
// e
|
|
C: HashToScalar(handler(k)),
|
|
R: &edwards25519.Scalar{},
|
|
}
|
|
|
|
// s = k - x * e
|
|
// EdDSA is an altered version, with addition instead of subtraction
|
|
signature.R = signature.R.Subtract(k.Scalar(), GetEdwards25519Scalar().Multiply(signature.C, privateKey.AsScalar().Scalar()))
|
|
return signature
|
|
}
|
|
|
|
func CreateMessageSignature(prefixHash types.Hash, key PrivateKey) *Signature {
|
|
buf := &SignatureComm{}
|
|
buf.Hash = prefixHash
|
|
buf.Key = key.PublicKey()
|
|
|
|
return CreateSignature(func(k PrivateKey) []byte {
|
|
buf.Comm = k.PublicKey()
|
|
return buf.Bytes()
|
|
}, key)
|
|
}
|
|
|
|
func VerifyMessageSignature(prefixHash types.Hash, publicKey PublicKey, signature *Signature) bool {
|
|
return VerifyMessageSignatureSplit(prefixHash, publicKey, publicKey, signature)
|
|
}
|
|
|
|
// VerifyMessageSignatureSplit Allows specifying a different signer key than for the rest. Use VerifyMessageSignature in all other cases
|
|
func VerifyMessageSignatureSplit(prefixHash types.Hash, commPublicKey, signPublicKey PublicKey, signature *Signature) bool {
|
|
buf := &SignatureComm{}
|
|
buf.Hash = prefixHash
|
|
buf.Key = commPublicKey
|
|
|
|
ok, _ := signature.Verify(func(r PublicKey) []byte {
|
|
buf.Comm = r
|
|
return buf.Bytes()
|
|
}, signPublicKey)
|
|
return ok
|
|
}
|