[ZK] Cairo 를 사용해보자

무앙·2025년 7월 4일

이번 글에서는 Cairo 언어로 실행 가능한 프로그램을 작성하고 실행하는 방법을 소개합니다. Starknet 스마트 컨트랙트가 아닌, 일반 Cairo 실행 파일을 만들고 그 안에서 로직을 작성해보고자 합니다.

목표

  • scarb로 Cairo 프로젝트 생성
  • 테스트 환경 대신 실행 타겟(executable target) 설정
  • 간단한 예제 함수 작성 및 실행

1. 패키지 생성

터미널에서 다음 명령어로 새 Cairo 프로젝트를 생성합니다:

scarb new <패키지명>

예시로는 다음과 같이 진행했습니다:

scarb new cairo_playground

아래와 같은 선택지가 나오게 됩니다:

scarb new 화면

? Which test runner do you want to set up? ›
❯ Starknet Foundry (default)
  Cairo Test

"Cairo Test"를 선택해 일반적인 Cairo 실행 프로젝트로 만듭니다.


2. Scarb.toml 수정

Scarb.toml 파일은 프로젝트 설정 파일입니다. 처음에는 다음과 같이 생성되어 있을 것입니다:

[package]
name = "cairo_playground"
version = "0.1.0"
edition = "2024_07"

[dependencies]

[dev-dependencies]
cairo_test = "2.11.4"

여기서 다음 항목을 추가해줍니다:

[[target.executable]]
name = "main"
function = "cairo_playground::main"

[dependencies]
cairo_execute = "2.11.4"

