Skip to content

Commit

Permalink
Merge pull request #492 from tuneinsight/he-collapse
Browse files Browse the repository at this point in the history
v6.0.0
  • Loading branch information
qantik authored Aug 6, 2024
2 parents faf7e1b + d6f5dfb commit 3214e2d
Show file tree
Hide file tree
Showing 169 changed files with 4,863 additions and 7,266 deletions.
34 changes: 32 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@

# Changelog
All notable changes to this library are documented in this file.

## UNRELEASED
## [6.0.0] - 06.08.2024
- Deprecated Go versions `1.18`, `1.19` and `1.20`. The minimum version is now `1.21`, due to the use of the slices of std library package.
- Removal of all slice utility functions in `utils/slices.go` that are provided in the standard library.
- Golang test cache is deleted before invoking the unit test suite via `make test`.
- Deletion of the `he` package and its abstraction layers for the BGV and CKKS, refocus of the library onto the scheme level, i.e., the `schemes` package.
- Extraction of the homomorphic circuits from the `he` into a new `circuits` package.
- Simplification of the API for several circuits:
- Removal of the circuit-specific evaluator interfaces, e.g., `EvaluatorForLinearTransformation`. These interfaces are replaced with a scheme-agnostic evaluator in `schemes/schemes.go` due to the refocus of the Lattigo towards the individual cryptosystems.
- The individual homomorphic circuits are organized by schemes, in other words in the packages `circuits/bgv`, `circuits/ckks` and `circuits/common` where the latter bundles scheme-generic functionalities of circuits common to all deriving schemes.
- Absorb the `bfv` package into the `bgv` package.
- Rename `mhe` into `multiparty`.
- Slot-wise permutations as part of the `LinearTransformation` circuits:
- Permutation are handled through `lintrans.Permutation` and `lintrans.PermutationMapping` that induce `lintrans.Diagonals` from which a regular linear transformation can be bootstrapped.
- New ring packing API:
- New packing evaluator: `rlwe.RingPackingEvaluator`:
- `NewRingPackingEvaluator(evk *RingPackingEvaluationKey)`
- `Extract(ct *rlwe.Ciphertext, idx []int, naive bool) (cts map[int]*rlwe.Ciphertext, err error)`
- `Repack(cts map[int]*rlwe.Ciphertext, naive bool) (ct *rlwe.Ciphertext, err error)`
- `Split(ctN, ctEvenNHalf, ctOddNHalf *rlwe.Ciphertext) (err error)`
- `Merge(ctEvenNHalf, ctOddNHalf, ctN *rlwe.Ciphertext) (err error)`
- `ShallowCopy() *RingPackingEvaluator`
- New packing evaluation key:
- `rlwe.RingPackingEvaluationKey`
- Streamlined unit test context generation to reduce boilerplate code duplication:
- `schemes/*/test_utils.go` to be reused in packages `schemes` and packages that depend on `schemes`.
- Introduction of the `lintrans.Parameters.LevelQ` and `lintrans.Parameters.LevelP` fields and the removal of the `lintrans.Parameters.Level` field.
- Optimizations:
- Reduce the number of masking operations in `rlwe.Evaluator.gadgetProductSinglePAndBitDecompLazy`.
- Reduce degree of relinearization key shares in `multiparty/keygen_relin.go`.
- Add `gosec` exception directive to weak randomness in unit tests.
- Fix various linter warnings.
- Various docstring formatting fixes and the addition of `godoc` links through the `[]` operator.
- Updated `README.md` with new package hierarchy figures `lattigo-hierachy.svg` and new issue policy.

## [5.0.0] - 15.11.2023
- Deprecated Go versions `1.14`, `1.15`, `1.16`, and `1.17`. The minimum version is now `1.18`, due to the required use of generics.
Expand Down
107 changes: 50 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,29 @@ is a common choice thanks to its natural concurrency model and portability.

## Library overview

The library exposes the following packages:

- `lattigo/he`: The main package of the library which provides scheme-agnostic interfaces
and Homomorphic Encryption for different plaintext domains.

