기본 콘텐츠로 건너뛰기

ZKP-1. 초보자를 위한 Circom 언어 가이드

Circom은 영지식 증명에 사용되는 '산술 회로'를 설계하기 위한 언어입니다. 이 회로를 통해 증명하고 싶은 논리나 규칙을 코드로 표현할 수 있습니다.

조금 어렵게 들릴 수 있지만, "어떤 비밀 정보(private input)를 공개하지 않으면서, 내가 그 비밀 정보를 알고 있다는 사실을 증명하는 프로그램"을 만드는 언어라고 생각하면 쉽습니다.

1. 핵심 개념: 회로, 신호, 제약 조건

Circom 코드는 3가지 핵심 요소로 이루어집니다.

회로 (Circuit)

Circom의 가장 기본 단위입니다. 우리는 템플릿(template)이라는 키워드를 사용해서 회로를 정의합니다. 마치 다른 언어의 함수나 클래스처럼, 재사용 가능한 로직의 묶음이라고 생각할 수 있습니다.

신호 (Signal)

회로의 입력(input)과 출력(output), 그리고 그 사이에서 계산되는 중간값들을 신호라고 부릅니다. 신호는 회로를 통해 흐르는 데이터입니다.

  • input: 회로에 입력되는 신호입니다.
    • public input: 증명을 검증하는 사람에게도 공개되는 입력값입니다. (예: 문제)
    • private input: 증명하는 사람만 알고 있는 비밀 입력값입니다. (예: 문제의 해답)
  • output: 회로의 계산 결과로 나오는 신호입니다. 보통 public으로 간주되어 공개됩니다.
  • var: 회로 내부에서만 사용되는 중간 신호입니다. 일반 프로그래밍 언어의 변수와 달리, Circom의 모든 신호(var 포함)는 최종적으로 제약 조건 시스템의 일부가 되어 증명 과정에 영향을 줍니다.

제약 조건 (Constraint)

Circom의 심장과도 같은 가장 중요한 개념입니다. 제약 조건은 신호들 사이에 반드시 성립해야 하는 수학적 관계(방정식)를 정의합니다. 증명(proof)을 생성한다는 것은, 이 모든 제약 조건을 만족하는 신호값들을 찾았다는 것을 의미합니다.

  • A === B: A와 B의 값이 반드시 같아야 한다는 제약 조건을 추가합니다. 이 연산자는 두 신호가 동일함을 '검증'하거나 '강제'할 때 사용되며, 주로 이미 계산된 두 값 사이의 관계를 확인할 때 유용합니다.
  • A <-- B: B의 값을 A에 할당하되, 제약 조건은 추가하지 않습니다.
  • A <== B: B의 값을 A에 할당하고, A === B 라는 제약 조건을 추가합니다. 가장 일반적으로 사용되는 연산자입니다.

간단 비유

  • 회로(템플릿)는 자물쇠가 달린 "마법 상자"의 설계도입니다.
  • 신호(signal)는 이 상자에 넣는 "비밀번호(private)"와 "공개된 힌트(public)"입니다.
  • 제약 조건(constraint)은 "이 비밀번호를 넣으면 상자가 열린다"는 상자의 내부 규칙입니다.

우리는 이 설계도(Circom 코드)를 통해, 상자를 여는 비밀번호를 절대 보여주지 않으면서도, '나는 이 상자를 열 수 있는 올바른 비밀번호를 확실히 알고 있다'는 사실만을 완벽하게 증명할 수 있습니다.

2. 기본 문법과 구조

Circom 코드의 기본 구조를 살펴봅시다.

pragma circom 2.0.0;

// 'Multiplier'라는 이름의 템플릿(회로)을 정의합니다.
template Multiplier() {
    // 입력 신호를 선언합니다.
    signal input a;
    signal input b;

    // 출력 신호를 선언합니다.
    signal output c;

    // 제약 조건을 정의합니다.
    // c는 a와 b의 곱과 같아야 한다는 규칙을 추가합니다.
    c <== a * b;
}

// 'main' 컴포넌트는 회로의 진입점입니다.
// public 신호를 지정할 수 있습니다.
component main = Multiplier();

코드 해설

  • pragma circom 2.0.0;: 사용할 Circom 컴파일러의 버전을 명시합니다.
  • template Multiplier(): Multiplier라는 이름의 템플릿을 선언합니다.
  • signal input a;: a라는 이름의 입력 신호를 선언합니다. public이나 private 키워드가 없으면 기본적으로 private으로 간주됩니다.
  • signal output c;: c라는 이름의 출력 신호를 선언합니다.
  • c <== a * b;: 가장 중요한 부분입니다. 출력 c는 반드시 입력 a와 b를 곱한 값과 같아야 한다는 제약 조건을 시스템에 추가합니다.
  • component main = Multiplier();: Multiplier 템플릿의 인스턴스를 생성하고, 이를 회로의 main 컴포넌트로 지정합니다.

