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 }