多密钥TFHE学习笔记2-MKTFHE算法关键步骤对应关键代码

多密钥 TFHE 算法关键步骤对应关键代码

详细理论过程见笔记1

1. 设置 - MKHE.Setup( 1 λ 1^{\lambda} 1λ )

  1. 调用 LWE.Setup ( 1 λ 1^\lambda 1λ ) 来生成 LWE 的参数 p p L W E = ( n , χ , α , B ′ , d ′ ) pp^{LWE} = (n, \chi, \alpha, B', d') ppLWE=(n,χ,α,B,d) 。其中 n n n 为 LWE 的维度, χ \chi χ 为 LWE 密钥的分布, α \alpha α 为错误率, B ′ B' B 为分解基, d ′ d' d 为密钥转换 gadget 向量的维度。密钥转换 gadget 向量: g ′ = ( B ′ − 1 , . . . , B ′ − d ′ ) g' = (B'^{-1}, ... , B'^{-d'}) g=(B1,...,Bd)

    // 结构体:LweParams
    // 位置:src/include/lweparams.h
    struct LweParams {
    	const int32_t n;// LWE 的维度
    	const double alpha_min;// 错误率最小值 - 安全性决定
    	const double alpha_max;// 错误率最大值 - 解密决定
    #ifdef __cplusplus
    	LweParams(int32_t n, double alpha_min, double alpha_max);
    	~LweParams();
    	LweParams(const LweParams&) = delete; //forbidden
    	LweParams& operator=(const LweParams& ) = delete; //forbidden
    #endif
    };
    
  2. 调用 RLWE.Setup ( 1 λ 1^\lambda 1λ ) 来生成 RLWE 的参数 p p R L W E = ( N , ψ , β , B , d , a ) pp^{RLWE} = (N, \psi, \beta, B, d,\pmb{a}) ppRLWE=(N,ψ,β,B,d,aaa) 。其中 N N N 为 RLWE 的维度(2的幂), ψ \psi ψ 为 RLWE 密钥在 R R R 上的分布,并且错误率为 α \alpha α B ≥ 2 B \geq 2 B2 是整数基,分解维度为 d d d , gadget 向量为 g = ( B − 1 , . . . , B − d ) g = (B^{-1}, ... , B^{-d}) g=(B1,...,Bd) a \pmb{a} aaa 为分布 T d T^d Td 上的均匀分布的采样。

    // 结构体:LweParams
    // 位置:src/include/tlwe.h
    struct TLweParams {
        const int32_t N; // RLWE 的维度,2 的幂
        const int32_t k; // mask 中多项式的数量
        const double alpha_min; // 错误率最小值 - 安全性决定
        const double alpha_max; // 错误率最大值 - 解密决定
        const LweParams extracted_lweparams; // 如果从 RLWE 中提取 LWE ,需使用
    #ifdef __cplusplus
        TLweParams(int32_t N, int32_t k, double alpha_min, double alpha_max);
        ~TLweParams();
        TLweParams(const TLweParams &) = delete;
        void operator=(const TLweParams &) = delete;
    #endif
    };
    
  3. 返回生成的公共参数 p p M K H E = ( p p L W E , p p R L W E ) pp^{MKHE} = (pp^{LWE}, pp^{RLWE}) ppMKHE=(ppLWE,ppRLWE)

    // 结构体:MKTFHEParams
    // 位置:src/include/mkTFHEparams.h
    struct MKTFHEParams{
    	const int32_t n;			// LWE 模
    	const int32_t n_extract;	// 提取 LWE 的模,自举用 
    	const int32_t hLWE;			// HW secret key LWE
    	const double stdevLWE;		// LWE 密文标准差
    	const int32_t Bksbit;		// Base bit key switching
    	const int32_t dks;			// dimension key switching
    	const double stdevKS;		// KS 密钥标准差
    	const int32_t N;			// RLWE,RGSW 模
    	const int32_t hRLWE;		// HW secret key RLWE,RGSW
    	const double stdevRLWEkey;	// RLWE 密钥标准差
    	const double stdevRLWE;		// RLWE 密文标准差
    	const double stdevRGSW;		// RGSW 密文标准差
    	const int32_t Bgbit;		// Base bit gadget
    	const int32_t dg;			// dimension gadget
    	const double stdevBK;		// BK 标准差
    	const int32_t parties;		// 参与方数量
    	const uint32_t maskMod;		// Bg - 1
        const int32_t halfBg; 		// Bg/2
    	Torus32 *g; 				// gadget: powers of Bgbit
        uint32_t offset; 			// offset = Bg/2 * (2^(32-Bgbit) + 2^(32-2*Bgbit) + ... + 2^(32-l*Bgbit))
    #ifdef __cplusplus
    	MKTFHEParams(int32_t n, int32_t n_extract, int32_t hLWE, double stdevLWE, 
    				int32_t Bksbit, int32_t dks, double stdevKS,
    				int32_t N, int32_t hRLWE, double stdevRLWEkey, double stdevRLWE, double stdevRGSW, 
    				int32_t Bgbit, int32_t dg, double stdevBK,
    				int32_t parties);
    	~MKTFHEParams();
    	MKTFHEParams(const MKTFHEParams&) = delete; //forbidden
    	MKTFHEParams& operator=(const MKTFHEParams& ) = delete; //forbidden
    #endif
    };
    

*假设 MKHE 的算法都默认将 p p M K H E pp^{MKHE} ppMKHE 作为输入。公共参数为 CRS ,可以理解为是所有人都知道的信息。

