From 9b84cf900f813e0343b640542b73b1bcf49f995f Mon Sep 17 00:00:00 2001 From: dinhbx Date: Tue, 16 Apr 2024 15:54:17 +0700 Subject: [PATCH] fix: optimize proof.check_against_spec() --- .../ics-023-vector-commitments/ics23/ops.ak | 47 ++++++++++--------- .../ics23/ops_test.ak | 46 ++++++++++++++++-- .../ics-023-vector-commitments/ics23/proof.ak | 24 +++++++++- .../ics23/proofs.ak | 12 +---- 4 files changed, 91 insertions(+), 38 deletions(-) diff --git a/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/ops.ak b/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/ops.ak index 95ba941b..b0a301ef 100644 --- a/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/ops.ak +++ b/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/ops.ak @@ -3,7 +3,7 @@ use aiken/bytearray use aiken/list use ibc/core/ics_023_vector_commitments/ics23/constants.{hash_op_no_hash} use ibc/core/ics_023_vector_commitments/ics23/proofs.{ - HashOp, InnerOp, LeafOp, LengthOp, ProofSpec, + HashOp, InnerOp, InnerSpec, LeafOp, LengthOp, ProofSpec, } use ibc/utils/bytes.{encode_varint, has_prefix} @@ -25,16 +25,18 @@ pub fn apply_inner_op(op: InnerOp, child: ByteArray) -> ByteArray { } /// check_against_spec_leaf_op() will verify the LeafOp is in the format defined in spec -pub fn check_against_spec_leaf_op(op: LeafOp, spec: ProofSpec) -> Bool { - expect spec != proofs.null_proof_spec() +pub fn check_against_spec_leaf_op( + op: LeafOp, + spec: ProofSpec, + is_iavl_spec: Bool, +) -> Bool { let lspec = spec.leaf_spec - expect lspec != proofs.null_leaf_op() expect op.hash == lspec.hash expect op.prehash_key == lspec.prehash_key expect op.prehash_value == lspec.prehash_value expect op.length == lspec.length expect has_prefix(op.prefix, lspec.prefix) - if validate_spec(spec) { + if is_iavl_spec { expect validate_iavl_ops_leaf_op(op, 0) True } else { @@ -43,23 +45,24 @@ pub fn check_against_spec_leaf_op(op: LeafOp, spec: ProofSpec) -> Bool { } /// check_against_spec_inner_op() will verify the InnerOp is in the format defined in spec -pub fn check_against_spec_inner_op(op: InnerOp, spec: ProofSpec, b: Int) -> Bool { - expect spec != proofs.null_proof_spec() - expect spec.inner_spec != proofs.null_inner_spec() - expect spec.leaf_spec != proofs.null_leaf_op() - expect op.hash == spec.inner_spec.hash - let leaf_prefix = spec.leaf_spec.prefix - expect !has_prefix(op.prefix, leaf_prefix) - expect bytearray.length(op.prefix) >= spec.inner_spec.min_prefix_length - let max_left_child_bytes = - ( list.length(spec.inner_spec.child_order) - 1 ) * spec.inner_spec.child_size - expect - bytearray.length(op.prefix) <= spec.inner_spec.max_prefix_length + max_left_child_bytes - expect spec.inner_spec.child_size >= 1 - expect bytearray.length(op.suffix) % spec.inner_spec.child_size == 0 - if validate_spec(spec) { - expect validate_iavl_ops_inner_op(op, b) - True +pub fn check_against_spec_inner_op( + op: InnerOp, + spec: ProofSpec, + b: Int, + inner_spec: InnerSpec, + max_op_prefix_length: Int, + is_iavl_spec: Bool, +) -> Bool { + expect op.hash == inner_spec.hash + + expect !has_prefix(op.prefix, spec.leaf_spec.prefix) + + expect bytearray.length(op.prefix) >= inner_spec.min_prefix_length + expect bytearray.length(op.prefix) <= max_op_prefix_length + expect bytearray.length(op.suffix) % inner_spec.child_size == 0 + + if is_iavl_spec { + validate_iavl_ops_inner_op(op, b) } else { True } diff --git a/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/ops_test.ak b/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/ops_test.ak index 2b6a8f5b..9beede19 100644 --- a/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/ops_test.ak +++ b/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/ops_test.ak @@ -1,3 +1,4 @@ +use aiken/list use ibc/core/ics_023_vector_commitments/ics23/ops use ibc/core/ics_023_vector_commitments/ics23/proof use ibc/core/ics_023_vector_commitments/ics23/proofs.{ @@ -223,7 +224,11 @@ test test_check_against_spec_leaf_op_success() { length: 1, prefix: #"000202", } - ops.check_against_spec_leaf_op(leaf, proofs.iavl_spec()) + + let spec = proofs.iavl_spec() + let is_iavl_spec = proofs.spec_equals(spec, proofs.iavl_spec()) + + ops.check_against_spec_leaf_op(leaf, spec, is_iavl_spec) } test test_check_against_spec_leaf_op_fail_with_other_spec() fail { @@ -235,7 +240,11 @@ test test_check_against_spec_leaf_op_fail_with_other_spec() fail { length: 1, prefix: #"000202", } - ops.check_against_spec_leaf_op(leaf, proofs.iavl_spec()) + + let spec = proofs.iavl_spec() + let is_iavl_spec = proofs.spec_equals(spec, proofs.iavl_spec()) + + ops.check_against_spec_leaf_op(leaf, spec, is_iavl_spec) } test test_check_against_spec_inner_op_success() { @@ -245,7 +254,22 @@ test test_check_against_spec_inner_op_success() { prefix: #"04060220", suffix: #"20afca3de8c7aefe1041f185a34e977a976b37d6ce4cce80e5e4545b93413eca02", } - ops.check_against_spec_inner_op(inner_op, proofs.iavl_spec(), 1) + + let spec = proofs.iavl_spec() + let inner_spec = spec.inner_spec + let max_op_prefix_length = + ( list.length(inner_spec.child_order) - 1 ) * inner_spec.child_size + inner_spec.max_prefix_length + + let is_iavl_spec = proofs.spec_equals(spec, proofs.iavl_spec()) + + ops.check_against_spec_inner_op( + inner_op, + spec, + 1, + spec.inner_spec, + max_op_prefix_length, + is_iavl_spec, + ) } test test_check_against_spec_inner_op_fail_with_other_spec() fail { @@ -255,7 +279,21 @@ test test_check_against_spec_inner_op_fail_with_other_spec() fail { prefix: #"04060220", suffix: #"20afca3de8c7aefe1041f185a34e977a976b37d6ce4cce80e5e4545b93413eca02", } - ops.check_against_spec_inner_op(inner_op, proofs.tendermint_spec(), 1) + let spec = proofs.tendermint_spec() + let inner_spec = spec.inner_spec + let max_op_prefix_length = + ( list.length(inner_spec.child_order) - 1 ) * inner_spec.child_size + inner_spec.max_prefix_length + + let is_iavl_spec = proofs.spec_equals(spec, proofs.iavl_spec()) + + ops.check_against_spec_inner_op( + inner_op, + spec, + 1, + spec.inner_spec, + max_op_prefix_length, + is_iavl_spec, + ) } test test_apply_leaf_op_success_with_only_hash() { diff --git a/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/proof.ak b/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/proof.ak index 911cad8a..225f7bee 100644 --- a/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/proof.ak +++ b/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/proof.ak @@ -138,18 +138,38 @@ fn calculate_exist_internal( /// check_against_spec() will verify the leaf and all path steps are in the format defined in spec pub fn check_against_spec(p: ExistenceProof, spec: ProofSpec) -> Bool { + expect spec != proofs.null_proof_spec() + expect spec.leaf_spec != proofs.null_leaf_op() + + let is_iavl_spec = proofs.spec_equals(spec, proofs.iavl_spec()) + let leaf = get_leaf_existence_proof(p) expect leaf != proofs.null_leaf_op() - expect ops.check_against_spec_leaf_op(leaf, spec) + expect ops.check_against_spec_leaf_op(leaf, spec, is_iavl_spec) expect !(spec.min_depth > 0 && list.length(p.path) < spec.min_depth) expect !(spec.max_depth > 0 && list.length(p.path) > spec.max_depth) + + let inner_spec = spec.inner_spec + expect inner_spec != proofs.null_inner_spec() + + let max_op_prefix_length = + ( list.length(inner_spec.child_order) - 1 ) * inner_spec.child_size + inner_spec.max_prefix_length + let layer_num = 1 let accum_layer_num = list.reduce( p.path, layer_num, fn(accum_layer_num, inner) { - expect ops.check_against_spec_inner_op(inner, spec, layer_num) + expect + ops.check_against_spec_inner_op( + inner, + spec, + layer_num, + inner_spec, + max_op_prefix_length, + is_iavl_spec, + ) accum_layer_num + 1 }, ) diff --git a/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/proofs.ak b/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/proofs.ak index 7c4a68f1..84de438e 100644 --- a/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/proofs.ak +++ b/cardano/lib/ibc/core/ics-023-vector-commitments/ics23/proofs.ak @@ -67,19 +67,11 @@ pub type CommitmentRoot = ByteArray pub fn get_prefix_leaf_op(m: LeafOp) -> ByteArray { - if m != null_leaf_op() { - m.prefix - } else { - #[] - } + m.prefix } pub fn get_prefix_inner_op(m: InnerOp) -> ByteArray { - if m != null_inner_op() { - m.prefix - } else { - #[] - } + m.prefix } pub fn null_leaf_op() -> LeafOp {