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)
+
def sign(self, private_keys):
import deserialize
+ is_complete = True
for i in range(len(self.inputs)):
txin = self.inputs[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')
if redeem_script:
# 1 parse the 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
keypairs = {}
- for sec in private_keys.values():
+ for sec in txin_pk:
compressed = is_compressed(sec)
pkey = regenerate_key(sec)
pubkey = GetPubKey(pkey.pubkey, compressed)
keypairs[ pubkey.encode('hex') ] = sec
- print "keypairs", keypairs
- print redeem_script, redeem_pubkeys
-
# list of already existing signatures
signatures = txin.get("signatures",[])
print_error("signatures",signatures)
for pubkey in redeem_pubkeys:
- # here we have compressed key.. it won't work
- #public_key = ecdsa.VerifyingKey.from_string(pubkey[2:].decode('hex'), curve = SECP256k1)
- #for s in signatures:
- # try:
- # public_key.verify_digest( s.decode('hex')[:-1], Hash( tx_for_sig.decode('hex') ), sigdecode = ecdsa.util.sigdecode_der)
- # break
- # except ecdsa.keys.BadSignatureError:
- # continue
- #else:
- if 1:
- # check if we have a key corresponding to the redeem script
- if pubkey in keypairs.keys():
- # 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') )
+ # check if we have a key corresponding to the redeem script
+ if pubkey in keypairs.keys():
+ # 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)
- self.inputs[i]["signatures"] = signatures
- print_error("signatures",signatures)
- self.is_complete = len(signatures) == num
+ txin["signatures"] = signatures
+ print_error("signatures", signatures)
+ is_complete = is_complete and (len(signatures) == num)
else:
sec = private_keys[txin['address']]
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)
- self.inputs[i]["pubkeysig"] = [(pubkey, sig)]
- self.is_complete = True
+ txin["pubkeysig"] = [(pubkey, sig)]
+ is_complete = is_complete = True
+ self.is_complete = is_complete
self.raw = self.serialize( self.inputs, self.outputs )
def get_private_key(self, address, password):
+ out = []
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:
account, sequence = self.get_address_index(address)
- m = re.match("m/0'/(\d+)'", account)
- if m:
- num = int(m.group(1))
- master_k = self.get_master_private_key("m/0'/", password)
- master_c, _, _ = self.master_public_keys["m/0'/"]
- master_k, master_c = CKD(master_k, master_c, num + BIP32_PRIME)
- return self.accounts[account].get_private_key(sequence, master_k)
-
- m2 = re.match("m/1'/(\d+) & m/2'/(\d+)", account)
- if m2:
- num = int(m2.group(1))
- master_k = self.get_master_private_key("m/1'/", password)
- master_c, master_K, _ = self.master_public_keys["m/1'/"]
- 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
+ # assert address == self.accounts[account].get_address(*sequence)
+ l = account.split("&")
+ for s in l:
+ s = s.strip()
+ m = re.match("(m/\d+'/)(\d+)", s)
+ if m:
+ root = m.group(1)
+ if root not in self.master_private_keys.keys(): continue
+ num = int(m.group(2))
+ master_k = self.get_master_private_key(root, password)
+ master_c, _, _ = self.master_public_keys[root]
+ pk = bip32_private_key( (num,) + sequence, master_k.decode('hex'), master_c.decode('hex'))
+ out.append(pk)
+
+ return out
def get_private_keys(self, addresses, password):
tx = Transaction.from_io(inputs, outputs)
- pk_addresses = []
+ private_keys = {}
for i in range(len(tx.inputs)):
txin = tx.inputs[i]
address = txin['address']
continue
account, sequence = self.get_address_index(address)
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.
- if self.seed:
- private_keys = self.get_private_keys(pk_addresses, password)
- print "private keys", private_keys
- tx.sign(private_keys)
+ if redeemScript:
+ txin['redeemScript'] = redeemScript
+ assert address == self.accounts[account].get_address(*sequence)
+
+ private_keys[address] = self.get_private_key(address, password)
+
+ print_error( "private keys", private_keys )
+ tx.sign(private_keys)
for address, x in outputs:
if address not in self.addressbook and not self.is_mine(address):