2. 密钥生成 - MKHE.KeyGen()

  1. 生成 LWE 密钥 s i ← L W E . K e y G e n ( ) s_i \leftarrow LWE.KeyGen() siLWE.KeyGen() 。这一步仅为从分布 χ \chi χ 中采样密钥。

    // 函数:MKLweKeyGen()
    // 位置:src/libtfhe/mkTFHEkeygen.cpp
    EXPORT void MKLweKeyGen(MKLweKey* result) {
        const int32_t parties = result->MKparams->parties;
        for (int i = 0; i < parties; ++i)
        {
            lweKeyGen(&result->key[i]);
        }
    }
    // 函数:lweKeyGen()
    // 位置:src/libtfhe/lwe-functions.cpp
    EXPORT void lweKeyGen(LweKey* result) {
      const int32_t n = result->params->n;
      uniform_int_distribution<int32_t> distribution(0,1);
      for (int32_t i=0; i<n; i++) 
        result->key[i]=distribution(generator);
    }
    
  2. 运行 ( z i , b i ) ← R L W E . K e y G e n ( ) (z_i, \pmb{b}_i) \leftarrow RLWE.KeyGen() (zi,bbbi)RLWE.KeyGen() 并且设置公钥为 P K i = b i PK_i = \pmb{b}_i PKi=bbbi 。从分布 ψ \psi ψ 中采样 z z z ,设 z = ( 1 , z ) \pmb{z} = (1, z) zzz=(1,z) 。从 D α d D_{\alpha}^d Dαd 中取一个误差向量 e \pmb{e} eee ,计算公钥 b = − z ⋅ a + e \pmb{b} = -z \sdot \pmb{a} + \pmb{e} bbb=zaaa+eee (mod 1) 。对于 z i = z 1 , 0 + z i , 1 X + . . . + z i , N − 1 X N − 1 z_i = z_{1,0} + z_{i,1}X + ... + z_{i,N-1}X^{N-1} zi=z1,0+zi,1X+...+zi,N1XN1 ,记 z i ∗ = ( z i , 0 , − z i , N − 1 , . . . , − z i , 1 ) ∈ Z N \pmb{z}_i^* = (z_{i,0},-z_{i,N-1}, ... , -z_{i,1}) \in \mathbb{Z}^N zzzi=(zi,0,zi,N1,...,zi,1)ZN

    // 函数:MKRLweKeyGen()
    // 位置:src/libtfhe/mkTFHEkeygen.cpp
    EXPORT void MKRLweKeyGen(MKRLweKey *result) {
        const int32_t parties = result->MKparams->parties;
        const int32_t dg = result->MKparams->dg;
        const int32_t N = result->MKparams->N;
        const double stdevRLWEkey = result->MKparams->stdevRLWEkey; 
        // 密钥
        for (int i = 0; i < parties; ++i)
        {
            tLweKeyGen(&result->key[i]); 
        }
        // 公钥 a
        for (int j = 0; j < dg; ++j)
        {
            torusPolynomialUniform(&result->Pkey[parties*dg + j]);
        }
        // 公钥 b_i = +a*s_i + e_i
        for (int i = 0; i < parties; ++i)
        {
            for (int j = 0; j < dg; ++j)
            {
                // b_i = e_i 
                for (int l = 0; l < N; ++l)
                {
                    result->Pkey[i*dg + j].coefsT[l] = gaussian32(0, stdevRLWEkey);
                }      
                // b_i = e_i + a*s_i
                torusPolynomialAddMulRFFT1(&result->Pkey[i*dg + j], result->key[i].key, &result->Pkey[parties*dg + j]); 
            }
        }
    }
    // 函数:tLweKeyGen()
    // 位置:src/libtfhe/tlwe-functions.cpp
    EXPORT void tLweKeyGen(TLweKey *result) {
        const int32_t N = result->params->N;
        const int32_t k = result->params->k;
        uniform_int_distribution<int32_t> distribution(0, 1);
        for (int32_t i = 0; i < k; ++i)
            for (int32_t j = 0; j < N; ++j)
                result->key[i].coefs[j] = distribution(generator);
    }
    
  3. 对于 j ∈ [ n ] j \in [n] j[n] ,生成 ( d i , j , F i , j ) ← R L W E . U n i E n c ( s i , j , z i ) (\pmb{d}_{i,j}, \pmb{F}_{i,j}) \leftarrow RLWE.UniEnc(s_{i,j},z_i) (dddi,j,FFFi,j)RLWE.UniEnc(si,j,zi) ,即使用 RLWE 密钥加密 LWE 密钥。同时,设置自举密钥为 B K i = { ( d i , j , F i , j ) } j ∈ [ n ] BK_i = \{ (\pmb{d}_{i,j}, \pmb{F}_{i,j}) \}_{j \in [n]} BKi={(dddi,j,FFFi,j)}j[n] 。从 ψ \psi ψ 中取一个随机值 r r r ,可将 d \pmb{d} ddd 看作是随机值 r r r 加密下的 LWE 密钥 s s s ,将 F \pmb{F} FFF 看成是 RLWE 密钥 z z z 加密下的随机值 r r r

    // 函数:MKlweCreateBootstrappingKey_v2()
    // 位置:src/libtfhe/mkTFHEkeygen.cpp
    EXPORT void MKlweCreateBootstrappingKey_v2(MKLweBootstrappingKey_v2* result, const MKLweKey* LWEkey, 
            const MKRLweKey* RLWEkey, const MKLweKey* extractedLWEkey, const LweParams *extractedLWEparams,
            const LweParams *LWEparams, const TLweParams *RLWEparams, const MKTFHEParams* MKparams)
    {
        const int32_t parties = MKparams->parties;
        const int32_t n = MKparams->n;
        // bootstrapping key generation -> expansion. 
        for (int i = 0; i < parties; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                // fix the party 
                result->bk[i*n+j].party = i; 
                // LWE key si encrypted with RLWE key Si
                MKTGswUniEncryptI_v2(&result->bk[i*n+j], LWEkey->key[i].key[j], i, MKparams->stdevBK, RLWEkey); // party = i
            }
        }
        // key switching key
        //MKlweCreateKeySwitchKey(result->ks, extractedLWEkey, LWEkey, MKparams);
        for (int i = 0; i < parties; ++i)
        {
            // every party generates his KS key independently 
            lweCreateKeySwitchKey(&result->ks[i], &extractedLWEkey->key[i], &LWEkey->key[i]);
        }
        result->MKparams = MKparams;
    }
    // 函数:MKTGswUniEncryptI_v2()
    // 位置:src/libtfhe/mkTFHEfunctions.cpp
    EXPORT void MKTGswUniEncryptI_v2(MKTGswUESample_v2 *result, int32_t message, int32_t party, double alpha, const MKRLweKey *key) {
        const int32_t N = key->RLWEparams->N;
        const int32_t dg = key->MKparams->dg;
        const int32_t parties = key->MKparams->parties;
        // 生成随机值 r
        uniform_int_distribution<int32_t> distribution(0, 1);
        IntPolynomial* r = new_IntPolynomial(N);
        for (int j = 0; j < N; ++j){
            r->coefs[j] = distribution(generator);
        }
        // d = r*Pkey_parties + m*g + E1 \in T^dg
        for (int i = 0; i < dg; ++i)
        {
            for (int j = 0; j < N; ++j)
            {
                result->d[i].coefsT[j] = gaussian32(0, alpha); // E1
            }
            // d = E1 + m*g[i]
            result->d[i].coefsT[0] += message * key->MKparams->g[i]; // m*g[i]
            torusPolynomialAddMulR(&result->d[i], r, &key->Pkey[dg*parties + i]); 
        }
        // F = (f0,f1) \in T^2dg, with f0 = s_party*f1 + e_f + r*g
        for (int i = 0; i < dg; ++i)
        {
            // f1 
            torusPolynomialUniform(&result->f1[i]); 
            // f0 = e_f[i] + r*g[i]
            for (int j = 0; j < N; ++j)
            {
                result->f0[i].coefsT[j] = gaussian32(0, alpha); // e_f
                result->f0[i].coefsT[j] += r->coefs[j] * key->MKparams->g[i]; // r*g[i]
            }
            // f0 = s_party*f1 + e_f + r*g
            torusPolynomialAddMulR(&result->f0[i], key->key[party].key, &result->f1[i]);       
        }
        result->current_variance = alpha * alpha;
        delete_IntPolynomial(r);
    }
    
  4. 生成密钥转换密钥 K S ← L W E . K S G e n ( z i ∗ , s i ) KS \leftarrow LWE.KSGen(\pmb{z}_i^*, \pmb{s}_i) KSLWE.KSGen(zzzi,sssi) ,能够将一个与 t ∈ Z N \pmb{t} \in \mathbb{Z}^N tttZN 对应的 LWE 密文转换为同一消息在 s ∈ Z n \pmb{s} \in \mathbb{Z}^n sssZn 加密下的另一个 LWE 密文。

    // 函数:lweCreateKeySwitchKey(
    // 位置:src/libtfhe/lwe-keyswitch-functions.cpp
    EXPORT void lweCreateKeySwitchKey(LweKeySwitchKey* result, const LweKey* in_key, const LweKey* out_key){
        const int32_t n = result->n;
        const int32_t t = result->t;
        const int32_t basebit = result->basebit;
        const int32_t base = 1<<basebit;
        const double alpha = out_key->params->alpha_min;
        const int32_t sizeks = n*t*(base-1);
        double err = 0;
        // 选择高斯噪声的随机向量
        double* noise = new double[sizeks];
        for (int32_t i = 0; i < sizeks; ++i){
            normal_distribution<double> distribution(0.,alpha); 
            noise[i] = distribution(generator);
            err += noise[i];
        }
        // recenter the noises
        err = err/sizeks;
        for (int32_t i = 0; i < sizeks; ++i) noise[i] -= err;
        // 生成 KS
        int32_t index = 0; 
        for (int32_t i = 0; i < n; ++i) {
            for (int32_t j = 0; j < t; ++j) {
                lweNoiselessTrivial(&result->ks[i][j][0], 0, out_key->params);
                for (int32_t h = 1; h < base; ++h) { // pas le terme en 0
                    Torus32 mess = (in_key->key[i]*h)*(1<<(32-(j+1)*basebit));
                    lweSymEncryptWithExternalNoise(&result->ks[i][j][h], mess, noise[index], alpha, out_key);
                    index += 1;
                }
            }
        }
        delete[] noise; 
    }
    
  5. 返回密钥 s i \pmb{s}_i sssi ,公开密钥的三元组 ( P K i , B K i , K S i ) (PK_i, BK_i, KS_i) (PKi,BKi,KSi) ,分别为公钥、自举密钥、密钥转换密钥。

