Skip to content

Instantly share code, notes, and snippets.

@bquast
Last active December 23, 2023 23:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bquast/73a9efbe4730809713b95271cdffc310 to your computer and use it in GitHub Desktop.
Save bquast/73a9efbe4730809713b95271cdffc310 to your computer and use it in GitHub Desktop.
Homomorphic Encryption CKKS encoder R
library(polynom)
M <- 8
N <- M %/% 2
scale <- 64
xi <- complex(real = cos(2 * pi / M), imaginary = sin(2 * pi / M))
vandermonde <- function(xi, M) {
N <- M %/% 2
# Initialize an empty matrix with complex data type
v_matrix <- matrix(complex(real = numeric(N * N)), nrow = N, ncol = N)
for (i in 1:N) {
root <- xi ^ (2 * (i - 1) + 1)
for (j in 1:N) {
v_matrix[i, j] <- root ^ (j - 1)
}
}
return(v_matrix)
}
sigma_inverse <- function(xi, M, b) {
A <- vandermonde(xi, M)
coeffs <- solve(A, b)
return(coeffs)
}
sigma <- function(xi, M, p) {
outputs <- numeric(N)
N <- M %/% 2
for (i in 1:N) {
root <- xi^(2 * (i - 1) + 1)
output <- sum(p * root^(0:(N-1)))
outputs[i] <- output
}
return(outputs)
}
sigma_R_discretization <- function(xi, M, z) {
sigma_R_basis <- vandermonde(xi, M)
coordinates <- compute_basis_coordinates(sigma_R_basis, z)
rounded_coordinates <- coordinate_wise_random_rounding(coordinates)
y <- sigma_R_basis %*% rounded_coordinates
return(y)
}
compute_basis_coordinates <- function(sigma_R_basis, z) {
return(sapply(1:ncol(sigma_R_basis), function(i) {
b <- sigma_R_basis[, i]
Re(sum(z * Conj(b)) / sum(b * Conj(b)))
}))
}
round_coordinates <- function(coordinates) {
return(coordinates - floor(coordinates))
}
coordinate_wise_random_rounding <- function(coordinates) {
r <- round_coordinates(coordinates)
f <- sapply(r, function(c) sample(c(c, c-1), 1, prob=c(1-c, c)))
rounded_coordinates <- coordinates - f
return(as.integer(rounded_coordinates))
}
pi_function <- function(M, z) {
N <- M %/% 4
return(z[1:N])
}
pi_inverse <- function(z) {
z_conjugate <- Conj(rev(z))
return(c(z, z_conjugate))
}
# Assuming all other functions are defined correctly, focusing on encode and decode
encode <- function(xi, M, scale, z) {
pi_z <- pi_inverse(z)
scaled_pi_z <- scale * pi_z
rounded_scale_pi_zi <- sigma_R_discretization(xi, M, scaled_pi_z)
p <- sigma_inverse(xi, M, rounded_scale_pi_zi)
coef <- as.vector(round(Re(p)))
return(polynomial(coef))
}
decode <- function(xi, M, scale, p) {
rescaled_p <- coef(p) / scale
z <- sigma(xi, M, rescaled_p)
return(pi_function(M, z))
}
# Example usage
z <- c(complex(real=3, imaginary=4), complex(real=2, imaginary=-1))
p <- encode(xi, M, scale, z)
decoded_z <- decode(xi, M, scale, p)
# Output the results
print(p)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment