Evaluate keccak256 of string literals at compile-time.

This commit is contained in:
chriseth 2020-07-07 15:10:21 +02:00
parent ad5ae2eefe
commit 0a0f578d7c
4 changed files with 50 additions and 15 deletions

View File

@ -1,5 +1,7 @@
### 0.6.12 (unreleased)
Compiler Features:
* Code Generator: Evaluate ``keccak256`` of string literals at compile-time.

View File

@ -792,20 +792,24 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
TypePointer const& argType = arguments.front()->annotation().type;
solAssert(argType, "");
arguments.front()->accept(*this);
// Optimization: If type is bytes or string, then do not encode,
// but directly compute keccak256 on memory.
if (*argType == *TypeProvider::bytesMemory() || *argType == *TypeProvider::stringMemory())
if (auto const* stringLiteral = dynamic_cast<StringLiteralType const*>(argType))
// Optimization: Compute keccak256 on string literals at compile-time.
m_context << u256(keccak256(stringLiteral->value()));
else if (*argType == *TypeProvider::bytesMemory() || *argType == *TypeProvider::stringMemory())
{
// Optimization: If type is bytes or string, then do not encode,
// but directly compute keccak256 on memory.
ArrayUtils(m_context).retrieveLength(*TypeProvider::bytesMemory());
m_context << Instruction::SWAP1 << u256(0x20) << Instruction::ADD;
m_context << Instruction::KECCAK256;
}
else
{
utils().fetchFreeMemoryPointer();
utils().packedEncode({argType}, TypePointers());
utils().toSizeAfterFreeMemoryPointer();
m_context << Instruction::KECCAK256;
}
m_context << Instruction::KECCAK256;
break;
}
case FunctionType::Kind::Log0:

View File

@ -1020,18 +1020,28 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
ArrayType const* arrayType = TypeProvider::bytesMemory();
auto array = convert(*arguments[0], *arrayType);
if (auto const* stringLiteral = dynamic_cast<StringLiteralType const*>(arguments.front()->annotation().type))
{
// Optimization: Compute keccak256 on string literals at compile-time.
define(_functionCall) <<
("0x" + keccak256(stringLiteral->value()).hex()) <<
"\n";
}
else
{
auto array = convert(*arguments[0], *arrayType);
define(_functionCall) <<
"keccak256(" <<
m_utils.arrayDataAreaFunction(*arrayType) <<
"(" <<
array.commaSeparatedList() <<
"), " <<
m_utils.arrayLengthFunction(*arrayType) <<
"(" <<
array.commaSeparatedList() <<
"))\n";
define(_functionCall) <<
"keccak256(" <<
m_utils.arrayDataAreaFunction(*arrayType) <<
"(" <<
array.commaSeparatedList() <<
"), " <<
m_utils.arrayLengthFunction(*arrayType) <<
"(" <<
array.commaSeparatedList() <<
"))\n";
}
break;
}
case FunctionType::Kind::ArrayPop:

View File

@ -0,0 +1,19 @@
// tests compile-time evaluation of keccak256 on literal strings
contract C {
function short() public pure returns (bool) {
bytes32 a = keccak256("abcdefghijklmn");
bytes memory s = "abcdefghijklmn";
return a == keccak256(s);
}
bytes32 constant sc = keccak256("abcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmn");
function long() public pure returns (bool, bool) {
bytes32 a = keccak256("abcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmn");
bytes memory s = "abcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmnabcdefghijklmn";
return (a == keccak256(s), sc == keccak256(s));
}
}
// ====
// compileViaYul: also
// ----
// short() -> true
// long() -> true, true