*每个参与方都独立进行该步骤,下标 i i i 表示第 i i i 个参与方。

*注意对于任意 a = a 0 + a 1 X + . . . + a N − 1 X N − 1 ∈ T a = a_0 + a_1X + ... + a_{N-1}X^{N-1} \in T a=a0+a1X+...+aN1XN1T 和它的系数构成的向量 ( a 0 , . . . , a N − 1 ) ∈ T N (a_0, ... , a_{N-1}) \in \mathbb{T}^N (a0,...,aN1)TN a ⋅ z ∈ T a \sdot z \in T azT 的常数项等价于 < a , z ⋆ > < \pmb{a}, \pmb{z}^{\star}> <aaa,zzz> 模 1 ,其中 T = T [ X ] / ( X N + 1 ) T = \mathbb{T} [X] / (X^N + 1) T=T[X]/(XN+1)

3. 加密 - MKHE.Enc( m m m )

对于输入比特 m ∈ { 0 , 1 } m \in \{ 0, 1 \} m{0,1} ,运行 L W E . E n c ( m ) LWE.Enc(m) LWE.Enc(m) 并返回一个 LWE 密文,其中 scaling factor = 1 4 \frac{1}{4} 41 (与 FHEW/TFHE 方案中意义相同)。这是一个标准的 LWE 加密,从 T n \mathbb{T}^n Tn 中均匀采样得到 a \pmb{a} aaa 作为 mask ,从 D α D_{\alpha} Dα 中采样得到 e e e 作为误差。输出密文 c t = ( b , a ) ∈ T n + 1 ct = (b, \pmb{a}) \in \mathbb{T}^{n+1} ct=(b,aaa)Tn+1 满足 b + < a , s > ≈ 1 4 m ( m o d 1 ) b + < \pmb{a} , \pmb{s} > \approx \frac{1}{4}m \quad (mod 1) b+<aaa,sss>41m(mod1)

