// 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
{
///
/// Describes the type of encryption scheme to be used.
///
public enum SchemeType : byte
{
///
/// No scheme set; cannot be used for encryption
///
None = 0x0,
///
/// Brakerski/Fan-Vercauteren scheme
///
BFV = 0x1,
///
/// Cheon-Kim-Kim-Song scheme
///
CKKS = 0x2
}
///
/// Represents the user-customizable encryption scheme settings.
///
///
///
/// 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 class,
/// which verifies the validity of the parameters, and performs necessary
/// pre-computations.
///
///
/// 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).
///
///
/// 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 class once the SEALContext
/// has been created.
///
///
/// In general, reading from EncryptionParameters is thread-safe, while mutating
/// is not.
///
///
/// 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.
///
///
public class EncryptionParameters : NativeObject, IEquatable
{
///
/// Creates an empty set of encryption parameters.
///
///
/// Scheme for the encryption parameters
public EncryptionParameters(SchemeType scheme = SchemeType.None)
{
NativeMethods.EncParams_Create((byte)scheme, out IntPtr ptr);
NativePtr = ptr;
}
///
/// Creates an empty set of encryption parameters.
///
/// Scheme for the encryption parameters
/// if scheme is not supported
public EncryptionParameters(byte scheme)
{
NativeMethods.EncParams_Create(scheme, out IntPtr ptr);
NativePtr = ptr;
}
///
/// Creates a copy of a given instance of EncryptionParameters.
///
/// The EncryptionParameters to copy from
/// if copy is null
public EncryptionParameters(EncryptionParameters copy)
{
if (null == copy)
throw new ArgumentNullException(nameof(copy));
NativeMethods.EncParams_Create(copy.NativePtr, out IntPtr ptr);
NativePtr = ptr;
}
///
/// Create an instance of Encryption Parameters through a pointer to a
/// native object.
///
/// Native encryption parameters
/// Whether this instance owns the native pointer
internal EncryptionParameters(IntPtr ptr, bool owned = true)
: base(ptr, owned)
{
}
///
/// Overwrites the EncryptionParameters instance with a copy of a given
/// instance.
///
/// The EncryptionParameters to copy from
/// if assign is null
public void Set(EncryptionParameters assign)
{
if (null == assign)
throw new ArgumentNullException(nameof(assign));
NativeMethods.EncParams_Set(NativePtr, assign.NativePtr);
}
///
/// Returns or Sets the degree of the polynomial modulus parameter.
///
///
/// 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).
///
public ulong PolyModulusDegree
{
get
{
NativeMethods.EncParams_GetPolyModulusDegree(NativePtr, out ulong result);
return result;
}
set
{
NativeMethods.EncParams_SetPolyModulusDegree(NativePtr, value);
}
}
///
/// Get a copy of the currently set coefficient modulus parameter, or
/// set the coefficient modulus parameter.
///
///
/// 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
/// 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.
///
/// if the value being set is null
/// if the value being set is invalid
public IEnumerable 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 result = new List(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);
}
}
///
/// Get a copy of the currently set plaintext modulus parameter, or
/// set the plaintext modulus parameter.
///
///
/// When setting:
/// Sets the plaintext modulus parameter. The plaintext modulus is an integer modulus
/// represented by the 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.
///
/// if the value being set is null
/// if scheme is not SchemeType.BFV
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);
}
}
///
/// Sets the plaintext modulus parameter.
///
///
/// Sets the plaintext modulus parameter. The plaintext modulus is an integer modulus
/// represented by the 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.
///
/// The new plaintext modulus
/// if scheme is not CKKS
public void SetPlainModulus(ulong plainModulus)
{
NativeMethods.EncParams_SetPlainModulus(NativePtr, plainModulus);
}
///
/// Returns the encryption scheme type.
///
public SchemeType Scheme
{
get
{
NativeMethods.EncParams_GetScheme(NativePtr, out byte scheme);
return (SchemeType)scheme;
}
}
///
/// Returns an upper bound on the size of the EncryptionParameters, as if
/// it was written to an output stream.
///
/// The compression mode
/// if the compression mode is not
/// supported
/// if the size does not fit in
/// the return type
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;
}
/// Saves the EncryptionParameters to an output stream.
///
/// Saves the EncryptionParameters to an output stream. The output is in
/// binary format and not human-readable.
///
/// The stream to save the EncryptionParameters to
/// The desired compression mode
/// if stream is null
/// if the stream is closed or does not
/// support writing, or if compression mode is not supported
/// if I/O operations failed
/// if the data to be saved
/// is invalid, or if compression failed
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);
}
///
/// Loads an EncryptionParameters from an input stream overwriting the
/// current EncryptionParameters.
///
/// The stream to load the EncryptionParameters from
/// if stream is null
/// if the stream is closed or does not
/// support reading
/// if the stream ended
/// unexpectedly
/// if I/O operations failed
/// 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
public long Load(Stream stream)
{
return Serialization.Load(
(byte[] outptr, ulong size, out long outBytes) =>
NativeMethods.EncParams_Load(NativePtr, outptr, size,
out outBytes),
stream);
}
///
/// Returns the ParmsId of the current parameters. This function is intended
/// for internal use.
///
internal ParmsId ParmsId
{
get
{
ParmsId id = new ParmsId();
NativeMethods.EncParams_GetParmsId(NativePtr, id.Block);
return id;
}
}
///
/// Compares a given set of encryption parameters to the current set of
/// encryption parameters.
///
///
/// 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.
///
/// The EncryptionParameters to compare against
public override bool Equals(object obj)
{
EncryptionParameters encParams = obj as EncryptionParameters;
return Equals(encParams);
}
///
/// Returns a hash-code based on the EncryptionParameters.
///
public override int GetHashCode()
{
return Utilities.ComputeArrayHashCode(ParmsId.Block);
}
#region IEquatable methods
///
/// Compares a given set of encryption parameters to the current set of
/// encryption parameters.
///
///
///
/// 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.
///
/// The EncryptionParameters to compare against
public bool Equals(EncryptionParameters other)
{
if (null == other)
return false;
NativeMethods.EncParams_Equals(NativePtr, other.NativePtr, out bool result);
return result;
}
#endregion
///
/// Destroy native object.
///
protected override void DestroyNativeObject()
{
NativeMethods.EncParams_Destroy(NativePtr);
}
}
}