diff --git a/.changelog/unreleased/improvements/939-less-alloc.md b/.changelog/unreleased/improvements/939-less-alloc.md new file mode 100644 index 000000000..b7ed133f9 --- /dev/null +++ b/.changelog/unreleased/improvements/939-less-alloc.md @@ -0,0 +1,2 @@ +- Reduce vector allocations in Commitment computation. + ([\#939](https://github.com/cosmos/ibc-rs/pull/939)) diff --git a/crates/ibc/src/core/ics04_channel/commitment.rs b/crates/ibc/src/core/ics04_channel/commitment.rs index c2979e910..8903f310a 100644 --- a/crates/ibc/src/core/ics04_channel/commitment.rs +++ b/crates/ibc/src/core/ics04_channel/commitment.rs @@ -86,31 +86,59 @@ pub(crate) fn compute_packet_commitment( timeout_height: &TimeoutHeight, timeout_timestamp: &Timestamp, ) -> PacketCommitment { - let mut hash_input = timeout_timestamp.nanoseconds().to_be_bytes().to_vec(); + let mut hash_input = [0; 8 * 3 + 32]; - let revision_number = timeout_height.commitment_revision_number().to_be_bytes(); - hash_input.append(&mut revision_number.to_vec()); + hash_input[..8].copy_from_slice(&timeout_timestamp.nanoseconds().to_be_bytes()); + hash_input[8..16].copy_from_slice(&timeout_height.commitment_revision_number().to_be_bytes()); + hash_input[16..24].copy_from_slice(&timeout_height.commitment_revision_height().to_be_bytes()); + hash_input[24..].copy_from_slice(&hash(packet_data)); - let revision_height = timeout_height.commitment_revision_height().to_be_bytes(); - hash_input.append(&mut revision_height.to_vec()); - - let packet_data_hash = hash(packet_data); - hash_input.append(&mut packet_data_hash.to_vec()); - - hash(&hash_input).into() + hash(&hash_input).to_vec().into() } /// Compute the commitment for an acknowledgement. pub(crate) fn compute_ack_commitment(ack: &Acknowledgement) -> AcknowledgementCommitment { - hash(ack.as_ref()).into() + hash(ack.as_ref()).to_vec().into() } /// Helper function to hash a byte slice using SHA256. /// /// Note that computing commitments with anything other than SHA256 will /// break the Merkle proofs of the IBC provable store. -fn hash(data: impl AsRef<[u8]>) -> Vec { +fn hash(data: &[u8]) -> [u8; 32] { use sha2::Digest; - sha2::Sha256::digest(&data).to_vec() + sha2::Sha256::digest(data).into() +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_compute_packet_commitment() { + let expected: [u8; 32] = [ + 0xa9, 0x28, 0xb5, 0x1f, 0x62, 0xbd, 0x54, 0x00, 0x91, 0xec, 0x45, 0x1f, 0x4e, 0xf3, + 0x45, 0x79, 0x4f, 0x05, 0x9e, 0x65, 0x91, 0x08, 0x16, 0x86, 0x61, 0x26, 0xdc, 0x36, + 0x4f, 0x84, 0xcc, 0x15, + ]; + let actual = compute_packet_commitment( + "packet data".as_bytes(), + &TimeoutHeight::At(crate::Height::new(42, 24).unwrap()), + &Timestamp::from_nanoseconds(0x42).unwrap(), + ); + assert_eq!(&expected[..], actual.as_ref()); + } + + #[test] + fn test_compute_ack_commitment() { + let expected: [u8; 32] = [ + 0x05, 0x4e, 0xde, 0xc1, 0xd0, 0x21, 0x1f, 0x62, 0x4f, 0xed, 0x0c, 0xbc, 0xa9, 0xd4, + 0xf9, 0x40, 0x0b, 0x0e, 0x49, 0x1c, 0x43, 0x74, 0x2a, 0xf2, 0xc5, 0xb0, 0xab, 0xeb, + 0xf0, 0xc9, 0x90, 0xd8, + ]; + let ack = Acknowledgement::try_from(vec![0, 1, 2, 3]).unwrap(); + let actual = compute_ack_commitment(&ack); + assert_eq!(&expected[..], actual.as_ref()) + } }