3. 간단한 예제: 제곱 검증 회로

이제 아주 간단한 예제를 통해 전체적인 흐름을 이해해 보겠습니다. "어떤 수 x를 제곱하면 y가 된다"는 것을 증명하는 회로를 만들어 봅시다.

여기서 y는 모두에게 공개된 값(public input)이고, x는 나만 아는 비밀 값(private input)입니다.

  • SquareTest.circom

pragma circom 2.0.0;

/*
* 이 회로는 y == x*x 임을 증명합니다.
* 입력:
* - x (private): 나만 아는 비밀 값
* - y (public): 모두에게 공개된 값
* 출력: 없음
*/
template SquareTest() {
    // 비밀 입력 x
    signal private input x;

    // 공개 입력 y
    signal public input y;

    // 제약 조건: y는 x의 제곱과 같아야 한다.
    y === x * x;
}

// public 신호를 명시하여 main 컴포언트를 생성합니다.
component main { public [y] } = SquareTest();

코드 해설

  • template SquareTest(): SquareTest라는 이름의 회로를 정의합니다.
  • signal private input x;: 증명자만 아는 비밀 값 x를 입력으로 받습니다.
  • signal public input y;: 모두가 아는 공개 값 y를 입력으로 받습니다.
  • y === x * x;: 이 회로의 핵심 규칙입니다. 공개된 y의 값은, 비밀 값 x를 제곱한 값과 반드시 같아야 한다는 제약 조건을 추가합니다.
  • component main { public [y] }: main 컴포넌트를 생성하며, 이 회로의 입력 신호 중 y가 외부로 공개되는 public input임을 명시합니다. 이렇게 선언된 public input은 나중에 증명을 검증할 때 사용됩니다.

동작 방식

  • 증명자(Prover): y가 9라고 공개되어 있을 때, 비밀 값 x가 3이라는 것을 알고 있습니다. 이 x=3, y=9 값을 회로에 넣어 증명(proof)을 생성합니다. 9 === 3 * 3 이라는 제약 조건이 만족되기 때문에 증명 생성에 성공합니다.
  • 검증자(Verifier): 증명자에게서 증명(proof)과 공개 값 y=9를 전달받습니다. 검증자는 비밀 값 x가 무엇인지는 전혀 모르지만, 전달받은 증명을 통해 "아, 이 사람은 y=9를 만족시키는 비밀 x값을 정말로 알고 있구나!"라는 사실을 100% 신뢰할 수 있게 됩니다.

만약 증명자가 x=4와 같이 엉뚱한 값을 사용하려 하면 9 === 4 * 4 (즉, 9 === 16) 라는 제약 조건이 깨지기 때문에 증명 생성 자체가 실패하게 됩니다.

4. 다음 단계는?

Circom의 기본 개념과 문법을 익혔으니, 이제 실제 도구들을 사용해 볼 차례입니다.

  1. 컴파일(Compile): 작성한 .circom 파일을 컴파일러를 이용해 회로의 수학적 표현(R1CS - Rank-1 Constraint System)으로 변환합니다. R1CS는 증명 시스템이 이해할 수 있는 표준화된 형식이라고 생각할 수 있습니다.
  2. Witness 계산: 회로의 입력값(private, public 포함)을 제공하여 모든 제약 조건을 만족하는 중간 신호값들을 계산합니다. 이 계산된 값의 집합을 witness라고 합니다.
  3. 증명 생성(Prove): 신뢰할 수 있는 설정(trusted setup) 단계에서 생성된 키(proving key)와 witness를 사용해 실제 암호학적 증명(proof)을 생성합니다.
  4. 증명 검증(Verify): verifying key와 public input, 그리고 proof를 이용해 해당 증명이 유효한지 검증합니다.

이 과정들은 snarkjs와 같은 커맨드라인 도구를 통해 진행할 수 있습니다.

댓글

이 블로그의 인기 게시물

Windows에 AMP와 MediaWiki 설치하기

