diff --git a/src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts b/src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts index 30887bd1e..6ef2be528 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/boilerplate/contract/solidity/nodes/ContractBoilerplateGenerator.ts b/src/boilerplate/contract/solidity/nodes/ContractBoilerplateGenerator.ts index 4fcc80a0c..1f4e64ec1 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')) { @@ -130,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'); } @@ -177,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 6535ffbae..d1e1685ab 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; @@ -220,7 +222,6 @@ class ContractBoilerplateGenerator { newCommitments: 0, encryption: 0, }; - _inputs.map(i => verifyInputsMap(type, i, counter)); 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 08bc5abff..4278b6f12 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, @@ -817,16 +823,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: diff --git a/src/codeGenerators/orchestration/nodejs/toOrchestration.ts b/src/codeGenerators/orchestration/nodejs/toOrchestration.ts index aec98dffa..ee4660743 100644 --- a/src/codeGenerators/orchestration/nodejs/toOrchestration.ts +++ b/src/codeGenerators/orchestration/nodejs/toOrchestration.ts @@ -90,7 +90,8 @@ export default function codeGenerator(node: any, options: any = {}): any { return `${getAccessedValue(node.declarations[0].name)}`; } - if ( + if (!node.initialValue && !node.declarations[0].isAccessed) return `\nlet ${codeGenerator(node.declarations[0])};`; + if (node.initialValue && node.initialValue.operator && !node.initialValue.operator.includes('=') ) @@ -117,8 +118,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 24ea2f537..44f5fb591 100644 --- a/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts +++ b/src/transformers/visitors/circuitInternalFunctionCallVisitor.ts @@ -4,8 +4,75 @@ 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); + }); +} +// 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 @@ -16,18 +83,22 @@ 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) { - 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') { - 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 +107,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 +117,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) @@ -54,9 +125,11 @@ const internalCallVisitor = { state.state.newReturnParameterList.splice(nodeIndex,1); } }) + } else if (childNode.nodeType === 'ImportStatementList'){ + state.newImportStatementList = cloneDeep(childNode.imports); } }) - + if(state.circuitImport[index].isImported ==='true') { // Collect the internal call ParameterList let internalFncParameters: string[] = []; state.newParameterList.forEach(node => { @@ -71,10 +144,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' : { @@ -112,19 +185,21 @@ const internalCallVisitor = { state.circuitArguments.push(param); } }); + } 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) + if(childNode.nodeType === 'StructDefinition' && !state.isAddStructDefinition && state.circuitImport[index].isImported === 'true') file.nodes.splice(file.nodes.indexOf(childNode),1); }) 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])] - if(childNode.nodeType === 'FunctionDefinition' && state.callingFncName[index].parent === 'FunctionDefinition'){ - childNode.body.statements.forEach(node => { + 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' && 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); @@ -133,7 +208,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 => { @@ -153,9 +228,8 @@ const internalCallVisitor = { } }) - } - else if(state.circuitImport[index] === 'false'){ + if(state.circuitImport[index].isImported === 'false'){ let newExpressionList = []; let isPartitioned = false let internalFncbpType: string; @@ -171,7 +245,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 +272,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); @@ -211,7 +285,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 => { @@ -219,13 +293,19 @@ 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'){ + // 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); + } 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){ @@ -234,8 +314,77 @@ const internalCallVisitor = { else 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' : { + 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); + }); + reorderBoilerPlate(childNode.body.preStatements); childNode.body.postStatements.forEach( node => { if(isPartitioned){ if(internalFncbpType === callingFncbpType) @@ -244,6 +393,77 @@ 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 = undefined; + 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 ? 0 : dupNode.index +1, 0, dupNode.node); + }); + reorderBoilerPlate(childNode.body.postStatements); + } else if (childNode.nodeType === 'ImportStatementList'){ + childNode.imports = [...new Set([...childNode.imports, ...state.newImportStatementList])]; } }) @@ -252,7 +472,8 @@ const internalCallVisitor = { } } }) - }) + }); + }, }, 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..a2ea05675 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)); @@ -24,21 +25,22 @@ 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') { - if(state.circuitImport[index]==='true') { file.nodes.forEach(childNode => { if(childNode.nodeType === 'FunctionDefinition'){ 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]) + 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()) { - node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[index]) + for(const [index, oldStateName] of state.oldStateArray[name].entries()) { + node.name = node.name.replace('_'+oldStateName, '_'+state.newStateArray[name][index]) } } state.newPreStatementList = cloneDeep(childNode.body.preStatements); @@ -48,8 +50,8 @@ const internalCallVisitor = { let stateNode: any; 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]) + 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]; delete(node.privateStates[ stateName ]); @@ -58,23 +60,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]+'.') + 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[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 : @@ -86,25 +88,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 oldStateArray.entries()) { - node.name = node.name.replace('_'+oldStateName, '_'+ state.newStateArray[index]); - } - }); - 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]); - } - } - 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]); - } - } - }) + 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'){ @@ -112,8 +111,8 @@ const internalCallVisitor = { let stateNode: any; 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]) + 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]; delete(node.privateStates[ stateName ]); @@ -126,18 +125,18 @@ const internalCallVisitor = { let stateNode: any; 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]) + 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]; 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]) } } } @@ -146,19 +145,19 @@ const internalCallVisitor = { let stateName: string; let newstateName: string; for( stateName of Object.keys(generateProofNode.privateStates)) { - for(const [index, oldStateName] of oldStateArray.entries()) { - newstateName = stateName.replace('_'+oldStateName, '_'+state.newStateArray[index]) + 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]; 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[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 = []; @@ -169,8 +168,8 @@ const internalCallVisitor = { let stateNode: any; 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]) + 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]; delete(sendTransactionNode.privateStates[ stateName ]); @@ -184,23 +183,23 @@ const internalCallVisitor = { let stateNode: any; 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]) + 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]; 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]) } } } }) state.newPostStatementList.splice(- 3); } - }) + }); 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); @@ -211,6 +210,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 +225,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 +241,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) } }); @@ -236,31 +258,55 @@ 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 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'){ + 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 = undefined; + 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 && 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); } 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; @@ -268,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 => { @@ -284,25 +343,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; } @@ -318,54 +401,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 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._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]); - } - }); - } - }) - - } - }) - } } }) }) @@ -377,15 +412,19 @@ FunctionCall: { if(path.isInternalFunctionCall()) { const args = node.arguments; let isCircuit = false; + const fn_name = node.expression.name; + state.newStateArray ??= {}; + state.newStateArray[fn_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[fn_name] = args.map(arg => (arg.expression.name+'.'+arg.memberName)); else - state.newStateArray = args.map(arg => (arg.name)); + state.newStateArray[fn_name] = args.map(arg => (arg.name)); } 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); @@ -394,7 +433,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){ @@ -402,7 +441,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; diff --git a/src/transformers/visitors/toCircuitVisitor.ts b/src/transformers/visitors/toCircuitVisitor.ts index 692097172..012ce94ef 100644 --- a/src/transformers/visitors/toCircuitVisitor.ts +++ b/src/transformers/visitors/toCircuitVisitor.ts @@ -317,6 +317,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]; @@ -1360,7 +1375,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); @@ -1370,33 +1386,50 @@ 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 = []; + // 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')){ - 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', { @@ -1404,12 +1437,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 6a91bdef0..0025fb35a 100644 --- a/src/transformers/visitors/toContractVisitor.ts +++ b/src/transformers/visitors/toContractVisitor.ts @@ -293,14 +293,30 @@ 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; 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) { @@ -315,7 +331,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', { @@ -332,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', @@ -901,7 +916,6 @@ DoWhileStatement: { ...(internalfnDefIndicators.nullifiersRequired? [`newNullifiers`] : []), ...(internalfnDefIndicators.oldCommitmentAccessRequired ? [`commitmentRoot`] : []), ...(internalfnDefIndicators.newCommitmentsRequired ? [`newCommitments`] : []), - ...(internalfnDefIndicators.containsAccessedOnlyState ? [`checkNullifiers`] : []), ...(internalfnDefIndicators.encryptionRequired ? [`cipherText`] : []), ...(internalfnDefIndicators.encryptionRequired ? [`ephPubKeys`] : []), `proof`, diff --git a/src/transformers/visitors/toOrchestrationVisitor.ts b/src/transformers/visitors/toOrchestrationVisitor.ts index 4f6ca1c3f..8a9caec82 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 @@ -1362,8 +1361,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' && 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, 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/contracts/InternalFunctionCallTest7.zol b/test/contracts/InternalFunctionCallTest7.zol new file mode 100644 index 000000000..afb08a951 --- /dev/null +++ b/test/contracts/InternalFunctionCallTest7.zol @@ -0,0 +1,37 @@ +// 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 remove( 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); + } + + 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 diff --git a/test/contracts/internalFunctionCallTest2.zol b/test/contracts/internalFunctionCallTest2.zol index 525412d79..3ee0b3a85 100644 --- a/test/contracts/internalFunctionCallTest2.zol +++ b/test/contracts/internalFunctionCallTest2.zol @@ -22,4 +22,4 @@ contract Assign { } -} +} \ No newline at end of file