Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 19204
1
r"""
2
Bent Boolean functions
3
======================
4
5
The ``bent_function`` module defines
6
the ``BentFunction`` class,
7
which represents a bent Boolean function and some of its properties.
8
9
AUTHORS:
10
11
- Paul Leopardi (2016-09-25): initial version
12
13
EXAMPLES:
14
15
::
16
17
sage: from sage.crypto.boolean_function import BooleanFunction
18
sage: bf = BooleanFunction([0,1,0,0])
19
sage: bf.algebraic_normal_form()
20
x0*x1 + x0
21
sage: from boolean_cayley_graphs.bent_function import BentFunction
22
sage: bentf = BentFunction(bf)
23
sage: type(bentf)
24
<class 'boolean_cayley_graphs.bent_function.BentFunction'>
25
sage: bentf.algebraic_normal_form()
26
x0*x1 + x0
27
28
REFERENCES:
29
30
.. Dillon [Dil1974]_, Rothaus [Rot1976]_, Tokareva [Tok2015]_.
31
32
"""
33
#*****************************************************************************
34
# Copyright (C) 2016-2020 Paul Leopardi [email protected]
35
#
36
# Distributed under the terms of the GNU General Public License (GPL)
37
# as published by the Free Software Foundation; either version 2 of
38
# the License, or (at your option) any later version.
39
# http://www.gnu.org/licenses/
40
#*****************************************************************************
41
42
from sage.graphs.graph import Graph
43
from sage.graphs.strongly_regular_db import strongly_regular_from_two_weight_code
44
from sage.misc.banner import require_version
45
from sage.matrix.constructor import matrix
46
47
from boolean_cayley_graphs.boolean_function_improved import BooleanFunctionImproved
48
49
import boolean_cayley_graphs.weight_class as wc
50
51
52
class BentFunction(BooleanFunctionImproved):
53
r"""
54
A bent Boolean function, with methods corresponding to some of its properties.
55
56
The class inherits from BooleanFunctionImproved and is initialized
57
in the same way as BooleanFunction.
58
Since BooleanFunctionImproved inherits from Saveable, so does BentFunction.
59
60
EXAMPLES:
61
62
::
63
64
sage: import os
65
sage: from boolean_cayley_graphs.bent_function import BentFunction
66
sage: bentf = BentFunction([0,0,0,1])
67
sage: bentf.algebraic_normal_form()
68
x0*x1
69
sage: d = tmp_dir()
70
sage: bentf.save_mangled('example', dir=d)
71
sage: ex = BentFunction.load_mangled('example', dir=d)
72
sage: type(ex)
73
<class 'boolean_cayley_graphs.bent_function.BentFunction'>
74
sage: ex is bentf
75
False
76
sage: ex == bentf
77
True
78
sage: BentFunction.remove_mangled('example', dir=d)
79
sage: os.rmdir(d)
80
81
TESTS:
82
83
::
84
85
sage: from sage.crypto.boolean_function import BooleanFunction
86
sage: bf = BentFunction([0,1,0,0])
87
sage: print(bf)
88
Boolean function with 2 variables
89
90
sage: from sage.crypto.boolean_function import BooleanFunction
91
sage: bf = BentFunction([0,1,0,0])
92
sage: latex(bf)
93
\text{\texttt{Boolean{ }function{ }with{ }2{ }variables}}
94
"""
95
96
97
def is_partial_spread_minus(self, certify=False):
98
r"""
99
Determine if a bent function is in the partial spread (-) class.
100
101
Partial spread (-) is Dillon's :math:`\mathcal{PS}^{(-)}` class [Dil1974]_.
102
103
INPUT:
104
105
- ``self`` -- the current object.
106
- ``certify`` -- boolean (default: False):
107
108
OUTPUT:
109
110
If certify is False, then return True if the bent function
111
represented by ``self`` is in :math:`\mathcal{PS}^{(-)}`,
112
otherwise return False.
113
If certify is True then return two values,
114
where the first is True or False as above,
115
and if the first value is True, the second value is
116
a list of intersections between maximal cliques,
117
otherwie the second value is an empty list.
118
119
EXAMPLES:
120
121
::
122
123
sage: from boolean_cayley_graphs.bent_function import BentFunction
124
sage: bentf = BentFunction([0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0])
125
sage: bentf.is_bent()
126
True
127
sage: bentf.is_partial_spread_minus()
128
True
129
sage: bentf.is_partial_spread_minus(certify=True)
130
(True, [{7, 11, 12}, {3, 13, 14}])
131
"""
132
dim = self.nvariables()
133
reqd_clique_size = 2 ** (dim // 2)
134
cayley = self.cayley_graph()
135
cliques_0 = cayley.cliques_containing_vertex(0)
136
reqd_cliques = [
137
set(clique)
138
for clique in cliques_0
139
if (len(clique) >= reqd_clique_size)]
140
nbr_cliques = len(reqd_cliques)
141
if nbr_cliques == 0:
142
if certify:
143
return False, []
144
else:
145
return False
146
clique_matrix = matrix(nbr_cliques)
147
for j in range(nbr_cliques):
148
for k in range(j + 1, nbr_cliques):
149
clique_matrix[j, k] = clique_matrix[k, j] = (
150
1
151
if reqd_cliques[j] & reqd_cliques[k] == {0} else
152
0)
153
154
clique_graph = Graph(clique_matrix)
155
clique_max = clique_graph.clique_maximum()
156
if len(clique_max) == reqd_clique_size // 2:
157
if certify:
158
part = [
159
reqd_cliques[j] - {0}
160
for j in clique_max]
161
return True, part
162
else:
163
return True
164
else:
165
if certify:
166
intersections = []
167
for j in range(nbr_cliques):
168
for k in range(j + 1, nbr_cliques):
169
intersections.append(
170
((j,k), reqd_cliques[j] & reqd_cliques[k]))
171
return False, intersections
172
else:
173
return False
174
175
176
def linear_code_graph(self):
177
r"""
178
Return the graph of the linear code corresponding to the bent function.
179
180
INPUT:
181
182
- ``self`` -- the current object.
183
184
OUTPUT:
185
186
The graph of the linear code corresponding to ``self``.
187
This is a strongly regular graph [Car2010]_, [Del1972]_, [Din2015].
188
189
EXAMPLES:
190
191
::
192
193
sage: from boolean_cayley_graphs.bent_function import BentFunction
194
sage: bentf = BentFunction([0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0])
195
sage: lcg = bentf.linear_code_graph()
196
sage: type(lcg)
197
<class 'sage.graphs.graph.Graph'>
198
sage: lcg.is_strongly_regular(parameters=True)
199
(16, 6, 2, 2)
200
201
REFERENCES:
202
203
.. Carlet [Car2010]_ Section 8.6 Proposition 8.29.
204
205
.. Delsarte [Del1972]_.
206
207
.. Ding [Din2015]_ Corollary 10.
208
209
"""
210
L = self.linear_code()
211
return strongly_regular_from_two_weight_code(L)
212
213
214
def sdp_design_matrix(self):
215
r"""
216
Return the incidence matrix of the SDP design of the bent function.
217
218
This method returns the incidence matrix of the design of type
219
:math:`R(\mathtt{self})`, as described by Dillon and Schatz [DS1987]_.
220
This is a design with the symmetric difference property [Kan1975]_.
221
222
INPUT:
223
224
- ``self`` -- the current object.
225
226
OUTPUT:
227
228
The incidence matrix of the SDP design corresponding to ``self``.
229
230
EXAMPLES:
231
232
::
233
234
sage: from boolean_cayley_graphs.bent_function import BentFunction
235
sage: bentf = BentFunction([0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0])
236
sage: sdp = bentf.sdp_design_matrix()
237
sage: print(sdp)
238
[0 0 0 1 0 0 0 1 0 0 0 1 1 1 1 0]
239
[0 1 0 0 0 1 0 0 0 1 0 0 1 0 1 1]
240
[0 0 1 0 0 0 1 0 0 0 1 0 1 1 0 1]
241
[1 0 0 0 1 0 0 0 1 0 0 0 0 1 1 1]
242
[0 0 0 1 1 1 1 0 0 0 0 1 0 0 0 1]
243
[0 1 0 0 1 0 1 1 0 1 0 0 0 1 0 0]
244
[0 0 1 0 1 1 0 1 0 0 1 0 0 0 1 0]
245
[1 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0]
246
[0 0 0 1 0 0 0 1 1 1 1 0 0 0 0 1]
247
[0 1 0 0 0 1 0 0 1 0 1 1 0 1 0 0]
248
[0 0 1 0 0 0 1 0 1 1 0 1 0 0 1 0]
249
[1 0 0 0 1 0 0 0 0 1 1 1 1 0 0 0]
250
[1 1 1 0 0 0 0 1 0 0 0 1 0 0 0 1]
251
[1 0 1 1 0 1 0 0 0 1 0 0 0 1 0 0]
252
[1 1 0 1 0 0 1 0 0 0 1 0 0 0 1 0]
253
[0 1 1 1 1 0 0 0 1 0 0 0 1 0 0 0]
254
sage: from sage.combinat.designs.incidence_structures import IncidenceStructure
255
sage: sdp_design = IncidenceStructure(sdp)
256
sage: sdp_design.is_t_design(return_parameters=True)
257
(True, (2, 16, 6, 2))
258
259
REFERENCES:
260
261
.. Dillon and Schatz [DS1987]_, Kantor [Kan1975]_.
262
263
"""
264
dim = self.nvariables()
265
v = 2 ** dim
266
result = matrix(v, v)
267
dual_self = self.walsh_hadamard_dual()
268
dual_f = dual_self.extended_translate()
269
for c in range(v):
270
result[c,:] = matrix([self.extended_translate(0, c, dual_f(c))(x)
271
for x in range(v)])
272
return result
273
274
275
def walsh_hadamard_dual(self):
276
r"""
277
Return the Walsh Hadamard dual of the bent function.
278
279
This method returns a ``BentFunction`` based on the Walsh Hadamard
280
transform of ``self``. Since ``self`` is a bent function, the returned
281
``BentFunction` is well-defined and is bent, being the *dual*
282
bent function [Hou1999]_ or *Fourier transform* of ``self`` [Rot1976]_.
283
284
INPUT:
285
286
- ``self`` -- the current object.
287
288
OUTPUT:
289
290
An object of class ``BentFunction``, being the dual of ``self``.
291
292
EXAMPLES:
293
294
::
295
296
sage: from boolean_cayley_graphs.bent_function import BentFunction
297
sage: bentf = BentFunction([0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0])
298
sage: dual_bentf = bentf.walsh_hadamard_dual()
299
sage: type(dual_bentf)
300
<class 'boolean_cayley_graphs.bent_function.BentFunction'>
301
sage: dual_bentf.is_bent()
302
True
303
sage: dual_bentf.algebraic_normal_form()
304
x0*x1 + x2*x3
305
306
.. NOTE::
307
308
Versions of Sage before 8.2 had an incorrect sign in
309
``BooleanFunction.walsh_hadamard_transform(self)``.
310
See [Sage trac ticket #23931](https://trac.sagemath.org/ticket/23931)
311
Previous versions of this method had ``1 + x // scale`` to compensate for
312
an incorrect sign in ``BooleanFunction.walsh_hadamard_transform(self)``.
313
[Since this has now been fixed in Sage 8.2](https://trac.sagemath.org/ticket/23931)
314
this is now changed to ``1 - x // scale``.
315
"""
316
dim = self.nvariables()
317
scale = 2 ** (dim // 2)
318
coefficient = lambda x: (
319
(1 - x // scale) // 2
320
if require_version(8,2,0)
321
else
322
(1 + x // scale) // 2)
323
return BentFunction([coefficient(x) for x in self.walsh_hadamard_transform()])
324
325
326
def weight_class(self):
327
r"""
328
Return the weight class of the bent function.
329
330
INPUT:
331
332
- ``self`` -- the current object.
333
334
OUTPUT:
335
336
The value 0 or 1, being the weight class of ``self``.
337
338
EXAMPLES:
339
340
::
341
342
sage: from boolean_cayley_graphs.bent_function import BentFunction
343
sage: bentf = BentFunction([0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0])
344
sage: bentf.weight_class()
345
0
346
"""
347
length = len(self)
348
weight = self.weight()
349
return wc.weight_class(length, weight)
350
351