From 2bfac5c45447e347165ee04fffef69da6b758796 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Wed, 20 Nov 2024 12:28:26 +0000 Subject: [PATCH 1/7] allow for mappings to structs in BackupDataRetriever --- .../javascript/raw/boilerplate-generator.ts | 2 +- .../orchestration/files/toOrchestration.ts | 52 ++++++++++++------- 2 files changed, 34 insertions(+), 20 deletions(-) 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/codeGenerators/orchestration/files/toOrchestration.ts b/src/codeGenerators/orchestration/files/toOrchestration.ts index b491ef57..64b9f08c 100644 --- a/src/codeGenerators/orchestration/files/toOrchestration.ts +++ b/src/codeGenerators/orchestration/files/toOrchestration.ts @@ -809,6 +809,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,31 +825,44 @@ 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++; + let reGenStateVarId = + genericApiServiceFile += `\nif (stateVarId.integer === + generalise(utils.mimcHash( + [ + ${stateVar.stateVarId[0]}, + generalise(${stateVar.mappingKey}).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){ From 01cf2e13a5431825887e13357c2d028de82091ec Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Wed, 20 Nov 2024 18:13:55 +0000 Subject: [PATCH 2/7] fix bugs due to correctly generating commitments and state variable ids for mapping to structs --- .../orchestration/files/toOrchestration.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/codeGenerators/orchestration/files/toOrchestration.ts b/src/codeGenerators/orchestration/files/toOrchestration.ts index 64b9f08c..a71b44ea 100644 --- a/src/codeGenerators/orchestration/files/toOrchestration.ts +++ b/src/codeGenerators/orchestration/files/toOrchestration.ts @@ -792,7 +792,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( @@ -843,8 +844,8 @@ const prepareBackupDataRetriever = (node: any) => { genericApiServiceFile += `\nif (stateVarId.integer === generalise(utils.mimcHash( [ - ${stateVar.stateVarId[0]}, - generalise(${stateVar.mappingKey}).bigInt, + BigInt(${stateVar.stateVarId[0]}), + generalise(plainText[1]).bigInt, ], "ALT_BN_254" )).integer) {` @@ -867,7 +868,8 @@ const prepareBackupDataRetriever = (node: any) => { 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))); From f185d003a024c0ae390a9174118f9b8be4755f60 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Thu, 21 Nov 2024 13:36:17 +0000 Subject: [PATCH 3/7] fix: error in variable declaration when mappings of structs are used with multiple mapping keys --- src/transformers/visitors/toOrchestrationVisitor.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/transformers/visitors/toOrchestrationVisitor.ts b/src/transformers/visitors/toOrchestrationVisitor.ts index 7847e670..ac7bd9cf 100644 --- a/src/transformers/visitors/toOrchestrationVisitor.ts +++ b/src/transformers/visitors/toOrchestrationVisitor.ts @@ -1511,13 +1511,11 @@ 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); - + (indicator.isStruct && indicator instanceof MappingKey && 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 +1529,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(); From 5c3476fefe3e34f09eaff49722dc9d193aea0d66 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Thu, 21 Nov 2024 14:35:07 +0000 Subject: [PATCH 4/7] fix: previous fix caused error for structs that aren't mappings --- src/transformers/visitors/toOrchestrationVisitor.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/transformers/visitors/toOrchestrationVisitor.ts b/src/transformers/visitors/toOrchestrationVisitor.ts index ac7bd9cf..19a6cb12 100644 --- a/src/transformers/visitors/toOrchestrationVisitor.ts +++ b/src/transformers/visitors/toOrchestrationVisitor.ts @@ -1515,7 +1515,9 @@ const visitor = { const firstEdit = (firstInstanceOfNewName && indicator.interactsWithSecret) || (!indicator.isStruct && indicator.modifyingPaths[0]?.node.id === lhs?.id && indicator.isSecret && indicator.isWhole) || - (indicator.isStruct && indicator instanceof MappingKey && indicator.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 ( From 8298158a8dd6c3b89a7b88a4ae723aff1e9272cb Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Thu, 21 Nov 2024 15:44:34 +0000 Subject: [PATCH 5/7] fix: fig error from nullifier fix due to accessed only commitments being included in transaction --- src/boilerplate/orchestration/javascript/raw/toOrchestration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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`); From 07d717f5f4d77a93c2fb6be0d1947fe300a59764 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Thu, 21 Nov 2024 18:17:55 +0000 Subject: [PATCH 6/7] chore: support mappings to struct for backing up specific variables --- .../orchestration/files/toOrchestration.ts | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/src/codeGenerators/orchestration/files/toOrchestration.ts b/src/codeGenerators/orchestration/files/toOrchestration.ts index a71b44ea..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))); @@ -840,7 +853,6 @@ const prepareBackupDataRetriever = (node: any) => { let propCount = 2; if (stateVar.mappingKey){ propCount++; - let reGenStateVarId = genericApiServiceFile += `\nif (stateVarId.integer === generalise(utils.mimcHash( [ @@ -860,7 +872,7 @@ const prepareBackupDataRetriever = (node: any) => { } }); - genericApiServiceFile += `console.log(\`\\tValue: \${value}\`); + genericApiServiceFile += `console.log(\`\\tValue: \${value}\`); } else { value = generalise(plainText[count]); console.log(\`\\tValue: \${value.integer}\`); From 0439293c8a13d92948d56bd859a2a0c2717b4a56 Mon Sep 17 00:00:00 2001 From: Lydia Garms Date: Thu, 21 Nov 2024 18:26:13 +0000 Subject: [PATCH 7/7] add test contract --- test/contracts/MappingtoStruct2.zol | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test/contracts/MappingtoStruct2.zol 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