// 函数:MKbootsSymEncrypt()
// 位置:src/libtfhe/mkTFHEfunctions.cpp
EXPORT void MKbootsSymEncrypt(MKLweSample *result, int32_t message, const MKLweKey* key) {
    Torus32 _1s8 = modSwitchToTorus32(1, 8);
    // 1 -> 1/8 , 0 -> - 1/8
    Torus32 mu = message ? _1s8 : -_1s8;
    double alpha = key->MKparams->stdevLWE; //TODO: specify noise
    MKlweSymEncrypt(result, mu, alpha, key);
}

*同态计算后密文的维度增加,应存储参与方的索引以便解密和进行同态操作。

4. 解密 - MKHE.Dec( c t ‾ , { s i } i ∈ [ k ] \overline{ct}, \{ \pmb{s}_i \} _{i \in [k]} ct,{sssi}i[k] )

对于密文 c t ‾ = ( b , a 1 , . . . , a k ) ∈ T k n + 1 \overline{ct} = (b, \pmb{a}_1, ... , \pmb{a}_k) \in \mathbb{T}^{kn+1} ct=(b,aaa1,...,aaak)Tkn+1 和一组密钥 ( s 1 , . . . , s k ) (\pmb{s}_1, ..., \pmb{s}_k) (sss1,...,sssk) ,返回比特 m ∈ { 0 , 1 } m \in \{ 0, 1 \} m{0,1} 使得 ∣ b + ∑ i = 1 k < a i , s i > − 1 4 m ∣ |b + \sum_{i = 1}^{k} <\pmb{a}_i , \pmb{s}_i> - \frac{1}{4}m | b+i=1k<aaai,sssi>41m 最小。

// 函数:MKbootsSymDecrypt()
// 位置:src/libtfhe/mkTFHEfunctions.cpp
EXPORT int32_t MKbootsSymDecrypt(const MKLweSample *sample, const MKLweKey* key) {
    Torus32 mu = MKlwePhase(sample, key);
    return (mu > 0 ? 1 : 0); //we have to do that because of the C binding
}

5. 与非门运算 - MKHE.NAND( c t 1 ‾ , c t 2 ‾ , { ( P K i , B K i , K S i ) } i ∈ [ k ] \overline{ct_1}, \overline{ct_2}, \{ (PK_i, BK_i, KS_i) \}_{i \in [k]} ct1,ct2,{(PKi,BKi,KSi)}i[k] )

给定两个 LWE 密文 c t 1 ‾ ∈ T k 1 n + 1 \overline{ct_1} \in \mathbb{T}^{k_1n+1} ct1Tk1n+1 c t 2 ‾ ∈ T k 2 n + 1 \overline{ct_2} \in \mathbb{T}^{k_2n+1} ct2Tk2n+1 ,令 k k k 为参与者的数量,与 c t 1 ‾ \overline{ct_1} ct1 c t 2 ‾ \overline{ct_2} ct2 相关。对于 i ∈ [ k ] i \in [k] i[k] P K i = b i , B K i = { ( d i , j , F i , j ) } i ∈ [ k ] , K S i PK_i = \pmb{b}_i , BK_i = \{ (\pmb{d}_{i,j}, \pmb{F}_{i,j}) \}_{i \in [k]}, KS_i PKi=bbbi,BKi={(dddi,j,FFFi,j)}i[k],KSi 分别为第 j j j 个参与方的 公钥、自举密钥、密钥转换密钥。

