added support for proto3 metadata definitions
added signing capabilities all with unit tests
This commit is contained in:
parent
50996a6b0d
commit
9159c7602d
18 changed files with 842 additions and 427 deletions
|
@ -1,14 +1,14 @@
|
|||
package address
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
"github.com/lbryio/lbryschema.go/address/base58"
|
||||
)
|
||||
|
||||
func DecodeAddress(address string, blockchainName string) ([addressLength]byte, error) {
|
||||
decoded, err := base58.DecodeBase58(address, addressLength)
|
||||
if err != nil {
|
||||
return [addressLength]byte{}, errors.New("failed to decode")
|
||||
return [addressLength]byte{}, errors.Err("failed to decode")
|
||||
}
|
||||
buf := [addressLength]byte{}
|
||||
for i, b := range decoded {
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package address
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
"github.com/lbryio/lbryschema.go/address/base58"
|
||||
)
|
||||
|
||||
const lbrycrdMainPubkeyPrefix = byte(85)
|
||||
const lbrycrdMainScriptPrefix = byte(122)
|
||||
|
||||
const lbrycrdTestnetPubkeyPrefix = byte(111)
|
||||
const lbrycrdTestnetScriptPrefix = byte(196)
|
||||
|
||||
const lbrycrdRegtestPubkeyPrefix = byte(111)
|
||||
const lbrycrdRegtestScriptPrefix = byte(196)
|
||||
|
||||
|
@ -17,6 +18,7 @@ const prefixLength = 1
|
|||
const pubkeyLength = 20
|
||||
const checksumLength = 4
|
||||
const addressLength = prefixLength + pubkeyLength + checksumLength
|
||||
|
||||
const lbrycrdMain = "lbrycrd_main"
|
||||
const lbrycrdTestnet = "lbrycrd_testnet"
|
||||
const lbrycrdRegtest = "lbrycrd_regtest"
|
||||
|
@ -52,16 +54,16 @@ func ChecksumIsValid(address [addressLength]byte) bool {
|
|||
|
||||
func ValidateAddress(address [addressLength]byte, blockchainName string) ([addressLength]byte, error) {
|
||||
if blockchainName != lbrycrdMain && blockchainName != lbrycrdTestnet && blockchainName != lbrycrdRegtest {
|
||||
return address, errors.New("invalid blockchain name")
|
||||
return address, errors.Err("invalid blockchain name")
|
||||
}
|
||||
if !PrefixIsValid(address, blockchainName) {
|
||||
return address, errors.New("invalid prefix")
|
||||
return address, errors.Err("invalid prefix")
|
||||
}
|
||||
if !PubKeyIsValid(address) {
|
||||
return address, errors.New("invalid pubkey")
|
||||
return address, errors.Err("invalid pubkey")
|
||||
}
|
||||
if !ChecksumIsValid(address) {
|
||||
return address, errors.New("invalid address checksum")
|
||||
return address, errors.Err("invalid address checksum")
|
||||
}
|
||||
return address, nil
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"C"
|
||||
"encoding/hex"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
"github.com/lbryio/lbryschema.go/claim"
|
||||
)
|
||||
|
||||
//export VerifySignature
|
||||
func VerifySignature(claimHex string, certificateHex string, claimAddress string, certificateId string, blockchainName string) bool {
|
||||
decodedClaim, err := claim.DecodeClaimHex(claimHex, blockchainName)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
decodedCertificate, err := claim.DecodeClaimHex(certificateHex, blockchainName)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
result, err := decodedClaim.ValidateClaimSignature(decodedCertificate, claimAddress, certificateId, blockchainName)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
//export DecodeClaimHex
|
||||
func DecodeClaimHex(claimHex string, blockchainName string) *C.char {
|
||||
decodedClaim, err := claim.DecodeClaimHex(claimHex, blockchainName)
|
||||
if err != nil {
|
||||
return C.CString("decode error: " + err.Error())
|
||||
}
|
||||
decoded, err := decodedClaim.RenderJSON()
|
||||
if err != nil {
|
||||
return C.CString("encode error: " + err.Error())
|
||||
}
|
||||
return C.CString(decoded)
|
||||
}
|
||||
|
||||
//export SerializeClaimFromJSON
|
||||
func SerializeClaimFromJSON(claimJSON string, blockchainName string) *C.char {
|
||||
decodedClaim, err := claim.DecodeClaimJSON(claimJSON, blockchainName)
|
||||
if err != nil {
|
||||
return C.CString("decode error: " + err.Error())
|
||||
}
|
||||
SerializedHex, err := decodedClaim.SerializedHexString()
|
||||
if err != nil {
|
||||
return C.CString("encode error: " + err.Error())
|
||||
}
|
||||
return C.CString(SerializedHex)
|
||||
}
|
||||
|
||||
//export DecodeAddress
|
||||
func DecodeAddress(addressString string, blockchainName string) *C.char {
|
||||
addressBytes, err := address.DecodeAddress(addressString, blockchainName)
|
||||
if err != nil {
|
||||
return C.CString("error: " + err.Error())
|
||||
}
|
||||
return C.CString(hex.EncodeToString(addressBytes[:]))
|
||||
}
|
||||
|
||||
//export EncodeAddress
|
||||
func EncodeAddress(addressChars string, blockchainName string) *C.char {
|
||||
addressBytes := [25]byte{}
|
||||
if len(addressChars) != 25 {
|
||||
return C.CString("error: address is not 25 bytes")
|
||||
}
|
||||
for i := range addressBytes {
|
||||
addressBytes[i] = byte(addressChars[i])
|
||||
}
|
||||
encodedAddress, err := address.EncodeAddress(addressBytes, blockchainName)
|
||||
if err != nil {
|
||||
return C.CString("error: " + err.Error())
|
||||
}
|
||||
return C.CString(encodedAddress)
|
||||
}
|
||||
|
||||
func main() {}
|
1
build.sh
1
build.sh
|
@ -3,4 +3,3 @@
|
|||
set -euxo pipefail
|
||||
go build ./...
|
||||
go build ./cli/lbryschema-cli.go
|
||||
go build -o lbryschema-python-binding.so -buildmode=c-shared ./binding/lbryschema-python-binding.go
|
||||
|
|
160
claim/claim.go
160
claim/claim.go
|
@ -2,27 +2,60 @@ package claim
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/protobuf/jsonpb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
"github.com/lbryio/lbry.go/errors"
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
"github.com/lbryio/types/go"
|
||||
legacy_pb "github.com/lbryio/types/v1/go"
|
||||
pb "github.com/lbryio/types/v2/go"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
type version byte
|
||||
|
||||
func (v version) byte() byte {
|
||||
return byte(v)
|
||||
}
|
||||
|
||||
const (
|
||||
NoSig = version(byte(0))
|
||||
//Signature using ECDSA SECP256k1 key and SHA-256 hash.
|
||||
WithSig = version(byte(1))
|
||||
UNKNOWN = version(byte(2))
|
||||
)
|
||||
|
||||
type ClaimHelper struct {
|
||||
*pb.Claim
|
||||
LegacyClaim *legacy_pb.Claim
|
||||
ClaimID []byte
|
||||
Version version
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
const migrationErrorMessage = "migration from v1 to v2 protobuf failed with: "
|
||||
|
||||
func (c *ClaimHelper) ValidateAddresses(blockchainName string) error {
|
||||
if c.Claim != nil { // V2
|
||||
// check the validity of a fee address
|
||||
if c.GetClaimType() == pb.Claim_streamType {
|
||||
fee := c.GetStream().GetMetadata().GetFee()
|
||||
if c.Claim.GetStream() != nil {
|
||||
fee := c.GetStream().GetFee()
|
||||
if fee != nil {
|
||||
tmp_addr := fee.GetAddress()
|
||||
return validateAddress(fee.GetAddress(), blockchainName)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else if c.GetChannel() != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return errors.Err("claim helper created with migrated v2 protobuf claim 'invalid state'")
|
||||
}
|
||||
|
||||
func validateAddress(tmp_addr []byte, blockchainName string) error {
|
||||
if len(tmp_addr) != 25 {
|
||||
return errors.Err("invalid address length: " + string(len(tmp_addr)) + "!")
|
||||
return errors.Err("invalid address length: " + strconv.FormatInt(int64(len(tmp_addr)), 10) + "!")
|
||||
}
|
||||
addr := [25]byte{}
|
||||
for i := range addr {
|
||||
|
@ -32,24 +65,28 @@ func (c *ClaimHelper) ValidateAddresses(blockchainName string) error {
|
|||
if err != nil {
|
||||
return errors.Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getVersionFromByte(versionByte byte) version {
|
||||
if versionByte == byte(0) {
|
||||
return NoSig
|
||||
} else if versionByte == byte(1) {
|
||||
return WithSig
|
||||
}
|
||||
|
||||
return UNKNOWN
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) ValidateCertificate() error {
|
||||
certificate := c.GetCertificate()
|
||||
if certificate == nil {
|
||||
if c.GetChannel() == nil {
|
||||
return nil
|
||||
}
|
||||
keyType := certificate.GetKeyType()
|
||||
_, err := c.GetCertificatePublicKey()
|
||||
_, err := c.GetPublicKey()
|
||||
if err != nil {
|
||||
return errors.Err(err)
|
||||
}
|
||||
if keyType.String() != SECP256k1 {
|
||||
return errors.Err("wrong curve: " + keyType.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -61,12 +98,52 @@ func (c *ClaimHelper) LoadFromBytes(raw_claim []byte, blockchainName string) err
|
|||
return errors.Err("there is nothing to decode")
|
||||
}
|
||||
|
||||
claim_pb := &pb.Claim{}
|
||||
err := proto.Unmarshal(raw_claim, claim_pb)
|
||||
var claim_pb *pb.Claim
|
||||
var legacy_claim_pb *legacy_pb.Claim
|
||||
|
||||
version := getVersionFromByte(raw_claim[0]) //First byte = version
|
||||
pbPayload := raw_claim[1:]
|
||||
var claimID []byte
|
||||
var signature []byte
|
||||
if version == WithSig {
|
||||
if len(raw_claim) < 86 {
|
||||
return errors.Err("signature version indicated by 1st byte but not enough bytes for valid format")
|
||||
}
|
||||
claimID = raw_claim[1:21] // channel claimid = next 20 bytes
|
||||
signature = raw_claim[21:85] // signature = next 64 bytes
|
||||
pbPayload = raw_claim[85:] // protobuf payload = remaining bytes
|
||||
}
|
||||
|
||||
claim_pb = &pb.Claim{}
|
||||
err := proto.Unmarshal(pbPayload, claim_pb)
|
||||
if err != nil {
|
||||
legacy_claim_pb = &legacy_pb.Claim{}
|
||||
legacyErr := proto.Unmarshal(raw_claim, legacy_claim_pb)
|
||||
if legacyErr == nil {
|
||||
claim_pb, err = migrateV1PBClaim(*legacy_claim_pb)
|
||||
if err != nil {
|
||||
return errors.Prefix(migrationErrorMessage, err)
|
||||
}
|
||||
if legacy_claim_pb.GetPublisherSignature() != nil {
|
||||
version = WithSig
|
||||
signature = legacy_claim_pb.GetPublisherSignature().GetSignature()
|
||||
}
|
||||
if legacy_claim_pb.GetCertificate() != nil {
|
||||
version = NoSig
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
*c = ClaimHelper{claim_pb}
|
||||
}
|
||||
|
||||
*c = ClaimHelper{
|
||||
Claim: claim_pb,
|
||||
LegacyClaim: legacy_claim_pb,
|
||||
ClaimID: claimID,
|
||||
Version: version,
|
||||
Signature: signature,
|
||||
}
|
||||
|
||||
err = c.ValidateAddresses(blockchainName)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -88,7 +165,7 @@ func (c *ClaimHelper) LoadFromHexString(claim_hex string, blockchainName string)
|
|||
}
|
||||
|
||||
func DecodeClaimProtoBytes(serialized []byte, blockchainName string) (*ClaimHelper, error) {
|
||||
claim := &ClaimHelper{&pb.Claim{}}
|
||||
claim := &ClaimHelper{&pb.Claim{}, nil, nil, NoSig, nil}
|
||||
err := claim.LoadFromBytes(serialized, blockchainName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -99,21 +176,12 @@ func DecodeClaimProtoBytes(serialized []byte, blockchainName string) (*ClaimHelp
|
|||
func DecodeClaimHex(serialized string, blockchainName string) (*ClaimHelper, error) {
|
||||
claim_bytes, err := hex.DecodeString(serialized)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
return DecodeClaimBytes(claim_bytes, blockchainName)
|
||||
}
|
||||
|
||||
func DecodeClaimJSON(claimJSON string, blockchainName string) (*ClaimHelper, error) {
|
||||
c := &pb.Claim{}
|
||||
err := jsonpb.UnmarshalString(claimJSON, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ClaimHelper{c}, nil
|
||||
}
|
||||
|
||||
// DecodeClaimBytes take a byte array and tries to decode it to a protobuf claim or migrate it from either json v1,2,3
|
||||
// DecodeClaimBytes take a byte array and tries to decode it to a protobuf claim or migrate it from either json v1,2,3 or pb v1
|
||||
func DecodeClaimBytes(serialized []byte, blockchainName string) (*ClaimHelper, error) {
|
||||
helper, err := DecodeClaimProtoBytes(serialized, blockchainName)
|
||||
if err == nil {
|
||||
|
@ -130,7 +198,7 @@ func DecodeClaimBytes(serialized []byte, blockchainName string) (*ClaimHelper, e
|
|||
v3Claim := new(V3Claim)
|
||||
err := v3Claim.Unmarshal(serialized)
|
||||
if err != nil {
|
||||
return nil, errors.Prefix("Claim value has no matching verion", err)
|
||||
return nil, errors.Prefix("Claim value has no matching version", err)
|
||||
}
|
||||
helper.Claim, err = migrateV3Claim(*v3Claim)
|
||||
if err != nil {
|
||||
|
@ -154,21 +222,23 @@ func DecodeClaimBytes(serialized []byte, blockchainName string) (*ClaimHelper, e
|
|||
|
||||
func (c *ClaimHelper) GetStream() *pb.Stream {
|
||||
if c != nil {
|
||||
return c.Stream
|
||||
return c.Claim.GetStream()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) GetCertificate() *pb.Certificate {
|
||||
if c != nil {
|
||||
return c.Certificate
|
||||
func (c *ClaimHelper) CompileValue() ([]byte, error) {
|
||||
payload, err := c.serialized()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var value []byte
|
||||
value = append(value, c.Version.byte())
|
||||
if c.Version == WithSig {
|
||||
value = append(value, c.ClaimID...)
|
||||
value = append(value, c.Signature...)
|
||||
}
|
||||
value = append(value, payload...)
|
||||
|
||||
func (c *ClaimHelper) GetPublisherSignature() *pb.Signature {
|
||||
if c != nil {
|
||||
return c.PublisherSignature
|
||||
}
|
||||
return nil
|
||||
return value, nil
|
||||
}
|
||||
|
|
|
@ -13,15 +13,15 @@ func TestClaimHelper(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = helper.Serialized()
|
||||
_, err = helper.serialized()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = helper.SerializedHexString()
|
||||
_, err = helper.serializedHexString()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = helper.SerializedNoSignature()
|
||||
_, err = helper.serializedNoSignature()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
|
@ -3,8 +3,17 @@ package claim
|
|||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
pb "github.com/lbryio/types/v2/go"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
type rawClaim struct {
|
||||
Hex string
|
||||
ClaimID string
|
||||
}
|
||||
|
||||
var raw_claims = []string{
|
||||
"08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367",
|
||||
"080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65",
|
||||
|
@ -23,7 +32,7 @@ func TestDecodeClaims(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
serializedHex, err := claim.SerializedHexString()
|
||||
serializedHex, err := claim.serializedHexString()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -40,7 +49,7 @@ func TestStripSignature(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
noSig, err := claim.SerializedNoSignature()
|
||||
noSig, err := claim.serializedNoSignature()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -48,3 +57,40 @@ func TestStripSignature(t *testing.T) {
|
|||
t.Error("failed to remove signature")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateChannelClaim(t *testing.T) {
|
||||
private, err := btcec.NewPrivateKey(btcec.S256())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
pubKeyBytes, err := PublicKeyToDER(private.PubKey())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
claim := &ClaimHelper{Claim: newChannelClaim(), Version: NoSig}
|
||||
claim.GetChannel().PublicKey = pubKeyBytes
|
||||
claim.GetChannel().Title = "Test Channel Title"
|
||||
claim.GetChannel().Description = "Test Channel Description"
|
||||
claim.GetChannel().CoverUrl = "http://testcoverurl.com"
|
||||
claim.GetChannel().Tags = []string{"TagA", "TagB", "TagC"}
|
||||
claim.GetChannel().Languages = []*pb.Language{{Language: pb.Language_en}, {Language: pb.Language_es}}
|
||||
claim.GetChannel().ThumbnailUrl = "http://thumbnailurl.com"
|
||||
claim.GetChannel().ContactEmail = "test@test.com"
|
||||
claim.GetChannel().HomepageUrl = "http://homepageurl.com"
|
||||
claim.GetChannel().Locations = []*pb.Location{{Country: pb.Location_AD}, {Country: pb.Location_US, State: "NJ", City: "some city"}}
|
||||
|
||||
rawClaim, err := claim.CompileValue()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
claim, err = DecodeClaimBytes(rawClaim, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if bytes, err := claim.CompileValue(); err != nil || len(bytes) != len(rawClaim) {
|
||||
t.Error("decoded claim does not match original")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
50
claim/keys.go
Normal file
50
claim/keys.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
func PublicKeyToDER(publicKey *btcec.PublicKey) ([]byte, error) {
|
||||
var publicKeyBytes []byte
|
||||
var publicKeyAlgorithm pkix.AlgorithmIdentifier
|
||||
var err error
|
||||
pub := publicKey.ToECDSA()
|
||||
publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
|
||||
//ans1 encoding oid for ecdsa public key https://github.com/golang/go/blob/release-branch.go1.12/src/crypto/x509/x509.go#L457
|
||||
publicKeyAlgorithm.Algorithm = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
//asn1 encoding oid for secp256k1 https://github.com/bitpay/bitpay-go/blob/v2.2.2/key_utils/key_utils.go#L30
|
||||
paramBytes, err := asn1.Marshal(asn1.ObjectIdentifier{1, 3, 132, 0, 10})
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
publicKeyAlgorithm.Parameters.FullBytes = paramBytes
|
||||
|
||||
return asn1.Marshal(publicKeyInfo{
|
||||
Algorithm: publicKeyAlgorithm,
|
||||
PublicKey: asn1.BitString{
|
||||
Bytes: publicKeyBytes,
|
||||
BitLength: 8 * len(publicKeyBytes),
|
||||
},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) GetPublicKey() (*btcec.PublicKey, error) {
|
||||
if c.GetChannel() == nil {
|
||||
return nil, errors.Err("claim is not of type channel, so there is no public key to get")
|
||||
}
|
||||
return getPublicKeyFromBytes(c.GetChannel().PublicKey)
|
||||
}
|
||||
|
||||
func getPublicKeyFromBytes(pubKeyBytes []byte) (*btcec.PublicKey, error) {
|
||||
PKInfo := publicKeyInfo{}
|
||||
asn1.Unmarshal(pubKeyBytes, &PKInfo)
|
||||
pubkeyBytes1 := []byte(PKInfo.PublicKey.Bytes)
|
||||
return btcec.ParsePubKey(pubkeyBytes1, btcec.S256())
|
||||
}
|
36
claim/keys_test.go
Normal file
36
claim/keys_test.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
// The purpose of this test, is to make sure the function converts btcec.PublicKey to DER format the same way
|
||||
// lbry SDK does as this is the bytes that are put into protobuf and the same bytes are used for verify signatures.
|
||||
// Making sure these
|
||||
func TestPublicKeyToDER(t *testing.T) {
|
||||
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||
cert_claim, err := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
p1, err := getPublicKeyFromBytes(cert_claim.Claim.GetChannel().PublicKey)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
pubkeyBytes2, err := PublicKeyToDER(p1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
for i, b := range cert_claim.Claim.GetChannel().PublicKey {
|
||||
assert.Assert(t, b == pubkeyBytes2[i], "DER format in bytes must match!")
|
||||
}
|
||||
|
||||
p2, err := getPublicKeyFromBytes(pubkeyBytes2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, p1.IsEqual(p2), "The keys produced must be the same key!")
|
||||
}
|
|
@ -3,121 +3,155 @@ package claim
|
|||
import (
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
v1pb "github.com/lbryio/types/v1/go"
|
||||
pb "github.com/lbryio/types/v2/go"
|
||||
|
||||
"github.com/btcsuite/btcutil/base58"
|
||||
"github.com/lbryio/types/go"
|
||||
)
|
||||
|
||||
const lbrySDHash = "lbry_sd_hash"
|
||||
|
||||
func newClaim() *pb.Claim {
|
||||
pbClaim := new(pb.Claim)
|
||||
func newStreamClaim() *pb.Claim {
|
||||
claimStream := new(pb.Claim_Stream)
|
||||
stream := new(pb.Stream)
|
||||
metadata := new(pb.Metadata)
|
||||
source := new(pb.Source)
|
||||
pubSig := new(pb.Signature)
|
||||
fee := new(pb.Fee)
|
||||
metadata.Fee = fee
|
||||
stream.Metadata = metadata
|
||||
stream.Source = source
|
||||
pbClaim.Stream = stream
|
||||
pbClaim.PublisherSignature = pubSig
|
||||
stream.File = new(pb.File)
|
||||
|
||||
//Fee version
|
||||
feeVersion := pb.Fee__0_0_1
|
||||
pbClaim.GetStream().GetMetadata().GetFee().Version = &feeVersion
|
||||
//Metadata version
|
||||
mdVersion := pb.Metadata__0_1_0
|
||||
pbClaim.GetStream().GetMetadata().Version = &mdVersion
|
||||
//Source version
|
||||
srcVersion := pb.Source__0_0_1
|
||||
pbClaim.GetStream().GetSource().Version = &srcVersion
|
||||
//Stream version
|
||||
streamVersion := pb.Stream__0_0_1
|
||||
pbClaim.GetStream().Version = &streamVersion
|
||||
//Claim version
|
||||
clmVersion := pb.Claim__0_0_1
|
||||
pbClaim.Version = &clmVersion
|
||||
//Claim type
|
||||
clmType := pb.Claim_streamType
|
||||
pbClaim.ClaimType = &clmType
|
||||
pbClaim := new(pb.Claim)
|
||||
pbClaim.Type = claimStream
|
||||
claimStream.Stream = stream
|
||||
|
||||
return pbClaim
|
||||
}
|
||||
|
||||
func setMetaData(claim pb.Claim, author string, description string, language pb.Metadata_Language, license string,
|
||||
licenseURL *string, title string, thumbnail *string, nsfw bool) {
|
||||
claim.GetStream().GetMetadata().Author = &author
|
||||
claim.GetStream().GetMetadata().Description = &description
|
||||
claim.GetStream().GetMetadata().Language = &language
|
||||
claim.GetStream().GetMetadata().License = &license
|
||||
claim.GetStream().GetMetadata().Title = &title
|
||||
claim.GetStream().GetMetadata().Thumbnail = thumbnail
|
||||
claim.GetStream().GetMetadata().Nsfw = &nsfw
|
||||
claim.GetStream().GetMetadata().LicenseUrl = licenseURL
|
||||
func newChannelClaim() *pb.Claim {
|
||||
claimChannel := new(pb.Claim_Channel)
|
||||
channel := new(pb.Channel)
|
||||
|
||||
pbClaim := new(pb.Claim)
|
||||
pbClaim.Type = claimChannel
|
||||
claimChannel.Channel = channel
|
||||
|
||||
return pbClaim
|
||||
}
|
||||
|
||||
func setMetaData(claim pb.Claim, author string, description string, language pb.Language_Language, license string,
|
||||
licenseURL *string, title string, thumbnail *string, nsfw bool) {
|
||||
claim.GetStream().Author = author
|
||||
claim.GetStream().Description = description
|
||||
claim.GetStream().Languages = []*pb.Language{{Language: language}}
|
||||
claim.GetStream().Title = title
|
||||
if thumbnail != nil {
|
||||
claim.GetStream().ThumbnailUrl = *thumbnail
|
||||
}
|
||||
claim.GetStream().Tags = []string{"mature"}
|
||||
claim.GetStream().License = license
|
||||
if licenseURL != nil {
|
||||
claim.GetStream().LicenseUrl = *licenseURL
|
||||
}
|
||||
}
|
||||
|
||||
func migrateV1PBClaim(vClaim v1pb.Claim) (*pb.Claim, error) {
|
||||
if *vClaim.ClaimType == v1pb.Claim_streamType {
|
||||
return migrateV1PBStream(vClaim)
|
||||
}
|
||||
if *vClaim.ClaimType == v1pb.Claim_certificateType {
|
||||
return migrateV1PBChannel(vClaim)
|
||||
}
|
||||
return nil, errors.Err("Could not migrate v1 protobuf claim due to unknown type '%s'.", vClaim.ClaimType.String())
|
||||
}
|
||||
|
||||
func migrateV1PBStream(vClaim v1pb.Claim) (*pb.Claim, error) {
|
||||
claim := newStreamClaim()
|
||||
claim.GetStream().MediaType = vClaim.GetStream().GetSource().GetContentType()
|
||||
md := vClaim.GetStream().GetMetadata()
|
||||
if md.GetFee() != nil {
|
||||
claim.GetStream().Fee = new(pb.Fee)
|
||||
claim.GetStream().GetFee().Amount = uint64(*md.GetFee().Amount * 100000000)
|
||||
claim.GetStream().GetFee().Address = md.GetFee().GetAddress()
|
||||
claim.GetStream().GetFee().Currency = pb.Fee_Currency(pb.Fee_Currency_value[md.GetFee().GetCurrency().String()])
|
||||
}
|
||||
claim.GetStream().SdHash = vClaim.GetStream().GetSource().GetSource()
|
||||
if vClaim.GetStream().GetMetadata().GetNsfw() {
|
||||
claim.GetStream().Tags = []string{"mature"}
|
||||
}
|
||||
claim.GetStream().ThumbnailUrl = md.GetThumbnail()
|
||||
language := pb.Language_Language(pb.Language_Language_value[md.GetLanguage().String()])
|
||||
claim.GetStream().Languages = []*pb.Language{{Language: language}}
|
||||
claim.GetStream().LicenseUrl = md.GetLicenseUrl()
|
||||
claim.GetStream().License = md.GetLicense()
|
||||
claim.GetStream().Title = md.GetTitle()
|
||||
claim.GetStream().Description = md.GetDescription()
|
||||
claim.GetStream().Author = md.GetAuthor()
|
||||
|
||||
return claim, nil
|
||||
}
|
||||
|
||||
func migrateV1PBChannel(vClaim v1pb.Claim) (*pb.Claim, error) {
|
||||
claim := newChannelClaim()
|
||||
claim.GetChannel().PublicKey = vClaim.GetCertificate().PublicKey
|
||||
|
||||
return claim, nil
|
||||
}
|
||||
|
||||
func migrateV1Claim(vClaim V1Claim) (*pb.Claim, error) {
|
||||
pbClaim := newClaim()
|
||||
//Not part of json V1
|
||||
pbClaim.PublisherSignature = nil
|
||||
pbClaim := newStreamClaim()
|
||||
//Stream
|
||||
// -->Universal
|
||||
setFee(vClaim.Fee, pbClaim)
|
||||
// -->MetaData
|
||||
language := pb.Metadata_Language(pb.Metadata_Language_value[vClaim.Language])
|
||||
language := pb.Language_Language(pb.Language_Language_value[vClaim.Language])
|
||||
setMetaData(*pbClaim, vClaim.Author, vClaim.Description, language,
|
||||
vClaim.License, nil, vClaim.Title, vClaim.Thumbnail, false)
|
||||
// -->Source
|
||||
pbClaim.GetStream().GetSource().ContentType = &vClaim.ContentType
|
||||
sourceType := pb.Source_SourceTypes(pb.Source_SourceTypes_value[lbrySDHash])
|
||||
pbClaim.GetStream().GetSource().SourceType = &sourceType
|
||||
pbClaim.GetStream().MediaType = vClaim.ContentType
|
||||
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
|
||||
pbClaim.GetStream().GetSource().Source = src
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
pbClaim.GetStream().SdHash = src
|
||||
|
||||
return pbClaim, err
|
||||
return pbClaim, nil
|
||||
}
|
||||
|
||||
func migrateV2Claim(vClaim V2Claim) (*pb.Claim, error) {
|
||||
pbClaim := newClaim()
|
||||
//Not part of json V2
|
||||
pbClaim.PublisherSignature = nil
|
||||
pbClaim := newStreamClaim()
|
||||
//Stream
|
||||
// -->Fee
|
||||
setFee(vClaim.Fee, pbClaim)
|
||||
// -->MetaData
|
||||
language := pb.Metadata_Language(pb.Metadata_Language_value[vClaim.Language])
|
||||
language := pb.Language_Language(pb.Language_Language_value[vClaim.Language])
|
||||
setMetaData(*pbClaim, vClaim.Author, vClaim.Description, language,
|
||||
vClaim.License, vClaim.LicenseURL, vClaim.Title, vClaim.Thumbnail, vClaim.NSFW)
|
||||
// -->Source
|
||||
pbClaim.GetStream().GetSource().ContentType = &vClaim.ContentType
|
||||
sourceType := pb.Source_SourceTypes(pb.Source_SourceTypes_value[lbrySDHash])
|
||||
pbClaim.GetStream().GetSource().SourceType = &sourceType
|
||||
pbClaim.GetStream().MediaType = vClaim.ContentType
|
||||
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
|
||||
pbClaim.GetStream().GetSource().Source = src
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
pbClaim.GetStream().SdHash = src
|
||||
|
||||
return pbClaim, err
|
||||
return pbClaim, nil
|
||||
}
|
||||
|
||||
func migrateV3Claim(vClaim V3Claim) (*pb.Claim, error) {
|
||||
pbClaim := newClaim()
|
||||
//Not part of json V3
|
||||
pbClaim.PublisherSignature = nil
|
||||
pbClaim := newStreamClaim()
|
||||
//Stream
|
||||
// -->Fee
|
||||
setFee(vClaim.Fee, pbClaim)
|
||||
// -->MetaData
|
||||
language := pb.Metadata_Language(pb.Metadata_Language_value[vClaim.Language])
|
||||
language := pb.Language_Language(pb.Language_Language_value[vClaim.Language])
|
||||
setMetaData(*pbClaim, vClaim.Author, vClaim.Description, language,
|
||||
vClaim.License, vClaim.LicenseURL, vClaim.Title, vClaim.Thumbnail, vClaim.NSFW)
|
||||
// -->Source
|
||||
pbClaim.GetStream().GetSource().ContentType = &vClaim.ContentType
|
||||
sourceType := pb.Source_SourceTypes(pb.Source_SourceTypes_value[lbrySDHash])
|
||||
pbClaim.GetStream().GetSource().SourceType = &sourceType
|
||||
pbClaim.GetStream().MediaType = vClaim.ContentType
|
||||
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
|
||||
pbClaim.GetStream().GetSource().Source = src
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
pbClaim.GetStream().SdHash = src
|
||||
|
||||
return pbClaim, err
|
||||
return pbClaim, nil
|
||||
}
|
||||
|
||||
func setFee(fee *Fee, pbClaim *pb.Claim) {
|
||||
|
@ -138,9 +172,10 @@ func setFee(fee *Fee, pbClaim *pb.Claim) {
|
|||
currency = pb.Fee_USD
|
||||
address = fee.USD.Address
|
||||
}
|
||||
pbClaim.GetStream().Fee = new(pb.Fee)
|
||||
//Fee Settings
|
||||
pbClaim.GetStream().GetMetadata().GetFee().Amount = &amount
|
||||
pbClaim.GetStream().GetMetadata().GetFee().Currency = ¤cy
|
||||
pbClaim.GetStream().GetMetadata().GetFee().Address = base58.Decode(address)
|
||||
pbClaim.GetStream().GetFee().Amount = uint64(amount * 100000000)
|
||||
pbClaim.GetStream().GetFee().Currency = currency
|
||||
pbClaim.GetStream().GetFee().Address = base58.Decode(address)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
|
||||
"github.com/btcsuite/btcutil/base58"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
type valueTestPair struct {
|
||||
|
@ -51,7 +55,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"LBC",
|
||||
"bPwGA9h7uijoy5uAvzVPQw9QyLoYZehHJo",
|
||||
"application/octet-stream",
|
||||
"UNKNOWN_LANGUAGE", //"English" is not supported for conversion.
|
||||
"", //"English" is not supported for conversion.
|
||||
"bd94033d13f4f3908708701caf565bfa09cfadf2f34fadf4a73fb86b295d1b21a7e64805994e45b5fbc650f30bac4874",
|
||||
"/homerobert/lbry/speed.jpg",
|
||||
false,
|
||||
|
@ -68,7 +72,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"LBC",
|
||||
"bLVs3ifPruyZnpYmFfT2TLAmhqZvgjpQDa",
|
||||
"video/quicktime",
|
||||
"en",
|
||||
"language:en ",
|
||||
"dcc1bf28893a5037eab9e4a9cd7a4bfe6f76ad6c21970ea4ceee0122f502ef079657d4dca456b4be3249849c4e1868b8",
|
||||
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
|
||||
false,
|
||||
|
@ -85,7 +89,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"UNKNOWN_CURRENCY",
|
||||
"",
|
||||
"video/mp4",
|
||||
"en",
|
||||
"language:en ",
|
||||
"799a1de93b8e556d7f668103a6ffc48ac5fd6801dd4d89cae6773c80d81c283710fd4fd25ed68d0dbeee268f82914145",
|
||||
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
|
||||
false,
|
||||
|
@ -102,7 +106,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"USD",
|
||||
"bMHmZKZbPq6bPBEQFc8MXpiDhF9f7MVxMR",
|
||||
"video/mp4",
|
||||
"en",
|
||||
"language:en ",
|
||||
"2bd8d9dd1a218c7f56717e53fa510efd5a8c089ed1f2675a0f8d0b5b8bb3c1ed383cb9f3aeb9b891789761305293979a",
|
||||
"",
|
||||
false,
|
||||
|
@ -119,7 +123,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"LBC",
|
||||
"bVPqWwYfvjBHYBouuvknbQMXUZFvLdEs5M",
|
||||
"text/plain",
|
||||
"en",
|
||||
"language:en ",
|
||||
"7c21ee237324e5a50a3425620fe6cc400d3cccc05519867cda1b9c10a977194e31200414d87146bff470bab7f7d75478",
|
||||
"",
|
||||
false,
|
||||
|
@ -136,7 +140,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"USD",
|
||||
"bHSe3KAvtVSR4m6S11zduuF9XHtwscDjoE",
|
||||
"audio/mpeg",
|
||||
"en",
|
||||
"language:en ",
|
||||
"340e1dda0e8414c21fafbb1f28f2c8b384821fe0d1e2a7143a4810545e64e26a4105042d4d47dc9754b618ecdfe0d191",
|
||||
"http://i.imgur.com/lyKEHZc.jpg",
|
||||
false,
|
||||
|
@ -153,7 +157,7 @@ var jsonVersionTests = []valueTestPair{
|
|||
"LBC",
|
||||
"bRTxtCUpj6TvJHgWcRsGcHaFyrRLkkiXgG",
|
||||
"video/mp4",
|
||||
"en",
|
||||
"language:en ",
|
||||
"fc0dac5cfc526354963ff1769f6e739c4e42a0790420ffab9fa3b6401e93ae5a0515eff960f8c9c272907eda6fcba254",
|
||||
"",
|
||||
true,
|
||||
|
@ -184,40 +188,95 @@ func TestMigrationFromJSON(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error("Decode error: ", err)
|
||||
}
|
||||
if helper.Claim.GetStream().GetMetadata().GetAuthor() != pair.Claim.Author {
|
||||
t.Error("Author mismatch: expected", pair.Claim.Author, "got", helper.Claim.GetStream().GetMetadata().GetAuthor())
|
||||
if helper.Claim.GetStream().GetAuthor() != pair.Claim.Author {
|
||||
t.Error("Author mismatch: expected", pair.Claim.Author, "got", helper.Claim.GetStream().GetAuthor())
|
||||
}
|
||||
if helper.Claim.GetStream().GetMetadata().GetTitle() != pair.Claim.Title {
|
||||
t.Error("Title mismatch: expected", pair.Claim.Title, "got", helper.Claim.GetStream().GetMetadata().GetTitle())
|
||||
if helper.Claim.GetStream().GetTitle() != pair.Claim.Title {
|
||||
t.Error("Title mismatch: expected", pair.Claim.Title, "got", helper.Claim.GetStream().GetTitle())
|
||||
}
|
||||
if helper.Claim.GetStream().GetMetadata().GetDescription() != pair.Claim.Description {
|
||||
t.Error("Description mismatch: expected", pair.Claim.Description, "got", helper.Claim.GetStream().GetMetadata().GetDescription())
|
||||
if helper.Claim.GetStream().GetDescription() != pair.Claim.Description {
|
||||
t.Error("Description mismatch: expected", pair.Claim.Description, "got", helper.Claim.GetStream().GetDescription())
|
||||
}
|
||||
if helper.Claim.GetStream().GetMetadata().GetLicense() != pair.Claim.License {
|
||||
t.Error("License mismatch: expected", pair.Claim.License, "got", helper.Claim.GetStream().GetMetadata().GetLicense())
|
||||
if helper.Claim.GetStream().GetLicense() != pair.Claim.License {
|
||||
t.Error("License mismatch: expected", pair.Claim.License, "got", helper.Claim.GetStream().GetLicense())
|
||||
}
|
||||
if helper.Claim.GetStream().GetMetadata().GetLicenseUrl() != pair.Claim.LicenseURL {
|
||||
t.Error("LicenseURL mismatch: expected", pair.Claim.LicenseURL, "got", helper.Claim.GetStream().GetMetadata().GetLicenseUrl())
|
||||
if helper.Claim.GetStream().GetLicenseUrl() != pair.Claim.LicenseURL {
|
||||
t.Error("LicenseURL mismatch: expected", pair.Claim.LicenseURL, "got", helper.Claim.GetStream().GetLicenseUrl())
|
||||
}
|
||||
if helper.Claim.GetStream().GetMetadata().GetFee().GetAmount() != pair.Claim.FeeAmount {
|
||||
t.Error("Fee Amount mismatch: expected", pair.Claim.FeeAmount, "got", helper.Claim.GetStream().GetMetadata().GetFee().GetAmount())
|
||||
if helper.Claim.GetStream().GetFee().GetAmount() != uint64(pair.Claim.FeeAmount*100000000) {
|
||||
t.Error("Fee Amount mismatch: expected", pair.Claim.FeeAmount, "got", helper.Claim.GetStream().GetFee().GetAmount())
|
||||
}
|
||||
if helper.Claim.GetStream().GetMetadata().GetFee().GetCurrency().String() != pair.Claim.FeeCurrency {
|
||||
t.Error("Fee Currency mismatch: expected", pair.Claim.FeeCurrency, "got", helper.Claim.GetStream().GetMetadata().GetFee().GetCurrency())
|
||||
if helper.Claim.GetStream().GetFee().GetCurrency().String() != pair.Claim.FeeCurrency {
|
||||
t.Error("Fee Currency mismatch: expected", pair.Claim.FeeCurrency, "got", helper.Claim.GetStream().GetFee().GetCurrency())
|
||||
}
|
||||
hexaddress := base58.Encode(helper.Claim.GetStream().GetMetadata().GetFee().GetAddress())
|
||||
hexaddress := base58.Encode(helper.Claim.GetStream().GetFee().GetAddress())
|
||||
if hexaddress != pair.Claim.FeeAddress {
|
||||
t.Error("Fee Address mismatch: expected", pair.Claim.FeeAddress, "got", hexaddress)
|
||||
}
|
||||
if helper.Claim.GetStream().GetSource().GetContentType() != pair.Claim.ContentType {
|
||||
t.Error("ContentType mismatch: expected", pair.Claim.ContentType, "got", helper.Claim.GetStream().GetSource().GetContentType())
|
||||
if helper.Claim.GetStream().GetMediaType() != pair.Claim.ContentType {
|
||||
t.Error("ContentType mismatch: expected", pair.Claim.ContentType, "got", helper.Claim.GetStream().GetMediaType())
|
||||
}
|
||||
if helper.Claim.GetStream().GetMetadata().GetLanguage().String() != pair.Claim.Language {
|
||||
t.Error("Language mismatch: expected ", pair.Claim.Language, " got ", helper.Claim.GetStream().GetMetadata().GetLanguage().String())
|
||||
if helper.Claim.GetStream().GetLanguages()[0].String() != pair.Claim.Language {
|
||||
t.Error("Language mismatch: expected ", pair.Claim.Language, " got ", helper.Claim.GetStream().GetLanguages()[0].String())
|
||||
}
|
||||
content := hex.EncodeToString(helper.Claim.GetStream().GetSource().GetSource())
|
||||
content := hex.EncodeToString(helper.Claim.GetStream().GetSdHash())
|
||||
if content != pair.Claim.LbrySDHash {
|
||||
t.Error("Source mismatch: expected", pair.Claim.LbrySDHash, "got", content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrationFromV1YTSync(t *testing.T) {
|
||||
claimHex := "080110011aee04080112a604080410011a2b4865726520617265203520526561736f6e73204920e29da4efb88f204e657874636c6f7564207c20544c4722920346696e64206f7574206d6f72652061626f7574204e657874636c6f75643a2068747470733a2f2f6e657874636c6f75642e636f6d2f0a0a596f752063616e2066696e64206d65206f6e20746865736520736f6369616c733a0a202a20466f72756d733a2068747470733a2f2f666f72756d2e6865617679656c656d656e742e696f2f0a202a20506f64636173743a2068747470733a2f2f6f6666746f706963616c2e6e65740a202a2050617472656f6e3a2068747470733a2f2f70617472656f6e2e636f6d2f7468656c696e757867616d65720a202a204d657263683a2068747470733a2f2f746565737072696e672e636f6d2f73746f7265732f6f6666696369616c2d6c696e75782d67616d65720a202a205477697463683a2068747470733a2f2f7477697463682e74762f786f6e64616b0a202a20547769747465723a2068747470733a2f2f747769747465722e636f6d2f7468656c696e757867616d65720a0a2e2e2e0a68747470733a2f2f7777772e796f75747562652e636f6d2f77617463683f763d4672546442434f535f66632a0f546865204c696e75782047616d6572321c436f7079726967687465642028636f6e7461637420617574686f722938004a2968747470733a2f2f6265726b2e6e696e6a612f7468756d626e61696c732f4672546442434f535f666352005a001a41080110011a30040e8ac6e89c061f982528c23ad33829fd7146435bf7a4cc22f0bff70c4fe0b91fd36da9a375e3e1c171db825bf5d1f32209766964656f2f6d70342a5c080110031a4062b2dd4c45e364030fbfad1a6fefff695ebf20ea33a5381b947753e2a0ca359989a5cc7d15e5392a0d354c0b68498382b2701b22c03beb8dcb91089031b871e72214feb61536c007cdf4faeeaab4876cb397feaf6b51"
|
||||
claim, err := DecodeClaimHex(claimHex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, claim.GetStream().GetTitle() == "Here are 5 Reasons I ❤️ Nextcloud | TLG")
|
||||
assert.Assert(t, claim.GetStream().GetDescription() == "Find out more about Nextcloud: https://nextcloud.com/\n\nYou can find me on these socials:\n * Forums: https://forum.heavyelement.io/\n * Podcast: https://offtopical.net\n * Patreon: https://patreon.com/thelinuxgamer\n * Merch: https://teespring.com/stores/official-linux-gamer\n * Twitch: https://twitch.tv/xondak\n * Twitter: https://twitter.com/thelinuxgamer\n\n...\nhttps://www.youtube.com/watch?v=FrTdBCOS_fc")
|
||||
assert.Assert(t, claim.GetStream().GetLicense() == "Copyrighted (contact author)")
|
||||
assert.Assert(t, claim.GetStream().GetAuthor() == "The Linux Gamer")
|
||||
//?assert.Assert(t, claim.GetStream().GetLanguages()[0])
|
||||
assert.Assert(t, claim.GetStream().GetMediaType() == "video/mp4")
|
||||
assert.Assert(t, claim.GetStream().GetThumbnailUrl() == "https://berk.ninja/thumbnails/FrTdBCOS_fc")
|
||||
sdHashBytes, err := hex.DecodeString("040e8ac6e89c061f982528c23ad33829fd7146435bf7a4cc22f0bff70c4fe0b91fd36da9a375e3e1c171db825bf5d1f3")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, bytes.Equal(claim.GetStream().GetSdHash(), sdHashBytes))
|
||||
|
||||
channelHex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a034200043878b1edd4a1373149909ef03f4339f6da9c2bd2214c040fd2e530463ffe66098eca14fc70b50ff3aefd106049a815f595ed5a13eda7419ad78d9ed7ae473f17"
|
||||
channel, err := DecodeClaimHex(channelHex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
pubKeyBytes, err := hex.DecodeString("3056301006072a8648ce3d020106052b8104000a034200043878b1edd4a1373149909ef03f4339f6da9c2bd2214c040fd2e530463ffe66098eca14fc70b50ff3aefd106049a815f595ed5a13eda7419ad78d9ed7ae473f17")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, bytes.Equal(pubKeyBytes, channel.GetChannel().GetPublicKey()))
|
||||
}
|
||||
|
||||
func TestMigrationFromV1UnsignedWithFee(t *testing.T) {
|
||||
claimHex := "080110011ad6010801127c080410011a08727067206d69646922046d6964692a08727067206d696469322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a19553f00bc139bbf40de425f94d51fffb34c1bea6d9171cd374c25000070414a0052005a001a54080110011a301f41eb0312aa7e8a5ce49349bc77d811da975833719d751523b19f123fc3d528d6a94e3446ccddb7b9329f27a9cad7e3221c6170706c69636174696f6e2f782d7a69702d636f6d70726573736564"
|
||||
claim, err := DecodeClaimHex(claimHex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, claim.GetStream().GetTitle() == "rpg midi")
|
||||
assert.Assert(t, claim.GetStream().GetDescription() == "midi")
|
||||
assert.Assert(t, claim.GetStream().GetLicense() == "Creative Commons Attribution 4.0 International")
|
||||
assert.Assert(t, claim.GetStream().GetAuthor() == "rpg midi")
|
||||
//assert.Assert(t, claim.GetStream().GetLanguage() == "en")
|
||||
assert.Assert(t, claim.GetStream().GetMediaType() == "application/x-zip-compressed")
|
||||
sdHashBytes, err := hex.DecodeString("1f41eb0312aa7e8a5ce49349bc77d811da975833719d751523b19f123fc3d528d6a94e3446ccddb7b9329f27a9cad7e3")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Assert(t, bytes.Equal(claim.GetStream().GetSdHash(), sdHashBytes))
|
||||
feeAddressBytes, err := address.DecodeAddress("bJUQ9MxS9N6M29zsA5GTpVSDzsnPjMBBX9", "lbrycrd_main")
|
||||
assert.Assert(t, bytes.Equal(claim.GetStream().GetFee().GetAddress(), feeAddressBytes[:]))
|
||||
assert.Assert(t, claim.GetStream().GetFee().GetAmount() == 1500000000)
|
||||
assert.Assert(t, claim.GetStream().GetFee().GetCurrency().String() == "LBC")
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package claim
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/lbryio/lbry.go/errors"
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
)
|
||||
|
||||
// V1Claim is the first version of claim metadata used by lbry.
|
||||
|
|
|
@ -2,43 +2,50 @@ package claim
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
legacy "github.com/lbryio/types/v1/go"
|
||||
pb "github.com/lbryio/types/v2/go"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/lbryio/types/go"
|
||||
)
|
||||
|
||||
func (c *ClaimHelper) Serialized() ([]byte, error) {
|
||||
func (c *ClaimHelper) serialized() ([]byte, error) {
|
||||
serialized := c.String()
|
||||
if serialized == "" {
|
||||
return nil, errors.New("not initialized")
|
||||
return nil, errors.Err("not initialized")
|
||||
}
|
||||
v := c.GetVersion()
|
||||
t := c.GetClaimType()
|
||||
|
||||
return proto.Marshal(
|
||||
&pb.Claim{
|
||||
Version: &v,
|
||||
ClaimType: &t,
|
||||
Stream: c.GetStream(),
|
||||
Certificate: c.GetCertificate(),
|
||||
PublisherSignature: c.GetPublisherSignature()})
|
||||
if c.LegacyClaim != nil {
|
||||
return proto.Marshal(c.getLegacyProtobuf())
|
||||
}
|
||||
|
||||
return proto.Marshal(c.getProtobuf())
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) GetProtobuf() *pb.Claim {
|
||||
v := c.GetVersion()
|
||||
t := c.GetClaimType()
|
||||
func (c *ClaimHelper) getProtobuf() *pb.Claim {
|
||||
if c.GetChannel() != nil {
|
||||
return &pb.Claim{Type: &pb.Claim_Channel{Channel: c.GetChannel()}}
|
||||
} else if c.GetStream() != nil {
|
||||
return &pb.Claim{Type: &pb.Claim_Stream{Stream: c.GetStream()}}
|
||||
}
|
||||
|
||||
return &pb.Claim{
|
||||
Version: &v,
|
||||
ClaimType: &t,
|
||||
Stream: c.GetStream(),
|
||||
Certificate: c.GetCertificate(),
|
||||
PublisherSignature: c.GetPublisherSignature()}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) SerializedHexString() (string, error) {
|
||||
serialized, err := c.Serialized()
|
||||
func (c *ClaimHelper) getLegacyProtobuf() *legacy.Claim {
|
||||
v := c.LegacyClaim.GetVersion()
|
||||
t := c.LegacyClaim.GetClaimType()
|
||||
return &legacy.Claim{
|
||||
Version: &v,
|
||||
ClaimType: &t,
|
||||
Stream: c.LegacyClaim.GetStream(),
|
||||
Certificate: c.LegacyClaim.GetCertificate(),
|
||||
PublisherSignature: c.LegacyClaim.GetPublisherSignature()}
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) serializedHexString() (string, error) {
|
||||
serialized, err := c.serialized()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -46,21 +53,26 @@ func (c *ClaimHelper) SerializedHexString() (string, error) {
|
|||
return serialized_hex, nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) SerializedNoSignature() ([]byte, error) {
|
||||
func (c *ClaimHelper) serializedNoSignature() ([]byte, error) {
|
||||
if c.String() == "" {
|
||||
return nil, errors.New("not initialized")
|
||||
return nil, errors.Err("not initialized")
|
||||
}
|
||||
if c.GetPublisherSignature() == nil {
|
||||
serialized, err := c.Serialized()
|
||||
if c.Signature == nil {
|
||||
serialized, err := c.serialized()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return serialized, nil
|
||||
} else {
|
||||
clone := &pb.Claim{}
|
||||
proto.Merge(clone, c.GetProtobuf())
|
||||
if c.LegacyClaim != nil {
|
||||
clone := &legacy.Claim{}
|
||||
proto.Merge(clone, c.getLegacyProtobuf())
|
||||
proto.ClearAllExtensions(clone.PublisherSignature)
|
||||
clone.PublisherSignature = nil
|
||||
return proto.Marshal(clone)
|
||||
}
|
||||
clone := &pb.Claim{}
|
||||
proto.Merge(clone, c.getProtobuf())
|
||||
return proto.Marshal(clone)
|
||||
}
|
||||
}
|
||||
|
|
112
claim/sign.go
Normal file
112
claim/sign.go
Normal file
|
@ -0,0 +1,112 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
func Sign(privKey btcec.PrivateKey, channel ClaimHelper, claim ClaimHelper, k string) (*Signature, error) {
|
||||
if channel.GetChannel() == nil {
|
||||
return nil, errors.Err("claim as channel is not of type channel")
|
||||
}
|
||||
if claim.LegacyClaim != nil {
|
||||
return claim.signV1(privKey, channel, k)
|
||||
}
|
||||
|
||||
return claim.sign(privKey, channel, k)
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) sign(privKey btcec.PrivateKey, channel ClaimHelper, firstInputTxID string) (*Signature, error) {
|
||||
|
||||
txidBytes, err := hex.DecodeString(firstInputTxID)
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
|
||||
metadataBytes, err := c.serialized()
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
|
||||
var digest []byte
|
||||
digest = append(digest, txidBytes...)
|
||||
digest = append(digest, c.ClaimID...)
|
||||
digest = append(digest, metadataBytes...)
|
||||
hash := sha256.Sum256(digest)
|
||||
hashBytes := make([]byte, len(hash))
|
||||
for i, b := range hash {
|
||||
hashBytes[i] = b
|
||||
}
|
||||
|
||||
sig, err := privKey.Sign(hashBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
|
||||
return &Signature{*sig}, nil
|
||||
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) signV1(privKey btcec.PrivateKey, channel ClaimHelper, claimAddress string) (*Signature, error) {
|
||||
metadataBytes, err := c.serializedNoSignature()
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
|
||||
addressBytes, err := address.DecodeAddress(claimAddress, "lbrycrd_main")
|
||||
if err != nil {
|
||||
return nil, errors.Prefix("V1 signing requires claim address and the decode failed with: ", err)
|
||||
}
|
||||
|
||||
var digest []byte
|
||||
|
||||
address := make([]byte, len(addressBytes))
|
||||
for i, b := range addressBytes {
|
||||
address[i] = b
|
||||
}
|
||||
|
||||
digest = append(digest, address...)
|
||||
digest = append(digest, metadataBytes...)
|
||||
digest = append(digest, channel.ClaimID...)
|
||||
|
||||
hash := sha256.Sum256(digest)
|
||||
hashBytes := make([]byte, len(hash))
|
||||
for i, b := range hash {
|
||||
hashBytes[i] = b
|
||||
}
|
||||
|
||||
sig, err := privKey.Sign(hashBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Err(err)
|
||||
}
|
||||
|
||||
return &Signature{*sig}, nil
|
||||
}
|
||||
|
||||
type Signature struct {
|
||||
btcec.Signature
|
||||
}
|
||||
|
||||
func (s *Signature) LBRYSDKEncode() ([]byte, error) {
|
||||
if s.R == nil || s.S == nil {
|
||||
return nil, errors.Err("invalid signature, both S & R are nil")
|
||||
}
|
||||
rBytes := s.R.Bytes()
|
||||
sBytes := s.S.Bytes()
|
||||
|
||||
return append(rBytes, sBytes...), nil
|
||||
}
|
||||
|
||||
// rev reverses a byte slice. useful for switching endian-ness
|
||||
func reverseBytes(b []byte) []byte {
|
||||
r := make([]byte, len(b))
|
||||
for left, right := 0, len(b)-1; left < right; left, right = left+1, right-1 {
|
||||
r[left], r[right] = b[right], b[left]
|
||||
}
|
||||
return r
|
||||
}
|
137
claim/sign_test.go
Normal file
137
claim/sign_test.go
Normal file
|
@ -0,0 +1,137 @@
|
|||
package claim
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
privateKey, err := btcec.NewPrivateKey(btcec.S256())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
channel := &ClaimHelper{newChannelClaim(), nil, nil, NoSig, nil}
|
||||
pubkeyBytes, err := PublicKeyToDER(privateKey.PubKey())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
channel.GetChannel().PublicKey = pubkeyBytes
|
||||
claimID := "cf3f7c898af87cc69b06a6ac7899efb9a4878fdb" //Fake
|
||||
txid := "4c1df9e022e396859175f9bfa69b38e444db10fb53355fa99a0989a83bcdb82f" //Fake
|
||||
claimIDHexBytes, err := hex.DecodeString(claimID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
claim := &ClaimHelper{newStreamClaim(), nil, reverseBytes(claimIDHexBytes), WithSig, nil}
|
||||
claim.Claim.GetStream().Title = "Test title"
|
||||
claim.Claim.GetStream().Description = "Test description"
|
||||
sig, err := Sign(*privateKey, *channel, *claim, txid)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
signatureBytes, err := sig.LBRYSDKEncode()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
claim.Signature = signatureBytes
|
||||
|
||||
rawChannel, err := channel.CompileValue()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
rawClaim, err := claim.CompileValue()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
channel, err = DecodeClaimBytes(rawChannel, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
claim, err = DecodeClaimBytes(rawClaim, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
valid, err := claim.ValidateClaimSignature(channel, txid, claimID, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Assert(t, valid, "could not verify signature")
|
||||
|
||||
}
|
||||
|
||||
func TestSignWithV1Channel(t *testing.T) {
|
||||
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||
channel, err := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
privateKey, err := btcec.NewPrivateKey(btcec.S256())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
pubkeyBytes, err := PublicKeyToDER(privateKey.PubKey())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
channel.GetChannel().PublicKey = pubkeyBytes
|
||||
|
||||
claimID := "251305ca93d4dbedb50dceb282ebcb7b07b7ac64"
|
||||
txid := "4c1df9e022e396859175f9bfa69b38e444db10fb53355fa99a0989a83bcdb82f" //Fake
|
||||
claimIDHexBytes, err := hex.DecodeString(claimID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
claim := &ClaimHelper{newStreamClaim(), nil, reverseBytes(claimIDHexBytes), WithSig, nil}
|
||||
claim.Claim.GetStream().Title = "Test title"
|
||||
claim.Claim.GetStream().Description = "Test description"
|
||||
sig, err := Sign(*privateKey, *channel, *claim, txid)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
signatureBytes, err := sig.LBRYSDKEncode()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
claim.Signature = signatureBytes
|
||||
compiledClaim, err := claim.CompileValue()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
claim, err = DecodeClaimBytes(compiledClaim, "lbrycrd_main")
|
||||
|
||||
valid, err := claim.ValidateClaimSignature(channel, txid, claimID, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Assert(t, valid, "could not verify signature")
|
||||
|
||||
}
|
|
@ -6,10 +6,10 @@ import (
|
|||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
"math/big"
|
||||
|
||||
"github.com/lbryio/lbry.go/extras/errors"
|
||||
"github.com/lbryio/lbryschema.go/address"
|
||||
)
|
||||
|
||||
type publicKeyInfo struct {
|
||||
|
@ -23,86 +23,100 @@ const SECP256k1 = "SECP256k1"
|
|||
//const NIST256p = "NIST256p"
|
||||
//const NIST384p = "NIST384p"
|
||||
|
||||
func GetClaimSignatureDigest(claimAddress [25]byte, certificateId [20]byte, serializedNoSig []byte) [32]byte {
|
||||
func getClaimSignatureDigest(bytes ...[]byte) [32]byte {
|
||||
|
||||
var combined []byte
|
||||
for _, c := range claimAddress {
|
||||
combined = append(combined, c)
|
||||
}
|
||||
for _, c := range serializedNoSig {
|
||||
combined = append(combined, c)
|
||||
}
|
||||
for _, c := range certificateId {
|
||||
combined = append(combined, c)
|
||||
for _, b := range bytes {
|
||||
combined = append(combined, b...)
|
||||
}
|
||||
digest := sha256.Sum256(combined)
|
||||
return [32]byte(digest)
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) GetCertificatePublicKey() (*btcec.PublicKey, error) {
|
||||
derBytes := c.GetCertificate().GetPublicKey()
|
||||
pub := publicKeyInfo{}
|
||||
asn1.Unmarshal(derBytes, &pub)
|
||||
pubkeyBytes := []byte(pub.PublicKey.Bytes)
|
||||
p, err := btcec.ParsePubKey(pubkeyBytes, btcec.S256())
|
||||
if err != nil {
|
||||
return &btcec.PublicKey{}, err
|
||||
}
|
||||
return p, err
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) VerifyDigest(certificate *ClaimHelper, signature [64]byte, digest [32]byte) bool {
|
||||
publicKey, err := certificate.GetCertificatePublicKey()
|
||||
if err != nil {
|
||||
if certificate == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if c.PublisherSignature.SignatureType.String() == SECP256k1 {
|
||||
R := &big.Int{}
|
||||
S := &big.Int{}
|
||||
R.SetBytes(signature[0:32])
|
||||
S.SetBytes(signature[32:64])
|
||||
return ecdsa.Verify(publicKey.ToECDSA(), digest[:], R, S)
|
||||
}
|
||||
pk, err := certificate.GetPublicKey()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return ecdsa.Verify(pk.ToECDSA(), digest[:], R, S)
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) ValidateClaimSignatureBytes(certificate *ClaimHelper, claimAddress [25]byte, certificateId [20]byte, blockchainName string) (bool, error) {
|
||||
signature := c.GetPublisherSignature()
|
||||
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)
|
||||
}
|
||||
|
||||
return c.validateClaimSignature(certificate, k, certificateId, blockchainName)
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) validateClaimSignature(certificate *ClaimHelper, firstInputTxID, certificateId string, blockchainName string) (bool, error) {
|
||||
certificateIdSlice, err := hex.DecodeString(certificateId)
|
||||
if err != nil {
|
||||
return false, errors.Err(err)
|
||||
}
|
||||
certificateIdSlice = reverseBytes(certificateIdSlice)
|
||||
firstInputTxIDBytes, err := hex.DecodeString(firstInputTxID)
|
||||
if err != nil {
|
||||
return false, errors.Err(err)
|
||||
}
|
||||
|
||||
signature := c.Signature
|
||||
if signature == nil {
|
||||
return false, errors.New("claim does not have a signature")
|
||||
return false, errors.Err("claim does not have a signature")
|
||||
}
|
||||
signatureSlice := signature.GetSignature()
|
||||
signatureBytes := [64]byte{}
|
||||
for i := range signatureBytes {
|
||||
signatureBytes[i] = signatureSlice[i]
|
||||
for i, b := range signature {
|
||||
signatureBytes[i] = b
|
||||
}
|
||||
|
||||
claimAddress, err := address.ValidateAddress(claimAddress, blockchainName)
|
||||
serialized, err := c.serialized()
|
||||
if err != nil {
|
||||
return false, errors.New("invalid address")
|
||||
return false, errors.Err("serialization error")
|
||||
}
|
||||
|
||||
serializedNoSig, err := c.SerializedNoSignature()
|
||||
if err != nil {
|
||||
return false, errors.New("serialization error")
|
||||
}
|
||||
|
||||
claimDigest := GetClaimSignatureDigest(claimAddress, certificateId, serializedNoSig)
|
||||
claimDigest := getClaimSignatureDigest(firstInputTxIDBytes, certificateIdSlice, serialized)
|
||||
return c.VerifyDigest(certificate, signatureBytes, claimDigest), nil
|
||||
}
|
||||
|
||||
func (c *ClaimHelper) ValidateClaimSignature(certificate *ClaimHelper, claimAddress string, certificateId string, blockchainName string) (bool, error) {
|
||||
addressBytes, err := address.DecodeAddress(claimAddress, blockchainName)
|
||||
func (c *ClaimHelper) validateV1ClaimSignature(certificate *ClaimHelper, claimAddy string, certificateId string, blockchainName string) (bool, error) {
|
||||
addressBytes, err := address.DecodeAddress(claimAddy, blockchainName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
//For V1 claim_id was incorrectly stored for claim signing.
|
||||
// So the bytes are not reversed like they are supposed to be (Endianess)
|
||||
certificateIdSlice, err := hex.DecodeString(certificateId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
certificateIdBytes := [20]byte{}
|
||||
for i := range certificateIdBytes {
|
||||
certificateIdBytes[i] = certificateIdSlice[i]
|
||||
|
||||
signature := c.Signature
|
||||
if signature == nil {
|
||||
return false, errors.Err("claim does not have a signature")
|
||||
}
|
||||
return c.ValidateClaimSignatureBytes(certificate, addressBytes, certificateIdBytes, blockchainName)
|
||||
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")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -4,12 +4,18 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateClaimSignature(t *testing.T) {
|
||||
func TestV1ValidateClaimSignature(t *testing.T) {
|
||||
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||
signed_claim_hex := "080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||
|
||||
signed_claim, _ := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||
cert_claim, _ := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
signed_claim, err := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cert_claim, err := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
claim_addr := "bSkUov7HMWpYBiXackDwRnR5ishhGHvtJt"
|
||||
cert_id := "251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||
|
@ -23,12 +29,18 @@ func TestValidateClaimSignature(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFailToValidateClaimSignature(t *testing.T) {
|
||||
func TestV1FailToValidateClaimSignature(t *testing.T) {
|
||||
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||
signed_claim_hex := "080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||
|
||||
signed_claim, _ := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||
cert_claim, _ := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
signed_claim, err := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cert_claim, err := DecodeClaimHex(cert_claim_hex, "lbrycrd_main")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
claim_addr := "bSkUov7HMWpYBiXackDwRnR5ishhGHvtJt"
|
||||
cert_id := "251305ca93d4dbedb50dceb282ebcb7b07b7ac64"
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
from ctypes import *
|
||||
|
||||
|
||||
class _GoString(Structure):
|
||||
_fields_ = [
|
||||
("p", c_char_p),
|
||||
("n", c_longlong)
|
||||
]
|
||||
|
||||
|
||||
def GoString(s):
|
||||
if not isinstance(s, (str, unicode)):
|
||||
raise TypeError("invalid type: %s" % str(type(s)))
|
||||
x = str(s)
|
||||
return _GoString(x, len(x))
|
||||
|
||||
|
||||
def GoBinding(library, *argTypes):
|
||||
"""
|
||||
Get a binding to a go function of the same name in the given .so
|
||||
The python function itself is not run, and can return or pass
|
||||
|
||||
:param argTypes: *parameter types
|
||||
"""
|
||||
|
||||
lib = cdll.LoadLibrary(library)
|
||||
|
||||
def inner(fn):
|
||||
_types = {
|
||||
str: _GoString
|
||||
}
|
||||
|
||||
_getters = {
|
||||
str: GoString
|
||||
}
|
||||
|
||||
for v in argTypes:
|
||||
if not isinstance(v, type):
|
||||
raise TypeError("invalid argument type")
|
||||
if v not in _types:
|
||||
raise TypeError("type does not have a mapping: %s" % str(type(v)))
|
||||
|
||||
_go_func = getattr(lib, fn.__name__)
|
||||
_go_func.argtypes = [_types[v] for v in argTypes]
|
||||
|
||||
def _wrap(*args):
|
||||
_args = [_getters[arg_type](arg) for arg_type, arg in zip(argTypes, args)]
|
||||
return _go_func(*tuple(_args))
|
||||
return _wrap
|
||||
return inner
|
||||
|
||||
|
||||
@GoBinding("./lbryschema-python-binding.so", str, str, str, str)
|
||||
def VerifySignature(claim, certificate, claim_address, certificate_id):
|
||||
pass
|
||||
|
||||
|
||||
cert_claim_hex = "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||
signed_claim_hex = "080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||
claim_addr = "bSkUov7HMWpYBiXackDwRnR5ishhGHvtJt"
|
||||
cert_id = "251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||
import time
|
||||
from lbryschema.decode import smart_decode
|
||||
|
||||
cd = smart_decode(signed_claim_hex)
|
||||
certd = smart_decode(cert_claim_hex)
|
||||
|
||||
|
||||
def clock_lbryschema_python(n=10.0):
|
||||
start = time.time()
|
||||
for i in range(int(n)):
|
||||
assert cd.validate_signature(claim_addr, certd)
|
||||
if i % 10 == 0:
|
||||
print i
|
||||
avg = float(time.time() - start) / n
|
||||
return 1.0 / avg
|
||||
|
||||
|
||||
def clock_lbryschema_go(n=100.0):
|
||||
start = time.time()
|
||||
for i in range(int(n)):
|
||||
assert VerifySignature(signed_claim_hex, cert_claim_hex, claim_addr, cert_id)
|
||||
if i % 10 == 0:
|
||||
print i
|
||||
avg = float(time.time() - start) / n
|
||||
return 1.0 / avg
|
||||
|
||||
print "Start"
|
||||
print "%f validations / second with python" % clock_lbryschema_python()
|
||||
print "%f validations / second with go binding" % clock_lbryschema_go()
|
||||
|
Loading…
Reference in a new issue