Skip to content

Commit

Permalink
send spend action to rust
Browse files Browse the repository at this point in the history
  • Loading branch information
abenso committed Nov 8, 2024
1 parent 4c1be97 commit be59cf9
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 46 deletions.
2 changes: 2 additions & 0 deletions app/rust/include/rslib.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ parser_error_t rs_compute_effect_hash();

parser_error_t rs_compute_transaction_plan(transaction_plan_t *plan, uint8_t *output, size_t output_len);

parser_error_t rs_spend_action_hash(spend_plan_t *plan, uint8_t *output, size_t output_len);

int32_t rs_bech32_encode(const uint8_t *hrp_ptr, size_t hrp_len, const uint8_t *data_ptr, size_t data_len,
uint8_t *output_ptr, size_t output_len);

Expand Down
32 changes: 28 additions & 4 deletions app/rust/src/parser/plans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
* limitations under the License.
********************************************************************************/
use self::{
action::ActionC, action::ActionPlan, detection::DetectionDataPlan,
detection::DetectionDataPlanC, memo::MemoPlanC,
action::ActionPlan, detection::DetectionDataPlan,
detection::DetectionDataPlanC, memo::MemoPlanC, spend::SpendPlanC,
};
use crate::parser::bytes::BytesC;

use super::{ObjectList, TransactionParameters};

