2017-09-12 18:02:30 +02:00
|
|
|
package claim
|
|
|
|
|
|
|
|
import (
|
2017-11-20 19:44:19 +01:00
|
|
|
"crypto/ecdsa"
|
2017-09-12 18:02:30 +02:00
|
|
|
"crypto/sha256"
|
2017-11-08 03:39:08 +01:00
|
|
|
"crypto/x509/pkix"
|
2017-11-20 19:44:19 +01:00
|
|
|
"encoding/asn1"
|
2019-05-04 06:00:23 +02:00
|
|
|
"encoding/binary"
|
2017-11-20 19:44:19 +01:00
|
|
|
"encoding/hex"
|
2017-11-08 03:39:08 +01:00
|
|
|
"math/big"
|
2019-04-07 06:29:12 +02:00
|
|
|
|
|
|
|
"github.com/lbryio/lbry.go/extras/errors"
|
|
|
|
"github.com/lbryio/lbryschema.go/address"
|
2017-09-12 18:02:30 +02:00
|
|
|
)
|
|
|
|
|
2017-11-08 03:39:08 +01:00
|
|
|
type publicKeyInfo struct {
|
|
|
|
Raw asn1.RawContent
|
|
|
|
Algorithm pkix.AlgorithmIdentifier
|
|
|
|
PublicKey asn1.BitString
|
|
|
|
}
|
|
|
|
|
|
|
|
const SECP256k1 = "SECP256k1"
|
|
|
|
|
2018-02-15 20:51:51 +01:00
|
|
|
//const NIST256p = "NIST256p"
|
|
|
|
//const NIST384p = "NIST384p"
|
|
|
|
|
2019-04-07 06:29:12 +02:00
|
|
|
func getClaimSignatureDigest(bytes ...[]byte) [32]byte {
|
|
|
|
|
2017-11-20 19:44:19 +01:00
|
|
|
var combined []byte
|
2019-04-07 06:29:12 +02:00
|
|
|
for _, b := range bytes {
|
|
|
|
combined = append(combined, b...)
|
2017-11-20 19:44:19 +01:00
|
|
|
}
|
2017-09-12 18:02:30 +02:00
|
|
|
digest := sha256.Sum256(combined)
|
|
|
|
return [32]byte(digest)
|
|
|
|
}
|
|
|
|
|
2019-04-07 06:29:12 +02:00
|
|
|
func (c *ClaimHelper) VerifyDigest(certificate *ClaimHelper, signature [64]byte, digest [32]byte) bool {
|
|
|
|
if certificate == nil {
|
|
|
|
return false
|
2017-11-08 03:39:08 +01:00
|
|
|
}
|
|
|
|
|
2019-04-07 06:29:12 +02:00
|
|
|
R := &big.Int{}
|
|
|
|
S := &big.Int{}
|
|
|
|
R.SetBytes(signature[0:32])
|
|
|
|
S.SetBytes(signature[32:64])
|
|
|
|
pk, err := certificate.GetPublicKey()
|
2017-11-08 03:39:08 +01:00
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
2019-04-07 06:29:12 +02:00
|
|
|
return ecdsa.Verify(pk.ToECDSA(), digest[:], R, S)
|
|
|
|
}
|
2017-11-08 03:39:08 +01:00
|
|
|
|
2019-04-07 06:29:12 +02:00
|
|
|
func (c *ClaimHelper) ValidateClaimSignature(certificate *ClaimHelper, k string, certificateId string, blockchainName string) (bool, error) {
|
|
|
|
if c.LegacyClaim != nil {
|
|
|
|
return c.validateV1ClaimSignature(certificate, k, certificateId, blockchainName)
|
2017-11-08 03:39:08 +01:00
|
|
|
}
|
2019-04-07 06:29:12 +02:00
|
|
|
|
|
|
|
return c.validateClaimSignature(certificate, k, certificateId, blockchainName)
|
2017-11-08 03:39:08 +01:00
|
|
|
}
|
|
|
|
|
2019-05-04 06:00:23 +02:00
|
|
|
func (c *ClaimHelper) validateClaimSignature(certificate *ClaimHelper, firstInputTxHash, certificateId string, blockchainName string) (bool, error) {
|
2019-04-07 06:29:12 +02:00
|
|
|
certificateIdSlice, err := hex.DecodeString(certificateId)
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Err(err)
|
2017-11-08 03:39:08 +01:00
|
|
|
}
|
2019-04-07 06:29:12 +02:00
|
|
|
certificateIdSlice = reverseBytes(certificateIdSlice)
|
2019-05-04 06:00:23 +02:00
|
|
|
firstInputTxIDBytes, err := hex.DecodeString(firstInputTxHash)
|
2019-04-07 06:29:12 +02:00
|
|
|
if err != nil {
|
|
|
|
return false, errors.Err(err)
|
2017-11-08 03:39:08 +01:00
|
|
|
}
|
|
|
|
|
2019-04-07 06:29:12 +02:00
|
|
|
signature := c.Signature
|
|
|
|
if signature == nil {
|
|
|
|
return false, errors.Err("claim does not have a signature")
|
|
|
|
}
|
|
|
|
signatureBytes := [64]byte{}
|
|
|
|
for i, b := range signature {
|
|
|
|
signatureBytes[i] = b
|
2017-11-08 03:39:08 +01:00
|
|
|
}
|
|
|
|
|
2019-05-04 06:00:23 +02:00
|
|
|
claimDigest := getClaimSignatureDigest(firstInputTxIDBytes, certificateIdSlice, c.Payload)
|
2017-11-27 16:22:04 +01:00
|
|
|
return c.VerifyDigest(certificate, signatureBytes, claimDigest), nil
|
2017-09-12 18:02:30 +02:00
|
|
|
}
|
|
|
|
|
2019-04-07 06:29:12 +02:00
|
|
|
func (c *ClaimHelper) validateV1ClaimSignature(certificate *ClaimHelper, claimAddy string, certificateId string, blockchainName string) (bool, error) {
|
|
|
|
addressBytes, err := address.DecodeAddress(claimAddy, blockchainName)
|
2017-11-08 03:39:08 +01:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
2019-04-07 06:29:12 +02:00
|
|
|
//For V1 claim_id was incorrectly stored for claim signing.
|
|
|
|
// So the bytes are not reversed like they are supposed to be (Endianess)
|
2017-11-08 03:39:08 +01:00
|
|
|
certificateIdSlice, err := hex.DecodeString(certificateId)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
2019-04-07 06:29:12 +02:00
|
|
|
|
|
|
|
signature := c.Signature
|
|
|
|
if signature == nil {
|
|
|
|
return false, errors.Err("claim does not have a signature")
|
|
|
|
}
|
|
|
|
signatureBytes := [64]byte{}
|
|
|
|
for i := range signatureBytes {
|
|
|
|
signatureBytes[i] = signature[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
claimAddress, err := address.ValidateAddress(addressBytes, blockchainName)
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Err("invalid address")
|
2017-11-08 03:39:08 +01:00
|
|
|
}
|
2019-04-07 06:29:12 +02:00
|
|
|
|
|
|
|
serializedNoSig, err := c.serializedNoSignature()
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Err("serialization error")
|
|
|
|
}
|
|
|
|
|
|
|
|
claimDigest := getClaimSignatureDigest(claimAddress[:], serializedNoSig, certificateIdSlice)
|
|
|
|
return c.VerifyDigest(certificate, signatureBytes, claimDigest), nil
|
2017-09-12 18:02:30 +02:00
|
|
|
}
|
2019-05-04 06:00:23 +02:00
|
|
|
|
|
|
|
func GetOutpointHash(txid string, vout uint32) (string, error) {
|
|
|
|
txidBytes, err := hex.DecodeString(txid)
|
|
|
|
if err != nil {
|
|
|
|
return "", errors.Err(err)
|
|
|
|
}
|
|
|
|
var voutBytes = make([]byte, 4)
|
|
|
|
binary.LittleEndian.PutUint32(voutBytes, vout)
|
|
|
|
return hex.EncodeToString(append(reverseBytes(txidBytes), voutBytes...)), nil
|
|
|
|
}
|