Semaphore docs V1 번역본

donghyun·2022년 7월 26일
1

**
현재는 V2로 운영중이며 컨셉은 동일하지만 많은 부분이 바뀌었으며 V2는 다음을 참고하면 된다.
세마포어 홈페이지 about V2: semaphore.appliedzkp.org

About

Semaphore는 이더리움 사용자가 본래의 신원을 드러내지 않고 이전에 가입했던 집단의 멤버십을 증명할 수 있게 해주는 영지식 가제트이다. 동시에, 사용자가 임의의 문자열에 대한 그들의 승인을 알릴 수 있다. Semaphore는 이더리움 dApp을 위한 간단하고 일반적인 privacy layer로 설계되었다. 사용사례로는 비밀 투표, 내부 고발, mixers, 익명 인증 등등을 포함한다. 마지막으로, Semaphore는 이중 신호 또는 이중 지불을 방지하는 간단한 내장 메커니즘을 제공한다.

이 가제트는 함께 동작하는 스마트 컨트랙트와 영지식 요소로 구성된다. Semaphore 스마트 컨트랙트는 온체인에서 상태, 권한, 증명 검증을 처리한다. 영지식 요소들은 오프체인에서 작동하는데, 사용자가 증명을 생성할 수 있게하여 그것이 유효하면 스마트컨트랙트가 상태를 업데이트할 수 있게 한다.

Semaphore와 기본 암호화 메커니즘을 공식적인 설명이 필요하다면 이 문서도 참고하면 된다. here

Semaphore는 최종 사용자가 아닌 스마트 컨트랙트와 dApp 개발자를 위해 고안되었다. 개발자는 사용자 친화적인 privacy를 제공하기 위해서 Sempahore 기능들을 추상화해야 한다.

here에서 간단한 데모를 시도하거나 here에서 높은 레벨의 설명을 읽을 수 있다.

Basic Features

요약하자면, Semaphore는 다음과 같은 기능들을 제공한다.

  1. 스마트 컨트랙트에 신원을 등록하고 다음을 수행
  2. 신호를 브로드캐스트:
    • 등록되어 있는 신원 집합에서 익명으로 자신의 신원을 증명하고, 동시에 다음을 수행
    • 문자열이 사용자한테 고유하고 컨트랙트의 현재 external nullifier(?)일때만 그 임의의 문자열(주제에 비슷한 고유한 값)을 컨트랙트에 공개적으로 저장한다. 이는 external nullifier 아래에서 똑같은 메시지에 대한 이중신호가 불가능하다는 것을 의미한다.

About external nullifier

external nullifier을 각 사용자가 하나의 투표만 행사할 수 있는 투표 부스로 생각하면 된다. 사용자가 똑같은 부스에서 두 번째 투표를 시도한다면 그 투표는 무효가 된다.

external nullifier는 어떤 29-byte 값이다. Semaphore는 항상 하나의 external nullifier(컨트랙트 배포시 설정되는)와 함께 시작한다. Semaphore 컨트랙트의 소유자는 추가적인 external nullifiers, 비활성화, (기존에 있는 것)재활성화를 할 수 있다.

특정 사용자가 활성화 되어있는 external nullifier n에게 신호를 처음 브로드캐스트할 때, 등록되어 있는 사용자 집단의 멤버십에 대한 사용자의 증명이 유효하면 트랜잭션이 성공할 것이다. 그러나 동일한 작업을 똑같은 n에게 두 번째로 수행하면 트랜잭션은 실패한다.

추가로, 비활성화 된 external nullifier에게 보내진 모든 신호 브로드캐스트는 실패한다.

각 클라이언트 어플리케이션은 각각에 맞는 privacy 목표를 달성하려면 semaphore의 기능을 고유한 방법으로 사용해야 한다. Mixer로 예를 들면, 다음과 같은 하나의 external nullifier를 사용한다.

Signal(신호)External nullifier
(수신자의 주소, 중개자의 주소, 중개자의 수수료)의 해시Mixer 컨트랙트의 주소

이것은 자금(수수료를 받는 중개자를 통해)을 익명 출금 할 수 있게 해주며, 단 하나의 external nullifier만 있기 때문에 이중 지출을 막아준다.

익명 투표 앱은 다르게 구성된다.

Signal(신호)External nullifier
응답자 답변의 해시질문의 해시

