github.com/stafiprotocol/go-substrate-rpc-client@v1.4.7/signature/signature.go (about)

     1  // Go Substrate RPC Client (GSRPC) provides APIs and types around Polkadot and any Substrate-based chain RPC calls
     2  //
     3  // Copyright 2020 Stafi Protocol
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package signature
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"os"
    23  	"strconv"
    24  
    25  	"github.com/stafiprotocol/go-substrate-rpc-client/sr25519"
    26  	"github.com/stafiprotocol/go-substrate-rpc-client/subkey"
    27  	"golang.org/x/crypto/blake2b"
    28  )
    29  
    30  type KeyringPair struct {
    31  	// URI is the derivation path for the private key in subkey
    32  	URI string
    33  	// Address is an SS58 address
    34  	Address string
    35  	// PublicKey
    36  	PublicKey []byte
    37  }
    38  
    39  // InspectKeyInfo type is used as target from `subkey` inspect JSON output
    40  type InspectKeyInfo struct {
    41  	AccountID    string `json:"accountId"`
    42  	PublicKey    string `json:"publicKey"`
    43  	SecretPhrase string `json:"secretPhrase"`
    44  	SecretSeed   string `json:"secretSeed"`
    45  	SS58Address  string `json:"ss58Address"`
    46  }
    47  
    48  // KeyringPairFromSecret creates KeyPair based on seed/phrase and network
    49  // Leave network empty for default behavior
    50  func KeyringPairFromSecret(seedOrPhrase string, network uint16) (KeyringPair, error) {
    51  
    52  	scheme := sr25519.Scheme{}
    53  	kyr, err := subkey.DeriveKeyPair(scheme, seedOrPhrase)
    54  	if err != nil {
    55  		return KeyringPair{}, err
    56  	}
    57  
    58  	return KeyringPair{
    59  		URI:       seedOrPhrase,
    60  		Address:   kyr.SS58Address(network),
    61  		PublicKey: kyr.Public(),
    62  	}, nil
    63  }
    64  
    65  var TestKeyringPairAlice = KeyringPair{
    66  	URI:       "//Alice",
    67  	PublicKey: []byte{0xd4, 0x35, 0x93, 0xc7, 0x15, 0xfd, 0xd3, 0x1c, 0x61, 0x14, 0x1a, 0xbd, 0x4, 0xa9, 0x9f, 0xd6, 0x82, 0x2c, 0x85, 0x58, 0x85, 0x4c, 0xcd, 0xe3, 0x9a, 0x56, 0x84, 0xe7, 0xa5, 0x6d, 0xa2, 0x7d}, //nolint:lll
    68  	Address:   "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
    69  }
    70  
    71  // Sign signs data with the private key under the given derivation path, returning the signature. Requires the subkey
    72  // command to be in path
    73  func Sign(data []byte, privateKeyURI string) ([]byte, error) {
    74  	// if data is longer than 256 bytes, hash it first
    75  	if len(data) > 256 {
    76  		h := blake2b.Sum256(data)
    77  		data = h[:]
    78  	}
    79  	scheme := sr25519.Scheme{}
    80  	kyr, err := subkey.DeriveKeyPair(scheme, privateKeyURI)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	signature, err := kyr.Sign(data)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	return signature, nil
    91  }
    92  
    93  // Verify verifies data using the provided signature and the key under the derivation path. Requires the subkey
    94  // command to be in path
    95  func Verify(data []byte, sig []byte, privateKeyURI string) (bool, error) {
    96  	// if data is longer than 256 bytes, hash it first
    97  	if len(data) > 256 {
    98  		h := blake2b.Sum256(data)
    99  		data = h[:]
   100  	}
   101  
   102  	scheme := sr25519.Scheme{}
   103  	kyr, err := subkey.DeriveKeyPair(scheme, privateKeyURI)
   104  	if err != nil {
   105  		return false, err
   106  	}
   107  
   108  	if len(sig) != 64 {
   109  		return false, errors.New("wrong signature length")
   110  	}
   111  
   112  	v := kyr.Verify(data, sig)
   113  
   114  	return v, nil
   115  }
   116  
   117  // LoadKeyringPairFromEnv looks up whether the env variable TEST_PRIV_KEY is set and is not empty and tries to use its
   118  // content as a private phrase, seed or URI to derive a key ring pair. Panics if the private phrase, seed or URI is
   119  // not valid or the keyring pair cannot be derived
   120  // Loads Network from TEST_NETWORK variable
   121  // Leave TEST_NETWORK empty or unset for default
   122  func LoadKeyringPairFromEnv() (kp KeyringPair, ok bool) {
   123  	networkString := os.Getenv("TEST_NETWORK")
   124  	network, err := strconv.ParseInt(networkString, 10, 16)
   125  	if err != nil {
   126  		// defaults to generic substrate address
   127  		// https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)#checksum-types
   128  		network = 42
   129  	}
   130  	priv, ok := os.LookupEnv("TEST_PRIV_KEY")
   131  	if !ok || priv == "" {
   132  		return kp, false
   133  	}
   134  	kp, err = KeyringPairFromSecret(priv, uint16(network))
   135  	if err != nil {
   136  		panic(fmt.Errorf("cannot load keyring pair from env or use fallback: %v", err))
   137  	}
   138  	return kp, true
   139  }