From 251bf72cafbe12bc50b98377441220f05cc4b669 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 2 Feb 2024 14:34:41 +0100 Subject: [PATCH 01/42] add sindri template --- .../src/app/tabs/locales/en/filePanel.json | 2 + .../workspace/src/lib/actions/workspace.ts | 10 +--- .../lib/components/workspace-hamburger.tsx | 14 ++++- libs/remix-ws-templates/src/index.ts | 1 + .../src/script-templates/sindri/index.ts | 15 +++++ .../src/script-templates/sindri/sindri.conf | 8 +++ .../src/script-templates/sindri/sindri.ts | 58 +++++++++++++++++++ 7 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 libs/remix-ws-templates/src/script-templates/sindri/index.ts create mode 100644 libs/remix-ws-templates/src/script-templates/sindri/sindri.conf create mode 100644 libs/remix-ws-templates/src/script-templates/sindri/sindri.ts diff --git a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json index 05fef4beab..57b7951f64 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json @@ -34,6 +34,8 @@ "filePanel.tssoltestghaction": "Mocha Chai Test Workflow", "filePanel.workspace.addscriptetherscan": "Adds scripts which can be used to interact with the Etherscan API", "filePanel.addscriptetherscan": "Add Etherscan scripts", + "filePanel.workspace.addscriptsindri": "Adds scripts for interacting with Sindri, a zk proof generation remote service", + "filePanel.addscriptsindri": "Add Sindri ZK scripts", "filePanel.workspace.addscriptdeployer": "Adds scripts which can be used to deploy contracts", "filePanel.addscriptdeployer": "Add contract deployer scripts", "filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI", diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index 98c3ef5919..fd5b09e9b0 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -42,7 +42,7 @@ import { ROOT_PATH, slitherYml, solTestYml, tsSolTestYml } from '../utils/consta import { IndexedDBStorage } from '../../../../../../apps/remix-ide/src/app/files/filesystems/indexedDB' import { getUncommittedFiles } from '../utils/gitStatusFilter' import { AppModal, ModalTypes } from '@remix-ui/app' -import { contractDeployerScripts, etherscanScripts } from '@remix-project/remix-ws-templates' +import * as templates from '@remix-project/remix-ws-templates' declare global { interface Window { @@ -869,13 +869,9 @@ export const createSlitherGithubAction = async () => { plugin.call('fileManager', 'open', path) } -const scriptsRef = { - deployer: contractDeployerScripts, - etherscan: etherscanScripts, -} export const createHelperScripts = async (script: string) => { - if (!scriptsRef[script]) return - await scriptsRef[script](plugin) + if (!templates[script]) return + await templates[script](plugin) plugin.call('notification', 'toast', 'scripts added in the "scripts" folder') } diff --git a/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx b/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx index 8960ad22c6..822490a06d 100644 --- a/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx +++ b/libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx @@ -169,7 +169,7 @@ export function HamburgerMenu(props: HamburgerMenuProps) { fa="fa-kit fa-ts-logo" hideOption={hideWorkspaceOptions || hideFileOperations} actionOnClick={() => { - props.addHelperScripts('etherscan') + props.addHelperScripts('etherscanScripts') props.hideIconsMenu(!showIconsMenu) }} platforms={[appPlatformTypes.web, appPlatformTypes.desktop]} @@ -179,7 +179,17 @@ export function HamburgerMenu(props: HamburgerMenuProps) { fa="fa-kit fa-ts-logo" hideOption={hideWorkspaceOptions || hideFileOperations} actionOnClick={() => { - props.addHelperScripts('deployer') + props.addHelperScripts('contractDeployerScripts') + props.hideIconsMenu(!showIconsMenu) + }} + platforms={[appPlatformTypes.web, appPlatformTypes.desktop]} + > + { + props.addHelperScripts('sindriScripts') props.hideIconsMenu(!showIconsMenu) }} platforms={[appPlatformTypes.web, appPlatformTypes.desktop]} diff --git a/libs/remix-ws-templates/src/index.ts b/libs/remix-ws-templates/src/index.ts index 2955f961db..e0e1a4edef 100644 --- a/libs/remix-ws-templates/src/index.ts +++ b/libs/remix-ws-templates/src/index.ts @@ -12,4 +12,5 @@ export { default as rln } from './templates/rln' export { contractDeployerScripts } from './script-templates/contract-deployer' export { etherscanScripts } from './script-templates/etherscan' +export { sindriScripts } from './script-templates/sindri' diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts new file mode 100644 index 0000000000..bcf90ca0a0 --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -0,0 +1,15 @@ +export const sindriScripts = async (plugin) => { + await plugin.call('fileManager', 'writeFile', + 'scripts/sindri/sindri.ts' , + // @ts-ignore + (await import('!!raw-loader!./sindri.ts')).default) + + + await plugin.call('fileManager', 'writeFile', + 'sindri.json' , + // @ts-ignore + (await import('raw-loader!./sindri.conf')).default) + + + await plugin.call('fileManager', 'open', 'scripts/sindri/sindri.ts') + } \ No newline at end of file diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf b/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf new file mode 100644 index 0000000000..204f4e7665 --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf @@ -0,0 +1,8 @@ +{ + "$schema": "https://forge.sindri.app/api/v1/sindri-manifest-schema.json", + "name": "circuit name", + "circuitType": "circom", + "curve": "bn254", + "provingScheme": "groth16", + "witnessCompiler": "c++" +} \ No newline at end of file diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts new file mode 100644 index 0000000000..a7dffed601 --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts @@ -0,0 +1,58 @@ +import client from 'sindri' + +/** + * Compile the given circuit + * @param {string} entryPoint - path to the circuit to compile + * @param {string} apiKey - sindri API key + * @returns {Circuit} compiled circuit + */ +export const createCircuit = async (entryPoint: string, apiKey: string) => { + client.authorize({ apiKey }) + + const sindriConf = await remix.call('fileManager', 'readFile', `sindri.json`) + const circuit = await remix.call('fileManager', 'readFile', entryPoint) + const deps = await remix.call('circuit-compiler' as any, 'resolveDependencies', entryPoint, circuit) + + const files = [] + files.push(new File([circuit], 'circuit.circom')) + files.push(new File([sindriConf], 'sindri.json')) + + for (const file in deps) { + if (file === entryPoint) continue + files.push(new File([deps[file]], file)) + } + + const circuitProject = await client.createCircuit(files) + return circuitProject +} + +/** + * Generate a proof against the given circuit + * @param {string} circuitId - id of the circuit + * @param {Object} signals - input signals + * @returns {Proof} generated proof + */ +export const proveCircuit = async (circuitId: string, signals: { [id: string]: string }, apiKey: string) => { + client.authorize({ apiKey }) + const proof = await client.proveCircuit(circuitId, JSON.stringify(signals)) + return proof +} + + +/** + * Save the circuit + * @param {Circuit} circuitProject - compiled circuit + */ +export const saveCircuit = async (circuitProject) => { + await remix.call('fileManager', 'writeFile', `.sindri/${circuitProject.circuit_id}.json`, JSON.stringify(circuitProject, null, '\t')) +} + +/** + * Load the circuit + * @param {string} circuitId - id of the circuit + * @param {Object} signals - input signals + * @returns {Proof} generated proof + */ +export const loadCircuit = async (circuitId: string) => { + return JSON.parse(await remix.call('fileManager', 'readFile', `.sindri/${circuitId}.json`)) +} \ No newline at end of file From be541ed84792ecf8b89125cba86258267e2ab0d6 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 2 Feb 2024 14:41:13 +0100 Subject: [PATCH 02/42] nr syntax in monaco editor --- apps/remix-ide/src/app/editor/editor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide/src/app/editor/editor.js b/apps/remix-ide/src/app/editor/editor.js index ef1ecaca66..045faa3c7b 100644 --- a/apps/remix-ide/src/app/editor/editor.js +++ b/apps/remix-ide/src/app/editor/editor.js @@ -52,7 +52,8 @@ class Editor extends Plugin { cairo: 'cairo', ts: 'typescript', move: 'move', - circom: 'circom' + circom: 'circom', + nr: 'rust' } this.activated = false From 2f9d502ed885992aa716f5ad4a6c4a25e20638a3 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 2 Feb 2024 15:07:35 +0100 Subject: [PATCH 03/42] Update sindri.conf --- .../src/script-templates/sindri/sindri.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf b/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf index 204f4e7665..83bbe7b463 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf @@ -1,8 +1,8 @@ { "$schema": "https://forge.sindri.app/api/v1/sindri-manifest-schema.json", - "name": "circuit name", + "name": "circuit_name", "circuitType": "circom", "curve": "bn254", "provingScheme": "groth16", "witnessCompiler": "c++" -} \ No newline at end of file +} From abf4ed7bf4e4638c1948fb133815c8f30cd26804 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 2 Feb 2024 15:11:25 +0100 Subject: [PATCH 04/42] Update sindri.ts --- .../src/script-templates/sindri/sindri.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts index a7dffed601..0f9092201d 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts @@ -21,8 +21,10 @@ export const createCircuit = async (entryPoint: string, apiKey: string) => { if (file === entryPoint) continue files.push(new File([deps[file]], file)) } - + + console.log(`creating circuit "${entryPoint}"...`) const circuitProject = await client.createCircuit(files) + console.log(`circuit created ${circuitProject.circuit_id}`) return circuitProject } @@ -34,7 +36,9 @@ export const createCircuit = async (entryPoint: string, apiKey: string) => { */ export const proveCircuit = async (circuitId: string, signals: { [id: string]: string }, apiKey: string) => { client.authorize({ apiKey }) + console.log(`proving circuit ${circuitId}...`) const proof = await client.proveCircuit(circuitId, JSON.stringify(signals)) + console.log(`proof id: ${proof.proof_id}`) return proof } @@ -55,4 +59,4 @@ export const saveCircuit = async (circuitProject) => { */ export const loadCircuit = async (circuitId: string) => { return JSON.parse(await remix.call('fileManager', 'readFile', `.sindri/${circuitId}.json`)) -} \ No newline at end of file +} From 5d06672dab153cf02879ae47a95d6def800047bd Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 5 Feb 2024 11:36:10 +0100 Subject: [PATCH 05/42] Update libs/remix-ws-templates/src/script-templates/sindri/sindri.conf Co-authored-by: Karl Preisner <107863522+KPreisner@users.noreply.github.com> --- libs/remix-ws-templates/src/script-templates/sindri/sindri.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf b/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf index 83bbe7b463..9d94755b12 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf @@ -1,5 +1,5 @@ { - "$schema": "https://forge.sindri.app/api/v1/sindri-manifest-schema.json", + "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", "name": "circuit_name", "circuitType": "circom", "curve": "bn254", From a292789acbecac3adb9f62e478493d62dce6c1de Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 5 Feb 2024 11:57:23 +0100 Subject: [PATCH 06/42] add copyFoldertoJson --- apps/remix-ide/src/app/files/fileManager.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts index 23d47cd094..b4b1a1ab9c 100644 --- a/apps/remix-ide/src/app/files/fileManager.ts +++ b/apps/remix-ide/src/app/files/fileManager.ts @@ -24,7 +24,7 @@ const profile = { methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'writeMultipleFiles', 'writeFileNoRewrite', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', - 'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory', 'hasGitSubmodule' + 'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory', 'hasGitSubmodule', 'copyFolderToJson' ], kind: 'file-system' } @@ -1041,6 +1041,14 @@ class FileManager extends Plugin { throw new Error(e) } } + + async copyFolderToJson(folder: string) { + const provider = this.currentFileProvider() + if (provider && provider.copyFolderToJson) { + return await provider.copyFolderToJson(folder) + } + throw new Error('copyFolderToJson not available') + } } module.exports = FileManager From 7a627f3fb2d0f1c9af0e6a9b3563eb3ced3c94ad Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Thu, 8 Feb 2024 13:31:28 -0600 Subject: [PATCH 07/42] Allow JSON schema fetching for `sindri.json` file validation. See: https://github.com/microsoft/monaco-editor/issues/1331 --- libs/remix-ui/editor/src/lib/remix-ui-editor.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx index 300d418360..f3fd27a798 100644 --- a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx +++ b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx @@ -858,6 +858,9 @@ export const EditorUI = (props: EditorUIProps) => { monacoRef.current.languages.register({ id: 'remix-move' }) monacoRef.current.languages.register({ id: 'remix-circom' }) + // Allow JSON schema requests + monacoRef.current.languages.json.jsonDefaults.setDiagnosticsOptions({enableSchemaRequest: true}) + // Register a tokens provider for the language monacoRef.current.languages.setMonarchTokensProvider('remix-solidity', solidityTokensProvider as any) monacoRef.current.languages.setLanguageConfiguration('remix-solidity', solidityLanguageConfig as any) From 8bb766885360c0d1bbe008d35ca61844b946b0e1 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Thu, 8 Feb 2024 14:05:26 -0600 Subject: [PATCH 08/42] Add `sindri.json` and `.sindriignore` to the Circom templates. --- .../src/templates/hashchecker/.sindriignore | 4 ++++ .../src/templates/hashchecker/index.ts | 6 +++++- .../src/templates/hashchecker/sindri.json | 9 +++++++++ libs/remix-ws-templates/src/templates/rln/.sindriignore | 4 ++++ libs/remix-ws-templates/src/templates/rln/index.ts | 6 +++++- libs/remix-ws-templates/src/templates/rln/sindri.json | 9 +++++++++ .../src/templates/semaphore/.sindriignore | 4 ++++ libs/remix-ws-templates/src/templates/semaphore/index.ts | 6 +++++- .../src/templates/semaphore/sindri.json | 9 +++++++++ 9 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 libs/remix-ws-templates/src/templates/hashchecker/.sindriignore create mode 100644 libs/remix-ws-templates/src/templates/hashchecker/sindri.json create mode 100644 libs/remix-ws-templates/src/templates/rln/.sindriignore create mode 100644 libs/remix-ws-templates/src/templates/rln/sindri.json create mode 100644 libs/remix-ws-templates/src/templates/semaphore/.sindriignore create mode 100644 libs/remix-ws-templates/src/templates/semaphore/sindri.json diff --git a/libs/remix-ws-templates/src/templates/hashchecker/.sindriignore b/libs/remix-ws-templates/src/templates/hashchecker/.sindriignore new file mode 100644 index 0000000000..382e53dfd3 --- /dev/null +++ b/libs/remix-ws-templates/src/templates/hashchecker/.sindriignore @@ -0,0 +1,4 @@ +# Files to exclude from Sindri circuit uploads (uses `.gitignore` syntax). +/.deps/ +/scripts/ +/templates/ diff --git a/libs/remix-ws-templates/src/templates/hashchecker/index.ts b/libs/remix-ws-templates/src/templates/hashchecker/index.ts index b119c6d251..223ea39df4 100644 --- a/libs/remix-ws-templates/src/templates/hashchecker/index.ts +++ b/libs/remix-ws-templates/src/templates/hashchecker/index.ts @@ -9,6 +9,10 @@ export default async () => { // @ts-ignore 'templates/groth16_verifier.sol.ejs': (await import('!!raw-loader!./templates/groth16_verifier.sol.ejs')).default, // @ts-ignore - 'README.md': (await import('raw-loader!./README.md')).default + 'README.md': (await import('raw-loader!./README.md')).default, + // @ts-ignore + '.sindriignore': (await import('raw-loader!./.sindriignore')).default, + // @ts-ignore + 'sindri.json': (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default, } } \ No newline at end of file diff --git a/libs/remix-ws-templates/src/templates/hashchecker/sindri.json b/libs/remix-ws-templates/src/templates/hashchecker/sindri.json new file mode 100644 index 0000000000..80715a6e92 --- /dev/null +++ b/libs/remix-ws-templates/src/templates/hashchecker/sindri.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", + "name": "circom-circuit", + "circuitPath": "./circuits/calculate_hash.circom", + "circuitType": "circom", + "curve": "bn254", + "provingScheme": "groth16", + "witnessCompiler": "wasm" +} diff --git a/libs/remix-ws-templates/src/templates/rln/.sindriignore b/libs/remix-ws-templates/src/templates/rln/.sindriignore new file mode 100644 index 0000000000..382e53dfd3 --- /dev/null +++ b/libs/remix-ws-templates/src/templates/rln/.sindriignore @@ -0,0 +1,4 @@ +# Files to exclude from Sindri circuit uploads (uses `.gitignore` syntax). +/.deps/ +/scripts/ +/templates/ diff --git a/libs/remix-ws-templates/src/templates/rln/index.ts b/libs/remix-ws-templates/src/templates/rln/index.ts index 92e290ccc3..a56c2844c0 100644 --- a/libs/remix-ws-templates/src/templates/rln/index.ts +++ b/libs/remix-ws-templates/src/templates/rln/index.ts @@ -17,6 +17,10 @@ export default async () => { // @ts-ignore 'LICENSE-MIT': (await import('!!raw-loader!./LICENSE-MIT')).default, // @ts-ignore - 'README.md': (await import('raw-loader!./README.md')).default + 'README.md': (await import('raw-loader!./README.md')).default, + // @ts-ignore + '.sindriignore': (await import('raw-loader!./.sindriignore')).default, + // @ts-ignore + 'sindri.json': (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default, } } \ No newline at end of file diff --git a/libs/remix-ws-templates/src/templates/rln/sindri.json b/libs/remix-ws-templates/src/templates/rln/sindri.json new file mode 100644 index 0000000000..60673ffdc6 --- /dev/null +++ b/libs/remix-ws-templates/src/templates/rln/sindri.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", + "name": "circom-circuit", + "circuitPath": "./circuits/rln.circom", + "circuitType": "circom", + "curve": "bn254", + "provingScheme": "groth16", + "witnessCompiler": "wasm" +} diff --git a/libs/remix-ws-templates/src/templates/semaphore/.sindriignore b/libs/remix-ws-templates/src/templates/semaphore/.sindriignore new file mode 100644 index 0000000000..382e53dfd3 --- /dev/null +++ b/libs/remix-ws-templates/src/templates/semaphore/.sindriignore @@ -0,0 +1,4 @@ +# Files to exclude from Sindri circuit uploads (uses `.gitignore` syntax). +/.deps/ +/scripts/ +/templates/ diff --git a/libs/remix-ws-templates/src/templates/semaphore/index.ts b/libs/remix-ws-templates/src/templates/semaphore/index.ts index 3c63bc8327..adabb9e65c 100644 --- a/libs/remix-ws-templates/src/templates/semaphore/index.ts +++ b/libs/remix-ws-templates/src/templates/semaphore/index.ts @@ -13,6 +13,10 @@ export default async () => { // @ts-ignore 'templates/groth16_verifier.sol.ejs': (await import('!!raw-loader!./templates/groth16_verifier.sol.ejs')).default, // @ts-ignore - 'README.md': (await import('raw-loader!./README.md')).default + 'README.md': (await import('raw-loader!./README.md')).default, + // @ts-ignore + '.sindriignore': (await import('raw-loader!./.sindriignore')).default, + // @ts-ignore + 'sindri.json': (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default, } } \ No newline at end of file diff --git a/libs/remix-ws-templates/src/templates/semaphore/sindri.json b/libs/remix-ws-templates/src/templates/semaphore/sindri.json new file mode 100644 index 0000000000..0372f6b6c6 --- /dev/null +++ b/libs/remix-ws-templates/src/templates/semaphore/sindri.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", + "name": "circom-circuit", + "circuitPath": "./circuits/semaphore.circom", + "circuitType": "circom", + "curve": "bn254", + "provingScheme": "groth16", + "witnessCompiler": "wasm" +} From ba45e114b4511bccfce69f627b075bf8b424c852 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Thu, 8 Feb 2024 14:18:01 -0600 Subject: [PATCH 09/42] Don't overwrite `sindri.json` if it exists. --- .../src/script-templates/sindri/index.ts | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index bcf90ca0a0..af0be38938 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -1,15 +1,23 @@ export const sindriScripts = async (plugin) => { - await plugin.call('fileManager', 'writeFile', - 'scripts/sindri/sindri.ts' , - // @ts-ignore - (await import('!!raw-loader!./sindri.ts')).default) + await plugin.call('fileManager', 'writeFile', + 'scripts/sindri/sindri.ts' , + // @ts-ignore + (await import('!!raw-loader!./sindri.ts')).default) - - await plugin.call('fileManager', 'writeFile', - 'sindri.json' , + // Only write out the `sindri.json` file if it doesn't already exist. + let sindriJsonExists: boolean + try { + await plugin.call('fileManager', 'readFile', './fake.json') + sindriJsonExists = true + } catch { + sindriJsonExists = false + } + if (!sindriJsonExists) { + await plugin.call('fileManager', 'writeFile', + 'sindri.json', // @ts-ignore (await import('raw-loader!./sindri.conf')).default) - - - await plugin.call('fileManager', 'open', 'scripts/sindri/sindri.ts') - } \ No newline at end of file + } + + await plugin.call('fileManager', 'open', 'scripts/sindri/sindri.ts') +} From 96189c185164454e7b4dbd85ee6dee0c9a327dfb Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Thu, 8 Feb 2024 14:21:25 -0600 Subject: [PATCH 10/42] Add `.sindriignore` when adding Sindri scripts. --- .../src/script-templates/sindri/.sindriignore | 4 ++++ .../src/script-templates/sindri/index.ts | 15 +++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 libs/remix-ws-templates/src/script-templates/sindri/.sindriignore diff --git a/libs/remix-ws-templates/src/script-templates/sindri/.sindriignore b/libs/remix-ws-templates/src/script-templates/sindri/.sindriignore new file mode 100644 index 0000000000..382e53dfd3 --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/.sindriignore @@ -0,0 +1,4 @@ +# Files to exclude from Sindri circuit uploads (uses `.gitignore` syntax). +/.deps/ +/scripts/ +/templates/ diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index af0be38938..dd2cdebaee 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -4,6 +4,21 @@ export const sindriScripts = async (plugin) => { // @ts-ignore (await import('!!raw-loader!./sindri.ts')).default) + // Only write out the `.sindriignore` file if it doesn't already exist. + let sindriIgnoreExists: boolean + try { + await plugin.call('fileManager', 'readFile', './.sindriignore') + sindriIgnoreExists = true + } catch { + sindriIgnoreExists = false + } + if (!sindriIgnoreExists) { + await plugin.call('fileManager', 'writeFile', + '.sindriignore', + // @ts-ignore + (await import('raw-loader!./.sindriignore')).default) + } + // Only write out the `sindri.json` file if it doesn't already exist. let sindriJsonExists: boolean try { From c8c2051bfb204cd0ccd44790f4cc95830d0f646c Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Thu, 8 Feb 2024 14:26:51 -0600 Subject: [PATCH 11/42] Rename the `sindri.json` template file and add `circuitPath`. --- .../src/script-templates/sindri/index.ts | 4 ++-- .../src/script-templates/sindri/sindri.conf | 8 -------- .../src/script-templates/sindri/sindri.json | 9 +++++++++ 3 files changed, 11 insertions(+), 10 deletions(-) delete mode 100644 libs/remix-ws-templates/src/script-templates/sindri/sindri.conf create mode 100644 libs/remix-ws-templates/src/script-templates/sindri/sindri.json diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index dd2cdebaee..b1f7764067 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -22,7 +22,7 @@ export const sindriScripts = async (plugin) => { // Only write out the `sindri.json` file if it doesn't already exist. let sindriJsonExists: boolean try { - await plugin.call('fileManager', 'readFile', './fake.json') + await plugin.call('fileManager', 'readFile', './sindri.json') sindriJsonExists = true } catch { sindriJsonExists = false @@ -31,7 +31,7 @@ export const sindriScripts = async (plugin) => { await plugin.call('fileManager', 'writeFile', 'sindri.json', // @ts-ignore - (await import('raw-loader!./sindri.conf')).default) + (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default) } await plugin.call('fileManager', 'open', 'scripts/sindri/sindri.ts') diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf b/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf deleted file mode 100644 index 9d94755b12..0000000000 --- a/libs/remix-ws-templates/src/script-templates/sindri/sindri.conf +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", - "name": "circuit_name", - "circuitType": "circom", - "curve": "bn254", - "provingScheme": "groth16", - "witnessCompiler": "c++" -} diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.json b/libs/remix-ws-templates/src/script-templates/sindri/sindri.json new file mode 100644 index 0000000000..65e277bda7 --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", + "name": "circuit_name", + "circuitPath": "./circuits/circuit.circom", + "circuitType": "circom", + "curve": "bn254", + "provingScheme": "groth16", + "witnessCompiler": "c++" +} From 2baaaa97e08551931b1e07e479e4620f34bd92ba Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Thu, 8 Feb 2024 14:31:57 -0600 Subject: [PATCH 12/42] Simplify the checking for existing files. --- .../src/script-templates/sindri/index.ts | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index b1f7764067..595560fc37 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -4,15 +4,10 @@ export const sindriScripts = async (plugin) => { // @ts-ignore (await import('!!raw-loader!./sindri.ts')).default) + const existingFiles = await plugin.call('fileManager', 'readdir', '') + // Only write out the `.sindriignore` file if it doesn't already exist. - let sindriIgnoreExists: boolean - try { - await plugin.call('fileManager', 'readFile', './.sindriignore') - sindriIgnoreExists = true - } catch { - sindriIgnoreExists = false - } - if (!sindriIgnoreExists) { + if (!('.sindriignore' in existingFiles)) { await plugin.call('fileManager', 'writeFile', '.sindriignore', // @ts-ignore @@ -20,14 +15,7 @@ export const sindriScripts = async (plugin) => { } // Only write out the `sindri.json` file if it doesn't already exist. - let sindriJsonExists: boolean - try { - await plugin.call('fileManager', 'readFile', './sindri.json') - sindriJsonExists = true - } catch { - sindriJsonExists = false - } - if (!sindriJsonExists) { + if (!('sindri.json' in existingFiles)) { await plugin.call('fileManager', 'writeFile', 'sindri.json', // @ts-ignore From 0df959cf596a919735e06557e33905e430f8505a Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Thu, 8 Feb 2024 14:33:20 -0600 Subject: [PATCH 13/42] Rename `sindri.ts` as `index.ts` to make imports cleaner. --- libs/remix-ws-templates/src/script-templates/sindri/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index 595560fc37..19e671a2f8 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -1,6 +1,6 @@ export const sindriScripts = async (plugin) => { await plugin.call('fileManager', 'writeFile', - 'scripts/sindri/sindri.ts' , + 'scripts/sindri/index.ts' , // @ts-ignore (await import('!!raw-loader!./sindri.ts')).default) From 3561b91b7bccb25dd7fe25648034af1b0ed6ec79 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 10:58:06 -0600 Subject: [PATCH 14/42] Add circuit names to the template circuits. --- libs/remix-ws-templates/src/templates/hashchecker/sindri.json | 2 +- libs/remix-ws-templates/src/templates/rln/sindri.json | 2 +- libs/remix-ws-templates/src/templates/semaphore/sindri.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/remix-ws-templates/src/templates/hashchecker/sindri.json b/libs/remix-ws-templates/src/templates/hashchecker/sindri.json index 80715a6e92..c23c7d37e7 100644 --- a/libs/remix-ws-templates/src/templates/hashchecker/sindri.json +++ b/libs/remix-ws-templates/src/templates/hashchecker/sindri.json @@ -1,6 +1,6 @@ { "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", - "name": "circom-circuit", + "name": "hashchecker", "circuitPath": "./circuits/calculate_hash.circom", "circuitType": "circom", "curve": "bn254", diff --git a/libs/remix-ws-templates/src/templates/rln/sindri.json b/libs/remix-ws-templates/src/templates/rln/sindri.json index 60673ffdc6..bf7d105b15 100644 --- a/libs/remix-ws-templates/src/templates/rln/sindri.json +++ b/libs/remix-ws-templates/src/templates/rln/sindri.json @@ -1,6 +1,6 @@ { "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", - "name": "circom-circuit", + "name": "rln", "circuitPath": "./circuits/rln.circom", "circuitType": "circom", "curve": "bn254", diff --git a/libs/remix-ws-templates/src/templates/semaphore/sindri.json b/libs/remix-ws-templates/src/templates/semaphore/sindri.json index 0372f6b6c6..b2d001ec87 100644 --- a/libs/remix-ws-templates/src/templates/semaphore/sindri.json +++ b/libs/remix-ws-templates/src/templates/semaphore/sindri.json @@ -1,6 +1,6 @@ { "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", - "name": "circom-circuit", + "name": "semaphore", "circuitPath": "./circuits/semaphore.circom", "circuitType": "circom", "curve": "bn254", From 706150825f5490b6106cef548e46f56f87224988 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 11:03:17 -0600 Subject: [PATCH 15/42] Include all workspace files when creating circuits. --- .../src/script-templates/sindri/sindri.ts | 101 ++++++++++-------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts index 0f9092201d..881699c329 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts @@ -1,62 +1,75 @@ import client from 'sindri' +const getSindriManifest = async () => { + const sindriJson = await remix.call('fileManager', 'readFile', `sindri.json`) + return JSON.parse(sindriJson) +} + +const normalizePath = (path: string): string => { + while (path.startsWith('/') || path.startsWith('./')) { + path = path.replace(/^(\.\/|\/)/, '') + } + return path +} + /** * Compile the given circuit - * @param {string} entryPoint - path to the circuit to compile * @param {string} apiKey - sindri API key * @returns {Circuit} compiled circuit */ -export const createCircuit = async (entryPoint: string, apiKey: string) => { - client.authorize({ apiKey }) - - const sindriConf = await remix.call('fileManager', 'readFile', `sindri.json`) - const circuit = await remix.call('fileManager', 'readFile', entryPoint) - const deps = await remix.call('circuit-compiler' as any, 'resolveDependencies', entryPoint, circuit) - - const files = [] - files.push(new File([circuit], 'circuit.circom')) - files.push(new File([sindriConf], 'sindri.json')) - - for (const file in deps) { - if (file === entryPoint) continue - files.push(new File([deps[file]], file)) +export const createCircuit = async (apiKey: string) => { + const sindriManifest = await getSindriManifest() + client.authorize({apiKey}) + + // Create a map from file paths to `File` objects for all files in the workspace. + const filesByPath: {[path: string]: File} = {} + interface Workspace { + children?: Workspace + content?: string + } + const workspace: Workspace = await remix.call('fileManager', 'copyFolderToJson', '/') + const childQueue: Array<[string, Workspace]> = Object.entries(workspace) + while (childQueue.length > 0) { + const [path, child] = childQueue.pop() + if ('content' in child) { + filesByPath[path] = new File([child.content], path) } + if ('children' in child) { + childQueue.push(...Object.entries(child.children)) + } + } + + // Merge any of the circuit's resolved dependencies into the files at their expected import paths. + if (sindriManifest.circuitType === 'circom') { + const circuitPath = normalizePath(sindriManifest.circuitPath || 'circuit.circom') + const circuitContent = await remix.call('fileManager', 'readFile', circuitPath) + const dependencies: {[path: string]: string} = await remix.call('circuit-compiler' as any, 'resolveDependencies', circuitPath, circuitContent) + Object.entries(dependencies).forEach(([rawPath, content]) => { + const path = normalizePath(rawPath) + filesByPath[path] = new File([content], path) + }) + } - console.log(`creating circuit "${entryPoint}"...`) - const circuitProject = await client.createCircuit(files) - console.log(`circuit created ${circuitProject.circuit_id}`) - return circuitProject + console.log(`creating circuit "${entryPoint}"...`) + const files = Object.values(filesByPath) + const circuitProject = await client.createCircuit(files) + console.log(`circuit created ${circuitProject.circuit_id}`) + return circuitProject } /** * Generate a proof against the given circuit - * @param {string} circuitId - id of the circuit * @param {Object} signals - input signals + * @param {string} apiKey - sindri API key * @returns {Proof} generated proof */ -export const proveCircuit = async (circuitId: string, signals: { [id: string]: string }, apiKey: string) => { - client.authorize({ apiKey }) - console.log(`proving circuit ${circuitId}...`) - const proof = await client.proveCircuit(circuitId, JSON.stringify(signals)) - console.log(`proof id: ${proof.proof_id}`) - return proof -} - - -/** - * Save the circuit - * @param {Circuit} circuitProject - compiled circuit - */ -export const saveCircuit = async (circuitProject) => { - await remix.call('fileManager', 'writeFile', `.sindri/${circuitProject.circuit_id}.json`, JSON.stringify(circuitProject, null, '\t')) -} +export const proveCircuit = async (signals: {[id: string]: string}, apiKey: string) => { + const sindriManifest = await getSindriManifest() + client.authorize({apiKey}) -/** - * Load the circuit - * @param {string} circuitId - id of the circuit - * @param {Object} signals - input signals - * @returns {Proof} generated proof - */ -export const loadCircuit = async (circuitId: string) => { - return JSON.parse(await remix.call('fileManager', 'readFile', `.sindri/${circuitId}.json`)) + const circuitName = sindriManifest.name + console.log(`proving circuit "${circuitName}"...`) + const proof = await client.proveCircuit(circuitName, JSON.stringify(signals)) + console.log(`proof id: ${proof.proof_id}`) + return proof } From 442fa196705fd5c086c380a65eefc679861ccbf3 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 11:44:11 -0600 Subject: [PATCH 16/42] Add Sindri credentials to the settings section. --- .../src/app/tabs/locales/en/settings.json | 3 + .../src/app/tabs/locales/es/settings.json | 3 + .../src/app/tabs/locales/fr/settings.json | 3 + .../src/app/tabs/locales/it/settings.json | 3 + .../src/app/tabs/locales/zh/settings.json | 3 + libs/remix-ui/settings/src/lib/constants.ts | 5 ++ .../settings/src/lib/remix-ui-settings.tsx | 10 +++ .../settings/src/lib/sindri-settings.tsx | 77 +++++++++++++++++++ libs/remix-ui/settings/src/types/index.ts | 13 ++++ projects.json | 8 ++ 10 files changed, 128 insertions(+) create mode 100644 libs/remix-ui/settings/src/lib/sindri-settings.tsx diff --git a/apps/remix-ide/src/app/tabs/locales/en/settings.json b/apps/remix-ide/src/app/tabs/locales/en/settings.json index b290156eec..aa8f67449c 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/en/settings.json @@ -17,6 +17,9 @@ "settings.etherscanTokenTitle": "EtherScan Access Token", "settings.etherscanAccessTokenText": "Manage the api key used to interact with Etherscan.", "settings.etherscanAccessTokenText2": "Go to Etherscan api key page (link below) to create a new api key and save it in Remix.", + "settings.sindriAccessTokenTitle": "Sindri Credentials", + "settings.sindriAccessTokenText": "The access token is used to compile ZKP circuits and generate proofs with Sindri.", + "settings.sindriAccessTokenText2":"Go to the Sindri account creation page (link below) to create a new token and save it in Remix.", "settings.save": "Save", "settings.remove": "Remove", "settings.themes": "Themes", diff --git a/apps/remix-ide/src/app/tabs/locales/es/settings.json b/apps/remix-ide/src/app/tabs/locales/es/settings.json index 899e2787cc..a3b8bfcb9c 100644 --- a/apps/remix-ide/src/app/tabs/locales/es/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/es/settings.json @@ -17,6 +17,9 @@ "settings.etherscanTokenTitle": "Token de Acceso de EtherScan", "settings.etherscanAccessTokenText": "Administra la clave api usada para interactuar con Etherscan.", "settings.etherscanAccessTokenText2": "Vaya a la página de claves api de Etherscan (enlace abajo) para crear una nueva clave api y guardarla en Remix.", + "settings.sindriAccessTokenTitle": "Credenciales de Sindri", + "settings.sindriAccessTokenText": "El token de acceso se utiliza para compilar circuitos ZKP y generar pruebas con Sindri.", + "settings.sindriAccessTokenText2":"Vaya a la página de creación de cuentas de Sindri (enlace abajo) para crear un nuevo token y guardarlo en Remix.", "settings.save": "Guardar", "settings.remove": "Eliminar", "settings.themes": "Temas", diff --git a/apps/remix-ide/src/app/tabs/locales/fr/settings.json b/apps/remix-ide/src/app/tabs/locales/fr/settings.json index 5d1859dfe9..fe5160fb16 100644 --- a/apps/remix-ide/src/app/tabs/locales/fr/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/fr/settings.json @@ -17,6 +17,9 @@ "settings.etherscanTokenTitle": "Token d'accés Etherscan", "settings.etherscanAccessTokenText": "Gérer la clé api utilisée pour interagir avec Etherscan.", "settings.etherscanAccessTokenText2": "Allez sur la page de clé Etherscan api (lien ci-dessous) pour créer une nouvelle clé api et l'enregistrer dans Remix.", + "settings.sindriAccessTokenTitle": "Identifiants Sindri", + "settings.sindriAccessTokenText": "Le jeton d'accès est utilisé pour compiler les circuits ZKP et générer des preuves avec Sindri.", + "settings.sindriAccessTokenText2":"Allez à la page de création de compte Sindri (lien ci-dessous) pour créer un nouveau jeton et l'enregistrer dans Remix.", "settings.save": "Sauvegarder", "settings.remove": "Supprimer", "settings.themes": "Thèmes", diff --git a/apps/remix-ide/src/app/tabs/locales/it/settings.json b/apps/remix-ide/src/app/tabs/locales/it/settings.json index 416f338b64..61c4c89ad3 100644 --- a/apps/remix-ide/src/app/tabs/locales/it/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/it/settings.json @@ -17,6 +17,9 @@ "settings.etherscanTokenTitle": "Token di accesso a Etherscan", "settings.etherscanAccessTokenText": "Gestione della chiave api utilizzata per interagire con Etherscan.", "settings.etherscanAccessTokenText2": "Vai alla pagina delle chiavi api di Etherscan (link in basso) per creare una nuova chiave api e salvarla in Remix.", + "settings.sindriAccessTokenTitle": "Credenziali Sindri", + "settings.sindriAccessTokenText": "Il token di accesso è utilizzato per compilare circuiti ZKP e generare prove con Sindri.", + "settings.sindriAccessTokenText2":"Vai alla pagina di creazione dell'account Sindri (link qui sotto) per creare un nuovo token e salvarlo in Remix.", "settings.save": "Salva", "settings.remove": "Rimuovi", "settings.themes": "Temi", diff --git a/apps/remix-ide/src/app/tabs/locales/zh/settings.json b/apps/remix-ide/src/app/tabs/locales/zh/settings.json index 5504874efd..3b363801c7 100644 --- a/apps/remix-ide/src/app/tabs/locales/zh/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/zh/settings.json @@ -17,6 +17,9 @@ "settings.etherscanTokenTitle": "EtherScan 访问 Token", "settings.etherscanAccessTokenText": "管理用于与Etherscan交互的api密钥.", "settings.etherscanAccessTokenText2": "前往 Etherscan api 密钥页面 (参见下方链接),创建一个新的api密钥并保存到Remix中.", + "settings.sindriAccessTokenTitle": "Sindri 凭证", + "settings.sindriAccessTokenText": "访问令牌用于使用 Sindri 编译 ZKP 电路和生成证明。", + "settings.sindriAccessTokenText2":"转到 Sindri 账户创建页面(下方链接),创建新令牌并将其保存在 Remix 中。", "settings.save": "保存", "settings.remove": "删除", "settings.themes": "主题", diff --git a/libs/remix-ui/settings/src/lib/constants.ts b/libs/remix-ui/settings/src/lib/constants.ts index 90f23a0939..453edaaf94 100644 --- a/libs/remix-ui/settings/src/lib/constants.ts +++ b/libs/remix-ui/settings/src/lib/constants.ts @@ -3,6 +3,7 @@ export const textDark = 'text-dark' export const gitAccessTokenLink = 'https://github.com/settings/tokens/new?scopes=gist,repo&description=Remix%20IDE%20Token' export const etherscanTokenLink = 'https://etherscan.io/myapikey' +export const sindriAccessTokenLink = 'https://sindri.app' export const labels = { 'gist': { 'link': gitAccessTokenLink, @@ -11,5 +12,9 @@ export const labels = { 'etherscan': { 'link': etherscanTokenLink, 'key': 'etherscan-access-token' + }, + 'sindri': { + 'link': sindriAccessTokenLink, + 'key': 'sindri-access-token' } } diff --git a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx index 34bac76242..28c6ec1f6c 100644 --- a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx +++ b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx @@ -28,6 +28,7 @@ import {RemixUiLocaleModule, LocaleModule} from '@remix-ui/locale-module' import {FormattedMessage, useIntl} from 'react-intl' import {GithubSettings} from './github-settings' import {EtherscanSettings} from './etherscan-settings' +import {SindriSettings} from './sindri-settings' /* eslint-disable-next-line */ export interface RemixUiSettingsProps { @@ -599,6 +600,15 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { }} config={props.config} /> + { + saveTokenToast(props.config, dispatchToast, sindriToken, 'sindri-access-token') + }} + removeToken={() => { + removeTokenToast(props.config, dispatchToast, 'sindri-access-token') + }} + config={props.config} + /> {swarmSettings()} {ipfsSettings()} diff --git a/libs/remix-ui/settings/src/lib/sindri-settings.tsx b/libs/remix-ui/settings/src/lib/sindri-settings.tsx new file mode 100644 index 0000000000..703f3c5ff8 --- /dev/null +++ b/libs/remix-ui/settings/src/lib/sindri-settings.tsx @@ -0,0 +1,77 @@ +import {CopyToClipboard} from '@remix-ui/clipboard' +import {CustomTooltip} from '@remix-ui/helper' +import React, {useEffect, useState} from 'react' +import {FormattedMessage, useIntl} from 'react-intl' +import {SindriSettingsProps} from '../types' +import {sindriAccessTokenLink} from './constants' + +export function SindriSettings(props: SindriSettingsProps) { + const [sindriToken, setSindriToken] = useState('') + const intl = useIntl() + + useEffect(() => { + if (props.config) { + const sindriToken = props.config.get('settings/sindri-access-token') || '' + setSindriToken(sindriToken) + } + }, [props.config]) + + const handleChangeTokenState = (event) => { + const token = event.target.value ? event.target.value.trim() : event.target.value + setSindriToken(token) + } + + // api key settings + const saveSindriToken = () => { + props.saveToken(sindriToken) + } + + const removeToken = () => { + setSindriToken('') + props.removeToken() + } + + return ( +
+
+
+ +
+