이것은 모든 사용자가 임의의 질문에 임의의 답변(ex. 예, 아니오 또는 아마도)으로 투표할 수 있도록 한다. 사용자는 질문당 한번만 투표할 수 있다.

About the code

이 저장소에는 Solidity로 작성된 semaphore의 컨트랙트 코드, circom으로 작성된 zk-SNARK 회로를 포함하고 있다. 또한 테스트 진행을 위한 Typescript 코드도 포함하고 있다.

코드는 ABDK Consulting의 감사를 받았고, 그들이 제안한 보안 및 효율성 수정 사항이 적용되었다.

zk-SNARK 증명 및 (semaphore에 대한)확인 키를 생성하기 위한 다자간 계산은 곧 시작될 것이다.

How it works

Inserting identities

신원(identity)은 다음 정보로 구성되어 있다.

  1. EdDSA 개인 키 (이더리움 개인 키가 아니다.)
  2. identity nullifier: 임의의 32-byte 값
  3. identity trapdoor: 임의의 32-byte 값

신원 약속(identity commitment)은 다음의 Pedersen 해시이다:

  1. 공개 키(identity의 개인 키와 연관된)

  2. identity nullifier

  3. identity trapdoor

    신원을 등록하기 위해, 사용자는 그들의 신원 약속을 Semaphore의 신원 트리에 추가해야한다. 해당 작업은 Semaphore 컨트랙트의 insertIdentity(uint256 _identityCommitment)함수를 호출함으로써 할 수 있다. API reference를 통해 더많은 정보를 얻을 수 있다.

Broadcasting signals

신호를 브로드캐스트하려면, 사용자가 다음 Semaphore 컨트랙트의 함수를 호출해야 한다:

broadcastSignal(
bytes memory _signal,
uint256[8] memory _proof,
uint256 _root,
uint256 _nullifiersHash,
uint232 _externalNullifier
)

_signal: 브로드캐스트할 신호

_proof: zk-SNARK 증명(아래 참조)

_root: 신원 트리(사용자의 신원 약속이 마지막으로 삽입된 leaf)의 루트

_nullifiersHash: 고유하게 파생된 (external nullifier, 사용자의 신원 nullifier, 그들의 신원 약속에 대한 머클 경로 index)의 해시. 이것은 사용자가 동일한 external nullifier를 사용해 두 번 이상 신호를 브로드캐스트할 수 없도록 한다.

_externalNullifier: 신호가 브로드캐스트되는 외부 nullifier

zk-SNARK증명을 하려면 아래 설명된 대로 semaphore의 zk-SNARK회로에 의해 생성된 제약 조건을 만족해야 한다:

The zk-SNARK circuit

semaphore-base.circom의 회로는 다음을 증명하는 데 도움이 된다.

That the identity commitment(신원 약속) exists in the Merkle tree

Private inputs:

  • identity_pk: 사용자의 EdDSA 공개 키
  • identity_nullifier: 랜덤 32-byte 값(사용자가 저장해야 할)
  • identity_trapdoor: 랜덤 32-byte 값(사용자가 저장해야 할)
  • identity_path_elements: 사용자의 신원 약속에 대한 머클 경로에 따른 값 (V2에선 treeSiblings[nLevels])
  • identity_path_index[n_levels]: 사용자의 신원 약속에 대한 머클 경로에 해당하는 트리 레벨별 방향(좌/우)(V2에선 treePathIndices[nLevels])

Public inputs:

  • root: 신원 트리의 머클 루트

Procedure:

회로(circuit)는 공개 키, identity nullifier, identity trapdoor를 해시하여 신원 약속(identity commitment)을 생성한다. 그런 다음 머클 루트와 신원 약속에 대한 머클 증명을 확인한다.

That the signal was only broadcasted once

Private inputs:

  • identity_nullifier: 랜덤 32-byte 값(사용자가 저장해야 할)
  • identity_path_index: 사용자의 신원 약속에 대한 머클 경로에 해당하는 트리 레벨별 방향(좌/우)

Public inputs:

  • external_nullifier: 29-byte external nullifier
  • nullifiers_hash: identity nullifier, external nullifier, Merkle path index(identity_path_index)의 해시

Procedure:

회로(circuit)는 주어진 identity nullifier, external nullifier, Merkle path index를 해시하고 주어진 nullifiers hash와 일치하는지 비교한다. 추가로 스마트 컨트랙트는 이전에 이 nullifiers hash를 보지 않았음을 보장한다. 이렇게 이중 신호는 불가능하다.

