Skip to content

Commit

Permalink
Merge pull request #311 from EYBlockchain/lydia/ifcircuits
Browse files Browse the repository at this point in the history
fix: ensure if statements that interact with secrets are included in …
  • Loading branch information
lydiagarms authored Jul 24, 2024
2 parents 14fad5a + ea819dc commit 1f85e62
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 26 deletions.
27 changes: 23 additions & 4 deletions src/codeGenerators/circuit/zokrates/toCircuit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,31 @@ function codeGenerator(node: any) {
}
});
for (let i =0; i<node.trueBody.length; i++) {
trueStatements+= `
${codeGenerator(node.trueBody[i].expression.leftHandSide)} = if ${codeGenerator(node.condition)} then ${codeGenerator(node.trueBody[i].expression.rightHandSide)} else ${codeGenerator(node.trueBody[i].expression.leftHandSide)} fi`
// We may have a statement that is not within the If statement but included due to the ordering (e.g. b_1 =b)
if (node.trueBody[i].outsideIf) {
trueStatements += `${codeGenerator(node.trueBody[i])}`;
} else {
if (node.trueBody[i].expression.nodeType === 'UnaryOperation'){
trueStatements+= `
${codeGenerator(node.trueBody[i].expression.subExpression)} = if ${codeGenerator(node.condition)} then ${codeGenerator(node.trueBody[i].expression.subExpression)} ${node.trueBody[i].expression.operator[0]} 1 else ${codeGenerator(node.trueBody[i].expression.subExpression)} fi`
} else {
trueStatements+= `
${codeGenerator(node.trueBody[i].expression.leftHandSide)} = if ${codeGenerator(node.condition)} then ${codeGenerator(node.trueBody[i].expression.rightHandSide)} else ${codeGenerator(node.trueBody[i].expression.leftHandSide)} fi`
}
}
}
for (let j =0; j<node.falseBody.length; j++) {
falseStatements+= `
${codeGenerator(node.falseBody[j].expression.leftHandSide)} = if ${codeGenerator(node.condition)} then ${codeGenerator(node.falseBody[j].expression.leftHandSide)} else ${codeGenerator(node.falseBody[j].expression.rightHandSide)} fi`
if (node.falseBody[j].outsideIf) {
falseStatements += `${codeGenerator(node.falseBody[j])}`;
} else {
if (node.falseBody[j].expression.nodeType === 'UnaryOperation'){
falseStatements+= `
${codeGenerator(node.falseBody[j].expression.subExpression)} = if ${codeGenerator(node.condition)} then ${codeGenerator(node.falseBody[j].expression.subExpression)} else ${codeGenerator(node.falseBody[j].expression.subExpression)} ${node.falseBody[j].expression.operator[0]} 1 fi`
} else {
falseStatements+= `
${codeGenerator(node.falseBody[j].expression.leftHandSide)} = if ${codeGenerator(node.condition)} then ${codeGenerator(node.falseBody[j].expression.leftHandSide)} else ${codeGenerator(node.falseBody[j].expression.rightHandSide)} fi`
}
}
}
return initialStatements + trueStatements + falseStatements;

Expand Down
26 changes: 23 additions & 3 deletions src/codeGenerators/orchestration/nodejs/toOrchestration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable import/no-cycle, no-param-reassign, consistent-return */
import cloneDeep from 'lodash.clonedeep';
import {OrchestrationCodeBoilerPlate} from '../../../boilerplate/orchestration/javascript/raw/toOrchestration.js';
import fileGenerator from '../files/toOrchestration.js';

