diff --git a/.github/workflows/parameters_check.yml b/.github/workflows/parameters_check.yml index 956dde0ab0..6eedd83e52 100644 --- a/.github/workflows/parameters_check.yml +++ b/.github/workflows/parameters_check.yml @@ -14,7 +14,7 @@ on: jobs: params-curves-security-check: - runs-on: ubuntu-latest + runs-on: large_ubuntu_16 steps: - name: Checkout tfhe-rs uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 diff --git a/ci/lattice_estimator.sage b/ci/lattice_estimator.sage index 163eeb3975..7fed9604c6 100755 --- a/ci/lattice_estimator.sage +++ b/ci/lattice_estimator.sage @@ -12,9 +12,7 @@ sys.path.insert(1, "lattice-estimator") from estimator import * # sys args to split lists to manage memory for the CI -split = 3 -part = int(sys.argv[1]) -name = sys.argv[2] +name = sys.argv[1] model = RC.MATZOV @@ -41,7 +39,7 @@ def check_security(filename): import numpy as np # split the list to help with memory consumption - for param in list(np.array_split(all_params,split)[part]): + for param in list(all_params): if param.tag.startswith("TFHE_LIB_PARAMETERS"): # This third-party parameters set is known to be less secure, just skip the analysis. continue diff --git a/ci/lattice_estimator.sage.py b/ci/lattice_estimator.sage.py new file mode 100644 index 0000000000..9685b8ee23 --- /dev/null +++ b/ci/lattice_estimator.sage.py @@ -0,0 +1,131 @@ +""" +lattice_estimator +----------------- + +Test cryptographic parameters set against several attacks to estimate their security level. +""" + + +# This file was *autogenerated* from the file ci/lattice_estimator.sage +from sage.all_cmdline import * # import sage library + +_sage_const_1 = Integer(1); _sage_const_3 = Integer(3); _sage_const_2 = Integer(2); _sage_const_132 = Integer(132); _sage_const_128 = Integer(128); _sage_const_450 = Integer(450); _sage_const_4p0 = RealNumber('4.0'); _sage_const_16384 = Integer(16384) +import pathlib +import sys + +sys.path.insert(_sage_const_1 , "lattice-estimator") +from estimator import * + +# sys args to split lists to manage memory for the CI +split = _sage_const_3 +part = int(sys.argv[_sage_const_1 ]) +name = sys.argv[_sage_const_2 ] + +model = RC.MATZOV + +# Minimum level of security thresholds for parameters set in bits +SECURITY_LEVEL_THRESHOLD_SOFT = _sage_const_132 +SECURITY_LEVEL_THRESHOLD_HARD = _sage_const_128 + + +def check_security(filename): + """ + Run lattice estimator to determine if a parameters set is secure or not. + + :param filename: name of the file containing parameters set + + :return: :class:`list` of parameters to update + """ + filepath = pathlib.Path("ci", filename) + load(filepath) + print(f"Parsing parameters in {filepath}") + + to_update = [] + to_watch = [] + + import numpy as np + + # split the list to help with memory consumption + for param in list(np.array_split(all_params,split)[part]): + if param.tag.startswith("TFHE_LIB_PARAMETERS"): + # This third-party parameters set is known to be less secure, just skip the analysis. + continue + + print(f"\t{param.tag}...\t", end="") + + is_n_size_too_low = param.n <= _sage_const_450 + is_noise_level_too_low = param.Xe.stddev < _sage_const_4p0 + if is_n_size_too_low: + reason = f"n size is too low {param.n} minimum is 450" + elif is_noise_level_too_low: + reason = f"noise level is too low {round(param.Xe.stddev,_sage_const_3 )} minimum is 4.0" + + if is_n_size_too_low or is_noise_level_too_low: + print(f"FAIL\t{reason}") + to_update.append((param, reason)) + continue + + try: + # The lattice estimator is not able to manage such large dimension. + # If we have the security for smaller `n` then we have security for larger ones. + if param.n > _sage_const_16384 : + param = param.updated(n=_sage_const_16384 ) + + usvp_level = LWE.primal_usvp(param, red_cost_model=model) + dual_level = LWE.dual_hybrid(param, red_cost_model=model) + + estimator_level = log(min(usvp_level["rop"], dual_level["rop"]), _sage_const_2 ).n() + security_level = f"security level = {estimator_level} bits" + if estimator_level < SECURITY_LEVEL_THRESHOLD_HARD: + print(f"FAIL\t({security_level})") + reason = f"attained {security_level} target is {SECURITY_LEVEL_THRESHOLD_HARD} bits" + to_update.append((param, reason)) + continue + elif estimator_level < SECURITY_LEVEL_THRESHOLD_SOFT: + print(f"WARNING\t({security_level})") + reason = f"attained {security_level} target is {SECURITY_LEVEL_THRESHOLD_SOFT} bits" + to_watch.append((param, reason)) + continue + except Exception as err: + print("FAIL") + to_update.append((param, f"{repr(err)}")) + else: + print(f"OK\t({security_level})") + + return to_update, to_watch + + +if __name__ == "__main__": + params_to_update = [] + params_to_watch = [] + + params_filename = "{}.sage".format(name) + + #in ( + # "boolean_parameters_lattice_estimator.sage", + # "shortint_classic_parameters_lattice_estimator.sage", + # "shortint_multi_bit_parameters_lattice_estimator.sage", + #): + + to_update, to_watch = check_security(params_filename) + params_to_update.extend(to_update) + params_to_watch.extend(to_watch) + + if params_to_watch: + print("Some parameters need attention") + print("------------------------------") + for param, reason in params_to_watch: + print(f"[{param.tag}] reason: {reason} (param: {param})") + + if params_to_update: + if params_to_watch: + # Add a visual separator. + print("\n\n ################################### \n\n") + print("Some parameters need update") + print("---------------------------") + for param, reason in params_to_update: + print(f"[{param.tag}] reason: {reason} (param: {param})") + sys.exit(int(_sage_const_1 )) # Explicit conversion is needed to make this call work + else: + print("All parameters passed the security check") +