commit
50eba204e3
@ -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<string>('') |
||||||
|
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 ( |
||||||
|
<div className="border-top"> |
||||||
|
<div className="card-body pt-3 pb-2"> |
||||||
|
<h6 className="card-title"> |
||||||
|
<FormattedMessage id="settings.sindriAccessTokenTitle" /> |
||||||
|
</h6> |
||||||
|
<p className="mb-1"> |
||||||
|
<FormattedMessage id="settings.sindriAccessTokenText" /> |
||||||
|
</p> |
||||||
|
<p className=""> |
||||||
|
<FormattedMessage id="settings.sindriAccessTokenText2" /> |
||||||
|
</p> |
||||||
|
<p className="mb-1"> |
||||||
|
<a className="text-primary" target="_blank" href={sindriAccessTokenLink}> |
||||||
|
{sindriAccessTokenLink} |
||||||
|
</a> |
||||||
|
</p> |
||||||
|
<div> |
||||||
|
<label className="mb-0 pb-0"> |
||||||
|
<FormattedMessage id="settings.token" />: |
||||||
|
</label> |
||||||
|
<div className="input-group text-secondary mb-0 h6"> |
||||||
|
<input id="sindriaccesstoken" data-id="settingsTabSindriAccessToken" type="password" className="form-control" onChange={(e) => handleChangeTokenState(e)} value={sindriToken} /> |
||||||
|
<div className="input-group-append"> |
||||||
|
<CopyToClipboard tip={intl.formatMessage({id: 'settings.copy'})} content={sindriToken} data-id="copyToClipboardCopyIcon" className="far fa-copy ml-1 p-2 mt-1" direction={'top'} /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<div className="text-secondary mb-0 h6"> |
||||||
|
<div className="d-flex justify-content-end pt-2"> |
||||||
|
<input className="btn btn-sm btn-primary ml-2" id="savesindritoken" data-id="settingsTabSaveSindriToken" onClick={saveSindriToken} value={intl.formatMessage({id: 'settings.save'})} type="button"></input> |
||||||
|
<CustomTooltip tooltipText={<FormattedMessage id="settings.deleteSindriCredentials" />} tooltipClasses="text-nowrap" tooltipId="removesindritokenTooltip" placement="top-start"> |
||||||
|
<button className="btn btn-sm btn-secondary ml-2" id="removesindritoken" data-id="settingsTabRemoveSindriToken" onClick={removeToken}> |
||||||
|
<FormattedMessage id="settings.remove" /> |
||||||
|
</button> |
||||||
|
</CustomTooltip> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
# Files to exclude from Sindri circuit uploads (uses `.gitignore` syntax). |
||||||
|
/.deps/ |
||||||
|
/scripts/ |
||||||
|
/templates/ |
@ -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. |
@ -0,0 +1,94 @@ |
|||||||
|
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 |
||||||
|
} |
||||||
|
|
||||||
|
export const sindriScripts = async (plugin: any) => { |
||||||
|
// 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)) { |
||||||
|
await plugin.call('fileManager', 'writeFile', path, content) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Write out all of the static files if they don't exist.
|
||||||
|
// @ts-ignore
|
||||||
|
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
|
||||||
|
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)) { |
||||||
|
// @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.
|
||||||
|
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.
|
||||||
|
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]+/, '') |
||||||
|
.toLowerCase() || `my-${sindriManifest.circuitType}-circuit` |
||||||
|
|
||||||
|
// 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') |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
import {compile} from './utils' |
||||||
|
|
||||||
|
const main = async () => { |
||||||
|
const circuit = await compile() |
||||||
|
} |
||||||
|
|
||||||
|
main() |
@ -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() |
@ -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++" |
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
import sindriClient from 'sindri' |
||||||
|
import type {CircuitInfoResponse, ProofInfoResponse} from 'sindri' |
||||||
|
|
||||||
|
sindriClient.logLevel = 'info' |
||||||
|
|
||||||
|
const authorize = async () => { |
||||||
|
try { |
||||||
|
const apiKey = await remix.call('settings', 'get', 'settings/sindri-access-token') |
||||||
|
if (!apiKey) { |
||||||
|
throw new Error('Missing API key.') |
||||||
|
} |
||||||
|
sindriClient.authorize({apiKey}) |
||||||
|
} catch { |
||||||
|
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) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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 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 (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 |
||||||
|
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 && !excludeRegex.test(path)) { |
||||||
|
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') |
||||||
|
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.
|
||||||
|
const path = normalizePath(rawPath) |
||||||
|
// 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) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
console.log(`Compiling circuit "${sindriManifest.name}"...`) |
||||||
|
const files = Object.values(filesByPath) |
||||||
|
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 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Generate a proof against the circuit. |
||||||
|
* |
||||||
|
* @param {Object} signals - Input signals for the circuit. |
||||||
|
* @returns {ProofInfoResponse} The generated proof. |
||||||
|
*/ |
||||||
|
export const prove = async (signals: {[id: string]: number | string}): ProofInfoResponse => { |
||||||
|
await authorize() |
||||||
|
const sindriManifest = await getSindriManifest() |
||||||
|
|
||||||
|
const circuitName = sindriManifest.name |
||||||
|
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 === 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) |
||||||
|
} else { |
||||||
|
console.error('Unknown error occurred.') |
||||||
|
throw error |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue