Skip to content

Commit

Permalink
some work on c
Browse files Browse the repository at this point in the history
  • Loading branch information
chcmedeiros committed Sep 25, 2024
1 parent bf43a4b commit 3764710
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 235 deletions.
116 changes: 116 additions & 0 deletions app/rust/src/parser/note.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use core::{mem::MaybeUninit, ptr::addr_of_mut};

use arrayref::array_ref;
use jubjub::{AffinePoint, Scalar};
use nom::{bytes::complete::take, number::complete::le_u64};

use crate::{
crypto::{decrypt, read_scalar},
ironfish::{errors::IronfishError, public_address::PublicAddress},
parser::AssetIdentifier,
parser::FromBytes,
};

use super::{memo::Memo, ParserError, ENCRYPTED_NOTE_SIZE, MAC_SIZE};

/// A note (think bank note) represents a value in the owner's "account".
/// When spending, proof that the note exists in the tree needs to be provided,
/// along with a nullifier key that is made public so the owner cannot attempt
/// to spend that note again.447903
///
/// When receiving funds, a new note needs to be created for the new owner
/// to hold those funds.
pub struct Note {
/// Asset identifier the note is associated with
pub(crate) asset_id: AssetIdentifier,

/// A public address for the owner of the note.
pub(crate) owner: PublicAddress,

/// Value this note represents.
pub(crate) value: u64,

/// A random value generated when the note is constructed.
/// This helps create zero knowledge around the note,
/// allowing the owner to prove they have the note without revealing
/// anything else about it.
pub(crate) randomness: jubjub::Fr,

/// Arbitrary note the spender can supply when constructing a spend so the
/// receiver has some record from whence it came.
/// Note: While this is encrypted with the output, it is not encoded into
/// the proof in any way.
pub(crate) memo: Memo,

/// A public address for the sender of the note.
pub(crate) sender: PublicAddress,
}

impl Note {
/// Create a note from its encrypted representation, given the spender's
/// view key.
///
/// The note is stored on the [`crate::outputs::OutputDescription`] in
/// encrypted form. The spender encrypts it when they construct the output
/// using a shared secret derived from the owner's public key.
///
/// This function allows the owner to decrypt the note using the derived
/// shared secret and their own view key.
#[inline(never)]
pub(crate) fn from_spender_encrypted(
// public_address: SubgroupPoint,
public_address: AffinePoint,
shared_secret: &[u8; 32],
encrypted_bytes: &[u8; ENCRYPTED_NOTE_SIZE + MAC_SIZE],
) -> Result<Self, IronfishError> {
let mut this = MaybeUninit::uninit();
Note::decrypt_note_parts(shared_secret, encrypted_bytes, &mut this)
.map_err(|_| IronfishError::FailedXChaCha20Poly1305Decryption)?;

let owner = PublicAddress(public_address);

let out = this.as_mut_ptr();
unsafe {
addr_of_mut!((*out).owner).write(owner);
}

Ok(unsafe { this.assume_init() })
}

#[inline(never)]
fn decrypt_note_parts(
shared_secret: &[u8; 32],
encrypted_bytes: &[u8; ENCRYPTED_NOTE_SIZE + MAC_SIZE],
out: &mut MaybeUninit<Self>,
) -> Result<(), ParserError> {
let out = out.as_mut_ptr();

let plaintext_bytes: [u8; ENCRYPTED_NOTE_SIZE] =
decrypt(shared_secret, encrypted_bytes).map_err(|_| ParserError::UnexpectedError)?;

// Fr
let (rem, randomness) = read_scalar(&plaintext_bytes[..])?;

let (rem, value) = le_u64(rem)?;

// Memo
let memo = unsafe { &mut *addr_of_mut!((*out).memo).cast() };
let rem = Memo::from_bytes_into(rem, memo)?;

// Asset Identifier
let asset_id = unsafe { &mut *addr_of_mut!((*out).asset_id).cast() };
let rem = AssetIdentifier::from_bytes_into(rem, asset_id)?;
let asset_id = unsafe { asset_id.assume_init() };

// PublicAddress
let sender = unsafe { &mut *addr_of_mut!((*out).sender).cast() };
let rem = PublicAddress::from_bytes_into(rem, sender)?;

unsafe {
addr_of_mut!((*out).randomness).write(randomness);
addr_of_mut!((*out).value).write(value);
}

Ok(())
}
}
3 changes: 3 additions & 0 deletions app/src/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ extern uint32_t hdPath[HDPATH_LEN_DEFAULT];
zxerr_t crypto_fillKeys(uint8_t *buffer, uint16_t bufferLen, key_kind_e requestedKey, uint16_t *cmdResponseLen);
zxerr_t crypto_sign(const uint8_t publickeyRandomness[32], const uint8_t txnHash[32], uint8_t *output, uint16_t outputLen);

