Add compute witness button

pull/4144/head
ioedeveloper 1 year ago
parent 4a40340f41
commit 63620c85dd
  1. 11
      apps/circuit-compiler/src/app/actions/index.ts
  2. 25
      apps/circuit-compiler/src/app/app.tsx
  3. 8
      apps/circuit-compiler/src/app/components/container.tsx
  4. 43
      apps/circuit-compiler/src/app/components/witness.tsx
  5. 9
      apps/circuit-compiler/src/app/reducers/state.ts
  6. 75
      apps/circuit-compiler/src/app/services/circomPluginClient.ts
  7. 8
      apps/circuit-compiler/src/app/types/index.ts
  8. 2
      apps/circuit-compiler/src/profile.json
  9. 4
      apps/remix-ide/src/app/tabs/locales/en/circuit.json
  10. 4
      apps/remix-ide/src/app/tabs/locales/es/circuit.json
  11. 4
      apps/remix-ide/src/app/tabs/locales/fr/circuit.json
  12. 4
      apps/remix-ide/src/app/tabs/locales/zh/circuit.json
  13. 2
      yarn.lock

@ -4,29 +4,24 @@ import { Actions, AppState } from "../types"
export const compileCircuit = async (plugin: CircomPluginClient, appState: AppState, dispatch: React.Dispatch<Actions>) => {
try {
if (appState.status !== "compiling") {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'compiling' })
await plugin.compile(appState.filePath, { version: appState.version, prime: appState.primeValue })
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })
} else {
console.log('Exisiting compilation in progress')
console.log('Exisiting circuit compilation in progress')
}
} catch (e) {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' })
console.error('Compiling failed: ', e)
console.error(e)
dispatch({ type: 'SET_SIGNAL_INPUTS', payload: [] })
}
}
export const generateR1cs = async (plugin: CircomPluginClient, appState: AppState, dispatch: React.Dispatch<Actions>) => {
try {
if (appState.status !== "generating") {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'generating' })
await plugin.generateR1cs(appState.filePath, { version: appState.version, prime: appState.primeValue })
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })
} else {
console.log('Exisiting r1cs generation in progress')
}
} catch (e) {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' })
console.error('Generating R1CS failed: ', e)
}
}

@ -21,7 +21,7 @@ function App() {
useEffect(() => {
const plugin = new CircomPluginClient()
plugin.internalEvents.on('activated', () => {
plugin.internalEvents.on('circom_activated', () => {
// @ts-ignore
plugin.on('locale', 'localeChanged', (locale: any) => {
setLocale(locale)
@ -40,6 +40,13 @@ function App() {
})
setPlugin(plugin)
})
plugin.internalEvents.on('circuit_compiling', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'compiling' }))
plugin.internalEvents.on('circuit_done', (signalInputs) => {
signalInputs = (signalInputs || []).filter(input => input)
dispatch({ type: 'SET_SIGNAL_INPUTS', payload: signalInputs })
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })
})
plugin.internalEvents.on('circuit_errored', (err) => dispatch({ type: 'SET_COMPILER_STATUS', payload: err.message }))
}, [])
useEffect(() => {
@ -48,7 +55,6 @@ function App() {
if (appState.autoCompile) await compileCircuit(plugin, appState, dispatch)
})()
setIsContentChanged(false)
setSignalInput()
}
}, [appState.autoCompile, isContentChanged])
@ -58,6 +64,14 @@ function App() {
}
}, [plugin])
useEffect(() => {
if (appState.filePath) {
(async () => {
if (appState.autoCompile) await compileCircuit(plugin, appState, dispatch)
})()
}
}, [appState.filePath])
const setCurrentLocale = async () => {
// @ts-ignore
const currentLocale = await plugin.call('locale', 'currentLocale')
@ -65,13 +79,6 @@ function App() {
setLocale(currentLocale)
}
const setSignalInput = () => {
const signalMatcher = /([a-z$_][a-z0-9$_]*)(\.[a-z$_][a-z0-9$_]*)*(\[\d+\])?/g
const signals = content.match(signalMatcher)
console.log('signals: ', signals)
}
const value = {
appState,
dispatch,

@ -35,9 +35,11 @@ export function Container () {
<Configurations />
</ConfigToggler>
<CircuitActions />
<WitnessToggler>
<WitnessSection />
</WitnessToggler>
<RenderIf condition={circuitApp.appState.signalInputs.length > 0}>
<WitnessToggler>
<WitnessSection signalInputs={circuitApp.appState.signalInputs} status={circuitApp.appState.status} />
</WitnessToggler>
</RenderIf>
</div>
</div>
</article>

@ -1,25 +1,34 @@
import { CustomTooltip } from "@remix-ui/helper";
import { RenderIf, RenderIfNot } from "@remix-ui/helper";
import { FormattedMessage } from "react-intl";
import { CompilerStatus } from "../types";
export function WitnessSection () {
export function WitnessSection ({ signalInputs, status }: {signalInputs: string[], status: CompilerStatus}) {
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>
<input className="form-control m-0 txinput" placeholder="Signal A" />
</div>
</CustomTooltip>
</div>
<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} />
</div>
))
}
<button className="btn btn-sm btn-secondary" >
<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>
)

