Skip to content

Commit 1487afa

Browse files
committed
collapse bfv
1 parent e2e3721 commit 1487afa

16 files changed

+300
-1202
lines changed

circuits/bgv/lintrans/lintrans_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func TestLinearTransformation(t *testing.T) {
3434
for _, plaintextModulus := range testPlaintextModulus[:] {
3535
p.PlaintextModulus = plaintextModulus
3636

37-
tc := bgv.NewTestContext(p)
37+
tc := bgv.NewTestContext(p, false)
3838

3939
for _, testSet := range []func(tc *bgv.TestContext, t *testing.T){
4040
run,

circuits/bgv/polynomial/polynomial_evaluator.go

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55

66
"github.com/tuneinsight/lattigo/v5/circuits/common/polynomial"
77
"github.com/tuneinsight/lattigo/v5/core/rlwe"
8-
"github.com/tuneinsight/lattigo/v5/schemes"
9-
"github.com/tuneinsight/lattigo/v5/schemes/bfv"
108
"github.com/tuneinsight/lattigo/v5/schemes/bgv"
119
)
1210

@@ -16,38 +14,16 @@ type Evaluator struct {
1614
InvariantTensoring bool
1715
}
1816

19-
// NewEvaluator instantiates a new PolynomialEvaluator from a [schemes.Evaluator].
20-
// The default [bgv.Evaluator] is compliant to the [schemes.Evaluator] interface.
21-
// InvariantTensoring is a boolean that specifies if the evaluator performed the invariant tensoring (BFV-style) or
22-
// the regular tensoring (BGV-style).
23-
func NewEvaluator(params bgv.Parameters, eval schemes.Evaluator, InvariantTensoring bool) *Evaluator {
24-
25-
var evalForPoly schemes.Evaluator
26-
27-
switch eval := eval.(type) {
28-
case *bgv.Evaluator:
29-
if InvariantTensoring {
30-
evalForPoly = scaleInvariantEvaluator{eval}
31-
} else {
32-
evalForPoly = eval
33-
}
34-
case *bfv.Evaluator:
35-
if InvariantTensoring {
36-
evalForPoly = eval
37-
} else {
38-
evalForPoly = eval.Evaluator
39-
}
40-
default:
41-
evalForPoly = eval
42-
}
17+
// NewEvaluator instantiates a new PolynomialEvaluator from a [bgv.Evaluator].
18+
func NewEvaluator(params bgv.Parameters, eval *bgv.Evaluator) *Evaluator {
4319

4420
return &Evaluator{
4521
Parameters: params,
4622
Evaluator: polynomial.Evaluator[uint64]{
47-
Evaluator: evalForPoly,
23+
Evaluator: eval,
4824
CoefficientGetter: CoefficientGetter{values: make([]uint64, params.MaxSlots())},
4925
},
50-
InvariantTensoring: InvariantTensoring,
26+
InvariantTensoring: eval.ScaleInvariant,
5127
}
5228
}
5329

circuits/bgv/polynomial/polynomial_evaluator_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func TestPolynomialEvaluator(t *testing.T) {
3333
for _, plaintextModulus := range testPlaintextModulus[:] {
3434
p.PlaintextModulus = plaintextModulus
3535

36-
tc := bgv.NewTestContext(p)
36+
tc := bgv.NewTestContext(p, false)
3737

3838
for _, testSet := range []func(tc *bgv.TestContext, t *testing.T){
3939
run,
@@ -65,7 +65,7 @@ func run(tc *bgv.TestContext, t *testing.T) {
6565

6666
t.Run("Standard"+tc.String(), func(t *testing.T) {
6767

68-
polyEval := NewEvaluator(tc.Params, tc.Evl, false)
68+
polyEval := NewEvaluator(tc.Params, tc.Evl)
6969

7070
res, err := polyEval.Evaluate(ciphertext, poly, tc.Params.DefaultScale())
7171
require.NoError(t, err)
@@ -76,8 +76,9 @@ func run(tc *bgv.TestContext, t *testing.T) {
7676
})
7777

7878
t.Run("Invariant"+tc.String(), func(t *testing.T) {
79+
tc.Evl.ScaleInvariant = true
7980

80-
polyEval := NewEvaluator(tc.Params, tc.Evl, true)
81+
polyEval := NewEvaluator(tc.Params, tc.Evl)
8182

8283
res, err := polyEval.Evaluate(ciphertext, poly, tc.Params.DefaultScale())
8384
require.NoError(t, err)

circuits/ckks/polynomial/polynomial_evaluator.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55

66
"github.com/tuneinsight/lattigo/v5/circuits/common/polynomial"
77
"github.com/tuneinsight/lattigo/v5/core/rlwe"
8-
"github.com/tuneinsight/lattigo/v5/schemes"
98
"github.com/tuneinsight/lattigo/v5/schemes/ckks"
109
"github.com/tuneinsight/lattigo/v5/utils/bignum"
1110
)
@@ -19,7 +18,7 @@ type Evaluator struct {
1918

2019
// NewEvaluator instantiates a new [Evaluator] from a [ckks.Evaluator].
2120
// This method is allocation free.
22-
func NewEvaluator(params ckks.Parameters, eval schemes.Evaluator) *Evaluator {
21+
func NewEvaluator(params ckks.Parameters, eval *ckks.Evaluator) *Evaluator {
2322
return &Evaluator{
2423
Parameters: params,
2524
Evaluator: polynomial.Evaluator[*bignum.Complex]{

lattigo-hierarchy.svg

Lines changed: 2 additions & 1 deletion
Loading

schemes/bfv/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The BFV package provides an RNS-accelerated implementation of the Fan-Vercautere
66

77
## Implementation Notes
88

9-
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).
9+
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`.
1010

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

schemes/bfv/bfv.go

Lines changed: 2 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -1,180 +1,4 @@
11
// Package bfv provides an RNS-accelerated implementation of the Fan-Vercauteren version of Brakerski's (BFV) scale-invariant homomorphic encryption scheme.
2-
// The BFV scheme enables SIMD modular arithmetic over encrypted vectors or integers.
2+
// The BFV scheme enables SIMD modular arithmetic over encrypted vectors or integers. See `README.md` for more information
3+
// on how to instantiate a BFV evaluator.
34
package bfv
4-
5-
import (
6-
"fmt"
7-
8-
"github.com/tuneinsight/lattigo/v5/core/rlwe"
9-
"github.com/tuneinsight/lattigo/v5/ring"
10-
"github.com/tuneinsight/lattigo/v5/schemes/bgv"
11-
)
12-
13-
// NewPlaintext allocates a new [rlwe.Plaintext] from the BFV parameters, at the
14-
// specified level. If the level argument is not provided, the plaintext is
15-
// initialized at level params.MaxLevelQ().
16-
//
17-
// The plaintext is initialized with its metadata so that it can be passed to a,
18-
// [bfv.Encoder]. Before doing so, the user can update the MetaData field to set
19-
// a specific scaling factor,
20-
// plaintext dimensions (if applicable) or encoding domain.
21-
func NewPlaintext(params Parameters, level ...int) (pt *rlwe.Plaintext) {
22-
pt = rlwe.NewPlaintext(params, level...)
23-
pt.IsBatched = true
24-
pt.Scale = params.DefaultScale()
25-
pt.LogDimensions = params.LogMaxDimensions()
26-
return
27-
}
28-
29-
// NewCiphertext allocates a new [rlwe.Ciphertext] from the BFV parameters,
30-
// at the specified level and ciphertext degree. If the level argument is not
31-
// provided, the ciphertext is initialized at level params.MaxLevelQ().
32-
//
33-
// To create a ciphertext for encrypting a new message, the ciphertext should be
34-
// at degree 1.
35-
func NewCiphertext(params Parameters, degree int, level ...int) (ct *rlwe.Ciphertext) {
36-
ct = rlwe.NewCiphertext(params, degree, level...)
37-
ct.IsBatched = true
38-
ct.Scale = params.DefaultScale()
39-
ct.LogDimensions = params.LogMaxDimensions()
40-
return
41-
}
42-
43-
// NewEncryptor instantiates a new [rlwe.Encryptor] from the given BFV parameters and
44-
// encryption key. This key can be either a *[rlwe.SecretKey] or a *[rlwe.PublicKey].
45-
func NewEncryptor(params Parameters, key rlwe.EncryptionKey) *rlwe.Encryptor {
46-
return rlwe.NewEncryptor(params, key)
47-
}
48-
49-
// NewDecryptor instantiates a new [rlwe.Decryptor] from the given BFV parameters and
50-
// secret decryption key.
51-
func NewDecryptor(params Parameters, key *rlwe.SecretKey) *rlwe.Decryptor {
52-
return rlwe.NewDecryptor(params, key)
53-
}
54-
55-
// NewKeyGenerator instantiates a new [rlwe.KeyGenerator] from the given
56-
// BFV parameters.
57-
func NewKeyGenerator(params Parameters) *rlwe.KeyGenerator {
58-
return rlwe.NewKeyGenerator(params)
59-
}
60-
61-
// Encoder is a structure that stores the parameters to encode values on a plaintext in a SIMD (Single-Instruction Multiple-Data) fashion.
62-
type Encoder struct {
63-
*bgv.Encoder
64-
}
65-
66-
// NewEncoder creates a new [Encoder] from the provided parameters.
67-
func NewEncoder(params Parameters) *Encoder {
68-
return &Encoder{bgv.NewEncoder(params.Parameters)}
69-
}
70-
71-
// ShallowCopy creates a shallow copy of this [Encoder] in which the read-only data-structures are
72-
// shared with the receiver.
73-
func (e Encoder) ShallowCopy() *Encoder {
74-
return &Encoder{Encoder: e.Encoder.ShallowCopy()}
75-
}
76-
77-
// Evaluator is a struct that holds the necessary elements to perform the homomorphic operations between ciphertexts and/or plaintexts.
78-
// It also holds a memory buffer used to store intermediate computations.
79-
type Evaluator struct {
80-
*bgv.Evaluator
81-
}
82-
83-
// NewEvaluator creates a new [Evaluator], that can be used to do homomorphic
84-
// operations on ciphertexts and/or plaintexts. It stores a memory buffer
85-
// and ciphertexts that will be used for intermediate values.
86-
func NewEvaluator(params Parameters, evk rlwe.EvaluationKeySet) *Evaluator {
87-
return &Evaluator{bgv.NewEvaluator(params.Parameters, evk)}
88-
}
89-
90-
// WithKey creates a shallow copy of this [Evaluator] in which the read-only data-structures are
91-
// shared with the receiver but for which the evaluation key is set to the provided [rlwe.EvaluationKeySet].
92-
func (eval Evaluator) WithKey(evk rlwe.EvaluationKeySet) *Evaluator {
93-
return &Evaluator{eval.Evaluator.WithKey(evk)}
94-
}
95-
96-
// ShallowCopy creates a shallow copy of this [Evaluator] in which the read-only data-structures are
97-
// shared with the receiver.
98-
func (eval Evaluator) ShallowCopy() *Evaluator {
99-
return &Evaluator{eval.Evaluator.ShallowCopy()}
100-
}
101-
102-
// Mul multiplies op0 with op1 without relinearization and returns the result in opOut.
103-
// inputs:
104-
// - op0: an *[rlwe.Ciphertext]
105-
// - op1:
106-
// - [rlwe.ElementInterface][ring.Poly]
107-
// - *big.Int, uint64, int64, int
108-
// - []uint64 or []int64 (of size at most N where N is the smallest integer satisfying PlaintextModulus = 1 mod 2N)
109-
// - opOut: an *[rlwe.Ciphertext]
110-
//
111-
// The procedure will return an error if either op0 or op1 are have a degree higher than 1.
112-
// The procedure will return an error if opOut.Degree != op0.Degree + op1.Degree.
113-
func (eval Evaluator) Mul(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rlwe.Ciphertext) (err error) {
114-
switch op1 := op1.(type) {
115-
case rlwe.ElementInterface[ring.Poly], []uint64:
116-
return eval.Evaluator.MulScaleInvariant(op0, op1, opOut)
117-
case uint64, int64, int:
118-
return eval.Evaluator.Mul(op0, op1, op0)
119-
default:
120-
return fmt.Errorf("invalid op1.(Type), expected rlwe.ElementInterface[ring.Poly], []uint64 or uint64, int64, int, but got %T", op1)
121-
}
122-
123-
}
124-
125-
// MulNew multiplies op0 with op1 without relinearization and returns the result in a new opOut.
126-
// inputs:
127-
// - op0: an *[rlwe.Ciphertext]
128-
// - op1:
129-
// - [rlwe.ElementInterface][[ring.Poly]]
130-
// - *big.Int, uint64, int64, int
131-
// - []uint64 or []int64 (of size at most N where N is the smallest integer satisfying PlaintextModulus = 1 mod 2N)
132-
// - opOut: an *[rlwe.Ciphertext]
133-
//
134-
// The procedure will return an error if either op0.Degree or op1.Degree > 1.
135-
func (eval Evaluator) MulNew(op0 *rlwe.Ciphertext, op1 rlwe.Operand) (opOut *rlwe.Ciphertext, err error) {
136-
switch op1 := op1.(type) {
137-
case rlwe.ElementInterface[ring.Poly], []uint64:
138-
return eval.Evaluator.MulScaleInvariantNew(op0, op1)
139-
case uint64, int64, int:
140-
return eval.Evaluator.MulNew(op0, op1)
141-
default:
142-
return nil, fmt.Errorf("invalid op1.(Type), expected rlwe.ElementInterface[ring.Poly], []uint64 or uint64, int64, int, but got %T", op1)
143-
}
144-
}
145-
146-
// MulRelinNew multiplies op0 with op1 with relinearization and returns the result in a new opOut.
147-
// inputs:
148-
// - op0: an *[rlwe.Ciphertext]
149-
// - op1:
150-
// - [rlwe.ElementInterface][[ring.Poly]]
151-
// - *big.Int, uint64, int64, int
152-
// - []uint64 or []int64 (of size at most N where N is the smallest integer satisfying PlaintextModulus = 1 mod 2N)
153-
// - opOut: an *[rlwe.Ciphertext]
154-
//
155-
// The procedure will return an error if either op0.Degree or op1.Degree > 1.
156-
// The procedure will return an error if the evaluator was not created with an relinearization key.
157-
func (eval Evaluator) MulRelinNew(op0 *rlwe.Ciphertext, op1 rlwe.Operand) (opOut *rlwe.Ciphertext, err error) {
158-
return eval.Evaluator.MulRelinScaleInvariantNew(op0, op1)
159-
}
160-
161-
// MulRelin multiplies op0 with op1 with relinearization and returns the result in opOut.
162-
// inputs:
163-
// - op0: an *[rlwe.Ciphertext]
164-
// - op1:
165-
// - [rlwe.ElementInterface][[ring.Poly]]
166-
// - *big.Int, uint64, int64, int
167-
// - []uint64 or []int64 (of size at most N where N is the smallest integer satisfying PlaintextModulus = 1 mod 2N)
168-
// - opOut: an *[rlwe.Ciphertext]
169-
//
170-
// The procedure will return an error if either op0.Degree or op1.Degree > 1.
171-
// The procedure will return an error if opOut.Degree != op0.Degree + op1.Degree.
172-
// The procedure will return an error if the evaluator was not created with an relinearization key.
173-
func (eval Evaluator) MulRelin(op0 *rlwe.Ciphertext, op1 rlwe.Operand, opOut *rlwe.Ciphertext) (err error) {
174-
return eval.Evaluator.MulRelinScaleInvariant(op0, op1, opOut)
175-
}
176-
177-
// Rescale does nothing when instantiated with the BFV scheme.
178-
func (eval Evaluator) Rescale(op0, op1 *rlwe.Ciphertext) (err error) {
179-
return nil
180-
}

0 commit comments

Comments
 (0)