# Circom

## 1. Circom이란

Circom은 영지식 증명에 사용되는 산술 회로를 정의하기 위한 DSL이다. \
개발자는 Circom 문법으로 회로를 작성하고, 이를 컴파일하여 실제 SNARK 프로토콜이 사용할 수 있는 형태의 제약식과 실행 코드를 얻을 수 있다.

Circom 컴파일러는 Rust로 구현된 컴파일러로, 하나의 Circom 회로로부터 다음과 같은 산출물을 생성한다.

* **R1CS 파일**: 회로를 R1CS 형태로 변환한 결과로, 각 wire가 어떤 곱셈·덧셈 관계를 만족해야 하는지에 대한 제약식을 포함한다.
* **witness 생성 프로그램(C++ 또는 WebAssembly)**: 주어진 입력에 대해 회로를 실행하여, 모든 wire/signal에 대한 유효한 할당값(witness)을 효율적으로 계산하는 프로그램이다.

이 과정을 통해 사용자의 회로 정의가 실제 SNARK proving 시스템이 사용할 수 있는 제약식 + witness 계산기로 연결된다.

***

#### 템플릿과 컴포넌트: 모듈형 회로 설계

Circom의 핵심 특징 중 하나는 모듈성이다. Circom에서는 회로를 template이라는 형태로 정의하고, 이를 component로 인스턴스화하여 더 큰 회로를 구성한다.

* **Template**: 파라미터를 받을 수 있는 회로 설계도에 해당한다. 특정 연산(곱셈기, 비교기, 해시 라운드 등)을 일반화된 형태로 정의한다.
* **Component**: template를 실제로 인스턴스화한 서브 회로이다. 하나의 큰 회로 안에서 template를 여러 번 재사용하여 구조적인 회로를 만들 수 있다.

이러한 설계 방식은 다음과 같은 장점을 갖는다.

* 작은 단위의 회로를 **독립적으로 테스트·리뷰·오딧·형식 검증**하기 쉽다.
* 동일한 패턴의 회로를 여러 번 재사용할 수 있어, 큰 회로를 설계할 때 구조가 명확해진다.

또한 Circom 생태계에는 circomlib이라는 공개 라이브러리가 존재하여, 다음과 같은 다양한 템플릿을 바로 가져다 쓸 수 있다.

* 비교기, 선택자 등 기본 연산
* Poseidon, MiMC 등 **해시 함수**
* 서명 검증 등 고수준 회로

개발자는 circomlib에 포함된 검증된 회로를 재사용하거나, 이를 참고해 자신의 템플릿을 정의하여 더 큰 시스템을 설계할 수 있다.

***

#### Proving 시스템과 도구 생태계

Circom은 회로 정의와 제약식/위트니스 생성까지를 담당하고, 실제 증명(proof)을 생성·검증하는 부분은 별도의 proving 라이브러리가 맡는다.

대표적으로 다음과 같은 구현체들이 있다.

* **snarkjs**: JavaScript 및 WebAssembly로 구현된 라이브러리로, 브라우저나 Node.js 환경에서 Groth16 등의 proving 시스템을 사용할 수 있다.
* **wasmsnark**: 네이티브 WebAssembly 환경을 위한 구현체이다.
* **rapidSnark**: C++ 및 Intel 어셈블리로 작성된 고성능 prover로, 대규모 증명 생성에 적합하다.

Circom으로 작성된 회로(R1CS + witness 생성기)는 이들 proving 라이브러리와 결합되어, 최종적으로 zk-SNARK 증명 생성·검증 파이프라인을 구성하게 된다.

***

## 2. 사용법

### 설치 방법

```zsh
git clone https://github.com/iden3/circom.git
```

다운받은 디렉토리에 들어가 rust를 사용하여 빌드한다.

```zsh
cargo build --release
```

빌드된 바이너리를 자유롭게 사용하기 위해 path를 고정시킨다.

```zsh
cargo install --path circom
```

### snarkjs&#x20;

만들어진 Circuit을 사용하여 zk proof를 만드는 패키지를 설치한다.