Expand Down Expand Up @@ -75,6 +76,10 @@ export default function codeGenerator(node: any, options: any = {}): any {
return node.name;

case 'VariableDeclarationStatement': {
// If the statement is inside an if statement but declared outside.
if (node.outsideIf){
return `${codeGenerator(node.initialValue)}`;
}
if (!node.interactsWithSecret)
return `\n// non-secret line would go here but has been filtered out`;
if (node.initialValue?.nodeType === 'Assignment') {
Expand Down Expand Up @@ -103,7 +108,7 @@ export default function codeGenerator(node: any, options: any = {}): any {
if (!node.initialValue.operator) {
if (!node.initialValue.nodeType) return `\nlet ${codeGenerator(node.declarations[0])};`
// local var dec
if (node.initialValue.nodeType === 'Literal' && !node.isInitializationExpression) return `\nlet ${codeGenerator(node.declarations[0])} = generalise(${codeGenerator(node.initialValue)});`;
if (node.initialValue.nodeType === 'Literal' && node.isInitializationExpression) return `\nlet ${codeGenerator(node.declarations[0])} = ${codeGenerator(node.initialValue)};`;
return `\nlet ${codeGenerator(node.declarations[0])} = generalise(${codeGenerator(node.initialValue)});`;
}
return `\nlet ${codeGenerator(node.initialValue)};`;
Expand Down Expand Up @@ -168,14 +173,29 @@ export default function codeGenerator(node: any, options: any = {}): any {
return ` `;

case 'IfStatement': {
let comment = (node.inPreStatements) ? "// some public statements of this if statement have been moved to pre-statements here, any other statements appear later" : '';

// We need to declare some variables before the if statement begins (because they are used outside the if statement).
let preIfStatements = node.trueBody.filter((node: any) => node.outsideIf).concat(node.falseBody.filter((node: any) => node.outsideIf));
let newPreIfStatements = [];
preIfStatements.forEach((node: any) => {
newPreIfStatements.push(cloneDeep(node));
newPreIfStatements[newPreIfStatements.length - 1].outsideIf = false;
});
let preIfStatementsString = newPreIfStatements.flatMap(codeGenerator).join('\n');

if(node.falseBody.length)
return `if (${codeGenerator(node.condition)}) {
return `${comment}
${preIfStatementsString}
if (${codeGenerator(node.condition)}) {
${node.trueBody.flatMap(codeGenerator).join('\n')}
} else {
${node.falseBody.flatMap(codeGenerator).join('\n')}
}`
else
return `if (${codeGenerator(node.condition)}) {
return `${comment}
${preIfStatementsString}
if (${codeGenerator(node.condition)}) {
${node.trueBody.flatMap(codeGenerator).join('\n')}
}`
}
Expand Down
80 changes: 69 additions & 11 deletions src/transformers/visitors/toCircuitVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,31 @@ const incrementNames = (node: any, indicator: any) => {
};


//Finds a statement with the correct ID
const findStatementId = (statements: any, ID: number) => {
let expNode = statements.find((n:any) => n?.id === ID);
let index_expNode = statements.indexOf(expNode);
let location = {index: index_expNode, trueIndex: -1, falseIndex: -1};
statements.forEach((st:any) => {
if (st.trueBody){
if (!expNode) {
expNode = st.trueBody.find((n:any) => n?.id === ID);
location.index = statements.indexOf(st);
location.trueIndex = st.trueBody.indexOf(expNode);
}
}
if (st.falseBody){
if (!expNode) {
expNode = st.falseBody.find((n:any) => n?.id === ID);
location.index = statements.indexOf(st);
location.falseIndex = st.falseBody.indexOf(expNode);
}
}
});
return {expNode, location};
};


// public variables that interact with the secret also need to be modified within the circuit.
const publicVariables = (path: NodePath, state: any, IDnode: any) => {
const {parent, node } = path;
Expand Down Expand Up @@ -91,8 +116,7 @@ const publicVariables = (path: NodePath, state: any, IDnode: any) => {
if (path.containerName !== 'indexExpression') {
num_modifiers++;
}
let expNode = statements.find((n:any) => n?.id === expressionId);
let index_expNode = fnDefNode.node._newASTPointer.body.statements.indexOf(expNode);
let {expNode, location} = findStatementId(statements, expressionId);
if (expNode && !expNode.isAccessed) {
expNode.isAccessed = true;
if((expNode.expression && expNode.expression.leftHandSide && expNode.expression.leftHandSide?.name === node.name) ||
Expand All @@ -109,8 +133,11 @@ const publicVariables = (path: NodePath, state: any, IDnode: any) => {
interactsWithSecret: true,
isVarDec: true,
});
if (index_expNode !== -1) {
fnDefNode.node._newASTPointer.body.statements.splice(index_expNode + 1, 0, newNode1);
newNode1.outsideIf = true;
if (location.index!== -1) {
if (location.trueIndex !== -1){ fnDefNode.node._newASTPointer.body.statements[location.index].trueBody.splice(location.trueIndex + 1, 0, newNode1); }
else if (location.falseIndex !== -1){ fnDefNode.node._newASTPointer.body.statements[location.index].falseBody.splice(location.falseIndex + 1, 0, newNode1); }
else {fnDefNode.node._newASTPointer.body.statements.splice(location.index + 1, 0, newNode1);}
}
}
} else{
Expand All @@ -124,8 +151,11 @@ const publicVariables = (path: NodePath, state: any, IDnode: any) => {
expression: InnerNode,
interactsWithSecret: true,
});
if (index_expNode !== -1) {
fnDefNode.node._newASTPointer.body.statements.splice(index_expNode + 1, 0, newNode1);
newNode1.outsideIf = true;
if (location.index!== -1) {
if (location.trueIndex !== -1){ fnDefNode.node._newASTPointer.body.statements[location.index].trueBody.splice(location.trueIndex + 1, 0, newNode1); }
else if (location.falseIndex !== -1){ fnDefNode.node._newASTPointer.body.statements[location.index].falseBody.splice(location.falseIndex + 1, 0, newNode1); }
else {fnDefNode.node._newASTPointer.body.statements.splice(location.index + 1, 0, newNode1);}
}
if (`${modName}` !== `${node.name}_${num_modifiers}` && num_modifiers !==0){
const initInnerNode1 = buildNode('Assignment', {
Expand All @@ -138,8 +168,11 @@ const publicVariables = (path: NodePath, state: any, IDnode: any) => {
interactsWithSecret: true,
isVarDec: true,
});
if (index_expNode !== -1) {
fnDefNode.node._newASTPointer.body.statements.splice(index_expNode + 2, 0, newNode2);
newNode2.outsideIf = true;
if (location.index!== -1) {
if (location.trueIndex !== -1){ fnDefNode.node._newASTPointer.body.statements[location.index].trueBody.splice(location.trueIndex + 2, 0, newNode2); }
else if (location.falseIndex !== -1){ fnDefNode.node._newASTPointer.body.statements[location.index].falseBody.splice(location.falseIndex + 2, 0, newNode2); }
else {fnDefNode.node._newASTPointer.body.statements.splice(location.index + 2, 0, newNode2);}
}
}
}
Expand Down Expand Up @@ -1193,9 +1226,34 @@ const visitor = {

IfStatement: {
enter(path: NodePath, state: any) {
const { node, parent } = path;
let isIfStatementSecret;
if(node.falseBody?.containsSecret || node.trueBody?.containsSecret || !node.condition?.containsPublic)
const { node, parent, scope } = path;
let isIfStatementSecret: boolean;
let interactsWithSecret = false;
function bodyInteractsWithSecrets(statements) {
statements.forEach((st) => {
if (st.nodeType === 'ExpressionStatement') {
if (st.expression.nodeType === 'UnaryOperation') {
const { operator, subExpression } = st.expression;
if ((operator === '++' || operator === '--') && subExpression.nodeType === 'Identifier') {
const referencedIndicator = scope.getReferencedIndicator(subExpression);
if (referencedIndicator?.interactsWithSecret) {
interactsWithSecret = true;
}
}
} else {
const referencedIndicator = scope.getReferencedIndicator(st.expression.leftHandSide);
if (referencedIndicator?.interactsWithSecret) {
interactsWithSecret = true;
}
}
}
});
}
if (node.trueBody?.statements) bodyInteractsWithSecrets(node.trueBody?.statements);
if (node.falseBody?.statements) bodyInteractsWithSecrets(node.falseBody?.statements);


if(node.falseBody?.containsSecret || node.trueBody?.containsSecret || interactsWithSecret || node.condition?.containsSecret)
isIfStatementSecret = true;
if(isIfStatementSecret) {
if(node.trueBody.statements[0].expression.nodeType === 'FunctionCall')
Expand Down
Loading

0 comments on commit 1f85e62

Please sign in to comment.