Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

abi.encodePacked mismatch between rust and solidity #2225

Closed
nabeel99 opened this issue Mar 3, 2023 · 3 comments
Closed

abi.encodePacked mismatch between rust and solidity #2225

nabeel99 opened this issue Mar 3, 2023 · 3 comments
Labels
bug Something isn't working

Comments

@nabeel99
Copy link

nabeel99 commented Mar 3, 2023

Version

1.5.0

Platform

Darwin random-MacBook-Pro.local 22.3.0 Darwin Kernel Version 22.3.0: Mon Jan 30 20:39:46 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T6020 arm64
Description

BUG : coded the same thing in solidity and rust, a function that returns the hash of a encodePacked uint256,
but apparently the outputs don't match,
Reason to do this :A sanity check since a more advance use case which I needed to do wasn't matching up with the solidity output, to my surprise the sanity check also failed

I tried this code(Rust Version):

use ethers::abi::encode_packed;
use ethers::abi::token::Token;
use ethers::types::{U256};
use ethers::utils::keccak256;
use ethers::utils::hex;

fn main() {


    let uint256_5 = U256::from(5);
    let result = get_keccak_256_of_uint(uint256_5);
    let result_str = format!("0x{}",hex::encode(result));

    println!("HASH IS {} ",result_str);


}



fn get_keccak_256_of_uint(x : U256)-> Vec<u8> { 

    let token = &[Token::Uint(x)];
    let encoded_value = encode_packed(token).expect("encode pack failed");
    keccak256(encoded_value).to_vec()
}


Solidity Version :

    function get_keccak_hash_of_uint_5 () public pure  returns(bytes32) {
uint x=5
    
        return keccak256(abi.encodePacked(x));    }


    }

I expected to see this happen(Solidity Output:
bytes32: 0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0

Instead, this happened (rust output) : 0xdbb8d0f4c497851a5043c6363657698cb1387682cac2f786c731f8936109d795
Posted this on telegram , was told it could better be checked out as a gh issue with the code, hopefully with your help I can get to the bottom of this annoying discrepancy.

@nabeel99 nabeel99 added the bug Something isn't working label Mar 3, 2023
@mattsse
Copy link
Collaborator

mattsse commented Mar 3, 2023

@DaniPopes is this right?

let start = if in_array { 0 } else { 32 - ((n.bits() + 7) / 8) };

@DaniPopes
Copy link
Collaborator

DaniPopes commented Mar 3, 2023

Solidity Version : ...

This function doesn't compile in Solidity with: error[7279]: TypeError: Cannot perform packed encoding for a literal. Please convert it to an explicit type first.

The input is ambiguous, I'll assume that you tried this code instead:

    function get_keccak_hash_of_uint256(uint256 x) public pure returns(bytes32) {
        return keccak256(abi.encodePacked(x));
    }

When called with 5, this would produce: keccak256(0x0000000000000000000000000000000000000000000000000000000000000005) -> 0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0

This is because the number is padded to the length of uint256 (32 bytes).

Our encode_packed does not do this padding, as explained in the telegram discussion and in the documentation of the function, thus the result of your Rust function will be that of the keccak256 of the single byte 0x05 with no padding:
keccak256(0x05) -> 0xdbb8d0f4c497851a5043c6363657698cb1387682cac2f786c731f8936109d795

If you want the padding of a uint<N>:

let n = ...;
let n = U256::from(n);
let mut buf = [0; 32];
n.to_big_endian(&mut buf);
let start = 32 - N / 8;
let uintN = Token::Bytes(buf[start..32].to_vec());

is this right?

Please see the discussion in the PR (#2104 (comment)).

@nabeel99
Copy link
Author

nabeel99 commented Mar 3, 2023

aah, the encodePacked name is kinda of a misnomer I was under the impression the solidity encodePacked would only use the minimum number of bits required ? it dint seem that to be the case or I misunderstand it even now.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants