Skip to content

Commit

Permalink
sign tx: extract reading tx-signing message fields into helper function
Browse files Browse the repository at this point in the history
  • Loading branch information
JamieDriver committed May 16, 2023
1 parent cc9c830 commit ee45290
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 86 deletions.
4 changes: 2 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1195,7 +1195,7 @@ A batch of 'tx_input' messages should be sent to Jade - one for each tx input.
}
}
* 'script' and 'path' should be omitted if a signature for this input is not required.
* 'is_witness', 'script' and 'path' should be omitted if a signature for this input is not required.
* If provided, 'script' should be the script-sig/redeem-script required to satisfy the input utxo.
* 'input_tx' should be the streamed bytes of the txn which output the utxo being spent.
* NOTE: if this is the only input, and 'is_witness' is 'true', the 'input_tx' can (optionally) be replaced with a 'satoshi' element, eg: '"satoshi": 2200000'.
Expand Down Expand Up @@ -1637,7 +1637,7 @@ A batch of 'tx_input' messages should be sent to Jade - one for each tx input, a
}
}
* 'script' and 'path' are as in sign_tx_legacy_input_request_.
* 'is_witness', 'script' and 'path' are as in sign_tx_legacy_input_request_.
* In addition, if a signature is required for this input and 'is_witness' is 'true', then the input utxo 'value_commitment' must be passed.
* NOTE: no 'input_tx' is needed.

