페이지

2024년 11월 16일 토요일

JWT 토큰 생성과 유효성 확인 과정

JWT 토큰 생성과 유효성 확인 과정

API 서비스를 개발하고 이에 대한 접근 권한을 제어하기 위하여 JSON Web Token(JWT)을 활용할 수 있습니다. 이 문서에서는 JWT 토큰의 생성과 유효성 확인 과정을 그림과 Python 코드를 사용하여 설명합니다. 전자서명 알고리즘으로는 HS256을 사용하였습니다.

  • HS256(HMAC-SHA256)
    • 대칭키 암호화 방식
  • HMAC(Hash-based Message Authentication Code)
    • 해시 함수를 기반으로 메시지 인증 코드를 생성하는 알고리즘

다음은 토큰 생성과 유효성 확인 과정에서 사용하게 될 Base64 인코딩/디코딩 함수입니다.

import base64
import hashlib
import hmac

def base64_encode(input_as_bytes):
    b = base64.urlsafe_b64encode(input_as_bytes).decode('utf-8')
    return b.rstrip('=')

def base64_decode(input_as_string):
    padding = 4 - len(input_as_string) % 4
    input_as_string = input_as_string + '=' * padding
    return base64.urlsafe_b64decode(input_as_string.encode('utf-8')).decode('utf-8')

1. 토큰 생성

1.1. 다이어그램

1.2. Python 구현

def create_jwt_token(header_obj_str, payload_obj_str, secret):
    header = base64_encode(header_obj_str.encode('utf-8'))
    payload = base64_encode(payload_obj_str.encode('utf-8'))
    header_plus_payload = f'{header}.{payload}'
    
    m = hmac.new(secret.encode('utf-8'), digestmod=hashlib.sha256)
    m.update(header_plus_payload.encode('utf-8'))
    d = m.digest()
    signature = base64_encode(d)
    print('** Signature (algorithm: HS256) **')
    print(f'Byte size: {len(d)}')
    print(f'Base64 encoded: {signature}')

    jwt_token = f'{header_plus_payload}.{signature}'
    return jwt_token

header_obj_str = '{\
"typ":"JWT",\
"alg":"HS256"\
}'

payload_obj_str = '{\
"iss":"fun-with-jwts",\
"sub":"AzureDiamond",\
"jti":"f6c1097f-cc48-4949-a627-8b94fc5e37ba",\
"iat":1596185001,\
"exp":1596185061\
}'

secret = 'my-secret'

jwt_token = create_jwt_token(header_obj_str, payload_obj_str, secret)
print('** JWT token (structure: header.payload.signature) **')
print(jwt_token)

실행 결과:

** Signature (algorithm: HS256) **
Byte size: 32
Base64 encoded: UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k
** JWT token (structure: header.payload.signature) **
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k

입력

  • header object

    {
        "typ": "JWT",
        "alg": "HS256"
    }
    
  • payload object

    {
        "iss": "fun-with-jwts",
        "sub": "AzureDiamond",
        "jti": "f6c1097f-cc48-4949-a627-8b94fc5e37ba",
        "iat": 1596185001,
        "exp": 1596185061
    }
    
  • secret

    my-secret
    

출력

  • token

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k
    

2. 토큰 유효성 확인

2.1. 다이어그램

2.2. Python 구현

def validate_jwt_token(token, secret):
    pos = token.rfind('.')
    header_plus_payload = token[:pos]
    signature = token[pos+1:]
    
    m = hmac.new(secret.encode('utf-8'), digestmod=hashlib.sha256)
    m.update(header_plus_payload.encode('utf-8'))
    d = m.digest()
    
    signature_derived = base64_encode(d)
    
    return signature_derived == signature

token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k'
secret = 'my-secret'

is_valid = validate_jwt_token(token, secret)
print(f'** is_valid: {is_valid} **')

실행 결과:

** is_valid: True **

입력

  • token

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdW4td2l0aC1qd3RzIiwic3ViIjoiQXp1cmVEaWFtb25kIiwianRpIjoiZjZjMTA5N2YtY2M0OC00OTQ5LWE2MjctOGI5NGZjNWUzN2JhIiwiaWF0IjoxNTk2MTg1MDAxLCJleHAiOjE1OTYxODUwNjF9.UXvXY97CNcHv7LobrBagePBPeGiW2F-Z-nuINSmUy5k
    
  • secret

    my-secret
    

