from concrete import fhe
from concrete.fhe import Value
from concrete.compiler import TransportValue # Import TransportValue
# Constants for scaling float embeddings
SCALING_FACTOR = 10 # Multiply by 10^4 to retain 4 decimal places
MAX_VALUE_incryption = 2**7 - 1 # Ensure values stay within 16-bit limit
MAX_VALUE = 2**17 - 1 # Ensure values stay within 16-bit limit
# Step 1: Define Encryption Function
def encrypt_single_value(x: int):
print("***********", x)
return x # Identity function for FHE encryption
# Step 2: Define Distance Functions
def manhattan_distance(vec1, vec2):
print("vec1 ", vec1)
return sum([fhe.abs(a - b) for a, b in zip(vec1, vec2)])
def euclidean_distance_squared(vec1, vec2):
return sum((a - b) ** 2 for a, b in zip(vec1, vec2))
# Step 3: Compile Encryption & Distance Circuits
print(f"🔹 Compiling encryption circuit...")
encryption_compiler = fhe.Compiler(encrypt_single_value, {"x": "encrypted"})
print(f"🔹 Compiling distance circuits...")
manhattan_compiler = fhe.Compiler(manhattan_distance, {"vec1": "encrypted", "vec2": "encrypted"})
euclidean_compiler = fhe.Compiler(euclidean_distance_squared, {"vec1": "encrypted", "vec2": "encrypted"})
# Step 4: Generate Encryption Circuit
inputset = [(a) for a in range(MAX_VALUE_incryption)]
print("inputset", inputset)
encryption_circuit = encryption_compiler.compile(inputset)
print(f"🔹 Generating keys for encryption...")
encryption_circuit.keygen()
# Step 5: Generate Distance Circuits
inputset_vectors = [(a, a + 100) for a in range(MAX_VALUE)]
print("inputset_vectors", inputset_vectors)
print(f"🔹 Compiling distance circuits with input set vectors...")
manhattan_circuit = manhattan_compiler.compile(inputset_vectors)
euclidean_circuit = euclidean_compiler.compile(inputset_vectors)
print(f"🔹 Generating keys for distance computation...")
manhattan_circuit.keygen()
euclidean_circuit.keygen()
# Step 6: Encrypt Face Embeddings
def encrypt_vector(vector, circuit):
print("vector", vector)
scaled_vector = [int(v * SCALING_FACTOR) for v in vector]
print("scaled_vector", scaled_vector)
encrypted_vector = [circuit.encrypt(v) for v in scaled_vector]
print("encrypted_vector", encrypted_vector)
# Validate the length of the encrypted vector
expected_shape = (4, 1281) # Expected shape: 4 feature vectors, each with 1281 values
# Print shape information
print("Length of encrypted_vector:", len(encrypted_vector)) # Should be 4
for i, enc_val in enumerate(encrypted_vector):
try:
print(f"Encrypted vector {i} shape:", enc_val.shape)
except AttributeError:
print(f"Encrypted vector {i} has no shape attribute, but is type {type(enc_val)}")
return encrypted_vector
face_embeddings = [
[0.12, 0.56, 0.78, 0.34],
[0.14, 0.54, 0.79, 0.31],
[0.20, 0.60, 0.72, 0.40],
[0.11, 0.50, 0.80, 0.30],
]
print(f"🔹 Encrypting face embeddings...")
encrypted_embeddings = [encrypt_vector(embedding, encryption_circuit) for embedding in face_embeddings]
# Step 7: Compute Homomorphic Distances
def compute_homomorphic_distances(enc_x, enc_y):
print(f"Computing distances for encrypted vectors...")
# Ensure that the encrypted values are passed as individual arguments, not as a list
try:
# Unpack the encrypted lists and pass them as separate arguments
print("enc_x ", enc_x)
print("enc_y ", enc_y)
encrypted_manhattan = [manhattan_circuit.run(ex, ey) for ex, ey in zip(enc_x, enc_y)]
decrypted_manhattan = manhattan_circuit.decrypt(encrypted_manhattan) / SCALING_FACTOR
print("decrypted_manhattan ", decrypted_manhattan)
encrypted_euclidean = euclidean_circuit.run(*enc_x, *enc_y)
decrypted_euclidean = euclidean_circuit.decrypt(encrypted_euclidean) / (SCALING_FACTOR ** 2)
return decrypted_manhattan, decrypted_euclidean
except Exception as e:
print("🚨 Error in computing homomorphic distances:", str(e))
raise
print(f"🔹 Computing homomorphic distances between embeddings...")
results = {}
for i in range(len(encrypted_embeddings)):
for j in range(i + 1, len(encrypted_embeddings)):
key = f"Face {i+1} vs Face {j+1}"
manhattan_result, euclidean_result = compute_homomorphic_distances(encrypted_embeddings[i], encrypted_embeddings[j])
results[key] = {
"Manhattan Distance": manhattan_result,
"Euclidean Distance Squared": euclidean_result
}
print(f"✅ Success! Computed distances:")
for key, value in results.items():
print(f"{key} -> Manhattan: {value['Manhattan Distance']}, Euclidean²: {value['Euclidean Distance Squared']}")
1 Like