Skip to content

Commit

Permalink
compute effect hash
Browse files Browse the repository at this point in the history
  • Loading branch information
abenso committed Nov 14, 2024
1 parent 2b6c700 commit 80762e0
Show file tree
Hide file tree
Showing 12 changed files with 77 additions and 143 deletions.
7 changes: 4 additions & 3 deletions app/rust/src/parser/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
use crate::ParserError;

#[cfg(any(feature = "derive-debug", test))]
use core::fmt;
Expand All @@ -35,11 +36,11 @@ impl fmt::Debug for BytesC {
}

impl BytesC {
pub fn get_bytes(&self) -> Option<&[u8]> {
pub fn get_bytes(&self) -> Result<&[u8], ParserError> {
if self.ptr.is_null() || self.len == 0 {
None
Err(ParserError::UnexpectedData)
} else {
unsafe { Some(std::slice::from_raw_parts(self.ptr, self.len as usize)) }
unsafe { Ok(std::slice::from_raw_parts(self.ptr, self.len as usize)) }
}
}
}
Expand Down
13 changes: 3 additions & 10 deletions app/rust/src/parser/note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,15 @@ impl NoteC {
}

pub fn get_rseed(&self) -> Result<&[u8], ParserError> {
self.rseed.get_bytes().ok_or(ParserError::UnexpectedData)
self.rseed.get_bytes()
}

pub fn get_asset_id(&self) -> Result<&[u8], ParserError> {
self.value
.asset_id
.inner
.get_bytes()
.ok_or(ParserError::UnexpectedData)
self.value.asset_id.inner.get_bytes()
}

pub fn get_address(&self) -> Result<&[u8], ParserError> {
self.address
.inner
.get_bytes()
.ok_or(ParserError::UnexpectedData)
self.address.inner.get_bytes()
}

pub fn get_asset_id_fq(&self) -> Result<Fq, ParserError> {
Expand Down
65 changes: 37 additions & 28 deletions app/rust/src/parser/plans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
use self::{detection::DetectionDataPlanC, memo::MemoPlanC, spend::SpendPlanC};
use self::{detection::DetectionDataPlanC, memo::MemoPlanC, spend::SpendPlanC, action::ActionsHashC};
use crate::keys::spend_key::SpendKeyBytes;
use crate::parser::bytes::BytesC;
use crate::effect_hash::EffectHash;

pub mod action;
pub mod amount;
Expand All @@ -38,12 +38,34 @@ use crate::ParserError;
#[repr(C)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
pub struct TransactionPlanC {
pub actions_hashes: [BytesC; ACTION_DATA_QTY],
pub actions_hashes: ActionsHashC,
pub transaction_parameters: TransactionParametersC,
pub memo: MemoPlanC,
pub detection_data: DetectionDataPlanC,
}

impl TransactionPlanC {
pub fn effect_hash(&self) -> Result<EffectHash, ParserError> {
let mut state = blake2b_simd::Params::new()
.personal(b"PenumbraEfHs")
.to_state();

state.update(self.transaction_parameters.effect_hash()?.as_array());
state.update(self.memo.effect_hash()?.as_array());
state.update(self.detection_data.effect_hash()?.as_array());

let num_actions = self.actions_hashes.qty as u32;
state.update(&num_actions.to_le_bytes());

for i in 0..num_actions {
let action_hash = self.actions_hashes.hashes[i as usize].0;
state.update(&action_hash);
}

Ok(EffectHash::from_array(*state.finalize().as_array()))
}
}

#[no_mangle]
/// Use to compute an address and write it back into output
/// argument.
Expand All @@ -65,27 +87,14 @@ pub unsafe extern "C" fn rs_compute_transaction_plan(
let output = std::slice::from_raw_parts_mut(output, output_len);

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

let transaction_parameters_hash = plan.transaction_parameters.effect_hash();
if let Ok(transaction_parameters_hash_bytes) = transaction_parameters_hash {
let transaction_parameters_hash_array = transaction_parameters_hash_bytes.as_array();
let copy_len: usize = core::cmp::min(output.len(), transaction_parameters_hash_array.len());
output[..copy_len].copy_from_slice(&transaction_parameters_hash_array[..copy_len]);
return ParserError::UnexpectedData as u32;
}

if let Ok(memo_hash_bytes) = plan.memo.effect_hash() {
let memo_hash_array = memo_hash_bytes.as_array();
let copy_len: usize = core::cmp::min(output.len() - 64, memo_hash_array.len());
output[68..68 + copy_len].copy_from_slice(&memo_hash_array[..copy_len]);
}

let detection_hash = plan.detection_data.effect_hash();
if let Ok(detection_hash_bytes) = detection_hash {
let detection_hash_array = detection_hash_bytes.as_array();
let copy_len: usize = core::cmp::min(output.len() - 136, detection_hash_array.len());
output[136..136 + copy_len].copy_from_slice(&detection_hash_array[..copy_len]);
let plan_hash_result = plan.effect_hash();
if let Ok(plan_hash) = plan_hash_result {
let plan_hash_array = plan_hash.as_array();
let copy_len: usize = core::cmp::min(output.len(), plan_hash_array.len());
output[..copy_len].copy_from_slice(&plan_hash_array[..copy_len]);
}

ParserError::Ok as u32
Expand Down Expand Up @@ -127,20 +136,20 @@ mod tests {
use crate::parser::bytes::BytesC;
use crate::parser::clue_plan::CluePlanC;
use crate::parser::note::NoteC;
use crate::parser::plans::action::ActionC;
use crate::parser::plans::action::ActionsHashC;
use crate::parser::plans::amount::AmountC;
use crate::parser::plans::detection::DetectionDataPlanC;
use crate::parser::plans::id::IdC;
use crate::parser::plans::memo::MemoPlanC;
use crate::parser::plans::memo_plain_text::MemoPlaintextC;
use crate::parser::plans::value::ValueC;
use crate::parser::tx_parameters::TransactionParametersC;
use crate::parser::plans::action::ActionHash;
#[test]
fn test_transaction_plan_hash() {
// Create dummy ActionC
let dummy_action = ActionC {
action_type: 0, // Assuming 0 is a valid action type
bytes: BytesC::from_slice(&[0u8; 32]),
let dummy_action_hashes = ActionsHashC {
qty: 1,
hashes: core::array::from_fn(|_| ActionHash([0u8; 64])),
};

// Create dummy TransactionParametersC
Expand Down Expand Up @@ -198,7 +207,7 @@ mod tests {

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

/*******************************************************************************
* (c) 2024 Zondax GmbH
*
Expand All @@ -15,79 +13,27 @@ use core::ptr::addr_of_mut;
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
use crate::{FromBytes, ParserError};

// use super::spend::SpendPlan;
use crate::parser::bytes::BytesC;
use crate::constants::ACTION_DATA_QTY;


#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum ActionType {
Spend = 0,
}

impl TryFrom<u64> for ActionType {
type Error = ParserError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Spend),
_ => Err(ParserError::InvalidActionType),
}
}
}

// #[repr(C)]
// struct SpendVariant<'a>(ActionType, SpendPlan<'a>);

// #[cfg_attr(test, derive(Debug))]
// #[derive(Copy, PartialEq, Eq, Clone)]
// pub enum ActionPlan<'a> {
// Spend(SpendPlan<'a>),
// }

// impl<'a> FromBytes<'a> for ActionPlan<'a> {
// fn from_bytes_into(
// input: &'a [u8],
// out: &mut core::mem::MaybeUninit<Self>,
// ) -> Result<&'a [u8], nom::Err<ParserError>> {
// // 1. Read the action plan type
// let (rem, action_type) = (input, 0); // TODO! read from input

// match action_type {
// 0 => {
// // Spend variant
// let out = out.as_mut_ptr() as *mut SpendVariant<'a>;
// let data = unsafe { &mut *addr_of_mut!((*out).1).cast() };
// let rem = SpendPlan::from_bytes_into(rem, data)?;
// unsafe {
// addr_of_mut!((*out).0).write(ActionType::Spend);
// }
// Ok(rem)
// }
// _ => Err(ParserError::InvalidActionType.into()),
// }
// }
// }

// impl<'a> ActionPlan<'a> {
// pub fn action(&self) -> ActionType {
// match self {
// Self::Spend(_) => ActionType::Spend,
// }
// }

// pub fn spend_plan(&self) -> Option<&SpendPlan<'a>> {
// match self {
// Self::Spend(info) => Some(info),
// }
// }
// }
#[repr(C)]
#[derive(Copy, Clone)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
pub struct ActionHash(pub [u8; 64]);

#[repr(C)]
#[derive(Clone)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
pub struct ActionC {
pub action_type: u8,
pub bytes: BytesC,
pub struct ActionsHashC {
pub qty: u8,
pub hashes: [ActionHash; ACTION_DATA_QTY],
}

2 changes: 1 addition & 1 deletion app/rust/src/parser/plans/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub struct IdC {
}
impl IdC {
pub fn get_inner(&self) -> Result<&[u8], ParserError> {
self.inner.get_bytes().ok_or(ParserError::UnexpectedData)
self.inner.get_bytes()
}
}

Expand Down
2 changes: 1 addition & 1 deletion app/rust/src/parser/plans/memo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl MemoCiphertext {
ciphertext[..memo_bytes.len()].copy_from_slice(memo_bytes);

// Get memo key bytes
let memo_key_bytes = memo_key.get_bytes().ok_or(ParserError::UnexpectedError)?;
let memo_key_bytes = memo_key.get_bytes()?;

// Create PayloadKey and encrypt
let key = PayloadKey::from_bytes(memo_key_bytes);
Expand Down
8 changes: 2 additions & 6 deletions app/rust/src/parser/plans/spend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,7 @@ impl SpendPlanC {
}

pub fn get_randomizer(&self) -> Result<&[u8], ParserError> {
self.randomizer
.get_bytes()
.ok_or(ParserError::UnexpectedData)
self.randomizer.get_bytes()
}

pub fn get_randomizer_fr(&self) -> Result<Fr, ParserError> {
Expand All @@ -159,9 +157,7 @@ impl SpendPlanC {
}

pub fn get_value_blinding(&self) -> Result<&[u8], ParserError> {
self.value_blinding
.get_bytes()
.ok_or(ParserError::UnexpectedData)
self.value_blinding.get_bytes()
}

pub fn get_value_blinding_fr(&self) -> Result<Fr, ParserError> {
Expand Down
13 changes: 3 additions & 10 deletions app/src/parser_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,14 +269,6 @@ parser_error_t _read(parser_context_t *c, parser_tx_t *v) {
penumbra_core_transaction_v1_TransactionPlan_transaction_parameters_tag);
print_buffer(&v->plan.transaction_parameters.parameters, "real transaction parameters");

// 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");
// 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++) {
switch (actions_plan[i].action_type) {
Expand All @@ -302,11 +294,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++) {
for (uint16_t i = 0; i < actions_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_spend_action_hash(&actions_plan[i].action.spend, &v->plan.actions.hashes[i]);
}
}
v->plan.actions.qty = actions_qty;

compute_transaction_plan(&v->plan);

Expand Down
26 changes: 10 additions & 16 deletions app/src/parser_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@
#include "rslib.h"
#include "zxformat.h"

void print_buffer_interface(Bytes_t *buffer, const char *title) {
void print_buffer_interface(uint8_t *buffer, size_t len, const char *title) {
#if defined(LEDGER_SPECIFIC)
ZEMU_LOGF(50, "%s\n", title);
char print[700] = {0};
array_to_hexstr(print, sizeof(print), buffer->ptr, buffer->len);
array_to_hexstr(print, sizeof(print), buffer, len);
ZEMU_LOGF(700, "%s\n", print);
#else
printf("%s: ", title);
for (uint16_t i = 0; i < buffer->len; i++) {
printf("%02x", buffer->ptr[i]);
for (size_t i = 0; i < len; i++) {
printf("%02x", buffer[i]);
}
printf("\n");
#endif
Expand All @@ -45,33 +45,27 @@ parser_error_t compute_transaction_plan(transaction_plan_t *plan) {
}

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

return parser_ok;
}

parser_error_t compute_spend_action_hash(spend_plan_t *plan) {
if (plan == NULL) return parser_unexpected_error;
parser_error_t compute_spend_action_hash(spend_plan_t *plan, action_hash_t *output) {
if (plan == NULL || output == NULL)
return parser_unexpected_error;

// TODO: we need to get the spend key
spend_key_bytes_t sk_bytes = {
0xa1, 0xff, 0xba, 0x0c, 0x37, 0x93, 0x1f, 0x0a, 0x62, 0x61, 0x37, 0x52, 0x0d, 0xa6, 0x50, 0x63,
0x2d, 0x35, 0x85, 0x3b, 0xf5, 0x91, 0xb3, 0x6b, 0xb4, 0x28, 0x63, 0x0a, 0x4d, 0x87, 0xc4, 0xdc
};

uint8_t output[64] = {0};
if (rs_spend_action_hash(&sk_bytes, plan, output, sizeof(output)) != parser_ok) {
if (rs_spend_action_hash(&sk_bytes, plan, (uint8_t *)output, 64) != 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");
print_buffer_interface((uint8_t *)output, 64, "spend action hash");

return parser_ok;
}
Loading

0 comments on commit 80762e0

Please sign in to comment.