Skip to content

Commit

Permalink
wip - output hash
Browse files Browse the repository at this point in the history
  • Loading branch information
abenso committed Nov 14, 2024
1 parent 238b722 commit a7ad07b
Show file tree
Hide file tree
Showing 20 changed files with 306 additions and 257 deletions.
4 changes: 1 addition & 3 deletions app/rust/include/rslib.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ parser_error_t rs_compute_address(keys_t *keys, uint32_t account, uint8_t *rando
// use to compute the full-viewing key
parser_error_t rs_compute_keys(keys_t *keys);

// use to compute the full-viewing key
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_key_bytes_t *sk, spend_plan_t *plan, uint8_t *output, size_t output_len);
parser_error_t rs_output_action_hash(spend_key_bytes_t *sk, output_plan_t *plan, bytes_t *memo_key, 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
2 changes: 0 additions & 2 deletions app/rust/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ mod precision;
mod tx_parameters;
mod bytes;

pub use address::Address;
pub use clue_plan::CluePlan;
pub use curve_fields::{Fq, Fr};
pub use error::ParserError;
pub use object_list::ObjectList;
Expand Down
37 changes: 0 additions & 37 deletions app/rust/src/parser/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,43 +40,6 @@ use nom::bytes::complete::take;
use super::bytes::BytesC;
use crate::{utils::varint, FromBytes, ParserError};

// TODO! It is unclear if this address is a raw-address to which F4Jumble and bech32 encoding
// has been applied as well, if that is the case, its length is not necessarly ADDRESS_LEN
// it could be more due to bech32 hrp and checksum.

#[cfg_attr(test, derive(Debug))]
#[derive(Copy, PartialEq, Eq, Clone)]
pub struct Address<'a>(&'a [u8]);

impl<'b> FromBytes<'b> for Address<'b> {
fn from_bytes_into(
input: &'b [u8],
out: &mut MaybeUninit<Self>,
) -> Result<&'b [u8], nom::Err<ParserError>> {
let out = out.as_mut_ptr();

let (input, _) = varint(input)?; // Parse field number and wire type
let (input, len) = varint(input)?; // Parse length
//
if len as usize == 0 {
return Err(ParserError::InvalidLength.into());
}

// TODO: not necessarly equal but less than
// if len as usize != ADDRESS_LEN {
// return Err(ParserError::InvalidLength.into());
// }

let (input, bytes) = take(len as usize)(input)?;

unsafe {
addr_of_mut!((*out).0).write(bytes);
}

Ok(input)
}
}

#[repr(C)]
#[derive(Clone, PartialEq, Default)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
Expand Down
42 changes: 0 additions & 42 deletions app/rust/src/parser/clue_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,50 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
use core::ptr::addr_of_mut;

use crate::{
utils::{read_fixed_bytes, varint},
FromBytes,
};

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

use super::{Address, Precision};

#[cfg_attr(test, derive(Debug))]
#[derive(Copy, Clone)]
pub struct CluePlan<'a> {
pub address: Address<'a>,
pub rseed: &'a [u8; 32],
pub precision: Precision,
}

impl<'a> FromBytes<'a> for CluePlan<'a> {
fn from_bytes_into(
input: &'a [u8],
out: &mut core::mem::MaybeUninit<Self>,
) -> Result<&'a [u8], nom::Err<crate::ParserError>> {
let out = out.as_mut_ptr();

let addr = unsafe { &mut *addr_of_mut!((*out).address).cast() };
let rem = Address::from_bytes_into(input, addr)?;

let (rem, rseed) = read_fixed_bytes::<32>(rem)?;

let (rem, precision) = varint(rem)?;

let precision = Precision::try_from(precision)?;

unsafe {
addr_of_mut!((*out).rseed).write(rseed);
addr_of_mut!((*out).precision).write(precision);
}

Ok(rem)
}
}

#[repr(C)]
#[derive(Clone, Default)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
Expand Down
37 changes: 35 additions & 2 deletions app/rust/src/parser/note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ use crate::address::Address;
use crate::parser::{
address::AddressC,
bytes::BytesC,
plans::{rseed::Rseed, value::{Value, ValueC}},
plans::{rseed::Rseed, value::{Value, ValueC}, symmetric::OvkWrappedKey},
};

use crate::ParserError;
use decaf377::Fq;
use decaf377::{Fq, Fr};

