ECC - Unable to produce entire cyclic group - python

I am reading the section about elliptic curve cryptography in Christoffer Paares book ("Understanding Cryptography"). I decided that I would implement a function for elliptic curve point addition and point doubling in python. For my test I used the example in the book so I could test my results.
The curve used in the example is: y^2 = x^3 + 2x + 2 mod 17
The generator used is: p = (5,1)
Thus the cycle becomes:
1p = (5,1)
2p = (6,3)
3p = (10,6)
4p = (3,1)
5p = (9,16)
6p = (16,13)
7p = (0,6)
8p = (13,7)
9p = (7,6)
10p = (7,1)
11p = (13,10)
12p = (0,11)
13p = (16,4)
14p = (9,1)
15p = (3,16)
16p = (10,11)
17p = (6,14)
18p = (5,16)
19p = The neutral element (Point at infinity)
20p = (5,1)
...
I wrote this code in an attempt to reproduce the results:
def add(a,p,P,Q):
#Check For Neutral Element
if P == (0,0) or Q == (0,0):
return (P[0]+Q[0],P[1]+Q[1])
#Check For Inverses (Return Neutral Element - Point At Infinity)
if P[0] == Q[0]:
if (-P[1])%p == Q[1] or (-Q[1])%p == P[1]:
return (0,0)
#Calculate Slope
if P != Q:
s = (Q[1]-P[1]) / (Q[0]-P[0])
else:
s = ((3*(P[0]*P[0])+a)%p) ** (2*P[1])
#Calculate Third Intersection
x = s*s - P[0] - Q[0]
y = (s*(P[0]-x)) - P[1]
y = y%p
x = x%p
return (x,y)
r = (5,1)
for i in range(1,20):
print i,':',r
r = add(2,17,r,(5,1))
However the output is:
: (5, 1)
: (6, 3)
: (10, 6)
: (3, 1)
: (9, 16)
: (12, 9)
: (1, 2)
: (12, 9)
: (1, 2)
: (12, 9)
: (1, 2)
: (12, 9)
: (1, 2)
: (12, 9)
: (1, 2)
: (12, 9)
: (1, 2)
: (12, 9)
: (1, 2)
As you might see it follows the expected result until 6p and then enters a cycle with the length of 2. I have been staring at this for hours now and I still don't know why it doesn't work (after all: how hard can it be... it's 30 lines of python) .

I am not really aware of the topic but here is a link to a repository implementing the ECC: github
Edit: The actual problem is the division modulo p. You can't just divide using integer arithmetics (15 / 4 == 3) but need to multiply by the inverse of 4 modulo 17 instead.
The inverse of 4 modulo 17 is 13, because 4 * 13 % 17 == 1. Your fraction becomes 15*13, which is the equivalent of saying »15 * 1/4 modulo 17«. Just put some debug prints around your slope computation and you will see when the inversion begins to differ from simple integer division.
def euclid(a, b):
'''Solve x*a + y*b = ggt(a, b) and return (x, y, ggt(a, b))'''
# Non-recursive approach hence suitable for large numbers
x = yy = 0
y = xx = 1
while b:
q = a // b
a, b = b, a % b
x, xx = xx - q * x, x
y, yy = yy - q * y, y
return xx, yy, a
def inv(a, n):
'''Perform inversion 1/a modulo n. a and n should be COPRIME.'''
# coprimality is not checked here in favour of performance
i = euclid(a, n)[0]
while i < 0:
i += n
return i
def add(a,p,P,Q):
#Check For Neutral Element
if P == (0,0) or Q == (0,0):
return (P[0]+Q[0],P[1]+Q[1])
#Check For Inverses (Return Neutral Element - Point At Infinity)
if P[0] == Q[0]:
if (-P[1])%p == Q[1] or (-Q[1])%p == P[1]:
return (0,0)
#Calculate Slope
if P != Q:
# perform multiplication with the inverse modulo p
s = (Q[1]-P[1]) * inv(Q[0]-P[0], p)
else:
s = ((3*(P[0]*P[0])+a)%p) ** (2*P[1])
#Calculate Third Intersection
x = s*s - P[0] - Q[0]
y = (s*(P[0]-x)) - P[1]
y = y%p
x = x%p
return (x,y)
r = (5,1)
for i in range(1,20):
print i,':',r
r = add(2,17,r,(5,1))
prints
1 : (5, 1)
2 : (6, 3)
3 : (10, 6)
4 : (3, 1)
5 : (9, 16)
6 : (16, 13)
7 : (0, 6)
8 : (13, 7)
9 : (7, 6)
10 : (7, 11)
11 : (13, 10)
12 : (0, 11)
13 : (16, 4)
14 : (9, 1)
15 : (3, 16)
16 : (10, 11)
17 : (6, 14)
18 : (5, 16)
19 : (0, 0)
Here a link to pypi.
Feel free to use or improve it.

Related

calculate the range and quartiles

[![Marks
Freq
0-10
5
10-20
13
20-30
20
30-40
32
40-50
60
I want to calculate quartile and range of above data please help using python also represent suitable plot using Matplotlib
[1]: https://i.stack.imgur.com/x0cNf.png
I used this formula to solve it
# Formula for finding "i"th quartile:
# Q_i = L + h/f (i*N/4 - c.f)
data = {
(0, 10): 5,
(10, 20): 13,
(20, 30): 20,
(30, 40): 32,
(40, 50): 60
}
i = 1 # Quartile you want to find
x = (i * sum(data.values())) / 4 # Precalculate i*N/4
c_f = [sum(list(data.values())[:n]) for n in range(1, len(data) + 1)] # Cumulative frequencies
# Calculate class which the quartile is in
# (L = lower, u = upper, f = frequency, c = cumulative frequency)
for ((L, u), f), c in zip(data.items(), c_f):
if c >= x:
break
h = u - L # Class size
C_f = c - f
Q_i = L + ((h/f) * (x - C_f))
print('Quartile ', i, ': ', Q_i, sep='')
Output: Quartile 1: 27.25

Determining neighbours of cell as diamond shape in python

I have a matrix variable in size where 1 indicates the cell such as:
Cells = [[0,0,0,0,0],
[0,0,0,0,0],
[0,0,1,0,0],
[0,0,0,0,0],
[0,0,0,0,0],
]
I need to find neigbours in a parametric sized diamond shape. Not a box as answer given in here or not a fixed sized 1 diamond, answer given here. For example, N=2 I want to know the column, rows for below:
Mask = [[0,0,1,0,0],
[0,1,1,1,0],
[1,1,0,1,1],
[0,1,1,1,0],
[0,0,1,0,0],
]
The function should receive x and y for the requested column and row, (for above I will input 2,2) and N (input 2) the size of diamond. The function should return list of tuples (x,y) for the given diamond size.
I struggled at defining the shape as a function of x, y and k in for loops. I need to know both numpy (if there is anything that helps) and non-numpy solution.
For an iterative approach where you just construct the diamond:
def get_neighbors(center, n=1):
ret = []
for dx in range(-n, n + 1):
ydiff = n - abs(dx)
for dy in range(-ydiff, ydiff + 1):
ret.append((center[0] + dx, center[1] + dy))
return ret
Result of get_neighbors((2, 2), 2):
[(0, 2), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 1), (3, 2), (3, 3), (4, 2)]
Or, for a recursive approach:
dirs = [(1, 0), (0, 1), (-1, 0), (0, -1)]
def add_tuples(a, b):
return tuple([x + y for (x, y) in zip(a, b)])
def get_neighbors(center, n=1, seen=set()):
seen.add(center)
if n <= 0:
return seen
for dir in dirs:
newpos = add_tuples(center, dir)
if newpos in seen:
continue
get_neighbors(newpos, n - 1, seen)
return seen
I would start by taking out a "sub-matrix" that is the smallest square that can contain your result cells. This is the part that numpy should be able to help with.
Then define a function that calculates the manhattan distance between two cells (abs(x - x_p) + abs(y - y_p)) and iterate through the cells of your sub-matrix and return the values with a manhattan distance of less than N from your origin.
Make mask with rotation
Convolute cell and mask
Fix the result
import numpy as np
from scipy.ndimage import rotate, convolve
import matplotlib.pyplot as plt
def diamond_filter(radius):
s = radius * 2 + 1
x = np.ones((s, s), dtype=int)
x[radius, radius] = 0
return rotate(x, angle=45)
def make_diamonds(x, radius):
filter = diamond_filter(radius)
out = convolve(x, filter)
out[out > 1] = 1
out -= x
out[out < 0] = 0
return out
def plot(x):
plt.imshow(x)
plt.show()
plt.close()
def main():
cell = np.random.choice([0, 1], size=(200, 200), p=[0.95, 0.05])
plot(diamond_filter(2))
plot(cell)
result = make_diamonds(cell, 2)
plot(result)
if __name__ == '__main__':
main()

How many boxes can we put to the big one?

I'm trying to work on simple algorithms.
I have 600 snacks and I have two kind of boxes 45 snacks inside and 60 snacks. We need to receive all the amount of options that we can do with this small boxes
I have this kind of code, but some how it doesn't work in a right way.
k = 0
for x in range(0,601):
for y in range(0, int(600 // 45) + 1):
for z in range(0, int(600 // 60) +1):
if x +45 * y + 45 * z == 600:
print(x,'45=',y,'60=',z)
k=k+1
print(k)
If I got you right it is simple math. You have 600 items and want use these 600 items in boxes size of 45 and size of 60. I don’t know what you use x for?
k=0
for y in range(0,20):
for z in range(0,20):
if 45 * y + 60 * z == 600
print('45=',y,'60=',z)
k = k + 1
print(k)
Result will be:
45= 0 60= 10
45= 4 60= 7
45= 8 60= 4
45= 12 60= 1
4
At a first glance, z seems to represent the box that can hold 60 snacks. So the line of code if x +45 * y + 45 * z == 600: does not seem ok. The multiplication factor for z should be 60, i.e., if x +45 * y + 60 * z == 600:
The answer is (EDIT: the solution is rewritten as functions):
Both functions return list of tuples with found combinations.
Both functions iterate only throw one box size and filter by second one.
The length of the list that return both functions is the amount of options
def box_comb(snacks, boxA, boxB):
res = []
for a in range(snacks // boxA + 1): # Iterate by boxA
free_space = snacks - boxA * a
if free_space % boxB == 0: # Filter by boxB
b = free_space // boxB # Calculate the count of boxB
res.append((a, b))
return res
# Try this
comb = box_comb(snacks=600,
boxA=60,
boxB=45)
print(comb)
print(f"Number of combinations = {len(comb)}")
The output:
[(1, 12), (4, 8), (7, 4), (10, 0)]
Number of combinations = 4
Single line solution:
The same algorithm written as single line solution
def box_comb_2(snacks, boxA, boxB):
return [(a, (snacks - a * boxA) // boxB) for a in range(snacks // boxA + 1) \
if (snacks - a * boxA) % boxB == 0]
# try this
comb = box_comb_2(snacks=600,
boxA=60,
boxB=45)
print(comb)
print(f"Number of combinations = {len(comb)}")
The output is
[(1, 12), (4, 8), (7, 4), (10, 0)]
Number of combinations = 4

Min. iterations drawing regular shape("turtle")

I'm trying to find the least number of iterations necessary to form a regular polygon without my "turtle" (shape) repeating its motion.... and noticed a strange(?) relationship which I cannot pinpoint.
If you run the code below and experiment with different values (NOTE: make sure to replace parameters 'x' & 'n' with actual numbers - of your choice):
import turtle
def draw_square():
wn = turtle.Screen()
wn.bgcolor("black")
mike = turtle.Turtle()
mike.shape("turtle")
mike.color("yellow")
mike.speed(100)
count = 0
while count < n: # replace n with number!
mike.forward(100)
mike.right(90)
mike.forward(100)
mike.right(90)
mike.forward(100)
mike.right(90)
mike.forward(100)
mike.right(x) # replace x with number!
if __name__ == "__main__":
draw_square()
You will find the turtle moving in a circular(-ish) motion.
For example, you'll notice that when x = 100, min. value of n needed to form a regular shape is 36 (since 100°- 90°=10°; 360°/10°=36).
when x = 10 e.g
.
Further tests show:
x = 1, (min.) n = 360 # 360°/1° = 360
x = 5, (min.) n = 72 # 360°/5° = 72
x = 9, (min.) n = 10* # 360°/9° = 10*
x = 10, (min.) n = 9* # 360°/10° = 9*
x = 45, (min.) n = 8 # 360°/45° = 8
x = 90, (min.) n = 1* # 360°/90° = 4*
## NOTE: no obvs. solution for n, if x isn't factor of 360....
*: Strangely, you must divide the result by 4 to get min. value of n for some numbers.
I had initially thought it was to do with multiples of 9, or four rotations for square, but [above] led me to reject my hypotheses.
So anyone have any better ideas as to a generic rule? Cheers.
So anyone have any better ideas as to a generic rule?
I believe I've narrowed it down. There are some errors in your table. And there are four different types of exception, not just the "divide the result by 4" one. In fact, across the factors of 360, the exceptions occur more often than the simple 360 / x rule. The four exceptions are:
After, n = 360 / x if x is a:
A) multiple of 8 then n *= 4
B) multiple of 4 then n *= 2
C) multiple of 6 and not a multiple of 9 then n /= 2
D) multiple of 2 then n /= 4
The rules must be applied in the above order and only one rule can fire. If no rules apply, leave n as it is. The revised table for all factors of 360:
x = 1, n = 360 , 360° / 1° = 360
x = 2, n = 45 (/ 4), 360° / 2° = 180 (D)
x = 3, n = 120 , 360° / 3° = 120
x = 4, n = 180 (* 2), 360° / 4° = 90 (B)
x = 5, n = 72 , 360° / 5° = 72
x = 6, n = 30 (/ 2), 360° / 6° = 60 (C)
x = 8, n = 180 (* 4), 360° / 8° = 45 (A)
x = 9, n = 40 , 360° / 9° = 40
x = 10, n = 9 (/ 4), 360° / 10° = 36 (D)
x = 12, n = 60 (* 2), 360° / 12° = 30 (B)
x = 15, n = 24 , 360° / 15° = 24
x = 18, n = 5 (/ 4), 360° / 18° = 20 (D)
x = 20, n = 36 (* 2), 360° / 20° = 18 (B)
x = 24, n = 60 (* 4), 360° / 24° = 15 (A)
x = 30, n = 6 (/ 2), 360° / 30° = 12 (C)
x = 36, n = 20 (* 2), 360° / 36° = 10 (B)
x = 40, n = 36 (* 4), 360° / 40° = 9 (A)
x = 45, n = 8 , 360° / 45° = 8
x = 60, n = 12 (* 2), 360° / 60° = 6 (B)
x = 72, n = 20 (* 4), 360° / 72° = 5 (A)
x = 90, n = 1 (/ 4), 360° / 90° = 4 (D)
x = 120, n = 12 (* 4), 360° / 120° = 3 (A)
x = 180, n = 4 (* 2), 360° / 180° = 2 (B)
x = 360, n = 4 (* 4), 360° / 360° = 1 (A)
The code that generated the above table:
EXCEPTIONS = [
('A', lambda x: x % 8 == 0, lambda n: n * 4, "(* 4)"),
('B', lambda x: x % 4 == 0, lambda n: n * 2, "(* 2)"),
('C', lambda x: x % 6 == 0 and x % 9 != 0, lambda n: n // 2, "(/ 2)"),
('D', lambda x: x % 2 == 0, lambda n: n // 4, "(/ 4)"),
]
for x in range(1, 360 + 1):
if 360 % x != 0:
continue
n = 360 // x
for exception, test, outcome, explain in EXCEPTIONS:
if test(x):
n = outcome(n)
exception = f"({exception})"
break
else: # no break
exception = explain = '' # no rule applies
angle = 360 // x
print(f"x = {x:3}, n = {n:3} {explain:5}, 360° / {x:3}° = {angle:3} {exception}")
My rework of your code which I used to test individual table entries:
from turtle import Screen, Turtle
def draw_square(angle, repetitions):
mike = Turtle("turtle")
mike.speed('fastest')
mike.color("yellow")
count = 0
while count < repetitions:
mike.forward(100)
mike.right(90)
mike.forward(100)
mike.right(90)
mike.forward(100)
mike.right(90)
mike.forward(100)
mike.right(angle)
count += 1
if __name__ == "__main__":
wn = Screen()
wn.bgcolor("black")
draw_square(9, 40)
wn.exitonclick()
Further on from the rule-set identified by #cdlane, I've found a quick way to find just the min. number of iterations for any input x - regardless of whether it's a factor of 360 or not - needed to complete a regular shape! (Of course, I've also realised there will not be a minimum value at all for some e.g. when x is 20.75)
.
Below code shows my corrections to faults identified & addition of heading(), to check if mike has returned to its original position after cycle(s):
import turtle
def draw_square(angle, repetitions):
mike = turtle.Turtle()
mike.shape("turtle")
mike.color("red")
mike.speed("fastest")
count = 0
while count < repetitions:
mike.forward(100)
mike.right(90)
mike.forward(100)
mike.right(90)
mike.forward(100)
mike.right(90)
mike.forward(100)
mike.right(angle)
count += 1
print("Turn ", count, "; ", mike.heading())
if mike.heading() == 0:
break
print("Min. iterations needed to complete cycle: ", count)
if __name__ == "__main__":
wn = turtle.Screen()
wn.bgcolor("black")
x = int(input("Enter angle: "))
n = int(input("Enter boundary: ")) # For n, advisably to a v large number; while loop will probably break before reaching its limit anyways
draw_square(x, n)
wn.exitonclick()

Python : How to store a value generated in a function for the second call of that function

I want to create a random number generation code that inputs "count" number which is that how many times it is called in the program. What I want to do is for the even number of calls of the function I want to create 2 random numbers which are "y1 ,y2" however I want to output y1 only and save y2 for the next call of the function. So at the odd number of calls the function will directly output y2 of the previous call. Thanks for help. The code so far:
import random
import math
def gaussianRandom ( count):
count += 1
if count%2 == 0:
while (1):
x1 = random.uniform(-1, 1)
x2 = random.uniform(-1, 1)
r = x1**2 + x2**2
if (r < 1):
break
y1 = x1 * math.sqrt( (-2 * math.log(r)) / r )
y2 = x2 * math.sqrt( (-2 * math.log(r)) / r )
return y1
functions can have attributes.
import random
import math
def gaussianRandom ( count):
count += 1
if count%2 == 0:
while (1):
x1 = random.uniform(-1, 1)
x2 = random.uniform(-1, 1)
r = x1**2 + x2**2
if (r < 1):
break
y1 = x1 * math.sqrt( (-2 * math.log(r)) / r )
gaussianRandom.y2 = x2 * math.sqrt( (-2 * math.log(r)) / r )
print(gaussianRandom.y2)
return y1
gaussianRandom.y2 = 99
print "y2", gaussianRandom(3)
print gaussianRandom(3)
print gaussianRandom(3)
y2 0.919282832355
-0.0887376744533
y2 -1.71553385287
0.422645022058
y2 -0.0668389339817
0.600351205084
Do you really need (or want) to tell gaussianRandom() how many times you intend to call it? That seems a bit restrictive to me.
I think this problem would be better solved using a generator function. The code below shows how to create one and a couple of ways of how to use it. Rather than implementing your Gaussian algorithm, this generator simply generates numbers of the form 6n±1, so you can easily see what's going on.
#! /usr/bin/env python
''' Generator demo '''
def gen():
x = 6
while True:
yield x-1
yield x+1
x += 6
def main():
g = gen()
for i in xrange(10):
print i, g.next()
print [(i, v) for i,v in zip(xrange(10), gen())]
if __name__ == "__main__":
main()
output
0 5
1 7
2 11
3 13
4 17
5 19
6 23
7 25
8 29
9 31
[(0, 5), (1, 7), (2, 11), (3, 13), (4, 17), (5, 19), (6, 23), (7, 25), (8, 29), (9, 31)]

Categories

Resources