github.com/0chain/gosdk@v1.17.11/core/zcncrypto/bls0chain_herumi.go (about)

     1  //go:build !js && !wasm
     2  // +build !js,!wasm
     3  
     4  package zcncrypto
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/hex"
     9  	"fmt"
    10  	"time"
    11  
    12  	"github.com/0chain/errors"
    13  	"github.com/tyler-smith/go-bip39"
    14  
    15  	"github.com/0chain/gosdk/core/encryption"
    16  )
    17  
    18  func init() {
    19  
    20  }
    21  
    22  // HerumiScheme - a signature scheme for BLS0Chain Signature
    23  type HerumiScheme struct {
    24  	PublicKey  string `json:"public_key"`
    25  	PrivateKey string `json:"private_key"`
    26  	Mnemonic   string `json:"mnemonic"`
    27  
    28  	id  ID
    29  	Ids string `json:"threshold_scheme_id"`
    30  }
    31  
    32  // NewHerumiScheme - create a MiraclScheme object
    33  func NewHerumiScheme() *HerumiScheme {
    34  	return &HerumiScheme{
    35  		id: BlsSignerInstance.NewID(),
    36  	}
    37  }
    38  
    39  // GenerateKeys  generate fresh keys
    40  func (b0 *HerumiScheme) GenerateKeys() (*Wallet, error) {
    41  	return b0.generateKeys("0chain-client-split-key")
    42  }
    43  
    44  // GenerateKeysWithEth  generate fresh keys based on eth wallet
    45  func (b0 *HerumiScheme) GenerateKeysWithEth(mnemonic, password string) (*Wallet, error) {
    46  	if len(mnemonic) == 0 {
    47  		return nil, fmt.Errorf("Mnemonic phase is mandatory.")
    48  	}
    49  	b0.Mnemonic = mnemonic
    50  
    51  	_, err := bip39.NewSeedWithErrorChecking(b0.Mnemonic, password)
    52  	if err != nil {
    53  		return nil, fmt.Errorf("Wrong mnemonic phase.")
    54  	}
    55  
    56  	return b0.generateKeys(password)
    57  }
    58  
    59  // RecoverKeys recovery keys from mnemonic
    60  func (b0 *HerumiScheme) RecoverKeys(mnemonic string) (*Wallet, error) {
    61  	if mnemonic == "" {
    62  		return nil, errors.New("recover_keys", "Set mnemonic key failed")
    63  	}
    64  	if b0.PublicKey != "" || b0.PrivateKey != "" {
    65  		return nil, errors.New("recover_keys", "Cannot recover when there are keys")
    66  	}
    67  	b0.Mnemonic = mnemonic
    68  	return b0.GenerateKeys()
    69  }
    70  
    71  func (b0 *HerumiScheme) GetMnemonic() string {
    72  	if b0 == nil {
    73  		return ""
    74  	}
    75  
    76  	return b0.Mnemonic
    77  }
    78  
    79  // SetPrivateKey  set private key to sign
    80  func (b0 *HerumiScheme) SetPrivateKey(privateKey string) error {
    81  	if b0.PublicKey != "" {
    82  		return errors.New("set_private_key", "cannot set private key when there is a public key")
    83  	}
    84  	if b0.PrivateKey != "" {
    85  		return errors.New("set_private_key", "private key already exists")
    86  	}
    87  	b0.PrivateKey = privateKey
    88  	//ToDo: b0.publicKey should be set here?
    89  	return nil
    90  }
    91  
    92  func (b0 *HerumiScheme) GetPrivateKey() string {
    93  	return b0.PrivateKey
    94  }
    95  
    96  func (b0 *HerumiScheme) SplitKeys(numSplits int) (*Wallet, error) {
    97  	if b0.PrivateKey == "" {
    98  		return nil, errors.New("split_keys", "primary private key not found")
    99  	}
   100  	primaryFr := BlsSignerInstance.NewFr()
   101  	primarySk := BlsSignerInstance.NewSecretKey()
   102  	err := primarySk.DeserializeHexStr(b0.PrivateKey)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	err = primaryFr.SetLittleEndian(primarySk.GetLittleEndian())
   107  
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	// New Wallet
   113  	w := &Wallet{}
   114  	w.Keys = make([]KeyPair, numSplits)
   115  	sk := BlsSignerInstance.NewSecretKey()
   116  	for i := 0; i < numSplits-1; i++ {
   117  		tmpSk := BlsSignerInstance.NewSecretKey()
   118  		tmpSk.SetByCSPRNG()
   119  		w.Keys[i].PrivateKey = tmpSk.SerializeToHexStr()
   120  		pub := tmpSk.GetPublicKey()
   121  		w.Keys[i].PublicKey = pub.SerializeToHexStr()
   122  		sk.Add(tmpSk)
   123  	}
   124  	aggregateSk := BlsSignerInstance.NewFr()
   125  	err = aggregateSk.SetLittleEndian(sk.GetLittleEndian())
   126  
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	//Subtract the aggregated private key from the primary private key to derive the last split private key
   132  	lastSk := BlsSignerInstance.NewFr()
   133  	BlsSignerInstance.FrSub(lastSk, primaryFr, aggregateSk)
   134  
   135  	// Last key
   136  	lastSecretKey := BlsSignerInstance.NewSecretKey()
   137  	err = lastSecretKey.SetLittleEndian(lastSk.Serialize())
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	w.Keys[numSplits-1].PrivateKey = lastSecretKey.SerializeToHexStr()
   142  	w.Keys[numSplits-1].PublicKey = lastSecretKey.GetPublicKey().SerializeToHexStr()
   143  
   144  	// Generate client ID and public
   145  	w.ClientKey = primarySk.GetPublicKey().SerializeToHexStr()
   146  	w.ClientID = encryption.Hash(primarySk.GetPublicKey().Serialize())
   147  	w.Mnemonic = b0.Mnemonic
   148  	w.Version = CryptoVersion
   149  	w.DateCreated = time.Now().Format(time.RFC3339)
   150  
   151  	return w, nil
   152  }
   153  
   154  // Sign sign message
   155  func (b0 *HerumiScheme) Sign(hash string) (string, error) {
   156  	sig, err := b0.rawSign(hash)
   157  	if err != nil {
   158  		return "", err
   159  	}
   160  	return sig.SerializeToHexStr(), nil
   161  }
   162  
   163  // SetPublicKey - implement interface
   164  func (b0 *HerumiScheme) SetPublicKey(publicKey string) error {
   165  	if b0.PrivateKey != "" {
   166  		return errors.New("set_public_key", "cannot set public key when there is a private key")
   167  	}
   168  	if b0.PublicKey != "" {
   169  		return errors.New("set_public_key", "public key already exists")
   170  	}
   171  	b0.PublicKey = publicKey
   172  	return nil
   173  }
   174  
   175  // GetPublicKey - implement interface
   176  func (b0 *HerumiScheme) GetPublicKey() string {
   177  	return b0.PublicKey
   178  }
   179  
   180  // Verify - implement interface
   181  func (b0 *HerumiScheme) Verify(signature, msg string) (bool, error) {
   182  	if b0.PublicKey == "" {
   183  		return false, errors.New("verify", "public key does not exists for verification")
   184  	}
   185  	sig := BlsSignerInstance.NewSignature()
   186  	pk := BlsSignerInstance.NewPublicKey()
   187  	err := sig.DeserializeHexStr(signature)
   188  	if err != nil {
   189  		return false, err
   190  	}
   191  	rawHash, err := hex.DecodeString(msg)
   192  	if err != nil {
   193  		return false, err
   194  	}
   195  	if rawHash == nil {
   196  		return false, errors.New("verify", "failed hash while signing")
   197  	}
   198  	err = pk.DeserializeHexStr(b0.PublicKey)
   199  	if err != nil {
   200  		return false, err
   201  	}
   202  
   203  	return sig.Verify(pk, string(rawHash)), nil
   204  }
   205  
   206  func (b0 *HerumiScheme) Add(signature, msg string) (string, error) {
   207  	sign := BlsSignerInstance.NewSignature()
   208  	err := sign.DeserializeHexStr(signature)
   209  	if err != nil {
   210  		return "", err
   211  	}
   212  	signature1, err := b0.rawSign(msg)
   213  	if err != nil {
   214  		return "", errors.Wrap(err, "BLS signing failed")
   215  	}
   216  	sign.Add(signature1)
   217  	return sign.SerializeToHexStr(), nil
   218  }
   219  
   220  // GetPrivateKeyAsByteArray - converts private key into byte array
   221  func (b0 *HerumiScheme) GetPrivateKeyAsByteArray() ([]byte, error) {
   222  	if len(b0.PrivateKey) == 0 {
   223  		return nil, errors.New("get_private_key_as_byte_array", "cannot convert empty private key to byte array")
   224  	}
   225  	privateKeyBytes, err := hex.DecodeString(b0.PrivateKey)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	return privateKeyBytes, nil
   230  }
   231  
   232  // SetID sets ID in HexString format
   233  func (b0 *HerumiScheme) SetID(id string) error {
   234  	if b0.id == nil {
   235  		b0.id = BlsSignerInstance.NewID()
   236  	}
   237  	b0.Ids = id
   238  	return b0.id.SetHexString(id)
   239  }
   240  
   241  // GetID gets ID in hex string format
   242  func (b0 *HerumiScheme) GetID() string {
   243  	if b0.id == nil {
   244  		b0.id = BlsSignerInstance.NewID()
   245  	}
   246  	return b0.id.GetHexString()
   247  }
   248  
   249  func (b0 *HerumiScheme) generateKeys(password string) (*Wallet, error) {
   250  	// Check for recovery
   251  	if len(b0.Mnemonic) == 0 {
   252  		entropy, err := bip39.NewEntropy(256)
   253  		if err != nil {
   254  			return nil, errors.Wrap(err, "Generating entropy failed")
   255  		}
   256  		b0.Mnemonic, err = bip39.NewMnemonic(entropy)
   257  		if err != nil {
   258  			return nil, errors.Wrap(err, "Generating mnemonic failed")
   259  		}
   260  	}
   261  
   262  	// Generate a Bip32 HD wallet for the mnemonic and a user supplied password
   263  	seed := bip39.NewSeed(b0.Mnemonic, password)
   264  	r := bytes.NewReader(seed)
   265  	BlsSignerInstance.SetRandFunc(r)
   266  
   267  	// New Wallet
   268  	w := &Wallet{}
   269  	w.Keys = make([]KeyPair, 1)
   270  
   271  	// Generate pair
   272  	sk := BlsSignerInstance.NewSecretKey()
   273  	sk.SetByCSPRNG()
   274  	w.Keys[0].PrivateKey = sk.SerializeToHexStr()
   275  	pub := sk.GetPublicKey()
   276  	w.Keys[0].PublicKey = pub.SerializeToHexStr()
   277  
   278  	b0.PrivateKey = w.Keys[0].PrivateKey
   279  	b0.PublicKey = w.Keys[0].PublicKey
   280  	w.ClientKey = w.Keys[0].PublicKey
   281  	w.ClientID = encryption.Hash(pub.Serialize())
   282  	w.Mnemonic = b0.Mnemonic
   283  	w.Version = CryptoVersion
   284  	w.DateCreated = time.Now().Format(time.RFC3339)
   285  
   286  	// Revert the Random function to default
   287  	BlsSignerInstance.SetRandFunc(nil)
   288  	return w, nil
   289  }
   290  
   291  func (b0 *HerumiScheme) rawSign(hash string) (Signature, error) {
   292  	sk := BlsSignerInstance.NewSecretKey()
   293  	if b0.PrivateKey == "" {
   294  		return nil, errors.New("raw_sign", "private key does not exists for signing")
   295  	}
   296  	rawHash, err := hex.DecodeString(hash)
   297  	if err != nil {
   298  		return nil, err
   299  	}
   300  	if rawHash == nil {
   301  		return nil, errors.New("raw_sign", "failed hash while signing")
   302  	}
   303  	sk.SetByCSPRNG()
   304  	err = sk.DeserializeHexStr(b0.PrivateKey)
   305  	if err != nil {
   306  		return nil, err
   307  	}
   308  	sig := sk.Sign(string(rawHash))
   309  	return sig, nil
   310  }