- `hebin`: Homomorphic Encryption for binary arithmetic. It comprises blind rotations (a.k.a Lookup Tables) over RLWE ciphertexts.

- `hefloat`: Homomorphic Encryption for fixed-point approximate arithmetic over the complex or real numbers.

- `bootstrapping`: Bootstrapping for fixed-point approximate arithmetic over the real
and complex numbers, with support for the Conjugate Invariant ring, batch bootstrapping with automatic
packing/unpacking of sparsely packed/smaller ring degree ciphertexts, arbitrary precision bootstrapping,
and advanced circuit customization/parameterization.

- `heint`: Homomorphic Encryption for modular arithmetic over the integers.
<p align="center" width="100%"">
<img width=500 height=350 alt="lattigo-hierarchy" src="./lattigo-hierarchy.svg">
</p>

- `lattigo/mhe`: Package for multiparty (a.k.a. distributed or threshold) key-generation and
interactive ciphertext bootstrapping with secret-shared secret keys.
Lattigo is a strictly hierarchical library whose packages form a linear dependency chain ranging from
low-level arithmetic functionalities to high-level homomorphic circuits. A graphical depiction of the
Lattigo package organization is given in the Figure above.

- `mhefloat`: Homomorphic decryption and re-encryption from and to Linear-Secret-Sharing-Shares,
as well as interactive ciphertext bootstrapping for the package `he/hefloat`.
- `lattigo/ring`: At the lowest level resides the `ring` package providing modular arithmetic operations for polynomials
in the RNS basis, including: RNS basis extension; RNS rescaling; number theoretic transform (NTT); uniform,
Gaussian and ternary sampling.

- `lattigo/core`: This package implements the core cryptographic functionalities of the library and builds directly
upon the arithmetic functionalities provided by the `ring` package:

- `mheint`: Homomorphic decryption and re-encryption from and to Linear-Secret-Sharing-Shares,
as well as interactive ciphertext bootstrapping for the package `he/heint`.
- `rlwe`: Common base for generic RLWE-based homomorphic encryption.
It provides all homomorphic functionalities and defines all structs that are not scheme-specific.
This includes plaintext, ciphertext, key-generation, encryption, decryption and key-switching, as
well as other more advanced primitives such as RLWE-repacking.

- `lattigo/schemes`: A package implementing RLWE-based homomorphic encryption schemes.
- `rgsw`: A Full-RNS variant of Ring-GSW ciphertexts and the external product.

- `lattigo/schemes`: The implementation of RLWE-based homomorphic encryption schemes are found in the `schemes` package:

- `bfv`: A Full-RNS variant of the Brakerski-Fan-Vercauteren scale-invariant homomorphic
encryption scheme. This scheme is instantiated via a wrapper of the `bgv` scheme.
Expand All @@ -59,19 +56,39 @@ The library exposes the following packages:
- `ckks`: A Full-RNS Homomorphic Encryption for Arithmetic for Approximate Numbers (HEAAN,
a.k.a. CKKS) scheme. It provides fixed-point approximate arithmetic over the complex numbers (in its classic
variant) and over the real numbers (in its conjugate-invariant variant).

- `lattigo/circuits`: The circuits package provides implementation of a select set of homomorphic circuits for
the `bgv` and `ckks` cryptosystems:

- `bgv/lintrans`, `ckks/lintrans`: Arbitrary linear transformations and slot permutations for both `bgv` and `ckks`.
Scheme-generic objects and functions are part of `common/lintrans`.

- `bgv/polynomial`, `ckks/polynomial`: Polynomial evaluation circuits for `bgv` and `ckks`.
Scheme-generic objects and functions are part of `common/polynomial`.

- `ckks/minimax`: Minimax composite polynomial evaluator for `ckks`.

- `ckks/comparison`: Homomorphic comparison-based circuits such as `sign`, `max` and `step` for the `ckks` scheme.

- `ckks/inverse`: Homomorphic inverse circuit for `ckks`.

