// New methods using proper ecdsa keys from the stdlib func ToECDSA(prv []byte) *ecdsa.PrivateKey { if len(prv) == 0 { return nil } priv := new(ecdsa.PrivateKey) priv.PublicKey.Curve = secp256k1.S256() priv.D = common.BigD(prv) priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(prv) return priv }
// parseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure. // The OID for the named curve may be provided from another source (such as // the PKCS8 container) - if it is provided then use this instead of the OID // that may exist in the EC private key structure. func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *ecdsa.PrivateKey, err error) { var privKey ecPrivateKey if _, err := asn1.Unmarshal(der, &privKey); err != nil { return nil, errors.New("x509: failed to parse EC private key: " + err.Error()) } if privKey.Version != ecPrivKeyVersion { return nil, fmt.Errorf("x509: unknown EC private key version %d", privKey.Version) } var curve elliptic.Curve if namedCurveOID != nil { curve = namedCurveFromOID(*namedCurveOID) } else { curve = namedCurveFromOID(privKey.NamedCurveOID) } if curve == nil { return nil, errors.New("x509: unknown elliptic curve") } k := new(big.Int).SetBytes(privKey.PrivateKey) if k.Cmp(curve.Params().N) >= 0 { return nil, errors.New("x509: invalid elliptic curve private key value") } priv := new(ecdsa.PrivateKey) priv.Curve = curve priv.D = k priv.X, priv.Y = curve.ScalarBaseMult(privKey.PrivateKey) return priv, nil }
// Verify the secret key's range and if a test message signed with it verifies OK // Returns nil if averything looks OK func VerifyKeyPair(priv []byte, publ []byte) error { const TestMessage = "Just some test message..." hash := Sha2Sum([]byte(TestMessage)) pub_key, e := NewPublicKey(publ) if e != nil { return e } var key ecdsa.PrivateKey key.D = new(big.Int).SetBytes(priv) key.PublicKey = pub_key.PublicKey if key.D.Cmp(big.NewInt(0)) == 0 { return errors.New("pubkey value is zero") } if key.D.Cmp(secp256k1.N) != -1 { return errors.New("pubkey value is too big") } r, s, err := ecdsa.Sign(rand.Reader, &key, hash[:]) if err != nil { return errors.New("ecdsa.Sign failed: " + err.Error()) } ok := ecdsa.Verify(&key.PublicKey, hash[:], r, s) if !ok { return errors.New("ecdsa.Sign Verify") } return nil }
// Signs a specified transaction input func (tx *Tx) Sign(in int, pk_script []byte, hash_type byte, pubkey, priv_key []byte) error { if in >= len(tx.TxIn) { return errors.New("tx.Sign() - input index overflow") } pub_key, er := NewPublicKey(pubkey) if er != nil { return er } // Load the key (private and public) var key ecdsa.PrivateKey key.D = new(big.Int).SetBytes(priv_key) key.PublicKey = pub_key.PublicKey //Calculate proper transaction hash h := tx.SignatureHash(pk_script, in, hash_type) // Sign r, s, er := EcdsaSign(&key, h) if er != nil { return er } rb := r.Bytes() sb := s.Bytes() if rb[0] >= 0x80 { rb = append([]byte{0x00}, rb...) } if sb[0] >= 0x80 { 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(pubkey))) buscr.Write(pubkey) // assign sign script ot the tx: tx.TxIn[in].ScriptSig = buscr.Bytes() return nil // no error }
func UnmarshalCertificate(data []byte) Certificate { priv := new(big.Int).SetBytes(data[:28]) pub := UnmarshalPublicCertificate(data[28:]) cert := new(ecdsa.PrivateKey) cert.D = priv cert.PublicKey = *pub return cert }
func DecodeECDSAPrivateKey(b []byte) (*ecdsa.PrivateKey, error) { var p []big.Int buf := bytes.NewBuffer(b) dec := gob.NewDecoder(buf) err := dec.Decode(&p) if err != nil { return nil, err } privateKey := new(ecdsa.PrivateKey) privateKey.PublicKey.Curve = btcec.S256() privateKey.PublicKey.X = &p[0] privateKey.PublicKey.Y = &p[1] privateKey.D = &p[2] return privateKey, nil }
// parseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure. // The OID for the named curve may be provided from another source (such as // the PKCS8 container) - if it is provided then use this instead of the OID // that may exist in the EC private key structure. func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *ecdsa.PrivateKey, err error) { var privKey ecPrivateKey if _, err := asn1.Unmarshal(der, &privKey); err != nil { return nil, errors.New("x509: failed to parse EC private key: " + err.Error()) } if privKey.Version != ecPrivKeyVersion { return nil, fmt.Errorf("x509: unknown EC private key version %d", privKey.Version) } var curve elliptic.Curve if namedCurveOID != nil { curve = namedCurveFromOID(*namedCurveOID) } else { curve = namedCurveFromOID(privKey.NamedCurveOID) } if curve == nil { return nil, errors.New("x509: unknown elliptic curve") } k := new(big.Int).SetBytes(privKey.PrivateKey) curveOrder := curve.Params().N if k.Cmp(curveOrder) >= 0 { return nil, errors.New("x509: invalid elliptic curve private key value") } priv := new(ecdsa.PrivateKey) priv.Curve = curve priv.D = k privateKey := make([]byte, (curveOrder.BitLen()+7)/8) // Some private keys have leading zero padding. This is invalid // according to [SEC1], but this code will ignore it. for len(privKey.PrivateKey) > len(privateKey) { if privKey.PrivateKey[0] != 0 { return nil, errors.New("x509: invalid private key length") } privKey.PrivateKey = privKey.PrivateKey[1:] } // Some private keys remove all leading zeros, this is also invalid // according to [SEC1] but since OpenSSL used to do this, we ignore // this too. copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey) priv.X, priv.Y = curve.ScalarBaseMult(privateKey) return priv, nil }
func readPrivateKeyECDSA(m map[string]string) (PrivateKey, error) { p := new(ecdsa.PrivateKey) p.D = big.NewInt(0) // TODO: validate that the required flags are present for k, v := range m { switch k { case "privatekey": v1, err := fromBase64([]byte(v)) if err != nil { return nil, err } p.D.SetBytes(v1) case "created", "publish", "activate": /* not used in Go (yet) */ } } return p, nil }
func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) { ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey) ecdsaPriv := new(ecdsa.PrivateKey) ecdsaPriv.PublicKey = *ecdsaPub buf := bytes.NewBuffer(data) d, _, err := readMPI(buf) if err != nil { return } ecdsaPriv.D = new(big.Int).SetBytes(d) pk.PrivateKey = ecdsaPriv pk.Encrypted = false pk.encryptedData = nil return nil }
func (k *RR_DNSKEY) readPrivateKeyECDSA(kv map[string]string) (PrivateKey, os.Error) { p := new(ecdsa.PrivateKey) p.D = big.NewInt(0) // Need to check if we have everything for k, v := range kv { switch k { case "privatekey:": v1, err := packBase64([]byte(v)) if err != nil { return nil, err } p.D.SetBytes(v1) case "created:", "publish:", "activate:": /* not used in Go (yet) */ } } return p, nil }
// 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 main() { id1 := "99375318-11c4-4a77-ba42-f7c08ca7b9d0" id2 := "ff375318-11c4-4a77-ba42-f7c08ca7b9d0" privkeyHex, err := ioutil.ReadFile(".gn_ecdsa") if err != nil { panic(err) } privkey, err := hex.DecodeString(string(privkeyHex[:len(privkeyHex)-1])) if err != nil { panic(err) } key := new(ecdsa.PrivateKey) key.D = big.NewInt(0) key.D.SetBytes(privkey) key.PublicKey.Curve = elliptic.P256() xb, _ := hex.DecodeString("212d26c6744803803e2f81fa117630a72eaf8a7c12f16e4e1b0188785a57c783256") x := big.NewInt(0) x.SetBytes(xb) key.PublicKey.X = x yb, _ := hex.DecodeString("b0802aac16e521569f549092c41c1b295e9ff627534d1b28fe050a37f5280ac9255") y := big.NewInt(0) y.SetBytes(yb) key.PublicKey.Y = y ids := map[string]*ecdsa.PublicKey{ id1: &key.PublicKey, id2: &key.PublicKey, } node1 := gophernet.NewNode(id1, key, 100, ids) node2 := gophernet.NewNode(id2, key, 100, ids) errChan := make(chan error) stopChan := make(chan struct{}) msgChan1 := make(chan *gophernet.Message, 1) msgChan2 := make(chan *gophernet.Message, 1) go gophernet.Listen(node1, ":7890", errChan, stopChan, msgChan1) go gophernet.Listen(node2, ":7891", errChan, stopChan, msgChan2) { log.Printf("MAIN: Giving listeners a couple seconds to start.") var err error select { case err = <-errChan: log.Printf("MAIN: Error: %v", err) case <-time.After(2 * time.Second): } if err != nil { log.Printf("MAIN: At least one error, stopping") close(stopChan) for err := range errChan { log.Print("MAIN: Error: %v", err) } } } c, err := net.Dial("tcp", "0.0.0.0:7891") if err != nil { panic(err) } p := node2.AddPeer(c) go gophernet.Handle(node2.ID, p, node2.DropPeer, node2.GetKey, stopChan, msgChan2) node2.Broadcast(&gophernet.Message{}) select { case err = <-errChan: log.Printf("MAIN: Error: %v", err) case msg := <-msgChan1: log.Printf("MAIN: msgChan1: %#v", msg) case msg := <-msgChan2: log.Printf("MAIN: msgChan2: %#v", msg) } }
// 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.") }
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.") }
// 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 (service *EMPService) PublishMessage(r *http.Request, args *SendMsg, reply *SendResponse) error { if !basicAuth(service.Config, r) { service.Config.Log <- fmt.Sprintf("Unauthorized RPC Request from: %s", r.RemoteAddr) return errors.New("Unauthorized") } // Nil Check if len(args.Sender) == 0 || len(args.Plaintext) == 0 { return errors.New("All fields required.") } var err error // Get Addresses sendAddr := encryption.StringToAddress(args.Sender) if len(sendAddr) == 0 { return errors.New("Invalid sender address!") } sender, err := localdb.GetAddressDetail(objects.MakeHash(sendAddr)) if err != nil { return errors.New(fmt.Sprintf("Error pulling send address from Database: %s", err)) } if sender.Privkey == nil { return errors.New("Private Key Required to Publish Message") } // Create New Message msg := new(objects.FullMessage) msg.Decrypted = new(objects.DecryptedMessage) msg.Encrypted = nil txid := make([]byte, len(msg.Decrypted.Txid), cap(msg.Decrypted.Txid)) // Fill out decrypted message n, err := rand.Read(txid) if n < len(msg.Decrypted.Txid[:]) || err != nil { return errors.New(fmt.Sprintf("Problem with random reader: %s", err)) } copy(msg.Decrypted.Pubkey[:], sender.Pubkey) msg.Decrypted.Subject = args.Subject msg.Decrypted.MimeType = "text/plain" msg.Decrypted.Content = args.Plaintext msg.Decrypted.Length = uint32(len(msg.Decrypted.Content)) // Fill Out Meta Message (save timestamp) msg.MetaMessage.Purged = false msg.MetaMessage.TxidHash = objects.MakeHash(txid) msg.MetaMessage.Sender = sender.String msg.MetaMessage.Recipient = "<Subscription Message>" // Get Signature priv := new(ecdsa.PrivateKey) priv.PublicKey.Curve = encryption.GetCurve() priv.D = new(big.Int) priv.D.SetBytes(sender.Privkey) sign := msg.Decrypted.GetBytes() sign = sign[:len(sign)-65] signHash := objects.MakeHash(sign) x, y, err := ecdsa.Sign(rand.Reader, priv, signHash.GetBytes()) if err != nil { return err } copy(msg.Decrypted.Signature[:], encryption.MarshalPubkey(x, y)) // Send message and add to sendbox... msg.Encrypted = encryption.EncryptPub(service.Config.Log, sender.Privkey, string(msg.Decrypted.GetBytes())) msg.MetaMessage.Timestamp = time.Now().Round(time.Second) // Now Add Txid copy(msg.Decrypted.Txid[:], txid) err = localdb.AddUpdateMessage(msg, localdb.SENDBOX) if err != nil { return err } sendMsg := new(objects.Message) sendMsg.TxidHash = msg.MetaMessage.TxidHash sendMsg.AddrHash = objects.MakeHash(sender.Address) sendMsg.Timestamp = msg.MetaMessage.Timestamp sendMsg.Content = *msg.Encrypted service.Config.RecvQueue <- *objects.MakeFrame(objects.PUB, objects.BROADCAST, sendMsg) reply.IsSent = true // Finish by setting msg's txid reply.TxidHash = msg.MetaMessage.TxidHash.GetBytes() return nil }
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) }