Expand Down Expand Up @@ -81,7 +82,7 @@ pub struct TransactionPlan<'a> {
#[repr(C)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
pub struct TransactionPlanC {
pub actions: [ActionC; ACTION_DATA_QTY],
pub actions_hashes: [BytesC; ACTION_DATA_QTY],
pub transaction_parameters: TransactionParametersC,
pub memo: MemoPlanC,
pub detection_data: DetectionDataPlanC,
Expand Down Expand Up @@ -134,6 +135,29 @@ pub unsafe extern "C" fn rs_compute_transaction_plan(
ParserError::Ok as u32
}

#[no_mangle]
/// Use to compute an address and write it back into output
/// argument.
pub unsafe extern "C" fn rs_spend_action_hash(
plan: &SpendPlanC,
output: *mut u8,
output_len: usize,
) -> u32 {
crate::zlog("rs_spend_action_hash\x00");
let output = std::slice::from_raw_parts_mut(output, output_len);

if output.len() < 64 {
return ParserError::Ok as u32;
}

// TODO: implement spend hash
for byte in output.iter_mut() {
*byte = 1;
}

ParserError::Ok as u32
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -208,7 +232,7 @@ mod tests {

// Create TransactionPlanC with dummy data
let transaction_plan = TransactionPlanC {
actions: core::array::from_fn(|_| dummy_action.clone()),
actions_hashes: core::array::from_fn(|_| BytesC::from_slice(&[0u8; 32])),
transaction_parameters: dummy_transaction_parameters,
memo: dummy_memo_plan,
detection_data: dummy_detection_data,
Expand Down
46 changes: 46 additions & 0 deletions app/rust/src/parser/plans/spend.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use core::{mem::MaybeUninit, ptr::addr_of_mut};

use crate::parser::{address::AddressC, bytes::BytesC};

use crate::{
parser::{Fq, Fr, Note, Position},
FromBytes, ParserError,
Expand Down Expand Up @@ -65,3 +67,47 @@ impl<'b> FromBytes<'b> for SpendPlan<'b> {
Ok(input)
}
}

#[repr(C)]
#[derive(Clone)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
pub struct AmountC {
pub lo: u64,
pub hi: u64,
}

#[repr(C)]
#[derive(Clone)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
pub struct AssetIdC {
pub inner: BytesC,
}

#[repr(C)]
#[derive(Clone)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
pub struct ValueC {
pub amount: AmountC,
pub asset_id: AssetIdC,
}

#[repr(C)]
#[derive(Clone)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
pub struct NoteC {
pub value: ValueC,
pub rseed: BytesC,
pub address: AddressC,
}

#[repr(C)]
#[derive(Clone)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
pub struct SpendPlanC {
pub note: NoteC,
pub position: u64,
pub randomizer: BytesC,
pub value_blinding: BytesC,
pub proof_blinding_r: BytesC,
pub proof_blinding_s: BytesC,
}
33 changes: 22 additions & 11 deletions app/src/parser_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ void print_string(const char *str) {

bool decode_action(pb_istream_t *stream, const pb_field_t *field, void **arg) {
penumbra_core_transaction_v1_ActionPlan action = penumbra_core_transaction_v1_ActionPlan_init_default;
spend_plan_t spend_plan;

action_t *decode_arg = (action_t *)*arg;
if (decode_arg == NULL) {
Expand All @@ -66,18 +65,17 @@ bool decode_action(pb_istream_t *stream, const pb_field_t *field, void **arg) {
return false;
}

const uint8_t *first_byte = stream->state;
uint16_t data_size = stream->bytes_left;
decode_arg[actions_qty].action.ptr = first_byte + 3;
decode_arg[actions_qty].action.len = data_size - 3;
Bytes_t action_data;
action_data.ptr = stream->state + 3;
action_data.len = stream->bytes_left - 3;

if (!pb_decode(stream, penumbra_core_transaction_v1_ActionPlan_fields, &action)) {
return false;
}
decode_arg[actions_qty].action_type = action.which_action;
switch (action.which_action) {
case penumbra_core_transaction_v1_ActionPlan_spend_tag:
decode_spend_plan(&decode_arg[actions_qty].action, &spend_plan);
decode_spend_plan(&action_data, &decode_arg[actions_qty].action.spend);
print_string("Spend action detected \n");
break;
case penumbra_core_transaction_v1_ActionPlan_output_tag:
Expand Down Expand Up @@ -137,6 +135,7 @@ bool decode_detection_data(pb_istream_t *stream, const pb_field_t *field, void *

parser_error_t _read(parser_context_t *c, parser_tx_t *v) {
Bytes_t data;
action_t actions_plan[ACTIONS_QTY];
data.ptr = c->buffer;
data.len = c->bufferLen;
actions_qty = 0;
Expand All @@ -156,7 +155,7 @@ parser_error_t _read(parser_context_t *c, parser_tx_t *v) {

// actions callbacks
request.actions.funcs.decode = &decode_action;
request.actions.arg = &v->plan.actions;
request.actions.arg = &actions_plan;

// detection data callbacks
request.detection_data.clue_plans.funcs.decode = &decode_detection_data;
Expand All @@ -183,15 +182,21 @@ parser_error_t _read(parser_context_t *c, parser_tx_t *v) {

// print detection data
for (uint16_t i = 0; i < DETECTION_DATA_QTY; i++) {
print_buffer(&v->plan.detection_data.clue_plans[i].address.inner, "real detection data address inner");
print_buffer(&v->plan.detection_data.clue_plans[i].address.alt_bech32m, "real detection data address alt bech32m");
print_buffer(&v->plan.detection_data.clue_plans[i].rseed, "real detection data rseed");
// print_buffer(&v->plan.detection_data.clue_plans[i].address.inner, "real detection data address inner");
// print_buffer(&v->plan.detection_data.clue_plans[i].address.alt_bech32m, "real detection data address alt bech32m");
// print_buffer(&v->plan.detection_data.clue_plans[i].rseed, "real detection data rseed");
// printf("precision bits: %lu\n", v->plan.detection_data.clue_plans[i].precision_bits);
}

// print actions
for (uint16_t i = 0; i < ACTIONS_QTY; i++) {
print_buffer(&v->plan.actions[i].action, "real actions");
switch (actions_plan[i].action_type) {
case penumbra_core_transaction_v1_ActionPlan_spend_tag:
// printf("spend action detected\n");
// printf("amount hi: %lu\n", actions_plan[i].action.spend.note.value.amount.hi);
// printf("amount lo: %lu\n", actions_plan[i].action.spend.note.value.amount.lo);
break;
}
}

// print memo
Expand All @@ -200,6 +205,12 @@ parser_error_t _read(parser_context_t *c, parser_tx_t *v) {
print_buffer(&v->plan.memo.plaintext.return_address.inner, "real memo return address inner");
print_buffer(&v->plan.memo.plaintext.return_address.alt_bech32m, "real memo return address alt bech32m");

for (uint16_t i = 0; i < DETECTION_DATA_QTY; i++) {
if (actions_plan[i].action_type == penumbra_core_transaction_v1_ActionPlan_spend_tag) {
compute_spend_action_hash(&actions_plan[i].action.spend);
}
}

compute_transaction_plan(&v->plan);

return parser_unexpected_error;
Expand Down
17 changes: 17 additions & 0 deletions app/src/parser_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,20 @@ parser_error_t compute_transaction_plan(transaction_plan_t *plan) {

return parser_ok;
}

parser_error_t compute_spend_action_hash(spend_plan_t *plan) {
if (plan == NULL) return parser_unexpected_error;

uint8_t output[64] = {0};
if (rs_spend_action_hash(plan, output, sizeof(output)) != parser_ok) {
return parser_unexpected_error;
}

// TODO: only for testing
Bytes_t output_bytes;
output_bytes.ptr = output;
output_bytes.len = 64;
print_buffer_interface(&output_bytes, "spend action hash");

return parser_ok;
}
1 change: 1 addition & 0 deletions app/src/parser_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ extern "C" {
#include "zxmacros.h"

parser_error_t compute_transaction_plan(transaction_plan_t *plan);
parser_error_t compute_spend_action_hash(spend_plan_t *plan);

#ifdef __cplusplus
}
Expand Down
10 changes: 8 additions & 2 deletions app/src/parser_txdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,17 @@ typedef struct {

typedef struct {
uint8_t action_type;
Bytes_t action;
union {
spend_plan_t spend;
} action;
} action_t;

typedef struct {
action_t actions[ACTIONS_QTY];
Bytes_t action_hash;
} action_hash_t;

typedef struct {
action_hash_t actions_hash[ACTIONS_QTY];
transaction_parameters_t transaction_parameters;
memo_plan_t memo;
detection_data_t detection_data;
Expand Down
8 changes: 4 additions & 4 deletions tests_zemu/tests/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ const APP_PATH_FL = resolve('../app/output/app_flex.elf')

export const models: IDeviceModel[] = [
// { name: 'nanos', prefix: 'S', path: APP_PATH_S },
{ name: 'nanox', prefix: 'X', path: APP_PATH_X },
// { name: 'nanox', prefix: 'X', path: APP_PATH_X },
{ name: 'nanosp', prefix: 'SP', path: APP_PATH_SP },
{ name: 'stax', prefix: 'ST', path: APP_PATH_ST },
{ name: 'flex', prefix: 'FL', path: APP_PATH_FL },
// { name: 'stax', prefix: 'ST', path: APP_PATH_ST },
// { name: 'flex', prefix: 'FL', path: APP_PATH_FL },
]

export const defaultOptions = {
Expand All @@ -29,5 +29,5 @@ export const defaultOptions = {
}

export const txBlobExample =
'0aaf020aac020aa1010a290a0308904e12220a2029ea9c2f3371f6a487e7e95c247041f4a356f983eb064e5d2b3bcf322ca96a1012207fa50bfe8946e53b33e8328672a0c6300ad9333c04707475f2d6cc502ec8513a1a520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d691a208d0887fd0d20bd002c336054772d56b8f9704a80ac8da45533e72f155f7145032220d1241d9d9f051c437455998e7c1eff33cd085ba9a9092d852d0381278bb6b1012a205e3505d5b6b1b99a8284f054bd650e8d4b64a23f6322c05a0ccee46bb481cb0932208c6abfdd0dd9111868fbed6a30c9dd5477b123f7aefd15bc73b68185f0a036110ab2020aaf020aa2010a2a0a0408a09c0112220a2029ea9c2f3371f6a487e7e95c247041f4a356f983eb064e5d2b3bcf322ca96a10122079ce0fe2f6695ebe61c22edb8de45e1290448500e0058156cb4e29f4d7234f091a520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d6910011a20c3021eb39eed577b5d609f5436d9128ff6c8bcc13e326a4fcab5c749e2f489002220c05b9ffb6512d40cc8cf03eb1e2b47f3fcc323a0f2db077362b2300eb77658022a20a45a2fc5a64032c3a68ce4ec9c542b564cfaa9b14d3af386bd142a645212540f32208cb5d93be25ba643ee760f56624cd051e53ca0e7047e4a95a5faf82f0636f60d0a8b021288020a2a0a0408b0ea0112220a2029ea9c2f3371f6a487e7e95c247041f4a356f983eb064e5d2b3bcf322ca96a1012520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d691a20cde64106162059a6800918036eb3c0e9b2872f56d4902259fba9b52d18dbd7c52220a1417029703aa865b08f19acc96eba15928a2178956f6c9c538ea5577a03ef032a20df5538e38602a2bd15119182c50d0f1b22fd8deba0a728a8fbbfb7e9b8c6fc0932207dee2a1d6d9c85ba68560cfa514b73897e77fe0355d92c9cc2bb3b522b5f3d110abc021ab9020ad0010a480a220a20116d0cd6de9349c686f5802f7c98179e70d4898a38e1cc3df93705c94e941d0c12220a2029ea9c2f3371f6a487e7e95c247041f4a356f983eb064e5d2b3bcf322ca96a10120408a08d061a02080122040a0208032a520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d69322057798bc1a097c26b47e61a9870ca98eb8cbe48e9cba4db86f5d8b67c12086afb1220fbf22b3005fdd84a03bdf0950c851a9c6e0618b0eea1004ca75e53ce3deef1031a205f9ddbd8093a028de6597d03d785302d8336e20a2148e15ae016bad0536d7e0122200d358f3968b24d5e612504b211cadb44ace485ceb3ad38821aa96b926279e6001213120d70656e756d6272612d746573741a020a0022f4012a780a520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d691220361218d216cfe90f77f54f045ff21b464795517c05057c595fd59e4958e3941718032a780a520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d69122013296da8c9dfdf969be7c7bd74e67e80977cd91635eb32038619f62c732dc46a18022a780a540a520a506ece16f387e0b932082cb0cf6823590fc287d068d6f684a36d1fb19bfd6dce8b22850f535824aeb66cb8c41309e6f5b2d58ff7b651ef4e09a09c7e48d770d190880e1827b47823a1d01f0c4b438a7b43122018bd5cedd0eb952244a296c1e3fba4f417ebdcc1cfec04cb9441a394316a58bd'
'0aaf020aac020aa1010a290a0308954e12220a2029ea9c2f3371f6a487e7e95c247041f4a356f983eb064e5d2b3bcf322ca96a101220c923f2f89ccea2aafe13dca34d083faf4894f156f604dc3d4817bf6717096e331a520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d691a2080b306db5db558a2d0cd19ad587c1f28b5b9f8139901ade057cba921fc76c7032220bf3a56c1b6236f007ea136ad1fb0735e03e4ccae3a5c93af28326485e3bb65002a20f7298845c66cba673959f9d3ca44d0831c90cd925c92afc1cf5299185a3f120b32202d700f646468f7434f34adc9854d8e8e5b8bb86d35f343db0fd8126ce49ad6030ab2020aaf020aa2010a2a0a0408a09c0112220a2029ea9c2f3371f6a487e7e95c247041f4a356f983eb064e5d2b3bcf322ca96a1012204988c0704b1c5beb92aa58168d75e32e8edbd60c2e7ec470bc50440f1a21f3eb1a520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d6910011a205550f06f9c3ba695c9bab8f317cc4bcd7f62e90f80de421ae70161678cc4200322200e93266e84a34cce2bd5b6021d78226e68f6f760b688765ddbc19b451ced11022a2069e48038c64d148608a27e9846ff74a85b0bc86188f3e5ca037c20b16476ff0032209ee9410d61a376540f140f88d38b0785f8c7852bd11512ea92281003aad805030a8b021288020a2a0a0408b0ea0112220a2029ea9c2f3371f6a487e7e95c247041f4a356f983eb064e5d2b3bcf322ca96a1012520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d691a20cee6fb736d421932e6c2b895ae1a0f65b6769ddbf96dfec8d0965d1487549e6622205994ad1abed78f6b5d48fc72eb114742d1b04f94a842621897eca948beb91c002a206c5beeab2d967b5347e002a7e453abee0ee9d9f0239fbc855c05502cdca459113220df0cd5b18b09548339a7d13e8fcdb6a5a8f0dc7fc8a587aa74ee746df2bba1100abc021ab9020ad0010a480a220a20116d0cd6de9349c686f5802f7c98179e70d4898a38e1cc3df93705c94e941d0c12220a2029ea9c2f3371f6a487e7e95c247041f4a356f983eb064e5d2b3bcf322ca96a10120408a08d061a02080122040a0208032a520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d69322096f795c0f70ae89247c62febde1488f3673b0fd48e03517b60b17fcc375d2fa912202efb6351ce1af7c5612481ad4660fd184db5e73908224455b50d7fe79f2bdf001a20a4cfed973f3f025070f6de90d2a2ea1336922cce1fbf0f1be443554e9652770a222081dc04672db59a2d011d82aa980a50012de22048b59f719e626f7c15b64a2e111213120d70656e756d6272612d746573741a020a0022f4012a780a520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d69122083f70f7faa82e24925010fd9fd248fb2bf16f96fb3d1f2aa984696b4f91fbc8d18032a780a520a50e0783360338067fc2ba548f460b3f06f33d3e756ebefa8a8c08c5e12a1e667df228df0720fb9bd963894183bc447e1c7ef591fa9625d4a66b7703eec2ec1ef543454673bb61a4f2a3d861114d6891d6912209ce6c8171c50847dffc5112fde5e1245fa1e561ea4ef2b0259ee3443fb9b26eb18022a780a540a520a50a39eff5d22636e107f0d0797fe9d89d79c98326fe640f8ef8dbe738148555c6d9f9bfc4059a190226bca124981087b604539638a0b16fd0a3ea73d47bb40604a02607ab23ffe910f636ba4b307db3cde1220a19b520a3749f7511bb02e0eed2e51fb2a6019920cb9dc7ba3f41906c91305c1'

50 changes: 25 additions & 25 deletions tests_zemu/tests/standard.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,31 +184,31 @@ describe('Standard', function () {
})

// TODO: WIP
// test.concurrent.each(models)('sign', async function (m) {
// const sim = new Zemu(m.path)
// try {
// await sim.start({ ...defaultOptions, model: m.name })
// const app = new PenumbraApp(sim.getTransport())

// const messageToSign = Buffer.from(txBlobExample, 'hex')
// console.log("messageToSignLength!!!!!", messageToSign.length)
// console.log("messageToSign!!!!!", messageToSign)
// // do not wait here... we need to navigate
// const signatureRequest = app.sign(PEN_PATH, ACCOUNT_ID, messageToSign)

// // Wait until we are not in the main menu
// // await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot())
// // await sim.compareSnapshotsAndApprove('.', `${m.prefix.toLowerCase()}-sign`)
test.only.each(models)('sign', async function (m) {
const sim = new Zemu(m.path)
try {
await sim.start({ ...defaultOptions, model: m.name })
const app = new PenumbraApp(sim.getTransport())

const messageToSign = Buffer.from(txBlobExample, 'hex')
console.log("messageToSignLength!!!!!", messageToSign.length)
console.log("messageToSign!!!!!", messageToSign)
// do not wait here... we need to navigate
const signatureRequest = app.sign(PEN_PATH, ACCOUNT_ID, messageToSign)

// Wait until we are not in the main menu
// await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot())
// await sim.compareSnapshotsAndApprove('.', `${m.prefix.toLowerCase()}-sign`)


// const signatureResponse = await signatureRequest
// console.log(signatureResponse)

// // Now verify the signature
// // const valid = ed25519.verify(signatureResponse.signature, messageToSign, pubKey)
// // expect(valid).toEqual(true)
// } finally {
// await sim.close()
// }
// })
const signatureResponse = await signatureRequest
console.log(signatureResponse)

// Now verify the signature
// const valid = ed25519.verify(signatureResponse.signature, messageToSign, pubKey)
// expect(valid).toEqual(true)
} finally {
await sim.close()
}
})
})

0 comments on commit be59cf9

Please sign in to comment.