Source code for sboxUv2.apn.database

from sboxUv2.core import \
    Sb, \
    degree_spectrum, algebraic_degree

from sboxUv2.statistics import \
    differential_spectrum, \
    walsh_spectrum, absolute_walsh_spectrum

from sboxUv2.ccz import \
    thickness_spectrum, \
    get_WalshZeroesSpaces, \
    ccz_equivalent_function, \
    are_ea_equivalent, \
    are_ccz_equivalent

from sboxUv2.apn import \
    get_WalshZeroesSpaces_quadratic_apn, \
    sigma_multiplicities, \
    apn_ea_mugshot, apn_ea_mugshot_from_spectra, ccz_equivalent_quadratic_function

from sboxUv2.databases import *
#from sage.all import *
from sboxUv2 import *
import hashlib

                 

[docs] class APNFunctions(FunctionsDB): """This class is expected to be bundled with a literal TinySQL database file called "apn_functions.db", and allows an easy interaction with it. It builds upon the `FunctionDB` class, and contains additional logic to handle the specifics of APN functions, and in particular of their CCZ-equivalence class. Here, "functions" should be thought of much more as "extended affine equivalence class representative" rather than function. This class provides another table containing the bases of all the spaces of dimension n contained with the Walsh zeroes of a function. In order to both save space and store the structure of a CCZ-equivalence, each APN function is stored along with the identifier of the Walsh spaces of its CCZ-equivalence class, and the FastLinearMapping that must be applied to it to obtain its own Walsh Zeroes. """ def __init__(self, db_file): # !IDEA! have a max_degree and a min_degree? super().__init__( db_file, { "lut" : "BLOB", # the lookup table of the representative "n" : "INTEGER", "m" : "INTEGER", "linearity" : "INTEGER", "thickness" : "INTEGER", "degree" : "INTEGER", "bibliography" : "TEXT", "ccz_id": "INTEGER", "mugshot" : "BLOB" } ) if self.new_db: self.number_of_ccz_classes = 0 else: try: self.cursor.execute("SELECT COUNT(ccz_id) FROM {}".format(self.functions_table)) self.number_of_ccz_classes = self.cursor.fetchall()[0][0] except: self.number_of_ccz_classes = 0 def __str__(self): return "APN function DB containing {} EA-classes from {} CCZ-classes".format( self.number_of_functions, self.number_of_ccz_classes ) # def insert_new_ea_repr(self, s, bibliography): # sb = Sb(s) # differential_spec = differential_spectrum(sb) # if differential_spec.maximum() != 2: # raise Exception("Trying to add a non-APN function to the APN function database: {}".format(lut)) # # spectra # walsh_spec = walsh_spectrum(sb) # lin = walsh_spec.absolute().maximum() # degree_spec = degree_spectrum(sb) # deg = degree_spec.maximum() # thk_spec = thickness_spectrum(sb) # thk = thk_spec.maximum() # sig_spec = sigma_multiplicities(sb, k=4) # # we assume that it is from a # self.number_of_ccz_classes += 1 # if deg == 2: # mug = apn_ea_mugshot(sb) # else: # mug = apn_ea_mugshot_from_spectra(walsh_spec, # degree_spec, # sig_spec, # thk_spec) # # inserting the function # to_insert = { # "lut" : sb.to_bytes(), # "n" : sb.get_input_length(), # "m" : sb.get_output_length(), # "bibliography" : bibliography, # "linearity" : lin, # "degree" : deg, # "thickness" : thk, # "ccz_id" : self.number_of_ccz_classes, # "mugshot" : mug # } # return self.insert_function(to_insert)
[docs] def insert_full_ccz_equivalence_class(self, s, bibliography): sb = Sb(s) differential_spec = differential_spectrum(sb) if differential_spec.maximum() != 2: raise Exception("Trying to add a non-APN function to the APN function database: {}".format(sb)) encoded = sb.to_bytes() # linear abs_walsh_spec = absolute_walsh_spectrum(sb) lin = abs_walsh_spec.maximum() inserted_ids = [] if algebraic_degree(sb) == 2: # if the function is quadratic, # we compute automorphisms # inserting the spaces ws = get_WalshZeroesSpaces_quadratic_apn(sb) quadratic = True else: ws = get_WalshZeroesSpaces(sb) quadratic = False # inserting all the functions for L in ws.get_mappings(): new_sb = ccz_equivalent_function(sb, L) new_ws = ws.image_by(L.transpose().inverse()) new_thk_spec = new_ws.thickness_spectrum() new_degree_spec = degree_spectrum(new_sb) new_sigma_mult = sigma_multiplicities(new_sb, k=4) if quadratic: worth_adding = True else: worth_adding = self.is_new( new_sb, degree_spec=new_degree_spec, abs_walsh_spec=abs_walsh_spec, sigma_mult=new_sigma_mult, thk_spec=new_thk_spec, ccz_id=self.number_of_ccz_classes ) if worth_adding: if new_degree_spec.maximum() == 2: mug = apn_ea_mugshot(new_sb) else: mug = apn_ea_mugshot_from_spectra( abs_walsh_spec, new_degree_spec, new_sigma_mult, new_thk_spec ) to_insert = { "lut" : new_sb.to_bytes(), "n" : new_sb.get_input_length(), "m" : new_sb.get_output_length(), "bibliography" : bibliography, "linearity" : lin, "degree" : new_degree_spec.maximum(), "thickness" : new_thk_spec.maximum(), "ccz_id" : self.number_of_ccz_classes, "mugshot" : mug } inserted_ids.append(self.insert_function(to_insert)) self.number_of_ccz_classes += 1 return inserted_ids
[docs] def parse_function_from_row(self, row): entry = {} for i, column in enumerate(sorted(self.row_structure.keys())): entry[column] = row[i] # post-processing entry["sbox"] = Sb(entry["lut"]) return entry
[docs] def is_new(self, s, degree_spec=None, abs_walsh_spec=None, sigma_mult=None, thk_spec=None, ccz_id=None ): """ # !TODO! docstring """ sb = Sb(s) if degree_spec == None: degree_spec = degree_spectrum(sb) if degree_spec.maximum() == 2: mug = apn_ea_mugshot(sb) else: if abs_walsh_spec == None: abs_walsh_spec = absolute_walsh_spectrum(sb) if sigma_mult == None: sigma_mult = sigma_multiplicities(sb) if thk_spec == None: thk_spec = thickness_spectrum(sb) mug = apn_ea_mugshot_from_spectra( abs_walsh_spec, degree_spec, sigma_mult, thk_spec ) query = {"mugshot" : mug} if ccz_id != None: query["ccz_id"] = ccz_id candidates = self.query_functions(query) if candidates == []: print("+ no candidate") return True else: # checking all the functions with a similar mugshot print("\n\n", len(candidates)) print(mug) print(sb) print("___") for entry in candidates: print(entry["id"], entry["ccz_id"]) print(entry["mugshot"]) if sb == entry["sbox"]: return False if are_ea_equivalent(sb.lut(), entry["sbox"].lut()): print("[found] ", len(test_result)) print(entry["sbox"]) return False return True