mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00

* [NOD-510] Change coinbase flags to kaspad. * [NOD-510] Removed superfluous spaces after periods in comments. * [NOD-510] Rename btcd -> kaspad in the root folder. * [NOD-510] Rename BtcEncode -> KaspaEncode and BtcDecode -> KaspaDecode. * [NOD-510] Rename BtcEncode -> KaspaEncode and BtcDecode -> KaspaDecode. * [NOD-510] Continue renaming btcd -> kaspad. * [NOD-510] Rename btcjson -> kaspajson. * [NOD-510] Rename file names inside kaspajson. * [NOD-510] Rename kaspajson -> jsonrpc. * [NOD-510] Finish renaming in addrmgr. * [NOD-510] Rename package btcec to ecc. * [NOD-510] Finish renaming stuff in blockdag. * [NOD-510] Rename stuff in cmd. * [NOD-510] Rename stuff in config. * [NOD-510] Rename stuff in connmgr. * [NOD-510] Rename stuff in dagconfig. * [NOD-510] Rename stuff in database. * [NOD-510] Rename stuff in docker. * [NOD-510] Rename stuff in integration. * [NOD-510] Rename jsonrpc to rpcmodel. * [NOD-510] Rename stuff in limits. * [NOD-510] Rename stuff in logger. * [NOD-510] Rename stuff in mempool. * [NOD-510] Rename stuff in mining. * [NOD-510] Rename stuff in netsync. * [NOD-510] Rename stuff in peer. * [NOD-510] Rename stuff in release. * [NOD-510] Rename stuff in rpcclient. * [NOD-510] Rename stuff in server. * [NOD-510] Rename stuff in signal. * [NOD-510] Rename stuff in txscript. * [NOD-510] Rename stuff in util. * [NOD-510] Rename stuff in wire. * [NOD-510] Fix failing tests. * [NOD-510] Fix merge errors. * [NOD-510] Fix go vet errors. * [NOD-510] Remove merged file that's no longer relevant. * [NOD-510] Add a comment above Op0. * [NOD-510] Fix some comments referencing Bitcoin Core. * [NOD-510] Fix some more comments referencing Bitcoin Core. * [NOD-510] Fix bitcoin -> kaspa. * [NOD-510] Fix more bitcoin -> kaspa. * [NOD-510] Fix comments, remove DisconnectBlock in addrindex. * [NOD-510] Rename KSPD to KASD. * [NOD-510] Fix comments and user agent.
268 lines
7.6 KiB
Go
268 lines
7.6 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"
|
|
)
|
|
|
|
// Errors returned by canonicalPadding.
|
|
var (
|
|
errNegativeValue = errors.New("value may be interpreted as negative")
|
|
errExcessivelyPaddedValue = errors.New("value is excessively padded")
|
|
)
|
|
|
|
// 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)
|
|
}
|