Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,25 @@ option(WITH_COVTEST "Turn on to enable coverage testing"
option(WITH_NOISE_DEBUG "Use only when running lattice estimator; not for production" OFF )
option(WITH_REDUCED_NOISE "Enable reduced noise within HKS and BFV HPSPOVERQ modes" OFF )
option(USE_MACPORTS "Use MacPorts installed packages" OFF )
# Chain Reaction flags
option(WITH_CR_PRNG "Enable Chain Reaction custom PRNG" OFF)
option(WITH_CR_MODULI "Enable Chain Reaction predefined moduli" OFF)

if(WITH_CR_PRNG)
add_definitions(-DWITH_CR_PRNG)
# FIX: Export flag to OpenFHEConfig.cmake
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITH_CR_PRNG")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWITH_CR_PRNG")
message(STATUS "Chain Reaction PRNG is enabled")
endif()

if(WITH_CR_MODULI)
add_definitions(-DWITH_CR_MODULI)
# FIX: Export flag to OpenFHEConfig.cmake
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITH_CR_MODULI")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWITH_CR_MODULI")
message(STATUS "Chain Reaction predefined moduli is enabled")
endif()

# Set required number of bits for native integer in build by setting NATIVE_SIZE to 64 or 128
if(NOT NATIVE_SIZE)
Expand Down Expand Up @@ -109,6 +128,9 @@ message(STATUS "WITH_COVTEST: ${WITH_COVTEST}")
message(STATUS "WITH_NOISE_DEBUG: ${WITH_NOISE_DEBUG}")
message(STATUS "WITH_REDUCED_NOISE: ${WITH_REDUCED_NOISE}")
message(STATUS "USE_MACPORTS: ${USE_MACPORTS}")
message(STATUS "USE_MACPORTS: ${USE_MACPORTS}")
message(STATUS "WITH_CR_PRNG: ${WITH_CR_PRNG}")
message(STATUS "WITH_CR_MODULI: ${WITH_CR_MODULI}")

#--------------------------------------------------------------------
# Compiler logic
Expand Down
135 changes: 135 additions & 0 deletions src/core/include/math/discreteuniformgenerator-cr-impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//==================================================================================
// BSD 2-Clause License
//
// Copyright (c) 2014-2023, NJIT, Duality Technologies Inc. and other contributors
//
// All rights reserved.
//
// Author TPOC: contact@openfhe.org
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//==================================================================================

/*
This code provides generation of uniform distributions of discrete values. Discrete uniform generator relies on
the built-in C++ generator for 32-bit unsigned integers defined in <random>
*/

#ifndef LBCRYPTO_INC_MATH_DISCRETEUNIFORMGENERATORCR_IMPL_H_
#define LBCRYPTO_INC_MATH_DISCRETEUNIFORMGENERATORCR_IMPL_H_

#include "math/discreteuniformgenerator-cr.h"
#include "math/discreteuniformgenerator.h"
#include "utils/exception.h"
#include "utils/prng/shake128engine.h"

namespace lbcrypto {

inline bool is_normalize(int32_t x, NativeVector::Integer q) {
NativeVector::Integer qh = q / 2;
int64_t x_64 = static_cast<int64_t>(x);
return (-qh.ConvertToInt<int64_t>() <= x_64) && (x_64 <= qh.ConvertToInt<int64_t>());
}

// -----------------------------------------------------------------------------
// Function: extract_signed_b_bits
// -----------------------------------------------------------------------------
inline int32_t extract_signed_b_bits(int32_t w, size_t b) {
assert(b > 0 && b <= 32);

// 1. Extract the signed MSB (W[31])
// Note: Arithmetic right shift on negative signed integers is implementation-defined
// prior to C++20, but standard in C++20. Most compilers do arithmetic shift by default.
int32_t msb = w >> 31;

// 2. Extract the (b-1) least significant bits
uint32_t mask = (1U << (b - 1)) - 1;
int32_t low_bits = w & static_cast<int32_t>(mask);

// 3. Concatenate: shift msb to top and OR with low bits.
// We cast `msb` to uint32_t before shifting to avoid Undefined Behavior
// (shifting a negative signed integer left is UB in older C++ standards).
uint32_t msb_shifted = static_cast<uint32_t>(msb) << (b - 1);

// Combine and cast back to signed
return static_cast<int32_t>(msb_shifted | static_cast<uint32_t>(low_bits));
}

inline int8_t FindQindex(const std::vector<NativeVector::Integer>& moduliList, const NativeVector::Integer& modulus) {
for (size_t i = 0; i < moduliList.size(); i++) {
if (moduliList[i] == modulus) {
return i;
}
}
return -1;
}

inline NativeVector::Integer DiscreteUniformGeneratorCRImpl::GenerateInteger() const {
OPENFHE_THROW("GenerateInteger operation not supported");
}

inline NativeVector DiscreteUniformGeneratorCRImpl::GenerateVector(const uint32_t size,
const NativeVector::Integer& modulus) {
this->SetModulus(modulus);

if (size != 65536)
OPENFHE_THROW("vector size must be 65536");

NativeVector v(size, this->m_modulus);
std::uniform_int_distribution<uint32_t> dist(DUG_CHUNK_MIN, DUG_CHUNK_MAX);
int8_t qIndex = FindQindex(this->m_moduli, this->m_modulus);

size_t b = static_cast<size_t>(std::ceil(std::log2(modulus.ConvertToDouble())));

for (uint16_t seg_i = 0; seg_i < 2048; ++seg_i) {
std::unique_ptr<PRNG> shake128engine = std::make_unique<Shake128Engine>(m_seed, m_salt, qIndex, seg_i);

size_t valid_words_idx = 0;

for (uint32_t i = 0; i < 42; ++i) {
uint32_t word = dist(*shake128engine);

int32_t x = extract_signed_b_bits(word, b);

if (is_normalize(x, modulus)) {
if (x < 0) {
x += modulus.ConvertToInt();
}
v[(seg_i * 32) + valid_words_idx] = x;
valid_words_idx++;
}
if (valid_words_idx == 32) {
break;
}
}
// if we tried 42 words and didn't reach to 32 valid words
if (valid_words_idx < 32) {
OPENFHE_THROW("Prng Reject Segment");
}
}

return v;
}

} // namespace lbcrypto

