github.com/klaytn/klaytn@v1.10.2/blockchain/types/accountkey/public_key.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package accountkey
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"math/big"
    26  
    27  	"github.com/klaytn/klaytn/common/hexutil"
    28  	"github.com/klaytn/klaytn/crypto"
    29  	"github.com/klaytn/klaytn/rlp"
    30  )
    31  
    32  var (
    33  	errNotS256Curve = errors.New("key is not on the S256 curve")
    34  	errNoXYValue    = errors.New("X or Y value of the public key does not exist")
    35  )
    36  
    37  // Since ecdsa.PublicKey does not provide RLP/JSON serialization,
    38  // PublicKeySerializable provides RLP/JSON serialization.
    39  // It is used for AccountKey as an internal structure.
    40  type PublicKeySerializable ecdsa.PublicKey
    41  
    42  type publicKeySerializableInternalJSON struct {
    43  	X *hexutil.Big `json:"x"`
    44  	Y *hexutil.Big `json:"y"`
    45  }
    46  
    47  // newPublicKeySerializable creates a PublicKeySerializable object.
    48  // The object is initialized with default values.
    49  // Curve = S256 curve
    50  // X = 0
    51  // Y = 0
    52  func newPublicKeySerializable() *PublicKeySerializable {
    53  	return &PublicKeySerializable{
    54  		Curve: crypto.S256(),
    55  		X:     new(big.Int),
    56  		Y:     new(big.Int),
    57  	}
    58  }
    59  
    60  // EncodeRLP encodes ecdsa.PublicKey using RLP.
    61  // For now, it supports S256 curve only.
    62  // For that reason, this function serializes only X and Y using CompressPubkey().
    63  func (p *PublicKeySerializable) EncodeRLP(w io.Writer) error {
    64  	// Do not serialize if it is not on S256 curve.
    65  	if !crypto.S256().IsOnCurve(p.X, p.Y) {
    66  		return errNotS256Curve
    67  	}
    68  	return rlp.Encode(w, crypto.CompressPubkey((*ecdsa.PublicKey)(p)))
    69  }
    70  
    71  // DecodeRLP decodes PublicKeySerializable using RLP.
    72  // For now, it supports S256 curve only.
    73  // This function deserializes using UncompressPubkey().
    74  func (p *PublicKeySerializable) DecodeRLP(s *rlp.Stream) error {
    75  	b := []byte{}
    76  	if err := s.Decode(&b); err != nil {
    77  		return err
    78  	}
    79  	pubkey, err := crypto.DecompressPubkey(b)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	*p = *((*PublicKeySerializable)(pubkey))
    84  
    85  	return nil
    86  }
    87  
    88  // MarshalJSON encodes PublicKeySerializable using JSON.
    89  // For now, it supports S256 curve only.
    90  // For that reason, this function serializes only X and Y.
    91  func (p *PublicKeySerializable) MarshalJSON() ([]byte, error) {
    92  	// Do not serialize if it is not on S256 curve.
    93  	if !crypto.S256().IsOnCurve(p.X, p.Y) {
    94  		return nil, errNotS256Curve
    95  	}
    96  	return json.Marshal(&publicKeySerializableInternalJSON{
    97  		(*hexutil.Big)(p.X), (*hexutil.Big)(p.Y),
    98  	})
    99  }
   100  
   101  // UnmarshalJSON decodes PublicKeySerializable using JSON.
   102  // For now, it supports S256 curve only.
   103  // For that reason, this function deserializes only X and Y. Refer to MarshalJSON() above.
   104  func (p *PublicKeySerializable) UnmarshalJSON(b []byte) error {
   105  	var dec publicKeySerializableInternalJSON
   106  	if err := json.Unmarshal(b, &dec); err != nil {
   107  		return err
   108  	}
   109  	if dec.X == nil || dec.Y == nil {
   110  		return errNoXYValue
   111  	}
   112  	p.X = (*big.Int)(dec.X)
   113  	p.Y = (*big.Int)(dec.Y)
   114  
   115  	return nil
   116  }
   117  
   118  // DeepCopy creates a new PublicKeySerializable object and newly allocates memory for all its attributes.
   119  // Then, the values of the original object are copied to those of the new object.
   120  func (p *PublicKeySerializable) DeepCopy() *PublicKeySerializable {
   121  	pk := newPublicKeySerializable()
   122  	pk.X = new(big.Int).Set(p.X)
   123  	pk.Y = new(big.Int).Set(p.Y)
   124  
   125  	return pk
   126  }
   127  
   128  // Equal returns true if all attributes between p and pk are the same.
   129  // Otherwise, it returns false.
   130  func (p *PublicKeySerializable) Equal(pk *PublicKeySerializable) bool {
   131  	return p.X.Cmp(pk.X) == 0 &&
   132  		p.Y.Cmp(pk.Y) == 0
   133  }
   134  
   135  // String returns a string containing information of all attributes.
   136  func (p *PublicKeySerializable) String() string {
   137  	b, _ := json.Marshal(p)
   138  
   139  	return fmt.Sprintf("S256Pubkey:%s", string(b))
   140  }