def get_private_key_secret(self, public_key): if public_key in self.wallet_database.keys: # private key is not crypted k = KEY() k.set_privkey(self.wallet_database.keys[public_key].private_key) return k.get_secret() crypted_secret = self.wallet_database.get_crypted_keys()[public_key] for key in self.plain_masterkeys: self.crypter.set_key(key, doublesha256(public_key)) secret = self.crypter.decrypt(crypted_secret) k = KEY() is_compressed = len(public_key) == 33 k.set_secret(secret, is_compressed) if k.get_pubkey() == public_key: return secret raise KeyDecryptException( "Can't decrypt private key, wallet not unlocked or incorrect masterkey" )
def create(self, passphrase): self.wallet_database.begin_updates() crypter = Crypter() #first create masterkey master_key = new_masterkey(passphrase) plain_masterkey = decrypt_masterkey(master_key, passphrase) self.wallet_database.add_master_key(master_key) #create transaction pool for i in range(100): k = KEY() k.generate(True) public_key = k.get_pubkey() crypter.set_key(plain_masterkey, doublesha256(public_key)) crypted_secret = crypter.encrypt(k.get_secret()) self.wallet_database.add_crypted_key(public_key, crypted_secret) pool_key = WalletPoolKey(i, 60000, time.time(), public_key) self.wallet_database.add_poolkey(pool_key) self.wallet_database.commit_updates() self.load()
def sign_transaction_input(tx, input_index, txout_script, intput_script_type, secret, compressed_pubkey=True): # Set all txin to empty txin_scripts_save = [txin.script for txin in tx.in_list] for txin in tx.in_list: txin.script = Script([]) # Set the current input script to the outpoint's script value tx.in_list[input_index].script = txout_script # Serialize and append hash type enctx = TxSerializer().serialize(tx) + b"\x01\x00\x00\x00" # Get hash and Sign txhash = doublesha256(enctx) key = KEY() key.set_secret(secret, compressed_pubkey) signature = key.sign(txhash) + "\x01" # append hash_type SIGHASH_ALL # Restore Txin scripts for txin, script_save in zip(tx.in_list, txin_scripts_save): txin.script = script_save # Set the signed script if intput_script_type == TX_PUBKEYHASH: tx.in_list[input_index].script = make_script_pubkeyhash_sig( key.get_pubkey(), signature) if intput_script_type == TX_PUBKEY: tx.in_list[input_index].script = make_script_pubkey_sig(signature)
def sign_transaction_input(tx, input_index, txout_script, intput_script_type, secret, compressed_pubkey=True): # Set all txin to empty txin_scripts_save = [txin.script for txin in tx.in_list] for txin in tx.in_list: txin.script = Script([]) # Set the current input script to the outpoint's script value tx.in_list[input_index].script = txout_script # Serialize and append hash type enctx = TxSerializer().serialize(tx) + b"\x01\x00\x00\x00" # Get hash and Sign txhash = doublesha256(enctx) key = KEY() key.set_secret(secret, compressed_pubkey) signature = key.sign(txhash) + "\x01" # append hash_type SIGHASH_ALL # Restore Txin scripts for txin, script_save in zip(tx.in_list, txin_scripts_save): txin.script = script_save # Set the signed script if intput_script_type == TX_PUBKEYHASH: tx.in_list[input_index].script = make_script_pubkeyhash_sig(key.get_pubkey(), signature) if intput_script_type == TX_PUBKEY: tx.in_list[input_index].script = make_script_pubkey_sig(signature)
def test_shamir_share_private_key(self): ssl_add_system_seeds() k = KEY() k.generate() pkey_bignum = k.get_privkey_bignum() pubkey = k.get_pubkey() numshares = 600 threshold = 100 sharenum_bytes = 2 print "private_key_bignum:", pkey_bignum print "public_key:", hexstr(pubkey) print "address:", BitcoinAddress.from_publickey(pubkey, MAIN) field = ZpField() V = field.value_type ZpPkey = V(pkey_bignum) sharer = SecretSharer(field, ZpRandom(field)) shares = sharer.share(ZpPkey, threshold, [V(i+1) for i in range(numshares)]) # print shares print "Shamir Shares: (%d/%d):" % (threshold, numshares) shares_hex = [hexstr(base256encode(int(pt), sharenum_bytes) + base256encode(int(value), 32)) for pt, value in shares] for share in shares_hex: print share # Try to reconstruct the private key using the hex encoded shares. recombiner = SecretRecombiner(field) for i in range(10): random4_hex = random.sample(shares_hex, threshold) random4_decoded = [decodehexstr(h) for h in random4_hex] random4 = [(V(base256decode(data[:sharenum_bytes])), V(base256decode(data[sharenum_bytes:]))) for data in random4_decoded] recombined_pkey_bignum = recombiner.recombine(random4, V(0)) assert recombined_pkey_bignum == ZpPkey k2 = KEY() k2.set_privkey_bignum(int(recombined_pkey_bignum)) assert k2.get_pubkey() == pubkey print i # With threshold-1 shares this fails for i in range(10): random4_hex = random.sample(shares_hex, threshold-1) random4_decoded = [decodehexstr(h) for h in random4_hex] random4 = [(V(base256decode(data[:sharenum_bytes])), V(base256decode(data[sharenum_bytes:]))) for data in random4_decoded] recombined_pkey_bignum = recombiner.recombine(random4, V(0)) assert recombined_pkey_bignum != ZpPkey
def get_private_key_secret(self, public_key): if public_key in self.wallet_database.keys: # private key is not crypted k = KEY() k.set_privkey(self.wallet_database.keys[public_key].private_key) return k.get_secret() crypted_secret = self.wallet_database.get_crypted_keys()[public_key] for key in self.plain_masterkeys: self.crypter.set_key(key, doublesha256(public_key)) secret = self.crypter.decrypt(crypted_secret) k = KEY() is_compressed = len(public_key) == 33 k.set_secret(secret, is_compressed) if k.get_pubkey() == public_key: return secret raise KeyDecryptException("Can't decrypt private key, wallet not unlocked or incorrect masterkey")
def checksig(vm, sig_param, pubkey_param): transaction, inputindex, unspent_script = vm.checksig_data #Hash type is the last byte of the signature hash_type, sig = ord(sig_param[-1]), sig_param[:-1] # last 5 bits of hash_type : 1=SIGHASH_ALL,2=SIGHASH_NONE, 3=SIGHASH_SINGLE # SIGHASH_ANYONECANPAY = 0x80 # For performance reasons no full copy is made of the transaction # although it would be simpler to read. # e.g. tx_tmp = copy.deepcopy(transaction) # The input scripts are saved and then restored. tx_tmp = Tx(transaction.version, [TxIn(txin.previous_output, txin.script, txin.sequence) for txin in transaction.in_list], [TxOut(txout.value, txout.script) for txout in transaction.out_list], transaction.locktime) #Save input scripts to restore them later #inlist = transaction.in_list #outlist = transaction.out_list #inscripts = [txin.script for txin in transaction.in_list] #TODO: blank out ouputs depending of hash_type (SIGHASH_NONE, SIGHASH_SINGLE) if (hash_type & SIGHASH_MASK == SIGHASH_NONE): tx_tmp.out_list = [] if (hash_type & SIGHASH_MASK == SIGHASH_SINGLE): if (inputindex > len(tx_tmp.out_list)): raise Exception("OP_CHECKSIG: no corresponding output for input %d using SIGHASH_SINGLE " % (inputindex)) #n-1 empty TxOuts + original Txout tx_tmp.out_list = [TxOut(-1, Script([])) for _ in range(inputindex)] + \ [tx_tmp.out_list[inputindex]] if (hash_type & SIGHASH_MASK == SIGHASH_SINGLE or hash_type & SIGHASH_MASK == SIGHASH_NONE): # let others update at will for i in range(len(tx_tmp.in_list)): if i != inputindex: tx_tmp.in_list[i].sequence = 0 #blank out other inputs in case of SIGHASH_ANYONECANPAY if (hash_type & SIGHASH_ANYONECANPAY): tx_tmp.in_list = [tx_tmp.in_list[inputindex]] inputindex = 0 #blank out input scripts for txin in tx_tmp.in_list: txin.script = Script([]) #except the current one that is replaced by the signed part (e.g. from the last OP_CODESEPARATOR) # of current_script with signature push_data removed # note: only 'optimal' push_data instructions with the same signature are removed current_script = Script(filter(lambda instr: instr!=push_data_instruction(sig_param), vm.current_script.signed_part().instructions)) tx_tmp.in_list[inputindex].script = current_script #serialize and append hash type enctx = TxSerializer().serialize(tx_tmp) + chr(hash_type) + b"\x00\x00\x00" #print "enctx:", hexstr(enctx) #print "sig:", hexstr(sig) #print "pubkey:", hexstr(pubkey_param) #Get hash hash = doublesha256(enctx) #Verify key = KEY() key.set_pubkey(pubkey_param) #ECDSA_verify: 1 = OK, 0=NOK, -1=ERROR result = key.verify(hash, sig) == 1 if not result: pass #Restore transaction scripts #for txin, script in zip(inlist,inscripts): # txin.script = script #transaction.in_list = inlist return (result)
def checksig(vm, sig_param, pubkey_param): transaction, inputindex, unspent_script = vm.checksig_data #Hash type is the last byte of the signature hash_type, sig = ord(sig_param[-1]), sig_param[:-1] # last 5 bits of hash_type : 1=SIGHASH_ALL,2=SIGHASH_NONE, 3=SIGHASH_SINGLE # SIGHASH_ANYONECANPAY = 0x80 # For performance reasons no full copy is made of the transaction # although it would be simpler to read. # e.g. tx_tmp = copy.deepcopy(transaction) # The input scripts are saved and then restored. tx_tmp = Tx(transaction.version, [ TxIn(txin.previous_output, txin.script, txin.sequence) for txin in transaction.in_list ], [TxOut(txout.value, txout.script) for txout in transaction.out_list], transaction.locktime) #Save input scripts to restore them later #inlist = transaction.in_list #outlist = transaction.out_list #inscripts = [txin.script for txin in transaction.in_list] #TODO: blank out ouputs depending of hash_type (SIGHASH_NONE, SIGHASH_SINGLE) if (hash_type & SIGHASH_MASK == SIGHASH_NONE): tx_tmp.out_list = [] if (hash_type & SIGHASH_MASK == SIGHASH_SINGLE): if (inputindex > len(tx_tmp.out_list)): raise Exception( "OP_CHECKSIG: no corresponding output for input %d using SIGHASH_SINGLE " % (inputindex)) #n-1 empty TxOuts + original Txout tx_tmp.out_list = [TxOut(-1, Script([])) for _ in range(inputindex)] + \ [tx_tmp.out_list[inputindex]] if (hash_type & SIGHASH_MASK == SIGHASH_SINGLE or hash_type & SIGHASH_MASK == SIGHASH_NONE): # let others update at will for i in range(len(tx_tmp.in_list)): if i != inputindex: tx_tmp.in_list[i].sequence = 0 #blank out other inputs in case of SIGHASH_ANYONECANPAY if (hash_type & SIGHASH_ANYONECANPAY): tx_tmp.in_list = [tx_tmp.in_list[inputindex]] inputindex = 0 #blank out input scripts for txin in tx_tmp.in_list: txin.script = Script([]) #except the current one that is replaced by the signed part (e.g. from the last OP_CODESEPARATOR) # of current_script with signature push_data removed # note: only 'optimal' push_data instructions with the same signature are removed current_script = Script( filter(lambda instr: instr != push_data_instruction(sig_param), vm.current_script.signed_part().instructions)) tx_tmp.in_list[inputindex].script = current_script #serialize and append hash type enctx = TxSerializer().serialize(tx_tmp) + chr(hash_type) + b"\x00\x00\x00" #print "enctx:", hexstr(enctx) #print "sig:", hexstr(sig) #print "pubkey:", hexstr(pubkey_param) #Get hash hash = doublesha256(enctx) #Verify key = KEY() key.set_pubkey(pubkey_param) #ECDSA_verify: 1 = OK, 0=NOK, -1=ERROR result = key.verify(hash, sig) == 1 if not result: pass #Restore transaction scripts #for txin, script in zip(inlist,inscripts): # txin.script = script #transaction.in_list = inlist return (result)
def test_generate(self): key = KEY() key.generate() sig = key.sign("cool") self.assertEquals(key.verify("cool", sig), 1)
def test_ssl_sign_verify(self): key = KEY() key.set_secret(decodehexstr("30d1d8d1d243ab41a80a3cc1481a626a137f771a636b2daca06c1f86cdfecffb")) sig = key.sign("cool") # verify on another key key2 = KEY() key2.set_pubkey(decodehexstr("030a43196c8bf389c0ce5987a3f4dac57f4ca0d9733c232659717d9404074b4504")) self.assertEquals(key2.verify("cool", sig), 1) self.assertEquals(key2.verify("coolx", sig), 0) self.assertEquals(key2.verify("cool", decodehexstr("3045022100ea3cbfca49123ecdcc419cf3277597307dca70b548ca1d4312f39186b043e86802201057af5c3889b65a59333d4f23bea915e76c2c26606dd35c57e00adf416ca31600")), 0)
def test_ssl_get_pubkey(self): key = KEY() key.set_secret(decodehexstr("30d1d8d1d243ab41a80a3cc1481a626a137f771a636b2daca06c1f86cdfecffb"), True) self.assertEquals(hexstr(key.get_pubkey()), "030a43196c8bf389c0ce5987a3f4dac57f4ca0d9733c232659717d9404074b4504")
def test_ssl_set_secret(self): key = KEY() key.set_secret(decodehexstr("30d1d8d1d243ab41a80a3cc1481a626a137f771a636b2daca06c1f86cdfecffb"), True) self.assertEquals(hexstr(key.get_privkey()), "3081d3020101042030d1d8d1d243ab41a80a3cc1481a626a137f771a636b2daca06c1f86cdfecffba08185308182020101302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300604010004010704210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101a124032200030a43196c8bf389c0ce5987a3f4dac57f4ca0d9733c232659717d9404074b4504")
def test_set_pubkey(self): sig = decodehexstr("3046022100b2a3e589f5ccd266b0b3ca34ec28a8730c34f16e7de2889f91fcb63824cb0da9022100b04e7b58680c55bb3cd5394c0feb5cfad98ba3695802e4fab61308f18d474031") key2 = KEY() key2.set_pubkey(decodehexstr("030a43196c8bf389c0ce5987a3f4dac57f4ca0d9733c232659717d9404074b4504")) self.assertEquals(key2.verify("cool", sig), 1)