Skip to content

Commit

Permalink
refactor(HashLock): Factor out related functions and structs
Browse files Browse the repository at this point in the history
 - Add dedicated struct for variant `RawHashLock` on `SpendingKey`.
   Variants of `SpendingKey` are now symmetric in the sense that all
   of them have a single unnamed field of a dedicated like-named
   struct.
 - Add new file `hash_lock.rs` for said struct `HashLock`. Note that
   this module must be marked `pub` because `SpendingKey`s are used
   in `neptune-dashboard`.
 - Move methods related to hash locks to `hash_lock.rs`.
 - Add method `guesser_spending_key` on `WalletSecret`, anticipating
   use in the guessing pipeline.
  • Loading branch information
aszepieniec committed Jan 31, 2025
1 parent 55142de commit adee45c
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 74 deletions.
7 changes: 3 additions & 4 deletions src/models/blockchain/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ use validity::block_primitive_witness::BlockPrimitiveWitness;
use validity::block_program::BlockProgram;
use validity::block_proof_witness::BlockProofWitness;

use super::transaction::lock_script::LockScript;
use super::transaction::transaction_kernel::TransactionKernelProxy;
use super::transaction::utxo::Utxo;
use super::transaction::Transaction;
Expand All @@ -58,6 +57,7 @@ use crate::models::proof_abstractions::tasm::program::TritonVmProofJobOptions;
use crate::models::proof_abstractions::timestamp::Timestamp;
use crate::models::proof_abstractions::verifier::verify;
use crate::models::proof_abstractions::SecretWitness;
use crate::models::state::wallet::address::hash_lock::HashLock;
use crate::models::state::wallet::address::ReceivingAddress;
use crate::models::state::wallet::expected_utxo::ExpectedUtxo;
use crate::models::state::wallet::expected_utxo::UtxoNotifier;
Expand Down Expand Up @@ -934,7 +934,7 @@ impl Block {
}

let lock = self.header().guesser_digest;
let lock_script = LockScript::hash_lock_from_after_image(lock);
let lock_script = HashLock::lock_script_from_after_image(lock);

