Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore Lost database #273

Merged
merged 38 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7405515
chore: added the encryption function
SwatiEY May 30, 2024
b7f2c01
chore: encrypt pre-image during orchestration
lydiagarms May 31, 2024
e900699
fix: encryption and decryption of backup
lydiagarms Jun 5, 2024
5d4bf7d
chore: fix for stack too deep Error
SwatiEY Jun 5, 2024
6b2a37f
chore: save ciphertexts in backup data array
lydiagarms Jun 5, 2024
06c4b21
chore: fixed the tx struct
SwatiEY Jun 5, 2024
46c5633
chore: fix for contructorInputs
SwatiEY Jun 5, 2024
16ff0cd
fix: return values in contract when encryption is used
lydiagarms Jun 5, 2024
a955c61
chore: custom Inputs fixed
SwatiEY Jun 5, 2024
39daa9b
support back up encryption for structs
lydiagarms Jun 6, 2024
d2997be
chore: fixed the custom Inputs
SwatiEY Jun 6, 2024
114ab2f
fix: errors in contract due to types of backdata not matching
lydiagarms Jun 6, 2024
107b602
merge with changes made in contract inputs due to stack too deep error
lydiagarms Jun 7, 2024
5fd9898
fix for bug when customInputs is empty and make event take as input t…
lydiagarms Jun 7, 2024
db53da2
fix: encrypt mapping key
lydiagarms Jun 7, 2024
7af0163
chore: encrypted events
lydiagarms Jun 7, 2024
86054ee
fix: error in Assign-return - return value not appearing in custom in…
lydiagarms Jun 7, 2024
e9bd03d
fix for BucketofBalls.zol and Assign-Return1.zol
lydiagarms Jun 10, 2024
859550f
Merge branch 'master' into lydia/restoreDB
lydiagarms Jun 10, 2024
4e6f9f7
fix: potential error due to change for internal function calls
lydiagarms Jun 10, 2024
47c39e3
fix: error due to mistake during merging
lydiagarms Jun 10, 2024
b744ec7
fix: add Backup data as input for internal function calls
lydiagarms Jun 10, 2024
36633e8
fix error due to data location of Inputs in contract
lydiagarms Jun 10, 2024
2680358
fix: error due to unknown secret returns appearing in contract
lydiagarms Jun 10, 2024
1d44444
fix: re-add msg sigs to ensure proof not verified twice with internal…
lydiagarms Jun 11, 2024
6b2f7a9
fix: function signature
lydiagarms Jun 11, 2024
50ec64a
fix: for arrays encrypt the state variable stateVarId as well as the …
lydiagarms Jun 11, 2024
98de32a
chore: backupreciever mjs file to rebuild commitment database
lydiagarms Jun 14, 2024
3acf463
fix: ciphertext name clash in orchestration
lydiagarms Jun 14, 2024
3de9194
fix: delete logs
lydiagarms Jun 14, 2024
39e98c9
fix: error in Booleans due to inputs struct being input a boolean
lydiagarms Jun 14, 2024
7da7ee6
fix: error in contract in Assign-Return
lydiagarms Jun 14, 2024
7cd4e8e
fix: unrelated error in Return-Bool
lydiagarms Jun 14, 2024
f83809e
fix: errors in orchestration for constructors
lydiagarms Jun 17, 2024
dd21c98
merge
lydiagarms Jun 18, 2024
ac3ca7f
fix: custom inputs for constructors
lydiagarms Jun 18, 2024
ed3b989
merge conflict
lydiagarms Jun 20, 2024
3914e46
chore: update readme
lydiagarms Jun 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,9 @@ You can also filter these commitments by variable name. Using the example above,
```
as a GET request to `http://localhost:3000/getCommitmentsByVariableName`.

If the commitment database that stores commitment preimages is lost you can restore the DB (by decrypting the onchain encryptions of the preimages) by sending a POST request to `http://localhost:3000/backupDataRetriever`.


#### Using secret states in the constructor