@ -7,7 +7,8 @@ export const appInitialState: AppState = {
filePath: "",
status: "idle",
primeValue: "bn128",
autoCompile: false
autoCompile: false,
signalInputs: []
}
export const appReducer = (state = appInitialState, action: Actions): AppState => {
@ -43,6 +44,12 @@ export const appReducer = (state = appInitialState, action: Actions): AppState =
autoCompile: action.payload
}
case 'SET_SIGNAL_INPUTS':
return {
...state,
signalInputs: action.payload
}
default:
throw new Error()
}

@ -2,8 +2,7 @@ import { PluginClient } from '@remixproject/plugin'
import { createClient } from '@remixproject/plugin-webview'
import EventManager from 'events'
import pathModule from 'path'
// @ts-ignore
import { parse, compile, generate_witness, generate_r1cs, compiler_list } from '../../../pkg'
import { parse, compile, generate_witness, generate_r1cs, compiler_list } from 'circom_wasm'
import { extractNameFromKey, extractParentFromKey } from '@remix-ui/helper'
import { CompilationConfig } from '../types'
@ -13,6 +12,7 @@ export class CircomPluginClient extends PluginClient {
version: "2.1.5",
prime: "bn128"
}
public lastCompiledCircuitPath: string = ''
constructor() {
super()
@ -34,7 +34,7 @@ export class CircomPluginClient extends PluginClient {
}
})
this.internalEvents.emit('activated')
this.internalEvents.emit('circom_activated')
}
async parse(path: string, fileContent: string): Promise<void> {
@ -107,6 +107,7 @@ export class CircomPluginClient extends PluginClient {
}
async compile(path: string, compilationConfig?: CompilationConfig): Promise<void> {
this.internalEvents.emit('circuit_compiling')
if (compilationConfig) {
const { prime, version } = compilationConfig
@ -121,27 +122,31 @@ export class CircomPluginClient extends PluginClient {
}
buildFiles = await this.resolveDependencies(path, fileContent, buildFiles)
const compiledOutput = compile(path, buildFiles, { prime: this._compilationConfig.prime })
const circuitApi = compile(path, buildFiles, { prime: this._compilationConfig.prime })
const circuitProgram = circuitApi.program()
console.log('compiledOutput: ', compiledOutput)
console.log('compiledOutput.program: ', compiledOutput.program())
console.log('compiledOutput.input_signals: ', compiledOutput.input_signals("Semaphore"))
if (circuitProgram.length < 1) {
const circuitErrors = circuitApi.report()
// if (compiledOutput.length < 1) {
// throw new Error("Compilation failed! See parsing errors.")
// } else {
// const fileName = extractNameFromKey(path)
// const writePath = extractParentFromKey(path) + "/.bin/" + fileName.replace('circom', 'wasm')
// // @ts-ignore
// await this.call('fileManager', 'writeFile', writePath, new Uint8Array(compiledOutput), true)
// console.log('compilation successful!')
// }
// @ts-ignore
// const buffer = await this.call('fileManager', 'readFile', writePath, true)
// // @ts-ignore
// const dataRead = new Uint8Array(buffer)
// const witness = await generate_witness(dataRead, '{ "a": "5", "b": "77" }')
this.internalEvents.emit('circuit_errored', circuitErrors)
throw new Error(circuitErrors)
} else {
const fileName = extractNameFromKey(path)
this.lastCompiledCircuitPath = extractParentFromKey(path) + "/.bin/" + fileName.replace('circom', 'wasm')
// @ts-ignore
await this.call('fileManager', 'writeFile', this.lastCompiledCircuitPath, circuitProgram, true)
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_done', signals)
} else {
this.internalEvents.emit('circuit_done', [])
}
}
// const witness = await generate_witness(compiledOutput, '{ "identityTrapdoor": "12656283236575022300303467601783819380815431272685589718060054649894766174337", "identityNullifier": "15178877681550417450385541477607788220584140707925739215609273992582659710290", "treePathIndices": "0", "treeSiblings": "1", "externalNullifier": "5df6e0e3480d6fbc32925076897ec6b9b935d75ae8f4d9f4858a426f8f6a4ab": "signalHash": "[85, 139, 239, 32, 221, 194, 165, 19, 20, 52, 104, 144, 41, 16, 40, 204, 171, 245, 198, 77, 94, 143, 30, 112, 105, 165, 33, 15, 62, 156, 18, 118]"}')
// const ptau_final = "https://ipfs-cluster.ethdevops.io/ipfs/QmTiT4eiYz5KF7gQrDsgfCSTRv3wBPYJ4bRN1MmTRshpnW";
@ -202,6 +207,7 @@ export class CircomPluginClient extends PluginClient {
}
async generateR1cs (path: string, compilationConfig?: CompilationConfig): Promise<void> {
this.internalEvents.emit('circuit_generating')
if (compilationConfig) {
const { prime, version } = compilationConfig
@ -216,20 +222,35 @@ export class CircomPluginClient extends PluginClient {
}
buildFiles = await this.resolveDependencies(path, fileContent, buildFiles)
const r1cs = generate_r1cs(path, buildFiles, { prime: this._compilationConfig.prime })
const r1csApi = generate_r1cs(path, buildFiles, { prime: this._compilationConfig.prime })
const r1csProgram = r1csApi.program()
if (r1csProgram.length < 1) {
const r1csErrors = r1csApi.report()
if (r1cs.length < 1) {
throw new Error("R1cs generation failed! See parsing errors.")
this.internalEvents.emit('circuit_errored', r1csErrors)
throw new Error(r1csErrors)
} else {
this.internalEvents.emit('circuit_done')
const fileName = extractNameFromKey(path)
const writePath = extractParentFromKey(path) + "/.bin/" + fileName.replace('circom', 'r1cs')
// @ts-ignore
await this.call('fileManager', 'writeFile', writePath, new Uint8Array(r1cs), true)
console.log('R1CS generation successful!')
await this.call('fileManager', 'writeFile', writePath, r1csProgram, true)
}
}
async computeWitness (input: string, wasmPath?: string): Promise<void> {
this.internalEvents.emit('circuit_computing')
if (!wasmPath) wasmPath = this.lastCompiledCircuitPath
if (!wasmPath) throw new Error('No wasm file found')
// @ts-ignore
const buffer: any = await this.call('fileManager', 'readFile', wasmPath, true)
const dataRead = new Uint8Array(buffer)
const witness = await generate_witness(dataRead, input)
}
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, ''))

@ -2,7 +2,7 @@ import { compiler_list } from 'circom_wasm'
import {Dispatch} from 'react'
import { CircomPluginClient } from '../services/circomPluginClient'
export type CompilerStatus = "compiling" | "generating" | "idle" | "errored"
export type CompilerStatus = "compiling" | "generating" | "computing" | "idle" | "errored"
export interface ICircuitAppContext {
appState: AppState
dispatch: Dispatch<Actions>,
@ -14,7 +14,8 @@ export interface ActionPayloadTypes {
SET_FILE_PATH: string,
SET_COMPILER_STATUS: CompilerStatus,
SET_PRIME_VALUE: PrimeValue,
SET_AUTO_COMPILE: boolean
SET_AUTO_COMPILE: boolean,
SET_SIGNAL_INPUTS: string[]
}
export interface Action<T extends keyof ActionPayloadTypes> {
type: T
@ -29,7 +30,8 @@ export interface AppState {
filePath: string,
status: CompilerStatus,
primeValue: PrimeValue,
autoCompile: boolean
autoCompile: boolean,
signalInputs: string[]
}
export type CompilationConfig = {

@ -9,7 +9,7 @@
"url": "",
"description": "Enables circuit compilation and computing a witness for ZK proofs",
"icon": "https://docs.circom.io/assets/images/favicon.png",
"location": "hiddenPanel",
"location": "sidePanel",
"documentation": "",
"repo": "https://github.com/ethereum/remix-project/tree/master/apps/circuit-compiler",
"maintainedBy": "Remix",

@ -9,5 +9,7 @@
"circuit.compile": "Compile",
"circuit.noFileSelected": "no file selected",
"circuit.generateR1cs": "Generate R1CS",
"circuit.computeWitness": "Compute Witness"
"circuit.computeWitness": "Compute Witness",
"circuit.signalInput": "Signal Input",
"circuit.compute": "Compute"
}

@ -9,5 +9,7 @@
"circuit.compile": "Compile",
"circuit.noFileSelected": "no file selected",
"circuit.generateR1cs": "Generate R1CS",
"circuit.computeWitness": "Compute Witness"
"circuit.computeWitness": "Compute Witness",
"circuit.signalInput": "Signal Input",
"circuit.compute": "Compute"
}

@ -9,5 +9,7 @@
"circuit.compile": "Compile",
"circuit.noFileSelected": "no file selected",
"circuit.generateR1cs": "Generate R1CS",
"circuit.computeWitness": "Compute Witness"
"circuit.computeWitness": "Compute Witness",
"circuit.signalInput": "Signal Input",
"circuit.compute": "Compute"
}

@ -10,5 +10,7 @@
"circuit.compile": "编译",
"circuit.noFileSelected": "未选中文件",
"circuit.generateR1cs": "生成R1CS",
"circuit.computeWitness": "证人计算器"
"circuit.computeWitness": "证人计算器",
"circuit.signalInput": "输入信号",
"circuit.compute": "计算"
}

@ -9729,7 +9729,7 @@ circom_runtime@0.1.22:
"circom_wasm@https://github.com/ioedeveloper/circom_wasm.git":
version "0.0.0-alpha.7"
resolved "https://github.com/ioedeveloper/circom_wasm.git#24d26dec739297a1bd3e61f74ca3b95b20f66a25"
resolved "https://github.com/ioedeveloper/circom_wasm.git#a8c53a02e97fa5e8533618a070d1b7fdb655fdc5"
circular-json@^0.3.0:
version "0.3.3"

Loading…
Cancel
Save