带有 CKKS 的 Microsoft SEAL 中的矢量点积
Vector dot product in Microsoft SEAL with CKKS
我目前正在尝试使用 Microsoft SEAL 库实现矩阵乘法方法。我创建了一个 vector<vector<double>>
作为输入矩阵并用 CKKSEncoder
对其进行编码。然而,编码器将整个向量打包成一个 Plaintext
,所以我只有一个 vector<Plaintext>
,这让我失去了 2D 结构(当然,加密后我会有一个 vector<Ciphertext>
) .拥有一维向量允许我完全访问行而不是列。
我设法在编码前转置了矩阵。这允许我按分量乘以第一个矩阵的行和第二个矩阵的列(转置形式的行),但我无法将结果向量的元素加在一起,因为它被打包到一个密文中。我只需要弄清楚如何使矢量点积在 SEAL 中工作以执行矩阵乘法。是我遗漏了什么还是我的方法有误?
向量的向量与数组的数组(二维,矩阵)不同。
虽然一维 vector<double>.data()
指向连续内存 space(例如,您可以对其执行 memcpy
),但每个 "subvectors" 分配自己的独立内存缓冲。因此 vector<vector<double>>.data()
没有意义,不能用作矩阵。
在 C++ 中,二维数组 array2D[W][H]
在内存中的存储方式与 array[W*H]
相同。因此,两者都可以由相同的例程处理(当它有意义时)。考虑以下示例:
void fill_array(double *array, size_t size, double value) {
for (size_t i = 0; i < size; ++i) {
array[i] = value;
}
}
int main(int argc, char *argv[])
{
constexpr size_t W = 10;
constexpr size_t H = 5;
double matrix[W][H];
// using 2D array as 1D to fill all elements with 5.
fill_array(&matrix[0][0], W * H, 5);
for (const auto &row: matrix) {
for (const auto v : row) {
cout << v << '\t';
}
cout << '\n';
}
return 0;
}
在上面的示例中,您可以将 double matrix[W][H];
替换为 vector<double> matrix(W * H);
,并将 matrix.data()
填入 fill_array()
。但是,您不能声明 vector(H) 的 vector(W)。
P.S。有很多数学向量和矩阵的 C++ 实现。如果你不想处理 C 风格的数组,你可以使用其中之一。
KyoohyungHan 在问题中提出:https://github.com/microsoft/SEAL/issues/138 可以通过旋转输出向量并反复求和来解决旋转问题。
例如:
// my_output_vector is the Ciphertext output
vector<Ciphertext> rotations_output(my_output_vector.size());
for(int steps = 0; steps < my_output_vector.size(); steps++)
{
evaluator.rotate_vector(my_output_vector, steps, galois_keys, rotations_output[steps]);
}
Ciphertext sum_output;
evaluator.add_many(rotations_output, sum_output);
我目前正在尝试使用 Microsoft SEAL 库实现矩阵乘法方法。我创建了一个 vector<vector<double>>
作为输入矩阵并用 CKKSEncoder
对其进行编码。然而,编码器将整个向量打包成一个 Plaintext
,所以我只有一个 vector<Plaintext>
,这让我失去了 2D 结构(当然,加密后我会有一个 vector<Ciphertext>
) .拥有一维向量允许我完全访问行而不是列。
我设法在编码前转置了矩阵。这允许我按分量乘以第一个矩阵的行和第二个矩阵的列(转置形式的行),但我无法将结果向量的元素加在一起,因为它被打包到一个密文中。我只需要弄清楚如何使矢量点积在 SEAL 中工作以执行矩阵乘法。是我遗漏了什么还是我的方法有误?
向量的向量与数组的数组(二维,矩阵)不同。
虽然一维 vector<double>.data()
指向连续内存 space(例如,您可以对其执行 memcpy
),但每个 "subvectors" 分配自己的独立内存缓冲。因此 vector<vector<double>>.data()
没有意义,不能用作矩阵。
在 C++ 中,二维数组 array2D[W][H]
在内存中的存储方式与 array[W*H]
相同。因此,两者都可以由相同的例程处理(当它有意义时)。考虑以下示例:
void fill_array(double *array, size_t size, double value) {
for (size_t i = 0; i < size; ++i) {
array[i] = value;
}
}
int main(int argc, char *argv[])
{
constexpr size_t W = 10;
constexpr size_t H = 5;
double matrix[W][H];
// using 2D array as 1D to fill all elements with 5.
fill_array(&matrix[0][0], W * H, 5);
for (const auto &row: matrix) {
for (const auto v : row) {
cout << v << '\t';
}
cout << '\n';
}
return 0;
}
在上面的示例中,您可以将 double matrix[W][H];
替换为 vector<double> matrix(W * H);
,并将 matrix.data()
填入 fill_array()
。但是,您不能声明 vector(H) 的 vector(W)。
P.S。有很多数学向量和矩阵的 C++ 实现。如果你不想处理 C 风格的数组,你可以使用其中之一。
KyoohyungHan 在问题中提出:https://github.com/microsoft/SEAL/issues/138 可以通过旋转输出向量并反复求和来解决旋转问题。
例如:
// my_output_vector is the Ciphertext output
vector<Ciphertext> rotations_output(my_output_vector.size());
for(int steps = 0; steps < my_output_vector.size(); steps++)
{
evaluator.rotate_vector(my_output_vector, steps, galois_keys, rotations_output[steps]);
}
Ciphertext sum_output;
evaluator.add_many(rotations_output, sum_output);