설정 설명

  • [[target.executable]]
    이 설정은 해당 패키지를 "실행 가능한 프로그램(Executable)"로 정의한다는 의미입니다. 기본적으로 Cairo 프로젝트는 라이브러리 형태로 시작되지만, 이 옵션을 설정함으로써 명령줄에서 실행할 수 있는 형태로 빌드할 수 있게 됩니다.

  • name = "main"
    실행 파일의 이름입니다. scarb execute -p cairo_playground 명령을 사용할 때 이 main이 실행됩니다. 나중에 여러 개의 실행 대상이 있을 경우 이름으로 구분할 수 있습니다.

  • function = "cairo_playground::main"
    이 부분이 가장 중요한데:

    • cairo_playgroundScarb.toml[package] 섹션에 명시된 패키지 이름입니다.
    • ::main은 해당 패키지의 루트 모듈(src/lib.cairo) 안에 정의된 main 함수를 뜻합니다.
    • 즉, "cairo_playground::main"은 "src/lib.cairo 안의 main 함수를 프로그램 진입점(entry point)으로 사용한다"는 의미입니다.
  • Cairo는 Rust와 비슷한 모듈 시스템을 사용하기 때문에, 패키지명::함수명으로 진입점을 지정할 수 있으며, src/lib.cairo가 암묵적으로 루트 모듈로 취급되므로 별도로 파일 경로를 지정하지 않아도 자동으로 찾아 실행합니다.

  • cairo_execute = "2.11.4"
    Cairo 프로그램을 실행할 수 있도록 도와주는 플러그인입니다. Cairo는 기본적으로 ZK 컨텍스트에서 동작하기 위한 언어이므로, 일반적인 실행 기능은 이 플러그인을 통해 제공됩니다.
    """


3. 예제 코드 작성

이제 src/lib.cairo 파일에 가서 간단한 함수 코드를 작성해봅니다.

/// 두 수를 더해서 결과가 예상한 값과 같은지 검증하는 함수
fn verify_addition(a: u16, b: u16, expected: u16) -> bool {
    let result = a + b;
    result == expected
}

// 두 수를 곱해서 결과가 예상한 값과 같은지 검증하는 함수
fn verify_multiplication(a: u16, b: u16, expected: u16) -> bool {
    let result = a * b;
    result == expected
}

#[executable]
fn main(input: (u16, u16, u16, u16)) -> bool {
    let (x, y, expectedAdd, exepectedMul) = input;
    //verify_addition 와 verify_multiplication 둘다 만족해야함.
    verify_addition(x, y, expectedAdd) && verify_multiplication(x, y, exepectedMul)
}

이 코드는 두 수의 합과 곱의 결과를 확인해 리턴합니다. Cairo는 순수 함수형 스타일이며, #[executable] 어노테이션이 붙은 함수가 프로그램의 진입점입니다.


4. 실행해보기

터미널에서 다음 명령어로 실행합니다:

 scarb execute -p cairo_playground --print-program-output --arguments "5,6,11,30"

출력 결과는 다음과 같을 것입니다:

Program output:
[0, 1]
  • [0, 1]에서 0은 정상 종료를 의미하며,
  • 1는 실제 반환된 결과값입니다. (참)

5. Prove: 실행 결과에 대한 증명 생성하기

Cairo의 가장 독특한 기능은 실행 결과에 대해 "정말로 이 코드가 올바르게 실행되었는지"를 증명할 수 있다는 점입니다.

즉, 단순히 어떤 숫자를 더했다는 결과만 보여주는 게 아니라,

"이 코드는 Cairo 프로그램으로 정확히 실행되었고, 그 결과가 맞다는 것을 수학적으로 증명할 수 있다"
는 것입니다.

이런 방식의 증명을 Zero-Knowledge Proof (ZKP) 라고 부릅니다. Cairo는 이 기능을 기본으로 내장하고 있어서, 몇 가지 명령어만으로 증명을 생성할 수 있습니다.

증명 생성 명령어

scarb prove --execution-id <번호>

<번호>는 실행했던 기록의 ID입니다. 예를 들어, execution1 디렉토리가 생겼다면 --execution-id 1로 입력합니다.

예시

scarb prove --execution-id 1

성공적으로 생성이 완료되면 다음과 같이 출력됩니다.

Proving cairo_playground
Saving proof to: target/execute/cairo_playground/execution1/proof/proof.json

proof.json 파일은 실행의 정확성을 증명하는 데이터입니다. 누군가에게 이 파일과 함께 실행 입력을 주면, 결과가 올바른지 검증할 수 있습니다.

6. Verify: 증명 검증하기

이제 생성된 증명을 검증해보겠습니다:

scarb verify --execution-id 5

성공적으로 검증되면 다음과 같은 메시지를 확인할 수 있습니다:

Verifying cairo_playground
Verified proof successfully

위에서 실행한 (5,6,11,30) → 1 계산이 올바르게 수행되었음을 보장하는 제로 지식 증명(ZK proof) 이 생성되었으며, 제3자는 입력값이나 내부 과정을 보지 않고도 이 결과가 맞다는 것을 검증할 수 있습니다.

코드의 길이가 너무 짧으면 Verify에 실패할 수도 있습니다.


7. 증명 관련 아티팩트 구조

다음은 target/execute/cairo_playground/execution5/폴더 구조의 예시이다:

target/
└── execute/
    └── cairo_playground/
        └── execution5/
            ├── memory.bin
            ├── trace.bin
            ├── air_public_input.json
            ├── air_private_input.json
            ├── program_output.json
            └── proof/
                └── proof.json
  • trace.bin, memory.bin: 프로그램의 실행 추적 및 메모리 상태
  • air_*.json: STARK 증명 시스템용 입력
  • proof/proof.json: 최종 생성된 증명 파일
  • program_output.json: 프로그램 실행 결과

이런 구조 덕분에 Cairo는 일반적인 실행 언어가 아니라 ZK-Friendly한 실행 언어이라는 것을 알 수 있다.


Cairo 명령어 요약

Cairo로 실행 가능한 프로그램을 만들고 증명·검증까지 수행하는 전체 흐름을 아래에 정리했습니다.

단계명령어설명
프로젝트 생성scarb new <패키지명>새 Cairo 프로젝트를 생성합니다.
디렉토리 이동cd <패키지명>생성된 프로젝트 폴더로 이동합니다.
빌드scarb build프로그램을 컴파일합니다.
실행scarb execute -p <패키지명> --print-program-output --arguments "5,6,11,30"실행 결과를 확인합니다.
증명 생성scarb prove --execution-id <번호>해당 실행 결과에 대한 ZK 증명을 생성합니다.
증명 검증scarb verify --execution-id <번호>

참고 자료

0개의 댓글