출력

  • is_valid

    True
    

Written with StackEdit.

2024년 11월 10일 일요일

Circom SHA256 해시 예제

Circom SHA256 해시 예제

아래 문서의 예제를 약간 변형해서 SHA256 해시 검증을 실습하였습니다.

회로 생성

  1. 프로젝트 디렉토리에서 회로 파일 program.circom 작성

    pragma circom 2.0.0;
    include "./circomlib/circuits/sha256/sha256.circom";
    
    template program() {
        signal input in[8];
        signal output out[256];
    
        component SHA = Sha256(8);
        SHA.in <== in;
        out <== SHA.out;
    }
    
    component main = program();
    
  2. 프로젝트 디렉토리에서 Git 저장소 circomlib 복제

    git clone https://github.com/iden3/circomlib.git
    
  3. 회로 컴파일

    circom program.circom --r1cs --wasm --sym --c
    

신뢰 설정 - Powers of Tau

  1. 프로젝트 디렉토리에서 ‘powers of tau’ ceremony 시작

    snarkjs powersoftau new bn128 15 pot15_0000.ptau -v
    
  2. 첫 번째 기여

    snarkjs powersoftau contribute pot15_0000.ptau pot15_0001.ptau --name="First contribution" -v
    

신뢰 설정 - Phase 2

  1. program_js 디렉토리에서 Phase 2 준비 (시간이 많이 걸림)

    snarkjs powersoftau prepare phase2 ..\pot15_0001.ptau pot15_final.ptau -v
    
  2. .r1cs 파일과 연관된 .zkey 파일 생성

    snarkjs groth16 setup ..\program.r1cs pot15_final.ptau program_0000.zkey
    
  3. 첫 번째 기여

    snarkjs zkey contribute program_0000.zkey program_0001.zkey --name="1st Contributor Name" -v
    
  4. 검증키 내보내기

    snarkjs zkey export verificationkey program_0001.zkey verification_key.json
    

증명 성공 예시

  1. program_js 디렉토리에 input.json 파일 생성

    정수 1의 big-endian 비트 표현

    {"in":["0","0","0","0","0","0","0","1"]}
    
  2. program_js 디렉토리에서 witness 생성

    node generate_witness.js program.wasm input.json witness.wtns
    
  3. 증명 생성

    snarkjs groth16 prove program_0001.zkey witness.wtns proof.json public.json
    

    public.json 파일의 내용

    [
     "0", "1", "0", "0", "1", "0", "1", "1",
     "1", "1", "1", "1", "0", "1", "0", "1",
     "0", "0", "0", "1", "0", "0", "1", "0",
     "0", "0", "1", "0", "1", "1", "1", "1",
     "0", "0", "1", "1", "0", "1", "0", "0",
     "0", "1", "0", "0", "0", "1", "0", "1",
     ...
    ]
    
  4. 증명 검증

    snarkjs groth16 verify verification_key.json public.json proof.json
    

Python 코드로 입출력 검증

스크립트 실행

input.json 파일로부터 big-endian 비트 배열을 읽어서 바이트 배열로 변환하고 SHA256 해시 생성하여 output.txt에 저장

python calc_sha256_python.py --input-filepath input.json --output-dir .

output.txt

Input Bytes:
   1

Output Bits (Little Endian):
1 1 0 1  0 0 1 0      1 0 1 0  1 1 1 1
0 1 0 0  1 0 0 0      1 1 1 1  0 1 0 0
0 0 1 0  1 1 0 0      1 0 1 0  0 0 1 0
0 0 1 0  1 0 1 0      1 0 1 0  0 0 1 1
1 1 0 1  1 1 0 0      0 1 1 1  1 0 1 1
0 1 1 1  0 1 0 0      1 1 0 1  1 1 0 1
0 0 1 1  0 0 0 1      0 1 0 0  1 0 1 1
1 1 1 0  1 1 0 1      1 1 0 0  0 1 1 1
1 0 0 0  1 0 1 1      0 0 0 0  0 1 1 0
0 1 0 1  0 0 0 0      0 1 1 0  1 0 1 1
1 0 0 0  1 1 0 0      1 1 0 0  0 0 1 1
1 0 1 0  0 0 0 1      1 0 1 0  0 1 0 1
1 1 1 0  1 0 1 1      0 0 1 1  0 0 1 1
0 1 0 0  0 1 1 1      0 0 1 1  1 1 0 0
1 1 1 0  1 1 1 0      1 0 1 0  0 0 0 1
1 0 1 0  0 0 1 0      0 1 0 1  1 0 0 1

