Commit c6c9d2f5 authored by Hoang Gia NGUYEN's avatar Hoang Gia NGUYEN
Browse files

first commit

parent fe2d6195
Pipeline #60 failed with stages
in 0 seconds

Too many changes to show.

To preserve performance only 275 of 275+ files are displayed.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace SEALNetExamples
{
public static class Utilities
{
/// <summary>
/// Helper function: Prints the name of the example in a fancy banner.
/// </summary>
public static void PrintExampleBanner(string title)
{
if (!string.IsNullOrEmpty(title))
{
int titleLength = title.Length;
int bannerLength = titleLength + 2 * 10;
string bannerTop = "+" + new string('-', bannerLength - 2) + "+";
string bannerMiddle =
"|" + new string(' ', 9) + title + new string(' ', 9) + "|";
Console.WriteLine();
Console.WriteLine(bannerTop);
Console.WriteLine(bannerMiddle);
Console.WriteLine(bannerTop);
}
}
/// <summary>
/// Helper function: Prints the parameters in a SEALContext.
/// </summary>
public static void PrintParameters(SEALContext context)
{
// Verify parameters
if (null == context)
{
throw new ArgumentNullException("context is not set");
}
SEALContext.ContextData contextData = context.KeyContextData;
/*
Which scheme are we using?
*/
string schemeName = null;
switch (contextData.Parms.Scheme)
{
case SchemeType.BFV:
schemeName = "BFV";
break;
case SchemeType.CKKS:
schemeName = "CKKS";
break;
default:
throw new ArgumentException("unsupported scheme");
}
Console.WriteLine("/");
Console.WriteLine("| Encryption parameters:");
Console.WriteLine($"| Scheme: {schemeName}");
Console.WriteLine("| PolyModulusDegree: {0}",
contextData.Parms.PolyModulusDegree);
/*
Print the size of the true (product) coefficient modulus.
*/
Console.Write("| CoeffModulus size: {0} (",
contextData.TotalCoeffModulusBitCount);
List<Modulus> coeffModulus =
(List<Modulus>)contextData.Parms.CoeffModulus;
for (int i = 0; i < coeffModulus.Count - 1; i++)
{
Console.Write($"{coeffModulus[i].BitCount} + ");
}
Console.WriteLine($"{coeffModulus.Last().BitCount}) bits");
/*
For the BFV scheme print the PlainModulus parameter.
*/
if (contextData.Parms.Scheme == SchemeType.BFV)
{
Console.WriteLine("| PlainModulus: {0}",
contextData.Parms.PlainModulus.Value);
}
Console.WriteLine("\\");
}
/// <summary>
/// Helper function: Print the first and last printSize elements
/// of a 2 row matrix.
/// </summary>
public static void PrintMatrix(IEnumerable<ulong> matrixPar,
int rowSize, int printSize = 5)
{
ulong[] matrix = matrixPar.ToArray();
Console.WriteLine();
/*
We're not going to print every column of the matrix (may be big). Instead
print printSize slots from beginning and end of the matrix.
*/
Console.Write(" [");
for (int i = 0; i < printSize; i++)
{
Console.Write("{0,3}, ", matrix[i]);
}
Console.Write(" ...");
for (int i = rowSize - printSize; i < rowSize; i++)
{
Console.Write(", {0,3}", matrix[i]);
}
Console.WriteLine(" ]");
Console.Write(" [");
for (int i = rowSize; i < rowSize + printSize; i++)
{
Console.Write("{0,3}, ", matrix[i]);
}
Console.Write(" ...");
for (int i = 2 * rowSize - printSize; i < 2 * rowSize; i++)
{
Console.Write(", {0,3}", matrix[i]);
}
Console.WriteLine(" ]");
Console.WriteLine();
}
/// <summary>
/// Helper function: Convert a ulong to a hex string representation
/// </summary>
public static string ULongToString(ulong value)
{
byte[] bytes = BitConverter.GetBytes(value);
return BitConverter.ToString(bytes).Replace("-", "");
}
/// <summary>
/// Helper function: Prints a vector of floating-point values.
/// </summary>
public static void PrintVector<T>(
IEnumerable<T> vec, int printSize = 4, int prec = 3)
{
string numFormat = string.Format("{{0:N{0}}}", prec);
T[] veca = vec.ToArray();
int slotCount = veca.Length;
Console.WriteLine();
if (slotCount <= 2 * printSize)
{
Console.Write(" [");
for (int i = 0; i < slotCount; i++)
{
Console.Write(" " + string.Format(numFormat, veca[i]));
if (i != (slotCount - 1))
Console.Write(",");
else
Console.Write(" ]");
}
Console.WriteLine();
}
else
{
Console.Write(" [");
for (int i = 0; i < printSize; i++)
{
Console.Write(" "+ string.Format(numFormat, veca[i]) + ", ");
}
if (veca.Length > 2 * printSize)
{
Console.Write(" ...");
}
for (int i = slotCount - printSize; i < slotCount; i++)
{
Console.Write(", " + string.Format(numFormat, veca[i]));
}
Console.WriteLine(" ]");
}
Console.WriteLine();
}
public static void PrintLine([CallerLineNumber] int lineNumber = 0)
{
Console.Write("Line {0,3} --> ", lineNumber);
}
}
}
\ No newline at end of file
# Creating a NuGet package
After building `dotnet\src\SEALNet.csproj` you can create a NuGet package that you can
use to easily add Microsoft SEAL capabilities to all of your .NET projects. Currently
the NuGet package is only supported in Windows.
You will need to:
1. Compile binaries
1. `native\src\SEAL.vcxproj`
2. `native\src\SEAL_C.vcxproj`
3. `dotnet\src\SEALNet.csproj`
3. [Download the NuGet command line tool](https://dist.nuget.org/win-x86-commandline/latest/nuget.exe)
4. Run the command below to create NuGet package
5. Add NuGet package reference to your .NET projects
The command to create the NuGet package after compiling binaries is the following:
````
cd dotnet\nuget
nuget.exe pack SEALNet.nuspec -properties Configuration=Release -Verbosity detailed -OutputDir Release
cd ..\..
````
After the package is created, copy it from `dotnet\nuget\Release` to a known location (e.g., `C:\NuGetPackages`).
To add a reference to the NuGet package, you will need to configure Visual Studio so it can find
packages in this known location. In Microsoft Visual Studio 2019, for example, you can:
1. Select the menu uption `Tools / Options...`
2. On the left pane of the Options dialog, navigate to `NuGet Package Manager / Package Sources`
3. On the right pane of the Options dialog, add a new package source that points to the directory
where you copied the NuGet package (e.g., `C:\NuGetPackages`)
After this, you should be able to add a reference to this package in your own .NET project. After
creating or opening your project in Visual Studio, you can right click on the project in the
Solution Explorer window, and select `Manage NuGet packages...`. In the window that appears
you will be able to select the `Microsoft.Research.SEAL` NuGet package to add to your project.
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT license. -->
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Microsoft.Research.SEALNet</id>
<version>@SEAL_VERSION@</version>
<title>Microsoft SEAL</title>
<authors>Microsoft</authors>
<owners>Microsoft</owners>
<projectUrl>http://sealcrypto.org</projectUrl>
<license type="file">LICENSE</license>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Microsoft SEAL is an easy-to-use and powerful open source homomorphic encryption library, developed by researchers in the Cryptography and Privacy Research Group at Microsoft Research. Microsoft SEAL is licensed under the MIT license.</description>
<releaseNotes>https://GitHub.com/Microsoft/SEAL</releaseNotes>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<tags>c# crypto cryptography homomorphic encryption</tags>
<dependencies>
<group targetFramework=".NETStandard2.0" />
</dependencies>
</metadata>
<files>
<file src="SEALNet.targets" target="build/Microsoft.Research.SEALNet.targets" />
<file src="$NUGET_WINDOWS_SEAL_C_PATH$" target="runtimes/win10-x64" />
<file src="$NUGET_LINUX_SEAL_C_PATH$" target="runtimes/linux-x64" />
<file src="$NUGET_MACOS_SEAL_C_PATH$" target="runtimes/macos-x64" />
<file src="$NUGET_ANDROIDARM64_SEAL_C_PATH$" target="runtimes/android-arm64" />
<file src="$NUGET_ANDROIDX64_SEAL_C_PATH$" target="runtimes/android-x64" />
<file src="../../lib/dotnet/$configuration$/netstandard2.0/SEALNet.dll" target="lib/netstandard2.0/" />
<file src="../../LICENSE" target="LICENSE" />
</files>
</package>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT license. -->
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Microsoft.Research.SEALNet</id>
<version>@SEAL_VERSION@</version>
<title>Microsoft SEAL</title>
<authors>Microsoft</authors>
<owners>Microsoft</owners>
<projectUrl>http://sealcrypto.org</projectUrl>
<license type="file">LICENSE</license>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Microsoft SEAL is an easy-to-use and powerful open source homomorphic encryption library, developed by researchers in the Cryptography and Privacy Research Group at Microsoft Research. Microsoft SEAL is licensed under the MIT license.</description>
<releaseNotes>https://GitHub.com/Microsoft/SEAL</releaseNotes>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<tags>c# crypto cryptography homomorphic encryption</tags>
<dependencies>
<group targetFramework=".NETStandard2.0" />
</dependencies>
</metadata>
<files>
<file src="SEALNet.targets" target="build/Microsoft.Research.SEALNet.targets" />
<file src="@SEAL_WINDOWS_SEAL_C_PATH@" target="runtimes/win10-x64" />
<file src="@SEAL_LINUX_SEAL_C_PATH@" target="runtimes/linux-x64" />
<file src="@SEAL_MACOS_SEAL_C_PATH@" target="runtimes/macos-x64" />
<file src="../../lib/dotnet/$configuration$/netstandard2.0/SEALNet.dll" target="lib/netstandard2.0/" />
<file src="../../LICENSE" target="LICENSE" />
</files>
</package>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT license. -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<SEALCBinaryFiles Condition="$([MSBuild]::IsOsPlatform('Windows'))" Include="$(MSBuildThisFileDirectory)../runtimes/win10-x64/sealc.dll" />
<SEALCBinaryFiles Condition="$([MSBuild]::IsOsPlatform('Linux'))" Include="$(MSBuildThisFileDirectory)../runtimes/linux-x64/libsealc.so*" />
<SEALCBinaryFiles Condition="$([MSBuild]::IsOsPlatform('OSX'))" Include="$(MSBuildThisFileDirectory)../runtimes/macos-x64/libsealc*.dylib" />
</ItemGroup>
<ItemGroup Condition="'$(AndroidApplication)'!='True'">
<None Include="@(SEALCBinaryFiles)">
<Link Condition="$([MSBuild]::IsOsPlatform('Windows'))">sealc.dll</Link>
<Link Condition="$([MSBuild]::IsOsPlatform('Linux'))">libsealc.so</Link>
<Link Condition="$([MSBuild]::IsOsPlatform('OSX'))">libsealc.dylib</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup Condition="'$(AndroidApplication)'=='True'">
<AndroidNativeLibrary Include="$(MSBuildThisFileDirectory)../runtimes/android-arm64/libsealc.so">
<Abi>arm64-v8a</Abi>
<Link>libs\arm64-v8a\libsealc.so</Link>
</AndroidNativeLibrary>
<AndroidNativeLibrary Include="$(MSBuildThisFileDirectory)../runtimes/android-x64/libsealc.so">
<Abi>x86_64</Abi>
<Link>libs\x86_64\libsealc.so</Link>
</AndroidNativeLibrary>
</ItemGroup>
</Project>
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Provides functionality for CRT batching. If the polynomial modulus degree is N, and
/// the plaintext modulus is a prime number T such that T is congruent to 1 modulo 2N,
/// then BatchEncoder allows the plaintext elements to be viewed as 2-by-(N/2)
/// matrices of integers modulo T. Homomorphic operations performed on such encrypted
/// matrices are applied coefficient (slot) wise, enabling powerful SIMD functionality
/// for computations that are vectorizable. This functionality is often called "batching"
/// in the homomorphic encryption literature.
/// </summary>
/// <remarks>
/// <para>
/// Mathematical Background
/// Mathematically speaking, if the polynomial modulus is X^N+1, N is a power of two, and
/// PlainModulus is a prime number T such that 2N divides T-1, then integers modulo T
/// contain a primitive 2N-th root of unity and the polynomial X^N+1 splits into n distinct
/// linear factors as X^N+1 = (X-a_1)*...*(X-a_N) mod T, where the constants a_1, ..., a_n
/// are all the distinct primitive 2N-th roots of unity in integers modulo T. The Chinese
/// Remainder Theorem (CRT) states that the plaintext space Z_T[X]/(X^N+1) in this case is
/// isomorphic (as an algebra) to the N-fold direct product of fields Z_T. The isomorphism
/// is easy to compute explicitly in both directions, which is what this class does.
/// Furthermore, the Galois group of the extension is (Z/2NZ)* ~= Z/2Z x Z/(N/2) whose
/// action on the primitive roots of unity is easy to describe. Since the batching slots
/// correspond 1-to-1 to the primitive roots of unity, applying Galois automorphisms on the
/// plaintext act by permuting the slots. By applying generators of the two cyclic
/// subgroups of the Galois group, we can effectively view the plaintext as a 2-by-(N/2)
/// matrix, and enable cyclic row rotations, and column rotations (row swaps).
/// </para>
/// <para>
/// Valid Parameters
/// Whether batching can be used depends on whether the plaintext modulus has been chosen
/// appropriately. Thus, to construct a BatchEncoder the user must provide an instance
/// of SEALContext such that its associated EncryptionParameterQualifiers object has the
/// flags ParametersSet and EnableBatching set to true.
/// </para>
/// </remarks>
/// <see cref="EncryptionParameters">see EncryptionParameters for more information about encryption parameters.</see>
/// <see cref="EncryptionParameterQualifiers">see EncryptionParameterQualifiers for more information about parameter qualifiers.</see>
/// <see cref="Evaluator">see Evaluator for rotating rows and columns of encrypted matrices.</see>
public class BatchEncoder : NativeObject
{
/// <summary>
/// Creates a BatchEncoder. It is necessary that the encryption parameters
/// given through the SEALContext object support batching.
/// </summary>
/// <param name="context">The SEALContext</param>
/// @param[in] context
/// <exception cref="ArgumentNullException">if context is null.</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid for batching</exception>
/// <exception cref="ArgumentException">if scheme is not SchemeType.BFV</exception>
public BatchEncoder(SEALContext context)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (!context.ParametersSet)
throw new ArgumentException("Encryption parameters are not set correctly");
SEALContext.ContextData contextData = context.FirstContextData;
if (contextData.Parms.Scheme != SchemeType.BFV)
throw new ArgumentException("Unsupported scheme");
if (!contextData.Qualifiers.UsingBatching)
throw new ArgumentException("Encryption parameters are not valid for batching");
NativeMethods.BatchEncoder_Create(context.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Creates a plaintext from a given matrix. This function "batches" a given matrix
/// of integers modulo the plaintext modulus into a plaintext element, and stores
/// the result in the destination parameter. The input vector must have size at most equal
/// to the degree of the polynomial modulus. The first half of the elements represent the
/// first row of the matrix, and the second half represent the second row. The numbers
/// in the matrix can be at most equal to the plaintext modulus for it to represent
/// a valid plaintext.
///
/// If the destination plaintext overlaps the input values in memory, the behavior of
/// this function is undefined.
/// </summary>
/// <param name="values">The matrix of integers modulo plaintext modulus to batch</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <exception cref="ArgumentNullException">if either values or destination are null</exception>
/// <exception cref="ArgumentException">if values is too large</exception>
public void Encode(IEnumerable<ulong> values, Plaintext destination)
{
if (null == values)
throw new ArgumentNullException(nameof(values));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
ulong[] valarray = values.ToArray();
NativeMethods.BatchEncoder_Encode(NativePtr, (ulong)valarray.LongLength, valarray, destination.NativePtr);
}
/// <summary>
/// Creates a plaintext from a given matrix. This function "batches" a given matrix
/// of integers modulo the plaintext modulus into a plaintext element, and stores
/// the result in the destination parameter. The input vector must have size at most equal
/// to the degree of the polynomial modulus. The first half of the elements represent the
/// first row of the matrix, and the second half represent the second row. The numbers
/// in the matrix can be at most equal to the plaintext modulus for it to represent
/// a valid plaintext.
///
/// If the destination plaintext overlaps the input values in memory, the behavior of
/// this function is undefined.
/// </summary>
/// <param name="values">The matrix of integers modulo plaintext modulus to batch</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <exception cref="ArgumentNullException">if either values or destionation are null</exception>
/// <exception cref="ArgumentException">if values is too large</exception>
public void Encode(IEnumerable<long> values, Plaintext destination)
{
if (null == values)
throw new ArgumentNullException(nameof(values));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
long[] valarray = values.ToArray();
NativeMethods.BatchEncoder_Encode(NativePtr, (ulong)valarray.LongLength, valarray, destination.NativePtr);
}
/// <summary>
/// Creates a plaintext from a given matrix. This function "batches" a given matrix
/// of integers modulo the plaintext modulus in-place into a plaintext ready to be
/// encrypted. The matrix is given as a plaintext element whose first N/2 coefficients
/// represent the first row of the matrix, and the second N/2 coefficients represent the
/// second row, where N denotes the degree of the polynomial modulus. The input plaintext
/// must have degress less than the polynomial modulus, and coefficients less than the
/// plaintext modulus, i.e. it must be a valid plaintext for the encryption parameters.
/// Dynamic memory allocations in the process are allocated from the memory pool pointed
/// to by the given MemoryPoolHandle.
/// </summary>
/// <param name="plain">The matrix of integers modulo plaintext modulus to batch</param>
/// <param name="pool"></param>
/// <exception cref="ArgumentNullException">if plain is null.</exception>
/// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if plain is in NTT form</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Encode(Plaintext plain, MemoryPoolHandle pool = null)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.BatchEncoder_Encode(NativePtr, plain.NativePtr, poolPtr);
}
/// <summary>
/// Inverse of encode. This function "unbatches" a given plaintext into a matrix
/// of integers modulo the plaintext modulus, and stores the result in the destination
/// parameter. The input plaintext must have degress less than the polynomial modulus,
/// and coefficients less than the plaintext modulus, i.e. it must be a valid plaintext
/// for the encryption parameters. Dynamic memory allocations in the process are
/// allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </summary>
/// <param name="plain">The plaintext polynomial to unbatch</param>
/// <param name="destination">The matrix to be overwritten with the values in the slots</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either plain or destionation are null</exception>
/// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if plain is in NTT form</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Decode(Plaintext plain, ICollection<ulong> destination, MemoryPoolHandle pool = null)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
ulong destCount = 0;
// Allocate a big enough array to hold the result
ulong[] destArray = new ulong[SlotCount];
NativeMethods.BatchEncoder_Decode(NativePtr, plain.NativePtr, ref destCount, destArray, poolPtr);
// Transfer result to actual destination
destination.Clear();
for (ulong i = 0; i < destCount; i++)
{
destination.Add(destArray[i]);
}
}
/// <summary>
/// Inverse of encode. This function "unbatches" a given plaintext into a matrix
/// of integers modulo the plaintext modulus, and stores the result in the destination
/// parameter. The input plaintext must have degress less than the polynomial modulus,
/// and coefficients less than the plaintext modulus, i.e. it must be a valid plaintext
/// for the encryption parameters. Dynamic memory allocations in the process are
/// allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </summary>
/// <param name="plain">The plaintext polynomial to unbatch</param>
/// <param name="destination">The matrix to be overwritten with the values in the slots</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either plain or destination are null</exception>
/// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if plain is in NTT form</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Decode(Plaintext plain, ICollection<long> destination, MemoryPoolHandle pool = null)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
ulong destCount = 0;
// Allocate a big enough array to hold the result
long[] destArray = new long[SlotCount];
NativeMethods.BatchEncoder_Decode(NativePtr, plain.NativePtr, ref destCount, destArray, poolPtr);
// Transfer result to actual destination
destination.Clear();
for (ulong i = 0; i < destCount; i++)
{
destination.Add(destArray[i]);
}
}
/// <summary>
/// Inverse of encode. This function "unbatches" a given plaintext in-place into
/// a matrix of integers modulo the plaintext modulus. The input plaintext must have
/// degress less than the polynomial modulus, and coefficients less than the plaintext
/// modulus, i.e. it must be a valid plaintext for the encryption parameters. Dynamic
/// memory allocations in the process are allocated from the memory pool pointed to by
/// the given MemoryPoolHandle.
/// </summary>
/// <param name="plain">The plaintext polynomial to unbatch</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if plain is null</exception>
/// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if plain is in NTT form</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Decode(Plaintext plain, MemoryPoolHandle pool = null)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.BatchEncoder_Decode(NativePtr, plain.NativePtr, poolPtr);
}
/// <summary>
/// Returns the number of slots.
/// </summary>
public ulong SlotCount
{
get
{
NativeMethods.BatchEncoder_GetSlotCount(NativePtr, out ulong slotCount);
return slotCount;
}
}
/// <summary>
/// Destroy native object
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.BatchEncoder_Destroy(NativePtr);
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.IO;
using System.Numerics;
using System.Text;
using Microsoft.Research.SEAL.Tools;
using System.Runtime.InteropServices;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Represents an unsigned integer with a specified bit width.
/// </summary>
/// <remarks>
/// <para>
/// Represents an unsigned integer with a specified bit width. BigUInts are mutable
/// and able to be resized. The bit count for a BigUInt (which can be read with
/// <see cref="BitCount"/>) is set initially by the constructor and can be resized
/// either explicitly with the <see cref="Resize(int)"/> function or implicitly
/// with an assignment operation (e.g., one of the Set() functions). A rich set
/// of unsigned integer operations are provided by the BigUInt class, including
/// comparison, traditional arithmetic (addition, subtraction, multiplication,
/// division), and modular arithmetic functions.
/// </para>
/// <para>
/// The backing array for a BigUInt stores its unsigned integer value as a contiguous
/// System.UInt64 array. Each System.UInt64 in the array sequentially represents
/// 64-bits of the integer value, with the least significant quad-word storing the
/// lower 64-bits and the order of the bits for each quad word dependent on the
/// architecture's System.UInt64 representation. The size of the array equals the bit
/// count of the BigUInt (which can be read with <see cref="BitCount"/>) rounded up
/// to the next System.UInt64 boundary (i.e., rounded up to the next 64-bit boundary).
/// The <see cref="UInt64Count"/> property returns the number of System.UInt64 in the
/// backing array. The <see cref="Data(ulong)"/> method returns an element of the
/// System.UInt64 array. Additionally, the index property allows accessing the
/// individual bytes of the integer value in a platform-independent way - for example,
/// reading the third byte will always return bits 16-24 of the BigUInt value
/// regardless of the platform being little-endian or big-endian.
/// </para>
/// <para>
/// Both the copy constructor and the Set function allocate more memory for the
/// backing array when needed, i.e. when the source BigUInt has a larger backing
/// array than the destination. Conversely, when the destination backing array is
/// already large enough, the data is only copied and the unnecessary higher order
/// bits are set to zero. When new memory has to be allocated, only the significant
/// bits of the source BigUInt are taken into account. This is is important, because
/// it avoids unnecessary zero bits to be included in the destination, which in some
/// cases could accumulate and result in very large unnecessary allocations. However,
/// sometimes it is necessary to preserve the original size, even if some of the
/// leading bits are zero. For this purpose BigUInt contains functions
/// <see cref="DuplicateFrom"/> and <see cref="DuplicateTo"/>, which create an exact
/// copy of the source BigUInt.
/// </para>
/// <para>
/// An aliased BigUInt (which can be determined with <see cref="IsAlias"/>) is
/// a special type of BigUInt that does not manage its underlying System.UInt64
/// pointer used to store the value. An aliased BigUInt supports most of the same
/// operations as a non-aliased BigUInt, including reading and writing the value,
/// however an aliased BigUInt does not internally allocate or deallocate its backing
/// array and, therefore, does not support resizing. Any attempt, either explicitly
/// or implicitly, to resize the BigUInt will result in an exception being thrown.
/// Aliased BigUInt's are only created internally. Aliasing is useful in cases where
/// it is desirable to not have each BigUInt manage its own memory allocation and/or
/// to prevent unnecessary copying.
/// </para>
/// <para>
/// In general, reading a BigUInt is thread-safe while mutating is not. Specifically,
/// the backing array may be freed whenever a resize occurs or the BigUInt is
/// destroyed. When it is known that a resize will not occur, concurrent reading and
/// mutating will not inherently fail but it is possible for a read to see a partially
/// updated value from a concurrent write. A non-aliased BigUInt allocates its backing
/// array from the global (thread-safe) memory pool. Consequently, creating or
/// resizing a large number of BigUInt can result in a performance loss due to thread
/// contention.
/// </para>
/// </remarks>
public class BigUInt : NativeObject, IEquatable<BigUInt>, IComparable<BigUInt>
{
/// <summary>Creates an empty BigUInt with zero bit width.</summary>
/// <remarks>
/// Creates an empty BigUInt with zero bit width. No memory is allocated by
/// this constructor.
/// </remarks>
public BigUInt()
{
IntPtr ptr = IntPtr.Zero;
NativeMethods.BigUInt_Create(out ptr);
NativePtr = ptr;
}
/// <summary>Creates a zero-initialized BigUInt of the specified bit
/// width.</summary>
/// <param name="bitCount">The bit width</param>
/// <exception cref="ArgumentException">if bitCount is negative</exception>
public BigUInt(int bitCount)
{
if (bitCount < 0)
throw new ArgumentException("bitCount cannot be negative");
IntPtr ptr = IntPtr.Zero;
NativeMethods.BigUInt_Create(bitCount, out ptr);
NativePtr = ptr;
}
/// <summary>Creates a BigUInt of the specified bit width and initializes
/// it with the unsigned hexadecimal integer specified by the string.</summary>
/// <remarks>
/// Creates a BigUInt of the specified bit width and initializes it with
/// the unsigned hexadecimal integer specified by the string. The string
/// must match the format returned by <see cref="ToString()"/> and must
/// consist of only the characters 0-9, A-F, or a-f, most-significant nibble
/// first.
/// </remarks>
///
/// <param name="bitCount">The bit width</param>
/// <param name="hexString">The hexadecimal integer string specifying the
/// initial value</param>
/// <exception cref="ArgumentNullException">if hexString is null</exception>
/// <exception cref="ArgumentException">if bitCount is negative</exception>
/// <exception cref="ArgumentException">if hexString does not adhere to the
/// expected format</exception>
public BigUInt(int bitCount, string hexString)
{
if (null == hexString)
throw new ArgumentNullException(nameof(hexString));
if (bitCount < 0)
throw new ArgumentException("bitCount cannot be negative");
IntPtr ptr = IntPtr.Zero;
NativeMethods.BigUInt_Create(bitCount, hexString, out ptr);
NativePtr = ptr;
}
/// <summary>Creates a BigUInt of the specified bit width and initializes it
/// to the specified unsigned integer value.</summary>
///
/// <param name="bitCount"> The bit width</param>
/// <param name="value"> The initial value to set the BigUInt</param>
/// <exception cref="ArgumentException">if bitCount is negative</exception>
public BigUInt(int bitCount, ulong value)
{
if (bitCount < 0)
throw new ArgumentException("bitCount cannot be negative");
IntPtr ptr = IntPtr.Zero;
NativeMethods.BigUInt_Create(bitCount, value, out ptr);
NativePtr = ptr;
}
/// <summary>Creates a BigUInt initialized and minimally sized to fit the
/// unsigned hexadecimal integer specified by the string.</summary>
/// <remarks>
/// Creates a BigUInt initialized and minimally sized to fit the unsigned
/// hexadecimal integer specified by the string. The string matches the format
/// returned by<see cref= "ToString()" /> and must consist of only the characters
/// 0-9, A-F, or a-f, most-significant nibble first.
/// </remarks>
/// <param name="hexString"> The hexadecimal integer string specifying the
/// initial value</param>
/// <exception cref="ArgumentNullException">if hexString is null</exception>
/// <exception cref="ArgumentException">if hexString does not adhere to the
/// expected format</exception>
public BigUInt(string hexString)
{
if (null == hexString)
throw new ArgumentNullException(nameof(hexString));
IntPtr ptr = IntPtr.Zero;
NativeMethods.BigUInt_Create(hexString, out ptr);
NativePtr = ptr;
}
/// <summary>Creates a deep copy of a BigUInt.</summary>
/// <remarks>
/// Creates a deep copy of a BigUInt. The created BigUInt will have the same
/// bit count and value as the original.
/// </remarks>
/// <param name="copy">The BigUInt to copy from</param>
/// <exception cref="ArgumentNullException">if copy is null</exception>
public BigUInt(BigUInt copy)
{
if (null == copy)
throw new ArgumentNullException(nameof(copy));
IntPtr ptr = IntPtr.Zero;
NativeMethods.BigUInt_Create(copy.NativePtr, out ptr);
NativePtr = ptr;
}
/// <summary>
/// Creates a BigUInt initialized and minimally sized to fit the unsigned
/// hexadecimal integer specified by the <see cref= "System.Numerics.BigInteger" />.
/// </summary >
/// <param name= "bigInteger"> The initial value of the BigUInt</param>
/// <exception cref="ArgumentNullException">if bigInteger is null</exception>
public BigUInt(BigInteger bigInteger)
{
if (null == bigInteger)
throw new ArgumentNullException(nameof(bigInteger));
string hex = bigInteger.ToString("X");
IntPtr ptr = IntPtr.Zero;
NativeMethods.BigUInt_Create(hex, out ptr);
NativePtr = ptr;
}
/// <summary>
/// Creates a BigUInt from an IntPtr.
/// </summary>
/// <param name="ptr">Native pointer</param>
/// <param name="owned">Whether this BigUInt instance owns the native
/// pointer</param>
internal BigUInt(IntPtr ptr, bool owned = true)
: base(ptr, owned)
{
}
/// <summary>Returns whether or not the BigUInt is an alias.</summary>
public bool IsAlias
{
get
{
NativeMethods.BigUInt_IsAlias(NativePtr, out bool isAlias);
return isAlias;
}
}
/// <summary>Returns the bit count for the BigUInt.</summary>
public int BitCount
{
get
{
NativeMethods.BigUInt_BitCount(NativePtr, out int bitCount);
return bitCount;
}
}
/// <summary>Returns the number of bytes in the backing array used to store
/// the BigUInt value.</summary>
public ulong ByteCount
{
get
{
NativeMethods.BigUInt_ByteCount(NativePtr, out ulong byteCount);
return byteCount;
}
}
/// <summary>Returns the number of System.UInt64 in the backing array used
/// to store the BigUInt value.</summary>
public ulong UInt64Count
{
get
{
NativeMethods.BigUInt_UInt64Count(NativePtr, out ulong uint64Count);
return uint64Count;
}
}
/// <summary>Gets/sets the byte at the corresponding byte index of the BigUInt's
/// integer value.</summary>
/// <remarks>
/// Gets/sets the byte at the corresponding byte index of the BigUInt's integer
/// value. The bytes of the BigUInt are indexed least-significant byte first.
/// </remarks>
/// <param name="index"> The index of the byte to get/set</param>
/// <exception cref="ArgumentOutOfRangeException">if index is not within
/// [0, <see cref="ByteCount"/>)</exception>
public byte this[ulong index]
{
get
{
if (index >= ByteCount)
throw new ArgumentOutOfRangeException(nameof(index));
NativeMethods.BigUInt_Get(NativePtr, index, out byte result);
return result;
}
set
{
if (index >= ByteCount)
throw new ArgumentOutOfRangeException(nameof(index));
NativeMethods.BigUInt_Set(NativePtr, index, value);
}
}
/// <summary>
/// Returns the ulong value at a given position in the backing array storing
/// the BigUInt value.
/// </summary>
/// <remarks>
/// Returns the <see cref="ulong"/> value that is at position <paramref name="index"/>
/// in the backing array storing the BigUInt value.
/// </remarks>
/// <param name="index"></param>
/// <exception cref="ArgumentOutOfRangeException">if index is not within
/// [0, <see cref="UInt64Count"/>)</exception>
public ulong Data(ulong index)
{
if (index >= UInt64Count)
throw new ArgumentOutOfRangeException(nameof(index));
NativeMethods.BigUInt_GetU64(NativePtr, index, out ulong result);
return result;
}
/// <summary>
/// Returns whether or not the BigUInt has the value zero.
/// </summary>
public bool IsZero
{
get
{
NativeMethods.BigUInt_IsZero(NativePtr, out bool isZero);
return isZero;
}
}
/// <summary>
/// Returns the number of significant bits for the BigUInt.
/// </summary>
public int GetSignificantBitCount()
{
NativeMethods.BigUInt_GetSignificantBitCount(NativePtr, out int result);
return result;
}
/// <summary>
/// Overwrites the BigUInt with the value of the specified BigUInt, enlarging
/// if needed to fit the assigned value.
/// </summary>
/// <remarks>
/// Overwrites the BigUInt with the value of the specified BigUInt, enlarging
/// if needed to fit the assigned value. Only significant bits are used to size
/// the BigUInt.
/// </remarks>
/// <param name="assign"> The BigUInt whose value should be assigned to the
/// current BigUInt</param>
/// <exception cref="ArgumentNullException">if assign is null</exception>
/// <exception cref="InvalidOperationException">if BigUInt is an alias and
/// the assigned BigUInt is too large to fit the current bit width</exception>
public void Set(BigUInt assign)
{
if (null == assign)
throw new ArgumentNullException(nameof(assign));
if (IsAlias)
throw new InvalidOperationException("Cannot assign to an alias");
NativeMethods.BigUInt_Set(NativePtr, assign.NativePtr);
}
/// <summary>
/// Overwrites the BigUInt with the unsigned hexadecimal value specified by
/// the string, enlarging if needed to fit the assigned value.
/// </summary>
/// <remarks>
/// Overwrites the BigUInt with the unsigned hexadecimal value specified by
/// the string, enlarging if needed to fit the assigned value. The string must
/// match the format returned by<see cref="ToString()"/> and must consist of
/// only the characters 0-9, A-F, or a-f, most-significant nibble first.
/// </remarks>
/// <param name="assign"> The hexadecimal integer string specifying the value
/// to assign</param>
/// <exception cref="ArgumentNullException">if assign is null</exception>
/// <exception cref="ArgumentException">if assign does not adhere to the
/// expected format</exception>
/// <exception cref="InvalidOperationException">if BigUInt is an alias and
/// the assigned value is too large to fit the current bit width</exception>
public void Set(string assign)
{
if (null == assign)
throw new ArgumentNullException(nameof(assign));
if (IsAlias)
throw new InvalidOperationException("Cannot assign to an alias");
NativeMethods.BigUInt_Set(NativePtr, assign);
}
/// <summary>Overwrites the BigUInt with the specified integer value, enlarging
/// if needed to fit the value.</summary>
///
/// <param name="assign"> The value to assign</param>
/// <exception cref="InvalidOperationException">if BigUInt is an alias and
/// the significant bit count of assign is too large to fit the current bit
/// width</exception>
public void Set(ulong assign)
{
NativeMethods.BigUInt_Set(NativePtr, assign);
}
/// <summary>Sets the BigUInt value to zero.</summary>
/// <remarks>
/// Sets the BigUInt value to zero. This does not resize the BigUInt.
/// </remarks>
public void SetZero()
{
NativeMethods.BigUInt_SetZero(NativePtr);
}
/// <summary>
/// Returns an upper bound on the size of the BigUInt, as if it was written
/// to an output stream.
/// </summary>
/// <param name="comprMode">The compression mode</param>
/// <exception cref="ArgumentException">if the compression mode is not
/// supported</exception>
/// <exception cref="InvalidOperationException">if the size does not fit in
/// the return type</exception>
public long SaveSize(ComprModeType? comprMode = null)
{
comprMode = comprMode ?? Serialization.ComprModeDefault;
if (!Serialization.IsSupportedComprMode(comprMode.Value))
throw new ArgumentException("Unsupported compression mode");
ComprModeType comprModeValue = comprMode.Value;
NativeMethods.BigUInt_SaveSize(
NativePtr, (byte)comprModeValue, out long outBytes);
return outBytes;
}
/// <summary>Saves the BigUInt to an output stream.</summary>
/// <remarks>
/// Saves the BigUInt to an output stream. The full state of the BigUInt is
/// serialized, including insignificant bits. The output is in binary format
/// and not human-readable.
/// </remarks>
/// <param name="stream">The stream to save the BigUInt to</param>
/// <param name="comprMode">The desired compression mode</param>
/// <exception cref="ArgumentNullException">if stream is null</exception>
/// <exception cref="ArgumentException">if the stream is closed or does not
/// support writing, or if compression mode is not supported</exception>
/// <exception cref="IOException">if I/O operations failed</exception>
/// <exception cref="InvalidOperationException">if the data to be saved
/// is invalid, or if compression failed</exception>
public long Save(Stream stream, ComprModeType? comprMode = null)
{
comprMode = comprMode ?? Serialization.ComprModeDefault;
if (!Serialization.IsSupportedComprMode(comprMode.Value))
throw new ArgumentException("Unsupported compression mode");
ComprModeType comprModeValue = comprMode.Value;
return Serialization.Save(
(byte[] outptr, ulong size, byte cm, out long outBytes) =>
NativeMethods.BigUInt_Save(NativePtr, outptr, size,
cm, out outBytes),
SaveSize(comprModeValue), comprModeValue, stream);
}
/// <summary>
/// Loads a BigUInt from an input stream overwriting the current BigUInt.
/// </summary>
/// <param name="stream">The stream to load the BigUInt from</param>
/// <exception cref="ArgumentNullException">if stream is null</exception>
/// <exception cref="ArgumentException">if the stream is closed or does not
/// support reading</exception>
/// <exception cref="EndOfStreamException">if the stream ended
/// unexpectedly</exception>
/// <exception cref="IOException">if I/O operations failed</exception>
/// <exception cref="InvalidOperationException">if the data cannot be loaded
/// by this version of Microsoft SEAL, if the loaded data is invalid, if the
/// loaded compression mode is not supported, or if the loaded BigUInt is too
/// large for an aliased BigUInt</exception>
public long Load(Stream stream)
{
return Serialization.Load(
(byte[] outptr, ulong size, out long outBytes) =>
NativeMethods.BigUInt_Load(NativePtr, outptr, size, out outBytes),
stream);
}
/// <summary>
/// Resizes the BigUInt to the specified bit width, copying over the old
/// value as much as will fit.
/// </summary>
/// <param name="bitCount">The bit width</param>
/// <exception cref="ArgumentException">if bitCount is negative</exception>
/// <exception cref="InvalidOperationException">if the BigUInt is an
/// alias</exception>
public void Resize(int bitCount)
{
if (bitCount < 0)
throw new ArgumentException("bitCount cannot be negative");
if (IsAlias)
throw new InvalidOperationException("Cannot resize an alias");
NativeMethods.BigUInt_Resize(NativePtr, bitCount);
}
/// <summary>
/// Returns the BigUInt value as a <see cref="System.Numerics.BigInteger"/>.
/// </summary>
public BigInteger ToBigInteger()
{
ulong byteCount = ByteCount;
byte[] bytes = new byte[byteCount + 1];
for (ulong i = 0; i < byteCount; i++)
{
bytes[i] = this[i];
}
bytes[byteCount] = 0;
BigInteger result = new BigInteger(bytes);
return result;
}
/// <summary>
/// Returns the BigUInt value as a decimal string.
/// </summary>
public string ToDecimalString()
{
NativeMethods.BigUInt_ToDecimalString(NativePtr, null, length: out ulong length);
StringBuilder buffer = new StringBuilder(checked((int)length));
NativeMethods.BigUInt_ToDecimalString(NativePtr, buffer, out length);
return buffer.ToString();
}
/// <summary>
/// Compares a BigUInt and an unsigned integer and returns -1, 0, or 1 if
/// the BigUInt is less-than, equal-to, or greater-than the second operand
/// respectively. The input operands are not modified.
/// </summary>
/// <param name="compare">The value to compare against</param>
public int CompareTo(ulong compare)
{
NativeMethods.BigUInt_CompareTo(NativePtr, compare, out int result);
return result;
}
/// <summary>Divides two BigUInts and returns the quotient and sets the
/// remainder parameter to the remainder.</summary>
/// <remarks>
/// Divides two BigUInts and returns the quotient and sets the remainder
/// parameter to the remainder. The bit count of the quotient is set to be
/// the significant bit count of the BigUInt. The remainder is resized if
/// and only if it is smaller than the bit count of the BigUInt.
/// </remarks>
/// <param name="operand2">The second operand to divide</param>
/// <param name="remainder">The BigUInt to store the remainder</param>
/// <exception cref="ArgumentNullException">if operand2 or remainder is
/// null</exception>
/// <exception cref="ArgumentException">if operand2 is zero</exception>
/// <exception cref="InvalidOperationException">if the remainder is an alias
/// and the operator attempts to enlarge the BigUInt to fit the result</exception>
public BigUInt DivideRemainder(BigUInt operand2, BigUInt remainder)
{
if (null == operand2)
throw new ArgumentNullException(nameof(operand2));
if (null == remainder)
throw new ArgumentNullException(nameof(remainder));
if (operand2.IsZero)
throw new ArgumentException("operand2 is zero");
if (remainder.IsAlias)
throw new InvalidOperationException("remainder is an alias");
NativeMethods.BigUInt_DivideRemainder(NativePtr, operand2.NativePtr,
remainder.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Divides a BigUInt and an unsigned integer and returns the quotient
/// and sets the remainder parameter to the remainder.</summary>
///
/// <remarks>
/// Divides a BigUInt and an unsigned integer and returns the quotient and
/// sets the remainder parameter to the remainder. The bit count of the quotient
/// is set to be the significant bit count of the BigUInt. The remainder is
/// resized if and only if it is smaller than the bit count of the BigUInt.
/// </remarks>
/// <param name="operand2">The second operand to divide</param>
/// <param name="remainder">The BigUInt to store the remainder</param>
/// <exception cref="ArgumentNullException">if remainder is null</exception>
/// <exception cref="ArgumentException">if operand2 is zero</exception>
/// <exception cref="InvalidOperationException">if the remainder is an alias
/// which the function attempts to enlarge to fit the result</exception>
public BigUInt DivideRemainder(ulong operand2, BigUInt remainder)
{
if (null == remainder)
throw new ArgumentNullException(nameof(remainder));
if (operand2 == 0)
throw new ArgumentException("operand2 is zero");
if (remainder.IsAlias)
throw new InvalidOperationException("remainder is an alias");
NativeMethods.BigUInt_DivideRemainder(NativePtr, operand2,
remainder.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Returns the inverse of a BigUInt with respect to the specified
/// modulus.</summary>
/// <remarks>
/// Returns the inverse of a BigUInt with respect to the specified modulus.
/// The original BigUInt is not modified. The bit count of the inverse is
/// set to be the significant bit count of the modulus.
/// </remarks>
/// <param name="modulus">The modulus to calculate the inverse with respect
/// to</param>
/// <exception cref="ArgumentNullException">if modulus is null</exception>
/// <exception cref="ArgumentException">if modulus is zero</exception>
/// <exception cref="ArgumentException">if modulus is not greater than the
/// BigUInt value</exception>
/// <exception cref="ArgumentException">if the BigUInt value and modulus
/// are not co-prime</exception>
/// <exception cref="InvalidOperationException">if the BigUInt value is
/// zero</exception>
public BigUInt ModuloInvert(BigUInt modulus)
{
if (null == modulus)
throw new ArgumentNullException(nameof(modulus));
BigUInt result = null;
NativeMethods.BigUInt_ModuloInvert(NativePtr, modulus.NativePtr,
out IntPtr resultptr);
result = new BigUInt(resultptr);
return result;
}
/// <summary>Returns the inverse of a BigUInt with respect to the specified
/// modulus.</summary>
/// <remarks>
/// Returns the inverse of a BigUInt with respect to the specified modulus.
/// The original BigUInt is not modified. The bit count of the inverse is set
/// to be the significant bit count of the modulus.
/// </remarks>
/// <param name="modulus">The modulus to calculate the inverse with respect
/// to</param>
/// <exception cref="ArgumentException">if modulus is zero</exception>
/// <exception cref="ArgumentException">if modulus is not greater than the
/// BigUInt value</exception>
/// <exception cref="ArgumentException">if the BigUInt value and modulus
/// are not co-prime</exception>
public BigUInt ModuloInvert(ulong modulus)
{
NativeMethods.BigUInt_ModuloInvert(NativePtr, modulus, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Attempts to calculate the inverse of a BigUInt with respect to
/// the specified modulus, returning whether or not the inverse was successful
/// and setting the inverse parameter to the inverse.</summary>
/// <remarks>
/// Attempts to calculate the inverse of a BigUInt with respect to the specified
/// modulus, returning whether or not the inverse was successful and setting
/// the inverse parameter to the inverse. The original BigUInt is not modified.
/// The inverse parameter is resized if and only if its bit count is smaller
/// than the significant bit count of the modulus.
/// </remarks>
/// <param name="modulus">The modulus to calculate the inverse with respect
/// to</param>
/// <param name="inverse">Stores the inverse if the inverse operation was
/// successful</param>
/// <exception cref="ArgumentNullException">if modulus or inverse is null</exception>
/// <exception cref="ArgumentException">if modulus is zero</exception>
/// <exception cref="ArgumentException">if modulus is not greater than the
/// BigUInt value</exception>
/// <exception cref="InvalidOperationException">if the inverse is an alias
/// which the function attempts to enlarge to fit the result</exception>
public bool TryModuloInvert(BigUInt modulus, BigUInt inverse)
{
if (null == modulus)
throw new ArgumentNullException(nameof(modulus));
if (null == inverse)
throw new ArgumentNullException(nameof(inverse));
if (inverse.IsAlias)
throw new InvalidOperationException("inverse is an alias");
NativeMethods.BigUInt_TryModuloInvert(NativePtr, modulus.NativePtr,
inverse.NativePtr, out bool result);
return result;
}
/// <summary>Attempts to calculate the inverse of a BigUInt with respect to
/// the specified modulus, returning whether or not the inverse was successful
/// and setting the inverse parameter to the inverse.</summary>
/// <remarks>
/// Attempts to calculate the inverse of a BigUInt with respect to the
/// specified modulus, returning whether or not the inverse was successful
/// and setting the inverse parameter to the inverse. The original BigUInt
/// is not modified. The inverse parameter is resized if and only if its bit
/// count is smaller than the significant bit count of the modulus.
/// </remarks>
/// <param name="modulus">The modulus to calculate the inverse with respect
/// to</param>
/// <param name="inverse">Stores the inverse if the inverse operation was
/// successful</param>
/// <exception cref="ArgumentNullException">if inverse is null</exception>
/// <exception cref="ArgumentException">if modulus is zero</exception>
/// <exception cref="ArgumentException">if modulus is not greater than the
/// BigUInt value</exception>
/// <exception cref="InvalidOperationException">if the inverse is an alias
/// which the function attempts to enlarge to fit the result</exception>
public bool TryModuloInvert(ulong modulus, BigUInt inverse)
{
if (null == inverse)
throw new ArgumentNullException(nameof(inverse));
if (inverse.IsAlias)
throw new InvalidOperationException("inverse is an alias");
NativeMethods.BigUInt_TryModuloInvert(NativePtr, modulus,
inverse.NativePtr, out bool result);
return result;
}
/// <summary>Duplicates the current BigUInt.</summary>
/// <remarks>
/// Duplicates the current BigUInt. The bit count and the value of the given
/// BigUInt are set to be exactly the same as in the current one.
/// </remarks>
/// <param name="destination">The BigUInt to overwrite with the duplicate</param>
/// <exception cref="ArgumentNullException">if destination is null</exception>
/// <exception cref="InvalidOperationException">if the destination BigUInt
/// is an alias</exception>
public void DuplicateTo(BigUInt destination)
{
if (null == destination)
throw new ArgumentNullException(nameof(destination));
if (destination.IsAlias)
throw new InvalidOperationException("destination is an alias");
NativeMethods.BigUInt_DuplicateTo(NativePtr, destination.NativePtr);
}
/// <summary>Duplicates a given BigUInt.</summary>
/// <remarks>
/// Duplicates a given BigUInt. The bit count and the value of the current
/// BigUInt are set to be exactly the same as in the given one.
/// </remarks>
/// <param name="value">The BigUInt to duplicate</param>
/// <exception cref="ArgumentNullException">if value is null</exception>
/// <exception cref="InvalidOperationException">if the current BigUInt is
/// an alias</exception>
public void DuplicateFrom(BigUInt value)
{
if (null == value)
throw new ArgumentNullException(nameof(value));
NativeMethods.BigUInt_DuplicateFrom(NativePtr, value.NativePtr);
}
#region Operators
/// <summary>Returns a copy of the BigUInt value resized to the significant bit count.</summary>
///
/// <param name="operand">The operand to copy</param>
/// <exception cref="ArgumentNullException">if operand is null</exception>
public static BigUInt operator +(BigUInt operand)
{
if (null == operand)
throw new ArgumentNullException(nameof(operand));
return new BigUInt(operand);
}
/// <summary>Returns a negated copy of the BigUInt value.</summary>
///
/// <remarks>
/// Returns a negated copy of the BigUInt value. The bit count does not change.
/// </remarks>
/// <param name="operand">The operand to negate</param>
/// <exception cref="ArgumentNullException">if operand is null</exception>
public static BigUInt operator -(BigUInt operand)
{
if (null == operand)
throw new ArgumentNullException(nameof(operand));
NativeMethods.BigUInt_OperatorNeg(operand.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Returns an inverted copy of the BigUInt value.</summary>
///
/// <remarks>
/// Returns an inverted copy of the BigUInt value. The bit count does not change.
/// </remarks>
/// <param name="operand">The operand to invert</param>
/// <exception cref="ArgumentNullException">if operand is null</exception>
public static BigUInt operator ~(BigUInt operand)
{
if (null == operand)
throw new ArgumentNullException(nameof(operand));
NativeMethods.BigUInt_OperatorTilde(operand.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Increments the BigUInt and returns the incremented value.</summary>
///
/// <remarks>
/// Increments the BigUInt and returns the incremented value. The BigUInt will increment the bit count if needed to fit the
/// carry.
/// </remarks>
/// <param name="operand">The operand to increment</param>
/// <exception cref="ArgumentNullException">if operand is null</exception>
/// <exception cref="InvalidOperationException">if BigUInt is an alias and a carry occurs requiring the BigUInt to
/// be resized</exception>
public static BigUInt operator ++(BigUInt operand)
{
if (null == operand)
throw new ArgumentNullException(nameof(operand));
NativeMethods.BigUInt_OperatorPlus(operand.NativePtr, operand: 1ul, result: out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Decrements the BigUInt and returns the decremented value.</summary>
///
/// <remarks>
/// Decrements the BigUInt and returns the decremented value. The bit count does not change.
/// </remarks>
/// <param name="operand">The operand to decrement</param>
/// <exception cref="ArgumentNullException">if operand is null</exception>
public static BigUInt operator --(BigUInt operand)
{
if (null == operand)
throw new ArgumentNullException(nameof(operand));
NativeMethods.BigUInt_OperatorMinus(operand.NativePtr, operand: 1ul, result: out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Adds two BigUInts and returns the sum.</summary>
///
/// <remarks>
/// Adds two BigUInts and returns the sum. The input operands are not modified. The bit count of the sum is set to be one
/// greater than the significant bit count of the larger of the two input operands.
/// </remarks>
/// <param name="operand1">The first operand to add</param>
/// <param name="operand2">The second operand to add</param>
/// <exception cref="ArgumentNullException">if operand1 or operand2 is null</exception>
public static BigUInt operator +(BigUInt operand1, BigUInt operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
if (null == operand2)
throw new ArgumentNullException(nameof(operand2));
NativeMethods.BigUInt_OperatorPlus(operand1.NativePtr, operand2.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Adds a BigUInt and an unsigned integer and returns the sum.</summary>
///
/// <remarks>
/// Adds a BigUInt and an unsigned integer and returns the sum. The input operands are not modified. The bit count of the
/// sum is set to be one greater than the significant bit count of the larger of the two operands.
/// </remarks>
/// <param name="operand1">The first operand to add</param>
/// <param name="operand2">The second operand to add</param>
/// <exception cref="ArgumentNullException">if operand1 is null</exception>
public static BigUInt operator +(BigUInt operand1, ulong operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
NativeMethods.BigUInt_OperatorPlus(operand1.NativePtr, operand2, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Subtracts two BigUInts and returns the difference.</summary>
///
/// <remarks>
/// Subtracts two BigUInts and returns the difference. The input operands are not modified. The bit count of the difference
/// is set to be the significant bit count of the larger of the two input operands.
/// </remarks>
/// <param name="operand1">The first operand to subtract</param>
/// <param name="operand2">The second operand to subtract</param>
/// <exception cref="ArgumentNullException">if operand1 or operand2 is null</exception>
public static BigUInt operator -(BigUInt operand1, BigUInt operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
if (null == operand2)
throw new ArgumentNullException(nameof(operand2));
NativeMethods.BigUInt_OperatorMinus(operand1.NativePtr, operand2.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Subtracts a BigUInt and an unsigned integer and returns the difference.</summary>
///
/// <remarks>
/// Subtracts a BigUInt and an unsigned integer and returns the difference. The input operands are not modified. The bit
/// count of the difference is set to be the significant bit count of the larger of the two operands.
/// </remarks>
/// <param name="operand1">The first operand to subtract</param>
/// <param name="operand2">The second operand to subtract</param>
/// <exception cref="ArgumentNullException">if operand1 is null</exception>
public static BigUInt operator -(BigUInt operand1, ulong operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
NativeMethods.BigUInt_OperatorMinus(operand1.NativePtr, operand2, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Multiplies two BigUInts and returns the product.</summary>
///
/// <remarks>
/// Multiplies two BigUInts and returns the product. The input operands are not modified. The bit count of the product is
/// set to be the sum of the significant bit counts of the two input operands.
/// </remarks>
/// <param name="operand1">The first operand to multiply</param>
/// <param name="operand2">The second operand to multiply</param>
/// <exception cref="ArgumentNullException">if operand1 or operand2 is null</exception>
public static BigUInt operator *(BigUInt operand1, BigUInt operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
if (null == operand2)
throw new ArgumentNullException(nameof(operand2));
NativeMethods.BigUInt_OperatorMult(operand1.NativePtr, operand2.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Multiplies a BigUInt and an unsigned integer and returns the product.</summary>
///
/// <remarks>
/// Multiplies a BigUInt and an unsigned integer and returns the product. The input operands are not modified. The bit
/// count of the product is set to be the sum of the significant bit counts of the two input operands.
/// </remarks>
/// <param name="operand1">The first operand to multiply</param>
/// <param name="operand2">The second operand to multiply</param>
/// <exception cref="ArgumentNullException">if operand1 is null</exception>
public static BigUInt operator *(BigUInt operand1, ulong operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
NativeMethods.BigUInt_OperatorMult(operand1.NativePtr, operand2, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Divides two BigUInts and returns the quotient.</summary>
///
/// <remarks>
/// Divides two BigUInts and returns the quotient. The input operands are not modified. The bit count of the quotient is
/// set to be the significant bit count of the first input operand.
/// </remarks>
/// <param name="operand1">The first operand to divide</param>
/// <param name="operand2">The second operand to divide</param>
/// <exception cref="ArgumentNullException">if operand1 or operand2 is null</exception>
/// <exception cref="ArgumentException">if operand2 is zero</exception>
public static BigUInt operator /(BigUInt operand1, BigUInt operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
if (null == operand2)
throw new ArgumentNullException(nameof(operand2));
if (operand2.IsZero)
throw new ArgumentException("operand2 is zero");
NativeMethods.BigUInt_OperatorDiv(operand1.NativePtr, operand2.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Divides a BigUInt and an unsigned integer and returns the quotient.</summary>
///
/// <remarks>
/// Divides a BigUInt and an unsigned integer and returns the quotient. The input operands are not modified. The bit count
/// of the quotient is set to be the significant bit count of the first input operand.
/// </remarks>
/// <param name="operand1">The first operand to divide</param>
/// <param name="operand2">The second operand to divide</param>
/// <exception cref="ArgumentNullException">if operand1 is null</exception>
/// <exception cref="ArgumentException">if operand2 is zero</exception>
public static BigUInt operator /(BigUInt operand1, ulong operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
if (0 == operand2)
throw new ArgumentException("operand2 is zero");
NativeMethods.BigUInt_OperatorDiv(operand1.NativePtr, operand2, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Performs a bit-wise XOR operation between two BigUInts and returns the result.</summary>
///
/// <remarks>
/// Performs a bit-wise XOR operation between two BigUInts and returns the result. The input operands are not modified. The
/// bit count of the result is set to the maximum of the two input operand bit counts.
/// </remarks>
/// <param name="operand1">The first operand to XOR</param>
/// <param name="operand2">The second operand to XOR</param>
/// <exception cref="ArgumentNullException">if operand1 or operand2 is null</exception>
public static BigUInt operator ^(BigUInt operand1, BigUInt operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
if (null == operand2)
throw new ArgumentNullException(nameof(operand2));
NativeMethods.BigUInt_OperatorXor(operand1.NativePtr, operand2.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Performs a bit-wise XOR operation between a BigUInt and an unsigned integer and returns the result.</summary>
///
/// <remarks>
/// Performs a bit-wise XOR operation between a BigUInt and an unsigned integer and returns the result. The input operands
/// are not modified. The bit count of the result is set to the maximum of the two input operand bit counts.
/// </remarks>
/// <param name="operand1">The first operand to XOR</param>
/// <param name="operand2">The second operand to XOR</param>
/// <exception cref="ArgumentNullException">if operand1 is null</exception>
public static BigUInt operator ^(BigUInt operand1, ulong operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
NativeMethods.BigUInt_OperatorXor(operand1.NativePtr, operand2, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Performs a bit-wise AND operation between two BigUInts and returns the result.</summary>
///
/// <remarks>
/// Performs a bit-wise AND operation between two BigUInts and returns the result. The input operands are not modified. The
/// bit count of the result is set to the maximum of the two input operand bit counts.
/// </remarks>
/// <param name="operand1">The first operand to AND</param>
/// <param name="operand2">The second operand to AND</param>
/// <exception cref="ArgumentNullException">if operand1 or operand2 is null</exception>
public static BigUInt operator &(BigUInt operand1, BigUInt operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
if (null == operand2)
throw new ArgumentNullException(nameof(operand2));
NativeMethods.BigUInt_OperatorAnd(operand1.NativePtr, operand2.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Performs a bit-wise AND operation between a BigUInt and an unsigned integer and returns the result.</summary>
///
/// <remarks>
/// Performs a bit-wise AND operation between a BigUInt and an unsigned integer and returns the result. The input operands
/// are not modified. The bit count of the result is set to the maximum of the two input operand bit counts.
/// </remarks>
/// <param name="operand1">The first operand to AND</param>
/// <param name="operand2">The second operand to AND</param>
/// <exception cref="ArgumentNullException">if operand1 is null</exception>
public static BigUInt operator &(BigUInt operand1, ulong operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
NativeMethods.BigUInt_OperatorAnd(operand1.NativePtr, operand2, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Performs a bit-wise OR operation between two BigUInts and returns the result.</summary>
///
/// <remarks>
/// Performs a bit-wise OR operation between two BigUInts and returns the result. The input operands are not modified. The
/// bit count of the result is set to the maximum of the two input operand bit counts.
/// </remarks>
/// <param name="operand1">The first operand to OR</param>
/// <param name="operand2">The second operand to OR</param>
/// <exception cref="ArgumentNullException">if operand1 or operand2 is null</exception>
public static BigUInt operator |(BigUInt operand1, BigUInt operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
if (null == operand2)
throw new ArgumentNullException(nameof(operand2));
NativeMethods.BigUInt_OperatorOr(operand1.NativePtr, operand2.NativePtr, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Performs a bit-wise OR operation between a BigUInt and an unsigned integer and returns the result.</summary>
///
/// <remarks>
/// Performs a bit-wise OR operation between a BigUInt and an unsigned integer and returns the result. The input operands
/// are not modified. The bit count of the result is set to the maximum of the two input operand bit counts.
/// </remarks>
/// <param name="operand1">The first operand to OR</param>
/// <param name="operand2">The second operand to OR</param>
/// <exception cref="ArgumentNullException">if operand1 is null</exception>
public static BigUInt operator |(BigUInt operand1, ulong operand2)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
NativeMethods.BigUInt_OperatorOr(operand1.NativePtr, operand2, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Returns a left-shifted copy of the BigUInt.</summary>
///
/// <remarks>
/// Returns a left-shifted copy of the BigUInt. The bit count of the returned value is the sum of the original significant
/// bit count and the shift amount.
/// </remarks>
/// <param name="operand1">The operand to left-shift</param>
/// <param name="shift">The number of bits to shift by</param>
/// <exception cref="ArgumentNullException">if operand1 is null</exception>
/// <exception cref="ArgumentException">if shift is negative</exception>
public static BigUInt operator <<(BigUInt operand1, int shift)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
if (shift < 0)
throw new ArgumentException("shift is negative");
NativeMethods.BigUInt_OperatorShiftLeft(operand1.NativePtr, shift, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Returns a right-shifted copy of the BigUInt.</summary>
///
/// <remarks>
/// Returns a right-shifted copy of the BigUInt. The bit count of the returned value is the original significant bit count
/// subtracted by the shift amount (clipped to zero if negative).
/// </remarks>
/// <param name="operand1">The operand to right-shift</param>
/// <param name="shift">The number of bits to shift by</param>
/// <exception cref="ArgumentNullException">if operand1 is null</exception>
/// <exception cref="ArgumentException">if shift is negative</exception>
public static BigUInt operator >>(BigUInt operand1, int shift)
{
if (null == operand1)
throw new ArgumentNullException(nameof(operand1));
if (shift < 0)
throw new ArgumentException("shift is negative");
NativeMethods.BigUInt_OperatorShiftRight(operand1.NativePtr, shift, out IntPtr resultptr);
BigUInt result = new BigUInt(resultptr);
return result;
}
/// <summary>Returns the BigUInt value as a double.</summary>
/// <remarks>
/// Returns the BigUInt value as a double. Note that precision may be lost during the conversion.
/// </remarks>
/// <param name="value">The value to convert</param>
/// <exception cref="ArgumentNullException">if value is null</exception>
public static explicit operator double(BigUInt value)
{
if (null == value)
throw new ArgumentNullException(nameof(value));
NativeMethods.BigUInt_ToDouble(value.NativePtr, out double result);
return result;
}
/// <summary>Returns the BigUInt value as a float.</summary>
/// <remarks>
/// Returns the BigUInt value as a float. Note that precision may be lost during the conversion.
/// </remarks>
/// <param name="value">The value to convert</param>
/// <exception cref="ArgumentNullException">if value is null</exception>
public static explicit operator float(BigUInt value)
{
if (null == value)
throw new ArgumentNullException(nameof(value));
double dblvalue = (double)value;
return unchecked((float)dblvalue);
}
/// <summary>Returns the lower 64-bits of a BigUInt value.</summary>
/// <remarks>
/// Returns the lower 64-bits of a BigUInt value. Note that if the value is greater than 64-bits,
/// the higher bits are dropped.
/// </remarks>
/// <param name="value">The value to convert</param>
/// <exception cref="ArgumentNullException">if value is null</exception>
public static explicit operator ulong(BigUInt value)
{
if (null == value)
throw new ArgumentNullException(nameof(value));
if (value.BitCount == 0)
return 0;
return value.Data(0);
}
/// <summary>Returns the lower 64-bits of a BigUInt value as a signed-integer.</summary>
/// <remarks>
/// Returns the lower 64-bits of a BigUInt value as a signed-integer. Note that if the value is greater than
/// 64-bits, the result may be negative and the higher bits are dropped.
/// </remarks>
/// <param name="value">The value to convert</param>
/// <exception cref="ArgumentNullException">if value is null</exception>
public static explicit operator long(BigUInt value)
{
if (null == value)
throw new ArgumentNullException(nameof(value));
ulong ulvalue = (ulong)value;
return unchecked((long)ulvalue);
}
/// <summary>Returns the lower 32-bits of a BigUInt value.</summary>
/// <remarks>
/// Returns the lower 32-bits of a BigUInt value. Note that if the value is greater than 32-bits,
/// the higher bits are dropped.
/// </remarks>
/// <param name="value">The value to convert</param>
/// <exception cref="ArgumentNullException">if value is null</exception>
public static explicit operator uint(BigUInt value)
{
if (null == value)
throw new ArgumentNullException(nameof(value));
ulong ulvalue = (ulong)value;
return unchecked((uint)ulvalue);
}
/// <summary>Returns the lower 32-bits of a BigUInt value as a signed-integer.</summary>
/// <remarks>
/// Returns the lower 32-bits of a BigUInt value as a signed-integer. Note that if the value is greater than
/// 32-bits, the result may be negative and the higher bits are dropped.
/// </remarks>
/// <param name="value">The value to convert</param>
/// <exception cref="ArgumentNullException">if value is null</exception>
public static explicit operator int(BigUInt value)
{
if (null == value)
throw new ArgumentNullException(nameof(value));
ulong ulvalue = (ulong)value;
return unchecked((int)ulvalue);
}
#endregion // Operators
#region IComparable methods
/// <summary>Compares two BigUInts and returns -1, 0, or 1 if the BigUInt is less-than, equal-to, or greater-than the
/// second operand respectively.</summary>
///
/// <remarks>
/// Compares two BigUInts and returns -1, 0, or 1 if the BigUInt is less-than, equal-to, or greater-than the second
/// operand respectively. The input operands are not modified.
/// </remarks>
/// <param name="compare">The value to compare against</param>
public int CompareTo(BigUInt compare)
{
if (null == compare)
return 1;
NativeMethods.BigUInt_CompareTo(NativePtr, compare.NativePtr, out int result);
return result;
}
#endregion
#region IEquatable methods
/// <summary>Returns whether or not a BigUInt is equal to a second BigUInt.</summary>
/// <remarks>
/// Returns whether or not a BigUInt is equal to a second BigUInt. The input operands are not modified.
/// </remarks>
///
/// <param name="compare">The value to compare against</param>
public bool Equals(BigUInt compare)
{
if (null == compare)
return false;
NativeMethods.BigUInt_Equals(NativePtr, compare.NativePtr, out bool result);
return result;
}
#endregion
#region Object overrides
/// <summary>Returns whether or not a BigUInt is equal to a second BigUInt.</summary>
/// <remarks>
/// Returns whether or not a BigUInt is equal to a second BigUInt. The input operands are not modified.
/// </remarks>
///
/// <param name="compare">The value to compare against</param>
public override bool Equals(object compare)
{
BigUInt other = compare as BigUInt;
return Equals(other);
}
/// <summary>
/// Returns the BigUInt value as a hexadecimal string.
/// </summary>
public override string ToString()
{
NativeMethods.BigUInt_ToString(NativePtr, null, length: out ulong length);
StringBuilder buffer = new StringBuilder(checked((int)length));
NativeMethods.BigUInt_ToString(NativePtr, buffer, out length);
return buffer.ToString();
}
/// <summary>
/// Returns a hash-code based on the value of the BigUInt.
/// </summary>
public override int GetHashCode()
{
ulong[] data = new ulong[UInt64Count];
for (long i = 0; i < data.LongLength; i++)
{
data[i] = Data((ulong)i);
}
return Utilities.ComputeArrayHashCode(data);
}
#endregion
/// <summary>
/// Destroy native object.
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.BigUInt_Destroy(NativePtr);
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Provides functionality for encoding vectors of complex or real numbers into plaintext
/// polynomials to be encrypted and computed on using the CKKS scheme. If the polynomial
/// modulus degree is N, then CKKSEncoder converts vectors of N/2 complex numbers into
/// plaintext elements. Homomorphic operations performed on such encrypted vectors are
/// applied coefficient (slot-)wise, enabling powerful SIMD functionality for computations
/// that are vectorizable. This functionality is often called "batching" in the homomorphic
/// encryption literature.
/// </summary>
/// <remarks>
/// <para>
/// Mathematical Background
/// Mathematically speaking, if the polynomial modulus is X^N+1, N is a power of two, the
/// CKKSEncoder implements an approximation of the canonical embedding of the ring of
/// integers Z[X]/(X^N+1) into C^(N/2), where C denotes the complex numbers. The Galois
/// group of the extension is (Z/2NZ)* ~= Z/2Z x Z/(N/2) whose action on the primitive roots
/// of unity modulo CoeffModulus is easy to describe. Since the batching slots correspond
/// 1-to-1 to the primitive roots of unity, applying Galois automorphisms on the plaintext
/// acts by permuting the slots. By applying generators of the two cyclic subgroups of the
/// Galois group, we can effectively enable cyclic rotations and complex conjugations of
/// the encrypted complex vectors.
/// </para>
/// </remarks>
public class CKKSEncoder : NativeObject
{
/// <summary>
/// Creates a CKKSEncoder instance initialized with the specified SEALContext.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <exception cref="ArgumentNullException">if context is null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption parameters
/// are not valid</exception>
/// <exception cref="ArgumentException">if scheme is not SchemeType.CKKS</exception>
public CKKSEncoder(SEALContext context)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (!context.ParametersSet)
throw new ArgumentException("Encryption parameters are not set correctly");
SEALContext.ContextData contextData = context.FirstContextData;
if (contextData.Parms.Scheme != SchemeType.CKKS)
throw new ArgumentException("Unsupported scheme");
NativeMethods.CKKSEncoder_Create(context.NativePtr, out IntPtr ptr);
NativePtr = ptr;
context_ = context;
}
/// <summary>
/// Encodes a vector of double-precision floating-point real numbers into a plaintext
/// polynomial.
/// </summary>
/// <remark>
/// Append zeros if vector size is less than N/2. Dynamic memory allocations in the process
/// are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </remark>
/// <param name="values">The enumeration of double-precision floating-point numbers
/// to encode</param>
/// <param name="parmsId">parmsId determining the encryption parameters to be used
/// by the result plaintext</param>
/// <param name="scale">Scaling parameter defining encoding precision</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either values, parmsId or destionation are null.</exception>
/// <exception cref="ArgumentException">if values has invalid size</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters </exception>
/// <exception cref="ArgumentException">if scale is not strictly positive</exception>
/// <exception cref="ArgumentException">if encoding is too large for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Encode(IEnumerable<double> values, ParmsId parmsId,
double scale, Plaintext destination, MemoryPoolHandle pool = null)
{
if (null == values)
throw new ArgumentNullException(nameof(values));
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
double[] valuearray = values.ToArray();
NativeMethods.CKKSEncoder_EncodeDouble(NativePtr, (ulong)valuearray.LongLength, valuearray,
parmsId.Block, scale, destination.NativePtr, poolPtr);
}
/// <summary>
/// Encodes a vector of double-precision floating-point complex numbers into a plaintext
/// polynomial.
/// </summary>
/// <remark>
/// Append zeros if vector size is less than N/2. Dynamic memory allocations in the process
/// are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </remark>
/// <param name="values">The enumeration of double-precision complex numbers
/// to encode</param>
/// <param name="parmsId">parmsId determining the encryption parameters to be used
/// by the result plaintext</param>
/// <param name="scale">Scaling parameter defining encoding precision</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either values, parmsId or destionation are null.</exception>
/// <exception cref="ArgumentException">if values has invalid size</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters </exception>
/// <exception cref="ArgumentException">if scale is not strictly positive</exception>
/// <exception cref="ArgumentException">if encoding is too large for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Encode(IEnumerable<Complex> values, ParmsId parmsId,
double scale, Plaintext destination, MemoryPoolHandle pool = null)
{
if (null == values)
throw new ArgumentNullException(nameof(values));
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
double[] valuearray = new double[values.LongCount() * 2];
ulong idx = 0;
foreach(Complex complex in values)
{
valuearray[idx++] = complex.Real;
valuearray[idx++] = complex.Imaginary;
}
// Note that we should pass values.Count as the length instead of valuearray.Length,
// since we are using two doubles in the array per element.
NativeMethods.CKKSEncoder_EncodeComplex(NativePtr, (ulong)values.LongCount(), valuearray,
parmsId.Block, scale, destination.NativePtr, poolPtr);
}
/// <summary>
/// Encodes a vector of double-precision floating-point real numbers into a plaintext
/// polynomial.
/// </summary>
/// <remark>
/// Append zeros if vector size is less than N/2. Dynamic memory allocations in the process
/// are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// The encryption parameters used are the top level parameters for the given context.
/// </remark>
/// <param name="values">The enumeration of double-precision floating-point numbers
/// to encode</param>
/// <param name="scale">Scaling parameter defining encoding precision</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either values or destionation are null.</exception>
/// <exception cref="ArgumentException">if values has invalid size</exception>
/// <exception cref="ArgumentException">if scale is not strictly positive</exception>
/// <exception cref="ArgumentException">if encoding is too large for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Encode(IEnumerable<double> values, double scale,
Plaintext destination, MemoryPoolHandle pool = null)
{
Encode(values, context_.FirstParmsId, scale, destination, pool);
}
/// <summary>
/// Encodes a vector of double-precision floating-point complex numbers into a plaintext
/// polynomial.
/// </summary>
/// <remark>
/// Append zeros if vector size is less than N/2. Dynamic memory allocations in the process
/// are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// The encryption parameters used are the top level parameters for the given context.
/// </remark>
/// <param name="values">The enumeration of double-precision floating-point numbers
/// to encode</param>
/// <param name="scale">Scaling parameter defining encoding precision</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either values or destionation are null.</exception>
/// <exception cref="ArgumentException">if values has invalid size</exception>
/// <exception cref="ArgumentException">if scale is not strictly positive</exception>
/// <exception cref="ArgumentException">if encoding is too large for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Encode(IEnumerable<Complex> values, double scale,
Plaintext destination, MemoryPoolHandle pool = null)
{
Encode(values, context_.FirstParmsId, scale, destination, pool);
}
/// <summary>
/// Encodes a double-precision floating-point real number into a plaintext polynomial.
/// </summary>
/// <remark>
/// The number repeats for N/2 times to fill all slots. Dynamic memory allocations in the
/// process are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </remark>
/// <param name="value">The double-precision floating-point number to encode</param>
/// <param name="parmsId">parmsId determining the encryption parameters to be used
/// by the result plaintext</param>
/// <param name="scale">Scaling parameter defining encoding precision</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either parmsId or destination are null</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters </exception>
/// <exception cref="ArgumentException">if scale is not strictly positive</exception>
/// <exception cref="ArgumentException">if encoding is too large for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Encode(double value, ParmsId parmsId,
double scale, Plaintext destination,
MemoryPoolHandle pool = null)
{
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.CKKSEncoder_Encode(NativePtr, value, parmsId.Block, scale, destination.NativePtr, poolPtr);
}
/// <summary>
/// Encodes a double-precision floating-point real number into a plaintext polynomial.
/// </summary>
/// <remark>
/// The number repeats for N/2 times to fill all slots. Dynamic memory allocations in the
/// process are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// The encryption parameters used are the top level parameters for the given context.
/// </remark>
/// <param name="value">The double-precision floating-point number to encode</param>
/// <param name="scale">Scaling parameter defining encoding precision</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if destination is null</exception>
/// <exception cref="ArgumentException">if scale is not strictly positive</exception>
/// <exception cref="ArgumentException">if encoding is too large for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Encode(double value, double scale, Plaintext destination,
MemoryPoolHandle pool = null)
{
Encode(value, context_.FirstParmsId, scale, destination, pool);
}
/// <summary>
/// Encodes a double-precision floating-point complex number into a plaintext polynomial.
/// </summary>
/// <remark>
/// The number repeats for N/2 times to fill all slots. Dynamic memory allocations in the
/// process are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </remark>
/// <param name="value">The double-precision complex number to encode</param>
/// <param name="parmsId">parmsId determining the encryption parameters to be used
/// by the result plaintext</param>
/// <param name="scale">Scaling parameter defining encoding precision</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either parmsId or destination are null</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters </exception>
/// <exception cref="ArgumentException">if scale is not strictly positive</exception>
/// <exception cref="ArgumentException">if encoding is too large for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Encode(Complex value, ParmsId parmsId, double scale,
Plaintext destination, MemoryPoolHandle pool = null)
{
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.CKKSEncoder_Encode(NativePtr, value.Real, value.Imaginary, parmsId.Block, scale, destination.NativePtr, poolPtr);
}
/// <summary>
/// Encodes a double-precision floating-point complex number into a plaintext polynomial.
/// </summary>
/// <remark>
/// The number repeats for N/2 times to fill all slots. Dynamic memory allocations in the
/// process are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// The encryption parameters used are the top level parameters for the given context.
/// </remark>
/// <param name="value">The double-precision complex number to encode</param>
/// <param name="scale">Scaling parameter defining encoding precision</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if destination is null</exception>
/// <exception cref="ArgumentException">if scale is not strictly positive</exception>
/// <exception cref="ArgumentException">if encoding is too large for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Encode(Complex value, double scale, Plaintext destination,
MemoryPoolHandle pool = null)
{
Encode(value, context_.FirstParmsId, scale, destination, pool);
}
/// <summary>
/// Encodes an integer number into a plaintext polynomial without any scaling.
/// </summary>
/// <remark>
/// The number repeats for N/2 times to fill all slots.
/// </remark>
/// <param name="value">The integer number to encode</param>
/// <param name="parmsId">parmsId determining the encryption parameters to be used
/// by the result plaintext</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <exception cref="ArgumentNullException">if either parmsId or destionation are null</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters </exception>
public void Encode(long value, ParmsId parmsId, Plaintext destination)
{
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.CKKSEncoder_Encode(NativePtr, value, parmsId.Block, destination.NativePtr);
}
/// <summary>
/// Encodes an integer number into a plaintext polynomial without any scaling.
/// </summary>
/// <remark>
/// The number repeats for N/2 times to fill all slots. The encryption parameters used are
/// the top level parameters for the given context.
/// </remark>
/// <param name="value">The integer number to encode</param>
/// <param name="destination">The plaintext polynomial to overwrite with the result</param>
/// <exception cref="ArgumentNullException">if destination is null</exception>
public void Encode(long value, Plaintext destination)
{
Encode(value, context_.FirstParmsId, destination);
}
/// <summary>
/// Decodes a plaintext polynomial into double-precision floating-point real numbers.
/// </summary>
/// <remark>
/// Dynamic memory allocations in the process are allocated from the memory pool pointed to
/// by the given MemoryPoolHandle.
/// </remark>
/// <param name="plain">plain The plaintext to decode</param>
/// <param name="destination">The collection to be overwritten with the values in the slots</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either plain or destination are null</exception>
/// <exception cref="ArgumentException">if plain is not in NTT form or is invalid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Decode(Plaintext plain, ICollection<double> destination,
MemoryPoolHandle pool = null)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
ulong destCount = 0;
// Allocate a big enough array to hold the result
double[] destArray = new double[SlotCount];
NativeMethods.CKKSEncoder_DecodeDouble(NativePtr, plain.NativePtr, ref destCount, destArray, poolPtr);
// Transfer result to actual destination; only destArray many slots were filled
destination.Clear();
for (ulong i = 0; i < destCount; i++)
{
destination.Add(destArray[i]);
}
}
/// <summary>
/// Decodes a plaintext polynomial into double-precision floating-point complex numbers.
/// </summary>
/// <remark>
/// Dynamic memory allocations in the process are allocated from the memory pool pointed to
/// by the given MemoryPoolHandle.
/// </remark>
/// <param name="plain">plain The plaintext to decode</param>
/// <param name="destination">The collection to be overwritten with the values in the slots</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either plain or destination are null</exception>
/// <exception cref="ArgumentException">if plain is not in NTT form or is invalid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Decode(Plaintext plain, ICollection<Complex> destination,
MemoryPoolHandle pool = null)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
ulong destCount = 0;
// Allocate a big enough array to hold the result
double[] destArray = new double[SlotCount * 2];
NativeMethods.CKKSEncoder_DecodeComplex(NativePtr, plain.NativePtr, ref destCount, destArray, poolPtr);
// Transfer result to actual destination
destination.Clear();
for (ulong i = 0; i < destCount; i++)
{
destination.Add(new Complex(destArray[i * 2], destArray[i * 2 + 1]));
}
}
/// <summary>
/// Returns the number of complex numbers encoded.
/// </summary>
public ulong SlotCount
{
get
{
NativeMethods.CKKSEncoder_SlotCount(NativePtr, out ulong slotCount);
return slotCount;
}
}
/// <summary>
/// SEALContext for this encoder
/// </summary>
private readonly SEALContext context_ = null;
/// <summary>
/// Destroy native object
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.CKKSEncoder_Destroy(NativePtr);
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Class to store a ciphertext element. The data for a ciphertext consists
/// of two or more polynomials, which are in Microsoft SEAL stored in a CRT
/// form with respect to the factors of the coefficient modulus. This data
/// itself is not meant to be modified directly by the user, but is instead
/// operated on by functions in the Evaluator class. The size of the backing
/// array of a ciphertext depends on the encryption parameters and the size
/// of the ciphertext (at least 2). If the PolyModulusDegree encryption
/// parameter is N, and the number of primes in the CoeffModulus encryption
/// parameter is K, then the ciphertext backing array requires precisely
/// 8*N*K*size bytes of memory. A ciphertext also carries with it the
/// parmsId of its associated encryption parameters, which is used to check
/// the validity of the ciphertext for homomorphic operations and decryption.
/// </summary>
/// <remarks>
/// <para>
/// Memory Management
/// The size of a ciphertext refers to the number of polynomials it contains,
/// whereas its capacity refers to the number of polynomials that fit in the
/// current memory allocation. In high-performance applications unnecessary
/// re-allocations should be avoided by reserving enough memory for the
/// ciphertext to begin with either by providing the desired capacity to the
/// constructor as an extra argument, or by calling the reserve function at
/// any time.
/// </para>
/// <para>
/// Thread Safety
/// In general, reading from ciphertext is thread-safe as long as no other
/// thread is concurrently mutating it. This is due to the underlying data
/// structure storing the ciphertext not being thread-safe.
/// </para>
/// </remarks>
/// <seealso cref="Plaintext">See Plaintext for the class that stores plaintexts.</seealso>
public class Ciphertext :
NativeObject,
ISerializableObject,
ISettable<Ciphertext>
{
/// <summary>
/// Constructs an empty ciphertext allocating no memory.
/// </summary>
public Ciphertext() : this(pool: null)
{
}
/// <summary>
/// Constructs an empty ciphertext allocating no memory.
/// </summary>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="System.ArgumentException">if pool is uninitialized</exception>
public Ciphertext(MemoryPoolHandle pool)
{
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Ciphertext_Create1(poolPtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Constructs an empty ciphertext with capacity 2. In addition to the
/// capacity, the allocation size is determined by the highest-level
/// parameters associated to the given SEALContext.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if context is null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public Ciphertext(SEALContext context, MemoryPoolHandle pool = null)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Ciphertext_Create3(context.NativePtr, poolPtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Constructs an empty ciphertext with capacity 2. In addition to the
/// capacity, the allocation size is determined by the encryption parameters
/// with given ParmsId.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <param name="parmsId">The ParmsId corresponding to the encryption
/// parameters to be used</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either context or parmsId are null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public Ciphertext(SEALContext context, ParmsId parmsId, MemoryPoolHandle pool = null)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Ciphertext_Create4(context.NativePtr, parmsId.Block, poolPtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Constructs an empty ciphertext with given capacity. In addition to
/// the capacity, the allocation size is determined by the given
/// encryption parameters.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <param name="parmsId">The ParmsId corresponding to the encryption
/// parameters to be used</param>
/// <param name="sizeCapacity">The capacity</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either context or parmsId are null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if sizeCapacity is less than 2 or too large</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public Ciphertext(SEALContext context, ParmsId parmsId, ulong sizeCapacity,
MemoryPoolHandle pool = null)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Ciphertext_Create5(context.NativePtr, parmsId.Block, sizeCapacity, poolPtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Constructs a new ciphertext by copying a given one.
/// </summary>
/// <param name="copy">The ciphertext to copy from</param>
/// <exception cref="ArgumentNullException">if copy is null</exception>
public Ciphertext(Ciphertext copy)
{
if (null == copy)
throw new ArgumentNullException(nameof(copy));
NativeMethods.Ciphertext_Create2(copy.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Constructs a new ciphertext by copying a given one.
/// </summary>
/// <param name="copy">The ciphertext to copy from</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either copy or pool are null</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public Ciphertext(Ciphertext copy, MemoryPoolHandle pool) : this(pool)
{
if (null == copy)
throw new ArgumentNullException(nameof(copy));
Set(copy);
}
/// <summary>
/// Constructs a new ciphertext by initializing it with a native
/// object pointer.
/// </summary>
/// <param name="ciphertextPtr">The native Ciphertext pointer</param>
/// <param name="owned">Whether this object owns the native pointer</param>
internal Ciphertext(IntPtr ciphertextPtr, bool owned = true)
: base(ciphertextPtr, owned)
{
}
/// <summary>
/// Allocates enough memory to accommodate the backing array of a ciphertext
/// with given capacity. In addition to the capacity, the allocation size is
/// determined by the encryption parameters corresponing to the given
/// parmsId.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <param name="parmsId">The ParmsId corresponding to the encryption
/// parameters to be used</param>
/// <param name="sizeCapacity">The capacity</param>
/// <exception cref="ArgumentNullException">if either context or parmsId are null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if sizeCapacity is less than 2 or too large</exception>
public void Reserve(SEALContext context, ParmsId parmsId, ulong sizeCapacity)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
NativeMethods.Ciphertext_Reserve(NativePtr, context.NativePtr, parmsId.Block, sizeCapacity);
}
/// <summary>
/// Allocates enough memory to accommodate the backing array of a ciphertext
/// with given capacity. In addition to the capacity, the allocation size is
/// determined by the highest-level parameters associated to the given
/// SEALContext.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <param name="sizeCapacity">The capacity</param>
/// <exception cref="ArgumentNullException">if context is null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="ArgumentException">if sizeCapacity is less than 2 or too large</exception>
public void Reserve(SEALContext context, ulong sizeCapacity)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
NativeMethods.Ciphertext_Reserve(NativePtr, context.NativePtr, sizeCapacity);
}
/// <summary>
/// Allocates enough memory to accommodate the backing array of a ciphertext
/// with given capacity. In addition to the capacity, the allocation size is
/// determined by the current encryption parameters.
/// </summary>
/// <param name="sizeCapacity">The capacity</param>
/// <exception cref="ArgumentException">if sizeCapacity is less than 2 or too large</exception>
public void Reserve(ulong sizeCapacity)
{
NativeMethods.Ciphertext_Reserve(NativePtr, sizeCapacity);
}
/// <summary>
/// Resizes the ciphertext to given size, reallocating if the capacity
/// of the ciphertext is too small. The ciphertext parameters are
/// determined by the given SEALContext and parmsId.
///
/// This function is mainly intended for internal use and is called
/// automatically by functions such as Evaluator::multiply and
/// Evaluator::relinearize. A normal user should never have a reason
/// to manually resize a ciphertext.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <param name="parmsId">The ParmsId corresponding to the encryption
/// parameters to be used</param>
/// <param name="size">The new size</param>
/// <exception cref="ArgumentNullException">if either context or parmsId are null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if size is less than 2 or too large</exception>
public void Resize(SEALContext context, ParmsId parmsId, ulong size)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
NativeMethods.Ciphertext_Resize(NativePtr, context.NativePtr, parmsId.Block, size);
}
/// <summary>
/// Resizes the ciphertext to given size, reallocating if the capacity
/// of the ciphertext is too small. The ciphertext parameters are
/// determined by the highest-level parameters associated to the given
/// SEALContext.
///
/// This function is mainly intended for internal use and is called
/// automatically by functions such as Evaluator::multiply and
/// Evaluator::relinearize. A normal user should never have a reason
/// to manually resize a ciphertext.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <param name="size">The new size</param>
/// <exception cref="ArgumentNullException">if context is null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="ArgumentException">if size is less than 2 or too large</exception>
public void Resize(SEALContext context, ulong size)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
NativeMethods.Ciphertext_Resize(NativePtr, context.NativePtr, size);
}
/// <summary>
/// Resizes the ciphertext to given size, reallocating if the capacity
/// of the ciphertext is too small.
///
/// This function is mainly intended for internal use and is called
/// automatically by functions such as Evaluator::multiply and
/// Evaluator::relinearize. A normal user should never have a reason
/// to manually resize a ciphertext.
/// </summary>
/// <param name="size">The new size</param>
/// <exception cref="ArgumentException">if size is less than 2 or too large</exception>
public void Resize(ulong size)
{
NativeMethods.Ciphertext_Resize(NativePtr, size);
}
/// <summary>
/// Resizes the ciphertext to the given size, poly modulus degree and
/// coefficient mod count. This is a helper for loading a ciphertext
/// from a stream.
/// </summary>
/// <param name="size">The new size</param>
/// <param name="polyModulusDegree">The new poly modulus degree</param>
/// <param name="coeffModCount">The new coefficient mod count</param>
private void Resize(ulong size, ulong polyModulusDegree, ulong coeffModCount)
{
NativeMethods.Ciphertext_Resize(NativePtr, size, polyModulusDegree, coeffModCount);
}
/// <summary>
/// Resets the ciphertext. This function releases any memory allocated
/// by the ciphertext, returning it to the memory pool. It also sets all
/// encryption parameter specific size information to zero.
/// </summary>
public void Release()
{
NativeMethods.Ciphertext_Release(NativePtr);
}
/// <summary>
/// Copies a given ciphertext to the current one.
/// </summary>
/// <param name="assign">The ciphertext to copy from</param>
/// <exception cref="ArgumentNullException">if assign is null</exception>
public void Set(Ciphertext assign)
{
if (null == assign)
throw new ArgumentNullException(nameof(assign));
NativeMethods.Ciphertext_Set(NativePtr, assign.NativePtr);
}
/// <summary>
/// Returns the polynomial coefficient at a particular index in the ciphertext data. If the
/// polynomial modulus has degree N, and the number of primes in the coefficient modulus is K, then
/// the ciphertext contains size*N*K coefficients. Thus, the index has a range of [0, size*N*K).
/// </summary>
/// <param name="coeffIndex">The index of the coefficient</param>
/// <exception cref="IndexOutOfRangeException">if coeffIndex is out of range</exception>
public ulong this[ulong coeffIndex]
{
get
{
try
{
NativeMethods.Ciphertext_GetDataAt(NativePtr, coeffIndex, out ulong value);
return value;
}
catch (COMException ex)
{
if ((uint)ex.HResult == NativeMethods.Errors.HRInvalidIndex)
throw new IndexOutOfRangeException(nameof(coeffIndex), ex);
throw;
}
}
set
{
try
{
NativeMethods.Ciphertext_SetDataAt(NativePtr, coeffIndex, value);
}
catch (COMException ex)
{
if ((uint)ex.HResult == NativeMethods.Errors.HRInvalidIndex)
throw new IndexOutOfRangeException(nameof(coeffIndex), ex);
throw;
}
}
}
/// <summary>
/// Get the value of a coefficient at the given index from
/// a particular polynomial in the ciphertext
/// data. Note that Microsoft SEAL stores each polynomial in the ciphertext
/// modulo all of the K primes in the coefficient modulus. The data
/// returned by this function is to the beginning (constant coefficient)
/// of the first one of these K polynomials.
/// </summary>
/// <param name="polyIndex">The index of the polynomial in the ciphertext</param>
/// <param name="coeffIndex">The index of the polynomial data</param>
/// <exception cref="IndexOutOfRangeException">if polyIndex is less than 0 or bigger
/// than the size of the ciphertext</exception>
/// <exception cref="IndexOutOfRangeException">if coeffIndex is less than 0 or bigger
/// than the size of the ciphertext</exception>
public ulong this[ulong polyIndex, ulong coeffIndex]
{
get
{
try
{
NativeMethods.Ciphertext_GetDataAt(NativePtr, polyIndex, coeffIndex, out ulong data);
return data;
}
catch(COMException ex)
{
if ((uint)ex.HResult == NativeMethods.Errors.HRInvalidIndex)
throw new IndexOutOfRangeException("polyIndex or coeffIndex out of range", ex);
throw;
}
}
}
/// <summary>
/// Returns the number of primes in the coefficient modulus of the
/// associated encryption parameters. This directly affects the
/// allocation size of the ciphertext.
/// </summary>
public ulong CoeffModulusSize
{
get
{
NativeMethods.Ciphertext_CoeffModulusSize(NativePtr, out ulong coeffModCount);
return coeffModCount;
}
}
/// <summary>
/// Returns the degree of the polynomial modulus of the associated
/// encryption parameters.This directly affects the allocation size
/// of the ciphertext.
/// </summary>
public ulong PolyModulusDegree
{
get
{
NativeMethods.Ciphertext_PolyModulusDegree(NativePtr, out ulong polyModulusDegree);
return polyModulusDegree;
}
}
/// <summary>
/// Returns the capacity of the allocation. This means the largest size
/// of the ciphertext that can be stored in the current allocation with
/// the current encryption parameters.
/// </summary>
public ulong SizeCapacity
{
get
{
NativeMethods.Ciphertext_SizeCapacity(NativePtr, out ulong sizeCapacity);
return sizeCapacity;
}
}
/// <summary>
/// Returns the size of the ciphertext.
/// </summary>
public ulong Size
{
get
{
NativeMethods.Ciphertext_Size(NativePtr, out ulong size);
return size;
}
}
/// <summary>
/// Check whether the current ciphertext is transparent, i.e. does not require
/// a secret key to decrypt. In typical security models such transparent
/// ciphertexts would not be considered to be valid. Starting from the second
/// polynomial in the current ciphertext, this function returns true if all
/// following coefficients are identically zero. Otherwise, returns false.
/// </summary>
public bool IsTransparent
{
get
{
NativeMethods.Ciphertext_IsTransparent(NativePtr, out bool result);
return result;
}
}
/// <summary>
/// Returns an upper bound on the size of the ciphertext, as if it was written
/// to an output stream.
/// </summary>
/// <param name="comprMode">The compression mode</param>
/// <exception cref="ArgumentException">if the compression mode is not
/// supported</exception>
/// <exception cref="InvalidOperationException">if the size does not fit in
/// the return type</exception>
public long SaveSize(ComprModeType? comprMode = null)
{
comprMode = comprMode ?? Serialization.ComprModeDefault;
if (!Serialization.IsSupportedComprMode(comprMode.Value))
throw new ArgumentException("Unsupported compression mode");
ComprModeType comprModeValue = comprMode.Value;
NativeMethods.Ciphertext_SaveSize(
NativePtr, (byte)comprModeValue, out long outBytes);
return outBytes;
}
/// <summary>Saves the ciphertext to an output stream.</summary>
/// <remarks>
/// Saves the ciphertext to an output stream. The output is in binary format
/// and not human-readable.
/// </remarks>
/// <param name="stream">The stream to save the ciphertext to</param>
/// <param name="comprMode">The desired compression mode</param>
/// <exception cref="ArgumentNullException">if stream is null</exception>
/// <exception cref="ArgumentException">if the stream is closed or does not
/// support writing, or if compression mode is not supported</exception>
/// <exception cref="IOException">if I/O operations failed</exception>
/// <exception cref="InvalidOperationException">if the data to be saved
/// is invalid, or if compression failed</exception>
public long Save(Stream stream, ComprModeType? comprMode = null)
{
comprMode = comprMode ?? Serialization.ComprModeDefault;
if (!Serialization.IsSupportedComprMode(comprMode.Value))
throw new ArgumentException("Unsupported compression mode");
ComprModeType comprModeValue = comprMode.Value;
return Serialization.Save(
(byte[] outptr, ulong size, byte cm, out long outBytes) =>
NativeMethods.Ciphertext_Save(NativePtr, outptr, size,
cm, out outBytes),
SaveSize(comprModeValue), comprModeValue, stream);
}
/// <summary>Loads a ciphertext from an input stream overwriting the current
/// ciphertext.</summary>
/// <remarks>
/// Loads a ciphertext from an input stream overwriting the current ciphertext.
/// No checking of the validity of the ciphertext data against encryption
/// parameters is performed. This function should not be used unless the
/// ciphertext comes from a fully trusted source.
/// </remarks>
/// <param name="context">The SEALContext</param>
/// <param name="stream">The stream to load the ciphertext from</param>
/// <exception cref="ArgumentNullException">if context or stream is
/// null</exception>
/// <exception cref="ArgumentException">if the stream is closed or does not
/// support reading</exception>
/// <exception cref="ArgumentException">if context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="EndOfStreamException">if the stream ended
/// unexpectedly</exception>
/// <exception cref="IOException">if I/O operations failed</exception>
/// <exception cref="InvalidOperationException">if the data cannot be loaded
/// by this version of Microsoft SEAL, if the loaded data is invalid, or if the
/// loaded compression mode is not supported</exception>
public long UnsafeLoad(SEALContext context, Stream stream)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
return Serialization.Load(
(byte[] outptr, ulong size, out long outBytes) =>
NativeMethods.Ciphertext_UnsafeLoad(NativePtr, context.NativePtr,
outptr, size, out outBytes),
stream);
}
/// <summary>Loads a ciphertext from an input stream overwriting the current
/// ciphertext.</summary>
/// <remarks>
/// Loads a ciphertext from an input stream overwriting the current ciphertext.
/// The loaded ciphertext is verified to be valid for the given SEALContext.
/// </remarks>
/// <param name="context">The SEALContext</param>
/// <param name="stream">The stream to load the ciphertext from</param>
/// <exception cref="ArgumentNullException">if context or stream is
/// null</exception>
/// <exception cref="ArgumentException">if the stream is closed or does not
/// support reading</exception>
/// <exception cref="ArgumentException">if context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="EndOfStreamException">if the stream ended
/// unexpectedly</exception>
/// <exception cref="IOException">if I/O operations failed</exception>
/// <exception cref="InvalidOperationException">if the data cannot be loaded
/// by this version of Microsoft SEAL, if the loaded data is invalid, or if the
/// loaded compression mode is not supported</exception>
public long Load(SEALContext context, Stream stream)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
return Serialization.Load(
(byte[] outptr, ulong size, out long outBytes) =>
NativeMethods.Ciphertext_Load(NativePtr, context.NativePtr,
outptr, size, out outBytes),
stream);
}
/// <summary>
/// Returns whether the ciphertext is in NTT form.
/// </summary>
public bool IsNTTForm
{
get
{
NativeMethods.Ciphertext_IsNTTForm(NativePtr, out bool isNTTForm);
return isNTTForm;
}
private set
{
NativeMethods.Ciphertext_SetIsNTTForm(NativePtr, value);
}
}
/// <summary>
/// Returns a copy of ParmsId.
/// </summary>
public ParmsId ParmsId
{
get
{
ParmsId parmsId = new ParmsId();
NativeMethods.Ciphertext_ParmsId(NativePtr, parmsId.Block);
return parmsId;
}
private set
{
NativeMethods.Ciphertext_SetParmsId(NativePtr, value.Block);
}
}
/// <summary>
/// Returns a reference to the scale. This is only needed when using the
/// CKKS encryption scheme. The user should have little or no reason to ever
/// change the scale by hand.
/// </summary>
public double Scale
{
get
{
NativeMethods.Ciphertext_Scale(NativePtr, out double scale);
return scale;
}
set
{
NativeMethods.Ciphertext_SetScale(NativePtr, value);
}
}
/// <summary>
/// Returns the currently used MemoryPoolHandle.
/// </summary>
public MemoryPoolHandle Pool
{
get
{
NativeMethods.Ciphertext_Pool(NativePtr, out IntPtr pool);
MemoryPoolHandle handle = new MemoryPoolHandle(pool);
return handle;
}
}
/// <summary>
/// Destroy native object.
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.Ciphertext_Destroy(NativePtr);
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Decrypts Ciphertext objects into Plaintext objects. Constructing a Decryptor requires
/// a SEALContext with valid encryption parameters, and the secret key. The Decryptor is
/// also used to compute the invariant noise budget in a given ciphertext.
/// </summary>
/// <remarks>
/// <para>
/// Overloads
/// For the decrypt function we provide two overloads concerning the memory pool used in
/// allocations needed during the operation. In one overload the global memory pool is used
/// for this purpose, and in another overload the user can supply a MemoryPoolHandle
/// to to be used instead. This is to allow one single Decryptor to be used concurrently by
/// several threads without running into thread contention in allocations taking place during
/// operations. For example, one can share one single Decryptor across any number of threads,
/// but in each thread call the decrypt function by giving it a thread-local MemoryPoolHandle
/// to use. It is important for a developer to understand how this works to avoid unnecessary
/// performance bottlenecks.
/// </para>
/// <para>
/// NTT form
/// When using the BFV scheme (SchemeType.BFV), all plaintext and ciphertexts should
/// remain by default in the usual coefficient representation, i.e. not in NTT form.
/// When using the CKKS scheme (SchemeType.CKKS), all plaintexts and ciphertexts
/// should remain by default in NTT form. We call these scheme-specific NTT states the
/// "default NTT form". Decryption requires the input ciphertexts to be in the default
/// NTT form, and will throw an exception if this is not the case.
/// </para>
/// </remarks>
public class Decryptor : NativeObject
{
/// <summary>
/// Creates a Decryptor instance initialized with the specified SEALContext
/// and secret key.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <param name="secretKey">The secret key</param>
/// <exception cref="ArgumentNullException">if either context or secretKey are null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="ArgumentException">if secretKey is not valid</exception>
public Decryptor(SEALContext context, SecretKey secretKey)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (null == secretKey)
throw new ArgumentNullException(nameof(secretKey));
if (!context.ParametersSet)
throw new ArgumentException("Encryption parameters are not set correctly");
if (!ValCheck.IsValidFor(secretKey, context))
throw new ArgumentException("Secret key is not valid for encryption parameters");
NativeMethods.Decryptor_Create(context.NativePtr, secretKey.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Decrypts a Ciphertext and stores the result in the destination parameter. Dynamic
/// memory allocations in the process are allocated from the memory pool pointed to by
/// the given MemoryPoolHandle.
/// </summary>
/// <param name="encrypted">The ciphertext to decrypt</param>
/// <param name="destination">The plaintext to overwrite with the decrypted ciphertext</param>
/// <exception cref="ArgumentNullException">if either encrypted or destination are null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Decrypt(Ciphertext encrypted, Plaintext destination)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.Decryptor_Decrypt(NativePtr, encrypted.NativePtr, destination.NativePtr);
}
/// <summary>
/// Computes the invariant noise budget (in bits) of a ciphertext. The invariant noise
/// budget measures the amount of room there is for the noise to grow while ensuring
/// correct decryptions. Dynamic memory allocations in the process are allocated from
/// the memory pool pointed to by the given MemoryPoolHandle. This function works only
/// with the BFV scheme.
/// </summary>
/// <remarks>
/// <para>
/// Invariant Noise Budget
/// The invariant noise polynomial of a ciphertext is a rational coefficient polynomial,
/// such that a ciphertext decrypts correctly as long as the coefficients of the invariant
/// noise polynomial are of absolute value less than 1/2. Thus, we call the infinity-norm
/// of the invariant noise polynomial the invariant noise, and for correct decryption require
/// it to be less than 1/2. If v denotes the invariant noise, we define the invariant noise
/// budget as -log2(2v). Thus, the invariant noise budget starts from some initial value,
/// which depends on the encryption parameters, and decreases when computations are performed.
/// When the budget reaches zero, the ciphertext becomes too noisy to decrypt correctly.
/// </para>
/// </remarks>
/// <param name="encrypted">The ciphertext</param>
/// <exception cref="ArgumentNullException">if encrypted is null</exception>
/// <exception cref="ArgumentException">if the scheme is not BFV</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is in NTT form</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public int InvariantNoiseBudget(Ciphertext encrypted)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
NativeMethods.Decryptor_InvariantNoiseBudget(NativePtr, encrypted.NativePtr, out int result);
return result;
}
/// <summary>
/// Destroy native object
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.Decryptor_Destroy(NativePtr);
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.Text;
using Microsoft.Research.SEAL.Tools;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Stores a set of attributes (qualifiers) of a set of encryption parameters.
/// </summary>
///
/// <remarks>
/// Stores a set of attributes (qualifiers) of a set of encryption parameters.
/// These parameters are mainly used internally in various parts of the library,
/// e.g., to determine which algorithmic optimizations the current support.
/// The qualifiers are automatically created by the <see cref="SEALContext" />
/// class, silently passed on to classes such as <see cref="Encryptor" />,
/// <see cref="Evaluator" />, and <see cref="Decryptor" />, and the only way
/// to change them is by changing the encryption parameters themselves. In
/// other words, a user will never have to create their own instance of this
/// class, and in most cases never have to worry about it at all.
/// </remarks>
public class EncryptionParameterQualifiers : NativeObject
{
/// <summary>
/// Create a copy of an existing instance of EncryptionParameterQualifiers
/// </summary>
/// <param name="copy">Original object to copy</param>
public EncryptionParameterQualifiers(EncryptionParameterQualifiers copy)
{
if (null == copy)
throw new ArgumentNullException(nameof(copy));
NativeMethods.EPQ_Create(copy.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Create an instance of EncryptionParameterQualifiers through a pointer to
/// a native object.
/// </summary>
/// <param name="ptr">Pointer to native EncryptionParameterQualifiers.</param>
/// <param name="owned">Whether this instance owns the native pointer.</param>
internal EncryptionParameterQualifiers(IntPtr ptr, bool owned = true)
: base(ptr, owned)
{
}
/// <summary>
/// If the encryption parameters are set in a way that is considered valid by SEAL,
/// the variable ParametersSet is set to true.
/// </summary>
public bool ParametersSet
{
get
{
NativeMethods.EPQ_ParametersSet(NativePtr, out bool result);
return result;
}
}
/// <summary>
/// If the encryption parameters are set in a way that is considered valid by SEAL, return "success".
/// If the encryption parameters are set but not validated yet, return "none".
/// Otherwise, return a brief reason.
/// </summary>
public string ParametersErrorName()
{
NativeMethods.EPQ_ParameterErrorName(NativePtr, null, out ulong length);
StringBuilder buffer = new StringBuilder(checked((int)length));
NativeMethods.EPQ_ParameterErrorName(NativePtr, buffer, out length);
return buffer.ToString();
}
/// <summary>
/// If the encryption parameters are set in a way that is considered valid by SEAL, return "valid".
/// Otherwise, return a comprehensive reason.
/// </summary>
public string ParametersErrorMessage()
{
NativeMethods.EPQ_ParameterErrorMessage(NativePtr, null, out ulong length);
StringBuilder buffer = new StringBuilder(checked((int)length));
NativeMethods.EPQ_ParameterErrorMessage(NativePtr, buffer, out length);
return buffer.ToString();
}
/// <summary>
/// Tells whether FFT can be used for polynomial multiplication.
/// </summary>
///
/// <remarks>
/// Tells whether FFT can be used for polynomial multiplication. If the polynomial modulus
/// is of the form X^N+1, where N is a power of two, then FFT can be used for fast
/// multiplication of polynomials modulo the polynomial modulus. In this case the
/// variable UsingFFT will be set to true. However, currently Microsoft SEAL requires this
/// to be the case for the parameters to be valid. Therefore, ParametersSet can only
/// be true if UsingFFT is true.
/// </remarks>
public bool UsingFFT
{
get
{
NativeMethods.EPQ_UsingFFT(NativePtr, out bool result);
return result;
}
}
/// <summary>
/// Tells whether NTT can be used for polynomial multiplication.
/// </summary>
///
/// <remarks>
/// Tells whether NTT can be used for polynomial multiplication. If the primes in the
/// coefficient modulus are congruent to 1 modulo 2N, where X^N+1 is the polynomial
/// modulus and N is a power of two, then the number-theoretic transform (NTT) can be
/// used for fast multiplications of polynomials modulo the polynomial modulus and
/// coefficient modulus.In this case the variable UsingNTT will be set to true. However,
/// currently Microsoft SEAL requires this to be the case for the parameters to be valid.
/// Therefore, ParametersSet can only be true if UsingNTT is true.
/// </remarks>
public bool UsingNTT
{
get
{
NativeMethods.EPQ_UsingNTT(NativePtr, out bool result);
return result;
}
}
/// <summary>
/// Tells whether batching is supported by the encryption parameters.
/// </summary>
///
/// <remarks>
/// Tells whether batching is supported by the encryption parameters. If the plaintext
/// modulus is congruent to 1 modulo 2N, where X^N+1 is the polynomial modulus and N is
/// a power of two, then it is possible to use the BatchEncoder class to view plaintext
/// elements as 2-by-(N/2) matrices of integers modulo the plaintext modulus.This is
/// called batching, and allows the user to operate on the matrix elements(slots) in
/// a SIMD fashion, and rotate the matrix rows and columns.When the computation is
/// easily vectorizable, using batching can yield a huge performance boost.If the
/// encryption parameters support batching, the variable UsingBatching is set to true.
/// </remarks>
public bool UsingBatching
{
get
{
NativeMethods.EPQ_UsingBatching(NativePtr, out bool result);
return result;
}
}
/// <summary>
/// Tells whether fast plain lift is supported by the encryption parameters.
/// </summary>
///
/// <remarks>
/// Tells whether fast plain lift is supported by the encryption parameters. A certain
/// performance optimization in multiplication of a ciphertext by a plaintext
/// (Evaluator.MultiplyPlain) and in transforming a plaintext element to NTT domain
/// (Evaluator.TransformToNTT) can be used when the plaintext modulus is smaller than
/// each prime in the coefficient modulus. In this case the variable UsingFastPlainLift
/// is set to true.
/// </remarks>
public bool UsingFastPlainLift
{
get
{
NativeMethods.EPQ_UsingFastPlainLift(NativePtr, out bool result);
return result;
}
}
/// <summary>
/// Tells whether the coefficient modulus consists of a set of primes that are in
/// decreasing order.
/// </summary>
///
/// <remarks>
/// Tells whether the coefficient modulus consists of a set of primes that are in
/// decreasing order. If this is true, certain modular reductions in base conversion
/// can be omitted, improving performance.
/// </remarks>
public bool UsingDescendingModulusChain
{
get
{
NativeMethods.EPQ_UsingDescendingModulusChain(NativePtr, out bool result);
return result;
}
}
/// <summary>
/// Tells whether the encryption parameters are secure based on the standard
/// parameters from HomomorphicEncryption.org security standard.
/// </summary>
public SecLevelType SecLevel
{
get
{
NativeMethods.EPQ_SecLevel(NativePtr, out int result);
return (SecLevelType)result;
}
}
/// <summary>
/// Destroy native object.
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.EPQ_Destroy(NativePtr);
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Describes the type of encryption scheme to be used.
/// </summary>
public enum SchemeType : byte
{
/// <summary>
/// No scheme set; cannot be used for encryption
/// </summary>
None = 0x0,
/// <summary>
/// Brakerski/Fan-Vercauteren scheme
/// </summary>
BFV = 0x1,
/// <summary>
/// Cheon-Kim-Kim-Song scheme
/// </summary>
CKKS = 0x2
}
/// <summary>
/// Represents the user-customizable encryption scheme settings.
/// </summary>
/// <remarks>
/// <para>
/// Represents user-customizable encryption scheme settings. The parameters (most
/// importantly PolyModulus, CoeffModulus, PlainModulus) significantly affect the
/// performance, capabilities, and security of the encryption scheme. Once an
/// instance of EncryptionParameters is populated with appropriate parameters, it
/// can be used to create an instance of the <see cref="SEALContext" /> class,
/// which verifies the validity of the parameters, and performs necessary
/// pre-computations.
/// </para>
/// <para>
/// Picking appropriate encryption parameters is essential to enable a particular
/// application while balancing performance and security. Some encryption settings
/// will not allow some inputs (e.g. attempting to encrypt a polynomial with more
/// coefficients than PolyModulus or larger coefficients than PlainModulus) or
/// support the desired computations (with noise growing too fast due to too large
/// PlainModulus and too small CoeffModulus).
/// </para>
/// <para>
/// The EncryptionParameters class maintains at all times a 256-bit hash of the
/// currently set encryption parameters called the ParmsId. This hash acts as
/// a unique identifier of the encryption parameters and is used by all further
/// objects created for these encryption parameters. The ParmsId is not intended
/// to be directly modified by the user but is used internally for pre-computation
/// data lookup and input validity checks. In modulus switching the user can use
/// the ParmsId to keep track of the chain of encryption parameters. The ParmsId is
/// not exposed in the public API of EncryptionParameters, but can be accessed
/// through the <see cref="SEALContext.ContextData" /> class once the SEALContext
/// has been created.
/// </para>
/// <para>
/// In general, reading from EncryptionParameters is thread-safe, while mutating
/// is not.
/// </para>
/// <para>
/// Choosing inappropriate encryption parameters may lead to an encryption scheme
/// that is not secure, does not perform well, and/or does not support the input
/// and computation of the desired application. We highly recommend consulting an
/// expert in RLWE-based encryption when selecting parameters, as this is where
/// inexperienced users seem to most often make critical mistakes.
/// </para>
/// </remarks>
public class EncryptionParameters : NativeObject, IEquatable<EncryptionParameters>
{
/// <summary>
/// Creates an empty set of encryption parameters.
/// </summary>
///
/// <param name="scheme">Scheme for the encryption parameters</param>
public EncryptionParameters(SchemeType scheme = SchemeType.None)
{
NativeMethods.EncParams_Create((byte)scheme, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Creates an empty set of encryption parameters.
/// </summary>
/// <param name="scheme">Scheme for the encryption parameters</param>
/// <exception cref="ArgumentException">if scheme is not supported</exception>
public EncryptionParameters(byte scheme)
{
NativeMethods.EncParams_Create(scheme, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Creates a copy of a given instance of EncryptionParameters.
/// </summary>
/// <param name="copy">The EncryptionParameters to copy from</param>
/// <exception cref="ArgumentNullException">if copy is null</exception>
public EncryptionParameters(EncryptionParameters copy)
{
if (null == copy)
throw new ArgumentNullException(nameof(copy));
NativeMethods.EncParams_Create(copy.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Create an instance of Encryption Parameters through a pointer to a
/// native object.
/// </summary>
/// <param name="ptr">Native encryption parameters</param>
/// <param name="owned">Whether this instance owns the native pointer</param>
internal EncryptionParameters(IntPtr ptr, bool owned = true)
: base(ptr, owned)
{
}
/// <summary>
/// Overwrites the EncryptionParameters instance with a copy of a given
/// instance.
/// </summary>
/// <param name="assign">The EncryptionParameters to copy from</param>
/// <exception cref="ArgumentNullException">if assign is null</exception>
public void Set(EncryptionParameters assign)
{
if (null == assign)
throw new ArgumentNullException(nameof(assign));
NativeMethods.EncParams_Set(NativePtr, assign.NativePtr);
}
/// <summary>
/// Returns or Sets the degree of the polynomial modulus parameter.
/// </summary>
/// <remarks>
/// Sets the degree of the polynomial modulus parameter to the specified value.
/// The polynomial modulus directly affects the number of coefficients in plaintext
/// polynomials, the size of ciphertext elements, the computational performance of
/// the scheme (bigger is worse), and the security level(bigger is better). In SEAL
/// the degree of the polynomial modulus must be a power of 2 (e.g. 1024, 2048, 4096,
/// 8192, 16384, or 32768).
/// </remarks>
public ulong PolyModulusDegree
{
get
{
NativeMethods.EncParams_GetPolyModulusDegree(NativePtr, out ulong result);
return result;
}
set
{
NativeMethods.EncParams_SetPolyModulusDegree(NativePtr, value);
}
}
/// <summary>
/// Get a copy of the currently set coefficient modulus parameter, or
/// set the coefficient modulus parameter.
/// </summary>
/// <remarks>
/// When setting:
/// Sets the coefficient modulus parameter. The coefficient modulus consists of a list
/// of distinct prime numbers, and is represented by a list of <see cref="Modulus" />
/// objects. The coefficient modulus directly affects the size of ciphertext elements,
/// the amount of computation that the scheme can perform (bigger is better), and the
/// security level (bigger is worse). In Microsoft SEAL each of the prime numbers in
/// the coefficient modulus must be at most 60 bits, and must be congruent to 1 modulo
/// 2*PolyModulusDegree.
/// </remarks>
/// <exception cref="ArgumentNullException">if the value being set is null</exception>
/// <exception cref="ArgumentException">if the value being set is invalid</exception>
public IEnumerable<Modulus> CoeffModulus
{
get
{
ulong length = 0;
NativeMethods.EncParams_GetCoeffModulus(NativePtr, ref length, null);
IntPtr[] coeffArray = new IntPtr[length];
NativeMethods.EncParams_GetCoeffModulus(NativePtr, ref length, coeffArray);
List<Modulus> result = new List<Modulus>(checked((int)length));
foreach(IntPtr sm in coeffArray)
{
result.Add(new Modulus(sm));
}
return result;
}
set
{
if (null == value)
throw new ArgumentNullException(nameof(value));
IntPtr[] coeffArray = value.Select(sm => sm.NativePtr).ToArray();
NativeMethods.EncParams_SetCoeffModulus(NativePtr, (ulong)coeffArray.LongLength, coeffArray);
}
}
/// <summary>
/// Get a copy of the currently set plaintext modulus parameter, or
/// set the plaintext modulus parameter.
/// </summary>
/// <remarks>
/// When setting:
/// Sets the plaintext modulus parameter. The plaintext modulus is an integer modulus
/// represented by the <see cref="Modulus" /> class. The plaintext modulus determines
/// the largest coefficient that plaintext polynomials can represent. It also affects the
/// amount of computation that the scheme can perform (bigger is worse). In Microsoft SEAL
/// the plaintext modulus can be at most 60 bits long, but can otherwise be any integer.
/// Note, however, that some features (e.g. batching) require the plaintext modulus to be
/// of a particular form.
/// </remarks>
/// <exception cref="ArgumentNullException">if the value being set is null</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception>
public Modulus PlainModulus
{
get
{
NativeMethods.EncParams_GetPlainModulus(NativePtr, out IntPtr ptr);
Modulus sm = new Modulus(ptr, owned: false);
return sm;
}
set
{
NativeMethods.EncParams_SetPlainModulus(NativePtr, value.NativePtr);
}
}
/// <summary>
/// Sets the plaintext modulus parameter.
/// </summary>
/// <remarks>
/// Sets the plaintext modulus parameter. The plaintext modulus is an integer modulus
/// represented by the <see cref="Modulus" /> class. This method instead takes
/// a ulong and automatically creates the Modulus object. The plaintext modulus
/// determines the largest coefficient that plaintext polynomials can represent. It also
/// affects the amount of computation that the scheme can perform (bigger is worse). In
/// Microsoft SEAL the plaintext modulus can be at most 60 bits long, but can otherwise
/// be any integer. Note, however, that some features (e.g. batching) require the
/// plaintext modulus to be of a particular form.
/// </remarks>
/// <param name="plainModulus">The new plaintext modulus</param>
/// <exception cref="InvalidOperationException">if scheme is not CKKS</exception>
public void SetPlainModulus(ulong plainModulus)
{
NativeMethods.EncParams_SetPlainModulus(NativePtr, plainModulus);
}
/// <summary>
/// Returns the encryption scheme type.
/// </summary>
public SchemeType Scheme
{
get
{
NativeMethods.EncParams_GetScheme(NativePtr, out byte scheme);
return (SchemeType)scheme;
}
}
/// <summary>
/// Returns an upper bound on the size of the EncryptionParameters, as if
/// it was written to an output stream.
/// </summary>
/// <param name="comprMode">The compression mode</param>
/// <exception cref="ArgumentException">if the compression mode is not
/// supported</exception>
/// <exception cref="InvalidOperationException">if the size does not fit in
/// the return type</exception>
public long SaveSize(ComprModeType? comprMode = null)
{
comprMode = comprMode ?? Serialization.ComprModeDefault;
if (!Serialization.IsSupportedComprMode(comprMode.Value))
throw new ArgumentException("Unsupported compression mode");
ComprModeType comprModeValue = comprMode.Value;
NativeMethods.EncParams_SaveSize(
NativePtr, (byte)comprModeValue, out long outBytes);
return outBytes;
}
/// <summary>Saves the EncryptionParameters to an output stream.</summary>
/// <remarks>
/// Saves the EncryptionParameters to an output stream. The output is in
/// binary format and not human-readable.
/// </remarks>
/// <param name="stream">The stream to save the EncryptionParameters to</param>
/// <param name="comprMode">The desired compression mode</param>
/// <exception cref="ArgumentNullException">if stream is null</exception>
/// <exception cref="ArgumentException">if the stream is closed or does not
/// support writing, or if compression mode is not supported</exception>
/// <exception cref="IOException">if I/O operations failed</exception>
/// <exception cref="InvalidOperationException">if the data to be saved
/// is invalid, or if compression failed</exception>
public long Save(Stream stream, ComprModeType? comprMode = null)
{
comprMode = comprMode ?? Serialization.ComprModeDefault;
if (!Serialization.IsSupportedComprMode(comprMode.Value))
throw new ArgumentException("Unsupported compression mode");
ComprModeType comprModeValue = comprMode.Value;
return Serialization.Save(
(byte[] outptr, ulong size, byte cm, out long outBytes) =>
NativeMethods.EncParams_Save(NativePtr, outptr, size,
cm, out outBytes),
SaveSize(comprModeValue), comprModeValue, stream);
}
/// <summary>
/// Loads an EncryptionParameters from an input stream overwriting the
/// current EncryptionParameters.
/// </summary>
/// <param name="stream">The stream to load the EncryptionParameters from</param>
/// <exception cref="ArgumentNullException">if stream is null</exception>
/// <exception cref="ArgumentException">if the stream is closed or does not
/// support reading</exception>
/// <exception cref="EndOfStreamException">if the stream ended
/// unexpectedly</exception>
/// <exception cref="IOException">if I/O operations failed</exception>
/// <exception cref="InvalidOperationException">if the data cannot be loaded
/// by this version of Microsoft SEAL, if the loaded data is invalid, or if the
/// loaded compression mode is not supported</exception>
public long Load(Stream stream)
{
return Serialization.Load(
(byte[] outptr, ulong size, out long outBytes) =>
NativeMethods.EncParams_Load(NativePtr, outptr, size,
out outBytes),
stream);
}
/// <summary>
/// Returns the ParmsId of the current parameters. This function is intended
/// for internal use.
/// </summary>
internal ParmsId ParmsId
{
get
{
ParmsId id = new ParmsId();
NativeMethods.EncParams_GetParmsId(NativePtr, id.Block);
return id;
}
}
/// <summary>
/// Compares a given set of encryption parameters to the current set of
/// encryption parameters.
/// </summary>
/// <remarks>
/// Compares a given set of encryption parameters to the current set of encryption
/// parameters. The comparison is performed by comparing hash blocks of the parameter
/// sets rather than comparing the parameters individually.
/// </remarks>
/// <param name="obj">The EncryptionParameters to compare against</param>
public override bool Equals(object obj)
{
EncryptionParameters encParams = obj as EncryptionParameters;
return Equals(encParams);
}
/// <summary>
/// Returns a hash-code based on the EncryptionParameters.
/// </summary>
public override int GetHashCode()
{
return Utilities.ComputeArrayHashCode(ParmsId.Block);
}
#region IEquatable<EncryptionParameters> methods
/// <summary>
/// Compares a given set of encryption parameters to the current set of
/// encryption parameters.
/// </summary>
///
/// <remarks>
/// Compares a given set of encryption parameters to the current set of encryption
/// parameters. The comparison is performed by comparing hash blocks of the parameter
/// sets rather than comparing the parameters individually.
/// </remarks>
/// <param name="other">The EncryptionParameters to compare against</param>
public bool Equals(EncryptionParameters other)
{
if (null == other)
return false;
NativeMethods.EncParams_Equals(NativePtr, other.NativePtr, out bool result);
return result;
}
#endregion
/// <summary>
/// Destroy native object.
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.EncParams_Destroy(NativePtr);
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Encrypts Plaintext objects into Ciphertext objects.
/// </summary>
/// <remarks>
/// <para>
/// Encrypts Plaintext objects into Ciphertext objects. Constructing an Encryptor
/// requires a SEALContext with valid encryption parameters, the public key and/or
/// the secret key. If an Encrytor is given a secret key, it supports symmetric-key
/// encryption. If an Encryptor is given a public key, it supports asymmetric-key
/// encryption.
/// </para>
/// <para>
/// Overloads
/// For the encrypt function we provide two overloads concerning the memory pool used in
/// allocations needed during the operation. In one overload the global memory pool is used
/// for this purpose, and in another overload the user can supply a MemoryPoolHandle
/// to to be used instead. This is to allow one single Encryptor to be used concurrently by
/// several threads without running into thread contention in allocations taking place during
/// operations. For example, one can share one single Encryptor across any number of threads,
/// but in each thread call the encrypt function by giving it a thread-local MemoryPoolHandle
/// to use. It is important for a developer to understand how this works to avoid unnecessary
/// performance bottlenecks.
/// </para>
/// <para>
/// NTT form
/// When using the BFV scheme (SchemeType.BFV), all plaintext and ciphertexts should
/// remain by default in the usual coefficient representation, i.e. not in NTT form.
/// When using the CKKS scheme (SchemeType.CKKS), all plaintexts and ciphertexts
/// should remain by default in NTT form. We call these scheme-specific NTT states the
/// "default NTT form". Decryption requires the input ciphertexts to be in the default
/// NTT form, and will throw an exception if this is not the case.
/// </para>
/// </remarks>
public class Encryptor : NativeObject
{
/// <summary>
/// Creates an Encryptor instance initialized with the specified SEALContext,
/// public key, and/or secret key.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <param name="publicKey">The public key</param>
/// <param name="secretKey">The secret key</param>
/// <exception cref="ArgumentNullException">if context is null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="ArgumentException">if publicKey is not valid</exception>
/// <exception cref="ArgumentException">if secretKey is not null and not valid</exception>
public Encryptor(SEALContext context, PublicKey publicKey, SecretKey secretKey = null)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (!context.ParametersSet)
throw new ArgumentException("Encryption parameters are not set correctly");
if (!ValCheck.IsValidFor(publicKey, context))
throw new ArgumentException("Public key is not valid for encryption parameters");
if (null == secretKey)
{
NativeMethods.Encryptor_Create(
context.NativePtr, publicKey.NativePtr, IntPtr.Zero, out IntPtr ptr);
NativePtr = ptr;
}
else
{
if (!ValCheck.IsValidFor(secretKey, context))
throw new ArgumentException("Secret key is not valid for encryption parameters");
NativeMethods.Encryptor_Create(
context.NativePtr, publicKey.NativePtr, secretKey.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
}
/// <summary>
/// Creates an Encryptor instance initialized with the specified SEALContext
/// and secret key.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <param name="secretKey">The secret key</param>
/// <exception cref="ArgumentNullException">if context is null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="ArgumentException">if secretKey is not valid</exception>
public Encryptor(SEALContext context, SecretKey secretKey)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (!context.ParametersSet)
throw new ArgumentException("Encryption parameters are not set correctly");
if (!ValCheck.IsValidFor(secretKey, context))
throw new ArgumentException("Secret key is not valid for encryption parameters");
NativeMethods.Encryptor_Create(context.NativePtr, IntPtr.Zero, secretKey.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Give a new instance of public key.
/// </summary>
/// <param name="publicKey">The public key</param>
/// <exception cref="ArgumentException">if publicKey is not valid</exception>
public void SetPublicKey(PublicKey publicKey)
{
NativeMethods.Encryptor_SetPublicKey(NativePtr, publicKey.NativePtr);
}
/// <summary>
/// Give a new instance of secret key.
/// </summary>
/// <param name="secretKey">The secret key</param>
/// <exception cref="ArgumentException">if secretKey is not valid</exception>
public void SetSecretKey(SecretKey secretKey)
{
NativeMethods.Encryptor_SetSecretKey(NativePtr, secretKey.NativePtr);
}
/// <summary>
/// Encrypts a plaintext with the public key and stores the result in destination.
/// </summary>
/// <remarks>
/// <para>
/// Encrypts a plaintext with the public key and stores the result in destination.
/// </para>
/// <para>
/// The encryption parameters for the resulting ciphertext correspond to:
/// 1) in BFV, the highest (data) level in the modulus switching chain,
/// 2) in CKKS, the encryption parameters of the plaintext.
/// Dynamic memory allocations in the process are allocated from the memory
/// pool pointed to by the given MemoryPoolHandle.
/// </para>
/// </remarks>
/// <param name="plain">The plaintext to encrypt</param>
/// <param name="destination">The ciphertext to overwrite with the encrypted
/// plaintext</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either plain or destination
/// are null</exception>
/// <exception cref="InvalidOperationException">if a public key is not
/// set</exception>
/// <exception cref="ArgumentException">if plain is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if plain is not in default NTT
/// form</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void Encrypt(
Plaintext plain, Ciphertext destination,
MemoryPoolHandle pool = null)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolHandle = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Encryptor_Encrypt(
NativePtr, plain.NativePtr, destination.NativePtr, poolHandle);
}
/// <summary>
/// Encrypts a zero plaintext with the public key and stores the result in
/// destination.
/// </summary>
/// <remarks>
/// <para>
/// Encrypts a zero plaintext with the public key and stores the result in
/// destination.
/// </para>
/// <para>
/// The encryption parameters for the resulting ciphertext correspond to
/// the given ParmsId. Dynamic memory allocations in the process are allocated
/// from the memory pool pointed to by the given MemoryPoolHandle.
/// </para>
/// </remarks>
/// <param name="parmsId">The ParmsId for the resulting ciphertext</param>
/// <param name="destination">The ciphertext to overwrite with the encrypted
/// plaintext</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either parmsId or destination are
/// null</exception>
/// <exception cref="InvalidOperationException">if a public key is not set</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void EncryptZero(
ParmsId parmsId, Ciphertext destination,
MemoryPoolHandle pool = null)
{
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolHandle = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Encryptor_EncryptZero1(
NativePtr, parmsId.Block, destination.NativePtr, poolHandle);
}
/// <summary>
/// Encrypts a zero plaintext with the public key and stores the result in
/// destination.
/// </summary>
/// <remarks>
/// <para>
/// Encrypts a zero plaintext with the public key and stores the result in
/// destination.
/// </para>
/// <para>
/// The encryption parameters for the resulting ciphertext correspond to the
/// highest (data) level in the modulus switching chain. Dynamic memory allocations
/// in the process are allocated from the memory pool pointed to by the given
/// MemoryPoolHandle.
/// </para>
/// </remarks>
/// <param name="destination">The ciphertext to overwrite with the encrypted
/// plaintext</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if destination is null</exception>
/// <exception cref="InvalidOperationException">if a public key is not set</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void EncryptZero(Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolHandle = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Encryptor_EncryptZero2(NativePtr, destination.NativePtr, poolHandle);
}
/// <summary>
/// Encrypts a plaintext with the secret key and stores the result in destination.
/// </summary>
/// <remarks>
/// <para>
/// Encrypts a plaintext with the secret key and stores the result in destination.
/// </para>
/// <para>
/// The encryption parameters for the resulting ciphertext correspond to:
/// 1) in BFV, the highest (data) level in the modulus switching chain,
/// 2) in CKKS, the encryption parameters of the plaintext.
/// Dynamic memory allocations in the process are allocated from the memory
/// pool pointed to by the given MemoryPoolHandle.
/// </para>
/// </remarks>
/// <param name="plain">The plaintext to encrypt</param>
/// <param name="destination">The ciphertext to overwrite with the encrypted
/// plaintext</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either plain or destination are
/// null</exception>
/// <exception cref="InvalidOperationException">if a secret key is not set</exception>
/// <exception cref="ArgumentException">if plain is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if plain is not in default NTT form</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void EncryptSymmetric(
Plaintext plain, Ciphertext destination,
MemoryPoolHandle pool = null)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolHandle = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Encryptor_EncryptSymmetric(
NativePtr, plain.NativePtr, false, destination.NativePtr, poolHandle);
}
/// <summary>
/// Encrypts a zero plaintext with the secret key and stores the result in
/// destination.
/// </summary>
/// <remarks>
/// <para>
/// Encrypts a zero plaintext with the secret key and stores the result in
/// destination.
/// </para>
/// <para>
/// The encryption parameters for the resulting ciphertext correspond to the given
/// ParmsId. Dynamic memory allocations in the process are allocated from the
/// memory pool pointed to by the given MemoryPoolHandle.
/// </para>
/// </remarks>
/// <param name="parmsId">The ParmsId for the resulting ciphertext</param>
/// <param name="destination">The ciphertext to overwrite with the encrypted
/// plaintext</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either parmsId or destination are
/// null</exception>
/// <exception cref="InvalidOperationException">if a secret key is not set</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void EncryptZeroSymmetric(
ParmsId parmsId, Ciphertext destination,
MemoryPoolHandle pool = null)
{
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolHandle = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Encryptor_EncryptZeroSymmetric1(
NativePtr, parmsId.Block, false, destination.NativePtr, poolHandle);
}
/// <summary>
/// Encrypts a zero plaintext with the secret key and stores the result in
/// destination.
/// </summary>
/// <remarks>
/// <para>
/// Encrypts a zero plaintext with the secret key and stores the result in
/// destination.
/// </para>
/// <para>
/// The encryption parameters for the resulting ciphertext correspond to the
/// highest (data) level in the modulus switching chain. Dynamic memory allocations
/// in the process are allocated from the memory pool pointed to by the given
/// MemoryPoolHandle.
/// </para>
/// </remarks>
/// <param name="destination">The ciphertext to overwrite with the encrypted
/// plaintext</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if destination is null</exception>
/// <exception cref="InvalidOperationException">if a secret key is not set</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void EncryptZeroSymmetric(
Ciphertext destination,
MemoryPoolHandle pool = null)
{
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolHandle = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Encryptor_EncryptZeroSymmetric2(
NativePtr, false, destination.NativePtr, poolHandle);
}
/// <summary>
/// Encrypts a plaintext with the secret key and returns the ciphertext as
/// a serializable object.
/// </summary>
/// <remarks>
/// <para>
/// Encrypts a plaintext with the secret key and returns the ciphertext as
/// a serializable object.
/// </para>
/// <para>
/// The encryption parameters for the resulting ciphertext correspond to:
/// 1) in BFV, the highest (data) level in the modulus switching chain,
/// 2) in CKKS, the encryption parameters of the plaintext.
/// Dynamic memory allocations in the process are allocated from the memory
/// pool pointed to by the given MemoryPoolHandle.
/// </para>
/// <para>
/// Half of the ciphertext data is pseudo-randomly generated from a seed to
/// reduce the object size. The resulting serializable object cannot be used
/// directly and is meant to be serialized for the size reduction to have an
/// impact.
/// </para>
/// </remarks>
/// <param name="plain">The plaintext to encrypt</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if plain is null</exception>
/// <exception cref="InvalidOperationException">if a secret key is not set</exception>
/// <exception cref="ArgumentException">if plain is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if plain is not in default NTT
/// form</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public Serializable<Ciphertext> EncryptSymmetric(
Plaintext plain,
MemoryPoolHandle pool = null)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
IntPtr poolHandle = pool?.NativePtr ?? IntPtr.Zero;
Ciphertext destination = new Ciphertext();
NativeMethods.Encryptor_EncryptSymmetric(
NativePtr, plain.NativePtr, true, destination.NativePtr, poolHandle);
return new Serializable<Ciphertext>(destination);
}
/// <summary>
/// Encrypts a zero plaintext with the secret key and returns the ciphertext
/// as a serializable object.
/// </summary>
/// <remarks>
/// <para>
/// Encrypts a zero plaintext with the secret key and returns the ciphertext
/// as a serializable object.
/// </para>
/// <para>
/// The encryption parameters for the resulting ciphertext correspond to
/// the given ParmsId. Dynamic memory allocations in the process are allocated
/// from the memory pool pointed to by the given MemoryPoolHandle.
/// </para>
/// <para>
/// Half of the ciphertext data is pseudo-randomly generated from a seed to
/// reduce the object size. The resulting serializable object cannot be used
/// directly and is meant to be serialized for the size reduction to have an
/// impact.
/// </para>
/// </remarks>
/// <param name="parmsId">The ParmsId for the resulting ciphertext</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory
/// pool</param>
/// <exception cref="ArgumentNullException">if parmsId is null</exception>
/// <exception cref="InvalidOperationException">if a secret key is not
/// set</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public Serializable<Ciphertext> EncryptZeroSymmetric(
ParmsId parmsId,
MemoryPoolHandle pool = null)
{
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
IntPtr poolHandle = pool?.NativePtr ?? IntPtr.Zero;
Ciphertext destination = new Ciphertext();
NativeMethods.Encryptor_EncryptZeroSymmetric1(
NativePtr, parmsId.Block, true, destination.NativePtr, poolHandle);
return new Serializable<Ciphertext>(destination);
}
/// <summary>
/// Encrypts a zero plaintext with the secret key and returns the ciphertext
/// as a serializable object.
/// </summary>
/// <remarks>
/// <para>
/// Encrypts a zero plaintext with the secret key and returns the ciphertext
/// as a serializable object.
/// </para>
/// <para>
/// The encryption parameters for the resulting ciphertext correspond to the
/// highest (data) level in the modulus switching chain. Dynamic memory
/// allocations in the process are allocated from the memory pool pointed to
/// by the given MemoryPoolHandle.
/// </para>
/// <para>
/// Half of the ciphertext data is pseudo-randomly generated from a seed to
/// reduce the object size. The resulting serializable object cannot be used
/// directly and is meant to be serialized for the size reduction to have an
/// impact.
/// </para>
/// </remarks>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory
/// pool</param>
/// <exception cref="InvalidOperationException">if a secret key is not
/// set</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public Serializable<Ciphertext> EncryptZeroSymmetric(MemoryPoolHandle pool = null)
{
IntPtr poolHandle = pool?.NativePtr ?? IntPtr.Zero;
Ciphertext destination = new Ciphertext();
NativeMethods.Encryptor_EncryptZeroSymmetric2(
NativePtr, true, destination.NativePtr, poolHandle);
return new Serializable<Ciphertext>(destination);
}
/// <summary>
/// Destroy native object.
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.Encryptor_Destroy(NativePtr);
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Provides operations on ciphertexts.
/// </summary>
///
/// <remarks>
/// <para>
/// Provides operations on ciphertexts. Due to the properties of the encryption scheme,
/// the arithmetic operations pass through the encryption layer to the underlying plaintext,
/// changing it according to the type of the operation. Since the plaintext elements are
/// fundamentally polynomials in the polynomial quotient ring 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 the
/// arithmetic operations will take place. BatchEncoder (batching) provider an alternative
/// possibly more convenient view of the plaintext elements as 2-by-(N2/2) matrices of
/// integers modulo the plaintext modulus. In the batching view the arithmetic operations
/// act on the matrices element-wise. Some of the operations only apply in the batching
/// view, such as matrix row and column rotations. Other operations such as relinearization
/// have no semantic meaning but are necessary for performance reasons.
/// </para>
/// <para>
/// Arithmetic Operations
/// The core operations are arithmetic operations, in particular multiplication and addition
/// of ciphertexts. In addition to these, we also provide negation, subtraction, squaring,
/// exponentiation, and multiplication and addition of several ciphertexts for convenience.
/// in many cases some of the inputs to a computation are plaintext elements rather than
/// ciphertexts. For this we provide fast "plain" operations: plain addition, plain subtraction,
/// and plain multiplication.
/// </para>
/// <para>
/// Relinearization
/// One of the most important non-arithmetic operations is relinearization, which takes
/// as input a ciphertext of size K+1 and relinearization keys (at least K-1 keys are needed),
/// and changes the size of the ciphertext down to 2 (minimum size). For most use-cases only
/// one relinearization key suffices, in which case relinearization should be performed after
/// every multiplication. Homomorphic multiplication of ciphertexts of size K+1 and L+1
/// outputs a ciphertext of size K+L+1, and the computational cost of multiplication is
/// proportional to K*L. Plain multiplication and addition operations of any type do not
/// change the size. Relinearization requires relinearization keys to have been generated.
/// </para>
/// <para>
/// Rotations
/// When batching is enabled, we provide operations for rotating the plaintext matrix rows
/// cyclically left or right, and for rotating the columns (swapping the rows). Rotations
/// require Galois keys to have been generated.
/// </para>
/// <para>
/// Other Operations
/// We also provide operations for transforming ciphertexts to NTT form and back, and for
/// transforming plaintext polynomials to NTT form. These can be used in a very fast plain
/// multiplication variant, that assumes the inputs to be in NTT form. Since the NTT has to
/// be done in any case in plain multiplication, this function can be used when e.g. one
/// plaintext input is used in several plain multiplication, and transforming it several
/// times would not make sense.
/// </para>
/// <para>
/// NTT form
/// When using the BFV scheme (SchemeType.BFV), all plaintexts and ciphertexts should
/// remain by default in the usual coefficient representation, i.e., not in NTT form.
/// When using the CKKS scheme (SchemeType.CKKS), all plaintexts and ciphertexts
/// should remain by default in NTT form. We call these scheme-specific NTT states the
/// "default NTT form". Some functions, such as add, work even if the inputs are not in
/// the default state, but others, such as multiply, will throw an exception. The output
/// of all evaluation functions will be in the same state as the input(s), with the
/// exception of the TransformToNTT and TransformFromNTT functions, which change the
/// state. Ideally, unless these two functions are called, all other functions should
/// "just work".
/// </para>
/// </remarks>
/// <see cref="EncryptionParameters"/> for more details on encryption parameters.
/// <see cref="BatchEncoder"/> for more details on batching
/// <see cref="RelinKeys"/> for more details on relinearization keys.
/// <see cref="GaloisKeys"/> for more details on Galois keys.
public class Evaluator : NativeObject
{
/// <summary>
/// Creates an Evaluator instance initialized with the specified SEALContext.
/// </summary>
///
/// <param name="context">The SEALContext</param>
/// <exception cref="ArgumentNullException">if context is null</exception>
/// <exception cref="ArgumentException">if the context is not set or encryption
/// parameters are not valid</exception>
public Evaluator(SEALContext context)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (!context.ParametersSet)
throw new ArgumentException("Encryption parameters are not set correctly");
NativeMethods.Evaluator_Create(context.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Negates a ciphertext.
/// </summary>
///
/// <param name="encrypted">The ciphertext to negate</param>
/// <exception cref="ArgumentNullException">if encrypted is null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void NegateInplace(Ciphertext encrypted)
{
Negate(encrypted, destination: encrypted);
}
/// <summary>
/// Negates a ciphertext and stores the result in the destination parameter.
/// </summary>
/// <param name="encrypted">The ciphertext to negate</param>
/// <param name="destination">The ciphertext to overwrite with the negated result</param>
/// <exception cref="ArgumentNullException">if either encrypted or destionation are null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void Negate(Ciphertext encrypted, Ciphertext destination)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.Evaluator_Negate(NativePtr, encrypted.NativePtr, destination.NativePtr);
}
/// <summary>
/// Adds two ciphertexts.
/// </summary>
/// <remarks>
/// This function adds together encrypted1 and encrypted2 and stores the result in encrypted1.
/// </remarks>
/// <param name="encrypted1">The first ciphertext to add</param>
/// <param name="encrypted2">The second ciphertext to add</param>
/// <exception cref="ArgumentNullException">if either encrypted1 or encrypted2 are null</exception>
/// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for
/// the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted1 and encrypted2 are in different
/// NTT forms</exception>
/// <exception cref="ArgumentException">if encrypted1 and encrypted2 have different scale</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void AddInplace(Ciphertext encrypted1, Ciphertext encrypted2)
{
Add(encrypted1, encrypted2, destination: encrypted1);
}
/// <summary>
/// Adds two ciphertexts.
/// </summary>
/// <remarks>
/// This function adds together encrypted1 and encrypted2 and stores the result in the destination
/// parameter.
/// </remarks>
/// <param name="encrypted1">The first ciphertext to add</param>
/// <param name="encrypted2">The second ciphertext to add</param>
/// <param name="destination">The ciphertext to overwrite with the addition result</param>
/// <exception cref="ArgumentNullException">if either encrypted1, encrypted2 or destination are null</exception>
/// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for
/// the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted1 and encrypted2 are in different
/// NTT forms</exception>
/// <exception cref="ArgumentException">if encrypted1 and encrypted2 have different scale</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void Add(Ciphertext encrypted1, Ciphertext encrypted2, Ciphertext destination)
{
if (null == encrypted1)
throw new ArgumentNullException(nameof(encrypted1));
if (null == encrypted2)
throw new ArgumentNullException(nameof(encrypted2));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.Evaluator_Add(NativePtr, encrypted1.NativePtr, encrypted2.NativePtr, destination.NativePtr);
}
/// <summary>
/// Adds together a vector of ciphertexts and stores the result in the destination
/// parameter.
/// </summary>
/// <param name="encrypteds">The ciphertexts to add</param>
/// <param name="destination">The ciphertext to overwrite with the addition result</param>
/// <exception cref="ArgumentNullException">if either encrypteds or destination are null</exception>
/// <exception cref="ArgumentException">if encrypteds is empty</exception>
/// <exception cref="ArgumentException">if the encrypteds are not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if encrypteds are in different NTT forms</exception>
/// <exception cref="ArgumentException">if encrypteds have different scale</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void AddMany(IEnumerable<Ciphertext> encrypteds, Ciphertext destination)
{
if (null == encrypteds)
throw new ArgumentNullException(nameof(encrypteds));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr[] encarray = encrypteds.Select(c => c.NativePtr).ToArray();
NativeMethods.Evaluator_AddMany(NativePtr, (ulong)encarray.Length, encarray, destination.NativePtr);
}
/// <summary>
/// Subtracts two ciphertexts.
/// </summary>
/// <remarks>
/// This function computes the difference of encrypted1 and encrypted2, and stores the result in encrypted1.
/// </remarks>
/// <param name="encrypted1">The ciphertext to subtract from</param>
/// <param name="encrypted2">The ciphertext to subtract</param>
/// <exception cref="ArgumentNullException">if either encrypted1 or encrypted2 are null</exception>
/// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted1 and encrypted2 are in different
/// NTT forms</exception>
/// <exception cref="ArgumentException">if encrypted1 and encrypted2 have different scale</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void SubInplace(Ciphertext encrypted1, Ciphertext encrypted2)
{
Sub(encrypted1, encrypted2, destination: encrypted1);
}
/// <summary>
/// Subtracts two ciphertexts.
/// </summary>
/// <remarks>This function computes the difference of encrypted1 and encrypted2 and stores the result
/// in the destination parameter.
/// </remarks>
/// <param name="encrypted1">The ciphertext to subtract from</param>
/// <param name="encrypted2">The ciphertext to subtract</param>
/// <param name="destination">The ciphertext to overwrite with the subtraction result</param>
/// <exception cref="ArgumentNullException">if either encrypted1, encrypted2 or destination are null</exception>
/// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted1 and encrypted2 are in different
/// NTT forms</exception>
/// <exception cref="ArgumentException">if encrypted1 and encrypted2 have different scale</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void Sub(Ciphertext encrypted1, Ciphertext encrypted2, Ciphertext destination)
{
if (null == encrypted1)
throw new ArgumentNullException(nameof(encrypted1));
if (null == encrypted2)
throw new ArgumentNullException(nameof(encrypted2));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.Evaluator_Sub(NativePtr, encrypted1.NativePtr, encrypted2.NativePtr, destination.NativePtr);
}
/// <summary>
/// Multiplies two ciphertexts.
/// </summary>
/// <remarks>This functions computes the product of encrypted1 and encrypted2 and stores the
/// result in encrypted1. Dynamic memory allocations in the process are allocated from the
/// memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted1">The first ciphertext to multiply</param>
/// <param name="encrypted2">The second ciphertext to multiply</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted1, encrypted2 are null</exception>
/// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not in the default
/// NTT form</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the output scale
/// is too large for the encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void MultiplyInplace(Ciphertext encrypted1, Ciphertext encrypted2,
MemoryPoolHandle pool = null)
{
Multiply(encrypted1, encrypted2, destination: encrypted1, pool: pool);
}
/// <summary>
/// Multiplies two ciphertexts.
/// </summary>
/// <remarks>
/// This functions computes the product of encrypted1 and encrypted2 and stores the result
/// in the destination parameter. Dynamic memory allocations in the process are allocated
/// from the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted1">The first ciphertext to multiply</param>
/// <param name="encrypted2">The second ciphertext to multiply</param>
/// <param name="destination">The ciphertext to overwrite with the multiplication result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted1, encrypted2, destination are null</exception>
/// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted1 or encrypted2 is not in the default
/// NTT form</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the output scale
/// is too large for the encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void Multiply(Ciphertext encrypted1, Ciphertext encrypted2,
Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted1)
throw new ArgumentNullException(nameof(encrypted1));
if (null == encrypted2)
throw new ArgumentNullException(nameof(encrypted2));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_Multiply(NativePtr, encrypted1.NativePtr, encrypted2.NativePtr, destination.NativePtr, poolPtr);
}
/// <summary>
/// Squares a ciphertext.
/// </summary>
/// <remarks>
/// This functions computes the square of encrypted. Dynamic memory allocations in the process
/// are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to square</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted are null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the output scale
/// is too large for the encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void SquareInplace(Ciphertext encrypted, MemoryPoolHandle pool = null)
{
Square(encrypted, destination: encrypted, pool: pool);
}
/// <summary>
/// Squares a ciphertext.
/// </summary>
/// <remarks>
/// This functions computes the square of encrypted and stores the result in the destination
/// parameter. Dynamic memory allocations in the process are allocated from the memory pool
/// pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to square</param>
/// <param name="destination">The ciphertext to overwrite with the square</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted, destination are null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the output scale
/// is too large for the encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void Square(Ciphertext encrypted, Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_Square(NativePtr, encrypted.NativePtr, destination.NativePtr, poolPtr);
}
/// <summary>
/// Relinearizes a ciphertext.
/// </summary>
/// <remarks>
/// This functions relinearizes encrypted, reducing its size down to 2. If the size
/// of encrypted is K+1, the given relinearization keys need to have size at least K-1.
/// Dynamic memory allocations in the process are allocated from the memory pool pointed
/// to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to relinearize</param>
/// <param name="relinKeys">The relinearization keys</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted, relinKeys are null</exception>
/// <exception cref="ArgumentException">if encrypted or relinKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if relinKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if the size of relinKeys is too small</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RelinearizeInplace(Ciphertext encrypted, RelinKeys relinKeys,
MemoryPoolHandle pool = null)
{
Relinearize(encrypted, relinKeys, destination: encrypted, pool: pool);
}
/// <summary>
/// Relinearizes a ciphertext.
/// </summary>
/// <remarks>
/// This functions relinearizes encrypted, reducing its size down to 2, and stores the
/// result in the destination parameter. If the size of encrypted is K+1, the given
/// relinearization keys need to have size at least K-1. Dynamic memory allocations in the
/// process are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to relinearize</param>
/// <param name="relinKeys">The relinearization keys</param>
/// <param name="destination">The ciphertext to overwrite with the relinearized result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted, relinKeys or destination are null</exception>
/// <exception cref="ArgumentException">if encrypted or relinKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if relinKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if the size of relinKeys is too small</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void Relinearize(Ciphertext encrypted, RelinKeys relinKeys,
Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == relinKeys)
throw new ArgumentNullException(nameof(relinKeys));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
if (!ContextUsingKeyswitching)
throw new InvalidOperationException("Keyswitching is not supported by the context");
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_Relinearize(
NativePtr, encrypted.NativePtr, relinKeys.NativePtr, destination.NativePtr, poolPtr);
}
/// <summary>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down to q_1...q_{k-1} and stores the result in the destination parameter.
/// </summary>
/// <remarks>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down to q_1...q_{k-1} and stores the result in the destination parameter. Dynamic
/// memory allocations in the process are allocated from the memory pool pointed to by
/// the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param>
/// <param name="destination">The ciphertext to overwrite with the modulus switched result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or destination are null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if encrypted is already at lowest level</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the scale is too
/// large for the new encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void ModSwitchToNext(Ciphertext encrypted, Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_ModSwitchToNext(
NativePtr, encrypted.NativePtr, destination.NativePtr, poolPtr);
}
/// <summary>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down to q_1...q_{k-1}.
/// </summary>
/// <remarks>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down to q_1...q_{k-1}. Dynamic memory allocations in the process are allocated from
/// the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if encrypted is null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if encrypted is already at lowest level</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the scale is too
/// large for the new encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void ModSwitchToNextInplace(Ciphertext encrypted, MemoryPoolHandle pool = null)
{
ModSwitchToNext(encrypted, destination: encrypted, pool: pool);
}
/// <summary>
/// Modulus switches an NTT transformed plaintext from modulo q_1...q_k down to modulo
/// q_1...q_{k-1}.
/// </summary>
/// <param name="plain">The plaintext to be switched to a smaller modulus</param>
/// <exception cref="ArgumentNullException">if plain is null</exception>
/// <exception cref="ArgumentException">if plain is not in NTT form</exception>
/// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if plain is already at lowest level</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the scale is too
/// large for the new encryption parameters</exception>
public void ModSwitchToNextInplace(Plaintext plain)
{
ModSwitchToNext(plain, destination: plain);
}
/// <summary>
/// Modulus switches an NTT transformed plaintext from modulo q_1...q_k down to modulo
/// q_1...q_{k-1} and stores the result in the destination parameter.
/// </summary>
/// <param name="plain">The plaintext to be switched to a smaller modulus</param>
/// <param name="destination">destination The plaintext to overwrite with the modulus switched result</param>
/// <exception cref="ArgumentNullException">if either plain or destination are null</exception>
/// <exception cref="ArgumentException">if plain is not in NTT form</exception>
/// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if plain is already at lowest level</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the scale is too
/// large for the new encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void ModSwitchToNext(Plaintext plain, Plaintext destination)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.Evaluator_ModSwitchToNext(NativePtr, plain.NativePtr, destination.NativePtr);
}
/// <summary>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down until the parameters reach the given ParmsId.
/// </summary>
/// <remarks>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down until the parameters reach the given ParmsId. Dynamic memory allocations in
/// the process are allocated from the memory pool pointed to by the given
/// MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param>
/// <param name="parmsId">The target parmsId</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or parmsId are null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is already at lower level in modulus chain
/// than the parameters corresponding to parmsId</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the scale is too
/// large for the new encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void ModSwitchToInplace(Ciphertext encrypted, ParmsId parmsId, MemoryPoolHandle pool = null)
{
ModSwitchTo(encrypted, parmsId, destination: encrypted, pool: pool);
}
/// <summary>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down until the parameters reach the given ParmsId and stores the result in the
/// destination parameter.
/// </summary>
/// <remarks>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down until the parameters reach the given ParmsId and stores the result in the
/// destination parameter. Dynamic memory allocations in the process are allocated
/// from the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param>
/// <param name="parmsId">The target parmsId</param>
/// <param name="destination">The ciphertext to overwrite with the modulus switched result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted, parmsId or destination are null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is already at lower level in modulus chain
/// than the parameters corresponding to parmsId</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the scale is too
/// large for the new encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void ModSwitchTo(Ciphertext encrypted, ParmsId parmsId, Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_ModSwitchTo(
NativePtr, encrypted.NativePtr, parmsId.Block, destination.NativePtr, poolPtr);
}
/// <summary>
/// Given an NTT transformed plaintext modulo q_1...q_k, this function switches the
/// modulus down until the parameters reach the given ParmsId.
/// </summary>
/// <param name="plain">The plaintext to be switched to a smaller modulus</param>
/// <param name="parmsId">The target parmsId</param>
/// <exception cref="ArgumentNullException">if either plain or parmsId is null</exception>
/// <exception cref="ArgumentException">if plain is not in NTT form</exception>
/// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if plain is already at lower level in modulus chain
/// than the parameters corresponding to parmsId</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the scale is too
/// large for the new encryption parameters</exception>
public void ModSwitchToInplace(Plaintext plain, ParmsId parmsId)
{
ModSwitchTo(plain, parmsId, destination: plain);
}
/// <summary>
/// Given an NTT transformed plaintext modulo q_1...q_k, this function switches the
/// modulus down until the parameters reach the given ParmsId and stores the result in
/// the destination parameter.
/// </summary>
/// <param name="plain">The plaintext to be switched to a smaller modulus</param>
/// <param name="parmsId">The target parmsId</param>
/// <param name="destination">The plaintext to overwrite with the modulus switched result</param>
/// <exception cref="ArgumentNullException">if either plain, parmsId or destination are null</exception>
/// <exception cref="ArgumentException">if plain is not in NTT form</exception>
/// <exception cref="ArgumentException">if plain is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if plain is already at lower level in modulus chain
/// than the parameters corresponding to parmsId</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the scale is too
/// large for the new encryption parameters</exception>
public void ModSwitchTo(Plaintext plain, ParmsId parmsId,
Plaintext destination)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.Evaluator_ModSwitchTo(NativePtr, plain.NativePtr, parmsId.Block, destination.NativePtr);
}
/// <summary>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down to q_1...q_{k-1}, scales the message down accordingly, and stores the
/// result in the destination parameter.
/// </summary>
/// <remarks>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down to q_1...q_{k-1}, scales the message down accordingly, and stores the
/// result in the destination parameter. Dynamic memory allocations in the process
/// are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param>
/// <param name="destination">The ciphertext to overwrite with the modulus switched result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or destination are null</exception>
/// <exception cref="ArgumentException">if the scheme is invalid for rescaling</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if encrypted is already at lowest level</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RescaleToNext(Ciphertext encrypted, Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_RescaleToNext(
NativePtr, encrypted.NativePtr, destination.NativePtr, poolPtr);
}
/// <summary>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down to q_1...q_{k-1} and scales the message down accordingly.
/// </summary>
/// <remarks>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down to q_1...q_{k-1} and scales the message down accordingly. Dynamic memory
/// allocations in the process are allocated from the memory pool pointed to by the
/// given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if encrypted is null</exception>
/// <exception cref="ArgumentException">if the scheme is invalid for rescaling</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form
/// guaranteed to be</exception>
/// <exception cref="ArgumentException">if encrypted is already at lowest level</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RescaleToNextInplace(Ciphertext encrypted, MemoryPoolHandle pool = null)
{
RescaleToNext(encrypted, destination: encrypted, pool: pool);
}
/// <summary>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down until the parameters reach the given ParmsId and scales the message down
/// accordingly.
/// </summary>
/// <remarks>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down until the parameters reach the given ParmsId and scales the message down
/// accordingly. Dynamic memory allocations in the process are allocated from the
/// memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param>
/// <param name="parmsId">The target parmsId</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or parmsId are null</exception>
/// <exception cref="ArgumentException">if the scheme is invalid for rescaling</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is already at lower level in modulus chain
/// than the parameters corresponding to parmsId</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RescaleToInplace(Ciphertext encrypted, ParmsId parmsId, MemoryPoolHandle pool = null)
{
RescaleTo(encrypted, parmsId, destination: encrypted, pool: pool);
}
/// <summary>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down until the parameters reach the given ParmsId, scales the message down
/// accordingly, and stores the result in the destination parameter.
/// </summary>
/// <remarks>
/// Given a ciphertext encrypted modulo q_1...q_k, this function switches the modulus
/// down until the parameters reach the given ParmsId, scales the message down
/// accordingly, and stores the result in the destination parameter. Dynamic memory
/// allocations in the process are allocated from the memory pool pointed to by the
/// given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to be switched to a smaller modulus</param>
/// <param name="parmsId">The target parmsId</param>
/// <param name="destination">The ciphertext to overwrite with the modulus switched result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted, parmsId or destination are null.</exception>
/// <exception cref="ArgumentException">if the scheme is invalid for rescaling</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if parmsId is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is already at lower level in modulus chain
/// than the parameters corresponding to parmsId</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RescaleTo(Ciphertext encrypted, ParmsId parmsId, Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_RescaleTo(
NativePtr, encrypted.NativePtr, parmsId.Block, destination.NativePtr, poolPtr);
}
/// <summary>
/// Multiplies several ciphertexts together. This function computes the product of several
/// ciphertext given as an IEnumerable and stores the result in the destination parameter.
/// </summary>
/// <remarks>
/// Multiplies several ciphertexts together. This function computes the product of several
/// ciphertext given as an IEnumerable and stores the result in the destination parameter.
/// The multiplication is done in a depth-optimal order, and relinearization is performed
/// automatically after every multiplication in the process. In relinearization the given
/// relinearization keys are used. Dynamic memory allocations in the process are allocated
/// from the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypteds">The ciphertexts to multiply</param>
/// <param name="relinKeys">The relinearization keys</param>
/// <param name="destination">The ciphertext to overwrite with the multiplication result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypteds, relinKeys or destination are null</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception>
/// <exception cref="ArgumentException">if encrypteds is empty</exception>
/// <exception cref="ArgumentException">if the ciphertexts or relinKeys are not valid for
/// the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypteds are not in the default NTT form</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the output scale
/// is too large for the encryption parameters</exception>
/// <exception cref="ArgumentException">if the size of relinKeys is too small</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void MultiplyMany(IEnumerable<Ciphertext> encrypteds, RelinKeys relinKeys,
Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypteds)
throw new ArgumentNullException(nameof(encrypteds));
if (null == relinKeys)
throw new ArgumentNullException(nameof(relinKeys));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
if (!ContextUsingKeyswitching)
throw new InvalidOperationException("Keyswitching is not supported by the context");
IntPtr[] encarray = encrypteds.Select(c => c.NativePtr).ToArray();
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_MultiplyMany(
NativePtr, (ulong)encarray.Length, encarray, relinKeys.NativePtr,
destination.NativePtr, poolPtr);
}
/// <summary>
/// Exponentiates a ciphertext.
/// </summary>
/// <remarks>
/// This functions raises encrypted to a power. Dynamic memory allocations in the process
/// are allocated from the memory pool pointed to by the given MemoryPoolHandle. The
/// exponentiation is done in a depth-optimal order, and relinearization is performed
/// automatically after every multiplication in the process. In relinearization the given
/// relinearization keys are used.
/// </remarks>
/// <param name="encrypted">The ciphertext to exponentiate</param>
/// <param name="exponent">The power to raise the ciphertext to</param>
/// <param name="relinKeys">The relinearization keys</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or relinKeys are null</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception>
/// <exception cref="ArgumentException">if encrypted or relinKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the output scale
/// is too large for the encryption parameters</exception>
/// <exception cref="ArgumentException">if exponent is zero</exception>
/// <exception cref="ArgumentException">if the size of relinKeys is too small</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void ExponentiateInplace(Ciphertext encrypted, ulong exponent,
RelinKeys relinKeys, MemoryPoolHandle pool = null)
{
Exponentiate(encrypted, exponent, relinKeys, destination: encrypted, pool: pool);
}
/// <summary>
/// Exponentiates a ciphertext.
/// </summary>
/// <remarks>
/// This functions raises encrypted to a power and stores the result in the destination
/// parameter. Dynamic memory allocations in the process are allocated from the memory pool
/// pointed to by the given MemoryPoolHandle. The exponentiation is done in a depth-optimal
/// order, and relinearization is performed automatically after every multiplication in the
/// process. In relinearization the given relinearization keys are used.
/// </remarks>
/// <param name="encrypted">The ciphertext to exponentiate</param>
/// <param name="exponent">The power to raise the ciphertext to</param>
/// <param name="relinKeys">The relinearization keys</param>
/// <param name="destination">The ciphertext to overwrite with the power</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception>
/// <exception cref="ArgumentException">if encrypted or relinKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the output scale
/// is too large for the encryption parameters</exception>
/// <exception cref="ArgumentException">if exponent is zero</exception>
/// <exception cref="ArgumentException">if the size of relinKeys is too small</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void Exponentiate(Ciphertext encrypted, ulong exponent, RelinKeys relinKeys,
Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == relinKeys)
throw new ArgumentNullException(nameof(relinKeys));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
if (!ContextUsingKeyswitching)
throw new InvalidOperationException("Keyswitching is not supported by the context");
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_Exponentiate(
NativePtr, encrypted.NativePtr, exponent, relinKeys.NativePtr,
destination.NativePtr, poolPtr);
}
/// <summary>
/// Adds a ciphertext and a plaintext.
/// </summary>
/// <remarks>
/// Adds a ciphertext and a plaintext. The plaintext must be valid for the current
/// encryption parameters.
/// </remarks>
/// <param name="encrypted">The ciphertext to add</param>
/// <param name="plain">The plaintext to add</param>
/// <exception cref="ArgumentNullException">if either encrypted or plain are null</exception>
/// <exception cref="ArgumentException">if encrypted or plain is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if encrypted or plain is in NTT form</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void AddPlainInplace(Ciphertext encrypted, Plaintext plain)
{
AddPlain(encrypted, plain, destination: encrypted);
}
/// <summary>
/// Adds a ciphertext and a plaintext.
/// </summary>
/// <remarks>
/// Adds a ciphertext and a plaintext. This function adds a ciphertext and a plaintext
/// and stores the result in the destination parameter. The plaintext must be valid for
/// the current encryption parameters.
/// </remarks>
/// <param name="encrypted">The ciphertext to add</param>
/// <param name="plain">The plaintext to add</param>
/// <param name="destination">The ciphertext to overwrite with the addition result</param>
/// <exception cref="ArgumentNullException">if either encrypted, plain or destination are null</exception>
/// <exception cref="ArgumentException">if encrypted or plain is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if encrypted or plain is in NTT form</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void AddPlain(Ciphertext encrypted, Plaintext plain, Ciphertext destination)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.Evaluator_AddPlain(
NativePtr, encrypted.NativePtr, plain.NativePtr, destination.NativePtr);
}
/// <summary>
/// Subtracts a plaintext from a ciphertext.
/// </summary>
/// <remarks>
/// Subtracts a plaintext from a ciphertext. The plaintext must be valid for the current
/// encryption parameters.
/// </remarks>
/// <param name="encrypted">The ciphertext to subtract from</param>
/// <param name="plain">The plaintext to subtract</param>
/// <exception cref="ArgumentNullException">if either encrypted or plain are null</exception>
/// <exception cref="ArgumentException">if encrypted or plain is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if encrypted or plain is in NTT form</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void SubPlainInplace(Ciphertext encrypted, Plaintext plain)
{
SubPlain(encrypted, plain, destination: encrypted);
}
/// <summary>
/// Subtracts a plaintext from a ciphertext.
/// </summary>
/// <remarks>This function subtracts a plaintext from a ciphertext and stores the result in the
/// destination parameter. The plaintext must be valid for the current encryption parameters.
/// </remarks>
/// <param name="encrypted">The ciphertext to subtract from</param>
/// <param name="plain">The plaintext to subtract</param>
/// <param name="destination">The ciphertext to overwrite with the subtraction result</param>
/// <exception cref="ArgumentNullException">if either encrypted, plain or destination are null</exception>
/// <exception cref="ArgumentException">if encrypted or plain is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if encrypted or plain is in NTT form</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void SubPlain(Ciphertext encrypted, Plaintext plain, Ciphertext destination)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.Evaluator_SubPlain(
NativePtr, encrypted.NativePtr, plain.NativePtr, destination.NativePtr);
}
/// <summary>
/// Multiplies a ciphertext with a plaintext.
/// </summary>
/// <remarks>Multiplies a ciphertext with a plaintext. The plaintext must be valid for the
/// current encryption parameters, and cannot be identially 0. Dynamic memory allocations in
/// the process are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to multiply</param>
/// <param name="plain">The plaintext to multiply</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or plain are null.</exception>
/// <exception cref="ArgumentException">if the encrypted or plain is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if encrypted and plain are in different NTT forms</exception>
/// <exception cref="ArgumentException">if plain is zero</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the output scale
/// is too large for the encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void MultiplyPlainInplace(Ciphertext encrypted, Plaintext plain, MemoryPoolHandle pool = null)
{
MultiplyPlain(encrypted, plain, destination: encrypted, pool: pool);
}
/// <summary>
/// Multiplies a ciphertext with a plaintext.
/// </summary>
/// <remarks>
/// This function multiplies a ciphertext with a plaintext and stores the result in the
/// destination parameter. The plaintext must be valid for the current encryption parameters,
/// and cannot be identially 0. Dynamic memory allocations in the process are allocated from
/// the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to multiply</param>
/// <param name="plain">The plaintext to multiply</param>
/// <param name="destination">The ciphertext to overwrite with the multiplication result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted, plain or destination are null</exception>
/// <exception cref="ArgumentException">if the encrypted or plain is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted and plain are in different NTT forms</exception>
/// <exception cref="ArgumentException">if plain is zero</exception>
/// <exception cref="ArgumentException">if, when using SchemeType.CKKS, the output scale
/// is too large for the encryption parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void MultiplyPlain(Ciphertext encrypted, Plaintext plain,
Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_MultiplyPlain(
NativePtr, encrypted.NativePtr, plain.NativePtr, destination.NativePtr, poolPtr);
}
/// <summary>
/// Transforms a plaintext to NTT domain.
/// </summary>
/// <remarks>This functions applies the Number Theoretic Transform to a plaintext by first
/// embedding integers modulo the plaintext modulus to integers modulo the coefficient
/// modulus and then performing David Harvey's NTT on the resulting polynomial. The
/// transformation is done with respect to encryption parameters corresponding to a given
/// parmsId. For the operation to be valid, the plaintext must have degree less than
/// PolyModulusDegree and each coefficient must be less than the plaintext modulus, i.e.,
/// the plaintext must be a valid plaintext under the current encryption parameters.
/// Dynamic memory allocations in the process are allocated from the memory pool pointed
/// to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="plain">The plaintext to transform</param>
/// <param name="parmsId">The ParmsId with respect to which the NTT is done</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either plain or parmsId are null</exception>
/// <exception cref="ArgumentException">if plain is already in NTT form</exception>
/// <exception cref="ArgumentException">if plain or parmsId is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void TransformToNTTInplace(Plaintext plain, ParmsId parmsId, MemoryPoolHandle pool = null)
{
TransformToNTT(plain, parmsId, destinationNTT: plain, pool: pool);
}
/// <summary>
/// Transforms a plaintext to NTT domain.
/// </summary>
/// <remarks>
/// This functions applies the Number Theoretic Transform to a plaintext by first
/// embedding integers modulo the plaintext modulus to integers modulo the coefficient
/// modulus and then performing David Harvey's NTT on the resulting polynomial. The
/// transformation is done with respect to encryption parameters corresponding to
/// a given ParmsId. The result is stored in the destinationNTT parameter. For the
/// operation to be valid, the plaintext must have degree less than PolyModulusDegree
/// and each coefficient must be less than the plaintext modulus, i.e., the plaintext
/// must be a valid plaintext under the current encryption parameters. Dynamic memory
/// allocations in the process are allocated from the memory pool pointed to by the
/// given MemoryPoolHandle.
/// </remarks>
/// <param name="plain">The plaintext to transform</param>
/// <param name="parmsId">The ParmsId with respect to which the NTT is done</param>
/// <param name="destinationNTT">The plaintext to overwrite with the transformed result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either plain, parmsId or destinationNTT are null</exception>
/// <exception cref="ArgumentException">if plain is already in NTT form</exception>
/// <exception cref="ArgumentException">if plain or parmsId is not valid for the encryption
/// parameters</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
public void TransformToNTT(Plaintext plain, ParmsId parmsId,
Plaintext destinationNTT, MemoryPoolHandle pool = null)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
if (null == parmsId)
throw new ArgumentNullException(nameof(parmsId));
if (null == destinationNTT)
throw new ArgumentNullException(nameof(destinationNTT));
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_TransformToNTT(NativePtr, plain.NativePtr, parmsId.Block, destinationNTT.NativePtr, poolPtr);
}
/// <summary>
/// Transforms a ciphertext to NTT domain.
/// </summary>
/// <remarks>
/// Transforms a ciphertext to NTT domain. This functions applies David Harvey's Number
/// Theoretic Transform separately to each polynomial of a ciphertext.
/// </remarks>
/// <param name="encrypted">The ciphertext to transform</param>
/// <exception cref="ArgumentNullException">if encrypted is null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is already in NTT form</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void TransformToNTTInplace(Ciphertext encrypted)
{
TransformToNTT(encrypted, destinationNTT: encrypted);
}
/// <summary>
/// Transforms a ciphertext to NTT domain.
/// </summary>
/// <remarks>
/// Transforms a ciphertext to NTT domain. This functions applies David Harvey's Number
/// Theoretic Transform separately to each polynomial of a ciphertext. The result is
/// stored in the DestinationNTT parameter.
/// </remarks>
/// <param name="encrypted">The ciphertext to transform</param>
/// <param name="destinationNTT">The ciphertext to overwrite with the transformed result</param>
/// <exception cref="ArgumentNullException">if either encrypted or destinationNTT are null</exception>
/// <exception cref="ArgumentException">if encrypted is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encrypted is already in NTT form</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void TransformToNTT(Ciphertext encrypted,
Ciphertext destinationNTT)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == destinationNTT)
throw new ArgumentNullException(nameof(destinationNTT));
NativeMethods.Evaluator_TransformToNTT(
NativePtr, encrypted.NativePtr, destinationNTT.NativePtr);
}
/// <summary>
/// Transforms a ciphertext back from NTT domain.
/// </summary>
/// <remarks>
/// Transforms a ciphertext back from NTT domain. This functions applies the inverse of
/// David Harvey's Number Theoretic Transform separately to each polynomial of a ciphertext.
/// </remarks>
/// <param name="encryptedNTT">The ciphertext to transform</param>
/// <exception cref="ArgumentNullException">if encryptedNTT is null</exception>
/// <exception cref="ArgumentException">if encryptedNTT is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encryptedNTT is not in NTT form</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void TransformFromNTTInplace(Ciphertext encryptedNTT)
{
TransformFromNTT(encryptedNTT, destination: encryptedNTT);
}
/// <summary>
/// Transforms a ciphertext back from NTT domain.
/// </summary>
/// <remarks>
/// Transforms a ciphertext back from NTT domain. This functions applies the inverse of
/// David Harvey's Number Theoretic Transform separately to each polynomial of a ciphertext.
/// The result is stored in the destination parameter.
/// </remarks>
/// <param name="encryptedNTT">The ciphertext to transform</param>
/// <param name="destination">The ciphertext to overwrite with the transformed result</param>
/// <exception cref="ArgumentNullException">if either encryptedNTT or destination are null</exception>
/// <exception cref="ArgumentException">if encryptedNTT is not valid for the encryption parameters</exception>
/// <exception cref="ArgumentException">if encryptedNTT is not in NTT form</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void TransformFromNTT(Ciphertext encryptedNTT, Ciphertext destination)
{
if (null == encryptedNTT)
throw new ArgumentNullException(nameof(encryptedNTT));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.Evaluator_TransformFromNTT(
NativePtr, encryptedNTT.NativePtr, destination.NativePtr);
}
/// <summary>
/// Applies a Galois automorphism to a ciphertext.
/// </summary>
/// <remarks>
/// <para>
/// Applies a Galois automorphism to a ciphertext. To evaluate the Galois automorphism,
/// an appropriate set of Galois keys must also be provided. Dynamic memory allocations
/// in the process are allocated from the memory pool pointed to by the given
/// MemoryPoolHandle.
/// </para>
/// <para>
/// The desired Galois automorphism is given as a Galois element, and must be an odd
/// integer in the interval [1, M-1], where M = 2*N, and N = PolyModulusDegree. Used
/// with batching, a Galois element 3^i % M corresponds to a cyclic row rotation i steps
/// to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation
/// i steps to the right. The Galois element M-1 corresponds to a column rotation (row
/// swap) in BFV, and complex conjugation in CKKS. In the polynomial view (not batching),
/// a Galois automorphism by a Galois element p changes Enc(plain(x)) to Enc(plain(x^p)).
/// </para>
/// </remarks>
/// <param name="encrypted">The ciphertext to apply the Galois automorphism to</param>
/// <param name="galoisElt">The Galois element</param>
/// <param name="galoisKeys">The Galois keys</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or galoisKeys are null</exception>
/// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if encrypted has size larger than 2</exception>
/// <exception cref="ArgumentException">if the Galois element is not valid</exception>
/// <exception cref="ArgumentException">if necessary Galois keys are not present</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void ApplyGaloisInplace(Ciphertext encrypted, uint galoisElt,
GaloisKeys galoisKeys, MemoryPoolHandle pool = null)
{
ApplyGalois(encrypted, galoisElt, galoisKeys, destination: encrypted, pool: pool);
}
/// <summary>
/// Applies a Galois automorphism to a ciphertext and writes the result to the
/// destination parameter.
/// </summary>
/// <remarks>
/// <para>
/// Applies a Galois automorphism to a ciphertext and writes the result to the
/// destination parameter. To evaluate the Galois automorphism, an appropriate set of
/// Galois keys must also be provided. Dynamic memory allocations in the process are
/// allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </para>
/// <para>
/// The desired Galois automorphism is given as a Galois element, and must be an odd
/// integer in the interval [1, M-1], where M = 2*N, and N = PolyModulusDegree. Used
/// with batching, a Galois element 3^i % M corresponds to a cyclic row rotation i steps
/// to the left, and a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation
/// i steps to the right. The Galois element M-1 corresponds to a column rotation (row
/// swap) in BFV, and complex conjugation in CKKS. In the polynomial view (not batching),
/// a Galois automorphism by a Galois element p changes Enc(plain(x)) to Enc(plain(x^p)).
/// </para>
/// </remarks>
/// <param name="encrypted">The ciphertext to apply the Galois automorphism to</param>
/// <param name="galoisElt">The Galois element</param>
/// <param name="galoisKeys">The Galois keys</param>
/// <param name="destination">The ciphertext to overwrite with the result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted, galoisKeys or destination are null</exception>
/// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if encrypted has size larger than 2</exception>
/// <exception cref="ArgumentException">if the Galois element is not valid</exception>
/// <exception cref="ArgumentException">if necessary Galois keys are not present</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void ApplyGalois(Ciphertext encrypted, uint galoisElt, GaloisKeys galoisKeys,
Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == galoisKeys)
throw new ArgumentNullException(nameof(galoisKeys));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
if (!ContextUsingKeyswitching)
throw new InvalidOperationException("Keyswitching is not supported by the context");
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_ApplyGalois(
NativePtr, encrypted.NativePtr, galoisElt,
galoisKeys.NativePtr, destination.NativePtr, poolPtr);
}
/// <summary>
/// Rotates plaintext matrix rows cyclically.
/// </summary>
/// <remarks>
/// When batching is used with the BFV scheme, this function rotates the encrypted plaintext
/// matrix rows cyclically to the left (steps &gt; 0) or to the right (steps &lt; 0). Since
/// the size of the batched matrix is 2-by-(N/2), where N is the degree of the polynomial
/// modulus, the number of steps to rotate must have absolute value at most N/2-1. Dynamic
/// memory allocations in the process are allocated from the memory pool pointed to by the
/// given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to rotate</param>
/// <param name="steps">The number of steps to rotate (negative left, positive right)</param>
/// <param name="galoisKeys">The Galois keys</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or galoisKeys are null</exception>
/// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception>
/// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if encrypted is not in the default NTT form</exception>
/// <exception cref="ArgumentException">if encrypted has size larger than 2</exception>
/// <exception cref="ArgumentException">if steps has too big absolute value</exception>
/// <exception cref="ArgumentException">if necessary Galois keys are not present</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RotateRowsInplace(Ciphertext encrypted,
int steps, GaloisKeys galoisKeys, MemoryPoolHandle pool = null)
{
RotateRows(encrypted, steps, galoisKeys, destination: encrypted, pool: pool);
}
/// <summary>
/// Rotates plaintext matrix rows cyclically.
/// </summary>
/// <remarks>
/// When batching is used with the BFV scheme, this function rotates the encrypted plaintext
/// matrix rows cyclically to the left (steps &gt; 0) or to the right (steps &lt; 0) and writes
/// the result to the destination parameter. Since the size of the batched matrix is 2-by-(N/2),
/// where N is the degree of the polynomial modulus, the number of steps to rotate must have
/// absolute value at most N/2-1. Dynamic memory allocations in the process are allocated from
/// the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to rotate</param>
/// <param name="steps">The number of steps to rotate (negative left, positive right)</param>
/// <param name="galoisKeys">The Galois keys</param>
/// <param name="destination">The ciphertext to overwrite with the rotated result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted, galoisKeys or destination are null</exception>
/// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception>
/// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if encrypted is in NTT form</exception>
/// <exception cref="ArgumentException">if encrypted has size larger than 2</exception>
/// <exception cref="ArgumentException">if steps has too big absolute value</exception>
/// <exception cref="ArgumentException">if necessary Galois keys are not present</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RotateRows(Ciphertext encrypted, int steps, GaloisKeys galoisKeys,
Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == galoisKeys)
throw new ArgumentNullException(nameof(galoisKeys));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
if (!ContextUsingKeyswitching)
throw new InvalidOperationException("Keyswitching is not supported by the context");
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_RotateRows(
NativePtr, encrypted.NativePtr, steps, galoisKeys.NativePtr,
destination.NativePtr, poolPtr);
}
/// <summary>
/// Rotates plaintext matrix columns cyclically.
/// </summary>
/// <remarks>
/// When batching is used with the BFV scheme, this function rotates the encrypted
/// plaintext matrix columns cyclically. Since the size of the batched matrix is 2-by-(N/2),
/// where N is the degree of the polynomial modulus, this means simply swapping the two
/// rows. Dynamic memory allocations in the process are allocated from the memory pool
/// pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to rotate</param>
/// <param name="galoisKeys">The Galois keys</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or galoisKeys are null</exception>
/// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception>
/// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if encrypted is in NTT form</exception>
/// <exception cref="ArgumentException">if encrypted has size larger than 2</exception>
/// <exception cref="ArgumentException">if necessary Galois keys are not present</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RotateColumnsInplace(Ciphertext encrypted, GaloisKeys galoisKeys, MemoryPoolHandle pool = null)
{
RotateColumns(encrypted, galoisKeys, destination: encrypted, pool: pool);
}
/// <summary>
/// Rotates plaintext matrix columns cyclically.
/// </summary>
/// <remarks>
/// When batching is used with the BFV scheme, this function rotates the encrypted plaintext
/// matrix columns cyclically, and writes the result to the destination parameter. Since the
/// size of the batched matrix is 2-by-(N/2), where N is the degree of the polynomial modulus,
/// this means simply swapping the two rows. Dynamic memory allocations in the process are
/// allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to rotate</param>
/// <param name="galoisKeys">The Galois keys</param>
/// <param name="destination">The ciphertext to overwrite with the rotated result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted, galoisKeys or destination are null</exception>
/// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.BFV</exception>
/// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if encrypted is in NTT form</exception>
/// <exception cref="ArgumentException">if encrypted has size larger than 2</exception>
/// <exception cref="ArgumentException">if necessary Galois keys are not present</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RotateColumns(Ciphertext encrypted, GaloisKeys galoisKeys,
Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == galoisKeys)
throw new ArgumentNullException(nameof(galoisKeys));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
if (!ContextUsingKeyswitching)
throw new InvalidOperationException("Keyswitching is not supported by the context");
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_RotateColumns(
NativePtr, encrypted.NativePtr, galoisKeys.NativePtr,
destination.NativePtr, poolPtr);
}
/// <summary>
/// Rotates plaintext vector cyclically.
/// </summary>
/// <remarks>
/// When using the CKKS scheme, this function rotates the encrypted plaintext vector
/// cyclically to the left (steps &gt; 0) or to the right (steps &lt; 0). Since the size
/// of the batched matrix is 2-by-(N/2), where N is the degree of the polynomial modulus,
/// the number of steps to rotate must have absolute value at most N/2-1. Dynamic memory
/// allocations in the process are allocated from the memory pool pointed to by the given
/// MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to rotate</param>
/// <param name="steps">The number of steps to rotate (negative left, positive right)</param>
/// <param name="galoisKeys">The Galois keys</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or galoisKeys are null</exception>
/// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.CKKS</exception>
/// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if encrypted is in NTT form</exception>
/// <exception cref="ArgumentException">if encrypted has size larger than 2</exception>
/// <exception cref="ArgumentException">if steps has too big absolute value</exception>
/// <exception cref="ArgumentException">if necessary Galois keys are not present</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RotateVectorInplace(Ciphertext encrypted, int steps,
GaloisKeys galoisKeys, MemoryPoolHandle pool = null)
{
RotateVector(encrypted, steps, galoisKeys, destination: encrypted, pool: pool);
}
/// <summary>
/// Rotates plaintext vector cyclically.
/// </summary>
/// <remarks>
/// When using the CKKS scheme, this function rotates the encrypted plaintext vector
/// cyclically to the left (steps &gt; 0) or to the right (steps &lt; 0) and writes
/// the result to the destination parameter. Since the size of the batched matrix is
/// 2-by-(N/2), where N is the degree of the polynomial modulus, the number of steps
/// to rotate must have absolute value at most N/2-1. Dynamic memory allocations in the
/// process are allocated from the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to rotate</param>
/// <param name="steps">The number of steps to rotate (negative left, positive right)</param>
/// <param name="galoisKeys">The Galois keys</param>
/// <param name="destination">The ciphertext to overwrite with the rotated result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted, galoisKeys or destination are null</exception>
/// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.CKKS</exception>
/// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if encrypted is in NTT form</exception>
/// <exception cref="ArgumentException">if encrypted has size larger than 2</exception>
/// <exception cref="ArgumentException">if steps has too big absolute value</exception>
/// <exception cref="ArgumentException">if necessary Galois keys are not present</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void RotateVector(Ciphertext encrypted, int steps, GaloisKeys galoisKeys,
Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == galoisKeys)
throw new ArgumentNullException(nameof(galoisKeys));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
if (!ContextUsingKeyswitching)
throw new InvalidOperationException("Keyswitching is not supported by the context");
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_RotateVector(
NativePtr, encrypted.NativePtr, steps, galoisKeys.NativePtr,
destination.NativePtr, poolPtr);
}
/// <summary>
/// Complex conjugates plaintext slot values.
/// </summary>
/// <remarks>
/// When using the CKKS scheme, this function complex conjugates all values in the
/// underlying plaintext. Dynamic memory allocations in the process are allocated from
/// the memory pool pointed to by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to rotate</param>
/// <param name="galoisKeys">The Galois keys</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="ArgumentNullException">if either encrypted or galoisKeys are null</exception>
/// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.CKKS</exception>
/// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if encrypted is in NTT form</exception>
/// <exception cref="ArgumentException">if encrypted has size larger than 2</exception>
/// <exception cref="ArgumentException">if necessary Galois keys are not present</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void ComplexConjugateInplace(Ciphertext encrypted, GaloisKeys galoisKeys, MemoryPoolHandle pool = null)
{
ComplexConjugate(encrypted, galoisKeys, destination: encrypted, pool: pool);
}
/// <summary>
/// Complex conjugates plaintext slot values.
/// </summary>
/// <remarks>
/// When using the CKKS scheme, this function complex conjugates all values in the
/// underlying plaintext, and writes the result to the destination parameter. Dynamic
/// memory allocations in the process are allocated from the memory pool pointed to
/// by the given MemoryPoolHandle.
/// </remarks>
/// <param name="encrypted">The ciphertext to rotate</param>
/// <param name="galoisKeys">The Galois keys</param>
/// <param name="destination">The ciphertext to overwrite with the rotated result</param>
/// <param name="pool">The MemoryPoolHandle pointing to a valid memory pool</param>
/// <exception cref="InvalidOperationException">if the encryption parameters do not support batching</exception>
/// <exception cref="InvalidOperationException">if scheme is not SchemeType.CKKS</exception>
/// <exception cref="ArgumentException">if encrypted or galoisKeys is not valid for the
/// encryption parameters</exception>
/// <exception cref="ArgumentException">if galoisKeys do not correspond to the top level
/// parameters in the current context</exception>
/// <exception cref="ArgumentException">if encrypted is in NTT form</exception>
/// <exception cref="ArgumentException">if encrypted has size larger than 2</exception>
/// <exception cref="ArgumentException">if necessary Galois keys are not present</exception>
/// <exception cref="ArgumentException">if pool is uninitialized</exception>
/// <exception cref="InvalidOperationException">if keyswitching is not supported by the context</exception>
/// <exception cref="InvalidOperationException">if result ciphertext is transparent</exception>
public void ComplexConjugate(Ciphertext encrypted, GaloisKeys galoisKeys,
Ciphertext destination, MemoryPoolHandle pool = null)
{
if (null == encrypted)
throw new ArgumentNullException(nameof(encrypted));
if (null == galoisKeys)
throw new ArgumentNullException(nameof(galoisKeys));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
if (!ContextUsingKeyswitching)
throw new InvalidOperationException("Keyswitching is not supported by the context");
IntPtr poolPtr = pool?.NativePtr ?? IntPtr.Zero;
NativeMethods.Evaluator_ComplexConjugate(
NativePtr, encrypted.NativePtr, galoisKeys.NativePtr,
destination.NativePtr, poolPtr);
}
/// <summary>
/// Destroy native object.
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.Evaluator_Destroy(NativePtr);
}
internal bool ContextUsingKeyswitching
{
get
{
NativeMethods.Evaluator_ContextUsingKeyswitching(NativePtr, out bool result);
return result;
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Class to store Galois keys.
/// </summary>
/// <remarks>
/// <para>
/// Slot rotations
/// Galois keys are certain types of public keys that are needed to perform encrypted
/// vector rotation operations on batched ciphertexts. Batched ciphertexts encrypt
/// a 2-by-(N/2) matrix of modular integers in the BFV scheme, or an N/2-dimensional
/// vector of complex numbers in the CKKS scheme, where N denotes the degree of the
/// polynomial modulus. In the BFV scheme Galois keys can enable both cyclic rotations
/// of the encrypted matrix rows, as well as row swaps (column rotations). In the CKKS
/// scheme Galois keys can enable cyclic vector rotations, as well as a complex
/// conjugation operation.
/// </para>
/// <para>
/// Thread Safety
/// In general, reading from GaloisKeys is thread-safe as long as no other thread is
/// concurrently mutating it. This is due to the underlying data structure storing
/// the Galois keys not being thread-safe.
/// </para>
/// </remarks>
public class GaloisKeys :
KSwitchKeys,
ISettable<GaloisKeys>
{
/// <summary>
/// Creates an empty set of Galois keys.
/// </summary>
public GaloisKeys() : base()
{
}
/// <summary>
/// Creates a new GaloisKeys instance by copying a given instance.
/// </summary>
/// <param name="copy">The GaloisKeys to copy from</param>
/// <exception cref="ArgumentNullException">if copy is null</exception>
public GaloisKeys(GaloisKeys copy)
: base(copy)
{
}
/// <summary>
/// Creates a new GaloisKeys instance initialized with a pointer to a native
/// KSwitchKeys object.
/// </summary>
/// <param name="kswitchKeys">Pointer to native KSwitchKeys object</param>
/// <param name="owned">Whether this instance owns the native pointer</param>
internal GaloisKeys(IntPtr kswitchKeys, bool owned = true)
: base(kswitchKeys, owned)
{
}
/// <summary>
/// Copies a given GaloisKeys instance to the current one.
/// </summary>
///
/// <param name="assign">The GaloisKeys to copy from</param>
/// <exception cref="ArgumentNullException">if assign is null</exception>
public void Set(GaloisKeys assign)
{
base.Set(assign);
}
/// <summary>
/// Returns the index of a Galois key in the backing KSwitchKeys instance that
/// corresponds to the given Galois element, assuming that it exists in the
/// backing KSwitchKeys.
/// </summary>
/// <param name="galoisElt">The Galois element</param>
/// <exception cref="ArgumentException">if Galois element is not valid</exception>
public static ulong GetIndex(uint galoisElt)
{
NativeMethods.GaloisKeys_GetIndex(galoisElt, out ulong index);
return index;
}
/// <summary>
/// Returns whether a Galois key corresponding to a given Galois key element
/// exists.
/// </summary>
/// <param name="galoisElt">The Galois element</param>
/// <exception cref="ArgumentException">if Galois element is not valid</exception>
public bool HasKey(uint galoisElt)
{
ulong index = GetIndex(galoisElt);
return (ulong)Data.LongCount() > index &&
Data.ElementAt(checked((int)index)).Count() != 0;
}
/// <summary>
/// Returns a specified Galois key.
/// </summary>
/// <remarks>
/// Returns a specified Galois key. The returned Galois key corresponds to the
/// given Galois element and is valid only as long as the GaloisKeys is valid.
/// </remarks>
/// <param name="galoisElt">The Galois element</param>
/// <exception cref="ArgumentException">if the key corresponding to galoisElt
/// does not exist</exception>
public IEnumerable<PublicKey> Key(uint galoisElt)
{
return Data.ElementAt(checked((int)GetIndex(galoisElt)));
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Encodes integers into plaintext polynomials that Encryptor can encrypt. An instance of
/// the IntegerEncoder class converts an integer into a plaintext polynomial by placing its
/// binary digits as the coefficients of the polynomial. Decoding the integer amounts to
/// evaluating the plaintext polynomial at x=2.
///
/// Addition and multiplication on the integer side translate into addition and multiplication
/// on the encoded plaintext polynomial side, provided that the length of the polynomial
/// never grows to be of the size of the polynomial modulus (PolyModulus), and that the
/// coefficients of the plaintext polynomials appearing throughout the computations never
/// experience coefficients larger than the plaintext modulus (PlainModulus).
/// </summary>
/// <remarks>
/// <para>
/// Negative Integers
/// Negative integers are represented by using -1 instead of 1 in the binary representation,
/// and the negative coefficients are stored in the plaintext polynomials as unsigned integers
/// that represent them modulo the plaintext modulus. Thus, for example, a coefficient of -1
/// would be stored as a polynomial coefficient PlainModulus-1.
/// </para>
/// </remarks>
public class IntegerEncoder : NativeObject
{
/// <summary>
/// Creates a IntegerEncoder object. The constructor takes as input a pointer to
/// a SEALContext object which contains the plaintext modulus.
/// </summary>
/// <param name="context">The SEALContext</param>
/// <exception cref="ArgumentNullException">if context is null</exception>
/// <exception cref="ArgumentException">if the context is not set</exception>
/// <exception cref="ArgumentException">if the PlainModulus set in context is not
/// at least 2</exception>
public IntegerEncoder(SEALContext context)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (!context.ParametersSet)
throw new ArgumentException("Encryption parameters are not set correctly");
SEALContext.ContextData contextData = context.FirstContextData;
if (contextData.Parms.Scheme != SchemeType.BFV)
throw new ArgumentException("Unsupported scheme");
NativeMethods.IntegerEncoder_Create(context.NativePtr, out IntPtr encoderPtr);
NativePtr = encoderPtr;
}
/// <summary>
/// Encodes an unsigned integer (represented by ulong) into a plaintext polynomial.
/// </summary>
/// <param name="value">The unsigned integer to encode</param>
public Plaintext Encode(ulong value)
{
Plaintext plain = new Plaintext();
NativeMethods.IntegerEncoder_Encode(NativePtr, value, plain.NativePtr);
return plain;
}
/// <summary>
/// Encodes an unsigned integer(represented by ulong) into a plaintext polynomial.
/// </summary>
/// <param name="value">The unsigned integer to encode</param>
/// <param name="destination">The plaintext to overwrite with the encoding</param>
/// <exception cref="ArgumentNullException">if destination is null</exception>
public void Encode(ulong value, Plaintext destination)
{
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.IntegerEncoder_Encode(NativePtr, value, destination.NativePtr);
}
/// <summary>
/// Decodes a plaintext polynomial and returns the result as uint. Mathematically
/// this amounts to evaluating the input polynomial at X = 2.
/// </summary>
/// <param name="plain">The plaintext to be decoded</param>
/// <exception cref="ArgumentNullException">if plain is null</exception>
/// <exception cref="ArgumentException">if plain does not represent a valid plaintext polynomial</exception>
/// <exception cref="ArgumentException">if the output does not fit in uint</exception>
public uint DecodeUInt32(Plaintext plain)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
NativeMethods.IntegerEncoder_DecodeUInt32(NativePtr, plain.NativePtr, out uint result);
return result;
}
/// <summary>
/// Decodes a plaintext polynomial and returns the result as ulong. Mathematically
/// this amounts to evaluating the input polynomial at X=2.
/// </summary>
/// <param name="plain">The plaintext to be decoded</param>
/// <exception cref="ArgumentNullException">if plain is null</exception>
/// <exception cref="ArgumentException">if plain does not represent a valid plaintext polynomial</exception>
/// <exception cref="ArgumentException">if the output does not fit in ulong</exception>
public ulong DecodeUInt64(Plaintext plain)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
NativeMethods.IntegerEncoder_DecodeUInt64(NativePtr, plain.NativePtr, out ulong result);
return result;
}
/// <summary>
/// Encodes a signed integer (represented by long) into a plaintext polynomial.
/// </summary>
/// <remarks>
/// <para>
/// Negative Integers
/// Negative integers are represented by using -1 instead of 1 in the binary representation,
/// and the negative coefficients are stored in the plaintext polynomials as unsigned integers
/// that represent them modulo the plaintext modulus. Thus, for example, a coefficient of -1
/// would be stored as a polynomial coefficient PlainModulus-1.
/// </para>
/// </remarks>
/// <param name="value">The signed integer to encode</param>
public Plaintext Encode(long value)
{
Plaintext plain = new Plaintext();
NativeMethods.IntegerEncoder_Encode(NativePtr, value, plain.NativePtr);
return plain;
}
/// <summary>
/// Encodes a signed integer(represented by long) into a plaintext polynomial.
/// </summary>
/// <remarks>
/// <para>
/// Negative Integers
/// Negative integers are represented by using -1 instead of 1 in the binary representation,
/// and the negative coefficients are stored in the plaintext polynomials as unsigned integers
/// that represent them modulo the plaintext modulus. Thus, for example, a coefficient of -1
/// would be stored as a polynomial coefficient PlainModulus-1.
/// </para>
/// </remarks>
/// <param name="value">The signed integer to encode</param>
/// <param name="destination">The plaintext to overwrite with the encoding</param>
public void Encode(long value, Plaintext destination)
{
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.IntegerEncoder_Encode(NativePtr, value, destination.NativePtr);
}
/// <summary>
/// Encodes an unsigned integer(represented by BigUInt) into a plaintext polynomial.
/// </summary>
/// <param name="value">The unsigned integer to encode</param>
/// <exception cref="ArgumentNullException">if value is null</exception>
public Plaintext Encode(BigUInt value)
{
if (null == value)
throw new ArgumentNullException(nameof(value));
Plaintext plain = new Plaintext();
NativeMethods.IntegerEncoder_Encode(NativePtr, value.NativePtr, plain.NativePtr);
return plain;
}
/// <summary>
/// Encodes an unsigned integer(represented by BigUInt) into a plaintext polynomial.
/// </summary>
/// <param name="value">The unsigned integer to encode</param>
/// <param name="destination">The plaintext to overwrite with the encoding</param>
/// <exception cref="ArgumentNullException">if either value or destination are null</exception>
public void Encode(BigUInt value, Plaintext destination)
{
if (null == value)
throw new ArgumentNullException(nameof(value));
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.IntegerEncoder_Encode(NativePtr, value.NativePtr, destination.NativePtr);
}
/// <summary>
/// Decodes a plaintext polynomial and returns the result as int. Mathematically
/// this amounts to evaluating the input polynomial at X = 2.
/// </summary>
/// <param name="plain">The plaintext to be decoded</param>
/// <exception cref="ArgumentNullException">if plain is null</exception>
/// <exception cref="ArgumentException">if plain does not represent a valid plaintext polynomial</exception>
/// <exception cref="ArgumentException">if the output does not fit in int</exception>
public int DecodeInt32(Plaintext plain)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
NativeMethods.IntegerEncoder_DecodeInt32(NativePtr, plain.NativePtr, out int result);
return result;
}
/// <summary>
/// Decodes a plaintext polynomial and returns the result as long. Mathematically
/// this amounts to evaluating the input polynomial at X = 2.
/// </summary>
/// <param name="plain">The plaintext to be decoded</param>
/// <exception cref="ArgumentNullException">if plain is null</exception>
/// <exception cref="ArgumentException">if plain does not represent a valid plaintext polynomial</exception>
/// <exception cref="ArgumentException">if the output does not fit in long</exception>
public long DecodeInt64(Plaintext plain)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
NativeMethods.IntegerEncoder_DecodeInt64(NativePtr, plain.NativePtr, out long result);
return result;
}
/// <summary>
/// Decodes a plaintext polynomial and returns the result as BigUInt.
/// Mathematically this amounts to evaluating the input polynomial at X = 2.
/// </summary>
/// <param name="plain">The plaintext to be decoded</param>
/// <exception cref="ArgumentNullException">if plain is null</exception>
/// <exception cref="ArgumentException">if plain does not represent a valid plaintext polynomial</exception>
/// <exception cref="ArgumentException">if the output is negative</exception>
public BigUInt DecodeBigUInt(Plaintext plain)
{
if (null == plain)
throw new ArgumentNullException(nameof(plain));
NativeMethods.IntegerEncoder_DecodeBigUInt(NativePtr, plain.NativePtr, out IntPtr buiPtr);
BigUInt bui = new BigUInt(buiPtr);
return bui;
}
/// <summary>
/// Encodes a signed integer(represented by int) into a plaintext polynomial.
/// </summary>
/// <remarks>
/// <para>
/// Negative Integers
/// Negative integers are represented by using -1 instead of 1 in the binary representation,
/// and the negative coefficients are stored in the plaintext polynomials as unsigned integers
/// that represent them modulo the plaintext modulus. Thus, for example, a coefficient of -1
/// would be stored as a polynomial coefficient PlainModulus-1.
/// </para>
/// </remarks>
/// <param name="value">The signed integer to encode</param>
public Plaintext Encode(int value)
{
Plaintext plain = new Plaintext();
NativeMethods.IntegerEncoder_Encode(NativePtr, value, plain.NativePtr);
return plain;
}
/// <summary>
/// Encodes an unsigned integer(represented by uint) into a plaintext polynomial.
/// </summary>
/// <param name="value">The unsigned integer to encode</param>
public Plaintext Encode(uint value)
{
Plaintext plain = new Plaintext();
NativeMethods.IntegerEncoder_Encode(NativePtr, value, plain.NativePtr);
return plain;
}
/// <summary>
/// Encodes a signed integer(represented by int) into a plaintext polynomial.
/// </summary>
/// <remarks>
/// <para>
/// Negative Integers
/// Negative integers are represented by using -1 instead of 1 in the binary representation,
/// and the negative coefficients are stored in the plaintext polynomials as unsigned integers
/// that represent them modulo the plaintext modulus. Thus, for example, a coefficient of -1
/// would be stored as a polynomial coefficient PlainModulus-1.
/// </para>
/// </remarks>
/// <param name="value">The signed integer to encode</param>
/// <param name="destination">The plaintext to overwrite with the encoding</param>
/// <exception cref="ArgumentNullException">if destination is null</exception>
public void Encode(int value, Plaintext destination)
{
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.IntegerEncoder_Encode(NativePtr, value, destination.NativePtr);
}
/// <summary>
/// Encodes an unsigned integer(represented by uint) into a plaintext polynomial.
/// </summary>
/// <param name="value">The unsigned integer to encode</param>
/// <param name="destination">The plaintext to overwrite with the encoding</param>
/// <exception cref="ArgumentNullException">if destination is null</exception>
public void Encode(uint value, Plaintext destination)
{
if (null == destination)
throw new ArgumentNullException(nameof(destination));
NativeMethods.IntegerEncoder_Encode(NativePtr, value, destination.NativePtr);
}
/// <summary>
/// Get a copy of the plaintext modulus.
/// </summary>
public Modulus PlainModulus
{
get
{
NativeMethods.IntegerEncoder_PlainModulus(NativePtr, out IntPtr sm);
Modulus result = new Modulus(sm);
return result;
}
}
/// <summary>
/// Destroy the native object
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.IntegerEncoder_Destroy(NativePtr);
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Class to store keyswitching keys.
/// </summary>
///
/// <remarks>
/// <para>
/// Class to store keyswitching keys. It should never be necessary for normal
/// users to create an instance of KSwitchKeys. This class is used strictly as
/// a base class for RelinKeys and GaloisKeys classes.
/// </para>
/// <para>
/// Concretely, keyswitching is used to change a ciphertext encrypted with one
/// key to be encrypted with another key.It is a general technique and is used
/// in relinearization and Galois rotations. A keyswitching key contains a sequence
/// (vector) of keys.In RelinKeys, each key is an encryption of a power of the
/// secret key.In GaloisKeys, each key corresponds to a type of rotation.
/// </para>
/// <para>
/// In general, reading from KSwitchKeys is thread-safe as long as no
/// other thread is concurrently mutating it.This is due to the underlying
/// data structure storing the keyswitching keys not being thread-safe.
/// </para>
/// </remarks>
public class KSwitchKeys :
NativeObject,
ISerializableObject,
ISettable<KSwitchKeys>
{
/// <summary>
/// Creates an empty KSwitchKeys.
/// </summary>
public KSwitchKeys()
{
NativeMethods.KSwitchKeys_Create(out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Creates a new KSwitchKeys instance by copying a given instance.
/// </summary>
/// <param name="copy">The KSwitchKeys to copy from</param>
/// <exception cref="ArgumentNullException">if copy is null</exception>
public KSwitchKeys(KSwitchKeys copy)
{
if (null == copy)
throw new ArgumentNullException(nameof(copy));
NativeMethods.KSwitchKeys_Create(copy.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Creates a new KSwitchKeys instance initialized with a pointer to a native
/// KSwitchKeys object.
/// </summary>
/// <param name="kswitchKeys">Pointer to native KSwitchKeys object</param>
/// <param name="owned">Whether this instance owns the native pointer</param>
internal KSwitchKeys(IntPtr kswitchKeys, bool owned = true)
: base(kswitchKeys, owned)
{
}
/// <summary>
/// Copies a given KSwitchKeys instance to the current one.
/// </summary>
///
/// <param name="assign">The KSwitchKeys to copy from</param>
/// <exception cref="ArgumentNullException">if assign is null</exception>
public void Set(KSwitchKeys assign)
{
if (null == assign)
throw new ArgumentNullException(nameof(assign));
NativeMethods.KSwitchKeys_Set(NativePtr, assign.NativePtr);
}
/// <summary>
/// Returns the current number of keyswitching keys. Only keys that are non-empty
/// are counted.
/// </summary>
public ulong Size
{
get
{
NativeMethods.KSwitchKeys_Size(NativePtr, out ulong size);
return size;
}
}
/// <summary>
/// Returns the KSwitchKeys data.
/// </summary>
/// <remarks>
/// Returns the KSwitchKeys data. The returned object is valid only as long as
/// the KSwitchKeys is valid and not changed.
/// </remarks>
public IEnumerable<IEnumerable<PublicKey>> Data
{
get
{
List<List<PublicKey>> result = new List<List<PublicKey>>();
NativeMethods.KSwitchKeys_RawSize(NativePtr, out ulong size);
for (ulong i = 0; i < size; i++)
{
ulong count = 0;
NativeMethods.KSwitchKeys_GetKeyList(NativePtr, i, ref count, null);
IntPtr[] pointers = new IntPtr[count];
NativeMethods.KSwitchKeys_GetKeyList(NativePtr, i, ref count, pointers);
List<PublicKey> key = new List<PublicKey>(checked((int)count));
foreach (IntPtr ptr in pointers)
{
key.Add(new PublicKey(ptr, owned: false));
}
result.Add(key);
}
return result;
}
}
/// <summary>
/// Returns a copy of ParmsId.
/// </summary>
public ParmsId ParmsId
{
get
{
ParmsId parms = new ParmsId();
NativeMethods.KSwitchKeys_GetParmsId(NativePtr, parms.Block);
return parms;
}
private set
{
NativeMethods.KSwitchKeys_SetParmsId(NativePtr, value.Block);
}
}
/// <summary>
/// Returns an upper bound on the size of the KSwitchKeys, as if it was written
/// to an output stream.
/// </summary>
/// <param name="comprMode">The compression mode</param>
/// <exception cref="ArgumentException">if the compression mode is not
/// supported</exception>
/// <exception cref="InvalidOperationException">if the size does not fit in
/// the return type</exception>
public long SaveSize(ComprModeType? comprMode = null)
{
comprMode = comprMode ?? Serialization.ComprModeDefault;
if (!Serialization.IsSupportedComprMode(comprMode.Value))
throw new ArgumentException("Unsupported compression mode");
ComprModeType comprModeValue = comprMode.Value;
NativeMethods.KSwitchKeys_SaveSize(
NativePtr, (byte)comprModeValue, out long outBytes);
return outBytes;
}
/// <summary>Saves the KSwitchKeys to an output stream.</summary>
/// <remarks>
/// Saves the KSwitchKeys to an output stream. The output is in binary format
/// and not human-readable.
/// </remarks>
/// <param name="stream">The stream to save the KSwitchKeys to</param>
/// <param name="comprMode">The desired compression mode</param>
/// <exception cref="ArgumentNullException">if stream is null</exception>
/// <exception cref="ArgumentException">if the stream is closed or does not
/// support writing, or if compression mode is not supported</exception>
/// <exception cref="IOException">if I/O operations failed</exception>
/// <exception cref="InvalidOperationException">if the data to be saved
/// is invalid, or if compression failed</exception>
public long Save(Stream stream, ComprModeType? comprMode = null)
{
comprMode = comprMode ?? Serialization.ComprModeDefault;
if (!Serialization.IsSupportedComprMode(comprMode.Value))
throw new ArgumentException("Unsupported compression mode");
ComprModeType comprModeValue = comprMode.Value;
return Serialization.Save(
(byte[] outptr, ulong size, byte cm, out long outBytes) =>
NativeMethods.KSwitchKeys_Save(NativePtr, outptr, size,
cm, out outBytes),
SaveSize(comprModeValue), comprModeValue, stream);
}
/// <summary>Loads a KSwitchKeys from an input stream overwriting the current
/// KSwitchKeys.</summary>
/// <remarks>
/// Loads a KSwitchKeys from an input stream overwriting the current
/// KSwitchKeys. No checking of the validity of the KSwitchKeys data against
/// encryption parameters is performed. This function should not be used
/// unless the KSwitchKeys comes from a fully trusted source.
/// </remarks>
/// <param name="context">The SEALContext</param>
/// <param name="stream">The stream to load the KSwitchKeys from</param>
/// <exception cref="ArgumentNullException">if context or stream is
/// null</exception>
/// <exception cref="ArgumentException">if the stream is closed or does not
/// support reading</exception>
/// <exception cref="ArgumentException">if context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="EndOfStreamException">if the stream ended
/// unexpectedly</exception>
/// <exception cref="IOException">if I/O operations failed</exception>
/// <exception cref="InvalidOperationException">if the data cannot be loaded
/// by this version of Microsoft SEAL, if the loaded data is invalid, or if the
/// loaded compression mode is not supported</exception>
public long UnsafeLoad(SEALContext context, Stream stream)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
return Serialization.Load(
(byte[] outptr, ulong size, out long outBytes) =>
NativeMethods.KSwitchKeys_UnsafeLoad(NativePtr, context.NativePtr,
outptr, size, out outBytes),
stream);
}
/// <summary>Loads a KSwitchKeys from an input stream overwriting the current
/// KSwitchKeys.</summary>
/// <remarks>
/// Loads a KSwitchKeys from an input stream overwriting the current
/// KSwitchKeys. The loaded KSwitchKeys is verified to be valid for the given
/// SEALContext.
/// </remarks>
/// <param name="context">The SEALContext</param>
/// <param name="stream">The stream to load the KSwitchKeys from</param>
/// <exception cref="ArgumentNullException">if context or stream is
/// null</exception>
/// <exception cref="ArgumentException">if the stream is closed or does not
/// support reading</exception>
/// <exception cref="ArgumentException">if context is not set or encryption
/// parameters are not valid</exception>
/// <exception cref="EndOfStreamException">if the stream ended
/// unexpectedly</exception>
/// <exception cref="IOException">if I/O operations failed</exception>
/// <exception cref="InvalidOperationException">if the data cannot be loaded
/// by this version of Microsoft SEAL, if the loaded data is invalid, or if the
/// loaded compression mode is not supported</exception>
public long Load(SEALContext context, Stream stream)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
return Serialization.Load(
(byte[] outptr, ulong size, out long outBytes) =>
NativeMethods.KSwitchKeys_Load(NativePtr, context.NativePtr,
outptr, size, out outBytes),
stream);
}
/// <summary>
/// Returns the currently used MemoryPoolHandle.
/// </summary>
public MemoryPoolHandle Pool
{
get
{
NativeMethods.KSwitchKeys_Pool(NativePtr, out IntPtr pool);
MemoryPoolHandle handle = new MemoryPoolHandle(pool);
return handle;
}
}
/// <summary>
/// Destroy native object.
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.KSwitchKeys_Destroy(NativePtr);
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Generates matching secret key and public key.
/// </summary>
/// <remarks>
/// Generates matching secret key and public key. An existing KeyGenerator can
/// also at any time be used to generate relinearization keys and Galois keys.
/// Constructing a KeyGenerator requires only a SEALContext.
/// </remarks>
public class KeyGenerator : NativeObject
{
/// <summary>
/// Creates a KeyGenerator initialized with the specified SEALContext.
/// </summary>
/// <remarks>
/// Creates a KeyGenerator initialized with the specified <see cref="SEALContext" />.
/// Dynamically allocated member variables are allocated from the global memory pool.
/// </remarks>
/// <param name="context">The SEALContext</param>
/// <exception cref="ArgumentException">if encryption parameters are not
/// valid</exception>
/// <exception cref="ArgumentNullException">if context is null</exception>
public KeyGenerator(SEALContext context)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (!context.ParametersSet)
throw new ArgumentException("Encryption parameters are not set correctly");
NativeMethods.KeyGenerator_Create(context.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Creates an KeyGenerator instance initialized with the specified
/// SEALContext and specified previously secret key.
/// </summary>
/// <remarks>
/// Creates an KeyGenerator instance initialized with the specified
/// SEALContext and specified previously secret key. This can e.g. be used
/// to increase the number of relinearization keys from what had earlier
/// been generated, or to generate Galois keys in case they had not been
/// generated earlier.
/// </remarks>
/// <param name="context">The SEALContext</param>
/// <param name="secretKey">A previously generated secret key</param>
/// <exception cref="ArgumentNullException">if either context or secretKey
/// are null</exception>
/// <exception cref="ArgumentException">if encryption parameters are not
/// valid</exception>
/// <exception cref="ArgumentException">if secretKey or publicKey is not
/// valid for encryption parameters</exception>
public KeyGenerator(SEALContext context, SecretKey secretKey)
{
if (null == context)
throw new ArgumentNullException(nameof(context));
if (null == secretKey)
throw new ArgumentNullException(nameof(secretKey));
if (!context.ParametersSet)
throw new ArgumentException("Encryption parameters are not set correctly");
if (!ValCheck.IsValidFor(secretKey, context))
throw new ArgumentException("Secret key is not valid for encryption parameters");
NativeMethods.KeyGenerator_Create(context.NativePtr,
secretKey.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
/// <summary>
/// Generates and returns a public key. Every time this function is called,
/// a new public key will be generated.
/// </summary>
public PublicKey PublicKey
{
get
{
NativeMethods.KeyGenerator_PublicKey(NativePtr, out IntPtr pubKeyPtr);
PublicKey pubKey = new PublicKey(pubKeyPtr);
return pubKey;
}
}
/// <summary>
/// Returns a copy of the secret key.
/// </summary>
public SecretKey SecretKey
{
get
{
NativeMethods.KeyGenerator_SecretKey(NativePtr, out IntPtr secretKeyPtr);
SecretKey secretKey = new SecretKey(secretKeyPtr);
return secretKey;
}
}
/// <summary>
/// Generates and returns relinearization keys.
/// </summary>
/// <remarks>
/// Generates and returns relinearization keys. This function returns
/// relinearization keys in a fully expanded form and is meant to be used
/// primarily for demo, testing, and debugging purposes.
/// </remarks>
/// <exception cref="InvalidOperationException">if the encryption
/// parameters do not support keyswitching</exception>
public RelinKeys RelinKeysLocal()
{
if (!UsingKeyswitching())
throw new InvalidOperationException("Encryption parameters do not support keyswitching");
NativeMethods.KeyGenerator_RelinKeys(NativePtr, false, out IntPtr relinKeysPtr);
return new RelinKeys(relinKeysPtr);
}
/// <summary>
/// Generates and returns relinearization keys as a serializable object.
/// </summary>
/// <remarks>
/// <para>
/// Generates and returns relinearization keys as a serializable object.
/// </para>
/// <para>
/// Half of the key data is pseudo-randomly generated from a seed to reduce
/// the object size. The resulting serializable object cannot be used
/// directly and is meant to be serialized for the size reduction to have an
/// impact.
/// </para>
/// </remarks>
/// <exception cref="InvalidOperationException">if the encryption
/// parameters do not support keyswitching</exception>
public Serializable<RelinKeys> RelinKeys()
{
if (!UsingKeyswitching())
throw new InvalidOperationException("Encryption parameters do not support keyswitching");
NativeMethods.KeyGenerator_RelinKeys(NativePtr, true, out IntPtr relinKeysPtr);
RelinKeys relinKeys = new RelinKeys(relinKeysPtr);
return new Serializable<RelinKeys>(relinKeys);
}
/// <summary>
/// Generates and returns Galois keys.
/// </summary>
/// <remarks>
/// <para>
/// Generates and returns Galois keys. This function returns Galois keys in
/// a fully expanded form and is meant to be used primarily for demo, testing,
/// and debugging purposes. This function creates specific Galois keys that
/// can be used to apply specific Galois automorphisms on encrypted data. The
/// user needs to give as input a vector of Galois elements corresponding to
/// the keys that are to be created.
/// </para>
/// <para>
/// The Galois elements are odd integers in the interval [1, M-1], where
/// M = 2*N, and N = PolyModulusDegree. Used with batching, a Galois element
/// 3^i % M corresponds to a cyclic row rotation i steps to the left, and
/// a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation i
/// steps to the right. The Galois element M-1 corresponds to a column rotation
/// (row swap). In the polynomial view (not batching), a Galois automorphism by
/// a Galois element p changes Enc(plain(x)) to Enc(plain(x^p)).
/// </para>
/// </remarks>
/// <param name="galoisElts">The Galois elements for which to generate keys</param>
/// <exception cref="InvalidOperationException">if the encryption parameters
/// do not support batching and scheme is SchemeType.BFV</exception>
/// <exception cref="InvalidOperationException">if the encryption
/// parameters do not support keyswitching</exception>
/// <exception cref="ArgumentException">if the Galois elements are not valid</exception>
public GaloisKeys GaloisKeysLocal(IEnumerable<uint> galoisElts)
{
if (null == galoisElts)
throw new ArgumentNullException(nameof(galoisElts));
if (!UsingKeyswitching())
throw new InvalidOperationException("Encryption parameters do not support keyswitching");
uint[] galoisEltsArr = galoisElts.ToArray();
NativeMethods.KeyGenerator_GaloisKeysFromElts(NativePtr,
(ulong)galoisEltsArr.Length, galoisEltsArr, false, out IntPtr galoisKeysPtr);
return new GaloisKeys(galoisKeysPtr);
}
/// <summary>
/// Generates and returns Galois keys as a serializable object.
/// </summary>
/// <remarks>
/// <para>
/// Generates and returns Galois keys as a serializable object. This function
/// creates specific Galois keys that can be used to apply specific Galois
/// automorphisms on encrypted data. The user needs to give as input a vector
/// of Galois elements corresponding to the keys that are to be created.
/// </para>
/// <para>
/// The Galois elements are odd integers in the interval [1, M-1], where
/// M = 2*N, and N = PolyModulusDegree. Used with batching, a Galois element
/// 3^i % M corresponds to a cyclic row rotation i steps to the left, and
/// a Galois element 3^(N/2-i) % M corresponds to a cyclic row rotation i
/// steps to the right. The Galois element M-1 corresponds to a column rotation
/// (row swap). In the polynomial view (not batching), a Galois automorphism by
/// a Galois element p changes Enc(plain(x)) to Enc(plain(x^p)).
/// </para>
/// <para>
/// Half of the key data is pseudo-randomly generated from a seed to reduce
/// the object size. The resulting serializable object cannot be used
/// directly and is meant to be serialized for the size reduction to have an
/// impact.
/// </para>
/// </remarks>
/// <param name="galoisElts">The Galois elements for which to generate keys</param>
/// <exception cref="ArgumentNullException">if galoisElts is null</exception>
/// <exception cref="InvalidOperationException">if the encryption parameters
/// do not support batching and scheme is SchemeType.BFV</exception>
/// <exception cref="InvalidOperationException">if the encryption
/// parameters do not support keyswitching</exception>
/// <exception cref="ArgumentException">if the Galois elements are not valid</exception>
public Serializable<GaloisKeys> GaloisKeys(IEnumerable<uint> galoisElts)
{
if (null == galoisElts)
throw new ArgumentNullException(nameof(galoisElts));
if (!UsingKeyswitching())
throw new InvalidOperationException("Encryption parameters do not support keyswitching");
uint[] galoisEltsArr = galoisElts.ToArray();
NativeMethods.KeyGenerator_GaloisKeysFromElts(NativePtr,
(ulong)galoisEltsArr.Length, galoisEltsArr, true, out IntPtr galoisKeysPtr);
GaloisKeys galoisKeys = new GaloisKeys(galoisKeysPtr);
return new Serializable<GaloisKeys>(galoisKeys);
}
/// <summary>
/// Generates and returns Galois keys.
/// </summary>
/// <remarks>
/// Generates and returns Galois keys. This function returns Galois keys in
/// a fully expanded form and is meant to be used primarily for demo, testing,
/// and debugging purposes. The user needs to give as input a vector of desired
/// Galois rotation step counts, where negative step counts correspond to
/// rotations to the right and positive step counts correspond to rotations to
/// the left. A step count of zero can be used to indicate a column rotation
/// in the BFV scheme complex conjugation in the CKKS scheme.
/// </remarks>
/// <param name="steps">The rotation step counts for which to generate keys</param>
/// <exception cref="ArgumentNullException">if steps is null</exception>
/// <exception cref="InvalidOperationException">if the encryption parameters
/// do not support batching and scheme is SchemeType.BFV</exception>
/// <exception cref="InvalidOperationException">if the encryption
/// parameters do not support keyswitching</exception>
/// <exception cref="ArgumentException">if the step counts are not valid</exception>
public GaloisKeys GaloisKeysLocal(IEnumerable<int> steps)
{
if (null == steps)
throw new ArgumentNullException(nameof(steps));
if (!UsingKeyswitching())
throw new InvalidOperationException("Encryption parameters do not support keyswitching");
int[] stepsArr = steps.ToArray();
NativeMethods.KeyGenerator_GaloisKeysFromSteps(NativePtr,
(ulong)stepsArr.Length, stepsArr, false, out IntPtr galoisKeysPtr);
return new GaloisKeys(galoisKeysPtr);
}
/// <summary>
/// Generates and returns Galois keys as a serializable object.
/// </summary>
/// <remarks>
/// <para>
/// Generates and returns Galois keys as a serializable object. This function
/// creates specific Galois keys that can be used to apply specific Galois
/// automorphisms on encrypted data. The user needs to give as input a vector
/// of desired Galois rotation step counts, where negative step counts
/// correspond to rotations to the right and positive step counts correspond
/// to rotations to the left. A step count of zero can be used to indicate
/// a column rotation in the BFV scheme complex conjugation in the CKKS scheme.
/// </para>
/// <para>
/// Half of the key data is pseudo-randomly generated from a seed to reduce
/// the object size. The resulting serializable object cannot be used
/// directly and is meant to be serialized for the size reduction to have an
/// impact.
/// </para>
/// </remarks>
/// <param name="steps">The rotation step counts for which to generate keys</param>
/// <exception cref="ArgumentNullException">if steps is null</exception>
/// <exception cref="InvalidOperationException">if the encryption parameters
/// do not support batching and scheme is SchemeType.BFV</exception>
/// <exception cref="InvalidOperationException">if the encryption
/// parameters do not support keyswitching</exception>
/// <exception cref="ArgumentException">if the step counts are not valid</exception>
public Serializable<GaloisKeys> GaloisKeys(IEnumerable<int> steps)
{
if (null == steps)
throw new ArgumentNullException(nameof(steps));
if (!UsingKeyswitching())
throw new InvalidOperationException("Encryption parameters do not support keyswitching");
int[] stepsArr = steps.ToArray();
NativeMethods.KeyGenerator_GaloisKeysFromSteps(NativePtr,
(ulong)stepsArr.Length, stepsArr, true, out IntPtr galoisKeysPtr);
GaloisKeys galoisKeys = new GaloisKeys(galoisKeysPtr);
return new Serializable<GaloisKeys>(galoisKeys);
}
/// <summary>
/// Generates and returns Galois keys.
/// </summary>
/// <remarks>
/// Generates and returns Galois keys. This function returns Galois keys in
/// a fully expanded form and is meant to be used primarily for demo, testing,
/// and debugging purposes. This function creates logarithmically many (in
/// degree of the polynomial modulus) Galois keys that is sufficient to apply
/// any Galois automorphism (e.g. rotations) on encrypted data. Most users
/// will want to use this overload of the function.
/// </remarks>
/// <exception cref="InvalidOperationException">if the encryption parameters
/// do not support batching and scheme is SchemeType.BFV</exception>
/// <exception cref="InvalidOperationException">if the encryption
/// parameters do not support keyswitching</exception>
public GaloisKeys GaloisKeysLocal()
{
if (!UsingKeyswitching())
throw new InvalidOperationException("Encryption parameters do not support keyswitching");
NativeMethods.KeyGenerator_GaloisKeysAll(NativePtr, false, out IntPtr galoisKeysPtr);
return new GaloisKeys(galoisKeysPtr);
}
/// <summary>
/// Generates and returns Galois keys as a serializable object.
/// </summary>
/// <remarks>
/// <para>
/// Generates and returns Galois keys as a serializable object. This function
/// creates logarithmically many (in degree of the polynomial modulus) Galois
/// keys that is sufficient to apply any Galois automorphism (e.g. rotations)
/// on encrypted data. Most users will want to use this overload of the function.
/// </para>
/// <para>
/// Half of the key data is pseudo-randomly generated from a seed to reduce
/// the object size. The resulting serializable object cannot be used
/// directly and is meant to be serialized for the size reduction to have an
/// impact.
/// </para>
/// </remarks>
/// <exception cref="InvalidOperationException">if the encryption parameters
/// do not support batching and scheme is SchemeType.BFV</exception>
/// <exception cref="InvalidOperationException">if the encryption
/// parameters do not support keyswitching</exception>
public Serializable<GaloisKeys> GaloisKeys()
{
if (!UsingKeyswitching())
throw new InvalidOperationException("Encryption parameters do not support keyswitching");
NativeMethods.KeyGenerator_GaloisKeysAll(NativePtr, true, out IntPtr galoisKeysPtr);
GaloisKeys galoisKeys = new GaloisKeys(galoisKeysPtr);
return new Serializable<GaloisKeys>(galoisKeys);
}
/// <summary>
/// Destroy native object.
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.KeyGenerator_Destroy(NativePtr);
}
internal bool UsingKeyswitching()
{
NativeMethods.KeyGenerator_ContextUsingKeyswitching(NativePtr, out bool result);
return result;
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL.Tools;
using System;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// The MMProf is a pure virtual class that every profile for the MemoryManager
/// should inherit from. The only functionality this class implements is the
/// GetPool() function that returns a MemoryPoolHandle pointing
/// to a pool selected by internal logic. The returned MemoryPoolHandle must
/// point to a valid memory pool.
/// </summary>
public abstract class MMProf : NativeObject
{
/// <summary>
/// Returns a MemoryPoolHandle pointing to a pool selected by internal logic
/// in a derived class.
/// </summary>
public MemoryPoolHandle GetPool()
{
NativeMethods.MMProf_GetPool(NativePtr, out IntPtr pool);
MemoryPoolHandle handle = new MemoryPoolHandle(pool);
return handle;
}
/// <summary>
/// Destroy native backing object.
/// </summary>
protected override void DestroyNativeObject()
{
NativeMethods.MMProf_Destroy(NativePtr);
}
}
/// <summary>
/// A memory manager profile that always returns a MemoryPoolHandle pointing to
/// the global memory pool. Microsoft SEAL uses this memory manager profile by default.
/// </summary>
public class MMProfGlobal : MMProf
{
/// <summary>
/// Create a new instance of MMProfGlobal
/// </summary>
public MMProfGlobal()
{
NativeMethods.MMProf_CreateGlobal(out IntPtr profile);
NativePtr = profile;
}
}
/// <summary>
/// A memory manager profile that always returns a MemoryPoolHandle pointing to
/// specific memory pool.
/// </summary>
public class MMProfFixed : MMProf
{
/// <summary>
/// Create a new instance of MMProfFixed
/// </summary>
/// <param name="pool">Fixed memory pool handle to use</param>
/// <exception cref="ArgumentNullException">if pool is null</exception>
public MMProfFixed(MemoryPoolHandle pool)
{
if (null == pool)
throw new ArgumentNullException(nameof(pool));
// Create a copy of MemoryPoolHandle, as the profile will take ownership
// of the pointer and will attempt to delete it when destroyed.
NativeMethods.MemoryPoolHandle_Create(pool.NativePtr, out IntPtr poolCopy);
NativeMethods.MMProf_CreateFixed(poolCopy, out IntPtr profile);
NativePtr = profile;
}
}
/// <summary>
/// A memory manager profile that always returns a MemoryPoolHandle pointing to
/// the new thread-safe memory pool. This profile should not be used except in
/// special circumstances, as it does not result in any reuse of allocated memory.
/// </summary>
public class MMProfNew : MMProf
{
/// <summary>
/// Create a new instance of MMProfNew
/// </summary>
public MMProfNew()
{
NativeMethods.MMProf_CreateNew(out IntPtr profile);
NativePtr = profile;
}
}
/// <summary>
/// A memory manager profile that always returns a MemoryPoolHandle pointing to
/// the thread-local memory pool. This profile should be used with care, as any
/// memory allocated by it will be released once the thread exits. In other words,
/// the thread-local memory pool cannot be used to share memory across different
/// threads. On the other hand, this profile can be useful when a very high number
/// of threads doing simultaneous allocations would cause contention in the
/// global memory pool.
/// </summary>
public class MMProfThreadLocal : MMProf
{
/// <summary>
/// Create a new instance of MMProfThreadLocal
/// </summary>
public MMProfThreadLocal()
{
NativeMethods.MMProf_CreateThreadLocal(out IntPtr profile);
NativePtr = profile;
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
namespace Microsoft.Research.SEAL
{
/// <summary>
/// Memory Manager Profile Options used in MemoryManager.GetPool method
/// </summary>
public enum MMProfOpt : ulong
{
/// <summary>
/// Use default profile
/// </summary>
Default = 0,
/// <summary>
/// Force use of the Global profile
/// </summary>
ForceGlobal = 1,
/// <summary>
/// Force use of a New profile
/// </summary>
ForceNew = 2,
/// <summary>
/// Force use of the Thread Local profile
/// </summary>
ForceThreadLocal = 4
}
/// <summary>
/// The MemoryManager class can be used to create instances of MemoryPoolHandle
/// based on a given "profile". A profile is implemented by inheriting from the
/// MMProf class (pure virtual) and encapsulates internal logic for deciding which
/// memory pool to use.
/// </summary>
public static class MemoryManager
{
/// <summary>
/// Static initialization of MemoryManager
/// </summary>
static MemoryManager()
{
// The default profile is Global
profile_ = new MMProfGlobal();
}
/// <summary>
/// Sets the current profile to a given one and returns an instance pointing
/// to the previously set profile.
/// </summary>
/// <param name="newProfile">New memory manager profile</param>
/// <exception cref="ArgumentNullException">if newProfile is null</exception>
public static MMProf SwitchProfile(MMProf newProfile)
{
if (null == newProfile)
throw new ArgumentNullException(nameof(newProfile));
NativeMethods.MemoryManager_SwitchProfile(newProfile.NativePtr);
MMProf oldProfile = profile_;
profile_ = newProfile;
return oldProfile;
}
/// <summary>
/// Returns a MemoryPoolHandle according to the currently set memory manager
/// profile and profOpt. The following values for profOpt have an effect
/// independent of the current profile:
///
/// MMProfOpt.ForceNew: return MemoryPoolHandle.New()
/// MMProfOpt.ForceGlobal: return MemoryPoolHandle.Global()
/// MMProfOpt.ForceThreadLocal: return MemoryPoolHandle.ThreadLocal()
///
/// Other values for profOpt are forwarded to the current profile and, depending
/// on the profile, may or may not have an effect. The value MMProfOpt.Default
/// will always invoke a default behavior for the current profile.
/// </summary>
/// <param name="profOpt">A MMProfOpt parameter used to provide additional
/// instructions to the memory manager profile for internal logic.</param>
/// <param name="clearOnDestruction">Indicates whether the memory pool data
/// should be cleared when destroyed.This can be important when memory pools
/// are used to store private data. This parameter is only used with MMProfOpt.ForceNew,
/// and ignored in all other cases.</param>
public static MemoryPoolHandle GetPool(MMProfOpt profOpt, bool clearOnDestruction = false)
{
NativeMethods.MemoryManager_GetPool((int)profOpt, clearOnDestruction, out IntPtr handlePtr);
MemoryPoolHandle handle = new MemoryPoolHandle(handlePtr);
return handle;
}
/// <summary>
/// Returns a MemoryPoolHandle according to the currently set memory manager profile.
/// </summary>
public static MemoryPoolHandle GetPool()
{
NativeMethods.MemoryManager_GetPool(out IntPtr handlePtr);
MemoryPoolHandle handle = new MemoryPoolHandle(handlePtr);
return handle;
}
/// <summary>
/// Currently set profile
/// </summary>
private static MMProf profile_ = null;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment