|
1 | 1 | // 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. |
3 | 4 | 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