Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new hash_memory proc #1519

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions stdlib/asm/crypto/hashes/rpo.masm
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ end

#! Hashes the memory `start_addr` to `end_addr` given an RPO state specified by 3 words.
#!
#! This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite
#! loop. `end_addr` is not inclusive.
#! This requires that `end_addr = start_addr + 2n` where n = {0, 1, 2 ...}, otherwise the procedure
#! will enter an infinite loop.
#!
#! Input: [C, B, A, start_addr, end_addr, ...]
#! Output: [C', B', A', end_addr, end_addr ...]
Expand All @@ -44,7 +44,7 @@ end
#! - `A` is the capacity word that will be used by the hashing function.
#! - `B` is the hash output.
#!
#! Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1`
#! Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr`
export.absorb_double_words_from_memory
dup.13 dup.13 neq # (4 cycles )
while.true
Expand All @@ -55,7 +55,7 @@ end

#! Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.
#!
#! Requires `start_addr < end_addr`, `end_addr` is not inclusive.
#! Requires `start_addr end_addr`, `end_addr` is not inclusive.
#!
#! Input: [start_addr, end_addr, ...]
#! Output: [H, ...]
Expand All @@ -65,48 +65,50 @@ end
#! - odd words: 61 cycles + 3 * words
#! where `words` is the `start_addr - end_addr - 1`
export.hash_memory_words
# enforce `start_addr < end_addr`
dup.1 dup.1 u32assert2 u32gt assert
# enforce `start_addr end_addr`
dup.1 dup.1 u32assert2 u32gte assert

# figure out if the range is for an odd number of words (9 cycles)
dup.1 dup.1 sub is_odd
# stack: [is_odd, start_addr, end_addr, ...]
# => [is_odd, start_addr, end_addr, ...]

# make the start/end range even (4 cycles)
movup.2 dup.1 sub
# stack: [end_addr, is_odd, start_addr, ...]
# => [end_addr, is_odd, start_addr, ...]

# move start_addr to the right stack position (1 cycles)
movup.2
# stack: [start_addr, end_addr, is_odd, ...]
# => [start_addr, end_addr, is_odd, ...]

# prepare hasher state (14 cycles)
dup.2 mul.4 push.0.0.0 padw padw
# stack: [C, B, A, start_addr, end_addr, is_odd, ...]
# => [C, B, A, start_addr, end_addr, is_odd, ...]

# (4 + 3 * words cycles)
exec.absorb_double_words_from_memory
# => [C', B', A', end_addr, end_addr, is_odd, ...]

# (1 cycles)
movup.14
# => [is_odd, C', B', A', end_addr, end_addr, ...]

# handle the odd element, if any (12 cycles)
if.true
# start_addr and end_addr are equal after calling `absorb_double_words_from_memory`, and both point
# to the last element. Load the last word (6 cycles)
# start_addr and end_addr are equal after calling `absorb_double_words_from_memory`, and both
# point to the last element. Load the last word (6 cycles)
dropw dup.9 mem_loadw
# => [D, A', end_addr, end_addr, ...]

# set the padding (4 cycles)
padw

# (1 cycles)
hperm
# set the padding and compute the permutation (5 cycles)
padw hperm
end

exec.squeeze_digest
# => [HASH, end_addr, end_addr, ...]

# drop start_addr/end_addr (4 cycles)
movup.4 drop movup.4 drop
# => [HASH]
end

#! Computes hash of Felt values starting at the specified memory address.
Expand Down
63 changes: 38 additions & 25 deletions stdlib/tests/crypto/rpo.rs
Fumuran marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,6 @@ fn test_invalid_end_addr() {
err_msg: None,
}
);

// address range can not contain zero elements
let empty_range = "
use.std::crypto::hashes::rpo

begin
push.1000 # end address
push.1000 # start address

exec.rpo::hash_memory_words
end
";
let test = build_test!(empty_range, &[]);
expect_exec_error!(
test,
ExecutionError::FailedAssertion {
clk: 18.into(),
err_code: 0,
err_msg: None,
}
);
}

#[test]
Expand Down Expand Up @@ -354,16 +333,50 @@ fn test_hash_memory() {

#[test]
fn test_hash_memory_empty() {
// try to hash 0 values
let compute_inputs_hash = "
// absorb_double_words_from_memory
let source = "
use.std::crypto::hashes::rpo

begin
push.1000 # end address
push.1000 # start address
padw padw padw # hasher state

exec.rpo::absorb_double_words_from_memory
end
";

let mut expected_stack = vec![0; 12];
expected_stack.push(1000);
expected_stack.push(1000);

build_test!(source, &[]).expect_stack(&expected_stack);

// hash_memory_words
let source = "
use.std::crypto::hashes::rpo

begin
push.1000 # end address
push.1000 # start address

exec.rpo::hash_memory_words
end
";

build_test!(source, &[]).expect_stack(&[0; 4]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not test against expected stack [0; 16]?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial thought was to check the actual value which hash_memory_words produces, but we can check the entire stack, the result should be the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's check the entire stack - this way we'll be sure that the procedure doesn't "mess" with the rest of the stack.


// hash_memory
let source = "
use.std::crypto::hashes::rpo

begin
push.0.1000
push.0 # number of elements to hash
push.1000 # start address

exec.rpo::hash_memory
end
";

build_test!(compute_inputs_hash, &[]).expect_stack(&[0; 16]);
build_test!(source, &[]).expect_stack(&[0; 16]);
}
Loading