Output Bits (Big Endian):
0 1 0 0  1 0 1 1      1 1 1 1  0 1 0 1
0 0 0 1  0 0 1 0      0 0 1 0  1 1 1 1
0 0 1 1  0 1 0 0      0 1 0 0  0 1 0 1
0 1 0 1  0 1 0 0      1 1 0 0  0 1 0 1
0 0 1 1  1 0 1 1      1 1 0 1  1 1 1 0
0 0 1 0  1 1 1 0      1 0 1 1  1 0 1 1
1 0 0 0  1 1 0 0      1 1 0 1  0 0 1 0
1 0 1 1  0 1 1 1      1 1 1 0  0 0 1 1
1 1 0 1  0 0 0 1      0 1 1 0  0 0 0 0
0 0 0 0  1 0 1 0      1 1 0 1  0 1 1 0
0 0 1 1  0 0 0 1      1 1 0 0  0 0 1 1
1 0 0 0  0 1 0 1      1 0 1 0  0 1 0 1
1 1 0 1  0 1 1 1      1 1 0 0  1 1 0 0
1 1 1 0  0 0 1 0      0 0 1 1  1 1 0 0
0 1 1 1  0 1 1 1      1 0 0 0  0 1 0 1
0 1 0 0  0 1 0 1      1 0 0 1  1 0 1 0

Output Bytes:
  75  245   18   47   52   69   84  197   59  222   46  187  140  210  183  227
 209   96   10  214   49  195  133  165  215  204  226   60  119  133   69  154

SHA-256 Hash: 4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a

참고 자료

  1. Zero-Knowledge Proof of SHA256 Hash using zkSNARK, Binod, Medium
  2. Circom SHA256, Jonas Pauli, Medium
  3. circom-sha256, jonas089, GitHub

Written with StackEdit.

Circom 예제로 영지식 증명 시작하기 (1)

Circom 예제로 영지식 증명 시작하기 (1)

Circom 2 Getting started 문서를 따라하면서 작성한 문서입니다.

실습 환경:

  • Windows 11
  • Node.js v20.18.0
  • circom compiler 2.1.9
  • snarkjs@0.7.5

1. 소프트웨어 설치

  1. Downloads 페이지에서 circom Windows binary를 클릭하고 파일 circom-windows-amd64.exe 를 원하는 디렉토리에 저장합니다. 파일 크기는 약 10MB입니다. 여기서는 파일 이름을 circom.exe로 바꾸고 아래 경로에 저장합니다.
    C:\DevTools\circom.exe
    
  2. snarkjs를 설치합니다.
    npm install -g snarkjs
    

2. 회로 생성하기

  1. 아래 내용을 multiplier2.circom 에 저장합니다.

    pragma circom 2.0.0;
    
    /*This circuit template checks that c is the multiplication of a and b.*/  
    
    template Multiplier2 () {
       // Declaration of signals.
       signal input a;
       signal input b;
       signal output c;
    
       // Constraints.
       c <== a * b;
    }
    
    component main = Multiplier2();
    

3. 회로 컴파일하기

  1. multiplier2.circom 파일을 컴파일합니다.

    circom multiplier2.circom --r1cs --wasm --sym --c
    

    컴파일 결과 다음과 같은 파일들이 생성됩니다.

    multiplier2.r1cs
    multiplier2.sym
    multiplier2_cpp\
        calcwit.cpp
        calcwit.hpp
        circom.hpp
        fr.asm
        fr.cpp
        fr.hpp
        main.cpp
        Makefile
        multiplier2.cpp
        multiplier2.dat
    multiplier2_js\
        generate_witness.js
        multiplier2.wasm
        witness_calculator.js
    

4. witness 계산하기

