add tx private key and key image proofs to transactions

This commit is contained in:
Sean Darcy 2023-04-24 07:41:25 +10:00
parent 71177fe9df
commit c764fbd5d4
8 changed files with 171 additions and 15 deletions

View File

@ -80,10 +80,14 @@ def load_test_wallet():
click.echo("Wallet already loaded")
return
spend_priv = "e6c9165356c619a64a0d26fafd99891acccccf8717a8067859d972ecd8bcfc0a"
spend_pub = "b76f2d7c8a036ff65c564dcb27081c04fe3f2157942e23b0496ca797ba728e4f"
view_priv = "961d67bb5b3ed1af8678bbfcf621f9c15c2b7bff080892890020bdfd47fe4f0a"
view_pub = "8a0ebacd613e0b03b8f27bc64bd961ea2ebf4c671c6e7f3268651acf0823fed5"
# spend_priv = "e6c9165356c619a64a0d26fafd99891acccccf8717a8067859d972ecd8bcfc0a"
# spend_pub = "b76f2d7c8a036ff65c564dcb27081c04fe3f2157942e23b0496ca797ba728e4f"
# view_priv = "961d67bb5b3ed1af8678bbfcf621f9c15c2b7bff080892890020bdfd47fe4f0a"
# view_pub = "8a0ebacd613e0b03b8f27bc64bd961ea2ebf4c671c6e7f3268651acf0823fed5"
view_pub = "ed26f4f9ed44baccb0aa32bfd91fd546115a60c77e6e8098cd4debf8f33cb9f9"
spend_pub = "9834c238ebecb78b1f30115c50b956e9e5e0d86072c61d57e65ee04f9c650b40"
view_priv = "5f51194e0f839ee32fdd85765be009b1fceb70e78204e4bfa3010e2ade61fc0d"
spend_priv = "0ac3dc5fff3a7a303b893a50119ff2da3125f6a51b980e409d6c8a3a3f7ec80b"
keyring = pywallet3.Keyring(spend_priv, spend_pub, view_priv, view_pub, context.options["network"])
click.echo("Wallet address " + click.style("{}", fg='cyan', bold=True).format(keyring.get_main_address()) + " loaded")

View File

