From 2d6035090a54733e8345edaaa356330a3ba8d9e5 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Mon, 13 May 2024 17:05:10 +0100 Subject: [PATCH 01/24] Bugs in InternalFunctionCallTest --- src/transformers/visitors/common.ts | 1 + ...rchestrationInternalFunctionCallVisitor.ts | 11 +++++--- test/contracts/InternalFunctionCallTest4.zol | 26 +++++++++++++++++++ .../internalFunctionCallTest2.zol | 0 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 test/contracts/InternalFunctionCallTest4.zol rename test/{contracts => error-checks}/internalFunctionCallTest2.zol (100%) diff --git a/src/transformers/visitors/common.ts b/src/transformers/visitors/common.ts index 65416f3b5..1365c1251 100644 --- a/src/transformers/visitors/common.ts +++ b/src/transformers/visitors/common.ts @@ -83,6 +83,7 @@ export const internalFunctionCallVisitor = (thisPath: NodePath, thisState: any) if((params.length !== 0) && (params.some(node => (node.isSecret || node._newASTPointer?.interactsWithSecret)))) { thisState.internalFunctionInteractsWithSecret = true; + thisPath.scope.indicators.internalFunctionInteractsWithSecret = true; } else thisState.internalFunctionInteractsWithSecret = false; oldStateArray = params.map(param => (param.name) ); diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index 5507da153..6943f779c 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -94,8 +94,8 @@ const internalCallVisitor = { } }); for(const [index, oldStateName] of oldStateArray.entries()) { - node.initialValue.leftHandSide.name = node.initialValue.leftHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[index]); - node.initialValue.rightHandSide.name = node.initialValue.rightHandSide.name.replace(oldStateName, state.newStateArray[index]); + node.initialValue.leftHandSide.name = node.initialValue.leftHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); + node.initialValue.rightHandSide.name = node.initialValue.rightHandSide.name.replace(oldStateName, state.newStateArray[name][index]); } } if(node.nodeType === 'Assignment'){ @@ -377,11 +377,14 @@ FunctionCall: { if(path.isInternalFunctionCall()) { const args = node.arguments; let isCircuit = false; + const name = node.expression.name; + state.newStateArray ??= {}; + state.newStateArray[name] ??= []; for (const arg of args) { if(arg.expression?.typeDescriptions.typeIdentifier.includes('_struct')) - state.newStateArray = args.map(arg => (arg.expression.name+'.'+arg.memberName)); + state.newStateArray[name] = args.map(arg => (arg.expression.name+'.'+arg.memberName)); else - state.newStateArray = args.map(arg => (arg.name)); + state.newStateArray[name] = args.map(arg => (arg.name)); } let internalFunctionInteractsWithSecret = false; const newState: any = {}; diff --git a/test/contracts/InternalFunctionCallTest4.zol b/test/contracts/InternalFunctionCallTest4.zol new file mode 100644 index 000000000..09488b5a9 --- /dev/null +++ b/test/contracts/InternalFunctionCallTest4.zol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: CC0 +pragma solidity ^0.8.0; +contract Assign { + secret uint256 private a; + secret uint256 private b; + uint256 public c; + secret uint256 private d; + + + + function addB( uint256 value, uint256 value1) public { + c += value1; + known a += value; + + } + function addA( uint256 value) public { + known d += value; + } + function remove( uint256 value, uint256 value1 ) public { + unknown b += value; + addB( value, value1); + addA(value1); + } + + +} \ No newline at end of file diff --git a/test/contracts/internalFunctionCallTest2.zol b/test/error-checks/internalFunctionCallTest2.zol similarity index 100% rename from test/contracts/internalFunctionCallTest2.zol rename to test/error-checks/internalFunctionCallTest2.zol From 89498aea597055db1f1e444e7344538d56736907 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Mon, 13 May 2024 18:18:03 +0100 Subject: [PATCH 02/24] fix: bug for internal function calls where non-secret parameters that interact with a secret only within the internal function call are marked as not interacting with the secret and so not input to the proof in the orchestration --- .../visitors/toOrchestrationVisitor.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/transformers/visitors/toOrchestrationVisitor.ts b/src/transformers/visitors/toOrchestrationVisitor.ts index f995df9a4..63a4e21ac 100644 --- a/src/transformers/visitors/toOrchestrationVisitor.ts +++ b/src/transformers/visitors/toOrchestrationVisitor.ts @@ -258,7 +258,7 @@ const addPublicInput = (path: NodePath, state: any, IDnode: any) => { // if the node is the indexExpression, we dont need its value in the circuit state.publicInputs ??= []; - if (!(path.containerName === 'indexExpression' && !(path.parentPath.isSecret|| path.parent.containsSecret))) state.publicInputs.push(node); + if (!(path.containerName === 'indexExpression' && !(path.parentPath.isSecret|| path.parent.containsSecret))) state.publicInputs.push(node); } if (['Identifier', 'IndexAccess'].includes(node.indexExpression?.nodeType)) addPublicInput(NodePath.getPath(node.indexExpression), state, null); @@ -598,7 +598,6 @@ const visitor = { indicator: stateVarIndicator, }); } - if (secretModified || accessedOnly) { newNodes.generateProofNode.privateStates[ name @@ -1357,8 +1356,18 @@ const visitor = { // we now have a param or a local var dec let interactsWithSecret = false; - if (scope.bindings[node.id].referencingPaths.some(refPath => refPath.node.interactsWithSecret)) - interactsWithSecret = true; + scope.bindings[node.id].referencingPaths.forEach(refPath => { + interactsWithSecret ||= refPath.node.interactsWithSecret; + // check for internal function call if the parameter passed in the function call interacts with secret or not + if(refPath.parentPath.isInternalFunctionCall()){ + refPath.parentPath.node.arguments?.forEach((element, index) => { + if(node.id === element.referencedDeclaration) { + let key = (Object.keys((refPath.getReferencedPath(refPath.parentPath.node?.expression) || refPath.parentPath).scope.bindings)[index]); + interactsWithSecret ||= refPath.getReferencedPath(refPath.parentPath.node?.expression)?.scope.indicators[key]?.interactsWithSecret + } + }) + } + }); if ( parent.nodeType === 'VariableDeclarationStatement' && From 70ea52c65b326e690200c4c5583f9e99dcfcfeb7 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Tue, 14 May 2024 10:19:45 +0100 Subject: [PATCH 03/24] fix: zappify bug in git testing --- ...rchestrationInternalFunctionCallVisitor.ts | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index 6943f779c..cf01e0493 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -32,13 +32,13 @@ const internalCallVisitor = { state.newParametersList = cloneDeep(childNode.parameters.modifiedStateVariables); state.newParametersList.forEach(node => { for(const [index, oldStateName] of oldStateArray.entries()) { - node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[index]) + node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) } }) if(childNode.decrementedSecretStates){ newdecrementedSecretStates = cloneDeep(childNode.decrementedSecretStates); for(const [index, oldStateName] of oldStateArray.entries()) { - node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[index]) + node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) } } state.newPreStatementList = cloneDeep(childNode.body.preStatements); @@ -49,7 +49,7 @@ const internalCallVisitor = { let newstateName: string; for( [stateName, stateNode] of Object.entries(node.privateStates)){ for(const [index, oldStateName] of oldStateArray.entries()) { - newstateName = stateName.replace('_'+oldStateName, '_'+ state.newStateArray[index]) + newstateName = stateName.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]) if(newstateName != stateName ){ node.privateStates[ newstateName ] = node.privateStates[stateName]; delete(node.privateStates[ stateName ]); @@ -58,23 +58,23 @@ const internalCallVisitor = { switch (node.nodeType) { case 'InitialisePreimage': { - stateNode.privateStateName = stateNode.privateStateName.replace('_'+oldStateName, '_'+ state.newStateArray[index]) + stateNode.privateStateName = stateNode.privateStateName.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]) if(stateNode.mappingKey === oldStateName) - stateNode.mappingKey = stateNode.mappingKey.replace(oldStateName, state.newStateArray[index]) + stateNode.mappingKey = stateNode.mappingKey.replace(oldStateName, state.newStateArray[name][index]) if(stateNode.stateVarId[1] === oldStateName) - stateNode.stateVarId[1] = stateNode.stateVarId[1].replace(oldStateName, state.newStateArray[index]) + stateNode.stateVarId[1] = stateNode.stateVarId[1].replace(oldStateName, state.newStateArray[name][index]) break; } case 'ReadPreimage': { - stateNode.increment = stateNode.increment.replace(oldStateName+'.', state.newStateArray[index]+'.') + stateNode.increment = stateNode.increment.replace(oldStateName+'.', state.newStateArray[name][index]+'.') if(stateNode.mappingKey === oldStateName) - stateNode.mappingKey = stateNode.mappingKey.replace(oldStateName, state.newStateArray[index]) + stateNode.mappingKey = stateNode.mappingKey.replace(oldStateName, state.newStateArray[name][index]) if(stateNode.stateVarId[1] === oldStateName) - stateNode.stateVarId[1] = stateNode.stateVarId[1].replace(oldStateName, state.newStateArray[index]) + stateNode.stateVarId[1] = stateNode.stateVarId[1].replace(oldStateName, state.newStateArray[name][index]) break; } case 'MembershipWitness': { - stateNode.privateStateName = stateNode.privateStateName.replace('_'+oldStateName, '_'+ state.newStateArray[index]) + stateNode.privateStateName = stateNode.privateStateName.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]) break; } default : @@ -90,7 +90,7 @@ const internalCallVisitor = { if(node.nodeType === 'VariableDeclarationStatement'){ node.declarations.forEach(node => { for(const [index, oldStateName] of oldStateArray.entries()) { - node.name = node.name.replace('_'+oldStateName, '_'+ state.newStateArray[index]); + node.name = node.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); } }); for(const [index, oldStateName] of oldStateArray.entries()) { @@ -100,8 +100,8 @@ const internalCallVisitor = { } if(node.nodeType === 'Assignment'){ for(const [index, oldStateName] of oldStateArray.entries()) { - node.leftHandSide.name = node.leftHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[index]); - node.rightHandSide.name = node.rightHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[index]); + node.leftHandSide.name = node.leftHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); + node.rightHandSide.name = node.rightHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); } } }) @@ -113,7 +113,7 @@ const internalCallVisitor = { let newstateName: string; for( [stateName, stateNode] of Object.entries(node.privateStates)){ for(const [index, oldStateName] of oldStateArray.entries()) { - newstateName = stateName.replace('_'+oldStateName, '_'+ state.newStateArray[index]) + newstateName = stateName.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]) if(newstateName != stateName ){ node.privateStates[ newstateName ] = node.privateStates[stateName]; delete(node.privateStates[ stateName ]); @@ -127,17 +127,17 @@ const internalCallVisitor = { let newstateName: string; for( [stateName, stateNode] of Object.entries(node.privateStates)){ for(const [index, oldStateName] of oldStateArray.entries()) { - newstateName = stateName.replace('_'+oldStateName, '_'+ state.newStateArray[index]) + newstateName = stateName.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]) if(newstateName != stateName ){ node.privateStates[ newstateName ] = node.privateStates[stateName]; delete(node.privateStates[ stateName ]); } if(stateNode.privateStateName === oldStateName) - stateNode.privateStateName = stateNode.privateStateName.replace(oldStateName, state.newStateArray[index]) + stateNode.privateStateName = stateNode.privateStateName.replace(oldStateName, state.newStateArray[name][index]) else - stateNode.privateStateName = stateNode.privateStateName.replace('_'+oldStateName, '_'+state.newStateArray[index]) + stateNode.privateStateName = stateNode.privateStateName.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) if(stateNode.stateVarId[1] === oldStateName) - stateNode.stateVarId[1] = stateNode.stateVarId[1].replace(oldStateName, state.newStateArray[index]) + stateNode.stateVarId[1] = stateNode.stateVarId[1].replace(oldStateName, state.newStateArray[name][index]) } } } @@ -147,7 +147,7 @@ const internalCallVisitor = { let newstateName: string; for( stateName of Object.keys(generateProofNode.privateStates)) { for(const [index, oldStateName] of oldStateArray.entries()) { - newstateName = stateName.replace('_'+oldStateName, '_'+state.newStateArray[index]) + newstateName = stateName.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) if(newstateName != stateName ){ generateProofNode.privateStates[ newstateName ] = generateProofNode.privateStates[stateName]; delete(generateProofNode.privateStates[ stateName ]); @@ -156,7 +156,7 @@ const internalCallVisitor = { for( const [id, node] of Object.entries(generateProofNode.privateStates[stateName].increment) ){ if(generateProofNode.privateStates[stateName].increment[id].name === oldStateName) - generateProofNode.privateStates[stateName].increment[id].name = state.newStateArray[index]; + generateProofNode.privateStates[stateName].increment[id].name = state.newStateArray[name][index]; } } @@ -170,7 +170,7 @@ const internalCallVisitor = { let newstateName: string; for( [stateName, stateNode] of Object.entries(sendTransactionNode.privateStates)){ for(const [index, oldStateName] of oldStateArray.entries()) { - newstateName = stateName.replace('_'+oldStateName, '_'+state.newStateArray[index]) + newstateName = stateName.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) if(newstateName != stateName ){ sendTransactionNode.privateStates[ newstateName ] = sendTransactionNode.privateStates[stateName]; delete(sendTransactionNode.privateStates[ stateName ]); @@ -185,13 +185,13 @@ const internalCallVisitor = { let newstateName: string; for( [stateName, stateNode] of Object.entries(writePreimageNode.privateStates)){ for(const [index, oldStateName] of oldStateArray.entries()) { - newstateName = stateName.replace('_'+oldStateName, '_'+state.newStateArray[index]) + newstateName = stateName.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) if(newstateName != stateName ){ writePreimageNode.privateStates[ newstateName ] = writePreimageNode.privateStates[stateName]; delete(writePreimageNode.privateStates[ stateName ]); } if(stateNode.mappingKey) - stateNode.mappingKey = stateNode.mappingKey.replace(oldStateName, state.newStateArray[index]) + stateNode.mappingKey = stateNode.mappingKey.replace(oldStateName, state.newStateArray[name][index]) } } } @@ -326,8 +326,8 @@ const internalCallVisitor = { state.newStatementList.forEach(node => { if(node.nodeType === 'VariableDeclarationStatement') { for(const [index, oldStateName] of oldStateArray.entries()) { - node.initialValue.leftHandSide.name = node.initialValue.leftHandSide.name?.replace('_'+oldStateName, '_'+ state.newStateArray[index]); - node.initialValue.rightHandSide.name = node.initialValue.rightHandSide.name?.replace(oldStateName, state.newStateArray[index]); + node.initialValue.leftHandSide.name = node.initialValue.leftHandSide.name?.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); + node.initialValue.rightHandSide.name = node.initialValue.rightHandSide.name?.replace(oldStateName, state.newStateArray[name][index]); } } }) @@ -377,14 +377,14 @@ FunctionCall: { if(path.isInternalFunctionCall()) { const args = node.arguments; let isCircuit = false; - const name = node.expression.name; + const fn_name = node.expression.name; state.newStateArray ??= {}; - state.newStateArray[name] ??= []; + state.newStateArray[fn_name] ??= []; for (const arg of args) { if(arg.expression?.typeDescriptions.typeIdentifier.includes('_struct')) - state.newStateArray[name] = args.map(arg => (arg.expression.name+'.'+arg.memberName)); + state.newStateArray[fn_name] = args.map(arg => (arg.expression.name+'.'+arg.memberName)); else - state.newStateArray[name] = args.map(arg => (arg.name)); + state.newStateArray[fn_name] = args.map(arg => (arg.name)); } let internalFunctionInteractsWithSecret = false; const newState: any = {}; @@ -405,7 +405,7 @@ FunctionCall: { if(callingfnDefIndicators[node.id].isModified) { if(internalfnDefIndicators[node.id].isMapping){ Object.keys(internalfnDefIndicators[node.id].mappingKeys).forEach(name => { - if(state.newStateArray.some(statename => statename === name)) + if(state.newStateArray[fn_name].some(statename => statename === name)) isCircuit = false; else isCircuit = true; From b6f4ba8a3b15aedf889c0855c395af6054c5ff9c Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Tue, 14 May 2024 13:08:46 +0100 Subject: [PATCH 04/24] fix: create error message when a function calls internal functions that use the same secret state variable --- .../visitors/checks/unsupportedVisitor.ts | 40 +++++++++++++++++++ .../internalFunctionCallTest2.zol | 6 ++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/transformers/visitors/checks/unsupportedVisitor.ts b/src/transformers/visitors/checks/unsupportedVisitor.ts index 4385335da..d004765d5 100644 --- a/src/transformers/visitors/checks/unsupportedVisitor.ts +++ b/src/transformers/visitors/checks/unsupportedVisitor.ts @@ -109,4 +109,44 @@ export default { ); }, }, + + ContractDefinition: { + enter(node: any, state: any) { + let internalFunctionStateVarList = {}; + let secretStateVarList = {}; + const nestedInternalFunctionVisitor = (thisNode: any, state: any) => { + if (thisNode.nodeType === 'VariableDeclaration' && thisNode.stateVariable && thisNode.isSecret){ + secretStateVarList[thisNode.name] = []; + } + if (thisNode.nodeType === 'FunctionDefinition'){ + internalFunctionStateVarList[thisNode.name] = []; + } + if (thisNode.nodeType === 'Identifier'){ + let fnDefKeys = Object.keys(internalFunctionStateVarList); + let fnName = fnDefKeys[fnDefKeys.length - 1]; + if (thisNode.typeDescriptions.typeIdentifier.includes("t_function_internal")){ + internalFunctionStateVarList[fnName].push(thisNode.name); + } + if (Object.keys(secretStateVarList).includes(thisNode.name)){ + secretStateVarList[thisNode.name].push(fnName); + } + } + } + traverseNodesFast(node, nestedInternalFunctionVisitor, state); + + Object.keys(internalFunctionStateVarList).forEach((fnVar) => { + Object.keys(secretStateVarList).forEach((stateVar) => { + let commonElements = internalFunctionStateVarList[fnVar].filter(element => secretStateVarList[stateVar].includes(element)); + if (commonElements.length > 1){ + /*throw new ZKPError( + `A function makes use of a secret state variable in multiple internal function calls. This would mean a commitment would be nullified twice per function call and so is not supported in Starlight.`, + node + );*/ + } + }); + }); + console.log(internalFunctionStateVarList); + console.log(secretStateVarList); + }, + }, }; diff --git a/test/error-checks/internalFunctionCallTest2.zol b/test/error-checks/internalFunctionCallTest2.zol index 525412d79..296e4c4e0 100644 --- a/test/error-checks/internalFunctionCallTest2.zol +++ b/test/error-checks/internalFunctionCallTest2.zol @@ -2,6 +2,8 @@ pragma solidity ^0.8.0; contract Assign { secret uint256 private a; + //Remove below + secret uint256 private d; secret uint256 private b; uint256 public c; @@ -10,10 +12,10 @@ contract Assign { function addB( uint256 value, uint256 value1) public { c += value1; known a += value; - } function addA( uint256 value) public { - known a += value; + //known a += value; + d = a+ value; } function remove( uint256 value, uint256 value1 ) public { unknown b += value; From 0900e2e15c87a7cfb56f2bc4ec10b43fe20e543c Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Tue, 14 May 2024 15:07:37 +0100 Subject: [PATCH 05/24] fix: zappify errors --- ...orchestrationInternalFunctionCallVisitor.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index cf01e0493..c5a040052 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -66,7 +66,7 @@ const internalCallVisitor = { break; } case 'ReadPreimage': { - stateNode.increment = stateNode.increment.replace(oldStateName+'.', state.newStateArray[name][index]+'.') + if (stateNode.increment) stateNode.increment = stateNode.increment.replace(oldStateName+'.', state.newStateArray[name][index]+'.'); if(stateNode.mappingKey === oldStateName) stateNode.mappingKey = stateNode.mappingKey.replace(oldStateName, state.newStateArray[name][index]) if(stateNode.stateVarId[1] === oldStateName) @@ -95,13 +95,13 @@ const internalCallVisitor = { }); for(const [index, oldStateName] of oldStateArray.entries()) { node.initialValue.leftHandSide.name = node.initialValue.leftHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); - node.initialValue.rightHandSide.name = node.initialValue.rightHandSide.name.replace(oldStateName, state.newStateArray[name][index]); + if (node.initialValue.rightHandSide.name) node.initialValue.rightHandSide.name = node.initialValue.rightHandSide.name.replace(oldStateName, state.newStateArray[name][index]); } } if(node.nodeType === 'Assignment'){ for(const [index, oldStateName] of oldStateArray.entries()) { node.leftHandSide.name = node.leftHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); - node.rightHandSide.name = node.rightHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); + if (node.rightHandSide.name) node.rightHandSide.name = node.rightHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); } } }) @@ -153,12 +153,12 @@ const internalCallVisitor = { delete(generateProofNode.privateStates[ stateName ]); stateName = newstateName; } - - for( const [id, node] of Object.entries(generateProofNode.privateStates[stateName].increment) ){ - if(generateProofNode.privateStates[stateName].increment[id].name === oldStateName) - generateProofNode.privateStates[stateName].increment[id].name = state.newStateArray[name][index]; - } - + if (generateProofNode.privateStates[stateName].increment){ + for( const [id, node] of Object.entries(generateProofNode.privateStates[stateName].increment) ){ + if(generateProofNode.privateStates[stateName].increment[id].name === oldStateName) + generateProofNode.privateStates[stateName].increment[id].name = state.newStateArray[name][index]; + } + } } } generateProofNode.parameters = []; From 53d8faa7b56982614c4d2df1def3886b80ce7791 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Tue, 14 May 2024 17:29:31 +0100 Subject: [PATCH 06/24] fix: zappify errors for InternalFunctionCalls --- .../circuitInternalFunctionCallVisitor.ts | 10 +++---- ...rchestrationInternalFunctionCallVisitor.ts | 27 ++++++++++--------- src/transformers/visitors/toCircuitVisitor.ts | 3 ++- .../internalFunctionCallTest2.zol | 5 +--- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts index 24ea2f537..a93c1a575 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -27,7 +27,7 @@ const internalCallVisitor = { state.newParameterList.forEach((node, nodeIndex) => { if(node.nodeType === 'Boilerplate') { - for(const [id, oldStateName] of state.oldStateArray.entries()) { + for(const [id, oldStateName] of state.oldStateArray[name].entries()) { node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[name][id].name) if(node.newCommitmentValue === oldStateName) node.newCommitmentValue = node.newCommitmentValue.replace(oldStateName, state.newStateArray[name][id].name) @@ -36,7 +36,7 @@ const internalCallVisitor = { } } if(node.nodeType === 'VariableDeclaration'){ - for(const [id, oldStateName] of state.oldStateArray.entries()) { + for(const [id, oldStateName] of state.oldStateArray[name].entries()) { if(oldStateName !== state.newStateArray[name][id].name) node.name = state.newStateArray[name][id].name; node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[name][id].name) @@ -46,7 +46,7 @@ const internalCallVisitor = { } }) state.newReturnParameterList.forEach((node,nodeIndex) => { - for(const [id, oldStateName] of state.oldStateArray.entries()) { + for(const [id, oldStateName] of state.oldStateArray[name].entries()) { if(oldStateName !== state.newStateArray[name][id].name) node.name = state.newStateArray[name][id].name; node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[name][id].name) @@ -171,7 +171,7 @@ const internalCallVisitor = { if(node.nodeType === 'ExpressionStatement') { if(node.expression.nodeType === 'Assignment') { let expressionList = cloneDeep(node); - for(const [id, oldStateName] of state.oldStateArray.entries()) { + for(const [id, oldStateName] of state.oldStateArray[name].entries()) { if(state.newStateArray[name][id].memberName ){ if(node.expression.rightHandSide.rightExpression.name === oldStateName) expressionList.expression.rightHandSide.rightExpression.name = expressionList.expression.rightHandSide.rightExpression.name.replace(oldStateName, state.newStateArray[name][id].name+'.'+state.newStateArray[name][id].memberName) @@ -198,7 +198,7 @@ const internalCallVisitor = { childNode.body.preStatements.forEach(node => { if(node.isPartitioned){ commitmentValue = node.newCommitmentValue; - for(const [id, oldStateName] of state.oldStateArray.entries()) { + for(const [id, oldStateName] of state.oldStateArray[name].entries()) { if(commitmentValue.includes(oldStateName)){ if(state.newStateArray[name][id].memberName) commitmentValue = commitmentValue.replace(oldStateName,state.newStateArray[name][id].name+'.'+state.newStateArray[name][id].memberName); diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index c5a040052..bf2e10709 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -31,13 +31,13 @@ const internalCallVisitor = { if(childNode.nodeType === 'FunctionDefinition'){ state.newParametersList = cloneDeep(childNode.parameters.modifiedStateVariables); state.newParametersList.forEach(node => { - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) } }) if(childNode.decrementedSecretStates){ newdecrementedSecretStates = cloneDeep(childNode.decrementedSecretStates); - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) } } @@ -48,7 +48,7 @@ const internalCallVisitor = { let stateNode: any; let newstateName: string; for( [stateName, stateNode] of Object.entries(node.privateStates)){ - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { newstateName = stateName.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]) if(newstateName != stateName ){ node.privateStates[ newstateName ] = node.privateStates[stateName]; @@ -89,17 +89,17 @@ const internalCallVisitor = { state.newStatementList.forEach(node => { if(node.nodeType === 'VariableDeclarationStatement'){ node.declarations.forEach(node => { - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { node.name = node.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); } }); - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { node.initialValue.leftHandSide.name = node.initialValue.leftHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); if (node.initialValue.rightHandSide.name) node.initialValue.rightHandSide.name = node.initialValue.rightHandSide.name.replace(oldStateName, state.newStateArray[name][index]); } } if(node.nodeType === 'Assignment'){ - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { node.leftHandSide.name = node.leftHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); if (node.rightHandSide.name) node.rightHandSide.name = node.rightHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); } @@ -112,7 +112,7 @@ const internalCallVisitor = { let stateNode: any; let newstateName: string; for( [stateName, stateNode] of Object.entries(node.privateStates)){ - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { newstateName = stateName.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]) if(newstateName != stateName ){ node.privateStates[ newstateName ] = node.privateStates[stateName]; @@ -126,7 +126,7 @@ const internalCallVisitor = { let stateNode: any; let newstateName: string; for( [stateName, stateNode] of Object.entries(node.privateStates)){ - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { newstateName = stateName.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]) if(newstateName != stateName ){ node.privateStates[ newstateName ] = node.privateStates[stateName]; @@ -146,7 +146,7 @@ const internalCallVisitor = { let stateName: string; let newstateName: string; for( stateName of Object.keys(generateProofNode.privateStates)) { - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { newstateName = stateName.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) if(newstateName != stateName ){ generateProofNode.privateStates[ newstateName ] = generateProofNode.privateStates[stateName]; @@ -169,7 +169,7 @@ const internalCallVisitor = { let stateNode: any; let newstateName: string; for( [stateName, stateNode] of Object.entries(sendTransactionNode.privateStates)){ - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { newstateName = stateName.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) if(newstateName != stateName ){ sendTransactionNode.privateStates[ newstateName ] = sendTransactionNode.privateStates[stateName]; @@ -184,7 +184,7 @@ const internalCallVisitor = { let stateNode: any; let newstateName: string; for( [stateName, stateNode] of Object.entries(writePreimageNode.privateStates)){ - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { newstateName = stateName.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) if(newstateName != stateName ){ writePreimageNode.privateStates[ newstateName ] = writePreimageNode.privateStates[stateName]; @@ -325,7 +325,7 @@ const internalCallVisitor = { state.newStatementList = cloneDeep(childNode.body.statements); state.newStatementList.forEach(node => { if(node.nodeType === 'VariableDeclarationStatement') { - for(const [index, oldStateName] of oldStateArray.entries()) { + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { node.initialValue.leftHandSide.name = node.initialValue.leftHandSide.name?.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); node.initialValue.rightHandSide.name = node.initialValue.rightHandSide.name?.replace(oldStateName, state.newStateArray[name][index]); } @@ -388,7 +388,8 @@ FunctionCall: { } let internalFunctionInteractsWithSecret = false; const newState: any = {}; - oldStateArray = internalFunctionCallVisitor(path, newState) + state.oldStateArray = state.oldStateArray ? state.oldStateArray : {}; + state.oldStateArray[fn_name] = internalFunctionCallVisitor(path, newState); internalFunctionInteractsWithSecret ||= newState.internalFunctionInteractsWithSecret; state.internalFncName ??= []; state.internalFncName.push(node.expression.name); diff --git a/src/transformers/visitors/toCircuitVisitor.ts b/src/transformers/visitors/toCircuitVisitor.ts index 4de792b53..96a9411b1 100644 --- a/src/transformers/visitors/toCircuitVisitor.ts +++ b/src/transformers/visitors/toCircuitVisitor.ts @@ -1344,7 +1344,8 @@ let childOfSecret = path.getAncestorOfType('ForStatement')?.containsSecret; } let internalFunctionInteractsWithSecret = false; const newState: any = {}; - state.oldStateArray = internalFunctionCallVisitor(path, newState) + state.oldStateArray = state.oldStateArray ? state.oldStateArray : {}; + state.oldStateArray[name] = internalFunctionCallVisitor(path, newState); internalFunctionInteractsWithSecret ||= newState.internalFunctionInteractsWithSecret; state.internalFncName ??= []; state.internalFncName.push(node.expression.name); diff --git a/test/error-checks/internalFunctionCallTest2.zol b/test/error-checks/internalFunctionCallTest2.zol index 296e4c4e0..c62c4aa71 100644 --- a/test/error-checks/internalFunctionCallTest2.zol +++ b/test/error-checks/internalFunctionCallTest2.zol @@ -2,8 +2,6 @@ pragma solidity ^0.8.0; contract Assign { secret uint256 private a; - //Remove below - secret uint256 private d; secret uint256 private b; uint256 public c; @@ -14,8 +12,7 @@ contract Assign { known a += value; } function addA( uint256 value) public { - //known a += value; - d = a+ value; + known a += value; } function remove( uint256 value, uint256 value1 ) public { unknown b += value; From e430c466b6d03a97ad56ddcedfc351869e328c30 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Fri, 17 May 2024 10:22:45 +0100 Subject: [PATCH 07/24] fix: bugs relating to internal function calls that use the same secret state variable in orchestration and circuits --- .../visitors/checks/unsupportedVisitor.ts | 2 - .../circuitInternalFunctionCallVisitor.ts | 63 +++++++++++++++++-- ...rchestrationInternalFunctionCallVisitor.ts | 55 ++++++++++++++-- 3 files changed, 110 insertions(+), 10 deletions(-) diff --git a/src/transformers/visitors/checks/unsupportedVisitor.ts b/src/transformers/visitors/checks/unsupportedVisitor.ts index d004765d5..7262629ff 100644 --- a/src/transformers/visitors/checks/unsupportedVisitor.ts +++ b/src/transformers/visitors/checks/unsupportedVisitor.ts @@ -145,8 +145,6 @@ export default { } }); }); - console.log(internalFunctionStateVarList); - console.log(secretStateVarList); }, }, }; diff --git a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts index a93c1a575..d89dc62f2 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -4,8 +4,62 @@ import NodePath from '../../traverse/NodePath.js'; import { FunctionDefinitionIndicator } from '../../traverse/Indicator.js'; import buildNode from '../../types/orchestration-types.js' - - +// We need to ensure that parameters appear in the same order as in the .mjs file if the same state variables are used in multiple function calls. +// All parameters relating to the same state variable should be grouped together. +const reorderParameters = (parameterList: any) => { + parameterList.forEach((param, index) => { + parameterList.forEach((newParam, newIndex) => { + if (param.name === newParam.name && param.bpType === 'nullification' && newParam.bpType === 'nullification') { + if (newIndex > index && param.isAccessed && !param.isNullified && (newParam.isNullified || !newParam.isAccessed) ){ + parameterList[index] = newParam; + } + } + if (param.name === newParam.name && param.bpType === 'oldCommitmentExistence' && newParam.bpType === 'oldCommitmentExistence') { + if (newIndex > index && (!param.isWhole || !param.initialisationRequired) && (newParam.isWhole && newParam.initialisationRequired) ){ + parameterList[index] = newParam; + } + } + }); + }); + let newBPName: string; + let currentIndex: number; + let newCommitment = {}; + parameterList.forEach((param, index) => { + if (param.name != newBPName && param.bpType){ + newBPName = param.name; + currentIndex = index; + newCommitment[newBPName] = newCommitment[newBPName] ? newCommitment[newBPName] : []; + newCommitment[newBPName].push({"firstIndex": currentIndex, "isNewCommitment": false }); + } + if (param.bpType === 'newCommitment'){ + newCommitment[newBPName][newCommitment[newBPName].length -1].isNewCommitment = true; + newCommitment[newBPName][newCommitment[newBPName].length -1].newCommitmentIndex = index; + } + if (param.bpType === 'mapping'){ + newCommitment[newBPName][newCommitment[newBPName].length -1].mappingIndex = index; + } + if (param.bpType === 'oldCommitmentExistence'){ + newCommitment[newBPName][newCommitment[newBPName].length -1].oldCommitmentIndex = index; + } + }); + let elementsToAdd = []; + Object.keys(newCommitment).forEach((varName) => { + if (newCommitment[varName][0].isNewCommitment === false && newCommitment[varName].length > 1){ + let isSwapped = false; + newCommitment[varName].forEach((element) => { + if (element.isNewCommitment === true && !isSwapped){ + let newIndex = newCommitment[varName][0].oldCommitmentIndex +1 || newCommitment[varName][0].mappingIndex+1 || newCommitment[varName][0].firstIndex +1; + let oldIndex = element.newCommitmentIndex; + elementsToAdd.push({"element": parameterList[oldIndex], "NewIndex": newIndex}); + } + }); + } + }); + elementsToAdd.sort((a, b) => b.NewIndex - a.NewIndex ); + elementsToAdd.forEach((element) => { + parameterList.splice(element.NewIndex, 0, element.element); + }); +} // let interactsWithSecret = false; // Added globaly as two objects are accesing it @@ -121,8 +175,9 @@ const internalCallVisitor = { }) file.nodes.forEach(childNode => { if(childNode.nodeType === 'FunctionDefinition'){ - childNode.parameters.parameters = [...new Set([...childNode.parameters.parameters, ...state.newParameterList])] - childNode.returnParameters.parameters = [...new Set([...childNode.returnParameters.parameters, ...state.newReturnParameterList])] + childNode.parameters.parameters = [...new Set([...childNode.parameters.parameters, ...state.newParameterList])]; + reorderParameters(childNode.parameters.parameters); + childNode.returnParameters.parameters = [...new Set([...childNode.returnParameters.parameters, ...state.newReturnParameterList])]; if(childNode.nodeType === 'FunctionDefinition' && state.callingFncName[index].parent === 'FunctionDefinition'){ childNode.body.statements.forEach(node => { if(node.nodeType === 'ExpressionStatement') { diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index bf2e10709..69e6ada30 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -211,6 +211,13 @@ const internalCallVisitor = { case 'InitialisePreimage' : { state.newPreStatementList.forEach(statenode => { if(statenode.nodeType === 'InitialisePreimage'){ + Object.keys(node.privateStates).forEach(key => { + Object.keys(statenode.privateStates).forEach(newKey => { + if (key === newKey){ + statenode.privateStates[newKey].accessedOnly = statenode.privateStates[newKey].accessedOnly && node.privateStates[key].accessedOnly; + } + }); + }); node.privateStates = Object.assign(node.privateStates,statenode.privateStates) } }); @@ -219,6 +226,14 @@ const internalCallVisitor = { case 'ReadPreimage': { state.newPreStatementList.forEach(statenode => { if(statenode.nodeType === 'ReadPreimage'){ + Object.keys(node.privateStates).forEach(key => { + Object.keys(statenode.privateStates).forEach(newKey => { + if (key === newKey){ + statenode.privateStates[newKey].accessedOnly = statenode.privateStates[newKey].accessedOnly && node.privateStates[key].accessedOnly; + statenode.privateStates[newKey].nullifierRequired = statenode.privateStates[newKey].nullifierRequired || node.privateStates[key].nullifierRequired; + } + }); + }); node.privateStates = Object.assign(node.privateStates,statenode.privateStates) } }); @@ -227,6 +242,14 @@ const internalCallVisitor = { case 'MembershipWitness': { state.newPreStatementList.forEach(statenode => { if(statenode.nodeType === 'MembershipWitness'){ + Object.keys(node.privateStates).forEach(key => { + Object.keys(statenode.privateStates).forEach(newKey => { + if (key === newKey){ + statenode.privateStates[newKey].accessedOnly = statenode.privateStates[newKey].accessedOnly && node.privateStates[key].accessedOnly; + statenode.privateStates[newKey].nullifierRequired = statenode.privateStates[newKey].nullifierRequired || node.privateStates[key].nullifierRequired; + } + }); + }); node.privateStates = Object.assign(node.privateStates,statenode.privateStates) } }); @@ -284,25 +307,49 @@ const internalCallVisitor = { case 'CalculateNullifier' : { state.newPostStatementList.forEach(statenode => { if(statenode.nodeType === 'CalculateNullifier'){ - node.privateStates = Object.assign(node.privateStates,statenode.privateStates) + Object.keys(node.privateStates).forEach(key => { + Object.keys(statenode.privateStates).forEach(newKey => { + if (key === newKey){ + statenode.privateStates[newKey].accessedOnly = statenode.privateStates[newKey].accessedOnly && node.privateStates[key].accessedOnly; + } + }); + }); + node.privateStates = Object.assign(node.privateStates,statenode.privateStates); } }); break; } case 'CalculateCommitment': { state.newPostStatementList.forEach(statenode => { - if(statenode.nodeType === 'CalculateCommitment'){ - node.privateStates = Object.assign(node.privateStates,statenode.privateStates) + if(statenode.nodeType === 'CalculateCommitment'){ + node.privateStates = Object.assign(node.privateStates,statenode.privateStates); } }); break; } case 'GenerateProof': { - node.privateStates = Object.assign(node.privateStates,generateProofNode.privateStates) + Object.keys(node.privateStates).forEach(key => { + Object.keys(generateProofNode.privateStates).forEach(newKey => { + if (key === newKey){ + generateProofNode.privateStates[newKey].accessedOnly = generateProofNode.privateStates[newKey].accessedOnly && node.privateStates[key].accessedOnly; + generateProofNode.privateStates[newKey].nullifierRequired = generateProofNode.privateStates[newKey].nullifierRequired || node.privateStates[key].nullifierRequired; + generateProofNode.privateStates[newKey].initialisationRequired = generateProofNode.privateStates[newKey].initialisationRequired || node.privateStates[key].initialisationRequired; + } + }); + }); + node.privateStates = Object.assign(node.privateStates,generateProofNode.privateStates); node.parameters = [...new Set([...node.parameters ,...generateProofNode.parameters])]; break; } case 'SendTransaction': { + Object.keys(node.privateStates).forEach(key => { + Object.keys(sendTransactionNode.privateStates).forEach(newKey => { + if (key === newKey){ + sendTransactionNode.privateStates[newKey].accessedOnly = sendTransactionNode.privateStates[newKey].accessedOnly && node.privateStates[key].accessedOnly; + sendTransactionNode.privateStates[newKey].nullifierRequired = sendTransactionNode.privateStates[newKey].nullifierRequired || node.privateStates[key].nullifierRequired; + } + }); + }); node.privateStates = Object.assign(node.privateStates,sendTransactionNode.privateStates) break; } From 79093b459ffe749f7cbb5a8819dc4ead490fd285 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Fri, 17 May 2024 15:56:19 +0100 Subject: [PATCH 08/24] fix: bug in orchestration due to multiple internal function calls modifying same secret state - specifically in the statements array where statements from internal functions are combined --- ...rchestrationInternalFunctionCallVisitor.ts | 96 +++++++++++-------- 1 file changed, 57 insertions(+), 39 deletions(-) diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index 69e6ada30..ac00dfc77 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -3,6 +3,7 @@ import NodePath from '../../traverse/NodePath.js'; import { FunctionDefinitionIndicator } from '../../traverse/Indicator.js'; import buildNode from '../../types/orchestration-types.js'; import { internalFunctionCallVisitor } from './common.js'; +import { traverseNodesFast } from '../../traverse/traverse.js'; function merge(array1, array2, index=0) { return array1.slice(0, index).concat(array2, array1.slice(index)); @@ -86,25 +87,22 @@ const internalCallVisitor = { }) state.newPreStatementList.splice(0,1); state.newStatementList = cloneDeep(childNode.body.statements); + const adjustNamesVisitor = (thisNode: any, state: any) => { + if (thisNode.nodeType === 'VariableDeclaration'){ + thisNode.name = thisNode.name.replace(state.oldStateName, state.newStateArray[name][state.currentIndex]); + } + if (thisNode.nodeType === 'Identifier'){ + thisNode.name = thisNode.name.replace(state.oldStateName, state.newStateArray[name][state.currentIndex]); + } + } state.newStatementList.forEach(node => { - if(node.nodeType === 'VariableDeclarationStatement'){ - node.declarations.forEach(node => { - for(const [index, oldStateName] of state.oldStateArray[name].entries()) { - node.name = node.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); - } - }); - for(const [index, oldStateName] of state.oldStateArray[name].entries()) { - node.initialValue.leftHandSide.name = node.initialValue.leftHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); - if (node.initialValue.rightHandSide.name) node.initialValue.rightHandSide.name = node.initialValue.rightHandSide.name.replace(oldStateName, state.newStateArray[name][index]); - } - } - if(node.nodeType === 'Assignment'){ - for(const [index, oldStateName] of state.oldStateArray[name].entries()) { - node.leftHandSide.name = node.leftHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); - if (node.rightHandSide.name) node.rightHandSide.name = node.rightHandSide.name.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); - } - } - }) + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { + state.oldStateName = oldStateName; + state.currentIndex = index; + traverseNodesFast(node, adjustNamesVisitor, state); + } + + }); state.newPostStatementList = cloneDeep(childNode.body.postStatements); state.newPostStatementList.forEach(node => { if(node.nodeType === 'CalculateNullifier'){ @@ -259,28 +257,48 @@ const internalCallVisitor = { break; } }); - let dupNode; - let dupIndex; - let dupAssignNode; if(state.callingFncName[index].parent === 'FunctionDefinition'){ - childNode.body.statements.forEach((node, index)=> { - if(node.nodeType === 'VariableDeclarationStatement'){ - state.newStatementList.some((statenode, id ) => { - if(statenode.nodeType === 'VariableDeclarationStatement' && (node.declarations[0].name === statenode.declarations[0].name)){ - dupNode = statenode; - dupIndex = index; - dupAssignNode = state.newStatementList[id+1]; - - } - }) - } - }) - if(dupNode){ - childNode.body.statements.splice(dupIndex+2, 0, dupNode.initialValue); - childNode.body.statements.splice(dupIndex+3, 0, dupAssignNode); - } - else - childNode.body.statements = [...new Set([...childNode.body.statements, ...state.newStatementList])] + let intFnindex = childNode.body.statements.findIndex(statement => statement.expression?.nodeType === 'InternalFunctionCall' && statement.expression?.name === name); + childNode.body.statements.splice(intFnindex +1, 0, ...state.newStatementList); + //insert extra var declarations if needed + const findVarVisitor = (thisNode: any, state: any) => { + if (thisNode.nodeType === 'Identifier'){ + if (!state.varNames.includes(thisNode.name)) { + state.varNames.push(thisNode.name); + } + } + } + let newVarDecs = []; + childNode.body.statements.forEach((node1, index1)=> { + state.varNames = []; + if (!(node1.expression && node1.expression?.nodeType === 'InternalFunctionCall')) traverseNodesFast(node1, findVarVisitor, state); + state.varNames.forEach((varName) => { + childNode.body.statements.forEach((node2, index2)=> { + if (index2 > index1 && node2.nodeType === 'VariableDeclarationStatement' && node2.declarations[0].name === varName){ + newVarDecs.push({"index": index1, "VarDec": cloneDeep(node2)}); + } + }); + }); + }); + newVarDecs.sort((a, b) => b.index - a.index); + newVarDecs.forEach((varDec) => { + varDec.VarDec.initialValue = null; + childNode.body.statements.splice(varDec.index, 0, varDec.VarDec); + }); + // remove multiple variable declarations + childNode.body.statements.forEach((node1, index1)=> { + let isDecDeleted = false; + if(node1.nodeType === 'VariableDeclarationStatement'){ + childNode.body.statements.forEach((node2, index2)=> { + if(!isDecDeleted && index2 < index1 && node2.nodeType === 'VariableDeclarationStatement'){ + if ((node1.declarations[0].name === node2.declarations[0].name)){ + childNode.body.statements.splice(index1, 1, node1.initialValue); + isDecDeleted = true; + } + } + }); + } + }); } else{ state.newStatementList.forEach((statenode, stateid) => { childNode.body.statements.forEach((node, id)=> { From c40cd6e16bc94dffb4eaa8666697cafdc68b07b7 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Fri, 17 May 2024 16:39:14 +0100 Subject: [PATCH 09/24] fix: error in circuits for internal function calls the wrong parameters were being called --- .../visitors/circuitInternalFunctionCallVisitor.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts index d89dc62f2..5161639c6 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -125,10 +125,10 @@ const internalCallVisitor = { case 'nullification' : { internalFncParameters.push(`${node.name}_oldCommitment_owner_secretKey`) ; internalFncParameters.push(`nullifierRoot`); - internalFncParameters.push(`newNullifierRoot`); - internalFncParameters.push(`${node.name}_oldCommitment_nullifier`); + if (!(node.isAccessed && !node.isNullified)) internalFncParameters.push(`newNullifierRoot`); + if (!(node.isAccessed && !node.isNullified)) internalFncParameters.push(`${node.name}_oldCommitment_nullifier`); internalFncParameters.push(`${node.name}_nullifier_nonmembershipWitness_siblingPath`); - internalFncParameters.push(`${node.name}_nullifier_nonmembershipWitness_newsiblingPath`); + if (!(node.isAccessed && !node.isNullified)) internalFncParameters.push(`${node.name}_nullifier_nonmembershipWitness_newsiblingPath`); break; }; case 'oldCommitmentPreimage' : { From da3d167a15dbb57d9cd42a93151a435ec322a788 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Fri, 17 May 2024 17:58:15 +0100 Subject: [PATCH 10/24] fix: errors in contract when mutliple internal function calls uses the same secret state --- .../raw/ContractBoilerplateGenerator.ts | 1 - src/transformers/visitors/toContractVisitor.ts | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts b/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts index abae7a1b3..03123130e 100644 --- a/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts +++ b/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts @@ -219,7 +219,6 @@ class ContractBoilerplateGenerator { newCommitments: 0, encryption: 0, }; - _inputs.map(i => verifyInputsMap(type, i, counter)); diff --git a/src/transformers/visitors/toContractVisitor.ts b/src/transformers/visitors/toContractVisitor.ts index 9e5c6618f..cb4acfc23 100644 --- a/src/transformers/visitors/toContractVisitor.ts +++ b/src/transformers/visitors/toContractVisitor.ts @@ -301,6 +301,23 @@ export default { state.circuitParams ??= {}; state.circuitParams[path.getUniqueFunctionName()] ??= {}; state.circuitParams[path.getUniqueFunctionName()].parameters = circuitParams; + // Delete repeated circuit parameters + let deletedIndexes = []; + state.circuitParams[path.getUniqueFunctionName()].parameters.forEach((circParam1, index1) => { + state.circuitParams[path.getUniqueFunctionName()].parameters.forEach((circParam2, index2) => { + if (circParam1.bpType === 'nullification' && circParam2.bpType === 'nullification' && circParam1.name === circParam2.name && index1 > index2) { + deletedIndexes.push(index1); + } + if (circParam1.bpType === 'newCommitment' && circParam2.bpType === 'newCommitment' && circParam1.name === circParam2.name && index1 > index2) { + deletedIndexes.push(index1); + } + }); + }); + deletedIndexes = [...new Set(deletedIndexes)]; + deletedIndexes.sort((a, b) => b - a); + deletedIndexes.forEach(index => { + state.circuitParams[path.getUniqueFunctionName()].parameters.splice(index, 1); + }); }, exit(path: NodePath, state: any) { @@ -901,7 +918,6 @@ DoWhileStatement: { ...(internalfnDefIndicators.nullifiersRequired? [`newNullifiers`] : []), ...(internalfnDefIndicators.oldCommitmentAccessRequired ? [`commitmentRoot`] : []), ...(internalfnDefIndicators.newCommitmentsRequired ? [`newCommitments`] : []), - ...(internalfnDefIndicators.containsAccessedOnlyState ? [`checkNullifiers`] : []), ...(internalfnDefIndicators.encryptionRequired ? [`cipherText`] : []), ...(internalfnDefIndicators.encryptionRequired ? [`ephPubKeys`] : []), `proof`, From 2485ccd8f4ef2c823d5c293aac62a10701127744 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Mon, 20 May 2024 13:49:18 +0100 Subject: [PATCH 11/24] fix: circuit compilation error because the nullifier is input to the circuit but only used in an internal function call - this means that the same variable is declared twice --- .../circuit/zokrates/raw/BoilerplateGenerator.ts | 6 +++--- .../visitors/circuitInternalFunctionCallVisitor.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts b/src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts index 40f5d02ed..cda28b6be 100644 --- a/src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts +++ b/src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts @@ -124,9 +124,9 @@ class BoilerplateGenerator { if(isAccessed && !isNullified) lines = [ ` - // Create the Nullifier for ${x} and no need to nnullify it as its accessed only: + // Create the Nullifier for ${x} and no need to nullify it as its accessed only: - field ${x}_oldCommitment_nullifier = poseidon([\\ + field ${x}_oldCommitment_nullifier_check_field = poseidon([\\ ${x}_stateVarId_field,\\ ${x}_oldCommitment_owner_secretKey,\\ ${x}_oldCommitment_salt\\ @@ -137,7 +137,7 @@ class BoilerplateGenerator { assert(\\ nullifierRoot == checkproof(\\ ${x}_nullifier_nonmembershipWitness_siblingPath,\\ - ${x}_oldCommitment_nullifier\\ + ${x}_oldCommitment_nullifier_check_field\\ )\ ) `, diff --git a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts index 5161639c6..66a8fe1b3 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -290,7 +290,6 @@ const internalCallVisitor = { node.newCommitmentValue = node.newCommitmentValue+' - ('+commitmentValue+')'; } }) - childNode.body.postStatements.forEach( node => { if(isPartitioned){ if(internalFncbpType === callingFncbpType) @@ -307,7 +306,8 @@ const internalCallVisitor = { } } }) - }) + }); + }, }, From 6e94ae22a3e7e73f1f178d5a7dc5bd5660493fc6 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Mon, 20 May 2024 16:45:25 +0100 Subject: [PATCH 12/24] fix: zappify error due to null entries being created in statements list --- .../visitors/orchestrationInternalFunctionCallVisitor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index ac00dfc77..6dd38b5c3 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -299,6 +299,7 @@ const internalCallVisitor = { }); } }); + childNode.body.statements = childNode.body.statements.filter(item => item !== null); } else{ state.newStatementList.forEach((statenode, stateid) => { childNode.body.statements.forEach((node, id)=> { From 5c5db4dce2b8b906aba5e445ea9a2c2b306fa8a0 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Wed, 22 May 2024 17:38:38 +0100 Subject: [PATCH 13/24] fix: logic for circuit imports due to Internal Function calls --- .../orchestration/nodejs/toOrchestration.ts | 5 +- .../circuitInternalFunctionCallVisitor.ts | 155 +++++++++++++++++- ...rchestrationInternalFunctionCallVisitor.ts | 53 +----- src/transformers/visitors/toCircuitVisitor.ts | 69 +++++--- .../visitors/toContractVisitor.ts | 2 +- src/types/zokrates-types.ts | 6 +- 6 files changed, 206 insertions(+), 84 deletions(-) diff --git a/src/codeGenerators/orchestration/nodejs/toOrchestration.ts b/src/codeGenerators/orchestration/nodejs/toOrchestration.ts index 877cd05bb..e91891739 100644 --- a/src/codeGenerators/orchestration/nodejs/toOrchestration.ts +++ b/src/codeGenerators/orchestration/nodejs/toOrchestration.ts @@ -90,6 +90,8 @@ export default function codeGenerator(node: any, options: any = {}): any { return `${getAccessedValue(node.declarations[0].name)}`; } + console.log("kangeroo"); + console.log(node); if ( node.initialValue.operator && !node.initialValue.operator.includes('=') @@ -117,8 +119,9 @@ export default function codeGenerator(node: any, options: any = {}): any { } case 'ExpressionStatement': - if (!node.incrementsSecretState && node.interactsWithSecret) + if (!node.incrementsSecretState && (node.interactsWithSecret || node.expression?.internalFunctionInteractsWithSecret)){ return `\n${codeGenerator(node.expression)};`; + } if (!node.interactsWithSecret) return `\n// non-secret line would go here but has been filtered out`; return `\n// increment would go here but has been filtered out`; diff --git a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts index 66a8fe1b3..3f0e51c6d 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -73,11 +73,12 @@ const internalCallVisitor = { state.internalFncName?.forEach( (name,index) => { node._newASTPointer.forEach(file => { if(file.fileName === name) { - if(state.circuitImport[index]==='true') { file.nodes.forEach(childNode => { if(childNode.nodeType === 'FunctionDefinition'){ state.newParameterList = cloneDeep(childNode.parameters.parameters); state.newReturnParameterList = cloneDeep(childNode.returnParameters.parameters); + state.newPreStatementList = cloneDeep(childNode.body.preStatements); + state.newPostStatementList = cloneDeep(childNode.body.postStatements); state.newParameterList.forEach((node, nodeIndex) => { if(node.nodeType === 'Boilerplate') { @@ -110,7 +111,7 @@ const internalCallVisitor = { }) } }) - + if(state.circuitImport[index].isImported ==='true') { // Collect the internal call ParameterList let internalFncParameters: string[] = []; state.newParameterList.forEach(node => { @@ -166,11 +167,12 @@ const internalCallVisitor = { state.circuitArguments.push(param); } }); + } node._newASTPointer.forEach(file => { if(file.fileName === state.callingFncName[index].name){ file.nodes.forEach(childNode => { - if(childNode.nodeType === 'StructDefinition' && !state.isAddStructDefinition) + if(childNode.nodeType === 'StructDefinition' && !state.isAddStructDefinition && state.circuitImport[index].isImported === 'true') file.nodes.splice(file.nodes.indexOf(childNode),1); }) file.nodes.forEach(childNode => { @@ -178,8 +180,8 @@ const internalCallVisitor = { childNode.parameters.parameters = [...new Set([...childNode.parameters.parameters, ...state.newParameterList])]; reorderParameters(childNode.parameters.parameters); childNode.returnParameters.parameters = [...new Set([...childNode.returnParameters.parameters, ...state.newReturnParameterList])]; - if(childNode.nodeType === 'FunctionDefinition' && state.callingFncName[index].parent === 'FunctionDefinition'){ - childNode.body.statements.forEach(node => { + if(childNode.nodeType === 'FunctionDefinition' && state.callingFncName[index].parent === 'FunctionDefinition' && state.circuitImport[index].isImported === 'true'){ + childNode.body.statements.forEach(node => { if(node.nodeType === 'ExpressionStatement') { if(node.expression.nodeType === 'InternalFunctionCall' && node.expression.name === name){ node.expression.CircuitArguments = node.expression.CircuitArguments.concat(state.circuitArguments); @@ -188,7 +190,7 @@ const internalCallVisitor = { } } }) - } else { + } else if (state.circuitImport[index].isImported === 'true') { childNode.body.statements.forEach(node => { if(node.nodeType === state.callingFncName[index].parent){ node.body.statements.forEach(kidNode => { @@ -208,9 +210,8 @@ const internalCallVisitor = { } }) - } - else if(state.circuitImport[index] === 'false'){ + if(state.circuitImport[index].isImported === 'false'){ let newExpressionList = []; let isPartitioned = false let internalFncbpType: string; @@ -289,7 +290,75 @@ const internalCallVisitor = { else node.newCommitmentValue = node.newCommitmentValue+' - ('+commitmentValue+')'; } - }) + }); + childNode.body.preStatements.forEach(node => { + switch(node.bpType) { + case 'PoKoSK' : { + state.newPreStatementList.forEach(statenode => { + if(statenode.bpType === 'PoKoSK' && statenode.name === node.name){ + statenode.isNullified = statenode.isNullified || node.isNullified; + node = Object.assign(node,statenode); + } + }); + break; + } + case 'nullification' : { + state.newPreStatementList.forEach(statenode => { + if(statenode.bpType === 'nullification' && statenode.name === node.name){ + statenode.isNullified = statenode.isNullified || node.isNullified; + node = Object.assign(node,statenode); + } + }); + break; + } + case 'oldCommitmentPreimage' : { + state.newPreStatementList.forEach(statenode => { + if(statenode.bpType === 'oldCommitmentPreimage' && statenode.name === node.name){ + statenode.isNullified = statenode.isNullified || node.isNullified; + node = Object.assign(node,statenode); + } + }); + break; + } + case 'oldCommitmentExistence' : { + state.newPreStatementList.forEach(statenode => { + if(statenode.bpType === 'oldCommitmentExistence' && statenode.name === node.name){ + statenode.isNullified = statenode.isNullified || node.isNullified; + node = Object.assign(node,statenode); + } + }); + break; + } + case 'newCommitment' : { + state.newPreStatementList.forEach(statenode => { + if(statenode.bpType === 'newCommitment' && statenode.name === node.name){ + statenode.isNullified = statenode.isNullified || node.isNullified; + node = Object.assign(node,statenode); + } + }); + break; + } + default : + break; + } + }); + let nonDuplicatePreStatements = []; + state.newPreStatementList.forEach(stateNode => { + let isDuplicate = false; + let dupIndex =0; + childNode.body.preStatements.forEach((existingNode, exIndex) => { + if(existingNode.bpType === stateNode.bpType && existingNode.name === stateNode.name){ + isDuplicate = true; + } + if (existingNode.name === stateNode.name) { + dupIndex = exIndex; + } + }); + if (!isDuplicate) nonDuplicatePreStatements.push({node: stateNode, index: dupIndex }); + }); + nonDuplicatePreStatements.forEach(dupNode => { + childNode.body.preStatements.splice(dupNode.index +1, 0, dupNode.node); + }); childNode.body.postStatements.forEach( node => { if(isPartitioned){ if(internalFncbpType === callingFncbpType) @@ -298,6 +367,74 @@ const internalCallVisitor = { node.newCommitmentValue = node.newCommitmentValue+' - ('+commitmentValue+')'; } }) + childNode.body.postStatements.forEach(node => { + switch(node.bpType) { + case 'PoKoSK' : { + state.newPostStatementList.forEach(statenode => { + if(statenode.bpType === 'PoKoSK' && statenode.name === node.name){ + statenode.isNullified = statenode.isNullified || node.isNullified; + node = Object.assign(node,statenode); + } + }); + break; + } + case 'nullification' : { + state.newPostStatementList.forEach(statenode => { + if(statenode.bpType === 'nullification' && statenode.name === node.name){ + statenode.isNullified = statenode.isNullified || node.isNullified; + node = Object.assign(node,statenode); + } + }); + break; + } + case 'oldCommitmentPreimage' : { + state.newPostStatementList.forEach(statenode => { + if(statenode.bpType === 'oldCommitmentPreimage' && statenode.name === node.name){ + statenode.isNullified = statenode.isNullified || node.isNullified; + node = Object.assign(node,statenode); + } + }); + break; + } + case 'oldCommitmentExistence' : { + state.newPostStatementList.forEach(statenode => { + if(statenode.bpType === 'oldCommitmentExistence' && statenode.name === node.name){ + statenode.isNullified = statenode.isNullified || node.isNullified; + node = Object.assign(node,statenode); + } + }); + break; + } + case 'newCommitment' : { + state.newPostStatementList.forEach(statenode => { + if(statenode.bpType === 'newCommitment' && statenode.name === node.name){ + statenode.isNullified = statenode.isNullified || node.isNullified; + node = Object.assign(node,statenode); + } + }); + break; + } + default : + break; + } + }); + let nonDuplicatePostStatements = []; + state.newPostStatementList.forEach(stateNode => { + let isDuplicate = false; + let dupIndex =0; + childNode.body.postStatements.forEach((existingNode, exIndex) => { + if(existingNode.bpType === stateNode.bpType && existingNode.name === stateNode.name){ + isDuplicate = true; + } + if (existingNode.name === stateNode.name) { + dupIndex = exIndex; + } + }); + if (!isDuplicate) nonDuplicatePostStatements.push({node: stateNode, index: dupIndex }); + }); + nonDuplicatePostStatements.forEach(dupNode => { + childNode.body.postStatements.splice(dupNode.index +1, 0, dupNode.node); + }); } }) diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index 6dd38b5c3..182ca423a 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -27,7 +27,6 @@ const internalCallVisitor = { node._newASTPointer.forEach(file => { state.internalFncName?.forEach( (name, index)=> { if(file.fileName === name && file.nodeType === 'File') { - if(state.circuitImport[index]==='true') { file.nodes.forEach(childNode => { if(childNode.nodeType === 'FunctionDefinition'){ state.newParametersList = cloneDeep(childNode.parameters.modifiedStateVariables); @@ -290,7 +289,7 @@ const internalCallVisitor = { let isDecDeleted = false; if(node1.nodeType === 'VariableDeclarationStatement'){ childNode.body.statements.forEach((node2, index2)=> { - if(!isDecDeleted && index2 < index1 && node2.nodeType === 'VariableDeclarationStatement'){ + if(!isDecDeleted && index2 < index1 && node2 && node2.nodeType === 'VariableDeclarationStatement'){ if ((node1.declarations[0].name === node2.declarations[0].name)){ childNode.body.statements.splice(index1, 1, node1.initialValue); isDecDeleted = true; @@ -384,54 +383,6 @@ const internalCallVisitor = { }) } }) - } - if(state.circuitImport[index] === 'false') { - file.nodes.forEach(childNode => { - if(childNode.nodeType === 'FunctionDefinition'){ - state.newStatementList = cloneDeep(childNode.body.statements); - state.newStatementList.forEach(node => { - if(node.nodeType === 'VariableDeclarationStatement') { - for(const [index, oldStateName] of state.oldStateArray[name].entries()) { - node.initialValue.leftHandSide.name = node.initialValue.leftHandSide.name?.replace('_'+oldStateName, '_'+ state.newStateArray[name][index]); - node.initialValue.rightHandSide.name = node.initialValue.rightHandSide.name?.replace(oldStateName, state.newStateArray[name][index]); - } - } - }) - } - }) - - node._newASTPointer.forEach(file => { - if(file.fileName === state.callingFncName[index].name) { - file.nodes.forEach(childNode => { - if(childNode.nodeType === 'FunctionDefinition') { - if(state.callingFncName[index].parent === 'FunctionDefinition'){ - state.statementnode = childNode; - } else{ - childNode.body.statements.forEach(kidNode => { - if(kidNode.nodeType === state.callingFncName[index].parent) - state.statementnode = kidNode; - }) - } - state.statementnode.body.statements.forEach(node => { - if(node.nodeType === 'ExpressionStatement'&& node.expression.name === state.internalFncName[index]) { - state.newStatementList.forEach(list => { - if(list.nodeType === 'VariableDeclarationStatement') - node.expression = Object.assign(node.expression,list.initialValue); - if(list.nodeType === 'Assignment') - state.statementnode.body.statements?.splice(state.statementnode.body.statements.indexOf(node)+1, 0, list); - }) - } - if(node.nodeType === 'VariableDeclarationStatement' && state.statementnode.body.statements.indexOf(node) != 0){ - state.statementnode.body.statements.splice(0, 0, state.statementnode.body.statements.splice(state.statementnode.body.statements.indexOf(node)+1, 1)[0]); - state.statementnode.body.statements.splice(0, 0, state.statementnode.body.statements.splice(state.statementnode.body.statements.indexOf(node), 1)[0]); - } - }); - } - }) - - } - }) - } } }) }) @@ -464,7 +415,7 @@ FunctionCall: { const callingfnDefIndicators = callingfnDefPath?.scope.indicators; const functionReferncedNode = scope.getReferencedPath(node.expression); const internalfnDefIndicators = functionReferncedNode?.scope.indicators; - const startNodePath = path.getAncestorOfType('ContractDefinition') + const startNodePath = path.getAncestorOfType('ContractDefinition'); startNodePath?.node.nodes.forEach(node => { if(node.nodeType === 'VariableDeclaration' && !node.typeDescriptions.typeIdentifier.includes('_struct')){ if(internalfnDefIndicators[node.id] && internalfnDefIndicators[node.id].isModified){ diff --git a/src/transformers/visitors/toCircuitVisitor.ts b/src/transformers/visitors/toCircuitVisitor.ts index 96a9411b1..8e964af60 100644 --- a/src/transformers/visitors/toCircuitVisitor.ts +++ b/src/transformers/visitors/toCircuitVisitor.ts @@ -313,6 +313,21 @@ const visitor = { const { indicators } = scope; const newFunctionDefinitionNode = node._newASTPointer; + // We need to ensure the correctness of the circuitImport flag for each internal function call. The state may have been updated due to later function calls that modify the same secret state. + let importStatementList: any; + parent._newASTPointer.forEach((file: any) => { + if (file.fileName === node.fileName) { + importStatementList = file.nodes[0]; + } + }); + importStatementList.imports.forEach((importNode: any) => { + if (importNode.bpType === 'internalFunctionCall' && importNode.circuitImport) { + if (state.circuitImport[importNode.functionCallIndex].isImported === 'false'){ + importNode.circuitImport = false; + } + } + }); + //Ensure we do not have any statements of the form x = x_init where x is not a parameter input to the circuit. for (let i = newFunctionDefinitionNode.body.statements.length - 1; i >= 0; i--) { const statementNode = newFunctionDefinitionNode.body.statements[i]; @@ -1355,33 +1370,49 @@ let childOfSecret = path.getAncestorOfType('ForStatement')?.containsSecret; const functionReferncedNode = scope.getReferencedPath(node.expression); const internalfnDefIndicators = functionReferncedNode?.scope.indicators; state.isEncrypted = internalfnDefIndicators.encryptionRequired; - const startNodePath = path.getAncestorOfType('ContractDefinition') + const startNodePath = path.getAncestorOfType('ContractDefinition'); + isCircuit = true; + let modifiedVariables = []; startNodePath?.node.nodes.forEach(node => { + //every state variable in the contract that isn't a struct if(node.nodeType === 'VariableDeclaration' && !node.typeDescriptions.typeIdentifier.includes('_struct')){ - if(internalfnDefIndicators[node.id] && internalfnDefIndicators[node.id].isModified){ - if(callingfnDefIndicators[node.id]) { - if(callingfnDefIndicators[node.id].isModified) { - if(internalfnDefIndicators[node.id].isMapping){ - Object.keys(internalfnDefIndicators[node.id].mappingKeys).forEach(vars => { - if(state.newStateArray[name].some(statename => statename === vars)) - isCircuit = false; - else - isCircuit = true; - }) - } else - isCircuit = false; + // Check if this state variable is accessed in the current internal function i.e. AddA, AddB + if(internalfnDefIndicators[node.id]){ + if (state.circuitImport) state.circuitImport.forEach(fnCall => { + if (fnCall.modVars.includes(node.name) && fnCall.callingFunction === callingfnDefPath.node.name) { + isCircuit = false; + fnCall.isImported = 'false'; } + }); + // Check if this state variable is modified in the current internal function i.e. AddA, AddB + if(internalfnDefIndicators[node.id].isModified){ + modifiedVariables.push(node.name); } - else - isCircuit = true; - } + // Check if the state variable is accessed or modified outside of the current internal function + if(callingfnDefIndicators[node.id]) { + // Check if the state variable is modified outside of the current internal function + if(callingfnDefIndicators[node.id].isModified) { + if(internalfnDefIndicators[node.id].isMapping){ + Object.keys(internalfnDefIndicators[node.id].mappingKeys).forEach(vars => { + if(state.newStateArray[name].some(statename => statename === vars)) + isCircuit = false; + }) + } else + isCircuit = false; + } else { + if(internalfnDefIndicators[node.id].isModified){ + isCircuit = false; + } + } + } + } } }); state.circuitImport ??= []; if(isCircuit) - state.circuitImport.push('true'); + state.circuitImport.push({isImported: 'true', modVars: modifiedVariables, callingFunction: callingfnDefPath.node.name}); else - state.circuitImport.push('false'); + state.circuitImport.push({isImported: 'false', modVars: modifiedVariables, callingFunction: callingfnDefPath.node.name}); const newNode = buildNode('InternalFunctionCall', { @@ -1389,12 +1420,12 @@ let childOfSecret = path.getAncestorOfType('ForStatement')?.containsSecret; internalFunctionInteractsWithSecret: internalFunctionInteractsWithSecret, CircuitArguments: [], CircuitReturn:[], - circuitImport: isCircuit, }); const fnNode = buildNode('InternalFunctionBoilerplate', { name: node.expression.name, internalFunctionInteractsWithSecret: internalFunctionInteractsWithSecret, circuitImport: isCircuit, + functionCallIndex: state.circuitImport.length -1, structImport: !state.isAddStructDefinition, structName: state.structName, isEncrypted: state.isEncrypted, diff --git a/src/transformers/visitors/toContractVisitor.ts b/src/transformers/visitors/toContractVisitor.ts index cb4acfc23..1f4824bbd 100644 --- a/src/transformers/visitors/toContractVisitor.ts +++ b/src/transformers/visitors/toContractVisitor.ts @@ -332,7 +332,7 @@ export default { // if contract is entirely public, we don't want zkp related boilerplate - if (!path.scope.containsSecret && !(node.kind === 'constructor')) return; + if (!path.scope.containsSecret && !path.scope.indicators.internalFunctionInteractsWithSecret && !(node.kind === 'constructor')) return; parameters.push( ...buildNode('FunctionBoilerplate', { diff --git a/src/types/zokrates-types.ts b/src/types/zokrates-types.ts index 866f950a2..e2668b9b6 100644 --- a/src/types/zokrates-types.ts +++ b/src/types/zokrates-types.ts @@ -252,7 +252,7 @@ export function buildNode(nodeType: string, fields: any = {}): any { }; } case 'InternalFunctionCall': { - const { name, internalFunctionInteractsWithSecret = false, oldStateName = [], newStateName =[], CircuitArguments = [],CircuitReturn =[],circuitImport = false} = fields; + const { name, internalFunctionInteractsWithSecret = false, oldStateName = [], newStateName =[], CircuitArguments = [],CircuitReturn =[]} = fields; return{ nodeType, name, @@ -261,11 +261,10 @@ export function buildNode(nodeType: string, fields: any = {}): any { newStateName, CircuitArguments, CircuitReturn, - circuitImport, }; } case 'InternalFunctionBoilerplate':{ - const { name, internalFunctionInteractsWithSecret = false,circuitImport = false,structImport = false, structName, isEncrypted = false} = fields; + const { name, internalFunctionInteractsWithSecret = false,circuitImport = false, functionCallIndex, structImport = false, structName, isEncrypted = false} = fields; return{ nodeType: 'Boilerplate', bpSection: 'importStatements', @@ -273,6 +272,7 @@ export function buildNode(nodeType: string, fields: any = {}): any { name, internalFunctionInteractsWithSecret, circuitImport, + functionCallIndex, structImport, structName, isEncrypted, From cc9af075881a6b4e2aedcf26519b5927000af31b Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Thu, 23 May 2024 10:05:35 +0100 Subject: [PATCH 14/24] fix: zappify bug and compilation error due to postStatements in the wrong order --- .../orchestration/nodejs/toOrchestration.ts | 3 +-- .../circuitInternalFunctionCallVisitor.ts | 25 +++++++++++++++---- ...rchestrationInternalFunctionCallVisitor.ts | 8 +++--- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/codeGenerators/orchestration/nodejs/toOrchestration.ts b/src/codeGenerators/orchestration/nodejs/toOrchestration.ts index e91891739..c72a3775d 100644 --- a/src/codeGenerators/orchestration/nodejs/toOrchestration.ts +++ b/src/codeGenerators/orchestration/nodejs/toOrchestration.ts @@ -90,8 +90,7 @@ export default function codeGenerator(node: any, options: any = {}): any { return `${getAccessedValue(node.declarations[0].name)}`; } - console.log("kangeroo"); - console.log(node); + if (!node.initialValue) return ``; if ( node.initialValue.operator && !node.initialValue.operator.includes('=') diff --git a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts index 3f0e51c6d..68fbf6051 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -61,6 +61,19 @@ const reorderParameters = (parameterList: any) => { }); } + +// We need to ensure that preStatments and postStatements are in the right order. +const reorderBoilerPlate = (bpStatementList: any) => { + let order = ['mapping','PoKoSK', 'nullification', 'oldCommitmentPreimage', 'oldCommitmentExistence', 'newCommitment', 'encryption']; + bpStatementList.sort((a, b) => { + if (a.name === b.name) { + return order.indexOf(a.bpType) - order.indexOf(b.bpType); + } else { + return 0; + } + }); +} + // let interactsWithSecret = false; // Added globaly as two objects are accesing it const internalCallVisitor = { @@ -359,6 +372,7 @@ const internalCallVisitor = { nonDuplicatePreStatements.forEach(dupNode => { childNode.body.preStatements.splice(dupNode.index +1, 0, dupNode.node); }); + reorderBoilerPlate(childNode.body.preStatements); childNode.body.postStatements.forEach( node => { if(isPartitioned){ if(internalFncbpType === callingFncbpType) @@ -421,7 +435,7 @@ const internalCallVisitor = { let nonDuplicatePostStatements = []; state.newPostStatementList.forEach(stateNode => { let isDuplicate = false; - let dupIndex =0; + let dupIndex = undefined; childNode.body.postStatements.forEach((existingNode, exIndex) => { if(existingNode.bpType === stateNode.bpType && existingNode.name === stateNode.name){ isDuplicate = true; @@ -431,10 +445,11 @@ const internalCallVisitor = { } }); if (!isDuplicate) nonDuplicatePostStatements.push({node: stateNode, index: dupIndex }); - }); - nonDuplicatePostStatements.forEach(dupNode => { - childNode.body.postStatements.splice(dupNode.index +1, 0, dupNode.node); - }); + }); + nonDuplicatePostStatements.forEach(dupNode => { + childNode.body.postStatements.splice(!dupNode.index ? 0 : dupNode.index +1, 0, dupNode.node); + }); + reorderBoilerPlate(childNode.body.postStatements); } }) diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index 182ca423a..6da798243 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -270,7 +270,9 @@ const internalCallVisitor = { let newVarDecs = []; childNode.body.statements.forEach((node1, index1)=> { state.varNames = []; - if (!(node1.expression && node1.expression?.nodeType === 'InternalFunctionCall')) traverseNodesFast(node1, findVarVisitor, state); + if (!(node1.expression && node1.expression?.nodeType === 'InternalFunctionCall')){ + traverseNodesFast(node1, findVarVisitor, state); + } state.varNames.forEach((varName) => { childNode.body.statements.forEach((node2, index2)=> { if (index2 > index1 && node2.nodeType === 'VariableDeclarationStatement' && node2.declarations[0].name === varName){ @@ -281,7 +283,7 @@ const internalCallVisitor = { }); newVarDecs.sort((a, b) => b.index - a.index); newVarDecs.forEach((varDec) => { - varDec.VarDec.initialValue = null; + varDec.VarDec.initialValue = undefined; childNode.body.statements.splice(varDec.index, 0, varDec.VarDec); }); // remove multiple variable declarations @@ -298,7 +300,7 @@ const internalCallVisitor = { }); } }); - childNode.body.statements = childNode.body.statements.filter(item => item !== null); + childNode.body.statements = childNode.body.statements.filter(item => item !== null && item !== undefined); } else{ state.newStatementList.forEach((statenode, stateid) => { childNode.body.statements.forEach((node, id)=> { From f7bad6c3aee9752a142b701053752ed58b257908 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Thu, 23 May 2024 12:55:30 +0100 Subject: [PATCH 15/24] fix: order of statements in orchestration and declaration of non-accessed variables in orchestration --- .../orchestration/nodejs/toOrchestration.ts | 4 ++-- .../visitors/orchestrationInternalFunctionCallVisitor.ts | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/codeGenerators/orchestration/nodejs/toOrchestration.ts b/src/codeGenerators/orchestration/nodejs/toOrchestration.ts index c72a3775d..67aee9720 100644 --- a/src/codeGenerators/orchestration/nodejs/toOrchestration.ts +++ b/src/codeGenerators/orchestration/nodejs/toOrchestration.ts @@ -90,8 +90,8 @@ export default function codeGenerator(node: any, options: any = {}): any { return `${getAccessedValue(node.declarations[0].name)}`; } - if (!node.initialValue) return ``; - if ( + if (!node.initialValue && !node.declarations[0].isAccessed) return `\nlet ${codeGenerator(node.declarations[0])};`; + if (node.initialValue && node.initialValue.operator && !node.initialValue.operator.includes('=') ) diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index 6da798243..e792016e9 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -25,7 +25,9 @@ const internalCallVisitor = { let sendTransactionNode : any; let newdecrementedSecretStates = []; node._newASTPointer.forEach(file => { + state.intFnindex = {}; state.internalFncName?.forEach( (name, index)=> { + let callingFncName = state.callingFncName[index].name; if(file.fileName === name && file.nodeType === 'File') { file.nodes.forEach(childNode => { if(childNode.nodeType === 'FunctionDefinition'){ @@ -197,7 +199,7 @@ const internalCallVisitor = { } }) node._newASTPointer.forEach(file => { - if(file.fileName === state.callingFncName[index].name) { + if(file.fileName === callingFncName) { file.nodes.forEach(childNode => { if(childNode.nodeType === 'FunctionDefinition') { childNode.parameters.modifiedStateVariables = joinWithoutDupes(childNode.parameters.modifiedStateVariables, state.newParametersList); @@ -257,8 +259,9 @@ const internalCallVisitor = { } }); if(state.callingFncName[index].parent === 'FunctionDefinition'){ - let intFnindex = childNode.body.statements.findIndex(statement => statement.expression?.nodeType === 'InternalFunctionCall' && statement.expression?.name === name); - childNode.body.statements.splice(intFnindex +1, 0, ...state.newStatementList); + let oldIndex = state.intFnindex[callingFncName] ? state.intFnindex[callingFncName] : -1; + state.intFnindex[callingFncName] = childNode.body.statements.findIndex((statement, stIndex) => statement.expression?.nodeType === 'InternalFunctionCall' && statement.expression?.name === name && stIndex > oldIndex); + childNode.body.statements.splice(state.intFnindex[callingFncName] +1, 0, ...state.newStatementList); //insert extra var declarations if needed const findVarVisitor = (thisNode: any, state: any) => { if (thisNode.nodeType === 'Identifier'){ From 7c4d2d91cebedf5ab79c0a277c8e775542e990b1 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Thu, 23 May 2024 18:17:14 +0100 Subject: [PATCH 16/24] fix: ordering of statements in circuits for internal function calls when circuits are not imported --- .../circuitInternalFunctionCallVisitor.ts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts index 68fbf6051..4f828189b 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -83,7 +83,10 @@ const internalCallVisitor = { // Find the Internal Function Node, const { node, parent } = path; + state.intFnindex = {}; state.internalFncName?.forEach( (name,index) => { + if (!state.intFnindex[name]) state.intFnindex[name] = {}; + let callingFncName = state.callingFncName[index].name; node._newASTPointer.forEach(file => { if(file.fileName === name) { file.nodes.forEach(childNode => { @@ -183,7 +186,7 @@ const internalCallVisitor = { } node._newASTPointer.forEach(file => { - if(file.fileName === state.callingFncName[index].name){ + if(file.fileName === callingFncName){ file.nodes.forEach(childNode => { if(childNode.nodeType === 'StructDefinition' && !state.isAddStructDefinition && state.circuitImport[index].isImported === 'true') file.nodes.splice(file.nodes.indexOf(childNode),1); @@ -280,7 +283,7 @@ const internalCallVisitor = { } }) node._newASTPointer.forEach(file => { - if(file.fileName === state.callingFncName[index].name) { + if(file.fileName === callingFncName) { file.nodes.forEach(childNode => { if(childNode.nodeType === 'FunctionDefinition') { childNode.body.statements.forEach(node => { @@ -288,13 +291,18 @@ const internalCallVisitor = { callingFncbpType = node.bpType; } }) - if(childNode.nodeType === 'FunctionDefinition' && state.callingFncName[index].parent === 'FunctionDefinition') - childNode.body.statements = [...new Set([...childNode.body.statements, ...newExpressionList])]; + let oldIndex = state.intFnindex[name][callingFncName] ? state.intFnindex[name][callingFncName] : -1; + if(state.callingFncName[index].parent === 'FunctionDefinition'){ + state.intFnindex[name][callingFncName] = childNode.body.statements.findIndex((statement, stIndex) => statement.expression?.nodeType === 'InternalFunctionCall' && statement.expression?.name === name && stIndex > oldIndex); + childNode.body.statements.splice(state.intFnindex[name][callingFncName] +1, 0, ...newExpressionList); + } else{ childNode.body.statements.forEach(node => { - if(node.nodeType === state.callingFncName[index].parent) - node.body.statements = [...new Set([...node.body.statements, ...newExpressionList])]; - }) + if(node.nodeType === state.callingFncName[index].parent){ + state.intFnindex[name][callingFncName] = node.body.statements.findIndex((statement, stIndex) => statement.expression?.nodeType === 'InternalFunctionCall' && statement.expression?.name === name && stIndex > oldIndex); + node.body.statements.splice(state.intFnindex[name][callingFncName] +1, 0, ...newExpressionList); + } + }) } childNode.body.preStatements.forEach( node => { if(isPartitioned){ From d0353f59d1ee34584d6369ad6c6f68e3ac03047c Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Fri, 24 May 2024 12:42:12 +0100 Subject: [PATCH 17/24] fix: bug meaning that function names were not appearing in contract because the fuction only interacts with the secret in the internal function calls --- .../contract/solidity/nodes/ContractBoilerplateGenerator.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/boilerplate/contract/solidity/nodes/ContractBoilerplateGenerator.ts b/src/boilerplate/contract/solidity/nodes/ContractBoilerplateGenerator.ts index 9bea62e34..0c905504d 100644 --- a/src/boilerplate/contract/solidity/nodes/ContractBoilerplateGenerator.ts +++ b/src/boilerplate/contract/solidity/nodes/ContractBoilerplateGenerator.ts @@ -10,9 +10,7 @@ class ContractBoilerplateGenerator { scope : Scope; constructor(scope: Scope) { if (bpCache.has(scope)) return bpCache.get(scope); - this.scope = scope; - bpCache.set(scope, this); } @@ -80,7 +78,7 @@ class ContractBoilerplateGenerator { indicators: { nullifiersRequired, oldCommitmentAccessRequired, newCommitmentsRequired, containsAccessedOnlyState, encryptionRequired }, } = scope; const fnDefBindings = scope.filterBindings( - (b: any) => b.kind === 'FunctionDefinition' && b.path.containsSecret, + (b: any) => b.kind === 'FunctionDefinition' && (b.path.containsSecret || b.path.scope.indicators.internalFunctionInteractsWithSecret), ); let functionNames = Object.values(fnDefBindings).map((b: any) => b.path.getUniqueFunctionName()); if (isjoinSplitCommitmentsFunction.includes('true')) { From 0415c4c211a1989974ab14a5125b91dc087c6f9e Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Fri, 24 May 2024 14:05:22 +0100 Subject: [PATCH 18/24] fix: error in contract due to internal function calls that interact with secret not being counted as interacting with secret --- src/transformers/visitors/toContractVisitor.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/transformers/visitors/toContractVisitor.ts b/src/transformers/visitors/toContractVisitor.ts index 1f4824bbd..c981bc49c 100644 --- a/src/transformers/visitors/toContractVisitor.ts +++ b/src/transformers/visitors/toContractVisitor.ts @@ -293,8 +293,7 @@ export default { node._newASTPointer = newNode; parent._newASTPointer.push(newNode); - - if (!path.containsSecret) return; + if (!path.containsSecret && !path.scope.indicators.internalFunctionInteractsWithSecret) return; const file = state.circuitAST.files.find((n: any) => n.fileId === node.id); const circuitParams = file.nodes.find((n: any) => n.nodeType === node.nodeType).parameters.parameters; @@ -349,8 +348,7 @@ export default { customInputs: state.customInputs, }), ); - - if (path.scope.containsSecret) + if (path.scope.containsSecret || path.scope.indicators.internalFunctionInteractsWithSecret) postStatements.push( ...buildNode('FunctionBoilerplate', { bpSection: 'postStatements', From 838924d3f5b274046837f98319f37e7a70e2ed2a Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Fri, 24 May 2024 17:10:53 +0100 Subject: [PATCH 19/24] fix: in the circuit when internal functions are not imported the import statement list is not updated --- .../visitors/circuitInternalFunctionCallVisitor.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts index 4f828189b..1e1ea55ed 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -125,6 +125,8 @@ const internalCallVisitor = { state.state.newReturnParameterList.splice(nodeIndex,1); } }) + } else if (childNode.nodeType === 'ImportStatementList'){ + state.newImportStatementList = cloneDeep(childNode.imports); } }) if(state.circuitImport[index].isImported ==='true') { @@ -458,6 +460,8 @@ const internalCallVisitor = { childNode.body.postStatements.splice(!dupNode.index ? 0 : dupNode.index +1, 0, dupNode.node); }); reorderBoilerPlate(childNode.body.postStatements); + } else if (childNode.nodeType === 'ImportStatementList'){ + childNode.imports = [...new Set([...childNode.imports, ...state.newImportStatementList])]; } }) From 6c5a61a995531cc9b500c137cccce0850ca6d71c Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Tue, 28 May 2024 14:20:33 +0100 Subject: [PATCH 20/24] fix issue due to root appearing twice in mjs file --- .../javascript/raw/boilerplate-generator.ts | 7 +++-- .../javascript/raw/toOrchestration.ts | 31 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts b/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts index 0bc1c822d..958aac764 100644 --- a/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts +++ b/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts @@ -439,6 +439,7 @@ class BoilerplateGenerator { burnedOnly, accessedOnly, nullifierRootRequired, + newNullifierRootRequired, initialisationRequired, encryptionRequired, rootRequired, @@ -466,7 +467,7 @@ class BoilerplateGenerator { \tsecretKey.integer, \tsecretKey.integer, ${nullifierRootRequired ? `\t${stateName}_nullifierRoot.integer,` : ``} - ${nullifierRootRequired ? `\t${stateName}_newNullifierRoot.integer,` : ``} + ${newNullifierRootRequired ? `\t${stateName}_newNullifierRoot.integer,` : ``} \t${stateName}_0_nullifier.integer, \t${stateName}_0_nullifier_path.integer, \t${stateName}_0_nullifier_updatedpath.integer, @@ -501,7 +502,7 @@ class BoilerplateGenerator { ${parameters.join('\n')}${stateVarIds.join('\n')} \tsecretKey.integer, ${nullifierRootRequired ? `\t${stateName}_nullifierRoot.integer,` : ``} - ${nullifierRootRequired ? `\t${stateName}_newNullifierRoot.integer,` : ``} + ${newNullifierRootRequired ? `\t${stateName}_newNullifierRoot.integer,` : ``} \t${stateName}_nullifier.integer, \t${stateName}_nullifier_path.integer, \t${stateName}_nullifier_updatedpath.integer, @@ -529,7 +530,7 @@ class BoilerplateGenerator { ${parameters.join('\n')}${stateVarIds.join('\n')} \t${stateName}_commitmentExists ? secretKey.integer: generalise(0).integer, ${nullifierRootRequired ? `\t${stateName}_nullifierRoot.integer,` : ``} - ${nullifierRootRequired ? `\t${stateName}_newNullifierRoot.integer,` : ``} + ${newNullifierRootRequired ? `\t${stateName}_newNullifierRoot.integer,` : ``} \t${stateName}_nullifier.integer, \t${stateName}_nullifier_path.integer, \t${stateName}_nullifier_updatedpath.integer, diff --git a/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts b/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts index 773e21fa8..42db7ac09 100644 --- a/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts +++ b/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts @@ -91,19 +91,19 @@ export const sendTransactionBoilerplate = (node: any) => { break; case false: default: - // whole + // whole if (!stateNode.reinitialisedOnly) output[2].push(`${privateStateName}_root.integer`); - if (!stateNode.accessedOnly && !stateNode.reinitialisedOnly) { - output[1].push(`${privateStateName}_nullifier.integer`); - output[0].push(`${privateStateName}_nullifierRoot.integer`,`${privateStateName}_newNullifierRoot.integer`); - } - if (!stateNode.accessedOnly && !stateNode.burnedOnly) - output[3].push(`${privateStateName}_newCommitment.integer`); - if (stateNode.encryptionRequired) { - output[4].push(`${privateStateName}_cipherText`); - output[5].push(`${privateStateName}_encKey`); - } + if (!stateNode.accessedOnly && !stateNode.reinitialisedOnly) { + output[1].push(`${privateStateName}_nullifier.integer`); + output[0].push(`${privateStateName}_nullifierRoot.integer`,`${privateStateName}_newNullifierRoot.integer`); + } + if (!stateNode.accessedOnly && !stateNode.burnedOnly) + output[3].push(`${privateStateName}_newCommitment.integer`); + if (stateNode.encryptionRequired) { + output[4].push(`${privateStateName}_cipherText`); + output[5].push(`${privateStateName}_encKey`); + } break; } @@ -117,6 +117,7 @@ export const generateProofBoilerplate = (node: any) => { const cipherTextLength: number[] = []; let containsRoot = false; let containsNullifierRoot = false; + let containsNewNullifierRoot = false; const privateStateNames = Object.keys(node.privateStates); let stateName: string; let stateNode: any; @@ -181,13 +182,15 @@ export const generateProofBoilerplate = (node: any) => { burnedOnly: stateNode.burnedOnly, accessedOnly: stateNode.accessedOnly, nullifierRootRequired: !containsNullifierRoot, + newNullifierRootRequired: !containsNewNullifierRoot, initialisationRequired: stateNode.initialisationRequired, encryptionRequired: stateNode.encryptionRequired, rootRequired: !containsRoot, parameters, }) ); - if(stateNode.nullifierRequired) containsNullifierRoot = true; + if(stateNode.nullifierRequired || stateNode.accessedOnly) containsNullifierRoot = true; + if(stateNode.nullifierRequired) containsNewNullifierRoot = true; if (!stateNode.reinitialisedOnly) containsRoot = true; break; @@ -216,6 +219,7 @@ export const generateProofBoilerplate = (node: any) => { reinitialisedOnly: false, burnedOnly: false, nullifierRootRequired: !containsNullifierRoot, + newNullifierRootRequired: !containsNewNullifierRoot, initialisationRequired: false, encryptionRequired: stateNode.encryptionRequired, rootRequired: !containsRoot, @@ -224,6 +228,7 @@ export const generateProofBoilerplate = (node: any) => { }) ); containsNullifierRoot = true; + containsNewNullifierRoot = true; containsRoot = true; break; case false: @@ -247,6 +252,7 @@ export const generateProofBoilerplate = (node: any) => { reinitialisedOnly: false, burnedOnly: false, nullifierRootRequired: false, + newNullifierRootRequired: false, initialisationRequired: false, encryptionRequired: stateNode.encryptionRequired, rootRequired: false, @@ -815,7 +821,6 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { // params[2] = arr of nullifiers // params[3] = arr of commitments - if (params[0][0][0]) params[0][0] = `${params[0][0][0]},${params[0][0][1]},`; // nullifierRoot - array if (params[0][2][0]) params[0][2] = `${params[0][2][0]},`; // commitmentRoot - array if (params[0][1][0]) params[0][1] = `[${params[0][1]}],`; // nullifiers - array From 2d655621aecc4e45b78fb2530aef2b5cf279209c Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Tue, 28 May 2024 16:55:50 +0100 Subject: [PATCH 21/24] fix: issue due to nullifier root and commitment root in wrong order in the contract --- .../solidity/nodes/ContractBoilerplateGenerator.ts | 8 +++++--- .../contract/solidity/raw/ContractBoilerplateGenerator.ts | 4 +++- .../orchestration/javascript/raw/toOrchestration.ts | 5 ++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/boilerplate/contract/solidity/nodes/ContractBoilerplateGenerator.ts b/src/boilerplate/contract/solidity/nodes/ContractBoilerplateGenerator.ts index 0c905504d..8d7f47ce6 100644 --- a/src/boilerplate/contract/solidity/nodes/ContractBoilerplateGenerator.ts +++ b/src/boilerplate/contract/solidity/nodes/ContractBoilerplateGenerator.ts @@ -128,9 +128,11 @@ class ContractBoilerplateGenerator { params?.forEach(circuitParamNode => { switch (circuitParamNode.bpType) { case 'nullification': + if (!newList.includes('nullifierRoot')) + newList.push('nullifierRoot'); if (circuitParamNode.isNullified) { - if (!newList.includes('nullifierRoot')) - newList.push('nullifierRoot') + if (!newList.includes('newNullifierRoot')) + newList.push('newNullifierRoot'); newList.push('nullifier'); } @@ -175,7 +177,7 @@ class ContractBoilerplateGenerator { } circuitParams[ functionName ] = parameterList; } - const constructorContainsSecret = Object.values(this.scope.bindings).some((binding: any) => binding.node.kind === 'constructor') + const constructorContainsSecret = Object.values(this.scope.bindings).some((binding: any) => binding.node.kind === 'constructor'); return { nullifiersRequired, oldCommitmentAccessRequired, newCommitmentsRequired, containsAccessedOnlyState, encryptionRequired, constructorContainsSecret, circuitParams, isjoinSplitCommitmentsFunction}; }, diff --git a/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts b/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts index 03123130e..d4623ba70 100644 --- a/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts +++ b/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts @@ -126,7 +126,9 @@ class ContractBoilerplateGenerator { switch (input) { case 'nullifierRoot': verifyInput.push( ` - inputs[k++] = _inputs.nullifierRoot;`); + inputs[k++] = _inputs.nullifierRoot;`); + break; + case 'newNullifierRoot': verifyInput.push( ` inputs[k++] = _inputs.latestNullifierRoot;`); break; diff --git a/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts b/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts index 42db7ac09..281849c8c 100644 --- a/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts +++ b/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts @@ -820,15 +820,14 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { // params[1] = arr of commitment root(s) // params[2] = arr of nullifiers // params[3] = arr of commitments - - if (params[0][0][0]) params[0][0] = `${params[0][0][0]},${params[0][0][1]},`; // nullifierRoot - array + + if (params[0][0][0]) params[0][0] = `${params[0][0][0]},${params[0][0][1]},`; // nullifierRoot - array if (params[0][2][0]) params[0][2] = `${params[0][2][0]},`; // commitmentRoot - array if (params[0][1][0]) params[0][1] = `[${params[0][1]}],`; // nullifiers - array if (params[0][3][0]) params[0][3] = `[${params[0][3]}],`; // commitments - array if (params[0][4][0]) params[0][4] = `[${params[0][4]}],`; // cipherText - array of arrays if (params[0][5][0]) params[0][5] = `[${params[0][5]}],`; // cipherText - array of arrays - if (node.functionName === 'cnstrctr') return { statements: [ `\n\n// Save transaction for the constructor: From bf5e2efdddac886b6a43ddd27ad6e36bb576d0e8 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Wed, 29 May 2024 17:09:20 +0100 Subject: [PATCH 22/24] fix: error introduced in for-InternalFunctionCall due to double variable declarqtion --- ...rchestrationInternalFunctionCallVisitor.ts | 35 +++++++++++++------ ...est4.zol => internalFunctionCallTest2.zol} | 3 +- 2 files changed, 25 insertions(+), 13 deletions(-) rename test/contracts/{InternalFunctionCallTest4.zol => internalFunctionCallTest2.zol} (89%) diff --git a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts index e792016e9..a2ea05675 100644 --- a/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/orchestrationInternalFunctionCallVisitor.ts @@ -197,7 +197,7 @@ const internalCallVisitor = { }) state.newPostStatementList.splice(- 3); } - }) + }); node._newASTPointer.forEach(file => { if(file.fileName === callingFncName) { file.nodes.forEach(childNode => { @@ -306,7 +306,7 @@ const internalCallVisitor = { childNode.body.statements = childNode.body.statements.filter(item => item !== null && item !== undefined); } else{ state.newStatementList.forEach((statenode, stateid) => { - childNode.body.statements.forEach((node, id)=> { + childNode.body.statements.forEach((node, id)=> { if(node.nodeType === state.callingFncName[index].parent){ if(statenode.nodeType === 'VariableDeclarationStatement'){ childNode.body.statements[id-1] = statenode; @@ -314,15 +314,28 @@ const internalCallVisitor = { if(kidNode.nodeType === 'ExpressionStatement'&& kidNode.expression.name === state.internalFncName[index]) { kidNode.expression = Object.assign(kidNode.expression,statenode.initialValue); node.body.statements?.splice(node.body.statements.indexOf(kidNode)+1, 0, state.newStatementList[stateid+1]); - } - }) - childNode.body.statements[id-1].initialValue ={}; - } - } - }) - - }) - + } + }); + childNode.body.statements[id-1].initialValue =undefined; + } + } + }); + }); + // remove multiple variable declarations + childNode.body.statements.forEach((node1, index1)=> { + let isDecDeleted = false; + if(node1.nodeType === 'VariableDeclarationStatement'){ + childNode.body.statements.forEach((node2, index2)=> { + if(!isDecDeleted && index2 < index1 && node2 && node2.nodeType === 'VariableDeclarationStatement'){ + if ((node1.declarations[0].name === node2.declarations[0].name)){ + childNode.body.statements.splice(index1, 1, node1.initialValue); + isDecDeleted = true; + } + } + }); + } + }); + childNode.body.statements = childNode.body.statements.filter(item => item !== null && item !== undefined ); } childNode.body.postStatements.forEach(node => { diff --git a/test/contracts/InternalFunctionCallTest4.zol b/test/contracts/internalFunctionCallTest2.zol similarity index 89% rename from test/contracts/InternalFunctionCallTest4.zol rename to test/contracts/internalFunctionCallTest2.zol index 09488b5a9..3ee0b3a85 100644 --- a/test/contracts/InternalFunctionCallTest4.zol +++ b/test/contracts/internalFunctionCallTest2.zol @@ -4,7 +4,6 @@ contract Assign { secret uint256 private a; secret uint256 private b; uint256 public c; - secret uint256 private d; @@ -14,7 +13,7 @@ contract Assign { } function addA( uint256 value) public { - known d += value; + known a += value; } function remove( uint256 value, uint256 value1 ) public { unknown b += value; From 458744e3943a16999b5336a359dd7842eef1735d Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Wed, 29 May 2024 18:59:58 +0100 Subject: [PATCH 23/24] finalise test contracts and add comments --- .../visitors/checks/unsupportedVisitor.ts | 38 -------------- .../circuitInternalFunctionCallVisitor.ts | 1 + src/transformers/visitors/toCircuitVisitor.ts | 1 + test/contracts/InternalFunctionCallTest10.zol | 49 +++++++++++++++++++ test/contracts/InternalFunctionCallTest5.zol | 39 +++++++++++++++ test/contracts/InternalFunctionCallTest6.zol | 48 ++++++++++++++++++ .../InternalFunctionCallTest7.zol} | 21 ++++++-- test/contracts/InternalFunctionCallTest8.zol | 36 ++++++++++++++ test/contracts/InternalFunctionCallTest9.zol | 44 +++++++++++++++++ 9 files changed, 235 insertions(+), 42 deletions(-) create mode 100644 test/contracts/InternalFunctionCallTest10.zol create mode 100644 test/contracts/InternalFunctionCallTest5.zol create mode 100644 test/contracts/InternalFunctionCallTest6.zol rename test/{error-checks/internalFunctionCallTest2.zol => contracts/InternalFunctionCallTest7.zol} (57%) create mode 100644 test/contracts/InternalFunctionCallTest8.zol create mode 100644 test/contracts/InternalFunctionCallTest9.zol diff --git a/src/transformers/visitors/checks/unsupportedVisitor.ts b/src/transformers/visitors/checks/unsupportedVisitor.ts index 7262629ff..4385335da 100644 --- a/src/transformers/visitors/checks/unsupportedVisitor.ts +++ b/src/transformers/visitors/checks/unsupportedVisitor.ts @@ -109,42 +109,4 @@ export default { ); }, }, - - ContractDefinition: { - enter(node: any, state: any) { - let internalFunctionStateVarList = {}; - let secretStateVarList = {}; - const nestedInternalFunctionVisitor = (thisNode: any, state: any) => { - if (thisNode.nodeType === 'VariableDeclaration' && thisNode.stateVariable && thisNode.isSecret){ - secretStateVarList[thisNode.name] = []; - } - if (thisNode.nodeType === 'FunctionDefinition'){ - internalFunctionStateVarList[thisNode.name] = []; - } - if (thisNode.nodeType === 'Identifier'){ - let fnDefKeys = Object.keys(internalFunctionStateVarList); - let fnName = fnDefKeys[fnDefKeys.length - 1]; - if (thisNode.typeDescriptions.typeIdentifier.includes("t_function_internal")){ - internalFunctionStateVarList[fnName].push(thisNode.name); - } - if (Object.keys(secretStateVarList).includes(thisNode.name)){ - secretStateVarList[thisNode.name].push(fnName); - } - } - } - traverseNodesFast(node, nestedInternalFunctionVisitor, state); - - Object.keys(internalFunctionStateVarList).forEach((fnVar) => { - Object.keys(secretStateVarList).forEach((stateVar) => { - let commonElements = internalFunctionStateVarList[fnVar].filter(element => secretStateVarList[stateVar].includes(element)); - if (commonElements.length > 1){ - /*throw new ZKPError( - `A function makes use of a secret state variable in multiple internal function calls. This would mean a commitment would be nullified twice per function call and so is not supported in Starlight.`, - node - );*/ - } - }); - }); - }, - }, }; diff --git a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts index 1e1ea55ed..2cbb08b94 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -295,6 +295,7 @@ const internalCallVisitor = { }) let oldIndex = state.intFnindex[name][callingFncName] ? state.intFnindex[name][callingFncName] : -1; if(state.callingFncName[index].parent === 'FunctionDefinition'){ + // When merging the statements, we need to ensure that the new statements are added after the InternalFunctionCall statement. state.intFnindex[name][callingFncName] = childNode.body.statements.findIndex((statement, stIndex) => statement.expression?.nodeType === 'InternalFunctionCall' && statement.expression?.name === name && stIndex > oldIndex); childNode.body.statements.splice(state.intFnindex[name][callingFncName] +1, 0, ...newExpressionList); } diff --git a/src/transformers/visitors/toCircuitVisitor.ts b/src/transformers/visitors/toCircuitVisitor.ts index 8e964af60..0d651b31c 100644 --- a/src/transformers/visitors/toCircuitVisitor.ts +++ b/src/transformers/visitors/toCircuitVisitor.ts @@ -1373,6 +1373,7 @@ let childOfSecret = path.getAncestorOfType('ForStatement')?.containsSecret; const startNodePath = path.getAncestorOfType('ContractDefinition'); isCircuit = true; let modifiedVariables = []; + // Check if the internal function should be imported into the circuit (this is updated later if future internal function calls modify the state variables accessed in this internal function) startNodePath?.node.nodes.forEach(node => { //every state variable in the contract that isn't a struct if(node.nodeType === 'VariableDeclaration' && !node.typeDescriptions.typeIdentifier.includes('_struct')){ diff --git a/test/contracts/InternalFunctionCallTest10.zol b/test/contracts/InternalFunctionCallTest10.zol new file mode 100644 index 000000000..6529a421b --- /dev/null +++ b/test/contracts/InternalFunctionCallTest10.zol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: CC0 +pragma solidity ^0.8.0; +contract Assign { + + secret uint256 private a; + secret uint256 private d; + secret uint256 private b; + uint256 public c; + + function addB( uint256 value, uint256 value1) public { + c += value1; + known a += value; + } + function addA( uint256 value) public { + d = a+ value; + } + + function addC( uint256 value, uint256 value1) public { + c += value1; + d = a+ value; + } + + + + function remove2( uint256 value, uint256 value1 ) public { + addC( value, value1); + addA(value1); + a += value; + known b += value +a; + } + + //function remove3( uint256 value, uint256 value1 ) public { + // addC( value, value1); + // a += value; + // addA(value1); + // known b += value +a; + //} + + function remove4( uint256 value, uint256 value1 ) public { + addC( value, value1); + addA(value1); + } + + + + + + +} \ No newline at end of file diff --git a/test/contracts/InternalFunctionCallTest5.zol b/test/contracts/InternalFunctionCallTest5.zol new file mode 100644 index 000000000..0a625f5ae --- /dev/null +++ b/test/contracts/InternalFunctionCallTest5.zol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: CC0 +pragma solidity ^0.8.0; +contract Assign { + secret uint256 private a; + secret uint256 private d; + secret uint256 private b; + uint256 public c; + + function addB( uint256 value, uint256 value1) public { + c += value1; + known a += value; + } + function addA( uint256 value) public { + d = a+ value; + } + + function fncall( uint256 value, uint256 value1 ) public { + addA(value1); + addB( value, value1); + } + function remove1( uint256 value, uint256 value1 ) public { + known b += value +a; + addA(value1); + addB( value, value1); + known b += value +a; + } + + + function remove2( uint256 value, uint256 value1 ) public { + known b += value +a; + addA(value1); + addB( value, value1); + addA(value1); + known b += value +a; + } + + + +} \ No newline at end of file diff --git a/test/contracts/InternalFunctionCallTest6.zol b/test/contracts/InternalFunctionCallTest6.zol new file mode 100644 index 000000000..f71d840bd --- /dev/null +++ b/test/contracts/InternalFunctionCallTest6.zol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: CC0 +pragma solidity ^0.8.0; +contract Assign { + secret uint256 private a; + secret uint256 private d; + secret uint256 private b; + uint256 public c; + + function addB( uint256 value, uint256 value1) public { + c += value1; + known a += value; + } + function addA( uint256 value) public { + d = a+ value; + } + + + + function remove( uint256 value, uint256 value1 ) public { + known b += value +a; + addB( value, value1); + addA(value1); + known b += value +a; + } + + + + function remove1( uint256 value, uint256 value1 ) public { + known a += value; + addB( value, value1); + known b += value +a; + } + + function remove2( uint256 value, uint256 value1 ) public { + known b += value +a; + addB( value, value1); + known a += value; + known b += value +a; + addA(value1); + } + + function remove3( uint256 value, uint256 value1 ) public { + addB( value, value1); + addA(value1); + } + + +} \ No newline at end of file diff --git a/test/error-checks/internalFunctionCallTest2.zol b/test/contracts/InternalFunctionCallTest7.zol similarity index 57% rename from test/error-checks/internalFunctionCallTest2.zol rename to test/contracts/InternalFunctionCallTest7.zol index c62c4aa71..afb08a951 100644 --- a/test/error-checks/internalFunctionCallTest2.zol +++ b/test/contracts/InternalFunctionCallTest7.zol @@ -5,8 +5,6 @@ contract Assign { secret uint256 private b; uint256 public c; - - function addB( uint256 value, uint256 value1) public { c += value1; known a += value; @@ -15,10 +13,25 @@ contract Assign { known a += value; } function remove( uint256 value, uint256 value1 ) public { - unknown b += value; + addA(value1); addB( value, value1); + } + + function remove1( uint256 value, uint256 value1 ) public { + known b += value +a; addA(value1); + addB( value, value1); } + function remove2( uint256 value, uint256 value1 ) public { + known b += value +a; + known a += value; + addA(value1); + addB( value, value1); + known b += value +a; + } + + + -} +} \ No newline at end of file diff --git a/test/contracts/InternalFunctionCallTest8.zol b/test/contracts/InternalFunctionCallTest8.zol new file mode 100644 index 000000000..ce503dede --- /dev/null +++ b/test/contracts/InternalFunctionCallTest8.zol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: CC0 +pragma solidity ^0.8.0; +contract Assign { + secret uint256 private a; + secret uint256 private b; + uint256 public c; + + function addB( uint256 value, uint256 value1) public { + c += value1; + known a += value; + } + function addA( uint256 value) public { + known a += value; + } + + function remove3( uint256 value, uint256 value1 ) public { + known b += value +a; + addA(value1); + known b += value +a; + addB( value, value1); + known a += value; + } + + function remove4( uint256 value, uint256 value1 ) public { + known b += value +a; + known a += value; + addA(value1); + known a += value; + addB( value, value1); + known a += value; + known b += value +a; + } + + + +} \ No newline at end of file diff --git a/test/contracts/InternalFunctionCallTest9.zol b/test/contracts/InternalFunctionCallTest9.zol new file mode 100644 index 000000000..d42b9fa3e --- /dev/null +++ b/test/contracts/InternalFunctionCallTest9.zol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: CC0 +pragma solidity ^0.8.0; +contract Assign { + + secret uint256 private a; + secret uint256 private d; + secret uint256 private b; + uint256 public c; + + function addB( uint256 value, uint256 value1) public { + c += value1; + known a += value; + } + function addA( uint256 value) public { + d = a+ value; + } + + function addC( uint256 value, uint256 value1) public { + c += value1; + d = a+ value; + } + + + + function remove( uint256 value, uint256 value1 ) public { + b += value +a; + addC( value, value1); + addA(value1); + b += value +a; + } + + function remove1( uint256 value, uint256 value1 ) public { + a += value; + addC( value, value1); + addA(value1); + known b += value +a; + } + + + + + + +} \ No newline at end of file From a29fa6d442375a09f2c3d97c2d4cbf8ed27f2eac Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Thu, 30 May 2024 10:24:41 +0100 Subject: [PATCH 24/24] comment --- src/transformers/visitors/circuitInternalFunctionCallVisitor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts index 2cbb08b94..44f5fb591 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -315,6 +315,7 @@ const internalCallVisitor = { node.newCommitmentValue = node.newCommitmentValue+' - ('+commitmentValue+')'; } }); + // We need to merge the pre-statments and post-statements of the internal function with the calling function. childNode.body.preStatements.forEach(node => { switch(node.bpType) { case 'PoKoSK' : {