```bash
npm install -g snarkjs
```

***

## 3. 실제 사용법

[Groth16](/upside-zkp-docs/step-1/groth16/groth16.md)

이제 Groth16과 Circom을 사용하여  $$x^3 + x + 5 = 35$$을 만족하는 𝑥 를 알고 있다는 명제를 어떻게 영지식 증명으로 만드는지 살펴보자.

먼저, Template이라는 구조를 통해 circuit을 설계한다.&#x20;

만든 Template를 인스턴스화 해서 실제 회로를 만드는 것이 component 이다.

### 컴파일

```rust
pragma circom 2.0.0;

template Main() {
    signal input x;       // 비밀 값
    signal output out;    // 공개 출력

    signal sym1;
    signal y;
    signal sym2;

    sym1 <== x * x;
    y    <== sym1 * x;
    sym2 <== x + y;
    out  <== sym2 + 5;

    // 우리가 원하는 명제: out == 35
    out === 35;
}

component main = Main();

```

이렇게 만든 파일을 아래 명령어를 통해 컴파일한다.

```zsh
## Circom 파일 컴파일
circom main.circom --r1cs --wasm --sym -o build
```

결과물로 나온 파일은 `build/main.r1cs` : R1CS 제약식, `build/main_js/main.wasm` : witness 계산용 wasm, `build/main.sym` : 디버깅용 심볼이 나온다.

\
즉 Circom는 회로를 R1CS 제약식으로 변환하고, 주어진 입력으로 witness를 계산하는 WebAssembly(wasm) 프로그램을 생성한다.

#### R1CS 분석

Circom에서 중요한 부분은 결국 우리가 작성한 circuit이 R1CS 제약식의 형태로 잘 나오는지다.

이를 확인하기 위해 snarkjs를 사용하여 확인 할 수 있다.

```zsh
## constraint 개수, wire 개수 같은 요약 정보가 나온다.
snarkjs r1cs info build/main.r1cs

## 여기서 main.x, main.sym1 같은 이름이 *.sym을 통해 매핑되어 나온다.
snarkjs r1cs print build/main.r1cs build/main.sym

## 제약식 전체를 JSON 구조로 볼 수 있다
snarkjs r1cs export json build/main.r1cs build/main.r1cs.json

```

{% code fullWidth="true" %}

```zsh
snarkjs r1cs print build/main.r1cs build/main.sym
[INFO]  snarkJS: [ 21888242871839275222246405745257275088548364400416034343698204186575808495616main.x ] * [ main.x ] - [ 21888242871839275222246405745257275088548364400416034343698204186575808495616main.sym1 ] = 0
[INFO]  snarkJS: [ 21888242871839275222246405745257275088548364400416034343698204186575808495616main.sym1 ] * [ main.x ] - [ 21888242871839275222246405745257275088548364400416034343698204186575808495616main.y ] = 0
[INFO]  snarkJS: [  ] * [  ] - [ 351 +21888242871839275222246405745257275088548364400416034343698204186575808495616main.out ] = 0
[INFO]  snarkJS: [  ] * [  ] - [ main.x +main.y +21888242871839275222246405745257275088548364400416034343698204186575808495616main.sym2 ] = 0
[INFO]  snarkJS: [  ] * [  ] - [ 51 +21888242871839275222246405745257275088548364400416034343698204186575808495616main.out +main.sym2 ] = 0
```

{% endcode %}

여기서 엄청나게 큰 수는 p - 1 즉 (-1)을 뜻하는 값이다 (mod 연산) &#x20;

따라서 첫 번째 R1CS 식을 보면 \[- main.x] \* \[main.x] - \[- main.sym1] = 0이다.&#x20;

즉 $$x^2 = sym\_1$$ 이라는 제약 조건이다.

나머지도 실제로 정리해 보면 아래 식과 같다

$$\begin {aligned} \&x \cdot x = sym\_1 \ \ \&sym\_1 \cdot x = y \ \ &(x + y) \cdot 1 = sym\_2 \ \ &(sym\_2 + 5) \cdot 1 = out \end {aligned}$$

