Merge pull request #4144 from ethereum/circuit-compiler

Circuit compiler UI
pull/4129/head
David Disu 1 year ago committed by GitHub
commit 50d745de2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      apps/circuit-compiler/project.json
  2. 43
      apps/circuit-compiler/src/app/actions/index.ts
  3. 138
      apps/circuit-compiler/src/app/app.tsx
  4. 11
      apps/circuit-compiler/src/app/components/actions.tsx
  5. 51
      apps/circuit-compiler/src/app/components/compileBtn.tsx
  6. 36
      apps/circuit-compiler/src/app/components/configToggler.tsx
  7. 38
      apps/circuit-compiler/src/app/components/configurations.tsx
  8. 81
      apps/circuit-compiler/src/app/components/container.tsx
  9. 60
      apps/circuit-compiler/src/app/components/feedback.tsx
  10. 31
      apps/circuit-compiler/src/app/components/feedbackAlert.tsx
  11. 36
      apps/circuit-compiler/src/app/components/options.tsx
  12. 43
      apps/circuit-compiler/src/app/components/r1csBtn.tsx
  13. 26
      apps/circuit-compiler/src/app/components/versions.tsx
  14. 50
      apps/circuit-compiler/src/app/components/witness.tsx
  15. 36
      apps/circuit-compiler/src/app/components/witnessToggler.tsx
  16. 4
      apps/circuit-compiler/src/app/contexts/index.ts
  17. 77
      apps/circuit-compiler/src/app/reducers/state.ts
  18. 325
      apps/circuit-compiler/src/app/services/circomPluginClient.ts
  19. 87
      apps/circuit-compiler/src/app/types/index.ts
  20. 88
      apps/circuit-compiler/src/css/app.css
  21. 27
      apps/circuit-compiler/src/example/hash.circom
  22. 2
      apps/circuit-compiler/src/example/simple.circom
  23. 8
      apps/circuit-compiler/src/index.html
  24. 8
      apps/circuit-compiler/src/profile.json
  25. 9
      apps/circuit-compiler/src/snarkjs.min.js
  26. 22
      apps/remix-ide/src/app/files/fileManager.ts
  27. 10
      apps/remix-ide/src/app/files/fileProvider.js
  28. 15
      apps/remix-ide/src/app/tabs/locales/en/circuit.json
  29. 2
      apps/remix-ide/src/app/tabs/locales/en/index.js
  30. 15
      apps/remix-ide/src/app/tabs/locales/es/circuit.json
  31. 15
      apps/remix-ide/src/app/tabs/locales/fr/circuit.json
  32. 16
      apps/remix-ide/src/app/tabs/locales/zh/circuit.json
  33. 2
      apps/remix-ide/src/app/tabs/locales/zh/index.js
  34. BIN
      apps/remix-ide/src/assets/img/circom-icon-bw-800b.webp
  35. BIN
      apps/remix-ide/src/assets/img/circom.webp
  36. 3
      apps/remix-ide/src/remixAppManager.js
  37. 2
      libs/remix-ui/helper/src/lib/remix-ui-helper.ts
  38. 5
      libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx
  39. 3
      package.json
  40. 0
      pkg/index.js
  41. 253
      yarn.lock

@ -3,7 +3,7 @@
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/circuit-compiler/src",
"projectType": "application",
"implicitDependencies": ["remixd"],
"implicitDependencies": [],
"targets": {
"build": {
"executor": "@nrwl/webpack:webpack",
@ -17,7 +17,7 @@
"main": "apps/circuit-compiler/src/main.tsx",
"polyfills": "apps/circuit-compiler/src/polyfills.ts",
"tsConfig": "apps/circuit-compiler/tsconfig.app.json",
"assets": ["apps/circuit-compiler/src/profile.json"],
"assets": ["apps/circuit-compiler/src/profile.json", "apps/circuit-compiler/src/snarkjs.min.js"],
"styles": ["apps/circuit-compiler/src/css/app.css"],
"scripts": [],
"webpackConfig": "apps/circuit-compiler/webpack.config.js"

@ -0,0 +1,43 @@
import type { CircomPluginClient } from "../services/circomPluginClient"
import { Actions, AppState } from "../types"
export const compileCircuit = async (plugin: CircomPluginClient, appState: AppState) => {
try {
if (appState.status !== "compiling") {
await plugin.compile(appState.filePath, { version: appState.version, prime: appState.primeValue })
} else {
console.log('Exisiting circuit compilation in progress')
}
} catch (e) {
plugin.internalEvents.emit('circuit_compiling_errored', e)
console.error(e)
}
}
export const generateR1cs = async (plugin: CircomPluginClient, appState: AppState) => {
try {
if (appState.status !== "generating") {
await plugin.generateR1cs(appState.filePath, { version: appState.version, prime: appState.primeValue })
} else {
console.log('Exisiting r1cs generation in progress')
}
} catch (e) {
plugin.internalEvents.emit('circuit_generating_r1cs_errored', e)
console.error('Generating R1CS failed: ', e)
}
}
export const computeWitness = async (plugin: CircomPluginClient, status: string, witnessValues: Record<string, string>) => {
try {
if (status !== "computing") {
const input = JSON.stringify(witnessValues)
await plugin.computeWitness(input)
} else {
console.log('Exisiting witness computation in progress')
}
} catch (e) {
plugin.internalEvents.emit('circuit_computing_witness_errored', e)
console.error('Computing witness failed: ', e)
}
}

@ -1,17 +1,143 @@
import React, { useEffect } from 'react'
import React, {useEffect, useReducer, useState} from 'react'
import {RenderIf} from '@remix-ui/helper'
import {IntlProvider} from 'react-intl'
import { CircomPluginClient } from './services/circomPluginClient'
import { Container } from './components/container'
import {CircuitAppContext} from './contexts'
import {appInitialState, appReducer} from './reducers/state'
import {CircomPluginClient} from './services/circomPluginClient'
import { compileCircuit } from './actions'
const plugin = new CircomPluginClient()
function App() {
const [appState, dispatch] = useReducer(appReducer, appInitialState)
const [locale, setLocale] = useState<{code: string; messages: any}>({
code: 'en',
messages: null
})
const [isContentChanged, setIsContentChanged] = useState<boolean>(false)
const [isPluginActivated, setIsPluginActivated] = useState<boolean>(false)
useEffect(() => {
new CircomPluginClient()
plugin.internalEvents.on('circom_activated', () => {
// @ts-ignore
plugin.on('locale', 'localeChanged', (locale: any) => {
setLocale(locale)
})
plugin.on('fileManager', 'currentFileChanged', (filePath) => {
if (filePath.endsWith('.circom')) {
dispatch({ type: 'SET_FILE_PATH', payload: filePath })
plugin.parse(filePath)
} else {
dispatch({ type: 'SET_FILE_PATH', payload: '' })
}
})
// @ts-ignore
plugin.on('editor', 'contentChanged', async (path: string, content: string) => {
setIsContentChanged(true)
if (path.endsWith('.circom')) {
plugin.parse(path, content)
}
})
setIsPluginActivated(true)
})
// compiling events
plugin.internalEvents.on('circuit_compiling_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'compiling' }))
plugin.internalEvents.on('circuit_compiling_done', (signalInputs: string[]) => {
signalInputs = (signalInputs || []).filter(input => input)
dispatch({ type: 'SET_SIGNAL_INPUTS', payload: signalInputs })
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })
})
plugin.internalEvents.on('circuit_compiling_errored', compilerErrored)
// r1cs events
plugin.internalEvents.on('circuit_generating_r1cs_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'generating' }))
plugin.internalEvents.on('circuit_generating_r1cs_done', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' }))
plugin.internalEvents.on('circuit_generating_r1cs_errored', compilerErrored)
// witness events
plugin.internalEvents.on('circuit_computing_witness_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'computing' }))
plugin.internalEvents.on('circuit_computing_witness_done', () => {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: null })
})
plugin.internalEvents.on('circuit_computing_witness_errored', compilerErrored)
// parsing events
plugin.internalEvents.on('circuit_parsing_done', (_, filePathToId) => {
dispatch({ type: 'SET_FILE_PATH_TO_ID', payload: filePathToId })
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: null })
})
plugin.internalEvents.on('circuit_parsing_errored', (report) => {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' })
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: report })
})
plugin.internalEvents.on('circuit_parsing_warning', (report) => {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'warning' })
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: report })
})
}, [])
useEffect(() => {
if (isContentChanged) {
(async () => {
if (appState.autoCompile) await compileCircuit(plugin, appState)
})()
setIsContentChanged(false)
}
}, [appState.autoCompile, isContentChanged])
useEffect(() => {
if (isPluginActivated) {
setCurrentLocale()
}
}, [isPluginActivated])
useEffect(() => {
if (appState.filePath) {
(async () => {
if (appState.autoCompile) await compileCircuit(plugin, appState)
})()
}
}, [appState.filePath])
const setCurrentLocale = async () => {
// @ts-ignore
const currentLocale = await plugin.call('locale', 'currentLocale')
setLocale(currentLocale)
}
const compilerErrored = (err: ErrorEvent) => {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' })
try {
const report = JSON.parse(err.message)
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: report })
} catch (e) {
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: err.message })
}
}
const value = {
appState,
dispatch,
plugin
}
return (
<div className="App">
<div className="circuit_compiler_app">
<RenderIf condition={locale.messages}>
<IntlProvider locale={locale.code} messages={locale.messages}>
<CircuitAppContext.Provider value={value}>
<Container />
</CircuitAppContext.Provider>
</IntlProvider>
</RenderIf>
</div>
)
}
export default App
export default App

