kaspad/ecc/signature.go
Ori Newman a4bb070722
[NOD-754] Fix staticcheck errors (#627)
* [NOD-754] Fix staticcheck errors

* [NOD-754] Remove some unused exported functions

* [NOD-754] Fix staticcheck errors

* [NOD-754] Don't panic if out/in close fails

* [NOD-754] Wrap outside errors with custom message
2020-02-18 16:56:38 +02:00

262 lines
7.4 KiB
Go

// Copyright (c) 2013-2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package ecc
import (
"bytes"
"crypto/elliptic"
"crypto/hmac"
"crypto/sha256"
"github.com/pkg/errors"
"hash"
"math/big"
)
// Signature is a type representing a Schnorr signature.
type Signature struct {
R *big.Int
S *big.Int
}
var (
// Used in RFC6979 implementation when testing the nonce for correctness
one = big.NewInt(1)
// oneInitializer is used to fill a byte slice with byte 0x01. It is provided
// here to avoid the need to create it multiple times.
oneInitializer = []byte{0x01}
)
// Serialize returns a serialized signature (R and S concatenated).
func (sig *Signature) Serialize() []byte {
return append(bigIntTo32Bytes(sig.R), bigIntTo32Bytes(sig.S)...)
}
// Verify verifies digital signatures. It returns true if the signature
// is valid, false otherwise.
func (sig *Signature) Verify(hash []byte, pubKey *PublicKey) bool {
return verifySchnorr(pubKey, hash, sig.R, sig.S)
}
// verifySchnorr verifies the schnorr signature of the hash using the pubkey key.
// It returns true if the signature is valid, false otherwise.
func verifySchnorr(pubKey *PublicKey, hash []byte, r *big.Int, s *big.Int) bool {
// This schnorr specification is specific to the secp256k1 curve so if the
// provided curve is not a KoblitizCurve then we'll just return false.
curve, ok := pubKey.Curve.(*KoblitzCurve)
if !ok {
return false
}
// Signature is invalid if s >= order or r >= p.
if s.Cmp(curve.Params().N) >= 0 || r.Cmp(curve.Params().P) >= 0 {
return false
}
// Compute scalar e = Hash(r || compressed(P) || m) mod N
eBytes := sha256.Sum256(append(append(bigIntTo32Bytes(r), pubKey.SerializeCompressed()...), hash...))
e := new(big.Int).SetBytes(eBytes[:])
e.Mod(e, curve.Params().N)
// Negate e
e.Neg(e).Mod(e, curve.Params().N)
// Compute point R = s * G - e * P.
sgx, sgy, sgz := curve.scalarBaseMultJacobian(s.Bytes())
epx, epy, epz := curve.scalarMultJacobian(pubKey.X, pubKey.Y, e.Bytes())
rx, ry, rz := new(fieldVal), new(fieldVal), new(fieldVal)
curve.addJacobian(sgx, sgy, sgz, epx, epy, epz, rx, ry, rz)
// Check that R is not infinity
if rz.Equals(new(fieldVal).SetInt(0)) {
return false
}
// Check if R.y is quadratic residue
yz := ry.Mul(rz).Normalize()
b := yz.Bytes()
if big.Jacobi(new(big.Int).SetBytes(b[:]), curve.P) != 1 {
return false
}
// Check R values match
// rx ≠ rz^2 * r mod p
fieldR := new(fieldVal).SetByteSlice(r.Bytes())
return rx.Normalize().Equals(rz.Square().Mul(fieldR).Normalize())
}
// IsEqual compares this Signature instance to the one passed, returning true
// if both Signatures are equivalent. A signature is equivalent to another, if
// they both have the same scalar value for R and S.
func (sig *Signature) IsEqual(otherSig *Signature) bool {
return sig.R.Cmp(otherSig.R) == 0 &&
sig.S.Cmp(otherSig.S) == 0
}
// ParseSignature parses a 64 byte schnorr signature into a Signature type.
func ParseSignature(sigStr []byte) (*Signature, error) {
if len(sigStr) != 64 {
return nil, errors.New("malformed schnorr signature: not 64 bytes")
}
bigR := new(big.Int).SetBytes(sigStr[:32])
bigS := new(big.Int).SetBytes(sigStr[32:64])
return &Signature{
R: bigR,
S: bigS,
}, nil
}
// bigIntTo32Bytes pads a big int bytes with leading zeros if they
// are missing to get the length up to 32 bytes.
func bigIntTo32Bytes(val *big.Int) []byte {
b := val.Bytes()
pad := bytes.Repeat([]byte{0x00}, 32-len(b))
return append(pad, b...)
}
// hashToInt converts a hash value to an integer. There is some disagreement
// about how this is done. [NSA] suggests that this is done in the obvious
// manner, but [SECG] truncates the hash to the bit-length of the curve order
// first. We follow [SECG] because that's what OpenSSL does. Additionally,
// OpenSSL right shifts excess bits from the number if the hash is too large
// and we mirror that too.
// This is borrowed from crypto/ecdsa.
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
orderBits := c.Params().N.BitLen()
orderBytes := (orderBits + 7) / 8
if len(hash) > orderBytes {
hash = hash[:orderBytes]
}
ret := new(big.Int).SetBytes(hash)
excess := len(hash)*8 - orderBits
if excess > 0 {
ret.Rsh(ret, uint(excess))
}
return ret
}
// sign signs the hash using the schnorr signature algorithm.
func sign(privateKey *PrivateKey, hash []byte) (*Signature, error) {
// The rfc6979 nonce derivation function accepts additional entropy.
// See https://github.com/bitcoincashorg/bitcoincash.org/blob/master/spec/2019-05-15-schnorr.md#recommended-practices-for-secure-signature-generation
additionalData := []byte{'S', 'c', 'h', 'n', 'o', 'r', 'r', '+', 'S', 'H', 'A', '2', '5', '6', ' ', ' '}
k := nonceRFC6979(privateKey.D, hash, additionalData)
// Compute point R = k * G
rx, ry := privateKey.Curve.ScalarBaseMult(k.Bytes())
// Negate nonce if R.y is not a quadratic residue.
if big.Jacobi(ry, privateKey.Params().P) != 1 {
k = k.Neg(k)
}
// Compute scalar e = Hash(R.x || compressed(P) || m) mod N
eBytes := sha256.Sum256(append(append(bigIntTo32Bytes(rx), privateKey.PubKey().SerializeCompressed()...), hash...))
e := new(big.Int).SetBytes(eBytes[:])
e.Mod(e, privateKey.Params().N)
// Compute scalar s = (k + e * x) mod N
x := new(big.Int).SetBytes(privateKey.Serialize())
s := e.Mul(e, x)
s.Add(s, k)
s.Mod(s, privateKey.Params().N)
return &Signature{
R: rx,
S: s,
}, nil
}
// nonceRFC6979 generates a nonce (`k`) deterministically according to RFC 6979.
// It takes a 32-byte hash as an input and returns 32-byte nonce to be used in the digital signature algorithm.
func nonceRFC6979(privkey *big.Int, hash []byte, additionalData []byte) *big.Int {
// Step A
curve := S256()
q := curve.Params().N
x := privkey
alg := sha256.New
qlen := q.BitLen()
holen := alg().Size()
rolen := (qlen + 7) >> 3
bx := append(int2octets(x, rolen), bits2octets(hash, curve, rolen)...)
// Step B
v := bytes.Repeat(oneInitializer, holen)
// Step C (Go zeroes the all allocated memory)
k := make([]byte, holen)
// Step D
k = mac(alg, k, append(append(append(v, 0x00), bx...), additionalData...))
// Step E
v = mac(alg, k, v)
// Step F
k = mac(alg, k, append(append(append(v, 0x01), bx...), additionalData...))
// Step G
v = mac(alg, k, v)
// Step H
for {
// Step H1
var t []byte
// Step H2
for len(t)*8 < qlen {
v = mac(alg, k, v)
t = append(t, v...)
}
// Step H3
secret := hashToInt(t, curve)
if secret.Cmp(one) >= 0 && secret.Cmp(q) < 0 {
return secret
}
k = mac(alg, k, append(v, 0x00))
v = mac(alg, k, v)
}
}
// mac returns an HMAC of the given key and message.
func mac(alg func() hash.Hash, k, m []byte) []byte {
h := hmac.New(alg, k)
h.Write(m)
return h.Sum(nil)
}
// https://tools.ietf.org/html/rfc6979#section-2.3.3
func int2octets(v *big.Int, rolen int) []byte {
out := v.Bytes()
// left pad with zeros if it's too short
if len(out) < rolen {
out2 := make([]byte, rolen)
copy(out2[rolen-len(out):], out)
return out2
}
// drop most significant bytes if it's too long
if len(out) > rolen {
out2 := make([]byte, rolen)
copy(out2, out[len(out)-rolen:])
return out2
}
return out
}
func bits2octets(in []byte, curve elliptic.Curve, rolen int) []byte {
// https://tools.ietf.org/html/rfc6979#section-2.3.4
z1 := hashToInt(in, curve)
z2 := new(big.Int).Sub(z1, curve.Params().N)
if z2.Sign() < 0 {
return int2octets(z1, rolen)
}
return int2octets(z2, rolen)
}