public static void SignRequest(SecretKey secret, HttpRequestMessage request) { #region Preconditions if (secret.Value == null) throw new ArgumentNullException(nameof(secret.Value)); #endregion request.Headers.Date = DateTimeOffset.UtcNow; request.Headers.Add("User-Agent", "Carbon/1.0"); var dateHeader = request.Headers.GetValues("Date").First(); var stringToSign = string.Join("\n", "HMAC-SHA256", // Algorithm dateHeader, // Request Date / TODO: Format as ISO request.Method.ToString().ToUpper(), request.RequestUri.Authority, request.RequestUri.AbsolutePath ); var signature = Signature.ComputeHmacSha256( key : secret, data : Encoding.UTF8.GetBytes(stringToSign) ); // TODO: Credential var headerValue = $"C Algorithm=HMAC-SHA256,Signature={signature.ToHexString()}"; request.Headers.TryAddWithoutValidation("Authorization", headerValue); }
private static void AddNewSecretKey(string key, string userId, bool isTestMode) { var secretKey = new SecretKey { UserId = userId, CreatedDate = DateTime.UtcNow, IsTest = isTestMode, Value = key }; using (var db = new DBEntities()) { var activeSecret = db.SecretKeys.Where(sk => sk.UserId == userId && !sk.IsRevoked && sk.IsTest == isTestMode).FirstOrDefault(); if (activeSecret != null) { activeSecret.IsRevoked = true; activeSecret.RevokedDate = DateTime.UtcNow; } db.SecretKeys.Add(secretKey); db.SaveChanges(); } }
public GFWPressForwardServerListener(IPAddress listenIPAddress, int listenPort, IPAddress forwardIPAddress, int forwardPort, SecretKey key) : base(listenIPAddress, listenPort, forwardIPAddress, forwardPort) { _key = key; }
public override void Write() { using (StreamWriter keyFile = new StreamWriter(Environment.CurrentDirectory + Constants.File.Path.SECRET_KEY + FileName)) { keyFile.WriteLine(Constants.START); keyFile.WriteLine(); keyFile.WriteLine(Constants.DESCRIPTION); keyFile.WriteLine(Constants.TAB + Constants.DESCRIPTION_SECRET_KEY); keyFile.WriteLine(); keyFile.WriteLine(Constants.METHOD); foreach (var m in Methods) { keyFile.WriteLine(Constants.TAB + m); // "SHA-1" } keyFile.WriteLine(); keyFile.WriteLine(Constants.KEY_LENGTH); foreach (var m in KeyLength) { keyFile.WriteLine(Constants.TAB + m); // "SHA-1" } keyFile.WriteLine(); keyFile.WriteLine(Constants.SECRET_KEY); for (int i = 0; i < GetNumberOfLines(SecretKey.Length); i++) { if ((SecretKey.Length - i * Constants.ROW__CHARACTER_COUNT) < Constants.ROW__CHARACTER_COUNT) { keyFile.WriteLine(Constants.TAB + SecretKey.Substring(i * Constants.ROW__CHARACTER_COUNT, (SecretKey.Length - i * Constants.ROW__CHARACTER_COUNT))); } else { keyFile.WriteLine(Constants.TAB + SecretKey.Substring(i * Constants.ROW__CHARACTER_COUNT, Constants.ROW__CHARACTER_COUNT)); } } keyFile.WriteLine(); keyFile.WriteLine(Constants.INIT_VECTOR); for (int i = 0; i < GetNumberOfLines(InitializationVector.Length); i++) { if ((InitializationVector.Length - i * Constants.ROW__CHARACTER_COUNT) < Constants.ROW__CHARACTER_COUNT) { keyFile.WriteLine(Constants.TAB + InitializationVector.Substring( i * Constants.ROW__CHARACTER_COUNT, (InitializationVector.Length - i * Constants.ROW__CHARACTER_COUNT))); } else { keyFile.WriteLine(Constants.TAB + InitializationVector.Substring(i * Constants.ROW__CHARACTER_COUNT, Constants.ROW__CHARACTER_COUNT)); } } keyFile.WriteLine(); keyFile.WriteLine(Constants.END); } }
public TransfersConsumer(CryptoNote.Currency currency, INodeOriginal node, Logging.ILogger logger, SecretKey viewSecret) { this.m_node = new CryptoNote.INodeOriginal(node); this.m_viewSecret = new Crypto.SecretKey(viewSecret); //C++ TO C# CONVERTER TODO TASK: The following line could not be converted: this.m_currency = new CryptoNote.Currency(currency); this.m_logger = new Logging.LoggerRef(logger, "TransfersConsumer"); updateSyncStart(); }
private static void BFVPerformanceTest(SEALContext context) { Stopwatch timer; Utilities.PrintParameters(context); Console.WriteLine(); bool hasZLIB = Serialization.IsSupportedComprMode(ComprModeType.ZLIB); bool hasZSTD = Serialization.IsSupportedComprMode(ComprModeType.ZSTD); using EncryptionParameters parms = context.FirstContextData.Parms; using Modulus plainModulus = parms.PlainModulus; ulong polyModulusDegree = parms.PolyModulusDegree; Console.Write("Generating secret/public keys: "); using KeyGenerator keygen = new KeyGenerator(context); Console.WriteLine("Done"); using SecretKey secretKey = keygen.SecretKey; keygen.CreatePublicKey(out PublicKey publicKey); Func <RelinKeys> GetRelinKeys = () => { if (context.UsingKeyswitching) { /* * Generate relinearization keys. */ Console.Write("Generating relinearization keys: "); timer = Stopwatch.StartNew(); keygen.CreateRelinKeys(out RelinKeys relinKeys); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); return(relinKeys); } else { return(null); } }; Func <GaloisKeys> GetGaloisKeys = () => { if (context.UsingKeyswitching) { if (!context.KeyContextData.Qualifiers.UsingBatching) { Console.WriteLine("Given encryption parameters do not support batching."); return(null); } /* * Generate Galois keys. In larger examples the Galois keys can use a lot of * memory, which can be a problem in constrained systems. The user should * try some of the larger runs of the test and observe their effect on the * memory pool allocation size. The key generation can also take a long time, * as can be observed from the print-out. */ Console.Write($"Generating Galois keys: "); timer = Stopwatch.StartNew(); keygen.CreateGaloisKeys(out GaloisKeys galoisKeys); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); return(galoisKeys); } else { return(null); } }; using RelinKeys relinKeys = GetRelinKeys(); using GaloisKeys galKeys = GetGaloisKeys(); using Encryptor encryptor = new Encryptor(context, publicKey); using Decryptor decryptor = new Decryptor(context, secretKey); using Evaluator evaluator = new Evaluator(context); using BatchEncoder batchEncoder = new BatchEncoder(context); /* * These will hold the total times used by each operation. */ Stopwatch timeBatchSum = new Stopwatch(); Stopwatch timeUnbatchSum = new Stopwatch(); Stopwatch timeEncryptSum = new Stopwatch(); Stopwatch timeDecryptSum = new Stopwatch(); Stopwatch timeAddSum = new Stopwatch(); Stopwatch timeMultiplySum = new Stopwatch(); Stopwatch timeMultiplyPlainSum = new Stopwatch(); Stopwatch timeSquareSum = new Stopwatch(); Stopwatch timeRelinearizeSum = new Stopwatch(); Stopwatch timeRotateRowsOneStepSum = new Stopwatch(); Stopwatch timeRotateRowsRandomSum = new Stopwatch(); Stopwatch timeRotateColumnsSum = new Stopwatch(); Stopwatch timeSerializeSum = new Stopwatch(); Stopwatch timeSerializeZLIBSum = new Stopwatch(); Stopwatch timeSerializeZSTDSum = new Stopwatch(); /* * How many times to run the test? */ int count = 10; /* * Populate a vector of values to batch. */ ulong slotCount = batchEncoder.SlotCount; ulong[] podValues = new ulong[slotCount]; Random rnd = new Random(); for (ulong i = 0; i < batchEncoder.SlotCount; i++) { podValues[i] = plainModulus.Reduce((ulong)rnd.Next()); } Console.Write("Running tests "); for (int i = 0; i < count; i++) { /* * [Batching] * There is nothing unusual here. We batch our random plaintext matrix * into the polynomial. Note how the plaintext we create is of the exactly * right size so unnecessary reallocations are avoided. */ using Plaintext plain = new Plaintext(parms.PolyModulusDegree, 0); timeBatchSum.Start(); batchEncoder.Encode(podValues, plain); timeBatchSum.Stop(); /* * [Unbatching] * We unbatch what we just batched. */ List <ulong> podList = new List <ulong>((int)slotCount); timeUnbatchSum.Start(); batchEncoder.Decode(plain, podList); timeUnbatchSum.Stop(); if (!podList.SequenceEqual(podValues)) { throw new InvalidOperationException("Batch/unbatch failed. Something is wrong."); } /* * [Encryption] * We make sure our ciphertext is already allocated and large enough * to hold the encryption with these encryption parameters. We encrypt * our random batched matrix here. */ using Ciphertext encrypted = new Ciphertext(context); timeEncryptSum.Start(); encryptor.Encrypt(plain, encrypted); timeEncryptSum.Stop(); /* * [Decryption] * We decrypt what we just encrypted. */ using Plaintext plain2 = new Plaintext(polyModulusDegree, 0); timeDecryptSum.Start(); decryptor.Decrypt(encrypted, plain2); timeDecryptSum.Stop(); if (!plain2.Equals(plain)) { throw new InvalidOperationException("Encrypt/decrypt failed. Something is wrong."); } /* * [Add] * We create two ciphertexts and perform a few additions with them. */ using Plaintext plain1 = new Plaintext(parms.PolyModulusDegree, 0); for (ulong j = 0; j < batchEncoder.SlotCount; j++) { podValues[j] = j; } batchEncoder.Encode(podValues, plain1); for (ulong j = 0; j < batchEncoder.SlotCount; j++) { podValues[j] = j + 1; } batchEncoder.Encode(podValues, plain2); using Ciphertext encrypted1 = new Ciphertext(context); encryptor.Encrypt(plain1, encrypted1); using Ciphertext encrypted2 = new Ciphertext(context); encryptor.Encrypt(plain2, encrypted2); timeAddSum.Start(); evaluator.AddInplace(encrypted1, encrypted1); evaluator.AddInplace(encrypted2, encrypted2); evaluator.AddInplace(encrypted1, encrypted2); timeAddSum.Stop(); /* * [Multiply] * We multiply two ciphertexts. Since the size of the result will be 3, * and will overwrite the first argument, we reserve first enough memory * to avoid reallocating during multiplication. */ encrypted1.Reserve(3); timeMultiplySum.Start(); evaluator.MultiplyInplace(encrypted1, encrypted2); timeMultiplySum.Stop(); /* * [Multiply Plain] * We multiply a ciphertext with a random plaintext. Recall that * MultiplyPlain does not change the size of the ciphertext so we use * encrypted2 here. */ timeMultiplyPlainSum.Start(); evaluator.MultiplyPlainInplace(encrypted2, plain); timeMultiplyPlainSum.Stop(); /* * [Square] * We continue to use encrypted2. Now we square it; this should be * faster than generic homomorphic multiplication. */ timeSquareSum.Start(); evaluator.SquareInplace(encrypted2); timeSquareSum.Stop(); if (context.UsingKeyswitching) { /* * [Relinearize] * Time to get back to encrypted1. We now relinearize it back * to size 2. Since the allocation is currently big enough to * contain a ciphertext of size 3, no costly reallocations are * needed in the process. */ timeRelinearizeSum.Start(); evaluator.RelinearizeInplace(encrypted1, relinKeys); timeRelinearizeSum.Stop(); /* * [Rotate Rows One Step] * We rotate matrix rows by one step left and measure the time. */ timeRotateRowsOneStepSum.Start(); evaluator.RotateRowsInplace(encrypted, 1, galKeys); evaluator.RotateRowsInplace(encrypted, -1, galKeys); timeRotateRowsOneStepSum.Stop(); /* * [Rotate Rows Random] * We rotate matrix rows by a random number of steps. This is much more * expensive than rotating by just one step. */ int rowSize = (int)batchEncoder.SlotCount / 2; // rowSize is always a power of 2. int randomRotation = rnd.Next() & (rowSize - 1); timeRotateRowsRandomSum.Start(); evaluator.RotateRowsInplace(encrypted, randomRotation, galKeys); timeRotateRowsRandomSum.Stop(); /* * [Rotate Columns] * Nothing surprising here. */ timeRotateColumnsSum.Start(); evaluator.RotateColumnsInplace(encrypted, galKeys); timeRotateColumnsSum.Stop(); } /* * [Serialize Ciphertext] */ using MemoryStream stream = new MemoryStream(); timeSerializeSum.Start(); encrypted.Save(stream, ComprModeType.None); timeSerializeSum.Stop(); if (hasZLIB) { /* * [Serialize Ciphertext (ZLIB)] */ timeSerializeZLIBSum.Start(); encrypted.Save(stream, ComprModeType.ZLIB); timeSerializeZLIBSum.Stop(); } if (hasZSTD) { /* * [Serialize Ciphertext (Zstandard)] */ timeSerializeZSTDSum.Start(); encrypted.Save(stream, ComprModeType.ZSTD); timeSerializeZSTDSum.Stop(); } /* * Print a dot to indicate progress. */ Console.Write("."); Console.Out.Flush(); } Console.WriteLine(" Done"); Console.WriteLine(); Console.Out.Flush(); int avgBatch = (int)(timeBatchSum.Elapsed.TotalMilliseconds * 1000 / count); int avgUnbatch = (int)(timeUnbatchSum.Elapsed.TotalMilliseconds * 1000 / count); int avgEncrypt = (int)(timeEncryptSum.Elapsed.TotalMilliseconds * 1000 / count); int avgDecrypt = (int)(timeDecryptSum.Elapsed.TotalMilliseconds * 1000 / count); int avgAdd = (int)(timeAddSum.Elapsed.TotalMilliseconds * 1000 / (3 * count)); int avgMultiply = (int)(timeMultiplySum.Elapsed.TotalMilliseconds * 1000 / count); int avgMultiplyPlain = (int)(timeMultiplyPlainSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSquare = (int)(timeSquareSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRelinearize = (int)(timeRelinearizeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRotateRowsOneStep = (int)(timeRotateRowsOneStepSum.Elapsed.TotalMilliseconds * 1000 / (2 * count)); int avgRotateRowsRandom = (int)(timeRotateRowsRandomSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRotateColumns = (int)(timeRotateColumnsSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeSum = (int)(timeSerializeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeZLIBSum = (int)(timeSerializeZLIBSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeZSTDSum = (int)(timeSerializeZSTDSum.Elapsed.TotalMilliseconds * 1000 / count); Console.WriteLine($"Average batch: {avgBatch} microseconds"); Console.WriteLine($"Average unbatch: {avgUnbatch} microseconds"); Console.WriteLine($"Average encrypt: {avgEncrypt} microseconds"); Console.WriteLine($"Average decrypt: {avgDecrypt} microseconds"); Console.WriteLine($"Average add: {avgAdd} microseconds"); Console.WriteLine($"Average multiply: {avgMultiply} microseconds"); Console.WriteLine($"Average multiply plain: {avgMultiplyPlain} microseconds"); Console.WriteLine($"Average square: {avgSquare} microseconds"); if (context.UsingKeyswitching) { Console.WriteLine($"Average relinearize: {avgRelinearize} microseconds"); Console.WriteLine($"Average rotate rows one step: {avgRotateRowsOneStep} microseconds"); Console.WriteLine($"Average rotate rows random: {avgRotateRowsRandom} microseconds"); Console.WriteLine($"Average rotate columns: {avgRotateColumns} microseconds"); } Console.WriteLine($"Average serialize ciphertext: {avgSerializeSum} microseconds"); if (hasZLIB) { Console.WriteLine( $"Average compressed (ZLIB) serialize ciphertext: {avgSerializeZLIBSum} microseconds"); } if (hasZSTD) { Console.WriteLine( $"Average compressed (Zstandard) serialize ciphertext: {avgSerializeZSTDSum} microseconds"); } Console.Out.Flush(); }
/// <summary>Compute the HMAC hash of the message using the key</summary> /// <param name="msg">the message to hash</param> /// <param name="key">the key to use</param> /// <returns>the computed hash</returns> public static byte[] ComputeHash(byte[] msg, SecretKey key) { return(CreatePassword(msg, key)); }
/// <exception cref="System.IO.IOException"/> public static string CreateDigest(byte[] password, string data) { SecretKey key = JobTokenSecretManager.CreateSecretKey(password); return(SecureShuffleUtils.HashFromString(data, key)); }
bool IKeyManagementDriver.LoadKeyBlob(int session, IntPtr pKey, int keyLen, KeyType keyType, KeyAttribute keyAttrib, out int hKey) { bool bRet = false; hKey = -1; try { SessionData ctx = ((SessionDriver)this.Hal.Session).GetSessionCtx(session); CryptokiObjectMgrDriver objMgr = (CryptokiObjectMgrDriver)Hal.CryptokiObjectMgr; byte[] keyData = new byte[keyLen]; Marshal.Copy(pKey, keyData, 0, keyLen); if (keyAttrib == KeyAttribute.Secret) { SecretKey key = new SecretKey(keyLen * 8, keyData); hKey = ctx.ObjectCtx.AddObject(CryptokiObjectType.Key, new KeyData(keyData, key)); bRet = true; } else { switch (keyType) { case KeyType.RSA: RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportCspBlob(keyData); hKey = ctx.ObjectCtx.AddObject(CryptokiObjectType.Key, new KeyData(rsa.ExportCspBlob(0 != (keyAttrib & KeyAttribute.Private)), rsa)); bRet = true; break; case KeyType.DSA: DSACryptoServiceProvider dsa = new DSACryptoServiceProvider(); dsa.ImportCspBlob(keyData); hKey = ctx.ObjectCtx.AddObject(CryptokiObjectType.Key, new KeyData(dsa.ExportCspBlob(0 != (keyAttrib & KeyAttribute.Private)), dsa)); bRet = true; break; case KeyType.ECDSA: { CngKeyBlobFormat fmt = (0 == (keyAttrib & KeyAttribute.Private)) ? CngKeyBlobFormat.EccPublicBlob : CngKeyBlobFormat.EccPrivateBlob; CngKey key = CngKey.Import(keyData, fmt); ECDsaCng ec = new ECDsaCng(key); hKey = ctx.ObjectCtx.AddObject(CryptokiObjectType.Key, new KeyData(ec.Key.Export(fmt), ec)); bRet = true; } break; case KeyType.DH: { CngKeyBlobFormat fmt = (0 == (keyAttrib & KeyAttribute.Private)) ? CngKeyBlobFormat.EccPublicBlob : CngKeyBlobFormat.EccPrivateBlob; CngKey key = CngKey.Import(keyData, fmt); ECDiffieHellmanCng ecdh = new ECDiffieHellmanCng(key); hKey = ctx.ObjectCtx.AddObject(CryptokiObjectType.Key, new KeyData(ecdh.Key.Export(fmt), ecdh)); bRet = true; } break; } } } catch { return(false); } return(bRet); }
bool IKeyManagementDriver.DeriveKey(int session, int alg, IntPtr pParam, int paramLen, int hBaseKey, out int hKey) { hKey = -1; try { SessionData ctx = ((SessionDriver)this.Hal.Session).GetSessionCtx(session); KeyData kd = ctx.ObjectCtx.GetObject(hBaseKey).Data as KeyData; if (kd == null) { return(false); } switch ((AlgorithmType)alg) { case AlgorithmType.ECDH1_DERIVE: ECDH_Params ecdh = new ECDH_Params(pParam, paramLen); ECDiffieHellmanCng ec = kd.KeyCsp as ECDiffieHellmanCng; ECDiffieHellmanCng cng = new ECDiffieHellmanCng(ec.Key); byte[] pubData = new byte[ecdh.PublicData.Length + 8]; pubData[0] = (byte)'E'; pubData[1] = (byte)'C'; pubData[2] = (byte)'K'; switch (ec.KeySize) { case 521: pubData[3] = (byte)'5'; pubData[4] = (byte)((521 + 7) / 8); break; case 384: pubData[3] = (byte)'3'; pubData[4] = (byte)((384 + 7) / 8); break; case 256: pubData[3] = (byte)'1'; pubData[4] = (byte)((256 + 7) / 8); break; } pubData[5] = 0; pubData[6] = 0; pubData[7] = 0; Array.Copy(ecdh.PublicData, 0, pubData, 8, ecdh.PublicData.Length); //CngKey otherPublicKey = CngKey.Import(pubData, CngKeyBlobFormat.EccPublicBlob); ECDiffieHellmanPublicKey otherPublicKey = ECDiffieHellmanCngPublicKey.FromByteArray(pubData, CngKeyBlobFormat.EccPublicBlob); //byte[] otherKeyData = otherPublicKey.Export(CngKeyBlobFormat.EccPublicBlob); //Debug.Print(otherKeyData[0].ToString()); switch (ecdh.kdf) { case AlgorithmType.NULL_KEY_DERIVATION: cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; cng.HashAlgorithm = CngAlgorithm.Sha1; break; case AlgorithmType.SHA1_KEY_DERIVATION: cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; cng.HashAlgorithm = CngAlgorithm.Sha1; break; case AlgorithmType.SHA256_KEY_DERIVATION: cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; cng.HashAlgorithm = CngAlgorithm.Sha256; break; case AlgorithmType.SHA512_KEY_DERIVATION: cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; cng.HashAlgorithm = CngAlgorithm.Sha512; break; case AlgorithmType.MD5_KEY_DERIVATION: cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; cng.HashAlgorithm = CngAlgorithm.MD5; break; case AlgorithmType.SHA224_HMAC: case AlgorithmType.TLS_MASTER_KEY_DERIVE_DH: default: return(false); } cng.SecretPrepend = null; cng.SecretAppend = null; byte[] keyData = cng.DeriveKeyMaterial(otherPublicKey); SecretKey key = new SecretKey(keyData.Length * 8, keyData); hKey = ctx.ObjectCtx.AddObject(CryptokiObjectType.Key, new KeyData(keyData, key)); break; default: return(false); } } catch { return(false); } return(true); }
static async Task RunAsync() { // Update port # in the following line. client.BaseAddress = new Uri("http://localhost/"); //client.BaseAddress = new Uri("https://sealserver20200623225403.azurewebsites.net/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/octet-stream")); UriBuilder builder = new UriBuilder(); builder.Port = 50755; builder.Path = "sealoperation"; using EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); ulong polyModulusDegree = 4096; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree); parms.PlainModulus = new Modulus(4096); using SEALContext context = new SEALContext(parms); using Evaluator evaluator = new Evaluator(context); using KeyGenerator keygen = new KeyGenerator(context); using PublicKey publicKey = keygen.PublicKey; using SecretKey secretKey = keygen.SecretKey; using Encryptor encryptor = new Encryptor(context, publicKey); using Decryptor decryptor = new Decryptor(context, secretKey); //BigInteger bint = BigInteger.Parse("97391909619002370737223511047161666878854921822310726371156754097341907215981"); BigInteger bint = BigInteger.Parse("998745113"); //int xVal = 625; //int degree = 10; //int coeff = 25; // These are good starting points for small numbers < 100mil /* * int tConst = 121; * int xVal = 10; * int degree = 2; * int coeff = 3; */ int tConst = 1210; int xVal = 25; int degree = 4; int coeff = 3; // Candidate first result from initial polynomial List <int> terms; BigInteger res = createBigIntFromPoly(degree, coeff, xVal, tConst, out terms); // compare res to target BigInteger, if way smaller, then create a new // result after increasing any of the polynomial values while (BigInteger.Compare(res, bint) < 0) // res is less than bint { BigInteger halfVal = BigInteger.Divide(bint, new BigInteger(2)); BigInteger onePercent = BigInteger.Divide(bint, new BigInteger(100)); BigInteger tenPercent = BigInteger.Multiply(onePercent, new BigInteger(10)); //BigInteger quarterVal = BigInteger.Divide(bint, new BigInteger(4)); if (BigInteger.Compare(halfVal, res) > 0) { //coeff += 1; int len = halfVal.ToString().Length; int len2 = res.ToString().Length; if (len == len2) { coeff *= 2; } else { degree += 2; } res = createBigIntFromPoly(degree, coeff, xVal, tConst, out terms); } else { BigInteger difference = BigInteger.Subtract(bint, res); if (BigInteger.Compare(tenPercent, difference) > 0) { tConst += 1111; } else { coeff += 1; } res = createBigIntFromPoly(degree, coeff, xVal, tConst, out terms); } //Console.WriteLine(res.ToString()); Console.WriteLine("..."); } // Res is now equal or greater to bint tConst = tConst - (int)BigInteger.Subtract(res, bint); // Now check the polynomial BigInteger testPoly = createBigIntFromPoly(degree, coeff, xVal, tConst, out terms); Console.WriteLine("For Big Integer {0}", bint.ToString()); foreach (int term in terms) { Console.WriteLine("Polynomial term is {0}x^{1}", coeff, term); } Console.WriteLine("Final term is constant {0} with x={1}", tConst, xVal); byte[] bytespan = bint.ToByteArray(); byte[] newspan = new byte[bytespan.Length]; newspan[0] = bytespan[0]; BigInteger binttemp = new BigInteger(bytespan); // Pick an 'x' value for the polynomial that is big enough to represent the upper 10 digits of the value BigInteger bint2 = BigInteger.Parse("7983012132846067729184195556448685457666384473549591845215215701504271855338012801306119587019479688581971723759499902125851173348207536911525267617909811"); BigInteger bintres = bint * bint2; using Plaintext bPlainB = new Plaintext(bint.ToString()); int x = 9; Console.WriteLine("Plain x value to set"); Console.WriteLine(x.ToString()); using Plaintext xPlainX = new Plaintext(Convert.ToString(x, 16)); Console.WriteLine("Hex value being set"); Console.WriteLine(xPlainX.ToString()); using Ciphertext xEncrypted = new Ciphertext(); Console.WriteLine("Encrypt xPlain to xEncrypted."); encryptor.Encrypt(xPlainX, xEncrypted); int y = 5; Console.WriteLine("Plain y value to set"); Console.WriteLine(y.ToString()); using Plaintext xPlainY = new Plaintext(Convert.ToString(y, 16)); Console.WriteLine("Hex y value being set"); Console.WriteLine(xPlainY.ToString()); using Ciphertext yEncrypted = new Ciphertext(); encryptor.Encrypt(xPlainY, yEncrypted); FHEParams fHEParams = new FHEParams(); fHEParams.param1 = xEncrypted; fHEParams.param2 = yEncrypted; fHEParams.result = new Ciphertext(); // DEBUG ONLY Ciphertext mAnswer = new Ciphertext(); evaluator.Multiply(fHEParams.param1, fHEParams.param2, mAnswer); evaluator.Add(fHEParams.param1, fHEParams.param2, fHEParams.result); string expAnswer = SerializeSEAL(fHEParams.result); using Plaintext xDecrypted2 = new Plaintext(); decryptor.Decrypt(mAnswer, xDecrypted2); Console.WriteLine(xDecrypted2.ToString()); decryptor.Decrypt(fHEParams.result, xDecrypted2); string answer = xDecrypted2.ToString(); int num = 0; Int32.TryParse(answer, System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture, out num); Console.WriteLine("Local answer"); Console.WriteLine(answer); Console.WriteLine(num.ToString()); // END DEBUG //fHEParams.param1. fHEParams.operation = "add"; SEALTransport transport = new SEALTransport(); transport.ContextParams = SerializeSEAL(parms); transport.FHEParam1 = SerializeSEAL(fHEParams.param1); // Console.WriteLine(transport.FHEParam1); transport.FHEParam2 = SerializeSEAL(fHEParams.param2); transport.FHEResult = SerializeSEAL(fHEParams.result); transport.Operation = fHEParams.operation; try { // Get the parameters, SEALTransport response = await PostFHEResultAsync(builder.Uri.AbsoluteUri, transport); Ciphertext result = new Ciphertext(); byte[] fp1 = System.Convert.FromBase64String(response.FHEResult); string recAnswer = response.FHEResult; if (expAnswer == recAnswer) { Console.WriteLine("Expected answer matches received answer"); } MemoryStream mst = new MemoryStream(fp1); result.Load(context, mst); Plaintext xDecrypted3 = new Plaintext(); decryptor.Decrypt(result, xDecrypted3); answer = xDecrypted3.ToString(); Console.WriteLine(answer); Console.WriteLine("Remote Decimal answer"); Int32.TryParse(answer, System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture, out num); Console.WriteLine(num.ToString()); } catch (Exception e) { Console.WriteLine(e.Message); } Console.ReadLine(); }
public void EncryptZeroTest() { { SEALContext context = GlobalContext.BFVContext; KeyGenerator keyGen = new KeyGenerator(context); PublicKey publicKey = keyGen.PublicKey; SecretKey secretKey = keyGen.SecretKey; Encryptor encryptor = new Encryptor(context, publicKey, secretKey); Decryptor decryptor = new Decryptor(context, secretKey); Assert.IsNotNull(encryptor); Assert.IsNotNull(decryptor); Ciphertext cipher = new Ciphertext(); Plaintext plain = new Plaintext(); ParmsId nextParms = context.FirstContextData.NextContextData.ParmsId; { encryptor.EncryptZero(cipher); Assert.IsFalse(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); decryptor.Decrypt(cipher, plain); Assert.IsTrue(plain.IsZero); encryptor.EncryptZero(nextParms, cipher); Assert.IsFalse(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); Assert.AreEqual(cipher.ParmsId, nextParms); decryptor.Decrypt(cipher, plain); Assert.IsTrue(plain.IsZero); } { encryptor.EncryptZeroSymmetric(cipher); Assert.IsFalse(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); decryptor.Decrypt(cipher, plain); Assert.IsTrue(plain.IsZero); encryptor.EncryptZeroSymmetric(nextParms, cipher); Assert.IsFalse(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); Assert.AreEqual(cipher.ParmsId, nextParms); decryptor.Decrypt(cipher, plain); Assert.IsTrue(plain.IsZero); } using (MemoryStream stream = new MemoryStream()) { encryptor.EncryptZeroSymmetricSave(stream); stream.Seek(0, SeekOrigin.Begin); cipher.Load(context, stream); Assert.IsFalse(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); decryptor.Decrypt(cipher, plain); Assert.IsTrue(plain.IsZero); } using (MemoryStream stream = new MemoryStream()) { encryptor.EncryptZeroSymmetricSave(nextParms, stream); stream.Seek(0, SeekOrigin.Begin); cipher.Load(context, stream); Assert.IsFalse(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); Assert.AreEqual(cipher.ParmsId, nextParms); decryptor.Decrypt(cipher, plain); Assert.IsTrue(plain.IsZero); } } { SEALContext context = GlobalContext.CKKSContext; KeyGenerator keyGen = new KeyGenerator(context); PublicKey publicKey = keyGen.PublicKey; SecretKey secretKey = keyGen.SecretKey; Encryptor encryptor = new Encryptor(context, publicKey, secretKey); Decryptor decryptor = new Decryptor(context, secretKey); CKKSEncoder encoder = new CKKSEncoder(context); Assert.IsNotNull(encryptor); Assert.IsNotNull(decryptor); Ciphertext cipher = new Ciphertext(); Plaintext plain = new Plaintext(); ParmsId nextParms = context.FirstContextData.NextContextData.ParmsId; List <Complex> res = new List <Complex>(); { encryptor.EncryptZero(cipher); Assert.IsTrue(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); cipher.Scale = Math.Pow(2.0, 30); decryptor.Decrypt(cipher, plain); encoder.Decode(plain, res); foreach (Complex val in res) { Assert.AreEqual(val.Real, 0.0, 0.01); Assert.AreEqual(val.Imaginary, 0.0, 0.01); } encryptor.EncryptZero(nextParms, cipher); Assert.IsTrue(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); cipher.Scale = Math.Pow(2.0, 30); Assert.AreEqual(cipher.ParmsId, nextParms); decryptor.Decrypt(cipher, plain); Assert.AreEqual(plain.ParmsId, nextParms); encoder.Decode(plain, res); foreach (Complex val in res) { Assert.AreEqual(val.Real, 0.0, 0.01); Assert.AreEqual(val.Imaginary, 0.0, 0.01); } } { encryptor.EncryptZeroSymmetric(cipher); Assert.IsTrue(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); cipher.Scale = Math.Pow(2.0, 30); decryptor.Decrypt(cipher, plain); encoder.Decode(plain, res); foreach (Complex val in res) { Assert.AreEqual(val.Real, 0.0, 0.01); Assert.AreEqual(val.Imaginary, 0.0, 0.01); } encryptor.EncryptZeroSymmetric(nextParms, cipher); Assert.IsTrue(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); cipher.Scale = Math.Pow(2.0, 30); Assert.AreEqual(cipher.ParmsId, nextParms); decryptor.Decrypt(cipher, plain); Assert.AreEqual(plain.ParmsId, nextParms); encoder.Decode(plain, res); foreach (Complex val in res) { Assert.AreEqual(val.Real, 0.0, 0.01); Assert.AreEqual(val.Imaginary, 0.0, 0.01); } } using (MemoryStream stream = new MemoryStream()) { encryptor.EncryptZeroSymmetricSave(stream); stream.Seek(0, SeekOrigin.Begin); cipher.Load(context, stream); Assert.IsTrue(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); cipher.Scale = Math.Pow(2.0, 30); decryptor.Decrypt(cipher, plain); encoder.Decode(plain, res); foreach (Complex val in res) { Assert.AreEqual(val.Real, 0.0, 0.01); Assert.AreEqual(val.Imaginary, 0.0, 0.01); } } using (MemoryStream stream = new MemoryStream()) { encryptor.EncryptZeroSymmetricSave(nextParms, stream); stream.Seek(0, SeekOrigin.Begin); cipher.Load(context, stream); Assert.IsTrue(cipher.IsNTTForm); Assert.IsFalse(cipher.IsTransparent); Assert.AreEqual(cipher.Scale, 1.0, double.Epsilon); cipher.Scale = Math.Pow(2.0, 30); Assert.AreEqual(cipher.ParmsId, nextParms); decryptor.Decrypt(cipher, plain); Assert.AreEqual(plain.ParmsId, nextParms); encoder.Decode(plain, res); foreach (Complex val in res) { Assert.AreEqual(val.Real, 0.0, 0.01); Assert.AreEqual(val.Imaginary, 0.0, 0.01); } } } }
/// <summary> /// 获取学校的详细信息(用于登录或其他) /// </summary> /// <param name="school">School Object</param> /// <param name="secretKey">SecretKey Object</param> /// <returns>SchoolDetails</returns> public Task <SchoolDetails> GetSchoolDetailsAsync(School school, SecretKey secretKey) { return(GetSchoolDetailsAsync(school.Id, secretKey.Chk)); }
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: //ORIGINAL LINE: virtual bool getTransactionSecretKey(SecretKey& key) const override public override bool GetTransactionSecretKey(SecretKey key) { return(false); }
/* * In `1_BFV_Basics.cs' we showed how to perform a very simple computation using the * BFV scheme. The computation was performed modulo the PlainModulus parameter, and * utilized only one coefficient from a BFV plaintext polynomial. This approach has * two notable problems: * * (1) Practical applications typically use integer or real number arithmetic, * not modular arithmetic; * (2) We used only one coefficient of the plaintext polynomial. This is really * wasteful, as the plaintext polynomial is large and will in any case be * encrypted in its entirety. * * For (1), one may ask why not just increase the PlainModulus parameter until no * overflow occurs, and the computations behave as in integer arithmetic. The problem * is that increasing PlainModulus increases noise budget consumption, and decreases * the initial noise budget too. * * In these examples we will discuss other ways of laying out data into plaintext * elements (encoding) that allow more computations without data type overflow, and * can allow the full plaintext polynomial to be utilized. */ private static void ExampleBatchEncoder() { Utilities.PrintExampleBanner("Example: Encoders / Batch Encoder"); /* * [BatchEncoder] (For BFV scheme only) * * Let N denote the PolyModulusDegree and T denote the PlainModulus. Batching * allows the BFV plaintext polynomials to be viewed as 2-by-(N/2) matrices, with * each element an integer modulo T. In the matrix view, encrypted operations act * element-wise on encrypted matrices, allowing the user to obtain speeds-ups of * several orders of magnitude in fully vectorizable computations. Thus, in all * but the simplest computations, batching should be the preferred method to use * with BFV, and when used properly will result in implementations outperforming * anything done without batching. */ using EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); ulong polyModulusDegree = 8192; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree); /* * To enable batching, we need to set the plain_modulus to be a prime number * congruent to 1 modulo 2*PolyModulusDegree. Microsoft SEAL provides a helper * method for finding such a prime. In this example we create a 20-bit prime * that supports batching. */ parms.PlainModulus = PlainModulus.Batching(polyModulusDegree, 20); using SEALContext context = new SEALContext(parms); Utilities.PrintParameters(context); Console.WriteLine(); /* * We can verify that batching is indeed enabled by looking at the encryption * parameter qualifiers created by SEALContext. */ using var qualifiers = context.FirstContextData.Qualifiers; Console.WriteLine($"Batching enabled: {qualifiers.UsingBatching}"); using KeyGenerator keygen = new KeyGenerator(context); using SecretKey secretKey = keygen.SecretKey; keygen.CreatePublicKey(out PublicKey publicKey); keygen.CreateRelinKeys(out RelinKeys relinKeys); using Encryptor encryptor = new Encryptor(context, publicKey); using Evaluator evaluator = new Evaluator(context); using Decryptor decryptor = new Decryptor(context, secretKey); /* * Batching is done through an instance of the BatchEncoder class. */ using BatchEncoder batchEncoder = new BatchEncoder(context); /* * The total number of batching `slots' equals the PolyModulusDegree, N, and * these slots are organized into 2-by-(N/2) matrices that can be encrypted and * computed on. Each slot contains an integer modulo PlainModulus. */ ulong slotCount = batchEncoder.SlotCount; ulong rowSize = slotCount / 2; Console.WriteLine($"Plaintext matrix row size: {rowSize}"); /* * The matrix plaintext is simply given to BatchEncoder as a flattened vector * of numbers. The first `rowSize' many numbers form the first row, and the * rest form the second row. Here we create the following matrix: * * [ 0, 1, 2, 3, 0, 0, ..., 0 ] * [ 4, 5, 6, 7, 0, 0, ..., 0 ] */ ulong[] podMatrix = new ulong[slotCount]; podMatrix[0] = 0; podMatrix[1] = 1; podMatrix[2] = 2; podMatrix[3] = 3; podMatrix[rowSize] = 4; podMatrix[rowSize + 1] = 5; podMatrix[rowSize + 2] = 6; podMatrix[rowSize + 3] = 7; Console.WriteLine("Input plaintext matrix:"); Utilities.PrintMatrix(podMatrix, (int)rowSize); /* * First we use BatchEncoder to encode the matrix into a plaintext polynomial. */ using Plaintext plainMatrix = new Plaintext(); Utilities.PrintLine(); Console.WriteLine("Encode plaintext matrix:"); batchEncoder.Encode(podMatrix, plainMatrix); /* * We can instantly decode to verify correctness of the encoding. Note that no * encryption or decryption has yet taken place. */ List <ulong> podResult = new List <ulong>(); Console.WriteLine(" + Decode plaintext matrix ...... Correct."); batchEncoder.Decode(plainMatrix, podResult); Utilities.PrintMatrix(podResult, (int)rowSize); /* * Next we encrypt the encoded plaintext. */ using Ciphertext encryptedMatrix = new Ciphertext(); Utilities.PrintLine(); Console.WriteLine("Encrypt plainMatrix to encryptedMatrix."); encryptor.Encrypt(plainMatrix, encryptedMatrix); Console.WriteLine(" + Noise budget in encryptedMatrix: {0} bits", decryptor.InvariantNoiseBudget(encryptedMatrix)); /* * Operating on the ciphertext results in homomorphic operations being performed * simultaneously in all 8192 slots (matrix elements). To illustrate this, we * form another plaintext matrix * * [ 1, 2, 1, 2, 1, 2, ..., 2 ] * [ 1, 2, 1, 2, 1, 2, ..., 2 ] * * and encode it into a plaintext. */ ulong[] podMatrix2 = new ulong[slotCount]; for (ulong i = 0; i < slotCount; i++) { podMatrix2[i] = (i & 1) + 1; } using Plaintext plainMatrix2 = new Plaintext(); batchEncoder.Encode(podMatrix2, plainMatrix2); Console.WriteLine(); Console.WriteLine("Second input plaintext matrix:"); Utilities.PrintMatrix(podMatrix2, (int)rowSize); /* * We now add the second (plaintext) matrix to the encrypted matrix, and square * the sum. */ Utilities.PrintLine(); Console.WriteLine("Sum, square, and relinearize."); evaluator.AddPlainInplace(encryptedMatrix, plainMatrix2); evaluator.SquareInplace(encryptedMatrix); evaluator.RelinearizeInplace(encryptedMatrix, relinKeys); /* * How much noise budget do we have left? */ Console.WriteLine(" + Noise budget in result: {0} bits", decryptor.InvariantNoiseBudget(encryptedMatrix)); /* * We decrypt and decompose the plaintext to recover the result as a matrix. */ using Plaintext plainResult = new Plaintext(); Utilities.PrintLine(); Console.WriteLine("Decrypt and decode result."); decryptor.Decrypt(encryptedMatrix, plainResult); batchEncoder.Decode(plainResult, podResult); Console.WriteLine(" + Result plaintext matrix ...... Correct."); Utilities.PrintMatrix(podResult, (int)rowSize); /* * Batching allows us to efficiently use the full plaintext polynomial when the * desired encrypted computation is highly parallelizable. However, it has not * solved the other problem mentioned in the beginning of this file: each slot * holds only an integer modulo plain_modulus, and unless plain_modulus is very * large, we can quickly encounter data type overflow and get unexpected results * when integer computations are desired. Note that overflow cannot be detected * in encrypted form. The CKKS scheme (and the CKKSEncoder) addresses the data * type overflow issue, but at the cost of yielding only approximate results. */ }
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: //ORIGINAL LINE: virtual bool findOutputsToAccount(const AccountPublicAddress& addr, const SecretKey& viewSecretKey, ClassicVector<uint>& outs, ulong& outputAmount) const override public override bool FindOutputsToAccount(AccountPublicAddress addr, SecretKey viewSecretKey, List <uint> outs, ulong outputAmount) { return(global::CryptoNote.findOutputsToAccount(m_txPrefix, addr, viewSecretKey, outs, outputAmount)); }
bool IKeyManagementDriver.GetPublicKeyData(int session, int hKey, IntPtr data, ref int dataLen) { try { SessionData ctx = ((SessionDriver)this.Hal.Session).GetSessionCtx(session); KeyData kd = ctx.ObjectCtx.GetObject(hKey).Data as KeyData; if (kd == null) { return(false); } if (kd.KeyCsp is RSACryptoServiceProvider) { RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)kd.KeyCsp; byte [] key = rsa.ExportCspBlob(false); if (dataLen < key.Length) { return(false); } Marshal.Copy(key, 0, data, key.Length); dataLen = key.Length; } else if (kd.KeyCsp is DSACryptoServiceProvider) { DSACryptoServiceProvider dsa = (DSACryptoServiceProvider)kd.KeyCsp; byte[] key = dsa.ExportCspBlob(false); if (dataLen < key.Length) { return(false); } Marshal.Copy(key, 0, data, key.Length); dataLen = key.Length; } else if (kd.KeyCsp is ECDsaCng) { ECDsaCng cng = (ECDsaCng)kd.KeyCsp; byte[] key = cng.Key.Export(CngKeyBlobFormat.EccPublicBlob); if (dataLen < (key.Length - 8)) { return(false); } Marshal.Copy(key, 8, data, key.Length - 8); dataLen = key.Length - 8; } else if (kd.KeyCsp is ECDiffieHellmanCng) { ECDiffieHellmanCng cng = (ECDiffieHellmanCng)kd.KeyCsp; byte[] key = cng.Key.Export(CngKeyBlobFormat.EccPublicBlob); if (dataLen < (key.Length - 8)) { return(false); } Marshal.Copy(key, 8, data, key.Length - 8); dataLen = key.Length - 8; } else if (kd.KeyCsp is SecretKey) { SecretKey key = (SecretKey)kd.KeyCsp; if (dataLen < key.Data.Length) { return(false); } Marshal.Copy(key.Data, 0, data, key.Data.Length); dataLen = key.Data.Length; } else if (kd.KeyCsp is AesCryptoServiceProvider) { AesCryptoServiceProvider aes = (AesCryptoServiceProvider)kd.KeyCsp; if (dataLen < aes.Key.Length) { return(false); } Marshal.Copy(aes.Key, 0, data, aes.Key.Length); dataLen = aes.Key.Length; } else { return(false); } } catch { return(false); } return(true); }
private static void ExampleLevels() { Utilities.PrintExampleBanner("Example: Levels"); /* * In this examples we describe the concept of `levels' in BFV and CKKS and the * related objects that represent them in Microsoft SEAL. * * In Microsoft SEAL a set of encryption parameters (excluding the random number * generator) is identified uniquely by a SHA-3 hash of the parameters. This * hash is called the `ParmsId' and can be easily accessed and printed at any * time. The hash will change as soon as any of the parameters is changed. * * When a SEALContext is created from a given EncryptionParameters instance, * Microsoft SEAL automatically creates a so-called `modulus switching chain', * which is a chain of other encryption parameters derived from the original set. * The parameters in the modulus switching chain are the same as the original * parameters with the exception that size of the coefficient modulus is * decreasing going down the chain. More precisely, each parameter set in the * chain attempts to remove the last coefficient modulus prime from the * previous set; this continues until the parameter set is no longer valid * (e.g., PlainModulus is larger than the remaining CoeffModulus). It is easy * to walk through the chain and access all the parameter sets. Additionally, * each parameter set in the chain has a `chain index' that indicates its * position in the chain so that the last set has index 0. We say that a set * of encryption parameters, or an object carrying those encryption parameters, * is at a higher level in the chain than another set of parameters if its the * chain index is bigger, i.e., it is earlier in the chain. * * Each set of parameters in the chain involves unique pre-computations performed * when the SEALContext is created, and stored in a SEALContext.ContextData * object. The chain is basically a linked list of SEALContext.ContextData * objects, and can easily be accessed through the SEALContext at any time. Each * node can be identified by the ParmsId of its specific encryption parameters * (PolyModulusDegree remains the same but CoeffModulus varies). */ EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); ulong polyModulusDegree = 8192; parms.PolyModulusDegree = polyModulusDegree; /* * In this example we use a custom CoeffModulus, consisting of 5 primes of * sizes 50, 30, 30, 50, and 50 bits. Note that this is still OK according to * the explanation in `1_BFV_Basics.cs'. Indeed, * * CoeffModulus.MaxBitCount(polyModulusDegree) * * returns 218 (less than 50+30+30+50+50=210). * * Due to the modulus switching chain, the order of the 5 primes is significant. * The last prime has a special meaning and we call it the `special prime'. Thus, * the first parameter set in the modulus switching chain is the only one that * involves the special prime. All key objects, such as SecretKey, are created * at this highest level. All data objects, such as Ciphertext, can be only at * lower levels. The special modulus should be as large as the largest of the * other primes in the CoeffModulus, although this is not a strict requirement. * * special prime +---------+ | | v | CoeffModulus: { 50, 30, 30, 50, 50 } +---+ Level 4 (all keys; `key level') | | | CoeffModulus: { 50, 30, 30, 50 } +---+ Level 3 (highest `data level') | | | CoeffModulus: { 50, 30, 30 } +---+ Level 2 | | | CoeffModulus: { 50, 30 } +---+ Level 1 | | | CoeffModulus: { 50 } +---+ Level 0 (lowest level) */ parms.CoeffModulus = CoeffModulus.Create( polyModulusDegree, new int[] { 50, 30, 30, 50, 50 }); /* * In this example the PlainModulus does not play much of a role; we choose * some reasonable value. */ parms.PlainModulus = new SmallModulus(1 << 20); SEALContext context = new SEALContext(parms); Utilities.PrintParameters(context); /* * There are convenience method for accessing the SEALContext.ContextData for * some of the most important levels: * * SEALContext.KeyContextData: access to key level ContextData * SEALContext.FirstContextData: access to highest data level ContextData * SEALContext.LastContextData: access to lowest level ContextData * * We iterate over the chain and print the ParmsId for each set of parameters. */ Console.WriteLine(); Utilities.PrintLine(); Console.WriteLine("Print the modulus switching chain."); /* * First print the key level parameter information. */ SEALContext.ContextData contextData = context.KeyContextData; Console.WriteLine("----> Level (chain index): {0} ...... KeyContextData", contextData.ChainIndex); Console.WriteLine($" ParmsId: {contextData.ParmsId}"); Console.Write(" CoeffModulus primes: "); foreach (SmallModulus prime in contextData.Parms.CoeffModulus) { Console.Write($"{Utilities.ULongToString(prime.Value)} "); } Console.WriteLine(); Console.WriteLine("\\"); Console.Write(" \\--> "); /* * Next iterate over the remaining (data) levels. */ contextData = context.FirstContextData; while (null != contextData) { Console.Write($"Level (chain index): {contextData.ChainIndex}"); if (contextData.ParmsId.Equals(context.FirstParmsId)) { Console.WriteLine(" ...... FirstContextData"); } else if (contextData.ParmsId.Equals(context.LastParmsId)) { Console.WriteLine(" ...... LastContextData"); } else { Console.WriteLine(); } Console.WriteLine($" ParmsId: {contextData.ParmsId}"); Console.Write(" CoeffModulus primes: "); foreach (SmallModulus prime in contextData.Parms.CoeffModulus) { Console.Write($"{Utilities.ULongToString(prime.Value)} "); } Console.WriteLine(); Console.WriteLine("\\"); Console.Write(" \\--> "); /* * Step forward in the chain. */ contextData = contextData.NextContextData; } Console.WriteLine("End of chain reached"); Console.WriteLine(); /* * We create some keys and check that indeed they appear at the highest level. */ KeyGenerator keygen = new KeyGenerator(context); PublicKey publicKey = keygen.PublicKey; SecretKey secretKey = keygen.SecretKey; RelinKeys relinKeys = keygen.RelinKeys(); GaloisKeys galoisKeys = keygen.GaloisKeys(); Utilities.PrintLine(); Console.WriteLine("Print the parameter IDs of generated elements."); Console.WriteLine($" + publicKey: {publicKey.ParmsId}"); Console.WriteLine($" + secretKey: {secretKey.ParmsId}"); Console.WriteLine($" + relinKeys: {relinKeys.ParmsId}"); Console.WriteLine($" + galoisKeys: {galoisKeys.ParmsId}"); Encryptor encryptor = new Encryptor(context, publicKey); Evaluator evaluator = new Evaluator(context); Decryptor decryptor = new Decryptor(context, secretKey); /* * In the BFV scheme plaintexts do not carry a ParmsId, but ciphertexts do. Note * how the freshly encrypted ciphertext is at the highest data level. */ Plaintext plain = new Plaintext("1x^3 + 2x^2 + 3x^1 + 4"); Ciphertext encrypted = new Ciphertext(); encryptor.Encrypt(plain, encrypted); Console.WriteLine($" + plain: {plain.ParmsId} (not set in BFV)"); Console.WriteLine($" + encrypted: {encrypted.ParmsId}"); Console.WriteLine(); /* * `Modulus switching' is a technique of changing the ciphertext parameters down * in the chain. The function Evaluator.ModSwitchToNext always switches to the * next level down the chain, whereas Evaluator.ModSwitchTo switches to a parameter * set down the chain corresponding to a given ParmsId. However, it is impossible * to switch up in the chain. */ Utilities.PrintLine(); Console.WriteLine("Perform modulus switching on encrypted and print."); contextData = context.FirstContextData; Console.Write("----> "); while (null != contextData.NextContextData) { Console.WriteLine($"Level (chain index): {contextData.ChainIndex}"); Console.WriteLine($" ParmsId of encrypted: {contextData.ParmsId}"); Console.WriteLine(" Noise budget at this level: {0} bits", decryptor.InvariantNoiseBudget(encrypted)); Console.WriteLine("\\"); Console.Write(" \\--> "); evaluator.ModSwitchToNextInplace(encrypted); contextData = contextData.NextContextData; } Console.WriteLine($"Level (chain index): {contextData.ChainIndex}"); Console.WriteLine($" ParmsId of encrypted: {contextData.ParmsId}"); Console.WriteLine(" Noise budget at this level: {0} bits", decryptor.InvariantNoiseBudget(encrypted)); Console.WriteLine("\\"); Console.Write(" \\--> "); Console.WriteLine("End of chain reached"); Console.WriteLine(); /* * At this point it is hard to see any benefit in doing this: we lost a huge * amount of noise budget (i.e., computational power) at each switch and seemed * to get nothing in return. Decryption still works. */ Utilities.PrintLine(); Console.WriteLine("Decrypt still works after modulus switching."); decryptor.Decrypt(encrypted, plain); Console.WriteLine($" + Decryption of encrypted: {plain} ...... Correct."); Console.WriteLine(); /* * However, there is a hidden benefit: the size of the ciphertext depends * linearly on the number of primes in the coefficient modulus. Thus, if there * is no need or intention to perform any further computations on a given * ciphertext, we might as well switch it down to the smallest (last) set of * parameters in the chain before sending it back to the secret key holder for * decryption. * * Also the lost noise budget is actually not as issue at all, if we do things * right, as we will see below. * * First we recreate the original ciphertext and perform some computations. */ Console.WriteLine("Computation is more efficient with modulus switching."); Utilities.PrintLine(); Console.WriteLine("Compute the fourth power."); encryptor.Encrypt(plain, encrypted); Console.WriteLine(" + Noise budget before squaring: {0} bits", decryptor.InvariantNoiseBudget(encrypted)); evaluator.SquareInplace(encrypted); evaluator.RelinearizeInplace(encrypted, relinKeys); Console.WriteLine(" + Noise budget after squaring: {0} bits", decryptor.InvariantNoiseBudget(encrypted)); /* * From the print-out we see that the noise budget after these computations is * just slightly below the level we would have in a fresh ciphertext after one * modulus switch (135 bits). Surprisingly, in this case modulus switching has * no effect at all on the noise budget. */ evaluator.ModSwitchToNextInplace(encrypted); Console.WriteLine(" + Noise budget after modulus switching: {0} bits", decryptor.InvariantNoiseBudget(encrypted)); /* * This means that there is no harm at all in dropping some of the coefficient * modulus after doing enough computations. In some cases one might want to * switch to a lower level slightly earlier, actually sacrificing some of the * noise budget in the process, to gain computational performance from having * smaller parameters. We see from the print-out that the next modulus switch * should be done ideally when the noise budget is down to around 81 bits. */ evaluator.SquareInplace(encrypted); evaluator.RelinearizeInplace(encrypted, relinKeys); Console.WriteLine(" + Noise budget after squaring: {0} bits", decryptor.InvariantNoiseBudget(encrypted)); evaluator.ModSwitchToNextInplace(encrypted); Console.WriteLine(" + Noise budget after modulus switching: {0} bits", decryptor.InvariantNoiseBudget(encrypted)); /* * At this point the ciphertext still decrypts correctly, has very small size, * and the computation was as efficient as possible. Note that the decryptor * can be used to decrypt a ciphertext at any level in the modulus switching * chain. */ decryptor.Decrypt(encrypted, plain); Console.WriteLine(" + Decryption of fourth power (hexadecimal) ...... Correct."); Console.WriteLine($" {plain}"); Console.WriteLine(); /* * In BFV modulus switching is not necessary and in some cases the user might * not want to create the modulus switching chain, except for the highest two * levels. This can be done by passing a bool `false' to SEALContext constructor. */ context = new SEALContext(parms, expandModChain: false); /* * We can check that indeed the modulus switching chain has been created only * for the highest two levels (key level and highest data level). The following * loop should execute only once. */ Console.WriteLine("Optionally disable modulus switching chain expansion."); Utilities.PrintLine(); Console.WriteLine("Print the modulus switching chain."); Console.Write("----> "); for (contextData = context.KeyContextData; null != contextData; contextData = contextData.NextContextData) { Console.WriteLine($"Level (chain index): {contextData.ChainIndex}"); Console.WriteLine($" ParmsId of encrypted: {contextData.ParmsId}"); Console.Write(" CoeffModulus primes: "); foreach (SmallModulus prime in contextData.Parms.CoeffModulus) { Console.Write($"{Utilities.ULongToString(prime.Value)} "); } Console.WriteLine(); Console.WriteLine("\\"); Console.Write(" \\--> "); } Console.WriteLine("End of chain reached"); Console.WriteLine(); /* * It is very important to understand how this example works since in the CKKS * scheme modulus switching has a much more fundamental purpose and the next * examples will be difficult to understand unless these basic properties are * totally clear. */ }
protected override void Execute(CodeActivityContext context) { try { var mUniversalDataHandler = new AwsS3DataHandler(AccessKey.Get(context), SecretKey.Get(context), Region.Get(context)); mUniversalDataHandler.CreateDir(Generate(SourcePath.Get(context), BucketName.Get(context))); Response.Set(context, "Complete"); } catch (Exception e) { Error.Set(context, e.Message); } }
public void ExceptionsTest() { { SEALContext context = GlobalContext.BFVContext; KeyGenerator keygen = new KeyGenerator(context); SecretKey secret = new SecretKey(); List <uint> elts = new List <uint> { 16385 }; List <uint> elts_null = null; List <int> steps = new List <int> { 4096 }; List <int> steps_null = null; Utilities.AssertThrows <ArgumentNullException>(() => keygen = new KeyGenerator(null)); Utilities.AssertThrows <ArgumentNullException>(() => keygen = new KeyGenerator(context, null)); Utilities.AssertThrows <ArgumentNullException>(() => keygen = new KeyGenerator(null, keygen.SecretKey)); Utilities.AssertThrows <ArgumentException>(() => keygen = new KeyGenerator(context, secret)); Utilities.AssertThrows <ArgumentNullException>(() => keygen.CreateGaloisKeys(elts_null)); Utilities.AssertThrows <ArgumentException>(() => keygen.CreateGaloisKeys(elts)); Utilities.AssertThrows <ArgumentNullException>(() => keygen.CreateGaloisKeys(steps_null)); Utilities.AssertThrows <ArgumentException>(() => keygen.CreateGaloisKeys(steps)); EncryptionParameters smallParms = new EncryptionParameters(SchemeType.CKKS); smallParms.PolyModulusDegree = 128; smallParms.CoeffModulus = CoeffModulus.Create(smallParms.PolyModulusDegree, new int[] { 60 }); context = new SEALContext(smallParms, true, SecLevelType.None); keygen = new KeyGenerator(context); Utilities.AssertThrows <InvalidOperationException>(() => keygen.CreateRelinKeys()); Utilities.AssertThrows <InvalidOperationException>(() => keygen.CreateGaloisKeys()); } { SEALContext context = GlobalContext.BGVContext; KeyGenerator keygen = new KeyGenerator(context); SecretKey secret = new SecretKey(); List <uint> elts = new List <uint> { 16385 }; List <uint> elts_null = null; List <int> steps = new List <int> { 4096 }; List <int> steps_null = null; Utilities.AssertThrows <ArgumentNullException>(() => keygen = new KeyGenerator(null)); Utilities.AssertThrows <ArgumentNullException>(() => keygen = new KeyGenerator(context, null)); Utilities.AssertThrows <ArgumentNullException>(() => keygen = new KeyGenerator(null, keygen.SecretKey)); Utilities.AssertThrows <ArgumentException>(() => keygen = new KeyGenerator(context, secret)); Utilities.AssertThrows <ArgumentNullException>(() => keygen.CreateGaloisKeys(elts_null)); Utilities.AssertThrows <ArgumentException>(() => keygen.CreateGaloisKeys(elts)); Utilities.AssertThrows <ArgumentNullException>(() => keygen.CreateGaloisKeys(steps_null)); Utilities.AssertThrows <ArgumentException>(() => keygen.CreateGaloisKeys(steps)); EncryptionParameters smallParms = new EncryptionParameters(SchemeType.CKKS); smallParms.PolyModulusDegree = 128; smallParms.CoeffModulus = CoeffModulus.Create(smallParms.PolyModulusDegree, new int[] { 60 }); context = new SEALContext(smallParms, true, SecLevelType.None); keygen = new KeyGenerator(context); Utilities.AssertThrows <InvalidOperationException>(() => keygen.CreateRelinKeys()); Utilities.AssertThrows <InvalidOperationException>(() => keygen.CreateGaloisKeys()); } }
public GFWPressEncryptForwarder(Socket ClientSocket, DestroyDelegate Destroyer, Socket DestinationSocket, SecretKey key) : base(ClientSocket, Destroyer) { ClientSocket.Blocking = false; this.DestinationSocket = DestinationSocket; this._key = key; }
/// <summary>Default constructor</summary> public JobTokenSecretManager() { this.masterKey = GenerateSecret(); this.currentJobTokens = new SortedDictionary <string, SecretKey>(); }
public int Predict(double[] features, int power, bool useRelinearizeInplace, bool useReScale, Stopwatch timePredictSum) { EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS); if (power < 60) { ulong polyModulusDegree = 8192; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree, new int[] { 60, 40, 40, 60 }); } else { ulong polyModulusDegree = 16384; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree, new int[] { 60, 60, 60, 60, 60, 60 }); } // double scale = Math.Pow(2.0, power); SEALContext context = new SEALContext(parms); Console.WriteLine(); KeyGenerator keygen = new KeyGenerator(context); PublicKey publicKey = keygen.PublicKey; SecretKey secretKey = keygen.SecretKey; RelinKeys relinKeys = keygen.RelinKeys(); Encryptor encryptor = new Encryptor(context, publicKey); Evaluator evaluator = new Evaluator(context); Decryptor decryptor = new Decryptor(context, secretKey); CKKSEncoder encoder = new CKKSEncoder(context); ulong slotCount = encoder.SlotCount; Console.WriteLine($"Number of slots: {slotCount}"); timePredictSum.Start(); var featuresLength = features.Length; var plaintexts = new Plaintext[featuresLength]; var featuresCiphertexts = new Ciphertext[featuresLength]; //Encode and encrypt features for (int i = 0; i < featuresLength; i++) { plaintexts[i] = new Plaintext(); encoder.Encode(features[i], scale, plaintexts[i]); SvcUtilities.PrintScale(plaintexts[i], "featurePlaintext" + i); featuresCiphertexts[i] = new Ciphertext(); encryptor.Encrypt(plaintexts[i], featuresCiphertexts[i]); SvcUtilities.PrintScale(featuresCiphertexts[i], "featurefEncrypted" + i); } // Handle SV var numOfrows = _vectors.Length; var numOfcolumns = _vectors[0].Length; var svPlaintexts = new Plaintext[numOfrows, numOfcolumns]; //Encode SV for (int i = 0; i < numOfrows; i++) { for (int j = 0; j < numOfcolumns; j++) { svPlaintexts[i, j] = new Plaintext(); encoder.Encode(_vectors[i][j], scale, svPlaintexts[i, j]); SvcUtilities.PrintScale(svPlaintexts[i, j], "supportVectorsPlaintext" + i + j); } } // Prepare sum of inner product var sums = new Ciphertext[numOfcolumns]; for (int i = 0; i < numOfcolumns; i++) { sums[i] = new Ciphertext(); } var kernels = new Ciphertext[numOfrows]; var decisionsArr = new Ciphertext[numOfrows]; var coefArr = new Plaintext [numOfrows]; for (int i = 0; i < numOfrows; i++) { kernels[i] = new Ciphertext(); decisionsArr[i] = new Ciphertext(); coefArr[i] = new Plaintext(); } // Level 1 for (int i = 0; i < numOfrows; i++) { var ciphertexts = new List <Ciphertext>(); //inner product for (int j = 0; j < numOfcolumns; j++) { evaluator.MultiplyPlain(featuresCiphertexts[j], svPlaintexts[i, j], sums[j]); if (useRelinearizeInplace) { evaluator.RelinearizeInplace(sums[j], relinKeys); } if (useReScale) { evaluator.RescaleToNextInplace(sums[j]); } SvcUtilities.PrintScale(sums[j], "tSum" + j); } evaluator.AddMany(sums, kernels[i]); evaluator.NegateInplace(kernels[i]); SvcUtilities.PrintScale(kernels[i], "kernel" + i); SvcUtilities.PrintCyprherText(decryptor, kernels[i], encoder, "kernel" + i); } // Encode coefficients : ParmsId! , scale! double scale2 = Math.Pow(2.0, power); if (useReScale) { scale2 = kernels[0].Scale; } for (int i = 0; i < numOfrows; i++) { encoder.Encode(_coefficients[0][i], scale2, coefArr[i]); SvcUtilities.PrintScale(coefArr[i], "coefPlainText+i"); } if (useReScale) { for (int i = 0; i < numOfrows; i++) { ParmsId lastParmsId = kernels[i].ParmsId; evaluator.ModSwitchToInplace(coefArr[i], lastParmsId); } } // Level 2 // Calculate decisionArr for (int i = 0; i < numOfrows; i++) { evaluator.MultiplyPlain(kernels[i], coefArr[i], decisionsArr[i]); if (useRelinearizeInplace) { evaluator.RelinearizeInplace(decisionsArr[i], relinKeys); } if (useReScale) { evaluator.RescaleToNextInplace(decisionsArr[i]); } SvcUtilities.PrintScale(decisionsArr[i], "decision" + i); SvcUtilities.PrintCyprherText(decryptor, decisionsArr[i], encoder, "decision" + i); } // Calculate decisionTotal Ciphertext decisionTotal = new Ciphertext(); //================================================================= evaluator.AddMany(decisionsArr, decisionTotal); //================================================================= SvcUtilities.PrintScale(decisionTotal, "decisionTotal"); SvcUtilities.PrintCyprherText(decryptor, decisionTotal, encoder, "decision total"); // Encode intercepts : ParmsId! , scale! Plaintext interceptsPlainText = new Plaintext(); double scale3 = Math.Pow(2.0, power * 3); if (useReScale) { scale3 = decisionTotal.Scale; } encoder.Encode(_intercepts[0], scale3, interceptsPlainText); if (useReScale) { ParmsId lastParmsId = decisionTotal.ParmsId; evaluator.ModSwitchToInplace(interceptsPlainText, lastParmsId); } SvcUtilities.PrintScale(interceptsPlainText, "interceptsPlainText"); SvcUtilities.PrintScale(decisionTotal, "decisionTotal"); //// Calculate finalTotal Ciphertext finalTotal = new Ciphertext(); //================================================================= evaluator.AddPlainInplace(decisionTotal, interceptsPlainText); //================================================================= timePredictSum.Stop(); SvcUtilities.PrintScale(decisionTotal, "decisionTotal"); //Level 3 List <double> result = SvcUtilities.PrintCyprherText(decryptor, decisionTotal, encoder, "finalTotal"); using (System.IO.StreamWriter file = new System.IO.StreamWriter( $@"{OutputDir}IrisLinear_IrisSecureSVC_total_{power}_{useRelinearizeInplace}_{useReScale}.txt", !_firstTime) ) { _firstTime = false; file.WriteLine($"{result[0]}"); } if (result[0] > 0) { return(0); } return(1); }
private static void CKKSPerformanceTest(SEALContext context) { Stopwatch timer; Utilities.PrintParameters(context); Console.WriteLine(); bool hasZLIB = Serialization.IsSupportedComprMode(ComprModeType.ZLIB); bool hasZSTD = Serialization.IsSupportedComprMode(ComprModeType.ZSTD); using EncryptionParameters parms = context.FirstContextData.Parms; ulong polyModulusDegree = parms.PolyModulusDegree; Console.Write("Generating secret/public keys: "); using KeyGenerator keygen = new KeyGenerator(context); Console.WriteLine("Done"); using SecretKey secretKey = keygen.SecretKey; keygen.CreatePublicKey(out PublicKey publicKey); Func <RelinKeys> GetRelinKeys = () => { if (context.UsingKeyswitching) { /* * Generate relinearization keys. */ Console.Write("Generating relinearization keys: "); timer = Stopwatch.StartNew(); keygen.CreateRelinKeys(out RelinKeys relinKeys); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); return(relinKeys); } else { return(null); } }; Func <GaloisKeys> GetGaloisKeys = () => { if (context.UsingKeyswitching) { if (!context.KeyContextData.Qualifiers.UsingBatching) { Console.WriteLine("Given encryption parameters do not support batching."); return(null); } /* * Generate Galois keys. In larger examples the Galois keys can use a lot of * memory, which can be a problem in constrained systems. The user should * try some of the larger runs of the test and observe their effect on the * memory pool allocation size. The key generation can also take a long time, * as can be observed from the print-out. */ Console.Write($"Generating Galois keys: "); timer = Stopwatch.StartNew(); keygen.CreateGaloisKeys(out GaloisKeys galoisKeys); int micros = (int)(timer.Elapsed.TotalMilliseconds * 1000); Console.WriteLine($"Done [{micros} microseconds]"); return(galoisKeys); } else { return(null); } }; using RelinKeys relinKeys = GetRelinKeys(); using GaloisKeys galKeys = GetGaloisKeys(); using Encryptor encryptor = new Encryptor(context, publicKey); using Decryptor decryptor = new Decryptor(context, secretKey); using Evaluator evaluator = new Evaluator(context); using CKKSEncoder ckksEncoder = new CKKSEncoder(context); Stopwatch timeEncodeSum = new Stopwatch(); Stopwatch timeDecodeSum = new Stopwatch(); Stopwatch timeEncryptSum = new Stopwatch(); Stopwatch timeDecryptSum = new Stopwatch(); Stopwatch timeAddSum = new Stopwatch(); Stopwatch timeMultiplySum = new Stopwatch(); Stopwatch timeMultiplyPlainSum = new Stopwatch(); Stopwatch timeSquareSum = new Stopwatch(); Stopwatch timeRelinearizeSum = new Stopwatch(); Stopwatch timeRescaleSum = new Stopwatch(); Stopwatch timeRotateOneStepSum = new Stopwatch(); Stopwatch timeRotateRandomSum = new Stopwatch(); Stopwatch timeConjugateSum = new Stopwatch(); Stopwatch timeSerializeSum = new Stopwatch(); Stopwatch timeSerializeZLIBSum = new Stopwatch(); Stopwatch timeSerializeZSTDSum = new Stopwatch(); Random rnd = new Random(); /* * How many times to run the test? */ int count = 10; /* * Populate a vector of floating-point values to batch. */ ulong slotCount = ckksEncoder.SlotCount; double[] podValues = new double[slotCount]; for (ulong i = 0; i < slotCount; i++) { podValues[i] = 1.001 * i; } Console.Write("Running tests "); for (int i = 0; i < count; i++) { /* * [Encoding] * For scale we use the square root of the last CoeffModulus prime * from parms. */ double scale = Math.Sqrt(parms.CoeffModulus.Last().Value); using Plaintext plain = new Plaintext(parms.PolyModulusDegree * (ulong)parms.CoeffModulus.Count(), 0); timeEncodeSum.Start(); ckksEncoder.Encode(podValues, scale, plain); timeEncodeSum.Stop(); /* * [Decoding] */ List <double> podList = new List <double>((int)slotCount); timeDecodeSum.Start(); ckksEncoder.Decode(plain, podList); timeDecodeSum.Stop(); /* * [Encryption] */ using Ciphertext encrypted = new Ciphertext(context); timeEncryptSum.Start(); encryptor.Encrypt(plain, encrypted); timeEncryptSum.Stop(); /* * [Decryption] */ using Plaintext plain2 = new Plaintext(polyModulusDegree, 0); timeDecryptSum.Start(); decryptor.Decrypt(encrypted, plain2); timeDecryptSum.Stop(); /* * [Add] */ using Ciphertext encrypted1 = new Ciphertext(context); ckksEncoder.Encode(i + 1, plain); encryptor.Encrypt(plain, encrypted1); using Ciphertext encrypted2 = new Ciphertext(context); ckksEncoder.Encode(i + 1, plain2); encryptor.Encrypt(plain2, encrypted2); timeAddSum.Start(); evaluator.AddInplace(encrypted1, encrypted2); evaluator.AddInplace(encrypted2, encrypted2); evaluator.AddInplace(encrypted1, encrypted2); timeAddSum.Stop(); /* * [Multiply] */ encrypted1.Reserve(3); timeMultiplySum.Start(); evaluator.MultiplyInplace(encrypted1, encrypted2); timeMultiplySum.Stop(); /* * [Multiply Plain] */ timeMultiplyPlainSum.Start(); evaluator.MultiplyPlainInplace(encrypted2, plain); timeMultiplyPlainSum.Stop(); /* * [Square] */ timeSquareSum.Start(); evaluator.SquareInplace(encrypted2); timeSquareSum.Stop(); if (context.UsingKeyswitching) { /* * [Relinearize] */ timeRelinearizeSum.Start(); evaluator.RelinearizeInplace(encrypted1, relinKeys); timeRelinearizeSum.Stop(); /* * [Rescale] */ timeRescaleSum.Start(); evaluator.RescaleToNextInplace(encrypted1); timeRescaleSum.Stop(); /* * [Rotate Vector] */ timeRotateOneStepSum.Start(); evaluator.RotateVectorInplace(encrypted, 1, galKeys); evaluator.RotateVectorInplace(encrypted, -1, galKeys); timeRotateOneStepSum.Stop(); /* * [Rotate Vector Random] */ // ckksEncoder.SlotCount is always a power of 2. int randomRotation = rnd.Next() & ((int)ckksEncoder.SlotCount - 1); timeRotateRandomSum.Start(); evaluator.RotateVectorInplace(encrypted, randomRotation, galKeys); timeRotateRandomSum.Stop(); /* * [Complex Conjugate] */ timeConjugateSum.Start(); evaluator.ComplexConjugateInplace(encrypted, galKeys); timeConjugateSum.Stop(); } /* * [Serialize Ciphertext] */ using MemoryStream stream = new MemoryStream(); timeSerializeSum.Start(); encrypted.Save(stream, ComprModeType.None); timeSerializeSum.Stop(); if (hasZLIB) { /* * [Serialize Ciphertext (ZLIB)] */ timeSerializeZLIBSum.Start(); encrypted.Save(stream, ComprModeType.ZLIB); timeSerializeZLIBSum.Stop(); } if (hasZSTD) { /* * [Serialize Ciphertext (Zstandard)] */ timeSerializeZSTDSum.Start(); encrypted.Save(stream, ComprModeType.ZSTD); timeSerializeZSTDSum.Stop(); } /* * Print a dot to indicate progress. */ Console.Write("."); Console.Out.Flush(); } Console.WriteLine(" Done"); Console.WriteLine(); Console.Out.Flush(); int avgEncode = (int)(timeEncodeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgDecode = (int)(timeDecodeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgEncrypt = (int)(timeEncryptSum.Elapsed.TotalMilliseconds * 1000 / count); int avgDecrypt = (int)(timeDecryptSum.Elapsed.TotalMilliseconds * 1000 / count); int avgAdd = (int)(timeAddSum.Elapsed.TotalMilliseconds * 1000 / (3 * count)); int avgMultiply = (int)(timeMultiplySum.Elapsed.TotalMilliseconds * 1000 / count); int avgMultiplyPlain = (int)(timeMultiplyPlainSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSquare = (int)(timeSquareSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRelinearize = (int)(timeRelinearizeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRescale = (int)(timeRescaleSum.Elapsed.TotalMilliseconds * 1000 / count); int avgRotateOneStep = (int)(timeRotateOneStepSum.Elapsed.TotalMilliseconds * 1000 / (2 * count)); int avgRotateRandom = (int)(timeRotateRandomSum.Elapsed.TotalMilliseconds * 1000 / count); int avgConjugate = (int)(timeConjugateSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeSum = (int)(timeSerializeSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeZLIBSum = (int)(timeSerializeZLIBSum.Elapsed.TotalMilliseconds * 1000 / count); int avgSerializeZSTDSum = (int)(timeSerializeZSTDSum.Elapsed.TotalMilliseconds * 1000 / count); Console.WriteLine($"Average encode: {avgEncode} microseconds"); Console.WriteLine($"Average decode: {avgDecode} microseconds"); Console.WriteLine($"Average encrypt: {avgEncrypt} microseconds"); Console.WriteLine($"Average decrypt: {avgDecrypt} microseconds"); Console.WriteLine($"Average add: {avgAdd} microseconds"); Console.WriteLine($"Average multiply: {avgMultiply} microseconds"); Console.WriteLine($"Average multiply plain: {avgMultiplyPlain} microseconds"); Console.WriteLine($"Average square: {avgSquare} microseconds"); if (context.UsingKeyswitching) { Console.WriteLine($"Average relinearize: {avgRelinearize} microseconds"); Console.WriteLine($"Average rescale: {avgRescale} microseconds"); Console.WriteLine($"Average rotate vector one step: {avgRotateOneStep} microseconds"); Console.WriteLine($"Average rotate vector random: {avgRotateRandom} microseconds"); Console.WriteLine($"Average complex conjugate: {avgConjugate} microseconds"); } Console.WriteLine($"Average serialize ciphertext: {avgSerializeSum} microseconds"); if (hasZLIB) { Console.WriteLine( $"Average compressed (ZLIB) serialize ciphertext: {avgSerializeZLIBSum} microseconds"); } if (hasZSTD) { Console.WriteLine( $"Average compressed (Zstandard) serialize ciphertext: {avgSerializeZSTDSum} microseconds"); } Console.Out.Flush(); }
private static void HomoExample() { EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); parms.PolyModulusDegree = 2048; parms.CoeffModulus = DefaultParams.CoeffModulus128(polyModulusDegree: 2048); parms.PlainModulus = new SmallModulus(1 << 8); SEALContext context = SEALContext.Create(parms); IntegerEncoder encoder = new IntegerEncoder(context); KeyGenerator keygen = new KeyGenerator(context); Microsoft.Research.SEAL.PublicKey publicKey = keygen.PublicKey; SecretKey secretKey = keygen.SecretKey; Encryptor encryptor = new Encryptor(context, publicKey); Evaluator evaluator = new Evaluator(context); Decryptor decryptor = new Decryptor(context, secretKey); int value1 = 5; Plaintext plain1 = encoder.Encode(value1); Console.WriteLine($"Encoded {value1} as polynomial {plain1.ToString()} (plain1)"); int value2 = -7; Plaintext plain2 = encoder.Encode(value2); Console.WriteLine($"Encoded {value2} as polynomial {plain2.ToString()} (plain2)"); Ciphertext encrypted1 = new Ciphertext(); Ciphertext encrypted2 = new Ciphertext(); Console.Write("Encrypting plain1: "); encryptor.Encrypt(plain1, encrypted1); Console.WriteLine("Done (encrypted1)"); Plaintext plainResult = new Plaintext(); decryptor.Decrypt(encrypted1, plainResult); Console.WriteLine(encoder.DecodeInt32(plainResult)); Console.Write("Encrypting plain2: "); encryptor.Encrypt(plain2, encrypted2); Console.WriteLine("Done (encrypted2)"); Console.WriteLine($"Noise budget in encrypted1: {decryptor.InvariantNoiseBudget(encrypted1)} bits"); Console.WriteLine($"Noise budget in encrypted2: {decryptor.InvariantNoiseBudget(encrypted2)} bits"); evaluator.NegateInplace(encrypted1); Console.WriteLine($"Noise budget in -encrypted1: {decryptor.InvariantNoiseBudget(encrypted1)} bits"); evaluator.AddInplace(encrypted1, encrypted2); Console.WriteLine($"Noise budget in -encrypted1 + encrypted2: {decryptor.InvariantNoiseBudget(encrypted1)} bits"); evaluator.MultiplyInplace(encrypted1, encrypted2); Console.WriteLine($"Noise budget in (-encrypted1 + encrypted2) * encrypted2: {decryptor.InvariantNoiseBudget(encrypted1)} bits"); plainResult = new Plaintext(); Console.Write("Decrypting result: "); decryptor.Decrypt(encrypted1, plainResult); Console.WriteLine("Done"); Console.WriteLine($"Plaintext polynomial: {plainResult.ToString()}"); Console.WriteLine($"Decoded integer: {encoder.DecodeInt32(plainResult)}"); }
/* * In `1_BFV_Basics.cs' we showed how to perform a very simple computation using the * BFV scheme. The computation was performed modulo the PlainModulus parameter, and * utilized only one coefficient from a BFV plaintext polynomial. This approach has * two notable problems: * * (1) Practical applications typically use integer or real number arithmetic, * not modular arithmetic; * (2) We used only one coefficient of the plaintext polynomial. This is really * wasteful, as the plaintext polynomial is large and will in any case be * encrypted in its entirety. * * For (1), one may ask why not just increase the PlainModulus parameter until no * overflow occurs, and the computations behave as in integer arithmetic. The problem * is that increasing PlainModulus increases noise budget consumption, and decreases * the initial noise budget too. * * In these examples we will discuss other ways of laying out data into plaintext * elements (encoding) that allow more computations without data type overflow, and * can allow the full plaintext polynomial to be utilized. */ private static void ExampleIntegerEncoder() { Utilities.PrintExampleBanner("Example: Encoders / Integer Encoder"); /* * [IntegerEncoder] (For BFV scheme only) * * The IntegerEncoder encodes integers to BFV plaintext polynomials as follows. * First, a binary expansion of the integer is computed. Next, a polynomial is * created with the bits as coefficients. For example, the integer * * 26 = 2^4 + 2^3 + 2^1 * * is encoded as the polynomial 1x^4 + 1x^3 + 1x^1. Conversely, plaintext * polynomials are decoded by evaluating them at x=2. For negative numbers the * IntegerEncoder simply stores all coefficients as either 0 or -1, where -1 is * represented by the unsigned integer PlainModulus - 1 in memory. * * Since encrypted computations operate on the polynomials rather than on the * encoded integers themselves, the polynomial coefficients will grow in the * course of such computations. For example, computing the sum of the encrypted * encoded integer 26 with itself will result in an encrypted polynomial with * larger coefficients: 2x^4 + 2x^3 + 2x^1. Squaring the encrypted encoded * integer 26 results also in increased coefficients due to cross-terms, namely, * * (1x^4 + 1x^3 + 1x^1)^2 = 1x^8 + 2x^7 + 1x^6 + 2x^5 + 2x^4 + 1x^2; * * further computations will quickly increase the coefficients much more. * Decoding will still work correctly in this case (evaluating the polynomial * at x=2), but since the coefficients of plaintext polynomials are really * integers modulo plain_modulus, implicit reduction modulo plain_modulus may * yield unexpected results. For example, adding 1x^4 + 1x^3 + 1x^1 to itself * plain_modulus many times will result in the constant polynomial 0, which is * clearly not equal to 26 * plain_modulus. It can be difficult to predict when * such overflow will take place especially when computing several sequential * multiplications. * * The IntegerEncoder is easy to understand and use for simple computations, * and can be a good tool to experiment with for users new to Microsoft SEAL. * However, advanced users will probably prefer more efficient approaches, * such as the BatchEncoder or the CKKSEncoder. */ EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); ulong polyModulusDegree = 4096; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree); /* * There is no hidden logic behind our choice of the plain_modulus. The only * thing that matters is that the plaintext polynomial coefficients will not * exceed this value at any point during our computation; otherwise the result * will be incorrect. */ parms.PlainModulus = new SmallModulus(512); SEALContext context = new SEALContext(parms); Utilities.PrintParameters(context); Console.WriteLine(); KeyGenerator keygen = new KeyGenerator(context); PublicKey publicKey = keygen.PublicKey; SecretKey secretKey = keygen.SecretKey; Encryptor encryptor = new Encryptor(context, publicKey); Evaluator evaluator = new Evaluator(context); Decryptor decryptor = new Decryptor(context, secretKey); /* * We create an IntegerEncoder. */ IntegerEncoder encoder = new IntegerEncoder(context); /* * First, we encode two integers as plaintext polynomials. Note that encoding * is not encryption: at this point nothing is encrypted. */ int value1 = 5; Plaintext plain1 = encoder.Encode(value1); Utilities.PrintLine(); Console.WriteLine($"Encode {value1} as polynomial {plain1} (plain1),"); int value2 = -7; Plaintext plain2 = encoder.Encode(value2); Console.WriteLine(new string(' ', 13) + $"Encode {value2} as polynomial {plain2} (plain2),"); /* * Now we can encrypt the plaintext polynomials. */ Ciphertext encrypted1 = new Ciphertext(); Ciphertext encrypted2 = new Ciphertext(); Utilities.PrintLine(); Console.WriteLine("Encrypt plain1 to encrypted1 and plain2 to encrypted2."); encryptor.Encrypt(plain1, encrypted1); encryptor.Encrypt(plain2, encrypted2); Console.WriteLine(" + Noise budget in encrypted1: {0} bits", decryptor.InvariantNoiseBudget(encrypted1)); Console.WriteLine(" + Noise budget in encrypted2: {0} bits", decryptor.InvariantNoiseBudget(encrypted2)); /* * As a simple example, we compute (-encrypted1 + encrypted2) * encrypted2. */ encryptor.Encrypt(plain2, encrypted2); Ciphertext encryptedResult = new Ciphertext(); Utilities.PrintLine(); Console.WriteLine("Compute encrypted_result = (-encrypted1 + encrypted2) * encrypted2."); evaluator.Negate(encrypted1, encryptedResult); evaluator.AddInplace(encryptedResult, encrypted2); evaluator.MultiplyInplace(encryptedResult, encrypted2); Console.WriteLine(" + Noise budget in encryptedResult: {0} bits", decryptor.InvariantNoiseBudget(encryptedResult)); Plaintext plainResult = new Plaintext(); Utilities.PrintLine(); Console.WriteLine("Decrypt encrypted_result to plain_result."); decryptor.Decrypt(encryptedResult, plainResult); /* * Print the result plaintext polynomial. The coefficients are not even close * to exceeding our plainModulus, 512. */ Console.WriteLine($" + Plaintext polynomial: {plainResult}"); /* * Decode to obtain an integer result. */ Utilities.PrintLine(); Console.WriteLine("Decode plain_result."); Console.WriteLine(" + Decoded integer: {0} ...... Correct.", encoder.DecodeInt32(plainResult)); }
//constructor for debugging , because it enables to pass secretkey which will not happen in real life // special parameters : // batchsize - number of batches sample in one ciphertext ,if the client batches mulitple samples in the ciphertet . // featureSize - number of features in sample private Svc(double[][] vectors, double[][] coefficients, double[] intercepts, String kernel, double gamma, double coef0, ulong degree, int power, PublicKey publicKey, SecretKey secretKey, RelinKeys relinKeys, GaloisKeys galoisKeys, int batchSize, int featureSize) { this._vectors = vectors; this._coefficients = coefficients; this._intercepts = intercepts; this._kernel = (Kernel)System.Enum.Parse(typeof(Kernel), kernel); this._gamma = gamma; this._coef0 = coef0; this._degree = degree; this._power = power; //Use the ckks SCheme EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS); // polyModulusDegree and CoeffModulus used for general SVM algorithm and depends on the polynomial kernel degree // ( and the percision constraint ) . // My implementation can be used up to dgree = 4 , but it can be easly refactored with some oprimizations to higher // polynomial degree ulong polyModulusDegree = 16384; if (power >= 20 && power < 40) { parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree, new int[] { 60, 20, 21, 22, 23, 24, 25, 26, 27, 60 }); } else if (power >= 40 && power < 60) { parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree, new int[] { 60, 40, 40, 40, 40, 40, 40, 40, 60 }); } else if (power == 60) { polyModulusDegree = 32768; parms.CoeffModulus = CoeffModulus.Create(polyModulusDegree, new int[] { 60, 60, 60, 60, 60, 60, 60, 60, 60 }); } parms.PolyModulusDegree = polyModulusDegree; _context = new SEALContext(parms); _publicKey = publicKey; _secretKey = secretKey; _relinKeys = relinKeys; _galoisKeys = galoisKeys; _evaluator = new Evaluator(_context); if (_secretKey != null) { _decryptor = new Decryptor(_context, _secretKey); //FOR DEBUG ONLY ( not used in real server) } _encoder = new CKKSEncoder(_context); Stopwatch serverInitStopwatch = new Stopwatch(); serverInitStopwatch.Start(); _numOfrowsCount = _vectors.Length; //Number of Support Vectors _numOfcolumnsCount = _vectors[0].Length; //Number of features in every Support vector _scale = Math.Pow(2.0, _power); // vars for batch rotations _svPlaintexts = new Plaintext[_numOfrowsCount]; //Encode support vectors _sums = new Ciphertext[_numOfrowsCount]; if (UseBatchInnerProduct) { double[] batchVectors = new double[batchSize * featureSize]; for (int i = 0; i < _numOfrowsCount; i++) { for (int k = 0; k < batchSize * featureSize; k++) { var index0 = k % featureSize; batchVectors[k] = index0 < _numOfcolumnsCount ? _vectors[i][index0] : 0; } _svPlaintexts[i] = new Plaintext(); _encoder.Encode(batchVectors, _scale, _svPlaintexts[i]); SVCUtilities.SvcUtilities.PrintScale(_svPlaintexts[i], "batch supportVectorsPlaintext" + i); _sums[i] = new Ciphertext(); } } else { ///////////////////////////////////////////////////////////////////////// // // vars for simple inner product // // Handle SV _svPlaintextsArr = new Plaintext[_numOfrowsCount, _numOfcolumnsCount]; //Encode SV for (int i = 0; i < _numOfrowsCount; i++) { for (int j = 0; j < _numOfcolumnsCount; j++) { _svPlaintextsArr[i, j] = new Plaintext(); _encoder.Encode(_vectors[i][j] != 0 ? _vectors[i][j] : Zero, _scale, _svPlaintextsArr[i, j]); SvcUtilities.PrintScale(_svPlaintextsArr[i, j], $"supportVectorsPlaintext[{i}][{j}]"); } } // Prepare sum of inner product _innerProdSums = new Ciphertext[_numOfcolumnsCount]; for (int i = 0; i < _numOfcolumnsCount; i++) { _innerProdSums[i] = new Ciphertext(); } ////////////////////////////////////////////////////////////// } // Allocate memory for svm secure calculation _kernels = new Ciphertext[_numOfrowsCount]; _decisionsArr = new Ciphertext[_numOfrowsCount]; _coefArr = new Plaintext[_numOfrowsCount]; for (int i = 0; i < _numOfrowsCount; i++) { _kernels[i] = new Ciphertext(); _decisionsArr[i] = new Ciphertext(); _coefArr[i] = new Plaintext(); } _gamaPlaintext = new Plaintext(); _encoder.Encode(_gamma != 0 ? _gamma : Zero, _scale, _gamaPlaintext); serverInitStopwatch.Stop(); Console.WriteLine($"server Init elapsed {serverInitStopwatch.ElapsedMilliseconds} ms"); }
public BlockKey(int keyId, long expiryDate, SecretKey key) : base(keyId, expiryDate, key) { }
private static void ExampleBFVBasics() { Utilities.PrintExampleBanner("Example: BFV Basics"); /* * In this example, we demonstrate performing simple computations (a polynomial * evaluation) on encrypted integers using the BFV encryption scheme. * * The first task is to set up an instance of the EncryptionParameters class. * It is critical to understand how the different parameters behave, how they * affect the encryption scheme, performance, and the security level. There are * three encryption parameters that are necessary to set: * * - PolyModulusDegree (degree of polynomial modulus); * - CoeffModulus ([ciphertext] coefficient modulus); * - PlainModulus (plaintext modulus; only for the BFV scheme). * * The BFV scheme cannot perform arbitrary computations on encrypted data. * Instead, each ciphertext has a specific quantity called the `invariant noise * budget' -- or `noise budget' for short -- measured in bits. The noise budget * in a freshly encrypted ciphertext (initial noise budget) is determined by * the encryption parameters. Homomorphic operations consume the noise budget * at a rate also determined by the encryption parameters. In BFV the two basic * operations allowed on encrypted data are additions and multiplications, of * which additions can generally be thought of as being nearly free in terms of * noise budget consumption compared to multiplications. Since noise budget * consumption compounds in sequential multiplications, the most significant * factor in choosing appropriate encryption parameters is the multiplicative * depth of the arithmetic circuit that the user wants to evaluate on encrypted * data. Once the noise budget of a ciphertext reaches zero it becomes too * corrupted to be decrypted. Thus, it is essential to choose the parameters to * be large enough to support the desired computation; otherwise the result is * impossible to make sense of even with the secret key. */ EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV); /* * The first parameter we set is the degree of the `polynomial modulus'. This * must be a positive power of 2, representing the degree of a power-of-two * cyclotomic polynomial; it is not necessary to understand what this means. * * Larger PolyModulusDegree makes ciphertext sizes larger and all operations * slower, but enables more complicated encrypted computations. Recommended * values are 1024, 2048, 4096, 8192, 16384, 32768, but it is also possible * to go beyond this range. * * In this example we use a relatively small polynomial modulus. Anything * smaller than this will enable only very restricted encrypted computations. */ ulong polyModulusDegree = 4096; parms.PolyModulusDegree = polyModulusDegree; /* * Next we set the [ciphertext] `coefficient modulus' (CoeffModulus). This * parameter is a large integer, which is a product of distinct prime numbers, * numbers, each represented by an instance of the SmallModulus class. The * bit-length of CoeffModulus means the sum of the bit-lengths of its prime * factors. * * A larger CoeffModulus implies a larger noise budget, hence more encrypted * computation capabilities. However, an upper bound for the total bit-length * of the CoeffModulus is determined by the PolyModulusDegree, as follows: * +----------------------------------------------------+ | PolyModulusDegree | max CoeffModulus bit-length | +---------------------+------------------------------+ | 1024 | 27 | | 2048 | 54 | | 4096 | 109 | | 8192 | 218 | | 16384 | 438 | | 32768 | 881 | +---------------------+------------------------------+ | | These numbers can also be found in native/src/seal/util/hestdparms.h encoded | in the function SEAL_HE_STD_PARMS_128_TC, and can also be obtained from the | function | | CoeffModulus.MaxBitCount(polyModulusDegree). | | For example, if PolyModulusDegree is 4096, the coeff_modulus could consist | of three 36-bit primes (108 bits). | | Microsoft SEAL comes with helper functions for selecting the CoeffModulus. | For new users the easiest way is to simply use | | CoeffModulus.BFVDefault(polyModulusDegree), | | which returns IEnumerable<SmallModulus> consisting of a generally good choice | for the given PolyModulusDegree. */ parms.CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree); /* * The plaintext modulus can be any positive integer, even though here we take * it to be a power of two. In fact, in many cases one might instead want it * to be a prime number; we will see this in later examples. The plaintext * modulus determines the size of the plaintext data type and the consumption * of noise budget in multiplications. Thus, it is essential to try to keep the * plaintext data type as small as possible for best performance. The noise * budget in a freshly encrypted ciphertext is * * ~ log2(CoeffModulus/PlainModulus) (bits) * * and the noise budget consumption in a homomorphic multiplication is of the * form log2(PlainModulus) + (other terms). * * The plaintext modulus is specific to the BFV scheme, and cannot be set when * using the CKKS scheme. */ parms.PlainModulus = new SmallModulus(1024); /* * Now that all parameters are set, we are ready to construct a SEALContext * object. This is a heavy class that checks the validity and properties of the * parameters we just set. */ SEALContext context = new SEALContext(parms); /* * Print the parameters that we have chosen. */ Utilities.PrintLine(); Console.WriteLine("Set encryption parameters and print"); Utilities.PrintParameters(context); Console.WriteLine(); Console.WriteLine("~~~~~~ A naive way to calculate 4(x^2+1)(x+1)^2. ~~~~~~"); /* * The encryption schemes in Microsoft SEAL are public key encryption schemes. * For users unfamiliar with this terminology, a public key encryption scheme * has a separate public key for encrypting data, and a separate secret key for * decrypting data. This way multiple parties can encrypt data using the same * shared public key, but only the proper recipient of the data can decrypt it * with the secret key. * * We are now ready to generate the secret and public keys. For this purpose * we need an instance of the KeyGenerator class. Constructing a KeyGenerator * automatically generates the public and secret key, which can immediately be * read to local variables. */ KeyGenerator keygen = new KeyGenerator(context); PublicKey publicKey = keygen.PublicKey; SecretKey secretKey = keygen.SecretKey; /* * To be able to encrypt we need to construct an instance of Encryptor. Note * that the Encryptor only requires the public key, as expected. */ Encryptor encryptor = new Encryptor(context, publicKey); /* * Computations on the ciphertexts are performed with the Evaluator class. In * a real use-case the Evaluator would not be constructed by the same party * that holds the secret key. */ Evaluator evaluator = new Evaluator(context); /* * We will of course want to decrypt our results to verify that everything worked, * so we need to also construct an instance of Decryptor. Note that the Decryptor * requires the secret key. */ Decryptor decryptor = new Decryptor(context, secretKey); /* * As an example, we evaluate the degree 4 polynomial * * 4x^4 + 8x^3 + 8x^2 + 8x + 4 * * over an encrypted x = 6. The coefficients of the polynomial can be considered * as plaintext inputs, as we will see below. The computation is done modulo the * plain_modulus 1024. * * While this examples is simple and easy to understand, it does not have much * practical value. In later examples we will demonstrate how to compute more * efficiently on encrypted integers and real or complex numbers. * * Plaintexts in the BFV scheme are polynomials of degree less than the degree * of the polynomial modulus, and coefficients integers modulo the plaintext * modulus. For readers with background in ring theory, the plaintext space is * the polynomial quotient ring Z_T[X]/(X^N + 1), where N is PolyModulusDegree * and T is PlainModulus. * * To get started, we create a plaintext containing the constant 6. For the * plaintext element we use a constructor that takes the desired polynomial as * a string with coefficients represented as hexadecimal numbers. */ Utilities.PrintLine(); int x = 6; Plaintext xPlain = new Plaintext(x.ToString()); Console.WriteLine($"Express x = {x} as a plaintext polynomial 0x{xPlain}."); /* * We then encrypt the plaintext, producing a ciphertext. */ Utilities.PrintLine(); Ciphertext xEncrypted = new Ciphertext(); Console.WriteLine("Encrypt xPlain to xEncrypted."); encryptor.Encrypt(xPlain, xEncrypted); /* * In Microsoft SEAL, a valid ciphertext consists of two or more polynomials * whose coefficients are integers modulo the product of the primes in the * coeff_modulus. The number of polynomials in a ciphertext is called its `size' * and is given by Ciphertext.Size. A freshly encrypted ciphertext always has * size 2. */ Console.WriteLine($" + size of freshly encrypted x: {xEncrypted.Size}"); /* * There is plenty of noise budget left in this freshly encrypted ciphertext. */ Console.WriteLine(" + noise budget in freshly encrypted x: {0} bits", decryptor.InvariantNoiseBudget(xEncrypted)); /* * We decrypt the ciphertext and print the resulting plaintext in order to * demonstrate correctness of the encryption. */ Plaintext xDecrypted = new Plaintext(); Console.Write(" + decryption of encrypted_x: "); decryptor.Decrypt(xEncrypted, xDecrypted); Console.WriteLine($"0x{xDecrypted} ...... Correct."); /* * When using Microsoft SEAL, it is typically advantageous to compute in a way * that minimizes the longest chain of sequential multiplications. In other * words, encrypted computations are best evaluated in a way that minimizes * the multiplicative depth of the computation, because the total noise budget * consumption is proportional to the multiplicative depth. For example, for * our example computation it is advantageous to factorize the polynomial as * * 4x^4 + 8x^3 + 8x^2 + 8x + 4 = 4(x + 1)^2 * (x^2 + 1) * * to obtain a simple depth 2 representation. Thus, we compute (x + 1)^2 and * (x^2 + 1) separately, before multiplying them, and multiplying by 4. * * First, we compute x^2 and add a plaintext "1". We can clearly see from the * print-out that multiplication has consumed a lot of noise budget. The user * can vary the plain_modulus parameter to see its effect on the rate of noise * budget consumption. */ Utilities.PrintLine(); Console.WriteLine("Compute xSqPlusOne (x^2+1)."); Ciphertext xSqPlusOne = new Ciphertext(); evaluator.Square(xEncrypted, xSqPlusOne); Plaintext plainOne = new Plaintext("1"); evaluator.AddPlainInplace(xSqPlusOne, plainOne); /* * Encrypted multiplication results in the output ciphertext growing in size. * More precisely, if the input ciphertexts have size M and N, then the output * ciphertext after homomorphic multiplication will have size M+N-1. In this * case we perform a squaring, and observe both size growth and noise budget * consumption. */ Console.WriteLine($" + size of xSqPlusOne: {xSqPlusOne.Size}"); Console.WriteLine(" + noise budget in xSqPlusOne: {0} bits", decryptor.InvariantNoiseBudget(xSqPlusOne)); /* * Even though the size has grown, decryption works as usual as long as noise * budget has not reached 0. */ Plaintext decryptedResult = new Plaintext(); Console.Write(" + decryption of xSqPlusOne: "); decryptor.Decrypt(xSqPlusOne, decryptedResult); Console.WriteLine($"0x{decryptedResult} ...... Correct."); /* * Next, we compute (x + 1)^2. */ Utilities.PrintLine(); Console.WriteLine("Compute xPlusOneSq ((x+1)^2)."); Ciphertext xPlusOneSq = new Ciphertext(); evaluator.AddPlain(xEncrypted, plainOne, xPlusOneSq); evaluator.SquareInplace(xPlusOneSq); Console.WriteLine($" + size of xPlusOneSq: {xPlusOneSq.Size}"); Console.WriteLine(" + noise budget in xPlusOneSq: {0} bits", decryptor.InvariantNoiseBudget(xPlusOneSq)); Console.Write(" + decryption of xPlusOneSq: "); decryptor.Decrypt(xPlusOneSq, decryptedResult); Console.WriteLine($"0x{decryptedResult} ...... Correct."); /* * Finally, we multiply (x^2 + 1) * (x + 1)^2 * 4. */ Utilities.PrintLine(); Console.WriteLine("Compute encryptedResult (4(x^2+1)(x+1)^2)."); Ciphertext encryptedResult = new Ciphertext(); Plaintext plainFour = new Plaintext("4"); evaluator.MultiplyPlainInplace(xSqPlusOne, plainFour); evaluator.Multiply(xSqPlusOne, xPlusOneSq, encryptedResult); Console.WriteLine($" + size of encrypted_result: {encryptedResult.Size}"); Console.WriteLine(" + noise budget in encrypted_result: {0} bits", decryptor.InvariantNoiseBudget(encryptedResult)); Console.WriteLine("NOTE: Decryption can be incorrect if noise budget is zero."); Console.WriteLine(); Console.WriteLine("~~~~~~ A better way to calculate 4(x^2+1)(x+1)^2. ~~~~~~"); /* * Noise budget has reached 0, which means that decryption cannot be expected * to give the correct result. This is because both ciphertexts xSqPlusOne and * xPlusOneSq consist of 3 polynomials due to the previous squaring operations, * and homomorphic operations on large ciphertexts consume much more noise budget * than computations on small ciphertexts. Computing on smaller ciphertexts is * also computationally significantly cheaper. * * `Relinearization' is an operation that reduces the size of a ciphertext after * multiplication back to the initial size, 2. Thus, relinearizing one or both * input ciphertexts before the next multiplication can have a huge positive * impact on both noise growth and performance, even though relinearization has * a significant computational cost itself. It is only possible to relinearize * size 3 ciphertexts down to size 2, so often the user would want to relinearize * after each multiplication to keep the ciphertext sizes at 2. * * Relinearization requires special `relinearization keys', which can be thought * of as a kind of public key. Relinearization keys can easily be created with * the KeyGenerator. * * Relinearization is used similarly in both the BFV and the CKKS schemes, but * in this example we continue using BFV. We repeat our computation from before, * but this time relinearize after every multiplication. * * We use KeyGenerator.RelinKeys() to create relinearization keys. */ Utilities.PrintLine(); Console.WriteLine("Generate relinearization keys."); RelinKeys relinKeys = keygen.RelinKeys(); /* * We now repeat the computation relinearizing after each multiplication. */ Utilities.PrintLine(); Console.WriteLine("Compute and relinearize xSquared (x^2),"); Console.WriteLine(new string(' ', 13) + "then compute xSqPlusOne (x^2+1)"); Ciphertext xSquared = new Ciphertext(); evaluator.Square(xEncrypted, xSquared); Console.WriteLine($" + size of xSquared: {xSquared.Size}"); evaluator.RelinearizeInplace(xSquared, relinKeys); Console.WriteLine(" + size of xSquared (after relinearization): {0}", xSquared.Size); evaluator.AddPlain(xSquared, plainOne, xSqPlusOne); Console.WriteLine(" + noise budget in xSqPlusOne: {0} bits", decryptor.InvariantNoiseBudget(xSqPlusOne)); Console.Write(" + decryption of xSqPlusOne: "); decryptor.Decrypt(xSqPlusOne, decryptedResult); Console.WriteLine($"0x{decryptedResult} ...... Correct."); Utilities.PrintLine(); Ciphertext xPlusOne = new Ciphertext(); Console.WriteLine("Compute xPlusOne (x+1),"); Console.WriteLine(new string(' ', 13) + "then compute and relinearize xPlusOneSq ((x+1)^2)."); evaluator.AddPlain(xEncrypted, plainOne, xPlusOne); evaluator.Square(xPlusOne, xPlusOneSq); Console.WriteLine($" + size of xPlusOneSq: {xPlusOneSq.Size}"); evaluator.RelinearizeInplace(xPlusOneSq, relinKeys); Console.WriteLine(" + noise budget in xPlusOneSq: {0} bits", decryptor.InvariantNoiseBudget(xPlusOneSq)); Console.Write(" + decryption of xPlusOneSq: "); decryptor.Decrypt(xPlusOneSq, decryptedResult); Console.WriteLine($"0x{decryptedResult} ...... Correct."); Utilities.PrintLine(); Console.WriteLine("Compute and relinearize encryptedResult (4(x^2+1)(x+1)^2)."); evaluator.MultiplyPlainInplace(xSqPlusOne, plainFour); evaluator.Multiply(xSqPlusOne, xPlusOneSq, encryptedResult); Console.WriteLine($" + size of encryptedResult: {encryptedResult.Size}"); evaluator.RelinearizeInplace(encryptedResult, relinKeys); Console.WriteLine(" + size of encryptedResult (after relinearization): {0}", encryptedResult.Size); Console.WriteLine(" + noise budget in encryptedResult: {0} bits", decryptor.InvariantNoiseBudget(encryptedResult)); Console.WriteLine(); Console.WriteLine("NOTE: Notice the increase in remaining noise budget."); /* * Relinearization clearly improved our noise consumption. We have still plenty * of noise budget left, so we can expect the correct answer when decrypting. */ Utilities.PrintLine(); Console.WriteLine("Decrypt encrypted_result (4(x^2+1)(x+1)^2)."); decryptor.Decrypt(encryptedResult, decryptedResult); Console.WriteLine(" + decryption of 4(x^2+1)(x+1)^2 = 0x{0} ...... Correct.", decryptedResult); /* * For x=6, 4(x^2+1)(x+1)^2 = 7252. Since the plaintext modulus is set to 1024, * this result is computed in integers modulo 1024. Therefore the expected output * should be 7252 % 1024 == 84, or 0x54 in hexadecimal. */ }
static private void ExampleCKKSEncoder() { Utilities.PrintExampleBanner("Example: Encoders / CKKS Encoder"); /* * [CKKSEncoder] (For CKKS scheme only) * * In this example we demonstrate the Cheon-Kim-Kim-Song (CKKS) scheme for * computing on encrypted real or complex numbers. We start by creating * encryption parameters for the CKKS scheme. There are two important * differences compared to the BFV scheme: * * (1) CKKS does not use the PlainModulus encryption parameter; * (2) Selecting the CoeffModulus in a specific way can be very important * when using the CKKS scheme. We will explain this further in the file * `CKKS_Basics.cs'. In this example we use CoeffModulus.Create to * generate 5 40-bit prime numbers. */ using EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS); ulong polyModulusDegree = 8192; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.Create( polyModulusDegree, new int[] { 40, 40, 40, 40, 40 }); /* * We create the SEALContext as usual and print the parameters. */ using SEALContext context = new SEALContext(parms); Utilities.PrintParameters(context); Console.WriteLine(); /* * Keys are created the same way as for the BFV scheme. */ using KeyGenerator keygen = new KeyGenerator(context); using SecretKey secretKey = keygen.SecretKey; keygen.CreatePublicKey(out PublicKey publicKey); keygen.CreateRelinKeys(out RelinKeys relinKeys); /* * We also set up an Encryptor, Evaluator, and Decryptor as usual. */ using Encryptor encryptor = new Encryptor(context, publicKey); using Evaluator evaluator = new Evaluator(context); using Decryptor decryptor = new Decryptor(context, secretKey); /* * To create CKKS plaintexts we need a special encoder: there is no other way * to create them. The BatchEncoder cannot be used with the * CKKS scheme. The CKKSEncoder encodes vectors of real or complex numbers into * Plaintext objects, which can subsequently be encrypted. At a high level this * looks a lot like what BatchEncoder does for the BFV scheme, but the theory * behind it is completely different. */ using CKKSEncoder encoder = new CKKSEncoder(context); /* * In CKKS the number of slots is PolyModulusDegree / 2 and each slot encodes * one real or complex number. This should be contrasted with BatchEncoder in * the BFV scheme, where the number of slots is equal to PolyModulusDegree * and they are arranged into a matrix with two rows. */ ulong slotCount = encoder.SlotCount; Console.WriteLine($"Number of slots: {slotCount}"); /* * We create a small vector to encode; the CKKSEncoder will implicitly pad it * with zeros to full size (PolyModulusDegree / 2) when encoding. */ double[] input = new double[] { 0.0, 1.1, 2.2, 3.3 }; Console.WriteLine("Input vector: "); Utilities.PrintVector(input); /* * Now we encode it with CKKSEncoder. The floating-point coefficients of `input' * will be scaled up by the parameter `scale'. This is necessary since even in * the CKKS scheme the plaintext elements are fundamentally polynomials with * integer coefficients. It is instructive to think of the scale as determining * the bit-precision of the encoding; naturally it will affect the precision of * the result. * * In CKKS the message is stored modulo CoeffModulus (in BFV it is stored modulo * PlainModulus), so the scaled message must not get too close to the total size * of CoeffModulus. In this case our CoeffModulus is quite large (200 bits) so * we have little to worry about in this regard. For this simple example a 30-bit * scale is more than enough. */ using Plaintext plain = new Plaintext(); double scale = Math.Pow(2.0, 30); Utilities.PrintLine(); Console.WriteLine("Encode input vector."); encoder.Encode(input, scale, plain); /* * We can instantly decode to check the correctness of encoding. */ List <double> output = new List <double>(); Console.WriteLine(" + Decode input vector ...... Correct."); encoder.Decode(plain, output); Utilities.PrintVector(output); /* * The vector is encrypted the same was as in BFV. */ using Ciphertext encrypted = new Ciphertext(); Utilities.PrintLine(); Console.WriteLine("Encrypt input vector, square, and relinearize."); encryptor.Encrypt(plain, encrypted); /* * Basic operations on the ciphertexts are still easy to do. Here we square * the ciphertext, decrypt, decode, and print the result. We note also that * decoding returns a vector of full size (PolyModulusDegree / 2); this is * because of the implicit zero-padding mentioned above. */ evaluator.SquareInplace(encrypted); evaluator.RelinearizeInplace(encrypted, relinKeys); /* * We notice that the scale in the result has increased. In fact, it is now * the square of the original scale: 2^60. */ Console.WriteLine(" + Scale in squared input: {0} ({1} bits)", encrypted.Scale, (int)Math.Ceiling(Math.Log(encrypted.Scale, newBase: 2))); Utilities.PrintLine(); Console.WriteLine("Decrypt and decode."); decryptor.Decrypt(encrypted, plain); encoder.Decode(plain, output); Console.WriteLine(" + Result vector ...... Correct."); Utilities.PrintVector(output); /* * The CKKS scheme allows the scale to be reduced between encrypted computations. * This is a fundamental and critical feature that makes CKKS very powerful and * flexible. We will discuss it in great detail in `3_Levels.cs' and later in * `4_CKKS_Basics.cs'. */ }
public MasterKeyData(MasterKey masterKeyRecord, SecretKey secretKey) { this.masterKeyRecord = masterKeyRecord; this.generatedSecretKey = secretKey; }
public static byte[] getServerHash(String toencode, PublicKey par1PublicKey, SecretKey par2SecretKey) { return digest("SHA-1", new byte[][] { Encoding.GetEncoding("iso-8859-1").GetBytes(toencode), par2SecretKey.getEncoded(), par1PublicKey.getEncoded() }); }
private static void ExampleCKKSBasics() { Utilities.PrintExampleBanner("Example: CKKS Basics"); /* * In this example we demonstrate evaluating a polynomial function * * PI*x^3 + 0.4*x + 1 * * on encrypted floating-point input data x for a set of 4096 equidistant points * in the interval [0, 1]. This example demonstrates many of the main features * of the CKKS scheme, but also the challenges in using it. * * We start by setting up the CKKS scheme. */ using EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS); /* * We saw in `2_Encoders.cs' that multiplication in CKKS causes scales in * ciphertexts to grow. The scale of any ciphertext must not get too close to * the total size of CoeffModulus, or else the ciphertext simply runs out of * room to store the scaled-up plaintext. The CKKS scheme provides a `rescale' * functionality that can reduce the scale, and stabilize the scale expansion. * * Rescaling is a kind of modulus switch operation (recall `3_Levels.cs'). * As modulus switching, it removes the last of the primes from CoeffModulus, * but as a side-effect it scales down the ciphertext by the removed prime. * Usually we want to have perfect control over how the scales are changed, * which is why for the CKKS scheme it is more common to use carefully selected * primes for the CoeffModulus. * * More precisely, suppose that the scale in a CKKS ciphertext is S, and the * last prime in the current CoeffModulus (for the ciphertext) is P. Rescaling * to the next level changes the scale to S/P, and removes the prime P from the * CoeffModulus, as usual in modulus switching. The number of primes limits * how many rescalings can be done, and thus limits the multiplicative depth of * the computation. * * It is possible to choose the initial scale freely. One good strategy can be * to is to set the initial scale S and primes P_i in the CoeffModulus to be * very close to each other. If ciphertexts have scale S before multiplication, * they have scale S^2 after multiplication, and S^2/P_i after rescaling. If all * P_i are close to S, then S^2/P_i is close to S again. This way we stabilize the * scales to be close to S throughout the computation. Generally, for a circuit * of depth D, we need to rescale D times, i.e., we need to be able to remove D * primes from the coefficient modulus. Once we have only one prime left in the * coeff_modulus, the remaining prime must be larger than S by a few bits to * preserve the pre-decimal-point value of the plaintext. * * Therefore, a generally good strategy is to choose parameters for the CKKS * scheme as follows: * * (1) Choose a 60-bit prime as the first prime in CoeffModulus. This will * give the highest precision when decrypting; * (2) Choose another 60-bit prime as the last element of CoeffModulus, as * this will be used as the special prime and should be as large as the * largest of the other primes; * (3) Choose the intermediate primes to be close to each other. * * We use CoeffModulus.Create to generate primes of the appropriate size. Note * that our CoeffModulus is 200 bits total, which is below the bound for our * PolyModulusDegree: CoeffModulus.MaxBitCount(8192) returns 218. */ ulong polyModulusDegree = 8192; parms.PolyModulusDegree = polyModulusDegree; parms.CoeffModulus = CoeffModulus.Create( polyModulusDegree, new int[] { 60, 40, 40, 60 }); /* * We choose the initial scale to be 2^40. At the last level, this leaves us * 60-40=20 bits of precision before the decimal point, and enough (roughly * 10-20 bits) of precision after the decimal point. Since our intermediate * primes are 40 bits (in fact, they are very close to 2^40), we can achieve * scale stabilization as described above. */ double scale = Math.Pow(2.0, 40); using SEALContext context = new SEALContext(parms); Utilities.PrintParameters(context); Console.WriteLine(); using KeyGenerator keygen = new KeyGenerator(context); using PublicKey publicKey = keygen.PublicKey; using SecretKey secretKey = keygen.SecretKey; using RelinKeys relinKeys = keygen.RelinKeysLocal(); using Encryptor encryptor = new Encryptor(context, publicKey); using Evaluator evaluator = new Evaluator(context); using Decryptor decryptor = new Decryptor(context, secretKey); using CKKSEncoder encoder = new CKKSEncoder(context); ulong slotCount = encoder.SlotCount; Console.WriteLine($"Number of slots: {slotCount}"); List <double> input = new List <double>((int)slotCount); double currPoint = 0, stepSize = 1.0 / (slotCount - 1); for (ulong i = 0; i < slotCount; i++, currPoint += stepSize) { input.Add(currPoint); } Console.WriteLine("Input vector:"); Utilities.PrintVector(input, 3, 7); Console.WriteLine("Evaluating polynomial PI*x^3 + 0.4x + 1 ..."); /* * We create plaintexts for PI, 0.4, and 1 using an overload of CKKSEncoder.Encode * that encodes the given floating-point value to every slot in the vector. */ using Plaintext plainCoeff3 = new Plaintext(), plainCoeff1 = new Plaintext(), plainCoeff0 = new Plaintext(); encoder.Encode(3.14159265, scale, plainCoeff3); encoder.Encode(0.4, scale, plainCoeff1); encoder.Encode(1.0, scale, plainCoeff0); using Plaintext xPlain = new Plaintext(); Utilities.PrintLine(); Console.WriteLine("Encode input vectors."); encoder.Encode(input, scale, xPlain); using Ciphertext x1Encrypted = new Ciphertext(); encryptor.Encrypt(xPlain, x1Encrypted); /* * To compute x^3 we first compute x^2 and relinearize. However, the scale has * now grown to 2^80. */ using Ciphertext x3Encrypted = new Ciphertext(); Utilities.PrintLine(); Console.WriteLine("Compute x^2 and relinearize:"); evaluator.Square(x1Encrypted, x3Encrypted); evaluator.RelinearizeInplace(x3Encrypted, relinKeys); Console.WriteLine(" + Scale of x^2 before rescale: {0} bits", Math.Log(x3Encrypted.Scale, newBase: 2)); /* * Now rescale; in addition to a modulus switch, the scale is reduced down by * a factor equal to the prime that was switched away (40-bit prime). Hence, the * new scale should be close to 2^40. Note, however, that the scale is not equal * to 2^40: this is because the 40-bit prime is only close to 2^40. */ Utilities.PrintLine(); Console.WriteLine("Rescale x^2."); evaluator.RescaleToNextInplace(x3Encrypted); Console.WriteLine(" + Scale of x^2 after rescale: {0} bits", Math.Log(x3Encrypted.Scale, newBase: 2)); /* * Now x3Encrypted is at a different level than x1Encrypted, which prevents us * from multiplying them to compute x^3. We could simply switch x1Encrypted to * the next parameters in the modulus switching chain. However, since we still * need to multiply the x^3 term with PI (plainCoeff3), we instead compute PI*x * first and multiply that with x^2 to obtain PI*x^3. To this end, we compute * PI*x and rescale it back from scale 2^80 to something close to 2^40. */ Utilities.PrintLine(); Console.WriteLine("Compute and rescale PI*x."); using Ciphertext x1EncryptedCoeff3 = new Ciphertext(); evaluator.MultiplyPlain(x1Encrypted, plainCoeff3, x1EncryptedCoeff3); Console.WriteLine(" + Scale of PI*x before rescale: {0} bits", Math.Log(x1EncryptedCoeff3.Scale, newBase: 2)); evaluator.RescaleToNextInplace(x1EncryptedCoeff3); Console.WriteLine(" + Scale of PI*x after rescale: {0} bits", Math.Log(x1EncryptedCoeff3.Scale, newBase: 2)); /* * Since x3Encrypted and x1EncryptedCoeff3 have the same exact scale and use * the same encryption parameters, we can multiply them together. We write the * result to x3Encrypted, relinearize, and rescale. Note that again the scale * is something close to 2^40, but not exactly 2^40 due to yet another scaling * by a prime. We are down to the last level in the modulus switching chain. */ Utilities.PrintLine(); Console.WriteLine("Compute, relinearize, and rescale (PI*x)*x^2."); evaluator.MultiplyInplace(x3Encrypted, x1EncryptedCoeff3); evaluator.RelinearizeInplace(x3Encrypted, relinKeys); Console.WriteLine(" + Scale of PI*x^3 before rescale: {0} bits", Math.Log(x3Encrypted.Scale, newBase: 2)); evaluator.RescaleToNextInplace(x3Encrypted); Console.WriteLine(" + Scale of PI*x^3 after rescale: {0} bits", Math.Log(x3Encrypted.Scale, newBase: 2)); /* * Next we compute the degree one term. All this requires is one MultiplyPlain * with plainCoeff1. We overwrite x1Encrypted with the result. */ Utilities.PrintLine(); Console.WriteLine("Compute and rescale 0.4*x."); evaluator.MultiplyPlainInplace(x1Encrypted, plainCoeff1); Console.WriteLine(" + Scale of 0.4*x before rescale: {0} bits", Math.Log(x1Encrypted.Scale, newBase: 2)); evaluator.RescaleToNextInplace(x1Encrypted); Console.WriteLine(" + Scale of 0.4*x after rescale: {0} bits", Math.Log(x1Encrypted.Scale, newBase: 2)); /* * Now we would hope to compute the sum of all three terms. However, there is * a serious problem: the encryption parameters used by all three terms are * different due to modulus switching from rescaling. * * Encrypted addition and subtraction require that the scales of the inputs are * the same, and also that the encryption parameters (ParmsId) match. If there * is a mismatch, Evaluator will throw an exception. */ Console.WriteLine(); Utilities.PrintLine(); Console.WriteLine("Parameters used by all three terms are different:"); Console.WriteLine(" + Modulus chain index for x3Encrypted: {0}", context.GetContextData(x3Encrypted.ParmsId).ChainIndex); Console.WriteLine(" + Modulus chain index for x1Encrypted: {0}", context.GetContextData(x1Encrypted.ParmsId).ChainIndex); Console.WriteLine(" + Modulus chain index for plainCoeff0: {0}", context.GetContextData(plainCoeff0.ParmsId).ChainIndex); Console.WriteLine(); /* * Let us carefully consider what the scales are at this point. We denote the * primes in coeff_modulus as P_0, P_1, P_2, P_3, in this order. P_3 is used as * the special modulus and is not involved in rescalings. After the computations * above the scales in ciphertexts are: * * - Product x^2 has scale 2^80 and is at level 2; * - Product PI*x has scale 2^80 and is at level 2; * - We rescaled both down to scale 2^80/P2 and level 1; * - Product PI*x^3 has scale (2^80/P_2)^2; * - We rescaled it down to scale (2^80/P_2)^2/P_1 and level 0; * - Product 0.4*x has scale 2^80; * - We rescaled it down to scale 2^80/P_2 and level 1; * - The contant term 1 has scale 2^40 and is at level 2. * * Although the scales of all three terms are approximately 2^40, their exact * values are different, hence they cannot be added together. */ Utilities.PrintLine(); Console.WriteLine("The exact scales of all three terms are different:"); Console.WriteLine(" + Exact scale in PI*x^3: {0:0.0000000000}", x3Encrypted.Scale); Console.WriteLine(" + Exact scale in 0.4*x: {0:0.0000000000}", x1Encrypted.Scale); Console.WriteLine(" + Exact scale in 1: {0:0.0000000000}", plainCoeff0.Scale); Console.WriteLine(); /* * There are many ways to fix this problem. Since P_2 and P_1 are really close * to 2^40, we can simply "lie" to Microsoft SEAL and set the scales to be the * same. For example, changing the scale of PI*x^3 to 2^40 simply means that we * scale the value of PI*x^3 by 2^120/(P_2^2*P_1), which is very close to 1. * This should not result in any noticeable error. * * Another option would be to encode 1 with scale 2^80/P_2, do a MultiplyPlain * with 0.4*x, and finally rescale. In this case we would need to additionally * make sure to encode 1 with appropriate encryption parameters (ParmsId). * * In this example we will use the first (simplest) approach and simply change * the scale of PI*x^3 and 0.4*x to 2^40. */ Utilities.PrintLine(); Console.WriteLine("Normalize scales to 2^40."); x3Encrypted.Scale = Math.Pow(2.0, 40); x1Encrypted.Scale = Math.Pow(2.0, 40); /* * We still have a problem with mismatching encryption parameters. This is easy * to fix by using traditional modulus switching (no rescaling). CKKS supports * modulus switching just like the BFV scheme, allowing us to switch away parts * of the coefficient modulus when it is simply not needed. */ Utilities.PrintLine(); Console.WriteLine("Normalize encryption parameters to the lowest level."); ParmsId lastParmsId = x3Encrypted.ParmsId; evaluator.ModSwitchToInplace(x1Encrypted, lastParmsId); evaluator.ModSwitchToInplace(plainCoeff0, lastParmsId); /* * All three ciphertexts are now compatible and can be added. */ Utilities.PrintLine(); Console.WriteLine("Compute PI*x^3 + 0.4*x + 1."); using Ciphertext encryptedResult = new Ciphertext(); evaluator.Add(x3Encrypted, x1Encrypted, encryptedResult); evaluator.AddPlainInplace(encryptedResult, plainCoeff0); /* * First print the true result. */ using Plaintext plainResult = new Plaintext(); Utilities.PrintLine(); Console.WriteLine("Decrypt and decode PI * x ^ 3 + 0.4x + 1."); Console.WriteLine(" + Expected result:"); List <double> trueResult = new List <double>(input.Count); foreach (double x in input) { trueResult.Add((3.14159265 * x * x + 0.4) * x + 1); } Utilities.PrintVector(trueResult, 3, 7); /* * We decrypt, decode, and print the result. */ decryptor.Decrypt(encryptedResult, plainResult); List <double> result = new List <double>(); encoder.Decode(plainResult, result); Console.WriteLine(" + Computed result ...... Correct."); Utilities.PrintVector(result, 3, 7); /* * While we did not show any computations on complex numbers in these examples, * the CKKSEncoder would allow us to have done that just as easily. Additions * and multiplications of complex numbers behave just as one would expect. */ }