#endif
53 changes: 53 additions & 0 deletions src/core/include/math/discreteuniformgenerator-cr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2025 Chain Reaction LTD
// All rights reserved.
//
// This product is protected by copyright and distributed
// under license terms that restrict copying, distribution, and decompilation.

#ifndef LBCRYPTO_INC_MATH_DISCRETEUNIFORMGENERATORCR_H_
#define LBCRYPTO_INC_MATH_DISCRETEUNIFORMGENERATORCR_H_

#include "math/distributiongenerator.h"

#include <limits>
#include <random>
#include <vector>
#include <array>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <cassert>

namespace lbcrypto {

/**
* @brief The class for Discrete Uniform Distribution generator over Zq.
*/
class DiscreteUniformGeneratorCRImpl : public DiscreteUniformGeneratorImpl<NativeVector>{
public:
DiscreteUniformGeneratorCRImpl(std::shared_ptr<lbcrypto::M4DCRTParams> params,std::vector<u_int32_t> seed) {
assert(seed.size()==8);
m_moduli = std::vector<NativeVector::Integer>(params->GetParams().size());
for (size_t i = 0; i < params->GetParams().size(); i++) {
m_moduli[i] = params->GetParams()[i]->GetModulus();
}
m_seed = seed;
}
void SetSalt(u_int32_t salt) {
m_salt = salt;
}

NativeVector GenerateVector(const uint32_t size, const NativeVector::Integer& modulus) override;
NativeVector::Integer GenerateInteger() const override;

private:
std::vector<uint32_t> m_seed;
u_int32_t m_salt = 0;
std::vector<NativeVector::Integer> m_moduli;
};

} // namespace lbcrypto

#include "math/discreteuniformgenerator-cr-impl.h"

#endif // LBCRYPTO_INC_MATH_DISCRETEUNIFORMGENERATORCR_H_
11 changes: 7 additions & 4 deletions src/core/include/math/discreteuniformgenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,18 @@ class DiscreteUniformGeneratorImpl {
* @brief Generates a random integer based on the modulus set for the Discrete
* Uniform Generator object. Required by DistributionGenerator.
*/
typename VecType::Integer GenerateInteger() const;
virtual typename VecType::Integer GenerateInteger() const;

/**
* @brief Generates a vector of random integers using GenerateInteger()
*/
VecType GenerateVector(const uint32_t size) const;
VecType GenerateVector(const uint32_t size, const typename VecType::Integer& modulus);
virtual VecType GenerateVector(const uint32_t size) const;
virtual VecType GenerateVector(const uint32_t size, const typename VecType::Integer& modulus);

private:
protected:
typename VecType::Integer m_modulus{};

private:
uint32_t m_chunksPerValue{};
uint32_t m_shiftChunk{};
std::uniform_int_distribution<uint32_t>::param_type m_bound{DUG_CHUNK_MIN, DUG_CHUNK_MAX};
Expand All @@ -86,3 +88,4 @@ class DiscreteUniformGeneratorImpl {
} // namespace lbcrypto

#endif // LBCRYPTO_INC_MATH_DISCRETEUNIFORMGENERATOR_H_

46 changes: 46 additions & 0 deletions src/core/include/utils/prng/sha3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// sha3.h
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>

#ifndef SHA3_H
#define SHA3_H

#include <stddef.h>
#include <stdint.h>

#ifndef KECCAKF_ROUNDS
#define KECCAKF_ROUNDS 24
#endif

#ifndef ROTL64
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#endif

// state context
typedef struct {
union { // state:
uint8_t b[200]; // 8-bit bytes
uint64_t q[25]; // 64-bit words
} st;
int pt, rsiz, mdlen; // these don't overflow
} sha3_ctx_t;

// Compression function.
void sha3_keccakf(uint64_t st[25]);

// OpenSSL - like interfece
int sha3_init(sha3_ctx_t *c, int mdlen); // mdlen = hash output in bytes
int sha3_update(sha3_ctx_t *c, const void *data, size_t len);
int sha3_final(void *md, sha3_ctx_t *c); // digest goes to md

// compute a sha3 hash (md) of given byte length from "in"
void *sha3(const void *in, size_t inlen, void *md, int mdlen);

// SHAKE128 and SHAKE256 extensible-output functions
#define shake128_init(c) sha3_init(c, 16)
#define shake256_init(c) sha3_init(c, 32)
#define shake_update sha3_update

void shake_xof(sha3_ctx_t *c);
void shake_out(sha3_ctx_t *c, void *out, size_t len);

#endif
Loading