@ -0,0 +1,11 @@
import { CompileBtn } from "./compileBtn";
import { R1CSBtn } from "./r1csBtn";
export function CircuitActions () {
return (
<div className="pb-3">
<CompileBtn />
<R1CSBtn />
</div>
)
}

@ -0,0 +1,51 @@
import { CustomTooltip, RenderIf, RenderIfNot, extractNameFromKey } from "@remix-ui/helper";
import { useContext } from "react";
import { CircuitAppContext } from "../contexts";
import { FormattedMessage } from "react-intl";
import { compileCircuit } from "../actions";
export function CompileBtn () {
const { plugin, appState } = useContext(CircuitAppContext)
return (
<button
className="btn btn-primary btn-block d-block w-100 text-break mb-1 mt-3"
onClick={() => { compileCircuit(plugin, appState) }}
disabled={(appState.filePath === "") || (appState.status === "compiling") || (appState.status === "generating")}
>
<CustomTooltip
placement="auto"
tooltipId="overlay-tooltip-compile"
tooltipText={
<div className="text-left">
<div>
<b>Ctrl+S</b> to compile {appState.filePath}
</div>
</div>
}
>
<div className="d-flex align-items-center justify-content-center">
<RenderIf condition={appState.status === 'compiling'}>
<i className="fas fa-sync fa-spin mr-2" aria-hidden="true"></i>
</RenderIf>
<RenderIfNot condition={appState.status === 'compiling'}>
<i className="fas fa-sync mr-2" aria-hidden="true"></i>
</RenderIfNot>
<div className="text-truncate overflow-hidden text-nowrap">
<span>
<FormattedMessage id="circuit.compile" />
</span>
<span className="ml-1 text-nowrap">
<RenderIf condition={appState.filePath === ""}>
<FormattedMessage id="circuit.noFileSelected" />
</RenderIf>
<RenderIfNot condition={appState.filePath === ""}>
<>{extractNameFromKey(appState.filePath)}</>
</RenderIfNot>
</span>
</div>
</div>
</CustomTooltip>
</button>
)
}

@ -0,0 +1,36 @@
import { useState } from "react"
import { FormattedMessage } from "react-intl"
import { RenderIf, RenderIfNot } from "@remix-ui/helper"
export function ConfigToggler ({ children }: { children: JSX.Element }) {
const [toggleExpander, setToggleExpander] = useState<boolean>(false)
const toggleConfigurations = () => {
setToggleExpander(!toggleExpander)
}
return (
<div>
<div className="d-flex circuit_config_section justify-content-between" onClick={toggleConfigurations}>
<div className="d-flex">
<label className="mt-1 circuit_config_section">
<FormattedMessage id="circuit.advancedConfigurations" />
</label>
</div>
<div>
<span data-id="scConfigExpander" onClick={toggleConfigurations}>
<RenderIf condition={toggleExpander}>
<i className="fas fa-angle-down" aria-hidden="true"></i>
</RenderIf>
<RenderIfNot condition={toggleExpander}>
<i className="fas fa-angle-right" aria-hidden="true"></i>
</RenderIfNot>
</span>
</div>
</div>
<RenderIf condition={toggleExpander}>
{ children }
</RenderIf>
</div>
)
}

@ -0,0 +1,38 @@
import { CustomTooltip } from "@remix-ui/helper"
import { FormattedMessage } from "react-intl"
import { ConfigurationsProps, PrimeValue } from "../types"
export function Configurations ({primeValue, setPrimeValue}: ConfigurationsProps) {
return (
<div className="pb-2 border-bottom flex-column">
<div className="flex-column d-flex">
<div className="mb-2 ml-0">
<label className="circuit_inner_label form-check-label" htmlFor="circuitPrimeSelector">
<FormattedMessage id="circuit.prime" />
</label>
<CustomTooltip
placement={"auto"}
tooltipId="circuitPrimeLabelTooltip"
tooltipClasses="text-nowrap"
tooltipText={<span>{'To choose the prime number to use to generate the circuit. Receives the name of the curve (bn128, bls12381, goldilocks) [default: bn128]'}</span>}
>
<div>
<select
onChange={(e) => setPrimeValue(e.target.value as PrimeValue)}
value={primeValue}
className="custom-select"
style={{
pointerEvents: 'auto'
}}
>
<option value="bn128">bn128</option>
<option value="bls12381">bls12381</option>
<option value="goldilocks">goldilocks</option>
</select>
</div>
</CustomTooltip>
</div>
</div>
</div>
)
}

@ -0,0 +1,81 @@
import { useContext } from 'react'
import { CustomTooltip, RenderIf } from '@remix-ui/helper'
import {FormattedMessage} from 'react-intl'
import { CircuitAppContext } from '../contexts'
import { CompileOptions } from './options'
import { VersionList } from './versions'
import { ConfigToggler } from './configToggler'
import { Configurations } from './configurations'
import { CircuitActions } from './actions'
import { WitnessToggler } from './witnessToggler'
import { WitnessSection } from './witness'
import { CompilerFeedback } from './feedback'
import { PrimeValue } from '../types'
export function Container () {
const circuitApp = useContext(CircuitAppContext)
const showCompilerLicense = (message = 'License not available') => {
// @ts-ignore
circuitApp.plugin.call('notification', 'modal', { id: 'modal_circuit_compiler_license', title: 'Compiler License', message })
}
const handleVersionSelect = (version: string) => {
circuitApp.dispatch({ type: 'SET_COMPILER_VERSION', payload: version })
}
const handleOpenErrorLocation = async (location: string, startRange: string) => {
if (location) {
const fullPathLocation = await circuitApp.plugin.resolveReportPath(location)
await circuitApp.plugin.call('fileManager', 'open', fullPathLocation)
// @ts-ignore
const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange)
// @ts-ignore
await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column)
}
}
const handlePrimeChange = (value: string) => {
circuitApp.dispatch({ type: 'SET_PRIME_VALUE', payload: value as PrimeValue })
}
const handleCircuitAutoCompile = (value: boolean) => {
circuitApp.dispatch({ type: 'SET_AUTO_COMPILE', payload: value })
}
const handleCircuitHideWarnings = (value: boolean) => {
circuitApp.dispatch({ type: 'SET_HIDE_WARNINGS', payload: value })
}
return (
<section>
<article>
<div className="pt-0 circuit_section">
<div className="mb-1">
<label className="circuit_label form-check-label" htmlFor="versionSelector">
<FormattedMessage id="circuit.compiler" />
</label>
<CustomTooltip placement="top" tooltipId="showCompilerTooltip" tooltipClasses="text-nowrap" tooltipText={'See compiler license'}>
<span className="fa fa-file-text-o border-0 p-0 ml-2" onClick={() => showCompilerLicense()}></span>
</CustomTooltip>
<VersionList setVersion={handleVersionSelect} versionList={circuitApp.appState.versionList} currentVersion={circuitApp.appState.version} />
<CompileOptions setCircuitAutoCompile={handleCircuitAutoCompile} setCircuitHideWarnings={handleCircuitHideWarnings} autoCompile={circuitApp.appState.autoCompile} hideWarnings={circuitApp.appState.hideWarnings} />
<ConfigToggler>
<Configurations setPrimeValue={handlePrimeChange} primeValue={circuitApp.appState.primeValue} />
</ConfigToggler>
<CircuitActions />
<RenderIf condition={circuitApp.appState.signalInputs.length > 0}>
<WitnessToggler>
<WitnessSection plugin={circuitApp.plugin} signalInputs={circuitApp.appState.signalInputs} status={circuitApp.appState.status} />
</WitnessToggler>
</RenderIf>
<RenderIf condition={circuitApp.appState.status !== 'compiling' && circuitApp.appState.status !== 'computing' && circuitApp.appState.status !== 'generating'}>
<CompilerFeedback feedback={circuitApp.appState.feedback} filePathToId={circuitApp.appState.filePathToId} openErrorLocation={handleOpenErrorLocation} hideWarnings={circuitApp.appState.hideWarnings} />
</RenderIf>
</div>
</div>
</article>
</section>
)
}

@ -0,0 +1,60 @@
import { useState } from 'react'
import { CompilerFeedbackProps, CompilerReport } from '../types'
import { RenderIf } from '@remix-ui/helper'
import {CopyToClipboard} from '@remix-ui/clipboard'
import { FeedbackAlert } from './feedbackAlert'
export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openErrorLocation }: CompilerFeedbackProps) {
const [ showException, setShowException ] = useState<boolean>(true)
const handleCloseException = () => {
setShowException(false)
}
const handleOpenError = (report: CompilerReport) => {
if (report.labels.length > 0) {
openErrorLocation(filePathToId[report.labels[0].file_id], report.labels[0].range.start)
}
}
return (
<div>
<div className="circuit_errors_box py-4">
<RenderIf condition={ (typeof feedback === "string") && showException }>
<div className="circuit_feedback error alert alert-danger">
<span> { feedback } </span>
<div className="close" data-id="renderer" onClick={handleCloseException}>
<i className="fas fa-times"></i>
</div>
<div className="d-flex pt-1 flex-row-reverse">
<span className="ml-3 pt-1 py-1" >
<CopyToClipboard content={feedback} className="p-0 m-0 far fa-copy error" direction={'top'} />
</span>
</div>
</div>
</RenderIf>
<RenderIf condition={ Array.isArray(feedback) }>
<>
{
Array.isArray(feedback) && feedback.map((response, index) => (
<div key={index} onClick={() => handleOpenError(response)}>
<RenderIf condition={response.type === 'Error'}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-danger`}>
<FeedbackAlert message={response.message} location={ response.labels[0] ? response.labels[0].message + ` ${filePathToId[response.labels[0].file_id]}:${response.labels[0].range.start}:${response.labels[0].range.end}` : null} />
</div>
</RenderIf>
<RenderIf condition={(response.type === 'Warning') && !hideWarnings}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-warning`}>
<FeedbackAlert message={response.message} location={null} />
</div>
</RenderIf>
</div>
)
)
}
</>
</RenderIf>
</div>
</div>
)
}

