mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-07 22:04:03 -05:00
sdk/crypto: Extend MerkleNode with incrementalmerkletree traits.
This commit is contained in:
@@ -17,9 +17,7 @@ overflow-checks = true
|
||||
|
||||
[dependencies]
|
||||
darkfi-sdk = { path = "../../src/sdk" }
|
||||
# TODO: serial/crypto feature that enables all this stuff
|
||||
darkfi = { path = "../../", features = ["serial", "pasta_curves", "incrementalmerkletree"] }
|
||||
incrementalmerkletree = "0.3.0"
|
||||
darkfi-serial = { path = "../../src/serial", features = ["crypto"] }
|
||||
|
||||
# TODO: Dummy getrandomndom = { version = "0.2.7", features = ["custom"] }
|
||||
# Dummy getrandom
|
||||
getrandom = { version = "0.2.7", features = ["custom"] }
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use darkfi::serial::{deserialize, SerialDecodable, SerialEncodable};
|
||||
use darkfi_sdk::{
|
||||
crypto::{MerkleNode, Nullifier},
|
||||
entrypoint,
|
||||
error::ContractResult,
|
||||
incrementalmerkletree::bridgetree::BridgeTree,
|
||||
};
|
||||
use incrementalmerkletree::bridgetree::BridgeTree;
|
||||
use darkfi_serial::{deserialize, SerialDecodable, SerialEncodable};
|
||||
|
||||
/// Available functions for this contract.
|
||||
/// We identify them with the first byte passed in through the payload.
|
||||
|
||||
@@ -4,8 +4,9 @@ use darkfi_sdk::{
|
||||
MerkleNode,
|
||||
},
|
||||
error::{ContractError, ContractResult},
|
||||
incrementalmerkletree::Tree,
|
||||
msg,
|
||||
pasta::pallas,
|
||||
pasta::{group::Group, pallas},
|
||||
state::Verification,
|
||||
};
|
||||
|
||||
@@ -68,6 +69,8 @@ pub fn exec(state: &mut State, tx: Transaction) -> ContractResult {
|
||||
state.tree.append(&MerkleNode::from(output.coin.inner()));
|
||||
state.merkle_roots.push(state.tree.root(0).unwrap());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// `Verification` could be a generic trait we implement for doing
|
||||
|
||||
@@ -27,6 +27,10 @@ pasta_curves = "0.4.0"
|
||||
incrementalmerkletree = "0.3.0"
|
||||
halo2_gadgets = "0.2.0"
|
||||
|
||||
# Misc
|
||||
lazy_static = "1.4.0"
|
||||
subtle = "2.4.1"
|
||||
|
||||
[dev-dependencies]
|
||||
halo2_proofs = "0.2.0"
|
||||
rand = "0.8.5"
|
||||
|
||||
@@ -1,8 +1,34 @@
|
||||
use core::str::FromStr;
|
||||
use std::io;
|
||||
use std::{io, iter};
|
||||
|
||||
use darkfi_serial::{SerialDecodable, SerialEncodable};
|
||||
use pasta_curves::{group::ff::PrimeField, pallas};
|
||||
use halo2_gadgets::sinsemilla::primitives::HashDomain;
|
||||
use incrementalmerkletree::{Altitude, Hashable};
|
||||
use lazy_static::lazy_static;
|
||||
use pasta_curves::{
|
||||
group::ff::{PrimeField, PrimeFieldBits},
|
||||
pallas,
|
||||
};
|
||||
use subtle::{Choice, ConditionallySelectable};
|
||||
|
||||
use crate::crypto::constants::{
|
||||
sinsemilla::{i2lebsp_k, L_ORCHARD_MERKLE, MERKLE_CRH_PERSONALIZATION},
|
||||
MERKLE_DEPTH_ORCHARD,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
static ref UNCOMMITTED_ORCHARD: pallas::Base = pallas::Base::from(2);
|
||||
static ref EMPTY_ROOTS: Vec<MerkleNode> = {
|
||||
iter::empty()
|
||||
.chain(Some(MerkleNode::empty_leaf()))
|
||||
.chain((0..MERKLE_DEPTH_ORCHARD).scan(MerkleNode::empty_leaf(), |state, l| {
|
||||
let l = l as u8;
|
||||
*state = MerkleNode::combine(l.into(), state, state);
|
||||
Some(*state)
|
||||
}))
|
||||
.collect()
|
||||
};
|
||||
}
|
||||
|
||||
/// The `MerkleNode` is represented as a base field element.
|
||||
#[repr(C)]
|
||||
@@ -58,3 +84,46 @@ impl FromStr for MerkleNode {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "Invalid bytes for MerkleNode"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ConditionallySelectable for MerkleNode {
|
||||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
||||
Self(pallas::Base::conditional_select(&a.0, &b.0, choice))
|
||||
}
|
||||
}
|
||||
|
||||
impl Hashable for MerkleNode {
|
||||
fn empty_leaf() -> Self {
|
||||
Self(*UNCOMMITTED_ORCHARD)
|
||||
}
|
||||
|
||||
/// Implements `MerkleCRH^Orchard` as defined in
|
||||
/// <https://zips.z.cash/protocol/protocol.pdf#orchardmerklecrh>
|
||||
///
|
||||
/// The layer with 2^n nodes is called "layer n":
|
||||
/// - leaves are at layer MERKLE_DEPTH_ORCHARD = 32;
|
||||
/// - the root is at layer 0.
|
||||
/// `l` is MERKLE_DEPTH_ORCHARD - layer - 1.
|
||||
/// - when hashing two leaves, we produce a node on the layer
|
||||
/// above the the leaves, i.e. layer = 31, l = 0
|
||||
/// - when hashing to the final root, we produce the anchor
|
||||
/// with layer = 0, l = 31.
|
||||
fn combine(altitude: Altitude, left: &Self, right: &Self) -> Self {
|
||||
// MerkleCRH Sinsemilla hash domain.
|
||||
let domain = HashDomain::new(MERKLE_CRH_PERSONALIZATION);
|
||||
|
||||
Self(
|
||||
domain
|
||||
.hash(
|
||||
iter::empty()
|
||||
.chain(i2lebsp_k(altitude.into()).iter().copied())
|
||||
.chain(left.inner().to_le_bits().iter().by_vals().take(L_ORCHARD_MERKLE))
|
||||
.chain(right.inner().to_le_bits().iter().by_vals().take(L_ORCHARD_MERKLE)),
|
||||
)
|
||||
.unwrap_or(pallas::Base::zero()),
|
||||
)
|
||||
}
|
||||
|
||||
fn empty_root(altitude: Altitude) -> Self {
|
||||
EMPTY_ROOTS[<usize>::from(altitude)]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use pasta_curves::{group::ff::PrimeField, pallas};
|
||||
|
||||
/// The `Nullifier` is represented as a base field element.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, SerialEncodable, SerialDecodable)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
pub struct Nullifier(pallas::Base);
|
||||
|
||||
impl Nullifier {
|
||||
|
||||
@@ -14,9 +14,9 @@ macro_rules! entrypoint {
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
|
||||
let instruction_data = $crate::entrypoint::deserialize(input);
|
||||
let (state, instruction_data) = $crate::entrypoint::deserialize(input);
|
||||
|
||||
match $process_instruction(&instruction_data) {
|
||||
match $process_instruction(&state, &instruction_data) {
|
||||
Ok(()) => $crate::entrypoint::SUCCESS,
|
||||
Err(e) => e.into(),
|
||||
}
|
||||
@@ -26,15 +26,19 @@ macro_rules! entrypoint {
|
||||
|
||||
/// Deserialize a given payload in `entrypoint`
|
||||
/// # Safety
|
||||
pub unsafe fn deserialize<'a>(input: *mut u8) -> &'a [u8] {
|
||||
pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a [u8], &'a [u8]) {
|
||||
let mut offset: usize = 0;
|
||||
|
||||
let state_data_len = *(input.add(offset) as *const u64) as usize;
|
||||
offset += size_of::<u64>();
|
||||
let state_data = { from_raw_parts(input.add(offset), state_data_len) };
|
||||
offset += state_data_len;
|
||||
|
||||
let instruction_data_len = *(input.add(offset) as *const u64) as usize;
|
||||
offset += size_of::<u64>();
|
||||
|
||||
let instruction_data = { from_raw_parts(input.add(offset), instruction_data_len) };
|
||||
|
||||
instruction_data
|
||||
(state_data, instruction_data)
|
||||
}
|
||||
|
||||
/// Allocate a piece of memory in the wasm VM
|
||||
|
||||
Reference in New Issue
Block a user