Skip to content

Commit

Permalink
add txid, rework midhash, init hashcache
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeanmichel7 committed Jan 19, 2025
1 parent 05a6315 commit aff2243
Show file tree
Hide file tree
Showing 18 changed files with 343 additions and 358 deletions.
26 changes: 20 additions & 6 deletions packages/cmds/src/main.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ use shinigami_tests::validate;
struct InputData {
ScriptSig: ByteArray,
ScriptPubKey: ByteArray,
txid: u256,
}

#[derive(Clone, Drop)]
struct InputDataWithFlags {
ScriptSig: ByteArray,
ScriptPubKey: ByteArray,
Flags: ByteArray,
txid: u256,
}

#[derive(Clone, Drop)]
Expand All @@ -29,6 +31,7 @@ struct InputDataWithWitness {
ScriptPubKey: ByteArray,
Flags: ByteArray,
Witness: ByteArray,
txid: u256,
}

fn run_with_flags(input: InputDataWithFlags) -> Result<(), felt252> {
Expand All @@ -42,7 +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(), array![]);
let tx = EngineInternalTransactionImpl::new_signed(
script_sig, script_pubkey.clone(), input.txid, array![],
);
let flags = flags::parse_flags(input.Flags);
let hash_cache = HashCacheImpl::new(@tx);
let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, flags, 0, @hash_cache)?;
Expand All @@ -65,7 +70,7 @@ 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, array![],
script_sig, script_pubkey.clone(), witness, value, input.txid, array![],
);
let flags = flags::parse_flags(input.Flags);
let hash_cache = HashCacheImpl::new(@tx);
Expand All @@ -84,7 +89,9 @@ 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(), array![]);
let tx = EngineInternalTransactionImpl::new_signed(
script_sig, script_pubkey.clone(), input.txid, array![],
);
let hash_cache = HashCacheImpl::new(@tx);
let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, 0, 0, @hash_cache)?;
let res = engine.execute();
Expand All @@ -110,7 +117,9 @@ 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(), array![]);
let tx = EngineInternalTransactionImpl::new_signed(
script_sig, script_pubkey.clone(), input.txid, array![],
);
let hash_cache = HashCacheImpl::new(@tx);
let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, 0, 0, @hash_cache)?;
let _ = engine.execute()?;
Expand All @@ -128,7 +137,9 @@ 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(), array![]);
let tx = EngineInternalTransactionImpl::new_signed(
script_sig, script_pubkey.clone(), input.txid, array![],
);
let hash_cache = HashCacheImpl::new(@tx);
let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, 0, 0, @hash_cache)?;
let mut res = Result::Ok(true);
Expand Down Expand Up @@ -206,6 +217,7 @@ struct ValidateRawInput {
raw_transaction: ByteArray,
utxo_hints: Array<UTXO>,
flags: ByteArray,
txid: u256 // from raito or calculate from raw_transaction in decode ?
}

fn run_raw_transaction(mut input: ValidateRawInput) -> u8 {
Expand Down Expand Up @@ -236,7 +248,9 @@ fn run_raw_transaction(mut input: ValidateRawInput) -> u8 {
);
};

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

let res = validate::validate_transaction(@transaction, script_flags);
Expand Down
157 changes: 90 additions & 67 deletions packages/engine/src/hash_cache.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ 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.
#[derive(Clone, Copy, Drop, Default)]
Expand All @@ -26,27 +29,13 @@ pub struct TaprootSigHashMidState {
pub hash_input_amounts_v1: u256,
}

