func main() { var testnet bool if len(os.Args) < 3 { fmt.Println("Specify B_secret, A_public_key and optionaly number of addresses you want.") fmt.Println("Use a negative value for number of addresses, to work with Testnet addresses.") return } A_public_key, er := hex.DecodeString(os.Args[2]) if er != nil { println("Error parsing A_public_key:", er.Error()) os.Exit(1) } pubk, er := btc.NewPublicKey(A_public_key) if er != nil { println("Invalid valid public key:", er.Error()) os.Exit(1) } compressed := len(A_public_key) == 33 B_secret, er := hex.DecodeString(os.Args[1]) if er != nil { println("Error parsing B_secret:", er.Error()) os.Exit(1) } sec := new(big.Int).SetBytes(B_secret) n := int64(25) if len(os.Args) > 3 { n, er = strconv.ParseInt(os.Args[3], 10, 32) if er != nil { println("Error parsing number of keys value:", er.Error()) os.Exit(1) } if n == 0 { return } if n < 0 { n = -n testnet = true } } fmt.Println("# Type-2") fmt.Println("#", hex.EncodeToString(pubk.Bytes(compressed))) fmt.Println("#", hex.EncodeToString(sec.Bytes())) for i := 1; i <= int(n); i++ { fmt.Println(btc.NewAddrFromPubkey(pubk.Bytes(compressed), btc.AddrVerPubkey(testnet)).String(), "TypB", i) if i >= int(n) { break } pubk.X, pubk.Y = btc.DeriveNextPublic(pubk.X, pubk.Y, sec) } }
func dump_sigscript(d []byte) { if len(d) < 10+34 { // at least 10 bytes for sig and 34 bytes key fmt.Println(" WARNING: Short sigScript") fmt.Print(hex_dump(d)) return } rd := bytes.NewReader(d) // ECDSA Signature le, _ := rd.ReadByte() sd := make([]byte, le) _, er := rd.Read(sd) if er != nil { fmt.Println(" WARNING: Signature too short", er.Error()) fmt.Print(hex_dump(d)) return } sig, er := btc.NewSignature(sd) if er != nil { fmt.Println(" WARNING: Signature broken", er.Error()) fmt.Print(hex_dump(d)) return } fmt.Printf(" R = %64s\n", hex.EncodeToString(sig.R.Bytes())) fmt.Printf(" S = %64s\n", hex.EncodeToString(sig.S.Bytes())) fmt.Printf(" HashType = %02x\n", sig.HashType) // Key le, er = rd.ReadByte() if er != nil { fmt.Println(" WARNING: PublicKey not present") fmt.Print(hex_dump(d)) return } sd = make([]byte, le) _, er = rd.Read(sd) if er != nil { fmt.Println(" WARNING: PublicKey too short", er.Error()) fmt.Print(hex_dump(d)) return } fmt.Printf(" PublicKeyType = %02x\n", sd[0]) key, er := btc.NewPublicKey(sd) if er != nil { fmt.Println(" WARNING: PublicKey broken", er.Error()) fmt.Print(hex_dump(d)) return } fmt.Printf(" X = %64s\n", hex.EncodeToString(key.X.Bytes())) if le >= 65 { fmt.Printf(" Y = %64s\n", hex.EncodeToString(key.Y.Bytes())) } if rd.Len() != 0 { fmt.Println(" WARNING: Extra bytes at the end of sigScript") fmt.Print(hex_dump(d[len(d)-rd.Len():])) } }
func main() { if len(os.Args) < 3 { fmt.Println("Specify B_secret and A_public_key to get the next Type-2 deterministic address") fmt.Println("Add -t as the third argument to work with Testnet addresses.") return } A_public_key, er := hex.DecodeString(os.Args[2]) if er != nil { println("Error parsing A_public_key:", er.Error()) os.Exit(1) } pubk, er := btc.NewPublicKey(A_public_key) if er != nil { println("Invalid valid public key:", er.Error()) os.Exit(1) } compressed := len(A_public_key) == 33 B_secret, er := hex.DecodeString(os.Args[1]) if er != nil { println("Error parsing B_secret:", er.Error()) os.Exit(1) } sec := new(big.Int).SetBytes(B_secret) testnet := len(os.Args) > 3 && os.Args[3] == "-t" // Old address fmt.Print(btc.NewAddrFromPubkey(pubk.Bytes(compressed), btc.AddrVerPubkey(testnet)).String(), " => ") pubk.X, pubk.Y = btc.DeriveNextPublic(pubk.X, pubk.Y, sec) // New address fmt.Println(btc.NewAddrFromPubkey(pubk.Bytes(compressed), btc.AddrVerPubkey(testnet)).String()) // New key fmt.Println(hex.EncodeToString(pubk.Bytes(compressed))) }
// Verify the secret key's range and al if a test message signed with it verifies OK func verify_key(priv []byte, publ []byte) bool { const TestMessage = "Just some test message..." hash := btc.Sha2Sum([]byte(TestMessage)) pub_key, e := btc.NewPublicKey(publ) if e != nil { println("NewPublicKey:", e.Error(), "\007") os.Exit(1) } var key ecdsa.PrivateKey key.D = new(big.Int).SetBytes(priv) key.PublicKey = pub_key.PublicKey if key.D.Cmp(big.NewInt(0)) == 0 { println("pubkey value is zero") return false } if key.D.Cmp(maxKeyVal) != -1 { println("pubkey value is too big", hex.EncodeToString(publ)) return false } r, s, err := ecdsa.Sign(rand.Reader, &key, hash[:]) if err != nil { println("ecdsa.Sign:", err.Error()) return false } ok := ecdsa.Verify(&key.PublicKey, hash[:], r, s) if !ok { println("The key pair does not verify!") return false } return true }
func multisig_sign() { tx := raw_tx_from_file(*rawtx) if tx == nil { println("ERROR: Cannot decode the raw multisig transaction") println("Always use -msign <addr> along with -raw multi2sign.txt") return } ad2s, e := btc.NewAddrFromString(*multisign) if e != nil { println("BTC addr:", e.Error()) return } var privkey *ecdsa.PrivateKey //var compr bool for i := range publ_addrs { if publ_addrs[i].Hash160 == ad2s.Hash160 { privkey = new(ecdsa.PrivateKey) pub, e := btc.NewPublicKey(publ_addrs[i].Pubkey) if e != nil { println("PubKey:", e.Error()) return } privkey.PublicKey = pub.PublicKey privkey.D = new(big.Int).SetBytes(priv_keys[i][:]) //compr = compressed_key[i] break } } if privkey == nil { println("You do not know a key for address", ad2s.String()) return } for i := range tx.TxIn { ms, er := btc.NewMultiSigFromScript(tx.TxIn[i].ScriptSig) if er != nil { println("WARNING: Input", i, "- not multisig:", er.Error()) continue } hash := tx.SignatureHash(ms.P2SH(), i, btc.SIGHASH_ALL) //fmt.Println("Input number", i, len(ms.Signatures), " - hash to sign:", hex.EncodeToString(hash)) btcsig := &btc.Signature{HashType: 0x01} btcsig.R, btcsig.S, e = btc.EcdsaSign(privkey, hash) if e != nil { println(e.Error()) return } ms.Signatures = append(ms.Signatures, btcsig) tx.TxIn[i].ScriptSig = ms.Bytes() } // Now re-order the signatures as they shall be: for i := range tx.TxIn { ms, er := btc.NewMultiSigFromScript(tx.TxIn[i].ScriptSig) if er != nil { //println(er.Error()) continue } hash := tx.SignatureHash(ms.P2SH(), i, btc.SIGHASH_ALL) //fmt.Println("Input number", i, " - hash to sign:", hex.EncodeToString(hash)) //fmt.Println(" ... number of signatures:", len(ms.Signatures)) var sigs []*btc.Signature for ki := range ms.PublicKeys { //pk := btc.NewPublicKey(ms.PublicKeys[ki]) //fmt.Println(ki, hex.EncodeToString(ms.PublicKeys[ki])) var sig *btc.Signature for si := range ms.Signatures { if btc.EcdsaVerify(ms.PublicKeys[ki], ms.Signatures[si].Bytes(), hash) { //fmt.Println("Key number", ki, "has signature number", si) sig = ms.Signatures[si] break } } if sig != nil { sigs = append(sigs, sig) } else if *verbose { fmt.Println("WARNING: Key number", ki, "has no matching signature") } if !*allowextramsigns && uint(len(sigs)) >= ms.SigsNeeded { break } } if len(ms.Signatures) > len(sigs) { fmt.Println("WARNING: Some signatures are obsolete and will be removed", len(ms.Signatures), "=>", len(sigs)) } else if len(ms.Signatures) < len(sigs) { fmt.Println("It appears that same key is re-used.", len(sigs)-len(ms.Signatures), "more signatures were added") } ms.Signatures = sigs tx.TxIn[i].ScriptSig = ms.Bytes() } write_tx_file(tx) }
// prepare a signed transaction func make_signed_tx() { // Make an empty transaction tx := new(btc.Tx) tx.Version = 1 tx.Lock_time = 0 // Select as many inputs as we need to pay the full amount (with the fee) var btcsofar uint64 var inpcnt uint for inpcnt = 0; inpcnt < uint(len(unspentOuts)); inpcnt++ { uo := UO(unspentOuts[inpcnt]) // add the input to our transaction: tin := new(btc.TxIn) tin.Input = *unspentOuts[inpcnt] tin.Sequence = 0xffffffff tx.TxIn = append(tx.TxIn, tin) btcsofar += uo.Value if btcsofar >= spendBtc+feeBtc { break } } changeBtc = btcsofar - (spendBtc + feeBtc) fmt.Printf("Spending %d out of %d outputs...\n", inpcnt+1, len(unspentOuts)) // Build transaction outputs: tx.TxOut = make([]*btc.TxOut, len(sendTo)) for o := range sendTo { tx.TxOut[o] = &btc.TxOut{Value: sendTo[o].amount, Pk_script: sendTo[o].addr.OutScript()} } if changeBtc > 0 { // Add one more output (with the change) tx.TxOut = append(tx.TxOut, &btc.TxOut{Value: changeBtc, Pk_script: get_change_addr().OutScript()}) } //fmt.Println("Unsigned:", hex.EncodeToString(tx.Serialize())) for in := range tx.TxIn { uo := UO(unspentOuts[in]) var found bool for j := range publ_addrs { if publ_addrs[j].Owns(uo.Pk_script) { pub_key, e := btc.NewPublicKey(publ_addrs[j].Pubkey) if e != nil { println("NewPublicKey:", e.Error(), "\007") os.Exit(1) } // Load the key (private and public) var key ecdsa.PrivateKey key.D = new(big.Int).SetBytes(priv_keys[j][:]) key.PublicKey = pub_key.PublicKey //Calculate proper transaction hash h := tx.SignatureHash(uo.Pk_script, in, btc.SIGHASH_ALL) //fmt.Println("SignatureHash:", btc.NewUint256(h).String()) // Sign r, s, err := ecdsa.Sign(rand.Reader, &key, h) if err != nil { println("Sign:", err.Error(), "\007") os.Exit(1) } rb := r.Bytes() sb := s.Bytes() if rb[0] >= 0x80 { // I thinnk this is needed, thought I am not quite sure... :P rb = append([]byte{0x00}, rb...) } if sb[0] >= 0x80 { // I thinnk this is needed, thought I am not quite sure... :P sb = append([]byte{0x00}, sb...) } // Output the signing result into a buffer, in format expected by bitcoin protocol busig := new(bytes.Buffer) busig.WriteByte(0x30) busig.WriteByte(byte(4 + len(rb) + len(sb))) busig.WriteByte(0x02) busig.WriteByte(byte(len(rb))) busig.Write(rb) busig.WriteByte(0x02) busig.WriteByte(byte(len(sb))) busig.Write(sb) busig.WriteByte(0x01) // hash type // Output the signature and the public key into tx.ScriptSig buscr := new(bytes.Buffer) buscr.WriteByte(byte(busig.Len())) buscr.Write(busig.Bytes()) buscr.WriteByte(byte(len(publ_addrs[j].Pubkey))) buscr.Write(publ_addrs[j].Pubkey) // assign: tx.TxIn[in].ScriptSig = buscr.Bytes() found = true break } } if !found { fmt.Println("You do not have private key for input number", hex.EncodeToString(uo.Pk_script), "\007") os.Exit(1) } } rawtx := tx.Serialize() tx.Hash = btc.NewSha2Hash(rawtx) hs := tx.Hash.String() fmt.Println(hs) f, _ := os.Create(hs[:8] + ".txt") if f != nil { f.Write([]byte(hex.EncodeToString(rawtx))) f.Close() fmt.Println("Transaction data stored in", hs[:8]+".txt") } f, _ = os.Create("balance/unspent.txt") if f != nil { for j := uint(0); j < uint(len(unspentOuts)); j++ { if j > inpcnt { fmt.Fprintln(f, unspentOuts[j], unspentOutsLabel[j]) } } fmt.Println(inpcnt, "spent output(s) removed from 'balance/unspent.txt'") var addback int for out := range tx.TxOut { for j := range publ_addrs { if publ_addrs[j].Owns(tx.TxOut[out].Pk_script) { fmt.Fprintf(f, "%s-%03d # %.8f / %s\n", tx.Hash.String(), out, float64(tx.TxOut[out].Value)/1e8, publ_addrs[j].String()) addback++ } } } f.Close() if addback > 0 { f, _ = os.Create("balance/" + hs + ".tx") if f != nil { f.Write(rawtx) f.Close() } fmt.Println(addback, "new output(s) appended to 'balance/unspent.txt'") } } }
func sign_message() { ad2s, e := btc.NewAddrFromString(*signaddr) if e != nil { println(e.Error()) return } var privkey *ecdsa.PrivateKey for i := range publ_addrs { if publ_addrs[i].Hash160 == ad2s.Hash160 { privkey = new(ecdsa.PrivateKey) pub, e := btc.NewPublicKey(publ_addrs[i].Pubkey) if e != nil { println(e.Error()) return } privkey.PublicKey = pub.PublicKey privkey.D = new(big.Int).SetBytes(priv_keys[i][:]) break } } if privkey == nil { println("You do not have a private key for", ad2s.String()) return } var msg []byte if *message == "" { msg, _ = ioutil.ReadAll(os.Stdin) } else { msg = []byte(*message) } hash := make([]byte, 32) btc.HashFromMessage(msg, hash) btcsig := new(btc.Signature) var sb [65]byte sb[0] = 27 if !*uncompressed { sb[0] += 4 } btcsig.R, btcsig.S, e = ecdsa_Sign(privkey, hash) if e != nil { println(e.Error()) return } rd := btcsig.R.Bytes() sd := btcsig.S.Bytes() copy(sb[1+32-len(rd):], rd) copy(sb[1+64-len(sd):], sd) rpk := btcsig.RecoverPublicKey(hash[:], 0) sa := btc.NewAddrFromPubkey(rpk.Bytes(!*uncompressed), ad2s.Version) if sa.Hash160 == ad2s.Hash160 { fmt.Println(base64.StdEncoding.EncodeToString(sb[:])) return } rpk = btcsig.RecoverPublicKey(hash[:], 1) sa = btc.NewAddrFromPubkey(rpk.Bytes(!*uncompressed), ad2s.Version) if sa.Hash160 == ad2s.Hash160 { sb[0]++ fmt.Println(base64.StdEncoding.EncodeToString(sb[:])) return } println("Something went wrong. The message has not been signed.") }
// this function signs either a message or a raw transaction hash func sign_message() { var hash []byte if *signhash != "" { var er error hash, er = hex.DecodeString(*signhash) if er != nil { println("Incorrect content of -hash parameter") println(er.Error()) return } } ad2s, e := btc.NewAddrFromString(*signaddr) if e != nil { println(e.Error()) if *signhash != "" { println("Always use -sign <addr> along with -hash <msghash>") } return } var privkey *ecdsa.PrivateKey var compr bool for i := range publ_addrs { if publ_addrs[i].Hash160 == ad2s.Hash160 { privkey = new(ecdsa.PrivateKey) pub, e := btc.NewPublicKey(publ_addrs[i].Pubkey) if e != nil { println(e.Error()) return } privkey.PublicKey = pub.PublicKey privkey.D = new(big.Int).SetBytes(priv_keys[i][:]) compr = compressed_key[i] // Sign raw hash? if hash != nil { txsig := new(btc.Signature) txsig.HashType = 0x01 txsig.R, txsig.S, e = btc.EcdsaSign(privkey, hash) if e != nil { println(e.Error()) return } fmt.Println("PublicKey:", hex.EncodeToString(publ_addrs[i].Pubkey)) fmt.Println(hex.EncodeToString(txsig.Bytes())) return } break } } if privkey == nil { println("You do not have a private key for", ad2s.String()) return } var msg []byte if *message == "" { msg, _ = ioutil.ReadAll(os.Stdin) } else { msg = []byte(*message) } hash = make([]byte, 32) btc.HashFromMessage(msg, hash) btcsig := new(btc.Signature) var sb [65]byte sb[0] = 27 if compr { sb[0] += 4 } btcsig.R, btcsig.S, e = btc.EcdsaSign(privkey, hash) if e != nil { println(e.Error()) return } rd := btcsig.R.Bytes() sd := btcsig.S.Bytes() copy(sb[1+32-len(rd):], rd) copy(sb[1+64-len(sd):], sd) rpk := btcsig.RecoverPublicKey(hash[:], 0) sa := btc.NewAddrFromPubkey(rpk.Bytes(compr), ad2s.Version) if sa.Hash160 == ad2s.Hash160 { fmt.Println(base64.StdEncoding.EncodeToString(sb[:])) return } rpk = btcsig.RecoverPublicKey(hash[:], 1) sa = btc.NewAddrFromPubkey(rpk.Bytes(compr), ad2s.Version) if sa.Hash160 == ad2s.Hash160 { sb[0]++ fmt.Println(base64.StdEncoding.EncodeToString(sb[:])) return } println("Something went wrong. The message has not been signed.") }
/* { "address" : "2NAHUDSC1EmbTBwQQp4VQ2FNzWDqHtmk1i6", "redeemScript" : "512102cdc4fff0ad031ea5f2d0d4337e2bf976b84334f8f80b08fe3f69886d58bc5a8a2102ebf54926d3edaae51bde71f2976948559a8d43fce52f5e7ed9ed85dbaa449d7f52ae" } */ func main() { var testnet bool if len(os.Args) < 3 { fmt.Println("Specify one integer and at least one public key.") fmt.Println("For Testent, make the integer negative.") return } cnt, er := strconv.ParseInt(os.Args[1], 10, 32) if er != nil { println("Count value:", er.Error()) return } if cnt < 0 { testnet = true cnt = -cnt } if cnt < 1 || cnt > 16 { println("The integer (required number of keys) must be between 1 and 16") return } buf := new(bytes.Buffer) buf.WriteByte(byte(0x50 + cnt)) fmt.Println("Trying to prepare multisig address for", cnt, "out of", len(os.Args)-2, "public keys ...") var pkeys byte var ads string for i := 2; i < len(os.Args); i++ { if pkeys == 16 { println("Oh, give me a break. You don't need more than 16 public keys - stopping here!") break } d, er := hex.DecodeString(os.Args[i]) if er != nil { println("pubkey", i, er.Error()) } _, er = btc.NewPublicKey(d) if er != nil { println("pubkey", i, er.Error()) return } pkeys++ buf.WriteByte(byte(len(d))) buf.Write(d) if ads != "" { ads += ", " } ads += "\"" + btc.NewAddrFromPubkey(d, btc.AddrVerPubkey(testnet)).String() + "\"" } buf.WriteByte(0x50 + pkeys) buf.WriteByte(0xae) p2sh := buf.Bytes() addr := btc.NewAddrFromPubkey(p2sh, btc.AddrVerScript(testnet)) rec := "{\n" rec += fmt.Sprintf("\t\"multiAddress\" : \"%s\",\n", addr.String()) rec += fmt.Sprintf("\t\"scriptPubKey\" : \"a914%s87\",\n", hex.EncodeToString(addr.Hash160[:])) rec += fmt.Sprintf("\t\"keysRequired\" : %d,\n", cnt) rec += fmt.Sprintf("\t\"keysProvided\" : %d,\n", pkeys) rec += fmt.Sprintf("\t\"redeemScript\" : \"%s\",\n", hex.EncodeToString(p2sh)) rec += fmt.Sprintf("\t\"listOfAddres\" : [%s]\n", ads) rec += "}\n" fname := addr.String() + ".json" ioutil.WriteFile(fname, []byte(rec), 0666) fmt.Println("The address record stored in", fname) }