3

If no one can recover the message, can I use this message as a "password" to some functions in the smart contract? like:

contract Test {
    bytes32 hash;

    constructor(bytes32 _hash) {
        hash = _hash;
    }

    function getReward(string calldata password) public  {
        require(
            keccak256(abi.encodePacked(password)) == hash,
            "wrong password!"
        );
        ...
    }

0

2 Answers 2

2

Nobody can recover the original message given the hash, it's impossible. An attacker would need to try many random messages to check if one produces the same hash, which is not feasible.

But, you cannot use the hash as a "password" in a smart contract, since when a user sends the "password" to your smart contract, the transaction will be sitting in the mempool and the "password" will be visible to everybody, which is not a good idea. In that scenario, a frontrunning attack can be launched, where a miner sees the transaction with the "password" in the mempool and decides to create another transaction of his own with the "password" and offer a higher gas price that your transaction, so his transaction is mined first than yours and hacking your contract.

There is nothing actually private in a smart contract or blockchain, even if you declare the variable as private in a smart contract, it could be seen directly with something web3.eth.getStorageAt like:

web3.eth.getStorageAt(yourSmartContractAddress, theIndexOfYourStateVariable);

For example, something like this:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

contract Rewards_v1 {

    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }

    // Only the owner is able to get the reward
    function getReward() public onlyOwner {
        //...
    }

}

Or like this:

contract Rewards {

    address public owner;
    mapping(address => bool) public whitelist;
    mapping(address => Reward) public rewards;

    struct Reward {
        address recipient;
        uint256 amount;
        //...
    }

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }

    modifier whitelisted() {
        require(whitelist[msg.sender], "Not whitelisted");
        _;
    }

    function getReward() public whitelisted view returns(Reward memory) {
        //... more logic
        return rewards[msg.sender];
    }

    function addToWhitelist(address recipient) public onlyOwner {
        whitelist[recipient] = true;
    }

    function removeFromWhitelist(address recipient) public onlyOwner {
        delete whitelist[recipient];
    }

    function addReward(address recipient, uint256 amount /*, more properties */) public onlyOwner {
        rewards[recipient] = Reward(recipient, amount);
    }

    //... more logic related to the reward issuing, transfering, etc.

}

It's just an idea. You can think of other approaches.

4
  • 1
    thank you, very professional answer! so is there any method to authorization without using address? I just wonder it
    – JESSE Bin
    Aug 31, 2022 at 15:19
  • Not really, not as you would think. But you could use an approach like using modifiers like onlyOwner, or use some sort of whitelist for users where you as the owner add them and allow certain users to call the getReward function and get their own reward and not anybody else's. Aug 31, 2022 at 16:31
  • 1
    Okay... Speaking of frontrunning attack, brings me to another question -----Why tornado cash can't affect by frontrunning attack?
    – JESSE Bin
    Aug 31, 2022 at 16:40
  • Probably because a miner would not know where the transaction is actually pointing to, hence, is not able to launch a frontrunning attack. Aug 31, 2022 at 17:39
1

You can not do this - transactions calling getReward are all publicly on-chain, so anyone could read the password that you pass in with the call to that function. Then anyone can call it from there

A better way to do this would be to have authorization be based on address instead of a password

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.