0

I was going through the solidity docs and in a contract example given I have seen keccak256 used.

// Perform checks to determine if transferring a token to the
// `OwnedToken` contract should proceed
function isTokenTransferOK(address currentOwner, address newOwner)
    public
    pure
    returns (bool ok)
{
    // Check an arbitrary condition to see if transfer should proceed
    return keccak256(abi.encodePacked(currentOwner, newOwner))[0] == 0x7f;
}

From this video I was able to understand that:

A hash function is a function that takes in an arbitrary size input and outputs data of fixed size.

I also understood that keccak is a hash function.

When is hashing used when creating a smart contract? What is its purpose? An example would really help me understand.

1

IMHO, it's not a terrific example for teaching.

Hash functions are very useful for validating information and they are used to prove things with Smart Contracts as well as on the blockchain itself. For example, block transactions are hashed which is a sort of fingerprint for authentic blocks. Previous blockhashes are part of that functions, so it forms a chain.

This will not be an academic description but it will give you a working knowledge of this tool.

Properties of a Hash function:

  1. Deterministic: For any given input, the output is always the same.
  2. Fixed Size: e.g. 32 bytes
  3. Uncorrelated: If even a single bit of the input is changed, the output in completely changed in an unpredictable way
  4. Collision-resistant: No two inputs should produce the same output, a "defect" known as a hash collision.
  5. High-performant: The compute resources to the compute the hash should be reasonable.
  6. One-way function: A hash tells one nothing about the size, format or content of the input.

Hashes are commonly used to store passwords on disks because hashes tell one nothing about the passwords, but user-inputted passwords can be quickly hashed and then compared to a table.

They are also commonly used to validate documents/files by storing only the hash of the files in a system of record such as a Smart Contract. Given that record, anyone can confirm that the file they have matches a previously-recorded hash - it must be the same file.

Here's a way to put money in a box and let it be released if someone knows a secret word.


pragma solidity 0.7.6;

contract Abracadabra {
    
    bytes32 public publicHash;
    
    constructor(bytes32 publicHash_) {
        publicHash = publicHash_;
    }
    
    function honeyPot(bytes32 password) public {
        
        // a little concatonation, then hash it
        // it can only be claimed by the intended recipient

        bytes32 hash = keccak256(abi.encodePacked(password, msg.sender));
    
        // no one knows the password unless they learn about it off-chain
        // revert the transaction if the hash is wrong

        require(hash == publicHash, "That's not the magic word");

        // the money only goes to msg.sender to prevent front-running

        msg.sender.transfer(address(this).balance);
    }
    
    receive () external payable {}
}

Notice that the hash is on the chain from the outset, but it doesn't help anyone figure out the password. The contract naively stored a password instead of a hash, then everyone would see the password and that would be bad. There's certainly more to think about if securing such a thing but I want to keep this answer on point.

You need to be able to make the hash when you deploy it. This is not safe from a security standpoint, but it should be possible to play with it in Remix.

// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.7.6;

contract Abracadabra {
    
    bytes32 public publicHash;
    
    constructor(bytes32 publicHash_) {
        publicHash = publicHash_;
    }
    
    function honeyPot(bytes32 password) public {   
        require(hashHelper(password, msg.sender) == publicHash, "That's not the magic word");
        msg.sender.transfer(address(this).balance);
    }
    
    function hashHelper(bytes32 password, address receiver) public pure returns(bytes32 hash) {
        hash = keccak256(abi.encodePacked(password, receiver));        
    }
    
    receive () external payable {}
}

Hope it helps.

7
  • You example is a great example. It showed me other utilities of the blockchain and smart contracts. Thank you. You have said that for a production contract code: "There's certainly more to think about if securing such a thing but I want to keep this answer on point." I would like to know of the more ways to secure such a contract so that it is production ready.
    – YulePale
    Apr 10 at 8:19
  • 1
    This one should be safe from "front-running" because it is limited to a specific receiver. The receiver address that signs is a second factor in addition to the password and that means others are unable to profit from knowledge of the password, which they will have when the unmined transaction (input) is visible in the pending transactions pool. Apr 10 at 8:31
  • 1
    Even though the hashHelper function is pure and runs locally it would not be safe to use for most users because they might (probably are) be using MetaMask and Infura (or similar) and that could be a starting point for a man-in-the-middle attack. They would need to know the password in order to give to the "client", so that's leak. A solution to that problem is to work out how to compute it client-side, e.g. with JavaScript. Apr 10 at 8:33
  • 1
    So you are saying to avoid the man in the middle attack the password should be hashed either in the browser or server side is before sending it to the blockchain? So that no one can see the actual password before the transaction gets mined?
    – YulePale
    Apr 10 at 12:20
  • Is doing it in the browser, let’s say with react or angular safe?
    – YulePale
    Apr 10 at 12:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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