Starlight handles secret initiation in the constructor by creating a proof at the setup stage. Any user supplied inputs will be prompted for in the command line when running `./bin/setup`.
Expand Down
12 changes: 9 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/boilerplate/common/generic-test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('FUNCTION_NAME', async function () {
await startEventFilter('CONTRACT_NAME');
// this calls your function! It returns the tx from the shield contract
// you can replace the values below - numbers are randomly generated
const { tx , encEvent } = await FUNCTION_NAME(FUNCTION_SIG_1);
const { tx , encEvent, encBackupEvent } = await FUNCTION_NAME(FUNCTION_SIG_1);
// prints the tx
console.log(tx);
// reassigns leafIndex to the index of the first commitment added by this function
Expand Down
51 changes: 49 additions & 2 deletions src/boilerplate/common/number-theory.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,34 @@ function compressStarlightKey(publicKeyPoint) {
return publicKey;
}

/**
Encrypt messages encrypted with KEM-DEM
@param {string[]} Plaintext - hex string[]
@param {string} SendersecretKey - hex string
@param {string[2]} RecieverPublicKey - hex string[]
@return {string[]} plainText - int string[]
*/
function encrypt(plaintext, secretKey, recieverPublicKey) {
const encryptedMessages = [];
const sharedSecret = scalarMult(secretKey, [
BigInt(recieverPublicKey[0]),
BigInt(recieverPublicKey[1]),
]);
const key = poseidonHash([
sharedSecret[0],
sharedSecret[1],
BigInt(DOMAIN_KEM),
]);
plaintext.forEach((msg, index) => {
const hash = poseidonHash([key.bigInt, BigInt(DOMAIN_DEM), BigInt(index)]);
encryptedMessages[index] = addMod([BigInt(msg), hash.bigInt], Fp);
while (encryptedMessages[index] < 0n) {
encryptedMessages[index] += Fp;
}
});
return encryptedMessages;
}

/**
Decrypt messages encrypted with KEM-DEM
@param {string[]} encryptedMessages - hex string[]
Expand Down Expand Up @@ -368,7 +396,8 @@ function sbox(state, f, p, r) {
const N = state.length;
state[0] = powerMod(state[0], 5n, q);
for (let i = 1; i < N; i++) {
state[i] = r < f / 2 || r >= f / 2 + p ? powerMod(state[i], 5n, q) : state[i];
state[i] =
r < f / 2 || r >= f / 2 + p ? powerMod(state[i], 5n, q) : state[i];
}
return state;
}
Expand All @@ -391,7 +420,24 @@ function poseidonHash(_inputs) {
const inputs = _inputs;
const N = inputs.length;
const t = N + 1;
const roundsP = [56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68];
const roundsP = [
56,
57,
56,
60,
60,
63,
64,
63,
60,
66,
60,
65,
70,
60,
64,
68,
];
const f = 8;
const p = roundsP[t - 2];
const c = C[t - 2];
Expand Down Expand Up @@ -421,6 +467,7 @@ export {
scalarMult,
compressStarlightKey,
decompressStarlightKey,
encrypt,
decrypt,
poseidonHash,
sharedSecretKey,
Expand Down
4 changes: 2 additions & 2 deletions src/boilerplate/common/services/generic-api_services.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ export async function service_FUNCTION_NAME (req, res, next){
await startEventFilter('CONTRACT_NAME');
const FUNCTION_SIG;
CONSTRUCTOR_INPUTS;
const { tx , encEvent, _RESPONSE_} = await FUNCTION_NAME(FUNCTION_SIG);
const { tx , encEvent, encBackupEvent, _RESPONSE_} = await FUNCTION_NAME(FUNCTION_SIG);
// prints the tx
console.log(tx);
res.send({tx, encEvent, _RESPONSE_});
res.send({tx, encEvent, encBackupEvent, _RESPONSE_});
// reassigns leafIndex to the index of the first commitment added by this function
if (tx.event) {
leafIndex = tx.returnValues[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class ContractBoilerplateGenerator {
delete parameterList[ paramtype ];
}
const newList: string[] = [];

params?.forEach(circuitParamNode => {
switch (circuitParamNode.bpType) {
case 'nullification':
Expand All @@ -144,8 +145,9 @@ class ContractBoilerplateGenerator {
if (!newList.includes(circuitParamNode.bpType)) newList.push(circuitParamNode.bpType);
break;
case 'encryption':
returnpara['returnParameters'] ??= [];
returnpara['returnParameters'].push(circuitParamNode.bpType);

returnpara['encryptionParameters'] ??= [];
returnpara['encryptionParameters'].push(circuitParamNode.bpType);
break;
case undefined: {
if (
Expand Down Expand Up @@ -176,6 +178,7 @@ class ContractBoilerplateGenerator {
parameterList = {...parameterList, ...returnpara};
}
circuitParams[ functionName ] = parameterList;

}
const constructorContainsSecret = Object.values(this.scope.bindings).some((binding: any) => binding.node.kind === 'constructor');
return { nullifiersRequired, oldCommitmentAccessRequired, newCommitmentsRequired, containsAccessedOnlyState, encryptionRequired, constructorContainsSecret, circuitParams, isjoinSplitCommitmentsFunction};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,18 +117,17 @@ class FunctionBoilerplateGenerator {

path.node._newASTPointer.body.statements?.forEach((node) => {
if(node.expression?.nodeType === 'InternalFunctionCall'){
if(node.expression.parameters.includes('cipherText') )
internalFunctionEncryptionRequired = true
if(node.expression.encryptionRequired)
internalFunctionEncryptionRequired = true;

}

})


if(path.node.returnParameters.parameters.length === 0 && !indicators.encryptionRequired && !internalFunctionEncryptionRequired) {
if(path.node.returnParameters.parameters.length === 0 && !indicators.encryptionRequired && !internalFunctionEncryptionRequired){
publicParams?.push({ name: 1, type: 'uint256', dummy: true , inCircuit: true });
}

return {
...(publicParams?.length && { customInputs: publicParams }),
functionName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,16 @@ class ContractBoilerplateGenerator {
...(encryptionRequired ? [`
event EncryptedData(uint256[] cipherText, uint256[2] ephPublicKey);`] : []),

...nullifiersRequired ? [`
...(newCommitmentsRequired ? [`
struct BackupDataElement {
string varName;
uint256[] cipherText;
uint256 ephPublicKey;
} \n
event EncryptedBackupData(BackupDataElement[] encPreimages);
`] : []),

...nullifiersRequired ? [`
uint256 public newNullifierRoot;`] : [],

...(oldCommitmentAccessRequired ? [`
Expand Down Expand Up @@ -121,7 +130,6 @@ class ContractBoilerplateGenerator {
let verifyInput: string[] = [];

const verifyInputsMap = (type: string, input: string, counter: any) => {

if(type === 'parameters'){
switch (input) {
case 'nullifierRoot':
Expand Down Expand Up @@ -150,8 +158,7 @@ class ContractBoilerplateGenerator {
break;
}
}
else if(type === 'returnParameters') {

else if(type === 'returnParameters' || type === 'encryptionParameters') {
switch (input) {
case 'encryption':
verifyInput.push( `
Expand Down Expand Up @@ -222,13 +229,13 @@ class ContractBoilerplateGenerator {
newCommitments: 0,
encryption: 0,
};
_inputs.map(i => verifyInputsMap(type, i, counter));
_inputs?.map(i => verifyInputsMap(type, i, counter));



}

if(_params && !(Object.keys(_params).includes('returnParameters'))) verifyInput.push(`
if(_params && !(Object.keys(_params).includes('returnParameters')) &&!(Object.keys(_params).includes('encryptionParameters'))) verifyInput.push(`
inputs[k++] = 1;`)

verifyInputs.push(`
Expand Down
104 changes: 51 additions & 53 deletions src/boilerplate/contract/solidity/raw/FunctionBoilerplateGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ class FunctionBoilerplateGenerator {
if (isConstructor && encryptionRequired) throw new Error(`There shouldn't be any secret states that require sharing encrypted data in the constructor.`)
const visibility = isConstructor ? 'memory' : 'calldata';
return [
...(newNullifiers ? [`uint256 nullifierRoot, uint256 latestNullifierRoot,uint256[] ${visibility} newNullifiers`] : []), // nullifiers and nullifier root exist together
...(commitmentRoot ? [`uint256 commitmentRoot`] : []),
...(newCommitments ? [`uint256[] ${visibility} newCommitments`] : []),
...(encryptionRequired ? [`uint256[][] calldata cipherText`] : []),
...(encryptionRequired ? [`uint256[2][] calldata ephPubKeys`] : []),
...(newCommitments || newNullifiers ? [`uint256[] ${visibility} proof`] : []),
// ...(newNullifiers ? [`uint256 nullifierRoot, uint256 latestNullifierRoot,uint256[] ${visibility} newNullifiers`] : []), // nullifiers and nullifier root exist together
// ...(commitmentRoot ? [`uint256 commitmentRoot`] : []),
// ...(newCommitments ? [`uint256[] ${visibility} newCommitments`] : []),
// ...(encryptionRequired ? [`uint256[][] calldata cipherText`] : []),
// ...(encryptionRequired ? [`uint256[2][] calldata ephPubKeys`] : []),
...(newCommitments || newNullifiers ? [`Inputs ${visibility} inputs, uint256[] ${visibility} proof, BackupDataElement[] memory BackupData`] : []),
];
},

Expand All @@ -64,20 +64,13 @@ class FunctionBoilerplateGenerator {
encryptionRequired
}): string[] {
// prettier-ignore

let parameter = [
...(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`] : []),
...(newNullifiers ? [`uint256[]`] : []),
...(commitmentRoot ? [`uint256`] : []),
...(newCommitments ? [`uint256[]`] : []),
...(encryptionRequired ? [`uint256[][]`] : []),
...(encryptionRequired ? [`uint256[2][]`] : []),
`(uint256,uint256,uint256[],uint256,uint256[],uint256[])`,
`uint256[]`,
`(string,uint256[],uint256)[]`,
].filter(para => para !== undefined); // Added for return parameter

customInputs?.forEach((input, i) => {
if (input.isConstantArray) {
const expanded = [];
Expand All @@ -93,60 +86,65 @@ class FunctionBoilerplateGenerator {
}
if (input.structName) customInputs[i] = input.properties;
});


let msgSigCheck = ([...(isConstructor ? [] : [`bytes4 sig = bytes4(keccak256("${functionName}(${parameter})")) ; \n \t \t \t if (sig == msg.sig)`])]);

customInputs = customInputs?.flat(Infinity).filter(p => p.inCircuit);

customInputs = customInputs?.flat(Infinity).filter(p => (p.inCircuit || p.isReturn));

const addCustomInputs = !customInputs || (customInputs?.length == 1 && customInputs[0].name == '1') ? false : true;
return [
`
Inputs memory inputs;`,

...(customInputs?.length ?
// `
// Inputs memory inputs;`,
...(addCustomInputs ?
[`
inputs.customInputs = new uint[](${customInputs.flat(Infinity).length});
Inputs memory updatedInputs = inputs;
updatedInputs.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' || 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')}`]
: []),
if (input.type === 'address') return `updatedInputs.customInputs[${i}] = uint256(uint160(address(${input.name})));`;
if ((input.type === 'bool' || input.typeName?.name === 'bool' ) && !['0', '1'].includes(input.name)) return `updatedInputs.customInputs[${i}] = ${input.name} == false ? 0 : 1;`;
if (input.isCommitment) return ``;
return `updatedInputs.customInputs[${i}] = ${input.name};`;
}).join('\n')}
${msgSigCheck.join('\n')}
verify(proof, uint(FunctionNames.${functionName}), updatedInputs);`]
: [`${msgSigCheck.join('\n')}
verify(proof, uint(FunctionNames.${functionName}), inputs);`]),

...(newNullifiers ? [`
inputs.nullifierRoot = nullifierRoot; `] : []),
// ...(newNullifiers ? [`
// // inputs.nullifierRoot = nullifierRoot; `] : []),

...(newNullifiers ? [`
inputs.latestNullifierRoot = latestNullifierRoot; `] : []),
// ...(newNullifiers ? [`
// inputs.latestNullifierRoot = latestNullifierRoot; `] : []),


...(newNullifiers ? [`
inputs.newNullifiers = newNullifiers;
`] : []),
// ...(newNullifiers ? [`
// inputs.newNullifiers = newNullifiers;
// `] : []),

...(commitmentRoot ? [`
inputs.commitmentRoot = commitmentRoot;`] : []),
// ...(commitmentRoot ? [`
// inputs.commitmentRoot = commitmentRoot;`] : []),

...(newCommitments ? [`
inputs.newCommitments = newCommitments;`] : []),
// ...(newCommitments ? [`
// inputs.newCommitments = newCommitments;`] : []),

...(encryptionRequired ? [`
inputs.cipherText = cipherText;`] : []),

...(encryptionRequired ? [`
inputs.encKeys = ephPubKeys;`] : []),
`
${msgSigCheck.join('\n')}`,
`
verify(proof, uint(FunctionNames.${functionName}), inputs);`,
// ...(encryptionRequired ? [`
// inputs.cipherText = cipherText;`] : []),

// ...(encryptionRequired ? [`
// inputs.encKeys = ephPubKeys;`] : []),

...(encryptionRequired ? [`
for (uint j; j < cipherText.length; j++) {
for (uint j; j < inputs.cipherText.length; j++) {
// this seems silly (it is) but its the only way to get the event to emit properly
uint256[2] memory ephKeyToEmit = ephPubKeys[j];
uint256[] memory cipherToEmit = cipherText[j];
uint256[2] memory ephKeyToEmit = inputs.encKeys[j];
uint256[] memory cipherToEmit = inputs.cipherText[j];
emit EncryptedData(cipherToEmit, ephKeyToEmit);
}`] : []),
}`]
: []),
...(newCommitments ? [`
// this seems silly (it is) but its the only way to get the event to emit properly
emit EncryptedBackupData(BackupData);`]
: []),
];
},
};
Expand Down
Loading
Loading