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_sqrpnt.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.
![]()
We construct each transparent in a pixel by pixel fashion.
fig, (ax0, ax1, ax2 ) = plt.subplots(ncols=3)
img=matplotlib.image.imread('sqrpnt_logo.png')
do_not_show_axis(ax0)
ax0.imshow(img)
show_sub_pixel([[white]*10]*10, ax=ax1, title="transparent 1")
show_sub_pixel([[white]*10]*10, ax=ax2, title="transparent 2")
/home/didier/dev/go/src/github.com/didiercrunch/shamir/env/lib/python3.5/site-packages/ipykernel/__main__.py: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 are enought black sub-pixels, the eye will see a black pixel
If there are not enought of black sub-pixels, the eye will see a white pixel
fig, (ax0, ax1, ax2 ) = plt.subplots(ncols=3)
show_sub_pixel([[black, black, black],
[black, black, black],
[black, black, black]],
ax=ax0,
title="a black pixel")
show_sub_pixel([[white, black, black],
[black, black, white],
[white, black, black]],
ax=ax1,
title="a black pixel")
show_sub_pixel([[white, white, black],
[white, black, white],
[white, black, white]],
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([[black, white, black],
[white, black, white],
[white, white, white]], 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([[black, white],
[black, white]], title="[1 0 1 0]", ax=ax0)
show_text("+", ax1)
show_sub_pixel([[black, black],
[white, white]], title="[1 1 0 0]", ax=ax2)
show_text("=", ax3)
show_sub_pixel([[black, black],
[black, white]], 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$
$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 = white, black
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 = white, black
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 = white, black
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 = white, black
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 = white, black
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 = white, black
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_sqrpnt.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='forged result')
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)$")
None
If $K$ bob comes togheter, they can figure out the secret polynomial $P(x)$ and compute $P(0)$
Francis wants to share between Valentin and Didier the
company's credit card: 5243 9021 9129 1828.
Francis chooses 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 beer.
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')
None
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)$")
None
If Francis 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 idea is to be able to proof the knowledge of something an information revealing how come we know it.
To prove that you know how to cook a carrot cake without providing one
To prove that you can decrypt a message without revealing the message
The objective is to find a way to allow Susie to authenticate to Calvin such that...
Susie can proof legetimate knowledge
Calvin is sure that Susie cannot cheet
Calvin does not lean any additional information
fig, (ax0, ax1, ax2 ) = plt.subplots(ncols=3)
img = matplotlib.image.imread('susie.png')
do_not_show_axis(ax0)
ax0.imshow(img)
do_not_show_axis(ax1)
img = matplotlib.image.imread('calvin.gif')
do_not_show_axis(ax2)
ax2.imshow(img)
None
Completness
Soundness
Zero-knowledge
Sign up and send your password
username:
didierpassword:******
The server keeps the the hash of your password
user = {"username": "didier", "hash": "cXdlcnR5MTIzNA=="}
Each time you authenticate, the server verifies that the password you provides hashed to the same value
assert hash(password) == user["hash"]
Sign up and send the hash of your password
totally private password:
******username:didierhash:cXdlcnR5MTIzNA==
The server keeps the the hash
user = {"username": "didier", "hash": "cXdlcnR5MTIzNA=="}
Each time you authenticate, there is a dance between the you and the server to allow the server to gain the knowledge that you know something that
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
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 element is a 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 Sussie will demonstrate to Calvin that she knows that a certain element $x$ is a quadratic residue without giving $\omega$ such that $\omega ^2 = x$
| Susie | Calvin |
|---|---|
| chose a random $r$ | |
| sends $a = r^2$ | |
| send challenge a or b at random | |
| if challenge is a returns r | accept if $r^2 = a$ |
| if challenge is b 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, he needs to repeat the protocol until he is convinced
zero-knowledge: Proof by intimidation