@2021SC@SDUSC 源码分析: core/lib/encoding
2021SC@SDUSC
看一看估计标准偏差过程是怎么样的
// Estimate standard deviation using the imaginary part of decoded vector z
// Compute m(X) - m(1/X) as a proxy for z - Conj(z) = 2*Im(z)
// vec is m(X) corresponding to z
// conjugate is m(1/X) corresponding to Conj(z)
首先可以关注一下这段注释
M(x) - M(1/x) as a Proxy..
using the imaginary part of decoded vector z
z - Conj(z) = 2*Im(z)
也就是说需要利用共轭的部分 其实这也就是共轭的定义式了
z - Conj(z) = 2*Im(z)
但是具体的含义不太清楚
可以看一下以下这段代码
不知道cck的编码方式是否要先虚数话然后再行具体的编码
#include "encoding/ckkspackedencoding.h"
#include "math/dftransfrm.h"
namespace lbcrypto {
std::vector<std::complex<double>> Conjugate(
const std::vector<std::complex<double>> &vec) {
uint32_t n = vec.size();
std::vector<std::complex<double>> result(n);
for (size_t i = 1; i < n; i++) {
result[i] = {-vec[n - i].imag(), -vec[n - i].real()};
}
result[0] = {vec[0].real(), -vec[0].imag()};
return result;
}
// Estimate standard deviation using the imaginary part of decoded vector z
// Compute m(X) - m(1/X) as a proxy for z - Conj(z) = 2*Im(z)
// vec is m(X) corresponding to z
// conjugate is m(1/X) corresponding to Conj(z)
double StdDev(const std::vector<std::complex<double>> &vec,
const std::vector<std::complex<double>> &conjugate) {
uint32_t Nh = vec.size();
// ring dimension
uint32_t n = Nh * 2;
// extract the complex part using identity z - Conj(z) == 2*Im(z)
// here we actually compute m(X) - m(1/X) corresponding to 2*Im(z).
// we only need first Nh/2 + 1 components of the imaginary part
// as the remaining Nh/2 - 1 components have a symmetry
// w.r.t. components from 1 to Nh/2 - 1
std::vector<std::complex<double>> complexValues(Nh / 2 + 1);
for (size_t i = 0; i < Nh / 2 + 1; ++i) {
complexValues[i] = vec[i] - conjugate[i];
}
// Calculate the mean
auto mean_func = [](double accumulator, const std::complex<double> &val) {
return accumulator + (val.real() + val.imag());
};
// use the symmetry condition
double mean =
2 * std::accumulate(complexValues.begin() + 1,
complexValues.begin() + Nh / 2, 0.0, mean_func);
// and then add values at indices 0 and Nh/2
mean += complexValues[0].imag();
mean += 2 * complexValues[Nh / 2].real();
// exclude the real part at index 0 as it is always 0
mean /= static_cast<double>(n) - 1.0;
// Now calculate the variance
auto variance_func = [&mean](double accumulator,
const std::complex<double> &val) {
return accumulator + (val.real() - mean) * (val.real() - mean) +
(val.imag() - mean) * (val.imag() - mean);
};
// use the symmetry condition
double variance =
2 * accumulate(complexValues.begin() + 1, complexValues.begin() + Nh / 2,
0.0, variance_func);
// and then add values at indices 0 and Nh/2
variance +=
(complexValues[0].imag() - mean) * (complexValues[0].imag() - mean);
variance += 2 * (complexValues[Nh / 2].real() - mean) *
(complexValues[Nh / 2].real() - mean);
// exclude the real part at index 0 as it is always 0
variance /= static_cast<double>(n) - 2.0;
// scale down by 2 as we have worked with 2*Im(z) up to this point
double stddev = 0.5 * std::sqrt(variance);
return stddev;
}
std::vector<DCRTPoly::Integer> CKKSPackedEncoding::CRTMult(
const std::vector<DCRTPoly::Integer> &a,
const std::vector<DCRTPoly::Integer> &b,
const std::vector<DCRTPoly::Integer> &mods) {
std::vector<DCRTPoly::Integer> result(mods.size());
for (usint i = 0; i < a.size(); i++) {
result[i] = a[i].ModMulFast(b[i], mods[i]);
}
return result;
}
但是由以上可见 这个实现过程并不容易 (不过这里有一个问题 那么是否只有cck才使用这样的编码方式呢 如果不是这样的话共轭计算可以作为core/lib/encoding下的一个公共的库函数的)
再说回这个具体的过程 最终的成果是一个实数 而输入则是一个向量
估计标准误差(Se)是说明实际值与其估计值之间相对偏离程度的指标,主要用来衡量 回归方程 的代表性。 估计标准误差的值越小,则 估计量 与其真实值的近似误差越小,但不能认为估计量与真实值之间的 绝对误差 就是估计标准误差。
这是一个统计学中的计算概念 而这里实现了它
再来看看接下来的部分
palisade作为一个跨平台的库 这里也进行了基于宏的机型适配
不过这两段方法之间会不会由相当可以提取重用逻辑的地方呢
还是由于本地Int长度的差别其中的优化和计算方式差别较大呢
#if NATIVEINT == 128
bool CKKSPackedEncoding::Encode() {
#else // NATIVEINT == 64
bool CKKSPackedEncoding::Encode()
那么ccks具体的编码方式是什么样的呢
首先先确定该条是否已经进行了编码
然后确认生一个多项式环
Nh已经出现了多次 但是目前尚未知道其具体含义
被加密的对象只能是DCRTPoly
一种特殊的多项式
这的概念有两篇很好的blog已经做了详尽的分析
(32条消息) 2021SC@SDUSC PALISADE开源库(二)CKKS讲解系列(一)普通编码和解码_小河豚oO的博客-CSDN博客
(32条消息) 2021SC@SDUSC PALISADE开源库(二)CKKS讲解系列(二)完整编码和解码_小河豚oO的博客-CSDN博客_palisade库
if (this->isEncoded) return true;
uint32_t ringDim = GetElementRingDimension();
uint32_t Nh = (ringDim >> 1);
std::vector<std::complex<double>> inverse = this->GetCKKSPackedValue();
// clears all imaginary values as CKKS for complex numbers
for (size_t i = 0; i < inverse.size(); i++) inverse[i].imag(0.0);
inverse.resize(Nh);
if (this->typeFlag == IsDCRTPoly) {
DiscreteFourierTransform::FFTSpecialInv(inverse);
uint64_t pBits = encodingParams->GetPlaintextModulus();
uint32_t precision = 52;
double powP = std::pow(2, precision);
int32_t pCurrent = pBits - precision;
// the idea is to break down real and imaginary parts
// expressed as input_mantissa * 2^input_exponent
// into (input_mantissa * 2^52) * 2^(p - 52 + input_exponent)
// to preserve 52-bit precision of doubles
// when converting to 128-bit numbers
std::vector<__int128> temp(2 * Nh);
for (size_t i = 0; i < Nh; ++i) {
// Check for possible overflow in llround function
int32_t n1 = 0;
// extract the mantissa of real part and multiply it by 2^52
double dre =
static_cast<double>(std::frexp(inverse[i].real(), &n1) * powP);
int32_t n2 = 0;
// extract the mantissa of imaginary part and multiply it by 2^52
double dim =
static_cast<double>(std::frexp(inverse[i].imag(), &n2) * powP);
if (is128BitOverflow(dre) || is128BitOverflow(dim)) {
PALISADE_THROW(math_error, "Overflow, try to decrease scaling factor");
}
int64_t re64 = std::llround(dre);
int32_t pRemaining = pCurrent + n1;
__int128 re = 0;
if (pRemaining < 0) {
re = re64 >> (-pRemaining);
} else {
__int128 pPowRemaining = ((__int128)1) << pRemaining;
re = pPowRemaining * re64;
}
int64_t im64 = std::llround(dim);
pRemaining = pCurrent + n2;
__int128 im = 0;
if (pRemaining < 0) {
im = im64 >> (-pRemaining);
} else {
__int128 pPowRemaining = ((int64_t)1) << pRemaining;
im = pPowRemaining * im64;
}
temp[i] = (re < 0) ? Max128BitValue() + re : re;
temp[i + Nh] = (im < 0) ? Max128BitValue() + im : im;
if (is128BitOverflow(temp[i]) || is128BitOverflow(temp[i + Nh])) {
PALISADE_THROW(math_error, "Overflow, try to decrease scaling factor");
}
}
const shared_ptr<ILDCRTParams<BigInteger>> params =
this->encodedVectorDCRT.GetParams();
const std::vector<std::shared_ptr<ILNativeParams>> &nativeParams =
params->GetParams();
for (size_t i = 0; i < nativeParams.size(); i++) {
NativeVector nativeVec(ringDim, nativeParams[i]->GetModulus());
FitToNativeVector(temp, Max128BitValue(), &nativeVec);
NativePoly element = this->GetElement<DCRTPoly>().GetElementAtIndex(i);
element.SetValues(
nativeVec, Format::COEFFICIENT); // output was in coefficient format
this->encodedVectorDCRT.SetElementAtIndex(i, element);
}
usint numTowers = nativeParams.size();
std::vector<DCRTPoly::Integer> moduli(numTowers);
for (usint i = 0; i < numTowers; i++) {
moduli[i] = nativeParams[i]->GetModulus();
}
DCRTPoly::Integer intPowP = NativeInteger(1) << pBits;
std::vector<DCRTPoly::Integer> crtPowP(numTowers, intPowP);
auto currPowP = crtPowP;
// We want to scale temp by 2^(pd), and the loop starts from j=2
// because temp is already scaled by 2^p in the re/im loop above,
// and currPowP already is 2^p.
for (size_t i = 2; i < depth; i++) {
currPowP = CKKSPackedEncoding::CRTMult(currPowP, crtPowP, moduli);
}
if (depth > 1) {
this->encodedVectorDCRT = this->encodedVectorDCRT.Times(currPowP);
}
this->GetElement<DCRTPoly>().SetFormat(Format::EVALUATION);
scalingFactor = pow(scalingFactor, depth);
} else {
PALISADE_THROW(config_error, "Only DCRTPoly is supported for CKKS.");
}
this->isEncoded = true;
return true;
那我们具体再来看看这64位的和128位的差别在于哪里
if (is64BitOverflow(dre) || is64BitOverflow(dim)) {
// IFFT formula:
// x[n] = (1/N) * \Sum^(N-1)_(k=0) X[k] * exp( j*2*pi*n*k/N )
// n is i
// k is idx below
// N is inverse.size()
//
// In the following, we switch to original data domain,
// and we identify the component that has the maximum
// contribution to the values in the iFFT domain. We do
// this to report it to the user, so they can identify
// large inputs.
由此可以看到 大概的差别是在计算方式上 也就是说 对于大整数的计算上和精度较高的计算上
需要进行一个映射以适应精度要求
@2021SC@SDUSC 源码分析: core/lib/encoding相关推荐
- @2021SC@SDUSC 源码分析: 格加密模块的初窥
2021SC@SDUSC 这次对格密码层进行一个分析 首先可以看到格密码层也是分了相当多的文件 从名字上直观认识,大多都是数学后端上功能以及一些辅助的运算模块 先来看看lattice中的poly模块 ...
- jQuery 2.0.3 源码分析core - 整体架构
拜读一个开源框架,最想学到的就是设计的思想和实现的技巧. 废话不多说,jquery这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery ...
- spring源码分析-core.io包里面的类
前些日子看<深入理解javaweb开发>时,看到第一章java的io流,发觉自己对io流真的不是很熟悉.然后看了下JDK1.7中io包的一点点代码,又看了org.springframewo ...
- 云客Drupal源码分析之数据库Schema及创建数据表
本主题是<云客Drupal源码分析之数据库系统及其使用>的补充,便于查询,所以独立成一个主题 讲解数据库系统如何操作Schema(创建修改数据库.数据表.字段:判断它们的存在性等等),以及 ...
- go-ethereum-code-analysis 以太坊源码分析
分析go-ethereum的过程,我希望从依赖比较少的底层技术组件开始,慢慢深入到核心逻辑. 目录 go-ethereum代码阅读环境搭建 以太坊黄皮书 符号索引 rlp源码解析 trie源码分析 e ...
- ZBar源码分析——多线程部分代码分析 | 2021SC@SDUSC
2021SC@SDUSC 目录 一.ZBar中的多线程 线程:cpu调度的最小单位 何为线程安全? 锁机制 二.ZBar中使用多线程的代码示例 Window线程的上锁与解锁 Vedio视频流的上锁与解 ...
- 深入理解Spark 2.1 Core (十二):TimSort 的原理与源码分析
在博文<深入理解Spark 2.1 Core (十):Shuffle Map 端的原理与源码分析 >中我们提到了: 使用Sort等对数据进行排序,其中用到了TimSort 这篇博文我们就来 ...
- 深入理解Spark 2.1 Core (十一):Shuffle Reduce 端的原理与源码分析
我们曾经在<深入理解Spark 2.1 Core (一):RDD的原理与源码分析 >讲解过: 为了有效地实现容错,RDD提供了一种高度受限的共享内存,即RDD是只读的,并且只能通过其他RD ...
- 深入理解Spark 2.1 Core (十):Shuffle Map 端的原理与源码分析
在上一篇<深入理解Spark 2.1 Core (九):迭代计算和Shuffle的原理与源码分析>提到经过迭代计算后, SortShuffleWriter.write中: // 根据排序方 ...
最新文章
- 2014目标!!!!
- 高精度加法(非负)和大数阶乘及和汽水问题
- mysql表的视图怎么建立_MySQL如何创建视图
- PE文件感染和内存驻留
- pdf从结构新建书签_强力推荐一款PDF神器
- 第34课 生命周期与素数 《小学生C++趣味编程》
- C++的继承知识点重温
- CUDA——Ubuntu系统上CUDA和cuDNN的安装教程
- 方舟编译器开源技术沙龙北京站首秀:让开源激活软件开发的潜力
- php-5.6.31安装视频教程_php安装图解教程
- STM32F103mini教程学习总结与心得(五)---->通用定时器
- 使用Maven导入MySQL驱动包遇到的问题
- 目标检测(Object Detection)—— M2Det
- PCA人脸识别详解——初学者必看
- matlab美国标准大气,国际标准大气(ISA)
- 测试用例---场景法和错误推测法
- Xmind怎么打开?在线转换成PNG,JPG图片格式,无需安装其他软件
- vue自定义插件 封装一个类似 element 中 message 消息提示框的插件
- CSAPP学习笔记 day1
- 【专题】“莓日一介”之(BlackBerry 7100t)