입력 값, 중간 신호, 출력 값을 witness라고 합니다.

  1. multiplier2_js 디렉토리로 이동합니다.

    cd multiplier2_js
    
  2. 아래 내용을 input.json 파일에 저장합니다.

    {"a": "3", "b": "11"}
    
  3. witness를 계산하여 witness.wtns 파일에 저장합니다.

    node generate_witness.js multiplier2.wasm input.json witness.wtns
    

5. 회로를 영지식으로 증명하기

증명을 생성하기 위하여 아래 두 파일을 사용합니다.

  • multiplier2.r1cs: 회로를 기술하는 제약사항 포함
  • witness.wtns: 모든 계산된 신호 값 포함

여기서는 Groth16 zk-SNARK 프로토콜을 사용하고자 합니다. 이 프로토콜은 trusted setup을 필요로 하고 이 과정은 두 단계로 구성됩니다.

  1. Powers of tau - 회로에 독립적
  2. Phase 2 - 회로에 의존적
5.1. Powers of Tau
  1. “powers of tau” ceremony 시작

    snarkjs powersoftau new bn128 12 pot12_0000.ptau -v
    
  2. ceremony에 기여

    snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="First contribution" -v
    
5.2. Phase 2
  1. Phase 생성

    snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau -v
    
  2. .r1cs 파일과 연관된 .zkey 파일 생성

    snarkjs groth16 setup ..\multiplier2.r1cs pot12_final.ptau multiplier2_0000.zkey
    
  3. ceremony의 phase 2에 기여

    snarkjs zkey contribute multiplier2_0000.zkey multiplier2_0001.zkey --name="1st Contributor Name" -v
    
  4. 검증키 내보내기

    snarkjs zkey export verificationkey multiplier2_0001.zkey verification_key.json
    
5.3. 증명 생성
  1. 회로 및 witness와 연관된 증명을 생성합니다.

    snarkjs groth16 prove multiplier2_0001.zkey witness.wtns proof.json public.json
    

    위 명령은 다음 두 파일을 생성합니다.

    • proof.json: 증명 포함
      {
       "pi_a": [
        "13983182679953556458842508347137149918023927201985471435159758927740558853016",
        "17126988695844741179284716898691257368385629126542168835554345497343624722940",
        "1"
       ],
       "pi_b": [
        [
         "19140696255248677436910729284929621534969442224058440363361064354121562854264",
         "14257009146984576436317952378148206632799369157719061977972167958840456095938"
        ],
        [
         "7733560110556055181607998374149392520454003067800483949057392794063019344423",
         "2891268127818819654691304244486325795969498402824384674233464052246905803426"
        ],
        [
         "1",
         "0"
        ]
       ],
       "pi_c": [
        "21608704327549608970596366226125688092932784974035385756433099903167703539664",
        "19614360261086173764968380312474156102058426242974580364381559870892304372835",
        "1"
       ],
       "protocol": "groth16",
       "curve": "bn128"
      }
      
    • public.json: 공개 입력 및 출력 값 포함
      [
      	"33"
      ]
      
5.4. 증명 검증
  1. 아래 명령을 수행하여 증명을 검증합니다.

    snarkjs groth16 verify verification_key.json public.json proof.json
    

    위 명령의 수행 결과는 다음과 같습니다.

    [INFO]  snarkJS: OK!
    

6. 정리

실습을 정상적으로 마쳤을 때 multiplier2_js 디렉토리의 파일 목록은 다음과 같습니다.

generate_witness.js
input.json
multiplier2.wasm
multiplier2_0000.zkey
multiplier2_0001.zkey
pot12_0000.ptau
pot12_0001.ptau
pot12_final.ptau
proof.json
public.json
verification_key.json
witness.wtns
witness_calculator.js

Written with StackEdit.

snarkjs 예제로 영지식 증명 시작하기 (2)

snarkjs 예제로 영지식 증명 시작하기 (2)

snarkjs 예제로 영지식 증명 시작하기 (1)에서 작성한 회로의 제한 조건 개수를 1000에서 1로 변경하여 다음 두 가지 예시를 보여 줍니다.

  • 증명 성공 예시
    • a*a + b의 결과가 20인 두 수를 제공할 수 있음
  • 증명 실패 예시
    • a*a + b의 결과가 21인 두 수를 제공할 수 있음

