FHE Basics¶
Einführung¶
Veranschaulichung was FHE kann:
- Encode
- Encrypt
- Decrypt
- Decode
Basisoperationen:
- Addition
- Multiplikation
- Rotation
Step 1. Importiere pyhelayers library¶
In [35]:
import pyhelayers
import utils
utils.verify_memory()
# Print the ciphertext content for demo purposes
pyhelayers.get_print_options().print_encrypted_content=True
print("Imported pyhelayers", pyhelayers.VERSION)
Imported pyhelayers 1.5.3.0
Step 2. Initialisiere kryptografische Parameter¶
In [37]:
requirement = pyhelayers.HeConfigRequirement(
num_slots = 8192, # Number of slots per ciphertext
multiplication_depth = 2, # Allow 2 levels of multiplications
fractional_part_precision = 40, # Set the precision to 1/2^40.
integer_part_precision = 20, # Set the largest number to 2^20.
security_level = 128)
he_context = pyhelayers.DefaultContext()
he_context.init(requirement)
Encoding(Klartextvektor) --> Polynom¶
- nur andere Repräsentation
- Encodings gleicher Klartexte sind identisch (deterministisch)
- Encoding fügt schon enormen Overhead hinzu In [39]:
# Create the Encoder using the context.
encoder = pyhelayers.Encoder(he_context)
# Encode a vector.
v1 = [1.0, 2.0, 3.0]
encode_v1_1 = encoder.encode(v1)
encode_v1_2 = encoder.encode(v1)
print(
f'1. Encoding: {encode_v1_1} \n'
f'2. Encoding: {encode_v1_2} \n'
)
print(f'Typ von Klartext: {type(v1)} \n'
f'Länge des Klartextes: {len(v1)} \n')
print(f'Typ von Encoding: {type(encode_v1_1)} \n'
f'Länge des Encodings: {encode_v1_1.slot_count()}\n \n'
f'--> Das Encoding ist viel länger als der Klartext - großer Overhead')
1. Encoding: PTile CI=2, logscale=40 , bit usage=41.585, max value=3 (1,-4.75e-17) (2,1.11e-18) (3,-1.19e-16) (2.42e-11,4.24e-18) ... (3.96e-11,-2.7e-18) 2. Encoding: PTile CI=2, logscale=40 , bit usage=41.585, max value=3 (1,-4.75e-17) (2,1.11e-18) (3,-1.19e-16) (2.42e-11,4.24e-18) ... (3.96e-11,-2.7e-18) Typ von Klartext: <class 'list'> Länge des Klartextes: 3 Typ von Encoding: <class 'pyhelayers.PTile'> Länge des Encodings: 8192 --> Das Encoding ist viel länger als der Klartext - großer Overhead
Encrypt(Encoding) --> Paar von Polynomen¶
- Sicherheit kommt hier her
- jeder Geheimtext sieht anders aus (fügt noise hinzu) In [4]:
c1_1 = encoder.encode_encrypt(v1)
c1_2 = encoder.encode_encrypt(v1)
print(f'1. Encryption: {c1_1} \n'
f'2. Encryption: {c1_2} \n'
)
print(f'Typ von Encryption: {type(c1_1)} \n'
f'Länge der Verschlüsselung: {c1_1.slot_count()}')
1. Encryption: CIPHERTEXT [[1131135981975755219,1112425318636213092,505430410042946198,667051018363176745 ... 537006492109] ] 2. Encryption: CIPHERTEXT [[429019767460013127,831004575477499145,566215651600707057,172610751300467944 ... 131783248038] ] Typ von Encryption: <class 'pyhelayers.CTile'> Länge der Verschlüsselung: 8192
Decrypt(ciphertext) --> Encoding¶
- geht nur mit secret key (Passwort)
- die Dechiffrierung ist korrekt
- die Dechiffrierung hat einen Overhead
- die Dechiffrierung ist approximativ In [5]:
d1 = encoder.decrypt_decode_double(c1_1)
d2 = encoder.decrypt_decode_double(c1_2)
print(f'1. Decryption: {d1} \n'
f'2. Decryption: {d2} \n'
)
print(f'Typ der Dechiffrierung: {type(d1)} \n'
f'Länge der Dechiffrierung: {len(d1)} \n')
print(f'Vergleich Klartext vs. Dechiffrierung \n'
f'Klartext: {v1} \n'
f'Dechiffrierung: {d1[0:3]} \n'
f'Rest des Vektors: {d1[3:6]}\n')
1. Decryption: [ 1.00000000e+00 2.00000000e+00 3.00000000e+00 ... 2.23855968e-10 -2.97007349e-09 -5.71343740e-10] 2. Decryption: [ 9.99999999e-01 2.00000000e+00 3.00000000e+00 ... 1.11710537e-11 -7.50825423e-10 -1.66492654e-09] Typ der Dechiffrierung: <class 'numpy.ndarray'> Länge der Dechiffrierung: 8192 Vergleich Klartext vs. Dechiffrierung Klartext: [1.0, 2.0, 3.0] Dechiffrierung: [1. 2. 3.] Rest des Vektors: [ 3.31488864e-09 -5.84605247e-10 -2.36247259e-09]
Zusammenfassung zu Encoding, Encryption, Decoding, Decryption¶
In [6]:
print('Initial vector: {}'.format(v1))
print('Encoded vector: {}'.format(encode_v1_1))
print('Encrypted vector: {}'.format(c1_1))
print('Decoded vector: {}'.format(d1[:3]))
Initial vector: [1.0, 2.0, 3.0] Encoded vector: PTile CI=2, logscale=40 , bit usage=41.585, max value=3 (1,-4.75e-17) (2,1.11e-18) (3,-1.19e-16) (2.42e-11,4.24e-18) ... (3.96e-11,-2.7e-18) Encrypted vector: CIPHERTEXT [[1131135981975755219,1112425318636213092,505430410042946198,667051018363176745 ... 537006492109] ] Decoded vector: [1. 2. 3.]
Rechnen auf verschlüsselten Daten¶
Addition/ Subtraktion¶
Addieren mittels .add() Methode auf dem ersten CTile:
In [21]:
plain_1 = [1, 2, 3]
plain_2 = [4, 5, 6.5]
cipher_1 = encoder.encode_encrypt(plain_1)
cipher_2 = encoder.encode_encrypt(plain_2)
print(f'geheimtext 1: {cipher_1} \ngeheimtext 2: {cipher_2}')
# !!! Wir addieren auf verschlüsselten Daten!!!
cipher_1.add(cipher_2)
print(f'ergebnis: {cipher_1} \n')
print('Result Addition: {}'.format(encoder.decrypt_decode_double(cipher_1)[:3]))
# analog mit subtraktion
plain_3 = [1, 2, 3]
plain_4 = [-4, -3, -6.5]
cipher_3 = encoder.encode_encrypt(plain_3)
cipher_4 = encoder.encode_encrypt(plain_4)
# !!! Wir subtrahieren auf verschlüsselten Daten!!!
cipher_3.add(cipher_4)
print('Result Subtraktion: {}'.format(encoder.decrypt_decode_double(cipher_3)[:3]))
geheimtext 1: CIPHERTEXT [[779118373764567359,777002830475277794,487170086735964006,607831202537423885 ... 28626693460] ] geheimtext 2: CIPHERTEXT [[636452704892897235,18073020191828212,252724995129612565,475442727712704636 ... 741442868876] ] ergebnis: CIPHERTEXT [[262649574050781457,795075850667106006,739895081865576571,1083273930250128521 ... 770069562336] ] Result Addition: [5. 7. 9.5] Result Subtraktion: [-3. -1. -3.49999999]
Multiplikation/ Division¶
Addieren mittels .multiply() Methode auf dem ersten CTile:
In [23]:
plain_1 = [1, 2, 3]
plain_2 = [4, 5, -6.5]
cipher_1 = encoder.encode_encrypt(plain_1)
cipher_2 = encoder.encode_encrypt(plain_2)
print(f'geheimtext 1: {cipher_1} \ngeheimtext 2: {cipher_2}')
# !!! Wir multiplizieren auf verschlüsselten Daten!!!
cipher_1.multiply(cipher_2)
print(f'ergebnis: {cipher_1} \n')
print('Result Multiplikation: {}'.format(encoder.decrypt_decode_double(cipher_1)[:3]))
# analog mit Division
plain_3 = [1, 2, 3]
plain_4 = [1/2, 1/3, -1/5]
cipher_3 = encoder.encode_encrypt(plain_3)
cipher_4 = encoder.encode_encrypt(plain_4)
# !!! Wir dividieren auf verschlüsselten Daten!!!
cipher_3.multiply(cipher_4)
print('Result Division: {}'.format(encoder.decrypt_decode_double(cipher_3)[:3]))
geheimtext 1: CIPHERTEXT [[1097283863602053394,9354795132089334,400621897882819895,326089640398490511 ... 454926127153] ] geheimtext 2: CIPHERTEXT [[916575898319111688,1053580958696087342,816237921836376049,138814830951217515 ... 913517383928] ] ergebnis: CIPHERTEXT [[654564794388088258,188519724547076812,1139610384326327666,1083455393637216895 ... 74583677062] ] Result Multiplikation: [ 4. 10. -19.49999997] Result Division: [ 0.5 0.66666667 -0.59999999]
Rotation¶
Rotieren mittels .rotate() Methode auf dem ersten CTile:
In [32]:
m = [1, 2, 3]
c = encoder.encode_encrypt(plain_1)
print(f'geheimtext 1: {c}')
c.rotate(-1)
print(f'ergebnis: {c} \n')
print(f'm: {m}')
print('Result Rotation: {}'.format(encoder.decrypt_decode_double(c)[:4]))
geheimtext 1: CIPHERTEXT [[586537068613204090,219016388662698895,1147545213661994966,768152345655487977 ... 179994915353] ] ergebnis: CIPHERTEXT [[599926430988645676,727055542217798224,998235849372833756,836812647448946916 ... 409630059191] ] m: [1, 2, 3] Result Rotation: [2.94314936e-07 1.00000044e+00 2.00000004e+00 3.00000000e+00]
Durchschnitt berechnen¶
Man kann auch komplizierte Funktionen zusammenbauen
In [34]:
v1 = [1.0, 5.0, 13.0]
c1 = encoder.encode_encrypt(v1)
v2 = [2.0, 6.0, 18.0]
c2 = encoder.encode_encrypt(v2)
v3 = [3.0, 1.0, 20.0]
c3 = encoder.encode_encrypt(v3)
print(f'geheimtext 1: {c1} \ngeheimtext 2: {c2}\ngeheimtext 3: {c3}')
c1.add(c2)
c1.add(c3)
c1.multiply_scalar(1/3)
print(f'ergebnis: {c1} \n')
print('Result: {}'.format(encoder.decrypt_decode_double(c1)[:3]))
geheimtext 1: CIPHERTEXT [[552070155153608120,805284675234682769,208357715202033589,310653003918033555 ... 1047349113151] ] geheimtext 2: CIPHERTEXT [[798657649215876734,860634207456706686,851552505377225521,792274579944754522 ... 468991438378] ] geheimtext 3: CIPHERTEXT [[385361835998236336,897719448037193841,580809716355919033,769178920464783808 ... 397939367739] ] ergebnis: CIPHERTEXT [[396067391478773528,1065516990712473916,888057515677871983,504469227572553077 ... 927220862567] ] Result: [ 2. 4. 17.]