Skip to content

Commit

Permalink
adapt changelog to v6
Browse files Browse the repository at this point in the history
  • Loading branch information
qantik committed Aug 5, 2024
1 parent 6b66bca commit 7813ec5
Show file tree
Hide file tree
Showing 29 changed files with 100 additions and 56 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] - 05.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
1 change: 1 addition & 0 deletions circuits/bgv/lintrans/lintrans.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package lintrans implements homomorphic linear transformations for the BFV/BGV schemes.
package lintrans

import (
Expand Down
1 change: 1 addition & 0 deletions circuits/bgv/polynomial/polynomial.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package polynomial implements a homomorphic polynomial evaluator for the BFV/BGV schemes.
package polynomial

import (
Expand Down
25 changes: 0 additions & 25 deletions circuits/bgv/polynomial/polynomial_evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,31 +72,6 @@ func (eval Evaluator) EvaluateFromPowerBasis(pb polynomial.PowerBasis, p interfa
return eval.Evaluator.Evaluate(pb, phe, targetScale, 1, &simEvaluator{eval.Parameters, eval.InvariantTensoring})
}

// scaleInvariantEvaluator is a struct containing a [bfv.Evaluator] with scale invariant tensoring (BFV-style).
type scaleInvariantEvaluator struct {
*bgv.Evaluator
}

func (polyEval scaleInvariantEvaluator) Mul(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rlwe.Ciphertext) (err error) {
return polyEval.MulScaleInvariant(op0, op1, opOut)
}

func (polyEval scaleInvariantEvaluator) MulRelin(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rlwe.Ciphertext) (err error) {
return polyEval.Evaluator.MulRelinScaleInvariant(op0, op1, opOut)
}

func (polyEval scaleInvariantEvaluator) MulNew(op0 *rlwe.Ciphertext, op1 rlwe.Operand) (opOut *rlwe.Ciphertext, err error) {
return polyEval.Evaluator.MulScaleInvariantNew(op0, op1)
}

func (polyEval scaleInvariantEvaluator) MulRelinNew(op0 *rlwe.Ciphertext, op1 rlwe.Operand) (opOut *rlwe.Ciphertext, err error) {
return polyEval.Evaluator.MulRelinScaleInvariantNew(op0, op1)
}

func (polyEval scaleInvariantEvaluator) Rescale(op0, op1 *rlwe.Ciphertext) (err error) {
return nil
}

// CoefficientGetter is a struct that implements the
// [polynomial.CoefficientGetter][uint64] interface.
type CoefficientGetter struct {
Expand Down
2 changes: 2 additions & 0 deletions circuits/ckks/bootstrapping/bootstrapper.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Package bootstrapping implements bootstrapping for fixed-point encrypted
// approximate homomorphic encryption over the complex/real numbers (CKKS scheme).
package bootstrapping

import "github.com/tuneinsight/lattigo/v5/core/rlwe"
Expand Down
1 change: 1 addition & 0 deletions circuits/ckks/comparison/comparison.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package comparison implements homomorphic comparisons for the CKKS scheme.
package comparison

import (
Expand Down
1 change: 1 addition & 0 deletions circuits/ckks/dft/dft.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package dft implements a homomorphic DFT circuit for the CKKS scheme.
package dft

import (
Expand Down
1 change: 1 addition & 0 deletions circuits/ckks/inverse/inverse.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package inverse implements a homomorphic inversion circuit for the CKKS scheme.
package inverse

import (
Expand Down
3 changes: 2 additions & 1 deletion circuits/ckks/lintrans/lintrans.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package lintrans implements homomorphic linear transformations for the CKKS scheme.
package lintrans

import (
Expand Down Expand Up @@ -122,7 +123,7 @@ func Encode[T ckks.Float](ecd schemes.Encoder, diagonals Diagonals[T], allocated
lintrans.LinearTransformation(allocated))
}

// // GaloisElements returns the list of Galois elements required to evaluate the linear transformation.
// GaloisElements returns the list of Galois elements required to evaluate the linear transformation.
func GaloisElements(params rlwe.ParameterProvider, lt Parameters) (galEls []uint64) {
return lintrans.GaloisElements(params, lt.DiagonalsIndexList, 1<<lt.LogDimensions.Cols, lt.LogBabyStepGiantStepRatio)
}
Expand Down
1 change: 1 addition & 0 deletions circuits/ckks/minimax/minimax_composite_polynomial.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package minimax implements a homomorphic minimax circuit for the CKKS scheme.
package minimax

import (
Expand Down
1 change: 1 addition & 0 deletions circuits/ckks/mod1/mod1_evaluator.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package mod1 implements a homomorphic mod1 circuit for the CKKS scheme.
package mod1

import (
Expand Down
1 change: 1 addition & 0 deletions circuits/ckks/polynomial/polynomial.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package polynomial implements a homomorphic polynomial evaluator for the CKKS scheme.
package polynomial

import (
Expand Down
1 change: 1 addition & 0 deletions circuits/common/lintrans/lintrans.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package lintrans bundles generic parts of the homomorphic linear transformation circuit.
package lintrans

import (
Expand Down
1 change: 1 addition & 0 deletions circuits/common/polynomial/polynomial.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package polynomial bundles generic parts of the homomorphic polynomial evaluation circuit.
package polynomial

import (
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package blind_rotation
// Package blindrot implements blind rotations evaluation for RLWE schemes.
package blindrot

import (
"github.com/tuneinsight/lattigo/v5/core/rlwe"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package blind_rotation
package blindrot

import (
"testing"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package blind_rotation
package blindrot

import (
"fmt"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package blind_rotation
package blindrot

import (
"fmt"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package blind_rotation
package blindrot

import (
"math/big"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package blind_rotation
package blindrot

import (
"math/big"
Expand Down
8 changes: 4 additions & 4 deletions examples/singleparty/ckks_scheme_switching/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"time"

"github.com/tuneinsight/lattigo/v5/circuits/ckks/dft"
"github.com/tuneinsight/lattigo/v5/core/rgsw/blind_rotation"
"github.com/tuneinsight/lattigo/v5/core/rgsw/blindrot"
"github.com/tuneinsight/lattigo/v5/core/rlwe"
"github.com/tuneinsight/lattigo/v5/ring"
"github.com/tuneinsight/lattigo/v5/schemes/ckks"
Expand Down Expand Up @@ -118,7 +118,7 @@ func main() {
fmt.Printf("Generating Test Poly... ")
now := time.Now()
// Generate test polynomial, provide function, outputscale, ring and interval.
testPoly := blind_rotation.InitTestPolynomial(sign, paramsN12.DefaultScale(), paramsN12.RingQ(), a, b)
testPoly := blindrot.InitTestPolynomial(sign, paramsN12.DefaultScale(), paramsN12.RingQ(), a, b)
fmt.Printf("Done (%s)\n", time.Since(now))

// Index of the test poly and repacking after evaluating the BlindRotation.
Expand Down Expand Up @@ -165,15 +165,15 @@ func main() {
evk := rlwe.NewMemEvaluationKeySet(nil, kgenN12.GenGaloisKeysNew(galEls, skN12)...)

// BlindRotation Evaluator
evalBR := blind_rotation.NewEvaluator(paramsN12, paramsN11)
evalBR := blindrot.NewEvaluator(paramsN12, paramsN11)

// Evaluator
eval := ckks.NewEvaluator(paramsN12, evk)
evalHDFT := dft.NewEvaluator(paramsN12, eval)

fmt.Printf("Encrypting bits of skLWE in RGSW... ")
now = time.Now()
blindRotateKey := blind_rotation.GenEvaluationKeyNew(paramsN12, skN12, paramsN11, skN11, evkParams) // Generate RGSW(sk_i) for all coefficients of sk
blindRotateKey := blindrot.GenEvaluationKeyNew(paramsN12, skN12, paramsN11, skN11, evkParams) // Generate RGSW(sk_i) for all coefficients of sk
fmt.Printf("Done (%s)\n", time.Since(now))

// Generates the starting plaintext values.
Expand Down
8 changes: 4 additions & 4 deletions examples/singleparty/rgsw_blind_rotations/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"fmt"
"time"

"github.com/tuneinsight/lattigo/v5/core/rgsw/blind_rotation"
"github.com/tuneinsight/lattigo/v5/core/rgsw/blindrot"
"github.com/tuneinsight/lattigo/v5/core/rlwe"
"github.com/tuneinsight/lattigo/v5/ring"
"github.com/tuneinsight/lattigo/v5/utils"
Expand Down Expand Up @@ -59,7 +59,7 @@ func main() {
slots := 32

// Test poly
testPoly := blind_rotation.InitTestPolynomial(sign, rlwe.NewScale(scaleBR), paramsBR.RingQ(), -1, 1)
testPoly := blindrot.InitTestPolynomial(sign, rlwe.NewScale(scaleBR), paramsBR.RingQ(), -1, 1)

// Index map of which test poly to evaluate on which slot
testPolyMap := make(map[int]*ring.Poly)
Expand Down Expand Up @@ -98,13 +98,13 @@ func main() {
}

// Evaluator for the Blind Rotations
eval := blind_rotation.NewEvaluator(paramsBR, paramsLWE)
eval := blindrot.NewEvaluator(paramsBR, paramsLWE)

// Secret of the RGSW ciphertexts encrypting the bits of skLWE
skBR := rlwe.NewKeyGenerator(paramsBR).GenSecretKeyNew()

// Collection of RGSW ciphertexts encrypting the bits of skLWE under skBR
blindeRotateKey := blind_rotation.GenEvaluationKeyNew(paramsBR, skBR, paramsLWE, skLWE, evkParams)
blindeRotateKey := blindrot.GenEvaluationKeyNew(paramsBR, skBR, paramsLWE, skLWE, evkParams)

// Evaluation of BlindRotate(ctLWE) = testPoly(X) * X^{dec{ctLWE}}
// Returns one RLWE sample per slot in ctLWE
Expand Down
4 changes: 3 additions & 1 deletion multiparty/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Multi-Party

The `multiparty` package implements several Multiparty Homomorphic Encryption (MHE) primitives based on Ring-Learning-with-Errors (RLWE).
It provides generic interfaces for the local steps of the MHE-based Secure Multiparty Computation (MHE-MPC) protocol that are common across all the RLWE distributed schemes implemented in Lattigo (e.g., collective key generation).
The `multiparty/mpbgv` and `multiparty/mpckks` packages import `multiparty` and provide scheme-specific functionalities (e.g., interactive bootstrapping).
The `multiparty/mpbgv` and `multiparty/mpckks` packages provide scheme-specific functionalities (e.g., interactive bootstrapping) by implementing **threshold** versions of the single-party BFV/BGV and CKKS cryptosystems
found in the `schemes` package.

This package implements local operations only, hence does not assume or provide any network-layer protocol implementation.
However, it provides serialization methods for all relevant structures that implement the standard `encoding.BinaryMarshaller` and `encoding.BinaryUnmarshaller` interfaces (see [https://pkg.go.dev/encoding](https://pkg.go.dev/encoding)) as well as the `io.WriterTo` and `io.ReaderFrom` interfaces (see [https://pkg.go.dev/encoding](https://pkg.go.dev/io)).
Expand Down
12 changes: 10 additions & 2 deletions schemes/bfv/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@

## Overview

The BFV package provides an RNS-accelerated implementation of the Fan-Vercauteren version of Brakerski's (BFV) scale-invariant homomorphic encryption schemes. It enables SIMD modular arithmetic over encrypted vectors or integers.
The BFV package is a placeholder for a RNS-accelerated implementation of the Fan-Vercauteren version of Brakerski's (BFV) scale-invariant homomorphic encryption schemes. It enables SIMD modular arithmetic over encrypted vectors or integers.

## Implementation Notes

The proposed implementation is built as a wrapper over the `bgv` package, which implements a unified variant of the BFV and BGV schemes. The only practical difference with the standard BFV is that the plaintext modulus must be coprime with the ciphertext modulus. This is both required for correctness ($T^{-1}\mod Q$ must be defined) and for security reasons (if $T|Q$ then the BGV scheme is not IND-CPA secure anymore). To instantiate the BFV cryptosystem, generate a new BGV evaluator by with the optional scale-invariant parameter set to `true`.

The implementation of BFV is part of the `bgv` package which implements a unified variant of the BFV and BGV schemes. The only practical difference with the standard BFV is that the plaintext modulus must be coprime with the ciphertext modulus. This is both required for correctness ($T^{-1}\mod Q$ must be defined) and for security reasons (if $T|Q$ then the BGV scheme is not IND-CPA secure anymore). To instantiate the BFV cryptosystem, generate a new BGV evaluator with the optional scale-invariant parameter set to `true`.
Under the hood, setting the scale-invariant flag replaces the following functions of the BGV evaluator object with their scale-invariant alternatives:

- `Evaluator.Mul`
- `Evaluator.MulNew`
- `Evaluator.MulRelin`
- `Evaluator.MulRelinNew`
- `Evaluator.Rescale`

For additional information, see the [`README.md`](../bgv/README.md) in the `bgv` package.

Expand Down
2 changes: 1 addition & 1 deletion schemes/bgv/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ func (ecd Encoder) EncodeRingT(values IntegerSlice, scale rlwe.Scale, pT ring.Po
return nil
}

// Embed is a generic method to encode an IntegerSlice on [ringqp.Poly] or *[ring.Poly].
// EmbedScale is a generic method to encode an IntegerSlice on [ringqp.Poly] or *[ring.Poly].
// If scaleUp is true, then the values will to be multiplied by PlaintextModulus^{-1} mod Q after being encoded on the polynomial.
// Encoding is done according to the metadata.
// Accepted polyOut.(type) are a ringqp.Poly and *ring.Poly
Expand Down
27 changes: 17 additions & 10 deletions schemes/bgv/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,8 @@ func (eval Evaluator) DropLevel(op0 *rlwe.Ciphertext, levels int) {
op0.Resize(op0.Degree(), op0.Level()-levels)
}

// Mul multiplies op0 with op1 without relinearization and using standard tensoring (BGV/CKKS-style), and returns the result in opOut.
// Mul multiplies op0 with op1 without relinearization using either standard tensoring (BGV/CKKS-style) when [Evaluator.ScaleInvariant]
// is set to false or scale-invariant tensoring (BFV-style) otherwise, i.e., [Evaluator.MulScaleInvariant], and returns the result in opOut.
// This tensoring increases the noise by a multiplicative factor of the plaintext and noise norms of the operands and will usually
// require to be followed by a rescaling operation to avoid an exponential growth of the noise from subsequent multiplications.
// The procedure will return an error if either op0 or op1 are have a degree higher than 1.
Expand Down Expand Up @@ -541,10 +542,12 @@ func (eval Evaluator) Mul(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rlwe.Ci
return
}

// MulNew multiplies op0 with op1 without relinearization and using standard tensoring (BGV/CKKS-style), and returns the result in a new *[rlwe.Ciphertext] opOut.
// This tensoring increases the noise by a multiplicative factor of the plaintext and noise norms of the operands and will usually
// require to be followed by a rescaling operation to avoid an exponential growth of the noise from subsequent multiplications.
// The procedure will return an error if either op0 or op1 are have a degree higher than 1.
// MulNew multiplies op0 with op1 without relinearization using standard tensoring (BGV/CKKS-style) when [Evaluator.ScaleInvariant]
// is set to false or scale-invariant tensoring (BFV-style) otherwise, i.e., [Evaluator.MulScaleInvariantNew], and returns
// the result in a new *[rlwe.Ciphertext] opOut. This tensoring increases the noise by a multiplicative factor of the plaintext
// and noise norms of the operands and will usually require to be followed by a rescaling operation to avoid an exponential
// growth of the noise from subsequent multiplications. The procedure will return an error if either op0 or op1 are have a
// degree higher than 1.
//
// inputs:
// - op0: an *[rlwe.Ciphertext]
Expand Down Expand Up @@ -576,8 +579,9 @@ func (eval Evaluator) MulNew(op0 *rlwe.Ciphertext, op1 rlwe.Operand) (opOut *rlw
return opOut, eval.Mul(op0, op1, opOut)
}

// MulRelin multiplies op0 with op1 with relinearization and using standard tensoring (BGV/CKKS-style), and returns the result in opOut.
// This tensoring increases the noise by a multiplicative factor of the plaintext and noise norms of the operands and will usually
// MulRelin multiplies op0 with op1 with relinearization using standard tensoring (BGV/CKKS-style) when [Evaluator.ScaleInvariant]
// is set to false or scale-invariant tensoring (BFV-style) otherwise, i.e., [Evaluator.MulRelinScaleInvariant], and returns the result in
// opOut. This tensoring increases the noise by a multiplicative factor of the plaintext and noise norms of the operands and will usually
// require to be followed by a rescaling operation to avoid an exponential growth of the noise from subsequent multiplications.
// The procedure will return an error if either op0.Degree or op1.Degree > 1.
// The procedure will return an error if opOut.Degree != op0.Degree + op1.Degree.
Expand Down Expand Up @@ -623,9 +627,11 @@ func (eval Evaluator) MulRelin(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rl
return
}

// MulRelinNew multiplies op0 with op1 with relinearization and and using standard tensoring (BGV/CKKS-style), returns the result in a new *[rlwe.Ciphertext] opOut.
// This tensoring increases the noise by a multiplicative factor of the plaintext and noise norms of the operands and will usually
// require to be followed by a rescaling operation to avoid an exponential growth of the noise from subsequent multiplications.
// MulRelinNew multiplies op0 with op1 with relinearization using standard tensoring (BGV/CKKS-style) when [Evaluator.ScaleInvariant]
// is set to false or scale-invariant tensoring (BFV-style) otherwise, i.e., [Evaluator.MulRelinScaleInvariantNew], and returns the result
// in a new *[rlwe.Ciphertext] opOut. This tensoring increases the noise by a multiplicative factor of the plaintext and noise norms
// of the operands and will usually require to be followed by a rescaling operation to avoid an exponential growth of the noise from
// subsequent multiplications.
// The procedure will return an error if either op0.Degree or op1.Degree > 1.
// The procedure will return an error if the evaluator was not created with an relinearization key.
//
Expand Down Expand Up @@ -1404,6 +1410,7 @@ func (eval Evaluator) mulRelinThenAdd(op0 *rlwe.Ciphertext, op1 *rlwe.Element[ri
//
// The scale of opOut will be updated to op0.Scale * qi^{-1} mod PlaintextModulus where qi is the prime consumed by
// the rescaling operation.
// Note that if the evaluator has been instantiated as scale-invariant (BFV-style), then Rescale is a nop.
func (eval Evaluator) Rescale(op0, opOut *rlwe.Ciphertext) (err error) {

if eval.ScaleInvariant {
Expand Down
1 change: 1 addition & 0 deletions schemes/schemes.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package schemes contains the implemented cryptosystems.
package schemes

import "github.com/tuneinsight/lattigo/v5/core/rlwe"
Expand Down
7 changes: 7 additions & 0 deletions utils/cosine/cosine_approx.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// Package cosine method is the Go implementation of the polynomial-approximation algorithm by Han and Ki in
//
// "Better Bootstrapping for Approximate Homomorphic Encryption", <https://epring.iacr.org/2019/688O>.
//
// The algorithm was originally implemented in C++, available at
//
// https://github.com/DohyeongKi/better-homomorphic-sine-evaluation
package cosine

import (
Expand Down

0 comments on commit 7813ec5

Please sign in to comment.