@ -0,0 +1,31 @@
import { useState } from 'react'
import { FeedbackAlertProps } from '../types'
import { RenderIf } from '@remix-ui/helper'
import {CopyToClipboard} from '@remix-ui/clipboard'
export function FeedbackAlert ({ message, location }: FeedbackAlertProps) {
const [ showAlert, setShowAlert] = useState<boolean>(true)
const handleCloseAlert = () => {
setShowAlert(false)
}
return (
<RenderIf condition={showAlert}>
<>
<span> { message } </span>
<RenderIf condition={location !== null}>
<span> { location }</span>
</RenderIf>
<div className="close" data-id="renderer" onClick={handleCloseAlert}>
<i className="fas fa-times"></i>
</div>
<div className="d-flex pt-1 flex-row-reverse">
<span className="ml-3 pt-1 py-1" >
<CopyToClipboard content={message} className="p-0 m-0 far fa-copy error" direction={'top'} />
</span>
</div>
</>
</RenderIf>
)
}

@ -0,0 +1,36 @@
import {FormattedMessage} from 'react-intl'
import { CompileOptionsProps } from '../types'
export function CompileOptions ({autoCompile, hideWarnings, setCircuitAutoCompile, setCircuitHideWarnings}: CompileOptionsProps) {
return (
<div className='pb-2'>
<div className="mt-2 custom-control custom-checkbox">
<input
className="custom-control-input"
type="checkbox"
onChange={(e) => setCircuitAutoCompile(e.target.checked)}
title="Auto compile"
checked={autoCompile}
id="autoCompileCircuit"
/>
<label className="form-check-label custom-control-label" htmlFor="autoCompileCircuit">
<FormattedMessage id="circuit.autoCompile" />
</label>
</div>
<div className="mt-1 mb-2 circuit_warnings_box custom-control custom-checkbox">
<input
className="custom-control-input"
onChange={(e) => setCircuitHideWarnings(e.target.checked)}
id="hideCircuitWarnings"
type="checkbox"
title="Hide warnings"
checked={hideWarnings}
/>
<label className="form-check-label custom-control-label" htmlFor="hideCircuitWarnings">
<FormattedMessage id="solidity.hideWarnings" />
</label>
</div>
</div>
)
}

@ -0,0 +1,43 @@
import { CustomTooltip, RenderIf, RenderIfNot } from "@remix-ui/helper";
import { useContext } from "react";
import { CircuitAppContext } from "../contexts";
import { FormattedMessage } from "react-intl";
import { generateR1cs } from "../actions";
export function R1CSBtn () {
const { plugin, appState } = useContext(CircuitAppContext)
return (
<button
className="btn btn-secondary btn-block d-block w-100 text-break mb-1 mt-2"
onClick={() => { generateR1cs(plugin, appState) }}
disabled={(appState.filePath === "") || (appState.status === "compiling") || (appState.status === "generating") || (appState.status === "computing")}
>
<CustomTooltip
placement="auto"
tooltipId="overlay-tooltip-compile"
tooltipText={
<div className="text-left">
<div>
Outputs the constraints in r1cs format
</div>
</div>
}
>
<div className="d-flex align-items-center justify-content-center">
<RenderIf condition={appState.status === 'generating'}>
<i className="fas fa-sync fa-spin mr-2" aria-hidden="true"></i>
</RenderIf>
<RenderIfNot condition={appState.status === 'generating'}>
<i className="fas fa-sync mr-2" aria-hidden="true"></i>
</RenderIfNot>
<div className="text-truncate overflow-hidden text-nowrap">
<span>
<FormattedMessage id="circuit.generateR1cs" />
</span>
</div>
</div>
</CustomTooltip>
</button>
)
}

@ -0,0 +1,26 @@
import { RenderIf } from "@remix-ui/helper";
import { AppState } from "../types";
export function VersionList ({ currentVersion, versionList, setVersion }: { versionList: AppState['versionList'], currentVersion: string, setVersion: (version: string) => void }) {
const versionListKeys = Object.keys(versionList)
return (
<select
value={currentVersion}
onChange={(e) => setVersion(e.target.value)}
className="custom-select"
>
<RenderIf condition={versionListKeys.length > 0}>
<>
{
versionListKeys.map((version, index) => (
<option value={version} key={index}>
{ versionList[version].name }
</option>
))
}
</>
</RenderIf>
</select>
)
}

@ -0,0 +1,50 @@
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";
export function WitnessSection ({ plugin, signalInputs, status }: {plugin: CircomPluginClient, signalInputs: string[], status: CompilerStatus}) {
const [witnessValues, setWitnessValues] = useState<Record<string, string>>({})
const handleSignalInput = (e: any) => {
setWitnessValues({
...witnessValues,
[e.target.name]: e.target.value
})
}
return (
<div className="pb-2 border-bottom flex-column">
<div className="flex-column d-flex">
<RenderIf condition={signalInputs.length > 0}>
<>
{
signalInputs.map((input, index) => (
<div className="mb-2 ml-0" key={index}>
<label className="circuit_inner_label form-check-label" htmlFor="circuitPrimeSelector">
<FormattedMessage id="circuit.signalInput" /> { input }
</label>
<input className="form-control m-0 txinput" placeholder={input} name={input} onChange={handleSignalInput} />
</div>
))
}
<button
className="btn btn-sm btn-secondary"
onClick={() => { computeWitness(plugin, status, witnessValues) }}
disabled={(status === "compiling") || (status === "generating") || (status === "computing")}>
<RenderIf condition={status === 'computing'}>
<i className="fas fa-sync fa-spin mr-2" aria-hidden="true"></i>
</RenderIf>
<RenderIfNot condition={status === 'computing'}>
<i className="fas fa-sync mr-2" aria-hidden="true"></i>
</RenderIfNot>
<FormattedMessage id="circuit.compute" />
</button>
</>
</RenderIf>
</div>
</div>
)
}

@ -0,0 +1,36 @@
import { useState } from "react"
import { FormattedMessage } from "react-intl"
import { RenderIf, RenderIfNot } from "@remix-ui/helper"
export function WitnessToggler ({ children }: { children: JSX.Element }) {
const [toggleExpander, setToggleExpander] = useState<boolean>(false)
const toggleConfigurations = () => {
setToggleExpander(!toggleExpander)
}
return (
<div>
<div className="d-flex circuit_config_section justify-content-between" onClick={toggleConfigurations}>
<div className="d-flex">
<label className="mt-1 circuit_config_section">
<FormattedMessage id="circuit.computeWitness" />
</label>
</div>
<div>
<span data-id="scConfigExpander" onClick={toggleConfigurations}>
<RenderIf condition={toggleExpander}>
<i className="fas fa-angle-down" aria-hidden="true"></i>
</RenderIf>
<RenderIfNot condition={toggleExpander}>
<i className="fas fa-angle-right" aria-hidden="true"></i>
</RenderIfNot>
</span>
</div>
</div>
<RenderIf condition={toggleExpander}>
{ children }
</RenderIf>
</div>
)
}

@ -0,0 +1,4 @@
import {createContext} from 'react'
import {ICircuitAppContext} from '../types'
export const CircuitAppContext = createContext<ICircuitAppContext>({} as ICircuitAppContext)

@ -0,0 +1,77 @@
import {Actions, AppState} from '../types'
import { compiler_list } from 'circom_wasm'
export const appInitialState: AppState = {
version: compiler_list.latest,
versionList: compiler_list.wasm_builds,
filePath: "",
filePathToId: {},
status: "idle",
primeValue: "bn128",
autoCompile: false,
hideWarnings: false,
signalInputs: [],
feedback: null
}
export const appReducer = (state = appInitialState, action: Actions): AppState => {
switch (action.type) {
case 'SET_COMPILER_VERSION':
return {
...state,
version: action.payload
}
case 'SET_FILE_PATH':
return {
...state,
filePath: action.payload
}
case 'SET_COMPILER_STATUS':
return {
...state,
status: action.payload
}
case 'SET_PRIME_VALUE':
return {
...state,
primeValue: action.payload
}
case 'SET_AUTO_COMPILE':
return {
...state,
autoCompile: action.payload
}
case 'SET_HIDE_WARNINGS':
return {
...state,
hideWarnings: action.payload
}
case 'SET_SIGNAL_INPUTS':
return {
...state,
signalInputs: action.payload
}
case 'SET_COMPILER_FEEDBACK':
return {
...state,
feedback: action.payload
}
case 'SET_FILE_PATH_TO_ID':
return {
...state,
filePathToId: action.payload
}
default:
throw new Error()
}
}