#if defined(LEDGER_SPECIFIC)
zxerr_t crypto_generateSaplingKeys(uint8_t *output, uint16_t outputLen, key_kind_e requestedKey);
#endif
#ifdef __cplusplus
}
#endif
12 changes: 12 additions & 0 deletions app/src/crypto_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,15 @@ zxerr_t crypto_signRedjubjub(const uint8_t randomizedPrivateKey[KEY_LENGTH], con

return zxerr_ok;
}

#if defined(LEDGER_SPECIFIC)
parser_error_t crypto_get_ovk(uint8_t ovk[KEY_LENGTH]) {
uint8_t buffer[4 * KEY_LENGTH] = {0};

if (crypto_generateSaplingKeys(buffer, sizeof(buffer), ViewKeys) != zxerr_ok) {
return parser_unexpected_error;
}
memcpy(ovk, buffer + 3 * KEY_LENGTH, KEY_LENGTH);
return parser_ok;
}
#endif
3 changes: 2 additions & 1 deletion app/src/crypto_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ extern "C" {
#include <stdint.h>

#include "coin.h"
#include "crypto.h"
#include "keys_def.h"
#include "parser_common.h"
#include "zxerror.h"
Expand All @@ -44,7 +45,7 @@ parser_error_t convertKey(const uint8_t spendingKey[KEY_LENGTH], const uint8_t m
bool reduceWideByte);
parser_error_t generate_key(const uint8_t expandedKey[KEY_LENGTH], constant_key_t keyType, uint8_t output[KEY_LENGTH]);
parser_error_t computeIVK(const ak_t ak, const nk_t nk, ivk_t ivk);

parser_error_t crypto_get_ovk(uint8_t ovk[KEY_LENGTH]);
parser_error_t transaction_signature_hash(parser_tx_t *txObj, uint8_t output[HASH_LEN]);
zxerr_t crypto_signRedjubjub(const uint8_t randomizedPrivateKey[KEY_LENGTH], const uint8_t rng[RNG_LEN],
const uint8_t transactionHash[HASH_LEN], uint8_t output[REDJUBJUB_SIGNATURE_LEN]);
Expand Down
50 changes: 35 additions & 15 deletions app/src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "crypto.h"
#include "parser_common.h"
#include "parser_impl.h"
#include "parser_utils.h"

parser_error_t parser_init_context(parser_context_t *ctx, const uint8_t *buffer, uint16_t bufferSize) {
ctx->offset = 0;
Expand Down Expand Up @@ -64,7 +65,10 @@ parser_error_t parser_validate(parser_context_t *ctx) {

parser_error_t parser_getNumItems(const parser_context_t *ctx, uint8_t *num_items) {
UNUSED(ctx);
*num_items = 5;

// Txversion + (ownner + amount + asset id) * n_output + fee + expiration
*num_items = 1 + ctx->tx_obj->outputs.elements * 3 + 2;

if (*num_items == 0) {
return parser_unexpected_number_items;
}
Expand All @@ -85,6 +89,7 @@ static parser_error_t checkSanity(uint8_t numItems, uint8_t displayIdx) {
return parser_ok;
}

uint8_t out_idx = 0;
parser_error_t parser_getItem(const parser_context_t *ctx, uint8_t displayIdx, char *outKey, uint16_t outKeyLen,
char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) {
UNUSED(pageIdx);
Expand All @@ -96,29 +101,44 @@ parser_error_t parser_getItem(const parser_context_t *ctx, uint8_t displayIdx, c
CHECK_ERROR(checkSanity(numItems, displayIdx));
cleanOutput(outKey, outKeyLen, outVal, outValLen);

switch (displayIdx) {
uint64_t total_out_elements = ctx->tx_obj->outputs.elements * ELEMENTS_PER_OUTPUT;
uint8_t tmp_idx = displayIdx;

if (tmp_idx > 0 && tmp_idx <= total_out_elements) {
tmp_idx = (tmp_idx % ELEMENTS_PER_OUTPUT) + OUTPUT_ELEMENT_OFFSET;
if (tmp_idx == 2) {
out_idx++;
}
} else if (tmp_idx > total_out_elements) {
tmp_idx -= total_out_elements - ELEMENTS_PER_OUTPUT;
}

switch (tmp_idx) {
case 0:
snprintf(outKey, outKeyLen, "Spends");
snprintf(outVal, outValLen, "%d", (uint8_t)ctx->tx_obj->spends.elements);
snprintf(outKey, outKeyLen, "Tx Version");
snprintf(outVal, outValLen, "V%d", (uint8_t)ctx->tx_obj->transactionVersion);
return parser_ok;
case 1:
snprintf(outKey, outKeyLen, "Outputs");
snprintf(outVal, outValLen, "%d", (uint8_t)ctx->tx_obj->outputs.elements);
snprintf(outKey, outKeyLen, "Amount %d", out_idx - 1);
// snprintf(outVal, outValLen, "%d", (uint8_t)ctx->tx_obj->outputs.elements);
return parser_ok;
case 2:
snprintf(outKey, outKeyLen, "Mints");
snprintf(outVal, outValLen, "%d", (uint8_t)ctx->tx_obj->mints.elements);
snprintf(outKey, outKeyLen, "Owner %d", out_idx - 1);
// snprintf(outVal, outValLen, "%d", (uint8_t)ctx->tx_obj->mints.elements);
return parser_ok;
case 3:
snprintf(outKey, outKeyLen, "Burns");
snprintf(outVal, outValLen, "%d", (uint8_t)ctx->tx_obj->burns.elements);
snprintf(outKey, outKeyLen, "AssetID %d", out_idx - 1);
// snprintf(outVal, outValLen, "%d", (uint8_t)ctx->tx_obj->burns.elements);
return parser_ok;
case 4: {
snprintf(outKey, outKeyLen, "TxnHash");
pageStringHex(outVal, outValLen, (const char *)ctx->tx_obj->transactionHash,
sizeof(ctx->tx_obj->transactionHash), pageIdx, pageCount);
case 4:
snprintf(outKey, outKeyLen, "Fee");
return _toStringBalance(&ctx->tx_obj->fee, COIN_AMOUNT_DECIMAL_PLACES, "", COIN_TICKER, outVal, outValLen,
pageIdx, pageCount);
return parser_ok;
case 5:
snprintf(outKey, outKeyLen, "Expiration");
snprintf(outVal, outValLen, "%d", ctx->tx_obj->expiration);
return parser_ok;
}
default:
break;
}
Expand Down
10 changes: 10 additions & 0 deletions app/src/parser_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,15 @@ parser_error_t _read(parser_context_t *ctx, parser_tx_t *v) {
}

CHECK_ERROR(transaction_signature_hash(v, v->transactionHash));

#if defined(LEDGER_SPECIFIC)
CHECK_ERROR(crypto_get_ovk(v->ovk));
#else
// Testing OVK
uint8_t buffer[32] = {0x49, 0xba, 0xd8, 0x39, 0x5e, 0xf4, 0x48, 0xeb, 0x00, 0x48, 0xaf, 0x13, 0x2b, 0x5c, 0x94, 0x25,
0x79, 0x02, 0x47, 0x36, 0xd4, 0xc3, 0xcf, 0xd6, 0x85, 0xb2, 0x41, 0xb9, 0x94, 0xf8, 0xf8, 0xe5};
memcpy(v->ovk, buffer, sizeof(buffer));
#endif

return parser_ok;
}
2 changes: 2 additions & 0 deletions app/src/parser_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
extern "C" {
#endif

#define ELEMENTS_PER_OUTPUT 3
#define OUTPUT_ELEMENT_OFFSET 1
/**
* @brief Checks that there are at least SIZE bytes available in the buffer.
* @param CTX Context
Expand Down
1 change: 1 addition & 0 deletions app/src/parser_txdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ typedef struct {
bytes_t randomizedPublicKey; // redjubjub::PublicKey,
bytes_t publicKeyRandomness;

uint8_t ovk[32];
bytes_t bindingSignature;

// Not part of the incoming txn but it's used to compute signatures
Expand Down
42 changes: 42 additions & 0 deletions app/src/parser_utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*******************************************************************************
* (c) 2018 - 2024 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#include "parser_utils.h"

#include "coin.h"
#include "crypto_helper.h"
#include "zxformat.h"
#include "zxmacros.h"

parser_error_t _toStringBalance(int64_t *amount, uint8_t decimalPlaces, const char postfix[], const char prefix[],
char *outValue, uint16_t outValueLen, uint8_t pageIdx, uint8_t *pageCount) {
char bufferUI[200] = {0};
if (int64_to_str(bufferUI, sizeof(bufferUI), *amount) != NULL) {
return parser_unexpected_value;
}

if (intstr_to_fpstr_inplace(bufferUI, sizeof(bufferUI), decimalPlaces) == 0) {
return parser_unexpected_value;
}

if (z_str3join(bufferUI, sizeof(bufferUI), prefix, postfix) != zxerr_ok) {
return parser_unexpected_buffer_end;
}

number_inplace_trimming(bufferUI, 1);

pageString(outValue, outValueLen, bufferUI, pageIdx, pageCount);
return parser_ok;
}
31 changes: 31 additions & 0 deletions app/src/parser_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*******************************************************************************
* (c) 2018 - 2024 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#pragma once

#include "parser_common.h"
#include "parser_txdef.h"

#ifdef __cplusplus
extern "C" {
#endif

parser_error_t _toStringBalance(int64_t *amount, uint8_t decimalPlaces, const char postfix[], const char prefix[],
char *outValue, uint16_t outValueLen, uint8_t pageIdx, uint8_t *pageCount);

#ifdef __cplusplus
}

#endif
Loading

0 comments on commit 3764710

Please sign in to comment.