Boolean Functions
Introduction
This page was created to exchange functions and computations developed in
The following lines need to be added to your
from sage.crypto.sbox import SBox
from sage.crypto.boolean_function import BooleanFunction
Basic tools
Below we give some basic tools which will be used going onwards, including:
- Walsh support of a Boolean function
- The inverse WHT given a Walsh spectra
of length - Checking wheather a Boolean function
in odd dimension is semi-bent - Walsh spectra of a vectorial Boolean function
- Checking whether an
-function is AB, if is defined by a list of its coordinates (If is given in integer form, there is already an integrated function in Sage)
def walsh_support(f,n):
w=BooleanFunction(f).walsh_hadamard_transform();
l=len(w);
V=VectorSpace(GF(2),n);
ws=[];
for v in V:
i=ZZ(list(v),base=2);
if(w[i] !=0):
ws.append(vector(GF(2),v));
return ws;
def inverseWHT(w,n):
t=[];
V=sorted(VectorSpace(GF(2),n));
for u in V:
s=0;
for x in V:
i=ZZ(list(x), base=2);
s=s+w[i]*(-1)^(vector(u,GF(2))*vector(x,GF(2)));
t.append((1-(2^(-n))*s)/2);
return t;
def is_semibent(f,n):
if((f.is_plateaued()) and (2^((n+1)/2) in f.walsh_hadamard_transform())):
return True;
else:
return False;
def walsh_spectrum(F):
n=len(F);
S=[];
for i in [1..2^n-1]:
f=F.component_function(i);
S=S+list(f.walsh_hadamard_transform());
K=sorted(list(set(S)));
return [[K[i],S.count(K[i])] for i in [0..len(K)-1]];
def isAB(M):
T=list(transpose(matrix(M)));
T1=[ZZ(list(x),base=2) for x in T];
T1=SBox(T1);
return T1.is_almost_bent();
and classes
The Maiorana-McFarland class
where
where
The permutation
Another class introduced by Carlet, called
where
We will define three
- the indicator function
which will be denoted with , - the trace function
denoted with and - the anihilator of a linear space
of denoted with .
#Fm=GF(2^m);
def ind(x,L):
if x in L:
return Fm.one();
else:
return Fm.zero();
def tr(x,m,n):
return sum([x^(2^(i*m)) for i in [0..(n/m)-1]])
def dualSpace(E,m):
Fm=GF(2^m);
t=[];
for x in Fm:
b=0;
for y in E:
if (x*y).trace()==0:
b=b+1;
if b==len(E):
t.append(x)
return t;
Example: Let
For
Fm=GF(2^9);
sFm=sorted(Fm);
p=Fm.primitive_element();
a=p^((2^9-1)/(2^3-1));
u=sFm[13];
Lperp=[x for x in Fm if ((x).trace()+1)*((x*a).trace()+1)==1];
f=[(x*y^284).trace()+ind(x,Lperp) for x in sFm for y in sFm];
f=BooleanFunction(f);
f.is_bent()
Example: Let
For
Fm=GF(2^9);
sFm=sorted(Fm);
p=Fm.primitive_element();
a=p^((2^9-1)/(2^3-1));
E2=[Fm.zero(),a^2,a+a^2,a];
E1=dualSpace(E2,9);
f=[(x*y^284).trace()+ind(x,E1)*ind(y,E2) for x in sFm for y in sFm];
f=BooleanFunction(f);
f.is_bent()
Let
Example: Let
For
Below we give a program (depending if we are using vector space or finite field notation), which checks if
def shift_space(W,u):
new=[];
for v in W:
new.append(vector(GF(2),v)+vector(GF(2),u));
return new;
def is_flat(A,n):
V=VectorSpace(GF(2),n);
A1=V.subspace(A);
if len(list(A1))==len(A):
return True;
else:
return False;
def is_closed(F):
C=Combinations([0..len(F)-1],2);
C=C.list();
G=Graph();
for i in C:
if F[i[0]]+F[i[1]] in F:
G.add_edge([i[0],i[1]])
if(len(G.clique_maximum())==len(F)):
return True;
else:
return False;
def satisfiesC(pi_inv,L,n):
t=[];
Fn=GF(2^n);
Vn=Fn.vector_space();
for a in Vn:
A=shift_space(L,a);
F=[Vn(pi_inv[ZZ(list(x),base=2)]) for x in A];
t.append[is_flat(F,n)];
return t;
def satisfiesC_field(pi_inv,L,n,F):
Fk=F;
for a in Fk:
if a!=Fk.zero():
A=[pi_inv(a+L[i]) for i in [0..3]];
B=[A[0]+A[i] for i in [0..3]];
if (0 in B) and (is_closed(B)):
return True;
else:
return False;
Inclusion/exclusion in
A bent function
def is_in_MM(f,n):
s=[];
for a in [1..2^n-1]:
for b in [a+1..2^n-1]:
if set(ttab(f.derivative(a).derivative(b)))=={0}:
s.append([a,b]);
G=Graph();
G.add_edges(s);
cl=list(sage.graphs.cliquer.all_cliques(G,2^(n/2)-1,2^(n/2)-1));
V=VectorSpace(GF(2),n);
V1=sorted(V);
b1=[V.subspace([V1[0]]+[V1[i] for i in s]) for s in cl];
for K in b1:
if len(K)==2^(n/2):
return True;
return False;
Example: The function
Fm=GF(2^4);
sFm=sorted(Fm);
f=[(x*y^7).trace()+ind(x,[0]) for x in sFm for y in sFm];
f=BooleanFunction(f);
is_in_MM(f,8)
False
Duals of Boolean function
Depending on wheather
For a bent Boolean function
def bent_dual(f,n): # f is bent
t=[];
w=f.walsh_hadamard_transform();
for x in w:
if x==2^(n/2):
t.append(0);
else:
t.append(1);
return BooleanFunction(t);
def stand_dual(f,n): # f is s-plateaued
t=[];
w=BooleanFunction(f).walsh_hadamard_transform();
for x in w:
if x==0:
t.append(0);
else:
t.append(1);
return BooleanFunction(t);
Let
def plateFromBent(S,ttD,s,n):
ws=[0 for i in [0..(2^n)-1]];
j=0;
for x in S:
i=ZZ(list(x), base=2);
ws[i]=2^((n+s)/2)*((-1)^(int(ttD[j])));
j=j+1;
return inverseWHT(ws);
property
We say that a Boolean function
def Property_PTau(g,n):
FF=sorted(GF(2^n));
l=[sorted([x,y]) for x in [1..2^n-1] for y in [x+1..2^n-1] if g.derivative(x).derivative(y).algebraic_degree()==-1];
G=Graph();
G.add_edges(l);
return G.cliques_maximum();
Functions and
For the definition and application of the functions
def phi(u,fd,gd,Sf,Sg):
L=[s for s in Sf if s not in intersection(Sf,Sg)];
tt=[];
for x in L:
i=Sf.index(x);
a=fd[i];
v=vector(GF(2),u)+vector(GF(2),x);
j=Sg.index(v);
b=gd[j];
tt.append((a+b)%2);
return tt;
def psi(u,fd,gd,Sf,Sg):
L1=intersection(Sf,Sg);
tt=[];
for x in L1:
i=Sf.index(x);
a=fd[i];
v=vector(GF(2),u)+vector(GF(2),x);
j=Sg.index(v);
b=gd[j];
tt.append((a+b)%2);
return tt;
Constructions of 4-bent decompositions outside
Let
Example: Below is an example in dimension
def concat(tt):
s=[];
for x in tt:
s=s+x;
return BooleanFunction(s)
def delta(x):
if x==0:
return 1;
else:
return 0;
n=8;
G=GL(n,GF(2));
M=G.random_element();
E=VectorSpace(GF(2),n);
c=E.random_element();
S1=[c+M*x for x in E];
t1=[delta(x) for x in sorted(GF(2^4)) for y in sorted(GF(2^4))];
Sf=[list(S1[i])+[t1[i],t1[i]] for i in [0..255]]
Sf2=[vector(GF(2),x)+vector([0,0,0,0,0,0,0,0,0,1]) for x in Sf]
Sf3=[vector(GF(2),x)+vector([0,0,0,0,0,0,0,0,1,0]) for x in Sf]
Sf4=[vector(GF(2),x)+vector([0,0,0,0,0,0,0,0,1,1]) for x in Sf]
SF=[Sf,Sf2,Sf3,Sf4];
F=[];
g=[(x*y^7).trace()+delta(x) for x in sorted(GF(2^4)) for y in sorted(GF(2^4))]
f1=[(-1)^(g[i]) for i in [0..len(g)-1]];
S1=[[ZZ(list(x),base=2) for x in A] for A in SF]
for s1 in S1:
t=[0 for i in [0..2^(10)-1]];
j=0;
for i in s1:
t[i]=(2^((n+4)/2)*f1[j]);
j=j+1;
F.append(inverseWHT(t,10));
G=concat(F);
G=BooleanFunction(G);