diff --git a/circuits/common/joinCommitments.zok b/circuits/common/joinCommitments.zok index b16831c47..d4c3779d1 100644 --- a/circuits/common/joinCommitments.zok +++ b/circuits/common/joinCommitments.zok @@ -93,18 +93,17 @@ def main(\ assert(\ field_to_bool_256(oldCommitment_0_nullifier)[8..256] == field_to_bool_256(oldCommitment_0_nullifier_check_field)[8..256]\ ) - - assert(\ + + assert(\ nullifierRoot == checkproof(\ oldCommitment_0_nullifier_nonmembershipWitness_siblingPath,\ oldCommitment_0_nullifier\ ) ) - assert( newNullifierRoot == checkUpdatedPath(oldCommitment_0_nullifier_nonmembershipWitness_newsiblingPath,\ + assert( newNullifierRoot == checkUpdatedPath(\ + oldCommitment_0_nullifier_nonmembershipWitness_newsiblingPath,\ oldCommitment_0_nullifier) ) - - - + // Nullify oldCommitment_1: @@ -124,9 +123,11 @@ def main(\ oldCommitment_1_nullifier\ ) ) - assert( newNullifierRoot == checkUpdatedPath(oldCommitment_1_nullifier_nonmembershipWitness_newsiblingPath,\ + assert( newNullifierRoot == checkUpdatedPath(\ + oldCommitment_1_nullifier_nonmembershipWitness_newsiblingPath,\ oldCommitment_1_nullifier) ) + // oldCommitment_0_commitment: preimage check field oldCommitment_0_commitment_field = poseidon([\ diff --git a/src/boilerplate/circuit/zokrates/nodes/BoilerplateGenerator.ts b/src/boilerplate/circuit/zokrates/nodes/BoilerplateGenerator.ts index fb33fb58c..d44994037 100644 --- a/src/boilerplate/circuit/zokrates/nodes/BoilerplateGenerator.ts +++ b/src/boilerplate/circuit/zokrates/nodes/BoilerplateGenerator.ts @@ -98,6 +98,7 @@ class BoilerplateGenerator { isPartitioned?: boolean; isNullified?: boolean; isAccessed?: boolean; + reinitialisable?: boolean; initialisationRequired?: boolean; newCommitmentsRequired?: boolean; encryptionRequired?: boolean; @@ -113,12 +114,12 @@ class BoilerplateGenerator { mappingName: string; indicators: any; newCommitmentValue: any; + containsAccessedOnlyStates: boolean bpSections: string[] = ['importStatements', 'parameters', 'preStatements', 'postStatements']; constructor(indicators: StateVariableIndicator) { - // Through prior traversals, a BoilerplateGenerator class for this set of indicators might already be stored in memory: if (bpCache.has(indicators)) return bpCache.get(indicators); @@ -141,6 +142,7 @@ class BoilerplateGenerator { isPartitioned, isNullified, isAccessed, + reinitialisable, newCommitmentsRequired, isMapping, isStruct, @@ -155,6 +157,7 @@ class BoilerplateGenerator { isPartitioned, isNullified, isAccessed, + reinitialisable, newCommitmentsRequired, isMapping, isStruct, @@ -264,6 +267,7 @@ class BoilerplateGenerator { ...(this.typeName && { typeName: this.typeName}), ...(this.mappingKeyName && { mappingKeyTypeName: this.mappingKeyTypeName }), ...(this.isAccessed && { isAccessed: this.isAccessed }), + ...(this.reinitialisable && { reinitialisable: this.reinitialisable }), ...(this.initialisationRequired && { initialisationRequired: this.initialisationRequired }), ...(this.newCommitmentValue && { newCommitmentValue: this.newCommitmentValue }), // ...(this.burnedOnly && { burnedOnly: this.burnedOnly }), // TODO @@ -310,6 +314,9 @@ class BoilerplateGenerator { addBP('oldCommitmentPreimage'); addBP('oldCommitmentExistence'); } + if(this.reinitialisable){ + addBP('oldCommitmentPreimage'); + } if (this.newCommitmentsRequired && !this.burnedOnly) { addBP('newCommitment'); } diff --git a/src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts b/src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts index 6ef2be528..247c93efa 100644 --- a/src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts +++ b/src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts @@ -166,25 +166,28 @@ class BoilerplateGenerator { ]; }, - parameters({ name: x, typeName }): string[] { + parameters({ name: x, typeName, reinitialisable }): string[] { // prettier-ignore + if(!reinitialisable) return [ `private ${typeName ? typeName : 'field'} ${x}_oldCommitment_value`, `private field ${x}_oldCommitment_salt`, ]; }, - preStatements({ name: x, typeName }): string[] { + preStatements({ name: x, typeName, reinitialisable }): string[] { // For a state variable, we'll have passed in `${x}_oldCommitment_value` as a parameter. But our AST nodes will be using `${x}`. This line resolves the two. + if (reinitialisable) + return [ `${typeName ? typeName : 'field'} ${x} = 0`]; return [ ` ${typeName ? typeName : 'field'} ${x} = ${x}_oldCommitment_value`, ]; }, - postStatements({ name: x, structProperties, structPropertiesTypes, typeName }): string[] { + postStatements({ name: x, structProperties, reinitialisable, structPropertiesTypes, typeName }): string[] { const lines: string[] = []; - if (!structProperties ) { + if (!structProperties && !reinitialisable ) { if (typeName === 'bool'){ lines.push(`field ${x}_oldCommitment_value_field = if ${x}_oldCommitment_value then 1 else 0 fi`); } else { @@ -216,6 +219,7 @@ class BoilerplateGenerator { ])`, ]; } + if(!reinitialisable) return [ ` diff --git a/src/boilerplate/common/bin/setup b/src/boilerplate/common/bin/setup index 6902324e7..27940ce29 100644 --- a/src/boilerplate/common/bin/setup +++ b/src/boilerplate/common/bin/setup @@ -38,6 +38,10 @@ cp docker-compose.zapp.override.default.yml docker-compose.zapp.override.yml cp entrypoint_default.sh entrypoint.sh + + +rm -rf proving-files + perl -i -pe "s,docker-compose.zapp.yml -f docker-compose.zapp.override.yml,docker-compose.zapp.yml,g" package.json if [[ $network == 'mumbai' ]] || [[ $network == 'sepolia' ]] || [[ $network == 'goerli' ]] diff --git a/src/boilerplate/common/commitment-storage.mjs b/src/boilerplate/common/commitment-storage.mjs index f7e73d44d..ad6bdbff3 100644 --- a/src/boilerplate/common/commitment-storage.mjs +++ b/src/boilerplate/common/commitment-storage.mjs @@ -4,19 +4,22 @@ Logic for storing and retrieving commitments from a mongo DB. */ import config from 'config'; +import fs from 'fs'; import gen from 'general-number'; import mongo from './mongo.mjs'; import logger from './logger.mjs'; import utils from 'zkp-utils'; import { poseidonHash } from './number-theory.mjs'; +import { sharedSecretKey } from './number-theory.mjs'; import { generateProof } from './zokrates.mjs'; -import { SumType, reduceTree, toBinArray, poseidonConcatHash } from './smt_utils.mjs'; +import { SumType, reduceTree, toBinArray, poseidonConcatHash,} from './smt_utils.mjs'; import { hlt } from './hash-lookup.mjs'; -import fs from "fs"; const { MONGO_URL, COMMITMENTS_DB, COMMITMENTS_COLLECTION } = config; const { generalise } = gen; +const keyDb = '/app/orchestration/common/db/key.json'; + const TRUNC_LENGTH = 32; // Just for testing so we don't make more than 32 deep smt trees. const WHOLE_STATES = [WHOLE_STATE_NAMES]; // structure for SMT @@ -121,18 +124,18 @@ export async function getNullifiedCommitments() { * @returns {Promise} The sum of the values ​​of all non-nullified commitments */ export async function getBalance() { - const connection = await mongo.connection(MONGO_URL); - const db = connection.db(COMMITMENTS_DB); - const commitments = await db - .collection(COMMITMENTS_COLLECTION) - .find({ isNullified: false }) // no nullified - .toArray(); - - let sumOfValues = 0; - commitments.forEach(commitment => { - sumOfValues += parseInt(commitment.preimage.value, 10); - }); - return sumOfValues; + const connection = await mongo.connection(MONGO_URL); + const db = connection.db(COMMITMENTS_DB); + const commitments = await db + .collection(COMMITMENTS_COLLECTION) + .find({ isNullified: false }) // no nullified + .toArray(); + + let sumOfValues = 0; + commitments.forEach(commitment => { + sumOfValues += parseInt(commitment.preimage.value, 10); + }); + return sumOfValues; } export async function getBalanceByState(name, mappingKey = null) { @@ -144,23 +147,27 @@ export async function getBalanceByState(name, mappingKey = null) { .collection(COMMITMENTS_COLLECTION) .find(query) .toArray(); - let sumOfValues = 0; - commitments.forEach(commitment => { - sumOfValues += commitment.isNullified ? 0 : parseInt(commitment.preimage.value, 10); - }); + let sumOfValues = 0; + commitments.forEach(commitment => { + sumOfValues += commitment.isNullified + ? 0 + : parseInt(commitment.preimage.value, 10); + }); return sumOfValues; } /** * @returns all the commitments existent in this database. */ - export async function getAllCommitments() { - const connection = await mongo.connection(MONGO_URL); - const db = connection.db(COMMITMENTS_DB); - const allCommitments = await db.collection(COMMITMENTS_COLLECTION).find().toArray(); - return allCommitments; - } - +export async function getAllCommitments() { + const connection = await mongo.connection(MONGO_URL); + const db = connection.db(COMMITMENTS_DB); + const allCommitments = await db + .collection(COMMITMENTS_COLLECTION) + .find() + .toArray(); + return allCommitments; +} // function to update an existing commitment export async function updateCommitment(commitment, updates) { @@ -679,7 +686,7 @@ export async function splitCommitments( // Call Zokrates to generate the proof: const allInputs = [ - value.integer, + value.integer, fromID, stateVarID, isMapping, @@ -902,4 +909,41 @@ export async function addConstructorNullifiers() { ); } -} \ No newline at end of file +} +export async function getSharedSecretskeys( + _recipientAddress, + _recipientPublicKey = 0, +) { + const keys = JSON.parse( + fs.readFileSync(keyDb, 'utf-8', err => { + console.log(err); + }), + ); + const secretKey = generalise(keys.secretKey); + const publicKey = generalise(keys.publicKey); + let recipientPublicKey = generalise(_recipientPublicKey); + const recipientAddress = generalise(_recipientAddress); + if (_recipientPublicKey === 0) { + recipientPublicKey = await this.instance.methods + .zkpPublicKeys(recipientAddress.hex(20)) + .call(); + recipientPublicKey = generalise(recipientPublicKey); + + if (recipientPublicKey.length === 0) { + throw new Error('WARNING: Public key for given eth address not found.'); + } + } + + const sharedKey = sharedSecretKey(secretKey, recipientPublicKey); + console.log('sharedKey:', sharedKey); + console.log('sharedKey:', sharedKey[1]); + const keyJson = { + secretKey: secretKey.integer, + publicKey: publicKey.integer, + sharedSecretKey: sharedKey[0].integer, + sharedPublicKey: sharedKey[1].integer, // not req + }; + fs.writeFileSync(keyDb, JSON.stringify(keyJson, null, 4)); + + return sharedKey[1]; +} diff --git a/src/boilerplate/common/encryptedEvnetListener.mjs b/src/boilerplate/common/encryptedEvnetListener.mjs new file mode 100644 index 000000000..e69de29bb diff --git a/src/boilerplate/common/number-theory.mjs b/src/boilerplate/common/number-theory.mjs index 630f6efae..c8d64701e 100644 --- a/src/boilerplate/common/number-theory.mjs +++ b/src/boilerplate/common/number-theory.mjs @@ -313,6 +313,43 @@ function decrypt(encryptedMessages, secretKey, encPublicKey) { return plainText; } + +/** +@param {string} secretKey - hex string +@param {string[2]} recipientPublicKey - hex string[] +@return {string} key - int string +*/ +function sharedSecretKey(secretKey, recipientPublicKey) { + const publickKeyPoint = decompressStarlightKey(recipientPublicKey); + const sharedSecret = scalarMult(secretKey.hex(32), [ + BigInt(generalise(publickKeyPoint[0]).hex(32)), + BigInt(generalise(publickKeyPoint[1]).hex(32)), + ]); + const key = poseidonHash([ + sharedSecret[0], + sharedSecret[1], + BigInt(DOMAIN_KEM), + ]); + + let sharePublicKeyPoint = generalise( + scalarMult(key.hex(32), config.BABYJUBJUB.GENERATOR) + ); + + let yBits = sharePublicKeyPoint[1].binary; + if (yBits.length > 253) + { + yBits = yBits.slice(yBits.length - 253); + } + + const xBits = sharePublicKeyPoint[0].binary; + const sign = xBits[xBits.length - 1]; + + let sharedPublicKey = new GN(sign + yBits.padStart(253, "0"), "binary"); + + + return [key, sharedPublicKey]; +} + // Implements the Poseidon hash, drawing on the ZoKrates implementation // roundsP values referred from circom library // https://github.com/iden3/circomlibjs/blob/main/src/poseidon_opt.js @@ -386,4 +423,5 @@ export { decompressStarlightKey, decrypt, poseidonHash, + sharedSecretKey, }; diff --git a/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts b/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts index d1e1685ab..83f6040d9 100644 --- a/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts +++ b/src/boilerplate/contract/solidity/raw/ContractBoilerplateGenerator.ts @@ -25,7 +25,6 @@ class ContractBoilerplateGenerator { oldCommitmentAccessRequired, nullifiersRequired, newCommitmentsRequired, - containsAccessedOnlyState, encryptionRequired, //isInternalFunctionCall add it }): string[] { @@ -44,7 +43,7 @@ class ContractBoilerplateGenerator { ...(encryptionRequired ? [` event EncryptedData(uint256[] cipherText, uint256[2] ephPublicKey);`] : []), - ...nullifiersRequired ? [` + ...nullifiersRequired ? [` uint256 public newNullifierRoot;`] : [], ...(oldCommitmentAccessRequired ? [` @@ -92,6 +91,7 @@ class ContractBoilerplateGenerator { ]; }, + registerZKPPublicKey(): string[] { return [ ` @@ -203,7 +203,7 @@ class ContractBoilerplateGenerator { uint256[] memory inputs = new uint256[](${[ 'customInputs.length', ...(newNullifiers ? ['newNullifiers.length'] : []), - ...(commitmentRoot ? ['(newNullifiers.length > 0 ? 3 : 0)'] : []), // newNullifiers , nullifierRoots(old and latest) and commitmentRoot are always submitted together (regardless of use case). It's just that nullifiers aren't always stored (when merely accessing a state). + ...(commitmentRoot ? ['(newNullifiers.length > 0 ? 3 : 0)'] : []), // newNullifiers and commitmentRoot are always submitted together (regardless of use case). It's just that nullifiers aren't always stored (when merely accessing a state). and commitmentRoot are always submitted together (regardless of use case). It's just that nullifiers aren't always stored (when merely accessing a state). ...(newCommitments ? ['newCommitments.length'] : []), ...(encryptionRequired ? ['encInputsLen'] : []), ].join(' + ')});`, @@ -255,10 +255,10 @@ class ContractBoilerplateGenerator { }`] : newCommitments ? [` insertLeaves(newCommitments);`] : - [] + [] ), - ...(newNullifiers) ? [` + ...(newNullifiers) ? [` if (newNullifiers.length > 0) { newNullifierRoot = _inputs.latestNullifierRoot; }`] : [] @@ -309,22 +309,22 @@ class ContractBoilerplateGenerator { }`) verifyInputs.push(` - if (functionId == uint(FunctionNames.joinCommitments)) { + if (functionId == uint(FunctionNames.joinCommitments)) { - require(newNullifierRoot == _inputs.nullifierRoot, "Input NullifierRoot does not exist."); - - uint k = 0; - - inputs[k++] = _inputs.nullifierRoot; - inputs[k++] = _inputs.latestNullifierRoot; - inputs[k++] = newNullifiers[0]; - inputs[k++] = newNullifiers[1]; - inputs[k++] = _inputs.commitmentRoot; - inputs[k++] = newCommitments[0]; - inputs[k++] = 1; - - } + require(newNullifierRoot == _inputs.nullifierRoot, "Input NullifierRoot does not exist."); + + uint k = 0; + + inputs[k++] = _inputs.nullifierRoot; + inputs[k++] = _inputs.latestNullifierRoot; + inputs[k++] = newNullifiers[0]; + inputs[k++] = newNullifiers[1]; + inputs[k++] = _inputs.commitmentRoot; + inputs[k++] = newCommitments[0]; + inputs[k++] = 1; + + } if (functionId == uint(FunctionNames.splitCommitments)) { diff --git a/src/boilerplate/contract/solidity/raw/FunctionBoilerplateGenerator.ts b/src/boilerplate/contract/solidity/raw/FunctionBoilerplateGenerator.ts index f95758539..3f7f8d6a5 100644 --- a/src/boilerplate/contract/solidity/raw/FunctionBoilerplateGenerator.ts +++ b/src/boilerplate/contract/solidity/raw/FunctionBoilerplateGenerator.ts @@ -60,12 +60,13 @@ class FunctionBoilerplateGenerator { nullifiersRequired: newNullifiers, oldCommitmentAccessRequired: commitmentRoot, newCommitmentsRequired: newCommitments, + containsAccessedOnlyState: checkNullifiers, encryptionRequired }): string[] { // prettier-ignore let parameter = [ - ...(customInputs ? customInputs.filter(input => !input.dummy && input.isParam) + ...(customInputs ? customInputs.filter(input => !input.dummy && input.isParam) .map(input => input.structName ? `(${input.properties.map(p => p.type)})` : input.isConstantArray ? `${input.type}[${input.isConstantArray}]` : input.type) : []), // TODO arrays of structs/ structs of arrays ...(newNullifiers ? [`uint256`] : []), ...(newNullifiers ? [`uint256`] : []), @@ -112,11 +113,11 @@ class FunctionBoilerplateGenerator { }).join('\n')}`] : []), - ...(newNullifiers ? [` - inputs.nullifierRoot = nullifierRoot; `] : []), + ...(newNullifiers ? [` + inputs.nullifierRoot = nullifierRoot; `] : []), - ...(newNullifiers ? [` - inputs.latestNullifierRoot = latestNullifierRoot; `] : []), + ...(newNullifiers ? [` + inputs.latestNullifierRoot = latestNullifierRoot; `] : []), ...(newNullifiers ? [` diff --git a/src/boilerplate/orchestration/javascript/nodes/boilerplate-generator.ts b/src/boilerplate/orchestration/javascript/nodes/boilerplate-generator.ts index 4c29082cc..2ac7e7ea6 100644 --- a/src/boilerplate/orchestration/javascript/nodes/boilerplate-generator.ts +++ b/src/boilerplate/orchestration/javascript/nodes/boilerplate-generator.ts @@ -30,6 +30,7 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any { return { increment, stateVarId: id, + isSharedSecret: indicator.isSharedSecret, isWhole: indicator.isWhole, isPartitioned: indicator.isPartitioned, structProperties: indicator.isStruct ? Object.keys(indicator.structProperties) : null, @@ -51,10 +52,11 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any { }; } case 'WritePreimage': { - const { id, increment, burnedOnly, indicator = {} } = fields; + const { id, increment, burnedOnly, reinitialisedOnly, indicator = {} } = fields return { increment, stateVarId: id, + isSharedSecret: indicator.isSharedSecret, isWhole: indicator.isWhole, isPartitioned: indicator.isPartitioned, structProperties: indicator.isStruct ? indicator.referencingPaths[0]?.getStructDeclaration()?.members.map(m => m.name) : null, @@ -62,6 +64,7 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any { mappingName: indicator.isMapping ? indicator.node?.name : null, nullifierRequired: indicator.isNullified, burnedOnly, + reinitialisedOnly, isOwned: indicator.isOwned, mappingOwnershipType: indicator.mappingOwnershipType, owner: indicator.isOwned @@ -92,6 +95,7 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any { return { increment, accessedOnly, + isSharedSecret: indicator.isSharedSecret, isWhole: indicator.isWhole, isPartitioned: indicator.isPartitioned, @@ -103,6 +107,7 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any { privateStateName, stateVarId: id, increment, + isSharedSecret: indicator.isSharedSecret, isWhole: indicator.isWhole, isPartitioned: indicator.isPartitioned, nullifierRequired: indicator.isNullified, @@ -134,6 +139,7 @@ export function buildPrivateStateNode(nodeType: string, fields: any = {}): any { reinitialisedOnly, burnedOnly, accessedOnly, + isSharedSecret: indicator.isSharedSecret, nullifierRequired: indicator.isNullified, increment, structProperties, diff --git a/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts b/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts index 3e99f917c..0b02467e0 100644 --- a/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts +++ b/src/boilerplate/orchestration/javascript/raw/boilerplate-generator.ts @@ -80,7 +80,8 @@ class BoilerplateGenerator { }), ); const secretKey = generalise(keys.secretKey); - const publicKey = generalise(keys.publicKey);` + const publicKey = generalise(keys.publicKey); + ` ]; }, @@ -99,6 +100,7 @@ class BoilerplateGenerator { structProperties, newOwnerStatment, reinitialisedOnly, + isSharedSecret, accessedOnly, stateVarIds }): string[] { @@ -181,12 +183,12 @@ class BoilerplateGenerator { \n${stateName}_witness_0 = await getMembershipWitness('${contractName}', generalise(${stateName}_0_oldCommitment._id).integer); \n${stateName}_witness_1 = await getMembershipWitness('${contractName}', generalise(${stateName}_1_oldCommitment._id).integer); - \n const tx = await joinCommitments('${contractName}', '${mappingName}', secretKey, publicKey, [${stateVarId.join(' , ')}], [${stateName}_0_oldCommitment, ${stateName}_1_oldCommitment], [${stateName}_witness_0, ${stateName}_witness_1], instance, contractAddr, web3); + \n const tx = await joinCommitments('${contractName}', '${mappingName}', ${isSharedSecret? `sharedSecretKey, sharedPublicKey`: `secretKey, publicKey`}, [${stateVarId.join(' , ')}], [${stateName}_0_oldCommitment, ${stateName}_1_oldCommitment], [${stateName}_witness_0, ${stateName}_witness_1], instance, contractAddr, web3); ${stateName}_preimage = await getCommitmentsById(${stateName}_stateVarId); [${stateName}_commitmentFlag, ${stateName}_0_oldCommitment, ${stateName}_1_oldCommitment] = getInputCommitments( - publicKey.hex(32), + ${isSharedSecret ? `sharedPublicKey.hex(32)` : `publicKey.hex(32)`}, ${stateName}_newCommitmentValue.integer, ${stateName}_preimage, ); @@ -271,14 +273,14 @@ class BoilerplateGenerator { calculateNullifier = { - postStatements({ stateName, accessedOnly, stateType }): string[] { + postStatements({ stateName, isSharedSecret, accessedOnly, stateType }): string[] { // if (!isWhole && !newCommitmentValue) throw new Error('PATH'); switch (stateType) { case 'partitioned': return [` - let ${stateName}_0_nullifier = poseidonHash([BigInt(${stateName}_stateVarId), BigInt(secretKey.hex(32)), BigInt(${stateName}_0_prevSalt.hex(32))],); - let ${stateName}_1_nullifier = poseidonHash([BigInt(${stateName}_stateVarId), BigInt(secretKey.hex(32)), BigInt(${stateName}_1_prevSalt.hex(32))],); + let ${stateName}_0_nullifier = poseidonHash([BigInt(${stateName}_stateVarId), ${isSharedSecret ? `BigInt(sharedSecretKey.hex(32))`: `BigInt(secretKey.hex(32))` }, BigInt(${stateName}_0_prevSalt.hex(32))],); + let ${stateName}_1_nullifier = poseidonHash([BigInt(${stateName}_stateVarId), ${isSharedSecret ? `BigInt(sharedSecretKey.hex(32))`: `BigInt(secretKey.hex(32))` }, BigInt(${stateName}_1_prevSalt.hex(32))],); ${stateName}_0_nullifier = generalise(${stateName}_0_nullifier.hex(32)); // truncate ${stateName}_1_nullifier = generalise(${stateName}_1_nullifier.hex(32)); // truncate // Non-membership witness for Nullifier @@ -292,9 +294,8 @@ class BoilerplateGenerator { case 'whole': if(accessedOnly) return [` - let ${stateName}_nullifier = ${stateName}_commitmentExists ? poseidonHash([BigInt(${stateName}_stateVarId), BigInt(secretKey.hex(32)), BigInt(${stateName}_prevSalt.hex(32))],) : poseidonHash([BigInt(${stateName}_stateVarId), BigInt(generalise(0).hex(32)), BigInt(${stateName}_prevSalt.hex(32))],); + let ${stateName}_nullifier = ${stateName}_commitmentExists ? poseidonHash([BigInt(${stateName}_stateVarId), ${isSharedSecret ? `BigInt(sharedSecretKey.hex(32))`: `BigInt(secretKey.hex(32))`}, BigInt(${stateName}_prevSalt.hex(32))],) : poseidonHash([BigInt(${stateName}_stateVarId), BigInt(generalise(0).hex(32)), BigInt(${stateName}_prevSalt.hex(32))],); \n${stateName}_nullifier = generalise(${stateName}_nullifier.hex(32)); // truncate - // Non-membership witness for Nullifier const ${stateName}_nullifier_NonMembership_witness = getnullifierMembershipWitness(${stateName}_nullifier); @@ -302,9 +303,8 @@ class BoilerplateGenerator { const ${stateName}_nullifier_path = generalise(${stateName}_nullifier_NonMembership_witness.path).all; `]; return [` - let ${stateName}_nullifier = ${stateName}_commitmentExists ? poseidonHash([BigInt(${stateName}_stateVarId), BigInt(secretKey.hex(32)), BigInt(${stateName}_prevSalt.hex(32))],) : poseidonHash([BigInt(${stateName}_stateVarId), BigInt(generalise(0).hex(32)), BigInt(${stateName}_prevSalt.hex(32))],); + let ${stateName}_nullifier = ${stateName}_commitmentExists ? poseidonHash([BigInt(${stateName}_stateVarId), ${isSharedSecret ? `BigInt(sharedSecretKey.hex(32))`: `BigInt(secretKey.hex(32))`}, BigInt(${stateName}_prevSalt.hex(32))],) : poseidonHash([BigInt(${stateName}_stateVarId), BigInt(generalise(0).hex(32)), BigInt(${stateName}_prevSalt.hex(32))],); \n${stateName}_nullifier = generalise(${stateName}_nullifier.hex(32)); // truncate - // Non-membership witness for Nullifier const ${stateName}_nullifier_NonMembership_witness = getnullifierMembershipWitness(${stateName}_nullifier); @@ -372,9 +372,12 @@ class BoilerplateGenerator { }, }; + + + calculateCommitment = { - postStatements({ stateName, stateType, structProperties }): string[] { + postStatements({ stateName, stateType, isSharedSecret, structProperties }): string[] { // once per state switch (stateType) { case 'increment': @@ -438,6 +441,7 @@ class BoilerplateGenerator { reinitialisedOnly, burnedOnly, accessedOnly, + isSharedSecret, nullifierRootRequired, newNullifierRootRequired, initialisationRequired, @@ -464,8 +468,8 @@ class BoilerplateGenerator { prev = (index: number) => structProperties ? structProperties.map(p => `\t${stateName}_${index}_prev.${p}.integer`) : `\t${stateName}_${index}_prev.integer`; return [` ${parameters.join('\n')}${stateVarIds.join('\n')} - \tsecretKey.integer, - \tsecretKey.integer, + \t${isSharedSecret ? `sharedSecretKey.integer`: `secretKey.integer`}, + \t${isSharedSecret ? `sharedSecretKey.integer`: `secretKey.integer`}, ${nullifierRootRequired ? `\t${stateName}_nullifierRoot.integer,` : ``} ${newNullifierRootRequired ? `\t${stateName}_newNullifierRoot.integer,` : ``} \t${stateName}_0_nullifier.integer, @@ -500,7 +504,7 @@ class BoilerplateGenerator { case true: return [` ${parameters.join('\n')}${stateVarIds.join('\n')} - \tsecretKey.integer, + \t${isSharedSecret ? `sharedSecretKey.integer`: `secretKey.integer`}, ${nullifierRootRequired ? `\t${stateName}_nullifierRoot.integer,` : ``} ${newNullifierRootRequired ? `\t${stateName}_newNullifierRoot.integer,` : ``} \t${stateName}_nullifier.integer, @@ -517,7 +521,7 @@ class BoilerplateGenerator { case true: return [` ${parameters.join('\n')}${stateVarIds.join('\n')} - \tsecretKey.integer, + \t${isSharedSecret ? `sharedSecretKey.integer`: `secretKey.integer`}, ${nullifierRootRequired ? `\t${stateName}_nullifierRoot.integer,` : ``} \t${stateName}_nullifier_path.integer, ${prev}, @@ -528,7 +532,7 @@ class BoilerplateGenerator { default: return [` ${parameters.join('\n')}${stateVarIds.join('\n')} - \t${stateName}_commitmentExists ? secretKey.integer: generalise(0).integer, + \t${stateName}_commitmentExists ? ${isSharedSecret ? `sharedSecretKey.integer`: `secretKey.integer`}: generalise(0).integer, ${nullifierRootRequired ? `\t${stateName}_nullifierRoot.integer,` : ``} ${newNullifierRootRequired ? `\t${stateName}_newNullifierRoot.integer,` : ``} \t${stateName}_nullifier.integer, @@ -566,9 +570,11 @@ sendTransaction = { postStatements({ stateName, stateType, + isSharedSecret, mappingName, mappingKey, burnedOnly, + reinitialisedOnly, structProperties, isConstructor }): string[] { @@ -587,7 +593,7 @@ sendTransaction = { \tsalt: ${stateName}_newSalt, \tpublicKey: ${stateName}_newOwnerPublicKey, }, - secretKey: ${stateName}_newOwnerPublicKey.integer === publicKey.integer ? secretKey : null, + secretKey: ${stateName}_newOwnerPublicKey.integer === ${isSharedSecret ? `sharedPublicKey.integer` : `publicKey.integer`} ? ${isSharedSecret ? `sharedSecretKey` : `secretKey`}: null, isNullified: false, });`]; case 'decrement': @@ -605,7 +611,7 @@ sendTransaction = { \tsalt: ${stateName}_2_newSalt, \tpublicKey: ${stateName}_newOwnerPublicKey, }, - secretKey: ${stateName}_newOwnerPublicKey.integer === publicKey.integer ? secretKey : null, + secretKey: ${stateName}_newOwnerPublicKey.integer === ${isSharedSecret ? `sharedPublicKey.integer` : `publicKey.integer`} ? ${isSharedSecret ? `sharedSecretKey` : `secretKey`}: null, isNullified: false, });`]; case 'whole': @@ -616,8 +622,8 @@ sendTransaction = { default: value = structProperties ? `{ ${structProperties.map(p => `${p}: ${stateName}.${p}`)} }` : `${stateName}`; return [` - \nif (${stateName}_commitmentExists) await markNullified(${stateName}_currentCommitment, secretKey.hex(32)); - \n else await updateNullifierTree(); // Else we always update it in markNullified + \n${reinitialisedOnly ? ' ': `if (${stateName}_commitmentExists) await markNullified(${stateName}_currentCommitment, secretKey.hex(32)); + \n else await updateNullifierTree(); // Else we always update it in markNullified`} \nawait storeCommitment({ hash: ${stateName}_newCommitment, name: '${mappingName}', @@ -628,7 +634,7 @@ sendTransaction = { \tsalt: ${stateName}_newSalt, \tpublicKey: ${stateName}_newOwnerPublicKey, }, - secretKey: ${stateName}_newOwnerPublicKey.integer === publicKey.integer ? secretKey : null, + secretKey: ${stateName}_newOwnerPublicKey.integer === ${isSharedSecret ? `sharedPublicKey.integer` : `publicKey.integer`} ? ${isSharedSecret ? `sharedSecretKey` : `secretKey`}: null, isNullified: false, });`]; } @@ -707,7 +713,7 @@ integrationApiServicesBoilerplate = { ` }, preStatements(): string{ - return ` import { startEventFilter, getSiblingPath } from './common/timber.mjs';\nimport fs from "fs";\nimport logger from './common/logger.mjs';\nimport { decrypt } from "./common/number-theory.mjs";\nimport { getAllCommitments, getCommitmentsByState, reinstateNullifiers, getBalance, getBalanceByState, addConstructorNullifiers } from "./common/commitment-storage.mjs";\nimport web3 from './common/web3.mjs';\n\n + return ` import { startEventFilter, getSiblingPath } from './common/timber.mjs';\nimport fs from "fs";\nimport logger from './common/logger.mjs';\nimport { decrypt } from "./common/number-theory.mjs";\nimport { getAllCommitments, getCommitmentsByState, reinstateNullifiers, getSharedSecretskeys , getBalance, getBalanceByState, addConstructorNullifiers } from "./common/commitment-storage.mjs";\nimport web3 from './common/web3.mjs';\n\n /** NOTE: this is the api service file, if you need to call any function use the correct url and if Your input contract has two functions, add() and minus(). minus() cannot be called before an initial add(). */ @@ -787,6 +793,18 @@ integrationApiServicesBoilerplate = { logger.error(err); res.send({ errors: [err.message] }); } + } + export async function service_getSharedKeys(req, res, next) { + try { + const { recipientAddress } = req.body; + const recipientPubKey = req.body.recipientPubKey || 0 + const SharedKeys = await getSharedSecretskeys(recipientAddress, recipientPubKey ); + res.send({ SharedKeys }); + await sleep(10); + } catch (err) { + logger.error(err); + res.send({ errors: [err.message] }); + } }` @@ -809,7 +827,7 @@ integrationApiRoutesBoilerplate = { (fs.readFileSync(apiRoutesReadPath, 'utf8').match(/router.post?[\s\S]*/g)|| [])[0]}` }, commitmentImports(): string { - return `import { service_allCommitments, service_getCommitmentsByState, service_reinstateNullifiers, service_getBalance, service_getBalanceByState } from "./api_services.mjs";\n`; + return `import { service_allCommitments, service_getCommitmentsByState, service_reinstateNullifiers, service_getSharedKeys, service_getBalance, service_getBalanceByState } from "./api_services.mjs";\n`; }, commitmentRoutes(): string { return `// commitment getter routes @@ -819,6 +837,7 @@ integrationApiRoutesBoilerplate = { router.get("/getBalanceByState", service_getBalanceByState); // nullifier route router.post("/reinstateNullifiers", service_reinstateNullifiers); + router.post("/getSharedKeys", service_getSharedKeys); `; } }; diff --git a/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts b/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts index 7531efc7c..ccc5c01f8 100644 --- a/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts +++ b/src/boilerplate/orchestration/javascript/raw/toOrchestration.ts @@ -181,6 +181,7 @@ export const generateProofBoilerplate = (node: any) => { reinitialisedOnly: stateNode.reinitialisedOnly, burnedOnly: stateNode.burnedOnly, accessedOnly: stateNode.accessedOnly, + isSharedSecret: stateNode.isSharedSecret, nullifierRootRequired: !containsNullifierRoot, newNullifierRootRequired: !containsNewNullifierRoot, initialisationRequired: stateNode.initialisationRequired, @@ -224,6 +225,7 @@ export const generateProofBoilerplate = (node: any) => { encryptionRequired: stateNode.encryptionRequired, rootRequired: !containsRoot, accessedOnly: false, + isSharedSecret: stateNode.isSharedSecret, parameters, }) ); @@ -257,6 +259,7 @@ export const generateProofBoilerplate = (node: any) => { encryptionRequired: stateNode.encryptionRequired, rootRequired: false, accessedOnly: false, + isSharedSecret: stateNode.isSharedSecret, parameters, }) ); @@ -303,6 +306,7 @@ export const preimageBoilerPlate = (node: any) => { reinitialisedOnly: false, initialised: stateNode.initialised, structProperties: stateNode.structProperties, + isSharedSecret: stateNode.isSharedSecret, accessedOnly: true, stateVarIds, })); @@ -318,6 +322,9 @@ export const preimageBoilerPlate = (node: any) => { let newOwnerStatment: string; switch (newOwner) { case null: + if(stateNode.isSharedSecret) + newOwnerStatment = `_${privateStateName}_newOwnerPublicKey === 0 ? sharedPublicKey : ${privateStateName}_newOwnerPublicKey;`; + else newOwnerStatment = `_${privateStateName}_newOwnerPublicKey === 0 ? publicKey : ${privateStateName}_newOwnerPublicKey;`; break; case 'msg': @@ -336,6 +343,9 @@ export const preimageBoilerPlate = (node: any) => { } \n${privateStateName}_newOwnerPublicKey = generalise(${privateStateName}_newOwnerPublicKey);`; } else { + if(stateNode.isSharedSecret) + newOwnerStatment = `_${privateStateName}_newOwnerPublicKey === 0 ? sharedPublicKey : ${privateStateName}_newOwnerPublicKey;`; + else newOwnerStatment = `_${privateStateName}_newOwnerPublicKey === 0 ? publicKey : ${privateStateName}_newOwnerPublicKey;`; } break; @@ -348,6 +358,9 @@ export const preimageBoilerPlate = (node: any) => { newOwnerStatment = `_${privateStateName}_newOwnerPublicKey === 0 ? ${newOwner} : ${privateStateName}_newOwnerPublicKey;`; } else { // is secret - we just use the users to avoid revealing the secret owner + if(stateNode.isSharedSecret) + newOwnerStatment = `_${privateStateName}_newOwnerPublicKey === 0 ? sharedPublicKey : ${privateStateName}_newOwnerPublicKey;`; + else newOwnerStatment = `_${privateStateName}_newOwnerPublicKey === 0 ? publicKey : ${privateStateName}_newOwnerPublicKey;` // BELOW reveals the secret owner as we check the public key in the contract @@ -370,6 +383,7 @@ export const preimageBoilerPlate = (node: any) => { reinitialisedOnly: stateNode.reinitialisedOnly, increment: stateNode.increment, newOwnerStatment, + isSharedSecret: stateNode.isSharedSecret, accessedOnly: false, stateVarIds, })); @@ -394,6 +408,7 @@ export const preimageBoilerPlate = (node: any) => { newOwnerStatment, initialised: false, reinitialisedOnly: false, + isSharedSecret: stateNode.isSharedSecret, accessedOnly: false, stateVarIds, })); @@ -414,6 +429,7 @@ export const preimageBoilerPlate = (node: any) => { structProperties: stateNode.structProperties, initialised: false, reinitialisedOnly: false, + isSharedSecret: stateNode.isSharedSecret, accessedOnly: false, stateVarIds, })); @@ -592,6 +608,7 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { Orchestrationbp.writePreimage.postStatements({ stateName, stateType: 'decrement', + isSharedSecret: stateNode.isSharedSecret, mappingName: stateNode.mappingName || stateName, mappingKey: stateNode.mappingKey ? `${stateName}_stateVarId_key.integer` @@ -599,6 +616,7 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { burnedOnly: false, structProperties: stateNode.structProperties, isConstructor: node.isConstructor, + reinitialisedOnly: false, })); break; @@ -608,6 +626,7 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { Orchestrationbp.writePreimage.postStatements({ stateName, stateType: 'increment', + isSharedSecret: stateNode.isSharedSecret, mappingName:stateNode.mappingName || stateName, mappingKey: stateNode.mappingKey ? `${stateName}_stateVarId_key.integer` @@ -615,6 +634,7 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { burnedOnly: false, structProperties: stateNode.structProperties, isConstructor: node.isConstructor, + reinitialisedOnly: stateNode.reinitialisedOnly, })); break; @@ -626,11 +646,13 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { Orchestrationbp.writePreimage.postStatements({ stateName, stateType: 'whole', + isSharedSecret: stateNode.isSharedSecret, mappingName: stateNode.mappingName || stateName, mappingKey: stateNode.mappingKey ? `${stateName}_stateVarId_key.integer` : ``, burnedOnly: stateNode.burnedOnly, + reinitialisedOnly: stateNode.reinitialisedOnly, structProperties: stateNode.structProperties, isConstructor: node.isConstructor, })); @@ -685,67 +707,69 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { statements: [`\n// Extract set membership witness: \n\n`, ...lines], }; - case 'CalculateNullifier': - for ([stateName, stateNode] of Object.entries(node.privateStates)) { - if (stateNode.isPartitioned) { - lines.push( - Orchestrationbp.calculateNullifier.postStatements({ - stateName, - accessedOnly: stateNode.accessedOnly, - stateType: 'partitioned', - })); - - } else { - lines.push( - Orchestrationbp.calculateNullifier.postStatements({ - stateName, - accessedOnly: stateNode.accessedOnly, - stateType: 'whole', - })); + case 'CalculateNullifier': + for ([stateName, stateNode] of Object.entries(node.privateStates)) { + if (stateNode.isPartitioned) { + lines.push( + Orchestrationbp.calculateNullifier.postStatements({ + stateName, + isSharedSecret: stateNode.isSharedSecret, + accessedOnly: stateNode.accessedOnly, + stateType: 'partitioned', + })); + + } else { + lines.push( + Orchestrationbp.calculateNullifier.postStatements({ + stateName, + isSharedSecret: stateNode.isSharedSecret, + accessedOnly: stateNode.accessedOnly, + stateType: 'whole', + })); + } } - } - - for ([stateName, stateNode] of Object.entries(node.privateStates)) { - if (stateNode.isPartitioned) { - lines.push( - Orchestrationbp.temporaryUpdatedNullifier.postStatements({ - stateName, - accessedOnly: stateNode.accessedOnly, - stateType: 'partitioned', - })); - - } else { - lines.push( - Orchestrationbp.temporaryUpdatedNullifier.postStatements({ - stateName, - accessedOnly: stateNode.accessedOnly, - stateType: 'whole', - })); + + for ([stateName, stateNode] of Object.entries(node.privateStates)) { + if (stateNode.isPartitioned) { + lines.push( + Orchestrationbp.temporaryUpdatedNullifier.postStatements({ + stateName, + accessedOnly: stateNode.accessedOnly, + stateType: 'partitioned', + })); + + } else { + lines.push( + Orchestrationbp.temporaryUpdatedNullifier.postStatements({ + stateName, + accessedOnly: stateNode.accessedOnly, + stateType: 'whole', + })); + } } - } - - for ([stateName, stateNode] of Object.entries(node.privateStates)) { - if (stateNode.isPartitioned) { - lines.push( - Orchestrationbp.calculateUpdateNullifierPath.postStatements({ - stateName, - accessedOnly: stateNode.accessedOnly, - stateType: 'partitioned', - })); - - } else { - lines.push( - Orchestrationbp.calculateUpdateNullifierPath.postStatements({ - stateName, - accessedOnly: stateNode.accessedOnly, - stateType: 'whole', - })); + + for ([stateName, stateNode] of Object.entries(node.privateStates)) { + if (stateNode.isPartitioned) { + lines.push( + Orchestrationbp.calculateUpdateNullifierPath.postStatements({ + stateName, + accessedOnly: stateNode.accessedOnly, + stateType: 'partitioned', + })); + + } else { + lines.push( + Orchestrationbp.calculateUpdateNullifierPath.postStatements({ + stateName, + accessedOnly: stateNode.accessedOnly, + stateType: 'whole', + })); + } } - } - - return { - statements: [`\n// Calculate nullifier(s): \n`, ...lines], - }; + + return { + statements: [`\n// Calculate nullifier(s): \n`, ...lines], + }; case 'CalculateCommitment': for ([stateName, stateNode] of Object.entries(node.privateStates)) { @@ -756,6 +780,7 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { Orchestrationbp.calculateCommitment.postStatements( { stateName, stateType: 'whole', + isSharedSecret: stateNode.isSharedSecret, structProperties: stateNode.structProperties, })); @@ -769,6 +794,7 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { Orchestrationbp.calculateCommitment.postStatements( { stateName, stateType: 'decrement', + isSharedSecret: stateNode.isSharedSecret, structProperties: stateNode.structProperties, })); @@ -780,6 +806,7 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { Orchestrationbp.calculateCommitment.postStatements( { stateName, stateType: 'increment', + isSharedSecret: stateNode.isSharedSecret, structProperties: stateNode.structProperties, })); @@ -805,14 +832,14 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => { ], }; - case 'SendTransaction': - if (node.publicInputs[0]) { - node.publicInputs.forEach((input: any) => { - if (input.properties) { - lines.push(`[${input.properties.map(p => p.type === 'bool' ? `(${input.name}${input.isConstantArray ? '.all' : ''}.${p.name}.integer === "1")` : `${input.name}${input.isConstantArray ? '.all' : ''}.${p.name}.integer`).join(',')}]`); - } else if (input.isConstantArray) { - lines.push(`${input.name}.all.integer`); - } else if(input.isBool) { + case 'SendTransaction': + if (node.publicInputs[0]) { + node.publicInputs.forEach((input: any) => { + if (input.properties) { + lines.push(`[${input.properties.map(p => p.type === 'bool' ? `(${input.name}${input.isConstantArray ? '.all' : ''}.${p.name}.integer === "1")` : `${input.name}${input.isConstantArray ? '.all' : ''}.${p.name}.integer`).join(',')}]`); + } else if (input.isConstantArray) { + lines.push(`${input.name}.all.integer`); + } else if(input.isBool) { lines.push(`(parseInt(${input.name}.integer, 10) === 1) ? true : false`); } else { diff --git a/src/parse/removeDecorators.ts b/src/parse/removeDecorators.ts index ad67c3791..af212929d 100644 --- a/src/parse/removeDecorators.ts +++ b/src/parse/removeDecorators.ts @@ -14,14 +14,14 @@ import { boolean } from 'yargs'; // regex: matches decorators when standalone words // eg: for {unknown knownknown known1 123lknown known secretvalue} finds only 1 match for decorator 'known' //const decorators = [/(? zolKeywords.map(zk => new RegExp(sk.source +' '+ zk.source))); function tidy(_line: string): string { diff --git a/src/transformers/visitors/redecorateVisitor.ts b/src/transformers/visitors/redecorateVisitor.ts index 5d21e367f..93b8f3355 100644 --- a/src/transformers/visitors/redecorateVisitor.ts +++ b/src/transformers/visitors/redecorateVisitor.ts @@ -40,14 +40,15 @@ export default { enter(node: any, state: any) { // for each decorator we have to re-add... for (const toRedecorate of state) { - // skip if the decorator is not secret (can't be a variable dec) or if its already been added - if (toRedecorate.added || toRedecorate.decorator !== 'secret') continue; + // skip if the decorator is not secret or sharedSecret (can't be a variable dec) or if its already been added + if (toRedecorate.added || (toRedecorate.decorator !== 'secret' && toRedecorate.decorator !== 'sharedSecret')) continue; // extract the char number const srcStart = node.src.split(':')[0]; // if it matches the one we removed, add it back to the AST if (toRedecorate.charStart === Number(srcStart)) { toRedecorate.added = true; node.isSecret = true; + if(toRedecorate.decorator === 'sharedSecret')node.isSharedSecret = true; return; } } diff --git a/src/transformers/visitors/toOrchestrationVisitor.ts b/src/transformers/visitors/toOrchestrationVisitor.ts index 8946c90c9..7858fa7b7 100644 --- a/src/transformers/visitors/toOrchestrationVisitor.ts +++ b/src/transformers/visitors/toOrchestrationVisitor.ts @@ -657,9 +657,12 @@ const visitor = { burnedOnly: stateVarIndicator.isBurned && !stateVarIndicator.newCommitmentsRequired, + reinitialisedOnly: stateVarIndicator.reinitialisable && + !stateVarIndicator.isNullified, }); } } + if (node.kind === 'constructor') { newNodes.writePreimageNode.isConstructor = true; diff --git a/src/traverse/Binding.ts b/src/traverse/Binding.ts index 7ff54317b..e3e8366ca 100644 --- a/src/traverse/Binding.ts +++ b/src/traverse/Binding.ts @@ -135,6 +135,7 @@ export class Binding { export class VariableBinding extends Binding { isSecret: boolean; + isSharedSecret: boolean; stateVariable: boolean; isModified: boolean; modificationCount: number = 0; @@ -191,6 +192,7 @@ export class VariableBinding extends Binding { this.stateVariable = node.stateVariable; this.isSecret = node.isSecret ?? false; + this.isSharedSecret = node.isSharedSecret ?? false; if (path.isMappingDeclaration() || path.isArrayDeclaration()) { diff --git a/src/traverse/Indicator.ts b/src/traverse/Indicator.ts index 2e4ade660..8486b6a10 100644 --- a/src/traverse/Indicator.ts +++ b/src/traverse/Indicator.ts @@ -347,6 +347,7 @@ export class StateVariableIndicator extends FunctionDefinitionIndicator { node: any; isSecret: boolean; + isSharedSecret: boolean; isUnknown?: boolean; isKnown?: boolean; @@ -406,6 +407,7 @@ export class StateVariableIndicator extends FunctionDefinitionIndicator { this.parentIndicator = path.scope.indicators; this.isSecret = referencedBinding.isSecret; + this.isSharedSecret = referencedBinding.isSharedSecret; this.referenceCount = 0; this.referencingPaths = []; diff --git a/src/traverse/MappingKey.ts b/src/traverse/MappingKey.ts index 09e2b8fb8..3057f4bc7 100644 --- a/src/traverse/MappingKey.ts +++ b/src/traverse/MappingKey.ts @@ -16,6 +16,7 @@ export default class MappingKey { node: any; path: NodePath; isSecret: boolean; + isSharedSecret: boolean; isReferenced?: boolean; referenceCount: number = 0; @@ -110,6 +111,7 @@ export default class MappingKey { this.referencedKeyIsParam = keyPath.isFunctionParameter(); // is a function parameter - used for finding owner this.isMsgSender = keyPath.isMsg(); // used for finding owner this.isSecret = container.isSecret; + this.isSharedSecret = container.isSharedSecret; this.isMapping = container.isMapping; this.isStruct = container.isStruct; // keyPath.isStruct(); diff --git a/src/traverse/NodePath.ts b/src/traverse/NodePath.ts index bfb0e9098..d6965f834 100644 --- a/src/traverse/NodePath.ts +++ b/src/traverse/NodePath.ts @@ -63,6 +63,7 @@ export default class NodePath { inList: boolean; scope: Scope; isSecret?: boolean; + isSharedSecret?:boolean; isPublic?: boolean; containsSecret?: boolean; containsPublic?: boolean; diff --git a/src/types/orchestration-types.ts b/src/types/orchestration-types.ts index ce71368a4..a5c553933 100644 --- a/src/types/orchestration-types.ts +++ b/src/types/orchestration-types.ts @@ -72,12 +72,13 @@ export default function buildNode(nodeType: string, fields: any = {}): any { }; } case 'VariableDeclaration': { - const { name, type, interactsWithSecret, isSecret, isAccessed, declarationType = 'state', oldASTId = 0 } = fields; + const { name, type, interactsWithSecret, isSecret,isSharedSecret, isAccessed, declarationType = 'state', oldASTId = 0 } = fields; return { nodeType, name, id: oldASTId, isSecret, + isSharedSecret, isAccessed, interactsWithSecret, declarationType, @@ -152,6 +153,7 @@ export default function buildNode(nodeType: string, fields: any = {}): any { name, isAccessed = false, isSecret = false, + isSharedSecret = false, } = fields; return { nodeType, @@ -160,6 +162,7 @@ export default function buildNode(nodeType: string, fields: any = {}): any { indexExpression, isAccessed, isSecret, + isSharedSecret, }; } case 'MemberAccess': { diff --git a/test/contracts/Assign-Shared-Secret.zol b/test/contracts/Assign-Shared-Secret.zol new file mode 100644 index 000000000..0f5a2a7a6 --- /dev/null +++ b/test/contracts/Assign-Shared-Secret.zol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: CC0 + +pragma solidity ^0.8.0; + +contract Swap { + + secret mapping(address => uint256) public balances; + secret mapping(uint256 => address) public tokenOwners; + struct swapStruct{ + uint256 swapAmountSent; + uint256 swapAmountRecieved; + uint256 swapTokenSent; + uint256 swapTokenRecieved; + + } + sharedSecret uint256 pendingStatus; + + sharedSecret mapping(address => swapStruct) swapProposals; + + + function deposit(secret uint256 amount, secret uint256 tokenId) public { + balances[msg.sender] += amount; + reinitialisable tokenOwners[tokenId] = msg.sender; + } + + function startSwap(secret address sharedAddress, secret uint256 amountSent, secret uint256 tokenIdSent, secret uint256 amountRecieved, secret uint256 tokenIdRecieved) public { + + require(pendingStatus == 0); + swapProposals[sharedAddress].swapAmountSent += amountSent; + balances[msg.sender] -= amountSent; + tokenOwners[tokenIdSent] = sharedAddress; + swapProposals[sharedAddress].swapTokenSent = tokenIdSent; + swapProposals[sharedAddress].swapAmountRecieved += amountRecieved; + swapProposals[sharedAddress].swapTokenRecieved = tokenIdRecieved; + pendingStatus = 1; + + } + + function completeSwap(secret address counterParty, secret address sharedAddress, secret uint256 amountSent, secret uint256 tokenIdSent, secret uint256 amountRecieved, secret uint256 tokenIdRecieved) public { + + require(swapProposals[sharedAddress].swapAmountRecieved == amountSent && swapProposals[sharedAddress].swapTokenRecieved == tokenIdSent); + require(swapProposals[sharedAddress].swapAmountSent == amountRecieved && swapProposals[sharedAddress].swapTokenSent == tokenIdRecieved); + require(pendingStatus == 1); + swapProposals[sharedAddress].swapAmountSent -= amountRecieved; + swapProposals[sharedAddress].swapAmountRecieved -= amountSent; + balances[msg.sender] += amountRecieved - amountSent; + unknown balances[counterParty] += amountSent; + + tokenOwners[tokenIdSent] = counterParty; + + tokenOwners[tokenIdRecieved] = msg.sender; + pendingStatus = 0; + + } + + function quitSwap(secret address sharedAddress, secret uint256 amountSent, secret uint256 tokenIdSent) public { + + require(swapProposals[sharedAddress].swapAmountSent == amountSent && swapProposals[sharedAddress].swapTokenSent == tokenIdSent); + require(pendingStatus == 1); + swapProposals[sharedAddress].swapAmountSent -= amountSent; + balances[msg.sender] += amountSent; + tokenOwners[tokenIdSent] = msg.sender; + swapProposals[sharedAddress].swapTokenSent = 0; + swapProposals[sharedAddress].swapTokenRecieved = 0; + swapProposals[sharedAddress].swapAmountRecieved = 0; + pendingStatus = 0; + + } +}