def test_multisig_one_at_a_time(self): N = 3 M = 3 keys = [Key(secret_exponent=i) for i in range(1, M + 2)] tx_in = TxIn.coinbase_tx_in(script=b'') script = ScriptMultisig(n=N, sec_keys=[key.sec() for key in keys[:M]]).script() tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()]) ids = [ "403e5bfc59e097bb197bf77a692d158dd3a4f7affb4a1fa41072dafe7bec7058", "5931d9995e83721243dca24772d7012afcd4378996a8b953c458175f15a544db", "9bb4421088190bbbb5b42a9eaa9baed7ec7574a407c25f71992ba56ca43d9c44", "03a1dc2a63f93a5cf5a7cb668658eb3fc2eda88c06dc287b85ba3e6aff751771" ] for i in range(1, M + 1): self.assertEqual(tx2.bad_signature_count(), 1) self.assertEqual(tx2.id(), ids[i - 1]) hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys[i - 1:i]) tx2.sign(hash160_lookup=hash160_lookup) self.assertEqual(tx2.id(), ids[i]) self.assertEqual(tx2.bad_signature_count(), 0)
def list_addresses(self, filterName=''): balance = {} for i in range(len(self.addresses)): person = self.addresses[i] name = person.items()[0][0] if '' != filterName and name != filterName: continue balance[name] = {} for j in range(len(person.items()[0][1])): addr = person.items()[0][1][j].items()[0][1] desc = person.items()[0][1][j].items()[0][0] if len(addr) == 3: # multisig deterministic hierarchical wallet kk0 = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr[0]) kk1 = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr[1]) kk2 = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr[2]) for k in range( 4 ): # device (0), web (1) or exchange (2) for case hardware wallet. idx (3) used for non-case for j in range( 2): # receive (0) and change (1) addresses gap = 0 found = False for i in range(99999): if k == 3: # regular keypath = "%d/%d.pub" % (j, i) else: # case keypath = "%d/%d/%d.pub" % (k, j, i) #print(keypath) sub0 = kk0.subkey_for_path(keypath).sec() sub1 = kk1.subkey_for_path(keypath).sec() sub2 = kk2.subkey_for_path(keypath).sec() if k == 3: # regular sub = sorted([sub0, sub1, sub2]) else: # case sub = [sub0, sub1, sub2] underlying_script = ScriptMultisig( n=2, sec_keys=[sub[0], sub[1], sub[2]]).script() addr = address_for_pay_to_script( underlying_script, netcode="BTC") ledger = blockchain_info.blockchain( addr, False) bal = ledger.balance() if ledger.tx_count != 0: found = True if found: print desc, i, j, k, addr, bal if bal == 0: if 0 == ledger.tx_count(): gap += 1 if gap > 20: break
def multisig_M_of_N(self, M, N, unsigned_id, signed_id): keys = [Key(secret_exponent=i) for i in range(1, N+2)] tx_in = TxIn.coinbase_tx_in(script=b'') script = ScriptMultisig(m=M, sec_keys=[key.sec() for key in keys[:N]]).script() tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()]) self.assertEqual(tx2.id(), unsigned_id) self.assertEqual(tx2.bad_signature_count(), 1) hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys) tx2.sign(hash160_lookup=hash160_lookup) self.assertEqual(tx2.id(), signed_id) self.assertEqual(tx2.bad_signature_count(), 0)
def multisig_M_of_N_individually(self, M, N): keys = [Key(secret_exponent=i) for i in range(1, N + 2)] tx_in = TxIn.coinbase_tx_in(script=b'') script = ScriptMultisig(m=M, sec_keys=[key.sec() for key in keys[:N]]).script() tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) for partial_key_list in itertools.permutations(keys[:N], M): tx2 = create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()]) for key in partial_key_list: self.assertEqual(tx2.bad_signature_count(), 1) hash160_lookup = build_hash160_lookup([key.secret_exponent()]) tx2.sign(hash160_lookup=hash160_lookup) self.assertEqual(tx2.bad_signature_count(), 0)
def test_sign_pay_to_script_multisig(self): M, N = 3, 3 keys = [Key(secret_exponent=i) for i in range(1, N+2)] tx_in = TxIn.coinbase_tx_in(script=b'') underlying_script = ScriptMultisig(m=M, sec_keys=[key.sec() for key in keys[:N]]).script() address = address_for_pay_to_script(underlying_script) self.assertEqual(address, "39qEwuwyb2cAX38MFtrNzvq3KV9hSNov3q") script = standard_tx_out_script(address) tx_out = TxOut(1000000, script) tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out]) tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [address]) hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys[:N]) p2sh_lookup = build_p2sh_lookup([underlying_script]) tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) self.assertEqual(tx2.bad_signature_count(), 0)
def post(self): logging.info("transaction coming in") hextx = self.get_argument('hextx', None) subkeys = self.get_argument('subkeys', None) payoutaddress = self.get_argument('payoutaddress', None) fees = self.get_argument('fees', None) print subkeys if not hextx or not subkeys or not payoutaddress or not fees: logging.error("Did not receive trans or tree argument") return fees = tornado.escape.json_decode(fees) subkeys = tornado.escape.json_decode(subkeys) seed = mnemonic.Mnemonic.to_seed(PHRASE) wallet = BIP32Node.from_master_secret(seed) wifs = [] keys = [] for subkey in subkeys: key = wallet.subkey_for_path(subkey) keys.append(key) wifs.append(key.wif()) underlying_script = ScriptMultisig( n=N, sec_keys=[key.sec() for key in keys[:M]]).script() address = address_for_pay_to_script(underlying_script) tx2 = Tx.tx_from_hex(hextx) # first tx out, need another for the 1% to our wallet script = standard_tx_out_script(payoutaddress) tx_out = TxOut(fees['seller'], script) # TODO: figure out final wallet. This is sending to my phone script = standard_tx_out_script("1LhkvTTxFXam672vjwbABtkp9td7dxCwyB") tx2_out = TxOut(fees['bestcrow'], script) txs_out = [tx_out, tx2_out] tx2.txs_out = txs_out hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys) p2sh_lookup = build_p2sh_lookup([underlying_script]) tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup) print tx2.as_hex() self.write(tx2.as_hex())
def script_for_path(self, path): """Get the redeem script for the path. The multisig format is (n-1) of n, but can be overridden. :param: path: the derivation path :type: path: str :return: the script :rtype: ScriptMultisig """ if not self._complete: raise Exception("account not complete") if path not in self._cache['keys']: self._cache['keys'][path] =\ [key.subkey_for_path(path + ".pub") for key in self.keys] subkeys = self._cache['keys'][path] secs = [key.sec() for key in subkeys] if self._sort: secs.sort() script = ScriptMultisig(self._num_sigs, secs) return script
def balances(self, filterName=''): balance = {} for i in range(len(self.addresses)): person = self.addresses[i] name = person.items()[0][0] if '' != filterName and name != filterName: continue balance[name] = {} for j in range(len(person.items()[0][1])): addr = person.items()[0][1][j].items()[0][1] desc = person.items()[0][1][j].items()[0][0] if len(addr) == 3: # multisig deterministic hierarchical wallet kk0 = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr[0]) kk1 = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr[1]) kk2 = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr[2]) for k in range( 5 ): # device (0), web (1) or exchange (2) for case hardware wallet. Regular non case: 2of3 (3), 3of3 (4) for j in range( 2): # receive (0) and change (1) addresses gap = 0 for i in range(99999): if k == 3 or k == 4: # regular keypath = "%d/%d.pub" % (j, i) else: # case keypath = "%d/%d/%d.pub" % (k, j, i) #print(keypath) sub0 = kk0.subkey_for_path(keypath).sec() sub1 = kk1.subkey_for_path(keypath).sec() sub2 = kk2.subkey_for_path(keypath).sec() if k == 3 or k == 4: # regular sub = sorted([sub0, sub1, sub2]) else: # case sub = [sub0, sub1, sub2] required_signatures = 3 if k == 4 else 2 underlying_script = ScriptMultisig( n=required_signatures, sec_keys=[sub[0], sub[1], sub[2]]).script() addr = address_for_pay_to_script( underlying_script, netcode="BTC") bal = self.get_balance(addr) #print desc, i, j, addr, bal balance[name][addr] = [ bal, '%s_%s_%d' % (desc, 'P' if 0 == j else 'Chg', i) ] if bal == 0: if 0 == ledger.tx_count(): gap += 1 if gap > 10: break elif len(addr) < 40: # regular address bal = self.get_balance(addr) balance[name][addr] = [bal, desc] elif 'xpub' == addr[0:4]: # deterministic hierarchical public key kk = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr) for j in range(2): # receive and change addresses gap = 0 for i in range(99999): keypath = "%d/%d.pub" % (j, i) #print(keypath) addr = kk.subkey_for_path(keypath).address() #print i, j, addr bal = self.get_balance(addr) balance[name][addr] = [ bal, '%s_%s_%d' % (desc, 'P' if 0 == j else 'Chg', i) ] if bal == 0: if 0 == ledger.tx_count(): gap += 1 if gap > 10: break else: kk = pycoin.key.electrum.ElectrumWallet(addr) for i in range(20): for j in range(2): keypath = "%d/%d" % (j, i) addr = kk.subkey(keypath).address() #print i, j, addr bal = self.get_balance(addr) balance[name][addr] = [ bal, '%s_%s_%d' % (desc, 'P' if 0 == j else 'Chg', i) ] return balance
def get_multisig_address(m, pub_keys): pay_to_multisig_script = ScriptMultisig(m, pub_keys).script() return address_for_pay_to_script( pay_to_multisig_script, netcode=NET_CODE), pay_to_multisig_script.hex()
def balances(self, filterName = ''): balance = {} for i in range(len(self.addresses)): person = self.addresses[i] name = person.items()[0][0] if '' != filterName and name != filterName: continue balance[name] = {} for j in range(len(person.items()[0][1])): addr = person.items()[0][1][j].items()[0][1] desc = person.items()[0][1][j].items()[0][0] if len(addr) == 3: # multisig deterministic hierarchical wallet kk0 = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr[0]) kk1 = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr[1]) kk2 = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr[2]) for j in range(2): # receive and change addresses gap = 0 for i in range(99999): keypath = "%d/%d.pub" % (j, i) #print(keypath) sub0 = kk0.subkey_for_path(keypath).sec() sub1 = kk1.subkey_for_path(keypath).sec() sub2 = kk2.subkey_for_path(keypath).sec() #print i, j, addr underlying_script = ScriptMultisig(n=2, sec_keys=[sub0, sub1, sub2]).script() addr = address_for_pay_to_script(underlying_script, netcode="BTC") ledger = blockchain_info.blockchain(addr, False) bal = ledger.balance() balance[name][addr] = [bal, '%s_%s_%d' % (desc, 'P' if 0 == j else 'Chg', i)] if bal == 0: if 0 == ledger.tx_count(): gap += 1 if gap > 10: break elif len(addr) < 40: # regular address ledger = blockchain_info.blockchain(addr, False) bal = ledger.balance() balance[name][addr] = [bal, desc] elif 'xpub' == addr[0:4]: # deterministic hierarchical public key kk = pycoin.key.BIP32Node.BIP32Node.from_hwif(addr) for j in range(2): # receive and change addresses gap = 0 for i in range(99999): keypath = "%d/%d.pub" % (j, i) #print(keypath) addr = kk.subkey_for_path(keypath).address() #print i, j, addr ledger = blockchain_info.blockchain(addr, False) bal = ledger.balance() balance[name][addr] = [bal, '%s_%s_%d' % (desc, 'P' if 0 == j else 'Chg', i)] if bal == 0: if 0 == ledger.tx_count(): gap += 1 if gap > 10: break else: kk = pycoin.key.electrum.ElectrumWallet(addr) for i in range(20): for j in range(2): keypath = "%d/%d" % (j, i) addr = kk.subkey(keypath).address() #print i, j, addr ledger = blockchain_info.blockchain(addr, False) bal = ledger.balance() balance[name][addr] = [bal, '%s_%s_%d' % (desc, 'P' if 0 == j else 'Chg', i)] return balance
subkeys = ["0/0/138", "0/0/139", "0/0/140"] wifs = [] seed = mnemonic.Mnemonic.to_seed(phrase) wallet = BIP32Node.from_master_secret(seed) for subkey in subkeys: key = wallet.subkey_for_path(subkey) wifs.append(key.wif()) N, M = 2, 3 ## TODO: create private keys. This is using wifs. Need to use only pub keys keys = [Key.from_text(wifs[i]) for i in range(0, M)] # redeem script. Sets it as 2-of-3. The hash of this is the bitcoin address underlying_script = ScriptMultisig(n=N, sec_keys=[key.sec() for key in keys[:M]]).script() # multisig address. Just hash the redeem script address = address_for_pay_to_script(underlying_script) ## going to create a spend from this address. This should be the code on the web server spendables = insight.spendables_for_address(address) txs_in = [] for s in spendables: print s txs_in.append(s.tx_in()) # make tx_out on web server script = standard_tx_out_script(address) tx_out = TxOut(100000, script)
from pycoin.key import Key from pycoin.serialize import h2b from pycoin.tx import Tx, TxIn, TxOut, SIGHASH_ALL, tx_utils from pycoin.tx.TxOut import standard_tx_out_script from pycoin.tx.pay_to import ScriptMultisig, ScriptPayToPublicKey from pycoin.tx.pay_to import address_for_pay_to_script, build_hash160_lookup, build_p2sh_lookup from pycoin.tx.pay_to import script_obj_from_address, script_obj_from_script import pymongo MONGOCONNECTION = pymongo.Connection('127.0.0.1', 27017) keys = MONGOCONNECTION.escrow.keys.find_one({'used': False}) N = 2 M = 3 keys = [Key(secret_exponent=i) for i in range(1, M + 2)] script = ScriptMultisig(2, [Key.from_text(k).sec() for k in sigs.values()]) print script.address() #print script
# public key in binary print key.sec() keys = [] subkeys = [] count = 0 while count < 300: subkey = "0/0/%s" % count key = wallet.subkey_for_path(subkey) keys.append(key) subkeys.append(subkey) if len(keys) == 3: redeemscript = ScriptMultisig(n=N, sec_keys=[key.sec() for key in keys[:M]]).script() address = address_for_pay_to_script(redeemscript) formongo = { 'multisigaddress': address, 'used': False, 'subkeys': subkeys } MONGODB.insert(formongo) keys = [] subkeys = [] #if not is_hashed_base58_valid(key.address()): # print "Nope" # sys.exit()
def create_multisig(self, escrow): logging.info("starting creation of multisig address") N, M = 2, 3 subkeydb = MONGOSUBKEYS.find_one() # first time running and we don't have a subkey set in the database if not subkeydb: subkeydb = MONGOSUBKEYS.insert({'subkey': 1}) # TODO: this has to be moved to the private key server # create the first public key. Needed for signing up from the website or the native client. subkey = subkeydb['subkey'] phrase = "sample core fitness wrong unusual inch hurry chaos myself credit welcome margin" seed = mnemonic.Mnemonic.to_seed(phrase) wallet = BIP32Node.from_master_secret(seed) subkeys = [] keys = [] if not escrow.has_key('sellerpubky') or not escrow['sellerpubkey']: logging.info( 'seller public key was not provided. We re making and storing the key' ) subkey += 1 subkeystring = "0/0/" + str(subkey) subkeys.append(subkeystring) key1 = wallet.subkey_for_path(subkeystring) else: logging.info( 'seller public key was provided from the native client') key1 = Key.from_sec(h2b(escrow['sellerpubkey'])) keys.append(key1) if not escrow.has_key('buyerpubkey') or not escrow['buyerpubkey']: logging.info( 'buyer public key was not provided. We re making and storing the key' ) subkey += 1 subkeystring = "0/0/" + str(subkey) subkeys.append(subkeystring) key2 = wallet.subkey_for_path(subkeystring) else: logging.info( 'buyer public key was provided from the native client.') key2 = Key.from_sec(h2b(escrow['buyerpubkey'])) keys.append(key2) # this is our own, no matter what subkey += 1 subkeystring = "0/0/" + str(subkey) subkeys.append(subkeystring) key3 = wallet.subkey_for_path(subkeystring) keys.append(key3) redeemscript = ScriptMultisig(n=N, sec_keys=[key.sec() for key in keys[:M]]).script() multisigaddress = address_for_pay_to_script(redeemscript) logging.info('multi-sig address was made: %s' % multisigaddress) MONGOSUBKEYS.update({'_id': subkeydb['_id']}, {"$set": { 'subkey': subkey }}) if escrow.has_key('_id'): MONGODB.update({'_id': escrow['_id']}, { "$set": { 'multisigaddress': multisigaddress, 'subkeys': subkeys } }) return (multisigaddress, subkeys)