CKKS에 대한 자세한 소개는 다음을 참고한다.

https://blog.openmined.org/ckks-explained-part-1-simple-encoding-and-decoding/

 

CKKS explained: Part 1, Vanilla Encoding and Decoding

First part of the series CKKS explained where we see how to implement a vanilla encoder and decoder.

blog.openmined.org

 

1. Theory : CKKS

Cheon-Kim-Kim-Song (CKKS)는 leveled 동형 암호 스킴으로 real numbers에 대해 approximate arithmetics을 지원한다. 간단한 구조는 다음과 같다.

 

CKKS parameter는 크게 3가지가 있다.

  • Scaling factor
  • Polynomial modulus degree
  • Coefficient modulus size

 

Scaling factor

Vector of real number를 plaintext polynomial로 encoding하는 과정이 필요하다.

$$ 1.01011 = 101011 * 2^{-5} $$

 

Polynomial modulus degree

그림에서 $N$을 의미하며 다음의 관계가 있다.

  • number of coefficients in plaintext polynomial
  • size of ciphertext elements
  • computational performance of the scheme (bigger is worse)
  • security level (bigger is better)

TenSEAL에서 $N$은 2의 거듭제곱 형태로만 가능하다. (1024, 2048, 4096 , ...)

 

Coefficient modulus size

List of binary size로 이 list를 이용해 SEAL이 list of primes를 생성한다. 그림에서는 $q$를 의미한다. 다음의 관계를 가진다.

  • size of ciphertext elements
  • length of the list = level of the scheme = number of encrypted multiplication supported
  • security level (bigger is worse)

TenSEAL에서 계수 모듈러스의 각 소수는 최대 60비트여야 하며 1 mod 2*poly_modulus_degree와 일치해야 한다. 다시 말하면 prime을 2*$N$으로 mod 연산을 수행했을 때, 나머지가 1이어야 한다는 의미이다.

 

 

CKKS key는 크게 4가지 종류가 있다.

  • Secret key
    • Decryption에 사용됨 / No share
  • Public encryption key
    • Encryption에 사용
  • Relinearization key
    • 새로운 ciphertext의 크기는 2임
    • $K$와 $L$ 크기의 ciphertext를 곱하면, $K+L-1$이 됨
    • size가 커지면 연산 속도가 느려짐
    • Relinearization을 통해 크기를 2로 다시 줄임
    • 이를 수행하기 위해서는 secret key에 의해 생성된 pulbic key, relinearization key가 필요함
  • Galois key (optional)
    • vector의 회전 및 복제를 위한 

 

CKKS 내부 operation은 크게 2가지가 있다.

  • Relinearization
    • TenSEAL에서는 encrypted multiplication 이후에 자동으로 수행
    • 암호문의 크기를 2로 줄이는 과정
    • $K+1$의 encrypted ciphertext를 relinearization하기 위해서는 $K-1$의 relinearization key가 필요함
  • Rescaling
    • TenSEAL에서는 encrypted나 plain multiplication 이후에 자동으로 수행
    • Approximation error는 지수적으로 커짐. 이를 해결하기 위해 대부분의 HE 스킴은 modulus-switching을 사용함. CKKS의 경우에는 rescaling을 수행함. Rescaling 알고리즘을 통해 error는 선형적으로 커짐
    • $q_1, ..., q_k$로 modulo된 encrypted ciphertext가 주어지면, $q_1, ..., q_{k-1}$로 modulo down하고 message를 scale down함
    • 이 operation은 coefficient modulus로부터 하나의 prime을 소모하기 때문에, 다 쓰면 더 이상 곱셈을 수행할 수 없음.

 

2. TenSEAL CKKS

우선적으로 수행할 것은 CKKS TenSEAL context를 만드는 것이다.

def context():
    context = ts.context(
                ts.SCHEME_TYPE.CKKS, # scheme
                8192, # poly modulus degree
                coeff_mod_bit_sizes=[60, 40, 40, 60]) 
                # coefficient modulus size
                # 4 primes of 60, 40, 40, 60 bits
                # 2 multiplication supported
    context.global_scale = pow(2, 40) # scaling factor
    context.generate_galois_keys()
    return context

context = context()

 

모델 학습을 위해서 tensor를 만들어야 한다. TenSEAL에서 지원하는 구조는 다음과 같다.

 

우선 plain tensor를 만드는 방법은 다음과 같다.

plain1 = ts.plain_tensor([1,2,3,4], [2,2])
print(" First tensor: Shape = {} Data = {}".format(plain1.shape, plain1.tolist()))

plain2 = ts.plain_tensor(np.array([5,6,7,8]).reshape(2,2))
print(" Second tensor: Shape = {} Data = {}".format(plain2.shape, plain2.tolist()))

 

Encrypt하기 전에 ckks에서 암호화와 복호화를 어떻게 진행하는지 알아보자.

 

2.1. CKKS encoding + decoding

Complex나 real number를 plaintext polynomial로 encoding하는 과정이 필요하다.

 

만약 polynomial modulus degree가 $N$이면, $N/2$개의 complex number가 plaintext elements로 변환될 수 있다. 또한 slot-wise 연산을 지원하지 때문에, SIMD가 가능하다. 그림으로 나타내면 다음과 같다.

 

2.2. CKKS encryption + decryption

Plaintext로 변환했으면, 이제 ckks로 암호화할 수 있다.

 

TenSEAL에서 만들 수 있는 element는 3개 정도이다.

  • BFVvector : 1D integer array
  • CKKSvector : 1D float array
  • CKKStensor : N-dimensional float array

 

코드는 다음과 같다.

encrypted_tensor1 = ts.ckks_tensor(context, plain1)
encrypted_tensor2 = ts.ckks_tensor(context, plain2)

print(" Shape = {}".format(encrypted_tensor1.shape))
print(" Encrypted Data = {}.".format(encrypted_tensor1))

encrypted_tensor_from_np = ts.ckks_tensor(context, np.array([5,6,7,8]).reshape([2,2]))
print(" Shape = {}".format(encrypted_tensor_from_np.shape))

 

였는데 TenSEAL은 마지막 commit이 2년전으로 MS에서 버린 것 같으니 다른거 공부한다