That the signal was truly broadcasted by the user who generated the proof

Private inputs:

  • identity_pk: 사용자의 EdDSA 공개 키
  • auth_sig_r: 신호의 서명의 r값
  • auth_sig_s: 신호의 서명의 s값

Public inputs:

  • signal_hash: 신호의 해시
  • external_nullifier: 29-byte external nullifier

Procedure:

회로(circuit)는 신호 해시와 external nullifier를 해시하고 주어진 공개키와 서명에 대해 이 출력을 검증한다. 이는 신호의 신뢰성을 보장하고 front-running 공격을 방지한다.

Cryptographic primitives

Semaphore는 머클 트리에 MiMC, identity commitments에 Pedersen commitments(커밋), nullifiers hash에 Blake2, 서명에 EdDSA를 사용한다.

MiMC는 비교적 새로운 해시 함수이다. 우리는 Albrecht et al에서 권장하는 MiMC 구성을 사용하고, and there is a prize to break MiMC at http://mimchash.org which has not been claimed yet.

우리는 머클 트리 및 EdDSA 서명 검증을 위한 Poseidon 해시 함수를 사용하는 Semaphore 버전도 구현했다. 이것은 MiMC보다 보안이 우수할 것이며, 신원 삽입을 통해 약 20% 가스를 줄일 수 있으며, 증명 시간도 대략 절반으로 줄일 수 있다. 단, Poseidon-related circuits과 EVM 바이트코드 생성기(generator)는 감사를 받지 않았으므로 사용에 주의해야한다. 그것을 사용하려면 feat/poseidon브랜치를 분기하면 된다.

Quick start

Semaphore는 Node 11.14.0에서 테스트 되었다. Node 12 LTE에서도 실행되지만 소스코드에서 개발하려는 경우 Node 11.14.0을 사용하는 것이 좋다.(종속성 중 script는 Node12에서 컴파일 될 수 없기때문에)

노드 버전을 관리하려면 nvm을 사용.

이 저장소를 클론하고 종속성을 다운받고 소스코드를 빌드한다:

git clone git@github.com:kobigurk/semaphore.git && \
cd semaphore && \
npm i && \
npm run bootstrap && \
npm run build

주의: circuits, config, contracts subpackages를 관리하는데 lerna를 사용한다. 이러한 디렉토리에서 npm install을 실행하지 마시오. 대신에 메인 디렉토리에서 npm run bootstrap를 실행하면 된다.

다음으로, 컴파일된 zk-SNARK circuit, proving key,and verification key 모두 다운 받는다.(toxic waste가 안전하게 폐기 되었다는 확실성이 없기때문에 이러한 키들은 테스팅 목적이며, 제품을 위한 것이 아니다.)

circuit, proving key,and verification key 모두 다운받기위해 실행한다:

# Start from the base directory

./circuits/scripts/download_snarks.sh

위의 파일을 로컬로 대신 생성하려면 다음을 실행한다:

# Start from the base directory

./circuits/scripts/build_snarks.sh

이 과정은 45분 정도 소요된다.

Solidity 컨트랙트들을 빌드($PATH에 solc v 0.5.12가 설치되어 있어야 한다.):

# Start from the base directory

cd contracts && \
npm run compileSol

contracts/ 디렉토리에 있는 동안 테스트를 실행:

# The first command tests the Merkle tree contract and the second
# tests the Semaphore contract

npm run test-semaphore && \
npm run test-mt

Usage

Semaphore 컨트랙트는 익명 신호에 의존하는 어플리케이션을 생성하기위해 다른 컨트랙트를 위한 base layer를 형성한다.

첫 째로, static한 [proving key, verification key, and circuit file]들이 사용자가 쉽게 이용할 수 있는지 확인해야 한다. 이들은 CDN에서 호스팅되거나 (당신의)어플리케이션 코드와 함께 번들로 제공될 수 있다.

Semaphore팀은 아직 신뢰할 수 있는 설정을 수행하지 않았으므로 이러한 파일의신뢰 버전은 아직 사용할 수 없다.

그럼에도, 이러한 파일들의 신뢰할 수 없는 버전은 circuits/scripts/download_snarks.sh스크립트를 통해 얻을 수 있다.

