Skip to content

Commit

Permalink
Merge pull request #248 from EYBlockchain/lydia/structbools
Browse files Browse the repository at this point in the history
Fix bugs caused due to boolean variables, including when they are properties of structs.
  • Loading branch information
SwatiEY authored May 30, 2024
2 parents d5b5952 + 5c7ea03 commit 65783e4
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 38 deletions.
18 changes: 14 additions & 4 deletions src/boilerplate/circuit/zokrates/nodes/BoilerplateGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class BoilerplateGenerator {
isMapping: boolean;
isStruct: boolean;
structProperties?: string[];
structPropertiesTypes?: string[];
typeName?: string;
mappingKeyTypeName?: string;
thisIndicator: any;
Expand Down Expand Up @@ -186,17 +187,25 @@ class BoilerplateGenerator {

if (mappingKeyIndicator.isStruct && mappingKeyIndicator.isParent) {
this.typeName = indicators.referencingPaths[0]?.getStructDeclaration()?.name;
this.structProperties = indicators.referencingPaths[0]?.getStructDeclaration()?.members.map(m => m.name)
this.structProperties = indicators.referencingPaths[0]?.getStructDeclaration()?.members.map(m => m.name);
this.structPropertiesTypes = indicators.referencingPaths[0]?.getStructDeclaration()?.members.map(m => ({ name: m.name, typeName: m.typeName.name }));
} else if (mappingKeyIndicator.referencingPaths[0]?.node.typeDescriptions.typeString.includes('struct ')) {
// somewhat janky way to include referenced structs not separated by property
this.typeName = mappingKeyIndicator.referencingPaths[0]?.getStructDeclaration()?.name;
}
this.generateBoilerplate();
}
} else {
if (indicators instanceof StateVariableIndicator && indicators.structProperties) {
this.structProperties = indicators.referencingPaths[0]?.getStructDeclaration()?.members.map(m => m.name);
this.typeName = indicators.referencingPaths[0]?.getStructDeclaration()?.name;
if (indicators instanceof StateVariableIndicator) {
if (indicators.structProperties){
this.structPropertiesTypes = indicators.referencingPaths[0]?.getStructDeclaration()?.members.map(m => ({ name: m.name, typeName: m.typeName.name }));
this.structProperties = indicators.referencingPaths[0]?.getStructDeclaration()?.members.map(m => m.name);
this.typeName = indicators.referencingPaths[0]?.getStructDeclaration()?.name;
} else {
if (indicators.referencingPaths[0]?.node.typeDescriptions?.typeString === 'bool'){
this.typeName = 'bool';
}
}
}
this.assignIndicators(indicators);
this.generateBoilerplate();
Expand Down Expand Up @@ -251,6 +260,7 @@ class BoilerplateGenerator {
...(this.isNullified && { isNullified: this.isNullified }),
...(this.isMapping && { isMapping: this.isMapping }),
...(this.isStruct && { structProperties: this.structProperties}),
...(this.isStruct && this.structPropertiesTypes && { structPropertiesTypes: this.structPropertiesTypes}),
...(this.typeName && { typeName: this.typeName}),
...(this.mappingKeyName && { mappingKeyTypeName: this.mappingKeyTypeName }),
...(this.isAccessed && { isAccessed: this.isAccessed }),
Expand Down
61 changes: 52 additions & 9 deletions src/boilerplate/circuit/zokrates/raw/BoilerplateGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,27 +182,54 @@ class BoilerplateGenerator {
];
},

postStatements({ name: x, structProperties }): string[] {
if (structProperties)
postStatements({ name: x, structProperties, structPropertiesTypes, typeName }): string[] {
const lines: string[] = [];
if (!structProperties ) {
if (typeName === 'bool'){
lines.push(`field ${x}_oldCommitment_value_field = if ${x}_oldCommitment_value then 1 else 0 fi`);
} else {
lines.push(`field ${x}_oldCommitment_value_field = ${x}_oldCommitment_value`);
}
}

if (structProperties){
if (structPropertiesTypes) {
structPropertiesTypes.forEach(property => {
if (property.typeName === 'bool'){
lines.push(`field ${x}_oldCommitment_value_${property.name}_field = if ${x}_oldCommitment_value.${property.name} then 1 else 0 fi`);
}
});
}
return [
`
// prepare secret state '${x}' for commitment
${lines}
// ${x}_oldCommitment_commitment: preimage check
field ${x}_oldCommitment_commitment_field = poseidon([\\
${x}_stateVarId_field,\\
${structProperties.map(p => `\t ${x}_oldCommitment_value.${p},\\`).join('\n')}
${structPropertiesTypes.map(p => (p.typeName === 'bool') ? `\t \t \t \t \t \t${x}_oldCommitment_value_${p.name}_field,\\` : `\t ${x}_oldCommitment_value.${p.name},\\`).join('\n')}
${x}_oldCommitment_owner_publicKey,\\
${x}_oldCommitment_salt\\
])`,
];
}
return [

`
// prepare secret state '${x}' for commitment
${lines}
// ${x}_oldCommitment_commitment: preimage check
field ${x}_oldCommitment_commitment_field = poseidon([\\
${x}_stateVarId_field,\\
${x}_oldCommitment_value,\\
${x}_oldCommitment_value_field,\\
${x}_oldCommitment_owner_publicKey,\\
${x}_oldCommitment_salt\
])`,
Expand Down Expand Up @@ -289,7 +316,7 @@ class BoilerplateGenerator {
];
},

postStatements({ name: x, isWhole, isNullified, newCommitmentValue, structProperties, typeName }): string[] {
postStatements({ name: x, isWhole, isNullified, newCommitmentValue, structProperties, structPropertiesTypes, typeName }): string[] {
// if (!isWhole && !newCommitmentValue) throw new Error('PATH');
const y = isWhole ? x : newCommitmentValue;
const lines: string[] = [];
Expand All @@ -315,22 +342,38 @@ class BoilerplateGenerator {
);
}
} else {
if (!structProperties) lines.push(`field ${x}_newCommitment_value_field = ${y}`);
else lines.push(`${typeName} ${x}_newCommitment_value = ${typeName} { ${structProperties.map(p => ` ${p}: ${isWhole ? `${y}.${p}` : `${y[p]}`}`)} }`)
if (!structProperties ) {
if (typeName === 'bool'){
lines.push(`field ${x}_newCommitment_value_field = if ${y} then 1 else 0 fi`);
} else {
lines.push(`field ${x}_newCommitment_value_field = ${y}`);
}

}
else {
lines.push(`${typeName} ${x}_newCommitment_value = ${typeName} { ${structProperties.map(p => ` ${p}: ${isWhole ? `${y}.${p}` : `${y[p]}`}`)} }\n`);
if (structPropertiesTypes) {
structPropertiesTypes.forEach(property => {
if (property.typeName === 'bool'){
lines.push(`\t \t \t \t field ${x}_newCommitment_value_${property.name}_field = if ${x}_newCommitment_value.${property.name} then 1 else 0 fi`);
}
});
}
}
}

if (structProperties)
return [
`
// prepare secret state '${x}' for commitment
${lines}
${lines.join('\n')}
// ${x}_newCommitment_commitment - preimage check
field ${x}_newCommitment_commitment_check_field = poseidon([\\
${x}_stateVarId_field,\\
${structProperties.map(p => `\t ${x}_newCommitment_value.${p},\\`).join('\n')}
${structPropertiesTypes.map(p => (p.typeName === 'bool') ? `\t \t \t \t \t \t${x}_newCommitment_value_${p.name}_field,\\` : `\t ${x}_newCommitment_value.${p.name},\\`).join('\n')}
${x}_newCommitment_owner_publicKey,\\
${x}_newCommitment_salt\\
])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ class FunctionBoilerplateGenerator {
`uint256[]`,
].filter(para => para !== undefined); // Added for return parameter


customInputs?.forEach((input, i) => {
if (input.isConstantArray) {
const expanded = [];
Expand Down Expand Up @@ -108,7 +107,7 @@ class FunctionBoilerplateGenerator {
inputs.customInputs = new uint[](${customInputs.flat(Infinity).length});
${customInputs.flat(Infinity).map((input: any, i: number) => {
if (input.type === 'address') return `inputs.customInputs[${i}] = uint256(uint160(address(${input.name})));`;
if (input.type === 'bool' && !['0', '1'].includes(input.name)) return `inputs.customInputs[${i}] = ${input.name} == false ? 0 : 1;`;
if ((input.type === 'bool' || input.typeName?.name === 'bool' ) && !['0', '1'].includes(input.name)) return `inputs.customInputs[${i}] = ${input.name} == false ? 0 : 1;`;
return `inputs.customInputs[${i}] = ${input.name};`;
}).join('\n')}`]
: []),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -800,10 +800,13 @@ export const OrchestrationCodeBoilerPlate: any = (node: any) => {
if (node.publicInputs[0]) {
node.publicInputs.forEach((input: any) => {
if (input.properties) {
lines.push(`[${input.properties.map(p => `${input.name}${input.isConstantArray ? '.all' : ''}.${p}.integer`).join(',')}]`)
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 {
} else if(input.isBool) {
lines.push(`(parseInt(${input.name}.integer, 10) === 1) ? true : false`);
}
else {
lines.push(`${input}.integer`);
}
});
Expand Down
7 changes: 7 additions & 0 deletions src/codeGenerators/circuit/zokrates/toCircuit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ function codeGenerator(node: any) {

case 'ExpressionStatement': {
if (node.isVarDec) {
if (node.expression?.leftHandSide?.typeName === 'bool'){
return `
bool ${codeGenerator(node.expression)}`;
}
return `
field ${codeGenerator(node.expression)}`;
}
Expand Down Expand Up @@ -209,6 +213,9 @@ function codeGenerator(node: any) {
return `${codeGenerator(node.leftHandSide)} ${node.operator} ${codeGenerator(node.rightHandSide)}`;

case 'UnaryOperation':
if (node.subExpression?.typeName?.name === 'bool' && node.operator === '!'){
return `${node.operator}${node.subExpression.name}`;
}
return `${codeGenerator(node.initialValue)} = ${codeGenerator(node.subExpression)} ${node.operator[0]} 1`

case 'BinaryOperation':
Expand Down
3 changes: 3 additions & 0 deletions src/codeGenerators/orchestration/nodejs/toOrchestration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ export default function codeGenerator(node: any, options: any = {}): any {

case 'UnaryOperation':
// ++ or -- on a parseInt() does not work
if (node.subExpression.subType === 'bool' && node.operator === '!'){
return `${node.operator}(parseInt(${node.subExpression.name}.integer, 10) === 1)`;
}
return `parseInt(${node.subExpression.name}.integer,10)${node.operator[0]}1`;

case 'Literal':
Expand Down
38 changes: 27 additions & 11 deletions src/transformers/visitors/toCircuitVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,12 @@ const publicInputsVisitor = (thisPath: NodePath, thisState: any) => {
// TODO other types
if (thisPath.isMapping() || thisPath.isArray())
name = name.replace('[', '_').replace(']', '').replace('.sender', 'Sender').replace('.value','Value');
let nodeTypeString = node.typeDescriptions.typeString === 'bool' ? 'bool': 'field';
// We never need the input to the circuit to be the MappingKeyName
//if (thisPath.containerName === 'indexExpression'){
// name = binding.getMappingKeyName(thisPath);
//}
const parameterNode = buildNode('VariableDeclaration', { name, type: 'field', isSecret: false, declarationType: 'parameter'});
const parameterNode = buildNode('VariableDeclaration', { name, type: nodeTypeString, isSecret: false, declarationType: 'parameter'});
parameterNode.id = thisPath.isMapping() || thisPath.isArray() ? binding.id + thisPath.getAncestorOfType('IndexAccess')?.node.indexExpression.referencedDeclaration : binding.id;
const fnDefNode = thisPath.getAncestorOfType('FunctionDefinition')?.node;
const params = fnDefNode._newASTPointer.parameters.parameters;
Expand All @@ -186,6 +187,9 @@ const publicInputsVisitor = (thisPath: NodePath, thisState: any) => {
operator: '=',
rightHandSide: buildNode('Identifier', { name: `${name}`, subType: 'generalNumber' }),
});
if (node.typeDescriptions?.typeString === 'bool') {
beginNodeInit.leftHandSide.typeName ='bool';
}
const beginNode = buildNode('ExpressionStatement', {
expression: beginNodeInit,
interactsWithSecret: true,
Expand Down Expand Up @@ -698,22 +702,23 @@ const visitor = {
const newNode = buildNode(node.nodeType, {
operator,
prefix,
subExpression: buildNode(subExpression.nodeType, {
name: path.scope.getIdentifierMappingKeyName(subExpression, true),
}),
initialValue: buildNode(subExpression.nodeType, {
name: path.scope.getIdentifierMappingKeyName(subExpression)
}),
});
if (subExpression.typeDescriptions.typeString === 'bool') {
newNode.subExpression.typeName = buildNode('ElementaryTypeName', {
name: `bool`});
}
//We need to ensure that for non-secret variables the name used on the right hand side of the assignment
// is always the original name. (As the original variable is always updated we always get the right value.)
if ( (binding instanceof VariableBinding) && !binding.isSecret &&
binding.stateVariable){
newNode.subExpression = buildNode(subExpression.nodeType, {
name: subExpression.name,
});
} else{
newNode.subExpression = buildNode(subExpression.nodeType, {
name: path.scope.getIdentifierMappingKeyName(subExpression, true)
});
}
newNode.subExpression.name = subExpression.name;
}
node._newASTPointer = newNode;
parentnewASTPointer(parent, path, newNode, parent._newASTPointer[path.containerName]);
state.skipSubNodes = true;
Expand Down Expand Up @@ -1145,8 +1150,19 @@ let childOfSecret = path.getAncestorOfType('ForStatement')?.containsSecret;
switch (thisPath.node.nodeType) {
case 'Identifier':
if (!thisPath.getAncestorOfType('IndexAccess')) {
state.list.push(cloneDeep(thisPath.node._newASTPointer));
thisPath.node._newASTPointer.name += '_temp';
if (thisPath.parent.nodeType === 'UnaryOperation'){
if (thisPath.getAncestorContainedWithin('subExpression')){
state.list.push(cloneDeep(thisPath.parent._newASTPointer.subExpression));
thisPath.parent._newASTPointer.subExpression.name += '_temp';
}
if (thisPath.getAncestorContainedWithin('initialValue')) {
state.list.push(cloneDeep(thisPath.parent._newASTPointer.initialValue));
thisPath.parent._newASTPointer.initialValue.name += '_temp';
}
} else{
state.list.push(cloneDeep(thisPath.node._newASTPointer));
thisPath.node._newASTPointer.name += '_temp';
}
} else {
thisPath.parent._newASTPointer.indexExpression.name += '_temp';
}
Expand Down
20 changes: 12 additions & 8 deletions src/transformers/visitors/toOrchestrationVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -691,11 +691,12 @@ const visitor = {
// this adds other values we need in the tx
for (const param of node.parameters.parameters) {
if (!param.isSecret) {
if (path.isStructDeclaration(param) || path.isConstantArray(param)) {
if (path.isStructDeclaration(param) || path.isConstantArray(param) ||( param.typeName && param.typeName.name === 'bool')) {
let newParam: any = {};
newParam.name = param.name;
if (path.isStructDeclaration(param)) newParam.properties = param._newASTPointer.typeName.properties.map(p => p.name);
if (path.isConstantArray) newParam.isConstantArray = true;
if (path.isStructDeclaration(param)) newParam.properties = param._newASTPointer.typeName.properties.map(p => ({"name" : p.name, "type" : p.type }));
if (path.isConstantArray(param)) newParam.isConstantArray = true;
if (param.typeName?.name === 'bool') newParam.isBool = true;
newNodes.sendTransactionNode.publicInputs.push(newParam);
} else newNodes.sendTransactionNode.publicInputs.push(param.name);
}
Expand Down Expand Up @@ -1087,7 +1088,6 @@ const visitor = {
enter(path: NodePath, state: any) {
const { node, parent } = path;
const { operator, prefix, subExpression } = node;

const newNode = buildNode('Assignment', { operator: '='});
newNode.rightHandSide = buildNode(node.nodeType, { operator, prefix });

Expand All @@ -1111,10 +1111,15 @@ const visitor = {
});
}

node._newASTPointer = newNode;
if (parent._newASTPointer.nodeType === 'VariableDeclarationStatement') {
if (operator === '!'){
node._newASTPointer = newNode.rightHandSide;
parent._newASTPointer[path.containerName] = newNode.rightHandSide;
}
else if (parent._newASTPointer.nodeType === 'VariableDeclarationStatement') {
node._newASTPointer = newNode;
parent._newASTPointer.initialValue = newNode;
} else {
node._newASTPointer = newNode;
parent._newASTPointer.expression = newNode;
}
// we make a custom node like a = a++ to avoid nodejs errors => stop traversing
Expand Down Expand Up @@ -1183,7 +1188,7 @@ const visitor = {
(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 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 (
Expand Down Expand Up @@ -1482,7 +1487,6 @@ const visitor = {
name,
subType: node.typeDescriptions.typeString,
});

// if this is a public state variable, this fn will add a public input
addPublicInput(path, state,newNode);
parentnewASTPointer(parent, path, newNode , parent._newASTPointer[path.containerName]);
Expand Down
4 changes: 2 additions & 2 deletions src/traverse/NodePath.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* eslint-disable no-param-reassign, no-shadow, import/no-cycle */
//eslint-disable no-param-reassign, no-shadow, import/no-cycle */

/**
This file contains portions of code from Babel (https://github.com/babel/babel). All such code has been modified for use in this repository. See below for Babel's MIT license and copyright notice:
Expand Down Expand Up @@ -1035,7 +1035,7 @@ export default class NodePath {
return (
!(this.queryAncestors(path => path.containerName === 'indexExpression')) && !this.getAncestorOfType('FunctionCall') &&
!this.getAncestorContainedWithin('initialValue') &&
!this.getRhsAncestor(true) && !(this.queryAncestors(path => path.containerName === 'condition') || this.queryAncestors(path => path.containerName === 'initializationExpression') || this.queryAncestors(path => path.containerName === 'loopExpression'))
!(this.getRhsAncestor(true)) && !(this.queryAncestors(path => path.containerName === 'condition') || this.queryAncestors(path => path.containerName === 'initializationExpression') || this.queryAncestors(path => path.containerName === 'loopExpression'))
);
default:
return false;
Expand Down
Loading

0 comments on commit 65783e4

Please sign in to comment.