### Witness 생성

여기서부터는 Circom을 사용하진 않는다. Circom에서 만든 generate\_witness.js와 wasm을 이용해서 input.json 에 내가 아는 x(비밀 값)을 넣고 Witness를 생성한다.

```zsh
node build/main_js/generate_witness.js build/main_js/main.wasm \
     input.json build/witness.wtns
```

input.json 에 올바른 값을 넣지 않으면 assert가 뜬다.

```json
// input.json
{
  "x": 3
}
```

여기서 나온 witness.wtns를 변환하면 constraint을 만족하는 유효한 witness가 나온다.\
$$w = \[1, out, x, sym\_1, y,sym\_2]$$

```zsh
snarkjs wtns export json build/witness.wtns build/witness.json
```

```json
// witness.json
[
 "1",
 "35",
 "3",
 "9",
 "27",
 "30"
]
```

### Powers of Tau, Groth16 setup

Groth16을 사용하여 proof를 만들기 때문에 공개 파라미터 설정이 필요하다.&#x20;

자세한 내용은 Groth16에서 설명되니 간단하게 명령어만 설명하겠다.

<pre class="language-zsh"><code class="lang-zsh"><strong>## Powers of Tau
</strong><strong># 1) 새 pot 파일 생성
</strong>snarkjs powersoftau new bn128 12 pot12_0000.ptau

# 2) 기여 한 번
snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau \
  --name="first contribution" -v

# 3) phase2용으로 준비
snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau

# 1) 회로 + pot로 zkey 1차 생성
snarkjs groth16 setup build/main.r1cs pot12_final.ptau build/circuit_0000.zkey

# 2) 기여 한 번 더 (옵션이지만 보통 한다)
snarkjs zkey contribute build/circuit_0000.zkey build/circuit_final.zkey \
  --name="circuit contribution" -v

# 3) 검증키 추출
snarkjs zkey export verificationkey \
  build/circuit_final.zkey \
  build/verification_key.json
</code></pre>

### 증명 생성

증명자는 circuit에 대한 증명키와 witness를 바탕으로 증명을 만든다.

결과물로는 proof와 공개 입력값이 나온다.

```shellscript
snarkjs groth16 prove \
  build/circuit_final.zkey \
  build/witness.wtns \
  build/proof.json \
  build/public.json
```

```json
// proof.json
{
 "pi_a": [
  "2292319416538939859201154273956115722590214103931389334485591721447225238910",
  "19111769558577349015868971779500990904290742705820502368384893433021281806467",
  "1"
 ],
 "pi_b": [
  [
   "3623544671139639729911711237732379685469066905141933193693026565106714625812",
   "20548909579081465004345388720650061102734787819110480924339461372281796710249"
  ],
  [
   "12677133574353034297782430001677023484863413520732045917635220787909690435757",
   "4838882721185144936352546280298927340185305702142561563330334152259051708952"
  ],
  [
   "1",
   "0"
  ]
 ],
 "pi_c": [
  "14187643094968055203162794487234713608924541262393801546395180119989228700015",
  "11409977509591853222081958976060609374311589537385913801060208734754872372279",
  "1"
 ],
 "protocol": "groth16",
 "curve": "bn128"
}
```

```json
// public.json
[
 "35"
]
```

### 검증 과정

검증자는 circuit에 대한 검증키와 공개 입력값, 증명을 바탕으로 검증을 진행한다.

```zsh
snarkjs groth16 verify \
  build/verification_key.json \
  build/public.json \
  build/proof.json
```

<figure><img src="/files/h77TIHHt5aKxxLRkOkBI" alt=""><figcaption></figcaption></figure>

***

## 4. References

* [https://docs.circom.io/getting-started/installation](https://docs.circom.io/getting-started/installation/)
* <https://github.com/iden3/circom>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://upsidezkp.gitbook.io/upside-zkp-docs/step-4/zkp-dsl-proving-system/circom.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
