引用的头文件
#include "seal/util/common.h"
#include "seal/util/defines.h"
#include "seal/util/pointer.h"
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <limits>
#include <stdexcept>
所有函数位于namespace util中
unsigned int 转换为 十六进制字符串或者十进制字符串
除这两个函数之外,剩下的都是inline函数
SEAL_NODISCARD std::string uint_to_hex_string(const std::uint64_t *value, std::size_t uint64_count);
SEAL_NODISCARD std::string uint_to_dec_string(
const std::uint64_t *value, std::size_t uint64_count, MemoryPool &pool);
第一个参数为需要转换的字符串,第二个为字符串数组中字符的个数,第三个参数为64位int的个数,结果保存在第四个参数中,为一个数组,低索引保存低位,高索引保存高位
inline void hex_string_to_uint(
const char *hex_string, int char_count, std::size_t uint64_count, std::uint64_t *result)
{
#ifdef SEAL_DEBUG
if (!hex_string && char_count > 0)
{
throw std::invalid_argument("hex_string");
}
if (uint64_count && !result)
{
throw std::invalid_argument("result");
}
if (unsigned_gt(
get_hex_string_bit_count(hex_string, char_count),
mul_safe(uint64_count, static_cast<size_t>(bits_per_uint64))))
{
throw std::invalid_argument("hex_string");
}
#endif
const char *hex_string_ptr = hex_string + char_count;
for (std::size_t uint64_index = 0; uint64_index < uint64_count; uint64_index++)
{
std::uint64_t value = 0;
for (int bit_index = 0; bit_index < bits_per_uint64; bit_index += bits_per_nibble)
{
if (hex_string_ptr == hex_string)
{
break;
}
char hex = *--hex_string_ptr;
int nibble = hex_to_nibble(hex);
if (nibble == -1)
{
throw std::invalid_argument("hex_value");
}
value |= static_cast<std::uint64_t>(nibble) << bit_index;
}
result[uint64_index] = value;
}
}
为数组分配内存
SEAL_NODISCARD inline auto allocate_uint(std::size_t uint64_count, MemoryPool &pool)
{
return allocate<std::uint64_t>(uint64_count, pool);
}
将 uint64_count 个数都赋予值 0
inline void set_zero_uint(std::size_t uint64_count, std::uint64_t *result)
{
#ifdef SEAL_DEBUG
if (!result && uint64_count)
{
throw std::invalid_argument("result");
}
#endif
std::fill_n(result, uint64_count, std::uint64_t(0));
}
先分配内存,再赋予 0
SEAL_NODISCARD inline auto allocate_zero_uint(std::size_t uint64_count, MemoryPool &pool)
{
auto result(allocate_uint(uint64_count, pool));
set_zero_uint(uint64_count, result.get());
return result;
// The following looks better but seems to yield worse results.
// return allocate<std::uint64_t>(uint64_count, pool, std::uint64_t(0));
}
value为 64位数,要总共赋值 uint64_count 个 64 位数,最低位赋予 value,剩余高位赋予 0
inline void set_uint(std::uint64_t value, std::size_t uint64_count, std::uint64_t *result)
{
#ifdef SEAL_DEBUG
if (!uint64_count)
{
throw std::invalid_argument("uint64_count");
}
if (!result)
{
throw std::invalid_argument("result");
}
#endif
*result++ = value;
for (; --uint64_count; result++)
{
*result = 0;
}
}
现在 value 为一个数组,依旧剩余高位赋予 0
inline void set_uint(const std::uint64_t *value, std::size_t uint64_count, std::uint64_t *result)
{
#ifdef SEAL_DEBUG
if (!value && uint64_count)
{
throw std::invalid_argument("value");
}
if (!result && uint64_count)
{
throw std::invalid_argument("result");
}
#endif
if ((value == result) || !uint64_count)
{
return;
}
std::copy_n(value, uint64_count, result);
}
判断整个数是否为0
SEAL_NODISCARD inline bool is_zero_uint(const std::uint64_t *value, std::size_t uint64_count)
{
#ifdef SEAL_DEBUG
if (!value && uint64_count)
{
throw std::invalid_argument("value");
}
#endif
return std::all_of(value, value + uint64_count, [](auto coeff) -> bool { return !coeff; });
}
判断整个数是否等于 scalar
SEAL_NODISCARD inline bool is_equal_uint(
const std::uint64_t *value, std::size_t uint64_count, std::uint64_t scalar)
{
#ifdef SEAL_DEBUG
if (!value)
{
throw std::invalid_argument("value");
}
if (!uint64_count)
{
throw std::invalid_argument("uint64_count");
}
#endif
if (*value++ != scalar)
{
return false;
}
return std::all_of(value, value + uint64_count - 1, [](auto coeff) -> bool { return !coeff; });
}
判断value整个数最高位的64位数的最高位是否为1,为1则返回true
SEAL_NODISCARD inline bool is_high_bit_set_uint(const std::uint64_t *value, std::size_t uint64_count)
{
#ifdef SEAL_DEBUG
if (!value)
{
throw std::invalid_argument("value");
}
if (!uint64_count)
{
throw std::invalid_argument("uint64_count");
}
#endif
return (value[uint64_count - 1] >> (bits_per_uint64 - 1)) != 0;
}
判断 bit_index 位置的比特是否为1,为1则返回true
SEAL_NODISCARD inline bool is_bit_set_uint(
const std::uint64_t *value, std::size_t uint64_count SEAL_MAYBE_UNUSED, int bit_index)
{
#ifdef SEAL_DEBUG
if (!value)
{
throw std::invalid_argument("value");
}
if (!uint64_count)
{
throw std::invalid_argument("uint64_count");
}
if (bit_index < 0 ||
static_cast<std::int64_t>(bit_index) >= static_cast<std::int64_t>(uint64_count) * bits_per_uint64)
{
throw std::invalid_argument("bit_index");
}
#endif
int uint64_index = bit_index / bits_per_uint64;
int sub_bit_index = bit_index - uint64_index * bits_per_uint64;
return ((value[static_cast<std::size_t>(uint64_index)] >> sub_bit_index) & 1) != 0;
}
将 bit_index 位置的比特置为1
inline void set_bit_uint(std::uint64_t *value, std::size_t uint64_count SEAL_MAYBE_UNUSED, int bit_index)
{
#ifdef SEAL_DEBUG
if (!value)
{
throw std::invalid_argument("value");
}
if (!uint64_count)
{
throw std::invalid_argument("uint64_count");
}
if (bit_index < 0 ||
static_cast<std::int64_t>(bit_index) >= static_cast<std::int64_t>(uint64_count) * bits_per_uint64)
{
throw std::invalid_argument("bit_index");
}
#endif
int uint64_index = bit_index / bits_per_uint64;
int sub_bit_index = bit_index % bits_per_uint64;
value[static_cast<std::size_t>(uint64_index)] |= std::uint64_t(1) << sub_bit_index;
}
获取有效位数,从这个函数的实现可以推断value数组保存的整个数低索引保存低位,高索引保存高位
SEAL_NODISCARD inline int get_significant_bit_count_uint(const std::uint64_t *value, std::size_t uint64_count)
{
#ifdef SEAL_DEBUG
if (!value && uint64_count)
{
throw std::invalid_argument("value");
}
if (!uint64_count)
{
throw std::invalid_argument("uint64_count");
}
#endif
value += uint64_count - 1;
for (; *value == 0 && uint64_count > 1; uint64_count--)
{
value--;
}
return static_cast<int>(uint64_count - 1) * bits_per_uint64 + get_significant_bit_count(*value);
}
获取整个数中 uint64 的个数
SEAL_NODISCARD inline std::size_t get_significant_uint64_count_uint(
const std::uint64_t *value, std::size_t uint64_count)
{
#ifdef SEAL_DEBUG
if (!value && uint64_count)
{
throw std::invalid_argument("value");
}
if (!uint64_count)
{
throw std::invalid_argument("uint64_count");
}
#endif
value += uint64_count - 1;
for (; uint64_count && !*value; uint64_count--)
{
value--;
}
return uint64_count;
}
获取整个数中非零的 uint64 的个数
SEAL_NODISCARD inline std::size_t get_nonzero_uint64_count_uint(
const std::uint64_t *value, std::size_t uint64_count)
{
#ifdef SEAL_DEBUG
if (!value && uint64_count)
{
throw std::invalid_argument("value");
}
if (!uint64_count)
{
throw std::invalid_argument("uint64_count");
}
#endif
std::size_t nonzero_count = uint64_count;
value += uint64_count - 1;
for (; uint64_count; uint64_count--)
{
if (*value-- == 0)
{
nonzero_count--;
}
}
return nonzero_count;
}
将 value 赋给 result,截断高位
inline void set_uint(
const std::uint64_t *value, std::size_t value_uint64_count, std::size_t result_uint64_count,
std::uint64_t *result)
{
#ifdef SEAL_DEBUG
if (!value && value_uint64_count)
{
throw std::invalid_argument("value");
}
if (!result && result_uint64_count)
{
throw std::invalid_argument("result");
}
#endif
if (value == result || !value_uint64_count)
{
// Fast path to handle self assignment.
std::fill(result + value_uint64_count, result + result_uint64_count, std::uint64_t(0));
}
else
{
std::size_t min_uint64_count = std::min<>(value_uint64_count, result_uint64_count);
std::copy_n(value, min_uint64_count, result);
std::fill(result + min_uint64_count, result + result_uint64_count, std::uint64_t(0));
}
}
If the value is a power of two, return the power; otherwise, return -1.
/**
If the value is a power of two, return the power; otherwise, return -1.
*/
SEAL_NODISCARD inline int get_power_of_two(std::uint64_t value)
{
if (value == 0 || (value & (value - 1)) != 0)
{
return -1;
}
unsigned long result = 0;
SEAL_MSB_INDEX_UINT64(&result, value);
return static_cast<int>(result);
}
截断从 bit_count 往后的所有高位,都被置为0
inline void filter_highbits_uint(std::uint64_t *operand, std::size_t uint64_count, int bit_count)
{
std::size_t bits_per_uint64_sz = static_cast<std::size_t>(bits_per_uint64);
#ifdef SEAL_DEBUG
if (!operand && uint64_count)
{
throw std::invalid_argument("operand");
}
if (bit_count < 0 || unsigned_gt(bit_count, mul_safe(uint64_count, bits_per_uint64_sz)))
{
throw std::invalid_argument("bit_count");
}
#endif
if (unsigned_eq(bit_count, mul_safe(uint64_count, bits_per_uint64_sz)))
{
return;
}
int uint64_index = bit_count / bits_per_uint64;
int subbit_index = bit_count - uint64_index * bits_per_uint64;
operand += uint64_index;
*operand++ &= (std::uint64_t(1) << subbit_index) - 1;
for (int long_index = uint64_index + 1; unsigned_lt(long_index, uint64_count); long_index++)
{
*operand++ = 0;
}
}
复制一个数,需要分配内存
SEAL_NODISCARD inline auto duplicate_uint_if_needed(
const std::uint64_t *input, std::size_t uint64_count, std::size_t new_uint64_count, bool force,
MemoryPool &pool)
{
#ifdef SEAL_DEBUG
if (!input && uint64_count)
{
throw std::invalid_argument("uint");
}
#endif
if (!force && uint64_count >= new_uint64_count)
{
return ConstPointer<std::uint64_t>::Aliasing(input);
}
auto allocation(allocate_uint(new_uint64_count, pool));
set_uint(input, uint64_count, new_uint64_count, allocation.get());
return ConstPointer<std::uint64_t>(std::move(allocation));
}
比较operand1 和 operand2大小,operand1大于operand2返回1,operand1小于operand2返回-1,相等返回0,两个数长度相同
SEAL_NODISCARD inline int compare_uint(
const std::uint64_t *operand1, const std::uint64_t *operand2, std::size_t uint64_count)
{
#ifdef SEAL_DEBUG
if (!operand1 && uint64_count)
{
throw std::invalid_argument("operand1");
}
if (!operand2 && uint64_count)
{
throw std::invalid_argument("operand2");
}
#endif
int result = 0;
operand1 += uint64_count - 1;
operand2 += uint64_count - 1;
for (; (result == 0) && uint64_count--; operand1--, operand2--)
{
result = (*operand1 > *operand2) - (*operand1 < *operand2);
}
return result;
}
SEAL_NODISCARD inline int compare_uint(
const std::uint64_t *operand1, std::size_t operand1_uint64_count, const std::uint64_t *operand2,
std::size_t operand2_uint64_count)
{
#ifdef SEAL_DEBUG
if (!operand1 && operand1_uint64_count)
{
throw std::invalid_argument("operand1");
}
if (!operand2 && operand2_uint64_count)
{
throw std::invalid_argument("operand2");
}
#endif
int result = 0;
operand1 += operand1_uint64_count - 1;
operand2 += operand2_uint64_count - 1;
std::size_t min_uint64_count = std::min<>(operand1_uint64_count, operand2_uint64_count);
operand1_uint64_count -= min_uint64_count;
for (; (result == 0) && operand1_uint64_count--; operand1--)
{
result = (*operand1 > 0);
}
operand2_uint64_count -= min_uint64_count;
for (; (result == 0) && operand2_uint64_count--; operand2--)
{
result = -(*operand2 > 0);
}
for (; (result == 0) && min_uint64_count--; operand1--, operand2--)
{
result = (*operand1 > *operand2) - (*operand1 < *operand2);
}
return result;
}
都是利用 compare_uint 函数
SEAL_NODISCARD inline bool is_greater_than_uint(
const std::uint64_t *operand1, const std::uint64_t *operand2, std::size_t uint64_count)
{
return compare_uint(operand1, operand2, uint64_count) > 0;
}
SEAL_NODISCARD inline bool is_greater_than_or_equal_uint(
const std::uint64_t *operand1, const std::uint64_t *operand2, std::size_t uint64_count)
{
return compare_uint(operand1, operand2, uint64_count) >= 0;
}
SEAL_NODISCARD inline bool is_less_than_uint(
const std::uint64_t *operand1, const std::uint64_t *operand2, std::size_t uint64_count)
{
return compare_uint(operand1, operand2, uint64_count) < 0;
}
SEAL_NODISCARD inline bool is_less_than_or_equal_uint(
const std::uint64_t *operand1, const std::uint64_t *operand2, std::size_t uint64_count)
{
return compare_uint(operand1, operand2, uint64_count) <= 0;
}
SEAL_NODISCARD inline bool is_equal_uint(
const std::uint64_t *operand1, const std::uint64_t *operand2, std::size_t uint64_count)
{
return compare_uint(operand1, operand2, uint64_count) == 0;
}
SEAL_NODISCARD inline bool is_greater_than_uint(
const std::uint64_t *operand1, std::size_t operand1_uint64_count, const std::uint64_t *operand2,
std::size_t operand2_uint64_count)
{
return compare_uint(operand1, operand1_uint64_count, operand2, operand2_uint64_count) > 0;
}
SEAL_NODISCARD inline bool is_greater_than_or_equal_uint(
const std::uint64_t *operand1, std::size_t operand1_uint64_count, const std::uint64_t *operand2,
std::size_t operand2_uint64_count)
{
return compare_uint(operand1, operand1_uint64_count, operand2, operand2_uint64_count) >= 0;
}
SEAL_NODISCARD inline bool is_less_than_uint(
const std::uint64_t *operand1, std::size_t operand1_uint64_count, const std::uint64_t *operand2,
std::size_t operand2_uint64_count)
{
return compare_uint(operand1, operand1_uint64_count, operand2, operand2_uint64_count) < 0;
}
SEAL_NODISCARD inline bool is_less_than_or_equal_uint(
const std::uint64_t *operand1, std::size_t operand1_uint64_count, const std::uint64_t *operand2,
std::size_t operand2_uint64_count)
{
return compare_uint(operand1, operand1_uint64_count, operand2, operand2_uint64_count) <= 0;
}
SEAL_NODISCARD inline bool is_equal_uint(
const std::uint64_t *operand1, std::size_t operand1_uint64_count, const std::uint64_t *operand2,
std::size_t operand2_uint64_count)
{
return compare_uint(operand1, operand1_uint64_count, operand2, operand2_uint64_count) == 0;
}
引用的头文件
#include "seal/serialization.h"
#include "seal/version.h"
#include "seal/util/defines.h"
#include "seal/util/hestdparms.h"
#include "seal/util/uintcore.h"
#include "seal/util/ztools.h"
#include <array>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <vector>
serialization.h 是进行序列化的类
表示最多61位的整数模量。Modulus类的实例表示最多61位的非负整数模量。其中加密参数plain_modulus和coeff_modulus中的质数都用Modulus的实例表示。这个类的目的是执行和存储Barrett缩减所需的预计算。
位于 namespace seal中
namespace seal
{
/**
Represent an integer modulus of up to 61 bits. An instance of the Modulus
class represents a non-negative integer modulus up to 61 bits. In particular,
the encryption parameter plain_modulus, and the primes in coeff_modulus, are
represented by instances of Modulus. The purpose of this class is to
perform and store the pre-computation required by Barrett reduction.
@par Thread Safety
In general, reading from Modulus is thread-safe as long as no other thread
is concurrently mutating it.
@see EncryptionParameters for a description of the encryption parameters.
*/
class Modulus
注意注释,注释写得很明白
set_value 为私有成员函数
/**
Creates a Modulus instance. The value of the Modulus is set to
the given value, or to zero by default.
@param[in] value The integer modulus
@throws std::invalid_argument if value is 1 or more than 61 bits
*/
Modulus(std::uint64_t value = 0)
{
set_value(value);
}
/**
Creates a new Modulus by copying a given one.
@param[in] copy The Modulus to copy from
*/
Modulus(const Modulus ©) = default;
/**
Creates a new Modulus by copying a given one.
@param[in] source The Modulus to move from
*/
Modulus(Modulus &&source) = default;
/**
Copies a given Modulus to the current one.
@param[in] assign The Modulus to copy from
*/
Modulus &operator=(const Modulus &assign) = default;
/**
Moves a given Modulus to the current one.
@param[in] assign The Modulus to move from
*/
Modulus &operator=(Modulus &&assign) = default;
/**
Sets the value of the Modulus.
@param[in] value The new integer modulus
@throws std::invalid_argument if value is 1 or more than 61 bits
*/
inline Modulus &operator=(std::uint64_t value)
{
set_value(value);
return *this;
}
/**
Returns the significant bit count of the value of the current Modulus.
*/
SEAL_NODISCARD inline int bit_count() const noexcept
{
return bit_count_;
}
/**
Returns the size (in 64-bit words) of the value of the current Modulus.
*/
SEAL_NODISCARD inline std::size_t uint64_count() const noexcept
{
return uint64_count_;
}
/**
Returns a const pointer to the value of the current Modulus.
*/
SEAL_NODISCARD inline const uint64_t *data() const noexcept
{
return &value_;
}
/**
Returns the value of the current Modulus.
*/
SEAL_NODISCARD inline std::uint64_t value() const noexcept
{
return value_;
}
/**
Returns the Barrett ratio computed for the value of the current Modulus.
The first two components of the Barrett ratio are the floor of 2^128/value,
and the third component is the remainder.
*/
SEAL_NODISCARD inline auto &const_ratio() const noexcept
{
return const_ratio_;
}
/**
Returns whether the value of the current Modulus is zero.
*/
SEAL_NODISCARD inline bool is_zero() const noexcept
{
return value_ == 0;
}
/**
Returns whether the value of the current Modulus is a prime number.
*/
SEAL_NODISCARD inline bool is_prime() const noexcept
{
return is_prime_;
}
/**
Compares two Modulus instances.
@param[in] compare The Modulus to compare against
*/
SEAL_NODISCARD inline bool operator==(const Modulus &compare) const noexcept
{
return value_ == compare.value_;
}
/**
Compares a Modulus value to an unsigned integer.
@param[in] compare The unsigned integer to compare against
*/
SEAL_NODISCARD inline bool operator==(std::uint64_t compare) const noexcept
{
return value_ == compare;
}
/**
Compares two Modulus instances.
@param[in] compare The Modulus to compare against
*/
SEAL_NODISCARD inline bool operator!=(const Modulus &compare) const noexcept
{
return !operator==(compare);
}
/**
Compares a Modulus value to an unsigned integer.
@param[in] compare The unsigned integer to compare against
*/
SEAL_NODISCARD inline bool operator!=(std::uint64_t compare) const noexcept
{
return !operator==(compare);
}
/**
Compares two Modulus instances.
@param[in] compare The Modulus to compare against
*/
SEAL_NODISCARD inline bool operator<(const Modulus &compare) const noexcept
{
return value_ < compare.value_;
}
/**
Compares a Modulus value to an unsigned integer.
@param[in] compare The unsigned integer to compare against
*/
SEAL_NODISCARD inline bool operator<(std::uint64_t compare) const noexcept
{
return value_ < compare;
}
/**
Compares two Modulus instances.
@param[in] compare The Modulus to compare against
*/
SEAL_NODISCARD inline bool operator<=(const Modulus &compare) const noexcept
{
return value_ <= compare.value_;
}
/**
Compares a Modulus value to an unsigned integer.
@param[in] compare The unsigned integer to compare against
*/
SEAL_NODISCARD inline bool operator<=(std::uint64_t compare) const noexcept
{
return value_ <= compare;
}
/**
Compares two Modulus instances.
@param[in] compare The Modulus to compare against
*/
SEAL_NODISCARD inline bool operator>(const Modulus &compare) const noexcept
{
return value_ > compare.value_;
}
/**
Compares a Modulus value to an unsigned integer.
@param[in] compare The unsigned integer to compare against
*/
SEAL_NODISCARD inline bool operator>(std::uint64_t compare) const noexcept
{
return value_ > compare;
}
/**
Compares two Modulus instances.
@param[in] compare The Modulus to compare against
*/
SEAL_NODISCARD inline bool operator>=(const Modulus &compare) const noexcept
{
return value_ >= compare.value_;
}
/**
Compares a Modulus value to an unsigned integer.
@param[in] compare The unsigned integer to compare against
*/
SEAL_NODISCARD inline bool operator>=(std::uint64_t compare) const noexcept
{
return value_ >= compare;
}
/**
Returns an upper bound on the size of the Modulus, as if it was
written to an output stream.
@param[in] compr_mode The compression mode
@throws std::invalid_argument if the compression mode is not supported
@throws std::logic_error if the size does not fit in the return type
*/
SEAL_NODISCARD inline std::streamoff save_size(
compr_mode_type compr_mode = Serialization::compr_mode_default) const
{
std::size_t members_size = Serialization::ComprSizeEstimate(util::add_safe(sizeof(value_)), compr_mode);
return util::safe_cast<std::streamoff>(util::add_safe(sizeof(Serialization::SEALHeader), members_size));
}
/**
Saves the Modulus to an output stream. The output is in binary format
and not human-readable. The output stream must have the "binary" flag set.
@param[out] stream The stream to save the Modulus to
@param[in] compr_mode The desired compression mode
@throws std::invalid_argument if the compression mode is not supported
@throws std::logic_error if the data to be saved is invalid, or if
compression failed
@throws std::runtime_error if I/O operations failed
*/
inline std::streamoff save(
std::ostream &stream, compr_mode_type compr_mode = Serialization::compr_mode_default) const
{
using namespace std::placeholders;
return Serialization::Save(
std::bind(&Modulus::save_members, this, _1), save_size(compr_mode_type::none), stream, compr_mode,
false);
}
/**
Loads a Modulus from an input stream overwriting the current Modulus.
@param[in] stream The stream to load the Modulus from
@throws std::logic_error if the data cannot be loaded by this version of
Microsoft SEAL, if the loaded data is invalid, or if decompression failed
@throws std::runtime_error if I/O operations failed
*/
inline std::streamoff load(std::istream &stream)
{
using namespace std::placeholders;
return Serialization::Load(std::bind(&Modulus::load_members, this, _1, _2), stream, false);
}
/**
Saves the Modulus to a given memory location. The output is in binary
format and not human-readable.
@param[out] out The memory location to write the Modulus to
@param[in] size The number of bytes available in the given memory location
@param[in] compr_mode The desired compression mode
@throws std::invalid_argument if out is null or if size is too small to
contain a SEALHeader, or if the compression mode is not supported
@throws std::logic_error if the data to be saved is invalid, or if
compression failed
@throws std::runtime_error if I/O operations failed
*/
inline std::streamoff save(
seal_byte *out, std::size_t size, compr_mode_type compr_mode = Serialization::compr_mode_default) const
{
using namespace std::placeholders;
return Serialization::Save(
std::bind(&Modulus::save_members, this, _1), save_size(compr_mode_type::none), out, size, compr_mode,
false);
}
/**
Loads a Modulus from a given memory location overwriting the current
Modulus.
@param[in] in The memory location to load the Modulus from
@param[in] size The number of bytes available in the given memory location
@throws std::invalid_argument if in is null or if size is too small to
contain a SEALHeader
@throws std::logic_error if the data cannot be loaded by this version of
Microsoft SEAL, if the loaded data is invalid, or if decompression failed
@throws std::runtime_error if I/O operations failed
*/
inline std::streamoff load(const seal_byte *in, std::size_t size)
{
using namespace std::placeholders;
return Serialization::Load(std::bind(&Modulus::load_members, this, _1, _2), in, size, false);
}
/**
Reduces a given unsigned integer modulo this modulus.
@param[in] value The unsigned integer to reduce
@throws std::logic_error if the Modulus is zero
*/
SEAL_NODISCARD std::uint64_t reduce(std::uint64_t value) const;
private:
void set_value(std::uint64_t value);
void save_members(std::ostream &stream) const;
void load_members(std::istream &stream, SEALVersion version);
std::uint64_t value_ = 0;
std::array<std::uint64_t, 3> const_ratio_{ { 0, 0, 0 } };
std::size_t uint64_count_ = 0;
int bit_count_ = 0;
bool is_prime_ = false;
void Modulus::set_value(uint64_t value)
{
if (value == 0)
{
// Zero settings
bit_count_ = 0;
uint64_count_ = 1;
value_ = 0;
const_ratio_ = { { 0, 0, 0 } };
is_prime_ = false;
}
else if ((value >> SEAL_MOD_BIT_COUNT_MAX != 0) || (value == 1))
{
throw invalid_argument("value can be at most 61-bit and cannot be 1");
}
else
{
// All normal, compute const_ratio and set everything
value_ = value;
bit_count_ = get_significant_bit_count(value_);
// Compute Barrett ratios for 64-bit words (barrett_reduce_128)
uint64_t numerator[3]{ 0, 0, 1 };
uint64_t quotient[3]{ 0, 0, 0 };
// Use a special method to avoid using memory pool
divide_uint192_inplace(numerator, value_, quotient);
const_ratio_[0] = quotient[0];
const_ratio_[1] = quotient[1];
// We store also the remainder
const_ratio_[2] = numerator[0];
uint64_count_ = 1;
// Set the primality flag
is_prime_ = util::is_prime(*this);
}
}
uint64_t Modulus::reduce(uint64_t value) const
{
if (value_ == 0)
{
throw logic_error("cannot reduce modulo a zero modulus");
}
return barrett_reduce_64(value, *this);
}
表示根据HomomorphicEncryption.org安全标准的标准安全级别。值sec_level_type::none表示不应该施加标准安全级别。sec_level_type::tc128值提供了非常高的安全级别,并且是Microsoft SEAL在构造SEALContext对象时强制执行的默认安全级别。普通用户不应该在任何地方显式地指定安全级别。
/**
Represents a standard security level according to the HomomorphicEncryption.org
security standard. The value sec_level_type::none signals that no standard
security level should be imposed. The value sec_level_type::tc128 provides
a very high level of security and is the default security level enforced by
Microsoft SEAL when constructing a SEALContext object. Normal users should not
have to specify the security level explicitly anywhere.
*/
enum class sec_level_type : int
{
/**
No security level specified.
*/
none = 0,
/**
128-bit security level according to HomomorphicEncryption.org standard.
*/
tc128 = 128,
/**
192-bit security level according to HomomorphicEncryption.org standard.
*/
tc192 = 192,
/**
256-bit security level according to HomomorphicEncryption.org standard.
*/
tc256 = 256
};
该类包含用于轻松创建系数模数的静态方法。注意,虽然这些函数接受一个sec_level_type参数,但如果输出与加密参数(poly_modulus_degree的值不匹配)一起使用,那么所有的安全保证都将丢失。
默认值sec_level_type::tc128提供了非常高的安全级别,并且是Microsoft SEAL在构造SEALContext对象时强制执行的默认安全级别。普通用户不应该在任何地方显式地指定安全级别。
CoeffModulus() = delete;
根据HomomorphicEncryption.org安全标准,返回系数模数的最大位长,即系数模数中质数乘积的位长,在使用给定的poly_modulus_degree时保证给定的安全级别。
/**
Returns the largest bit-length of the coefficient modulus, i.e., bit-length
of the product of the primes in the coefficient modulus, that guarantees
a given security level when using a given poly_modulus_degree, according
to the HomomorphicEncryption.org security standard.
@param[in] poly_modulus_degree The value of the poly_modulus_degree
encryption parameter
@param[in] sec_level The desired standard security level
*/
SEAL_NODISCARD static constexpr int MaxBitCount(
std::size_t poly_modulus_degree, sec_level_type sec_level = sec_level_type::tc128) noexcept
{
switch (sec_level)
{
case sec_level_type::tc128:
return util::seal_he_std_parms_128_tc(poly_modulus_degree);
case sec_level_type::tc192:
return util::seal_he_std_parms_192_tc(poly_modulus_degree);
case sec_level_type::tc256:
return util::seal_he_std_parms_256_tc(poly_modulus_degree);
case sec_level_type::none:
return (std::numeric_limits<int>::max)();
default:
return 0;
}
}
Returns a default coefficient modulus for the BFV scheme that guarantees
a given security level when using a given poly_modulus_degree, according
to the HomomorphicEncryption.org security standard. Note that all security
guarantees are lost if the output is used with encryption parameters with
a mismatching value for the poly_modulus_degree.
/**
Returns a default coefficient modulus for the BFV scheme that guarantees
a given security level when using a given poly_modulus_degree, according
to the HomomorphicEncryption.org security standard. Note that all security
guarantees are lost if the output is used with encryption parameters with
a mismatching value for the poly_modulus_degree.
The coefficient modulus returned by this function will not perform well
if used with the CKKS scheme.
@param[in] poly_modulus_degree The value of the poly_modulus_degree
encryption parameter
@param[in] sec_level The desired standard security level
@throws std::invalid_argument if poly_modulus_degree is not a power-of-two
or is too large
@throws std::invalid_argument if sec_level is sec_level_type::none
*/
SEAL_NODISCARD static std::vector<Modulus> BFVDefault(
std::size_t poly_modulus_degree, sec_level_type sec_level = sec_level_type::tc128);
Returns a custom coefficient modulus suitable for use with the specified
poly_modulus_degree. The return value will be a vector consisting of
Modulus elements representing distinct prime numbers such that:
1) have bit-lengths as given in the bit_sizes parameter (at most 60 bits) and
2) are congruent to 1 modulo 2*poly_modulus_degree.
/**
Returns a custom coefficient modulus suitable for use with the specified
poly_modulus_degree. The return value will be a vector consisting of
Modulus elements representing distinct prime numbers such that:
1) have bit-lengths as given in the bit_sizes parameter (at most 60 bits) and
2) are congruent to 1 modulo 2*poly_modulus_degree.
@param[in] poly_modulus_degree The value of the poly_modulus_degree
encryption parameter
@param[in] bit_sizes The bit-lengths of the primes to be generated
@throws std::invalid_argument if poly_modulus_degree is not a power-of-two
or is too large
@throws std::invalid_argument if bit_sizes is too large or if its elements
are out of bounds
@throws std::logic_error if not enough suitable primes could be found
*/
SEAL_NODISCARD static std::vector<Modulus> Create(std::size_t poly_modulus_degree, std::vector<int> bit_sizes);
/**
Returns a custom coefficient modulus suitable for use with the specified
poly_modulus_degree. The return value will be a vector consisting of
Modulus elements representing distinct prime numbers such that:
1) have bit-lengths as given in the bit_sizes parameter (at most 60 bits) and
2) are congruent to 1 modulo LCM(2*poly_modulus_degree, plain_modulus).
@param[in] poly_modulus_degree The value of the poly_modulus_degree encryption parameter
@param[in] plain_modulus The value of the plain_modulus encryption parameter
@param[in] bit_sizes The bit-lengths of the primes to be generated
@throws std::invalid_argument if poly_modulus_degree is not a power-of-two
or is too large
@throws std::invalid_argument if bit_sizes is too large or if its elements
are out of bounds
@throws std::logic_error if LCM(2*poly_modulus_degree, plain_modulus) is more than 64-bit
@throws std::logic_error if not enough suitable primes could be found
*/
SEAL_NODISCARD static std::vector<Modulus> Create(
std::size_t poly_modulus_degree, const Modulus &plain_modulus, std::vector<int> bit_sizes);
vector<Modulus> CoeffModulus::BFVDefault(size_t poly_modulus_degree, sec_level_type sec_level)
{
if (!MaxBitCount(poly_modulus_degree, sec_level))
{
throw invalid_argument("non-standard poly_modulus_degree");
}
if (sec_level == sec_level_type::none)
{
throw invalid_argument("invalid security level");
}
switch (sec_level)
{
case sec_level_type::tc128:
return global_variables::GetDefaultCoeffModulus128().at(poly_modulus_degree);
case sec_level_type::tc192:
return global_variables::GetDefaultCoeffModulus192().at(poly_modulus_degree);
case sec_level_type::tc256:
return global_variables::GetDefaultCoeffModulus256().at(poly_modulus_degree);
default:
throw runtime_error("invalid security level");
}
}
vector<Modulus> CoeffModulus::Create(size_t poly_modulus_degree, vector<int> bit_sizes)
{
if (poly_modulus_degree > SEAL_POLY_MOD_DEGREE_MAX || poly_modulus_degree < SEAL_POLY_MOD_DEGREE_MIN ||
get_power_of_two(static_cast<uint64_t>(poly_modulus_degree)) < 0)
{
throw invalid_argument("poly_modulus_degree is invalid");
}
if (bit_sizes.size() > SEAL_COEFF_MOD_COUNT_MAX)
{
throw invalid_argument("bit_sizes is invalid");
}
if (accumulate(
bit_sizes.cbegin(), bit_sizes.cend(), SEAL_USER_MOD_BIT_COUNT_MIN,
[](int a, int b) { return max(a, b); }) > SEAL_USER_MOD_BIT_COUNT_MAX ||
accumulate(bit_sizes.cbegin(), bit_sizes.cend(), SEAL_USER_MOD_BIT_COUNT_MAX, [](int a, int b) {
return min(a, b);
}) < SEAL_USER_MOD_BIT_COUNT_MIN)
{
throw invalid_argument("bit_sizes is invalid");
}
unordered_map<int, size_t> count_table;
unordered_map<int, vector<Modulus>> prime_table;
for (int size : bit_sizes)
{
++count_table[size];
}
uint64_t factor = mul_safe(uint64_t(2), safe_cast<uint64_t>(poly_modulus_degree));
for (const auto &table_elt : count_table)
{
prime_table[table_elt.first] = get_primes(factor, table_elt.first, table_elt.second);
}
vector<Modulus> result;
for (int size : bit_sizes)
{
result.emplace_back(prime_table[size].back());
prime_table[size].pop_back();
}
return result;
}
vector<Modulus> CoeffModulus::Create(
size_t poly_modulus_degree, const Modulus &plain_modulus, vector<int> bit_sizes)
{
if (poly_modulus_degree > SEAL_POLY_MOD_DEGREE_MAX || poly_modulus_degree < SEAL_POLY_MOD_DEGREE_MIN ||
get_power_of_two(static_cast<uint64_t>(poly_modulus_degree)) < 0)
{
throw invalid_argument("poly_modulus_degree is invalid");
}
if (bit_sizes.size() > SEAL_COEFF_MOD_COUNT_MAX)
{
throw invalid_argument("bit_sizes is invalid");
}
if (accumulate(
bit_sizes.cbegin(), bit_sizes.cend(), SEAL_USER_MOD_BIT_COUNT_MIN,
[](int a, int b) { return max(a, b); }) > SEAL_USER_MOD_BIT_COUNT_MAX ||
accumulate(bit_sizes.cbegin(), bit_sizes.cend(), SEAL_USER_MOD_BIT_COUNT_MAX, [](int a, int b) {
return min(a, b);
}) < SEAL_USER_MOD_BIT_COUNT_MIN)
{
throw invalid_argument("bit_sizes is invalid");
}
unordered_map<int, size_t> count_table;
unordered_map<int, vector<Modulus>> prime_table;
for (int size : bit_sizes)
{
++count_table[size];
}
uint64_t factor = mul_safe(uint64_t(2), safe_cast<uint64_t>(poly_modulus_degree));
factor = mul_safe(factor, plain_modulus.value() / gcd(plain_modulus.value(), factor)); // 计算的是 LCM(factor,plain_modulus)
for (const auto &table_elt : count_table)
{
prime_table[table_elt.first] = get_primes(factor, table_elt.first, table_elt.second);
}
vector<Modulus> result;
for (int size : bit_sizes)
{
result.emplace_back(prime_table[size].back());
prime_table[size].pop_back();
}
return result;
}
该类包含用于轻松创建明文模数的静态方法。
PlainModulus() = delete;
Creates a prime number Modulus for use as plain_modulus encryption parameter that supports batching with a given poly_modulus_degree.
/**
Creates a prime number Modulus for use as plain_modulus encryption
parameter that supports batching with a given poly_modulus_degree.
@param[in] poly_modulus_degree The value of the poly_modulus_degree
encryption parameter
@param[in] bit_size The bit-length of the prime to be generated
@throws std::invalid_argument if poly_modulus_degree is not a power-of-two
or is too large
@throws std::invalid_argument if bit_size is out of bounds
@throws std::logic_error if a suitable prime could not be found
*/
SEAL_NODISCARD static inline Modulus Batching(std::size_t poly_modulus_degree, int bit_size)
{
return CoeffModulus::Create(poly_modulus_degree, { bit_size })[0];
}
Creates several prime number Modulus elements that can be used as plain_modulus encryption parameters, each supporting batching with a given poly_modulus_degree.
/**
Creates several prime number Modulus elements that can be used as
plain_modulus encryption parameters, each supporting batching with a given
poly_modulus_degree.
@param[in] poly_modulus_degree The value of the poly_modulus_degree
encryption parameter
@param[in] bit_sizes The bit-lengths of the primes to be generated
@throws std::invalid_argument if poly_modulus_degree is not a power-of-two
or is too large
@throws std::invalid_argument if bit_sizes is too large or if its elements
are out of bounds
@throws std::logic_error if not enough suitable primes could be found
*/
SEAL_NODISCARD static inline std::vector<Modulus> Batching(
std::size_t poly_modulus_degree, std::vector<int> bit_sizes)
{
return CoeffModulus::Create(poly_modulus_degree, bit_sizes);
}
注:modulus.cpp 引用了以下头文件:
#include "seal/modulus.h"
#include "seal/util/common.h"
#include "seal/util/numth.h"
#include "seal/util/uintarith.h"
#include "seal/util/uintarithsmallmod.h"
#include <numeric>
#include <stdexcept>
#include <unordered_map>