/*
* Extends `bytes32_tr_storage` using `array_fold` for larger buffers.
* Optimized for small, fixed-size states where linear hashing is more efficient
* than Merkle Trees. By avoiding proof overhead like sibling hashes, we reduce
* witness size and simplify contract logic for small N.
* This approach is particularly advantageous when updating all slots within every transaction.
*/
fn hash_array_tr_storage(elem: u256, ctx: Ctx8) -> Ctx8 {
jet::sha_256_ctx_8_add_32(ctx, elem)
}
fn hash_array_tr_storage_with_update(elem: u256, triplet: (Ctx8, u16, u16)) -> (Ctx8, u16, u16) {
let (ctx, i, changed_index): (Ctx8, u16, u16) = triplet;
match jet::eq_16(i, changed_index) {
true => {
let (_, val): (bool, u16) = jet::increment_16(i);
// There may be arbitrary logic here
let (state1, state2, state3, state4): (u64, u64, u64, u64) = <u256>::into(elem);
let new_state4: u64 = 20;
let new_state: u256 = <(u64, u64, u64, u64)>::into((state1, state2, state3, new_state4));
(
jet::sha_256_ctx_8_add_32(ctx, new_state),
val,
changed_index,
)
},
false => {
let (_, val): (bool, u16) = jet::increment_16(i);
(
jet::sha_256_ctx_8_add_32(ctx, elem),
val,
changed_index,
)
}
}
}
fn script_hash_for_input_script(state: [u256; 3], changed_index: Option<u16>) -> u256 {
let tap_leaf: u256 = jet::tapleaf_hash();
let ctx: Ctx8 = jet::tapdata_init();
let (ctx, _, _): (Ctx8, u16, u16) = match changed_index {
Some(ind: u16) => {
array_fold::<hash_array_tr_storage_with_update, 3>(state, (ctx, 0, ind))
},
None => {
(array_fold::<hash_array_tr_storage, 3>(state, ctx), 0, 0)
}
};
let computed: u256 = jet::sha_256_ctx_8_finalize(ctx);
let tap_node: u256 = jet::build_tapbranch(tap_leaf, computed);
let bip0341_key: u256 = 0x50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0;
let tweaked_key: u256 = jet::build_taptweak(bip0341_key, tap_node);
let hash_ctx1: Ctx8 = jet::sha_256_ctx_8_init();
let hash_ctx2: Ctx8 = jet::sha_256_ctx_8_add_2(hash_ctx1, 0x5120); // Segwit v1, length 32
let hash_ctx3: Ctx8 = jet::sha_256_ctx_8_add_32(hash_ctx2, tweaked_key);
jet::sha_256_ctx_8_finalize(hash_ctx3)
}
fn main() {
let state: [u256; 3] = witness::STATE;
// Assert that the input is correct, i.e. "load".
assert!(jet::eq_256(
script_hash_for_input_script(state, None),
unwrap(jet::input_script_hash(jet::current_index()))
));
// Assert that the output is correct, i.e. "store".
assert!(jet::eq_256(
script_hash_for_input_script(state, Some(witness::CHANGED_INDEX)),
unwrap(jet::output_script_hash(jet::current_index()))
));
}