diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index b928291d8..5e3c5bd87 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -961,6 +961,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) bool TypeChecker::visit(IfStatement const& _ifStatement) { expectBoolOrShieldedBool(_ifStatement.condition()); + checkAndWarnShieldedCondition(_ifStatement.condition()); _ifStatement.trueStatement().accept(*this); if (_ifStatement.falseStatement()) _ifStatement.falseStatement()->accept(*this); @@ -1125,6 +1126,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) bool TypeChecker::visit(WhileStatement const& _whileStatement) { expectBoolOrShieldedBool(_whileStatement.condition()); + checkAndWarnShieldedCondition(_whileStatement.condition()); _whileStatement.body().accept(*this); return false; } @@ -1134,7 +1136,10 @@ bool TypeChecker::visit(ForStatement const& _forStatement) if (_forStatement.initializationExpression()) _forStatement.initializationExpression()->accept(*this); if (_forStatement.condition()) + { expectBoolOrShieldedBool(*_forStatement.condition()); + checkAndWarnShieldedCondition(*_forStatement.condition()); + } if (_forStatement.loopExpression()) _forStatement.loopExpression()->accept(*this); _forStatement.body().accept(*this); @@ -1413,6 +1418,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement) bool TypeChecker::visit(Conditional const& _conditional) { expectBoolOrShieldedBool(_conditional.condition()); + checkAndWarnShieldedCondition(_conditional.condition()); _conditional.trueExpression().accept(*this); _conditional.falseExpression().accept(*this); @@ -2215,6 +2221,21 @@ void TypeChecker::typeCheckABIEncodeFunctions( { auto const& argType = type(*arguments[i]); + // Prevent encoding of shielded types (skip check for tuples to avoid unimplemented feature errors) + if (argType && argType->category() != Type::Category::Tuple) + { + if (argType->isShielded() || argType->containsShieldedType()) + { + m_errorReporter.typeError( + 9664_error, + arguments[i]->location(), + "Shielded types cannot be ABI-encoded. " + "Encoding shielded values would leak information through the resulting bytes." + ); + continue; + } + } + if (argType->category() == Type::Category::RationalNumber) { auto const& rationalType = dynamic_cast(*argType); @@ -2354,6 +2375,22 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa return; } solAssert(!externalFunctionType->takesArbitraryParameters(), "Function must have fixed parameters."); + + // Check if function has shielded parameters + for (auto const& paramType : externalFunctionType->parameterTypes()) + { + if (paramType && (paramType->isShielded() || paramType->containsShieldedType())) + { + m_errorReporter.typeError( + 9664_error, + arguments[0]->location(), + "Cannot use abi.encodeCall with functions that have shielded parameter types. " + "Encoding shielded values would leak information through the resulting bytes." + ); + return; + } + } + // Tuples with only one component become that component std::vector> callArguments; @@ -2403,6 +2440,7 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa for (size_t i = 0; i < numParameters; i++) { Type const& argType = *type(*callArguments[i]); + BoolResult result = argType.isImplicitlyConvertibleTo(*externalFunctionType->parameterTypes()[i]); if (!result) m_errorReporter.typeError( @@ -4268,6 +4306,37 @@ bool TypeChecker::expectBoolOrShieldedBool(Expression const& _expression) { return expectType(_expression, *TypeProvider::boolean()); } +bool TypeChecker::checkAndWarnShieldedCondition(Expression const& _condition) +{ + Type const* condType = type(_condition); + + // Check if condition result type is shielded + bool isShielded = condType && (condType->isShielded() || condType->containsShieldedType()); + + // For binary operations, also check if operands are shielded (e.g., suint >= suint produces bool, not sbool) + if (!isShielded) + { + if (auto binOp = dynamic_cast(&_condition)) + { + Type const* leftType = type(binOp->leftExpression()); + Type const* rightType = type(binOp->rightExpression()); + isShielded = (leftType && (leftType->isShielded() || leftType->containsShieldedType())) || + (rightType && (rightType->isShielded() || rightType->containsShieldedType())); + } + } + + if (isShielded) + { + m_errorReporter.warning( + 9663_error, + _condition.location(), + "Using shielded types in branching conditions can leak information through " + "observable execution patterns such as gas costs, state changes, and execution traces." + ); + return true; + } + return false; +} void TypeChecker::requireLValue(Expression const& _expression) { diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 64401535a..ceb45fc11 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -176,6 +176,8 @@ class TypeChecker: private ASTConstVisitor bool expectType(Expression const& _expression, Type const& _expectedType); /// Helper function for conditionals that checks for either bool or shielded_bools. bool expectBoolOrShieldedBool(Expression const& _expression); + /// Checks if a condition uses shielded types and emits a warning about potential information leakage. + bool checkAndWarnShieldedCondition(Expression const& _condition); /// Runs type checks on @a _expression to infer its type and then checks that it is an LValue. void requireLValue(Expression const& _expression); diff --git a/test/libsolidity/semanticTests/functionCall/seismic_precompiles/AESEncryptAndDecryptWithRng.sol b/test/libsolidity/semanticTests/functionCall/seismic_precompiles/AESEncryptAndDecryptWithRng.sol index a2ce0112e..d777bb3c3 100644 --- a/test/libsolidity/semanticTests/functionCall/seismic_precompiles/AESEncryptAndDecryptWithRng.sol +++ b/test/libsolidity/semanticTests/functionCall/seismic_precompiles/AESEncryptAndDecryptWithRng.sol @@ -5,14 +5,14 @@ contract AES { bytes32 public constant AES_KEY = hex"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"; bytes public constant PLAINTEXT = hex"0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"; - suint96 NONCE; + uint96 NONCE; bytes public encryptedData; bytes public decryptedData; /// @notice Generates a random nonce using seismicRng. function updateNonce() public { bytes32 rngOutput = seismicRng(); - NONCE = suint96(suint256(rngOutput)); + NONCE = uint96(uint256(rngOutput)); } diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_shielded_address.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_shielded_address.sol index 1a9d16838..ece75d03d 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_shielded_address.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_shielded_address.sol @@ -8,4 +8,4 @@ contract testContract { } } // ---- -// TypeError 5407: (172-183): Cannot implicitly convert component at position 0 from "saddress" to "saddress payable". +// TypeError 9664: (155-170): Cannot use abi.encodeCall with functions that have shielded parameter types. Encoding shielded values would leak information through the resulting bytes. diff --git a/test/libsolidity/syntaxTests/abiEncoder/shielded_abi_encode_error.sol b/test/libsolidity/syntaxTests/abiEncoder/shielded_abi_encode_error.sol new file mode 100644 index 000000000..e8128a683 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/shielded_abi_encode_error.sol @@ -0,0 +1,33 @@ +contract TestShieldedABIEncode { + function testEncode(suint value) public pure returns (bytes memory) { + return abi.encode(value); + } + + function testEncodePacked(suint value) public pure returns (bytes memory) { + return abi.encodePacked(value); + } + + function testEncodeWithSelector(suint value) public pure returns (bytes memory) { + return abi.encodeWithSelector(bytes4(0x12345678), value); + } + + function testEncodeWithSignature(suint value) public pure returns (bytes memory) { + return abi.encodeWithSignature("transfer(uint256)", value); + } + + function testEncodeCall(suint value) public pure returns (bytes memory) { + return abi.encodeCall(this.someFunction, (value)); + } + + function someFunction(suint) external {} + + function testEncodeRegular(uint value) public pure returns (bytes memory) { + return abi.encode(value); + } +} +// ---- +// TypeError 9664: (133-138): Shielded types cannot be ABI-encoded. Encoding shielded values would leak information through the resulting bytes. +// TypeError 9664: (260-265): Shielded types cannot be ABI-encoded. Encoding shielded values would leak information through the resulting bytes. +// TypeError 9664: (419-424): Shielded types cannot be ABI-encoded. Encoding shielded values would leak information through the resulting bytes. +// TypeError 9664: (581-586): Shielded types cannot be ABI-encoded. Encoding shielded values would leak information through the resulting bytes. +// TypeError 9664: (704-721): Cannot use abi.encodeCall with functions that have shielded parameter types. Encoding shielded values would leak information through the resulting bytes. diff --git a/test/libsolidity/syntaxTests/parsing/shielded_conditional.sol b/test/libsolidity/syntaxTests/parsing/shielded_conditional.sol index 6611998ed..c78e313ca 100644 --- a/test/libsolidity/syntaxTests/parsing/shielded_conditional.sol +++ b/test/libsolidity/syntaxTests/parsing/shielded_conditional.sol @@ -21,7 +21,10 @@ contract TestSbool { } // ---- +// Warning 9663: (81-82): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. +// Warning 9663: (227-228): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. // Warning 9661: (294-315): Bool Literals converted to shielded bools will leak during contract deployment. +// Warning 9663: (332-333): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. // Warning 2018: (25-162): Function state mutability can be restricted to pure // Warning 2018: (168-243): Function state mutability can be restricted to pure // Warning 2018: (249-394): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/shielded_for_loop.sol b/test/libsolidity/syntaxTests/parsing/shielded_for_loop.sol index 08dcdd68c..43bfe8456 100644 --- a/test/libsolidity/syntaxTests/parsing/shielded_for_loop.sol +++ b/test/libsolidity/syntaxTests/parsing/shielded_for_loop.sol @@ -9,4 +9,7 @@ contract TestForSbool { return uint(counter); } } +// ---- +// Warning 9663: (128-137): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. +// Warning 9663: (182-198): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. diff --git a/test/libsolidity/syntaxTests/parsing/shielded_for_loop_simple_initexpr.sol b/test/libsolidity/syntaxTests/parsing/shielded_for_loop_simple_initexpr.sol index f33304449..6188f9623 100644 --- a/test/libsolidity/syntaxTests/parsing/shielded_for_loop_simple_initexpr.sol +++ b/test/libsolidity/syntaxTests/parsing/shielded_for_loop_simple_initexpr.sol @@ -8,6 +8,7 @@ contract test { } // ---- // Warning 9660: (62-85): Literals converted to shielded integers will leak during contract deployment. +// Warning 9663: (103-116): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. // Warning 5740: (118-121): Unreachable code. // Warning 5740: (160-168): Unreachable code. // Warning 5667: (33-43): Unused function parameter. Remove or comment out the variable name to silence this warning. diff --git a/test/libsolidity/syntaxTests/parsing/shielded_for_loop_single_stmt_body.sol b/test/libsolidity/syntaxTests/parsing/shielded_for_loop_single_stmt_body.sol index 98bf6dc51..d288e6b6c 100644 --- a/test/libsolidity/syntaxTests/parsing/shielded_for_loop_single_stmt_body.sol +++ b/test/libsolidity/syntaxTests/parsing/shielded_for_loop_single_stmt_body.sol @@ -7,5 +7,6 @@ contract test { } // ---- // Warning 9660: (62-83): Literals converted to shielded integers will leak during contract deployment. +// Warning 9663: (112-125): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. // Warning 5667: (33-43): Unused function parameter. Remove or comment out the variable name to silence this warning. // Warning 2018: (20-159): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/shielded_for_loop_vardef_initexpr.sol b/test/libsolidity/syntaxTests/parsing/shielded_for_loop_vardef_initexpr.sol index 558cf1d4b..f2b0abef1 100644 --- a/test/libsolidity/syntaxTests/parsing/shielded_for_loop_vardef_initexpr.sol +++ b/test/libsolidity/syntaxTests/parsing/shielded_for_loop_vardef_initexpr.sol @@ -7,6 +7,7 @@ contract test { } // ---- // Warning 9660: (67-88): Literals converted to shielded integers will leak during contract deployment. +// Warning 9663: (90-103): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. // Warning 5740: (105-108): Unreachable code. // Warning 5740: (147-155): Unreachable code. // Warning 5667: (33-43): Unused function parameter. Remove or comment out the variable name to silence this warning. diff --git a/test/libsolidity/syntaxTests/parsing/shielded_if_statement.sol b/test/libsolidity/syntaxTests/parsing/shielded_if_statement.sol index a40cba1f6..62bd3786d 100644 --- a/test/libsolidity/syntaxTests/parsing/shielded_if_statement.sol +++ b/test/libsolidity/syntaxTests/parsing/shielded_if_statement.sol @@ -4,6 +4,7 @@ contract test { } } // ---- +// Warning 9663: (81-94): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. // Warning 9660: (117-135): Literals converted to shielded integers will leak during contract deployment. // Warning 6321: (61-65): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable. // Warning 2072: (117-124): Unused local variable. diff --git a/test/libsolidity/syntaxTests/types/shielded_conditional_warning.sol b/test/libsolidity/syntaxTests/types/shielded_conditional_warning.sol new file mode 100644 index 000000000..51174f71e --- /dev/null +++ b/test/libsolidity/syntaxTests/types/shielded_conditional_warning.sol @@ -0,0 +1,20 @@ +contract TestShieldedConditionalWarnings { + function testShieldedBool(sbool condition) public pure returns (uint) { + return condition ? 1 : 2; + } + + function testShieldedComparison(suint a, suint b) public pure returns (uint) { + return a >= b ? 100 : 50; + } + + function testRegularBool(bool flag) public pure returns (uint) { + return flag ? 1 : 2; + } + + function testRegularComparison(uint a, uint b) public pure returns (uint) { + return a >= b ? 100 : 50; + } +} +// ---- +// Warning 9663: (134-143): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. +// Warning 9663: (258-264): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. diff --git a/test/libsolidity/syntaxTests/types/shielded_for_condition_warning.sol b/test/libsolidity/syntaxTests/types/shielded_for_condition_warning.sol new file mode 100644 index 000000000..ec823894f --- /dev/null +++ b/test/libsolidity/syntaxTests/types/shielded_for_condition_warning.sol @@ -0,0 +1,32 @@ +contract TestShieldedForWarnings { + function testShieldedBool(sbool condition) public { + for (; condition;) { + break; + } + } + + function testShieldedComparison(suint counter, suint limit) public { + for (; counter < limit;) { + counter++; + } + } + + function testRegularBool(bool flag) public { + for (; flag;) { + break; + } + } + + function testRegularComparison(uint counter, uint limit) public { + for (; counter < limit;) { + counter++; + } + } +} +// ---- +// Warning 9663: (106-115): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. +// Warning 9663: (244-259): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. +// Warning 2018: (39-154): Function state mutability can be restricted to pure +// Warning 2018: (160-302): Function state mutability can be restricted to pure +// Warning 2018: (308-411): Function state mutability can be restricted to pure +// Warning 2018: (417-556): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/types/shielded_if_condition_warning.sol b/test/libsolidity/syntaxTests/types/shielded_if_condition_warning.sol new file mode 100644 index 000000000..b91bff1fc --- /dev/null +++ b/test/libsolidity/syntaxTests/types/shielded_if_condition_warning.sol @@ -0,0 +1,36 @@ +contract TestShieldedIfWarnings { + function testShieldedBool(sbool condition) public { + if (condition) { + uint x = 1; + } + } + + function testShieldedComparison(suint a, suint b) public { + if (a >= b) { + uint x = 1; + } + } + + function testRegularBool(bool flag) public { + if (flag) { + uint x = 1; + } + } + + function testRegularComparison(uint a, uint b) public { + if (a >= b) { + uint x = 1; + } + } +} +// ---- +// Warning 9663: (102-111): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. +// Warning 9663: (231-237): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. +// Warning 2072: (127-133): Unused local variable. +// Warning 2072: (253-259): Unused local variable. +// Warning 2072: (363-369): Unused local variable. +// Warning 2072: (486-492): Unused local variable. +// Warning 2018: (38-154): Function state mutability can be restricted to pure +// Warning 2018: (160-280): Function state mutability can be restricted to pure +// Warning 2018: (286-390): Function state mutability can be restricted to pure +// Warning 2018: (396-513): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/types/shielded_while_condition_warning.sol b/test/libsolidity/syntaxTests/types/shielded_while_condition_warning.sol new file mode 100644 index 000000000..1a9dbc41f --- /dev/null +++ b/test/libsolidity/syntaxTests/types/shielded_while_condition_warning.sol @@ -0,0 +1,32 @@ +contract TestShieldedWhileWarnings { + function testShieldedBool(sbool condition) public { + while (condition) { + break; + } + } + + function testShieldedComparison(suint counter, suint limit) public { + while (counter < limit) { + counter++; + } + } + + function testRegularBool(bool flag) public { + while (flag) { + break; + } + } + + function testRegularComparison(uint counter, uint limit) public { + while (counter < limit) { + counter++; + } + } +} +// ---- +// Warning 9663: (108-117): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. +// Warning 9663: (245-260): Using shielded types in branching conditions can leak information through observable execution patterns such as gas costs, state changes, and execution traces. +// Warning 2018: (41-155): Function state mutability can be restricted to pure +// Warning 2018: (161-302): Function state mutability can be restricted to pure +// Warning 2018: (308-410): Function state mutability can be restricted to pure +// Warning 2018: (416-554): Function state mutability can be restricted to pure