Skip to content

Commit

Permalink
Incorporate assert and mpverify arguments into eq_hash
Browse files Browse the repository at this point in the history
  • Loading branch information
plafer committed Sep 10, 2024
1 parent 4007733 commit adbfe9a
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 5 deletions.
30 changes: 25 additions & 5 deletions assembly/src/assembler/mast_forest_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,17 +450,37 @@ impl MastForestBuilder {
fn eq_hash_for_node(&self, node: &MastNode) -> EqHash {
match node {
MastNode::Block(node) => {
let mut decorator_bytes_to_hash = Vec::new();
let mut bytes_to_hash = Vec::new();

for &(idx, decorator_id) in node.decorators() {
decorator_bytes_to_hash.extend(idx.to_le_bytes());
decorator_bytes_to_hash.extend(self[decorator_id].eq_hash().as_bytes());
bytes_to_hash.extend(idx.to_le_bytes());
bytes_to_hash.extend(self[decorator_id].eq_hash().as_bytes());
}

if decorator_bytes_to_hash.is_empty() {
// Add any `Assert` or `U32assert2` opcodes present, since these are not included in
// the MAST root.
for (op_idx, op) in node.operations().enumerate() {
if let Operation::U32assert2(inner_value)
| Operation::Assert(inner_value)
| Operation::MpVerify(inner_value) = op
{
let op_idx: u32 = op_idx
.try_into()
.expect("there are more than 2^{32}-1 operations in basic block");

// we include the opcode to differentiate between `Assert` and `U32assert2`
bytes_to_hash.push(op.op_code());
// we include the operation index to distinguish between basic blocks that
// would have the same assert instructions, but in a different order
bytes_to_hash.extend(op_idx.to_le_bytes());
bytes_to_hash.extend(inner_value.to_le_bytes());
}
}

if bytes_to_hash.is_empty() {
EqHash::new(node.digest())
} else {
let decorator_root = Blake3_256::hash(&decorator_bytes_to_hash);
let decorator_root = Blake3_256::hash(&bytes_to_hash);
EqHash::with_decorator_root(node.digest(), decorator_root)
}
},
Expand Down
125 changes: 125 additions & 0 deletions assembly/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,131 @@ end";
Ok(())
}

/// Ensure that there is no collision between `Assert`, `U32assert2`, and `MpVerify` instructions
/// with different inner values (which all don't contribute to the MAST root).
#[test]
fn asserts_and_mpverify_with_code_in_duplicate_procedure() -> TestResult {
let context = TestContext::default();
let source = source_file!(
&context,
"\
proc.f1
u32assert.err=1
end
proc.f2
u32assert.err=2
end
proc.f12
u32assert.err=1
u32assert.err=2
end
proc.f21
u32assert.err=2
u32assert.err=1
end
proc.g1
assert.err=1
end
proc.g2
assert.err=2
end
proc.g12
assert.err=1
assert.err=2
end
proc.g21
assert.err=2
assert.err=1
end
proc.fg
assert.err=1
u32assert.err=1
assert.err=2
u32assert.err=2
u32assert.err=1
assert.err=1
u32assert.err=2
assert.err=2
end
proc.mpverify
mtree_verify.err=1
mtree_verify.err=2
mtree_verify.err=2
mtree_verify.err=1
end
begin
exec.f1
exec.f2
exec.f12
exec.f21
exec.g1
exec.g2
exec.g12
exec.g21
exec.fg
exec.mpverify
end
"
);
let program = context.assemble(source)?;

let expected = "\
begin
basic_block
pad
u32assert2(1)
drop
pad
u32assert2(2)
drop
pad
u32assert2(1)
drop
pad
u32assert2(2)
drop
pad
u32assert2(2)
drop
pad
u32assert2(1)
drop
assert(1)
assert(2)
assert(1)
assert(2)
assert(2)
assert(1)
assert(1)
pad
u32assert2(1)
drop
assert(2)
pad
u32assert2(2)
drop
pad
u32assert2(1)
drop
assert(1)
pad
u32assert2(2)
drop
assert(2)
mpverify(1)
mpverify(2)
mpverify(2)
mpverify(1)
end
end";

assert_str_eq!(expected, format!("{program}"));
Ok(())
}

#[test]
fn mtree_verify_with_code() -> TestResult {
let context = TestContext::default();
Expand Down

0 comments on commit adbfe9a

Please sign in to comment.