1. 회로 생성

  1. 제한 조건 개수 변경하여 circuit2.circom 파일로 저장

    pragma circom 2.0.0;
    
    template Multiplier(n) {
        signal input a;
        signal input b;
        signal output c;
    
        signal int[n];
    
        int[0] <== a*a + b;
        for (var i=1; i<n; i++) {
            int[i] <== int[i-1]*int[i-1] + b;
        }
    
        c <== int[n-1];
    }
    
    component main = Multiplier(1);
    
  2. 컴파일

    circom --r1cs --wasm --c --sym --inspect circuit2.circom
    

2. 신뢰 설정 - Phase 2

snarkjs 예제로 영지식 증명 시작하기 (1)의 중간 결과물을 활용하면서 새로 생성하는 파일들이 기존 파일들을 덮어쓰는 것을 피하기 위하여 circuit2_js 디렉토리로 이동하여 다음 작업들을 수행합니다.

  1. Phase 2 준비

    snarkjs powersoftau prepare phase2 ..\pot14_beacon.ptau pot14_final.ptau -v
    
  2. 마지막 ptau 검증

    snarkjs powersoftau verify pot14_final.ptau
    
  3. .r1cs 파일과 연관된 .zkey 파일 생성

    snarkjs groth16 setup ..\circuit2.r1cs pot14_final.ptau circuit2_0000.zkey
    
  4. ceremony의 phase 2에 기여

    snarkjs zkey contribute circuit2_0000.zkey circuit2_0001.zkey --name="1st Contributor Name" -v
    
  5. 두 번째 기여

    snarkjs zkey contribute circuit2_0001.zkey circuit2_0002.zkey --name="Second contribution Name" -v -e="Another random entropy"
    
  6. 세 번째 기여

    snarkjs zkey export bellman circuit2_0002.zkey  challenge_phase2_0003
    snarkjs zkey bellman contribute bn128 challenge_phase2_0003 response_phase2_0003 -e="some random text"
    snarkjs zkey import bellman circuit2_0002.zkey response_phase2_0003 circuit2_0003.zkey -n="Third contribution name"
    
  7. 무작위 비콘 적용

    snarkjs zkey beacon circuit2_0003.zkey circuit2_final.zkey 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon phase2"
    
  8. 검증키 내보내기

    snarkjs zkey export verificationkey circuit2_final.zkey verification_key.json
    

5. 증명 생성 및 검증

  1. input.json 작성

    {"a": "3", "b": "11"}
    
  2. witness 계산

    snarkjs wtns calculate circuit2.wasm input.json witness.wtns
    
  3. 증명 생성

    snarkjs groth16 prove circuit2_final.zkey witness.wtns proof.json public.json
    

    public.json 파일의 내용은 다음과 같습니다.

    [
    	"20"
    ]
    
  4. 증명 검증

    snarkjs groth16 verify verification_key.json public.json proof.json
    

    실행 결과는 다음과 같습니다.

    [INFO]  snarkJS: OK!
    

6. 증명 실패 예시

  1. public2.json 파일의 내용

    [
    	"21"
    ]
    
  2. 증명 검증

    snarkjs groth16 verify verification_key.json public2.json proof.json
    

    실행 결과는 다음과 같습니다.

    [ERROR] snarkJS: Invalid proof
    

Written with StackEdit.

Circom 예제로 영지식 증명 시작하기 (2)

Circom 예제로 영지식 증명 시작하기 (2)

Circom 예제로 영지식 증명 시작하기 (1)에서 작성한 회로를 사용하여 다음 두 가지 예시를 보여 줍니다.

  • 증명 성공 예시
    • 곱셈의 결과가 34인 두 수를 제공할 수 있음
  • 증명 실패 예시
    • 곱셈의 결과가 33인 두 수를 제공할 수 있음
    • 곱셈의 결과가 34인 두 수를 제공할 수 있음

1. witness 계산하기

입력 값, 중간 신호, 출력 값을 witness라고 합니다.

  1. multiplier2_js 디렉토리로 이동합니다.

    cd multiplier2_js
    
  2. 아래 내용을 input2.json 파일에 저장합니다.

    {"a": "2", "b": "17"}
    
  3. witness를 계산하여 witness2.wtns 파일에 저장합니다.

    node generate_witness.js multiplier2.wasm input2.json witness2.wtns
    

