From a13b6505ce733e7bd68c1a5523d12b254db66f32 Mon Sep 17 00:00:00 2001 From: CJ Cobb <46455409+cjcobb23@users.noreply.github.com> Date: Fri, 22 Sep 2023 12:55:25 -0400 Subject: [PATCH] feat(multisig-prover): bcs msg to sign (#117) * feat(multisig-prover): bcs msg to sign --- contracts/multisig-prover/src/encoding/bcs.rs | 57 ++++++++++++++++++- contracts/multisig-prover/src/encoding/mod.rs | 2 +- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/contracts/multisig-prover/src/encoding/bcs.rs b/contracts/multisig-prover/src/encoding/bcs.rs index 7605da1d6..6e28354aa 100644 --- a/contracts/multisig-prover/src/encoding/bcs.rs +++ b/contracts/multisig-prover/src/encoding/bcs.rs @@ -3,9 +3,13 @@ use cosmwasm_std::{HexBinary, Uint256}; use itertools::Itertools; use multisig::{key::Signature, msg::Signer}; -use crate::{error::ContractError, types::Operator}; +use crate::{ + error::ContractError, + types::{CommandBatch, Operator}, +}; use super::Data; +use sha3::{Digest, Keccak256}; // TODO: all of the public functions in this file should be moved to a trait, // that has an abi and bcs implementation (and possibly others) @@ -111,6 +115,19 @@ pub fn encode(data: &Data) -> HexBinary { .into() } +pub fn msg_digest(command_batch: &CommandBatch) -> HexBinary { + let msg = Keccak256::digest(encode(&command_batch.data).as_slice()); + + // Sui is just mimicking EVM here + let unsigned = [ + "\x19Sui Signed Message:\n32".as_bytes(), // Keccek256 hash length = 32 + msg.as_slice(), + ] + .concat(); + + Keccak256::digest(unsigned).as_slice().into() +} + fn u256_to_u128(val: Uint256) -> u128 { val.to_string().parse().expect("value is larger than u128") } @@ -128,6 +145,7 @@ mod test { use std::vec; use bcs::from_bytes; + use connection_router::msg::Message; use cosmwasm_std::{Addr, HexBinary, Uint256}; use multisig::{ key::{PublicKey, Signature}, @@ -139,11 +157,12 @@ mod test { bcs::{ command_params, encode, encode_proof, make_command_id, u256_to_u128, u256_to_u64, }, - Data, + CommandBatchBuilder, Data, }, types::Command, }; + use super::msg_digest; #[test] fn test_u256_to_u128() { let val = u128::MAX; @@ -343,4 +362,38 @@ mod test { assert_eq!(payload_hash_decoded, payload_hash.to_vec()); } + + #[test] + fn test_msg_to_sign() { + let mut builder = CommandBatchBuilder::new(1u128.into(), crate::encoding::Encoder::Bcs); + let _ = builder + .add_message(Message { + id: "ethereum:foobar".into(), + destination_address: "0F".repeat(32), + destination_chain: "sui".into(), + source_chain: "ethereum".into(), + source_address: "0x00".into(), + payload_hash: HexBinary::from(vec![1; 32]), + }) + .unwrap(); + let batch = builder.build().unwrap(); + let msg = msg_digest(&batch); + assert_eq!(msg.len(), 32); + + let mut builder = CommandBatchBuilder::new(1u128.into(), crate::encoding::Encoder::Bcs); + let _ = builder + .add_message(Message { + id: "ethereum:foobar2".into(), + destination_address: "0A".repeat(32), + destination_chain: "sui".into(), + source_chain: "ethereum".into(), + source_address: "0x00".into(), + payload_hash: HexBinary::from(vec![2; 32]), + }) + .unwrap(); + + let batch = builder.build().unwrap(); + let msg2 = msg_digest(&batch); + assert_ne!(msg, msg2); + } } diff --git a/contracts/multisig-prover/src/encoding/mod.rs b/contracts/multisig-prover/src/encoding/mod.rs index c6a9c03f3..14e905ad4 100644 --- a/contracts/multisig-prover/src/encoding/mod.rs +++ b/contracts/multisig-prover/src/encoding/mod.rs @@ -113,7 +113,7 @@ impl CommandBatch { pub fn msg_digest(&self) -> HexBinary { match self.encoder { Encoder::Abi => abi::msg_digest(self), - Encoder::Bcs => todo!(), + Encoder::Bcs => bcs::msg_digest(self), } }