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  }