from openfhe import * from math import * def main(): SwitchCKKSToFHEW() SwitchFHEWtoCKKS() FloorViaSchemeSwitching() # FuncViaSchemeSwitching() # PolyViaSchemeSwitching() ComparisonViaSchemeSwitching() ArgminViaSchemeSwitching() ArgminViaSchemeSwitchingAlt() #ArgminViaSchemeSwitchingUnit() #ArgminViaSchemeSwitchingAltUnit() def SwitchCKKSToFHEW(): # Example of switching a packed ciphertext from CKKS to multiple FHEW ciphertexts. print("\n-----SwitchCKKSToFHEW-----\n") # Step 1: Setup CryptoContext for CKKS # Specify main parameters multDepth = 3 firstModSize = 60 scaleModSize = 50 ringDim = 4096 sl = HEStd_NotSet slBin = TOY logQ_ccLWE = 25 # slots = ringDim / 2 # Uncomment for fully-packed slots = 16 # sparsely-packed batchSize = slots parameters = CCParamsCKKSRNS() parameters.SetMultiplicativeDepth(multDepth) parameters.SetFirstModSize(firstModSize) parameters.SetScalingModSize(scaleModSize) parameters.SetScalingTechnique(FIXEDMANUAL) parameters.SetSecurityLevel(sl) parameters.SetRingDim(ringDim) parameters.SetBatchSize(batchSize) cc = GenCryptoContext(parameters) # Enable the features that you wish to use cc.Enable(PKE) cc.Enable(KEYSWITCH) cc.Enable(LEVELEDSHE) cc.Enable(SCHEMESWITCH) print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},") print(f"number of slots {slots}, and supports a multiplicative depth of {multDepth}\n") # Generate encryption keys keys = cc.KeyGen() # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching FHEWparams = cc.EvalCKKStoFHEWSetup(sl, slBin, False, logQ_ccLWE, False, slots) ccLWE = FHEWparams[0] privateKeyFHEW = FHEWparams[1] cc.EvalCKKStoFHEWKeyGen(keys, privateKeyFHEW) print(f"FHEW scheme is using a lattice parameter {ccLWE.Getn()},") print(f"logQ {logQ_ccLWE},") print(f"and modulus q {ccLWE.Getq()}\n") # Compute the scaling factor to decrypt correctly in FHEW; the LWE mod switch is performed on the ciphertext at the last level modulus_CKKS_from = cc.GetModulusCKKS() pLWE1 = ccLWE.GetMaxPlaintextSpace() # Small precision modulus_LWE = 1 << logQ_ccLWE beta = ccLWE.GetBeta() pLWE2 = modulus_LWE / (2*beta) # Large precision scFactor = cc.GetScalingFactorReal(0) # if (cc.GetScalingTechnique() == FLEXIBLEAUTOEXT): # scFactor = cc.GetScalingFactorReal(1) scale1 = modulus_CKKS_from / (scFactor * pLWE1) scale2 = modulus_CKKS_from / (scFactor * pLWE2) # Perform the precomputation for switching cc.EvalCKKStoFHEWPrecompute(scale1) # Step 3: Encoding and encryption of inputs # Inputs x1 = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0] x2 = [0.0, 271.1, 30000.0, pLWE2-2] encodedLength1 = len(x1) encodedLength2 = len(x2) # Encoding as plaintexts ptxt1 = cc.MakeCKKSPackedPlaintext(x1, 1, 0) ptxt2 = cc.MakeCKKSPackedPlaintext(x2, 1, 0) # Encrypt the encoded vectors c1 = cc.Encrypt(keys.publicKey, ptxt1) c2 = cc.Encrypt(keys.publicKey, ptxt2) # Step 4: Scheme Switching from CKKS to FHEW cTemp = cc.EvalCKKStoFHEW(c1, encodedLength1) print(f"\n---Decrypting switched ciphertext with small precision (plaintext modulus {pLWE1}) ---\n") x1Int = [round(x) % pLWE1 for x in x1] ptxt1.SetLength(encodedLength1) print(f"Input x1: {ptxt1.GetRealPackedValue()}; which rounds to {x1Int}") print("FHEW Decryption") for i in range(len(cTemp)): result = ccLWE.Decrypt(privateKeyFHEW, cTemp[i], pLWE1) print(result, end=" ") print("\n") # B: Second scheme switching case # Perform the precomputation for switching cc.EvalCKKStoFHEWPrecompute(scale2) # Transform the ciphertext from CKKS to FHEW (only for the number of inputs given) cTemp2 = cc.EvalCKKStoFHEW(c2, encodedLength2) print(f"\n---Decrypting switched ciphertext with large precision (plaintext modulus {pLWE2}) ---\n") ptxt2.SetLength(encodedLength2) print(f"Input x2: {ptxt2.GetRealPackedValue()}") print("FHEW Decryption") for i in range(len(cTemp2)): result = ccLWE.Decrypt(privateKeyFHEW, cTemp2[i], int(pLWE2)) print(result, end=" ") print("\n") # C: Decompose the FHEW ciphertexts in smaller digits print(f"Decomposed values for digit size of {pLWE1}:") # Generate the bootstrapping keys (refresh and switching keys) ccLWE.BTKeyGen(privateKeyFHEW) for j in range(len(cTemp2)): # Decompose the large ciphertext into small ciphertexts that fit in q decomp = ccLWE.EvalDecomp(cTemp2[j]) # Decryption p = ccLWE.GetMaxPlaintextSpace() for i in range(len(decomp)): ct = decomp[i] if i == len(decomp) - 1: p = int(pLWE2 / (pLWE1 ** floor(log(pLWE2)/log(pLWE1)))) # The last digit should be up to P / p^floor(log_p(P)) resultDecomp = ccLWE.Decrypt(privateKeyFHEW, ct, p) print(f"( {resultDecomp} * {pLWE1} ^ {i} )") if i != len(decomp) - 1: print("+", end=" ") print("\n") def SwitchFHEWtoCKKS(): print("\n-----SwitchFHEWtoCKKS-----\n") print("Output precision is only wrt the operations in CKKS after switching back.\n") # Step 1: Setup CryptoContext for CKKS to be switched into # A. Specify main parameters scTech = FIXEDAUTO multDepth = 3 + 9 + 1 # for r = 3 in FHEWtoCKKS, Chebyshev max depth allowed is 9, 1 more level for postscaling if scTech == FLEXIBLEAUTOEXT: multDepth += 1 scaleModSize = 50 ringDim = 8192 sl = HEStd_NotSet # If this is not HEStd_NotSet, ensure ringDim is compatible logQ_ccLWE = 28 # slots = ringDim/2; # Uncomment for fully-packed slots = 16 # sparsely-packed batchSize = slots parameters = CCParamsCKKSRNS() parameters.SetMultiplicativeDepth(multDepth) parameters.SetScalingModSize(scaleModSize) parameters.SetScalingTechnique(scTech) parameters.SetSecurityLevel(sl) parameters.SetRingDim(ringDim) parameters.SetBatchSize(batchSize) cc = GenCryptoContext(parameters) # Enable the features that you wish to use cc.Enable(PKE) cc.Enable(KEYSWITCH) cc.Enable(LEVELEDSHE) cc.Enable(ADVANCEDSHE) cc.Enable(SCHEMESWITCH) print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},\n number of slots {slots}, and suports a multiplicative depth of {multDepth}\n") # Generate encryption keys keys = cc.KeyGen() # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching ccLWE = BinFHEContext() ccLWE.GenerateBinFHEContext(TOY, False, logQ_ccLWE, 0, GINX, False) # LWE private key lwesk = ccLWE.KeyGen() print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n") # Step 3. Precompute the necessary keys and information for switching from FHEW to CKKS cc.EvalFHEWtoCKKSSetup(ccLWE, slots, logQ_ccLWE) cc.EvalFHEWtoCKKSKeyGen(keys, lwesk) # Step 4: Encoding and encryption of inputs # For correct CKKS decryption, the messages have to be much smaller than the FHEW plaintext modulus! pLWE1 = ccLWE.GetMaxPlaintextSpace() # Small precision pLWE2 = 256 # Medium precision modulus_LWE = 1 << logQ_ccLWE beta = ccLWE.GetBeta() pLWE3 = int(modulus_LWE / (2 * beta)) # Large precision x1 = [1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0] x2 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] if len(x1) < slots: zeros = [0] * (slots - len(x1)) x1.extend(zeros) x2.extend(zeros) # Encrypt # Encrypted nder small plaintext modulus p = 4 and ciphertext modulus: ctxtsLWE1 = [ccLWE.Encrypt(lwesk, x1[i]) for i in range(slots)] # Encrypted under larger plaintext modulus p = 16 but small ciphertext modulus: ctxtsLWE2 = [ccLWE.Encrypt(lwesk, x1[i], FRESH, pLWE1) for i in range(slots)] # Encrypted under larger plaintext modulus and large ciphertext modulus: ctxtsLWE3 = [ccLWE.Encrypt(lwesk, x2[i], FRESH, pLWE2, modulus_LWE) for i in range(slots)] # Encrypted under large plaintext modulus and large ciphertext modulus: ctxtsLWE4 = [ccLWE.Encrypt(lwesk, x2[i], FRESH, pLWE3, modulus_LWE) for i in range(slots)] # Step 5. Perform the scheme switching cTemp = cc.EvalFHEWtoCKKS(ctxtsLWE1, slots, slots) print(f"\n---Input x1: {x1} encrypted under p = 4 and Q = {ctxtsLWE1[0].GetModulus()} ---") # Step 6. Decrypt plaintextDec = cc.Decrypt(keys.secretKey, cTemp) plaintextDec.SetLength(slots) print(f"Switched CKKS decryption 1: {plaintextDec}") # Step 5'. Perform the scheme switching cTemp = cc.EvalFHEWtoCKKS(ctxtsLWE2, slots, slots, pLWE1, 0, pLWE1) print(f"\n---Input x1: {x1} encrypted under p = {pLWE1} and Q = {ctxtsLWE2[0].GetModulus()} ---") # Step 6'. Decrypt plaintextDec = cc.Decrypt(keys.secretKey, cTemp) plaintextDec.SetLength(slots) print(f"Switched CKKS decryption 2: {plaintextDec}") # Step 5''. Perform the scheme switching cTemp = cc.EvalFHEWtoCKKS(ctxtsLWE3, slots, slots, pLWE2, 0, pLWE2) print(f"\n---Input x2: {x2} encrypted under p = {pLWE2} and Q = {ctxtsLWE3[0].GetModulus()} ---") # Step 6''. Decrypt plaintextDec = cc.Decrypt(keys.secretKey, cTemp) plaintextDec.SetLength(slots) print(f"Switched CKKS decryption 3: {plaintextDec}") # Step 5'''. Perform the scheme switching cTemp2 = cc.EvalFHEWtoCKKS(ctxtsLWE4, slots, slots, pLWE3, 0, pLWE3) print(f"\n---Input x2: {x2} encrypted under p = {pLWE3} and Q = {ctxtsLWE4[0].GetModulus()} ---") # Step 6'''. Decrypt plaintextDec = cc.Decrypt(keys.secretKey, cTemp2) plaintextDec.SetLength(slots) print(f"Switched CKKS decryption 4: {plaintextDec}") def FloorViaSchemeSwitching(): print("\n-----FloorViaSchemeSwitching-----\n") print("Output precision is only wrt the operations in CKKS after switching back.\n") # Step 1: Setup CryptoContext for CKKS scTech = FIXEDAUTO multDepth = 3 + 9 + 1 # for r = 3 in FHEWtoCKKS, Chebyshev max depth allowed is 9, 1 more level for postscaling if scTech == FLEXIBLEAUTOEXT: multDepth += 1 scaleModSize = 50 ringDim = 8192 sl = HEStd_NotSet slBin = TOY logQ_ccLWE = 23 slots = 16 # sparsely-packed batchSize = slots parameters = CCParamsCKKSRNS() parameters.SetMultiplicativeDepth(multDepth) parameters.SetScalingModSize(scaleModSize) parameters.SetScalingTechnique(scTech) parameters.SetSecurityLevel(sl) parameters.SetRingDim(ringDim) parameters.SetBatchSize(batchSize) cc = GenCryptoContext(parameters) # Enable the features that you wish to use cc.Enable(PKE) cc.Enable(KEYSWITCH) cc.Enable(LEVELEDSHE) cc.Enable(ADVANCEDSHE) cc.Enable(SCHEMESWITCH) print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},\n number of slots {slots}, and suports a multiplicative depth of {multDepth}\n") # Generate encryption keys. keys = cc.KeyGen() # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching arbFunc = False FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots) ccLWE = FHEWparams[0] privateKeyFHEW = FHEWparams[1] cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW) # Generate bootstrapping key for EvalFloor ccLWE.BTKeyGen(privateKeyFHEW) print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n") # Set the scaling factor to be able to decrypt; the LWE mod switch is performed on the ciphertext at the last level modulus_CKKS_from = cc.GetModulusCKKS() modulus_LWE = 1 << logQ_ccLWE beta = ccLWE.GetBeta() pLWE = int(modulus_LWE / (2 * beta)) # Large precision scFactor = cc.GetScalingFactorReal(0) if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT: scFactor = cc.GetScalingFactorReal(1) scaleCF = int(modulus_CKKS_from) / (scFactor * pLWE) cc.EvalCKKStoFHEWPrecompute(scaleCF) # Step 3: Encoding and encryption of inputs # Inputs x1 = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0] # Encoding as plaintexts ptxt1 = cc.MakeCKKSPackedPlaintext(x1, 1, 0)#, None) # Encrypt the encoded vectors c1 = cc.Encrypt(keys.publicKey, ptxt1) # Step 4: Scheme switching from CKKS to FHEW cTemp = cc.EvalCKKStoFHEW(c1) # Step 5: Evaluate the floor function bits = 2 cFloor = [ccLWE.EvalFloor(cTemp[i], bits) for i in range(len(cTemp))] print(f"Input x1: {ptxt1.GetRealPackedValue()}") print(f"Expected result for EvalFloor with {bits} bits: ", end="") for i in range(slots): print(int(ptxt1.GetRealPackedValue()[i]) >> bits, end=" ") print(f"\nFHEW decryption p = {pLWE}/(1 << bits) = {pLWE // (1 << bits)}: ", end="") for i in range(len(cFloor)): pFloor = ccLWE.Decrypt(privateKeyFHEW, cFloor[i], pLWE // (1 << bits)) print(pFloor, end=" ") print("\n") # Step 6: Scheme switching from FHEW to CKKS cTemp2 = cc.EvalFHEWtoCKKS(cFloor, slots, slots, pLWE // (1 << bits), 0, pLWE / (1 << bits)) plaintextDec2 = cc.Decrypt(keys.secretKey, cTemp2) plaintextDec2.SetLength(slots) print(f"Switched floor decryption modulus_LWE mod {pLWE // (1 << bits)}: {plaintextDec2}") def FuncViaSchemeSwitching(): print("\n-----FuncViaSchemeSwitching-----\n") print("Output precision is only wrt the operations in CKKS after switching back.\n") # Step 1: Setup CryptoContext for CKKS multDepth = 9 + 3 + 2 # 1 for CKKS to FHEW, 14 for FHEW to CKKS scaleModSize = 50 ringDim = 2048 sl = HEStd_NotSet slBin = TOY logQ_ccLWE = 25 arbFunc = True slots = 8 # sparsely-packed batchSize = slots parameters = CCParamsCKKSRNS() parameters.SetMultiplicativeDepth(multDepth) parameters.SetScalingModSize(scaleModSize) parameters.SetScalingTechnique(FIXEDMANUAL) parameters.SetSecurityLevel(sl) parameters.SetRingDim(ringDim) parameters.SetBatchSize(batchSize) cc = GenCryptoContext(parameters) # Enable the features that you wish to use cc.Enable(PKE) cc.Enable(KEYSWITCH) cc.Enable(LEVELEDSHE) cc.Enable(ADVANCEDSHE) cc.Enable(SCHEMESWITCH) print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},\n and number of slots {slots}\n") # Generate encryption keys. keys = cc.KeyGen() # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots) ccLWE = FHEWparams[0] privateKeyFHEW = FHEWparams[1] cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW) # Generate the bootstrapping keys for EvalFunc in FHEW ccLWE.BTKeyGen(privateKeyFHEW) print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n") # Set the scaling factor to be able to decrypt; the LWE mod switch is performed on the ciphertext at the last level modulus_CKKS_from = cc.GetModulusCKKS() pLWE = ccLWE.GetMaxPlaintextSpace() # Small precision because GenerateLUTviaFunction needs p < q scFactor = cc.GetScalingFactorReal(0) if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT: scFactor = cc.GetScalingFactorReal(1) scaleCF = modulus_CKKS_from / (scFactor * pLWE) cc.EvalCKKStoFHEWPrecompute(scaleCF) # Step 3: Initialize the function # Initialize Function f(x) = x^3 + 2x + 1 % p def fp(m, p1): if m < p1: return (m * m * m + 2 * m * m + 1) % p1 else: return ((m - p1 / 2) * (m - p1 / 2) * (m - p1 / 2) + 2 * (m - p1 / 2) * (m - p1 / 2) + 1) % p1 # Generate LUT from function f(x) lut = ccLWE.GenerateLUTviaFunction(fp, pLWE) # Step 4: Encoding and encryption of inputs # Inputs x1 = [0.0, 0.3, 2.0, 4.0, 5.0, 6.0, 7.0, 8.0] # Encoding as plaintexts ptxt1 = cc.MakeCKKSPackedPlaintext(x1, 1, 0, None) # Encrypt the encoded vectors c1 = cc.Encrypt(keys.publicKey, ptxt1) # Step 5: Scheme switching from CKKS to FHEW cTemp = cc.EvalCKKStoFHEW(c1) print(f"Input x1: {ptxt1.GetRealPackedValue()}") print("FHEW decryption: ", end="") for i in range(len(cTemp)): result = ccLWE.Decrypt(privateKeyFHEW, cTemp[i], pLWE) print(result, end=" ") # Step 6: Evaluate the function cFunc = [ccLWE.EvalFunc(cTemp[i], lut) for i in range(len(cTemp))] print("\nExpected result x^3 + 2*x + 1 mod p: ", end="") for i in range(slots): print(fp(int(x1[i]) % pLWE, pLWE), end=" ") print(f"\nFHEW decryption mod {pLWE}: ", end="") for i in range(len(cFunc)): pFunc = ccLWE.Decrypt(privateKeyFHEW, cFunc[i], pLWE) print(pFunc, end=" ") print("\n") # Step 7: Scheme switching from FHEW to CKKS cTemp2 = cc.EvalFHEWtoCKKS(cFunc, slots, slots, pLWE, 0, pLWE) plaintextDec2 = cc.Decrypt(keys.secretKey, cTemp2) plaintextDec2.SetLength(slots) print(f"\nSwitched decryption modulus_LWE mod {pLWE}\nwoeks only for messages << p: {plaintextDec2}") # Transform through arcsine cTemp2 = cc.EvalFHEWtoCKKS(cFunc, slots, slots, 4, 0, 2) plaintextDec2 = cc.Decrypt(keys.secretKey, cTemp2) plaintextDec2.SetLength(slots) print("Arcsin(switched result) * p/2pi gives the correct result if messages are < p/4: ", end="") for i in range(slots): x = max(min(plaintextDec2.GetRealPackedValue()[i], 1.0), -1.0) print(asin(x) * pLWE / (2 * pi), end=" ") print() def PolyViaSchemeSwitching(): print("\n-----PolyViaSchemeSwitching-----\n") # Step 1: Setup CryptoContext for CKKS to be switched into # A. Specify main parameters scTech = FIXEDAUTO multDepth = 3 + 9 + 1 + 2 # for r = 3 in FHEWtoCKKS, Chebyshev max depth allowed is 9, 1 more level for postscaling, 3 levels for functionality if scTech == FLEXIBLEAUTOEXT: multDepth += 1 scaleModSize = 50 ringDim = 2048 sl = HEStd_NotSet slBin = TOY logQ_ccLWE = 25 slots = 16 # sparsely-packed batchSize = slots # Create encryption parameters parameters = CCParamsCKKSRNS() parameters.SetMultiplicativeDepth(multDepth) parameters.SetScalingModSize(scaleModSize) parameters.SetScalingTechnique(scTech) parameters.SetSecurityLevel(sl) parameters.SetRingDim(ringDim) parameters.SetBatchSize(batchSize) cc = GenCryptoContext(parameters) # Enable the features that you wish to use cc.Enable(PKE) cc.Enable(KEYSWITCH) cc.Enable(LEVELEDSHE) cc.Enable(ADVANCEDSHE) cc.Enable(SCHEMESWITCH) print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},\n number of slots {slots}, and suports a multiplicative depth of {multDepth}\n") # Generate encryption keys keys = cc.KeyGen() # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, False, logQ_ccLWE, False, slots) ccLWE = FHEWparams[0] privateKeyFHEW = FHEWparams[1] # Step 3: Precompute the necessary keys and information for switching from FHEW to CKKS cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, slots) print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n") pLWE1 = ccLWE.GetMaxPlaintextSpace() # Small precision modulus_LWE = 1 << logQ_ccLWE beta = ccLWE.GetBeta() pLWE2 = modulus_LWE // (2 * beta) # Large precision modulus_from_CKKS = cc.GetModulusCKKS() scFactor = cc.GetScalingFactorReal(0) if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT: scFactor = cc.GetScalingFactorReal(1) scale1 = modulus_from_CKKS // (scFactor * pLWE1) scale2 = modulus_from_CKKS // (scFactor * pLWE2) # Generate keys for the CKKS intermediate computation cc.EvalMultKeyGen(keys.secretKey) cc.EvalRotateKeyGen(keys.secretKey, [1,2]) # Step 4: Encoding and encryption of inputs # For correct CKKS decryption, the messages have to be much smaller than the FHEW plaintext modulus! # Inputs x1 = [1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0] x2 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] x1Rot = RotateInt(x1,1) x1Rot = [x1Rot[i] + x1[i] for i in range(len(x1))] x1Int = [int(round(0.25 * elem * elem) % pLWE1) for elem in x1Rot] x2Rot = RotateInt(x2,2) x2Rot = [x2Rot[i] + x2[i] for i in range(len(x2))] x2Int = [int(round(0.25 * elem * elem) % pLWE2) for elem in x2Rot] # Encrypt # encrypted under small plantext modulus p = 4 and ciphertext modulus ctxtsLWE1 = [ccLWE.Encrypt(privateKeyFHEW, x1[i]) for i in range(slots)] # encrypted under large plaintext modulus and large ciphertext modulus ctxtsLWE2 = [ccLWE.Encrypt(privateKeyFHEW, x2[i], FRESH, pLWE2, modulus_LWE) for i in range(slots)] # Step 5. Perform the scheme switching cTemp = cc.EvalFHEWtoCKKS(ctxtsLWE1, slots, slots) print(f"\n---Input x1: {x1} encrypted under p = 4 and Q = {ctxtsLWE1[0].GetModulus()} ---\n") print(f"round( 0.5 * (x1 + rot(x1,1) )^2 ): {x1Int}\n") # Step 6. Perform the desired computation in CKKS cPoly = cc.EvalAdd(cTemp, cc.EvalRotate(cTemp, 1)) cPoly = cc.EvalMult(cc.EvalMult(cPoly, cPoly), 0.25) # Perform the precomputation for switching back to CKKS cc.EvalCKKStoFHEWPrecompute(scale1) # Tranform the ciphertext from CKKS to FHEW cTemp1 = cc.EvalCKKStoFHEW(cPoly, slots) print(f"\nFHEW decryption with plaintext modulus {pLWE1}: ", end="") for i in range(len(cTemp1)): result = ccLWE.Decrypt(privateKeyFHEW, cTemp1[i], pLWE1) print(result, end=" ") print("\n") # Step 5'. Perform the scheme switching cTemp = cc.EvalFHEWtoCKKS(ctxtsLWE2, slots, slots, pLWE2, 0, pLWE2) print(f"\n---Input x2: {x2} encrypted under p = {pLWE2} and Q = {ctxtsLWE2[0].GetModulus()} ---\n") print(f"round( 0.5 * (x2 + rot(x2,2) )^2 ): {x2Int}\n") # Step 6'. Perform the desired computation in CKKS cPoly = cc.EvalAdd(cTemp, cc.EvalRotate(cTemp, 2)) cPoly = cc.EvalMult(cc.EvalMult(cPoly, cPoly), 0.25) # Perform the precomputation for switching back to CKKS cc.EvalCKKStoFHEWPrecompute(scale2) # Tranform the ciphertext from CKKS to FHEW cTemp2 = cc.EvalCKKStoFHEW(cPoly, slots) print(f"\nFHEW decryption with plaintext modulus {pLWE2}: ", end="") for i in range(len(cTemp2)): result = ccLWE.Decrypt(privateKeyFHEW, cTemp2[i], pLWE2) print(result, end=" ") print("\n") def ComparisonViaSchemeSwitching(): print("\n-----ComparisonViaSchemeSwitching-----\n") print("Output precision is only wrt the operations in CKKS after switching back.\n") # Step 1: Setup CryptoContext for CKKS scTech = FIXEDAUTO multDepth = 17 if scTech == FLEXIBLEAUTOEXT: multDepth += 1 scaleModSize = 50 firstModSize = 60 ringDim = 8192 sl = HEStd_NotSet slBin = TOY logQ_ccLWE = 25 slots = 16 # sparsely-packed batchSize = slots parameters = CCParamsCKKSRNS() parameters.SetMultiplicativeDepth(multDepth) parameters.SetScalingModSize(scaleModSize) parameters.SetFirstModSize(firstModSize) parameters.SetScalingTechnique(scTech) parameters.SetSecurityLevel(sl) parameters.SetRingDim(ringDim) parameters.SetBatchSize(batchSize) parameters.SetSecretKeyDist(UNIFORM_TERNARY) parameters.SetKeySwitchTechnique(HYBRID) parameters.SetNumLargeDigits(3) cc = GenCryptoContext(parameters) # Enable the features that you wish to use cc.Enable(PKE) cc.Enable(KEYSWITCH) cc.Enable(LEVELEDSHE) cc.Enable(ADVANCEDSHE) cc.Enable(SCHEMESWITCH) print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},\n and number of slots {slots}\n and supports a multiplicative depth of {multDepth}\n") # Generate encryption keys. keys = cc.KeyGen() # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, False, logQ_ccLWE, False, slots) ccLWE = FHEWparams[0] privateKeyFHEW = FHEWparams[1] ccLWE.BTKeyGen(privateKeyFHEW) cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW) print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n") # Set the scaling factor to be able to decrypt; the LWE mod switch is performed on the ciphertext at the last level pLWE1 = ccLWE.GetMaxPlaintextSpace() # Small precision modulus_LWE = 1 << logQ_ccLWE beta = ccLWE.GetBeta() pLWE2 = modulus_LWE // (2 * beta) # Large precision scaleSignFHEW = 1 init_level = 0 if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT: init_level = 1 cc.EvalCompareSwitchPrecompute(pLWE2, init_level, scaleSignFHEW) # Step 3: Encoding and encryption of inputs x1 = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0] x2 = [5.25] * slots ptxt1 = cc.MakeCKKSPackedPlaintext(x1, 1, 0, None, slots) ptxt2 = cc.MakeCKKSPackedPlaintext(x2, 1, 0, None, slots) c1 = cc.Encrypt(keys.publicKey, ptxt1) c2 = cc.Encrypt(keys.publicKey, ptxt2) cDiff = cc.EvalSub(c1, c2) # Step 4: CKKS to FHEW switching and sign evaluation to test correctness pDiff = cc.Decrypt(keys.secretKey, cDiff) pDiff.SetLength(slots) print("Difference of inputs: ", end="") for i in range(slots): print(pDiff.GetRealPackedValue()[i], end=" ") eps = 0.0001 print("\nExpected sign result from CKKS: ", end="") for i in range(slots): print(int(round(pDiff.GetRealPackedValue()[i] / eps) * eps < 0), end=" ") print() LWECiphertexts = cc.EvalCKKStoFHEW(cDiff, slots) print("\nFHEW decryption with plaintext modulus ", pLWE2, ": ", end="") for i in range(len(LWECiphertexts)): plainLWE = ccLWE.Decrypt(privateKeyFHEW, LWECiphertexts[i], pLWE2) print(plainLWE, end=" ") print("\nExpected sign result in FHEW with plaintext modulus ", pLWE2, " and scale ", scaleSignFHEW, ": ", end="") for i in range(slots): print((int(round(pDiff.GetRealPackedValue()[i] * scaleSignFHEW)) % pLWE2 - pLWE2 / 2.0 >= 0), end=" ") print() print("Obtained sign result in FHEW with plaintext modulus ", pLWE2, " and scale ", scaleSignFHEW, ": ", end="") LWESign = [None] * len(LWECiphertexts) for i in range(len(LWECiphertexts)): LWESign[i] = ccLWE.EvalSign(LWECiphertexts[i]) plainLWE = ccLWE.Decrypt(privateKeyFHEW, LWESign[i], 2) print(plainLWE, end=" ") print() # Step 5'': Direct comparison via CKKS->FHEW->CKKS cResult = cc.EvalCompareSchemeSwitching(c1, c2, slots, 0, scaleSignFHEW) plaintextDec3 = cc.Decrypt(keys.secretKey, cResult) plaintextDec3.SetLength(slots) print(f"Decrypted swutched result: {plaintextDec3}\n") def ArgminViaSchemeSwitching(): print("\n-----ArgminViaSchemeSwitching-----\n") print("Output precision is only wrt the operations in CKKS after switching back\n") # Step 1: Setup CryptoContext for CKKS scaleModSize = 50 firstModSize = 60 ringDim = 8192 sl = HEStd_NotSet slBin = TOY logQ_ccLWE = 25 arbFunc = False oneHot = True # Change to false if the output should not be one-hot encoded slots = 16 # sparsely-packed batchSize = slots numValues = 16 scTech = FIXEDMANUAL multDepth = 9 + 3 + 1 + int(log2(numValues)) # 13 for FHEW to CKKS, log2(numValues) for argmin if scTech == FLEXIBLEAUTOEXT: multDepth += 1 parameters = CCParamsCKKSRNS() parameters.SetMultiplicativeDepth(multDepth) parameters.SetScalingModSize(scaleModSize) parameters.SetFirstModSize(firstModSize) parameters.SetScalingTechnique(scTech) parameters.SetSecurityLevel(sl) parameters.SetRingDim(ringDim) parameters.SetBatchSize(batchSize) cc = GenCryptoContext(parameters) # Enable the features that you wish to use cc.Enable(PKE) cc.Enable(KEYSWITCH) cc.Enable(LEVELEDSHE) cc.Enable(ADVANCEDSHE) cc.Enable(SCHEMESWITCH) print("CKKS scheme is using ring dimension ", cc.GetRingDimension()) print(", and number of slots ", slots, ", and supports a depth of ", multDepth, "\n") # Generate encryption keys keys = cc.KeyGen() # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots) ccLWE = FHEWparams[0] privateKeyFHEW = FHEWparams[1] cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, numValues, oneHot) print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n") # Scale the inputs to ensure their difference is correctly represented after switching to FHEW scaleSign = 512 modulus_LWE = 1 << logQ_ccLWE beta = ccLWE.GetBeta() pLWE = modulus_LWE // (2 * beta) # Large precision init_level = 0 if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT: init_level = 1 cc.EvalCompareSwitchPrecompute(pLWE, init_level, scaleSign) # Step 3: Encoding and encryption of inputs x1 = [-1.125, -1.12, 5.0, 6.0, -1.0, 2.0, 8.0, -1.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.25, 15.30] print("Expected minimum value ", min(x1), " at location ", x1.index(min(x1))) print("Expected maximum value ", max(x1), " at location ", x1.index(max(x1))) ptxt1 = cc.MakeCKKSPackedPlaintext(x1) c1 = cc.Encrypt(keys.publicKey, ptxt1) # Step 4: Argmin evaluation result = cc.EvalMinSchemeSwitching(c1, keys.publicKey, numValues, slots, oneHot) ptxtMin = cc.Decrypt(keys.secretKey, result[0]) ptxtMin.SetLength(1) print("Minimum value: ", ptxtMin) ptxtMin = cc.Decrypt(keys.secretKey, result[1]) if oneHot: ptxtMin.SetLength(numValues) print("Argmin indicator vector: ", ptxtMin) else: ptxtMin.SetLength(1) print("Argmin: ", ptxtMin) result = cc.EvalMaxSchemeSwitching(c1, keys.publicKey, numValues, slots, oneHot) ptxtMax = cc.Decrypt(keys.secretKey, result[0]) ptxtMax.SetLength(1) print("Maximum value: ", ptxtMax) ptxtMax = cc.Decrypt(keys.secretKey, result[1]) if oneHot: ptxtMax.SetLength(numValues) print("Argmax indicator vector: ", ptxtMax) else: ptxtMax.SetLength(1) print("Argmax: ", ptxtMax) def ArgminViaSchemeSwitchingAlt(): print("\n-----ArgminViaSchemeSwitchingAlt-----\n") print("Output precision is only wrt the operations in CKKS after switching back\n") # Step 1: Setup CryptoContext for CKKS scaleModSize = 50 firstModSize = 60 ringDim = 8192 sl = HEStd_NotSet slBin = TOY logQ_ccLWE = 25 arbFunc = False oneHot = True alt = True slots = 16 batchSize = slots numValues = 16 scTech = FIXEDAUTO multDepth = 9 + 3 + 1 + int(log2(numValues)) parameters = CCParamsCKKSRNS() parameters.SetMultiplicativeDepth(multDepth) parameters.SetScalingModSize(scaleModSize) parameters.SetFirstModSize(firstModSize) parameters.SetScalingTechnique(scTech) parameters.SetSecurityLevel(sl) parameters.SetRingDim(ringDim) parameters.SetBatchSize(batchSize) cc = GenCryptoContext(parameters) cc.Enable(PKE) cc.Enable(KEYSWITCH) cc.Enable(LEVELEDSHE) cc.Enable(ADVANCEDSHE) cc.Enable(SCHEMESWITCH) print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},") print(f"number of slots {slots}, and supports a multiplicative depth of {multDepth}\n") keys = cc.KeyGen() # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots) ccLWE = FHEWparams[0] privateKeyFHEW = FHEWparams[1] cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, numValues, oneHot, alt) print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n") scaleSign = 512 modulus_LWE = 1 << logQ_ccLWE beta = ccLWE.GetBeta() pLWE = modulus_LWE // (2 * beta) init_level = 0 if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT: init_level = 1 cc.EvalCompareSwitchPrecompute(pLWE, init_level, scaleSign) # But we can also include the scaleSign in pLWE (here we use the fact both pLWE and scaleSign are powers of two) # cc.EvalCompareSwitchPrecompute(pLWE / scaleSign, init_level, 1) # Step 3: Encoding and encryption of inputs # Inputs x1 = [-1.125, -1.12, 5.0, 6.0, -1.0, 2.0, 8.0, -1.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.25, 15.30] print("Expected minimum value ", min(x1), " at location ", x1.index(min(x1))) print("Expected maximum value ", max(x1), " at location ", x1.index(max(x1))) # Encoding as plaintexts ptxt1 = cc.MakeCKKSPackedPlaintext(x1) # Only if we set batchsize # ptxt1 = cc.MakeCKKSPackedPlaintext(x1, 1, 0, None, slots) # If batchsize is not set # Encrypt the encoded vectors c1 = cc.Encrypt(keys.publicKey, ptxt1) # Step 4: Argmin evaluation result = cc.EvalMinSchemeSwitchingAlt(c1, keys.publicKey, numValues, slots, oneHot) ptxtMin = cc.Decrypt(keys.secretKey, result[0]) ptxtMin.SetLength(1) print("Minimum value: ", ptxtMin) ptxtMin = cc.Decrypt(keys.secretKey, result[1]) if oneHot: ptxtMin.SetLength(numValues) print("Argmin indicator vector: ", ptxtMin) else: ptxtMin.SetLength(1) print("Argmin: ", ptxtMin) result = cc.EvalMaxSchemeSwitchingAlt(c1, keys.publicKey, numValues, slots, oneHot) ptxtMax = cc.Decrypt(keys.secretKey, result[0]) ptxtMax.SetLength(1) print("Maximum value: ", ptxtMax) ptxtMax = cc.Decrypt(keys.secretKey, result[1]) if oneHot: ptxtMax.SetLength(numValues) print("Argmax indicator vector: ", ptxtMax) else: ptxtMax.SetLength(1) print("Argmax: ", ptxtMax) def ArgminViaSchemeSwitchingUnit(): print("\n-----ArgminViaSchemeSwitchingUnit-----\n") print("Output precision is only wrt the operations in CKKS after switching back\n") # Step 1: Setup CryptoContext for CKKS scaleModSize = 50 firstModSize = 60 ringDim = 8192 sl = HEStd_NotSet slBin = TOY logQ_ccLWE = 25 arbFunc = False oneHot = True slots = 32 # sparsely-packed batchSize = slots numValues = 32 scTech = FLEXIBLEAUTOEXT multDepth = 9 + 3 + 1 + int(log2(numValues)) # 1 for CKKS to FHEW, 13 for FHEW to CKKS, log2(numValues) for argmin if scTech == FLEXIBLEAUTOEXT: multDepth += 1 parameters = CCParamsCKKSRNS() parameters.SetMultiplicativeDepth(multDepth) parameters.SetScalingModSize(scaleModSize) parameters.SetFirstModSize(firstModSize) parameters.SetScalingTechnique(scTech) parameters.SetSecurityLevel(sl) parameters.SetRingDim(ringDim) parameters.SetBatchSize(batchSize) cc = GenCryptoContext(parameters) # Enable the features that you wish to use cc.Enable(PKE) cc.Enable(KEYSWITCH) cc.Enable(LEVELEDSHE) cc.Enable(ADVANCEDSHE) cc.Enable(SCHEMESWITCH) cc.Enable(FHE) print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},") print(f"number of slots {slots}, and supports a multiplicative depth of {multDepth}\n") # Generate encryption keys. keys = cc.KeyGen() # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots) ccLWE = FHEWparams[0] privateKeyFHEW = FHEWparams[1] cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, numValues, oneHot) print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n") init_level = 0 if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT: init_level = 1 # Here we assume the message does not need scaling, as they are in the unit circle. cc.EvalCompareSwitchPrecompute(1, init_level, 1) # Step 3: Encoding and encryption of inputs # Inputs x1 = [-1.125, -1.12, 5.0, 6.0, -1.0, 2.0, 8.0, -1.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.25, 15.30] if len(x1) < slots: x1.extend([0] * (slots - len(x1))) print("Input: ", x1) p = 1 << (firstModSize - scaleModSize - 1) x1 = [elem / (2 * p) for elem in x1] print("Input scaled: ", x1) print("Expected minimum value ", min(x1), " at location ", x1.index(min(x1))) print("Expected maximum value ", max(x1), " at location ", x1.index(max(x1))) # Encoding as plaintexts ptxt1 = cc.MakeCKKSPackedPlaintext(x1) # Encrypt the encoded vectors c1 = cc.Encrypt(keys.publicKey, ptxt1) # Step 4: Argmin evaluation result = cc.EvalMinSchemeSwitching(c1, keys.publicKey, numValues, slots, oneHot) ptxtMin = cc.Decrypt(keys.secretKey, result[0]) ptxtMin.SetLength(1) print("Minimum value: ", ptxtMin) ptxtMin = cc.Decrypt(keys.secretKey, result[1]) if oneHot: ptxtMin.SetLength(numValues) print("Argmin indicator vector: ", ptxtMin) else: ptxtMin.SetLength(1) print("Argmin: ", ptxtMin) result = cc.EvalMaxSchemeSwitching(c1, keys.publicKey, numValues, slots, oneHot) ptxtMax = cc.Decrypt(keys.secretKey, result[0]) ptxtMax.SetLength(1) print("Maximum value: ", ptxtMax) ptxtMax = cc.Decrypt(keys.secretKey, result[1]) if oneHot: ptxtMax.SetLength(numValues) print("Argmax indicator vector: ", ptxtMax) else: ptxtMax.SetLength(1) print("Argmax: ", ptxtMax) def ArgminViaSchemeSwitchingAltUnit(): print("\n-----ArgminViaSchemeSwitchingAltUnit-----\n") print("Output precision is only wrt the operations in CKKS after switching back\n") # Step 1: Setup CryptoContext for CKKS scaleModSize = 50 firstModSize = 60 ringDim = 8192 sl = HEStd_NotSet slBin = TOY logQ_ccLWE = 25 arbFunc = False oneHot = True alt = True # alternative mode of argmin which has fewer rotation keys and does more operations in FHEW than in CKKS slots = 32 # sparsely-packed batchSize = slots numValues = 32 scTech = FLEXIBLEAUTOEXT multDepth = 9 + 3 + 1 + int(log2(numValues)) # 1 for CKKS to FHEW, 13 for FHEW to CKKS, log2(numValues) for argmin if scTech == FLEXIBLEAUTOEXT: multDepth += 1 parameters = CCParamsCKKSRNS() parameters.SetMultiplicativeDepth(multDepth) parameters.SetScalingModSize(scaleModSize) parameters.SetFirstModSize(firstModSize) parameters.SetScalingTechnique(scTech) parameters.SetSecurityLevel(sl) parameters.SetRingDim(ringDim) parameters.SetBatchSize(batchSize) cc = GenCryptoContext(parameters) # Enable the features that you wish to use cc.Enable(PKE) cc.Enable(KEYSWITCH) cc.Enable(LEVELEDSHE) cc.Enable(ADVANCEDSHE) cc.Enable(SCHEMESWITCH) cc.Enable(FHE) print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()},") print(f"number of slots {slots}, and supports a multiplicative depth of {multDepth}\n") # Generate encryption keys. keys = cc.KeyGen() # Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching FHEWparams = cc.EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, False, slots) ccLWE = FHEWparams[0] privateKeyFHEW = FHEWparams[1] cc.EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, numValues, oneHot, alt) print(f"FHEW scheme is using lattice parameter {ccLWE.Getn()},\n logQ {logQ_ccLWE},\n and modulus q {ccLWE.Getq()}\n") init_level = 0 if cc.GetScalingTechnique() == FLEXIBLEAUTOEXT: init_level = 1 # Here we assume the message does not need scaling, as they are in the unit circle. cc.EvalCompareSwitchPrecompute(1, init_level, 1) # Step 3: Encoding and encryption of inputs # Inputs x1 = [-1.125, -1.12, 5.0, 6.0, -1.0, 2.0, 8.0, -1.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.25, 15.30] if len(x1) < slots: zeros = [0] * (slots - len(x1)) x1.extend(zeros) print("Input: ", x1) p = 1 << (firstModSize - scaleModSize - 1) x1 = [elem / (2 * p) for elem in x1] print("Input scaled: ", x1) print("Expected minimum value ", min(x1), " at location ", x1.index(min(x1))) print("Expected maximum value ", max(x1), " at location ", x1.index(max(x1))) # Encoding as plaintexts ptxt1 = cc.MakeCKKSPackedPlaintext(x1) # Encrypt the encoded vectors c1 = cc.Encrypt(keys.publicKey, ptxt1) # Step 4: Argmin evaluation result = cc.EvalMinSchemeSwitchingAlt(c1, keys.publicKey, numValues, slots, oneHot) ptxtMin = cc.Decrypt(keys.secretKey, result[0]) ptxtMin.SetLength(1) print("Minimum value: ", ptxtMin) ptxtMin = cc.Decrypt(keys.secretKey, result[1]) if oneHot: ptxtMin.SetLength(numValues) print("Argmin indicator vector: ", ptxtMin) else: ptxtMin.SetLength(1) print("Argmin: ", ptxtMin) result = cc.EvalMaxSchemeSwitchingAlt(c1, keys.publicKey, numValues, slots, oneHot) ptxtMax = cc.Decrypt(keys.secretKey, result[0]) ptxtMax.SetLength(1) print("Maximum value: ", ptxtMax) ptxtMax = cc.Decrypt(keys.secretKey, result[1]) if oneHot: ptxtMax.SetLength(numValues) print("Argmax indicator vector: ", ptxtMax) else: ptxtMax.SetLength(1) print("Argmax: ", ptxtMax) # Helper functions: def ReduceRotation(index, slots): islots = int(slots) # if slots is a power of 2 if (slots & (slots - 1)) == 0: n = int(log2(slots)) if index >= 0: return index - ((index >> n) << n) return index + islots + ((int(abs(index)) >> n) << n) return (islots + index % islots) % islots def RotateInt(a, index): slots = len(a) result = [0]*slots if index < 0 or index > slots: index = ReduceRotation(index, slots) if index == 0: result = a.copy() else: # two cases: i+index <= slots and i+index > slots for i in range(0, slots - index): result[i] = a[i + index] for i in range(slots - index, slots): result[i] = a[i + index - slots] return result if __name__ == "__main__": main()