- `ckks/mod1`: Homomorphic circuit for the `mod1` function using the `ckks` cryptosystem.

- `ckks/dft`: Homomorphic Discrete Fourier Transform circuits for the `ckks` scheme.

- `ckks/bootstrapping`: Bootstrapping for fixed-point approximate arithmetic over the real
and complex numbers, i.e., the `ckks` scheme, with support for the Conjugate Invariant ring, batch bootstrapping with automatic
packing/unpacking of sparsely packed/smaller ring degree ciphertexts, arbitrary precision bootstrapping,
and advanced circuit customization/parameterization.

- `lattigo/multiparty`: Package for multiparty (a.k.a. distributed or threshold) key-generation and
interactive ciphertext bootstrapping with secret-shared secret keys.

- `lattigo/core`: A package implementing the core cryptographic functionalities of the library.

- `rlwe`: Common base for generic RLWE-based homomorphic encryption.
It provides all homomorphic functionalities and defines all structs that are not scheme-specific.
This includes plaintext, ciphertext, key-generation, encryption, decryption and key-switching, as
well as other more advanced primitives such as RLWE-repacking.

- `rgsw`: A Full-RNS variant of Ring-GSW ciphertexts and the external product.
- `mpckks`: Homomorphic decryption and re-encryption from and to Linear-Secret-Sharing-Shares,
as well as interactive ciphertext bootstrapping for the `schemes/ckks` package.

- `lattigo/ring`: Modular arithmetic operations for polynomials in the RNS basis, including: RNS
basis extension; RNS rescaling; number theoretic transform (NTT); uniform, Gaussian and ternary
sampling.
- `mpbgv`: Homomorphic decryption and re-encryption from and to Linear-Secret-Sharing-Shares,
as well as interactive ciphertext bootstrapping for the `schemes/bgv` package.

- `lattigo/examples`: Executable Go programs that demonstrate the use of the Lattigo library. Each
subpackage includes test files that further demonstrate the use of Lattigo
Expand All @@ -84,30 +101,6 @@ The library exposes the following packages:
- `sampling`: Secure bytes sampling.
- `structs`: Generic structs for maps, vectors and matrices, including serialization.

```mermaid
---
title: Packages Dependency & Organization
---
flowchart LR
RING(RING) --> RLWE(RLWE)
RLWE --> RGSW(RGSW)
RLWE --> HE([HE])
RLWE --> CKKS{{CKKS}}
RGSW --> HEBin{HEBin}
HE --> HEFloat{HEFloat}
HE --> HEInt{HEInt}
HE --> HEBin
BFV/BGV --> HEInt
CKKS --> HEFloat
RLWE --> BFV/BGV{{BFV/BGV}}
MHE --> MHEFloat
HEFloat --> MHEFloat((MHEFloat))
HEFloat --> Bootstrapping
HEInt --> MHEInt((MHEInt))
RLWE --> MHE([MHE])
MHE --> MHEInt
```

### Documentation

The full documentation of the individual packages can be browsed as a web page using official
Expand Down
196 changes: 196 additions & 0 deletions circuits/bgv/lintrans/lintrans.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// Package lintrans implements homomorphic linear transformations for the BFV/BGV schemes.
package lintrans

import (
"github.com/tuneinsight/lattigo/v5/circuits/common/lintrans"
"github.com/tuneinsight/lattigo/v5/core/rlwe"
"github.com/tuneinsight/lattigo/v5/schemes"
"github.com/tuneinsight/lattigo/v5/schemes/bgv"
"github.com/tuneinsight/lattigo/v5/utils"
)

// Diagonals is a wrapper of [lintrans.Diagonals].
type Diagonals[T bgv.Integer] lintrans.Diagonals[T]

// DiagonalsIndexList returns the list of the non-zero diagonals of the square matrix.
// A non zero diagonals is a diagonal with a least one non-zero element.
func (m Diagonals[T]) DiagonalsIndexList() (indexes []int) {
return lintrans.Diagonals[T](m).DiagonalsIndexList()
}

