Browse Source

fix tx signing

283
ThomasV 12 years ago
parent
commit
419c778fa3
  1. 6
      lib/account.py
  2. 62
      lib/bitcoin.py
  3. 53
      lib/wallet.py

6
lib/account.py

@ -171,12 +171,6 @@ class BIP32_Account(Account):
K, K_compressed, chain = CKD_prime(K, chain, i) K, K_compressed, chain = CKD_prime(K, chain, i)
return K_compressed.encode('hex') return K_compressed.encode('hex')
def get_private_key(self, sequence, master_k):
chain = self.c
k = master_k
for i in sequence:
k, chain = CKD(k, chain, i)
return SecretToASecret(k, True)
def get_private_keys(self, sequence_list, seed): def get_private_keys(self, sequence_list, seed):
return [ self.get_private_key( sequence, seed) for sequence in sequence_list] return [ self.get_private_key( sequence, seed) for sequence in sequence_list]

62
lib/bitcoin.py

@ -448,6 +448,11 @@ def bip32_public_derivation(c, K, branch, sequence):
return c.encode('hex'), K.encode('hex'), cK.encode('hex') return c.encode('hex'), K.encode('hex'), cK.encode('hex')
def bip32_private_key(sequence, k, chain):
for i in sequence:
k, chain = CKD(k, chain, i)
return SecretToASecret(k, True)
@ -588,61 +593,53 @@ class Transaction:
def sign(self, private_keys): def sign(self, private_keys):
import deserialize import deserialize
is_complete = True
for i in range(len(self.inputs)): for i in range(len(self.inputs)):
txin = self.inputs[i] txin = self.inputs[i]
tx_for_sig = self.serialize( self.inputs, self.outputs, for_sig = i ) tx_for_sig = self.serialize( self.inputs, self.outputs, for_sig = i )
txin_pk = private_keys.get( txin.get('address') )
if not txin_pk:
continue
redeem_script = txin.get('redeemScript') redeem_script = txin.get('redeemScript')
if redeem_script: if redeem_script:
# 1 parse the redeem script # 1 parse the redeem script
num, redeem_pubkeys = deserialize.parse_redeemScript(redeem_script) num, redeem_pubkeys = deserialize.parse_redeemScript(redeem_script)
self.inputs[i]["pubkeys"] = redeem_pubkeys txin["pubkeys"] = redeem_pubkeys
# build list of public/private keys # build list of public/private keys
keypairs = {} keypairs = {}
for sec in private_keys.values(): for sec in txin_pk:
compressed = is_compressed(sec) compressed = is_compressed(sec)
pkey = regenerate_key(sec) pkey = regenerate_key(sec)
pubkey = GetPubKey(pkey.pubkey, compressed) pubkey = GetPubKey(pkey.pubkey, compressed)
keypairs[ pubkey.encode('hex') ] = sec keypairs[ pubkey.encode('hex') ] = sec
print "keypairs", keypairs
print redeem_script, redeem_pubkeys
# list of already existing signatures # list of already existing signatures
signatures = txin.get("signatures",[]) signatures = txin.get("signatures",[])
print_error("signatures",signatures) print_error("signatures",signatures)
for pubkey in redeem_pubkeys: for pubkey in redeem_pubkeys:
# here we have compressed key.. it won't work # check if we have a key corresponding to the redeem script
#public_key = ecdsa.VerifyingKey.from_string(pubkey[2:].decode('hex'), curve = SECP256k1) if pubkey in keypairs.keys():
#for s in signatures: # add signature
# try: sec = keypairs[pubkey]
# public_key.verify_digest( s.decode('hex')[:-1], Hash( tx_for_sig.decode('hex') ), sigdecode = ecdsa.util.sigdecode_der) compressed = is_compressed(sec)
# break pkey = regenerate_key(sec)
# except ecdsa.keys.BadSignatureError: secexp = pkey.secret
# continue private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
#else: public_key = private_key.get_verifying_key()
if 1: sig = private_key.sign_digest( Hash( tx_for_sig.decode('hex') ), sigencode = ecdsa.util.sigencode_der )
# check if we have a key corresponding to the redeem script assert public_key.verify_digest( sig, Hash( tx_for_sig.decode('hex') ), sigdecode = ecdsa.util.sigdecode_der)
if pubkey in keypairs.keys(): signatures.append( sig.encode('hex') )
# add signature
sec = keypairs[pubkey]
compressed = is_compressed(sec)
pkey = regenerate_key(sec)
secexp = pkey.secret
private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
public_key = private_key.get_verifying_key()
sig = private_key.sign_digest( Hash( tx_for_sig.decode('hex') ), sigencode = ecdsa.util.sigencode_der )
assert public_key.verify_digest( sig, Hash( tx_for_sig.decode('hex') ), sigdecode = ecdsa.util.sigdecode_der)
signatures.append( sig.encode('hex') )
# for p2sh, pubkeysig is a tuple (may be incomplete) # for p2sh, pubkeysig is a tuple (may be incomplete)
self.inputs[i]["signatures"] = signatures txin["signatures"] = signatures
print_error("signatures",signatures) print_error("signatures", signatures)
self.is_complete = len(signatures) == num is_complete = is_complete and (len(signatures) == num)
else: else:
sec = private_keys[txin['address']] sec = private_keys[txin['address']]
@ -656,9 +653,10 @@ class Transaction:
sig = private_key.sign_digest( Hash( tx_for_sig.decode('hex') ), sigencode = ecdsa.util.sigencode_der ) sig = private_key.sign_digest( Hash( tx_for_sig.decode('hex') ), sigencode = ecdsa.util.sigencode_der )
assert public_key.verify_digest( sig, Hash( tx_for_sig.decode('hex') ), sigdecode = ecdsa.util.sigdecode_der) assert public_key.verify_digest( sig, Hash( tx_for_sig.decode('hex') ), sigdecode = ecdsa.util.sigdecode_der)
self.inputs[i]["pubkeysig"] = [(pubkey, sig)] txin["pubkeysig"] = [(pubkey, sig)]
self.is_complete = True is_complete = is_complete = True
self.is_complete = is_complete
self.raw = self.serialize( self.inputs, self.outputs ) self.raw = self.serialize( self.inputs, self.outputs )

