func main() { var testnet bool if len(os.Args) < 3 { fmt.Println("Specify secret, 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 } public_key, er := hex.DecodeString(os.Args[2]) if er != nil { println("Error parsing public_key:", er.Error()) os.Exit(1) } if len(public_key) == 33 && (public_key[0] == 2 || public_key[0] == 3) { fmt.Println("Compressed") } else if len(public_key) == 65 && (public_key[0] == 4) { fmt.Println("Uncompressed") } else { println("Incorrect public key") } secret, er := hex.DecodeString(os.Args[1]) if er != nil { println("Error parsing secret:", er.Error()) os.Exit(1) } 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(public_key)) fmt.Println("#", hex.EncodeToString(secret)) for i := 1; i <= int(n); i++ { fmt.Println(btc.NewAddrFromPubkey(public_key, btc.AddrVerPubkey(testnet)).String(), "TypB", i) if i >= int(n) { break } public_key = btc.DeriveNextPublic(public_key, secret) } }
func main() { if len(os.Args) < 3 { fmt.Println("Specify at least two parameters:") fmt.Println(" 1) The base58 encoded bitcoin addres, that the signature was made with") fmt.Println(" 2) The base64 encoded signature for the message...") fmt.Println("If you specify a 3rd parameter - this will be assumed to be the message you want to verify") fmt.Println("If you do not specify a 3rd parameter - the message will be read from stdin") return } ad, er := btc.NewAddrFromString(os.Args[1]) if er != nil { println("Address:", er.Error()) return } nv, btcsig, er := btc.ParseMessageSignature(os.Args[2]) if er != nil { println("ParseMessageSignature:", er.Error()) return } var msg []byte if len(os.Args) < 4 { msg, _ = ioutil.ReadAll(os.Stdin) } else { msg = []byte(os.Args[3]) } hash := make([]byte, 32) btc.HashFromMessage(msg, hash) compressed := false if nv >= 31 { //println("compressed key") nv -= 4 compressed = true } pub := btcsig.RecoverPublicKey(hash[:], int(nv-27)) if pub != nil { pk := pub.Bytes(compressed) ok := btc.EcdsaVerify(pk, btcsig.Bytes(), hash) if ok { sa := btc.NewAddrFromPubkey(pk, ad.Version) if ad.Hash160 != sa.Hash160 { fmt.Println("BAD signature for", ad.String()) os.Exit(1) } else { fmt.Println("Good signature for", sa.String()) } } else { println("BAD signature") os.Exit(1) } } else { println("BAD, BAD, BAD signature") os.Exit(1) } }
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 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))) }
// Get the secret seed and generate "*keycnt" key pairs (both private and public) func make_wallet() { var verbyte byte // normally it will be zero (means: normal bitcoin network) if *testnet { verbyte = 0x6f // .. but for testnet we need 0x6f } pass := getpass() curv := btc.S256() seed_key := btc.Sha2Sum([]byte(pass)) priv_keys = make([][32]byte, *keycnt) publ_addrs = make([]*btc.BtcAddr, *keycnt) fmt.Println("Generating", *keycnt, "keys, version", verbyte, "...") for i := uint(0); i < *keycnt; i++ { seed_key = btc.Sha2Sum(seed_key[:]) priv_keys[i] = seed_key publ_addrs[i] = btc.NewAddrFromPubkey(getPubKey(curv, seed_key[:]), verbyte) } fmt.Println("Private keys re-generated") }
func main() { if len(os.Args) < 3 { fmt.Println("Specify secret and public_key to get the next Type-2 deterministic address") fmt.Println("Add -t as the third argument to work with Testnet addresses.") return } public_key, er := hex.DecodeString(os.Args[2]) if er != nil { println("Error parsing public_key:", er.Error()) os.Exit(1) } if len(public_key) == 33 && (public_key[0] == 2 || public_key[0] == 3) { fmt.Println("Compressed") } else if len(public_key) == 65 && (public_key[0] == 4) { fmt.Println("Uncompressed") } else { println("Incorrect public key") } secret, er := hex.DecodeString(os.Args[1]) if er != nil { println("Error parsing secret:", er.Error()) os.Exit(1) } testnet := len(os.Args) > 3 && os.Args[3] == "-t" // Old address public_key = btc.DeriveNextPublic(public_key, secret) // New address fmt.Println(btc.NewAddrFromPubkey(public_key, btc.AddrVerPubkey(testnet)).String()) // New key fmt.Println(hex.EncodeToString(public_key)) }
func newAddressInfoFromWord(word string) *AddressInfo { sha256Hash := sha256.New() _, err := sha256Hash.Write([]byte(word)) if err != nil { panic(err) } privateKey := sha256Hash.Sum(nil) publicKey, err := btc.PublicFromPrivate(privateKey, false) if err != nil { panic(err) } address := btc.NewAddrFromPubkey(publicKey, btc.ADDRVER_BTC).String() resp, err := http.Get("http://blockchain.info/address/" + address + "?format=json") if err != nil { panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } var addressInfo AddressInfo err = json.Unmarshal(body, &addressInfo) if err != nil { panic(err) } addressInfo.Word = word addressInfo.Key = hex.EncodeToString(privateKey) return &addressInfo }
func load_others() { f, e := os.Open(RawKeysFilename) if e == nil { defer f.Close() td := bufio.NewReader(f) for { li, _, _ := td.ReadLine() if li == nil { break } pk := strings.SplitN(strings.Trim(string(li), " "), " ", 2) if pk[0][0] == '#' { continue // Just a comment-line } pkb := btc.Decodeb58(pk[0]) if pkb == nil { println("Decodeb58 failed:", pk[0][:6]) continue } if len(pkb) != 37 && len(pkb) != 38 { println(pk[0][:6], "has wrong key", len(pkb)) println(hex.EncodeToString(pkb)) continue } if pkb[0] != privver { println(pk[0][:6], "has version", pkb[0], "while we expect", privver) if pkb[0] == 0xef { fmt.Println("You probably meant testnet, so use -t switch") os.Exit(0) } else { continue } } var sh [32]byte var compr bool if len(pkb) == 37 { // compressed key sh = btc.Sha2Sum(pkb[0:33]) if !bytes.Equal(sh[:4], pkb[33:37]) { println(pk[0][:6], "checksum error") continue } compr = false } else { if pkb[33] != 1 { println(pk[0][:6], "a key of length 38 bytes must be compressed") continue } sh = btc.Sha2Sum(pkb[0:34]) if !bytes.Equal(sh[:4], pkb[34:38]) { println(pk[0][:6], "checksum error") continue } compr = true } key := pkb[1:33] pub, er := btc.PublicFromPrivate(key, compr) if er != nil { println("PublicFromPrivate:", e.Error()) os.Exit(1) } priv_keys = append(priv_keys, key) publ_addrs = append(publ_addrs, btc.NewAddrFromPubkey(pub, verbyte)) if len(pk) > 1 { labels = append(labels, pk[1]) } else { labels = append(labels, fmt.Sprint("Other ", len(priv_keys))) } } if *verbose { fmt.Println(len(priv_keys), "keys imported from", RawKeysFilename) } } else { if *verbose { fmt.Println("You can also have some dumped (b58 encoded) priv keys in file", RawKeysFilename) } } }
// Get the secret seed and generate "*keycnt" key pairs (both private and public) func make_wallet() { var lab string if *testnet { verbyte = 0x6f privver = 0xef } else { // verbyte is be zero by definition privver = 0x80 } load_others() pass := getpass() seed_key := make([]byte, 32) btc.ShaHash([]byte(pass), seed_key) if *waltype == 3 { lab = "TypC" } else if *waltype == 2 { if *type2sec != "" { d, e := hex.DecodeString(*type2sec) if e != nil { println("t2sec error:", e.Error()) os.Exit(1) } type2_secret = new(big.Int).SetBytes(d) } else { var buf [32]byte btc.ShaHash([]byte(pass+pass), buf[:]) type2_secret = new(big.Int).SetBytes(buf[:]) } lab = "TypB" } else { lab = "TypA" } if pass != "" { if *verbose { fmt.Println("Generating", *keycnt, "keys, version", verbyte, "...") } for i := uint(0); i < *keycnt; { prv_key := make([]byte, 32) if *waltype == 3 { btc.ShaHash(seed_key, prv_key) seed_key = append(seed_key, byte(i)) } else if *waltype == 2 { seed_key = btc.DeriveNextPrivate(new(big.Int).SetBytes(seed_key), type2_secret).Bytes() copy(prv_key, seed_key) } else { btc.ShaHash(seed_key, prv_key) copy(seed_key, prv_key) } priv_keys = append(priv_keys, prv_key) pub, er := btc.PublicFromPrivate(prv_key, !*uncompressed) if er == nil { publ_addrs = append(publ_addrs, btc.NewAddrFromPubkey(pub, verbyte)) labels = append(labels, fmt.Sprint(lab, " ", i+1)) i++ } else { println("PublicFromPrivate:", er.Error()) } } if *verbose { fmt.Println("Private keys re-generated") } } }
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 []byte var compr bool for i := range publ_addrs { if publ_addrs[i].Hash160 == ad2s.Hash160 { privkey = priv_keys[i][:] compr = compressed_key[i] // Sign raw hash? if hash != nil { txsig := new(btc.Signature) txsig.HashType = 0x01 r, s, e := btc.EcdsaSign(privkey, hash) if e != nil { println(e.Error()) return } txsig.R.Set(r) txsig.S.Set(s) 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 } r, s, e := btc.EcdsaSign(privkey, hash) if e != nil { println(e.Error()) return } btcsig.R.Set(r) btcsig.S.Set(s) 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.") }
// load the content of the "balance/" folder func load_balance(showbalance bool) { var unknownInputs, multisigInputs int f, e := os.Open("balance/unspent.txt") if e != nil { println(e.Error()) return } rd := bufio.NewReader(f) for { l, _, e := rd.ReadLine() if len(l) == 0 && e != nil { break } if l[64] == '-' { txid := btc.NewUint256FromString(string(l[:64])) rst := strings.SplitN(string(l[65:]), " ", 2) vout, _ := strconv.ParseUint(rst[0], 10, 32) uns := new(btc.TxPrevOut) copy(uns.Hash[:], txid.Hash[:]) uns.Vout = uint32(vout) lab := "" if len(rst) > 1 { lab = rst[1] } str := string(l) if sti := strings.Index(str, "_StealthC:"); sti != -1 { c, e := hex.DecodeString(str[sti+10 : sti+10+64]) if e != nil { fmt.Println("ERROR at stealth", txid.String(), vout, e.Error()) } else { // add a new key to the wallet sec := btc.DeriveNextPrivate(first_seed[:], c) is_stealth[len(priv_keys)] = true priv_keys = append(priv_keys, sec) labels = append(labels, lab) pub_key := btc.PublicFromPrivate(sec, true) publ_addrs = append(publ_addrs, btc.NewAddrFromPubkey(pub_key, btc.AddrVerPubkey(*testnet))) compressed_key = append(compressed_key, true) // stealth keys are always compressed } } if _, ok := loadedTxs[txid.Hash]; !ok { tf, _ := os.Open("balance/" + txid.String() + ".tx") if tf != nil { siz, _ := tf.Seek(0, os.SEEK_END) tf.Seek(0, os.SEEK_SET) buf := make([]byte, siz) tf.Read(buf) tf.Close() th := btc.Sha2Sum(buf) if bytes.Equal(th[:], txid.Hash[:]) { tx, _ := btc.NewTx(buf) if tx != nil { loadedTxs[txid.Hash] = tx } else { println("transaction is corrupt:", txid.String()) } } else { println("transaction file is corrupt:", txid.String()) os.Exit(1) } } else { println("transaction file not found:", txid.String()) os.Exit(1) } } // Sum up all the balance and check if we have private key for this input uo := UO(uns) add_it := true if !btc.IsP2SH(uo.Pk_script) { fnd := false for j := range publ_addrs { if publ_addrs[j].Owns(uo.Pk_script) { fnd = true break } } if !fnd { if *onlvalid { add_it = false } if showbalance { unknownInputs++ if *verbose { ss := uns.String() ss = ss[:8] + "..." + ss[len(ss)-12:] fmt.Println(ss, "does not belong to your wallet (cannot sign it)") } } } } else { if *onlvalid { add_it = false } if *verbose { ss := uns.String() ss = ss[:8] + "..." + ss[len(ss)-12:] fmt.Println(ss, "belongs to a multisig address") } multisigInputs++ } if add_it { unspentOuts = append(unspentOuts, uns) unspentOutsLabel = append(unspentOutsLabel, lab) totBtc += UO(uns).Value } } } f.Close() fmt.Printf("You have %.8f BTC in %d unspent outputs. %d inputs are multisig type\n", float64(totBtc)/1e8, len(unspentOuts), multisigInputs) if showbalance { if unknownInputs > 0 { fmt.Printf("WARNING: Some inputs (%d) cannot be spent with this password (-v to print them)\n", unknownInputs) } } }
func main() { var msg []byte flag.Parse() if *help || *addr == "" || *sign == "" { flag.PrintDefaults() return } ad, er := btc.NewAddrFromString(*addr) if er != nil { println("Address:", er.Error()) flag.PrintDefaults() return } nv, btcsig, er := btc.ParseMessageSignature(*sign) if er != nil { println("ParseMessageSignature:", er.Error()) return } if *mess != "" { msg = []byte(*mess) } else if *mfil != "" { msg, er = ioutil.ReadFile(*mfil) if er != nil { println(er.Error()) return } } else { fmt.Println("Enter the message:") msg, _ = ioutil.ReadAll(os.Stdin) } if *unix { fmt.Println("Enforcing Unix text format") msg = []byte(strings.Replace(string(msg), "\r", "", -1)) } hash := make([]byte, 32) btc.HashFromMessage(msg, hash) compressed := false if nv >= 31 { //println("compressed key") nv -= 4 compressed = true } pub := btcsig.RecoverPublicKey(hash[:], int(nv-27)) if pub != nil { pk := pub.Bytes(compressed) ok := btc.EcdsaVerify(pk, btcsig.Bytes(), hash) if ok { sa := btc.NewAddrFromPubkey(pk, ad.Version) if ad.Hash160 != sa.Hash160 { fmt.Println("BAD signature for", ad.String()) os.Exit(1) } else { fmt.Println("Good signature for", sa.String()) } } else { println("BAD signature") os.Exit(1) } } else { println("BAD, BAD, BAD signature") os.Exit(1) } }
/* { "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) }
// Get the secret seed and generate "*keycnt" key pairs (both private and public) func make_wallet() { var lab string if *testnet { verbyte = 0x6f privver = 0xef } else { // verbyte is be zero by definition privver = 0x80 } load_others() seed_key := make([]byte, 32) if !getseed(seed_key) { os.Exit(0) } defer func() { utils.ClearBuffer(seed_key) }() if *waltype == 3 { lab = "TypC" } else if *waltype == 2 { if *type2sec != "" { d, e := hex.DecodeString(*type2sec) if e != nil { println("t2sec error:", e.Error()) os.Exit(1) } type2_secret = d } else { type2_secret = make([]byte, 20) btc.RimpHash(seed_key, type2_secret) } lab = "TypB" } else { lab = "TypA" } if *verbose { fmt.Println("Generating", *keycnt, "keys, version", verbyte, "...") } for i := uint(0); i < *keycnt; { prv_key := make([]byte, 32) if *waltype == 3 { btc.ShaHash(seed_key, prv_key) seed_key = append(seed_key, byte(i)) } else if *waltype == 2 { seed_key = btc.DeriveNextPrivate(seed_key, type2_secret) copy(prv_key, seed_key) } else { btc.ShaHash(seed_key, prv_key) copy(seed_key, prv_key) } priv_keys = append(priv_keys, prv_key) if *scankey != "" { new_stealth_address(prv_key) return } // for stealth keys if i == 0 { copy(first_seed[:], prv_key) } compressed_key = append(compressed_key, !*uncompressed) pub := btc.PublicFromPrivate(prv_key, !*uncompressed) if pub != nil { adr := btc.NewAddrFromPubkey(pub, verbyte) if *pubkey != "" && *pubkey == adr.String() { fmt.Println(adr.String(), "=>", hex.EncodeToString(pub)) return } publ_addrs = append(publ_addrs, adr) labels = append(labels, fmt.Sprint(lab, " ", i+1)) i++ } else { println("PublicFromPrivate error 3") } } if *verbose { fmt.Println("Private keys re-generated") } }
// Thanks @dabura667 - https://bitcointalk.org/index.php?topic=590349.msg6560332#msg6560332 func stealth_txout(sa *btc.StealthAddr, value uint64) (res []*btc.TxOut) { if sa.Version != btc.StealthAddressVersion(*testnet) { fmt.Println("ERROR: Unsupported version of a stealth address", sa.Version) os.Exit(1) } if len(sa.SpendKeys) != 1 { fmt.Println("ERROR: Currently only non-multisig stealth addresses are supported", len(sa.SpendKeys)) os.Exit(1) } // Make two outpus res = make([]*btc.TxOut, 2) var e, ephemkey, pkscr []byte var nonce, nonce_from uint32 var look4pref bool sha := sha256.New() // 6. create a new pub/priv keypair (lets call its pubkey "ephemkey" and privkey "e") pick_different_e: e = make([]byte, 32) rand.Read(e) defer utils.ClearBuffer(e) ephemkey = btc.PublicFromPrivate(e, true) if *verbose { fmt.Println("e", hex.EncodeToString(e)) fmt.Println("ephemkey", hex.EncodeToString(ephemkey)) } // 7. IF there is a prefix in the stealth address, brute force a nonce such // that SHA256(nonce.concate(ephemkey)) first 4 bytes are equal to the prefix. // IF NOT, then just run through the loop once and pickup a random nonce. // (probably make the while condition include "or prefix = null" or something to that nature. look4pref = len(sa.Prefix) > 0 && sa.Prefix[0] > 0 if look4pref { fmt.Print("Prefix is ", sa.Prefix[0], ":", hex.EncodeToString(sa.Prefix[1:]), " - looking for nonce...") } binary.Read(rand.Reader, binary.LittleEndian, &nonce_from) nonce = nonce_from for { binary.Write(sha, binary.LittleEndian, nonce) sha.Write(ephemkey) if sa.CheckPrefix(sha.Sum(nil)[:4]) { break } sha.Reset() nonce++ if nonce == nonce_from { fmt.Println("EOF") goto pick_different_e } if (nonce & 0xfffff) == 0 { fmt.Print(".") } } if look4pref { fmt.Println(uint32(nonce - nonce_from)) } // 8. Once you have the nonce and the ephemkey, you can create the first output, which is pkscr = make([]byte, 40) pkscr[0] = 0x6a // OP_RETURN pkscr[1] = 38 // length pkscr[2] = 0x06 // always 6 binary.LittleEndian.PutUint32(pkscr[3:7], nonce) copy(pkscr[7:40], ephemkey) res[0] = &btc.TxOut{Pk_script: pkscr} // 9. Now use ECC multiplication to calculate e*Q where Q = scan_pubkey // an e = privkey to ephemkey and then hash it. c := btc.StealthDH(sa.ScanKey[:], e) if *verbose { fmt.Println("c", hex.EncodeToString(c)) } // 10. That hash is now "c". use ECC multiplication and addition to // calculate D + (c*G) where D = spend_pubkey, and G is the reference // point for secp256k1. This will give you a new pubkey. (we'll call it D') Dpr := btc.DeriveNextPublic(sa.SpendKeys[0][:], c) if *verbose { fmt.Println("Dpr", hex.EncodeToString(Dpr)) } // 11. Create a normal P2KH output spending to D' as public key. adr := btc.NewAddrFromPubkey(Dpr, btc.AddrVerPubkey(*testnet)) res[1] = &btc.TxOut{Value: value, Pk_script: adr.OutScript()} fmt.Println("Sending to stealth", adr.String()) return }