pub struct Note {
/// The typed value recorded by this note.
Expand Down Expand Up @@ -50,6 +51,16 @@ impl TryFrom<NoteC> for Note {
}

impl Note {
pub fn from_parts(address: Address, value: Value, rseed: Rseed) -> Result<Self, ParserError> {
Ok(Note {
value,
rseed,
address: address.clone(),
transmission_key_s: Fq::from_bytes_checked(&address.transmission_key().0)
.map_err(|_| ParserError::InvalidFvk)?,
})
}

pub fn commit(&self) -> Result<Fq, ParserError> {
let commit = poseidon377::hash_6(
&Self::notecommit_domain_sep(),
Expand All @@ -65,6 +76,24 @@ impl Note {
Ok(commit)
}

// /// Generate encrypted outgoing cipher key for use with this note.
// pub fn encrypt_key(&self, ovk: &OutgoingViewingKey, cv: balance::Commitment) -> OvkWrappedKey {
// let esk = self.ephemeral_secret_key();
// let epk = esk.diversified_public(&self.diversified_generator());
// let ock = OutgoingCipherKey::derive(ovk, cv, self.commit(), &epk);
// let shared_secret = esk
// .key_agreement_with(self.transmission_key())
// .expect("key agreement succeeded");

// let encryption_result = ock.encrypt(shared_secret.0.to_vec(), PayloadKind::Note);

// OvkWrappedKey(
// encryption_result
// .try_into()
// .expect("OVK encryption result fits in ciphertext len"),
// )
// }

pub fn note_blinding(&self) -> Result<Fq, ParserError> {
let rseed = self.rseed.derive_note_blinding()?;
Ok(rseed)
Expand All @@ -83,4 +112,8 @@ impl Note {
pub fn notecommit_domain_sep() -> Fq {
Fq::from_le_bytes_mod_order(blake2b_simd::blake2b(b"penumbra.notecommit").as_bytes())
}

pub fn ephemeral_secret_key(&self) -> Result<Fr, ParserError> {
self.rseed.derive_esk()
}
}
114 changes: 103 additions & 11 deletions app/rust/src/parser/plans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
use self::{detection::DetectionDataPlanC, memo::MemoPlanC, spend::SpendPlanC, action::ActionsHashC};
use self::{detection::DetectionDataPlanC, memo::MemoPlanC, spend::SpendPlanC, action::ActionsHashC, output::OutputPlanC};
use crate::keys::spend_key::SpendKeyBytes;
use crate::effect_hash::EffectHash;

use crate::parser::bytes::BytesC;
pub mod action;
pub mod amount;
pub mod balance;
Expand All @@ -30,6 +30,7 @@ pub mod rseed;
pub mod spend;
pub mod symmetric;
pub mod value;
pub mod output;

use super::tx_parameters::TransactionParametersC;
use crate::constants::ACTION_DATA_QTY;
Expand Down Expand Up @@ -66,15 +67,6 @@ impl TransactionPlanC {
}
}

#[no_mangle]
/// Use to compute an address and write it back into output
/// argument.
pub unsafe extern "C" fn rs_compute_effect_hash() -> u32 {
crate::zlog("rs_compute_effect_hash\x00");

ParserError::Ok as u32
}

#[no_mangle]
/// Use to compute an address and write it back into output
/// argument.
Expand Down Expand Up @@ -128,6 +120,40 @@ pub unsafe extern "C" fn rs_spend_action_hash(
ParserError::Ok as u32
}

#[no_mangle]
/// Use to compute an address and write it back into output
/// argument.
pub unsafe extern "C" fn rs_output_action_hash(
sk: &SpendKeyBytes,
plan: &OutputPlanC,
memo_key: &BytesC,
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;
}

let fvk: crate::keys::FullViewingKey = sk.fvk().unwrap();
let memo_key_bytes = match memo_key.get_bytes() {
Ok(bytes) => bytes,
Err(_) => &[0u8; 32],
};

let body_hash_bytes = plan.effect_hash(&fvk, &memo_key_bytes);

if let Ok(body_hash_bytes) = body_hash_bytes {
let body_hash_array = body_hash_bytes.as_array();
let copy_len: usize = core::cmp::min(output.len(), body_hash_array.len());
output[..copy_len].copy_from_slice(&body_hash_array[..copy_len]);
}

ParserError::Ok as u32
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -312,4 +338,70 @@ mod tests {
panic!("spend_action_hash is not Ok");
}
}

#[test]
fn test_output_action_hash() {
// Create dummy ActionC
let dummy_amount = AmountC {
lo: 535446340456032950,
hi: 0,
};

let asset_id_bytes =
hex::decode("29ea9c2f3371f6a487e7e95c247041f4a356f983eb064e5d2b3bcf322ca96a10")
.unwrap();
let dummy_asset_id = IdC {
inner: BytesC::from_slice(&asset_id_bytes),
};

let dummy_value = ValueC {
amount: dummy_amount,
asset_id: dummy_asset_id,
};

let dummy_address_inner = hex::decode("f72c37238af64e9c8517e4cac09a43a99cee8aa4cb7e2c20419f55dd06f0884bfbfa5202b88852edda3d54273de22c4ef40edb4bc54c0c14fd0b5475d33433d0bd9793c8670795eb822b94c3cbb1a412").unwrap();
let dummy_address = AddressC {
inner: BytesC::from_slice(&dummy_address_inner),
alt_bech32m: BytesC::default(),
};

let dummy_rseed_bytes =
hex::decode("28fc41cb8153082b110af95a0eb013a25c4248bdc25ab2f7c7e0041258d01c42")
.unwrap();

let dummy_value_blinding_bytes =
hex::decode("4c19474a9edb1933a643ae2b2648131061b95b25fb6ffeafb3e53ccacf8fe700")
.unwrap();
let dummy_proof_blinding_r_bytes =
hex::decode("825b816bfb539eb34a7933f362ab7b9a3fe128074a1603a5c43afb125d44e002")
.unwrap();
let dummy_proof_blinding_s_bytes =
hex::decode("86ae5038cfd758ee6520792a143ea401ef8e2afbc70f65c0b6e1d58b3492b211")
.unwrap();

let dummy_action = OutputPlanC {
value: dummy_value,
dest_address: dummy_address,
rseed: BytesC::from_slice(&dummy_rseed_bytes),
value_blinding: BytesC::from_slice(&dummy_value_blinding_bytes),
proof_blinding_r: BytesC::from_slice(&dummy_proof_blinding_r_bytes),
proof_blinding_s: BytesC::from_slice(&dummy_proof_blinding_s_bytes),
};

let spend_key = SpendKeyBytes::from([
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,
]);
let fvk = spend_key.fvk().unwrap();

let output_action_hash = dummy_action.effect_hash(&fvk, &[0u8; 32]);
let expected_hash = "27e17cfb588ad724519232789f2cfdb724b3072ac2db6e411b3504eb8e05ab1d26545495dc9e1b8a59ad049706102b2c58f23aba6a346f8ff4b595ce4e1d8f4c";
if let Ok(output_action_hash_bytes) = output_action_hash {
let computed_hash = hex::encode(output_action_hash_bytes.as_array());
assert_eq!(computed_hash, expected_hash);
} else {
panic!("output_action_hash is not Ok");
}
}
}
34 changes: 0 additions & 34 deletions app/rust/src/parser/plans/detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,8 @@
use crate::address::Address;
use crate::constants::DETECTION_DATA_QTY;
use crate::effect_hash::{create_personalized_state, EffectHash};
use crate::keys::clue_key::Clue;
use crate::parser::clue_plan::CluePlanC;
use crate::ParserError;
use core::{mem::MaybeUninit, ptr::addr_of_mut};

use crate::{
parser::{CluePlan, ObjectList},
utils::varint,
FromBytes,
};

#[cfg_attr(test, derive(Debug))]
#[derive(Copy, PartialEq, Eq, Clone)]
pub struct DetectionDataPlan<'a>(ObjectList<'a, CluePlan<'a>>);

impl<'a> FromBytes<'a> for DetectionDataPlan<'a> {
fn from_bytes_into(
input: &'a [u8],
out: &mut core::mem::MaybeUninit<Self>,
) -> Result<&'a [u8], nom::Err<crate::ParserError>> {
let out = out.as_mut_ptr();

let (rem, size) = varint(input)?;

let detection: &mut MaybeUninit<ObjectList<'a, CluePlan<'a>>> =
unsafe { &mut *addr_of_mut!((*out).0).cast() };

let rem = ObjectList::new_into_with_len(rem, detection, size as usize)?;

Ok(rem)
}
}

pub struct DetectionData {
pub fmd_clues: [Clue; DETECTION_DATA_QTY],
}

#[repr(C)]
#[cfg_attr(any(feature = "derive-debug", test), derive(Debug))]
Expand Down
4 changes: 4 additions & 0 deletions app/rust/src/parser/plans/memo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ impl MemoPlanC {
&& self.plaintext.text.len == 0
&& self.key.len == 0
}

pub fn get_memo_key(&self) -> Result<&[u8], ParserError> {
self.key.get_bytes()
}
}

pub struct MemoCiphertext(pub [u8; MEMO_CIPHERTEXT_LEN_BYTES]);
Expand Down
Loading

0 comments on commit a7ad07b

Please sign in to comment.