Skip to content

invariant_noise_budget does not guarantee correctness and should be noted as such in docstring #742

@ChanYatChunSunny

Description

@ChanYatChunSunny

Decryptor::invariant_noise_budget does not always return 0 when the error has entered the message space.

Since, at least for BFV, the function calculates the noise by canceling the message term with
$t(\frac{q}{t}m+e)\mathrm{\ }mod\mathrm{\ }q$
$=qm+e \mathrm{\ }mod\mathrm{\ } q$
$=e\mathrm{\ }mod\mathrm{\ } q$

By noise-growing techniques like adding a ciphertext by itself repeatedly, one could get $e' \geq \frac{q}{t}e$, where by substituting $e$ with $e'$:

$t(\frac{q}{t}m+\frac{q}{t}e)\mathrm{\ }mod\mathrm{\ }q$
$=qm+qe\mathrm{\ }mod\mathrm{\ }q$
$= 0$

Since the question of whether the noise has entered the message space is both an integrity and a secrecy issue, the docstring of the function should clearly state that it provides no correctness guarantee and should only be used for reference/sanity check, not for security purposes.

This example in C# shows that the function sometimes returns a non-zero value when the decryption is not correct:

        static void Main(string[] args)
        {
            using EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV);
            parms.PolyModulusDegree = 8192;
            parms.CoeffModulus = CoeffModulus.BFVDefault(parms.PolyModulusDegree);
            parms.PlainModulus = PlainModulus.Batching(parms.PolyModulusDegree, 20);
            using SEALContext context = new SEALContext(parms);
            using KeyGenerator keygen = new KeyGenerator(context);

            using SecretKey secretKey = keygen.SecretKey;
            keygen.CreatePublicKey(out PublicKey publicKey);
            using BatchEncoder batchEncoder = new BatchEncoder(context);
            using Encryptor encryptor = new Encryptor(context, publicKey);
            using Evaluator evaluator = new Evaluator(context);
            using Decryptor decryptor = new Decryptor(context, secretKey);
            using Plaintext plaintextZero = new Plaintext();
            batchEncoder.Encode(new ulong[batchEncoder.SlotCount], plaintextZero);
            Ciphertext ciphertext = new Ciphertext();
            encryptor.Encrypt(plaintextZero, ciphertext);
            for (int i = 0; ; i++)
            {
                evaluator.AddInplace(ciphertext, ciphertext);
                using Plaintext plaintextAddResult = new Plaintext();
                decryptor.Decrypt(ciphertext, plaintextAddResult);
                int budget = decryptor.InvariantNoiseBudget(ciphertext);
                string plaintextAddResultStrIsZero = plaintextAddResult[0] == 0 ? "is zero" : "is not zero";
                Console.WriteLine($"[{i}]: Budget is {budget}, plaintext {plaintextAddResultStrIsZero}");
                if (budget != 0 && plaintextAddResult[0] != 0) 
                { Console.WriteLine($"Noise budget is not zero at {i} when the decryption is not correct"); return; }
            }
        }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions