1

I'm coming from Ethereum, and in Solidity we can pack data then hash it like keccak256(abi.encodePacked(typed_data1, typed_data2, ....)), and there is a corresponding approach in nodejs ethers.utils.keccak256(ethers.utils.solidityPack(types, values)).

Using this, the hash of the off-chain data can be signed, then submitted to a smart contract for verification.

I'm trying to figure out how to accomplish this in Solana and am having trouble finding resources. I was looking at anchor_lang::solana_program::keccak::hashv but this seems to be limited to arrays of u8 data, whereas I need to pack any sequence of data types.

Any tips and suggestions appreciated.

Edit:

Thanks to @arowana, I've manage to hash arbitary data using the following:

        #[derive(BorshSerialize)]
        struct OffChainData {
          a: u8,
          b: u64
        }
    let data = OffChainData { a: 1, b: 100213123 };
    let serialized_data: Vec<u8> = data.try_to_vec()?;
    let hash = anchor_lang::solana_program::keccak::hash(&serialized_data[..]);
    
    msg!("keccak::hash {:?}", hash);

My concern now is that the hash doesn't appear to be keccak-256, at least as I am used to seeing it (I would expect the above hash to be 0xa2bd9883818ee366d2793fc267127e1b2b6df28041c8a0d65fdaab5928e4d26e). However, the above code is giving the following as a result: Fg3EvJQ1r2FiKr7ReRUAFmn35LPGy1dVrmgVJCtf2h5B

My remaining question is how to get this result in nodejs, ideally via @project-serum/anchor

2 Answers 2

2

It is the same as solidity, you need to encode the data structure first, then only you can hash it. So once encoded to bytes you can use solana_program::keccak::hashv on the slice of bytes.

To pack data there is no solana strong standard but anchor is using the borsh crate https://crates.io/crates/borsh

#[derive(BorshSerialize]
struct SomeStuff {
  a: u8,
  b: u64
}
let data = SomeStuff { a: 1, b: 100213123 };

so if your data structure implements BorshSerialize (usually with the derive macro), you can serialize it with let serialized_data: Vec<u8> = data.try_to_vec()? then provide the slice &serialized_data to the hashv function.

1
  • I've updated my post with new info after trying your suggestions. My remaining question is how to achieve this with nodejs. I also am unfamiliar with the encoding that is being used by Solana. Fg3EvJQ1r2FiKr7ReRUAFmn35LPGy1dVrmgVJCtf2h5B doesn't seem like a hash I've ever seen.
    – britt
    Commented Aug 16, 2022 at 13:25
0

solana web3 is using @noble/hashes
see https://github.com/solana-labs/solana/pull/27630

Nodejs:

import { keccak_256 } from '@noble/hashes/sha3';

const secret = "YourSuperSecretString";
const hashedUint8Array = keccak_256(Buffer.from(secret))

Rust:

let secret = "YourSuperSecretString".to_string();
let secret_bytes = secret.as_bytes();
let res = anchor_lang::solana_program::keccak::hash(&secret_bytes);
let hash_bytes = res.to_bytes();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.