use miden::protocol::native_account
use miden::protocol::tx
use miden::core::crypto::hashes::rpo256

#! Inputs:  [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
#! Outputs: [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
@locals(16)
pub proc adv_insert_hqword
    loc_storew_be.0
    movdnw.3
    loc_storew_be.4
    movdnw.3
    loc_storew_be.8
    movdnw.3
    loc_storew_be.12
    movdnw.3
    # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]

    exec.hash_tx_summary
    # => [MESSAGE]

    locaddr.0
    dup add.16
    # => [mem_addr_end, mem_addr_start, MESSAGE]

    movdn.5 movdn.4
    # => [MESSAGE, mem_addr_start, mem_addr_end]

    adv.insert_mem
    drop drop
    # => [<4 stack elements>]

    loc_loadw_be.12
    padw loc_loadw_be.8
    padw loc_loadw_be.4
    padw loc_loadw_be.0
    # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
end

#! Creates the transaction summary and returns it in the order in which it will be hashed.
#!
#! Inputs:  [SALT]
#! Outputs: [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
#!
#! Where:
#! - SALT is a user-defined input recommended to use as replay protection.
#! - OUTPUT_NOTES_COMMITMENT is the commitment to the transaction's output notes.
#! - INPUT_NOTES_COMMITMENT is the commitment to the transaction's inputs notes.
#! - ACCOUNT_DELTA_COMMITMENT is the commitment to the transaction's account delta.
pub proc create_tx_summary
    exec.native_account::compute_delta_commitment
    # => [ACCOUNT_DELTA_COMMITMENT, SALT]

    exec.tx::get_input_notes_commitment
    # => [INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT, SALT]

    exec.tx::get_output_notes_commitment
    # => [OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT, SALT]

    movupw.3
    # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
end

#! Hashes the provided transaction summary and returns its commitment.
#!
#! Inputs:  [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
#! Outputs: [TX_SUMMARY_COMMITMENT]
#!
#! Where:
#! - SALT is an arbitrary word used for replay protection.
#! - OUTPUT_NOTES_COMMITMENT is the commitment to the transaction's output notes.
#! - INPUT_NOTES_COMMITMENT is the commitment to the transaction's inputs notes.
#! - ACCOUNT_DELTA_COMMITMENT is the commitment to the transaction's account delta.
pub proc hash_tx_summary
    swapdw
    # => [INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT, SALT, OUTPUT_NOTES_COMMITMENT]

    # pad capacity element of the hasher
    padw movdnw.2
    # => [INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT, CAPACITY, SALT, OUTPUT_NOTES_COMMITMENT]

    exec.rpo256::permute
    # => [RATE, RATE, PERM, SALT, OUTPUT_NOTES_COMMITMENT]

    # drop rate words
    dropw dropw
    # => [PERM, SALT, OUTPUT_NOTES_COMMITMENT]

    movdnw.2
    # => [SALT, OUTPUT_NOTES_COMMITMENT, PERM]

    exec.rpo256::permute
    # => [RATE, RATE, PERM]

    exec.rpo256::squeeze_digest
    # => [TX_SUMMARY_COMMITMENT]
end
