# all the imports
%pylab inline
from visual_cryptography.visual_cryptography import (ImageLayer,
produce_image_layer_from_real_image)
pylab.rcParams['figure.figsize'] = (18.0, 8.0)
Populating the interactive namespace from numpy and matplotlib
noir = 1
blanc = 0
def plot_matrix(data, title="", ax=None):
if ax is None:
fig, ax = pylab.subplots()
ax.imshow(data, cmap=plt.cm.gray, interpolation='nearest')
if title:
ax.set_title(title)
ax.axis('off')
#pylab.show()
def do_not_show_axis(ax):
ax.xaxis.set_major_locator(plt.NullLocator())
ax.yaxis.set_major_locator(plt.NullLocator())
def plot_function(f, xmin=-10, xmax=10, ax=None, title=""):
if ax is None:
fig, ax = pylab.subplots()
X = arange(xmin, xmax, 0.1)
Y = [f(x) for x in X]
ax.plot(X, Y)
if title:
ax.set_title(title)
def plot_function_in_finite_field(f, xmin=-10, xmax=10, ax=None, title=""):
if ax is None:
fig, ax = pylab.subplots()
X = arange(xmin, xmax, 1)
Y = [f(x) for x in X]
ax.plot(X, Y, 'r--', alpha=0.75)
ax.plot(X, Y, 'bo')
if title:
ax.set_title(title)
def show_sub_pixel(matrix, ax=None, title=""):
"""Draw Hinton diagram for visualizing a weight matrix."""
ax = ax or pylab.gca()
if title:
ax.set_title(title)
max_weight = 2**np.ceil(numpy.log(np.abs(matrix).max())/np.log(2))
ax.patch.set_facecolor('white')
ax.set_aspect('equal', 'box')
do_not_show_axis(ax)
for (x,y),w in np.ndenumerate(matrix):
if w == 0:
color = "white"
else:
color = "gray"
size = 0.8
rect = plt.Rectangle([y - size / 2, x - size / 2], size, size,
facecolor=color, edgecolor="black")
ax.add_patch(rect)
ax.autoscale_view()
ax.invert_yaxis()
#pylab.show()
def show_text(text, ax=None):
ax = ax or pylab.gca()
ax.xaxis.set_major_locator(plt.NullLocator())
ax.yaxis.set_major_locator(plt.NullLocator())
ax.text(0.5, 0.5,text , color='black',
fontsize=40,
#fontname='Courier',
horizontalalignment='center',
verticalalignment='center',
)
ax.axis('off')
def plot_tuple_of_pixels(pixel_1, pixel_2, axs):
show_text("(", axs[0])
show_sub_pixel(pixel_1, ax=axs[1])
show_text(",", axs[2])
show_sub_pixel(pixel_2, ax=axs[3])
show_text(")", axs[4])
Encrypting information in a 100% visual way.
Sharing a secret between $n$ persons such that any subset of size $k$ can recover it.
Using a zero knowledge proof to authenticate ourself to a third party.
Let's present the Shamir and Naor ideas to encrypt a message in a secure way such that the decrypting does not require any computers or calculations.
The big idea is to encrypt an image on two separate transparents. When the two transparents are stack togheter, the original image can be recover.
img = produce_image_layer_from_real_image("image.png")
shares = img.produce_two_shares_from_image()
plot_matrix(shares[0], title='first transparent')
plot_matrix(shares[1], title='second transparent')
sum_of_the_shares = shares[0] * shares[1] # note that matplotlib associates 0 to black and 1 to white
plot_matrix(sum_of_the_shares, title="both transparents")
The person that creates encrypt the message is called the dealer
One of the transparent can be called the cypher and the other the key.
A crytosystem is said to be secure if, without the key, it impossible to know the original message from the cypher.
This image is said as the message

