//GenerateKey generates random PublicKey and PrivateKey. func GenerateKey(flagTestnet bool) (*Key, error) { seed := make([]byte, 32) _, err := rand.Read(seed) if err != nil { return nil, err } s256 := btcec.S256() private := PrivateKey{} private.isTestnet = flagTestnet public := PublicKey{} public.isTestnet = flagTestnet private.key, public.key = btcec.PrivKeyFromBytes(s256, seed) key := Key{ Pub: &public, Priv: &private, } //Print the keys logging.Println("Your private key in WIF is") logging.Println(private.GetWIFAddress()) logging.Println("Your address is") logging.Println(public.GetAddress()) return &key, nil }
//GetKeyFromWIF gets PublicKey and PrivateKey from private key of WIF format. func GetKeyFromWIF(wif string) (*Key, error) { secp256k1 := btcec.S256() privateKeyBytes, isCmpressed, err := base58check.Decode(wif) if err != nil { return nil, err } pub := PublicKey{} priv := PrivateKey{} key := Key{ Pub: &pub, Priv: &priv, } switch privateKeyBytes[0] { case 0xef: pub.isTestnet = true priv.isTestnet = true case 0x80: pub.isTestnet = false priv.isTestnet = false default: return nil, errors.New("cannot determin net param from private key") } pub.isCompressed = isCmpressed //Get the raw public priv.key, pub.key = btcec.PrivKeyFromBytes(secp256k1, privateKeyBytes[1:]) return &key, nil }
//GetPublicKey returns PublicKey struct using public key hex string. func GetPublicKey(pubKeyByte []byte, isTestnet bool) (*PublicKey, error) { secp256k1 := btcec.S256() key, err := btcec.ParsePubKey(pubKeyByte, secp256k1) if err != nil { return nil, err } return &PublicKey{key: key, isTestnet: isTestnet}, nil }
// CreateScriptSig signs a raw transaction with keys. func (rs *RedeemScript) createScriptSig(rawTransactionHashed []byte, signs [][]byte) ([]byte, error) { //Verify that it worked. secp256k1 := btcec.S256() count := 0 for i, signature := range signs { if signature == nil { continue } count++ sig, err := btcec.ParseSignature(signature, secp256k1) if err != nil { return nil, err } valid := sig.Verify(rawTransactionHashed, rs.PublicKeys[i].key) if !valid { return nil, fmt.Errorf("number %d of signature is invalid", i) } } if count != rs.M { return nil, fmt.Errorf("number of signatures %d must be %d", count, rs.M) } //redeemScript length. To allow redeemScript > 255 bytes, we use OP_PUSHDATA2 and use two bytes to specify length var redeemScriptLengthBytes []byte var requiredPUSHDATA byte if len(rs.Script) < 255 { requiredPUSHDATA = opPUSHDATA1 //OP_PUSHDATA1 specifies next *one byte* will be length to be pushed to stack redeemScriptLengthBytes = []byte{byte(len(rs.Script))} } else { requiredPUSHDATA = opPUSHDATA2 //OP_PUSHDATA2 specifies next *two bytes* will be length to be pushed to stack redeemScriptLengthBytes = make([]byte, 2) binary.LittleEndian.PutUint16(redeemScriptLengthBytes, uint16(len(rs.Script))) } //Create scriptSig var buffer bytes.Buffer buffer.WriteByte(op0) //OP_0 for Multisig off-by-one error for _, signature := range signs { if signature == nil { continue } buffer.WriteByte(byte(len(signature) + 1)) //PUSH each signature. Add one for hash type byte buffer.Write(signature) // Signature bytes buffer.WriteByte(0x1) //hash type } buffer.WriteByte(requiredPUSHDATA) //OP_PUSHDATA1 or OP_PUSHDATA2 depending on size of redeemScript buffer.Write(redeemScriptLengthBytes) //PUSH redeemScript buffer.Write(rs.Script) //redeemScript return buffer.Bytes(), nil }
//SignMessage sign using bitcoin sign struct func (key *Key) SignMessage(hash []byte) ([]byte, error) { msg := make([]byte, 0) msg = append(msg, []byte("\x18Bitcoin Signed Message:\n")...) msg = append(msg, []byte{byte(len(hash))}...) msg = append(msg, hash...) h := sha256.Sum256(msg) hh := sha256.Sum256(h[:]) s256 := btcec.S256() sig, err := btcec.SignCompact(s256, key.Priv.key, hh[:], key.Pub.isCompressed) if err != nil { return nil, err } return sig, nil }