let total_guesser_reward = self.total_guesser_reward();
let mut value_locked = total_guesser_reward;
Expand Down Expand Up @@ -1021,7 +1021,6 @@ pub(crate) mod block_tests {
use crate::config_models::network::Network;
use crate::database::storage::storage_schema::SimpleRustyStorage;
use crate::database::NeptuneLevelDb;
use crate::models::blockchain::transaction::lock_script::LockScriptAndWitness;
use crate::models::state::tx_proving_capability::TxProvingCapability;
use crate::models::state::wallet::transaction_output::TxOutput;
use crate::models::state::wallet::utxo_notification::UtxoNotificationMedium;
Expand Down Expand Up @@ -1602,7 +1601,7 @@ pub(crate) mod block_tests {

let guesser_fee_utxos = block.guesser_fee_utxos();

let lock_script_and_witness = LockScriptAndWitness::hash_lock_from_preimage(preimage);
let lock_script_and_witness = HashLock::from(preimage).lock_script_and_witness();
assert!(guesser_fee_utxos
.iter()
.all(|guesser_fee_utxo| lock_script_and_witness.can_unlock(guesser_fee_utxo)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pub(crate) mod test {
use crate::models::blockchain::transaction::TransactionProof;
use crate::models::blockchain::type_scripts::native_currency_amount::NativeCurrencyAmount;
use crate::models::proof_abstractions::timestamp::Timestamp;
use crate::models::state::wallet::address::hash_lock::HashLock;
use crate::util_types::mutator_set::ms_membership_proof::MsMembershipProof;
use crate::util_types::mutator_set::msa_and_records::MsaAndRecords;
use crate::util_types::mutator_set::removal_record::RemovalRecord;
Expand Down Expand Up @@ -259,7 +260,8 @@ pub(crate) mod test {
let lock_scripts_and_witnesses = hash_lock_keys
.iter()
.copied()
.map(LockScriptAndWitness::hash_lock_from_preimage)
.map(HashLock::from)
.map(|hl| hl.lock_script_and_witness())
.collect_vec();
let lock_script_hashes = lock_scripts_and_witnesses
.iter()
Expand Down
43 changes: 0 additions & 43 deletions src/models/blockchain/transaction/lock_script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::collections::HashMap;
#[cfg(any(test, feature = "arbitrary-impls"))]
use arbitrary::Arbitrary;
use get_size2::GetSize;
use itertools::Itertools;
use rand::thread_rng;
use rand::Rng;
use serde::Deserialize;
Expand Down Expand Up @@ -54,38 +53,6 @@ impl LockScript {
}
}

/// Generate a lock script that verifies knowledge of a hash preimage.
///
/// Satisfaction of this lock script establishes the UTXO owner's assent to
/// the transaction.
pub(crate) fn hash_lock_from_preimage(preimage: Digest) -> Self {
Self::hash_lock_from_after_image(preimage.hash())
}

/// Generate a lock script that verifies knowledge of a hash preimage.
///
/// Satisfaction of this lock script establishes the UTXO owner's assent to
/// the transaction.
pub(crate) fn hash_lock_from_after_image(after_image: Digest) -> Self {
let push_spending_lock_digest_to_stack = after_image
.values()
.iter()
.rev()
.map(|elem| triton_instr!(push elem.value()))
.collect_vec();

let instructions = triton_asm!(
divine 5
hash
{&push_spending_lock_digest_to_stack}
assert_vector
read_io 5
halt
);

instructions.into()
}

pub fn hash(&self) -> Digest {
self.program.hash()
}
Expand Down Expand Up @@ -151,16 +118,6 @@ impl LockScriptAndWitness {
}
}

/// Generate a lock script and a witness for a simple standard
/// proof-of-preimage-knowledge lock script.
pub(crate) fn hash_lock_from_preimage(preimage: Digest) -> Self {
let lock_script = LockScript::hash_lock_from_after_image(preimage.hash());
LockScriptAndWitness::new_with_nondeterminism(
lock_script.program,
NonDeterminism::new(preimage.reversed().values()),
)
}

pub fn nondeterminism(&self) -> NonDeterminism {
NonDeterminism::new(self.nd_tokens.clone())
.with_digests(self.nd_digests.clone())
Expand Down
10 changes: 5 additions & 5 deletions src/models/blockchain/transaction/primitive_witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,6 @@ mod test {

use super::*;
use crate::models::blockchain::block::MINING_REWARD_TIME_LOCK_PERIOD;
use crate::models::blockchain::transaction::lock_script::LockScript;
use crate::models::blockchain::transaction::PublicAnnouncement;
use crate::models::blockchain::transaction::TransactionProof;
use crate::models::blockchain::type_scripts::native_currency::NativeCurrency;
Expand All @@ -958,6 +957,7 @@ mod test {
use crate::models::proof_abstractions::mast_hash::MastHash;
use crate::models::proof_abstractions::tasm::program::ConsensusProgram;
use crate::models::proof_abstractions::timestamp::Timestamp;
use crate::models::state::wallet::address::hash_lock::HashLock;
use crate::util_types::mutator_set::commit;
use crate::util_types::mutator_set::msa_and_records::MsaAndRecords;
use crate::util_types::mutator_set::removal_record::RemovalRecord;
Expand Down Expand Up @@ -1485,7 +1485,7 @@ mod test {
timelocked_amount.div_two();
assert!(total_amount >= timelocked_amount);
let timelocked_output = Utxo::new_native_currency(
LockScript::hash_lock_from_after_image(output_seeds[0]),
HashLock::lock_script_from_after_image(output_seeds[0]),
timelocked_amount,
)
.with_time_lock(timestamp + MINING_REWARD_TIME_LOCK_PERIOD);
Expand All @@ -1494,7 +1494,7 @@ mod test {
total_amount.checked_sub(&timelocked_amount).unwrap();
liquid_amount = liquid_amount.checked_add(&(-fee)).unwrap();
let liquid_output = Utxo::new_native_currency(
LockScript::hash_lock_from_after_image(output_seeds[0]),
HashLock::lock_script_from_after_image(output_seeds[0]),
liquid_amount,
);

Expand All @@ -1513,7 +1513,7 @@ mod test {
first_amount.div_two();
}
let first_output = Utxo::new_native_currency(
LockScript::hash_lock_from_after_image(output_seeds[0]),
HashLock::lock_script_from_after_image(output_seeds[0]),
first_amount,
)
.with_time_lock(timestamp + MINING_REWARD_TIME_LOCK_PERIOD);
Expand All @@ -1524,7 +1524,7 @@ mod test {
.checked_sub(&fee)
.unwrap();
let second_output = Utxo::new_native_currency(
LockScript::hash_lock_from_after_image(output_seeds[1]),
HashLock::lock_script_from_after_image(output_seeds[1]),
second_amount,
);

Expand Down
3 changes: 2 additions & 1 deletion src/models/blockchain/transaction/utxo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::models::blockchain::type_scripts::native_currency_amount::NativeCurre
use crate::models::blockchain::type_scripts::time_lock::TimeLock;
use crate::models::proof_abstractions::tasm::program::ConsensusProgram;
use crate::models::proof_abstractions::timestamp::Timestamp;
use crate::models::state::wallet::address::hash_lock::HashLock;
use crate::prelude::twenty_first;

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, BFieldCodec, TasmObject)]
Expand Down Expand Up @@ -132,7 +133,7 @@ impl Utxo {
/// Returns true iff this UTXO is a lock script with the preimage provided
/// as input argument.
pub(crate) fn is_lockscript_with_preimage(&self, preimage: Digest) -> bool {
self.lock_script_hash == LockScript::hash_lock_from_preimage(preimage).hash()
self.lock_script_hash == HashLock::from(preimage).lock_script_hash()
}

pub fn new_native_currency(lock_script: LockScript, amount: NativeCurrencyAmount) -> Self {
Expand Down
5 changes: 2 additions & 3 deletions src/models/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1752,6 +1752,7 @@ mod global_state_tests {
use crate::config_models::network::Network;
use crate::mine_loop::mine_loop_tests::make_coinbase_transaction_from_state;
use crate::models::blockchain::block::Block;
use crate::models::state::wallet::address::hash_lock::HashLock;
use crate::tests::shared::fake_valid_successor_for_tests;
use crate::tests::shared::make_mock_block;
use crate::tests::shared::make_mock_block_guesser_preimage_and_guesser_fraction;
Expand Down Expand Up @@ -2106,9 +2107,7 @@ mod global_state_tests {
.get_known_raw_hash_lock_keys()
.collect_vec();
assert_eq!(
vec![SpendingKey::RawHashLock {
preimage: guesser_preimage
}],
vec![SpendingKey::RawHashLock(HashLock::from(guesser_preimage))],
cached_hash_lock_keys,
"Cached hash lock keys must match expected value after recovery"
);
Expand Down
1 change: 1 addition & 0 deletions src/models/state/wallet/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod common;

pub mod encrypted_utxo_notification;
pub mod generation_address;
pub(crate) mod hash_lock;
pub mod symmetric_key;

/// KeyType simply enumerates the known key types.
Expand Down
13 changes: 5 additions & 8 deletions src/models/state/wallet/address/address_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use tracing::warn;

use super::common;
use super::generation_address;
use super::hash_lock;
use super::symmetric_key;
use crate::config_models::network::Network;
use crate::models::blockchain::transaction::lock_script::LockScript;
Expand All @@ -36,7 +37,7 @@ use crate::BFieldElement;
#[repr(u8)]
pub enum KeyType {
/// To unlock, prove knowledge of the preimage.
RawHashLock = 0,
RawHashLock = hash_lock::RAW_HASH_LOCK_FLAG_U8,

/// [generation_address] built on [crate::prelude::twenty_first::math::lattice::kem]
///
Expand Down Expand Up @@ -370,9 +371,7 @@ impl ReceivingAddress {
/// particular, the `HashLock` variant has no associated address.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SpendingKey {
RawHashLock {
preimage: Digest,
},
RawHashLock(hash_lock::HashLock),

/// a key from [generation_address]
Generation(generation_address::GenerationSpendingKey),
Expand Down Expand Up @@ -405,7 +404,7 @@ impl SpendingKey {
match self {
Self::Generation(k) => Some(k.to_address().into()),
Self::Symmetric(k) => Some((*k).into()),
Self::RawHashLock { .. } => None,
Self::RawHashLock(_) => None,
}
}

Expand All @@ -416,9 +415,7 @@ impl SpendingKey {
generation_spending_key.lock_script_and_witness()
}
SpendingKey::Symmetric(symmetric_key) => symmetric_key.lock_script_and_witness(),
SpendingKey::RawHashLock { preimage } => {
LockScriptAndWitness::hash_lock_from_preimage(*preimage)
}
SpendingKey::RawHashLock(raw_hash_lock) => raw_hash_lock.lock_script_and_witness(),
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/models/state/wallet/address/generation_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use super::common;
use super::common::deterministically_derive_seed_and_nonce;
use super::common::network_hrp_char;
use super::encrypted_utxo_notification::EncryptedUtxoNotification;
use super::hash_lock::HashLock;
use crate::config_models::network::Network;
use crate::models::blockchain::shared::Hash;
use crate::models::blockchain::transaction::lock_script::LockScript;
Expand Down Expand Up @@ -160,7 +161,7 @@ impl GenerationSpendingKey {
}

pub(crate) fn lock_script_and_witness(&self) -> LockScriptAndWitness {
LockScriptAndWitness::hash_lock_from_preimage(self.unlock_key_preimage)
HashLock::from(self.unlock_key_preimage).lock_script_and_witness()
}

pub fn derive_from_seed(seed: Digest) -> Self {
Expand Down Expand Up @@ -365,7 +366,7 @@ impl GenerationReceivingAddress {
/// Satisfaction of this lock script establishes the UTXO owner's assent to
/// the transaction.
pub fn lock_script(&self) -> LockScript {
LockScript::hash_lock_from_after_image(self.lock_after_image)
HashLock::lock_script_from_after_image(self.lock_after_image)
}

pub(crate) fn generate_public_announcement(
Expand Down
77 changes: 77 additions & 0 deletions src/models/state/wallet/address/hash_lock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use itertools::Itertools;
use serde::Deserialize;
use serde::Serialize;
use tasm_lib::prelude::Digest;
use tasm_lib::triton_vm::isa::triton_asm;
use tasm_lib::triton_vm::isa::triton_instr;
use tasm_lib::triton_vm::vm::NonDeterminism;

use crate::models::blockchain::transaction::lock_script::LockScript;
use crate::models::blockchain::transaction::lock_script::LockScriptAndWitness;

pub(crate) const RAW_HASH_LOCK_FLAG_U8: u8 = 0u8;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct HashLock {
preimage: Digest,
}

impl From<Digest> for HashLock {
fn from(value: Digest) -> Self {
Self { preimage: value }
}
}

impl From<HashLock> for Digest {
fn from(value: HashLock) -> Self {
value.preimage
}
}

impl HashLock {
pub(crate) fn after_image(&self) -> Digest {
self.preimage.hash()
}

/// Generate a lock script for this hash lock.
pub(crate) fn lock_script(&self) -> LockScript {
Self::lock_script_from_after_image(self.after_image())
}

pub(crate) fn lock_script_hash(&self) -> Digest {
self.lock_script().hash()
}

pub(crate) fn lock_script_and_witness(&self) -> LockScriptAndWitness {
let lock_script = Self::lock_script_from_after_image(self.after_image());
LockScriptAndWitness::new_with_nondeterminism(
lock_script.program,
NonDeterminism::new(self.preimage.reversed().values()),
)
}

/// Generate a lock script that verifies knowledge of a hash preimage, given
/// the after-image.
///
/// Satisfaction of this lock script establishes the UTXO owner's assent to
/// the transaction.
pub(crate) fn lock_script_from_after_image(after_image: Digest) -> LockScript {
let push_spending_lock_digest_to_stack = after_image
.values()
.iter()
.rev()
.map(|elem| triton_instr!(push elem.value()))
.collect_vec();

let instructions = triton_asm!(
divine 5
hash
{&push_spending_lock_digest_to_stack}
assert_vector
read_io 5
halt
);

instructions.into()
}
}
5 changes: 3 additions & 2 deletions src/models/state/wallet/address/symmetric_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use twenty_first::math::tip5::Digest;
use super::common;
use super::common::deterministically_derive_seed_and_nonce;
use super::encrypted_utxo_notification::EncryptedUtxoNotification;
use super::hash_lock::HashLock;
use crate::config_models::network::Network;
use crate::models::blockchain::shared::Hash;
use crate::models::blockchain::transaction::lock_script::LockScript;
Expand Down Expand Up @@ -186,11 +187,11 @@ impl SymmetricKey {
/// Satisfaction of this lock script establishes the UTXO owner's assent to
/// the transaction.
pub fn lock_script(&self) -> LockScript {
LockScript::hash_lock_from_after_image(self.lock_after_image())
HashLock::lock_script_from_after_image(self.lock_after_image())
}

pub(crate) fn lock_script_and_witness(&self) -> LockScriptAndWitness {
LockScriptAndWitness::hash_lock_from_preimage(self.unlock_key())
HashLock::from(self.unlock_key()).lock_script_and_witness()
}

pub(crate) fn generate_public_announcement(
Expand Down
Loading

0 comments on commit adee45c

Please sign in to comment.