github.com/MetalBlockchain/metalgo@v1.11.9/vms/platformvm/signer/proof_of_possession.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package signer 5 6 import ( 7 "encoding/json" 8 "errors" 9 10 "github.com/MetalBlockchain/metalgo/utils/crypto/bls" 11 "github.com/MetalBlockchain/metalgo/utils/formatting" 12 ) 13 14 var ( 15 _ Signer = (*ProofOfPossession)(nil) 16 17 errInvalidProofOfPossession = errors.New("invalid proof of possession") 18 ) 19 20 type ProofOfPossession struct { 21 PublicKey [bls.PublicKeyLen]byte `serialize:"true" json:"publicKey"` 22 // BLS signature proving ownership of [PublicKey]. The signed message is the 23 // [PublicKey]. 24 ProofOfPossession [bls.SignatureLen]byte `serialize:"true" json:"proofOfPossession"` 25 26 // publicKey is the parsed version of [PublicKey]. It is populated in 27 // [Verify]. 28 publicKey *bls.PublicKey 29 } 30 31 func NewProofOfPossession(sk *bls.SecretKey) *ProofOfPossession { 32 pk := bls.PublicFromSecretKey(sk) 33 pkBytes := bls.PublicKeyToCompressedBytes(pk) 34 sig := bls.SignProofOfPossession(sk, pkBytes) 35 sigBytes := bls.SignatureToBytes(sig) 36 37 pop := &ProofOfPossession{ 38 publicKey: pk, 39 } 40 copy(pop.PublicKey[:], pkBytes) 41 copy(pop.ProofOfPossession[:], sigBytes) 42 return pop 43 } 44 45 func (p *ProofOfPossession) Verify() error { 46 publicKey, err := bls.PublicKeyFromCompressedBytes(p.PublicKey[:]) 47 if err != nil { 48 return err 49 } 50 signature, err := bls.SignatureFromBytes(p.ProofOfPossession[:]) 51 if err != nil { 52 return err 53 } 54 if !bls.VerifyProofOfPossession(publicKey, signature, p.PublicKey[:]) { 55 return errInvalidProofOfPossession 56 } 57 58 p.publicKey = publicKey 59 return nil 60 } 61 62 func (p *ProofOfPossession) Key() *bls.PublicKey { 63 return p.publicKey 64 } 65 66 type jsonProofOfPossession struct { 67 PublicKey string `json:"publicKey"` 68 ProofOfPossession string `json:"proofOfPossession"` 69 } 70 71 func (p *ProofOfPossession) MarshalJSON() ([]byte, error) { 72 pk, err := formatting.Encode(formatting.HexNC, p.PublicKey[:]) 73 if err != nil { 74 return nil, err 75 } 76 pop, err := formatting.Encode(formatting.HexNC, p.ProofOfPossession[:]) 77 if err != nil { 78 return nil, err 79 } 80 return json.Marshal(jsonProofOfPossession{ 81 PublicKey: pk, 82 ProofOfPossession: pop, 83 }) 84 } 85 86 func (p *ProofOfPossession) UnmarshalJSON(b []byte) error { 87 jsonBLS := jsonProofOfPossession{} 88 err := json.Unmarshal(b, &jsonBLS) 89 if err != nil { 90 return err 91 } 92 93 pkBytes, err := formatting.Decode(formatting.HexNC, jsonBLS.PublicKey) 94 if err != nil { 95 return err 96 } 97 pk, err := bls.PublicKeyFromCompressedBytes(pkBytes) 98 if err != nil { 99 return err 100 } 101 102 popBytes, err := formatting.Decode(formatting.HexNC, jsonBLS.ProofOfPossession) 103 if err != nil { 104 return err 105 } 106 107 copy(p.PublicKey[:], pkBytes) 108 copy(p.ProofOfPossession[:], popBytes) 109 p.publicKey = pk 110 return nil 111 }