2. 증명 성공 예시

2.1. 증명 생성
  1. 회로 및 witness와 연관된 증명을 생성합니다.

    snarkjs groth16 prove multiplier2_0001.zkey witness2.wtns proof2.json public2.json
    

    위 명령은 다음 두 파일을 생성합니다.

    • proof2.json: 증명 포함
      {
       "pi_a": [
        "14743280952072949668948706550574899717145559551048017963794441189237494636481",
        "14298005267871599183835964858782397954547197261581693679006469198474879205631",
        "1"
       ],
       "pi_b": [
        [
         "3626277144031511427418657496308860145981471611754900712998539558757189996322",
         "19214378261821279575001588540284946453492239896169946671818976034832760915828"
        ],
        [
         "17050251975840390849719173233534275494368423304240394905189026587388563221923",
         "2634421260606614787002565397702133406990838684718588715509117554509241602439"
        ],
        [
         "1",
         "0"
        ]
       ],
       "pi_c": [
        "17316308177915526759196441569174377596954015849854187372616893918873802428359",
        "12807215143857622682136446721264951084285188093999940643258181139940589592908",
        "1"
       ],
       "protocol": "groth16",
       "curve": "bn128"
      }
      
    • public2.json: 공개 입력 및 출력 값 포함
      [
      	"34"
      ]
      
2.2. 증명 검증
  1. 아래 명령을 수행하여 증명을 검증합니다.

    snarkjs groth16 verify verification_key.json public2.json proof2.json
    

    위 명령의 수행 결과는 다음과 같습니다.

    [INFO]  snarkJS: OK!
    

3. 증명 실패 예시

3.1. input2.json -> public.json 증명 검증
  1. 아래 명령을 수행하여 증명을 검증합니다.

    snarkjs groth16 verify verification_key.json public.json proof2.json
    

    위 명령의 수행 결과는 다음과 같습니다.

    [ERROR] snarkJS: Invalid proof
    
3.2. input.json -> public2.json 증명 검증
  1. 아래 명령을 수행하여 증명을 검증합니다.

    snarkjs groth16 verify verification_key.json public2.json proof.json
    

    위 명령의 수행 결과는 다음과 같습니다.

    [ERROR] snarkJS: Invalid proof
    

Written with StackEdit.

snarkjs 예제로 영지식 증명 시작하기 (1)

snarkjs 예제로 영지식 증명 시작하기 (1)

snarkjs README.md 문서를 따라하면서 작성한 문서입니다.

실습 환경:

  • Windows 11
  • Node.js v20.18.0
  • circom compiler 2.1.9
  • snarkjs@0.7.5

1. 소프트웨어 설치

  1. Downloads 페이지에서 circom Windows binary를 클릭하고 파일 circom-windows-amd64.exe 를 원하는 디렉토리에 저장합니다. 파일 크기는 약 10MB입니다. 여기서는 파일 이름을 circom.exe로 바꾸고 아래 경로에 저장합니다.
    C:\DevTools\circom.exe
    
  2. snarkjs를 설치합니다.
    npm install -g snarkjs
    

2. 신뢰 설정 - Powers of Tau

  1. “powers of tau” ceremony 시작

    snarkjs powersoftau new bn128 14 pot14_0000.ptau -v
    
  2. 첫 번째 기여

    snarkjs powersoftau contribute pot14_0000.ptau pot14_0001.ptau --name="First contribution" -v
    
  3. 두 번째 기여

    snarkjs powersoftau contribute pot14_0001.ptau pot14_0002.ptau --name="Second contribution" -v -e="some random text"
    
  4. 세 번째 기여

    snarkjs powersoftau export challenge pot14_0002.ptau challenge_0003
    snarkjs powersoftau challenge contribute bn128 challenge_0003 response_0003 -e="some random text"
    snarkjs powersoftau import response pot14_0002.ptau response_0003 pot14_0003.ptau -n="Third contribution name"
    
  5. 프로토콜 검증

    snarkjs powersoftau verify pot14_0003.ptau
    
  6. 무작위 비콘 적용

    snarkjs powersoftau beacon pot14_0003.ptau pot14_beacon.ptau 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon"
    

