diff --git a/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts b/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts index f7eba5be..e4eb6414 100644 --- a/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts +++ b/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts @@ -579,8 +579,8 @@ encryptBackupPreimage = { } else{ plainText = `[BigInt(${saltName}.hex(32)), BigInt(${stateName}_stateVarId), ${valueName}]`; - if (structProperties) varName += ` s`; } + if (structProperties) varName += ` s`; if (stateType === 'increment') varName += ` u`; return[`\n\n// Encrypt pre-image for state variable ${stateName} as a backup: \n let ${stateName}_ephSecretKey = generalise(utils.randomHex(31)); \n diff --git a/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts b/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts index 2c5390f5..90d6bda8 100644 --- a/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts +++ b/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts @@ -100,7 +100,7 @@ export const sendTransactionBoilerplate = (node: any) => { output[0].push(`${privateStateName}_nullifier.integer`); } } - if (!stateNode.burnedOnly) + if (!stateNode.accessedOnly && !stateNode.burnedOnly) output[2].push(`${privateStateName}_newCommitment.integer`); if (stateNode.encryptionRequired) { output[4].push(`${privateStateName}_cipherText`); diff --git a/src/codeGenerators/orchestration/files/toOrchestration.ts b/src/codeGenerators/orchestration/files/toOrchestration.ts index b491ef57..62aacd17 100644 --- a/src/codeGenerators/orchestration/files/toOrchestration.ts +++ b/src/codeGenerators/orchestration/files/toOrchestration.ts @@ -600,7 +600,8 @@ const prepareBackupVariable = (node: any) => { let isStruct = false; if (varName.includes(" a")) { isArray = true; - } else if (varName.includes(" s")) { + } + if (varName.includes(" s")) { isStruct = true; } const plainText = decrypt( @@ -617,6 +618,7 @@ const prepareBackupVariable = (node: any) => { console.log("Decrypted pre-image of commitment for variable name: " + name + ": "); let salt = generalise(plainText[0]); console.log(\`\\tSalt: \${salt.integer}\`); + let count; if (isArray){ console.log(\`\\tState variable StateVarId: \${plainText[2]}\`); mappingKey = generalise(plainText[1]); @@ -632,36 +634,47 @@ const prepareBackupVariable = (node: any) => { ); stateVarId = reGenStateVarId; console.log(\`Regenerated StateVarId: \${reGenStateVarId.bigInt}\`); - value = generalise(plainText[3]); - console.log(\`\\tValue: \${value.integer}\`); + count = 3; } else { stateVarId = generalise(plainText[1]); console.log(\`\\tStateVarId: \${plainText[1]}\`); - if (isStruct){ - value = {};`; - - node.privateStates.forEach((stateVar: any) => { - if (stateVar.structProperties){ - let propCount = 2; + count = 2; + } + if (isStruct){ + value = {};`; + node.privateStates.forEach((stateVar: any) => { + if (stateVar.structProperties){ + let propCount = 2; + if (stateVar.mappingKey){ + propCount++; + genericApiServiceFile += `\nif (stateVarId.integer === + generalise(utils.mimcHash( + [ + BigInt(${stateVar.stateVarId[0]}), + generalise(plainText[1]).bigInt, + ], + "ALT_BN_254" + )).integer) {` + } else { genericApiServiceFile += `\nif (stateVarId.integer === '${stateVar.stateVarId}') {` - stateVar.structProperties.forEach((prop: any) => { - genericApiServiceFile += `value.${prop} = plainText[${propCount}];\n`; - propCount++; - }); - genericApiServiceFile += `}\n`; } - }); - - genericApiServiceFile += `console.log(\`\\tValue: \${value}\`); - } else { - value = generalise(plainText[2]); - console.log(\`\\tValue: \${value.integer}\`); - } + stateVar.structProperties.forEach((prop: any) => { + genericApiServiceFile += `value.${prop} = plainText[${propCount}];\n`; + propCount++; + }); + genericApiServiceFile += `}\n`; + } + }); + genericApiServiceFile += `console.log(\`\\tValue: \${value}\`); + } else { + value = generalise(plainText[count]); + console.log(\`\\tValue: \${value.integer}\`); } let newCommitment; if (isStruct){ let hashInput = [BigInt(stateVarId.hex(32))]; - for (let i = 2; i < plainText.length; i++) { + let start = isArray ? 3 : 2; + for (let i = start; i < plainText.length; i++) { hashInput.push(BigInt(generalise(plainText[i]).hex(32))); } hashInput.push(BigInt(publicKey.hex(32))); @@ -792,7 +805,8 @@ const prepareBackupDataRetriever = (node: any) => { let isStruct = false; if (varName.includes(" a")) { isArray = true; - } else if (varName.includes(" s")) { + } + if (varName.includes(" s")) { isStruct = true; } const plainText = decrypt( @@ -809,6 +823,7 @@ const prepareBackupDataRetriever = (node: any) => { console.log("Decrypted pre-image of commitment for variable name: " + name + ": "); let salt = generalise(plainText[0]); console.log(\`\\tSalt: \${salt.integer}\`); + let count; if (isArray){ console.log(\`\\tState variable StateVarId: \${plainText[2]}\`); mappingKey = generalise(plainText[1]); @@ -824,36 +839,49 @@ const prepareBackupDataRetriever = (node: any) => { ); stateVarId = reGenStateVarId; console.log(\`Regenerated StateVarId: \${reGenStateVarId.bigInt}\`); - value = generalise(plainText[3]); - console.log(\`\\tValue: \${value.integer}\`); + count = 3; } else { stateVarId = generalise(plainText[1]); console.log(\`\\tStateVarId: \${plainText[1]}\`); - if (isStruct){ - value = {};`; + count = 2; + } + if (isStruct){ + value = {};`; - node.privateStates.forEach((stateVar: any) => { - if (stateVar.structProperties){ - let propCount = 2; + node.privateStates.forEach((stateVar: any) => { + if (stateVar.structProperties){ + let propCount = 2; + if (stateVar.mappingKey){ + propCount++; + genericApiServiceFile += `\nif (stateVarId.integer === + generalise(utils.mimcHash( + [ + BigInt(${stateVar.stateVarId[0]}), + generalise(plainText[1]).bigInt, + ], + "ALT_BN_254" + )).integer) {` + } else{ genericApiServiceFile += `\nif (stateVarId.integer === '${stateVar.stateVarId}') {` - stateVar.structProperties.forEach((prop: any) => { - genericApiServiceFile += `value.${prop} = plainText[${propCount}];\n`; - propCount++; - }); - genericApiServiceFile += `}\n`; } - }); - - genericApiServiceFile += `console.log(\`\\tValue: \${value}\`); - } else { - value = generalise(plainText[2]); - console.log(\`\\tValue: \${value.integer}\`); - } + stateVar.structProperties.forEach((prop: any) => { + genericApiServiceFile += `value.${prop} = plainText[${propCount}];\n`; + propCount++; + }); + genericApiServiceFile += `}\n`; + } + }); + + genericApiServiceFile += `console.log(\`\\tValue: \${value}\`); + } else { + value = generalise(plainText[count]); + console.log(\`\\tValue: \${value.integer}\`); } let newCommitment; if (isStruct){ let hashInput = [BigInt(stateVarId.hex(32))]; - for (let i = 2; i < plainText.length; i++) { + let start = isArray ? 3 : 2; + for (let i = start; i < plainText.length; i++) { hashInput.push(BigInt(generalise(plainText[i]).hex(32))); } hashInput.push(BigInt(publicKey.hex(32))); diff --git a/src/transformers/visitors/toOrchestrationVisitor.ts b/src/transformers/visitors/toOrchestrationVisitor.ts index 7847e670..19a6cb12 100644 --- a/src/transformers/visitors/toOrchestrationVisitor.ts +++ b/src/transformers/visitors/toOrchestrationVisitor.ts @@ -1511,13 +1511,13 @@ const visitor = { } i++; }); - // check whether this should be a VariableDeclaration const firstEdit = (firstInstanceOfNewName && indicator.interactsWithSecret) || (!indicator.isStruct && indicator.modifyingPaths[0]?.node.id === lhs?.id && indicator.isSecret && indicator.isWhole) || - (indicator.isStruct && indicator instanceof MappingKey && indicator.container.modifyingPaths[0]?.node.id === lhs?.id && indicator.isSecret && indicator.isWhole); - + // We want to check the indicator of the struct and not the struct property + (indicator.isStruct && indicator instanceof MappingKey && !indicator.isMapping && indicator.container.modifyingPaths[0]?.node.id === lhs?.id && indicator.isSecret && indicator.isWhole) || + ((indicator.isStruct && indicator.isMapping && indicator.modifyingPaths[0]?.node.id === lhs?.id && indicator.isSecret && indicator.isWhole)); // We should only replace the _first_ assignment to this node. Let's look at the scope's modifiedBindings for any prior modifications to this binding: // if its secret and this is the first assigment, we add a vardec if ( @@ -1531,7 +1531,6 @@ const visitor = { ) accessed = true; }); - // we still need to initialise accessed states if they were accessed _before_ this modification const accessedBeforeModification = indicator.isAccessed && indicator.accessedPaths[0].node.id < lhs.id && !indicator.accessedPaths[0].isModification(); diff --git a/test/contracts/MappingtoStruct2.zol b/test/contracts/MappingtoStruct2.zol new file mode 100644 index 00000000..6066984b --- /dev/null +++ b/test/contracts/MappingtoStruct2.zol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: CC0 + +pragma solidity ^0.8.0; +contract Assign { + secret uint256 private a; + address public immutable owner; + + struct myStruct { + uint256 prop1; + uint256 prop2; + uint256 prop3; + } + secret mapping(uint256 => myStruct) private d; + + + + function add(secret uint256 value) public { + secret uint256 index1 = 0; + secret uint256 index2 = 5; + d[index1].prop1 = value; + d[index1].prop2 = value +1; + d[index1].prop3 = value +2; + d[index2].prop1 = 5; + d[index2].prop2 = 1; + d[index2].prop3 = 1; + + } + + + + + + +} \ No newline at end of file