Expand Down
20 changes: 10 additions & 10 deletions jadepy/jade.py
Original file line number Diff line number Diff line change
Expand Up @@ -1330,18 +1330,19 @@ def sign_liquid_tx(self, network, txn, inputs, commitments, change, use_ae_signa
The transaction to sign
inputs : [dict]
The tx inputs. Should contain keys:
The tx inputs.
If signing this input, should contain keys:
is_witness, bool - whether this is a segwit input
value_commitment, 33-bytes - The value commitment of ths input
These are only required if signing this input:
script, bytes- the redeem script
path, [int] - the bip32 path to sign with
value_commitment, 33-bytes - The value commitment of ths input
These are only required for Anti-Exfil signatures:
ae_host_commitment, 32-bytes - The host-commitment for Anti-Exfil signatures
ae_host_entropy, 32-bytes - The host-entropy for Anti-Exfil signatures
If not signing this input a null or an empty dict can be passed.
commitments : [dict]
An array sized for the number of outputs.
Unblinded outputs should have a 'null' placeholder element.
Expand Down Expand Up @@ -1415,17 +1416,16 @@ def sign_tx(self, network, txn, inputs, change, use_ae_signatures=False):
inputs : [dict]
The tx inputs. Should contain keys:
is_witness, bool - whether this is a segwit input
These are only required if signing this input:
script, bytes- the redeem script
path, [int] - the bip32 path to sign with
One of these is required:
input_tx, bytes - The prior transaction which created the utxo of this input
satoshi, int - The satoshi amount of this input - can be used in place of
'input_tx' for a tx with a single segwit input
These are only required if signing this input:
is_witness, bool - whether this is a segwit input
script, bytes- the redeem script
path, [int] - the bip32 path to sign with
These are only required for Anti-Exfil signatures:
ae_host_commitment, 32-bytes - The host-commitment for Anti-Exfil signatures
ae_host_entropy, 32-bytes - The host-entropy for Anti-Exfil signatures
Expand Down
53 changes: 52 additions & 1 deletion main/process/process_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "../utils/cbor_rpc.h"

#include <sys/time.h>
#include <wally_anti_exfil.h>
#include <wally_script.h>

#include "process_utils.h"
Expand Down Expand Up @@ -256,6 +257,56 @@ bool params_get_master_blindingkey(
return true;
}

// Get the common parameters required when signing an tx input
bool params_tx_input_signing_data(const bool use_ae_signatures, CborValue* params, bool* is_witness,
signing_data_t* sig_data, const uint8_t** ae_host_commitment, size_t* ae_host_commitment_len,
const uint8_t** script, size_t* script_len, script_flavour_t* aggregate_script_flavour, const char** errmsg)
{
JADE_ASSERT(params);
JADE_ASSERT(is_witness);
JADE_ASSERT(sig_data);
JADE_INIT_OUT_PPTR(ae_host_commitment);
JADE_INIT_OUT_SIZE(ae_host_commitment_len);
JADE_INIT_OUT_PPTR(script);
JADE_INIT_OUT_SIZE(script_len);
JADE_ASSERT(aggregate_script_flavour);
JADE_ASSERT(errmsg);

if (!rpc_get_boolean("is_witness", params, is_witness)) {
*errmsg = "Failed to extract is_witness from parameters";
return false;
}

const size_t max_path_len = sizeof(sig_data->path) / sizeof(sig_data->path[0]);
if (!rpc_get_bip32_path("path", params, sig_data->path, max_path_len, &sig_data->path_len)
|| sig_data->path_len == 0) {
*errmsg = "Failed to extract valid path from parameters";
return false;
}

// If required, read anti-exfil host commitment data
if (use_ae_signatures) {
rpc_get_bytes_ptr("ae_host_commitment", params, ae_host_commitment, ae_host_commitment_len);
if (!*ae_host_commitment || *ae_host_commitment_len != WALLY_HOST_COMMITMENT_LEN) {
*errmsg = "Failed to extract valid host commitment from parameters";
return false;
}
}

// Get prevout script - required for signing inputs
rpc_get_bytes_ptr("script", params, script, script_len);
if (!*script || *script_len == 0) {
*errmsg = "Failed to extract script from parameters";
return false;
}

// Track the types of the input prevout scripts
const script_flavour_t script_flavour = get_script_flavour(*script, *script_len);
update_aggregate_scripts_flavour(script_flavour, aggregate_script_flavour);

return true;
}

// For now just return 'single-sig' or 'other'.
// In future may extend to inlcude eg. 'green', 'other-multisig', etc.
script_flavour_t get_script_flavour(const uint8_t* script, const size_t script_len)
Expand Down Expand Up @@ -284,4 +335,4 @@ void update_aggregate_scripts_flavour(
// As soon as we see something differet, set to 'mixed'
*aggregate_scripts_flavour = SCRIPT_FLAVOUR_MIXED;
}
}
}
4 changes: 4 additions & 0 deletions main/process/process_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ bool params_multisig_pubkeys(bool is_change, CborValue* params, multisig_data_t*
bool params_get_master_blindingkey(
CborValue* params, uint8_t* master_blinding_key, size_t master_blinding_key_len, const char** errmsg);

bool params_tx_input_signing_data(const bool use_ae_signatures, CborValue* params, bool* is_witness,
signing_data_t* sig_data, const uint8_t** ae_host_commitment, size_t* ae_host_commitment_len,
const uint8_t** script, size_t* script_len, script_flavour_t* aggregate_script_flavour, const char** errmsg);

// Track the types of the input prevout scripts
script_flavour_t get_script_flavour(const uint8_t* script, const size_t script_len);
void update_aggregate_scripts_flavour(script_flavour_t new_script_flavour, script_flavour_t* aggregate_scripts_flavour);
Expand Down
40 changes: 5 additions & 35 deletions main/process/sign_liquid_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ void sign_liquid_tx_process(void* process_ptr)
// txn input as expected - get input parameters
GET_MSG_PARAMS(process);

bool is_witness = false;
size_t script_len = 0;
const uint8_t* script = NULL;

Expand All @@ -555,47 +556,16 @@ void sign_liquid_tx_process(void* process_ptr)
rpc_get_id(&process->ctx.value, sig_data->id, sizeof(sig_data->id), &written);
JADE_ASSERT(written != 0);

bool is_witness = false;
ret = rpc_get_boolean("is_witness", &params, &is_witness);
if (!ret) {
jade_process_reject_message(
process, CBOR_RPC_BAD_PARAMETERS, "Failed to extract is_witness from parameters", NULL);
goto cleanup;
}

// Path node can be omitted if we don't want to sign this input
// (But if passed must be valid - empty/root path is not allowed for signing)
const bool has_path = rpc_has_field_data("path", &params);
if (has_path) {
const size_t max_path_len = sizeof(sig_data->path) / sizeof(sig_data->path[0]);
if (!rpc_get_bip32_path("path", &params, sig_data->path, max_path_len, &sig_data->path_len)
|| sig_data->path_len == 0) {
jade_process_reject_message(
process, CBOR_RPC_BAD_PARAMETERS, "Failed to extract valid path from parameters", NULL);
// Get all common tx-signing input fields which must be present if a path is given
if (!params_tx_input_signing_data(use_ae_signatures, &params, &is_witness, sig_data, &ae_host_commitment,
&ae_host_commitment_len, &script, &script_len, &aggregate_inputs_scripts_flavour, &errmsg)) {
jade_process_reject_message(process, CBOR_RPC_BAD_PARAMETERS, errmsg, NULL);
goto cleanup;
}

// If required, read anti-exfil host commitment data
if (use_ae_signatures) {
rpc_get_bytes_ptr("ae_host_commitment", &params, &ae_host_commitment, &ae_host_commitment_len);
if (!ae_host_commitment || ae_host_commitment_len != WALLY_HOST_COMMITMENT_LEN) {
jade_process_reject_message(process, CBOR_RPC_BAD_PARAMETERS,
"Failed to extract valid host commitment from parameters", NULL);
goto cleanup;
}
}

// Get prevout script - required for signing inputs
rpc_get_bytes_ptr("script", &params, &script, &script_len);
if (!script || script_len == 0) {
jade_process_reject_message(
process, CBOR_RPC_BAD_PARAMETERS, "Failed to extract script from parameters", NULL);
goto cleanup;
}

// Track the types of the input prevout scripts
const script_flavour_t script_flavour = get_script_flavour(script, script_len);
update_aggregate_scripts_flavour(script_flavour, &aggregate_inputs_scripts_flavour);
}

size_t value_len = 0;
Expand Down
40 changes: 5 additions & 35 deletions main/process/sign_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ void sign_tx_process(void* process_ptr)
// txn input as expected - get input parameters
GET_MSG_PARAMS(process);

bool is_witness = false;
size_t script_len = 0;
const uint8_t* script = NULL;
uint64_t input_satoshi = 0;
Expand All @@ -448,47 +449,16 @@ void sign_tx_process(void* process_ptr)
rpc_get_id(&process->ctx.value, sig_data->id, sizeof(sig_data->id), &written);
JADE_ASSERT(written != 0);

bool is_witness = false;
ret = rpc_get_boolean("is_witness", &params, &is_witness);
if (!ret) {
jade_process_reject_message(
process, CBOR_RPC_BAD_PARAMETERS, "Failed to extract is_witness from parameters", NULL);
goto cleanup;
}

// Path node can be omitted if we don't want to sign this input
// (But if passed must be valid - empty/root path is not allowed for signing)
const bool has_path = rpc_has_field_data("path", &params);
if (has_path) {
const size_t max_path_len = sizeof(sig_data->path) / sizeof(sig_data->path[0]);
if (!rpc_get_bip32_path("path", &params, sig_data->path, max_path_len, &sig_data->path_len)
|| sig_data->path_len == 0) {
jade_process_reject_message(
process, CBOR_RPC_BAD_PARAMETERS, "Failed to extract valid path from parameters", NULL);
// Get all common tx-signing input fields which must be present if a path is given
if (!params_tx_input_signing_data(use_ae_signatures, &params, &is_witness, sig_data, &ae_host_commitment,
&ae_host_commitment_len, &script, &script_len, &aggregate_inputs_scripts_flavour, &errmsg)) {
jade_process_reject_message(process, CBOR_RPC_BAD_PARAMETERS, errmsg, NULL);
goto cleanup;
}

// If required, read anti-exfil host commitment data
if (use_ae_signatures) {
rpc_get_bytes_ptr("ae_host_commitment", &params, &ae_host_commitment, &ae_host_commitment_len);
if (!ae_host_commitment || ae_host_commitment_len != WALLY_HOST_COMMITMENT_LEN) {
jade_process_reject_message(process, CBOR_RPC_BAD_PARAMETERS,
"Failed to extract valid host commitment from parameters", NULL);
goto cleanup;
}
}

// Get prevout script - required for signing inputs
rpc_get_bytes_ptr("script", &params, &script, &script_len);
if (!script || script_len == 0) {
jade_process_reject_message(
process, CBOR_RPC_BAD_PARAMETERS, "Failed to extract script from parameters", NULL);
goto cleanup;
}

// Track the types of the input prevout scripts
const script_flavour_t script_flavour = get_script_flavour(script, script_len);
update_aggregate_scripts_flavour(script_flavour, &aggregate_inputs_scripts_flavour);
}

// Full input tx can be omitted for transactions with only one single witness
Expand Down
Loading

0 comments on commit ee45290

Please sign in to comment.