3. 회로 생성

  1. 회로 파일 작성

    pragma circom 2.0.0;
    
    template Multiplier(n) {
        signal input a;
        signal input b;
        signal output c;
    
        signal int[n];
    
        int[0] <== a*a + b;
        for (var i=1; i<n; i++) {
            int[i] <== int[i-1]*int[i-1] + b;
        }
    
        c <== int[n-1];
    }
    
    component main = Multiplier(1000);
    
  2. 컴파일

    circom --r1cs --wasm --c --sym --inspect circuit.circom
    

4. 신뢰 설정 - Phase 2

  1. Phase 2 준비

    snarkjs powersoftau prepare phase2 pot14_beacon.ptau pot14_final.ptau -v
    
  2. 마지막 ptau 검증

    snarkjs powersoftau verify pot14_final.ptau
    
  3. .r1cs 파일과 연관된 .zkey 파일 생성

    snarkjs groth16 setup circuit.r1cs pot14_final.ptau circuit_0000.zkey
    
  4. ceremony의 phase 2에 기여

    snarkjs zkey contribute circuit_0000.zkey circuit_0001.zkey --name="1st Contributor Name" -v
    
  5. 두 번째 기여

    snarkjs zkey contribute circuit_0001.zkey circuit_0002.zkey --name="Second contribution Name" -v -e="Another random entropy"
    
  6. 세 번째 기여

    snarkjs zkey export bellman circuit_0002.zkey  challenge_phase2_0003
    snarkjs zkey bellman contribute bn128 challenge_phase2_0003 response_phase2_0003 -e="some random text"
    snarkjs zkey import bellman circuit_0002.zkey response_phase2_0003 circuit_0003.zkey -n="Third contribution name"
    
  7. 무작위 비콘 적용

    snarkjs zkey beacon circuit_0003.zkey circuit_final.zkey 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon phase2"
    
  8. 검증키 내보내기

    snarkjs zkey export verificationkey circuit_final.zkey verification_key.json
    

5. 증명 생성 및 검증

  1. input.json 작성

    {"a": "3", "b": "11"}
    
  2. witness 계산

    snarkjs wtns calculate circuit_js/circuit.wasm input.json witness.wtns
    
  3. 증명 생성

    snarkjs groth16 prove circuit_final.zkey witness.wtns proof.json public.json
    
  4. 증명 검증

    snarkjs groth16 verify verification_key.json public.json proof.json
    

Written with StackEdit.

2024년 10월 22일 화요일

Python 객체 저장 - pickle, pickletools

Python 객체 저장 - pickle, pickletools

pickle, pickletools 모듈 문서

pickle - Python object serialization

  • Protocol version 0 is the original “human-readable” protocol and is backwards compatible with earlier versions of Python.
  • Protocol version 1 is an old binary format which is also compatible with earlier versions of Python.
  • Protocol version 2 was introduced in Python 2.3. It provides much more efficient pickling of new-style classes. Refer to PEP 307 for information about improvements brought by protocol 2.
  • Protocol version 3 was added in Python 3.0. It has explicit support for bytes objects and cannot be unpickled by Python 2.x. This was the default protocol in Python 3.0–3.7.
  • Protocol version 4 was added in Python 3.4. It adds support for very large objects, pickling more kinds of objects, and some data format optimizations. It is the default protocol starting with Python 3.8. Refer to PEP 3154 for information about improvements brought by protocol 4.
  • Protocol version 5 was added in Python 3.8. It adds support for out-of-band data and speedup for in-band data. Refer to PEP 574 for information about improvements brought by protocol 5.

pickletools — Tools for pickle developers

명령 실행 예시

아래 소스 코드를 실행하여 튜플 (1, 2)를 x.pickle 파일로 저장합니다.

from pickle import dump, load

t = (1, 2) 

with open('x.pickle', 'wb') as f: 
    dump(t, f) 

print(f'Write Done: {t}')

x.pickle 파일에 대한 pickle, pickletools 명령 실행 예시입니다.

$ python -m pickle x.pickle 
(1, 2) 
$ python -m pickletools x.pickle 
    0: \x80 PROTO 3 
    2: K BININT1 1 
    4: K BININT1 2 
    6: \x86 TUPLE2 
    7: q BINPUT 0 
    9: . STOP 