// 函数:MKbootsNAND_FFT_v2m2()
// 位置:src/libtfhe/mkTFHEfunctions.cpp
EXPORT void MKbootsNAND_FFT_v2m2(MKLweSample *result, const MKLweSample *ca, const MKLweSample *cb,
                                 const MKLweBootstrappingKeyFFT_v2 *bkFFT, const LweParams *LWEparams, const LweParams *extractedLWEparams,
                                 const TLweParams *RLWEparams, const MKTFHEParams *MKparams, const MKRLweKey *MKrlwekey)
{
    // 生成消息 mu
    static const Torus32 MU = modSwitchToTorus32(1, 8);
    // 生成结果来存放 LWE sample
    MKLweSample *temp_result = new_MKLweSample(LWEparams, MKparams);
    // 计算: (0,1/8) - ca - cb
    static const Torus32 NandConst = modSwitchToTorus32(1, 8);
    MKlweNoiselessTrivial(temp_result, NandConst, MKparams);
    MKlweSubTo(temp_result, ca, MKparams);
    MKlweSubTo(temp_result, cb, MKparams);
    // 如果相函数是正的,返回 1/8
    // 如果相函数是负的,返回 -1/8
    MKtfhe_bootstrapFFT_v2m2(result, bkFFT, MU, temp_result, LWEparams, extractedLWEparams, RLWEparams, MKparams, MKrlwekey);
    // 释放内存空间
    delete_MKLweSample(temp_result);
}
  1. 拓展输入的 LWE 密文并且在密文比特上同态评估与非门 m = m 1 ⊼ m 2 m = m_1 \barwedge m_2 m=m1m2

    1. 将密文 c t 1 ‾ \overline{ct_1} ct1 c t 2 ‾ \overline{ct_2} ct2 拓展至 c t 1 ‾ ′ , c t 2 ‾ ′ ∈ T k n + 1 \overline{ct_1}',\overline{ct_2}' \in \mathbb{T}^{kn + 1} ct1ct2Tkn+1 :联合密钥 s ‾ = ( s 1 , . . . , s k ) ∈ Z k n \overline{\pmb{s}} = (\pmb{s}_1, ... , \pmb{s}_k) \in \mathbb{Z}^{kn} sss=(sss1,...,sssk)Zkn 加密下的相同消息。只需要重新排列并在空槽 (slots) 中放入 0 即可。
    2. 计算 c t ‾ ′ = ( 5 8 , 0 , . . . , 0 ) − c t 1 ‾ ′ − c t 2 ‾ ′ \overline{ct}' = (\frac{5}{8}, \pmb{0}, ... , \pmb{0}) - \overline{ct_1}' - \overline{ct_2}' ct=(85,000,...,000)ct1ct2 (mod 1) 。这个是与非门的标志步骤
  2. 同态累加 (homomorphic accumulator) :使用 RSGW 方案的外积来评估拓展 LWE 密文的解密电路,来实现自举。

    1. 初始化累加器 c ˉ \bar{\pmb{c}} cccˉ :令 c t ‾ ′ = ( b ′ , a 1 ′ , . . . , a k ′ ) ∈ T k n + 1 \overline{ct}' = (b', \pmb{a}_1', ... , \pmb{a}_k') \in \mathbb{T}^{kn+1} ct=(b,aaa1,...,aaak)Tkn+1

      • 计算 b ~ = ⌊ 2 N ⋅ b ′ ⌉ \widetilde{b} = \lfloor 2N \sdot b' \rceil b =2Nb a ~ i = ⌊ 2 N ⋅ a i ′ ⌉ \widetilde{\pmb{a}}_i = \lfloor 2N \sdot \pmb{a}_i' \rceil aaa i=2Naaai

      • 初始化 RLWE 密文为 c ‾ = ( − 1 8 h ( X ) ⋅ X b ~ , 0 ) ∈ T k + 1 \overline{\pmb{c}} = (- \frac{1}{8}h(X) \sdot X ^{\tilde{b}},\pmb{0}) \in T^{k + 1} ccc=(81h(X)Xb~,000)Tk+1 其中 h = ∑ − N 2 < j < N 2 X j = 1 + X + . . . + X N 2 − 1 − X N 2 + 1 − . . . − X N − 1 h = \sum_{- \frac{N}{2} < j < \frac{N}{2}} X^j = 1 + X + ... + X^{\frac{N}{2}-1} - X^{\frac{N}{2} + 1} - ... - X^{N-1} h=2N<j<2NXj=1+X+...+X2N1X2N+1...XN1 。这是 − 1 8 h ( X ) ⋅ X b ~ - \frac{1}{8}h(X) \sdot X ^{\tilde{b}} 81h(X)Xb~ 的平凡的 (trivial) RLWE 密文。

        // 函数:MKtfhe_bootstrap_woKSFFT_v2m2()
        // 位置:src/libtfhe/mkTFHEfunctions.cpp
        EXPORT void MKtfhe_bootstrap_woKSFFT_v2m2(MKLweSample *result, const MKLweBootstrappingKeyFFT_v2 *bkFFT,
                                                  Torus32 mu, const MKLweSample *x, const TLweParams *RLWEparams, const MKTFHEParams *MKparams,
                                                  const MKRLweKey *MKrlwekey)
        {
            const int32_t parties = MKparams->parties;
            const int32_t N = MKparams->N;
            const int32_t Nx2 = 2 * N;
            const int32_t n = MKparams->n;
            TorusPolynomial *testvect = new_TorusPolynomial(N);
            int32_t *bara = new int32_t[parties * n];
            // 计算 b*2N
            int32_t barb = modSwitchFromTorus32(x->b, Nx2);
            // 计算 a*2N
            for (int i = 0; i < parties; ++i)
            {
                for (int j = 0; j < n; ++j)
                {
                    bara[n * i + j] = modSwitchFromTorus32(x->a[n * i + j], Nx2);
             }
            }
         // 最初的 testvec = [mu,mu,mu,...,mu]
            for (int32_t i = 0; i < N; i++)
            {
                testvect->coefsT[i] = mu;
            }
            MKtfhe_blindRotateAndExtractFFT_v2m2(result, testvect, bkFFT->bkFFT, barb, bara, RLWEparams, MKparams, MKrlwekey);
            delete[] bara;
            delete_TorusPolynomial(testvect);
        }
        
    2. 使用 Mux 门来实现主要的计算

      • 对于 i ∈ [ k ] i \in [k] i[k] ,令 a ~ i = ( a ~ i , j ) j ∈ [ n ] \tilde{\pmb{a}}_i = (\tilde{a}_{i,j})_{j \in [n]} aaa~i=(a~i,j)j[n] 。对于 i ∈ [ k ] i \in [k] i[k] j ∈ [ n ] j \in [n] j[n] ,递归地计算 c ˉ ← R L W E . C M u x ( c ˉ , X a ~ i , j ⋅ c ˉ , ( d i , j , F i , j ) , { b l } l ∈ ⌈ k ⌉ ) \bar{\pmb{c}} \leftarrow RLWE.CMux(\bar{\pmb{c}}, X^{\tilde{a}_{i,j}} \sdot \bar{\pmb{c}}, (\pmb{d}_{i,j}, \pmb{F}_{i,j}), \{ \pmb{b}_l \}_{l \in \lceil k \rceil}) cccˉRLWE.CMux(cccˉ,Xa~i,jcccˉ,(dddi,j,FFFi,j),{bbbl}lk) 。具体计算步骤参考单密钥 TFHE 。

        // 函数:MKtfhe_blindRotateFFT_v2m2()
        // 位置:src/libtfhe/mkTFHEfunctions.cpp
        EXPORT void MKtfhe_blindRotateFFT_v2m2(MKTLweSample *accum, const MKTGswUESampleFFT_v2 *bkFFT,
                                            const int32_t *bara, const TLweParams *RLWEparams, const MKTFHEParams *MKparams,
                                               const MKRLweKey *MKrlwekey)
        {
            const int32_t parties = MKparams->parties;
         const int32_t n = MKparams->n;
            MKTLweSample *temp = new_MKTLweSample(RLWEparams, MKparams);
            // MKTLweSample *temp1 = accum;
            MKTLweSample *temp1 = new_MKTLweSample(RLWEparams, MKparams);
            MKtLweCopy(temp1, accum, MKparams);
            // 此处计算 baraij
            for (int i = 0; i < parties; ++i)
            {
                for (int j = 0; j < n; ++j)
                {
                    const int32_t baraij = bara[n * i + j];
                    if (baraij == 0)
                        continue; //indeed, this is an easy case!
                    MKtfhe_MuxRotateFFT_v2m2(temp, temp1, bkFFT + (n * i + j), baraij, RLWEparams, MKparams, MKrlwekey);
                    swap(temp, temp1);
                }
            }
            // 如果最后没有 swap 回来
            if (temp1 != accum)
            {
                MKtLweCopy(accum, temp1, MKparams);
            }
            delete_MKTLweSample(temp1);
            delete_MKTLweSample(temp);
        }
        
        // 函数:MKtfhe_MuxRotateFFT_v2m2()
        // 位置:src/libtfhe/mkTFHEfunctions.cpp
        // 这个是递归计算的具体实现
        void MKtfhe_MuxRotateFFT_v2m2(MKTLweSample *result, MKTLweSample *accum, const MKTGswUESampleFFT_v2 *bkiFFT,
                                      const int32_t barai, const TLweParams *RLWEparams, const MKTFHEParams *MKparams, const MKRLweKey *RLWEkey)
        {
            MKTLweSample *temp_result = new_MKTLweSample(RLWEparams, MKparams);
            // ACC = BKi*[(X^barai-1)*ACC]+ACC
            // temp = (X^barai-1)*ACC
            MKtLweMulByXaiMinusOne(temp_result, barai, accum, MKparams);
            // temp *= BKi
            MKtGswUEExternMulToMKtLwe_FFT_v2m2(result, temp_result, bkiFFT, RLWEparams, MKparams, RLWEkey);
            // ACC += temp
            MKtLweAddTo(result, accum, MKparams);
            delete_MKTLweSample(temp_result);
        }
        
    3. 返回 c ˉ ← ( 1 8 , 0 ) + c ˉ \bar{\pmb{c}} \leftarrow (\frac{1}{8}, \pmb{0}) + \bar{\pmb{c}} cccˉ(81,000)+cccˉ (mod 1) 。

      • 详见上一步。
  3. c ‾ \overline{\pmb{c}} ccc 转换为 LWE 密文并运行多密钥的密钥转换算法。

    1. 对于 c ˉ = ( c 0 , c 1 , . . . , c k ) ∈ T k + 1 \bar{\pmb{c}} = (c_0, c_1, ... , c_k) \in T^{k + 1} cccˉ=(c0,c1,...,ck)Tk+1

      • 提取 b ∗ b^* b c 0 c_0 c0 的常数项,对于 i ∈ [ k ] i \in [k] i[k] ,令 a i ∗ \pmb{a}_i^* aaai c i c_i ci 的系数向量。计算 LWE 密文 c t ‾ ∗ = ( b ∗ , a 1 ∗ , . . . , a k ∗ ) ∈ T k N + 1 \overline{ct}^* = (b^*, \pmb{a}_1^*, ... , \pmb{a}_k^*) \in \mathbb{T}^{kN + 1} ct=(b,aaa1,...,aaak)TkN+1

        // 函数:MKlweKeySwitch()
        // 位置:src/libtfhe/mkTFHEfunctions.cpp - 711
        EXPORT void MKlweKeySwitch(MKLweSample* result, const LweKeySwitchKey* ks, const MKLweSample* sample, 
                const LweParams* LWEparams, const MKTFHEParams* MKparams)
        {
            const int32_t n_extract = MKparams->n_extract;
            const int32_t Bksbit = MKparams->Bksbit;
            const int32_t dks = MKparams->dks;
            const int32_t parties = MKparams->parties;
            const int32_t Bks = 1 << Bksbit;
            const int32_t prec_offset = 1 << (32-(1+Bksbit*dks)); //precision
            const int32_t mask = Bks-1;
            const int32_t n = LWEparams->n;
            LweSample* temp = new_LweSample(LWEparams);
            // result = (b, 0,...,0)
            // 将取出的 b 累加到结果中
            MKlweNoiselessTrivial(result, sample->b, MKparams);
            for (int p = 0; p < parties; ++p)
            {
                // temp = (0,0)
                lweClear(temp, LWEparams);
                // temp = (a', b')
                for (int i = 0; i < n_extract; ++i)
                {
                    const uint32_t aibar = sample->a[p*n_extract + i] + prec_offset;
                    for (int j = 0; j < dks; ++j)
                    {
                        const uint32_t aij = (aibar >> (32-(j+1)*Bksbit)) & mask;
                        if(aij != 0) 
                        {
                            lweSubTo(temp, &ks[p].ks[i][j][aij], LWEparams);
                        }
                    }
                }
                // result = (b + \sum b', a1', ..., ak')
                result->b += temp->b;
                for (int i = 0; i < n; ++i)
                {
                    result->a[p*n +i] = temp->a[i]; 
                }        
            }
        }
        
    2. K S ‾ = { K S i } i ∈ [ k ] \overline{KS} = \{ KS_i \}_{i \in [k]} KS={KSi}i[k] ,执行多密钥的密钥转换算法 (multi-key-switching) 并返回密文 c t ‾ ′ ′ ← L W E . M K S w i t c h ( c t ‾ ∗ , K S ‾ ) \overline{ct}'' \leftarrow LWE.MKSwitch(\overline{ct}^*, \overline{KS}) ctLWE.MKSwitch(ct,KS) 。这个密钥转换算法输入拓展密文和一系列密钥转换密钥,返回相同消息在联合密钥加密下的密文。

      • 详见上一步。