다음으로, Semaphore 메커니즘에 대한 완전한 유연성을 갖기 위해, Client 컨트랙트를 작성하고 Semaphore 컨트랙트의 소유자를 Client 컨트랙트의 주소로 설정한다. Semaphore 컨트랙트를 배포하는 Client 컨트랙트의 생성자에 적을 수도 있고 즉석에서도 할 수 있다.

Client 컨트랙트가 Semaphore 컨트랙트의 소유자인 경우, Client 컨트랙트는 addExternalNullifier()같은 소유자 전용 Semaphore 함수를 호출할 수 있다.

Add, deactivate, or reactivate external nullifiers

이러한 함수들은 external nullifier을 각각 추가, 비활성화, 재활성화 한다. 각각의 신원은 external nullifier에 오직 한번의 신호를 보낼 수 있고, 신호는 활성화된 external nullifier에만 성공적으로 브로드캐스트 될 수 있으므로, 이러한 함수들은 다중 external nullifiers가 필요한 혹은 활성화/비활성화 하는 사용사례를 만들 수 있다.

자세한 내용은 high-level explanation of Semaphore를 참고

Set broadcast permissioning

기본적으로 Semaphore.broadcastSignal() 권한이 부여되므로, 누구든지 신호를 브로드캐스트할 수 있게 하려면 Semaphore 컨트랙트의 소유자(client 컨트랙트 와 외부 소유 계정 모두)는 setPermissioning(false)를 먼저 깨워야한다.

SemaphoreClient.sol를 예시로 참고

Insert identities

신원 약속(identity commitment)를 생성하려면 libsemaphore 함수 genIdentity() 그리고 genIdentityCommitment() Typescript(혹은 Javascript) 함수를 사용하면 된다.

const identity: Identity = genIdentity()
const identityCommitment = genIdentityCommitment(identity)

identity는 안전한곳에 보관해야한다. serialiseIdentity() 함수가 다음과 같이 도울 수 있다.

const serialisedId: string = serialiseIdentity(identity: Identity)

이것은 Identity를 JSON 문자열으로 다음과 같이 변환해준다.

["e82cc2b8654705e427df423c6300307a873a2e637028fab3163cf95b18bb172e","a02e517dfb3a4184adaa951d02bfe0fe092d1ee34438721d798db75b8db083","15c6540bf7bddb0616984fccda7e954a0fb5ea4679ac686509dc4bd7ba9c3b"]

이 문자열을 다시 Identity로 변환하려면, unSerialiseIentity()를 사용

const id: Identity = unSerialiseIentity(serialisedId)

Broadcast signals

먼저 신원 트리의 leaves(잎)을 얻는다.(순차적으로, 사용자 신원 약속까지 혹은 그 이상)

const leaves = <list of leaves>

그 다음, 디스크(또는 원격 소스)에서 회로를 load한다.

const circuitPath = path.join(__dirname, '/path/to/circuit.json')
const cirDef = JSON.parse(fs.readFileSync(circuitPath).toString())
const circuit = genCircuit(cirDef)

그 다음, libsemaphore의 genWitness() helper 함수를 사용한다.

const result = await genWitness(
	signal,
	circuit,
	identity,
	leaves,
	num_levels,
	external_nullifier,
)
  • signal: 브로드캐스트할 신호인 문자열
  • circuit: genCircuit()의 출력(위 참조)
  • identity: (identity 객체)사용자의 신원
  • leaves: 트리의 잎 목록(위 참조)
  • num_levels: 머클 트리의 깊이
  • external_nullifier: 브로드캐스트할 external nullifier

proving key를 디스크(또는 원격 소스)에서 load한다.

const provingKeyPath = path.join(__dirname, '/path/to/proving_key.bin')
const provingKey: SnarkProvingKey = fs.readFileSync(provingKeyPath)

증명을 생성(최신 컴퓨터에서 30-45초 소요)

const proof = await genProof(result.witness, provingKey)

broadcastSignal() 매개변수 생성

const publicSignals = genPublicSignals(result.witness, circuit)
const params = genBroadcastSignalParams()

마지막으로 매개변수를 사용해 broadcastSignal()를 깨운다.

const tx = await semaphoreClientContract.broadcastSignal(
	ethers.utils.toUtf8Bytes(signal),
	params.proof,
	params.root,
	params.nullifiersHash,
	external_nullifier,
	{ gasLimit: 500000 },
)