pub trait SigHashMidstateTrait<
I,
O,
T,
+EngineTransactionInputTrait<I>,
+EngineTransactionOutputTrait<O>,
+EngineTransactionTrait<T, I, O>,
> {
fn new(transaction: @T, tx_idx: u32) -> TxSigHashes;
pub trait SigHashMidstateTrait<T> {
fn new(transaction: @T) -> TxSigHashes;
fn calc_hash_inputs_amount(transaction: @T) -> u256;
fn calc_hash_input_scripts(transaction: @T) -> u256;
}

// TxSigHashes houses the partial set of sighashes introduced within BIP0143.
#[derive(Drop, Default)]
pub enum TxSigHashes {
Segwit: @SegwitSigHashMidstate,
#[default] // make sense ? for TaprootSigVerifierTrait::empty()
Taproot: @TaprootSigHashMidState,
}

pub impl SigHashMidstateImpl<
I,
O,
Expand All @@ -56,14 +45,23 @@ pub impl SigHashMidstateImpl<
impl IEngineTransaction: EngineTransactionTrait<
T, I, O, IEngineTransactionInput, IEngineTransactionOutput,
>,
> of SigHashMidstateTrait<I, O, T> {
fn new(transaction: @T, tx_idx: u32) -> TxSigHashes {
> of SigHashMidstateTrait<T> {
fn new(transaction: @T) -> TxSigHashes {
let mut hasV0Inputs = false;
let mut hasV1Inputs = false;

let prevout: ByteArray = transaction.get_input_utxo(tx_idx).pubkey_script;
for _ in transaction.get_transaction_inputs() {
if is_witness_v1_pub_key_hash(@prevout) {
for i in 0..transaction.get_transaction_inputs().len() {
let input = transaction.get_transaction_inputs()[i];
let input_txid = input.get_prevout_txid();
let input_vout = input.get_prevout_vout();

if (input_vout == 0xFFFFFFFF && input_txid == 0) {
hasV0Inputs = true;
continue;
}

let utxo = transaction.get_input_utxo(i);
if is_witness_v1_pub_key_hash(@utxo.pubkey_script) {
hasV1Inputs = true;
} else {
hasV0Inputs = true;
Expand All @@ -74,7 +72,6 @@ pub impl SigHashMidstateImpl<
}
};

// compute v0 hash midstate
let mut prevouts_v0_bytes: ByteArray = "";
let inputs = transaction.get_transaction_inputs();
for input in inputs {
Expand All @@ -99,28 +96,33 @@ pub impl SigHashMidstateImpl<
let hashSequenceV1: [u32; 8] = compute_sha256_byte_array(@sequence_v0_bytes);
let hashOutputsV1: [u32; 8] = compute_sha256_byte_array(@outputs_v0_bytes);

let mut txSigHashes: TxSigHashes = Default::default();
if hasV0Inputs {
return TxSigHashes::Segwit(
@SegwitSigHashMidstate {
hash_prevouts_v0: sha256_u256(hashPrevOutsV1),
hash_sequence_v0: sha256_u256(hashSequenceV1),
hash_outputs_v0: sha256_u256(hashOutputsV1),
},
);
} else {
txSigHashes
.set_v0_sighash(
SegwitSigHashMidstate {
hash_prevouts_v0: sha256_u256(hashPrevOutsV1),
hash_sequence_v0: sha256_u256(hashSequenceV1),
hash_outputs_v0: sha256_u256(hashOutputsV1),
},
);
}
if hasV1Inputs {
let hash_input_amounts_v1 = Self::calc_hash_inputs_amount(transaction);
let hash_input_scripts_v1 = Self::calc_hash_input_scripts(transaction);

return TxSigHashes::Taproot(
@TaprootSigHashMidState {
hash_prevouts_v1: hash_to_u256(hashPrevOutsV1),
hash_sequence_v1: hash_to_u256(hashSequenceV1),
hash_outputs_v1: hash_to_u256(hashOutputsV1),
hash_input_scripts_v1: hash_input_scripts_v1,
hash_input_amounts_v1: hash_input_amounts_v1,
},
);
txSigHashes
.set_v1_sighash(
TaprootSigHashMidState {
hash_prevouts_v1: hash_to_u256(hashPrevOutsV1),
hash_sequence_v1: hash_to_u256(hashSequenceV1),
hash_outputs_v1: hash_to_u256(hashOutputsV1),
hash_input_scripts_v1: hash_input_scripts_v1,
hash_input_amounts_v1: hash_input_amounts_v1,
},
);
}
txSigHashes
}

// calcHashInputAmounts computes a hash digest of the input amounts of all
Expand Down Expand Up @@ -155,39 +157,57 @@ pub trait SigCacheTrait<S> {
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 {
fn new() -> TxSigHashes {
TxSigHashes { segwit: Default::default(), taproot: Default::default() }
}

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

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

// TODO
#[derive(Destruct, Default)]
pub struct HashCache<T> {
// use dict ? index = hash = u256 != felt
sigHashes: Felt252Dict<Nullable<TxSigHashes>>,
}

// 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;
}
// 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 @@ -202,11 +222,14 @@ pub impl HashCacheImpl<
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)));
// }

// Add sighashes for a transaction
// fn add_sig_hashes(ref self: HashCache<T>, tx: @T) {
// self
// .sigHashes
// .insert(tx.get_prevout_txid(), NullableTrait::new(SigHashMidstateTrait::new(tx)));
// let txid_hash = PoseidonTrait::new().update_with(tx.get_txid()).finalize();
// self.sigHashes.insert(txid_hash, NullableTrait::new(SigHashMidstateTrait::new(tx)));
// }

// Get sighashes for a transaction
Expand Down
2 changes: 1 addition & 1 deletion packages/engine/src/opcodes/crypto.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ pub fn opcode_checkmultisig<
let amount = engine.amount;

if engine.is_witness_active(BASE_SEGWIT_VERSION) {
let sig_hashes = SigHashMidstateTrait::new(transaction, tx_idx);
let sig_hashes = SigHashMidstateTrait::new(transaction);
sig_hash =
sighash::calc_witness_signature_hash(
@script, sig_hashes, hash_type, transaction, tx_idx, amount,
Expand Down
Loading

0 comments on commit aff2243

Please sign in to comment.