Merge branch 'master' into github_fe

pull/4979/head
Aniket 3 months ago committed by GitHub
commit d9e6c92560
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .circleci/config.yml
  2. 31
      apps/circuit-compiler/src/app/actions/index.ts
  3. 2
      apps/circuit-compiler/src/app/components/container.tsx
  4. 25
      apps/circuit-compiler/src/app/components/witness.tsx
  5. 7
      apps/circuit-compiler/src/app/reducers/state.ts
  6. 7
      apps/circuit-compiler/src/app/services/circomPluginClient.ts
  7. 2
      apps/circuit-compiler/src/app/types/index.ts
  8. 1
      apps/remix-ide/src/app/tabs/locales/en/circuit.json
  9. 5
      libs/remix-ui/workspace/src/lib/actions/workspace.ts

@ -398,7 +398,7 @@ jobs:
tests-passed:
machine:
image: ubuntu-2004:202010-01
image: default
steps:
- run: echo done

@ -3,7 +3,6 @@ import type { CircomPluginClient } from "../services/circomPluginClient"
import { ActionPayloadTypes, AppState, ICircuitAppContext } from "../types"
import { GROTH16_VERIFIER, PLONK_VERIFIER } from './constant'
import { extractNameFromKey, extractParentFromKey } from '@remix-ui/helper'
import { ethers } from 'ethers'
export const compileCircuit = async (plugin: CircomPluginClient, appState: AppState) => {
try {
@ -19,12 +18,21 @@ export const compileCircuit = async (plugin: CircomPluginClient, appState: AppSt
}
}
export const computeWitness = async (plugin: CircomPluginClient, status: string, witnessValues: Record<string, string>) => {
export const computeWitness = async (plugin: CircomPluginClient, appState: AppState, dispatch: ICircuitAppContext['dispatch'], status: string, witnessValues: Record<string, string>) => {
try {
if (status !== "computing") {
const input = JSON.stringify(witnessValues)
const witness = await plugin.computeWitness(input)
await plugin.computeWitness(input)
if (appState.exportWtnsJson) {
const wtns = await snarkjs.wtns.exportJson(witness)
const wtnsJson = wtns.map(wtn => wtn.toString())
const fileName = extractNameFromKey(appState.filePath)
const writePath = extractParentFromKey(appState.filePath) + `/.bin/${fileName.replace('.circom', '.wtn.json')}`
await plugin.call('fileManager', 'writeFile', writePath, JSON.stringify(wtnsJson, null, 2))
plugin._paq.push(['trackEvent', 'circuit-compiler', 'computeWitness', 'wtns.exportJson', writePath])
}
} else {
console.log('Existing witness computation in progress')
}
@ -38,6 +46,8 @@ export const computeWitness = async (plugin: CircomPluginClient, status: string,
export const runSetupAndExport = async (plugin: CircomPluginClient, appState: AppState, dispatch: ICircuitAppContext['dispatch']) => {
try {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'exporting' })
dispatch({ type: 'SET_SETUP_EXPORT_FEEDBACK', payload: null })
plugin.emit('statusChanged', { key: 'none' })
const ptau_final = `https://ipfs-cluster.ethdevops.io/ipfs/${appState.ptauList.find(ptau => ptau.name === appState.ptauValue)?.ipfsHash}`
await plugin.generateR1cs(appState.filePath, { version: appState.version, prime: appState.primeValue })
@ -50,32 +60,38 @@ export const runSetupAndExport = async (plugin: CircomPluginClient, appState: Ap
const zkey_final = { type: "mem" }
if (appState.provingScheme === 'groth16') {
plugin._paq.push(['trackEvent', 'circuit-compiler', 'runSetupAndExport', 'provingScheme', 'groth16'])
await snarkjs.zKey.newZKey(r1cs, ptau_final, zkey_final, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK'))
const vKey = await snarkjs.zKey.exportVerificationKey(zkey_final, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK'))
if (appState.exportVerificationKey) {
await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/keys/verification_key.json`, JSON.stringify(vKey, null, 2))
plugin._paq.push(['trackEvent', 'circuit-compiler', 'runSetupAndExport', 'zKey.exportVerificationKey', `${extractParentFromKey(appState.filePath)}/groth16/zk/keys/verification_key.json`])
}
if (appState.exportVerificationContract) {
const templates = { groth16: GROTH16_VERIFIER }
const solidityContract = await snarkjs.zKey.exportSolidityVerifier(zkey_final, templates, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK'))
await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/build/zk_verifier.sol`, solidityContract)
plugin._paq.push(['trackEvent', 'circuit-compiler', 'runSetupAndExport', 'zKey.exportSolidityVerifier', `${extractParentFromKey(appState.filePath)}/groth16/zk/build/zk_verifier.sol`])
}
dispatch({ type: 'SET_ZKEY', payload: zkey_final })
dispatch({ type: 'SET_VERIFICATION_KEY', payload: vKey })
} else if (appState.provingScheme === 'plonk') {
plugin._paq.push(['trackEvent', 'circuit-compiler', 'runSetupAndExport', 'provingScheme', 'plonk'])
await snarkjs.plonk.setup(r1cs, ptau_final, zkey_final, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK'))
const vKey = await snarkjs.zKey.exportVerificationKey(zkey_final, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK'))
if (appState.exportVerificationKey) {
await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/keys/verification_key.json`, JSON.stringify(vKey, null, 2))
plugin._paq.push(['trackEvent', 'circuit-compiler', 'runSetupAndExport', 'zKey.exportVerificationKey', `${extractParentFromKey(appState.filePath)}/plonk/zk/keys/verification_key.json`])
}
if (appState.exportVerificationContract) {
const templates = { plonk: PLONK_VERIFIER }
const solidityContract = await snarkjs.zKey.exportSolidityVerifier(zkey_final, templates, zkLogger(plugin, dispatch, 'SET_SETUP_EXPORT_FEEDBACK'))
await plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/build/zk_verifier.sol`, solidityContract)
plugin._paq.push(['trackEvent', 'circuit-compiler', 'runSetupAndExport', 'zKey.exportSolidityVerifier', `${extractParentFromKey(appState.filePath)}/plonk/zk/build/zk_verifier.sol`])
}
dispatch({ type: 'SET_ZKEY', payload: zkey_final })
dispatch({ type: 'SET_VERIFICATION_KEY', payload: vKey })
@ -83,6 +99,7 @@ export const runSetupAndExport = async (plugin: CircomPluginClient, appState: Ap
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })
dispatch({ type: 'SET_SETUP_EXPORT_STATUS', payload: 'done' })
} catch (e) {
plugin._paq.push(['trackEvent', 'circuit-compiler', 'runSetupAndExport', 'error', e.message])
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' })
console.error(e)
}
@ -91,6 +108,8 @@ export const runSetupAndExport = async (plugin: CircomPluginClient, appState: Ap
export const generateProof = async (plugin: CircomPluginClient, appState: AppState, dispatch: ICircuitAppContext['dispatch']) => {
try {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'proving' })
dispatch({ type: 'SET_PROOF_FEEDBACK', payload: null })
plugin.emit('statusChanged', { key: 'none' })
const fileName = extractNameFromKey(appState.filePath)
const r1csPath = extractParentFromKey(appState.filePath) + `/.bin/${fileName.replace('.circom', '.r1cs')}`
// @ts-ignore
@ -110,21 +129,27 @@ export const generateProof = async (plugin: CircomPluginClient, appState: AppSta
const { proof, publicSignals } = await snarkjs.groth16.prove(zkey_final, wtns, zkLogger(plugin, dispatch, 'SET_PROOF_FEEDBACK'))
const verified = await snarkjs.groth16.verify(vKey, publicSignals, proof, zkLogger(plugin, dispatch, 'SET_PROOF_FEEDBACK'))
plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/build/proof.json`, JSON.stringify(proof, null, 2))
plugin.call('terminal', 'log', { type: 'log', value: 'zk proof validity ' + verified })
plugin._paq.push(['trackEvent', 'circuit-compiler', 'generateProof', 'groth16.prove', verified])
if (appState.exportVerifierCalldata) {
const calldata = await snarkjs.groth16.exportSolidityCallData(proof, publicSignals)
plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/groth16/zk/build/verifierCalldata.json`, calldata)
plugin._paq.push(['trackEvent', 'circuit-compiler', 'generateProof', 'groth16.exportSolidityCallData', `${extractParentFromKey(appState.filePath)}/groth16/zk/build/verifierCalldata.json`])
}
} else if (appState.provingScheme === 'plonk') {
const { proof, publicSignals } = await snarkjs.plonk.prove(zkey_final, wtns, zkLogger(plugin, dispatch, 'SET_PROOF_FEEDBACK'))
const verified = await snarkjs.plonk.verify(vKey, publicSignals, proof, zkLogger(plugin, dispatch, 'SET_PROOF_FEEDBACK'))
plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/build/proof.json`, JSON.stringify(proof, null, 2))
plugin.call('terminal', 'log', { type: 'log', value: 'zk proof validity ' + verified })
plugin._paq.push(['trackEvent', 'circuit-compiler', 'generateProof', 'plonk.prove', verified])
if (appState.exportVerifierCalldata) {
const calldata = await snarkjs.plonk.exportSolidityCallData(proof, publicSignals)
plugin.call('fileManager', 'writeFile', `${extractParentFromKey(appState.filePath)}/plonk/zk/build/verifierCalldata.json`, calldata)
plugin._paq.push(['trackEvent', 'circuit-compiler', 'generateProof', 'plonk.exportSolidityCallData', `${extractParentFromKey(appState.filePath)}/plonk/zk/build/verifierCalldata.json`])
}
}
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })

@ -140,7 +140,7 @@ export function Container () {
<RenderIf condition={circuitApp.appState.signalInputs.length > 0}>
<Toggler title='circuit.computeWitness' dataId='witness_toggler' show={!!circuitApp.appState.setupExportStatus}>
<>
<WitnessSection plugin={circuitApp.plugin} signalInputs={circuitApp.appState.signalInputs} status={circuitApp.appState.status} />
<WitnessSection />
<RenderIf condition={circuitApp.appState.status !== 'computing'}>
<CompilerFeedback feedback={circuitApp.appState.computeFeedback} filePathToId={circuitApp.appState.filePathToId} openErrorLocation={handleOpenErrorLocation} hideWarnings={circuitApp.appState.hideWarnings} askGPT={askGPT} />
</RenderIf>

@ -1,12 +1,14 @@
import { RenderIf, RenderIfNot } from "@remix-ui/helper";
import { FormattedMessage } from "react-intl";
import { CompilerStatus } from "../types";
import { computeWitness } from "../actions";
import { useState } from "react";
import type { CircomPluginClient } from "../services/circomPluginClient";
import { useContext, useState } from "react";
import * as remixLib from '@remix-project/remix-lib'
import { CircuitAppContext } from "../contexts";
export function WitnessSection ({ plugin, signalInputs, status }: {plugin: CircomPluginClient, signalInputs: string[], status: CompilerStatus}) {
export function WitnessSection () {
const circuitApp = useContext(CircuitAppContext)
const { signalInputs, status, exportWtnsJson } = circuitApp.appState
const { plugin, dispatch, appState } = circuitApp
const [witnessValues, setWitnessValues] = useState<Record<string, string>>({})
const handleSignalInput = (e: any) => {
@ -47,9 +49,22 @@ export function WitnessSection ({ plugin, signalInputs, status }: {plugin: Circo
</div>
))
}
<div className="custom-control custom-checkbox">
<input
className="custom-control-input"
type="checkbox"
title="Export Witness As JSON"
id="circuitExportWtnsJson"
onChange={() => { dispatch({ type: 'SET_EXPORT_WTNS_JSON', payload: !exportWtnsJson }) }}
checked={exportWtnsJson}
/>
<label className="form-check-label custom-control-label pt-1" htmlFor="circuitExportWtnsJson">
<FormattedMessage id="circuit.exportWtnsJson" />
</label>
</div>
<button
className="btn btn-secondary btn-block d-block w-100 text-break mb-1 mt-1"
onClick={() => { computeWitness(plugin, status, witnessValues) }}
onClick={() => { computeWitness(plugin, appState, dispatch, status, witnessValues) }}
disabled={(status === "compiling") || (status === "computing")}
data-id="compute_witness_btn"
>

@ -23,6 +23,7 @@ export const appInitialState: AppState = {
exportVerificationContract: true,
exportVerificationKey: true,
exportVerifierCalldata: true,
exportWtnsJson: false,
verificationKey: null,
zKey: null
}
@ -138,6 +139,12 @@ export const appReducer = (state = appInitialState, action: Actions): AppState =
setupExportStatus: action.payload
}
case 'SET_EXPORT_WTNS_JSON':
return {
...state,
exportWtnsJson: action.payload
}
case 'SET_VERIFICATION_KEY':
return {
...state,

@ -20,7 +20,7 @@ export class CircomPluginClient extends PluginClient {
private lastParsedFiles: Record<string, string> = {}
private lastCompiledFile: string = ''
private compiler: typeof compilerV215 & typeof compilerV216 & typeof compilerV217 & typeof compilerV218
private _paq = {
public _paq = {
push: (args) => {
this.call('matomo' as any, 'track', args)
}
@ -237,7 +237,7 @@ export class CircomPluginClient extends PluginClient {
}
}
async computeWitness (input: string): Promise<void> {
async computeWitness (input: string): Promise<Uint8Array> {
this.internalEvents.emit('circuit_computing_witness_start')
this.emit('statusChanged', { key: 'loading', title: 'Computing...', type: 'info' })
const wasmPath = this.lastCompiledCircuitPath
@ -249,9 +249,10 @@ export class CircomPluginClient extends PluginClient {
const witness = this.compiler ? await this.compiler.generate_witness(dataRead, input) : await generate_witness(dataRead, input)
// @ts-ignore
await this.call('fileManager', 'writeFile', wasmPath.replace('.wasm', '.wtn'), witness, true)
this._paq.push(['trackEvent', 'circuit-compiler', 'computeWitness', 'Witness computing successful'])
this._paq.push(['trackEvent', 'circuit-compiler', 'computeWitness', 'compiler.generate_witness', wasmPath.replace('.wasm', '.wtn')])
this.internalEvents.emit('circuit_computing_witness_done')
this.emit('statusChanged', { key: 'succeed', title: 'witness computed successfully', type: 'success' })
return witness
}
async resolveDependencies(filePath: string, fileContent: string, output?: Record<string, string>, depPath: string = '', blackPath: string[] = []): Promise<Record<string, string>> {

@ -39,6 +39,7 @@ export interface ActionPayloadTypes {
SET_EXPORT_VERIFICATION_CONTRACT: boolean,
SET_EXPORT_VERIFICATION_KEY: boolean,
SET_EXPORT_VERIFIER_CALLDATA: boolean,
SET_EXPORT_WTNS_JSON: boolean,
SET_SETUP_EXPORT_STATUS: SetupExportStatus,
SET_VERIFICATION_KEY: Record<string, any>,
SET_ZKEY: any
@ -71,6 +72,7 @@ export interface AppState {
exportVerificationContract: boolean,
exportVerificationKey: boolean,
exportVerifierCalldata: boolean,
exportWtnsJson: boolean,
verificationKey: Record<string, any>,
zKey: Uint8Array
}

@ -21,5 +21,6 @@
"circuit.exportVerifierContract": "Export verifier contract",
"circuit.exportVerificationKey": "Export verification key",
"circuit.exportVerifierCalldata": "Export verifier calldata",
"circuit.exportWtnsJson": "Export witness as JSON",
"circuit.runSetup": "Run setup"
}

@ -272,6 +272,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
let content
if (params.code) {
_paq.push(['trackEvent', 'workspace', 'template', 'code-template-code-param'])
const hashed = bytesToHex(hash.keccakFromString(params.code))
path = 'contract-' + hashed.replace('0x', '').substring(0, 10) + (params.language && params.language.toLowerCase() === 'yul' ? '.yul' : '.sol')
@ -279,6 +280,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
await workspaceProvider.set(path, content)
}
if (params.shareCode) {
_paq.push(['trackEvent', 'workspace', 'template', 'code-template-shareCode-param'])
const host = '127.0.0.1'
const port = 5001
const protocol = 'http'
@ -303,6 +305,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
await workspaceProvider.set(path, content)
}
if (params.url) {
_paq.push(['trackEvent', 'workspace', 'template', 'code-template-url-param'])
const data = await plugin.call('contentImport', 'resolve', params.url)
path = data.cleanUrl
content = data.content
@ -326,6 +329,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
}
if (params.ghfolder) {
try {
_paq.push(['trackEvent', 'workspace', 'template', 'code-template-ghfolder-param'])
const files = await plugin.call('contentImport', 'resolveGithubFolder', params.ghfolder)
for (const [path, content] of Object.entries(files)) {
await workspaceProvider.set(path, content)
@ -344,6 +348,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
case 'gist-template':
// creates a new workspace gist-sample and get the file from gist
try {
_paq.push(['trackEvent', 'workspace', 'template', 'gist-template'])
const gistId = params.gist
const response: AxiosResponse = await axios.get(`https://api.github.com/gists/${gistId}`)
const data = response.data as { files: any }

Loading…
Cancel
Save