Contract API

Constructor

Contract ABI:

constructor(uint8 _treeLevels, uint232 _firstExternalNullifier)

  • _treeLevel: 신원 트리의 깊이
  • _firstExternalNullifier: 추가할 첫 번째 identity nullifier

신원 트리의 깊이는 컨트랙트에 추가될 수 있는 신원 약속의 수를 결정한다: 2 ^ _Levels. 트리가 가득차면, 추가 삽입이 실패할 것이다. revert 이유 IncrementalMerkleTree: tree is full.

첫번째 external nullifier는 컨트랙트에 external nullifier로 추가될 것이고, 이것은 배포가 완료되면 활성화 된다.

Add, deactivate, or reactivate external nullifiers

contract ABI:

addExternalNullifier(uint232 _externalNullifier)

컨트랙트에 external nullifier 추가. 소유자만 할 수 있음. 이 external nullifier는 추가되면 활성화된다.

  • _externalNullifier: 설정할 새로운 external nullifier

deactivateExternalNullifier(uint232 _externalNullifier)

  • _externalNullifier: 비활성화할 존재하는 external nullifier

external nullifier을 비활성화. 이 함수가 작동하려면 external nullifier는 이미 활성화되어 있어야 한다. 소유자만이 할 수 있다.

reactivateExternalNullifier(uint232 _externalNullifier)

external nullifier을 재활성화. 이 함수가 작동하려면 external nullifier는 이미 비활성화되어 있어야 한다. 소유자만이 할 수 있다.

  • _externalNullifier: 재활성화할 비활성화되어 있는 external nullifier

Insert identities

Contract ABI:

function insertIdentity(uint256 _identityCommitment)

  • _identity_commitment: 사용자의 공개 키와 identity nullifier(랜덤 31-byte 값)의 해시인 사용자의 신원 약속. 이것은 Pedersen 해시의 출력 값이어야 한다. 이를 확인하는 것은 호출자의 책임이다.

Off-chain libsemaphore helper functions:

컨트랙트에 전달할 Identity 객체를 생성하기위해 genIdentity()를 사용하고, _identityCommitment값을 생성하기 위해 genIdentityCommitment(identity: Identity)를 사용한다.

identity를 문자열로 변환하거나 되돌리려면, 데이터베이스에 저장하거나 안전한곳에 저장해야한다.(serialiseIdentity() 와 unSerialiseIdentity()를 사용)

자세한 정보는 Usage section on inserting identities를 확인

Broadcast signals

Contract ABI:

broadcastSignal(
	bytes memory _signal,
	uint256[8] memory _proof,
	uint256 _root,
	uint256 _nullifiersHash,
	uint232 _externalNullifier
)
  • _signal: 브로드캐스트할 신호
  • _proof: zk-SNARK 증명 (위 참조)
  • _root: 신원 트리의 root, (사용자의 신원 약속이 마지막 잎에 추가된)
  • _nullifiersHash: external nullifier의 고유하게 파생된 해시, 사용자의 identity nullifier, 그리고 사용자의 신원 약속의 머클 경로 index. 이는 사용자가 동일한 external nullifier을 두번 이상 사용하여 신호를 브로드캐스트할 수 없게 한다.
  • _externalNullifier: 신호가 브로드캐스트되는 external nullifier

Off-chain libsemaphore helper functions:

libsemaphore의 genWitness(), genProof(), genPublicSignals()를 사용하고 마지막으로 컨트랙트의 broadcastSignal()함수의 매개변수를 생성하기위해 genBroadcastSignalParams() 사용한다.

자세한 정보는 Usage section on broadcasting signals를 확인

libsemaphore

libsemaphore는 Typescript로 작성된 Semaphore용 helper라이브러리이다. 신원, 증명 생성과 같은 일반적인 작업 및 객체에 대한 유용한 추상화를 제공하므로 Javascript나 Typescript로 작성된 모든 dApp은 이를 사용해야 한다.

이 저장소의 semaphore 코드는 v1.0.14이상에서만 작동한다. v0.0.x는 이전에 감사된 semaphore코드와 호환된다.

Available types, interfaces, and functions

Types

SnarkBigInt

snarkjs 라이브러리와 호환되는 큰 정수 타입. 이 유형의 변수를 bigNumber 혹은 BigInt와 혼합하는 것은 바람직하지 않다. snarkjs.bigInt를 캡슐화한다.