![]()
We construct each transparent in a pixel by pixel fashion.
fig, (ax0, ax1, ax2 ) = plt.subplots(ncols=3)
img=matplotlib.image.imread('image.png')
do_not_show_axis(ax0)
ax0.imshow(img)
show_sub_pixel([[blanc]*10]*10, ax=ax1, title="transparent 1")
show_sub_pixel([[blanc]*10]*10, ax=ax2, title="transparent 2")
-c:43: RuntimeWarning: divide by zero encountered in log
To encrypt a pixel, we'll decompose it in $m$ sub-pixel. Each sub-pixel can be black or white.
The humain eye will approximate the $m$ sub-pixel in a pixel
If there is enought black sub-pixel, the eye will see a black pixel
If there is not enought of black sub-pixel, the eye will see a white pixel
fig, (ax0, ax1, ax2 ) = plt.subplots(ncols=3)
show_sub_pixel([[noir, noir, noir],
[noir, noir, noir],
[noir, noir, noir]],
ax=ax0,
title="a black pixel")
show_sub_pixel([[blanc, noir, noir],
[noir, noir, blanc],
[blanc, noir, noir]],
ax=ax1,
title="a black pixel")
show_sub_pixel([[blanc, blanc, noir],
[blanc, noir, blanc],
[blanc, noir, blanc]],
ax=ax2,
title="a white pixel")
To help the humain, we need the black to be as dark as possible and the white to be as bright as possible
A pixel is said to be black if it is made of at least $d \leq m$ black sub-pixels
A pixel is said to be white if it is made of no more than $d - \alpha m$ black sub-pixels
$m$ is the number of sub-pixels in a pixel
Bigger $d$ is, darker the blacks are
Bigger $\alpha$ is, brighter the whites are.
$\alpha$ represent here a "distance" between the white and black. Greather this distance will be easier it will be to distinguist between the blacks and whites
import matplotlib as mpl
fig, ax = pylab.subplots()
cmap = mpl.cm.gray_r
norm = mpl.colors.Normalize(vmin=5, vmax=10)
cb = mpl.colorbar.ColorbarBase(ax, cmap=cmap,
norm=norm,
orientation='horizontal')
ax.set_axis_off()
ax.text(0.9, 0.5, 'black',
horizontalalignment='center',
verticalalignment='center',
rotation='vertical',
size="20",
color="white",
transform=ax.transAxes)
ax.text(0.1, 0.5, 'white',
horizontalalignment='center',
verticalalignment='center',
rotation='vertical',
size="20",
color="black",
transform=ax.transAxes)
pylab.show()
In a way or an other, for each pixel we figured out sub-pixel to place on each transparent such that.
when stacked, they form the the original image
with only one transparent, it is impossible to know what is the original image
fig, (ax0, ax1, ax2 ) = plt.subplots(ncols=3)
plot_matrix(shares[0], title='first transparent', ax=ax0)
plot_matrix(shares[1], title='second transparent', ax=ax1)
plot_matrix(shares[1] * shares[0], title='stacked transparents', ax=ax2)
We encode a pixel in an array of size $m$, $[ p_1, p_2, \dots, p_m ]$
where $i$ represents a specific sub-pixel position
the $i^th$ sub-pixel is black is $p_i$ is $1$ and white if $p_i$ is $0$
show_sub_pixel([[noir, blanc, noir],
[blanc, noir, blanc],
[blanc, blanc, blanc]], title="[1 0 1 0 1 0 0 0 0]")
Consequently the transparent superposition can be seen as componentwise or operation
[1 0 1 0 ]
+ [1 1 0 0 ]
-----------------------
[1 1 1 0 ]
fig, (ax0, ax1, ax2, ax3, ax4 ) = plt.subplots(ncols=5)
show_sub_pixel([[noir, blanc],
[noir, blanc]], title="[1 0 1 0]", ax=ax0)
show_text("+", ax1)
show_sub_pixel([[noir, noir],
[blanc, blanc]], title="[1 1 0 0]", ax=ax2)
show_text("=", ax3)
show_sub_pixel([[noir, noir],
[noir, blanc]], title="[1 1 1 0]", ax=ax4)
How can we encode a pixel $P$ (black or white) in two pixels $Q_1$ $Q_2$ such that...
$Q_1 + Q_2 \sim P$
Without having access to $Q_1$ and $Q_2$, we grain no knowledge on $P$
$$ Prob(\text{P is white} | Q_i) = Prob(\text{P is black} | Q_i) $$
$A \sim B$ if $A$ is the same colour as $B$
We create two sets
$W = \{ (r_1, l_1) , (r_2, l_2), \dots, (r_k, l_k) \}$
$K = \{ (g_1, d_1) , (g_2, d_2), \dots, (g_k, d_k) \}$
such that...
$r_i + l_i$ is white
$g_i + d_i$ is black
The cardinality of $x$ in the multiset $\{r_1, l_1, \dots r_k, l_k\}$ is the same in the multiset $\{g_1, d_1, \dots g_k, d_k\}$.
fig, axs = plt.subplots(ncols=14)
pixel = lambda a, b, c, d : [[a, b], [c, d]]
w, b = blanc, noir
show_text("white={ ", axs[0])
show_text(" ", axs[1])
plot_tuple_of_pixels(pixel(w, b, w, b), pixel(w, b, w, b), axs[2:])
show_text(",", axs[7])
plot_tuple_of_pixels(pixel(b, w, b, w), pixel(b, w, b, w), axs[8:])
show_text("}", axs[13])
fig, axs = plt.subplots(ncols=14)
pixel = lambda a, b, c, d : [[a, b], [c, d]]
w, b = blanc, noir
show_text("black={ ", axs[0])
show_text(" ", axs[1])
plot_tuple_of_pixels(pixel(w, b, w, b), pixel(b, w, b, w), axs[2:])
show_text(",", axs[7])
plot_tuple_of_pixels(pixel(b, w, b, w), pixel(w, b, w, b), axs[8:])
show_text("}", axs[13])
fig, axs = plt.subplots(ncols=14)
pixel = lambda a, b, c, d : [[a, b], [c, d]]
w, b = blanc, noir
show_text("white={ ", axs[0])
show_text(" ", axs[1])
plot_tuple_of_pixels(pixel(w, b, b, w), pixel(w, b, b, w), axs[2:])
show_text(",", axs[7])
plot_tuple_of_pixels(pixel(b, w, w, b), pixel(b, w, w, b), axs[8:])
show_text("}", axs[13])
fig, axs = plt.subplots(ncols=14)
pixel = lambda a, b, c, d : [[a, b], [c, d]]
w, b = blanc, noir
show_text("black={ ", axs[0])
show_text(" ", axs[1])
plot_tuple_of_pixels(pixel(w, b, b, w), pixel(b, w, w, b), axs[2:])
show_text(",", axs[7])
plot_tuple_of_pixels(pixel(b, w, w, b), pixel(w, b, b, w), axs[8:])
show_text("}", axs[13])
fig, axs = plt.subplots(ncols=14)
pixel = lambda a, b : [[a, b]]
w, b = blanc, noir
show_text("white={ ", axs[0])
show_text(" ", axs[1])
plot_tuple_of_pixels(pixel(w, b), pixel(w, b), axs[2:])
show_text(",", axs[7])
plot_tuple_of_pixels(pixel(b, w), pixel(b, w), axs[8:])
show_text("}", axs[13])
fig, axs = plt.subplots(ncols=14)
pixel = lambda a, b : [[a, b]]
w, b = blanc, noir
show_text("black={ ", axs[0])
show_text(" ", axs[1])
plot_tuple_of_pixels(pixel(w, b), pixel(b, w), axs[2:])
show_text(",", axs[7])
plot_tuple_of_pixels(pixel(b, w), pixel(w, b), axs[8:])
show_text("}", axs[13])
By crafting its own transparent, knowing the other transparent, a cheater could show whatever he wants as a results
cheated = produce_image_layer_from_real_image("cheatedimage.png")
cheated_share = cheated.produce_cheated_image_from_other_share(shares[0])
plot_matrix(cheated_share , title='crafted transparent')
savefig("crafted_transparen.pdf")
plot_matrix(cheated_share * shares[0], title='forge results')
Alice wants to share his swiss bank account number with Bob TheFirst, Bob TheSecond, Bob TheThird,... Bob TheNth such that...
If any $k$ Bobs comes togheter they need to be able to recover the bank account number
If any less that $k$ Bobs comes togheter they need to have no idea whatsoever about the bank account number
***********
***** ***********
** ****** *** ********
**** ****** ** *******
*** ******* ** ******
*** ** * **
*|/------ -------\ ** *
| |=| :===**
| O | | O | }|*
|---- | ---- | |*
| |___ |\/
| |
\ ----- |
\ |
-__ -- -/
A polynomial is a function that can be written as
$$ a_0 + a_1 \cdot x^1 + a_2 \cdot x^2 + \dots + a_n \cdot x^n $$
fig, (ax0, ax1, ax2) = plt.subplots(ncols=3)
plot_function(lambda x : 2 * x + 1, title="$2 \cdot x + 1$", ax=ax0)
plot_function(lambda x : 2 * x**2 + 1, title="$2 \cdot x^2 + 1$", ax=ax1)
plot_function(lambda x : 2 * x**3 - 2 * x**2 + 1, title="$2 \cdot x^3 - 2 \cdot x^2 + 1$", ax=ax2)
Any $n + 1$ points define an unique polynomials of degre $n$.
fig, (ax0, ax1, ax2) = plt.subplots(ncols=3)
p = lambda x : 2 * x + 1
plot_function(p, title="$2 \cdot x + 1$", ax=ax0)
ax0.plot([-7, 7] , [p(-7), p(7)], "ro")
p = lambda x : 2 * x**2 + 1
plot_function(p, title="$2 \cdot x^2 + 1$", ax=ax1)
ax1.plot([-7, 0, 7], [p(-7), p(0), p(7)], "ro")
p = lambda x : 2 * x**3 - 2 * x**2 + 1
plot_function(p, title="$2 \cdot x^3 - 2 \cdot x^2 + 1$", ax=ax2)
ax2.plot([-7, -3, 3, 7], [p(-7), p(-3), p(3), p(7)], "ro")
show()
by $n$ points pass an infinite number of polynomials of degree $n$
fig, ax = plt.subplots()
b = 0
d = 1
c = lambda a : -100 - 7**2 * a
P = lambda a : (lambda x: a * x**3 + b * x**2 + x * c(a) + d)
for i in range(-12, 12, 3):
plot_function(P(i), ax=ax)
p = P(1)
ax.plot([-7, 0, 7] , [p(-7), p(0), p(7)], "ro")
ax.set_title("Polynomials passing through $(-7, 701), (0, 1), (7, -699)$")
fig.show()
$$ P(x) = a_0 + a_1 \cdot x^1 + a_2 \cdot x^2 + \dots + a_{k-1}\cdot x^{x-1} $$
If $K$ bob comes togheter, they can figure out the secret polynomial $P(x)$ and compute $P(0)$
Peter wants to share between Wolf and Didier the
ACS's credit card: 5243 9021 9129 1828.
p = lambda x : 5243902191291828 + 7873787349 * x + 7893478934 * x ** 2
credit_card_number = 5243902191291828
wolf_secret = p(1) # keyboard random number
didier_secret = p(2)
print(wolf_secret)
print(didier_secret)
5243917958558111 5243949512782262
Peter choose the bellow polynomials because he likes it very much
$$P(X) = 5243902191291828 + 7873787349\cdot x + 7893478934\cdot x^2$$
Didier will try to figure out the credit card number to buy a truck load of maple sirup.
He knows that he is looking for a number $a_0$ of 12 digits
$a_0$ is positive
$a_0$ is an integer
... $$P(x) = a_0 + a_1 \cdot x + a_2 \cdot x^2 $$ $$5243949512782262 = a_0 + a_1 \cdot 2 + a_2 \cdot 4 $$ $$a_0 = 5243949512782262 - a_1 \cdot 2 - a_2 \cdot 4$$ $$a_0 = 5243949512782262 - 2\cdot(a_1 \cdot - 2 \cdot a_2)$$ $$a_0 = 5243949512782262 - \text{even number}$$
Didier knows the credit card number is even
With the help of EC2 Didier can find the solution in a relative small amount of time.
We could process the original message before wharing it
$$\underbrace{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}_\text{very random number}\underbrace{5243902191291828}_\text{the credit card number}$$
We could work in a more appropriate field
$$\mathbb{Z}/p\mathbb{Z}$$
| x | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
| 2 | 0 | 2 | 4 | 6 | 1 | 3 | 5 |
| 3 | 0 | 3 | 6 | 2 | 5 | 1 | 4 |
| 4 | 0 | 4 | 1 | 5 | 2 | 6 | 3 |
| 5 | 0 | 5 | 3 | 1 | 6 | 4 | 2 |
| 6 | 0 | 6 | 5 | 4 | 3 | 2 | 1 |
| + | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
| 1 | 1 | 2 | 3 | 4 | 5 | 6 | 0 |
| 2 | 2 | 3 | 4 | 5 | 6 | 0 | 1 |
| 3 | 3 | 4 | 5 | 6 | 0 | 1 | 2 |
| 4 | 4 | 5 | 6 | 0 | 1 | 2 | 3 |
| 5 | 5 | 6 | 0 | 1 | 2 | 3 | 4 |
| 6 | 6 | 0 | 1 | 2 | 3 | 4 | 5 |
fig, (ax0, ax1, ax2) = plt.subplots(ncols=3)
plot_function_in_finite_field(lambda x : (2 * x + 1) % 7, title="$2 \cdot x + 1$ mod 7", ax=ax0)
plot_function_in_finite_field(lambda x : (2 * x**2 + 1) % 7, title="$2 \cdot x^2 + 1$ mod 7", ax=ax1)
plot_function_in_finite_field(lambda x : (2 * x**3 - 2 * x**2 + 1) % 7, title="$2 \cdot x^3 - 2 \cdot x^2 + 1$ mod 7", ax=ax2)
fig, ax = plt.subplots()
f = lambda x : (2 * x**3 - 2 * x**2 + 1) % 7
plot_function_in_finite_field(f, title="$2 \cdot x^3 - 2 \cdot x^2 + 1 mod 7$", ax=ax)
ax.plot([-7, 0, 7], [f(-7), f(0), f(7)], 'rD')
fig.show()
fig, ax = plt.subplots()
b = 0
d = 1
c = lambda a : -100 - 7**2 * a
P = lambda a : (lambda x: (a * x**3 + b * x**2 + x * c(a) + d) % 7)
for i in range(-12, 12, 3):
plot_function_in_finite_field(P(i), ax=ax)
p = P(1)
ax.plot([-7, 0, 7] , [p(-7), p(0), p(7)], "ro")
ax.set_title("Polynomials passing through $(-7, 1), (0, 1), (7, 1)$")
fig.show()
If peter would have choosen polynomials in $\mathbb{Z}/p\mathbb{Z}$ with $p$ big enough...
Didier could not have easely discarted some numbers
For Didier, a large $p$ in infinite even with the help of $aws$
The objective of this sections is to present the idea of the article how to proof yourself, an article publish by Fiat and Shamir in the year of grace 1987.
The objective is to find a way to allow Alice to authenticate to Bob such that...
Alice can authenticate
Bob is sure that the Alice is really Alice
Bob cannot copy the credentials of alice in any way.
Completness
Soundness
Zero-knowledge
Bob and Alice exchange some information while they know they are talking to the each other (sign up)
In that exchange, Alice will tell Bob that she knows something, proof without giving Bob or anyone else any factual proof.
Each time Alice will authenticate, Alice will provide enough information to Bob to demonstrate that she knows the information but without giving any factual proofs.
There are some problems that are easy to solve in $\mathbb{R}$ but very hard to solve in $\mathbb{Z}/n\mathbb{Z}$
The quandratric residue of $x$ in $\mathbb{Z}/n\mathbb{Z}$ is an element $y$ such that $x^2 = y$
We say that $y$ is a quadratic residue if there exists $x$ such that $x^2 = y$
not every elements are quadratic residue
It is hard to know if a number is a quadratic residue
It is easy to find a quadratic residue: just take a random $r$ and compute $r^2$
The idea is that Alice will demonstrate to Bob that she knows that a certain element $x$ is a quadratic residue without giving $\omega$ such that $\omega ^2 = x$
| Alice | Bob |
|---|---|
| chose a random $r$ | |
| sends $a = r^2$ | |
| send challenge 0 or 1 at random | |
| if challenge is 1 returns r | accept if $r^2 = a$ |
| if challenge is 0 returns $r\cdot\omega$ | accept is $(r\cdot\omega)^2 = a \cdot x$ |
completeness: If Alice plays the game, she will be to proof that she is herself with probability 1
soundness: Bob as a probablylity $1/2$ to catch a cheeter
zero-knowledge: Proof by intimidation