highest protocol among opcodes = 2

위에서 pickle은 x.pickle 파일에 저장되어 있는 객체를 복원하여 출력하고 pickletools는 x.pickle 파일을 파싱하여 출력합니다.

Keras 2와 3에서 Tokenizer 객체 저장 및 읽기 테스트

Tokenizer 객체의 pickle 파일은 Keras 2와 Keras 3 간에 호환되지 않습니다. 테스트를 통해서 그 이유를 파악해 봅니다.

아래 소스 코드는 Tokenizer 객체를 tokenizer.pkl 파일에 저장합니다.

from tensorflow.keras.preprocessing.text import Tokenizer 
from pickle import dump 

sample_texts = [ 
    '산악용 자전거' , 
    '자전거 전조등 후미등' , 
    '온라인 상품권' , 
    '온라인 상품 세트' 
] 

sample_tokenizer = Tokenizer() 
sample_tokenizer.fit_on_texts(sample_texts) 

dump(sample_tokenizer, open('tokenizer.pkl', 'wb'))

위 코드를 Keras 2에서 실행하여 tokenizer.pkl 파일을 생성하고 Keras 3에서 읽기를 시도합니다.

$ python -m pickle tokenizer.pkl 
... 
ModuleNotFoundError: No module named 'keras.src.preprocessing'

Keras 2에서 생성한 tokenizer.pkl 파일을 Keras 3에서 읽는 과정에서 오류가 발생했고 pickletools로 tokenizer.pkl 파일에 대하여 좀 더 자세한 정보를 출력해 봅니다.

$ python -m pickletools tokenizer.pkl 
     0: \x80 PROTO 4 
     2: \x95 FRAME 587 
    11: \x8c SHORT_BINUNICODE 'keras.src.preprocessing.text' 
    41: \x94 MEMOIZE (as 0) 
    42: \x8c SHORT_BINUNICODE 'Tokenizer' 
    53: \x94 MEMOIZE (as 1) 
    ...

이번에는 위 코드를 Keras 3에서 실행하여 tokenizer.pkl 파일을 생성하고 Keras 2에서 읽기를 시도합니다.

$ python -m pickle tokenizer.pkl 
... 
ModuleNotFoundError: No module named 'keras.src.legacy'

Keras 3에서 생성한 tokenizer.pkl 파일을 Keras 2에서 읽는 과정에서 오류가 발생했고 pickletools로 tokenizer.pkl 파일에 대하여 좀 더 자세한 정보를 출력해 봅니다.

python -m pickletools tokenizer.pkl 
     0: \x80 PROTO 4 
     2: \x95 FRAME 594 
    11: \x8c SHORT_BINUNICODE 'keras.src.legacy.preprocessing.text' 
    48: \x94 MEMOIZE (as 0) 
    49: \x8c SHORT_BINUNICODE 'Tokenizer' 
    60: \x94 MEMOIZE (as 1) 
    ...

Keras 2와 비교하여 Keras 3에서 Tokenizer를 저장하고 읽을 때 사용하는 모듈의 이름이 바뀌었고 이름 중에 legacy가 들어가 있습니다.

  • Keras 2: keras.src.preprocessing.text
  • Keras 3: keras.src.legacy.preprocessing.text

이것은 아마도 아래와 같이 Tokenizer 상태를 DEPRECATED로 바꾼 것과 관련이 있어 보입니다.

  • Tokenizer는 DEPRECATED 상태

※ 참고: preprocessing 모듈 전체가 DEPRECATED 상태

정리

  • Tokenizer 객체의 pickle 파일은 Keras 2와 Keras 3 간에 호환되지 않습니다. 호환되지 않는 이유는 Tokenizer 직렬화에 사용하는 Keras 모듈의 이름이 바뀌었기 때문이며 pickle 프로토콜 버전과는 관련이 없습니다.

Written with StackEdit.

JWT 토큰 생성과 유효성 확인 과정

JWT 토큰 생성과 유효성 확인 과정 API 서비스를 개발하고 이에 대한 접근 권한을 제어하기 위하여 JSON Web Token(JWT)을 활용할 수 있습니다. 이 문서에서는 JWT 토큰의 생성과 유효성 확인 과정...