EddsaPrivateKey

EdDSA 개인 키(32 bytes이어야 함). Buffer를 캡슐화한다.

EddsaPublicKey

EdDSA 공개 키. SnarkBigInt의 배열을 캡슐화한다.

SnarkProvingKey

Proving key, 비밀 증거(목격자?)와 함께 사용되고, 해당 증거(목격자?)에 대한 zk-SNARK 증명을 생성한다. Buffer을 캡슐화한다.

SnarkVerifyingKey

zk-SNARK와 SnarkProof에 대한 공개 inputs와 사용될 때 증명의 유효성을 증명할 수 있는 verifying key. Buffer을 캡슐화한다.

SnarkWitness

zk-SNARK에 대한 비밀 inputs. SnarkBigInt의 배열을 캡슐화한다.

SnarkPublicSignals

zk-SNARK에 대한 공개 inputs. SnarkBigInt의 배열을 캡슐화한다.

Interfaces

EddsaKeyPair

EddsaPublicKey 및 EddsaPrivateKey를 캡슐화한다.

interface EddsaKeyPair {
		pubKey: EddsaPublicKey,
		privKey: EddsaPrivateKey,
}

Identity

신원 약속(identity commitment)를 생성하는데 필요한 모든 정보를 캡슐화하고, 브로드캐스트 신호를 위한 SnarkProof를 생성하는데 중요하다.

interface Identity {
		keypair: EddsaKeyPair,
		identityNullifier: SnarkBigInt,
		identityTrapdoor: SnarkBigInt,
}

SnarkProof

broadcastSignal()은 _proof 매개변수를 위해 uint256[8] 배열을 허용해야 한다. genBroadcastSignalParams() 참고.

interface SnarkProof {
		pi_a: SnarkBigInt[]
		pi_b: SnarkBigInt[][]
		pi_c: SnarkBigInt[]
}

Functions

genPubKey(privKey: EddsaPrivateKey): EddsaPublicKey

제공된 private key로 public EdDSA key를 생성. private key를 생성하기 위해, crypto.randomBytes(32)를 사용 where crypto is the built-in Node or browser module.

genIdentity(): Identity

fresh하고 random한 Identity를 생성하기 위한 편의 함수이다. EddsaKeyPair를 위한 32-byte private key가 랜덤하게 생성된다. 고유한(별개의) 31-byte identity nullifier와 31-byte identity trapdoor 값 처럼

serialiseIdentity(identity: Identity): string

Identity를 다음과 같이 JSON 문자열로 변환

["e82cc2b8654705e427df423c6300307a873a2e637028fab3163cf95b18bb172e","a02e517dfb3a4184adaa951d02bfe0fe092d1ee34438721d798db75b8db083","15c6540bf7bddb0616984fccda7e954a0fb5ea4679ac686509dc4bd7ba9c3b"]

이 함수를 serializeIdentity로 철자할 수 있다.

이 문자열을 다시 Identity로 변환하고 싶다면 unSerialiseIdentity()를 사용.

unSerialiseIdentity(string: serialiseId): Identity

serialiseIdentity()의 string 출력을 Identity로 변환

이 함수를 unSerializeIdentity로 철자할 수 있다.

genIdentityCommitment(identity: Identity): SnarkBigInt

(public key, identity nullifier, identity trapdoor)의 해시인 신원 약속(identity commitment) 생성

async genProof(witness: SnarkWitness, provingKey: SnarkProvingKey): SnarkProof

Semaphore 컨트랙트의 broadcastSignal() 함수에 보내질 수 있는 SnarkProof 생성. verifyProof()을 사용하여 off-chain으로도 검증 될 수 있다.

genPublicSignals(witness: SnarkWitness, circuit: SnarkCircuit): SnarkPublicSignals

컨트랙트 또는 verifyProof()에 제공될 공개 신호를 추출한다.

verifyProof(verifyingKey: SnarkVerifyingKey, proof: SnarkProof, publicSignals: SnarkPublicSignals): boolean

올바른 verifying key와 공개 신호와 주어진 proof가 유효하면 true를 반환, 아니면 false 반환

signMsg(privKey: EddsaPrivateKey, msg: SnarkBigInt): EdDSAMiMcSpongeSignature)

private key privKey를 사용해 msg 메시지를 사인하기위해 circomlib.eddsa.signMiMCSponge를 캡슐화한다.