自行实现的 AND 门、 OR 门 、 NOT 门 与 XOR 门

因为 MKTFHE 库中仅给出与非门 NAND 的实现,因此参考论文中的公式尝试实现了其他基础门电路。首先构造各门电路的计算公式,并分析所需的函数:

表达式MKtfhe_bootstrapFFTMklweAddToMklweSubToMklweAddMulTomodToTorus32
NAND B o o t s t r a p ( ( 0 , 5 8 ) − c 1 − c 2 ) Bootstrap((0,\frac{5}{8}) - c_1 - c_2) Bootstrap((0,85)c1c2) √ \surd √ \surd √ \surd
AND B o o t s t r a p ( ( 0 , − 1 8 ) + c 1 + c 2 ) Bootstrap((0,-\frac{1}{8}) + c_1 + c_2) Bootstrap((0,81)+c1+c2) √ \surd √ \surd √ \surd
OR B o o t s t r a p ( ( 0 , 1 8 ) + c 1 + c 2 ) Bootstrap((0,\frac{1}{8}) + c_1 + c_2) Bootstrap((0,81)+c1+c2) √ \surd √ \surd √ \surd
NOT ( 0 , 1 4 ) − c (0,\frac{1}{4}) - c (0,41)c √ \surd √ \surd
XOR B o o t s t r a p ( ( 0 , 1 8 ) + 2 c 1 + 2 c 2 ) Bootstrap((0,\frac{1}{8}) + 2 c_1 + 2 c_2) Bootstrap((0,81)+2c1+2c2) √ \surd √ \surd √ \surd