+ +

+

+ +

+

+ + {sindriAccessTokenLink} + +

+
+ +
+ handleChangeTokenState(e)} value={sindriToken} /> +
+ +
+
+
+
+
+
+ + } tooltipClasses="text-nowrap" tooltipId="removesindritokenTooltip" placement="top-start"> + + +
+
+
+
+
+ ) +} diff --git a/libs/remix-ui/settings/src/types/index.ts b/libs/remix-ui/settings/src/types/index.ts index f14027f886..3b25907d20 100644 --- a/libs/remix-ui/settings/src/types/index.ts +++ b/libs/remix-ui/settings/src/types/index.ts @@ -23,3 +23,16 @@ export interface EtherscanSettingsProps { setUnpersistedProperty: (key: string, value: string) => void } } + +export interface SindriSettingsProps { + saveToken: (sindriToken: string) => void, + removeToken: () => void, + config: { + exists: (key: string) => boolean, + get: (key: string) => string, + set: (key: string, content: string) => void, + clear: () => void, + getUnpersistedProperty: (key: string) => void, + setUnpersistedProperty: (key: string, value: string) => void + } +} diff --git a/projects.json b/projects.json index 33a1d79d2f..da979d3749 100644 --- a/projects.json +++ b/projects.json @@ -8112,6 +8112,14 @@ "npm:react-intl" ] }, + { + "file": "libs/remix-ui/settings/src/lib/sindri-settings.tsx", + "hash": "f25473fcac87f3e7aa8be1828ea446b1b261fc66", + "deps": [ + "npm:react", + "npm:react-intl" + ] + }, { "file": "libs/remix-ui/settings/src/lib/remix-ui-settings.css", "hash": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" From e7415fc638551fb085eede2def541634d5824769 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 12:12:40 -0600 Subject: [PATCH 17/42] Use the API key from settings. --- .../src/script-templates/sindri/sindri.ts | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts index 881699c329..803c052570 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts @@ -1,5 +1,19 @@ import client from 'sindri' +const authorize = async () => { + try { + const apiKey = await remix.call('settings', 'get', 'settings/sindri-access-token') + if (!apiKey) { + throw new Error('Missing API key.') + } + client.authorize({apiKey}) + } catch { + const message = 'No Sindri API key found. Please add your API key in the settings tab.' + await remix.call('notification', 'toast', message) + throw new Error(message) + } +} + const getSindriManifest = async () => { const sindriJson = await remix.call('fileManager', 'readFile', `sindri.json`) return JSON.parse(sindriJson) @@ -14,12 +28,11 @@ const normalizePath = (path: string): string => { /** * Compile the given circuit - * @param {string} apiKey - sindri API key * @returns {Circuit} compiled circuit */ -export const createCircuit = async (apiKey: string) => { +export const createCircuit = async () => { + authorize() const sindriManifest = await getSindriManifest() - client.authorize({apiKey}) // Create a map from file paths to `File` objects for all files in the workspace. const filesByPath: {[path: string]: File} = {} @@ -50,7 +63,7 @@ export const createCircuit = async (apiKey: string) => { }) } - console.log(`creating circuit "${entryPoint}"...`) + console.log(`creating circuit "${sindriManifest.name}"...`) const files = Object.values(filesByPath) const circuitProject = await client.createCircuit(files) console.log(`circuit created ${circuitProject.circuit_id}`) @@ -60,12 +73,11 @@ export const createCircuit = async (apiKey: string) => { /** * Generate a proof against the given circuit * @param {Object} signals - input signals - * @param {string} apiKey - sindri API key * @returns {Proof} generated proof */ -export const proveCircuit = async (signals: {[id: string]: string}, apiKey: string) => { +export const proveCircuit = async (signals: {[id: string]: string}) => { + authorize() const sindriManifest = await getSindriManifest() - client.authorize({apiKey}) const circuitName = sindriManifest.name console.log(`proving circuit "${circuitName}"...`) From eb556702e8f737ab90eb0c5c81466f6718dac7f5 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 12:16:09 -0600 Subject: [PATCH 18/42] Set the client log-level. --- libs/remix-ws-templates/src/script-templates/sindri/sindri.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts index 803c052570..4d5f3dcaeb 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts @@ -1,5 +1,7 @@ import client from 'sindri' +client.logLevel = 'info' + const authorize = async () => { try { const apiKey = await remix.call('settings', 'get', 'settings/sindri-access-token') From 6df1d5c686dd4432eda23e8ae9ac33974ced5af9 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 12:29:58 -0600 Subject: [PATCH 19/42] Clean up some of the documentation. --- .../src/script-templates/sindri/sindri.ts | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts index 4d5f3dcaeb..33383ca5e5 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts @@ -1,6 +1,7 @@ -import client from 'sindri' +import sindriClient from 'sindri' +import type {CircuitInfoResponse, ProofInfoResponse} from 'sindri' -client.logLevel = 'info' +sindriClient.logLevel = 'info' const authorize = async () => { try { @@ -8,7 +9,7 @@ const authorize = async () => { if (!apiKey) { throw new Error('Missing API key.') } - client.authorize({apiKey}) + sindriClient.authorize({apiKey}) } catch { const message = 'No Sindri API key found. Please add your API key in the settings tab.' await remix.call('notification', 'toast', message) @@ -29,10 +30,12 @@ const normalizePath = (path: string): string => { } /** - * Compile the given circuit - * @returns {Circuit} compiled circuit + * Compile the circuit. + * + * @param {string | string[] | null} tags - The tag or tags to use when compiling the circuit. + * @returns {CircuitInfoResponse} compiled circuit */ -export const createCircuit = async () => { +export const compile = async (tags: string | string[] | null = ['latest']): CircuitInfoResponse => { authorize() const sindriManifest = await getSindriManifest() @@ -67,23 +70,24 @@ export const createCircuit = async () => { console.log(`creating circuit "${sindriManifest.name}"...`) const files = Object.values(filesByPath) - const circuitProject = await client.createCircuit(files) + const circuitProject = await sindriClient.createCircuit(files, tags) console.log(`circuit created ${circuitProject.circuit_id}`) return circuitProject } /** - * Generate a proof against the given circuit - * @param {Object} signals - input signals - * @returns {Proof} generated proof + * Generate a proof against the circuit. + * + * @param {Object} signals - Input signals for the circuit. + * @returns {ProofInfoResponse} The generated proof. */ -export const proveCircuit = async (signals: {[id: string]: string}) => { +export const proveCircuit = async (signals: {[id: string]: string}): ProofInfoResponse => { authorize() const sindriManifest = await getSindriManifest() const circuitName = sindriManifest.name console.log(`proving circuit "${circuitName}"...`) - const proof = await client.proveCircuit(circuitName, JSON.stringify(signals)) + const proof = await sindriClient.proveCircuit(circuitName, JSON.stringify(signals)) console.log(`proof id: ${proof.proof_id}`) return proof } From b7b6d84735c0008dcd68c5368ece274007a2bb65 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 12:31:57 -0600 Subject: [PATCH 20/42] Rename `sindri.ts` to `utils.ts`. --- libs/remix-ws-templates/src/script-templates/sindri/index.ts | 4 ++-- .../src/script-templates/sindri/{sindri.ts => utils.ts} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename libs/remix-ws-templates/src/script-templates/sindri/{sindri.ts => utils.ts} (100%) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index 19e671a2f8..f4c2073f29 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -1,8 +1,8 @@ export const sindriScripts = async (plugin) => { await plugin.call('fileManager', 'writeFile', - 'scripts/sindri/index.ts' , + 'scripts/sindri/utils.ts' , // @ts-ignore - (await import('!!raw-loader!./sindri.ts')).default) + (await import('!!raw-loader!./utils.ts')).default) const existingFiles = await plugin.call('fileManager', 'readdir', '') diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts similarity index 100% rename from libs/remix-ws-templates/src/script-templates/sindri/sindri.ts rename to libs/remix-ws-templates/src/script-templates/sindri/utils.ts From 783c828d1b6023d7cb561296874607277913f6f3 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 13:23:46 -0600 Subject: [PATCH 21/42] Add basic proof/compile scripts. --- .../src/script-templates/sindri/index.ts | 10 +++++ .../script-templates/sindri/run_compile.ts | 7 ++++ .../src/script-templates/sindri/run_prove.ts | 15 ++++++++ .../src/script-templates/sindri/utils.ts | 37 ++++++++++++++----- 4 files changed, 60 insertions(+), 9 deletions(-) create mode 100644 libs/remix-ws-templates/src/script-templates/sindri/run_compile.ts create mode 100644 libs/remix-ws-templates/src/script-templates/sindri/run_prove.ts diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index f4c2073f29..e26f495589 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -4,6 +4,16 @@ export const sindriScripts = async (plugin) => { // @ts-ignore (await import('!!raw-loader!./utils.ts')).default) + await plugin.call('fileManager', 'writeFile', + 'scripts/sindri/run_compile.ts' , + // @ts-ignore + (await import('!!raw-loader!./run_compile.ts')).default) + + await plugin.call('fileManager', 'writeFile', + 'scripts/sindri/run_prove.ts' , + // @ts-ignore + (await import('!!raw-loader!./run_prove.ts')).default) + const existingFiles = await plugin.call('fileManager', 'readdir', '') // Only write out the `.sindriignore` file if it doesn't already exist. diff --git a/libs/remix-ws-templates/src/script-templates/sindri/run_compile.ts b/libs/remix-ws-templates/src/script-templates/sindri/run_compile.ts new file mode 100644 index 0000000000..40a2bb42ad --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/run_compile.ts @@ -0,0 +1,7 @@ +import {compile} from './utils' + +const main = async () => { + const circuit = await compile() +} + +main() diff --git a/libs/remix-ws-templates/src/script-templates/sindri/run_prove.ts b/libs/remix-ws-templates/src/script-templates/sindri/run_prove.ts new file mode 100644 index 0000000000..98e2ea43d7 --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/run_prove.ts @@ -0,0 +1,15 @@ +import {prove} from './utils' + +// You must modify the input signals to include the data you're trying to generate a proof for. +const signals: {[name: string]: number | string} = {} + +const main = async () => { + if (Object.keys(signals).length === 0) { + console.error("You must modify the input signals to include the data you're trying to generate a proof for.") + return + } + const proofResponse = await prove(signals) + console.log('Proof:\n', JSON.stringify(proofResponse.proof, null, 2)) +} + +main() diff --git a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts index 33383ca5e5..642582e651 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts @@ -68,11 +68,15 @@ export const compile = async (tags: string | string[] | null = ['latest']): Circ }) } - console.log(`creating circuit "${sindriManifest.name}"...`) + console.log(`Compiling circuit "${sindriManifest.name}"...`) const files = Object.values(filesByPath) - const circuitProject = await sindriClient.createCircuit(files, tags) - console.log(`circuit created ${circuitProject.circuit_id}`) - return circuitProject + const circuitResponse = await sindriClient.createCircuit(files, tags) + if (circuitResponse.status === 'Ready') { + console.log(`Circuit compiled successfully, circuit id: ${circuitResponse.circuit_id}`) + } else { + console.error('Circuit compilation failed:', circuitResponse.error || 'Unknown error') + } + return circuitResponse } /** @@ -81,13 +85,28 @@ export const compile = async (tags: string | string[] | null = ['latest']): Circ * @param {Object} signals - Input signals for the circuit. * @returns {ProofInfoResponse} The generated proof. */ -export const proveCircuit = async (signals: {[id: string]: string}): ProofInfoResponse => { +export const prove = async (signals: {[id: string]: number | string}): ProofInfoResponse => { authorize() const sindriManifest = await getSindriManifest() const circuitName = sindriManifest.name - console.log(`proving circuit "${circuitName}"...`) - const proof = await sindriClient.proveCircuit(circuitName, JSON.stringify(signals)) - console.log(`proof id: ${proof.proof_id}`) - return proof + console.log(`Proving circuit "${circuitName}"...`) + try { + const proofResponse = await sindriClient.proveCircuit(circuitName, JSON.stringify(signals)) + if (proofResponse.status === 'Ready') { + console.log(`Proof generated successfully, proof id: ${proofResponse.proof_id}`) + } else { + console.error('Proof generation failed:', proofResponse.error || 'Unknown error') + } + return proofResponse + } catch (error) { + if ('status' in error && error.status === 404) { + const message = `No compiled circuit "${circuitName}" found, have you successfully compiled the circuit?` + console.error(message) + throw new Error(message) + } else { + console.error('Unknown error occurred.') + throw error + } + } } From 0e9c722d1b9140b36fd54e58c8238d38a05d1241 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 13:35:01 -0600 Subject: [PATCH 22/42] Convert absolute imports to relative ones. --- libs/remix-ws-templates/src/script-templates/sindri/utils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts index 642582e651..13f20cbaae 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts @@ -62,8 +62,10 @@ export const compile = async (tags: string | string[] | null = ['latest']): Circ const circuitPath = normalizePath(sindriManifest.circuitPath || 'circuit.circom') const circuitContent = await remix.call('fileManager', 'readFile', circuitPath) const dependencies: {[path: string]: string} = await remix.call('circuit-compiler' as any, 'resolveDependencies', circuitPath, circuitContent) - Object.entries(dependencies).forEach(([rawPath, content]) => { + Object.entries(dependencies).forEach(([rawPath, rawContent]) => { + // Convert absolute file paths to paths relative to the project root. const path = normalizePath(rawPath) + const content = path.endsWith('.circom') ? rawContent.replace(/^\s*include\s+"\/([^"]+)"\s*;\s*$/gm, 'include "$1";') : rawContent filesByPath[path] = new File([content], path) }) } From ff29a69597db51ae0b7c22c7c18b0f295f2257fe Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 18:15:38 -0600 Subject: [PATCH 23/42] Fix the include rewriting regex. --- libs/remix-ws-templates/src/script-templates/sindri/utils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts index 13f20cbaae..1b061a9639 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts @@ -65,7 +65,8 @@ export const compile = async (tags: string | string[] | null = ['latest']): Circ Object.entries(dependencies).forEach(([rawPath, rawContent]) => { // Convert absolute file paths to paths relative to the project root. const path = normalizePath(rawPath) - const content = path.endsWith('.circom') ? rawContent.replace(/^\s*include\s+"\/([^"]+)"\s*;\s*$/gm, 'include "$1";') : rawContent + // Removes any leading `/`s from Circom `include` paths to make them relative to the root. + const content = path.endsWith('.circom') ? rawContent.replace(/^\s*include\s+"\/+([^"]+)"\s*;\s*$/gm, 'include "$1";') : rawContent filesByPath[path] = new File([content], path) }) } From 565ec34145916ec2f01892bb6f49e48219677c0a Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 18:17:33 -0600 Subject: [PATCH 24/42] Make the toast error more detailed. --- libs/remix-ws-templates/src/script-templates/sindri/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts index 1b061a9639..13d5dd7b26 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts @@ -11,7 +11,7 @@ const authorize = async () => { } sindriClient.authorize({apiKey}) } catch { - const message = 'No Sindri API key found. Please add your API key in the settings tab.' + const message = 'No Sindri API key found. Please click the gear in the lower left corner to open the settings page, and add your API key under "Sindri Credentials".' await remix.call('notification', 'toast', message) throw new Error(message) } From 0ea9417dd60aabdd8485933a6b36d17787d90cf8 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Mon, 12 Feb 2024 10:08:19 -0600 Subject: [PATCH 25/42] Improve error reporting around authorization. --- .../src/script-templates/sindri/utils.ts | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts index 13d5dd7b26..3f8245cf68 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts @@ -36,7 +36,7 @@ const normalizePath = (path: string): string => { * @returns {CircuitInfoResponse} compiled circuit */ export const compile = async (tags: string | string[] | null = ['latest']): CircuitInfoResponse => { - authorize() + await authorize() const sindriManifest = await getSindriManifest() // Create a map from file paths to `File` objects for all files in the workspace. @@ -73,13 +73,24 @@ export const compile = async (tags: string | string[] | null = ['latest']): Circ console.log(`Compiling circuit "${sindriManifest.name}"...`) const files = Object.values(filesByPath) - const circuitResponse = await sindriClient.createCircuit(files, tags) - if (circuitResponse.status === 'Ready') { - console.log(`Circuit compiled successfully, circuit id: ${circuitResponse.circuit_id}`) - } else { - console.error('Circuit compilation failed:', circuitResponse.error || 'Unknown error') + try { + const circuitResponse = await sindriClient.createCircuit(files, tags) + if (circuitResponse.status === 'Ready') { + console.log(`Circuit compiled successfully, circuit id: ${circuitResponse.circuit_id}`) + } else { + console.error('Circuit compilation failed:', circuitResponse.error || 'Unknown error') + } + return circuitResponse + } catch (error) { + if ('status' in error && error.status === 401) { + const message = 'Sindri API key authentication failed, please check that your key is correct in the settings.' + console.error(message) + throw new Error(message) + } else { + console.error('Unknown error occurred.') + throw error + } } - return circuitResponse } /** @@ -89,7 +100,7 @@ export const compile = async (tags: string | string[] | null = ['latest']): Circ * @returns {ProofInfoResponse} The generated proof. */ export const prove = async (signals: {[id: string]: number | string}): ProofInfoResponse => { - authorize() + await authorize() const sindriManifest = await getSindriManifest() const circuitName = sindriManifest.name @@ -103,7 +114,11 @@ export const prove = async (signals: {[id: string]: number | string}): ProofInfo } return proofResponse } catch (error) { - if ('status' in error && error.status === 404) { + if ('status' in error && error.status === 401) { + const message = 'Sindri API key authentication failed, please check that your key is correct in the settings.' + console.error(message) + throw new Error(message) + } else if ('status' in error && error.status === 404) { const message = `No compiled circuit "${circuitName}" found, have you successfully compiled the circuit?` console.error(message) throw new Error(message) From fd04b0a81e121fb8821abfdaeab2b646739cc93d Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Tue, 13 Feb 2024 13:47:50 -0600 Subject: [PATCH 26/42] Remove translations of the settings strings. --- apps/remix-ide/src/app/tabs/locales/es/settings.json | 3 --- apps/remix-ide/src/app/tabs/locales/fr/settings.json | 3 --- apps/remix-ide/src/app/tabs/locales/it/settings.json | 3 --- apps/remix-ide/src/app/tabs/locales/zh/settings.json | 3 --- 4 files changed, 12 deletions(-) diff --git a/apps/remix-ide/src/app/tabs/locales/es/settings.json b/apps/remix-ide/src/app/tabs/locales/es/settings.json index a3b8bfcb9c..899e2787cc 100644 --- a/apps/remix-ide/src/app/tabs/locales/es/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/es/settings.json @@ -17,9 +17,6 @@ "settings.etherscanTokenTitle": "Token de Acceso de EtherScan", "settings.etherscanAccessTokenText": "Administra la clave api usada para interactuar con Etherscan.", "settings.etherscanAccessTokenText2": "Vaya a la página de claves api de Etherscan (enlace abajo) para crear una nueva clave api y guardarla en Remix.", - "settings.sindriAccessTokenTitle": "Credenciales de Sindri", - "settings.sindriAccessTokenText": "El token de acceso se utiliza para compilar circuitos ZKP y generar pruebas con Sindri.", - "settings.sindriAccessTokenText2":"Vaya a la página de creación de cuentas de Sindri (enlace abajo) para crear un nuevo token y guardarlo en Remix.", "settings.save": "Guardar", "settings.remove": "Eliminar", "settings.themes": "Temas", diff --git a/apps/remix-ide/src/app/tabs/locales/fr/settings.json b/apps/remix-ide/src/app/tabs/locales/fr/settings.json index fe5160fb16..5d1859dfe9 100644 --- a/apps/remix-ide/src/app/tabs/locales/fr/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/fr/settings.json @@ -17,9 +17,6 @@ "settings.etherscanTokenTitle": "Token d'accés Etherscan", "settings.etherscanAccessTokenText": "Gérer la clé api utilisée pour interagir avec Etherscan.", "settings.etherscanAccessTokenText2": "Allez sur la page de clé Etherscan api (lien ci-dessous) pour créer une nouvelle clé api et l'enregistrer dans Remix.", - "settings.sindriAccessTokenTitle": "Identifiants Sindri", - "settings.sindriAccessTokenText": "Le jeton d'accès est utilisé pour compiler les circuits ZKP et générer des preuves avec Sindri.", - "settings.sindriAccessTokenText2":"Allez à la page de création de compte Sindri (lien ci-dessous) pour créer un nouveau jeton et l'enregistrer dans Remix.", "settings.save": "Sauvegarder", "settings.remove": "Supprimer", "settings.themes": "Thèmes", diff --git a/apps/remix-ide/src/app/tabs/locales/it/settings.json b/apps/remix-ide/src/app/tabs/locales/it/settings.json index 61c4c89ad3..416f338b64 100644 --- a/apps/remix-ide/src/app/tabs/locales/it/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/it/settings.json @@ -17,9 +17,6 @@ "settings.etherscanTokenTitle": "Token di accesso a Etherscan", "settings.etherscanAccessTokenText": "Gestione della chiave api utilizzata per interagire con Etherscan.", "settings.etherscanAccessTokenText2": "Vai alla pagina delle chiavi api di Etherscan (link in basso) per creare una nuova chiave api e salvarla in Remix.", - "settings.sindriAccessTokenTitle": "Credenziali Sindri", - "settings.sindriAccessTokenText": "Il token di accesso è utilizzato per compilare circuiti ZKP e generare prove con Sindri.", - "settings.sindriAccessTokenText2":"Vai alla pagina di creazione dell'account Sindri (link qui sotto) per creare un nuovo token e salvarlo in Remix.", "settings.save": "Salva", "settings.remove": "Rimuovi", "settings.themes": "Temi", diff --git a/apps/remix-ide/src/app/tabs/locales/zh/settings.json b/apps/remix-ide/src/app/tabs/locales/zh/settings.json index 3b363801c7..5504874efd 100644 --- a/apps/remix-ide/src/app/tabs/locales/zh/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/zh/settings.json @@ -17,9 +17,6 @@ "settings.etherscanTokenTitle": "EtherScan 访问 Token", "settings.etherscanAccessTokenText": "管理用于与Etherscan交互的api密钥.", "settings.etherscanAccessTokenText2": "前往 Etherscan api 密钥页面 (参见下方链接),创建一个新的api密钥并保存到Remix中.", - "settings.sindriAccessTokenTitle": "Sindri 凭证", - "settings.sindriAccessTokenText": "访问令牌用于使用 Sindri 编译 ZKP 电路和生成证明。", - "settings.sindriAccessTokenText2":"转到 Sindri 账户创建页面(下方链接),创建新令牌并将其保存在 Remix 中。", "settings.save": "保存", "settings.remove": "删除", "settings.themes": "主题", From aed1a8c0231c9a1942441f5f8614d841b2a61a2a Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 13:26:17 -0600 Subject: [PATCH 27/42] Remove `.sindriignore` from the Circom templates. --- .../src/templates/hashchecker/.sindriignore | 4 ---- libs/remix-ws-templates/src/templates/hashchecker/index.ts | 4 +--- libs/remix-ws-templates/src/templates/rln/.sindriignore | 4 ---- libs/remix-ws-templates/src/templates/rln/index.ts | 4 +--- libs/remix-ws-templates/src/templates/semaphore/.sindriignore | 4 ---- libs/remix-ws-templates/src/templates/semaphore/index.ts | 4 +--- 6 files changed, 3 insertions(+), 21 deletions(-) delete mode 100644 libs/remix-ws-templates/src/templates/hashchecker/.sindriignore delete mode 100644 libs/remix-ws-templates/src/templates/rln/.sindriignore delete mode 100644 libs/remix-ws-templates/src/templates/semaphore/.sindriignore diff --git a/libs/remix-ws-templates/src/templates/hashchecker/.sindriignore b/libs/remix-ws-templates/src/templates/hashchecker/.sindriignore deleted file mode 100644 index 382e53dfd3..0000000000 --- a/libs/remix-ws-templates/src/templates/hashchecker/.sindriignore +++ /dev/null @@ -1,4 +0,0 @@ -# Files to exclude from Sindri circuit uploads (uses `.gitignore` syntax). -/.deps/ -/scripts/ -/templates/ diff --git a/libs/remix-ws-templates/src/templates/hashchecker/index.ts b/libs/remix-ws-templates/src/templates/hashchecker/index.ts index 223ea39df4..bed5f13e7f 100644 --- a/libs/remix-ws-templates/src/templates/hashchecker/index.ts +++ b/libs/remix-ws-templates/src/templates/hashchecker/index.ts @@ -11,8 +11,6 @@ export default async () => { // @ts-ignore 'README.md': (await import('raw-loader!./README.md')).default, // @ts-ignore - '.sindriignore': (await import('raw-loader!./.sindriignore')).default, - // @ts-ignore 'sindri.json': (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default, } -} \ No newline at end of file +} diff --git a/libs/remix-ws-templates/src/templates/rln/.sindriignore b/libs/remix-ws-templates/src/templates/rln/.sindriignore deleted file mode 100644 index 382e53dfd3..0000000000 --- a/libs/remix-ws-templates/src/templates/rln/.sindriignore +++ /dev/null @@ -1,4 +0,0 @@ -# Files to exclude from Sindri circuit uploads (uses `.gitignore` syntax). -/.deps/ -/scripts/ -/templates/ diff --git a/libs/remix-ws-templates/src/templates/rln/index.ts b/libs/remix-ws-templates/src/templates/rln/index.ts index a56c2844c0..6da6c5e7f3 100644 --- a/libs/remix-ws-templates/src/templates/rln/index.ts +++ b/libs/remix-ws-templates/src/templates/rln/index.ts @@ -19,8 +19,6 @@ export default async () => { // @ts-ignore 'README.md': (await import('raw-loader!./README.md')).default, // @ts-ignore - '.sindriignore': (await import('raw-loader!./.sindriignore')).default, - // @ts-ignore 'sindri.json': (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default, } -} \ No newline at end of file +} diff --git a/libs/remix-ws-templates/src/templates/semaphore/.sindriignore b/libs/remix-ws-templates/src/templates/semaphore/.sindriignore deleted file mode 100644 index 382e53dfd3..0000000000 --- a/libs/remix-ws-templates/src/templates/semaphore/.sindriignore +++ /dev/null @@ -1,4 +0,0 @@ -# Files to exclude from Sindri circuit uploads (uses `.gitignore` syntax). -/.deps/ -/scripts/ -/templates/ diff --git a/libs/remix-ws-templates/src/templates/semaphore/index.ts b/libs/remix-ws-templates/src/templates/semaphore/index.ts index adabb9e65c..5deeec74e6 100644 --- a/libs/remix-ws-templates/src/templates/semaphore/index.ts +++ b/libs/remix-ws-templates/src/templates/semaphore/index.ts @@ -15,8 +15,6 @@ export default async () => { // @ts-ignore 'README.md': (await import('raw-loader!./README.md')).default, // @ts-ignore - '.sindriignore': (await import('raw-loader!./.sindriignore')).default, - // @ts-ignore 'sindri.json': (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default, } -} \ No newline at end of file +} From dd06e22b4bfc66045c475e6d400bf7d2babe0333 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 15:06:54 -0600 Subject: [PATCH 28/42] Remove `sindri.json` from the Circom templates. --- .../src/templates/hashchecker/index.ts | 2 -- .../src/templates/hashchecker/sindri.json | 9 --------- libs/remix-ws-templates/src/templates/rln/index.ts | 2 -- libs/remix-ws-templates/src/templates/rln/sindri.json | 9 --------- libs/remix-ws-templates/src/templates/semaphore/index.ts | 4 ---- .../src/templates/semaphore/sindri.json | 9 --------- 6 files changed, 35 deletions(-) delete mode 100644 libs/remix-ws-templates/src/templates/hashchecker/sindri.json delete mode 100644 libs/remix-ws-templates/src/templates/rln/sindri.json delete mode 100644 libs/remix-ws-templates/src/templates/semaphore/sindri.json diff --git a/libs/remix-ws-templates/src/templates/hashchecker/index.ts b/libs/remix-ws-templates/src/templates/hashchecker/index.ts index bed5f13e7f..5f7945ed8b 100644 --- a/libs/remix-ws-templates/src/templates/hashchecker/index.ts +++ b/libs/remix-ws-templates/src/templates/hashchecker/index.ts @@ -10,7 +10,5 @@ export default async () => { 'templates/groth16_verifier.sol.ejs': (await import('!!raw-loader!./templates/groth16_verifier.sol.ejs')).default, // @ts-ignore 'README.md': (await import('raw-loader!./README.md')).default, - // @ts-ignore - 'sindri.json': (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default, } } diff --git a/libs/remix-ws-templates/src/templates/hashchecker/sindri.json b/libs/remix-ws-templates/src/templates/hashchecker/sindri.json deleted file mode 100644 index c23c7d37e7..0000000000 --- a/libs/remix-ws-templates/src/templates/hashchecker/sindri.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", - "name": "hashchecker", - "circuitPath": "./circuits/calculate_hash.circom", - "circuitType": "circom", - "curve": "bn254", - "provingScheme": "groth16", - "witnessCompiler": "wasm" -} diff --git a/libs/remix-ws-templates/src/templates/rln/index.ts b/libs/remix-ws-templates/src/templates/rln/index.ts index 6da6c5e7f3..9b8d77372e 100644 --- a/libs/remix-ws-templates/src/templates/rln/index.ts +++ b/libs/remix-ws-templates/src/templates/rln/index.ts @@ -18,7 +18,5 @@ export default async () => { 'LICENSE-MIT': (await import('!!raw-loader!./LICENSE-MIT')).default, // @ts-ignore 'README.md': (await import('raw-loader!./README.md')).default, - // @ts-ignore - 'sindri.json': (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default, } } diff --git a/libs/remix-ws-templates/src/templates/rln/sindri.json b/libs/remix-ws-templates/src/templates/rln/sindri.json deleted file mode 100644 index bf7d105b15..0000000000 --- a/libs/remix-ws-templates/src/templates/rln/sindri.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", - "name": "rln", - "circuitPath": "./circuits/rln.circom", - "circuitType": "circom", - "curve": "bn254", - "provingScheme": "groth16", - "witnessCompiler": "wasm" -} diff --git a/libs/remix-ws-templates/src/templates/semaphore/index.ts b/libs/remix-ws-templates/src/templates/semaphore/index.ts index 5deeec74e6..3c8889362e 100644 --- a/libs/remix-ws-templates/src/templates/semaphore/index.ts +++ b/libs/remix-ws-templates/src/templates/semaphore/index.ts @@ -12,9 +12,5 @@ export default async () => { 'scripts/run_verification.ts': (await import('!!raw-loader!./scripts/run_verification.ts')).default, // @ts-ignore 'templates/groth16_verifier.sol.ejs': (await import('!!raw-loader!./templates/groth16_verifier.sol.ejs')).default, - // @ts-ignore - 'README.md': (await import('raw-loader!./README.md')).default, - // @ts-ignore - 'sindri.json': (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default, } } diff --git a/libs/remix-ws-templates/src/templates/semaphore/sindri.json b/libs/remix-ws-templates/src/templates/semaphore/sindri.json deleted file mode 100644 index b2d001ec87..0000000000 --- a/libs/remix-ws-templates/src/templates/semaphore/sindri.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://sindri.app/api/v1/sindri-manifest-schema.json", - "name": "semaphore", - "circuitPath": "./circuits/semaphore.circom", - "circuitType": "circom", - "curve": "bn254", - "provingScheme": "groth16", - "witnessCompiler": "wasm" -} From eb450578780efe843d1cb0ba2ff4e45a7903d7c6 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 15:20:52 -0600 Subject: [PATCH 29/42] Refactor the workspace loading into a function. --- .../src/script-templates/sindri/utils.ts | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts index 3f8245cf68..21016b6abe 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts @@ -22,24 +22,14 @@ const getSindriManifest = async () => { return JSON.parse(sindriJson) } -const normalizePath = (path: string): string => { - while (path.startsWith('/') || path.startsWith('./')) { - path = path.replace(/^(\.\/|\/)/, '') - } - return path -} - /** - * Compile the circuit. + * Create a map of file paths to `File` objects for either all or a subset of files in the workspace. * - * @param {string | string[] | null} tags - The tag or tags to use when compiling the circuit. - * @returns {CircuitInfoResponse} compiled circuit + * @param {RegExp | null} pathRegex - A regular expression to limit the included files to those + * whose paths match. If not specified, then all paths are included. + * @returns {Promise<{[path: string]: File}>} A map of file paths to `File` objects. */ -export const compile = async (tags: string | string[] | null = ['latest']): CircuitInfoResponse => { - await authorize() - const sindriManifest = await getSindriManifest() - - // Create a map from file paths to `File` objects for all files in the workspace. +export const getWorkspaceFilesByPath = async (pathRegex: RegExp | null = null): Promise<{[path: string]: File}> => { const filesByPath: {[path: string]: File} = {} interface Workspace { children?: Workspace @@ -49,13 +39,35 @@ export const compile = async (tags: string | string[] | null = ['latest']): Circ const childQueue: Array<[string, Workspace]> = Object.entries(workspace) while (childQueue.length > 0) { const [path, child] = childQueue.pop() - if ('content' in child) { + if ('content' in child && (pathRegex === null || pathRegex.test(path))) { filesByPath[path] = new File([child.content], path) } if ('children' in child) { childQueue.push(...Object.entries(child.children)) } } + return filesByPath +} + +const normalizePath = (path: string): string => { + while (path.startsWith('/') || path.startsWith('./')) { + path = path.replace(/^(\.\/|\/)/, '') + } + return path +} + +/** + * Compile the circuit. + * + * @param {string | string[] | null} tags - The tag or tags to use when compiling the circuit. + * @returns {CircuitInfoResponse} compiled circuit + */ +export const compile = async (tags: string | string[] | null = ['latest']): CircuitInfoResponse => { + await authorize() + const sindriManifest = await getSindriManifest() + + // Create a map from file paths to `File` objects for all files in the workspace. + const filesByPath = getWorkspaceFilesByPath() // Merge any of the circuit's resolved dependencies into the files at their expected import paths. if (sindriManifest.circuitType === 'circom') { From b21617250e0742bc2b82e1c3876cd677823681b2 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 15:23:12 -0600 Subject: [PATCH 30/42] Rough cut of modifying sindri.json when adding it. --- .../src/script-templates/sindri/index.ts | 109 +++++++++++++----- 1 file changed, 81 insertions(+), 28 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index e26f495589..8ffe1b1298 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -1,36 +1,89 @@ -export const sindriScripts = async (plugin) => { - await plugin.call('fileManager', 'writeFile', - 'scripts/sindri/utils.ts' , - // @ts-ignore - (await import('!!raw-loader!./utils.ts')).default) +const getWorkspaceFilesByPath = async (plugin: any, pathRegex: RegExp | null = null): Promise<{[path: string]: File}> => { + const filesByPath: {[path: string]: File} = {} + interface Workspace { + children?: Workspace + content?: string + } + const workspace: Workspace = await plugin.call('fileManager', 'copyFolderToJson', '/') + const childQueue: Array<[string, Workspace]> = Object.entries(workspace) + while (childQueue.length > 0) { + const [path, child] = childQueue.pop() + if ('content' in child && (pathRegex === null || pathRegex.test(path))) { + filesByPath[path] = new File([child.content], path) + } + if ('children' in child) { + childQueue.push(...Object.entries(child.children)) + } + } + return filesByPath +} - await plugin.call('fileManager', 'writeFile', - 'scripts/sindri/run_compile.ts' , - // @ts-ignore - (await import('!!raw-loader!./run_compile.ts')).default) +export const sindriScripts = async (plugin: any) => { + // Load in all of the Sindri or Circom-related files in the workspace. + const existingFilesByPath = await getWorkspaceFilesByPath(plugin, /sindri|\.circom$/i) + const writeIfNotExists = async (path: string, content: string) => { + if (!(path in existingFilesByPath)) { + await plugin.call('fileManager', 'writeFile', path, content) + } + } - await plugin.call('fileManager', 'writeFile', - 'scripts/sindri/run_prove.ts' , + // Write out all of the static files if they don't exist. + // @ts-ignore + await writeIfNotExists('scripts/.sindriignore', (await import('!!raw-loader!./.sindriignore')).default) + // @ts-ignore + await writeIfNotExists('scripts/sindri/utils.ts', (await import('!!raw-loader!./utils.ts')).default) + // @ts-ignore + await writeIfNotExists('scripts/sindri/run_compile.ts', (await import('!!raw-loader!./run_compile.ts')).default) + // @ts-ignore + await writeIfNotExists('scripts/sindri/run_prove.ts', (await import('!!raw-loader!./run_prove.ts')).default) + + // Only write out the `sindri.json` file if it doesn't already exist. + if (!('sindri.json' in existingFilesByPath)) { // @ts-ignore - (await import('!!raw-loader!./run_prove.ts')).default) + const sindriManifest = (await import('./sindri.json')).default - const existingFiles = await plugin.call('fileManager', 'readdir', '') + // Infer manifest properties from the existing files in the workspace. + switch (sindriManifest.circuitType) { + case 'circom': + // Try to find the best `.circom` source file to use as the main component. + // First, we limit ourselves to `.circom` files. + const circomPathsAndContents = await Promise.all( + Object.entries(existingFilesByPath) + .filter(([path]) => /\.circom$/i.test(path)) + .map(async ([path, file]) => [path, await file.text()]) + ) + // Now we apply some heuristics to find the "best" file. + const circomCircuitPath = + circomPathsAndContents + .map(([path, content]) => ({ + content, + hasMainComponent: !!/^[ \t\f]*component[ \t\f]+main[^\n\r]*;[ \t\f]*$/m.test(content), + // These files are the entrypoints to the Remix Circom templates, so we give them a boost if there are multiple main components. + isTemplateEntrypoint: !!['calculate_hash.circom', 'rln.circom', 'semaphore.circom'].includes(path.split('/').pop() ?? ''), + path, + })) + .sort((a, b) => { + if (a.hasMainComponent !== b.hasMainComponent) return +b.hasMainComponent - +a.hasMainComponent + if (a.isTemplateEntrypoint !== b.isTemplateEntrypoint) return +b.isTemplateEntrypoint - +a.isTemplateEntrypoint + return a.path.localeCompare(b.path) + }) + .map(({path}) => path)[0] || './circuit.circom' - // Only write out the `.sindriignore` file if it doesn't already exist. - if (!('.sindriignore' in existingFiles)) { - await plugin.call('fileManager', 'writeFile', - '.sindriignore', - // @ts-ignore - (await import('raw-loader!./.sindriignore')).default) - } + // Use the basename of the circuit path as the circuit name. + const circomCircuitName = + circomCircuitPath + .split('/') + .pop() + .replace(/\.circom$/i, '') || 'my-circom-circuit' + sindriManifest.name = circomCircuitName + sindriManifest.circuitPath = circomCircuitPath + break + } - // Only write out the `sindri.json` file if it doesn't already exist. - if (!('sindri.json' in existingFiles)) { - await plugin.call('fileManager', 'writeFile', - 'sindri.json', - // @ts-ignore - (await import('./sindri.json.raw!=!raw-loader!./sindri.json')).default) - } + // Remove any unsupported characters from the circuit name. + sindriManifest.name = (sindriManifest.name || '').replace(/[^-a-zA-Z0-9_]+/g, '-') - await plugin.call('fileManager', 'open', 'scripts/sindri/sindri.ts') + // Write out the modified manifest file. + writeIfNotExists('sindri.json', JSON.stringify(sindriManifest, null, 2)) + } } From bcb4cc2c47bff4db9e2f7caee082996c5af24305 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 15:28:55 -0600 Subject: [PATCH 31/42] Use the wrokspace name to determine the circuit name. --- .../src/script-templates/sindri/index.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index 8ffe1b1298..a15f1c3438 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -68,18 +68,17 @@ export const sindriScripts = async (plugin: any) => { return a.path.localeCompare(b.path) }) .map(({path}) => path)[0] || './circuit.circom' - - // Use the basename of the circuit path as the circuit name. - const circomCircuitName = - circomCircuitPath - .split('/') - .pop() - .replace(/\.circom$/i, '') || 'my-circom-circuit' - sindriManifest.name = circomCircuitName sindriManifest.circuitPath = circomCircuitPath break } + const {name: workspaceName} = await plugin.call('filePanel', 'getCurrentWorkspace') + sindriManifest.name = + workspaceName + .replace(/\s*-+\s*\d*$/, '') + .replace(/[^a-zA-Z0-9]+/g, '-') + .replace(/^[^a-zA-Z]+/, '') || `my-${sindriManifest.circuitType}-circuit` + // Remove any unsupported characters from the circuit name. sindriManifest.name = (sindriManifest.name || '').replace(/[^-a-zA-Z0-9_]+/g, '-') From d390641c8dcf964e077cb515904ed018a043a036 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 15:33:46 -0600 Subject: [PATCH 32/42] Add a note about only supporting Circom. --- libs/remix-ws-templates/src/script-templates/sindri/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index a15f1c3438..c6d0f64420 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -19,7 +19,7 @@ const getWorkspaceFilesByPath = async (plugin: any, pathRegex: RegExp | null = n } export const sindriScripts = async (plugin: any) => { - // Load in all of the Sindri or Circom-related files in the workspace. + // Load in all of the Sindri or circuit-related files in the workspace. const existingFilesByPath = await getWorkspaceFilesByPath(plugin, /sindri|\.circom$/i) const writeIfNotExists = async (path: string, content: string) => { if (!(path in existingFilesByPath)) { @@ -42,6 +42,9 @@ export const sindriScripts = async (plugin: any) => { // @ts-ignore const sindriManifest = (await import('./sindri.json')).default + // TODO: We can try to infer the circuit framework here from the project contents. + // For now, we only support Circom. + // Infer manifest properties from the existing files in the workspace. switch (sindriManifest.circuitType) { case 'circom': From 74c1c2dde718277e100ffa999f1f0a2a4aa6f749 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 15:38:41 -0600 Subject: [PATCH 33/42] Fix: missing await. --- libs/remix-ws-templates/src/script-templates/sindri/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts index 21016b6abe..99bc82dea1 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts @@ -67,7 +67,7 @@ export const compile = async (tags: string | string[] | null = ['latest']): Circ const sindriManifest = await getSindriManifest() // Create a map from file paths to `File` objects for all files in the workspace. - const filesByPath = getWorkspaceFilesByPath() + const filesByPath = await getWorkspaceFilesByPath() // Merge any of the circuit's resolved dependencies into the files at their expected import paths. if (sindriManifest.circuitType === 'circom') { From a7f0aed3337c43e9a9fc74be4f4266fb9342d988 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 15:38:49 -0600 Subject: [PATCH 34/42] Lowercase the circuit name. --- .../src/script-templates/sindri/index.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index c6d0f64420..45e323706d 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -75,15 +75,14 @@ export const sindriScripts = async (plugin: any) => { break } + // Derive the circuit name from the workspace name. const {name: workspaceName} = await plugin.call('filePanel', 'getCurrentWorkspace') sindriManifest.name = workspaceName .replace(/\s*-+\s*\d*$/, '') .replace(/[^a-zA-Z0-9]+/g, '-') - .replace(/^[^a-zA-Z]+/, '') || `my-${sindriManifest.circuitType}-circuit` - - // Remove any unsupported characters from the circuit name. - sindriManifest.name = (sindriManifest.name || '').replace(/[^-a-zA-Z0-9_]+/g, '-') + .replace(/^[^a-zA-Z]+/, '') + .toLowerCase() || `my-${sindriManifest.circuitType}-circuit` // Write out the modified manifest file. writeIfNotExists('sindri.json', JSON.stringify(sindriManifest, null, 2)) From db18dc435959196ce226435ef535a2c5e17b3057 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 16:19:08 -0600 Subject: [PATCH 35/42] Maybe fix linting. --- .../src/script-templates/sindri/index.ts | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index 45e323706d..347b6610a6 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -46,33 +46,31 @@ export const sindriScripts = async (plugin: any) => { // For now, we only support Circom. // Infer manifest properties from the existing files in the workspace. - switch (sindriManifest.circuitType) { - case 'circom': - // Try to find the best `.circom` source file to use as the main component. - // First, we limit ourselves to `.circom` files. - const circomPathsAndContents = await Promise.all( - Object.entries(existingFilesByPath) - .filter(([path]) => /\.circom$/i.test(path)) - .map(async ([path, file]) => [path, await file.text()]) - ) - // Now we apply some heuristics to find the "best" file. - const circomCircuitPath = - circomPathsAndContents - .map(([path, content]) => ({ - content, - hasMainComponent: !!/^[ \t\f]*component[ \t\f]+main[^\n\r]*;[ \t\f]*$/m.test(content), - // These files are the entrypoints to the Remix Circom templates, so we give them a boost if there are multiple main components. - isTemplateEntrypoint: !!['calculate_hash.circom', 'rln.circom', 'semaphore.circom'].includes(path.split('/').pop() ?? ''), - path, - })) - .sort((a, b) => { - if (a.hasMainComponent !== b.hasMainComponent) return +b.hasMainComponent - +a.hasMainComponent - if (a.isTemplateEntrypoint !== b.isTemplateEntrypoint) return +b.isTemplateEntrypoint - +a.isTemplateEntrypoint - return a.path.localeCompare(b.path) - }) - .map(({path}) => path)[0] || './circuit.circom' - sindriManifest.circuitPath = circomCircuitPath - break + if (sindriManifest.circuitType === 'circom') { + // Try to find the best `.circom` source file to use as the main component. + // First, we limit ourselves to `.circom` files. + const circomPathsAndContents = await Promise.all( + Object.entries(existingFilesByPath) + .filter(([path]) => /\.circom$/i.test(path)) + .map(async ([path, file]) => [path, await file.text()]) + ) + // Now we apply some heuristics to find the "best" file. + const circomCircuitPath = + circomPathsAndContents + .map(([path, content]) => ({ + content, + hasMainComponent: !!/^[ \t\f]*component[ \t\f]+main[^\n\r]*;[ \t\f]*$/m.test(content), + // These files are the entrypoints to the Remix Circom templates, so we give them a boost if there are multiple main components. + isTemplateEntrypoint: !!['calculate_hash.circom', 'rln.circom', 'semaphore.circom'].includes(path.split('/').pop() ?? ''), + path, + })) + .sort((a, b) => { + if (a.hasMainComponent !== b.hasMainComponent) return +b.hasMainComponent - +a.hasMainComponent + if (a.isTemplateEntrypoint !== b.isTemplateEntrypoint) return +b.isTemplateEntrypoint - +a.isTemplateEntrypoint + return a.path.localeCompare(b.path) + }) + .map(({path}) => path)[0] || './circuit.circom' + sindriManifest.circuitPath = circomCircuitPath } // Derive the circuit name from the workspace name. From 4edded1b4413b0d76083f816eeac2c20b3518a94 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 17:59:32 -0600 Subject: [PATCH 36/42] Manually exclude everything in `.deps` for now. --- .../src/script-templates/sindri/utils.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts index 99bc82dea1..41a7c30736 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts @@ -25,11 +25,12 @@ const getSindriManifest = async () => { /** * Create a map of file paths to `File` objects for either all or a subset of files in the workspace. * - * @param {RegExp | null} pathRegex - A regular expression to limit the included files to those + * @param {RegExp | null} includeRegex - A regular expression to limit the included files to those * whose paths match. If not specified, then all paths are included. + * @param {RegExp | null} excludeRegex - A regular expression to exclude files whose paths match. * @returns {Promise<{[path: string]: File}>} A map of file paths to `File` objects. */ -export const getWorkspaceFilesByPath = async (pathRegex: RegExp | null = null): Promise<{[path: string]: File}> => { +const getWorkspaceFilesByPath = async (includeRegex: RegExp | null = null, excludeRegex: RegExp | null = null): Promise<{[path: string]: File}> => { const filesByPath: {[path: string]: File} = {} interface Workspace { children?: Workspace @@ -39,7 +40,7 @@ export const getWorkspaceFilesByPath = async (pathRegex: RegExp | null = null): const childQueue: Array<[string, Workspace]> = Object.entries(workspace) while (childQueue.length > 0) { const [path, child] = childQueue.pop() - if ('content' in child && (pathRegex === null || pathRegex.test(path))) { + if ('content' in child && (includeRegex === null || includeRegex.test(path)) && (excludeRegex === null || !excludeRegex.test(path))) { filesByPath[path] = new File([child.content], path) } if ('children' in child) { @@ -67,7 +68,7 @@ export const compile = async (tags: string | string[] | null = ['latest']): Circ const sindriManifest = await getSindriManifest() // Create a map from file paths to `File` objects for all files in the workspace. - const filesByPath = await getWorkspaceFilesByPath() + const filesByPath = await getWorkspaceFilesByPath(null, /^\.deps\//) // Merge any of the circuit's resolved dependencies into the files at their expected import paths. if (sindriManifest.circuitType === 'circom') { From 2223442b09de658e02109a11dcbc609504bf31f7 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 18:38:03 -0600 Subject: [PATCH 37/42] Add better error handling for when `circuitPath` is set wrong. --- .../src/script-templates/sindri/utils.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts index 41a7c30736..82030a0df7 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts @@ -73,7 +73,12 @@ export const compile = async (tags: string | string[] | null = ['latest']): Circ // Merge any of the circuit's resolved dependencies into the files at their expected import paths. if (sindriManifest.circuitType === 'circom') { const circuitPath = normalizePath(sindriManifest.circuitPath || 'circuit.circom') - const circuitContent = await remix.call('fileManager', 'readFile', circuitPath) + let circuitContent: string + try { + circuitContent = await remix.call('fileManager', 'readFile', circuitPath) + } catch (error) { + console.error(`No circuit file found at "${circuitPath}", try setting "circuitPath" in "sindri.json".`) + } const dependencies: {[path: string]: string} = await remix.call('circuit-compiler' as any, 'resolveDependencies', circuitPath, circuitContent) Object.entries(dependencies).forEach(([rawPath, rawContent]) => { // Convert absolute file paths to paths relative to the project root. From 53aa914b7e454b2aca40d6170a7d772893f37993 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Wed, 14 Feb 2024 18:47:59 -0600 Subject: [PATCH 38/42] Clean up the last vestiges of changes to the circom templates. --- libs/remix-ws-templates/src/templates/hashchecker/index.ts | 4 ++-- libs/remix-ws-templates/src/templates/rln/index.ts | 4 ++-- libs/remix-ws-templates/src/templates/semaphore/index.ts | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libs/remix-ws-templates/src/templates/hashchecker/index.ts b/libs/remix-ws-templates/src/templates/hashchecker/index.ts index 5f7945ed8b..b119c6d251 100644 --- a/libs/remix-ws-templates/src/templates/hashchecker/index.ts +++ b/libs/remix-ws-templates/src/templates/hashchecker/index.ts @@ -9,6 +9,6 @@ export default async () => { // @ts-ignore 'templates/groth16_verifier.sol.ejs': (await import('!!raw-loader!./templates/groth16_verifier.sol.ejs')).default, // @ts-ignore - 'README.md': (await import('raw-loader!./README.md')).default, + 'README.md': (await import('raw-loader!./README.md')).default } -} +} \ No newline at end of file diff --git a/libs/remix-ws-templates/src/templates/rln/index.ts b/libs/remix-ws-templates/src/templates/rln/index.ts index 9b8d77372e..92e290ccc3 100644 --- a/libs/remix-ws-templates/src/templates/rln/index.ts +++ b/libs/remix-ws-templates/src/templates/rln/index.ts @@ -17,6 +17,6 @@ export default async () => { // @ts-ignore 'LICENSE-MIT': (await import('!!raw-loader!./LICENSE-MIT')).default, // @ts-ignore - 'README.md': (await import('raw-loader!./README.md')).default, + 'README.md': (await import('raw-loader!./README.md')).default } -} +} \ No newline at end of file diff --git a/libs/remix-ws-templates/src/templates/semaphore/index.ts b/libs/remix-ws-templates/src/templates/semaphore/index.ts index 3c8889362e..3c63bc8327 100644 --- a/libs/remix-ws-templates/src/templates/semaphore/index.ts +++ b/libs/remix-ws-templates/src/templates/semaphore/index.ts @@ -12,5 +12,7 @@ export default async () => { 'scripts/run_verification.ts': (await import('!!raw-loader!./scripts/run_verification.ts')).default, // @ts-ignore 'templates/groth16_verifier.sol.ejs': (await import('!!raw-loader!./templates/groth16_verifier.sol.ejs')).default, + // @ts-ignore + 'README.md': (await import('raw-loader!./README.md')).default } -} +} \ No newline at end of file From 6e41b5892727d69ea60cb1d64e6b8ea914feced3 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Thu, 15 Feb 2024 07:51:31 -0600 Subject: [PATCH 39/42] Inline getting the workspace paths. --- .../src/script-templates/sindri/utils.ts | 49 ++++++++----------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts index 82030a0df7..8905d037da 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/utils.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/utils.ts @@ -22,15 +22,28 @@ const getSindriManifest = async () => { return JSON.parse(sindriJson) } +const normalizePath = (path: string): string => { + while (path.startsWith('/') || path.startsWith('./')) { + path = path.replace(/^(\.\/|\/)/, '') + } + return path +} + /** - * Create a map of file paths to `File` objects for either all or a subset of files in the workspace. + * Compile the circuit. * - * @param {RegExp | null} includeRegex - A regular expression to limit the included files to those - * whose paths match. If not specified, then all paths are included. - * @param {RegExp | null} excludeRegex - A regular expression to exclude files whose paths match. - * @returns {Promise<{[path: string]: File}>} A map of file paths to `File` objects. + * @param {string | string[] | null} tags - The tag or tags to use when compiling the circuit. + * @returns {CircuitInfoResponse} compiled circuit */ -const getWorkspaceFilesByPath = async (includeRegex: RegExp | null = null, excludeRegex: RegExp | null = null): Promise<{[path: string]: File}> => { +export const compile = async (tags: string | string[] | null = ['latest']): CircuitInfoResponse => { + await authorize() + const sindriManifest = await getSindriManifest() + + // Create a map from file paths to `File` objects for (almost) all files in the workspace. + // We exclude `.deps/` files because these are resolved to more intuitive locations so they can + // be used by the circuit without specifying a complex import path. We'll merge the dependencies + // into the files at their expected import paths in a later step. + const excludeRegex = /^\.deps\// const filesByPath: {[path: string]: File} = {} interface Workspace { children?: Workspace @@ -40,35 +53,13 @@ const getWorkspaceFilesByPath = async (includeRegex: RegExp | null = null, exclu const childQueue: Array<[string, Workspace]> = Object.entries(workspace) while (childQueue.length > 0) { const [path, child] = childQueue.pop() - if ('content' in child && (includeRegex === null || includeRegex.test(path)) && (excludeRegex === null || !excludeRegex.test(path))) { + if ('content' in child && !excludeRegex.test(path)) { filesByPath[path] = new File([child.content], path) } if ('children' in child) { childQueue.push(...Object.entries(child.children)) } } - return filesByPath -} - -const normalizePath = (path: string): string => { - while (path.startsWith('/') || path.startsWith('./')) { - path = path.replace(/^(\.\/|\/)/, '') - } - return path -} - -/** - * Compile the circuit. - * - * @param {string | string[] | null} tags - The tag or tags to use when compiling the circuit. - * @returns {CircuitInfoResponse} compiled circuit - */ -export const compile = async (tags: string | string[] | null = ['latest']): CircuitInfoResponse => { - await authorize() - const sindriManifest = await getSindriManifest() - - // Create a map from file paths to `File` objects for all files in the workspace. - const filesByPath = await getWorkspaceFilesByPath(null, /^\.deps\//) // Merge any of the circuit's resolved dependencies into the files at their expected import paths. if (sindriManifest.circuitType === 'circom') { From 515d0eacc31dbc6a9db37a67d836bed09be41934 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Thu, 15 Feb 2024 12:22:23 -0600 Subject: [PATCH 40/42] Add a README to `sindri/scripts/`. --- .../src/script-templates/sindri/README.md | 120 ++++++++++++++++++ .../src/script-templates/sindri/index.ts | 8 +- 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 libs/remix-ws-templates/src/script-templates/sindri/README.md diff --git a/libs/remix-ws-templates/src/script-templates/sindri/README.md b/libs/remix-ws-templates/src/script-templates/sindri/README.md new file mode 100644 index 0000000000..141c7f7935 --- /dev/null +++ b/libs/remix-ws-templates/src/script-templates/sindri/README.md @@ -0,0 +1,120 @@ +# Sindri Scripts + +The `sindri/scripts/` directory contains scripts for compiling circuits and generating Zero-Knowledge Proofs remotely using [Sindri](https://sindri.app). +This README file will walk you through all of the steps necessary to compile your circuit and generate proofs. +As you read through it, you might also find it helpful to refer to external documentation: + +- [Circom 2 Documentation](https://docs.circom.io/) +- [Sindri Documentation](https://sindri.app/docs/) + +## Add the Sindri ZK Scripts + +If you're seeing this README, then you've probably already figured out this step on your own! +You can add the Sindri ZK scripts and related project files to your workspace by clicking the hamburger icon in the upper left corner of the **File Explorer** and selecting **Add Sindri ZK scripts**. +This will automatically add this README file, several TypeScript files, a `sindri.json` project manifest, and a `.sindriignore` file to your workspace. +We'll cover these files in more detail below. + +## API Key + +To interact with the Sindri API, you will first need to create a Sindri account, generate an API key, and add it to your Remix IDE settings. +This only needs to be done once, your credentials will be shared across all of your current and future workspaces once you've added your API key. + +1. Visit [The Sindri Homepage](https://sindri.app/) and request a demo to create your account. +2. Follow the instructions in the [Access Management](https://sindri.app/docs/topic-guides/access-management/#api-key-creation-and-management) documentation to generate an API key. +3. Open the **Settings** panel by clicking on the gear icon at the very bottom of the icon panel on the left side of the Remix IDE (see the [Remix IDE Settings](https://remix-ide.readthedocs.io/en/latest/settings.html) documentation if you're having trouble finding it. +4. Navigate to the **Sindri Credentials** section of the **Settings** panel, enter your Sindri API key under **Token**, and click the **Save** button. + +## Customize `sindri.json` _(Optional)_ + +A `sindri.json` file was added to the root of your workspace, and automatically customized to fit your project layout. +This file is the **Sindri Manifest** and is required for all projects deployed to Sindri. +It's also used by the [Sindri CLI](https://github.com/Sindri-Labs/sindri-js) for local circuit operations which don't require a Sindri account. + +If the automatic customization missed something, or if you'd like to make further customizations, then you'll need to edit this file yourself. +When editing `sindri.json` in the Remix IDE, you should get in-editor diagnostics and documentation about the format of the file. +You can mouse over the different properties and their values to view their documentation and any potential errors with the values. + +The fields that you're most likely to want to customize are: + +- `name` - This is a unique project identifier for your circuit. + You can think of it as being analogous to a GitHub project name or a DockerHub image name. + Every time you compile a circuit with Sindri, the compiled circuit will be associated with the project and one or more tags (`latest` by default). + We guessed this based on your workspace name, but you can change this to something else if you don't like that name. +- `circuitPath` - This defines the entrypoint for a Circom circuit (_i.e_ the `.circom` source file which contains your `main` component). + We did our best to guess this as well, but you'll need to update this manually if you refactor your circuit files or the wrong entrypoint was detected. + +## Customize `.sindriignore` _(Optional)_ + +A `.sindriignore` file was automatically added to the root of your workspace when you added the ZK scripts. +This file can be used to exclude files and directories from your circuit package when deploying it to Sindri, and it follows the [`.gitignore` Format](https://git-scm.com/docs/gitignore). +The generated file includes some sane defaults, but you can feel free to customize it as you see fit. +This is particularly useful if you want to exclude files that contain sensitive information like credentials or secret keys. +Excluding irrelevant files will also have a positive impact on the performance of compiling and generating proofs because less data needs to be transferred. + +## Compile the Circuit + +The `scripts/sindri/run_compile.ts` script can be used to compile a new version of your circuit. +To run it, you can open the script from the **File Explorer**, then either click the play button icon in the upper left corner of the editor panel or press `CTRL + SHIFT + S`. +After running it, you should see something like + +``` +Compiling circuit "multiplier2"... +Circuit compiled successfully, circuit id: f593a775-723c-4c57-8d75-196aa8c22aa0 +``` + +indicating that the circuit compiled successfully. + +By default, this newly compiled circuit will be assigned a tag of `latest` and replace any previous circuit with that tag. +If you would like to use alternative tags, you can modify the script to pass an array of tags to the `compile()` function call in the script. +We recommend starting out with the default of `latest` as you're getting started, and then moving towards tighter tag management once you're closer to productionizing your circuit. + +## Generate a Proof + +Once you've compiled your circuit, you're almost ready to use the `scripts/sindri/run_prove.ts` script to generate a proof. +You'll first need to modify this file to pass in the input signals that you would like to generate a proof for when calling `prove(signals)` (see Circom's [Signals & Variables](https://docs.circom.io/circom-language/signals/) documentation if you need a refresher on circuit signals). +Towards the top of the script, you'll see where the `signals` variable is defined. + +```typescript +const signals: {[name: string]: number | string} = {} +``` + +You'll need to modify this object to include a map from your circuit's signal names to the values you would like to generate a proof with. +If the signals aren't set correctly, then you'll get an error when you try to generate a proof, so make sure you don't skip this step. + +While the `scripts/sindri/run_prove.ts` script is open in the editor, you can click the play icon or press `CTRL + SHIFT + S` to run the script. +If proof generation is successful, you should see an output like this. + +``` +Proving circuit "multiplier2"... +Proof generated successfully, proof id: 8c457574-99cd-4042-a598-0514ee83ea28 +Proof: +{ + "pi_a": [ + "6067132175610399619979395342154926888794311761598436094198046058376456187483", + "12601521866404307402196517712981356634013036480344794909770435164414221099781", + "1" + ], + "pi_b": [ + [ + "4834637265002576910303922443793957462767968914058257618737938706178679757759", + "9112483377654285712375849001111771826297690938023943203596780715231459796539" + ], + [ + "10769047435756102293620257834720404252539733306406452142820929656229947907912", + "13357635314682194333795190402038393873064494630028726306217246944693858036728" + ], + [ + "1", + "0" + ] + ], + "pi_c": [ + "14880777940364750676687351211095959384403767617776048892575602333362895582325", + "16991336882479219442414889002846661737157620156103416755440340170710340617407", + "1" + ], + "protocol": "groth16" +} +``` + +You can either manually copy the proof to wherever you would like to use it, or modify the script to save it to a dedicated location. diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index 347b6610a6..229f92098b 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -31,11 +31,13 @@ export const sindriScripts = async (plugin: any) => { // @ts-ignore await writeIfNotExists('scripts/.sindriignore', (await import('!!raw-loader!./.sindriignore')).default) // @ts-ignore - await writeIfNotExists('scripts/sindri/utils.ts', (await import('!!raw-loader!./utils.ts')).default) + await writeIfNotExists('scripts/sindri/README.md', (await import('!!raw-loader!./README.md')).default) // @ts-ignore await writeIfNotExists('scripts/sindri/run_compile.ts', (await import('!!raw-loader!./run_compile.ts')).default) // @ts-ignore await writeIfNotExists('scripts/sindri/run_prove.ts', (await import('!!raw-loader!./run_prove.ts')).default) + // @ts-ignore + await writeIfNotExists('scripts/sindri/utils.ts', (await import('!!raw-loader!./utils.ts')).default) // Only write out the `sindri.json` file if it doesn't already exist. if (!('sindri.json' in existingFilesByPath)) { @@ -85,4 +87,8 @@ export const sindriScripts = async (plugin: any) => { // Write out the modified manifest file. writeIfNotExists('sindri.json', JSON.stringify(sindriManifest, null, 2)) } + + // Open the README file in the editor. + await plugin.call('doc-viewer' as any, 'viewDocs', ["scripts/sindri/README.md"]) + plugin.call('tabs' as any, 'focus', 'doc-viewer') } From c096aa444e5ed30867254b07f41b76b7e065139e Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Fri, 16 Feb 2024 10:07:00 -0600 Subject: [PATCH 41/42] Fix `.sindriignore` file location. --- libs/remix-ws-templates/src/script-templates/sindri/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/index.ts b/libs/remix-ws-templates/src/script-templates/sindri/index.ts index 229f92098b..fdc58bfad1 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/index.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/index.ts @@ -29,7 +29,7 @@ export const sindriScripts = async (plugin: any) => { // Write out all of the static files if they don't exist. // @ts-ignore - await writeIfNotExists('scripts/.sindriignore', (await import('!!raw-loader!./.sindriignore')).default) + await writeIfNotExists('.sindriignore', (await import('!!raw-loader!./.sindriignore')).default) // @ts-ignore await writeIfNotExists('scripts/sindri/README.md', (await import('!!raw-loader!./README.md')).default) // @ts-ignore From 60a8e5714946f1adb333a36743222241d8a21c32 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 26 Feb 2024 18:25:00 +0100 Subject: [PATCH 42/42] Update workspace.ts --- libs/remix-ui/workspace/src/lib/actions/workspace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index fd5b09e9b0..047975301d 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -872,7 +872,7 @@ export const createSlitherGithubAction = async () => { export const createHelperScripts = async (script: string) => { if (!templates[script]) return await templates[script](plugin) - plugin.call('notification', 'toast', 'scripts added in the "scripts" folder') + plugin.call('notification', 'toast', `'${script}' added to the workspace.`) } export const updateGitSubmodules = async () => {