// Uncompressed private key func sec2b58unc(pk []byte) string { var dat [37]byte dat[0] = privver copy(dat[1:33], pk) sh := btc.Sha2Sum(dat[0:33]) copy(dat[33:37], sh[:4]) return btc.Encodeb58(dat[:]) }
// Compressed private key func sec2b58com(pk []byte) string { var dat [38]byte dat[0] = privver copy(dat[1:33], pk) dat[33] = 1 // compressed sh := btc.Sha2Sum(dat[0:34]) copy(dat[34:38], sh[:4]) return btc.Encodeb58(dat[:]) }
// 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 (c *oneConnection) FetchMessage() *BCmsg { var e error var n int // Try for 1 millisecond and timeout if full msg not received c.TCPConn.SetReadDeadline(time.Now().Add(time.Millisecond)) for c.hdr_len < 24 { n, e = SockRead(c.TCPConn, c.hdr[c.hdr_len:24]) c.hdr_len += n if e != nil { c.HandleError(e) return nil } if c.hdr_len >= 4 && !bytes.Equal(c.hdr[:4], Magic[:]) { println("FetchMessage: Proto out of sync") c.broken = true return nil } } dlen := binary.LittleEndian.Uint32(c.hdr[16:20]) if dlen > 0 { if c.dat == nil { c.dat = make([]byte, dlen) c.datlen = 0 } for c.datlen < dlen { n, e = SockRead(c.TCPConn, c.dat[c.datlen:]) c.datlen += uint32(n) if e != nil { c.HandleError(e) return nil } } } sh := btc.Sha2Sum(c.dat) if !bytes.Equal(c.hdr[20:24], sh[:4]) { println("Msg checksum error") c.hdr_len = 0 c.dat = nil c.broken = true return nil } ret := new(BCmsg) ret.cmd = strings.TrimRight(string(c.hdr[4:16]), "\000") ret.pl = c.dat c.dat = nil c.hdr_len = 0 c.BytesReceived += uint64(24 + len(ret.pl)) return ret }
func (c *one_net_conn) readmsg() *one_net_cmd { var ( hdr [24]byte hdr_len int pl_len uint32 // length taken from the message header cmd string dat []byte datlen uint32 ) for hdr_len < 24 { n, e := c.Read(hdr[hdr_len:]) if e != nil { return nil } hdr_len += n if hdr_len >= 4 && !bytes.Equal(hdr[:4], Magic[:]) { println(c.peerip, "NetBadMagic") return nil } } pl_len = binary.LittleEndian.Uint32(hdr[16:20]) cmd = strings.TrimRight(string(hdr[4:16]), "\000") if pl_len > 0 { dat = make([]byte, pl_len) for datlen < pl_len { n, e := c.Read(dat[datlen:]) if e != nil { return nil } if n > 0 { datlen += uint32(n) } } } sh := btc.Sha2Sum(dat) if !bytes.Equal(hdr[20:24], sh[:4]) { println(c.peerip, "Msg checksum error") return nil } res := new(one_net_cmd) res.cmd = cmd res.pl = dat return res }
func (c *one_net_conn) sendmsg(cmd string, pl []byte) (e error) { sbuf := make([]byte, 24+len(pl)) binary.LittleEndian.PutUint32(sbuf[0:4], Version) copy(sbuf[0:4], Magic[:]) copy(sbuf[4:16], cmd) binary.LittleEndian.PutUint32(sbuf[16:20], uint32(len(pl))) sh := btc.Sha2Sum(pl[:]) copy(sbuf[20:24], sh[:4]) copy(sbuf[24:], pl) //println("send", cmd, len(sbuf), "...") c.send.buf = append(c.send.buf, sbuf...) return }
func (c *oneConnection) SendRawMsg(cmd string, pl []byte) (e error) { var b [20]byte c.last_cmd = cmd + "*" c.writing = true binary.LittleEndian.PutUint32(b[0:4], Version) copy(b[0:4], Magic[:]) copy(b[4:16], cmd) binary.LittleEndian.PutUint32(b[16:20], uint32(len(pl))) e = SockWrite(c.TCPConn, b[:20]) if e != nil { if dbg > 0 { println("SendRawMsg 1", e.Error()) } c.broken = true c.writing = false return } sh := btc.Sha2Sum(pl[:]) e = SockWrite(c.TCPConn, sh[:4]) if e != nil { if dbg > 0 { println("SendRawMsg 2", e.Error()) } c.broken = true c.writing = false return } e = SockWrite(c.TCPConn, pl[:]) if e != nil { if dbg > 0 { println("SendRawMsg 3", e.Error()) } c.broken = true } c.BytesSent += uint64(24 + len(pl)) c.last_cmd = cmd c.writing = false return }
func (c *OneConnection) SendRawMsg(cmd string, pl []byte) (e error) { c.Mutex.Lock() if c.Send.Buf != nil { // Before adding more data to the buffer, check the limit if len(c.Send.Buf) > MaxSendBufferSize { c.Mutex.Unlock() if common.DebugLevel > 0 { println(c.PeerAddr.Ip(), "Peer Send Buffer Overflow") } c.Disconnect() common.CountSafe("PeerSendOverflow") return errors.New("Send buffer overflow") } } else { c.Send.LastSent = time.Now() } common.CountSafe("sent_" + cmd) common.CountSafeAdd("sbts_"+cmd, uint64(len(pl))) sbuf := make([]byte, 24+len(pl)) c.LastCmdSent = cmd c.LastBtsSent = uint32(len(pl)) binary.LittleEndian.PutUint32(sbuf[0:4], common.Version) copy(sbuf[0:4], common.Magic[:]) copy(sbuf[4:16], cmd) binary.LittleEndian.PutUint32(sbuf[16:20], uint32(len(pl))) sh := btc.Sha2Sum(pl[:]) copy(sbuf[20:24], sh[:4]) copy(sbuf[24:], pl) c.Send.Buf = append(c.Send.Buf, sbuf...) if common.DebugLevel < 0 { fmt.Println(cmd, len(c.Send.Buf), "->", c.PeerAddr.Ip()) } c.Mutex.Unlock() //println(len(c.Send.Buf), "queued for seding to", c.PeerAddr.Ip()) return }
// 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 }
// load the content of the "balance/" folder func load_balance() { var unknownInputs int f, e := os.Open("balance/unspent.txt") if e != nil { println(e.Error()) os.Exit(1) } 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] } 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) } } uo := UO(uns) fnd := false for j := range publ_addrs { if publ_addrs[j].Owns(uo.Pk_script) { unspentOuts = append(unspentOuts, uns) unspentOutsLabel = append(unspentOutsLabel, lab) totBtc += UO(uns).Value fnd = true break } } if !fnd { unknownInputs++ if *verbose { fmt.Println(uns.String(), "does not belogn to your wallet - ignore it") } } } } f.Close() fmt.Printf("You have %.8f BTC in %d unspent outputs\n", float64(totBtc)/1e8, len(unspentOuts)) if unknownInputs > 0 { fmt.Printf("WARNING: Some inputs (%d) cannot be spent (-v to print them)\n", unknownInputs) } }
func (c *OneConnection) FetchMessage() *BCmsg { var e error var n int for c.recv.hdr_len < 24 { n, e = common.SockRead(c.NetConn, c.recv.hdr[c.recv.hdr_len:24]) c.Mutex.Lock() c.recv.hdr_len += n if e != nil { c.Mutex.Unlock() c.HandleError(e) return nil } if c.recv.hdr_len >= 4 && !bytes.Equal(c.recv.hdr[:4], common.Magic[:]) { c.Mutex.Unlock() if common.DebugLevel > 0 { println("FetchMessage: Proto out of sync") } common.CountSafe("NetBadMagic") c.Disconnect() return nil } if c.broken { c.Mutex.Unlock() return nil } if c.recv.hdr_len >= 24 { c.recv.pl_len = binary.LittleEndian.Uint32(c.recv.hdr[16:20]) c.recv.cmd = strings.TrimRight(string(c.recv.hdr[4:16]), "\000") } c.Mutex.Unlock() } if c.recv.pl_len > 0 { if c.recv.dat == nil { msi := maxmsgsize(c.recv.cmd) if c.recv.pl_len > msi { //println(c.PeerAddr.Ip(), "Command", c.recv.cmd, "is going to be too big", c.recv.pl_len, msi) c.DoS("MsgTooBig") return nil } c.Mutex.Lock() c.recv.dat = make([]byte, c.recv.pl_len) c.recv.datlen = 0 c.Mutex.Unlock() } for c.recv.datlen < c.recv.pl_len { n, e = common.SockRead(c.NetConn, c.recv.dat[c.recv.datlen:]) if n > 0 { c.Mutex.Lock() c.recv.datlen += uint32(n) c.Mutex.Unlock() if c.recv.datlen > c.recv.pl_len { println(c.PeerAddr.Ip(), "is sending more of", c.recv.cmd, "then it should have", c.recv.datlen, c.recv.pl_len) c.DoS("MsgSizeMismatch") return nil } } if e != nil { c.HandleError(e) return nil } if c.broken { return nil } } } sh := btc.Sha2Sum(c.recv.dat) if !bytes.Equal(c.recv.hdr[20:24], sh[:4]) { //println(c.PeerAddr.Ip(), "Msg checksum error") c.DoS("MsgBadChksum") return nil } ret := new(BCmsg) ret.cmd = c.recv.cmd ret.pl = c.recv.dat c.Mutex.Lock() c.recv.dat = nil c.recv.hdr_len = 0 c.BytesReceived += uint64(24 + len(ret.pl)) c.Mutex.Unlock() return ret }
func (c *one_net_conn) readmsg() *one_net_cmd { c.SetReadDeadline(time.Now().Add(10 * time.Millisecond)) if c.recv.hdr_len < 24 { for { n, e := c.Read(c.recv.hdr[c.recv.hdr_len:]) if e != nil { if nerr, ok := e.(net.Error); ok && nerr.Timeout() { //COUNTER("HDRT") } else { c.setbroken(true) } return nil } c.Lock() c.bytes_received += uint64(n) c.Unlock() c.recv.hdr_len += n if c.recv.hdr_len >= 4 { if !bytes.Equal(c.recv.hdr[:4], Magic[:]) { fmt.Println(c.peerip, "NetBadMagic") c.setbroken(true) return nil } if c.recv.hdr_len == 24 { c.recv.cmd = strings.TrimRight(string(c.recv.hdr[4:16]), "\000") c.recv.pl_len = binary.LittleEndian.Uint32(c.recv.hdr[16:20]) c.recv.datlen = 0 if c.recv.pl_len > 0 { c.recv.dat = make([]byte, c.recv.pl_len) } break } } } } for c.recv.datlen < c.recv.pl_len { n, e := c.Read(c.recv.dat[c.recv.datlen:]) if e != nil { if nerr, ok := e.(net.Error); ok && nerr.Timeout() { //COUNTER("HDRT") } else { c.setbroken(true) } return nil } if n > 0 { c.recv.datlen += uint32(n) c.Lock() c.bytes_received += uint64(n) c.Unlock() } } sh := btc.Sha2Sum(c.recv.dat) if !bytes.Equal(c.recv.hdr[20:24], sh[:4]) { fmt.Println(c.peerip, "Msg checksum error") c.setbroken(true) return nil } res := new(one_net_cmd) res.cmd = c.recv.cmd res.pl = c.recv.dat c.recv.hdr_len = 0 c.recv.dat = nil return res }
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) } } }
// 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] } 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) } } unspentOuts = append(unspentOuts, uns) unspentOutsLabel = append(unspentOutsLabel, lab) // Sum up all the balance and check if we have private key for this input uo := UO(uns) totBtc += UO(uns).Value 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 showbalance && !fnd { 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 *verbose { ss := uns.String() ss = ss[:8] + "..." + ss[len(ss)-12:] fmt.Println(ss, "belongs to a multisig address") } multisigInputs++ } } } 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) } } }
// 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) } } }