53
lib/wallet.py

@ -325,26 +325,26 @@ class Wallet:
def get_private_key(self, address, password): def get_private_key(self, address, password):
out = []
if address in self.imported_keys.keys(): if address in self.imported_keys.keys():
return pw_decode( self.imported_keys[address], password ) out.append( pw_decode( self.imported_keys[address], password ) )
else: else:
account, sequence = self.get_address_index(address) account, sequence = self.get_address_index(address)
m = re.match("m/0'/(\d+)'", account) # assert address == self.accounts[account].get_address(*sequence)
if m: l = account.split("&")
num = int(m.group(1)) for s in l:
master_k = self.get_master_private_key("m/0'/", password) s = s.strip()
master_c, _, _ = self.master_public_keys["m/0'/"] m = re.match("(m/\d+'/)(\d+)", s)
master_k, master_c = CKD(master_k, master_c, num + BIP32_PRIME) if m:
return self.accounts[account].get_private_key(sequence, master_k) root = m.group(1)
if root not in self.master_private_keys.keys(): continue
m2 = re.match("m/1'/(\d+) & m/2'/(\d+)", account) num = int(m.group(2))
if m2: master_k = self.get_master_private_key(root, password)
num = int(m2.group(1)) master_c, _, _ = self.master_public_keys[root]
master_k = self.get_master_private_key("m/1'/", password) pk = bip32_private_key( (num,) + sequence, master_k.decode('hex'), master_c.decode('hex'))
master_c, master_K, _ = self.master_public_keys["m/1'/"] out.append(pk)
master_k, master_c = CKD(master_k.decode('hex'), master_c.decode('hex'), num)
return self.accounts[account].get_private_key(sequence, master_k) return out
return
def get_private_keys(self, addresses, password): def get_private_keys(self, addresses, password):
@ -915,7 +915,7 @@ class Wallet:
tx = Transaction.from_io(inputs, outputs) tx = Transaction.from_io(inputs, outputs)
pk_addresses = [] private_keys = {}
for i in range(len(tx.inputs)): for i in range(len(tx.inputs)):
txin = tx.inputs[i] txin = tx.inputs[i]
address = txin['address'] address = txin['address']
@ -924,15 +924,16 @@ class Wallet:
continue continue
account, sequence = self.get_address_index(address) account, sequence = self.get_address_index(address)
txin['KeyID'] = (account, 'BIP32', sequence) # used by the server to find the key txin['KeyID'] = (account, 'BIP32', sequence) # used by the server to find the key
redeemScript = self.accounts[account].redeem_script(sequence) redeemScript = self.accounts[account].redeem_script(sequence)
if redeemScript: txin['redeemScript'] = redeemScript if redeemScript:
pk_addresses.append(address) txin['redeemScript'] = redeemScript
assert address == self.accounts[account].get_address(*sequence)
# get all private keys at once.
if self.seed: private_keys[address] = self.get_private_key(address, password)
private_keys = self.get_private_keys(pk_addresses, password)
print "private keys", private_keys print_error( "private keys", private_keys )
tx.sign(private_keys) tx.sign(private_keys)
for address, x in outputs: for address, x in outputs:
if address not in self.addressbook and not self.is_mine(address): if address not in self.addressbook and not self.is_mine(address):

Loading…
Cancel
Save