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
|
package address
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"github.com/lbryio/lbry.go/extras/errors"
|
||||||
"github.com/lbryio/lbryschema.go/address/base58"
|
"github.com/lbryio/lbryschema.go/address/base58"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DecodeAddress(address string, blockchainName string) ([addressLength]byte, error) {
|
func DecodeAddress(address string, blockchainName string) ([addressLength]byte, error) {
|
||||||
decoded, err := base58.DecodeBase58(address, addressLength)
|
decoded, err := base58.DecodeBase58(address, addressLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return [addressLength]byte{}, errors.New("failed to decode")
|
return [addressLength]byte{}, errors.Err("failed to decode")
|
||||||
}
|
}
|
||||||
buf := [addressLength]byte{}
|
buf := [addressLength]byte{}
|
||||||
for i, b := range decoded {
|
for i, b := range decoded {
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
package address
|
package address
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"github.com/lbryio/lbry.go/extras/errors"
|
||||||
|
|
||||||
"github.com/lbryio/lbryschema.go/address/base58"
|
"github.com/lbryio/lbryschema.go/address/base58"
|
||||||
)
|
)
|
||||||
|
|
||||||
const lbrycrdMainPubkeyPrefix = byte(85)
|
const lbrycrdMainPubkeyPrefix = byte(85)
|
||||||
const lbrycrdMainScriptPrefix = byte(122)
|
const lbrycrdMainScriptPrefix = byte(122)
|
||||||
|
|
||||||
const lbrycrdTestnetPubkeyPrefix = byte(111)
|
const lbrycrdTestnetPubkeyPrefix = byte(111)
|
||||||
const lbrycrdTestnetScriptPrefix = byte(196)
|
const lbrycrdTestnetScriptPrefix = byte(196)
|
||||||
|
|
||||||
const lbrycrdRegtestPubkeyPrefix = byte(111)
|
const lbrycrdRegtestPubkeyPrefix = byte(111)
|
||||||
const lbrycrdRegtestScriptPrefix = byte(196)
|
const lbrycrdRegtestScriptPrefix = byte(196)
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ const prefixLength = 1
|
||||||
const pubkeyLength = 20
|
const pubkeyLength = 20
|
||||||
const checksumLength = 4
|
const checksumLength = 4
|
||||||
const addressLength = prefixLength + pubkeyLength + checksumLength
|
const addressLength = prefixLength + pubkeyLength + checksumLength
|
||||||
|
|
||||||
const lbrycrdMain = "lbrycrd_main"
|
const lbrycrdMain = "lbrycrd_main"
|
||||||
const lbrycrdTestnet = "lbrycrd_testnet"
|
const lbrycrdTestnet = "lbrycrd_testnet"
|
||||||
const lbrycrdRegtest = "lbrycrd_regtest"
|
const lbrycrdRegtest = "lbrycrd_regtest"
|
||||||
|
@ -52,16 +54,16 @@ func ChecksumIsValid(address [addressLength]byte) bool {
|
||||||
|
|
||||||
func ValidateAddress(address [addressLength]byte, blockchainName string) ([addressLength]byte, error) {
|
func ValidateAddress(address [addressLength]byte, blockchainName string) ([addressLength]byte, error) {
|
||||||
if blockchainName != lbrycrdMain && blockchainName != lbrycrdTestnet && blockchainName != lbrycrdRegtest {
|
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) {
|
if !PrefixIsValid(address, blockchainName) {
|
||||||
return address, errors.New("invalid prefix")
|
return address, errors.Err("invalid prefix")
|
||||||
}
|
}
|
||||||
if !PubKeyIsValid(address) {
|
if !PubKeyIsValid(address) {
|
||||||
return address, errors.New("invalid pubkey")
|
return address, errors.Err("invalid pubkey")
|
||||||
}
|
}
|
||||||
if !ChecksumIsValid(address) {
|
if !ChecksumIsValid(address) {
|
||||||
return address, errors.New("invalid address checksum")
|
return address, errors.Err("invalid address checksum")
|
||||||
}
|
}
|
||||||
return address, nil
|
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
|
set -euxo pipefail
|
||||||
go build ./...
|
go build ./...
|
||||||
go build ./cli/lbryschema-cli.go
|
go build ./cli/lbryschema-cli.go
|
||||||
go build -o lbryschema-python-binding.so -buildmode=c-shared ./binding/lbryschema-python-binding.go
|
|
||||||
|
|
186
claim/claim.go
186
claim/claim.go
|
@ -2,53 +2,90 @@ package claim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/golang/protobuf/jsonpb"
|
"github.com/lbryio/lbry.go/extras/errors"
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
|
|
||||||
"github.com/lbryio/lbry.go/errors"
|
|
||||||
"github.com/lbryio/lbryschema.go/address"
|
"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 {
|
type ClaimHelper struct {
|
||||||
*pb.Claim
|
*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 {
|
func (c *ClaimHelper) ValidateAddresses(blockchainName string) error {
|
||||||
// check the validity of a fee address
|
if c.Claim != nil { // V2
|
||||||
if c.GetClaimType() == pb.Claim_streamType {
|
// check the validity of a fee address
|
||||||
fee := c.GetStream().GetMetadata().GetFee()
|
if c.Claim.GetStream() != nil {
|
||||||
if fee != nil {
|
fee := c.GetStream().GetFee()
|
||||||
tmp_addr := fee.GetAddress()
|
if fee != nil {
|
||||||
if len(tmp_addr) != 25 {
|
return validateAddress(fee.GetAddress(), blockchainName)
|
||||||
return errors.Err("invalid address length: " + string(len(tmp_addr)) + "!")
|
} else {
|
||||||
}
|
return nil
|
||||||
addr := [25]byte{}
|
|
||||||
for i := range addr {
|
|
||||||
addr[i] = tmp_addr[i]
|
|
||||||
}
|
|
||||||
_, err := address.EncodeAddress(addr, blockchainName)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Err(err)
|
|
||||||
}
|
}
|
||||||
|
} else if c.GetChannel() != nil {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
return errors.Err("claim helper created with migrated v2 protobuf claim 'invalid state'")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClaimHelper) ValidateCertificate() error {
|
func validateAddress(tmp_addr []byte, blockchainName string) error {
|
||||||
certificate := c.GetCertificate()
|
if len(tmp_addr) != 25 {
|
||||||
if certificate == nil {
|
return errors.Err("invalid address length: " + strconv.FormatInt(int64(len(tmp_addr)), 10) + "!")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
keyType := certificate.GetKeyType()
|
addr := [25]byte{}
|
||||||
_, err := c.GetCertificatePublicKey()
|
for i := range addr {
|
||||||
|
addr[i] = tmp_addr[i]
|
||||||
|
}
|
||||||
|
_, err := address.EncodeAddress(addr, blockchainName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Err(err)
|
return errors.Err(err)
|
||||||
}
|
}
|
||||||
if keyType.String() != SECP256k1 {
|
|
||||||
return errors.Err("wrong curve: " + keyType.String())
|
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 {
|
||||||
|
if c.GetChannel() == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := c.GetPublicKey()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Err(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -61,12 +98,52 @@ func (c *ClaimHelper) LoadFromBytes(raw_claim []byte, blockchainName string) err
|
||||||
return errors.Err("there is nothing to decode")
|
return errors.Err("there is nothing to decode")
|
||||||
}
|
}
|
||||||
|
|
||||||
claim_pb := &pb.Claim{}
|
var claim_pb *pb.Claim
|
||||||
err := proto.Unmarshal(raw_claim, claim_pb)
|
var legacy_claim_pb *legacy_pb.Claim
|
||||||
if err != nil {
|
|
||||||
return err
|
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
|
||||||
}
|
}
|
||||||
*c = ClaimHelper{claim_pb}
|
|
||||||
|
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: claim_pb,
|
||||||
|
LegacyClaim: legacy_claim_pb,
|
||||||
|
ClaimID: claimID,
|
||||||
|
Version: version,
|
||||||
|
Signature: signature,
|
||||||
|
}
|
||||||
|
|
||||||
err = c.ValidateAddresses(blockchainName)
|
err = c.ValidateAddresses(blockchainName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -88,7 +165,7 @@ func (c *ClaimHelper) LoadFromHexString(claim_hex string, blockchainName string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeClaimProtoBytes(serialized []byte, blockchainName string) (*ClaimHelper, error) {
|
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)
|
err := claim.LoadFromBytes(serialized, blockchainName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -99,21 +176,12 @@ func DecodeClaimProtoBytes(serialized []byte, blockchainName string) (*ClaimHelp
|
||||||
func DecodeClaimHex(serialized string, blockchainName string) (*ClaimHelper, error) {
|
func DecodeClaimHex(serialized string, blockchainName string) (*ClaimHelper, error) {
|
||||||
claim_bytes, err := hex.DecodeString(serialized)
|
claim_bytes, err := hex.DecodeString(serialized)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Err(err)
|
||||||
}
|
}
|
||||||
return DecodeClaimBytes(claim_bytes, blockchainName)
|
return DecodeClaimBytes(claim_bytes, blockchainName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeClaimJSON(claimJSON string, blockchainName string) (*ClaimHelper, error) {
|
// 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
|
||||||
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
|
|
||||||
func DecodeClaimBytes(serialized []byte, blockchainName string) (*ClaimHelper, error) {
|
func DecodeClaimBytes(serialized []byte, blockchainName string) (*ClaimHelper, error) {
|
||||||
helper, err := DecodeClaimProtoBytes(serialized, blockchainName)
|
helper, err := DecodeClaimProtoBytes(serialized, blockchainName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -130,7 +198,7 @@ func DecodeClaimBytes(serialized []byte, blockchainName string) (*ClaimHelper, e
|
||||||
v3Claim := new(V3Claim)
|
v3Claim := new(V3Claim)
|
||||||
err := v3Claim.Unmarshal(serialized)
|
err := v3Claim.Unmarshal(serialized)
|
||||||
if err != nil {
|
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)
|
helper.Claim, err = migrateV3Claim(*v3Claim)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -154,21 +222,23 @@ func DecodeClaimBytes(serialized []byte, blockchainName string) (*ClaimHelper, e
|
||||||
|
|
||||||
func (c *ClaimHelper) GetStream() *pb.Stream {
|
func (c *ClaimHelper) GetStream() *pb.Stream {
|
||||||
if c != nil {
|
if c != nil {
|
||||||
return c.Stream
|
return c.Claim.GetStream()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClaimHelper) GetCertificate() *pb.Certificate {
|
func (c *ClaimHelper) CompileValue() ([]byte, error) {
|
||||||
if c != nil {
|
payload, err := c.serialized()
|
||||||
return c.Certificate
|
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 {
|
return value, nil
|
||||||
if c != nil {
|
|
||||||
return c.PublisherSignature
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,15 +13,15 @@ func TestClaimHelper(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = helper.Serialized()
|
_, err = helper.serialized()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
_, err = helper.SerializedHexString()
|
_, err = helper.serializedHexString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
_, err = helper.SerializedNoSignature()
|
_, err = helper.serializedNoSignature()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,17 @@ package claim
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
pb "github.com/lbryio/types/v2/go"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/btcec"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type rawClaim struct {
|
||||||
|
Hex string
|
||||||
|
ClaimID string
|
||||||
|
}
|
||||||
|
|
||||||
var raw_claims = []string{
|
var raw_claims = []string{
|
||||||
"08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367",
|
"08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367",
|
||||||
"080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65",
|
"080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65",
|
||||||
|
@ -23,7 +32,7 @@ func TestDecodeClaims(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
serializedHex, err := claim.SerializedHexString()
|
serializedHex, err := claim.serializedHexString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +49,7 @@ func TestStripSignature(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
noSig, err := claim.SerializedNoSignature()
|
noSig, err := claim.serializedNoSignature()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -48,3 +57,40 @@ func TestStripSignature(t *testing.T) {
|
||||||
t.Error("failed to remove signature")
|
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 (
|
import (
|
||||||
"encoding/hex"
|
"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/btcsuite/btcutil/base58"
|
||||||
"github.com/lbryio/types/go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const lbrySDHash = "lbry_sd_hash"
|
const lbrySDHash = "lbry_sd_hash"
|
||||||
|
|
||||||
func newClaim() *pb.Claim {
|
func newStreamClaim() *pb.Claim {
|
||||||
pbClaim := new(pb.Claim)
|
claimStream := new(pb.Claim_Stream)
|
||||||
stream := new(pb.Stream)
|
stream := new(pb.Stream)
|
||||||
metadata := new(pb.Metadata)
|
stream.File = new(pb.File)
|
||||||
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
|
|
||||||
|
|
||||||
//Fee version
|
pbClaim := new(pb.Claim)
|
||||||
feeVersion := pb.Fee__0_0_1
|
pbClaim.Type = claimStream
|
||||||
pbClaim.GetStream().GetMetadata().GetFee().Version = &feeVersion
|
claimStream.Stream = stream
|
||||||
//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
|
|
||||||
|
|
||||||
return pbClaim
|
return pbClaim
|
||||||
}
|
}
|
||||||
|
|
||||||
func setMetaData(claim pb.Claim, author string, description string, language pb.Metadata_Language, license string,
|
func newChannelClaim() *pb.Claim {
|
||||||
licenseURL *string, title string, thumbnail *string, nsfw bool) {
|
claimChannel := new(pb.Claim_Channel)
|
||||||
claim.GetStream().GetMetadata().Author = &author
|
channel := new(pb.Channel)
|
||||||
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
|
|
||||||
|
|
||||||
|
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) {
|
func migrateV1Claim(vClaim V1Claim) (*pb.Claim, error) {
|
||||||
pbClaim := newClaim()
|
pbClaim := newStreamClaim()
|
||||||
//Not part of json V1
|
|
||||||
pbClaim.PublisherSignature = nil
|
|
||||||
//Stream
|
//Stream
|
||||||
// -->Universal
|
// -->Universal
|
||||||
setFee(vClaim.Fee, pbClaim)
|
setFee(vClaim.Fee, pbClaim)
|
||||||
// -->MetaData
|
// -->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,
|
setMetaData(*pbClaim, vClaim.Author, vClaim.Description, language,
|
||||||
vClaim.License, nil, vClaim.Title, vClaim.Thumbnail, false)
|
vClaim.License, nil, vClaim.Title, vClaim.Thumbnail, false)
|
||||||
// -->Source
|
// -->Source
|
||||||
pbClaim.GetStream().GetSource().ContentType = &vClaim.ContentType
|
pbClaim.GetStream().MediaType = vClaim.ContentType
|
||||||
sourceType := pb.Source_SourceTypes(pb.Source_SourceTypes_value[lbrySDHash])
|
|
||||||
pbClaim.GetStream().GetSource().SourceType = &sourceType
|
|
||||||
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
|
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) {
|
func migrateV2Claim(vClaim V2Claim) (*pb.Claim, error) {
|
||||||
pbClaim := newClaim()
|
pbClaim := newStreamClaim()
|
||||||
//Not part of json V2
|
|
||||||
pbClaim.PublisherSignature = nil
|
|
||||||
//Stream
|
//Stream
|
||||||
// -->Fee
|
// -->Fee
|
||||||
setFee(vClaim.Fee, pbClaim)
|
setFee(vClaim.Fee, pbClaim)
|
||||||
// -->MetaData
|
// -->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,
|
setMetaData(*pbClaim, vClaim.Author, vClaim.Description, language,
|
||||||
vClaim.License, vClaim.LicenseURL, vClaim.Title, vClaim.Thumbnail, vClaim.NSFW)
|
vClaim.License, vClaim.LicenseURL, vClaim.Title, vClaim.Thumbnail, vClaim.NSFW)
|
||||||
// -->Source
|
// -->Source
|
||||||
pbClaim.GetStream().GetSource().ContentType = &vClaim.ContentType
|
pbClaim.GetStream().MediaType = vClaim.ContentType
|
||||||
sourceType := pb.Source_SourceTypes(pb.Source_SourceTypes_value[lbrySDHash])
|
|
||||||
pbClaim.GetStream().GetSource().SourceType = &sourceType
|
|
||||||
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
|
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) {
|
func migrateV3Claim(vClaim V3Claim) (*pb.Claim, error) {
|
||||||
pbClaim := newClaim()
|
pbClaim := newStreamClaim()
|
||||||
//Not part of json V3
|
|
||||||
pbClaim.PublisherSignature = nil
|
|
||||||
//Stream
|
//Stream
|
||||||
// -->Fee
|
// -->Fee
|
||||||
setFee(vClaim.Fee, pbClaim)
|
setFee(vClaim.Fee, pbClaim)
|
||||||
// -->MetaData
|
// -->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,
|
setMetaData(*pbClaim, vClaim.Author, vClaim.Description, language,
|
||||||
vClaim.License, vClaim.LicenseURL, vClaim.Title, vClaim.Thumbnail, vClaim.NSFW)
|
vClaim.License, vClaim.LicenseURL, vClaim.Title, vClaim.Thumbnail, vClaim.NSFW)
|
||||||
// -->Source
|
// -->Source
|
||||||
pbClaim.GetStream().GetSource().ContentType = &vClaim.ContentType
|
pbClaim.GetStream().MediaType = vClaim.ContentType
|
||||||
sourceType := pb.Source_SourceTypes(pb.Source_SourceTypes_value[lbrySDHash])
|
|
||||||
pbClaim.GetStream().GetSource().SourceType = &sourceType
|
|
||||||
src, err := hex.DecodeString(vClaim.Sources.LbrySDHash)
|
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) {
|
func setFee(fee *Fee, pbClaim *pb.Claim) {
|
||||||
|
@ -138,9 +172,10 @@ func setFee(fee *Fee, pbClaim *pb.Claim) {
|
||||||
currency = pb.Fee_USD
|
currency = pb.Fee_USD
|
||||||
address = fee.USD.Address
|
address = fee.USD.Address
|
||||||
}
|
}
|
||||||
|
pbClaim.GetStream().Fee = new(pb.Fee)
|
||||||
//Fee Settings
|
//Fee Settings
|
||||||
pbClaim.GetStream().GetMetadata().GetFee().Amount = &amount
|
pbClaim.GetStream().GetFee().Amount = uint64(amount * 100000000)
|
||||||
pbClaim.GetStream().GetMetadata().GetFee().Currency = ¤cy
|
pbClaim.GetStream().GetFee().Currency = currency
|
||||||
pbClaim.GetStream().GetMetadata().GetFee().Address = base58.Decode(address)
|
pbClaim.GetStream().GetFee().Address = base58.Decode(address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package claim
|
package claim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lbryio/lbryschema.go/address"
|
||||||
|
|
||||||
"github.com/btcsuite/btcutil/base58"
|
"github.com/btcsuite/btcutil/base58"
|
||||||
|
"gotest.tools/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type valueTestPair struct {
|
type valueTestPair struct {
|
||||||
|
@ -51,7 +55,7 @@ var jsonVersionTests = []valueTestPair{
|
||||||
"LBC",
|
"LBC",
|
||||||
"bPwGA9h7uijoy5uAvzVPQw9QyLoYZehHJo",
|
"bPwGA9h7uijoy5uAvzVPQw9QyLoYZehHJo",
|
||||||
"application/octet-stream",
|
"application/octet-stream",
|
||||||
"UNKNOWN_LANGUAGE", //"English" is not supported for conversion.
|
"", //"English" is not supported for conversion.
|
||||||
"bd94033d13f4f3908708701caf565bfa09cfadf2f34fadf4a73fb86b295d1b21a7e64805994e45b5fbc650f30bac4874",
|
"bd94033d13f4f3908708701caf565bfa09cfadf2f34fadf4a73fb86b295d1b21a7e64805994e45b5fbc650f30bac4874",
|
||||||
"/homerobert/lbry/speed.jpg",
|
"/homerobert/lbry/speed.jpg",
|
||||||
false,
|
false,
|
||||||
|
@ -68,7 +72,7 @@ var jsonVersionTests = []valueTestPair{
|
||||||
"LBC",
|
"LBC",
|
||||||
"bLVs3ifPruyZnpYmFfT2TLAmhqZvgjpQDa",
|
"bLVs3ifPruyZnpYmFfT2TLAmhqZvgjpQDa",
|
||||||
"video/quicktime",
|
"video/quicktime",
|
||||||
"en",
|
"language:en ",
|
||||||
"dcc1bf28893a5037eab9e4a9cd7a4bfe6f76ad6c21970ea4ceee0122f502ef079657d4dca456b4be3249849c4e1868b8",
|
"dcc1bf28893a5037eab9e4a9cd7a4bfe6f76ad6c21970ea4ceee0122f502ef079657d4dca456b4be3249849c4e1868b8",
|
||||||
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
|
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
|
||||||
false,
|
false,
|
||||||
|
@ -85,7 +89,7 @@ var jsonVersionTests = []valueTestPair{
|
||||||
"UNKNOWN_CURRENCY",
|
"UNKNOWN_CURRENCY",
|
||||||
"",
|
"",
|
||||||
"video/mp4",
|
"video/mp4",
|
||||||
"en",
|
"language:en ",
|
||||||
"799a1de93b8e556d7f668103a6ffc48ac5fd6801dd4d89cae6773c80d81c283710fd4fd25ed68d0dbeee268f82914145",
|
"799a1de93b8e556d7f668103a6ffc48ac5fd6801dd4d89cae6773c80d81c283710fd4fd25ed68d0dbeee268f82914145",
|
||||||
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
|
"http://ia.media-imdb.com/images/M/MV5BMTQwNjYzMTQ0Ml5BMl5BanBnXkFtZTcwNDUzODM5Nw@@._V1_SY1000_CR0,0,673,1000_AL_.jpg",
|
||||||
false,
|
false,
|
||||||
|
@ -102,7 +106,7 @@ var jsonVersionTests = []valueTestPair{
|
||||||
"USD",
|
"USD",
|
||||||
"bMHmZKZbPq6bPBEQFc8MXpiDhF9f7MVxMR",
|
"bMHmZKZbPq6bPBEQFc8MXpiDhF9f7MVxMR",
|
||||||
"video/mp4",
|
"video/mp4",
|
||||||
"en",
|
"language:en ",
|
||||||
"2bd8d9dd1a218c7f56717e53fa510efd5a8c089ed1f2675a0f8d0b5b8bb3c1ed383cb9f3aeb9b891789761305293979a",
|
"2bd8d9dd1a218c7f56717e53fa510efd5a8c089ed1f2675a0f8d0b5b8bb3c1ed383cb9f3aeb9b891789761305293979a",
|
||||||
"",
|
"",
|
||||||
false,
|
false,
|
||||||
|
@ -119,7 +123,7 @@ var jsonVersionTests = []valueTestPair{
|
||||||
"LBC",
|
"LBC",
|
||||||
"bVPqWwYfvjBHYBouuvknbQMXUZFvLdEs5M",
|
"bVPqWwYfvjBHYBouuvknbQMXUZFvLdEs5M",
|
||||||
"text/plain",
|
"text/plain",
|
||||||
"en",
|
"language:en ",
|
||||||
"7c21ee237324e5a50a3425620fe6cc400d3cccc05519867cda1b9c10a977194e31200414d87146bff470bab7f7d75478",
|
"7c21ee237324e5a50a3425620fe6cc400d3cccc05519867cda1b9c10a977194e31200414d87146bff470bab7f7d75478",
|
||||||
"",
|
"",
|
||||||
false,
|
false,
|
||||||
|
@ -136,7 +140,7 @@ var jsonVersionTests = []valueTestPair{
|
||||||
"USD",
|
"USD",
|
||||||
"bHSe3KAvtVSR4m6S11zduuF9XHtwscDjoE",
|
"bHSe3KAvtVSR4m6S11zduuF9XHtwscDjoE",
|
||||||
"audio/mpeg",
|
"audio/mpeg",
|
||||||
"en",
|
"language:en ",
|
||||||
"340e1dda0e8414c21fafbb1f28f2c8b384821fe0d1e2a7143a4810545e64e26a4105042d4d47dc9754b618ecdfe0d191",
|
"340e1dda0e8414c21fafbb1f28f2c8b384821fe0d1e2a7143a4810545e64e26a4105042d4d47dc9754b618ecdfe0d191",
|
||||||
"http://i.imgur.com/lyKEHZc.jpg",
|
"http://i.imgur.com/lyKEHZc.jpg",
|
||||||
false,
|
false,
|
||||||
|
@ -153,7 +157,7 @@ var jsonVersionTests = []valueTestPair{
|
||||||
"LBC",
|
"LBC",
|
||||||
"bRTxtCUpj6TvJHgWcRsGcHaFyrRLkkiXgG",
|
"bRTxtCUpj6TvJHgWcRsGcHaFyrRLkkiXgG",
|
||||||
"video/mp4",
|
"video/mp4",
|
||||||
"en",
|
"language:en ",
|
||||||
"fc0dac5cfc526354963ff1769f6e739c4e42a0790420ffab9fa3b6401e93ae5a0515eff960f8c9c272907eda6fcba254",
|
"fc0dac5cfc526354963ff1769f6e739c4e42a0790420ffab9fa3b6401e93ae5a0515eff960f8c9c272907eda6fcba254",
|
||||||
"",
|
"",
|
||||||
true,
|
true,
|
||||||
|
@ -184,40 +188,95 @@ func TestMigrationFromJSON(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Decode error: ", err)
|
t.Error("Decode error: ", err)
|
||||||
}
|
}
|
||||||
if helper.Claim.GetStream().GetMetadata().GetAuthor() != pair.Claim.Author {
|
if helper.Claim.GetStream().GetAuthor() != pair.Claim.Author {
|
||||||
t.Error("Author mismatch: expected", pair.Claim.Author, "got", helper.Claim.GetStream().GetMetadata().GetAuthor())
|
t.Error("Author mismatch: expected", pair.Claim.Author, "got", helper.Claim.GetStream().GetAuthor())
|
||||||
}
|
}
|
||||||
if helper.Claim.GetStream().GetMetadata().GetTitle() != pair.Claim.Title {
|
if helper.Claim.GetStream().GetTitle() != pair.Claim.Title {
|
||||||
t.Error("Title mismatch: expected", pair.Claim.Title, "got", helper.Claim.GetStream().GetMetadata().GetTitle())
|
t.Error("Title mismatch: expected", pair.Claim.Title, "got", helper.Claim.GetStream().GetTitle())
|
||||||
}
|
}
|
||||||
if helper.Claim.GetStream().GetMetadata().GetDescription() != pair.Claim.Description {
|
if helper.Claim.GetStream().GetDescription() != pair.Claim.Description {
|
||||||
t.Error("Description mismatch: expected", pair.Claim.Description, "got", helper.Claim.GetStream().GetMetadata().GetDescription())
|
t.Error("Description mismatch: expected", pair.Claim.Description, "got", helper.Claim.GetStream().GetDescription())
|
||||||
}
|
}
|
||||||
if helper.Claim.GetStream().GetMetadata().GetLicense() != pair.Claim.License {
|
if helper.Claim.GetStream().GetLicense() != pair.Claim.License {
|
||||||
t.Error("License mismatch: expected", pair.Claim.License, "got", helper.Claim.GetStream().GetMetadata().GetLicense())
|
t.Error("License mismatch: expected", pair.Claim.License, "got", helper.Claim.GetStream().GetLicense())
|
||||||
}
|
}
|
||||||
if helper.Claim.GetStream().GetMetadata().GetLicenseUrl() != pair.Claim.LicenseURL {
|
if helper.Claim.GetStream().GetLicenseUrl() != pair.Claim.LicenseURL {
|
||||||
t.Error("LicenseURL mismatch: expected", pair.Claim.LicenseURL, "got", helper.Claim.GetStream().GetMetadata().GetLicenseUrl())
|
t.Error("LicenseURL mismatch: expected", pair.Claim.LicenseURL, "got", helper.Claim.GetStream().GetLicenseUrl())
|
||||||
}
|
}
|
||||||
if helper.Claim.GetStream().GetMetadata().GetFee().GetAmount() != pair.Claim.FeeAmount {
|
if helper.Claim.GetStream().GetFee().GetAmount() != uint64(pair.Claim.FeeAmount*100000000) {
|
||||||
t.Error("Fee Amount mismatch: expected", pair.Claim.FeeAmount, "got", helper.Claim.GetStream().GetMetadata().GetFee().GetAmount())
|
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 {
|
if helper.Claim.GetStream().GetFee().GetCurrency().String() != pair.Claim.FeeCurrency {
|
||||||
t.Error("Fee Currency mismatch: expected", pair.Claim.FeeCurrency, "got", helper.Claim.GetStream().GetMetadata().GetFee().GetCurrency())
|
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 {
|
if hexaddress != pair.Claim.FeeAddress {
|
||||||
t.Error("Fee Address mismatch: expected", pair.Claim.FeeAddress, "got", hexaddress)
|
t.Error("Fee Address mismatch: expected", pair.Claim.FeeAddress, "got", hexaddress)
|
||||||
}
|
}
|
||||||
if helper.Claim.GetStream().GetSource().GetContentType() != pair.Claim.ContentType {
|
if helper.Claim.GetStream().GetMediaType() != pair.Claim.ContentType {
|
||||||
t.Error("ContentType mismatch: expected", pair.Claim.ContentType, "got", helper.Claim.GetStream().GetSource().GetContentType())
|
t.Error("ContentType mismatch: expected", pair.Claim.ContentType, "got", helper.Claim.GetStream().GetMediaType())
|
||||||
}
|
}
|
||||||
if helper.Claim.GetStream().GetMetadata().GetLanguage().String() != pair.Claim.Language {
|
if helper.Claim.GetStream().GetLanguages()[0].String() != pair.Claim.Language {
|
||||||
t.Error("Language mismatch: expected ", pair.Claim.Language, " got ", helper.Claim.GetStream().GetMetadata().GetLanguage().String())
|
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 {
|
if content != pair.Claim.LbrySDHash {
|
||||||
t.Error("Source mismatch: expected", pair.Claim.LbrySDHash, "got", content)
|
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 (
|
import (
|
||||||
"encoding/json"
|
"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.
|
// V1Claim is the first version of claim metadata used by lbry.
|
||||||
|
|
|
@ -2,43 +2,50 @@ package claim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"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/golang/protobuf/proto"
|
||||||
"github.com/lbryio/types/go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *ClaimHelper) Serialized() ([]byte, error) {
|
func (c *ClaimHelper) serialized() ([]byte, error) {
|
||||||
serialized := c.String()
|
serialized := c.String()
|
||||||
if serialized == "" {
|
if serialized == "" {
|
||||||
return nil, errors.New("not initialized")
|
return nil, errors.Err("not initialized")
|
||||||
}
|
}
|
||||||
v := c.GetVersion()
|
|
||||||
t := c.GetClaimType()
|
|
||||||
|
|
||||||
return proto.Marshal(
|
if c.LegacyClaim != nil {
|
||||||
&pb.Claim{
|
return proto.Marshal(c.getLegacyProtobuf())
|
||||||
Version: &v,
|
}
|
||||||
ClaimType: &t,
|
|
||||||
Stream: c.GetStream(),
|
return proto.Marshal(c.getProtobuf())
|
||||||
Certificate: c.GetCertificate(),
|
|
||||||
PublisherSignature: c.GetPublisherSignature()})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClaimHelper) GetProtobuf() *pb.Claim {
|
func (c *ClaimHelper) getProtobuf() *pb.Claim {
|
||||||
v := c.GetVersion()
|
if c.GetChannel() != nil {
|
||||||
t := c.GetClaimType()
|
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{
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ClaimHelper) getLegacyProtobuf() *legacy.Claim {
|
||||||
|
v := c.LegacyClaim.GetVersion()
|
||||||
|
t := c.LegacyClaim.GetClaimType()
|
||||||
|
return &legacy.Claim{
|
||||||
Version: &v,
|
Version: &v,
|
||||||
ClaimType: &t,
|
ClaimType: &t,
|
||||||
Stream: c.GetStream(),
|
Stream: c.LegacyClaim.GetStream(),
|
||||||
Certificate: c.GetCertificate(),
|
Certificate: c.LegacyClaim.GetCertificate(),
|
||||||
PublisherSignature: c.GetPublisherSignature()}
|
PublisherSignature: c.LegacyClaim.GetPublisherSignature()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClaimHelper) SerializedHexString() (string, error) {
|
func (c *ClaimHelper) serializedHexString() (string, error) {
|
||||||
serialized, err := c.Serialized()
|
serialized, err := c.serialized()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -46,21 +53,26 @@ func (c *ClaimHelper) SerializedHexString() (string, error) {
|
||||||
return serialized_hex, nil
|
return serialized_hex, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClaimHelper) SerializedNoSignature() ([]byte, error) {
|
func (c *ClaimHelper) serializedNoSignature() ([]byte, error) {
|
||||||
if c.String() == "" {
|
if c.String() == "" {
|
||||||
return nil, errors.New("not initialized")
|
return nil, errors.Err("not initialized")
|
||||||
}
|
}
|
||||||
if c.GetPublisherSignature() == nil {
|
if c.Signature == nil {
|
||||||
serialized, err := c.Serialized()
|
serialized, err := c.serialized()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return serialized, nil
|
return serialized, nil
|
||||||
} else {
|
} else {
|
||||||
|
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{}
|
clone := &pb.Claim{}
|
||||||
proto.Merge(clone, c.GetProtobuf())
|
proto.Merge(clone, c.getProtobuf())
|
||||||
proto.ClearAllExtensions(clone.PublisherSignature)
|
|
||||||
clone.PublisherSignature = nil
|
|
||||||
return proto.Marshal(clone)
|
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"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
|
||||||
"github.com/lbryio/lbryschema.go/address"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/lbryio/lbry.go/extras/errors"
|
||||||
|
"github.com/lbryio/lbryschema.go/address"
|
||||||
)
|
)
|
||||||
|
|
||||||
type publicKeyInfo struct {
|
type publicKeyInfo struct {
|
||||||
|
@ -23,86 +23,100 @@ const SECP256k1 = "SECP256k1"
|
||||||
//const NIST256p = "NIST256p"
|
//const NIST256p = "NIST256p"
|
||||||
//const NIST384p = "NIST384p"
|
//const NIST384p = "NIST384p"
|
||||||
|
|
||||||
func GetClaimSignatureDigest(claimAddress [25]byte, certificateId [20]byte, serializedNoSig []byte) [32]byte {
|
func getClaimSignatureDigest(bytes ...[]byte) [32]byte {
|
||||||
|
|
||||||
var combined []byte
|
var combined []byte
|
||||||
for _, c := range claimAddress {
|
for _, b := range bytes {
|
||||||
combined = append(combined, c)
|
combined = append(combined, b...)
|
||||||
}
|
|
||||||
for _, c := range serializedNoSig {
|
|
||||||
combined = append(combined, c)
|
|
||||||
}
|
|
||||||
for _, c := range certificateId {
|
|
||||||
combined = append(combined, c)
|
|
||||||
}
|
}
|
||||||
digest := sha256.Sum256(combined)
|
digest := sha256.Sum256(combined)
|
||||||
return [32]byte(digest)
|
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 {
|
func (c *ClaimHelper) VerifyDigest(certificate *ClaimHelper, signature [64]byte, digest [32]byte) bool {
|
||||||
publicKey, err := certificate.GetCertificatePublicKey()
|
if certificate == nil {
|
||||||
if err != nil {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.PublisherSignature.SignatureType.String() == SECP256k1 {
|
R := &big.Int{}
|
||||||
R := &big.Int{}
|
S := &big.Int{}
|
||||||
S := &big.Int{}
|
R.SetBytes(signature[0:32])
|
||||||
R.SetBytes(signature[0:32])
|
S.SetBytes(signature[32:64])
|
||||||
S.SetBytes(signature[32:64])
|
pk, err := certificate.GetPublicKey()
|
||||||
return ecdsa.Verify(publicKey.ToECDSA(), digest[:], R, S)
|
if err != nil {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
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) {
|
func (c *ClaimHelper) ValidateClaimSignature(certificate *ClaimHelper, k string, certificateId string, blockchainName string) (bool, error) {
|
||||||
signature := c.GetPublisherSignature()
|
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 {
|
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{}
|
signatureBytes := [64]byte{}
|
||||||
for i := range signatureBytes {
|
for i, b := range signature {
|
||||||
signatureBytes[i] = signatureSlice[i]
|
signatureBytes[i] = b
|
||||||
}
|
}
|
||||||
|
|
||||||
claimAddress, err := address.ValidateAddress(claimAddress, blockchainName)
|
serialized, err := c.serialized()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.New("invalid address")
|
return false, errors.Err("serialization error")
|
||||||
}
|
}
|
||||||
|
|
||||||
serializedNoSig, err := c.SerializedNoSignature()
|
claimDigest := getClaimSignatureDigest(firstInputTxIDBytes, certificateIdSlice, serialized)
|
||||||
if err != nil {
|
|
||||||
return false, errors.New("serialization error")
|
|
||||||
}
|
|
||||||
|
|
||||||
claimDigest := GetClaimSignatureDigest(claimAddress, certificateId, serializedNoSig)
|
|
||||||
return c.VerifyDigest(certificate, signatureBytes, claimDigest), nil
|
return c.VerifyDigest(certificate, signatureBytes, claimDigest), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClaimHelper) ValidateClaimSignature(certificate *ClaimHelper, claimAddress string, certificateId string, blockchainName string) (bool, error) {
|
func (c *ClaimHelper) validateV1ClaimSignature(certificate *ClaimHelper, claimAddy string, certificateId string, blockchainName string) (bool, error) {
|
||||||
addressBytes, err := address.DecodeAddress(claimAddress, blockchainName)
|
addressBytes, err := address.DecodeAddress(claimAddy, blockchainName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
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)
|
certificateIdSlice, err := hex.DecodeString(certificateId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
certificateIdBytes := [20]byte{}
|
|
||||||
for i := range certificateIdBytes {
|
signature := c.Signature
|
||||||
certificateIdBytes[i] = certificateIdSlice[i]
|
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"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateClaimSignature(t *testing.T) {
|
func TestV1ValidateClaimSignature(t *testing.T) {
|
||||||
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||||
signed_claim_hex := "080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
signed_claim_hex := "080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||||
|
|
||||||
signed_claim, _ := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
signed_claim, err := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||||
cert_claim, _ := DecodeClaimHex(cert_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"
|
claim_addr := "bSkUov7HMWpYBiXackDwRnR5ishhGHvtJt"
|
||||||
cert_id := "251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
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"
|
cert_claim_hex := "08011002225e0801100322583056301006072a8648ce3d020106052b8104000a03420004d015365a40f3e5c03c87227168e5851f44659837bcf6a3398ae633bc37d04ee19baeb26dc888003bd728146dbea39f5344bf8c52cedaf1a3a1623a0166f4a367"
|
||||||
signed_claim_hex := "080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
signed_claim_hex := "080110011ad7010801128f01080410011a0c47616d65206f66206c696665221047616d65206f66206c696665206769662a0b4a6f686e20436f6e776179322e437265617469766520436f6d6d6f6e73204174747269627574696f6e20342e3020496e7465726e6174696f6e616c38004224080110011a195569c917f18bf5d2d67f1346aa467b218ba90cdbf2795676da250000803f4a0052005a001a41080110011a30b6adf6e2a62950407ea9fb045a96127b67d39088678d2f738c359894c88d95698075ee6203533d3c204330713aa7acaf2209696d6167652f6769662a5c080110031a40c73fe1be4f1743c2996102eec6ce0509e03744ab940c97d19ddb3b25596206367ab1a3d2583b16c04d2717eeb983ae8f84fee2a46621ffa5c4726b30174c6ff82214251305ca93d4dbedb50dceb282ebcb7b07b7ac65"
|
||||||
|
|
||||||
signed_claim, _ := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
signed_claim, err := DecodeClaimHex(signed_claim_hex, "lbrycrd_main")
|
||||||
cert_claim, _ := DecodeClaimHex(cert_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"
|
claim_addr := "bSkUov7HMWpYBiXackDwRnR5ishhGHvtJt"
|
||||||
cert_id := "251305ca93d4dbedb50dceb282ebcb7b07b7ac64"
|
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