Skip to content

Commit

Permalink
remove txid + new hashcache with flag + impl hashcache + use hashcach…
Browse files Browse the repository at this point in the history
…e in validation + add test p2wpkh witness + handle error in loop multi inputs
  • Loading branch information
Jeanmichel7 committed Jan 26, 2025
1 parent 7e8c05d commit f5e5367
Show file tree
Hide file tree
Showing 23 changed files with 439 additions and 269 deletions.
33 changes: 11 additions & 22 deletions packages/cmds/src/main.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,9 @@ fn run_with_flags(input: InputDataWithFlags) -> Result<(), felt252> {
let script_pubkey = compiler.compile(input.ScriptPubKey)?;
let compiler = CompilerImpl::new();
let script_sig = compiler.compile(input.ScriptSig)?;
let tx = EngineInternalTransactionImpl::new_signed(
script_sig, script_pubkey.clone(), input.txid, array![],
);
let tx = EngineInternalTransactionImpl::new_signed(script_sig, script_pubkey.clone(), array![]);
let flags = flags::parse_flags(input.Flags);
let hash_cache = HashCacheImpl::new(@tx);
let hash_cache = HashCacheImpl::new(@tx, flags);
let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, flags, 0, @hash_cache)?;
let _ = engine.execute()?;
Result::Ok(())
Expand All @@ -70,10 +68,10 @@ fn run_with_witness(input: InputDataWithWitness) -> Result<(), felt252> {
let witness = witness::parse_witness_input(input.Witness);
let value = 1; // TODO
let tx = EngineInternalTransactionImpl::new_signed_witness(
script_sig, script_pubkey.clone(), witness, value, input.txid, array![],
script_sig, script_pubkey.clone(), witness, value, array![],
);
let flags = flags::parse_flags(input.Flags);
let hash_cache = HashCacheImpl::new(@tx);
let hash_cache = HashCacheImpl::new(@tx, flags);
let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, flags, value, @hash_cache)?;
let _ = engine.execute()?;
Result::Ok(())
Expand All @@ -89,10 +87,8 @@ fn run(input: InputData) -> Result<(), felt252> {
let script_pubkey = compiler.compile(input.ScriptPubKey)?;
let compiler = CompilerImpl::new();
let script_sig = compiler.compile(input.ScriptSig)?;
let tx = EngineInternalTransactionImpl::new_signed(
script_sig, script_pubkey.clone(), input.txid, array![],
);
let hash_cache = HashCacheImpl::new(@tx);
let tx = EngineInternalTransactionImpl::new_signed(script_sig, script_pubkey.clone(), array![]);
let hash_cache = HashCacheImpl::new(@tx, 0);
let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, 0, 0, @hash_cache)?;
let res = engine.execute();
match res {
Expand All @@ -117,10 +113,8 @@ fn run_with_json(input: InputData) -> Result<(), felt252> {
let script_pubkey = compiler.compile(input.ScriptPubKey)?;
let compiler = CompilerImpl::new();
let script_sig = compiler.compile(input.ScriptSig)?;
let tx = EngineInternalTransactionImpl::new_signed(
script_sig, script_pubkey.clone(), input.txid, array![],
);
let hash_cache = HashCacheImpl::new(@tx);
let tx = EngineInternalTransactionImpl::new_signed(script_sig, script_pubkey.clone(), array![]);
let hash_cache = HashCacheImpl::new(@tx, 0);
let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, 0, 0, @hash_cache)?;
let _ = engine.execute()?;
engine.json();
Expand All @@ -137,10 +131,8 @@ fn debug(input: InputData) -> Result<bool, felt252> {
let script_pubkey = compiler.compile(input.ScriptPubKey)?;
let compiler = CompilerImpl::new();
let script_sig = compiler.compile(input.ScriptSig)?;
let tx = EngineInternalTransactionImpl::new_signed(
script_sig, script_pubkey.clone(), input.txid, array![],
);
let hash_cache = HashCacheImpl::new(@tx);
let tx = EngineInternalTransactionImpl::new_signed(script_sig, script_pubkey.clone(), array![]);
let hash_cache = HashCacheImpl::new(@tx, 0);
let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, 0, 0, @hash_cache)?;
let mut res = Result::Ok(true);
while true {
Expand Down Expand Up @@ -248,10 +240,7 @@ fn run_raw_transaction(mut input: ValidateRawInput) -> u8 {
);
};

let transaction = EngineInternalTransactionTrait::deserialize(
raw_transaction, input.txid, utxo_hints,
);
// transaction.set_utxos(utxo_hints);
let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction, utxo_hints);