@ -1,17 +1,26 @@
import {PluginClient} from '@remixproject/plugin'
import {createClient} from '@remixproject/plugin-webview'
import { PluginClient } from '@remixproject/plugin'
import { createClient } from '@remixproject/plugin-webview'
import EventManager from 'events'
import pathModule from 'path'
import {parse} from 'circom_wasm'
import { parse, compile, generate_witness, generate_r1cs, compiler_list } from 'circom_wasm'
import { extractNameFromKey, extractParentFromKey } from '@remix-ui/helper'
import { CompilationConfig, CompilerReport } from '../types'
export class CircomPluginClient extends PluginClient {
public internalEvents: EventManager
private _compilationConfig: CompilationConfig = {
version: "2.1.5",
prime: "bn128"
}
private lastCompiledCircuitPath: string = ''
private lastParsedFiles: Record<string, string> = {}
private lastCompiledFile: string = ''
constructor() {
super()
this.methods = ['init', 'parse', 'compile', 'generateR1cs']
createClient(this)
this.internalEvents = new EventManager()
this.methods = ['init', 'parse']
this.onload()
}
@ -20,24 +29,23 @@ export class CircomPluginClient extends PluginClient {
}
onActivation(): void {
// @ts-ignore
this.on('editor', 'contentChanged', (path: string, fileContent) => {
if (path.endsWith('.circom')) {
this.parse(path, fileContent)
}
})
this.internalEvents.emit('circom_activated')
}
async parse(path: string, fileContent: string): Promise<void> {
let buildFiles = {
[path]: fileContent
async parse(path: string, fileContent?: string): Promise<CompilerReport[]> {
if (!fileContent) {
// @ts-ignore
fileContent = await this.call('fileManager', 'readFile', path)
}
buildFiles = await this.resolveDependencies(path, fileContent, buildFiles)
const parsedOutput = parse(path, buildFiles)
this.lastParsedFiles = {
[path]: fileContent,
}
this.lastParsedFiles = await this.resolveDependencies(path, fileContent, this.lastParsedFiles)
const parsedOutput = parse(path, this.lastParsedFiles)
try {
const result = JSON.parse(parsedOutput)
const result: CompilerReport[] = JSON.parse(parsedOutput.report())
const mapReportFilePathToId = {}
if (result.length === 0) {
// @ts-ignore
@ -47,23 +55,24 @@ export class CircomPluginClient extends PluginClient {
for (const report of result) {
for (const label in report.labels) {
if (report.labels[label].file_id === '0') {
const file_id = report.labels[label].file_id
mapReportFilePathToId[file_id] = parsedOutput.get_report_name(parseInt(file_id))
if (file_id === '0') {
// @ts-ignore
const startPosition: {lineNumber: number; column: number} =
await this.call(
'editor',
// @ts-ignore
'getPositionAt',
report.labels[label].range.start
)
const startPosition: { lineNumber: number; column: number } = await this.call(
'editor',
// @ts-ignore
'getPositionAt',
report.labels[label].range.start
)
// @ts-ignore
const endPosition: {lineNumber: number; column: number} =
await this.call(
'editor',
// @ts-ignore
'getPositionAt',
report.labels[label].range.end
)
const endPosition: { lineNumber: number; column: number } = await this.call(
'editor',
// @ts-ignore
'getPositionAt',
report.labels[label].range.end
)
markers.push({
message: report.message,
@ -71,14 +80,14 @@ export class CircomPluginClient extends PluginClient {
position: {
start: {
line: startPosition.lineNumber,
column: startPosition.column
column: startPosition.column,
},
end: {
line: endPosition.lineNumber,
column: endPosition.column
}
column: endPosition.column,
},
},
file: path
file: path,
})
}
}
@ -92,22 +101,117 @@ export class CircomPluginClient extends PluginClient {
await this.call('editor', 'clearErrorMarkers', [path])
}
}
this.internalEvents.emit('circuit_parsing_done', result, mapReportFilePathToId)
return result
} catch (e) {
console.log(e)
throw new Error(e)
}
}
async compile(path: string, compilationConfig?: CompilationConfig): Promise<void> {
this.internalEvents.emit('circuit_compiling_start')
const parseErrors = await this.parse(path)
if (parseErrors && (parseErrors.length > 0)) {
if (parseErrors[0].type === 'Error') {
this.internalEvents.emit('circuit_parsing_errored', parseErrors)
return
} else if (parseErrors[0].type === 'Warning') {
this.internalEvents.emit('circuit_parsing_warning', parseErrors)
}
}
if (compilationConfig) {
const { prime, version } = compilationConfig
if ((prime !== "bn128") && (prime !== "bls12381") && (prime !== "goldilocks")) throw new Error('Invalid prime value')
if (!compiler_list.versions.includes(version)) throw new Error("Unsupported compiler version")
this._compilationConfig.prime = prime
this._compilationConfig.version = version
}
const circuitApi = compile(path, this.lastParsedFiles, { prime: this._compilationConfig.prime })
const circuitProgram = circuitApi.program()
if (circuitProgram.length < 1) {
const circuitErrors = circuitApi.report()
throw new Error(circuitErrors)
} else {
this.lastCompiledFile = path
const fileName = extractNameFromKey(path)
this.lastCompiledCircuitPath = extractParentFromKey(path) + "/.bin/" + fileName.replace('circom', 'wasm')
// @ts-ignore
await this.call('fileManager', 'writeFile', this.lastCompiledCircuitPath, circuitProgram, { encoding: null })
const fileContent = this.lastParsedFiles[path]
const searchComponentName = fileContent.match(/component\s+main\s*(?:{[^{}]*})?\s*=\s*([A-Za-z_]\w*)\s*\(.*\)/)
if (searchComponentName) {
const componentName = searchComponentName[1]
const signals = circuitApi.input_signals(componentName)
this.internalEvents.emit('circuit_compiling_done', signals)
} else {
this.internalEvents.emit('circuit_compiling_done', [])
}
}
}
async generateR1cs (path: string, compilationConfig?: CompilationConfig): Promise<void> {
this.internalEvents.emit('circuit_generating_r1cs_start')
const parseErrors = await this.parse(path)
if (parseErrors && (parseErrors.length > 0)) {
if (parseErrors[0].type === 'Error') {
this.internalEvents.emit('circuit_parsing_errored', parseErrors)
return
} else if (parseErrors[0].type === 'Warning') {
this.internalEvents.emit('circuit_parsing_warning', parseErrors)
}
}
if (compilationConfig) {
const { prime, version } = compilationConfig
if ((prime !== "bn128") && (prime !== "bls12381") && (prime !== "goldilocks")) throw new Error('Invalid prime value')
if (!compiler_list.versions.includes(version)) throw new Error("Unsupported compiler version")
this._compilationConfig.prime = prime
this._compilationConfig.version = version
}
const r1csApi = generate_r1cs(path, this.lastParsedFiles, { prime: this._compilationConfig.prime })
const r1csProgram = r1csApi.program()
if (r1csProgram.length < 1) {
const r1csErrors = r1csApi.report()
throw new Error(r1csErrors)
} else {
this.internalEvents.emit('circuit_generating_r1cs_done')
const fileName = extractNameFromKey(path)
const writePath = extractParentFromKey(path) + "/.bin/" + fileName.replace('circom', 'r1cs')
// @ts-ignore
await this.call('fileManager', 'writeFile', writePath, r1csProgram, true)
}
}
async computeWitness (input: string): Promise<void> {
this.internalEvents.emit('circuit_computing_witness_start')
const wasmPath = this.lastCompiledCircuitPath
if (!wasmPath) throw new Error('No wasm file found')
// @ts-ignore
const buffer: any = await this.call('fileManager', 'readFile', wasmPath, { encoding: null })
const dataRead = new Uint8Array(buffer)
const witness = await generate_witness(dataRead, input)
// @ts-ignore
await this.call('fileManager', 'writeFile', wasmPath.replace('.wasm', '.wtn'), witness, true)
this.internalEvents.emit('circuit_computing_witness_done')
}
async resolveDependencies(
filePath: string,
fileContent: string,
output = {},
depPath: string = '',
blackPath: string[] = []
): Promise<Record<string, string>> {
async resolveDependencies(filePath: string, fileContent: string, output = {}, depPath: string = '', blackPath: string[] = []): Promise<Record<string, string>> {
// extract all includes
const includes = (fileContent.match(/include ['"].*['"]/g) || []).map(
(include) => include.replace(/include ['"]/g, '').replace(/['"]/g, '')
)
const includes = (fileContent.match(/include ['"].*['"]/g) || []).map((include) => include.replace(/include ['"]/g, '').replace(/['"]/g, ''))
await Promise.all(
includes.map(async (include) => {
@ -123,12 +227,8 @@ export class CircomPluginClient extends PluginClient {
dependencyContent = await this.call('fileManager', 'readFile', path)
} else {
// if include import (path) does not exist, try to construct relative path using the original file path (current file opened in editor)
let relativePath = pathModule.resolve(
filePath.slice(0, filePath.lastIndexOf('/')),
include
)
if (relativePath.indexOf('/') === 0)
relativePath = relativePath.slice(1)
let relativePath = pathModule.resolve(filePath.slice(0, filePath.lastIndexOf('/')), include)
if (relativePath.indexOf('/') === 0) relativePath = relativePath.slice(1)
const relativePathExists = await this.call(
'fileManager',
// @ts-ignore
@ -138,81 +238,40 @@ export class CircomPluginClient extends PluginClient {
if (relativePathExists) {
// fetch file content if include import exists as a relative path
dependencyContent = await this.call(
'fileManager',
'readFile',
relativePath
)
dependencyContent = await this.call('fileManager', 'readFile', relativePath)
} else {
if (depPath) {
// if depPath is provided, try to resolve include import from './deps' folder in remix
path = pathModule.resolve(
depPath.slice(0, depPath.lastIndexOf('/')),
include
)
if (path.indexOf('/') === 0) path = path.slice(1)
dependencyContent = await this.call(
'contentImport',
'resolveAndSave',
path,
null
)
if (include.startsWith('circomlib')) {
// try to resolve include import from github if it is a circomlib dependency
const splitInclude = include.split('/')
const version = splitInclude[1].match(/v[0-9]+.[0-9]+.[0-9]+/g)
if (version && version[0]) {
path = `https://raw.githubusercontent.com/iden3/circomlib/${version[0]}/circuits/${splitInclude.slice(2).join('/')}`
dependencyContent = await this.call('contentImport', 'resolveAndSave', path, null)
} else {
path = `https://raw.githubusercontent.com/iden3/circomlib/master/circuits/${splitInclude.slice(1).join('/')}`
dependencyContent = await this.call('contentImport', 'resolveAndSave', path, null)
}
} else {
if (include.startsWith('circomlib')) {
// try to resolve include import from github if it is a circomlib dependency
const splitInclude = include.split('/')
const version = splitInclude[1].match(/v[0-9]+.[0-9]+.[0-9]+/g)
if (version && version[0]) {
path = `https://raw.githubusercontent.com/iden3/circomlib/${
version[0]
}/circuits/${splitInclude.slice(2).join('/')}`
dependencyContent = await this.call(
'contentImport',
'resolveAndSave',
path,
null
)
} else {
path = `https://raw.githubusercontent.com/iden3/circomlib/master/circuits/${splitInclude
.slice(1)
.join('/')}`
dependencyContent = await this.call(
'contentImport',
'resolveAndSave',
path,
null
)
}
if (depPath) {
// if depPath is provided, try to resolve include import from './deps' folder in remix
path = pathModule.resolve(depPath.slice(0, depPath.lastIndexOf('/')), include)
if (path.indexOf('/') === 0) path = path.slice(1)
dependencyContent = await this.call('contentImport', 'resolveAndSave', path, null)
} else {
// If all import cases are not true, use the default import to try fetching from node_modules and unpkg
dependencyContent = await this.call(
'contentImport',
'resolveAndSave',
path,
null
)
dependencyContent = await this.call('contentImport', 'resolveAndSave', path, null)
}
}
}
}
// extract all includes from the dependency content
const dependencyIncludes = (
dependencyContent.match(/include ['"].*['"]/g) || []
).map((include) =>
include.replace(/include ['"]/g, '').replace(/['"]/g, '')
)
const dependencyIncludes = (dependencyContent.match(/include ['"].*['"]/g) || []).map((include) => include.replace(/include ['"]/g, '').replace(/['"]/g, ''))
blackPath.push(include)
// recursively resolve all dependencies of the dependency
if (dependencyIncludes.length > 0) {
await this.resolveDependencies(
filePath,
dependencyContent,
output,
path,
blackPath
)
await this.resolveDependencies(filePath, dependencyContent, output, path, blackPath)
output[include] = dependencyContent
} else {
output[include] = dependencyContent
@ -221,4 +280,40 @@ export class CircomPluginClient extends PluginClient {
)
return output
}
async resolveReportPath (path: string): Promise<string> {
// @ts-ignore
const pathExists = await this.call('fileManager', 'exists', path)
if (pathExists) return path
else {
// if include import (path) does not exist, try to construct relative path using the original file path (current file opened in editor)
let relativePath = pathModule.resolve(this.lastCompiledFile.slice(0, this.lastCompiledFile.lastIndexOf('/')), path)
if (relativePath.indexOf('/') === 0) relativePath = relativePath.slice(1)
// @ts-ignore
const relativePathExists = await this.call('fileManager', 'exists', relativePath)
if (relativePathExists) return relativePath
else {
if (path.startsWith('circomlib')) {
// try to resolve include import from github if it is a circomlib dependency
const splitInclude = path.split('/')
const version = splitInclude[1].match(/v[0-9]+.[0-9]+.[0-9]+/g)
if (version && version[0]) {
path = `/.deps/https/raw.githubusercontent.com/iden3/circomlib/${version[0]}/circuits/${splitInclude.slice(2).join('/')}`
} else {
path = `/.deps/https/raw.githubusercontent.com/iden3/circomlib/master/circuits/${splitInclude.slice(1).join('/')}`
}
// @ts-ignore
const exists = await this.call('fileManager', 'exists', path)
if (exists) return path
else throw new Error(`Report path ${path} do no exist in the Remix FileSystem`)
} else {
throw new Error(`Report path ${path} do no exist in the Remix FileSystem`)
}
}
}
}
}

@ -0,0 +1,87 @@
import { compiler_list } from 'circom_wasm'
import {Dispatch} from 'react'
import { CircomPluginClient } from '../services/circomPluginClient'
export type CompilerStatus = "compiling" | "generating" | "computing" | "idle" | "errored" | "warning"
export interface ICircuitAppContext {
appState: AppState
dispatch: Dispatch<Actions>,
plugin: CircomPluginClient
}
export interface ActionPayloadTypes {
SET_COMPILER_VERSION: string,
SET_FILE_PATH: string,
SET_COMPILER_STATUS: CompilerStatus,
SET_PRIME_VALUE: PrimeValue,
SET_AUTO_COMPILE: boolean,
SET_HIDE_WARNINGS: boolean,
SET_SIGNAL_INPUTS: string[],
SET_COMPILER_FEEDBACK: string | CompilerReport[]
SET_FILE_PATH_TO_ID: Record<number, string>
}
export interface Action<T extends keyof ActionPayloadTypes> {
type: T
payload: ActionPayloadTypes[T]
}
export type Actions = {[A in keyof ActionPayloadTypes]: Action<A>}[keyof ActionPayloadTypes]
export interface AppState {
version: string,
versionList: typeof compiler_list.wasm_builds,
filePath: string,
filePathToId: Record<string, string>,
status: CompilerStatus,
primeValue: PrimeValue,
autoCompile: boolean,
hideWarnings: boolean,
signalInputs: string[],
feedback: string | CompilerReport[]
}
export type CompilationConfig = {
prime: PrimeValue,
version: string
}
export type PrimeValue = "bn128" | "bls12381" | "goldilocks"
export type CompilerFeedbackProps = {
feedback: string | CompilerReport[],
filePathToId: Record<string, string>,
openErrorLocation: (location: string, startRange: string) => void,
hideWarnings: boolean
}
export type CompilerReport = {
type: "Error" | "Bug" | "Help" | "Note" | "Warning" | "Unknown",
message: string,
labels: {
style: "Primary" | "Secondary" | "Unknown",
file_id: string,
range: {
start: string,
end: string
},
message: string
}[],
notes: string[]
}
export type FeedbackAlertProps = {
message: string,
location: string
}
export type ConfigurationsProps = {
setPrimeValue: (prime: PrimeValue) => void,
primeValue: PrimeValue
}
export type CompileOptionsProps = {
setCircuitAutoCompile: (value: boolean) => void,
setCircuitHideWarnings: (value: boolean) => void,
autoCompile: boolean,
hideWarnings: boolean
}

@ -0,0 +1,88 @@
body {
font-size : .8rem;
}
.circuit_section {
padding: 12px 24px 16px;
}
.circuit_label {
margin-bottom: 2px;
font-size: 11px;
line-height: 12px;
text-transform: uppercase;
}
.circuit_warnings_box {
display: flex;
align-items: center;
}
.circuit_warnings_box label {
margin: 0;
}
.circuit_config_section:hover {
cursor: pointer;
}
.circuit_config_section {
font-size: 1rem;
}
.circuit_config {
display: flex;
align-items: center;
}
.circuit_config label {
margin: 0;
}
.circuit_inner_label {
margin-bottom: 2px;
font-size: 11px;
line-height: 12px;
text-transform: uppercase;
}
.circuit_errors_box {
padding-left: 5px;
padding-right: 5px;
word-break: break-word;
}
.circuit_feedback.success,
.circuit_feedback.error,
.circuit_feedback.warning {
white-space: pre-line;
word-wrap: break-word;
cursor: pointer;
position: relative;
margin: 0.5em 0 1em 0;
border-radius: 5px;
line-height: 20px;
padding: 8px 15px;
}
.circuit_feedback.success pre,
.circuit_feedback.error pre,
.circuit_feedback.warning pre {
white-space: pre-line;
overflow-y: hidden;
background-color: transparent;
margin: 0;
font-size: 12px;
border: 0 none;
padding: 0;
border-radius: 0;
}
.circuit_feedback.success .close,
.circuit_feedback.error .close,
.circuit_feedback.warning .close {
visibility: hidden;
white-space: pre-line;
font-weight: bold;
position: absolute;
color: hsl(0, 0%, 0%); /* black in style-guide.js */
top: 0;
right: 0;
padding: 0.5em;
}
.circuit_feedback.success a,
.circuit_feedback.error a,
.circuit_feedback.warning a {
bottom: 0;
right: 0;
}

@ -0,0 +1,27 @@
pragma circom 2.1.4;
include "circomlib/poseidon.circom";
// include "https://github.com/0xPARC/circom-secp256k1/blob/master/circuits/bigint.circom";
template Example () {
signal input a;
signal input b;
signal output c;
var unused = 4;
c <== a * b;
assert(a > 2);
component hash = Poseidon(2);
hash.inputs[0] <== a;
hash.inputs[1] <== b;
log("hash", hash.out);
}
component main { public [ a ] } = Example();
/* INPUT = {
"a": "5",
"b": "77"
} */

@ -4,7 +4,9 @@ template Multiplier2() {
signal input a;
signal input b;
signal output c;
signal output d;
c <== a*b;
d <== c*b;
}
component main = Multiplier2();

@ -6,10 +6,14 @@
<base href="./" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous"/>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<!-- <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous"/> -->
<!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous"> -->
<link rel="stylesheet" integrity="ha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf"
crossorigin="anonymous" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css">
</head>
<body>
<div id="root"></div>
<script src="snarkjs.min.js"> </script>
<script src="https://kit.fontawesome.com/41dd021e94.js" crossorigin="anonymous"></script>
</body>
</html>

@ -1,15 +1,15 @@
{
"name": "circuit-compiler",
"kind": "provider",
"displayName": "Circuit Compiler",
"displayName": "Circom ZKP compiler",
"events": [],
"version": "2.0.0",
"methods": ["init", "parse"],
"methods": ["init", "parse", "compile", "generateR1cs"],
"canActivate": [],
"url": "",
"description": "Enables circuit compilation and computing a witness for ZK proofs",
"icon": "https://docs.circom.io/assets/images/favicon.png",
"location": "hiddenPanel",
"icon": "assets/img/circom-icon-bw-800b.webp",
"location": "sidePanel",
"documentation": "",
"repo": "https://github.com/ethereum/remix-project/tree/master/apps/circuit-compiler",
"maintainedBy": "Remix",

File diff suppressed because one or more lines are too long

@ -201,15 +201,15 @@ class FileManager extends Plugin {
* @param {string} data content to write on the file
* @returns {void}
*/
async writeFile(path, data) {
async writeFile(path, data, options?) {
try {
path = this.normalize(path)
path = this.limitPluginScope(path)
if (await this.exists(path)) {
await this._handleIsFile(path, `Cannot write file ${path}`)
return await this.setFileContent(path, data)
return await this.setFileContent(path, data, options)
} else {
const ret = await this.setFileContent(path, data)
const ret = await this.setFileContent(path, data, options)
this.emit('fileAdded', path)
return ret
}
@ -255,13 +255,13 @@ class FileManager extends Plugin {
* @param {string} path path of the file
* @returns {string} content of the file
*/
async readFile(path) {
async readFile(path, options?) {
try {
path = this.normalize(path)
path = this.limitPluginScope(path)
await this._handleExists(path, `Cannot read file ${path}`)
await this._handleIsFile(path, `Cannot read file ${path}`)
return this.getFileContent(path)
return this.getFileContent(path, options)
} catch (e) {
throw new Error(e)
}
@ -579,7 +579,7 @@ class FileManager extends Plugin {
return path ? path[1] : '/'
}
getFileContent(path) {
getFileContent(path, options?) {
const provider = this.fileProviderOf(path)
if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` })
@ -589,11 +589,11 @@ class FileManager extends Plugin {
provider.get(path, (err, content) => {
if (err) reject(err)
resolve(content)
})
}, options)
})
}
async setFileContent(path, content) {
async setFileContent(path, content, options?) {
if (this.currentRequest) {
const canCall = await this.askUserPermission(`writeFile`, `modifying ${path} ...`)
const required = this.appManager.isRequired(this.currentRequest.from)
@ -602,10 +602,10 @@ class FileManager extends Plugin {
this.call('notification', 'toast', fileChangedToastMsg(this.currentRequest.from, path))
}
}
return await this._setFileInternal(path, content)
return await this._setFileInternal(path, content, options)
}
_setFileInternal(path, content) {
_setFileInternal(path, content, options?) {
const provider = this.fileProviderOf(path)
if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` })
// TODO : Add permission
@ -616,7 +616,7 @@ class FileManager extends Plugin {
this.syncEditor(path)
this.emit('fileSaved', path)
resolve(true)
})
}, options)
})
}

@ -87,12 +87,12 @@ class FileProvider {
cb()
}
async get (path, cb) {
async get (path, cb, options = { encoding: 'utf8' }) {
cb = cb || function () { /* do nothing. */ }
path = this.getPathFromUrl(path) || path // ensure we actually use the normalized path from here
var unprefixedpath = this.removePrefix(path)
try {
const content = await window.remixFileSystem.readFile(unprefixedpath, 'utf8')
const content = await window.remixFileSystem.readFile(unprefixedpath, options)
if (cb) cb(null, content)
return content
} catch (err) {
@ -101,17 +101,17 @@ class FileProvider {
}
}
async set (path, content, cb) {
async set (path, content, cb, options = { encoding: 'utf8' }) {
cb = cb || function () { /* do nothing. */ }
var unprefixedpath = this.removePrefix(path)
const exists = await window.remixFileSystem.exists(unprefixedpath)
if (exists && await window.remixFileSystem.readFile(unprefixedpath, 'utf8') === content) {
if (exists && await window.remixFileSystem.readFile(unprefixedpath, options) === content) {
if (cb) cb()
return null
}
await this.createDir(path.substr(0, path.lastIndexOf('/')))
try {
await window.remixFileSystem.writeFile(unprefixedpath, content, 'utf8')
await window.remixFileSystem.writeFile(unprefixedpath, content, options)
} catch (e) {
if (cb) cb(e)
return false

@ -0,0 +1,15 @@
{
"circuit.compiler": "Compiler",
"circuit.autoCompile": "Auto compile",
"circuit.hideWarnings": "Hide warnings",
"circuit.advancedConfigurations": "Advanced Configurations",
"circuit.compilerConfiguration": "Compiler configuration",
"circuit.prime": "Prime",
"circuit.useConfigurationFile": "Use configuration file",
"circuit.compile": "Compile",
"circuit.noFileSelected": "no file selected",
"circuit.generateR1cs": "Generate R1CS",
"circuit.computeWitness": "Compute Witness",
"circuit.signalInput": "Signal Input",
"circuit.compute": "Compute"
}

@ -13,6 +13,7 @@ import permissionHandlerJson from './permissionHandler.json';
import solUmlGenJson from './solUmlGen.json'
import remixAppJson from './remixApp.json'
import remixUiTabsJson from './remixUiTabs.json'
import circuitJson from './circuit.json';
export default {
...debuggerJson,
@ -30,4 +31,5 @@ export default {
...solUmlGenJson,
...remixAppJson,
...remixUiTabsJson,
...circuitJson
}

@ -0,0 +1,15 @@
{
"circuit.compiler": "Compiler",
"circuit.autoCompile": "Auto compile",
"circuit.hideWarnings": "Hide warnings",
"circuit.advancedConfigurations": "Advanced Configurations",
"circuit.compilerConfiguration": "Compiler configuration",
"circuit.prime": "Prime",
"circuit.useConfigurationFile": "Use configuration file",
"circuit.compile": "Compile",
"circuit.noFileSelected": "no file selected",
"circuit.generateR1cs": "Generate R1CS",
"circuit.computeWitness": "Compute Witness",
"circuit.signalInput": "Signal Input",
"circuit.compute": "Compute"
}

@ -0,0 +1,15 @@
{
"circuit.compiler": "Compiler",
"circuit.autoCompile": "Auto compile",
"circuit.hideWarnings": "Hide warnings",
"circuit.advancedConfigurations": "Advanced Configurations",
"circuit.compilerConfiguration": "Compiler configuration",
"circuit.prime": "Prime",
"circuit.useConfigurationFile": "Use configuration file",
"circuit.compile": "Compile",
"circuit.noFileSelected": "no file selected",
"circuit.generateR1cs": "Generate R1CS",
"circuit.computeWitness": "Compute Witness",
"circuit.signalInput": "Signal Input",
"circuit.compute": "Compute"
}

@ -0,0 +1,16 @@
{
"circuit-compiler.displayName": "Circuit 编译器",
"circuit.compiler": "Compiler",
"circuit.autoCompile": "自动编译",
"circuit.hideWarnings": "隐藏警告",
"circuit.advancedConfigurations": "高级配置",
"circuit.compilerConfiguration": "编译器配置",
"circuit.prime": "质数",
"circuit.useConfigurationFile": "使用配置文件",
"circuit.compile": "编译",
"circuit.noFileSelected": "未选中文件",
"circuit.generateR1cs": "生成R1CS",
"circuit.computeWitness": "证人计算器",
"circuit.signalInput": "输入信号",
"circuit.compute": "计算"
}

@ -14,6 +14,7 @@ import solUmlGenJson from './solUmlGen.json'
import remixAppJson from './remixApp.json'
import remixUiTabsJson from './remixUiTabs.json'
import enJson from '../en';
import circuitJson from './circuit.json';
// There may have some un-translated content. Always fill in the gaps with EN JSON.
// No need for a defaultMessage prop when render a FormattedMessage component.
@ -33,4 +34,5 @@ export default Object.assign({}, enJson, {
...solUmlGenJson,
...remixAppJson,
...remixUiTabsJson,
...circuitJson
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

@ -74,7 +74,8 @@ const requiredModules = [
'compilationDetails',
'contractflattener',
'solidity-script',
'openaigpt'
'openaigpt',
'circuit-compiler'
]
// dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd)

@ -81,7 +81,7 @@ export const getPathIcon = (path: string) => {
? 'small fak fa-ts-logo' : path.endsWith('.tsc')
? 'fad fa-brackets-curly' : path.endsWith('.cairo')
? 'small fak fa-cairo' : path.endsWith('.circom')
? 'fak fa-circom-plug1' : 'far fa-file'
? 'fak fa-circom' : 'far fa-file'
}
export const isNumeric = (value) => {

@ -179,6 +179,9 @@ export const TabsUI = (props: TabsUIProps) => {
} else if (tabsState.currentExt === 'sol' || tabsState.currentExt === 'yul') {
await props.plugin.call('solidity', 'compile', path)
_paq.push(['trackEvent', 'editor', 'clickRunFromEditor', tabsState.currentExt])
} else if (tabsState.currentExt === 'circom') {
await props.plugin.call('circuit-compiler', 'compile', path)
_paq.push(['trackEvent', 'editor', 'clickRunFromEditor', tabsState.currentExt])
}
}}
>
@ -189,7 +192,7 @@ export const TabsUI = (props: TabsUIProps) => {
<span>
{tabsState.currentExt === 'js' || tabsState.currentExt === 'ts' ? (
<FormattedMessage id="remixUiTabs.tooltipText1" />
) : tabsState.currentExt === 'sol' || tabsState.currentExt === 'yul' ? (
) : tabsState.currentExt === 'sol' || tabsState.currentExt === 'yul' || tabsState.currentExt === 'circom' ? (
<FormattedMessage id="remixUiTabs.tooltipText2" />
) : (
<FormattedMessage id="remixUiTabs.tooltipText3" />

@ -150,7 +150,7 @@
"brace": "^0.8.0",
"change-case": "^4.1.1",
"chokidar": "^2.1.8",
"circom_wasm": "^0.0.2",
"circom_wasm": "^0.1.0",
"color-support": "^1.1.3",
"commander": "^9.4.1",
"core-js": "^3.6.5",
@ -202,6 +202,7 @@
"remark-gfm": "^3.0.1",
"rss-parser": "^3.12.0",
"signale": "^1.4.0",
"snarkjs": "^0.7.0",
"sol2uml": "^2.4.3",
"string-similarity": "^4.0.4",
"svg2pdf.js": "^2.2.1",

@ -2616,6 +2616,19 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@iden3/bigarray@0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@iden3/bigarray/-/bigarray-0.0.2.tgz#6fc4ba5be18daf8a26ee393f2fb62b80d98c05e9"
integrity sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==
"@iden3/binfileutils@0.0.11":
version "0.0.11"
resolved "https://registry.yarnpkg.com/@iden3/binfileutils/-/binfileutils-0.0.11.tgz#9ffbbcc1279f2b2182bb6dcff4eee8a5b2167911"
integrity sha512-LylnJoZ0CTdgErnKY8OxohvW4K+p6UHD3sxt+3P9AmMyBQjYR4IpoqoYZZ+9aMj89cmCQ21UvdhndAx04er3NA==
dependencies:
fastfile "0.0.20"
ffjavascript "^0.2.48"
"@isomorphic-git/idb-keyval@3.3.2":
version "3.3.2"
resolved "https://registry.yarnpkg.com/@isomorphic-git/idb-keyval/-/idb-keyval-3.3.2.tgz#c0509a6c5987d8a62efb3e47f2815bcc5eda2489"
@ -7660,7 +7673,7 @@ axobject-query@^2.2.0:
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==
b4a@^1.6.4:
b4a@^1.0.1, b4a@^1.6.4:
version "1.6.4"
resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9"
integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==
@ -8432,6 +8445,17 @@ before-after-hook@^2.0.0:
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e"
integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==
bfj@^7.0.2:
version "7.1.0"
resolved "https://registry.yarnpkg.com/bfj/-/bfj-7.1.0.tgz#c5177d522103f9040e1b12980fe8c38cf41d3f8b"
integrity sha512-I6MMLkn+anzNdCUp9hMRyui1HaNEUCco50lxbvNS4+EyXg8lN3nJ48PjPWtbH8UVS9CuMoaKE9U2V3l29DaRQw==
dependencies:
bluebird "^3.7.2"
check-types "^11.2.3"
hoopy "^0.1.4"
jsonpath "^1.1.1"
tryer "^1.0.1"
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
@ -8497,6 +8521,14 @@ bl@^4.0.0, bl@^4.0.3, bl@^4.1.0:
inherits "^2.0.4"
readable-stream "^3.4.0"
blake2b-wasm@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz#9115649111edbbd87eb24ce7c04b427e4e2be5be"
integrity sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==
dependencies:
b4a "^1.0.1"
nanoassert "^2.0.0"
blakejs@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.1.tgz#bf313053978b2cd4c444a48795710be05c785702"
@ -8521,7 +8553,7 @@ block-stream@*:
dependencies:
inherits "~2.0.0"
bluebird@^3.0.5, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5:
bluebird@^3.0.5, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5, bluebird@^3.7.2:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
@ -9525,6 +9557,11 @@ check-error@1.0.2, check-error@^1.0.2:
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==
check-types@^11.2.3:
version "11.2.3"
resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.3.tgz#1ffdf68faae4e941fce252840b1787b8edc93b71"
integrity sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==
cheerio-select@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4"
@ -9683,10 +9720,17 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
inherits "^2.0.1"
safe-buffer "^5.0.1"
circom_wasm@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/circom_wasm/-/circom_wasm-0.0.2.tgz#9d24866b8289a5778999270823a4cb06e64145b5"
integrity sha512-SCMP6cxHHL7MLedDrTl+nGYyE6+kE5GepbxtZm65GlR0wUMD9eNOD1shwScWaDnmBOZTrImmNeTYZA5DWCmIww==
circom_runtime@0.1.22:
version "0.1.22"
resolved "https://registry.yarnpkg.com/circom_runtime/-/circom_runtime-0.1.22.tgz#f957c47662cdd03cd3fb76979c434c719a366373"
integrity sha512-V/XYZWBhbZY8SotkaGH4FbiDYAZ8a1Md++MBiKPDOuWS/NIJB+Q+XIiTC8zKMgoDaa9cd2OiTvsC9J6te7twNg==
dependencies:
ffjavascript "0.2.57"
circom_wasm@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/circom_wasm/-/circom_wasm-0.1.0.tgz#dda76c7ae9046ea6f1e1cd3754c017ad753bd5c1"
integrity sha512-F7ihfVGjfSz+01yFXLHjKocQFm8j9KBageqMw5+olFWB6+7CXHLjnUaFuU6u+7T0FsL7+JuP18jdcAVQEXoQgw==
circular-json@^0.3.0:
version "0.3.3"
@ -11250,7 +11294,7 @@ deep-extend@~0.4.0:
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253"
integrity sha1-7+QRPQgIX05vlod1mBD4B0aeIlM=
deep-is@^0.1.3:
deep-is@^0.1.3, deep-is@~0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
@ -11839,6 +11883,13 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
ejs@^3.1.6:
version "3.1.9"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361"
integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==
dependencies:
jake "^10.8.5"
ejs@^3.1.7, ejs@^3.1.8:
version "3.1.8"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b"
@ -12248,6 +12299,18 @@ escape-string-regexp@^5.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
escodegen@^1.8.1:
version "1.14.3"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
dependencies:
esprima "^4.0.1"
estraverse "^4.2.0"
esutils "^2.0.2"
optionator "^0.8.1"
optionalDependencies:
source-map "~0.6.1"
escodegen@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17"
@ -12476,6 +12539,11 @@ espree@^9.4.0:
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.3.0"
esprima@1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.2.tgz#76a0fd66fcfe154fd292667dc264019750b1657b"
integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==
esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
@ -12495,7 +12563,7 @@ esrecurse@^4.3.0:
dependencies:
estraverse "^5.2.0"
estraverse@^4.1.1:
estraverse@^4.1.1, estraverse@^4.2.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
@ -13133,7 +13201,7 @@ fast-levenshtein@^1.0.0:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz#e6a754cc8f15e58987aa9cbd27af66fd6f4e5af9"
integrity sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=
fast-levenshtein@^2.0.6:
fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
@ -13163,6 +13231,11 @@ fastest-levenshtein@^1.0.12:
resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
fastfile@0.0.20:
version "0.0.20"
resolved "https://registry.yarnpkg.com/fastfile/-/fastfile-0.0.20.tgz#794a143d58cfda2e24c298e5ef619c748c8a1879"
integrity sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==
fastq@^1.6.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
@ -13226,6 +13299,33 @@ fetch-blob@^2.1.1, fetch-blob@^2.1.2:
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-2.1.2.tgz#a7805db1361bd44c1ef62bb57fb5fe8ea173ef3c"
integrity sha512-YKqtUDwqLyfyMnmbw8XD6Q8j9i/HggKtPEI+pZ1+8bvheBu78biSmNaXWusx1TauGqtUUGx/cBb1mKdq2rLYow==
ffjavascript@0.2.57:
version "0.2.57"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.57.tgz#ba1be96015b2688192e49f2f4de2cc5150fd8594"
integrity sha512-V+vxZ/zPNcthrWmqfe/1YGgqdkTamJeXiED0tsk7B84g40DKlrTdx47IqZuiygqAVG6zMw4qYuvXftIJWsmfKQ==
dependencies:
wasmbuilder "0.0.16"
wasmcurves "0.2.0"
web-worker "^1.2.0"
ffjavascript@0.2.59:
version "0.2.59"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.59.tgz#b2f836082587fab333dfb181b909a188f80036f3"
integrity sha512-QssOEUv+wilz9Sg7Zaj6KWAm7QceOAEsFuEBTltUsDo1cjn11rA/LGYvzFBPbzNfxRlZxwgJ7uxpCQcdDlrNfw==
dependencies:
wasmbuilder "0.0.16"
wasmcurves "0.2.1"
web-worker "^1.2.0"
ffjavascript@^0.2.48:
version "0.2.60"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.60.tgz#4d8ae613d6bf4e98b3cc29ba10c626f5853854cf"
integrity sha512-T/9bnEL5xAZRDbQoEMf+pM9nrhK+C3JyZNmqiWub26EQorW7Jt+jR54gpqDhceA4Nj0YctPQwYnl8xa52/A26A==
dependencies:
wasmbuilder "0.0.16"
wasmcurves "0.2.2"
web-worker "^1.2.0"
fflate@^0.4.8:
version "0.4.8"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae"
@ -14883,6 +14983,11 @@ homedir-polyfill@^1.0.1:
dependencies:
parse-passwd "^1.0.0"
hoopy@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==
hosted-git-info@^2.1.4, hosted-git-info@^2.7.1:
version "2.8.9"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
@ -17196,6 +17301,15 @@ jsonparse@^1.2.0:
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.0.tgz#85fc245b1d9259acc6941960b905adf64e7de0e8"
integrity sha1-hfwkWx2SWazGlBlguQWt9k594Og=
jsonpath@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/jsonpath/-/jsonpath-1.1.1.tgz#0ca1ed8fb65bb3309248cc9d5466d12d5b0b9901"
integrity sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==
dependencies:
esprima "1.2.2"
static-eval "2.0.2"
underscore "1.12.1"
jspdf@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/jspdf/-/jspdf-2.5.1.tgz#00c85250abf5447a05f3b32ab9935ab4a56592cc"
@ -17537,6 +17651,14 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==
dependencies:
prelude-ls "~1.1.2"
type-check "~0.3.2"
license-webpack-plugin@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz#1e18442ed20b754b82f1adeff42249b81d11aec6"
@ -18033,6 +18155,11 @@ logform@^2.2.0:
safe-stable-stringify "^1.1.0"
triple-beam "^1.3.0"
logplease@^1.2.15:
version "1.2.15"
resolved "https://registry.yarnpkg.com/logplease/-/logplease-1.2.15.tgz#3da442e93751a5992cc19010a826b08d0293c48a"
integrity sha512-jLlHnlsPSJjpwUfcNyUxXCl33AYg2cHhIf9QhGL2T4iPT0XPB+xP1LRKFPgIg1M/sg9kAJvy94w9CzBNrfnstA==
longest-streak@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4"
@ -19574,6 +19701,11 @@ nanoassert@^1.1.0:
resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-1.1.0.tgz#4f3152e09540fde28c76f44b19bbcd1d5a42478d"
integrity sha1-TzFS4JVA/eKMdvRLGbvNHVpCR40=
nanoassert@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-2.0.0.tgz#a05f86de6c7a51618038a620f88878ed1e490c09"
integrity sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==
nanobench@^2.1.0, nanobench@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/nanobench/-/nanobench-2.1.1.tgz#c2f23fcce116d50b4998b1954ba114674c137269"
@ -20767,6 +20899,18 @@ optimist@^0.6.1:
minimist "~0.0.1"
wordwrap "~0.0.2"
optionator@^0.8.1:
version "0.8.3"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
dependencies:
deep-is "~0.1.3"
fast-levenshtein "~2.0.6"
levn "~0.3.0"
prelude-ls "~1.1.2"
type-check "~0.3.2"
word-wrap "~1.2.3"
optionator@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
@ -21988,6 +22132,11 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
prepend-http@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@ -22443,6 +22592,16 @@ quick-lru@^5.1.1:
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
r1csfile@0.0.45:
version "0.0.45"
resolved "https://registry.yarnpkg.com/r1csfile/-/r1csfile-0.0.45.tgz#59d59a33f8b5280017fc00ee691d003a3d705fe0"
integrity sha512-YKIp4D441aZ6OoI9y+bfAyb2j4Cl+OFq/iiX6pPWDrL4ZO968h0dq0w07i65edvrTt7/G43mTnl0qEuLXyp/Yw==
dependencies:
"@iden3/bigarray" "0.0.2"
"@iden3/binfileutils" "0.0.11"
fastfile "0.0.20"
ffjavascript "0.2.57"
raf-schd@^4.0.2:
version "4.0.3"
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
@ -24446,6 +24605,22 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
snarkjs@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/snarkjs/-/snarkjs-0.7.0.tgz#9b4d193a0535c1903e45f1508aa7ad74cd130844"
integrity sha512-Vu5W+0Va6X1xvlCllpZ2r3/S7MafnL6IrAv09lk/F+VNDHuHEHx3xopR9Kr70p2KpbBBJ/HB9VCDZWism8WGlA==
dependencies:
"@iden3/binfileutils" "0.0.11"
bfj "^7.0.2"
blake2b-wasm "^2.4.0"
circom_runtime "0.1.22"
ejs "^3.1.6"
fastfile "0.0.20"
ffjavascript "0.2.59"
js-sha3 "^0.8.0"
logplease "^1.2.15"
r1csfile "0.0.45"
sntp@1.x.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
@ -24868,6 +25043,13 @@ state-local@^1.0.6:
resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5"
integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==
static-eval@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42"
integrity sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==
dependencies:
escodegen "^1.8.1"
static-extend@^0.1.1, static-extend@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
@ -25997,6 +26179,11 @@ truncate-utf8-bytes@^1.0.0:
dependencies:
utf8-byte-length "^1.0.1"
tryer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
ts-loader@^9.2.6:
version "9.2.6"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.2.6.tgz#9937c4dd0a1e3dbbb5e433f8102a6601c6615d74"
@ -26166,6 +26353,13 @@ type-check@^0.4.0, type-check@~0.4.0:
dependencies:
prelude-ls "^1.2.1"
type-check@~0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==
dependencies:
prelude-ls "~1.1.2"
type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5:
version "4.0.8"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
@ -26418,6 +26612,11 @@ undefsafe@^2.0.5:
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
underscore@1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e"
integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==
undertaker-registry@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/undertaker-registry/-/undertaker-registry-1.0.1.tgz#5e4bda308e4a8a2ae584f9b9a4359a499825cc50"
@ -27072,6 +27271,32 @@ warning@^4.0.0, warning@^4.0.3:
dependencies:
loose-envify "^1.0.0"
wasmbuilder@0.0.16:
version "0.0.16"
resolved "https://registry.yarnpkg.com/wasmbuilder/-/wasmbuilder-0.0.16.tgz#f34c1f2c047d2f6e1065cbfec5603988f16d8549"
integrity sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA==
wasmcurves@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.2.0.tgz#ccfc5a7d3778b6e0768b82a9336c80054f9bc0cf"
integrity sha512-3e2rbxdujOwaod657gxgmdhZNn+i1qKdHO3Y/bK+8E7bV8ttV/fu5FO4/WLBACF375cK0QDLOP+65Na63qYuWA==
dependencies:
wasmbuilder "0.0.16"
wasmcurves@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.2.1.tgz#416d15432a9c6a7b79ef6000eab1e8e7302624ad"
integrity sha512-9ciO7bUE5bgpbOcdK7IO3enrSVIKHwrQmPibok4GLJWaCA7Wyqc9PRYnu5HbiFv9NDFNqVKPtU5R6Is5KujBLg==
dependencies:
wasmbuilder "0.0.16"
wasmcurves@0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.2.2.tgz#ca444f6a6f6e2a5cbe6629d98ff478a62b4ccb2b"
integrity sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ==
dependencies:
wasmbuilder "0.0.16"
watchify@^3.9.0:
version "3.11.1"
resolved "https://registry.yarnpkg.com/watchify/-/watchify-3.11.1.tgz#8e4665871fff1ef64c0430d1a2c9d084d9721881"
@ -27128,6 +27353,11 @@ web-streams-polyfill@^3.1.0:
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965"
integrity sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==
web-worker@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.2.0.tgz#5d85a04a7fbc1e7db58f66595d7a3ac7c9c180da"
integrity sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==
web3-core@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-4.3.0.tgz#96c5e8f7ec92ea573f388785548bf31c4089d508"
@ -27670,6 +27900,11 @@ word-wrap@^1.2.3:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
word-wrap@~1.2.3:
version "1.2.5"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"

Loading…
Cancel
Save