enable multisig with trezor
This commit is contained in:
parent
93e8c7da6e
commit
c224a9ad9d
|
@ -487,6 +487,36 @@ class Transaction:
|
|||
self.raw = raw
|
||||
self.deserialize()
|
||||
|
||||
def update_signatures(self, raw):
|
||||
"""Add new signatures to a transaction"""
|
||||
d = deserialize(raw)
|
||||
for i, txin in enumerate(self.inputs):
|
||||
sigs1 = txin.get('signatures')
|
||||
sigs2 = d['inputs'][i].get('signatures')
|
||||
for sig in sigs2:
|
||||
if sig in sigs1:
|
||||
continue
|
||||
for_sig = Hash(self.tx_for_sig(i).decode('hex'))
|
||||
# der to string
|
||||
order = ecdsa.ecdsa.generator_secp256k1.order()
|
||||
r, s = ecdsa.util.sigdecode_der(sig.decode('hex'), order)
|
||||
sig_string = ecdsa.util.sigencode_string(r, s, order)
|
||||
pubkeys = txin.get('pubkeys')
|
||||
compressed = True
|
||||
for recid in range(4):
|
||||
public_key = MyVerifyingKey.from_signature(sig_string, recid, for_sig, curve = SECP256k1)
|
||||
pubkey = point_to_ser(public_key.pubkey.point, compressed).encode('hex')
|
||||
if pubkey in pubkeys:
|
||||
public_key.verify_digest(sig_string, for_sig, sigdecode = ecdsa.util.sigdecode_string)
|
||||
j = pubkeys.index(pubkey)
|
||||
print_error("adding sig", i, j, pubkey, sig)
|
||||
self.inputs[i]['signatures'][j] = sig
|
||||
self.inputs[i]['x_pubkeys'][j] = pubkey
|
||||
break
|
||||
# redo raw
|
||||
self.raw = self.serialize()
|
||||
|
||||
|
||||
def deserialize(self):
|
||||
d = deserialize(self.raw)
|
||||
self.inputs = d['inputs']
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from PyQt4.Qt import QMessageBox, QDialog, QVBoxLayout, QLabel, QThread, SIGNAL, QGridLayout, QInputDialog, QPushButton
|
||||
import PyQt4.QtCore as QtCore
|
||||
from binascii import unhexlify
|
||||
from struct import pack
|
||||
from sys import stderr
|
||||
|
@ -7,13 +5,17 @@ from time import sleep
|
|||
from base64 import b64encode, b64decode
|
||||
import unicodedata
|
||||
import threading
|
||||
import re
|
||||
|
||||
from PyQt4.Qt import QMessageBox, QDialog, QVBoxLayout, QLabel, QThread, SIGNAL, QGridLayout, QInputDialog, QPushButton
|
||||
import PyQt4.QtCore as QtCore
|
||||
|
||||
import electrum
|
||||
from electrum.account import BIP32_Account
|
||||
from electrum.bitcoin import EncodeBase58Check, public_key_to_bc_address, bc_address_to_hash_160
|
||||
from electrum.i18n import _
|
||||
from electrum.plugins import BasePlugin, hook, always_hook, run_hook
|
||||
from electrum.transaction import deserialize
|
||||
from electrum.transaction import Transaction, deserialize, is_extended_pubkey, x_to_xpub
|
||||
from electrum.wallet import BIP32_HD_Wallet
|
||||
from electrum.util import print_error, print_msg
|
||||
from electrum.wallet import pw_decode, bip32_private_derivation, bip32_root
|
||||
|
@ -30,6 +32,8 @@ try:
|
|||
except ImportError:
|
||||
TREZOR = False
|
||||
|
||||
import trezorlib.ckd_public as ckd_public
|
||||
|
||||
def log(msg):
|
||||
stderr.write("%s\n" % msg)
|
||||
stderr.flush()
|
||||
|
@ -234,43 +238,68 @@ class Plugin(BasePlugin):
|
|||
#finally:
|
||||
self.handler.stop()
|
||||
|
||||
#values = [i['value'] for i in tx.inputs]
|
||||
raw = signed_tx.encode('hex')
|
||||
tx.update(raw)
|
||||
#for i, txinput in enumerate(tx.inputs):
|
||||
# txinput['value'] = values[i]
|
||||
tx.update_signatures(raw)
|
||||
|
||||
|
||||
def tx_inputs(self, tx, for_sig=False):
|
||||
inputs = []
|
||||
for txinput in tx.inputs:
|
||||
for txin in tx.inputs:
|
||||
print txin
|
||||
|
||||
txinputtype = types.TxInputType()
|
||||
if ('is_coinbase' in txinput and txinput['is_coinbase']):
|
||||
if txin.get('is_coinbase'):
|
||||
prev_hash = "\0"*32
|
||||
prev_index = 0xffffffff # signed int -1
|
||||
else:
|
||||
|
||||
if for_sig:
|
||||
x_pubkey = txinput['x_pubkeys'][0]
|
||||
x_pubkeys = txin['x_pubkeys']
|
||||
if len(x_pubkeys) == 1:
|
||||
x_pubkey = x_pubkeys[0]
|
||||
xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
|
||||
xpub_n = self.get_client().expand_path(self.xpub_path[xpub])
|
||||
txinputtype.address_n.extend(xpub_n + s)
|
||||
else:
|
||||
def f(x_pubkey):
|
||||
xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
|
||||
node = ckd_public.deserialize(xpub)
|
||||
return types.HDNodePathType(node=node, address_n=s)
|
||||
pubkeys = map(f, x_pubkeys)
|
||||
multisig = types.MultisigRedeemScriptType(
|
||||
pubkeys=pubkeys,
|
||||
signatures=map(lambda x: x if x else '', txin.get('signatures')),
|
||||
m=txin.get('num_sig'),
|
||||
)
|
||||
txinputtype = types.TxInputType(
|
||||
script_type=types.SPENDMULTISIG,
|
||||
multisig= multisig
|
||||
)
|
||||
# find which key is mine
|
||||
for x_pubkey in x_pubkeys:
|
||||
xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
|
||||
if xpub in self.xpub_path:
|
||||
xpub_n = self.get_client().expand_path(self.xpub_path[xpub])
|
||||
txinputtype.address_n.extend(xpub_n + s)
|
||||
break
|
||||
else:
|
||||
raise
|
||||
|
||||
prev_hash = unhexlify(txinput['prevout_hash'])
|
||||
prev_index = txinput['prevout_n']
|
||||
prev_hash = unhexlify(txin['prevout_hash'])
|
||||
prev_index = txin['prevout_n']
|
||||
|
||||
txinputtype.prev_hash = prev_hash
|
||||
txinputtype.prev_index = prev_index
|
||||
|
||||
if 'scriptSig' in txinput:
|
||||
script_sig = txinput['scriptSig'].decode('hex')
|
||||
if 'scriptSig' in txin:
|
||||
script_sig = txin['scriptSig'].decode('hex')
|
||||
txinputtype.script_sig = script_sig
|
||||
|
||||
if 'sequence' in txinput:
|
||||
sequence = txinput['sequence']
|
||||
if 'sequence' in txin:
|
||||
sequence = txin['sequence']
|
||||
txinputtype.sequence = sequence
|
||||
|
||||
inputs.append(txinputtype)
|
||||
#TODO P2SH
|
||||
|
||||
return inputs
|
||||
|
||||
def tx_outputs(self, tx):
|
||||
|
@ -440,14 +469,22 @@ class TrezorWallet(BIP32_HD_Wallet):
|
|||
xpub_path = {}
|
||||
for txin in tx.inputs:
|
||||
tx_hash = txin['prevout_hash']
|
||||
prev_tx[tx_hash] = self.transactions[tx_hash]
|
||||
address = txin['address']
|
||||
address_path = self.address_id(address)
|
||||
account_id, (change, address_index) = self.get_address_index(address)
|
||||
|
||||
ptx = self.transactions.get(tx_hash)
|
||||
if ptx is None:
|
||||
ptx = self.network.synchronous_get([('blockchain.transaction.get', [tx_hash])])[0]
|
||||
ptx = Transaction(ptx)
|
||||
prev_tx[tx_hash] = ptx
|
||||
|
||||
for x_pubkey in txin['x_pubkeys']:
|
||||
xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
|
||||
xpub_path[xpub] = "44'/0'/%s'"%account_id
|
||||
if not is_extended_pubkey(x_pubkey):
|
||||
continue
|
||||
xpub = x_to_xpub(x_pubkey)
|
||||
for k, v in self.master_public_keys.items():
|
||||
if v == xpub:
|
||||
account_id = re.match("x/(\d+)'", k).group(1)
|
||||
account_derivation = "44'/0'/%s'"%account_id
|
||||
xpub_path[xpub] = account_derivation
|
||||
|
||||
self.plugin.sign_transaction(tx, prev_tx, xpub_path)
|
||||
|
||||
|
|
Loading…
Reference in New Issue