Skip to content
LogoLogo

Hashing

Crypto.keccak256 hashes bytes or string. To hash several values, encode them first.

hashing.lithe
(* A commit-reveal guessing game. `Crypto.keccak256` hashes `bytes` or `string`;
   encode several values with `Abi.encode` first, since `encodePacked` of
   adjacent dynamic values can collide. *)
 
import "std/abi";
import "std/crypto";
import "std/evm";
 
error WrongGuess;
error AlreadySolved;
 
event Solved of record {
  indexed by : address;
}
 
storage is record {
  answerHash : bytes32;
  solved : bool;
}
 
external function setPuzzle(const answerHash : bytes32) is {
  storage.answerHash := answerHash;
  storage.solved := false;
}
 
external pure function hashAnswer(const answer : string; const salt : bytes32) : bytes32 is
  Crypto.keccak256(Abi.encode(answer, salt))
 
external function solve(const answer : string; const salt : bytes32)
  raises WrongGuess | AlreadySolved
is {
  assert(not storage.solved, AlreadySolved);
  assert(Crypto.keccak256(Abi.encode(answer, salt)) = storage.answerHash, WrongGuess);
  storage.solved := true;
  emit Solved { by = Evm.sender(); };
}

Prefer Abi.encode over Abi.encodePacked when hashing several values. With packed encoding, ("ab", "c") and ("a", "bc") produce the same bytes.