// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.Research.SEAL; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; namespace SEALNetTest { [TestClass] public class SEALContextTests { [TestMethod] public void SEALContextCreateTest() { EncryptionParameters encParams1 = new EncryptionParameters(SchemeType.BFV); EncryptionParameters encParams2 = new EncryptionParameters(SchemeType.CKKS); EncryptionParameters encParams3 = new EncryptionParameters(SchemeType.BGV); SEALContext context1 = new SEALContext(encParams1); SEALContext context2 = new SEALContext(encParams2); SEALContext context3 = new SEALContext(encParams3); Assert.IsNotNull(context1); Assert.IsNotNull(context2); Assert.IsNotNull(context3); Assert.IsFalse(context1.ParametersSet); Assert.IsFalse(context2.ParametersSet); Assert.IsFalse(context3.ParametersSet); Assert.AreNotSame(context1.FirstParmsId, context1.LastParmsId); Assert.AreEqual(context1.FirstParmsId, context1.LastParmsId); Assert.AreNotSame(context3.FirstParmsId, context3.LastParmsId); Assert.AreEqual(context3.FirstParmsId, context3.LastParmsId); SEALContext.ContextData data1 = context2.FirstContextData; SEALContext.ContextData data2 = context2.GetContextData(context2.FirstParmsId); Assert.AreNotSame(data1, data2); ulong[] totalCoeffMod1 = data1.TotalCoeffModulus; ulong[] totalCoeffMod2 = data2.TotalCoeffModulus; int bitCount1 = data1.TotalCoeffModulusBitCount; int bitCount2 = data2.TotalCoeffModulusBitCount; Assert.AreEqual(bitCount1, bitCount2); Assert.AreEqual(totalCoeffMod1.Length, totalCoeffMod2.Length); for (int i = 0; i < totalCoeffMod1.Length; i++) { Assert.AreEqual(totalCoeffMod1[i], totalCoeffMod2[i]); } } [TestMethod] public void SEALContextParamsTest() { { EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV) { PolyModulusDegree = 128, PlainModulus = new Modulus(1 << 6), CoeffModulus = CoeffModulus.Create(128, new int[] { 30, 30, 30 }) }; SEALContext context = new SEALContext(parms, expandModChain: true, secLevel: SecLevelType.None); SEALContext.ContextData data = context.KeyContextData; Assert.IsNotNull(data); EncryptionParameters parms2 = data.Parms; Assert.AreEqual(parms.PolyModulusDegree, parms2.PolyModulusDegree); EncryptionParameterQualifiers qualifiers = data.Qualifiers; Assert.IsNotNull(qualifiers); Assert.IsTrue(qualifiers.ParametersSet); Assert.IsFalse(qualifiers.UsingBatching); Assert.IsTrue(qualifiers.UsingFastPlainLift); Assert.IsTrue(qualifiers.UsingFFT); Assert.IsTrue(qualifiers.UsingNTT); Assert.AreEqual(SecLevelType.None, qualifiers.SecLevel); Assert.IsFalse(qualifiers.UsingDescendingModulusChain); Assert.IsTrue(context.UsingKeyswitching); ulong[] cdpm = data.CoeffDivPlainModulus; Assert.AreEqual(3, cdpm.Length); Assert.AreEqual(32ul, data.PlainUpperHalfThreshold); Assert.AreEqual(3, data.PlainUpperHalfIncrement.Length); Assert.IsNull(data.UpperHalfThreshold); Assert.IsNotNull(data.UpperHalfIncrement); Assert.AreEqual(3, data.UpperHalfIncrement.Length); Assert.AreEqual(2ul, data.ChainIndex); Assert.IsNull(data.PrevContextData); SEALContext.ContextData data2 = data.NextContextData; Assert.IsNotNull(data2); Assert.AreEqual(1ul, data2.ChainIndex); Assert.AreEqual(2ul, data2.PrevContextData.ChainIndex); SEALContext.ContextData data3 = data2.NextContextData; Assert.IsNotNull(data3); Assert.AreEqual(0ul, data3.ChainIndex); Assert.AreEqual(1ul, data3.PrevContextData.ChainIndex); Assert.IsNull(data3.NextContextData); parms = new EncryptionParameters(SchemeType.BFV) { PolyModulusDegree = 127, PlainModulus = new Modulus(1 << 6), CoeffModulus = CoeffModulus.Create(128, new int[] { 30, 30, 30 }) }; context = new SEALContext(parms, expandModChain: true, secLevel: SecLevelType.None); Assert.AreEqual(context.ParameterErrorName(), "invalid_poly_modulus_degree_non_power_of_two"); Assert.AreEqual(context.ParameterErrorMessage(), "poly_modulus_degree is not a power of two"); } { EncryptionParameters parms = new EncryptionParameters(SchemeType.BGV) { PolyModulusDegree = 128, PlainModulus = new Modulus(1 << 6), CoeffModulus = CoeffModulus.Create(128, new int[] { 30, 30, 30 }) }; SEALContext context = new SEALContext(parms, expandModChain: true, secLevel: SecLevelType.None); SEALContext.ContextData data = context.KeyContextData; Assert.IsNotNull(data); EncryptionParameters parms2 = data.Parms; Assert.AreEqual(parms.PolyModulusDegree, parms2.PolyModulusDegree); EncryptionParameterQualifiers qualifiers = data.Qualifiers; Assert.IsNotNull(qualifiers); Assert.IsTrue(qualifiers.ParametersSet); Assert.IsFalse(qualifiers.UsingBatching); Assert.IsTrue(qualifiers.UsingFastPlainLift); Assert.IsTrue(qualifiers.UsingFFT); Assert.IsTrue(qualifiers.UsingNTT); Assert.AreEqual(SecLevelType.None, qualifiers.SecLevel); Assert.IsFalse(qualifiers.UsingDescendingModulusChain); Assert.IsTrue(context.UsingKeyswitching); ulong[] cdpm = data.CoeffDivPlainModulus; Assert.AreEqual(3, cdpm.Length); Assert.AreEqual(32ul, data.PlainUpperHalfThreshold); Assert.AreEqual(3, data.PlainUpperHalfIncrement.Length); Assert.IsNull(data.UpperHalfThreshold); Assert.IsNotNull(data.UpperHalfIncrement); Assert.AreEqual(3, data.UpperHalfIncrement.Length); Assert.AreEqual(2ul, data.ChainIndex); Assert.IsNull(data.PrevContextData); SEALContext.ContextData data2 = data.NextContextData; Assert.IsNotNull(data2); Assert.AreEqual(1ul, data2.ChainIndex); Assert.AreEqual(2ul, data2.PrevContextData.ChainIndex); SEALContext.ContextData data3 = data2.NextContextData; Assert.IsNotNull(data3); Assert.AreEqual(0ul, data3.ChainIndex); Assert.AreEqual(1ul, data3.PrevContextData.ChainIndex); Assert.IsNull(data3.NextContextData); parms = new EncryptionParameters(SchemeType.BGV) { PolyModulusDegree = 127, PlainModulus = new Modulus(1 << 6), CoeffModulus = CoeffModulus.Create(128, new int[] { 30, 30, 30 }) }; context = new SEALContext(parms, expandModChain: true, secLevel: SecLevelType.None); Assert.AreEqual(context.ParameterErrorName(), "invalid_poly_modulus_degree_non_power_of_two"); Assert.AreEqual(context.ParameterErrorMessage(), "poly_modulus_degree is not a power of two"); } } [TestMethod] public void SEALContextCKKSParamsTest() { int slotSize = 4; EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS) { PolyModulusDegree = 2 * (ulong)slotSize, CoeffModulus = CoeffModulus.Create(2 * (ulong)slotSize, new int[] { 40, 40, 40, 40 }) }; SEALContext context = new SEALContext(parms, expandModChain: true, secLevel: SecLevelType.None); SEALContext.ContextData data = context.KeyContextData; Assert.IsNotNull(data); // This should be available in CKKS Assert.IsNotNull(data.UpperHalfThreshold); Assert.AreEqual(4, data.UpperHalfThreshold.Length); Assert.IsNull(data.UpperHalfIncrement); Assert.AreEqual(3ul, data.ChainIndex); Assert.IsNull(data.PrevContextData); SEALContext.ContextData data2 = data.NextContextData; Assert.IsNotNull(data2); Assert.AreEqual(2ul, data2.ChainIndex); Assert.AreEqual(3ul, data2.PrevContextData.ChainIndex); SEALContext.ContextData data3 = data2.NextContextData; Assert.IsNotNull(data3); Assert.AreEqual(1ul, data3.ChainIndex); Assert.AreEqual(2ul, data3.PrevContextData.ChainIndex); SEALContext.ContextData data4 = data3.NextContextData; Assert.IsNotNull(data4); Assert.AreEqual(0ul, data4.ChainIndex); Assert.AreEqual(1ul, data4.PrevContextData.ChainIndex); Assert.IsNull(data4.NextContextData); } [TestMethod] public void ExpandModChainTest() { { EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV) { PolyModulusDegree = 4096, CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree: 4096), PlainModulus = new Modulus(1 << 20) }; SEALContext context1 = new SEALContext(parms, expandModChain: true, secLevel: SecLevelType.None); // By default there is a chain SEALContext.ContextData contextData = context1.KeyContextData; Assert.IsNotNull(contextData); Assert.IsNull(contextData.PrevContextData); Assert.IsNotNull(contextData.NextContextData); contextData = context1.FirstContextData; Assert.IsNotNull(contextData); Assert.IsNotNull(contextData.PrevContextData); Assert.IsNotNull(contextData.NextContextData); // This should not create a chain SEALContext context2 = new SEALContext(parms, expandModChain: false); contextData = context2.KeyContextData; Assert.IsNotNull(contextData); Assert.IsNull(contextData.PrevContextData); Assert.IsNotNull(contextData.NextContextData); contextData = context2.FirstContextData; Assert.IsNotNull(contextData); Assert.IsNotNull(contextData.PrevContextData); Assert.IsNull(contextData.NextContextData); } { EncryptionParameters parms = new EncryptionParameters(SchemeType.BGV) { PolyModulusDegree = 4096, CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree: 4096), PlainModulus = new Modulus(1 << 20) }; SEALContext context1 = new SEALContext(parms, expandModChain: true, secLevel: SecLevelType.None); // By default there is a chain SEALContext.ContextData contextData = context1.KeyContextData; Assert.IsNotNull(contextData); Assert.IsNull(contextData.PrevContextData); Assert.IsNotNull(contextData.NextContextData); contextData = context1.FirstContextData; Assert.IsNotNull(contextData); Assert.IsNotNull(contextData.PrevContextData); Assert.IsNotNull(contextData.NextContextData); // This should not create a chain SEALContext context2 = new SEALContext(parms, expandModChain: false); contextData = context2.KeyContextData; Assert.IsNotNull(contextData); Assert.IsNull(contextData.PrevContextData); Assert.IsNotNull(contextData.NextContextData); contextData = context2.FirstContextData; Assert.IsNotNull(contextData); Assert.IsNotNull(contextData.PrevContextData); Assert.IsNull(contextData.NextContextData); } } } }