68 lines
1.9 KiB
Go
68 lines
1.9 KiB
Go
// Copyright 2016 The Go Authors. All rights reserved.
|
|
// Copyright 2016 Henry de Valence. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package ed25519consensus implements Ed25519 verification according to ZIP215.
|
|
package ed25519consensus
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"crypto/sha512"
|
|
|
|
"filippo.io/edwards25519"
|
|
)
|
|
|
|
// Verify reports whether sig is a valid signature of message by
|
|
// publicKey, using precisely-specified validation criteria (ZIP 215) suitable
|
|
// for use in consensus-critical contexts.
|
|
func Verify(publicKey ed25519.PublicKey, message, sig []byte) bool {
|
|
if l := len(publicKey); l != ed25519.PublicKeySize {
|
|
return false
|
|
}
|
|
|
|
if len(sig) != ed25519.SignatureSize || sig[63]&224 != 0 {
|
|
return false
|
|
}
|
|
|
|
// ZIP215: this works because SetBytes does not check that encodings are canonical.
|
|
A, err := new(edwards25519.Point).SetBytes(publicKey)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
A.Negate(A)
|
|
|
|
h := sha512.New()
|
|
h.Write(sig[:32])
|
|
h.Write(publicKey[:])
|
|
h.Write(message)
|
|
var digest [64]byte
|
|
h.Sum(digest[:0])
|
|
|
|
hReduced, err := new(edwards25519.Scalar).SetUniformBytes(digest[:])
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
// ZIP215: this works because SetBytes does not check that encodings are canonical.
|
|
checkR, err := new(edwards25519.Point).SetBytes(sig[:32])
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
// https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
|
|
// the range [0, order) in order to prevent signature malleability.
|
|
// ZIP215: This is also required by ZIP215.
|
|
s, err := new(edwards25519.Scalar).SetCanonicalBytes(sig[32:])
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
R := new(edwards25519.Point).VarTimeDoubleScalarBaseMult(hReduced, A, s)
|
|
|
|
// ZIP215: We want to check [8](R - checkR) == 0
|
|
p := new(edwards25519.Point).Subtract(R, checkR) // p = R - checkR
|
|
p.MultByCofactor(p)
|
|
return p.Equal(edwards25519.NewIdentityPoint()) == 1 // p == 0
|
|
}
|