github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/model/flow/account_encoder.go (about)

     1  package flow
     2  
     3  // TODO: these functions will be moved to a separate `encoding` package in a future PR
     4  
     5  import (
     6  	"github.com/ethereum/go-ethereum/rlp"
     7  
     8  	"github.com/onflow/cadence"
     9  
    10  	"github.com/onflow/crypto"
    11  	"github.com/onflow/crypto/hash"
    12  )
    13  
    14  // accountPublicKeyWrapper is used for encoding and decoding.
    15  type accountPublicKeyWrapper struct {
    16  	PublicKey []byte
    17  	SignAlgo  uint
    18  	HashAlgo  uint
    19  	Weight    uint
    20  	SeqNumber uint64
    21  	Revoked   bool
    22  }
    23  
    24  // legacyAccountPublicKeyWrapper is an RLP wrapper for the old public key format that does
    25  // not contain a Revoked field.
    26  type legacyAccountPublicKeyWrapper struct {
    27  	PublicKey []byte
    28  	SignAlgo  uint
    29  	HashAlgo  uint
    30  	Weight    uint
    31  	SeqNumber uint64
    32  }
    33  
    34  // runtimeAccountPublicKeyWrapper must match format used in Transaction
    35  // currently should match SDK AccountKey encoded format
    36  type runtimeAccountPublicKeyWrapper struct {
    37  	PublicKey []byte
    38  	SignAlgo  uint
    39  	HashAlgo  uint
    40  	Weight    uint
    41  }
    42  
    43  // accountPrivateKeyWrapper is used for encoding and decoding.
    44  type accountPrivateKeyWrapper struct {
    45  	PrivateKey []byte
    46  	SignAlgo   uint
    47  	HashAlgo   uint
    48  }
    49  
    50  func EncodeAccountPublicKey(a AccountPublicKey) ([]byte, error) {
    51  	w := accountPublicKeyWrapper{
    52  		PublicKey: a.PublicKey.Encode(),
    53  		SignAlgo:  uint(a.SignAlgo),
    54  		HashAlgo:  uint(a.HashAlgo),
    55  		Weight:    uint(a.Weight),
    56  		SeqNumber: a.SeqNumber,
    57  		Revoked:   a.Revoked,
    58  	}
    59  
    60  	return rlp.EncodeToBytes(&w)
    61  }
    62  
    63  func EncodeRuntimeAccountPublicKeys(keys []AccountPublicKey) ([]cadence.Value, error) {
    64  	encodedKeys := make([]cadence.Value, len(keys))
    65  	for i, key := range keys {
    66  		k, err := EncodeRuntimeAccountPublicKey(key)
    67  		if err != nil {
    68  			return nil, err
    69  		}
    70  
    71  		values := make([]cadence.Value, len(k))
    72  		for j, v := range k {
    73  			values[j] = cadence.NewUInt8(v)
    74  		}
    75  		encodedKeys[i] = cadence.NewArray(values)
    76  	}
    77  
    78  	return encodedKeys, nil
    79  }
    80  
    81  func EncodeRuntimeAccountPublicKey(a AccountPublicKey) ([]byte, error) {
    82  	publicKey := a.PublicKey.Encode()
    83  
    84  	w := runtimeAccountPublicKeyWrapper{
    85  		PublicKey: publicKey,
    86  		SignAlgo:  uint(a.SignAlgo),
    87  		HashAlgo:  uint(a.HashAlgo),
    88  		Weight:    uint(a.Weight),
    89  	}
    90  
    91  	return rlp.EncodeToBytes(&w)
    92  }
    93  
    94  func decodeAccountPublicKeyWrapper(b []byte) (accountPublicKeyWrapper, error) {
    95  	var wrapper accountPublicKeyWrapper
    96  
    97  	err := rlp.DecodeBytes(b, &wrapper)
    98  	if err != nil {
    99  		// public key data may be stored in legacy format, so convert
   100  		var legacyWrapper legacyAccountPublicKeyWrapper
   101  
   102  		err := rlp.DecodeBytes(b, &legacyWrapper)
   103  		if err != nil {
   104  			return accountPublicKeyWrapper{}, err
   105  		}
   106  
   107  		return accountPublicKeyWrapper{
   108  			PublicKey: legacyWrapper.PublicKey,
   109  			SignAlgo:  legacyWrapper.SignAlgo,
   110  			HashAlgo:  legacyWrapper.HashAlgo,
   111  			Weight:    legacyWrapper.Weight,
   112  			SeqNumber: legacyWrapper.SeqNumber,
   113  			Revoked:   false, // all legacy keys are not revoked
   114  		}, nil
   115  	}
   116  
   117  	return wrapper, nil
   118  }
   119  
   120  func DecodeAccountPublicKey(b []byte, index uint64) (AccountPublicKey, error) {
   121  	w, err := decodeAccountPublicKeyWrapper(b)
   122  	if err != nil {
   123  		return AccountPublicKey{}, err
   124  	}
   125  
   126  	signAlgo := crypto.SigningAlgorithm(w.SignAlgo)
   127  	hashAlgo := hash.HashingAlgorithm(w.HashAlgo)
   128  
   129  	publicKey, err := crypto.DecodePublicKey(signAlgo, w.PublicKey)
   130  	if err != nil {
   131  		return AccountPublicKey{}, err
   132  	}
   133  
   134  	return AccountPublicKey{
   135  		Index:     int(index),
   136  		PublicKey: publicKey,
   137  		SignAlgo:  signAlgo,
   138  		HashAlgo:  hashAlgo,
   139  		Weight:    int(w.Weight),
   140  		SeqNumber: w.SeqNumber,
   141  		Revoked:   w.Revoked,
   142  	}, nil
   143  }
   144  
   145  // DecodeRuntimeAccountPublicKey decode bytes into AccountPublicKey
   146  // but it is designed to accept byte-format used by Cadence runtime
   147  // (currently same as SDK, but we don't want to keep explicit dependency
   148  // on SDK)
   149  func DecodeRuntimeAccountPublicKey(b []byte, seqNumber uint64) (AccountPublicKey, error) {
   150  	var w runtimeAccountPublicKeyWrapper
   151  
   152  	err := rlp.DecodeBytes(b, &w)
   153  	if err != nil {
   154  		return AccountPublicKey{}, err
   155  	}
   156  
   157  	signAlgo := crypto.SigningAlgorithm(w.SignAlgo)
   158  	hashAlgo := hash.HashingAlgorithm(w.HashAlgo)
   159  
   160  	publicKey, err := crypto.DecodePublicKey(signAlgo, w.PublicKey)
   161  	if err != nil {
   162  		return AccountPublicKey{}, err
   163  	}
   164  
   165  	return AccountPublicKey{
   166  		PublicKey: publicKey,
   167  		SignAlgo:  signAlgo,
   168  		HashAlgo:  hashAlgo,
   169  		Weight:    int(w.Weight),
   170  		SeqNumber: seqNumber,
   171  	}, nil
   172  }
   173  
   174  func EncodeAccountPrivateKey(a AccountPrivateKey) ([]byte, error) {
   175  	privateKey := a.PrivateKey.Encode()
   176  
   177  	w := accountPrivateKeyWrapper{
   178  		PrivateKey: privateKey,
   179  		SignAlgo:   uint(a.SignAlgo),
   180  		HashAlgo:   uint(a.HashAlgo),
   181  	}
   182  
   183  	return rlp.EncodeToBytes(&w)
   184  }
   185  
   186  func DecodeAccountPrivateKey(b []byte) (AccountPrivateKey, error) {
   187  	var w accountPrivateKeyWrapper
   188  
   189  	err := rlp.DecodeBytes(b, &w)
   190  	if err != nil {
   191  		return AccountPrivateKey{}, err
   192  	}
   193  
   194  	signAlgo := crypto.SigningAlgorithm(w.SignAlgo)
   195  	hashAlgo := hash.HashingAlgorithm(w.HashAlgo)
   196  
   197  	privateKey, err := crypto.DecodePrivateKey(signAlgo, w.PrivateKey)
   198  	if err != nil {
   199  		return AccountPrivateKey{}, err
   200  	}
   201  
   202  	return AccountPrivateKey{
   203  		PrivateKey: privateKey,
   204  		SignAlgo:   signAlgo,
   205  		HashAlgo:   hashAlgo,
   206  	}, nil
   207  }