// Evaluate evaluates the linear transformation on the provided vector.
// add: c = a + b
// muladd: c = c + a * b
func (m Diagonals[T]) Evaluate(vector []T, newVec func(size int) []T, add func(a, b, c []T), muladd func(a, b, c []T)) (res []T) {

slots := len(vector) >> 1 // 2 x n/2 matrix

keys := utils.GetKeys(m)

N1 := lintrans.FindBestBSGSRatio(keys, slots, 1)

index, _, _ := lintrans.BSGSIndex(keys, slots, N1)

res = newVec(2 * slots)

for j := range index {

rot := -j & (slots - 1)

tmp := newVec(2 * slots)

for _, i := range index[j] {

v, ok := m[j+i]
if !ok {
v = m[j+i-slots]
}

muladd(utils.RotateSlice(vector[:slots], i), utils.RotateSlice(v[:slots], rot), tmp[:slots])
muladd(utils.RotateSlice(vector[slots:], i), utils.RotateSlice(v[slots:], rot), tmp[slots:])
}

add(res[:slots], utils.RotateSlice(tmp[:slots], j), res[:slots])
add(res[slots:], utils.RotateSlice(tmp[slots:], j), res[slots:])
}

return
}

// PermutationMapping is a struct storing
// a mapping: From -> To and a scaling value.
type PermutationMapping[T bgv.Integer] struct {
From int
To int
Scaling T
}

// Permutation is a struct that defines generic permutations
// over 2 x n/2 matrices, treating each row independently.
//
// For example, given the 2x2 matrix [[a, b] [c, d]] that would
// be mapped to [[1b, 2a] [3c, 4d]] then the Permutation would
// contain the following map:
// {{0:{1, 2}, 1:{0: 1}}, {0:{0, 3}: 1:{1, 4}}}
type Permutation[T bgv.Integer] [2][]PermutationMapping[T]

// GetDiagonals returns the non-zero diagonals of the matrix
// representation of the permutation, which can be used to
// instantiate [Parameters].
func (p Permutation[T]) GetDiagonals(logSlots int) Diagonals[T] {

slots := 1 << (logSlots - 1) // matrix of 2 x 2^{logSlots}

diagonals := map[int][]T{}

for i := range p {

offset := i * slots

for _, pm := range p[i] {

From := pm.From
To := pm.To
Scaling := pm.Scaling

diagIndex := (slots + From - To) & (slots - 1)

if _, ok := diagonals[diagIndex]; !ok {
diagonals[diagIndex] = make([]T, 2*slots)
}

diagonals[diagIndex][To+offset] = Scaling
}
}

return Diagonals[T](diagonals)
}

// Parameters is a wrapper of [lintrans.Parameters].
type Parameters lintrans.Parameters

// LinearTransformation is a wrapper of [lintrans.Parameters].
type LinearTransformation lintrans.LinearTransformation

// GaloisElements returns the list of Galois elements required to evaluate the linear transformation.
func (lt LinearTransformation) GaloisElements(params rlwe.ParameterProvider) []uint64 {
return lintrans.LinearTransformation(lt).GaloisElements(params)
}

// NewLinearTransformation instantiates a new [LinearTransformation] and is a wrapper of [lintrans.LinearTransformation].
func NewLinearTransformation(params rlwe.ParameterProvider, lt Parameters) LinearTransformation {
return LinearTransformation(lintrans.NewLinearTransformation(params, lintrans.Parameters(lt)))
}

// Encode is a method used to encode a [LinearTransformation] and a wrapper of [lintrans.Encode].
func Encode[T bgv.Integer](ecd schemes.Encoder, diagonals Diagonals[T], allocated LinearTransformation) (err error) {
return lintrans.Encode(
ecd,
lintrans.Diagonals[T](diagonals),
lintrans.LinearTransformation(allocated))
}

// Evaluator is a struct for evaluating linear transformations on [rlwe.Ciphertexts].
// All fields of this struct are public, enabling custom instantiations.
type Evaluator struct {
lintrans.Evaluator
}