库中未给出的函数的具体实现:

  • MklweAddTo

    // 函数功能:实现两个多密钥 LWE SAMPLE 的加法
    EXPORT void MKlweAddTo(MKLweSample *result, const MKLweSample *sample, const MKTFHEParams *MKparams)
    {
        const int32_t n = MKparams->n;
        const int32_t parties = MKparams->parties;
        for (int i = 0; i < parties; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                result->a[i * n + j] += sample->a[i * n + j];
            }
        }
        result->b += sample->b;
        result->current_variance += sample->current_variance;
    }
    
  • MklweAddMulTo

    // 返回 result = result + p.sample
    EXPORT void MKlweAddMulTo(MKLweSample *result, int32_t p, const MKLweSample *sample, const MKTFHEParams *MKparams)
    {
        const int32_t n = MKparams->n;
        const int32_t parties = MKparams->parties;
        for (int i = 0; i < parties; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                result->a[i * n + j] += p * sample->a[i * n + j];
            }
        }
        result->b += p * sample->b;
        result->current_variance += (p * p) * sample->current_variance;
    }
    
  • MKbootsAND_FFT_v2m2

    // 函数功能:实现自举的与门
    EXPORT void MKbootsAND_FFT_v2m2(MKLweSample *result, const MKLweSample *ca, const MKLweSample *cb,
                                     const MKLweBootstrappingKeyFFT_v2 *bkFFT, const LweParams *LWEparams, const LweParams *extractedLWEparams,
                                     const TLweParams *RLWEparams, const MKTFHEParams *MKparams, const MKRLweKey *MKrlwekey)
    {
        static const Torus32 MU = modSwitchToTorus32(1, 8);
        // 生成消息 mu
        cout << "MU = " << MU << endl;
        // 生成结果来存放 LWE sample
        MKLweSample *temp_result = new_MKLweSample(LWEparams, MKparams);
        // 计算: (0,-1/8) + ca + cb
        static const Torus32 AndConst = modSwitchToTorus32(-1, 8);
        cout << "AndConst = " << AndConst << endl;
        MKlweNoiselessTrivial(temp_result, AndConst, MKparams);
        MKlweAddTo(temp_result, ca, MKparams);
        MKlweAddTo(temp_result, cb, MKparams);
        // 如果相函数是正的,返回 1/8
        // 如果相函数是负的,返回 -1/8
        MKtfhe_bootstrapFFT_v2m2(result, bkFFT, MU, temp_result, LWEparams, extractedLWEparams, RLWEparams, MKparams, MKrlwekey);
        // 释放内存空间
        delete_MKLweSample(temp_result);
    }
    
  • MKbootsOR_FFT_v2m2

    // 函数功能:实现自举的或门
    EXPORT void MKbootsOR_FFT_v2m2(MKLweSample *result, const MKLweSample *ca, const MKLweSample *cb,
                                     const MKLweBootstrappingKeyFFT_v2 *bkFFT, const LweParams *LWEparams, const LweParams *extractedLWEparams,
                                     const TLweParams *RLWEparams, const MKTFHEParams *MKparams, const MKRLweKey *MKrlwekey)
    {
        static const Torus32 MU = modSwitchToTorus32(1, 8);
        // 生成消息 mu
        cout << "MU = " << MU << endl;
        // 生成结果来存放 LWE sample
        MKLweSample *temp_result = new_MKLweSample(LWEparams, MKparams);
        // 计算: (0,-1/8) + ca + cb
        static const Torus32 OrConst = modSwitchToTorus32(1, 8);
        cout << "OrConst = " << OrConst << endl;
        MKlweNoiselessTrivial(temp_result, OrConst, MKparams);
        MKlweAddTo(temp_result, ca, MKparams);
        MKlweAddTo(temp_result, cb, MKparams);
        // 如果相函数是正的,返回 1/8
        // 如果相函数是负的,返回 -1/8
        MKtfhe_bootstrapFFT_v2m2(result, bkFFT, MU, temp_result, LWEparams, extractedLWEparams, RLWEparams, MKparams, MKrlwekey);
        // 释放内存空间
        delete_MKLweSample(temp_result);
    }
    
  • MKlweNegate

    // 函数功能:实现自举的非门
    EXPORT void MKlweNegate(MKLweSample *result, const MKLweSample *sample, const MKTFHEParams *MKparams)
    {
        const int32_t n = MKparams->n;
        const int32_t parties = MKparams->parties;
        for (int i = 0; i < parties; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                result->a[i * n + j] = - sample->a[i * n + j];
            }
        }
        result->b = - sample->b;
        result->current_variance += sample->current_variance;
    }
    
  • MKbootsXOR_FFT_v2m2

    // 函数功能:实现自举的异或门
    EXPORT void MKbootsXOR_FFT_v2m2(MKLweSample *result, const MKLweSample *ca, const MKLweSample *cb,
                                     const MKLweBootstrappingKeyFFT_v2 *bkFFT, const LweParams *LWEparams, const LweParams *extractedLWEparams,
                                     const TLweParams *RLWEparams, const MKTFHEParams *MKparams, const MKRLweKey *MKrlwekey)
    {
        static const Torus32 MU = modSwitchToTorus32(1, 8);
        // 生成消息 mu
        cout << "MU = " << MU << endl;
        // 生成结果来存放 LWE sample
        MKLweSample *temp_result = new_MKLweSample(LWEparams, MKparams);
        // 计算: 1/8 + 2 * ( ca + cb )
        static const Torus32 XorConst = modSwitchToTorus32(1, 8);
        MKlweNoiselessTrivial(temp_result, XorConst, MKparams);
        MKlweAddMulTo(temp_result, 2, ca, MKparams);
        MKlweAddMulTo(temp_result, 2, cb, MKparams);
        MKtfhe_bootstrapFFT_v2m2(result, bkFFT, MU, temp_result, LWEparams, extractedLWEparams, RLWEparams, MKparams, MKrlwekey);
        // 释放内存空间
        delete_MKLweSample(temp_result);
    }
    

主要参考论文:

  • Chillotti I, Gama N, Georgieva M, et al. TFHE: fast fully homomorphic encryption over the torus[J]. Journal of Cryptology, 2020, 33(1): 34-91.
  • Chen H, Chillotti I, Song Y. Multi-key homomorphic encryption from TFHE[C]//International Conference on the Theory and Application of Cryptology and Information Security. Springer, Cham, 2019: 446-472.
  • Ilaria Chillotti; Nicolas Gama; Mariya Georgieva; Malika Izabachene. Faster Fully Homomorphic Encryption: Bootstrapping in less than 0.1 Seconds. ASIACRYPT 2016.

算法库:https://github.com/ilachill/MK-TFHE

本文仅供个人学习使用

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值