diff --git a/Changelog.md b/Changelog.md index d427d637f..e6e49a3c6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,7 @@ ### 0.6.12 (unreleased) +Compiler Features: + * Code Generator: Evaluate ``keccak256`` of string literals at compile-time. diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index ffa8ced4c..694ea8fa6 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -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(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: diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index c14d65121..a8d657b02 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -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(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: diff --git a/test/libsolidity/semanticTests/specialFunctions/keccak256_optimized.sol b/test/libsolidity/semanticTests/specialFunctions/keccak256_optimized.sol new file mode 100644 index 000000000..cb3c8d608 --- /dev/null +++ b/test/libsolidity/semanticTests/specialFunctions/keccak256_optimized.sol @@ -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