let res = validate::validate_transaction(@transaction, script_flags);
match res {
Expand Down
2 changes: 1 addition & 1 deletion packages/engine/src/engine.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ pub impl EngineImpl<
if !valid_sizes {
return Result::Err('Engine::new: script too large');
}

if script_sig.len() == 0 {
engine.script_idx = 1;
}
Expand Down Expand Up @@ -312,6 +311,7 @@ pub impl EngineImpl<
// TODO: Optimize with != instead of < and check for bounds errors within the loop
while self.script_idx < self.scripts.len() {
let script: @ByteArray = *self.scripts[self.script_idx];

let script_len = script.len();
if script_len == 0 {
self.script_idx += 1;
Expand Down
174 changes: 109 additions & 65 deletions packages/engine/src/hash_cache.cairo
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use crate::transaction::{
EngineTransactionInputTrait, EngineTransactionOutputTrait, EngineTransactionTrait,
};
use crate::flags::ScriptFlags;

use shinigami_utils::{bytecode::{write_var_int}, hash::{hash_to_u256, sha256_u256, simple_sha256}};
use core::sha256::compute_sha256_byte_array;
use crate::signature::utils::is_witness_v1_pub_key_hash;
use core::dict::Felt252Dict;

// use core::poseidon::PoseidonTrait;
// use core::hash::{HashStateTrait, HashStateExTrait};

// SegwitSigHashMidstate is the sighash midstate used in the base segwit
// sighash calculation as defined in BIP 143.
Expand All @@ -30,7 +28,7 @@ pub struct TaprootSigHashMidState {
}

pub trait SigHashMidstateTrait<T> {
fn new(transaction: @T) -> TxSigHashes;
fn new(transaction: @T) -> @TxSigHashes;
fn calc_hash_inputs_amount(transaction: @T) -> u256;
fn calc_hash_input_scripts(transaction: @T) -> u256;
}
Expand All @@ -46,7 +44,7 @@ pub impl SigHashMidstateImpl<
T, I, O, IEngineTransactionInput, IEngineTransactionOutput,
>,
> of SigHashMidstateTrait<T> {
fn new(transaction: @T) -> TxSigHashes {
fn new(transaction: @T) -> @TxSigHashes {
let mut hasV0Inputs = false;
let mut hasV1Inputs = false;

Expand Down Expand Up @@ -100,7 +98,7 @@ pub impl SigHashMidstateImpl<
if hasV0Inputs {
txSigHashes
.set_v0_sighash(
SegwitSigHashMidstate {
@SegwitSigHashMidstate {
hash_prevouts_v0: sha256_u256(hashPrevOutsV1),
hash_sequence_v0: sha256_u256(hashSequenceV1),
hash_outputs_v0: sha256_u256(hashOutputsV1),
Expand All @@ -113,7 +111,7 @@ pub impl SigHashMidstateImpl<

txSigHashes
.set_v1_sighash(
TaprootSigHashMidState {
@TaprootSigHashMidState {
hash_prevouts_v1: hash_to_u256(hashPrevOutsV1),
hash_sequence_v1: hash_to_u256(hashSequenceV1),
hash_outputs_v1: hash_to_u256(hashOutputsV1),
Expand All @@ -122,7 +120,7 @@ pub impl SigHashMidstateImpl<
},
);
}
txSigHashes
@txSigHashes
}

// calcHashInputAmounts computes a hash digest of the input amounts of all
Expand Down Expand Up @@ -156,58 +154,94 @@ pub trait SigCacheTrait<S> {
// Adds a signature to the cache
fn add(sig_hash: u256, signature: ByteArray, pub_key: ByteArray);
}

#[derive(Drop, Default, Copy)]
pub struct TxSigHashes {
pub segwit: SegwitSigHashMidstate,
pub taproot: TaprootSigHashMidState,
}

#[generate_trait]
impl TxSigHashesImpl of TxSigHashesTrait {
pub impl TxSigHashesImpl of TxSigHashesTrait {
fn new() -> TxSigHashes {
TxSigHashes { segwit: Default::default(), taproot: Default::default() }
}

fn set_v0_sighash(ref self: TxSigHashes, sighash: SegwitSigHashMidstate) {
self.segwit = sighash;
fn set_v0_sighash(ref self: TxSigHashes, sighash: @SegwitSigHashMidstate) {
self.segwit = *sighash;
}

fn set_v1_sighash(ref self: TxSigHashes, sighash: @TaprootSigHashMidState) {
self.taproot = *sighash;
}

fn get_hash_segwit_v0(self: @TxSigHashes) -> @SegwitSigHashMidstate {
self.segwit
}

fn get_hash_taproot_v1(self: @TxSigHashes) -> @TaprootSigHashMidState {
self.taproot
}

fn get_hash_prevouts_v0(self: @TxSigHashes) -> u256 {
*self.segwit.hash_prevouts_v0
}

fn get_hash_sequence_v0(self: @TxSigHashes) -> u256 {
*self.segwit.hash_sequence_v0
}

fn get_hash_outputs_v0(self: @TxSigHashes) -> u256 {
*self.segwit.hash_outputs_v0
}

fn get_hash_prevouts_v1(self: @TxSigHashes) -> u256 {
*self.taproot.hash_prevouts_v1
}

fn get_hash_sequence_v1(self: @TxSigHashes) -> u256 {
*self.taproot.hash_sequence_v1
}

fn get_hash_outputs_v1(self: @TxSigHashes) -> u256 {
*self.taproot.hash_outputs_v1
}

fn get_hash_input_amounts_v1(self: @TxSigHashes) -> u256 {
*self.taproot.hash_input_amounts_v1
}

fn set_v1_sighash(ref self: TxSigHashes, sighash: TaprootSigHashMidState) {
self.taproot = sighash;
fn get_hash_input_scripts_v1(self: @TxSigHashes) -> u256 {
*self.taproot.hash_input_scripts_v1
}
}

#[derive(Destruct, Default)]
#[derive(Drop, Default)]
pub struct HashCache<T> {
sigHashes: Felt252Dict<Nullable<TxSigHashes>>,
pub sigHashes: Option<@TxSigHashes>,
}

pub trait HashCacheTrait<
I,
O,
T,
impl IEngineTransactionInput: EngineTransactionInputTrait<I>,
impl IEngineTransactionOutput: EngineTransactionOutputTrait<O>,
impl IEngineTransaction: EngineTransactionTrait<
T, I, O, IEngineTransactionInput, IEngineTransactionOutput,
>,
> {
fn new(tx: @T, flags: u32) -> HashCache<T>;
fn get_sig_hashes(self: @HashCache<T>) -> Option<@TxSigHashes>;
fn get_hash_prevouts_v0(self: @HashCache<T>) -> u256;
fn get_hash_sequence_v0(self: @HashCache<T>) -> u256;
fn get_hash_outputs_v0(self: @HashCache<T>) -> u256;
fn get_hash_prevouts_v1(self: @HashCache<T>) -> u256;
fn get_hash_sequence_v1(self: @HashCache<T>) -> u256;
fn get_hash_outputs_v1(self: @HashCache<T>) -> u256;
fn get_hash_input_amounts_v1(self: @HashCache<T>) -> u256;
fn get_hash_input_scripts_v1(self: @HashCache<T>) -> u256;
}

// HashCache caches the midstate of segwit v0 and v1 sighashes
// pub trait HashCacheTrait<
// I,
// O,
// T,
// +EngineTransactionInputTrait<I>,
// +EngineTransactionOutputTrait<O>,
// +EngineTransactionTrait<T, I, O>,
// > {
// fn new(transaction: @T) -> HashCache<T>;
// // fn add_sig_hashes(ref self: HashCache<T>, tx: @T);
// // fn get_sig_hashes(ref self: HashCache<T>, tx_hash: felt252) -> Option<TxSigHashes>;

// // v0 represents sighash midstate used in the base segwit signatures BIP-143
// fn get_hash_prevouts_v0(self: @HashCache<T>) -> u256;
// fn get_hash_sequence_v0(self: @HashCache<T>) -> u256;
// fn get_hash_outputs_v0(self: @HashCache<T>) -> u256;

// // v1 represents sighash midstate used to compute taproot signatures BIP-341
// fn get_hash_prevouts_v1(self: @HashCache<T>) -> u256;
// fn get_hash_sequence_v1(self: @HashCache<T>) -> u256;
// fn get_hash_outputs_v1(self: @HashCache<T>) -> u256;
// fn get_hash_input_scripts_v1(self: @HashCache<T>) -> u256;
// }
#[generate_trait]
pub impl HashCacheImpl<
I,
O,
Expand All @@ -217,51 +251,61 @@ pub impl HashCacheImpl<
impl IEngineTransaction: EngineTransactionTrait<
T, I, O, IEngineTransactionInput, IEngineTransactionOutput,
>,
+Drop<I>,
+Drop<O>,
+Drop<T>,
> of HashCacheTrait<I, O, T> {
fn new(transaction: @T) -> HashCache<T> {
HashCache { sigHashes: Default::default() }
}

// fn set_v0_sighash(self: @HashCache<T>, tx_hash: u256, sighash: SegwitSigHashMidstate) {
// self.sigHashes.insert(tx_hash, NullableTrait::new(TxSigHashes::Segwit(@sighash)));
// }
fn new(tx: @T, flags: u32) -> HashCache<T> {
let segwit_active = flags
& ScriptFlags::ScriptVerifyWitness.into() == ScriptFlags::ScriptVerifyWitness.into();

let mut has_witness = false;
for input in tx.get_transaction_inputs() {
if input.get_witness().len() != 0 {
has_witness = true;
break;
}
};

// Add sighashes for a transaction
// fn add_sig_hashes(ref self: HashCache<T>, tx: @T) {
// let txid_hash = PoseidonTrait::new().update_with(tx.get_txid()).finalize();
// self.sigHashes.insert(txid_hash, NullableTrait::new(SigHashMidstateTrait::new(tx)));
// }
if (segwit_active && has_witness) {
return HashCache { sigHashes: Option::Some(SigHashMidstateTrait::new(tx)) };
}
return HashCache { sigHashes: Default::default() };
}

// Get sighashes for a transaction
// fn get_sig_hashes(ref self: HashCache, tx_hash: felt252) -> Option<TxSigHashes> {
// self.sig_hashes.get(tx_hash)
// }
fn get_sig_hashes(self: @HashCache<T>) -> Option<@TxSigHashes> {
*self.sigHashes
}

fn get_hash_prevouts_v0(self: @HashCache<T>) -> u256 {
0
self.get_sig_hashes().unwrap().get_hash_prevouts_v0()
}

fn get_hash_sequence_v0(self: @HashCache<T>) -> u256 {
0
self.get_sig_hashes().unwrap().get_hash_sequence_v0()
}

fn get_hash_outputs_v0(self: @HashCache<T>) -> u256 {
0
self.get_sig_hashes().unwrap().get_hash_outputs_v0()
}

fn get_hash_prevouts_v1(self: @HashCache<T>) -> u256 {
0
self.get_sig_hashes().unwrap().get_hash_prevouts_v1()
}

fn get_hash_sequence_v1(self: @HashCache<T>) -> u256 {
0
self.get_sig_hashes().unwrap().get_hash_sequence_v1()
}

fn get_hash_outputs_v1(self: @HashCache<T>) -> u256 {
0
self.get_sig_hashes().unwrap().get_hash_outputs_v1()
}

fn get_hash_input_amounts_v1(self: @HashCache<T>) -> u256 {
self.get_sig_hashes().unwrap().get_hash_input_amounts_v1()
}

fn get_hash_input_scripts_v1(self: @HashCache<T>) -> u256 {
0
self.get_sig_hashes().unwrap().get_hash_input_scripts_v1()
}
}
1 change: 0 additions & 1 deletion packages/engine/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,4 @@ pub mod transaction;
mod tests {
mod test_scriptnum;
mod test_schnorr;
mod test_taproot_hash;
}
Loading

0 comments on commit f5e5367

Please sign in to comment.