// NewEvaluator instantiates a new [Evaluator] from a [schemes.Evaluator].
// The default [bgv.Evaluator] is compliant to the [schemes.Evaluator] interface.
func NewEvaluator(eval schemes.Evaluator) (linTransEval *Evaluator) {
return &Evaluator{
lintrans.Evaluator{
Evaluator: eval,
},
}
}

// EvaluateNew takes as input a ciphertext ctIn and a linear transformation M and evaluate and returns opOut: M(ctIn).
func (eval Evaluator) EvaluateNew(ctIn *rlwe.Ciphertext, linearTransformation LinearTransformation) (opOut *rlwe.Ciphertext, err error) {
ops, err := eval.EvaluateManyNew(ctIn, []LinearTransformation{linearTransformation})
if err != nil {
return nil, err
}
return ops[0], nil
}

// Evaluate takes as input a ciphertext ctIn, a linear transformation M and evaluates opOut: M(ctIn).
func (eval Evaluator) Evaluate(ctIn *rlwe.Ciphertext, linearTransformation LinearTransformation, opOut *rlwe.Ciphertext) (err error) {
return eval.Evaluator.EvaluateMany(ctIn, []lintrans.LinearTransformation{lintrans.LinearTransformation(linearTransformation)}, []*rlwe.Ciphertext{opOut})
}

// EvaluateManyNew takes as input a ciphertext ctIn and a list of linear transformations [M0, M1, M2, ...] and returns opOut:[M0(ctIn), M1(ctIn), M2(ctInt), ...].
func (eval Evaluator) EvaluateManyNew(ctIn *rlwe.Ciphertext, linearTransformations []LinearTransformation) (opOut []*rlwe.Ciphertext, err error) {
params := eval.GetRLWEParameters()
opOut = make([]*rlwe.Ciphertext, len(linearTransformations))
for i := range opOut {
opOut[i] = rlwe.NewCiphertext(params, 1, linearTransformations[i].LevelQ)
}
return opOut, eval.EvaluateMany(ctIn, linearTransformations, opOut)
}

// EvaluateMany takes as input a ciphertext ctIn, a list of linear transformations [M0, M1, M2, ...] and a list of pre-allocated receiver opOut
// and evaluates opOut: [M0(ctIn), M1(ctIn), M2(ctIn), ...]
func (eval Evaluator) EvaluateMany(ctIn *rlwe.Ciphertext, linearTransformations []LinearTransformation, opOut []*rlwe.Ciphertext) (err error) {
circuitLTs := make([]lintrans.LinearTransformation, len(linearTransformations))
for i := range circuitLTs {
circuitLTs[i] = lintrans.LinearTransformation(linearTransformations[i])
}
return eval.Evaluator.EvaluateMany(ctIn, circuitLTs, opOut)
}

// EvaluateSequentialNew takes as input a ciphertext ctIn and a list of linear transformations [M0, M1, M2, ...] and returns opOut:...M2(M1(M0(ctIn))
func (eval Evaluator) EvaluateSequentialNew(ctIn *rlwe.Ciphertext, linearTransformations []LinearTransformation) (opOut *rlwe.Ciphertext, err error) {
opOut = rlwe.NewCiphertext(eval.GetRLWEParameters(), 1, linearTransformations[0].LevelQ)
return opOut, eval.EvaluateSequential(ctIn, linearTransformations, opOut)
}

// EvaluateSequential takes as input a ciphertext ctIn and a list of linear transformations [M0, M1, M2, ...] and returns opOut:...M2(M1(M0(ctIn))
func (eval Evaluator) EvaluateSequential(ctIn *rlwe.Ciphertext, linearTransformations []LinearTransformation, opOut *rlwe.Ciphertext) (err error) {
circuitLTs := make([]lintrans.LinearTransformation, len(linearTransformations))
for i := range circuitLTs {
circuitLTs[i] = lintrans.LinearTransformation(linearTransformations[i])
}
return eval.Evaluator.EvaluateSequential(ctIn, circuitLTs, opOut)
}
Loading

0 comments on commit 3214e2d

Please sign in to comment.