@ -101,6 +101,22 @@ crypto::key_image Keyring::key_image(
return ret;
}
crypto::key_image Keyring::generate_key_image(const crypto::secret_key& output_private_key) {
crypto::key_image ret;
crypto::public_key output_pubkey_computed;
key_device.secret_key_to_public_key(output_private_key, output_pubkey_computed);
key_device.generate_key_image(output_pubkey_computed, output_private_key, ret);
return ret;
}
crypto::signature Keyring::generate_key_image_signature(const crypto::secret_key& output_private_key, const crypto::key_image& key_image) {
crypto::signature ret;
crypto::public_key output_pubkey_computed;
key_device.secret_key_to_public_key(output_private_key, output_pubkey_computed);
key_device.generate_key_image_signature(key_image, output_pubkey_computed, output_private_key, ret);
return ret;
}
// TODO: replace later when removing wallet2½ layer
std::pair<uint64_t, rct::key> Keyring::output_amount_and_mask(
const rct::rctSig& rv, const crypto::key_derivation& derivation, unsigned int i) {
@ -213,7 +229,7 @@ crypto::hash Keyring::get_transaction_prefix_hash(const cryptonote::transaction_
void Keyring::sign_transaction(PendingTransaction& ptx) {
auto hf_version = cryptonote::hf::hf19_reward_batching;
auto tx_key = generate_tx_key(hf_version);
auto tx_key = ptx.tx_secret_key.value_or(generate_tx_key(hf_version));
rct::ctkeyV inSk;
rct::keyV dest_keys;

View File

@ -77,6 +77,10 @@ class Keyring : public WalletKeys {
uint64_t output_index,
const cryptonote::subaddress_index& sub_index);
virtual crypto::key_image generate_key_image(const crypto::secret_key& output_private_key);
virtual crypto::signature generate_key_image_signature(const crypto::secret_key& output_private_key, const crypto::key_image& key_image);
virtual std::pair<uint64_t, rct::key> output_amount_and_mask(
const rct::rctSig& rv, const crypto::key_derivation& derivation, unsigned int i);

View File

@ -37,6 +37,8 @@ struct PendingTransaction {
uint64_t burn_fixed = 0;
std::optional<crypto::secret_key> tx_secret_key = std::nullopt;
std::vector<uint8_t> extra = {};
size_t extra_size() const { return extra.size(); };

View File

@ -63,11 +63,11 @@ std::string RequestHandler::submit_transaction(wallet::PendingTransaction& ptx)
{
w->keys->sign_transaction(ptx);
auto submit_future = w->daemon_comms->submit_transaction(ptx.tx, false);
auto submit_future = w->daemon_comms->submit_transaction(ptx.tx, false);
if (submit_future.wait_for(5s) != std::future_status::ready)
throw rpc_error(500, "request to daemon timed out");
response = submit_future.get();
if (submit_future.wait_for(5s) != std::future_status::ready)
throw rpc_error(500, "request to daemon timed out");
response = submit_future.get();
}
return response;
}
@ -390,7 +390,8 @@ void RequestHandler::invoke(REGISTER_SERVICE_NODE& command, rpc_context context)
command.request.hardfork,
command.request.service_node_key,
command.request.signature,
change_dest
change_dest,
w->keys
);
}
command.response["result"] = submit_transaction(ptx);

View File

@ -227,8 +227,8 @@ PendingTransaction TransactionConstructor::create_ons_update_transaction(
const uint64_t registration_hardfork,
const std::string& service_node_key,
const std::string& signature_str,
const cryptonote::tx_destination_entry& change_recipient
)
const cryptonote::tx_destination_entry& change_recipient,
std::shared_ptr<Keyring> keyring)
{
std::vector<cryptonote::tx_destination_entry> recipients;
@ -272,10 +272,27 @@ PendingTransaction TransactionConstructor::create_ons_update_transaction(
if (!cryptonote::add_service_node_registration_to_tx_extra(new_tx.extra, registration))
throw std::runtime_error("Failed to serialize service node registration tx extra");
new_tx.tx_secret_key = keyring->generate_tx_key(hf);
cryptonote::add_tx_secret_key_to_tx_extra(new_tx.extra, *new_tx.tx_secret_key);
// TODO this sends the secret key to the hardware device so it know to use it
//if (!hwdev.update_staking_tx_secret_key(tx_sk)) {
//log::warning(globallogcat, "Failed to add tx secret key to stake transaction");
//return false;
//}
cryptonote::tx_extra_tx_key_image_proofs key_image_proofs;
auto& proof = key_image_proofs.proofs.emplace_back();
proof.key_image = keyring->generate_key_image(*new_tx.tx_secret_key);
proof.signature = keyring->generate_key_image_signature(*new_tx.tx_secret_key, proof.key_image);
cryptonote::add_tx_key_image_proofs_to_tx_extra(new_tx.extra, key_image_proofs);
validate_register_service_node_parameters(service_node_key, registration, hf);
new_tx.update_change();
//TODO sean get use the new tx_key from somewhere
select_inputs_and_finalise(new_tx);
return new_tx;
}

View File

@ -74,8 +74,8 @@ class TransactionConstructor {
const uint64_t registration_hardfork,
const std::string& service_node_key,
const std::string& signature_str,
const cryptonote::tx_destination_entry& change_recipient
);
const cryptonote::tx_destination_entry& change_recipient,
std::shared_ptr<Keyring> keyring);
void
validate_stake_parameters(

View File

@ -130,6 +130,12 @@ def eat_ons_data():
return ons_data
def eat_uint64_t():
return eat_uint(8)
def eat_uint8_t():
return eat_uint(1)
def eat_uint(size_in_bytes):
global tx_extra_list
amount = ''.join(tx_extra_list[:8*2])
tx_extra_list = tx_extra_list[8*2:]
@ -140,13 +146,119 @@ def eat_burn():
global tx_extra_list
return {"amount": eat_uint64_t()}
def eat_varint():
global tx_extra_list
length = 0
x = 0
b = 1
for i in range(0, len(tx_extra_list), 2):
length = length + 2
z = int(''.join(tx_extra_list[i:i+2]), 16)
x += b * (z & ~0x80)
if z & 0x80 == 0:
break
b <<= 7
tx_extra_list = tx_extra_list[length:]
return x
def eat_service_node_contributor():
global tx_extra_list
spend_public_key = ''.join(tx_extra_list[:64])
tx_extra_list = tx_extra_list[64:]
view_public_key = ''.join(tx_extra_list[:64])
tx_extra_list = tx_extra_list[64:]
return {"spend_public_key": spend_public_key,
"view_public_key": view_public_key }
def eat_service_node_pubkey():
global tx_extra_list
public_key = ''.join(tx_extra_list[:64])
tx_extra_list = tx_extra_list[64:]
return {"service_node_pubkey": public_key}
def eat_list(elem_size):
global tx_extra_list
results = []
size_hex = ''.join(tx_extra_list[:2])
tx_extra_list = tx_extra_list[2:]
size = int(size_hex, 16)
for i in range(size):
result = ''.join(tx_extra_list[:elem_size])
tx_extra_list = tx_extra_list[elem_size:]
results.append(result)
return results
def eat_uint64_t_list():
global tx_extra_list
results = []
size_hex = ''.join(tx_extra_list[:2])
tx_extra_list = tx_extra_list[2:]
size = int(size_hex, 16)
for i in range(size):
result = eat_uint64_t()
results.append(result)
return results
def eat_varint_list():
global tx_extra_list
results = []
size_hex = ''.join(tx_extra_list[:2])
tx_extra_list = tx_extra_list[2:]
size = int(size_hex, 16)
for i in range(size):
result = eat_varint()
results.append(result)
return results
def eat_service_node_registration():
global tx_extra_list
public_spend_keys = eat_list(64)
public_view_keys = eat_list(64)
fee = eat_uint64_t()
amounts= eat_varint_list()
hf = eat_uint8_t()
signature = ''.join(tx_extra_list[:128])
tx_extra_list = tx_extra_list[128:]
return {"public_spend_keys": public_spend_keys,
"public_view_keys": public_view_keys,
"fee": fee,
"amounts":amounts,
"hf":hf,
"signature": signature}
def eat_tx_secret_key():
global tx_extra_list
tx_secret_key = ''.join(tx_extra_list[:64])
tx_extra_list = tx_extra_list[64:]
return {"tx_secret_key": tx_secret_key}
def eat_tx_key_image_proofs():
global tx_extra_list
size_hex = ''.join(tx_extra_list[:2])
tx_extra_list = tx_extra_list[2:]
size = int(size_hex, 16)
key_images = []
signatures = []
for i in range(size):
tx_key_image = ''.join(tx_extra_list[:64])
key_images.append(tx_key_image)
tx_extra_list = tx_extra_list[64:]
signature = ''.join(tx_extra_list[:128])
signatures.append(signature)
tx_extra_list = tx_extra_list[128:]
return {"key_images": key_images,
"signatures": signatures}
eat_data_functions = {
"TX_EXTRA_TAG_PUBKEY": eat_pubkey_data,
"TX_EXTRA_NONCE": eat_nonce_data,
"TX_EXTRA_TAG_OXEN_NAME_SYSTEM": eat_ons_data,
"TX_EXTRA_TAG_BURN": eat_burn
"TX_EXTRA_TAG_BURN": eat_burn,
"TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR": eat_service_node_contributor,
"TX_EXTRA_TAG_SERVICE_NODE_PUBKEY": eat_service_node_pubkey,
"TX_EXTRA_TAG_SERVICE_NODE_REGISTER": eat_service_node_registration,
"TX_EXTRA_TAG_TX_SECRET_KEY": eat_tx_secret_key,
"TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS": eat_tx_key_image_proofs
}
# Main loop that reads over every item