fix tx signing
This commit is contained in:
@@ -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]
|
||||||
|
|||||||
@@ -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 )
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
if redeemScript: txin['redeemScript'] = redeemScript
|
|
||||||
pk_addresses.append(address)
|
|
||||||
|
|
||||||
# get all private keys at once.
|
redeemScript = self.accounts[account].redeem_script(sequence)
|
||||||
if self.seed:
|
if redeemScript:
|
||||||
private_keys = self.get_private_keys(pk_addresses, password)
|
txin['redeemScript'] = redeemScript
|
||||||
print "private keys", private_keys
|
assert address == self.accounts[account].get_address(*sequence)
|
||||||
tx.sign(private_keys)
|
|
||||||
|
private_keys[address] = self.get_private_key(address, password)
|
||||||
|
|
||||||
|
print_error( "private keys", 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):
|
||||||
|
|||||||
Reference in New Issue
Block a user