verifySignature(msg: SnarkBigInt, signature: EdDSAMiMcSpongeSignature, pubKey: EddsaPublicKey): boolean

서명된 msg의 암호화 signature가 pubKey와 관련된 private key에서 왔다면 true를 반환, 아니면 false 반환

setupTree(levels: number, prefix: string): MerkleTree

Semaphore zk-SNARK circuit의 예상과 동일한 레벨의 수를 가진 semaphore-merkle-tree를 사용해 생성된 머클트리를 반환. 이 트리는 또한 circuit이 기대하는 MimcSpongeHasher을 사용하도록 구성되어 있다.

levels는 트리의 레벨의 수를 설정한다. 예를들어, 20 levels의 트리는 최대 1048576 deposits을 지원한다.

genCircuit(circuitDefinition: any)

new snarkjs.Circuit(circuitDefinition)을 반환. circuitDefinition 객체는 .circom파일을 .json파일로 변환하는 circom 명령의 JSON.parse된 결과여야한다.

async genWitness(...)

이 함수는 다음과 같은 signature을 가진다:

const genWitness = async (
	signal: string,
	circuit: SnarkCircuit,
	identity: Identity,
	idCommitments: SnarkBigInt[] | BigInt[] | ethers.utils.BigNumber[],
	treeDepth: number,
	externalNullifier: SnarkBigInt,
)
  • signal은 브로드캐스트하려는 문자열이다.
  • circuit는 genCircuit()의 출력이다.
  • identity는 등록된 신원의 집합에 속한다는 것을 증명하고 싶은 신원 약속의 Identity이다.
  • idCommitments는 등록된 신원 약속들의 배열이다. 즉, 트리의 잎
  • treeDepth는 머클 트리가 사용하는 레벨의 수이다.
  • externalNullifier는 현재 external nullifier이다.

다음과 같이 객체를 반환:

  • witness: genProof()에 전달할 증인
  • signal: Semaphore에 의해 계산된 신호. 이것은 (수신자(recipient)의 주소, 중개자(relayer)의 주소, 수수료)의 해시
  • signalHash: 계산된 신호의 해시
  • msg: external nullifier과 signal hash의 해시
  • signature: 위 msg의 서명
  • tree: 신원 약속으로 업데이트된 머클 트리 객체
  • identityPath: 신원 약속으로 가는 머클 경로
  • identityPathIndex: 신원 약속의 leaf index
  • identityPathElements: 위의 머클 경로를 따르는 요소

증거를 생성하는데 단지 witness만 필수적이다. 다른 데이터들은 디버깅과 추가적인 off-chain 검사에만 유용하다. 예를들어, 머클 트리 루트와 서명을 검증하는 것들

formatForVerifierContract = (proof: SnarkProof, publicSignals: SnarkPublicSignals

proof와 publicSignals의 데이터를 문자열로 변환하고 snarkjs의 verifier.sol이 하용할 수 있도록 proof.pi_b의 요소들을 재정렬한다. 구체적으로 다음과 같은 객체를 반환한다.

{
	a: [ proof.pi_a[0].toString(), proof.pi_a[1].toString() ],
	b: [
			 [ proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString() ],
			 [ proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString() ],
	]
	c: [ proof.pi_c[0].toString(), proof.pi_c[1].toString() ],
	input: publicSignals.map((x) => x.toString()),
}

stringifyBigInts = (obj: any) ⇒ object

snarkjs.stringifyBigInts()를 캡슐화한다. SnarkProof를 JSON으로 변환하기 편하게 만들어 준다.

unstringifyBigInts = (obj: any) ⇒ object

snarkjs.unstringifyBigInts()를 캡슐화한다. JSON을 SnarkProof으로 변환하기 편하게 만들어 준다.

genExternalNullifier = (plaintext: string) ⇒ string

각각의 external nullifier은 최대 29bytes여야 한다. 이 함수는 주어진 plaintext를 keccak-256-hashes하고, 마지막 29bytes를 얻어서, (처음부터)0으로 채우고 붙인다. 결과로 16진수 문자열을 반환한다.

Multi-party trusted setup

Semaphore 작성자는 신뢰할수 있는 설정의 1단계로 Perpetual Powers of Tau ceremony를 사용할것이고 랜덤 beacon을 사용할 것이다.

profile
Blockchain

0개의 댓글