mirror of
https://github.com/zama-ai/concrete.git
synced 2026-01-09 12:57:55 -05:00
chore(compiler): Update security curves
security estimated using the MATZOV cost model in the lattice estimator commit: 60808bdc17f99b78bd1bbcd621af04bc6f0e98bb (see "Report on the Security of LWE: Improved Dual Lattice Attack", April 2022)
This commit is contained in:
2
third_party/lattice-estimator
vendored
2
third_party/lattice-estimator
vendored
Submodule third_party/lattice-estimator updated: f9f4b3c69d...f18533a194
@@ -1,69 +0,0 @@
|
||||
LATTICE_ESTIMATOR_DIR=$(PWD)/../../third_party/lattice-estimator
|
||||
SECURITY_LEVELS=80 112 128 192
|
||||
SAGE_OBJECT_DIR=sage-object
|
||||
SAGE_SECURITY_CURVES=$(SECURITY_LEVELS:%=$(SAGE_OBJECT_DIR)/%.sobj)
|
||||
SAGE_VERIFIED_CURVES=$(SAGE_OBJECT_DIR)/verified_curves.sobj
|
||||
CURVES_JSON_PATH=json/curves.json
|
||||
CURVES_CPP_GEN_H=concrete-security-curves-cpp/include/concrete/curves.gen.h
|
||||
CURVES_RUST_GEN_TXT=concrete-security-curves-rust/src/gaussian/curves_gen.rs
|
||||
|
||||
generate-code: generate-cpp generate-rust
|
||||
|
||||
# Generate CPP ########################
|
||||
|
||||
$(CURVES_CPP_GEN_H): concrete-security-curves-cpp/gen_header.py $(CURVES_JSON_PATH)
|
||||
cat $(CURVES_JSON_PATH) | python3 concrete-security-curves-cpp/gen_header.py > $(CURVES_CPP_GEN_H)
|
||||
|
||||
generate-cpp: $(CURVES_CPP_GEN_H)
|
||||
|
||||
# Generate RUST ########################
|
||||
|
||||
$(CURVES_RUST_GEN_TXT): concrete-security-curves-rust/gen_table.py $(CURVES_JSON_PATH)
|
||||
cat $(CURVES_JSON_PATH) | python3 concrete-security-curves-rust/gen_table.py > $(CURVES_RUST_GEN_TXT)
|
||||
|
||||
generate-rust: $(CURVES_RUST_GEN_TXT)
|
||||
|
||||
# Compare curves #######################
|
||||
|
||||
$(SAGE_OBJECT_DIR)/outdated_curves.timestamp: ./lattice-scripts/compare_curves_and_estimator.py
|
||||
PYTHONPATH=$(LATTICE_ESTIMATOR_DIR) python3 ./lattice-scripts/compare_curves_and_estimator.py \
|
||||
--curves-dir $(SAGE_OBJECT_DIR) --security-levels $(SECURITY_LEVELS) --log-q 64 \
|
||||
&& touch $(SAGE_OBJECT_DIR)/outdated_curves.timestamp
|
||||
|
||||
compare-curves: $(SAGE_OBJECT_DIR)/outdated_curves.timestamp
|
||||
|
||||
# Compare curves custom q #######################
|
||||
# run via e.g:
|
||||
# logq=128 make compare-curves-custom-q
|
||||
# for q = 2**(128)
|
||||
|
||||
$(SAGE_OBJECT_DIR)/outdated_curves.timestamp: ./lattice-scripts/compare_curves_and_estimator.py
|
||||
PYTHONPATH=$(LATTICE_ESTIMATOR_DIR) python3 ./lattice-scripts/compare_curves_and_estimator.py \
|
||||
--curves-dir $(SAGE_OBJECT_DIR) --security-levels $(SECURITY_LEVELS) --log-q $(logq) \
|
||||
&& touch $(SAGE_OBJECT_DIR)/outdated_curves.timestamp
|
||||
|
||||
compare-curves-custom-q: $(SAGE_OBJECT_DIR)/outdated_curves.timestamp
|
||||
|
||||
# Generate curves ######################
|
||||
|
||||
$(SAGE_OBJECT_DIR)/%.sobj: $(SAGE_OBJECT_DIR)/outdated_curves.timestamp ./lattice-scripts/generate_data.sh ./lattice-scripts/generate_data.py
|
||||
PYTHONPATH=$(LATTICE_ESTIMATOR_DIR) ./lattice-scripts/generate_data.sh \
|
||||
$* --output $(SAGE_OBJECT_DIR) --old-models $(SAGE_VERIFIED_CURVES)
|
||||
|
||||
generate-curves: $(SAGE_SECURITY_CURVES)
|
||||
|
||||
# Verify curves #######################
|
||||
|
||||
$(CURVES_JSON_PATH) $(SAGE_VERIFIED_CURVES): ./lattice-scripts/verify_curves.py #$(SAGE_SECURITY_CURVES)
|
||||
python3 ./lattice-scripts/verify_curves.py \
|
||||
--curves-dir $(SAGE_OBJECT_DIR) --verified-curves-path $(SAGE_VERIFIED_CURVES) \
|
||||
--security-levels $(SECURITY_LEVELS) --log-q 64 > $(CURVES_JSON_PATH)
|
||||
|
||||
verify-curves: $(CURVES_JSON_PATH)
|
||||
|
||||
.PHONY: generate-cpp \
|
||||
generate-rust \
|
||||
generate-code \
|
||||
compare-curves \
|
||||
generate-curves \
|
||||
verify-curves
|
||||
@@ -1,43 +0,0 @@
|
||||
=========
|
||||
Parameter Curves
|
||||
=========
|
||||
|
||||
This folder contains the code used to choose secure parameters using the Lattice-Estimator_. In particular, we use data obtained from calls to the lattice estimator to generate parameter curves of the form: ``sigma(n) = a * n + b`` which can then be used to choose a suitable error standard deviation `sigma` for a given LWE dimension n.
|
||||
|
||||
Usage
|
||||
---------
|
||||
|
||||
To generate the raw data from the lattice estimator, use::
|
||||
|
||||
make generate-curves
|
||||
|
||||
by default, this script will generate parameter curves for {80, 112, 128, 192} bits of security, using ``log_2(q) = 64``.
|
||||
|
||||
To compare the current curves with the output of the lattice estimator, use::
|
||||
|
||||
make compare-curves
|
||||
|
||||
this will compare the four curves generated above against the output of the version of the lattice estimator found in /third_party.
|
||||
|
||||
To generate the associated cpp and rust code, use::
|
||||
|
||||
make generate-code
|
||||
|
||||
further advanced options can be found inside the Makefile.
|
||||
|
||||
Current curves
|
||||
---------
|
||||
|
||||
Current versions of the curves can be found in the ``sage-object`` folder_. To view the raw data used to generate a curve, load one of the files contained in the director sage-object in Sagemath::
|
||||
|
||||
sage: X = load("128.sobj")
|
||||
|
||||
entries are tuples of the form: ``(n, log_2(q), log_2(sd), \lambda)``. We can view individual entries via::
|
||||
|
||||
sage: X["128"][0]
|
||||
(2366, 64.0, 4.0, 128.51)
|
||||
|
||||
|
||||
|
||||
.. _Lattice-Estimator: https://github.com/malb/lattice-estimator
|
||||
.. _folder: https://github.com/zama-ai/concrete/tree/main/tools/parameter-curves/sage-object
|
||||
@@ -1,13 +0,0 @@
|
||||
import sys, json;
|
||||
|
||||
def print_curve(data):
|
||||
print(f'\tSecurityCurve({data["security_level"]},{data["slope"]}, {data["bias"]}, {data["minimal_lwe_dimension"]}, KeyFormat::BINARY),')
|
||||
|
||||
def print_cpp_curves_declaration(datas):
|
||||
print("SecurityCurve curves[] = {")
|
||||
for data in datas:
|
||||
print_curve(data)
|
||||
print("};\n")
|
||||
print(f"size_t curvesLen = {len(data)};")
|
||||
|
||||
print_cpp_curves_declaration(json.load(sys.stdin))
|
||||
@@ -1,8 +1,5 @@
|
||||
SecurityCurve curves[] = {
|
||||
SecurityCurve(80,-0.04045822621883835, 1.7183812000404686, 450, KeyFormat::BINARY),
|
||||
SecurityCurve(112,-0.029881371645803536, 2.6539316216894946, 450, KeyFormat::BINARY),
|
||||
SecurityCurve(128,-0.026599462343105267, 2.981543184145991, 450, KeyFormat::BINARY),
|
||||
SecurityCurve(192,-0.018894148763647572, 4.2700349965659115, 532, KeyFormat::BINARY),
|
||||
SecurityCurve(128, -0.025696778711484593, 2.675931372549016, 450, KeyFormat::BINARY),
|
||||
};
|
||||
|
||||
size_t curvesLen = 4;
|
||||
size_t curvesLen = 1;
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import sys, json;
|
||||
|
||||
def print_curve(data):
|
||||
print(f' ({data["security_level"]}, SecurityWeights {{ slope: {data["slope"]}, bias: {data["bias"]}, minimal_lwe_dimension: {data["minimal_lwe_dimension"]} }}),')
|
||||
|
||||
|
||||
def print_rust_curves_declaration(datas):
|
||||
print("use super::security_weights::SecurityWeights;")
|
||||
print(f"pub const SECURITY_WEIGHTS_ARRAY: [(u64, SecurityWeights); {len(datas)}] = [")
|
||||
for data in datas:
|
||||
print_curve(data)
|
||||
print("];")
|
||||
|
||||
print_rust_curves_declaration(json.load(sys.stdin))
|
||||
@@ -1,7 +1,4 @@
|
||||
use super::security_weights::SecurityWeights;
|
||||
pub const SECURITY_WEIGHTS_ARRAY: [(u64, SecurityWeights); 4] = [
|
||||
(80, SecurityWeights { slope: -0.04045822621883835, bias: 1.7183812000404686, minimal_lwe_dimension: 450 }),
|
||||
(112, SecurityWeights { slope: -0.029881371645803536, bias: 2.6539316216894946, minimal_lwe_dimension: 450 }),
|
||||
(128, SecurityWeights { slope: -0.026599462343105267, bias: 2.981543184145991, minimal_lwe_dimension: 450 }),
|
||||
(192, SecurityWeights { slope: -0.018894148763647572, bias: 4.2700349965659115, minimal_lwe_dimension: 532 }),
|
||||
pub const SECURITY_WEIGHTS_ARRAY: [(u64, SecurityWeights); 1] = [
|
||||
(128, SecurityWeights { slope: -0.025696778711484593, bias: 2.675931372549016, minimal_lwe_dimension: 450 }),
|
||||
];
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
[{"slope": -0.04045822621883835, "bias": 1.7183812000404686, "security_level": 80, "minimal_lwe_dimension": 450}, {"slope": -0.029881371645803536, "bias": 2.6539316216894946, "security_level": 112, "minimal_lwe_dimension": 450}, {"slope": -0.026599462343105267, "bias": 2.981543184145991, "security_level": 128, "minimal_lwe_dimension": 450}, {"slope": -0.018894148763647572, "bias": 4.2700349965659115, "security_level": 192, "minimal_lwe_dimension": 532}]
|
||||
@@ -1,139 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
from estimator import LWE, ND, RC
|
||||
from sage.all import oo, load, floor, ceil
|
||||
from generate_data import estimate, get_security_level
|
||||
import argparse
|
||||
|
||||
|
||||
LOG_N_MAX = 17 + 1
|
||||
LOG_N_MIN = 10
|
||||
|
||||
def get_index(sec, curves):
|
||||
"""
|
||||
Retrieve the index of the curve corresponding to the right security :sec:
|
||||
:param sec: security level
|
||||
:param curves: output of `generate_and_verify`
|
||||
:return: index of the right curve
|
||||
"""
|
||||
# TODO: Duplicated code from verify_curve
|
||||
for i in range(len(curves)):
|
||||
if curves[i][2] == sec:
|
||||
return i
|
||||
|
||||
|
||||
def estimate_security_with_lattice_estimator(lwe_dimension, std_dev, log_q):
|
||||
"""
|
||||
Return the security of (lwe_dimension, std_dev, log_q) as estimated by the latest
|
||||
version of the lattice estimator
|
||||
:param lwe_dimension:
|
||||
:param std_dev:
|
||||
:param log_q:
|
||||
:return:
|
||||
"""
|
||||
params = LWE.Parameters(
|
||||
n=lwe_dimension, q=2 ** log_q, Xs=ND.UniformMod(2), Xe=ND.DiscreteGaussian(std_dev), m=oo, tag="params"
|
||||
)
|
||||
costs = estimate(params, red_cost_model = RC.BDGL16)
|
||||
return get_security_level(costs, 2)
|
||||
|
||||
def get_minimal_lwe_dimension(curve, security_level, log_q):
|
||||
"""
|
||||
Retrieve the smallest lwe dimension usable for the given security level and log_q
|
||||
:param curve:
|
||||
:param security_level:
|
||||
:param log_q:
|
||||
:return:
|
||||
"""
|
||||
minimal_lwe_dim = curve[-1]
|
||||
return minimal_lwe_dim
|
||||
|
||||
|
||||
def estimate_stddev_with_current_curve(curve, lwe_dimension, log_q):
|
||||
"""
|
||||
Use the current formula to estimate the secure noise from the lwe_dimension
|
||||
:param curve:
|
||||
:param lwe_dimension:
|
||||
:param log_q:
|
||||
:return:
|
||||
"""
|
||||
|
||||
def minimal_stddev(a, b, lwe_dim):
|
||||
return 2. ** max(ceil(a * lwe_dim + b), 2)
|
||||
|
||||
a = curve[0]
|
||||
b = curve[1] + log_q
|
||||
|
||||
stddev = minimal_stddev(a, b, lwe_dimension)
|
||||
return stddev
|
||||
|
||||
|
||||
def compare_curve_and_estimator(security_level, log_q, curves_dir):
|
||||
"""
|
||||
For a subset of every lwe dimension possibles, estimate the security of those lwe dimension
|
||||
associated with the stddev recommended by our current curve.
|
||||
|
||||
|
||||
Test whether some (lwe_dimension, std dev) that are assumed to be secure with
|
||||
the current curves are
|
||||
:param security_level:
|
||||
:param log_q:
|
||||
:return: If one of (lwe dim, std dev) is estimated to be less secure than our target `security_level`
|
||||
this function return False, else return True
|
||||
"""
|
||||
print(f"Security Target: {security_level} bits")
|
||||
|
||||
# step 0. loading the right curve
|
||||
curves = load(os.path.join(curves_dir, "verified_curves.sobj"))
|
||||
j = get_index(security_level, curves)
|
||||
curve = curves[j]
|
||||
|
||||
# step 1. define range of lwe dimensions
|
||||
n_min = curve[-1]
|
||||
n_min = max(2 * security_level, 450, n_min)
|
||||
# TODO: REMOVE HARDCODED 10
|
||||
lwe_dimensions = list(range(n_min, 1024, 10)) + [2**i for i in range(LOG_N_MIN, LOG_N_MAX)]
|
||||
|
||||
# step 2. check security of those points
|
||||
for lwe_dim in lwe_dimensions:
|
||||
print("-------------------------")
|
||||
# (i) get stddev with current curves
|
||||
predicted_stddev = estimate_stddev_with_current_curve(curve, lwe_dim, log_q)
|
||||
# (ii) estimate up-to-date security
|
||||
predicted_security = estimate_security_with_lattice_estimator(lwe_dim, predicted_stddev, log_q)
|
||||
|
||||
print("-------------------------")
|
||||
print(f"lwe dim: {lwe_dim}")
|
||||
print(f"stddev: {predicted_stddev}")
|
||||
print(f"Security: {predicted_security}")
|
||||
|
||||
if predicted_security < security_level:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
CLI = argparse.ArgumentParser()
|
||||
CLI.add_argument(
|
||||
"--curves-dir",
|
||||
help="The directory where curves has been saved (sage object)",
|
||||
type=str,
|
||||
required=True,
|
||||
)
|
||||
CLI.add_argument(
|
||||
"--security-levels",
|
||||
help="The security levels to verify",
|
||||
nargs="+",
|
||||
type=int,
|
||||
required=True
|
||||
)
|
||||
CLI.add_argument(
|
||||
"--log-q",
|
||||
type=int,
|
||||
required=True
|
||||
)
|
||||
args = CLI.parse_args()
|
||||
for security_level in args.security_levels:
|
||||
if not(compare_curve_and_estimator(security_level, args.log_q, args.curves_dir)):
|
||||
exit(1)
|
||||
exit(0)
|
||||
@@ -1,238 +0,0 @@
|
||||
from sage.all import oo, save, load
|
||||
from math import log2
|
||||
import multiprocessing
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from estimator import RC, LWE, ND
|
||||
|
||||
|
||||
old_models_sobj = ""
|
||||
|
||||
def old_models(security_level, sd, logq=32):
|
||||
"""
|
||||
Use the old model as a starting point for the data gathering step
|
||||
:param security_level: the security level under consideration
|
||||
:param sd : the standard deviation of the LWE error distribution Xe
|
||||
:param logq : the (base 2 log) value of the LWE modulus q
|
||||
"""
|
||||
|
||||
def evaluate_model(a, b, stddev=sd):
|
||||
return (stddev - b) / a
|
||||
|
||||
def get_index(sec, curves):
|
||||
for i in range(len(curves)):
|
||||
if curves[i][2] == sec:
|
||||
return i
|
||||
|
||||
if old_models_sobj is None or not(os.path.exists(old_models_sobj)):
|
||||
return 450
|
||||
|
||||
curves = load(old_models_sobj)
|
||||
j = get_index(security_level, curves)
|
||||
|
||||
a = curves[j][0]
|
||||
b = curves[j][1] + logq
|
||||
|
||||
n_est = evaluate_model(a, b, sd)
|
||||
|
||||
return round(n_est)
|
||||
|
||||
|
||||
def estimate(params, red_cost_model=RC.BDGL16, skip=("arora-gb", "bkw")):
|
||||
"""
|
||||
Retrieve an estimate using the Lattice Estimator, for a given set of input parameters
|
||||
:param params: the input LWE parameters
|
||||
:param red_cost_model: the lattice reduction cost model
|
||||
:param skip: attacks to skip
|
||||
"""
|
||||
|
||||
est = LWE.estimate(params, red_cost_model=red_cost_model, deny_list=skip)
|
||||
|
||||
return est
|
||||
|
||||
|
||||
def get_security_level(est, dp=2):
|
||||
"""
|
||||
Get the security level lambda from a Lattice Estimator output
|
||||
:param est: the Lattice Estimator output
|
||||
:param dp: the number of decimal places to consider
|
||||
"""
|
||||
attack_costs = []
|
||||
# note: key does not need to be specified est vs est.keys()
|
||||
for key in est:
|
||||
attack_costs.append(est[key]["rop"])
|
||||
# get the security level correct to 'dp' decimal places
|
||||
security_level = round(log2(min(attack_costs)), dp)
|
||||
|
||||
return security_level
|
||||
|
||||
|
||||
def inequality(x, y):
|
||||
"""A utility function which compresses the conditions x < y and x > y into a single condition via a multiplier
|
||||
:param x: the LHS of the inequality
|
||||
:param y: the RHS of the inequality
|
||||
"""
|
||||
if x <= y:
|
||||
return 1
|
||||
|
||||
if x > y:
|
||||
return -1
|
||||
|
||||
|
||||
def automated_param_select_n(params, target_security=128):
|
||||
"""A function used to generate the smallest value of n which allows for
|
||||
target_security bits of security, for the input values of (params.Xe.stddev,params.q)
|
||||
:param params: the standard deviation of the error
|
||||
:param target_security: the target number of bits of security, 128 is default
|
||||
|
||||
EXAMPLE:
|
||||
sage: X = automated_param_select_n(Kyber512, target_security = 128)
|
||||
sage: X
|
||||
456
|
||||
"""
|
||||
|
||||
# get an estimate based on the prev. model
|
||||
print("n = {}".format(params.n))
|
||||
n_start = old_models(target_security, log2(params.Xe.stddev), log2(params.q))
|
||||
# n_start = max(n_start, 450)
|
||||
# TODO: think about throwing an error if the required n < 450
|
||||
|
||||
params = params.updated(n=n_start)
|
||||
costs2 = estimate(params)
|
||||
security_level = get_security_level(costs2, 2)
|
||||
z = inequality(security_level, target_security)
|
||||
|
||||
# we keep n > 2 * target_security as a rough baseline for mitm security
|
||||
# (on binary key guessing)
|
||||
while z * security_level < z * target_security:
|
||||
# TODO: fill in this case! For n > 1024 we only need to consider every
|
||||
# 256 (optimization)
|
||||
params = params.updated(n=params.n + z * 8)
|
||||
costs = estimate(params)
|
||||
security_level = get_security_level(costs, 2)
|
||||
|
||||
if -1 * params.Xe.stddev > 0:
|
||||
print("target security level is unattainable")
|
||||
break
|
||||
|
||||
# final estimate (we went too far in the above loop)
|
||||
if security_level < target_security:
|
||||
# we make n larger
|
||||
print("we make n larger")
|
||||
params = params.updated(n=params.n + 8)
|
||||
costs = estimate(params)
|
||||
security_level = get_security_level(costs, 2)
|
||||
|
||||
print(
|
||||
"the finalised parameters are n = {}, log2(sd) = {}, log2(q) = {}, with a security level of {}-bits".format(
|
||||
params.n, log2(params.Xe.stddev), log2(params.q), security_level
|
||||
)
|
||||
)
|
||||
|
||||
if security_level < target_security:
|
||||
params.updated(n=None)
|
||||
|
||||
return params, security_level
|
||||
|
||||
|
||||
def generate_parameter_matrix(
|
||||
params_in, sd_range, target_security_levels=[128], name="default_name"
|
||||
):
|
||||
"""
|
||||
:param params_in: a initial set of LWE parameters
|
||||
:param sd_range: a tuple (sd_min, sd_max) giving the values of sd for which to generate parameters
|
||||
:param target_security_levels: a list of the target number of bits of security, 128 is default
|
||||
:param name: a name to save the file
|
||||
"""
|
||||
|
||||
(sd_min, sd_max) = sd_range
|
||||
for lam in target_security_levels:
|
||||
for sd in range(sd_min, sd_max + 1):
|
||||
print(f"run for {lam} {sd}")
|
||||
Xe_new = ND.DiscreteGaussian(2 ** sd)
|
||||
(params_out, sec) = automated_param_select_n(
|
||||
params_in.updated(Xe=Xe_new), target_security=lam
|
||||
)
|
||||
|
||||
try:
|
||||
results = load("{}.sobj".format(name))
|
||||
except BaseException:
|
||||
results = dict()
|
||||
results["{}".format(lam)] = []
|
||||
|
||||
results["{}".format(lam)].append(
|
||||
(params_out.n, log2(params_out.q), log2(params_out.Xe.stddev), sec)
|
||||
)
|
||||
save(results, "{}.sobj".format(name))
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def generate_zama_curves64(
|
||||
sd_range=[2, 58], target_security_levels=[128], name="default_name"
|
||||
):
|
||||
"""
|
||||
The top level function which we use to run the experiment
|
||||
|
||||
:param sd_range: a tuple (sd_min, sd_max) giving the values of sd for which to generate parameters
|
||||
:param target_security_levels: a list of the target number of bits of security, 128 is default
|
||||
:param name: a name to save the file
|
||||
"""
|
||||
if __name__ == "__main__":
|
||||
|
||||
D = ND.DiscreteGaussian
|
||||
vals = range(sd_range[0], sd_range[1])
|
||||
pool = multiprocessing.Pool(2)
|
||||
init_params = LWE.Parameters(
|
||||
n=1024, q=2 ** 64, Xs=D(0.50, -0.50), Xe=D(2 ** 55), m=oo, tag="params"
|
||||
)
|
||||
inputs = [
|
||||
(init_params, (val, val), target_security_levels, name) for val in vals
|
||||
]
|
||||
_res = pool.starmap(generate_parameter_matrix, inputs)
|
||||
|
||||
return "done"
|
||||
|
||||
if __name__ == "__main__":
|
||||
CLI = argparse.ArgumentParser()
|
||||
CLI.add_argument(
|
||||
"--security-level",
|
||||
type=int,
|
||||
required=True,
|
||||
)
|
||||
CLI.add_argument(
|
||||
"--output",
|
||||
type=str,
|
||||
required=True,
|
||||
)
|
||||
CLI.add_argument(
|
||||
"--old-models",
|
||||
type=str,
|
||||
)
|
||||
CLI.add_argument(
|
||||
"--sd-min",
|
||||
type=int,
|
||||
required=True,
|
||||
)
|
||||
CLI.add_argument(
|
||||
"--sd-max",
|
||||
type=int,
|
||||
required=True,
|
||||
)
|
||||
CLI.add_argument(
|
||||
"--margin",
|
||||
type=int,
|
||||
default=0,
|
||||
)
|
||||
args = CLI.parse_args()
|
||||
# The script runs the following commands
|
||||
# grab values of the command-line input arguments
|
||||
security = args.security_level
|
||||
sd_min = args.sd_min
|
||||
sd_max = args.sd_max
|
||||
margin = args.margin
|
||||
output = args.output
|
||||
old_models_sobj = args.old_models
|
||||
# run the code
|
||||
generate_zama_curves64(sd_range=(sd_min, sd_max), target_security_levels=[security + margin], name="security_{}_margin_{} ".format(security, margin))
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
output_dir=""
|
||||
old_models=""
|
||||
while :
|
||||
do
|
||||
case $1 in
|
||||
--help)
|
||||
echo "generate_data.sh -o [output_dir] [security_levels]"
|
||||
exit 2
|
||||
;;
|
||||
--output)
|
||||
output_dir="$2"
|
||||
shift 2
|
||||
;;
|
||||
--old-models)
|
||||
old_models="$2"
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
break;
|
||||
;;
|
||||
"")
|
||||
break
|
||||
;;
|
||||
*)
|
||||
security_levels="$security_levels $1"
|
||||
shift;
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
for security_level in $security_levels; do
|
||||
sage lattice-scripts/generate_data.py --output $output_dir/$security_level.sobj --old-models $old_models --security-level $security_level --sd-min 2 --sd-max 12 --margin 0
|
||||
sage lattice-scripts/generate_data.py --output $output_dir/$security_level.sobj --old-models $old_models --security-level $security_level --sd-min 12 --sd-max 22 --margin 0
|
||||
sage lattice-scripts/generate_data.py --output $output_dir/$security_level.sobj --old-models $old_models --security-level $security_level --sd-min 22 --sd-max 32 --margin 0
|
||||
sage lattice-scripts/generate_data.py --output $output_dir/$security_level.sobj --old-models $old_models --security-level $security_level --sd-min 32 --sd-max 42 --margin 0
|
||||
sage lattice-scripts/generate_data.py --output $output_dir/$security_level.sobj --old-models $old_models --security-level $security_level --sd-min 42 --sd-max 52 --margin 0
|
||||
sage lattice-scripts/generate_data.py --output $output_dir/$security_level.sobj --old-models $old_models --security-level $security_level --sd-min 52 --sd-max 59 --margin 0
|
||||
done
|
||||
@@ -1,134 +0,0 @@
|
||||
import numpy as np
|
||||
from sage.all import save, load, ceil
|
||||
import json
|
||||
import os
|
||||
import argparse
|
||||
|
||||
def sort_data(security_level, curves_dir):
|
||||
from operator import itemgetter
|
||||
|
||||
# step 1. load the data
|
||||
X = load(os.path.join(curves_dir, f"{security_level}.sobj"))
|
||||
|
||||
# step 2. sort by SD
|
||||
x = sorted(X["{}".format(security_level)], key=itemgetter(2))
|
||||
|
||||
# step3. replace the sorted value
|
||||
X["{}".format(security_level)] = x
|
||||
|
||||
return X
|
||||
|
||||
|
||||
def generate_curve(security_level, curves_dir):
|
||||
|
||||
# step 1. get the data
|
||||
X = sort_data(security_level, curves_dir)
|
||||
|
||||
# step 2. group the n and sigma data into lists
|
||||
N = []
|
||||
SD = []
|
||||
for x in X["{}".format(security_level)]:
|
||||
N.append(x[0])
|
||||
SD.append(x[2] + 0.5)
|
||||
|
||||
# step 3. perform interpolation and return coefficients
|
||||
(a, b) = np.polyfit(N, SD, 1)
|
||||
|
||||
return a, b
|
||||
|
||||
|
||||
def verify_curve(security_level, a, b, curves_dir):
|
||||
|
||||
# step 1. get the table and max values of n, sd
|
||||
X = sort_data(security_level, curves_dir)
|
||||
n_max = X["{}".format(security_level)][0][0]
|
||||
|
||||
# step 2. a function to get model values
|
||||
def f_model(a, b, n):
|
||||
return ceil(a * n + b)
|
||||
|
||||
# step 3. a function to get table values
|
||||
def f_table(table, n):
|
||||
for i in range(len(table)):
|
||||
n_val = table[i][0]
|
||||
if n < n_val:
|
||||
pass
|
||||
else:
|
||||
j = i
|
||||
break
|
||||
|
||||
# now j is the correct index, we return the corresponding sd
|
||||
return table[j][2]
|
||||
|
||||
# step 3. for each n, check whether we satisfy the table
|
||||
n_min = max(2 * security_level, 450, X["{}".format(security_level)][-1][0])
|
||||
|
||||
for n in range(n_max, n_min, -1):
|
||||
model_sd = f_model(a, b, n)
|
||||
table_sd = f_table(X["{}".format(security_level)], n)
|
||||
#print(n, table_sd, model_sd, model_sd >= table_sd)
|
||||
|
||||
if table_sd > model_sd:
|
||||
#print("MODEL FAILS at n = {}".format(n))
|
||||
return False
|
||||
|
||||
return True, n_min
|
||||
|
||||
|
||||
def generate_and_verify(security_levels, log_q, curves_dir, verified_curves_path):
|
||||
success = []
|
||||
json = []
|
||||
|
||||
fail = []
|
||||
|
||||
for sec in security_levels:
|
||||
# generate the model for security level sec
|
||||
(a_sec, b_sec) = generate_curve(sec, curves_dir)
|
||||
# verify the model for security level sec
|
||||
(status, n_alpha) = verify_curve(sec, a_sec, b_sec, curves_dir)
|
||||
# append the information into a list
|
||||
if status:
|
||||
json.append({"slope": a_sec, "bias": b_sec - log_q, "security_level": sec, "minimal_lwe_dimension": n_alpha})
|
||||
success.append((a_sec, b_sec - log_q, sec, a_sec, b_sec))
|
||||
else:
|
||||
fail.append(sec)
|
||||
|
||||
save(success, verified_curves_path)
|
||||
|
||||
return json, fail
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
CLI = argparse.ArgumentParser()
|
||||
CLI.add_argument(
|
||||
"--verified-curves-path",
|
||||
help="The path to store the verified curves (sage object)",
|
||||
type=str,
|
||||
required=True,
|
||||
)
|
||||
CLI.add_argument(
|
||||
"--curves-dir",
|
||||
help="The directory where curves has been saved (sage object)",
|
||||
type=str,
|
||||
required=True,
|
||||
)
|
||||
CLI.add_argument(
|
||||
"--security-levels",
|
||||
help="The security levels to verify",
|
||||
nargs="+",
|
||||
type=int,
|
||||
required=True
|
||||
)
|
||||
CLI.add_argument(
|
||||
"--log-q",
|
||||
type=int,
|
||||
required=True
|
||||
)
|
||||
args = CLI.parse_args()
|
||||
(success, fail) = generate_and_verify(args.security_levels, log_q=args.log_q, curves_dir=args.curves_dir, verified_curves_path=args.verified_curves_path)
|
||||
if (fail):
|
||||
print("FAILURE: Fail to verify the following curves")
|
||||
print(json.dumps(fail))
|
||||
exit(1)
|
||||
|
||||
print(json.dumps(success))
|
||||
@@ -1,3 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="311px" height="283px" viewBox="-0.5 -0.5 311 283" content="<mxfile host="app.diagrams.net" modified="2021-08-13T09:23:09.119Z" agent="5.0 (Macintosh)" etag="KWBmlER1U8BgVACrMNTv" version="14.8.6" type="device"><diagram id="8zlkHKYxUkOq8ADBIQsa" name="Page-1">5ZZdb9sgFIZ/jS8r2YCpe7mmXSdNk6r2ouvuCBzbaNhEmMRJf/1Ijb+7j3RK1KpXhpfDC+c8GBHgRbG9MWyVf9MCVIBCsQ3wVYBQRBB1n72ya5QEhY2QGSl8UC/cyyfwYhu2lgKqUaDVWlm5GotclyVwO9KYMboeh6VajVddsQxmwj1naq4+SGHzNovzXv8CMsvblSN60YwUrA32mVQ5E7oeSPg6wAujtW1axXYBal+8ti7NvM+/Ge02ZqC0/zIhrflXdlewux83j6uNUY/1982Zd9kwtfYJ+83aXVsBKMWnfSFdr9SlEy9zWyjXi1yzskb/7Crjcrps5oOYlbXfZ9Rl744N6AKs2bmQuq9v7GuWD0rbagYUs3Iztmcec9bZdSvcaukWRqE/kiT0Pv5AEhKOLSq9Nhz8rGE9/2IU0YmRZSYDOzNyjUHavfSM6wB06MOho8mR0M2MjowOH4SOK1ZVkv+JHnZKKpVaaKXNswFOEw6cd5GDkWUSE0fk7fMmaIwJX7ySN8WTXzU5LW9yCt5pil7mLeiSxvQ98J5g6n7Tg3lPLgo0NToy7/gEvEUMiSAv8U7QEtN3wZtMeKNX8j6f3OfdBv+bt+v2L7QmvH/n4utf</diagram></mxfile>"><defs/><g><path d="M 1 281 L 1 1" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 281 281 L 1 281" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 21 231 L 223.86 28.14" fill="none" stroke="#b85450" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 228.63 23.37 L 225.45 32.92 L 223.86 28.14 L 219.08 26.55 Z" fill="#b85450" stroke="#b85450" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><path d="M 31 241 L 273.11 47.31" fill="none" stroke="#d6b656" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 278.38 43.1 L 274.16 52.23 L 273.11 47.31 L 268.54 45.2 Z" fill="#d6b656" stroke="#d6b656" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><path d="M 41 261 L 292.54 96.53" fill="none" stroke="#82b366" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 298.19 92.84 L 293.12 101.53 L 292.54 96.53 L 288.2 93.99 Z" fill="#82b366" stroke="#82b366" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,2 +0,0 @@
|
||||
[tool.ruff]
|
||||
line-length = 169
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +0,0 @@
|
||||
xœUÏ[kA‡ñ›vÓ´<C393>ÖS[µjññmÚ®¶jëBˆï…ì<E280A6>hÜF¶˜¤ù§Û‹ J*2UðBÑSDAŠ ŠÊ¼Lg´<67>8Ã0óž™zà*|‰„S^,UjIg¾ZH–‹Þ\¾ZÍ׌'_ÌW
|
||||
øÿ<EFBFBD>³^R0°>ŸïfÁ‡–"„VÐö«½Ú²Ùì¥ßjü<6A>,Ÿ‡È
|
||||
@@ -1,9 +0,0 @@
|
||||
[(-0.04042633119364589, 1.6609788641436722, 80, 'PASS', 450),
|
||||
(-0.03414780360867051, 2.017310258660345, 96, 'PASS', 450),
|
||||
(-0.029670137081135885, 2.162463714083856, 112, 'PASS', 450),
|
||||
(-0.02640502876522622, 2.4826422691043177, 128, 'PASS', 450),
|
||||
(-0.023821437305989134, 2.7177789440636673, 144, 'PASS', 450),
|
||||
(-0.02174358218716036, 2.938810548493322, 160, 'PASS', 498),
|
||||
(-0.019904056582117684, 2.8161252801542247, 176, 'PASS', 551),
|
||||
(-0.018610403247590085, 3.2996236848399008, 192, 'PASS', 606),
|
||||
(-0.014606812351714953, 3.8493629234693003, 256, 'PASS', 826)]
|
||||
Reference in New Issue
Block a user