Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incrementation/ Decrementation fixes #313

Merged
merged 10 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const collectIncrements = (bpg: BoilerplateGenerator) => {
incrementsString += ` + ${dec.name}`;
}
}

return { incrementsArray, incrementsString };
};

Expand Down Expand Up @@ -353,7 +354,6 @@ class BoilerplateGenerator {
} else {
throw new Error('This should be unreachable.');
}

return index;
}

Expand Down
98 changes: 73 additions & 25 deletions src/transformers/visitors/checks/incrementedVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,21 @@ const literalOneNode = {
precedingOperator: '',
};

const collectIncrements = (increments: any, incrementedIdentifier: any) => {
const collectIncrements = (increments: any, incrementedIdentifier: any, assignmentOperator: any, isTupleExpression: boolean) => {
const { operands, precedingOperator } = increments;
const newIncrements: any[] = [];
for (const [index, operand] of operands.entries()) {
if(assignmentOperator === '=' && precedingOperator[1] === '-' && index != 0){
SwatiEY marked this conversation as resolved.
Show resolved Hide resolved
if(index == 1)
operand.precedingOperator = '+';
else {
if(!isTupleExpression)
operand.precedingOperator = precedingOperator[index] === '+' ? '-' : '+';
else
operand.precedingOperator = precedingOperator[index];
}
}
else
operand.precedingOperator = precedingOperator[index];
if (
operand.name !== incrementedIdentifier.name &&
Expand All @@ -36,6 +47,15 @@ const collectIncrements = (increments: any, incrementedIdentifier: any) => {
return newIncrements;
};

const mixedOperatorsWarning = (path: NodePath) => {
backtrace.getSourceCode(path.node.src);
logger.warn(
`When we mix positive and negative operands in assigning to a secret variable, we may encounter underflow errors. Make sure that incrementing (a = a + ...) always increases the secret state value while decrementing (a = a - ...) decreases it.
\nWhenever we see something like a = a + b - c, we assume it's a positive incrementation, so b > c. Similarly, we assume a = a - b + c is a decrementation, so c - b < a.`,
);

};

// marks the parent ExpressionStatement
const markParentIncrementation = (
path: NodePath,
Expand All @@ -50,14 +70,16 @@ const markParentIncrementation = (
: incrementedIdentifier;
const parent = path.getAncestorOfType('ExpressionStatement');
if (!parent) throw new Error(`No parent of node ${path.node.name} found`);
const isTupleExpression = parent?.node.expression?.rightHandSide?.nodeType === 'TupleExpression' || parent?.node.expression?.rightHandSide?.rightExpression?.nodeType === 'TupleExpression'
const assignmentOp = parent?.node.expression?.operator;
parent.isIncremented = isIncremented;
parent.isDecremented = isDecremented;
parent.incrementedDeclaration = incrementedIdentifier.referencedDeclaration;
parent.node.expression.incrementedDeclaration = parent.incrementedDeclaration;
state.unmarkedIncrementation = false;
state.incrementedIdentifier = incrementedIdentifier;
if (increments?.operands)
increments = collectIncrements(increments, incrementedIdentifier);
increments = collectIncrements(increments, incrementedIdentifier, assignmentOp, isTupleExpression);
increments?.forEach((inc: any) => {
if (
inc.precedingOperator === '-' &&
Expand Down Expand Up @@ -93,23 +115,19 @@ const getIncrementedPath = (path: NodePath, state: any) => {
state.stopTraversal = !!state.incrementedPath?.node;
};

const mixedOperatorsWarning = (path: NodePath) => {
backtrace.getSourceCode(path.node.src);
logger.warn(
`When we mix positive and negative operands in assigning to a secret variable, we may encounter underflow errors. Make sure that incrementing (a = a + ...) always increases the secret state value while decrementing (a = a - ...) decreases it. \nWhenever we see something like a = a + b - c, we assume it's a positive incrementation, so b > c. Similarly, we assume a = a - b + c is a decrementation, so c - b < a.`,
);
};


const binOpToIncrements = (path: NodePath, state: any) => {
const parentExpressionStatement = path.getAncestorOfType(
'ExpressionStatement',
);
const lhsNode = parentExpressionStatement?.node.expression?.leftHandSide;
const assignmentOp = parentExpressionStatement?.node.expression?.operator;
const { operator, leftExpression, rightExpression } = path.node;
const { operator, leftExpression, rightExpression } = path.node ;

const operands = [leftExpression, rightExpression];
const precedingOperator = ['+', operator];

const isTupleExpression = operands[1].nodeType === 'TupleExpression';
// if we dont have any + or -, it can't be an incrementation
if (
!operator.includes('+') &&
Expand All @@ -120,25 +138,56 @@ const binOpToIncrements = (path: NodePath, state: any) => {
markParentIncrementation(path, state, false, false, lhsNode);
return;
}

// correct the operands for case when a = a - (b + c + d).
if(assignmentOp === '=' && isTupleExpression) {
SwatiEY marked this conversation as resolved.
Show resolved Hide resolved

operands[0] = operands[1].components[0].leftExpression;
precedingOperator.push(operands[1].components[0].operator);
operands[1] = operands[1].components[0].rightExpression;

for (const [index, operand] of operands.entries()) {
if (operand.nodeType === 'BinaryOperation') {
operands[index] = operand.leftExpression;
operands.splice(index+1, 0, operand.rightExpression);
precedingOperator.splice(index+2, 0, operand.operator);
}
}

}
// fills an array of operands
// e.g. if we have a = b - c + a + d, operands = [b, c, a, d]
if(!isTupleExpression){
for (const [index, operand] of operands.entries()) {
if (operand.nodeType === 'BinaryOperation') {
operands[index] = operand.leftExpression;
operands.push(operand.rightExpression);
precedingOperator.push(operand.operator);
operands.splice(index+1, 0, operand.rightExpression);
precedingOperator.splice(index+1, 0, operand.operator);
}
}
}}
// if we have mixed operators, we may have an underflow or not be able to tell whether this is increasing (incrementation) or decreasing (decrementation) the secret value
if (
precedingOperator.length > 2 &&
precedingOperator.includes('+') &&
precedingOperator.includes('-') &&
parentExpressionStatement
)
mixedOperatorsWarning(parentExpressionStatement);

{
mixedOperatorsWarning(parentExpressionStatement);
if(!isTupleExpression)
logger.warn(
`Whenever you have multiple operands in an expression, such as a = a - b - c + d, it's better to use parentheses for clarity. For example, rewrite it as a = a - (b + c - d). This makes the expression easier to understand. `,
);
}
if(assignmentOp === '=' && precedingOperator.length > 2) {
SwatiEY marked this conversation as resolved.
Show resolved Hide resolved
if(isTupleExpression) {
operands.splice(0, 0, path.node.leftExpression);
} else {
if(operands[0].rightExpression){
operands.splice(1, 0, operands[0].rightExpression);
precedingOperator.splice(1, 0, operands[0].operator);
operands[0] = operands[0].leftExpression;}
}
}
return { operands, precedingOperator };
};

Expand All @@ -153,6 +202,7 @@ export default {
ExpressionStatement: {
enter(path: NodePath, state: any) {
// starts here - if the path hasn't yet been marked as incremented, we find out if it is

if (path.isIncremented === undefined) {
state.unmarkedIncrementation = true;
state.increments = [];
Expand All @@ -175,7 +225,6 @@ export default {
const { isIncremented, isDecremented } = path;
expressionNode.isIncremented = isIncremented;
expressionNode.isDecremented = isDecremented;

// print if in debug mode
if (logger.level === 'debug') backtrace.getSourceCode(node.src);
logger.debug(`statement is incremented? ${isIncremented}`);
Expand Down Expand Up @@ -238,7 +287,6 @@ export default {
const { operator, leftHandSide, rightHandSide } = node;
const lhsSecret = !!scope.getReferencedBinding(leftHandSide)?.isSecret;


if (['bool', 'address'].includes(leftHandSide.typeDescriptions.typeString)) {
markParentIncrementation(path, state, false, false, leftHandSide);
const lhsBinding = scope.getReferencedBinding(leftHandSide)
Expand Down Expand Up @@ -350,7 +398,6 @@ export default {
}

const { operands, precedingOperator } = binOpToIncrements(path, state) || {};

if (!operands || !precedingOperator) return;

// if we find our lhs variable (a) on the rhs (a = a + b), then we make sure we don't find it again (a = a + b + a = b + 2a)
Expand Down Expand Up @@ -394,7 +441,6 @@ export default {
discoveredLHS += 1;
isIncremented = { incremented: true, decremented: true };
}

// a = something - a
if (
nameMatch &&
Expand All @@ -416,17 +462,19 @@ export default {
) {
// a = a + b - c - d counts as an incrementation since the 1st operator is a plus
// the mixed operators warning will have been given
// length of operator will be more than 2 in case of mixed operators
if (
precedingOperator.length > 2 &&
precedingOperator.includes('+') &&
precedingOperator.includes('-') &&
precedingOperator[0] === '+'
)
isIncremented.decremented = false;
precedingOperator.includes('-')
){
isIncremented.decremented = precedingOperator[1] === '+' ? false : true;
}
markParentIncrementation(
path,
state,
isIncremented.incremented,
false,
isIncremented.decremented,
lhsNode.baseExpression || lhsNode,
{ operands, precedingOperator },
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const internalCallVisitor = {
let sendTransactionNode : any;
let newdecrementedSecretStates = [];
node._newASTPointer.forEach(file => {
state.intFnindex = {};
state.intFnindex = {};
state.internalFncName?.forEach( (name, index)=> {
let callingFncName = state.callingFncName[index].name;
if(file.fileName === name && file.nodeType === 'File') {
Expand Down
3 changes: 3 additions & 0 deletions test/contracts/Arrays1.zol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ contract Assign {
index++;
a = a + index;
index++;
j =j + 2;
j++;
b[index] = value;
a += j;
}

function remove(secret uint256 value) public {
Expand Down
2 changes: 1 addition & 1 deletion test/contracts/Arrays2.zol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract Assign {
b[index] = value;
index++;
j++;
b[index] = value +index +j;
b[index] = (value - index +j);
index += 1;
a += value + index;
b[index] = value + index;
Expand Down
30 changes: 30 additions & 0 deletions test/contracts/Assign-Increment.zol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: CC0

pragma solidity ^0.8.0;

contract Assign {

secret uint256 private a;
secret uint256 private b;
function add(secret uint256 value) public {
a += value;
unknown b += value;
}

function remove(secret uint256 value, secret uint256 value1) public {
a += value;
b -= value + value1;
}

function add1(secret uint256 value, secret uint256 value1, secret uint256 value2, secret uint256 value3) public {
a = a + value - value1 + value3;
unknown b = b + value1 - value2 - value3;
}


function remove1(secret uint256 value, secret uint256 value1, secret uint256 value2, secret uint256 value3) public {
a = a - value - value1 + value3;
b = b - (value1 - value2 + value3);
}

}
7 changes: 3 additions & 4 deletions test/contracts/Assign.zol
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ contract Assign {

secret uint256 private a;
function add(secret uint256 value) public {
unknown a += value;
a += value;
}

function remove(secret uint256 value) public returns (uint256) {
a -= value;
return a;
function remove(secret uint256 value) public {
a += value ;
}

}
4 changes: 3 additions & 1 deletion test/contracts/BucketsOfBalls.zol
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ pragma solidity ^0.8.0;
contract BucketsOfBalls {

secret mapping(address => uint256) public buckets;
secret uint256 private a;

function deposit( uint256 amountDeposit) public {
buckets[msg.sender] += amountDeposit;
}

function transfer(secret address toBucketId, secret uint256 numberOfBalls) public {
buckets[msg.sender] -= numberOfBalls;
encrypt unknown buckets[toBucketId] += numberOfBalls;
unknown buckets[toBucketId] += numberOfBalls;
a += buckets[toBucketId] + numberOfBalls;
}
}
Loading