1 // Copyright (c) Microsoft Corporation. All rights reserved. 2 // Licensed under the MIT license. 3 4 using Microsoft.Research.SEAL.Tools; 5 using System; 6 using System.Collections.Generic; 7 using System.Linq; 8 using System.Runtime.InteropServices; 9 10 namespace Microsoft.Research.SEAL 11 { 12 /// <summary> 13 /// Provides operations on ciphertexts. 14 /// </summary> 15 /// 16 /// <remarks> 17 /// <para> 18 /// Provides operations on ciphertexts. Due to the properties of the encryption scheme, the arithmetic operations 19 /// pass through the encryption layer to the underlying plaintext, changing it according to the type of the 20 /// operation. Since the plaintext elements are fundamentally polynomials in the polynomial quotient ring 21 /// Z_T[x]/(X^N+1), where T is the plaintext modulus and X^N+1 is the polynomial modulus, this is the ring where 22 /// the arithmetic operations will take place. BatchEncoder (batching) provider an alternative possibly more 23 /// convenient view of the plaintext elements as 2-by-(N2/2) matrices of integers modulo the plaintext modulus. In 24 /// the batching view the arithmetic operations act on the matrices element-wise. Some of the operations only apply 25 /// in the batching view, such as matrix row and column rotations. Other operations such as relinearization have no 26 /// semantic meaning but are necessary for performance reasons. 27 /// </para> 28 /// <para> 29 /// Arithmetic Operations 30 /// The core operations are arithmetic operations, in particular multiplication and addition of ciphertexts. In 31 /// addition to these, we also provide negation, subtraction, squaring, exponentiation, and multiplication and 32 /// addition of several ciphertexts for convenience. in many cases some of the inputs to a computation are plaintext 33 /// elements rather than ciphertexts. For this we provide fast "plain" operations: plain addition, plain 34 /// subtraction, and plain multiplication. 35 /// </para> 36 /// <para> 37 /// Relinearization 38 /// One of the most important non-arithmetic operations is relinearization, which takes as input a ciphertext of 39 /// size K+1 and relinearization keys (at least K-1 keys are needed), and changes the size of the ciphertext down 40 /// to 2 (minimum size). For most use-cases only one relinearization key suffices, in which case relinearization 41 /// should be performed after every multiplication. Homomorphic multiplication of ciphertexts of size K+1 and L+1 42 /// outputs a ciphertext of size K+L+1, and the computational cost of multiplication is proportional to K*L. Plain 43 /// multiplication and addition operations of any type do not change the size. Relinearization requires 44 /// relinearization keys to have been generated. 45 /// </para> 46 /// <para> 47 /// Rotations 48 /// When batching is enabled, we provide operations for rotating the plaintext matrix rows cyclically left or right, 49 /// and for rotating the columns (swapping the rows). Rotations require Galois keys to have been generated. 50 /// </para> 51 /// <para> 52 /// Other Operations 53 /// We also provide operations for transforming ciphertexts to NTT form and back, and for transforming plaintext 54 /// polynomials to NTT form. These can be used in a very fast plain multiplication variant, that assumes the inputs 55 /// to be in NTT form. Since the NTT has to be done in any case in plain multiplication, this function can be used 56 /// when e.g. one plaintext input is used in several plain multiplication, and transforming it several times would 57 /// not make sense. 58 /// </para> 59 /// <para> 60 /// NTT form 61 /// When using the BFV scheme (SchemeType.BFV), all plaintexts and ciphertexts should remain by default in the usual 62 /// coefficient representation, i.e., not in NTT form. When using the CKKS scheme (SchemeType.CKKS), all plaintexts 63 /// and ciphertexts should remain by default in NTT form. We call these scheme-specific NTT states the "default NTT 64 /// form". Some functions, such as add, work even if the inputs are not in the default state, but others, such as 65 /// multiply, will throw an exception. The output of all evaluation functions will be in the same state as the 66 /// input(s), with the exception of the TransformToNTT and TransformFromNTT functions, which change the state. 67 /// Ideally, unless these two functions are called, all other functions should "just work". 68 /// </para> 69 /// </remarks> 70 /// <see cref="EncryptionParameters"/> for more details on encryption parameters. 71 /// <see cref="BatchEncoder"/> for more details on batching 72 /// <see cref="RelinKeys"/> for more details on relinearization keys. 73 /// <see cref="GaloisKeys"/> for more details on Galois keys. 74 public class Evaluator : NativeObject 75 { 76 /// <summary> 77 /// Creates an Evaluator instance initialized with the specified SEALContext. 78 /// </summary> 79 /// <param name="context">The SEALContext</param> 80 /// <exception cref="ArgumentNullException">if context is null</exception> 81 /// <exception cref="ArgumentException">if the encryption parameters are not valid</exception> Evaluator(SEALContext context)82 public Evaluator(SEALContext context) 83 { 84 if (null == context) 85 throw new ArgumentNullException(nameof(context)); 86 if (!context.ParametersSet) 87 throw new ArgumentException("Encryption parameters are not set correctly"); 88 89 NativeMethods.Evaluator_Create(context.NativePtr, out IntPtr ptr); 90 NativePtr = ptr; 91 } 92 93 /// <summary> 94 /// Negates a ciphertext. 95 /// </summary> 96 /// <param name="encrypted">The ciphertext to negate</param> 97 /// <exception cref="ArgumentNullException">if encrypted is null</exception> 98 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 99 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> NegateInplace(Ciphertext encrypted)100 public void NegateInplace(Ciphertext encrypted) 101 { 102 Negate(encrypted, destination: encrypted); 103 } 104 105 /// <summary> 106 /// Negates a ciphertext and stores the result in the destination parameter. 107 /// </summary> 108 /// <param name="encrypted">The ciphertext to negate</param> 109 /// <param name="destination">The ciphertext to overwrite with the negated result</param> 110 /// <exception cref="ArgumentNullException">if encrypted or destination is null</exception> 111 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 112 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> Negate(Ciphertext encrypted, Ciphertext destination)113 public void Negate(Ciphertext encrypted, Ciphertext destination) 114 { 115 if (null == encrypted) 116 throw new ArgumentNullException(nameof(encrypted)); 117 if (null == destination) 118 throw new ArgumentNullException(nameof(destination)); 119 120 NativeMethods.Evaluator_Negate(NativePtr, encrypted.NativePtr, destination.NativePtr); 121 } 122 123 /// <summary> 124 /// Adds two ciphertexts. 125 /// </summary> 126 /// <remarks> 127 /// This function adds together encrypted1 and encrypted2 and stores the result in encrypted1. 128 /// </remarks> 129 /// <param name="encrypted1">The first ciphertext to add</param> 130 /// <param name="encrypted2">The second ciphertext to add</param> 131 /// <exception cref="ArgumentNullException">if encrypted1 or encrypted2 is null</exception> 132 /// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for the encryption 133 /// parameters</exception> 134 /// <exception cref="ArgumentException">if encrypted1 and encrypted2 are in different NTT forms</exception> 135 /// <exception cref="ArgumentException">if encrypted1 and encrypted2 are at different level or scale</exception> 136 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> AddInplace(Ciphertext encrypted1, Ciphertext encrypted2)137 public void AddInplace(Ciphertext encrypted1, Ciphertext encrypted2) 138 { 139 Add(encrypted1, encrypted2, destination: encrypted1); 140 } 141 142 /// <summary> 143 /// Adds two ciphertexts. 144 /// </summary> 145 /// <remarks> 146 /// This function adds together encrypted1 and encrypted2 and stores the result in the destination parameter. 147 /// </remarks> 148 /// <param name="encrypted1">The first ciphertext to add</param> 149 /// <param name="encrypted2">The second ciphertext to add</param> 150 /// <param name="destination">The ciphertext to overwrite with the addition result</param> 151 /// <exception cref="ArgumentNullException">if encrypted1, encrypted2, or destination is null</exception> 152 /// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for the encryption 153 /// parameters</exception> 154 /// <exception cref="ArgumentException">if encrypted1 and encrypted2 are in different NTT forms</exception> 155 /// <exception cref="ArgumentException">if encrypted1 and encrypted2 are at different level or scale</exception> 156 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> Add(Ciphertext encrypted1, Ciphertext encrypted2, Ciphertext destination)157 public void Add(Ciphertext encrypted1, Ciphertext encrypted2, Ciphertext destination) 158 { 159 if (null == encrypted1) 160 throw new ArgumentNullException(nameof(encrypted1)); 161 if (null == encrypted2) 162 throw new ArgumentNullException(nameof(encrypted2)); 163 if (null == destination) 164 throw new ArgumentNullException(nameof(destination)); 165 166 NativeMethods.Evaluator_Add(NativePtr, encrypted1.NativePtr, encrypted2.NativePtr, destination.NativePtr); 167 } 168 169 /// <summary> 170 /// Adds together a vector of ciphertexts and stores the result in the destination parameter. 171 /// </summary> 172 /// <param name="encrypteds">The ciphertexts to add</param> 173 /// <param name="destination">The ciphertext to overwrite with the addition result</param> 174 /// <exception cref="ArgumentNullException">if encrypteds or destination is null</exception> 175 /// <exception cref="ArgumentException">if encrypteds is empty</exception> 176 /// <exception cref="ArgumentException">if encrypteds are not valid for the encryption parameters</exception> 177 /// <exception cref="ArgumentException">if encrypteds are in different NTT forms</exception> 178 /// <exception cref="ArgumentException">if encrypteds are at different level or scale</exception> 179 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> AddMany(IEnumerable<Ciphertext> encrypteds, Ciphertext destination)180 public void AddMany(IEnumerable<Ciphertext> encrypteds, Ciphertext destination) 181 { 182 if (null == encrypteds) 183 throw new ArgumentNullException(nameof(encrypteds)); 184 if (null == destination) 185 throw new ArgumentNullException(nameof(destination)); 186 187 IntPtr[] encarray = encrypteds.Select(c => c.NativePtr).ToArray(); 188 NativeMethods.Evaluator_AddMany(NativePtr, (ulong)encarray.Length, encarray, destination.NativePtr); 189 } 190 191 /// <summary> 192 /// Subtracts two ciphertexts. 193 /// </summary> 194 /// <remarks> 195 /// This function computes the difference of encrypted1 and encrypted2, and stores the result in encrypted1. 196 /// </remarks> 197 /// <param name="encrypted1">The ciphertext to subtract from</param> 198 /// <param name="encrypted2">The ciphertext to subtract</param> 199 /// <exception cref="ArgumentNullException">if encrypted1 or encrypted2 is null</exception> 200 /// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for the encryption 201 /// parameters</exception> 202 /// <exception cref="ArgumentException">if encrypted1 and encrypted2 are in different NTT forms</exception> 203 /// <exception cref="ArgumentException">if encrypted1 and encrypted2 are at different level or scale</exception> 204 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> SubInplace(Ciphertext encrypted1, Ciphertext encrypted2)205 public void SubInplace(Ciphertext encrypted1, Ciphertext encrypted2) 206 { 207 Sub(encrypted1, encrypted2, destination: encrypted1); 208 } 209 210 /// <summary> 211 /// Subtracts two ciphertexts. 212 /// </summary> 213 /// <remarks>This function computes the difference of encrypted1 and encrypted2 and stores the result in the 214 /// destination parameter. 215 /// </remarks> 216 /// <param name="encrypted1">The ciphertext to subtract from</param> 217 /// <param name="encrypted2">The ciphertext to subtract</param> 218 /// <param name="destination">The ciphertext to overwrite with the subtraction result</param> 219 /// <exception cref="ArgumentNullException">if encrypted1, encrypted2, or destination is null</exception> 220 /// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for the encryption 221 /// parameters</exception> 222 /// <exception cref="ArgumentException">if encrypted1 and encrypted2 are in different NTT forms</exception> 223 /// <exception cref="ArgumentException">if encrypted1 and encrypted2 are at different level or scale</exception> 224 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> Sub(Ciphertext encrypted1, Ciphertext encrypted2, Ciphertext destination)225 public void Sub(Ciphertext encrypted1, Ciphertext encrypted2, Ciphertext destination) 226 { 227 if (null == encrypted1) 228 throw new ArgumentNullException(nameof(encrypted1)); 229 if (null == encrypted2) 230 throw new ArgumentNullException(nameof(encrypted2)); 231 if (null == destination) 232 throw new ArgumentNullException(nameof(destination)); 233 234 NativeMethods.Evaluator_Sub(NativePtr, encrypted1.NativePtr, encrypted2.NativePtr, destination.NativePtr); 235 } 236 237 /// <summary> 238 /// Multiplies two ciphertexts. 239 /// </summary> 240 /// <remarks> 241 /// This functions computes the product of encrypted1 and encrypted2 and stores the result in encrypted1. 242 /// Dynamic memory allocations in the process are allocated from the memory pool pointed to by the given 243 /// MemoryPoolHandle. 244 /// </remarks> 245 /// <param name="encrypted1">The first ciphertext to multiply</param> 246 /// <param name="encrypted2">The second ciphertext to multiply</param> 247 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 248 /// <exception cref="ArgumentNullException">if encrypted1 or encrypted2 is null</exception> 249 /// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for the encryption 250 /// parameters</exception> 251 /// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not in the default NTT form</exception> 252 /// <exception cref="ArgumentException">if encrypted1 and encrypted2 are at different level</exception> 253 /// <exception cref="ArgumentException">if the output scale is too large for the encryption 254 /// parameters</exception> 255 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 256 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> MultiplyInplace(Ciphertext encrypted1, Ciphertext encrypted2, MemoryPoolHandle pool = null)257 public void MultiplyInplace(Ciphertext encrypted1, Ciphertext encrypted2, 258 MemoryPoolHandle pool = null) 259 { 260 Multiply(encrypted1, encrypted2, destination: encrypted1, pool: pool); 261 } 262 263 /// <summary> 264 /// Multiplies two ciphertexts. 265 /// </summary> 266 /// <remarks> 267 /// This functions computes the product of encrypted1 and encrypted2 and stores the result in the destination 268 /// parameter. Dynamic memory allocations in the process are allocated from the memory pool pointed to by the 269 /// given MemoryPoolHandle. 270 /// </remarks> 271 /// <param name="encrypted1">The first ciphertext to multiply</param> 272 /// <param name="encrypted2">The second ciphertext to multiply</param> 273 /// <param name="destination">The ciphertext to overwrite with the multiplication result</param> 274 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 275 /// <exception cref="ArgumentNullException">if encrypted1, encrypted2, destination is null</exception> 276 /// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not in the default NTT form</exception> 277 /// <exception cref="ArgumentException">if encrypted1 and encrypted2 are at different level</exception> 278 /// <exception cref="ArgumentException">if the output scale is too large for the encryption 279 /// parameters</exception> 280 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 281 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> Multiply(Ciphertext encrypted1, Ciphertext encrypted2, Ciphertext destination, MemoryPoolHandle pool = null)282 public void Multiply(Ciphertext encrypted1, Ciphertext encrypted2, 283 Ciphertext destination, MemoryPoolHandle pool = null) 284 { 285 if (null == encrypted1) 286 throw new ArgumentNullException(nameof(encrypted1)); 287 if (null == encrypted2) 288 throw new ArgumentNullException(nameof(encrypted2)); 289 if (null == destination) 290 throw new ArgumentNullException(nameof(destination)); 291 292 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 293 NativeMethods.Evaluator_Multiply(NativePtr, encrypted1.NativePtr, encrypted2.NativePtr, destination.NativePtr, poolPtr); 294 } 295 296 /// <summary> 297 /// Squares a ciphertext. 298 /// </summary> 299 /// <remarks> 300 /// This functions computes the square of encrypted. Dynamic memory allocations in the process are allocated 301 /// from the memory pool pointed to by the given MemoryPoolHandle. 302 /// </remarks> 303 /// <param name="encrypted">The ciphertext to square</param> 304 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 305 /// <exception cref="ArgumentNullException">if encrypted is null</exception> 306 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 307 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 308 /// <exception cref="ArgumentException">if the output scale is too large for the encryption 309 /// parameters</exception> 310 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 311 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> SquareInplace(Ciphertext encrypted, MemoryPoolHandle pool = null)312 public void SquareInplace(Ciphertext encrypted, MemoryPoolHandle pool = null) 313 { 314 Square(encrypted, destination: encrypted, pool: pool); 315 } 316 317 /// <summary> 318 /// Squares a ciphertext. 319 /// </summary> 320 /// <remarks> 321 /// This functions computes the square of encrypted and stores the result in the destination parameter. Dynamic 322 /// memory allocations in the process are allocated from the memory pool pointed to by the given 323 /// MemoryPoolHandle. 324 /// </remarks> 325 /// <param name="encrypted">The ciphertext to square</param> 326 /// <param name="destination">The ciphertext to overwrite with the square</param> 327 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 328 /// <exception cref="ArgumentNullException">if encrypted, destination is null</exception> 329 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 330 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 331 /// <exception cref="ArgumentException">if the output scale is too large for the encryption 332 /// parameters</exception> 333 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 334 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> Square(Ciphertext encrypted, Ciphertext destination, MemoryPoolHandle pool = null)335 public void Square(Ciphertext encrypted, Ciphertext destination, MemoryPoolHandle pool = null) 336 { 337 if (null == encrypted) 338 throw new ArgumentNullException(nameof(encrypted)); 339 if (null == destination) 340 throw new ArgumentNullException(nameof(destination)); 341 342 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 343 NativeMethods.Evaluator_Square(NativePtr, encrypted.NativePtr, destination.NativePtr, poolPtr); 344 } 345 346 /// <summary> 347 /// Relinearizes a ciphertext. 348 /// </summary> 349 /// <remarks> 350 /// This functions relinearizes encrypted, reducing its size down to 2. If the size of encrypted is K+1, the 351 /// given relinearization keys need to have size at least K-1. Dynamic memory allocations in the process are 352 /// allocated from the memory pool pointed to by the given MemoryPoolHandle. 353 /// </remarks> 354 /// <param name="encrypted">The ciphertext to relinearize</param> 355 /// <param name="relinKeys">The relinearization keys</param> 356 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 357 /// <exception cref="ArgumentNullException">if encrypted or relinKeys is null</exception> 358 /// <exception cref="ArgumentException">if encrypted or relinKeys is not valid for the encryption 359 /// parameters</exception> 360 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 361 /// <exception cref="ArgumentException">if relinKeys do not correspond to the top level parameters in the 362 /// current context</exception> 363 /// <exception cref="ArgumentException">if the size of relinKeys is too small</exception> 364 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 365 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 366 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RelinearizeInplace(Ciphertext encrypted, RelinKeys relinKeys, MemoryPoolHandle pool = null)367 public void RelinearizeInplace(Ciphertext encrypted, RelinKeys relinKeys, 368 MemoryPoolHandle pool = null) 369 { 370 Relinearize(encrypted, relinKeys, destination: encrypted, pool: pool); 371 } 372 373 /// <summary> 374 /// Relinearizes a ciphertext. 375 /// </summary> 376 /// <remarks> 377 /// This functions relinearizes encrypted, reducing its size down to 2, and stores the result in the destination 378 /// parameter. If the size of encrypted is K+1, the given relinearization keys need to have size at least K-1. 379 /// Dynamic memory allocations in the process are allocated from the memory pool pointed to by the given 380 /// MemoryPoolHandle. 381 /// </remarks> 382 /// <param name="encrypted">The ciphertext to relinearize</param> 383 /// <param name="relinKeys">The relinearization keys</param> 384 /// <param name="destination">The ciphertext to overwrite with the relinearized result</param> 385 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 386 /// <exception cref="ArgumentNullException">if encrypted, relinKeys, or destination is null</exception> 387 /// <exception cref="ArgumentException">if encrypted or relinKeys is not valid for the encryption 388 /// parameters</exception> 389 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 390 /// <exception cref="ArgumentException">if relinKeys do not correspond to the top level parameters in the 391 /// current context</exception> 392 /// <exception cref="ArgumentException">if the size of relinKeys is too small</exception> 393 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 394 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 395 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> Relinearize(Ciphertext encrypted, RelinKeys relinKeys, Ciphertext destination, MemoryPoolHandle pool = null)396 public void Relinearize(Ciphertext encrypted, RelinKeys relinKeys, 397 Ciphertext destination, MemoryPoolHandle pool = null) 398 { 399 if (null == encrypted) 400 throw new ArgumentNullException(nameof(encrypted)); 401 if (null == relinKeys) 402 throw new ArgumentNullException(nameof(relinKeys)); 403 if (null == destination) 404 throw new ArgumentNullException(nameof(destination)); 405 if (!ContextUsingKeyswitching) 406 throw new InvalidOperationException("Keyswitching is not supported by the context"); 407 408 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 409 NativeMethods.Evaluator_Relinearize( 410 NativePtr, encrypted.NativePtr, relinKeys.NativePtr, destination.NativePtr, poolPtr); 411 } 412 413 /// <summary> 414 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down to q_1...q_{k-1} and 415 /// stores the result in the destination parameter. 416 /// </summary> 417 /// <remarks> 418 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down to q_1...q_{k-1} and 419 /// stores the result in the destination parameter. Dynamic memory allocations in the process are allocated from 420 /// the memory pool pointed to by the given MemoryPoolHandle. 421 /// </remarks> 422 /// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param> 423 /// <param name="destination">The ciphertext to overwrite with the modulus switched result</param> 424 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 425 /// <exception cref="ArgumentNullException">if encrypted, or destination is null</exception> 426 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 427 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 428 /// <exception cref="ArgumentException">if encrypted is already at lowest level</exception> 429 /// <exception cref="ArgumentException">if the scale is too large for the new encryption parameters</exception> 430 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 431 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> ModSwitchToNext(Ciphertext encrypted, Ciphertext destination, MemoryPoolHandle pool = null)432 public void ModSwitchToNext(Ciphertext encrypted, Ciphertext destination, MemoryPoolHandle pool = null) 433 { 434 if (null == encrypted) 435 throw new ArgumentNullException(nameof(encrypted)); 436 if (null == destination) 437 throw new ArgumentNullException(nameof(destination)); 438 439 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 440 NativeMethods.Evaluator_ModSwitchToNext( 441 NativePtr, encrypted.NativePtr, destination.NativePtr, poolPtr); 442 } 443 444 /// <summary> 445 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down to q_1...q_{k-1}. 446 /// </summary> 447 /// <remarks> 448 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down to q_1...q_{k-1}. 449 /// Dynamic memory allocations in the process are allocated from the memory pool pointed to by the given 450 /// MemoryPoolHandle. 451 /// </remarks> 452 /// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param> 453 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 454 /// <exception cref="ArgumentNullException">if encrypted is null</exception> 455 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 456 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 457 /// <exception cref="ArgumentException">if encrypted is already at lowest level</exception> 458 /// <exception cref="ArgumentException">if the scale is too large for the new encryption parameters</exception> 459 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 460 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> ModSwitchToNextInplace(Ciphertext encrypted, MemoryPoolHandle pool = null)461 public void ModSwitchToNextInplace(Ciphertext encrypted, MemoryPoolHandle pool = null) 462 { 463 ModSwitchToNext(encrypted, destination: encrypted, pool: pool); 464 } 465 466 /// <summary> 467 /// Modulus switches an NTT transformed plaintext from modulo q_1...q_k down to modulo q_1...q_{k-1}. 468 /// </summary> 469 /// <param name="plain">The plaintext to be switched to a smaller modulus</param> 470 /// <exception cref="ArgumentNullException">if plain is null</exception> 471 /// <exception cref="ArgumentException">if plain is not in NTT form</exception> 472 /// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception> 473 /// <exception cref="ArgumentException">if plain is already at lowest level</exception> 474 /// <exception cref="ArgumentException">if the scale is too large for the new encryption parameters</exception> ModSwitchToNextInplace(Plaintext plain)475 public void ModSwitchToNextInplace(Plaintext plain) 476 { 477 ModSwitchToNext(plain, destination: plain); 478 } 479 480 /// <summary> 481 /// Modulus switches an NTT transformed plaintext from modulo q_1...q_k down to modulo q_1...q_{k-1} and stores 482 /// the result in the destination parameter. 483 /// </summary> 484 /// <param name="plain">The plaintext to be switched to a smaller modulus</param> 485 /// <param name="destination">destination The plaintext to overwrite with the modulus switched result</param> 486 /// <exception cref="ArgumentNullException">if plain, or destination is null</exception> 487 /// <exception cref="ArgumentException">if plain is not in NTT form</exception> 488 /// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception> 489 /// <exception cref="ArgumentException">if plain is already at lowest level</exception> 490 /// <exception cref="ArgumentException">if the scale is too large for the new encryption parameters</exception> 491 /// <exception cref="ArgumentException">if pool is uninitialized</exception> ModSwitchToNext(Plaintext plain, Plaintext destination)492 public void ModSwitchToNext(Plaintext plain, Plaintext destination) 493 { 494 if (null == plain) 495 throw new ArgumentNullException(nameof(plain)); 496 if (null == destination) 497 throw new ArgumentNullException(nameof(destination)); 498 499 NativeMethods.Evaluator_ModSwitchToNext(NativePtr, plain.NativePtr, destination.NativePtr); 500 } 501 502 /// <summary> 503 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down until the parameters 504 /// reach the given ParmsId. 505 /// </summary> 506 /// <remarks> 507 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down until the parameters 508 /// reach the given ParmsId. Dynamic memory allocations in the process are allocated from the memory pool 509 /// pointed to by the given MemoryPoolHandle. 510 /// </remarks> 511 /// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param> 512 /// <param name="parmsId">The target parmsId</param> 513 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 514 /// <exception cref="ArgumentNullException">if encrypted or parmsId is null</exception> 515 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 516 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 517 /// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception> 518 /// <exception cref="ArgumentException">if encrypted is already at lower level in modulus chain than the 519 /// parameters corresponding to parmsId</exception> 520 /// <exception cref="ArgumentException">if the scale is too large for the new encryption parameters</exception> 521 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 522 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> ModSwitchToInplace(Ciphertext encrypted, ParmsId parmsId, MemoryPoolHandle pool = null)523 public void ModSwitchToInplace(Ciphertext encrypted, ParmsId parmsId, MemoryPoolHandle pool = null) 524 { 525 ModSwitchTo(encrypted, parmsId, destination: encrypted, pool: pool); 526 } 527 528 /// <summary> 529 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down until the parameters 530 /// reach the given ParmsId and stores the result in the destination parameter. 531 /// </summary> 532 /// <remarks> 533 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down until the parameters 534 /// reach the given ParmsId and stores the result in the destination parameter. Dynamic memory allocations in 535 /// the process are allocated from the memory pool pointed to by the given MemoryPoolHandle. 536 /// </remarks> 537 /// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param> 538 /// <param name="parmsId">The target parmsId</param> 539 /// <param name="destination">The ciphertext to overwrite with the modulus switched result</param> 540 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 541 /// <exception cref="ArgumentNullException">if encrypted, parmsId, or destination is null</exception> 542 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 543 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 544 /// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception> 545 /// <exception cref="ArgumentException">if encrypted is already at lower level in modulus chain than the 546 /// parameters corresponding to parmsId</exception> 547 /// <exception cref="ArgumentException">if the scale is too large for the new encryption parameters</exception> 548 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 549 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> ModSwitchTo(Ciphertext encrypted, ParmsId parmsId, Ciphertext destination, MemoryPoolHandle pool = null)550 public void ModSwitchTo(Ciphertext encrypted, ParmsId parmsId, Ciphertext destination, MemoryPoolHandle pool = null) 551 { 552 if (null == encrypted) 553 throw new ArgumentNullException(nameof(encrypted)); 554 if (null == parmsId) 555 throw new ArgumentNullException(nameof(parmsId)); 556 if (null == destination) 557 throw new ArgumentNullException(nameof(destination)); 558 559 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 560 NativeMethods.Evaluator_ModSwitchTo( 561 NativePtr, encrypted.NativePtr, parmsId.Block, destination.NativePtr, poolPtr); 562 } 563 564 /// <summary> 565 /// Given an NTT transformed plaintext modulo q_1...q_k, this function switches the modulus down until the 566 /// parameters reach the given ParmsId. 567 /// </summary> 568 /// <param name="plain">The plaintext to be switched to a smaller modulus</param> 569 /// <param name="parmsId">The target parmsId</param> 570 /// <exception cref="ArgumentNullException">if plain or parmsId is null</exception> 571 /// <exception cref="ArgumentException">if plain is not in NTT form</exception> 572 /// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception> 573 /// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception> 574 /// <exception cref="ArgumentException">if plain is already at lower level in modulus chain than the parameters 575 /// corresponding to parmsId</exception> 576 /// <exception cref="ArgumentException">if the scale is too large for the new encryption parameters</exception> ModSwitchToInplace(Plaintext plain, ParmsId parmsId)577 public void ModSwitchToInplace(Plaintext plain, ParmsId parmsId) 578 { 579 ModSwitchTo(plain, parmsId, destination: plain); 580 } 581 582 /// <summary> 583 /// Given an NTT transformed plaintext modulo q_1...q_k, this function switches the modulus down until the 584 /// parameters reach the given ParmsId and stores the result in the destination parameter. 585 /// </summary> 586 /// <param name="plain">The plaintext to be switched to a smaller modulus</param> 587 /// <param name="parmsId">The target parmsId</param> 588 /// <param name="destination">The plaintext to overwrite with the modulus switched result</param> 589 /// <exception cref="ArgumentNullException">if plain, parmsId, or destination is null</exception> 590 /// <exception cref="ArgumentException">if plain is not in NTT form</exception> 591 /// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception> 592 /// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception> 593 /// <exception cref="ArgumentException">if plain is already at lower level in modulus chain than the parameters 594 /// corresponding to parmsId</exception> 595 /// <exception cref="ArgumentException">if the scale is too large for the new encryption parameters</exception> ModSwitchTo(Plaintext plain, ParmsId parmsId, Plaintext destination)596 public void ModSwitchTo(Plaintext plain, ParmsId parmsId, 597 Plaintext destination) 598 { 599 if (null == plain) 600 throw new ArgumentNullException(nameof(plain)); 601 if (null == parmsId) 602 throw new ArgumentNullException(nameof(parmsId)); 603 if (null == destination) 604 throw new ArgumentNullException(nameof(destination)); 605 606 NativeMethods.Evaluator_ModSwitchTo(NativePtr, plain.NativePtr, parmsId.Block, destination.NativePtr); 607 } 608 609 /// <summary> 610 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down to q_1...q_{k-1}, 611 /// scales the message down accordingly, and stores the result in the destination parameter. 612 /// </summary> 613 /// <remarks> 614 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down to q_1...q_{k-1}, 615 /// scales the message down accordingly, and stores the result in the destination parameter. Dynamic memory 616 /// allocations in the process are allocated from the memory pool pointed to by the given MemoryPoolHandle. 617 /// </remarks> 618 /// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param> 619 /// <param name="destination">The ciphertext to overwrite with the modulus switched result</param> 620 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 621 /// <exception cref="ArgumentNullException">if encrypted, or destination is null</exception> 622 /// <exception cref="ArgumentException">if the scheme is invalid for rescaling</exception> 623 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 624 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 625 /// <exception cref="ArgumentException">if encrypted is already at lowest level</exception> 626 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 627 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RescaleToNext(Ciphertext encrypted, Ciphertext destination, MemoryPoolHandle pool = null)628 public void RescaleToNext(Ciphertext encrypted, Ciphertext destination, MemoryPoolHandle pool = null) 629 { 630 if (null == encrypted) 631 throw new ArgumentNullException(nameof(encrypted)); 632 if (null == destination) 633 throw new ArgumentNullException(nameof(destination)); 634 635 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 636 NativeMethods.Evaluator_RescaleToNext( 637 NativePtr, encrypted.NativePtr, destination.NativePtr, poolPtr); 638 } 639 640 /// <summary> 641 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down to q_1...q_{k-1} and 642 /// scales the message down accordingly. 643 /// </summary> 644 /// <remarks> 645 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down to q_1...q_{k-1} and 646 /// scales the message down accordingly. Dynamic memory allocations in the process are allocated from the memory 647 /// pool pointed to by the given MemoryPoolHandle. 648 /// </remarks> 649 /// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param> 650 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 651 /// <exception cref="ArgumentNullException">if encrypted is null</exception> 652 /// <exception cref="ArgumentException">if the scheme is invalid for rescaling</exception> 653 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 654 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form guaranteed to be</exception> 655 /// <exception cref="ArgumentException">if encrypted is already at lowest level</exception> 656 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 657 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RescaleToNextInplace(Ciphertext encrypted, MemoryPoolHandle pool = null)658 public void RescaleToNextInplace(Ciphertext encrypted, MemoryPoolHandle pool = null) 659 { 660 RescaleToNext(encrypted, destination: encrypted, pool: pool); 661 } 662 663 /// <summary> 664 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down until the parameters 665 /// reach the given ParmsId and scales the message down accordingly. 666 /// </summary> 667 /// <remarks> 668 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down until the parameters 669 /// reach the given ParmsId and scales the message down accordingly. Dynamic memory allocations in the process 670 /// are allocated from the memory pool pointed to by the given MemoryPoolHandle. 671 /// </remarks> 672 /// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param> 673 /// <param name="parmsId">The target parmsId</param> 674 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 675 /// <exception cref="ArgumentNullException">if encrypted or parmsId is null</exception> 676 /// <exception cref="ArgumentException">if the scheme is invalid for rescaling</exception> 677 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 678 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 679 /// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception> 680 /// <exception cref="ArgumentException">if encrypted is already at lower level in modulus chain than the 681 /// parameters corresponding to parmsId</exception> 682 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 683 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RescaleToInplace(Ciphertext encrypted, ParmsId parmsId, MemoryPoolHandle pool = null)684 public void RescaleToInplace(Ciphertext encrypted, ParmsId parmsId, MemoryPoolHandle pool = null) 685 { 686 RescaleTo(encrypted, parmsId, destination: encrypted, pool: pool); 687 } 688 689 /// <summary> 690 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down until the parameters 691 /// reach the given ParmsId, scales the message down accordingly, and stores the result in the destination 692 /// parameter. 693 /// </summary> 694 /// <remarks> 695 /// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus down until the parameters 696 /// reach the given ParmsId, scales the message down accordingly, and stores the result in the destination 697 /// parameter. Dynamic memory allocations in the process are allocated from the memory pool pointed to by the 698 /// given MemoryPoolHandle. 699 /// </remarks> 700 /// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param> 701 /// <param name="parmsId">The target parmsId</param> 702 /// <param name="destination">The ciphertext to overwrite with the modulus switched result</param> 703 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 704 /// <exception cref="ArgumentNullException">if encrypted, parmsId, or destination is null.</exception> 705 /// <exception cref="ArgumentException">if the scheme is invalid for rescaling</exception> 706 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 707 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 708 /// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception> 709 /// <exception cref="ArgumentException">if encrypted is already at lower level in modulus chain than the 710 /// parameters corresponding to parmsId</exception> 711 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 712 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RescaleTo(Ciphertext encrypted, ParmsId parmsId, Ciphertext destination, MemoryPoolHandle pool = null)713 public void RescaleTo(Ciphertext encrypted, ParmsId parmsId, Ciphertext destination, MemoryPoolHandle pool = null) 714 { 715 if (null == encrypted) 716 throw new ArgumentNullException(nameof(encrypted)); 717 if (null == parmsId) 718 throw new ArgumentNullException(nameof(parmsId)); 719 if (null == destination) 720 throw new ArgumentNullException(nameof(destination)); 721 722 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 723 NativeMethods.Evaluator_RescaleTo( 724 NativePtr, encrypted.NativePtr, parmsId.Block, destination.NativePtr, poolPtr); 725 } 726 727 /// <summary> 728 /// Multiplies several ciphertexts together. This function computes the product of several ciphertext given as 729 /// an IEnumerable and stores the result in the destination parameter. 730 /// </summary> 731 /// <remarks> 732 /// Multiplies several ciphertexts together. This function computes the product of several ciphertext given as 733 /// an IEnumerable and stores the result in the destination parameter. The multiplication is done in a 734 /// depth-optimal order, and relinearization is performed automatically after every multiplication in the 735 /// process. In relinearization the given relinearization keys are used. Dynamic memory allocations in the 736 /// process are allocated from the memory pool pointed to by the given MemoryPoolHandle. 737 /// </remarks> 738 /// <param name="encrypteds">The ciphertexts to multiply</param> 739 /// <param name="relinKeys">The relinearization keys</param> 740 /// <param name="destination">The ciphertext to overwrite with the multiplication result</param> 741 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 742 /// <exception cref="ArgumentNullException">if encrypteds, relinKeys, or destination is null</exception> 743 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception> 744 /// <exception cref="ArgumentException">if encrypteds is empty</exception> 745 /// <exception cref="ArgumentException">if encrypteds or relinKeys are not valid for the encryption 746 /// parameters</exception> 747 /// <exception cref="ArgumentException">if encrypteds are not in the default NTT form</exception> 748 /// <exception cref="ArgumentException">if the output scale is too large for the encryption 749 /// parameters</exception> 750 /// <exception cref="ArgumentException">if the size of relinKeys is too small</exception> 751 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 752 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 753 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> MultiplyMany(IEnumerable<Ciphertext> encrypteds, RelinKeys relinKeys, Ciphertext destination, MemoryPoolHandle pool = null)754 public void MultiplyMany(IEnumerable<Ciphertext> encrypteds, RelinKeys relinKeys, 755 Ciphertext destination, MemoryPoolHandle pool = null) 756 { 757 if (null == encrypteds) 758 throw new ArgumentNullException(nameof(encrypteds)); 759 if (null == relinKeys) 760 throw new ArgumentNullException(nameof(relinKeys)); 761 if (null == destination) 762 throw new ArgumentNullException(nameof(destination)); 763 if (!ContextUsingKeyswitching) 764 throw new InvalidOperationException("Keyswitching is not supported by the context"); 765 766 IntPtr[] encarray = encrypteds.Select(c => c.NativePtr).ToArray(); 767 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 768 NativeMethods.Evaluator_MultiplyMany( 769 NativePtr, (ulong)encarray.Length, encarray, relinKeys.NativePtr, 770 destination.NativePtr, poolPtr); 771 } 772 773 /// <summary> 774 /// Exponentiates a ciphertext. 775 /// </summary> 776 /// <remarks> 777 /// This functions raises encrypted to a power. Dynamic memory allocations in the process are allocated from the 778 /// memory pool pointed to by the given MemoryPoolHandle. The exponentiation is done in a depth-optimal order, 779 /// and relinearization is performed automatically after every multiplication in the process. In relinearization 780 /// the given relinearization keys are used. 781 /// </remarks> 782 /// <param name="encrypted">The ciphertext to exponentiate</param> 783 /// <param name="exponent">The power to raise the ciphertext to</param> 784 /// <param name="relinKeys">The relinearization keys</param> 785 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 786 /// <exception cref="ArgumentNullException">if encrypted or relinKeys is null</exception> 787 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception> 788 /// <exception cref="ArgumentException">if encrypted or relinKeys is not valid for the encryption 789 /// parameters</exception> 790 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 791 /// <exception cref="ArgumentException">if the output scale is too large for the encryption 792 /// parameters</exception> 793 /// <exception cref="ArgumentException">if exponent is zero</exception> 794 /// <exception cref="ArgumentException">if the size of relinKeys is too small</exception> 795 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 796 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 797 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> ExponentiateInplace(Ciphertext encrypted, ulong exponent, RelinKeys relinKeys, MemoryPoolHandle pool = null)798 public void ExponentiateInplace(Ciphertext encrypted, ulong exponent, 799 RelinKeys relinKeys, MemoryPoolHandle pool = null) 800 { 801 Exponentiate(encrypted, exponent, relinKeys, destination: encrypted, pool: pool); 802 } 803 804 /// <summary> 805 /// Exponentiates a ciphertext. 806 /// </summary> 807 /// <remarks> 808 /// This functions raises encrypted to a power and stores the result in the destination parameter. Dynamic 809 /// memory allocations in the process are allocated from the memory pool pointed to by the given 810 /// MemoryPoolHandle. The exponentiation is done in a depth-optimal order, and relinearization is performed 811 /// automatically after every multiplication in the process. In relinearization the given relinearization keys 812 /// are used. 813 /// </remarks> 814 /// <param name="encrypted">The ciphertext to exponentiate</param> 815 /// <param name="exponent">The power to raise the ciphertext to</param> 816 /// <param name="relinKeys">The relinearization keys</param> 817 /// <param name="destination">The ciphertext to overwrite with the power</param> 818 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 819 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception> 820 /// <exception cref="ArgumentException">if encrypted or relinKeys is not valid for the encryption 821 /// parameters</exception> 822 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 823 /// <exception cref="ArgumentException">if the output scale is too large for the encryption 824 /// parameters</exception> 825 /// <exception cref="ArgumentException">if exponent is zero</exception> 826 /// <exception cref="ArgumentException">if the size of relinKeys is too small</exception> 827 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 828 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 829 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> Exponentiate(Ciphertext encrypted, ulong exponent, RelinKeys relinKeys, Ciphertext destination, MemoryPoolHandle pool = null)830 public void Exponentiate(Ciphertext encrypted, ulong exponent, RelinKeys relinKeys, 831 Ciphertext destination, MemoryPoolHandle pool = null) 832 { 833 if (null == encrypted) 834 throw new ArgumentNullException(nameof(encrypted)); 835 if (null == relinKeys) 836 throw new ArgumentNullException(nameof(relinKeys)); 837 if (null == destination) 838 throw new ArgumentNullException(nameof(destination)); 839 if (!ContextUsingKeyswitching) 840 throw new InvalidOperationException("Keyswitching is not supported by the context"); 841 842 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 843 NativeMethods.Evaluator_Exponentiate( 844 NativePtr, encrypted.NativePtr, exponent, relinKeys.NativePtr, 845 destination.NativePtr, poolPtr); 846 } 847 848 /// <summary> 849 /// Adds a ciphertext and a plaintext and stores the result in encrypted. 850 /// </summary> 851 /// <param name="encrypted">The ciphertext to add</param> 852 /// <param name="plain">The plaintext to add</param> 853 /// <exception cref="ArgumentNullException">if encrypted or plain is null</exception> 854 /// <exception cref="ArgumentException">if encrypted or plain is not valid for the encryption 855 /// parameters</exception> 856 /// <exception cref="ArgumentException">if encrypted or plain is not in the default NTT form</exception> 857 /// <exception cref="ArgumentException">if encrypted and plain are at different level or scale</exception> 858 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> AddPlainInplace(Ciphertext encrypted, Plaintext plain)859 public void AddPlainInplace(Ciphertext encrypted, Plaintext plain) 860 { 861 AddPlain(encrypted, plain, destination: encrypted); 862 } 863 864 /// <summary> 865 /// Adds a ciphertext and a plaintext. 866 /// </summary> 867 /// <remarks> 868 /// This function adds a ciphertext and a plaintext and stores the result in the destination parameter. 869 /// </remarks> 870 /// <param name="encrypted">The ciphertext to add</param> 871 /// <param name="plain">The plaintext to add</param> 872 /// <param name="destination">The ciphertext to overwrite with the addition result</param> 873 /// <exception cref="ArgumentNullException">if encrypted, plain, or destination is null</exception> 874 /// <exception cref="ArgumentException">if encrypted or plain is not valid for the encryption 875 /// parameters</exception> 876 /// <exception cref="ArgumentException">if encrypted or plain is not in the default NTT form</exception> 877 /// <exception cref="ArgumentException">if encrypted and plain are at different level or scale</exception> 878 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> AddPlain(Ciphertext encrypted, Plaintext plain, Ciphertext destination)879 public void AddPlain(Ciphertext encrypted, Plaintext plain, Ciphertext destination) 880 { 881 if (null == encrypted) 882 throw new ArgumentNullException(nameof(encrypted)); 883 if (null == plain) 884 throw new ArgumentNullException(nameof(plain)); 885 if (null == destination) 886 throw new ArgumentNullException(nameof(destination)); 887 888 NativeMethods.Evaluator_AddPlain( 889 NativePtr, encrypted.NativePtr, plain.NativePtr, destination.NativePtr); 890 } 891 892 /// <summary> 893 /// Subtracts a plaintext from a ciphertext and stores the result in encrypted. 894 /// </summary> 895 /// <param name="encrypted">The ciphertext to subtract from</param> 896 /// <param name="plain">The plaintext to subtract</param> 897 /// <exception cref="ArgumentNullException">if encrypted or plain is null</exception> 898 /// <exception cref="ArgumentException">if encrypted or plain is not valid for the encryption 899 /// parameters</exception> 900 /// <exception cref="ArgumentException">if encrypted or plain is not in the default NTT form</exception> 901 /// <exception cref="ArgumentException">if encrypted and plain are at different level or scale</exception> 902 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> SubPlainInplace(Ciphertext encrypted, Plaintext plain)903 public void SubPlainInplace(Ciphertext encrypted, Plaintext plain) 904 { 905 SubPlain(encrypted, plain, destination: encrypted); 906 } 907 908 /// <summary> 909 /// Subtracts a plaintext from a ciphertext. 910 /// </summary> 911 /// <remarks> 912 /// This function subtracts a plaintext from a ciphertext and stores the result in the destination parameter. 913 /// </remarks> 914 /// <param name="encrypted">The ciphertext to subtract from</param> 915 /// <param name="plain">The plaintext to subtract</param> 916 /// <param name="destination">The ciphertext to overwrite with the subtraction result</param> 917 /// <exception cref="ArgumentNullException">if encrypted, plain, or destination is null</exception> 918 /// <exception cref="ArgumentException">if encrypted or plain is not valid for the encryption 919 /// parameters</exception> 920 /// <exception cref="ArgumentException">if encrypted or plain is not in the default NTT form</exception> 921 /// <exception cref="ArgumentException">if encrypted and plain are at different level or scale</exception> 922 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> SubPlain(Ciphertext encrypted, Plaintext plain, Ciphertext destination)923 public void SubPlain(Ciphertext encrypted, Plaintext plain, Ciphertext destination) 924 { 925 if (null == encrypted) 926 throw new ArgumentNullException(nameof(encrypted)); 927 if (null == plain) 928 throw new ArgumentNullException(nameof(plain)); 929 if (null == destination) 930 throw new ArgumentNullException(nameof(destination)); 931 932 NativeMethods.Evaluator_SubPlain( 933 NativePtr, encrypted.NativePtr, plain.NativePtr, destination.NativePtr); 934 } 935 936 /// <summary> 937 /// Multiplies a ciphertext with a plaintext and stores the result in encrypted. 938 /// </summary> 939 /// <remarks> 940 /// Multiplies a ciphertext with a plaintext. The plaintext cannot be identically 0. Dynamic memory allocations 941 /// in the process are allocated from the memory pool pointed to by the given MemoryPoolHandle. 942 /// </remarks> 943 /// <param name="encrypted">The ciphertext to multiply</param> 944 /// <param name="plain">The plaintext to multiply</param> 945 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 946 /// <exception cref="ArgumentNullException">if encrypted or plain is null.</exception> 947 /// <exception cref="ArgumentException">if encrypted or plain is not valid for the encryption 948 /// parameters</exception> 949 /// <exception cref="ArgumentException">if encrypted and plain are in different NTT forms</exception> 950 /// <exception cref="ArgumentException">if the output scale is too large for the encryption 951 /// parameters</exception> 952 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 953 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> MultiplyPlainInplace(Ciphertext encrypted, Plaintext plain, MemoryPoolHandle pool = null)954 public void MultiplyPlainInplace(Ciphertext encrypted, Plaintext plain, MemoryPoolHandle pool = null) 955 { 956 MultiplyPlain(encrypted, plain, destination: encrypted, pool: pool); 957 } 958 959 /// <summary> 960 /// Multiplies a ciphertext with a plaintext. 961 /// </summary> 962 /// <remarks> 963 /// This function multiplies a ciphertext with a plaintext and stores the result in the destination parameter. 964 /// The plaintext cannot be identically 0. Dynamic memory allocations in the process are allocated from the 965 /// memory pool pointed to by the given MemoryPoolHandle. 966 /// </remarks> 967 /// <param name="encrypted">The ciphertext to multiply</param> 968 /// <param name="plain">The plaintext to multiply</param> 969 /// <param name="destination">The ciphertext to overwrite with the multiplication result</param> 970 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 971 /// <exception cref="ArgumentNullException">if encrypted, plain, or destination is null</exception> 972 /// <exception cref="ArgumentException">if encrypted or plain is not valid for the encryption 973 /// parameters</exception> 974 /// <exception cref="ArgumentException">if encrypted and plain are in different NTT forms</exception> 975 /// <exception cref="ArgumentException">if the output scale is too large for the encryption 976 /// parameters</exception> 977 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 978 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> MultiplyPlain(Ciphertext encrypted, Plaintext plain, Ciphertext destination, MemoryPoolHandle pool = null)979 public void MultiplyPlain(Ciphertext encrypted, Plaintext plain, Ciphertext destination, 980 MemoryPoolHandle pool = null) 981 { 982 if (null == encrypted) 983 throw new ArgumentNullException(nameof(encrypted)); 984 if (null == plain) 985 throw new ArgumentNullException(nameof(plain)); 986 if (null == destination) 987 throw new ArgumentNullException(nameof(destination)); 988 989 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 990 NativeMethods.Evaluator_MultiplyPlain( 991 NativePtr, encrypted.NativePtr, plain.NativePtr, destination.NativePtr, poolPtr); 992 } 993 994 /// <summary> 995 /// Transforms a plaintext to NTT domain. 996 /// </summary> 997 /// <remarks> 998 /// This functions applies the Number Theoretic Transform to a plaintext by first embedding integers modulo the 999 /// plaintext modulus to integers modulo the coefficient modulus and then performing David Harvey's NTT on the 1000 /// resulting polynomial. The transformation is done with respect to encryption parameters corresponding to a 1001 /// given parmsId. For the operation to be valid, the plaintext must have degree less than PolyModulusDegree and 1002 /// each coefficient must be less than the plaintext modulus, i.e., the plaintext must be a valid plaintext 1003 /// under the current encryption parameters. Dynamic memory allocations in the process are allocated from the 1004 /// memory pool pointed to by the given MemoryPoolHandle. 1005 /// </remarks> 1006 /// <param name="plain">The plaintext to transform</param> 1007 /// <param name="parmsId">The ParmsId with respect to which the NTT is done</param> 1008 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1009 /// <exception cref="ArgumentNullException">if plain or parmsId is null</exception> 1010 /// <exception cref="ArgumentException">if plain is already in NTT form</exception> 1011 /// <exception cref="ArgumentException">if plain or parmsId is not valid for the encryption 1012 /// parameters</exception> 1013 /// <exception cref="ArgumentException">if pool is uninitialized</exception> TransformToNTTInplace(Plaintext plain, ParmsId parmsId, MemoryPoolHandle pool = null)1014 public void TransformToNTTInplace(Plaintext plain, ParmsId parmsId, MemoryPoolHandle pool = null) 1015 { 1016 TransformToNTT(plain, parmsId, destinationNTT: plain, pool: pool); 1017 } 1018 1019 /// <summary> 1020 /// Transforms a plaintext to NTT domain. 1021 /// </summary> 1022 /// <remarks> 1023 /// This functions applies the Number Theoretic Transform to a plaintext by first embedding integers modulo the 1024 /// plaintext modulus to integers modulo the coefficient modulus and then performing David Harvey's NTT on the 1025 /// resulting polynomial. The transformation is done with respect to encryption parameters corresponding to a 1026 /// given ParmsId. The result is stored in the destinationNTT parameter. For the operation to be valid, the 1027 /// plaintext must have degree less than PolyModulusDegree and each coefficient must be less than the plaintext 1028 /// modulus, i.e., the plaintext must be a valid plaintext under the current encryption parameters. Dynamic 1029 /// memory allocations in the process are allocated from the memory pool pointed to by the given 1030 /// MemoryPoolHandle. 1031 /// </remarks> 1032 /// <param name="plain">The plaintext to transform</param> 1033 /// <param name="parmsId">The ParmsId with respect to which the NTT is done</param> 1034 /// <param name="destinationNTT">The plaintext to overwrite with the transformed result</param> 1035 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1036 /// <exception cref="ArgumentNullException">if plain, parmsId, or destinationNTT is null</exception> 1037 /// <exception cref="ArgumentException">if plain is already in NTT form</exception> 1038 /// <exception cref="ArgumentException">if plain or parmsId is not valid for the encryption 1039 /// parameters</exception> 1040 /// <exception cref="ArgumentException">if pool is uninitialized</exception> TransformToNTT(Plaintext plain, ParmsId parmsId, Plaintext destinationNTT, MemoryPoolHandle pool = null)1041 public void TransformToNTT(Plaintext plain, ParmsId parmsId, 1042 Plaintext destinationNTT, MemoryPoolHandle pool = null) 1043 { 1044 if (null == plain) 1045 throw new ArgumentNullException(nameof(plain)); 1046 if (null == parmsId) 1047 throw new ArgumentNullException(nameof(parmsId)); 1048 if (null == destinationNTT) 1049 throw new ArgumentNullException(nameof(destinationNTT)); 1050 1051 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 1052 NativeMethods.Evaluator_TransformToNTT(NativePtr, plain.NativePtr, parmsId.Block, destinationNTT.NativePtr, poolPtr); 1053 } 1054 1055 /// <summary> 1056 /// Transforms a ciphertext to NTT domain. 1057 /// </summary> 1058 /// <remarks> 1059 /// Transforms a ciphertext to NTT domain. This functions applies David Harvey's Number Theoretic Transform 1060 /// separately to each polynomial of a ciphertext. 1061 /// </remarks> 1062 /// <param name="encrypted">The ciphertext to transform</param> 1063 /// <exception cref="ArgumentNullException">if encrypted is null</exception> 1064 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 1065 /// <exception cref="ArgumentException">if encrypted is already in NTT form</exception> 1066 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> TransformToNTTInplace(Ciphertext encrypted)1067 public void TransformToNTTInplace(Ciphertext encrypted) 1068 { 1069 TransformToNTT(encrypted, destinationNTT: encrypted); 1070 } 1071 1072 /// <summary> 1073 /// Transforms a ciphertext to NTT domain. 1074 /// </summary> 1075 /// <remarks> 1076 /// Transforms a ciphertext to NTT domain. This functions applies David Harvey's Number Theoretic Transform 1077 /// separately to each polynomial of a ciphertext. The result is stored in the DestinationNTT parameter. 1078 /// </remarks> 1079 /// <param name="encrypted">The ciphertext to transform</param> 1080 /// <param name="destinationNTT">The ciphertext to overwrite with the transformed result</param> 1081 /// <exception cref="ArgumentNullException">if encrypted or destinationNTT is null</exception> 1082 /// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception> 1083 /// <exception cref="ArgumentException">if encrypted is already in NTT form</exception> 1084 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> TransformToNTT(Ciphertext encrypted, Ciphertext destinationNTT)1085 public void TransformToNTT(Ciphertext encrypted, Ciphertext destinationNTT) 1086 { 1087 if (null == encrypted) 1088 throw new ArgumentNullException(nameof(encrypted)); 1089 if (null == destinationNTT) 1090 throw new ArgumentNullException(nameof(destinationNTT)); 1091 1092 NativeMethods.Evaluator_TransformToNTT( 1093 NativePtr, encrypted.NativePtr, destinationNTT.NativePtr); 1094 } 1095 1096 /// <summary> 1097 /// Transforms a ciphertext back from NTT domain. 1098 /// </summary> 1099 /// <remarks> 1100 /// Transforms a ciphertext back from NTT domain. This functions applies the inverse of David Harvey's Number 1101 /// Theoretic Transform separately to each polynomial of a ciphertext. 1102 /// </remarks> 1103 /// <param name="encryptedNTT">The ciphertext to transform</param> 1104 /// <exception cref="ArgumentNullException">if encryptedNTT is null</exception> 1105 /// <exception cref="ArgumentException">if encryptedNTT is not valid for the encryption parameters</exception> 1106 /// <exception cref="ArgumentException">if encryptedNTT is not in NTT form</exception> 1107 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> TransformFromNTTInplace(Ciphertext encryptedNTT)1108 public void TransformFromNTTInplace(Ciphertext encryptedNTT) 1109 { 1110 TransformFromNTT(encryptedNTT, destination: encryptedNTT); 1111 } 1112 1113 /// <summary> 1114 /// Transforms a ciphertext back from NTT domain. 1115 /// </summary> 1116 /// <remarks> 1117 /// Transforms a ciphertext back from NTT domain. This functions applies the inverse of David Harvey's Number 1118 /// Theoretic Transform separately to each polynomial of a ciphertext. The result is stored in the destination 1119 /// parameter. 1120 /// </remarks> 1121 /// <param name="encryptedNTT">The ciphertext to transform</param> 1122 /// <param name="destination">The ciphertext to overwrite with the transformed result</param> 1123 /// <exception cref="ArgumentNullException">if encryptedNTT or destination is null</exception> 1124 /// <exception cref="ArgumentException">if encryptedNTT is not valid for the encryption parameters</exception> 1125 /// <exception cref="ArgumentException">if encryptedNTT is not in NTT form</exception> 1126 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> TransformFromNTT(Ciphertext encryptedNTT, Ciphertext destination)1127 public void TransformFromNTT(Ciphertext encryptedNTT, Ciphertext destination) 1128 { 1129 if (null == encryptedNTT) 1130 throw new ArgumentNullException(nameof(encryptedNTT)); 1131 if (null == destination) 1132 throw new ArgumentNullException(nameof(destination)); 1133 1134 NativeMethods.Evaluator_TransformFromNTT( 1135 NativePtr, encryptedNTT.NativePtr, destination.NativePtr); 1136 } 1137 1138 /// <summary> 1139 /// Applies a Galois automorphism to a ciphertext. 1140 /// </summary> 1141 /// <remarks> 1142 /// <para> 1143 /// Applies a Galois automorphism to a ciphertext. To evaluate the Galois automorphism, an appropriate set of 1144 /// Galois keys must also be provided. Dynamic memory allocations in the process are allocated from the memory 1145 /// pool pointed to by the given MemoryPoolHandle. 1146 /// </para> 1147 /// <para> 1148 /// The desired Galois automorphism is given as a Galois element, and must be an odd integer in the interval 1149 /// [1, M-1], where M = 2*N, and N = PolyModulusDegree. Used with batching, a Galois element 3^i % M corresponds 1150 /// to a cyclic row rotation i steps to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row 1151 /// rotation i steps to the right. The Galois element M-1 corresponds to a column rotation (row swap) in BFV, 1152 /// and complex conjugation in CKKS. In the polynomial view (not batching), a Galois automorphism by a Galois 1153 /// element p changes Enc(plain(x)) to Enc(plain(x^p)). 1154 /// </para> 1155 /// </remarks> 1156 /// <param name="encrypted">The ciphertext to apply the Galois automorphism to</param> 1157 /// <param name="galoisElt">The Galois element</param> 1158 /// <param name="galoisKeys">The Galois keys</param> 1159 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1160 /// <exception cref="ArgumentNullException">if encrypted or galoisKeys is null</exception> 1161 /// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the encryption 1162 /// parameters</exception> 1163 /// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level parameters in the 1164 /// current context</exception> 1165 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 1166 /// <exception cref="ArgumentException">if encrypted has size larger than 2</exception> 1167 /// <exception cref="ArgumentException">if the Galois element is not valid</exception> 1168 /// <exception cref="ArgumentException">if necessary Galois keys are not present</exception> 1169 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 1170 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 1171 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> ApplyGaloisInplace(Ciphertext encrypted, uint galoisElt, GaloisKeys galoisKeys, MemoryPoolHandle pool = null)1172 public void ApplyGaloisInplace(Ciphertext encrypted, uint galoisElt, 1173 GaloisKeys galoisKeys, MemoryPoolHandle pool = null) 1174 { 1175 ApplyGalois(encrypted, galoisElt, galoisKeys, destination: encrypted, pool: pool); 1176 } 1177 1178 /// <summary> 1179 /// Applies a Galois automorphism to a ciphertext and writes the result to the destination parameter. 1180 /// </summary> 1181 /// <remarks> 1182 /// <para> 1183 /// Applies a Galois automorphism to a ciphertext and writes the result to the destination parameter. To 1184 /// evaluate the Galois automorphism, an appropriate set of Galois keys must also be provided. Dynamic memory 1185 /// allocations in the process are allocated from the memory pool pointed to by the given MemoryPoolHandle. 1186 /// </para> 1187 /// <para> 1188 /// The desired Galois automorphism is given as a Galois element, and must be an odd integer in the interval 1189 /// [1, M-1], where M = 2*N, and N = PolyModulusDegree. Used with batching, a Galois element 3^i % M corresponds 1190 /// to a cyclic row rotation i steps to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row 1191 /// rotation i steps to the right. The Galois element M-1 corresponds to a column rotation (row swap) in BFV, 1192 /// and complex conjugation in CKKS. In the polynomial view (not batching), a Galois automorphism by a Galois 1193 /// element p changes Enc(plain(x)) to Enc(plain(x^p)). 1194 /// </para> 1195 /// </remarks> 1196 /// <param name="encrypted">The ciphertext to apply the Galois automorphism to</param> 1197 /// <param name="galoisElt">The Galois element</param> 1198 /// <param name="galoisKeys">The Galois keys</param> 1199 /// <param name="destination">The ciphertext to overwrite with the result</param> 1200 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1201 /// <exception cref="ArgumentNullException">if encrypted, galoisKeys, or destination is null</exception> 1202 /// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the encryption 1203 /// parameters</exception> 1204 /// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level parameters in the 1205 /// current context</exception> 1206 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 1207 /// <exception cref="ArgumentException">if encrypted has size larger than 2</exception> 1208 /// <exception cref="ArgumentException">if the Galois element is not valid</exception> 1209 /// <exception cref="ArgumentException">if necessary Galois keys are not present</exception> 1210 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 1211 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 1212 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> ApplyGalois(Ciphertext encrypted, uint galoisElt, GaloisKeys galoisKeys, Ciphertext destination, MemoryPoolHandle pool = null)1213 public void ApplyGalois(Ciphertext encrypted, uint galoisElt, GaloisKeys galoisKeys, 1214 Ciphertext destination, MemoryPoolHandle pool = null) 1215 { 1216 if (null == encrypted) 1217 throw new ArgumentNullException(nameof(encrypted)); 1218 if (null == galoisKeys) 1219 throw new ArgumentNullException(nameof(galoisKeys)); 1220 if (null == destination) 1221 throw new ArgumentNullException(nameof(destination)); 1222 if (!ContextUsingKeyswitching) 1223 throw new InvalidOperationException("Keyswitching is not supported by the context"); 1224 1225 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 1226 NativeMethods.Evaluator_ApplyGalois( 1227 NativePtr, encrypted.NativePtr, galoisElt, 1228 galoisKeys.NativePtr, destination.NativePtr, poolPtr); 1229 } 1230 1231 /// <summary> 1232 /// Rotates plaintext matrix rows cyclically. 1233 /// </summary> 1234 /// <remarks> 1235 /// When batching is used with the BFV scheme, this function rotates the encrypted plaintext matrix rows 1236 /// cyclically to the left (steps > 0) or to the right (steps < 0). Since the size of the batched matrix 1237 /// is 2-by-(N/2), where N is the degree of the polynomial modulus, the number of steps to rotate must have 1238 /// absolute value at most N/2-1. Dynamic memory allocations in the process are allocated from the memory pool 1239 /// pointed to by the given MemoryPoolHandle. 1240 /// </remarks> 1241 /// <param name="encrypted">The ciphertext to rotate</param> 1242 /// <param name="steps">The number of steps to rotate (positive left, negative right)</param> 1243 /// <param name="galoisKeys">The Galois keys</param> 1244 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1245 /// <exception cref="ArgumentNullException">if encrypted or galoisKeys is null</exception> 1246 /// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception> 1247 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception> 1248 /// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the encryption 1249 /// parameters</exception> 1250 /// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level parameters in the 1251 /// current context</exception> 1252 /// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception> 1253 /// <exception cref="ArgumentException">if encrypted has size larger than 2</exception> 1254 /// <exception cref="ArgumentException">if steps has too big absolute value</exception> 1255 /// <exception cref="ArgumentException">if necessary Galois keys are not present</exception> 1256 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 1257 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 1258 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RotateRowsInplace(Ciphertext encrypted, int steps, GaloisKeys galoisKeys, MemoryPoolHandle pool = null)1259 public void RotateRowsInplace(Ciphertext encrypted, 1260 int steps, GaloisKeys galoisKeys, MemoryPoolHandle pool = null) 1261 { 1262 RotateRows(encrypted, steps, galoisKeys, destination: encrypted, pool: pool); 1263 } 1264 1265 /// <summary> 1266 /// Rotates plaintext matrix rows cyclically. 1267 /// </summary> 1268 /// <remarks> 1269 /// When batching is used with the BFV scheme, this function rotates the encrypted plaintext matrix rows 1270 /// cyclically to the left (steps > 0) or to the right (steps < 0) and writes the result to the 1271 /// destination parameter. Since the size of the batched matrix is 2-by-(N/2), where N is the degree of the 1272 /// polynomial modulus, the number of steps to rotate must have absolute value at most N/2-1. Dynamic memory 1273 /// allocations in the process are allocated from the memory pool pointed to by the given MemoryPoolHandle. 1274 /// </remarks> 1275 /// <param name="encrypted">The ciphertext to rotate</param> 1276 /// <param name="steps">The number of steps to rotate (positive left, negative right)</param> 1277 /// <param name="galoisKeys">The Galois keys</param> 1278 /// <param name="destination">The ciphertext to overwrite with the rotated result</param> 1279 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1280 /// <exception cref="ArgumentNullException">if encrypted, galoisKeys, or destination is null</exception> 1281 /// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception> 1282 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception> 1283 /// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the encryption 1284 /// parameters</exception> 1285 /// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level parameters in the 1286 /// current context</exception> 1287 /// <exception cref="ArgumentException">if encrypted is in NTT form</exception> 1288 /// <exception cref="ArgumentException">if encrypted has size larger than 2</exception> 1289 /// <exception cref="ArgumentException">if steps has too big absolute value</exception> 1290 /// <exception cref="ArgumentException">if necessary Galois keys are not present</exception> 1291 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 1292 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 1293 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RotateRows(Ciphertext encrypted, int steps, GaloisKeys galoisKeys, Ciphertext destination, MemoryPoolHandle pool = null)1294 public void RotateRows(Ciphertext encrypted, int steps, GaloisKeys galoisKeys, 1295 Ciphertext destination, MemoryPoolHandle pool = null) 1296 { 1297 if (null == encrypted) 1298 throw new ArgumentNullException(nameof(encrypted)); 1299 if (null == galoisKeys) 1300 throw new ArgumentNullException(nameof(galoisKeys)); 1301 if (null == destination) 1302 throw new ArgumentNullException(nameof(destination)); 1303 if (!ContextUsingKeyswitching) 1304 throw new InvalidOperationException("Keyswitching is not supported by the context"); 1305 1306 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 1307 NativeMethods.Evaluator_RotateRows( 1308 NativePtr, encrypted.NativePtr, steps, galoisKeys.NativePtr, 1309 destination.NativePtr, poolPtr); 1310 } 1311 1312 /// <summary> 1313 /// Rotates plaintext matrix columns cyclically. 1314 /// </summary> 1315 /// <remarks> 1316 /// When batching is used with the BFV scheme, this function rotates the encrypted plaintext matrix columns 1317 /// cyclically. Since the size of the batched matrix is 2-by-(N/2), where N is the degree of the polynomial 1318 /// modulus, this means simply swapping the two rows. Dynamic memory allocations in the process are allocated 1319 /// from the memory pool pointed to by the given MemoryPoolHandle. 1320 /// </remarks> 1321 /// <param name="encrypted">The ciphertext to rotate</param> 1322 /// <param name="galoisKeys">The Galois keys</param> 1323 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1324 /// <exception cref="ArgumentNullException">if encrypted or galoisKeys is null</exception> 1325 /// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception> 1326 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception> 1327 /// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the encryption 1328 /// parameters</exception> 1329 /// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level parameters in the 1330 /// current context</exception> 1331 /// <exception cref="ArgumentException">if encrypted is in NTT form</exception> 1332 /// <exception cref="ArgumentException">if encrypted has size larger than 2</exception> 1333 /// <exception cref="ArgumentException">if necessary Galois keys are not present</exception> 1334 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 1335 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 1336 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RotateColumnsInplace(Ciphertext encrypted, GaloisKeys galoisKeys, MemoryPoolHandle pool = null)1337 public void RotateColumnsInplace(Ciphertext encrypted, GaloisKeys galoisKeys, MemoryPoolHandle pool = null) 1338 { 1339 RotateColumns(encrypted, galoisKeys, destination: encrypted, pool: pool); 1340 } 1341 1342 /// <summary> 1343 /// Rotates plaintext matrix columns cyclically. 1344 /// </summary> 1345 /// <remarks> 1346 /// When batching is used with the BFV scheme, this function rotates the encrypted plaintext matrix columns 1347 /// cyclically, and writes the result to the destination parameter. Since the size of the batched matrix is 1348 /// 2-by-(N/2), where N is the degree of the polynomial modulus, this means simply swapping the two rows. 1349 /// Dynamic memory allocations in the process are allocated from the memory pool pointed to by the given 1350 /// MemoryPoolHandle. 1351 /// </remarks> 1352 /// <param name="encrypted">The ciphertext to rotate</param> 1353 /// <param name="galoisKeys">The Galois keys</param> 1354 /// <param name="destination">The ciphertext to overwrite with the rotated result</param> 1355 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1356 /// <exception cref="ArgumentNullException">if encrypted, galoisKeys, or destination is null</exception> 1357 /// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception> 1358 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception> 1359 /// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the encryption 1360 /// parameters</exception> 1361 /// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level parameters in the 1362 /// current context</exception> 1363 /// <exception cref="ArgumentException">if encrypted is in NTT form</exception> 1364 /// <exception cref="ArgumentException">if encrypted has size larger than 2</exception> 1365 /// <exception cref="ArgumentException">if necessary Galois keys are not present</exception> 1366 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 1367 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 1368 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RotateColumns(Ciphertext encrypted, GaloisKeys galoisKeys, Ciphertext destination, MemoryPoolHandle pool = null)1369 public void RotateColumns(Ciphertext encrypted, GaloisKeys galoisKeys, 1370 Ciphertext destination, MemoryPoolHandle pool = null) 1371 { 1372 if (null == encrypted) 1373 throw new ArgumentNullException(nameof(encrypted)); 1374 if (null == galoisKeys) 1375 throw new ArgumentNullException(nameof(galoisKeys)); 1376 if (null == destination) 1377 throw new ArgumentNullException(nameof(destination)); 1378 if (!ContextUsingKeyswitching) 1379 throw new InvalidOperationException("Keyswitching is not supported by the context"); 1380 1381 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 1382 NativeMethods.Evaluator_RotateColumns( 1383 NativePtr, encrypted.NativePtr, galoisKeys.NativePtr, 1384 destination.NativePtr, poolPtr); 1385 } 1386 1387 /// <summary> 1388 /// Rotates plaintext vector cyclically. 1389 /// </summary> 1390 /// <remarks> 1391 /// When using the CKKS scheme, this function rotates the encrypted plaintext vector cyclically to the left 1392 /// (steps > 0) or to the right (steps < 0). Since the size of the batched matrix is 2-by-(N/2), where N 1393 /// is the degree of the polynomial modulus, the number of steps to rotate must have absolute value at most 1394 /// N/2-1. Dynamic memory allocations in the process are allocated from the memory pool pointed to by the given 1395 /// MemoryPoolHandle. 1396 /// </remarks> 1397 /// <param name="encrypted">The ciphertext to rotate</param> 1398 /// <param name="steps">The number of steps to rotate (positive left, negative right)</param> 1399 /// <param name="galoisKeys">The Galois keys</param> 1400 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1401 /// <exception cref="ArgumentNullException">if encrypted or galoisKeys is null</exception> 1402 /// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception> 1403 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.CKKS</exception> 1404 /// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the encryption 1405 /// parameters</exception> 1406 /// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level parameters in the 1407 /// current context</exception> 1408 /// <exception cref="ArgumentException">if encrypted is in NTT form</exception> 1409 /// <exception cref="ArgumentException">if encrypted has size larger than 2</exception> 1410 /// <exception cref="ArgumentException">if steps has too big absolute value</exception> 1411 /// <exception cref="ArgumentException">if necessary Galois keys are not present</exception> 1412 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 1413 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 1414 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RotateVectorInplace(Ciphertext encrypted, int steps, GaloisKeys galoisKeys, MemoryPoolHandle pool = null)1415 public void RotateVectorInplace(Ciphertext encrypted, int steps, 1416 GaloisKeys galoisKeys, MemoryPoolHandle pool = null) 1417 { 1418 RotateVector(encrypted, steps, galoisKeys, destination: encrypted, pool: pool); 1419 } 1420 1421 /// <summary> 1422 /// Rotates plaintext vector cyclically. 1423 /// </summary> 1424 /// <remarks> 1425 /// When using the CKKS scheme, this function rotates the encrypted plaintext vector cyclically to the left 1426 /// (steps > 0) or to the right (steps < 0) and writes the result to the destination parameter. Since the 1427 /// size of the batched matrix is 2-by-(N/2), where N is the degree of the polynomial modulus, the number of 1428 /// steps to rotate must have absolute value at most N/2-1. Dynamic memory allocations in the process are 1429 /// allocated from the memory pool pointed to by the given MemoryPoolHandle. 1430 /// </remarks> 1431 /// <param name="encrypted">The ciphertext to rotate</param> 1432 /// <param name="steps">The number of steps to rotate (positive left, negative right)</param> 1433 /// <param name="galoisKeys">The Galois keys</param> 1434 /// <param name="destination">The ciphertext to overwrite with the rotated result</param> 1435 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1436 /// <exception cref="ArgumentNullException">if encrypted, galoisKeys, or destination is null</exception> 1437 /// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception> 1438 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.CKKS</exception> 1439 /// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the encryption 1440 /// parameters</exception> 1441 /// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level parameters in the 1442 /// current context</exception> 1443 /// <exception cref="ArgumentException">if encrypted is in NTT form</exception> 1444 /// <exception cref="ArgumentException">if encrypted has size larger than 2</exception> 1445 /// <exception cref="ArgumentException">if steps has too big absolute value</exception> 1446 /// <exception cref="ArgumentException">if necessary Galois keys are not present</exception> 1447 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 1448 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 1449 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> RotateVector(Ciphertext encrypted, int steps, GaloisKeys galoisKeys, Ciphertext destination, MemoryPoolHandle pool = null)1450 public void RotateVector(Ciphertext encrypted, int steps, GaloisKeys galoisKeys, 1451 Ciphertext destination, MemoryPoolHandle pool = null) 1452 { 1453 if (null == encrypted) 1454 throw new ArgumentNullException(nameof(encrypted)); 1455 if (null == galoisKeys) 1456 throw new ArgumentNullException(nameof(galoisKeys)); 1457 if (null == destination) 1458 throw new ArgumentNullException(nameof(destination)); 1459 if (!ContextUsingKeyswitching) 1460 throw new InvalidOperationException("Keyswitching is not supported by the context"); 1461 1462 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 1463 NativeMethods.Evaluator_RotateVector( 1464 NativePtr, encrypted.NativePtr, steps, galoisKeys.NativePtr, 1465 destination.NativePtr, poolPtr); 1466 } 1467 1468 /// <summary> 1469 /// Complex conjugates plaintext slot values. 1470 /// </summary> 1471 /// <remarks> 1472 /// When using the CKKS scheme, this function complex conjugates all values in the underlying plaintext. Dynamic 1473 /// memory allocations in the process are allocated from the memory pool pointed to by the given 1474 /// MemoryPoolHandle. 1475 /// </remarks> 1476 /// <param name="encrypted">The ciphertext to rotate</param> 1477 /// <param name="galoisKeys">The Galois keys</param> 1478 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1479 /// <exception cref="ArgumentNullException">if encrypted or galoisKeys is null</exception> 1480 /// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception> 1481 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.CKKS</exception> 1482 /// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the encryption 1483 /// parameters</exception> 1484 /// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level parameters in the 1485 /// current context</exception> 1486 /// <exception cref="ArgumentException">if encrypted is in NTT form</exception> 1487 /// <exception cref="ArgumentException">if encrypted has size larger than 2</exception> 1488 /// <exception cref="ArgumentException">if necessary Galois keys are not present</exception> 1489 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 1490 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 1491 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> ComplexConjugateInplace(Ciphertext encrypted, GaloisKeys galoisKeys, MemoryPoolHandle pool = null)1492 public void ComplexConjugateInplace(Ciphertext encrypted, GaloisKeys galoisKeys, MemoryPoolHandle pool = null) 1493 { 1494 ComplexConjugate(encrypted, galoisKeys, destination: encrypted, pool: pool); 1495 } 1496 1497 /// <summary> 1498 /// Complex conjugates plaintext slot values. 1499 /// </summary> 1500 /// <remarks> 1501 /// When using the CKKS scheme, this function complex conjugates all values in the underlying plaintext, and 1502 /// writes the result to the destination parameter. Dynamic memory allocations in the process are allocated from 1503 /// the memory pool pointed to by the given MemoryPoolHandle. 1504 /// </remarks> 1505 /// <param name="encrypted">The ciphertext to rotate</param> 1506 /// <param name="galoisKeys">The Galois keys</param> 1507 /// <param name="destination">The ciphertext to overwrite with the rotated result</param> 1508 /// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param> 1509 /// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception> 1510 /// <exception cref="InvalidOperationException">if scheme is not SchemeType.CKKS</exception> 1511 /// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the encryption 1512 /// parameters</exception> 1513 /// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level parameters in the 1514 /// current context</exception> 1515 /// <exception cref="ArgumentException">if encrypted is in NTT form</exception> 1516 /// <exception cref="ArgumentException">if encrypted has size larger than 2</exception> 1517 /// <exception cref="ArgumentException">if necessary Galois keys are not present</exception> 1518 /// <exception cref="ArgumentException">if pool is uninitialized</exception> 1519 /// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception> 1520 /// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception> ComplexConjugate(Ciphertext encrypted, GaloisKeys galoisKeys, Ciphertext destination, MemoryPoolHandle pool = null)1521 public void ComplexConjugate(Ciphertext encrypted, GaloisKeys galoisKeys, 1522 Ciphertext destination, MemoryPoolHandle pool = null) 1523 { 1524 if (null == encrypted) 1525 throw new ArgumentNullException(nameof(encrypted)); 1526 if (null == galoisKeys) 1527 throw new ArgumentNullException(nameof(galoisKeys)); 1528 if (null == destination) 1529 throw new ArgumentNullException(nameof(destination)); 1530 if (!ContextUsingKeyswitching) 1531 throw new InvalidOperationException("Keyswitching is not supported by the context"); 1532 1533 IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero; 1534 NativeMethods.Evaluator_ComplexConjugate( 1535 NativePtr, encrypted.NativePtr, galoisKeys.NativePtr, 1536 destination.NativePtr, poolPtr); 1537 } 1538 1539 /// <summary> 1540 /// Destroy native object. 1541 /// </summary> DestroyNativeObject()1542 protected override void DestroyNativeObject() 1543 { 1544 NativeMethods.Evaluator_Destroy(NativePtr); 1545 } 1546 1547 internal bool ContextUsingKeyswitching 1548 { 1549 get 1550 { 1551 NativeMethods.Evaluator_ContextUsingKeyswitching(NativePtr, out bool result); 1552 return result; 1553 } 1554 } 1555 } 1556 } 1557