1. 들어가기     AMP는 Apache + MySQL +  Perl/PHP/Python에 대한 줄임말이다. LAMP (Linux + AMP)라고 하여 Linux에 설치하는 것으로 많이 소개하고 있지만 Windows에서도 간편하게 설치하여 사용할 수 있다.       이 글은 Windows 7에 Apache + MySQL + PHP를 설치하고 그 기반에서 MediaWiki를 설치하여 실행하는 과정을 간략히 정리한 것이다. 2. MySQL     * 버전 5.6.12     1) 다운로드         http://dev.mysql.com/downloads/installer/         MySQL Installer 5.6.12         Windows (x86, 32-bit), MSI Installer         (mysql-installer-web-community-5.6.12.0.msi)     2) 다운로드한 MSI 파일을 더블클릭하여 설치를 진행한다.           설치 위치:                   C:\Program Files\MySQL               선택 사항:                       Install MySQL Products             Choosing a Se...

MATLAB Rutime 설치하기

MATLAB Rutime 설치하기 미설치시 에러 MATLAB Runtime 을 설치하지 않은 환경에서 MATLAB 응용프로그램이나 공유 라이브러리를 사용하려고 하면 아래와 같은 에러 메시지가 표시될 것입니다. 처리되지 않은 예외: System.TypeInitializationException: 'MathWorks.MATLAB.NET.Utility.MWMCR'의 형식 이니셜라이저에서 예 외를 Throw했습니다. ---> System.TypeInitializationException: 'MathWorks.MATLAB.NET.Arrays.MWArray'의 형식 이니셜라이저에서 예외를 Throw했습니다. ---> System.DllNotFoundException: DLL 'mclmcrrt9_3.dll'을(를) 로드할 수 없습니다. 지정된 모듈을 찾을 수 없습니다. (예외가 발생한 HRESULT: 0x8007007E) 위치: MathWorks.MATLAB.NET.Arrays.MWArray.mclmcrInitialize2(Int32 primaryMode) 위치: MathWorks.MATLAB.NET.Arrays.MWArray..cctor() --- 내부 예외 스택 추적의 끝 --- 위치: MathWorks.MATLAB.NET.Utility.MWMCR..cctor() --- 내부 예외 스택 추적의 끝 --- 위치: MathWorks.MATLAB.NET.Utility.MWMCR.processExiting(Exception exception) 해결 방법 이 문제를 해결하기 위해서는 MATLAB Runtime 을 설치해야 합니다. 여러 가지 방법으로 MATLAB Runtime 을 설치할 수 있습니다. MATLAB 이 설치되어 있는 경우에는 MATLAB 설치 폴더 아래에 있는 MATLAB Runtime 설치 프로그램을 실행하여 설치합니다. ...

Wi-Fi 카드 2.4GHz로만 동작시키기

Wi-Fi 카드 2.4GHz로만 동작시키기 별도의 Wi-Fi AP 장치를 두지 않고 아래와 같은 기기들로만 Wi-Fi 네트워크를 구성하고자 할 때 주변 기기들이 2.4GHz만 지원하기 때문에 PC에서 실행하는 AP가 항상 2.4GHz를 사용하도록 Wi-Fi 카드를 설정해 주어야 합니다. 기기 Wi-Fi 카드 주파수 대역 Wi-Fi Direct 지원 PC (Windows 10) 2.4GHz, 5GHz O 주변 기기들 2.4GHz X Wi-Fi 카드별 주파수 대역 선택 방법 Windows 시작 메뉴에서 설정 을 클릭합니다. Windows 설정 화면에서 네트워크 및 인터넷 을 클릭합니다. 설정 화면의 왼쪽 메뉴바에서 Wi-Fi 를 클릭합니다. 화면 오른쪽 관련 설정 구역에 있는 어댑터 옵션 변경 을 클릭합니다. 설정을 바꾸고자 하는 Wi-Fi 카드 항목을 선택하고 마우스 오른쪽을 누른 다음 속성 메뉴를 클릭합니다. 대화상자의 네트워킹 탭 화면에 있는 구성 버튼을 클릭합니다. 장치 속성 대화상자의 고급 탭 화면으로 이동합니다. 제시되는 속성 항목들은 제품별로 다르며 자세한 사항은 아래의 제품별 설명을 참고하여 값을 설정하시기 바랍니다. Intel Dual Band Wireless-AC 7265 기술 사양 주파수 대역: 2.4GHz, 5GHz 무선 표준: 802.11ac 주파수 대역 선택 장치 속성 대화상자에서 아래와 같이 선택합니다. Wireless Mode 1. 802.11a => 5GHz 4. 802.11b/g => 2.4GHz (이 항목 선택) 6. 802.11a/b/g => 2.4GHz, 5GHz Intel Dual Band Wireless-AC 8265 기술 사양 주파수 대역: 2.4GHz, 5GHz 무선 표준: 802.11ac 주파수 대역 선택 장치 속성 대화상자에서 아래와 같이 ...