// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.Research.SEAL.Tools; using System; using System.IO; using System.Collections.Generic; using System.Linq; namespace Microsoft.Research.SEAL { /// Represent an integer modulus of up to 61 bits. /// /// /// Represent an integer modulus of up to 61 bits. An instance of the Modulus /// class represents a non-negative integer modulus up to 61 bits. In particular, /// the encryption parameter PlainModulus, and the primes in CoeffModulus, are /// represented by instances of Modulus. The purpose of this class is to /// perform and store the pre-computation required by Barrett reduction. /// /// /// In general, reading from Modulus is thread-safe as long as no other thread /// is concurrently mutating it. /// /// /// See EncryptionParameters for a description /// of the encryption parameters. public class Modulus : NativeObject, IEquatable, IEquatable, IComparable, IComparable { /// Creates a Modulus instance. /// /// Creates a Modulus instance. The value of the Modulus is set to 0. /// public Modulus() { NativeMethods.Modulus_Create(value: 0, smallModulus: out IntPtr ptr); NativePtr = ptr; } /// Creates a Modulus instance. /// /// Creates a Modulus instance. The value of the Modulus is set to /// the given value. /// /// The integer modulus /// if value is 1 or more than /// 61 bits public Modulus(ulong value) { NativeMethods.Modulus_Create(value, out IntPtr ptr); NativePtr = ptr; } /// Creates a new Modulus by copying a given one. /// The Modulus to copy from /// if copy is null public Modulus(Modulus copy) { if (null == copy) throw new ArgumentNullException(nameof(copy)); NativeMethods.Modulus_Create(copy.NativePtr, out IntPtr ptr); NativePtr = ptr; } /// /// Creates a Modulus from a native pointer /// /// Pointer to the native Modulus /// Whether this instance owns the native pointer internal Modulus(IntPtr sm, bool owned = true) : base(sm, owned) { } /// Copies a given Modulus to the current one. /// The Modulus to copy from /// if assign is null public void Set(Modulus assign) { if (null == assign) throw new ArgumentNullException(nameof(assign)); NativeMethods.Modulus_Set(NativePtr, assign.NativePtr); } /// Sets the value of the Modulus. /// The new integer modulus /// if value is 1 or more than /// 61 bits public void Set(ulong value) { NativeMethods.Modulus_Set(NativePtr, value); } /// /// Returns the significant bit count of the value of the current Modulus. /// public int BitCount { get { NativeMethods.Modulus_BitCount(NativePtr, out int result); return result; } } /// /// Returns the size (in 64-bit words) of the value of the current Modulus. /// public ulong UInt64Count { get { NativeMethods.Modulus_UInt64Count(NativePtr, out ulong result); return result; } } /// /// Returns the value of the current Modulus. /// public ulong Value { get { NativeMethods.Modulus_Value(NativePtr, out ulong result); return result; } } /// /// Returns the Barrett ratio computed for the value of the current Modulus. /// /// /// Returns the Barrett ratio computed for the value of the current Modulus. /// The first two components of the Barrett ratio are the floor of 2^128/value, /// and the third component is the remainder. /// public Tuple ConstRatio { get { ulong[] ratio = new ulong[3]; NativeMethods.Modulus_ConstRatio(NativePtr, length: (ulong)3, ratio: ratio); return new Tuple(ratio[0], ratio[1], ratio[2]); } } /// /// Returns whether the value of the current Modulus is zero. /// public bool IsZero { get { NativeMethods.Modulus_IsZero(NativePtr, out bool result); return result; } } /// /// Returns whether the value of the current Modulus is a prime number. /// public bool IsPrime { get { NativeMethods.Modulus_IsPrime(NativePtr, out bool result); return result; } } /// /// Returns an upper bound on the size of the Modulus, 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.Modulus_SaveSize( NativePtr, (byte)comprModeValue, out long outBytes); return outBytes; } /// Saves the Modulus to an output stream. /// /// Saves the Modulus to an output stream. The output is in binary format /// and not human-readable. /// /// The stream to save the Modulus 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.Modulus_Save(NativePtr, outptr, size, cm, out outBytes), SaveSize(comprModeValue), comprModeValue, stream); } /// /// Loads a Modulus from an input stream overwriting the current Modulus. /// /// The stream to load the Modulus 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.Modulus_Load(NativePtr, outptr, size, out outBytes), stream); } /// /// Reduces a given unsigned integer modulo this modulus. /// /// The unsigned integer to reduce /// public ulong Reduce(ulong value) { NativeMethods.Modulus_Reduce(NativePtr, value, out ulong result); return result; } /// /// Returns a hash-code based on the value of the Modulus. /// public override int GetHashCode() { ulong[] arr = new ulong[1]; arr[0] = Value; return Utilities.ComputeArrayHashCode(arr); } /// /// Compares two Modulus instances. /// /// The value to compare against public override bool Equals(object obj) { Modulus sm = obj as Modulus; return Equals(sm); } /// Creates a Modulus instance. /// /// Creates a Modulus instance. The value of the Modulus is set to /// the given value. /// /// The integer modulus /// if value is 1 or more than 61 bits public static explicit operator Modulus(ulong value) { Modulus sm = new Modulus(value); return sm; } #region IEquatable methods /// /// Determines whether this instance equals another Modulus instance /// /// Instance to compare against public bool Equals(Modulus other) { if (null == other) return false; NativeMethods.Modulus_Equals(NativePtr, other.NativePtr, out bool result); return result; } #endregion #region IEquatable methods /// /// Determines whether the value of this instance equals the given UInt64 value /// /// The value to compare against public bool Equals(ulong other) { NativeMethods.Modulus_Equals(NativePtr, other, out bool result); return result; } #endregion #region IComparable methods /// /// Compares two Modulus instances. /// /// The Modulus to compare against public int CompareTo(Modulus compare) { if (null == compare) return 1; return Value.CompareTo(compare.Value); } #endregion #region IComparable methods /// /// Compares a Modulus value to an unsigned integer. /// /// The unsigned integer to compare against public int CompareTo(ulong compare) { return Value.CompareTo(compare); } #endregion /// /// Destroy native object. /// protected override void DestroyNativeObject() { NativeMethods.Modulus_Destroy(NativePtr); } } /// /// Represents a standard security level according to the HomomorphicEncryption.org /// security standard. /// /// /// Represents a standard security level according to the HomomorphicEncryption.org /// security standard. The value SecLevelType.None signals that no standard /// security level should be imposed. The value SecLevelType.TC128 provides /// a very high level of security and is the default security level enforced by /// Microsoft SEAL when constructing a SEALContext object. Normal users should not /// have to specify the security level explicitly anywhere. /// public enum SecLevelType : int { /// /// No security level specified. /// None = 0, /// /// 128-bit security level according to HomomorphicEncryption.org standard. /// TC128 = 128, /// /// 192-bit security level according to HomomorphicEncryption.org standard. /// TC192 = 192, /// /// 256-bit security level according to HomomorphicEncryption.org standard. /// TC256 = 256 } /// /// This class contains static methods for creating a coefficient modulus easily. /// /// /// /// This class contains static methods for creating a coefficient modulus easily. /// Note that while these functions take a SecLevelType argument, all security /// guarantees are lost if the output is used with encryption parameters with /// a mismatching value for the PolyModulusDegree. /// /// /// The default value SecLevelType.TC128 provides a very high level of security /// and is the default security level enforced by Microsoft SEAL when constructing /// a SEALContext object. Normal users should not have to specify the security /// level explicitly anywhere. /// /// public static class CoeffModulus { /// /// Returns the largest bit-length of the coefficient modulus, i.e., bit-length /// of the product of the primes in the coefficient modulus, that guarantees /// a given security level when using a given PolyModulusDegree, according /// to the HomomorphicEncryption.org security standard. /// /// The value of the PolyModulusDegree /// encryption parameter /// The desired standard security level static public int MaxBitCount(ulong polyModulusDegree, SecLevelType secLevel = SecLevelType.TC128) { NativeMethods.CoeffModulus_MaxBitCount(polyModulusDegree, (int)secLevel, out int result); return result; } /// /// Returns a default coefficient modulus for the BFV scheme that guarantees /// a given security level when using a given PolyModulusDegree, according /// to the HomomorphicEncryption.org security standard. /// /// /// /// Returns a default coefficient modulus for the BFV scheme that guarantees /// a given security level when using a given PolyModulusDegree, according /// to the HomomorphicEncryption.org security standard. Note that all security /// guarantees are lost if the output is used with encryption parameters with /// a mismatching value for the PolyModulusDegree. /// /// /// The coefficient modulus returned by this function will not perform well /// if used with the CKKS scheme. /// /// /// The value of the PolyModulusDegree /// encryption parameter /// The desired standard security level /// if polyModulusDegree is not /// a power-of-two or is too large /// if secLevel is SecLevelType.None static public IEnumerable BFVDefault( ulong polyModulusDegree, SecLevelType secLevel = SecLevelType.TC128) { List result = null; ulong length = 0; NativeMethods.CoeffModulus_BFVDefault(polyModulusDegree, (int)secLevel, ref length, null); IntPtr[] coeffArray = new IntPtr[length]; NativeMethods.CoeffModulus_BFVDefault(polyModulusDegree, (int)secLevel, ref length, coeffArray); result = new List(checked((int)length)); foreach (IntPtr sm in coeffArray) { result.Add(new Modulus(sm)); } return result; } /// /// Returns a custom coefficient modulus suitable for use with the specified /// PolyModulusDegree. /// /// /// Returns a custom coefficient modulus suitable for use with the specified /// PolyModulusDegree.The return value will be a vector consisting of /// Modulus elements representing distinct prime numbers of bit-lengths /// as given in the bitSizes parameter. The bit sizes of the prime numbers /// can be at most 60 bits. /// /// The value of the PolyModulusDegree encryption parameter /// The bit-lengths of the primes to be generated /// if polyModulusDegree is not /// a power-of-two or is too large /// if bitSizes is too large or if its /// elements are out of bounds /// if not enough suitable primes could be found static public IEnumerable Create( ulong polyModulusDegree, IEnumerable bitSizes) { if (null == bitSizes) throw new ArgumentNullException(nameof(bitSizes)); List result = null; int[] bitSizesArr = bitSizes.ToArray(); int length = bitSizesArr.Length; IntPtr[] coeffArray = new IntPtr[length]; NativeMethods.CoeffModulus_Create(polyModulusDegree, (ulong)length, bitSizesArr, coeffArray); result = new List(length); foreach (IntPtr sm in coeffArray) { result.Add(new Modulus(sm)); } return result; } /// /// Returns a custom coefficient modulus suitable for use with the specified /// PolyModulusDegree. /// /// /// Returns a custom coefficient modulus suitable for use with the specified /// PolyModulusDegree.The return value will be a vector consisting of /// Modulus elements representing distinct prime numbers of bit-lengths /// as given in the bitSizes parameter. The bit sizes of the prime numbers /// can be at most 60 bits. /// /// The value of the PolyModulusDegree encryption parameter /// The value of the PlainModulus encryption parameter /// The bit-lengths of the primes to be generated /// if polyModulusDegree is not /// a power-of-two or is too large /// if bitSizes is too large or if its /// elements are out of bounds /// if LCM(2*polyModulusDegree, PlainModulus) is /// more than 64-bit /// if not enough suitable primes could be found static public IEnumerable Create( ulong polyModulusDegree, Modulus plainModulus, IEnumerable bitSizes) { if (null == bitSizes) throw new ArgumentNullException(nameof(bitSizes)); List result = null; int[] bitSizesArr = bitSizes.ToArray(); int length = bitSizesArr.Length; IntPtr[] coeffArray = new IntPtr[length]; NativeMethods.CoeffModulus_Create(polyModulusDegree, (ulong)length, bitSizesArr, plainModulus.NativePtr, coeffArray); result = new List(length); foreach (IntPtr sm in coeffArray) { result.Add(new Modulus(sm)); } return result; } } /// /// This class contains static methods for creating a plaintext modulus easily. /// public static class PlainModulus { /// /// Creates a prime number Modulus for use as PlainModulus encryption /// parameter that supports batching with a given PolyModulusDegree. /// /// The value of the PolyModulusDegree /// encryption parameter /// The bit-length of the prime to be generated /// if polyModulusDegree is not /// a power-of-two or is too large /// if bitSize is out of bounds /// if a suitable prime could not be found static public Modulus Batching(ulong polyModulusDegree, int bitSize) { return CoeffModulus.Create( polyModulusDegree, new int[] { bitSize }).First(); } /// /// Creates several prime number Modulus elements that can be used as /// PlainModulus encryption parameters, each supporting batching with a given /// PolyModulusDegree. /// /// The value of the PolyModulusDegree /// encryption parameter /// The bit-lengths of the primes to be generated /// if polyModulusDegree is not /// a power-of-two or is too large /// if bitSizes is too large or if its /// elements are out of bounds /// if not enough suitable primes could be found static public IEnumerable Batching( ulong polyModulusDegree, IEnumerable bitSizes) { return CoeffModulus.Create(polyModulusDegree, bitSizes); } } }