타원곡선의 유래
•
고대 그리스 수학자인 디오판토스가 낸 퍼즐에서 기원을 찾을 수 있다.
•
피라미드 쌓기 문제로 발견한 함수
•
탑의 높이를 x 라 할 때, 필요한 공의 수는 다음과 같다.
•
자연수 거듭제곱의 합을 구하는 공식에 따라 다음처럼 유도가 가능하다.
•
결국 이 함수는 다음과 형태를 갖는다.
•
이 함수를 정리하면 다음과 같은 식의 형태를 얻을 수 있다. 이는 타원곡선 함수의 원형이 된다.
•
a, b 값에 따라 그래프의 모양은 아래와 같이 나타난다.
•
비트코인에서 사용하는 secp256k1은 타원곡선 함수를 다음과 같이 사용한다. (a=0, b=7)
타원 곡선 위의 점이 비트코인의 지갑에서 사용하는 공개키이다.
타원곡선의 덧셈
•
점 덧셈의 정의
◦
일반적인 덧셈 연산과는 다른 타원곡선 내의 두 점을 통해 연산하는 새로운 연산자이다.
◦
점 덧셈은 타원곡선의 두 점을 더해 제 3의 점을 얻는 과정을 말한다.
◦
일부의 예외를 제외하고 어떤 직선이든 반드시 곡선의 점과 만난다.
◦
덧셈은 타원곡선의 두 점을 지나는 직선이 만나는 다른 접점을 x축으로 대칭시킨 점으로 정의한다.
◦
이 점 덧셈의 결과는 쉽게 예측하기 어렵다는 성질을 가진다.
•
점 덧셈의 성질
◦
항등원과 역원이 존재한다.
▪
더해도 자기 자신이되는 점을 무한원점(point at infinity)라 부른다.
▪
y축과 평행한 점이 그어져도 언젠간은 만날 수 있다는 것을 가정한다.
▪
더해서 무한원점이 되는 점이 존재한다.
▪
역원이 존재하므로 항등원이 존재할 수 있다.
▪
점 덧셈에서 항등원은 무한원점이다.
◦
교환법칙과 결합법칙의 성립
▪
점 덧셈은 순서과 관계 없으므로 자연스럽게 결합법칙이 성립한다.
▪
교환법칙은 눈으로 직접 확인해볼 수 있다.
•
점 덧셈의 공식
◦
다음 타원 곡선을 가정한다.
◦
세 개의 점을 정의해보자.
◦
더하는 두 점은 같은 직선에 있으므로 기울기와 y절편을 구할 수 있다.
◦
타원 방정식에 대입해보자.
◦
정리하면 다음과 같다.
◦
모든 x점은 윗 방정식을 만족하는 근이므로 다음과 같은 형식이어야 한다.
◦
(A), (B) 식을 근과 계수의 관계에 따라 같은 차수들의 계수는 동일해야 한다.
◦
이를 통해 다음을 구할 수 있다.
◦
이를 직선의 방정식에 대입하여 도출 가능
◦
y는 반대부호를 가져야 함.
◦
공식 도출 완료
덧셈의 결과(x,y) 를 얻기 위해서는
1. 두 점의 기울기를 먼저 구한다.
2. 기울기를 통해 x좌표를 구한다.
3. 기울기와 x좌표를 통해 y좌표를 구한다.
•
두 점이 같은 경우 점 덧셈 계산
◦
두 점이 같은 경우는 아래와 같다.
◦
다음 타원 곡선을 가정한다.
◦
두 개의 점을 정의해보자.
◦
덧셈 유도 공식에 따라 아래 공식이 유도된다.
◦
기울기를 구하기 위해서는 미분이 필요하다.
미분은 곡선에서 특정 점의 기울기를 구하는 데 활용한다.
기울기가 y의 증가량/x의 증가량 일 때, x의 증가량을 0으로 수렴하면 접선의 기울기를 구할 수 있다.
◦
순간 가속도(접점의 기울기)를 구하기 위해서는 다음을 구해야 한다.
◦
타원곡선을 미분하면 다음과 같다.
◦
정리하면 특정 x점에서 접선의 기울기를 구하는 공식은 다음과 같다.
◦
정리하면 기울기는 다음과 같다.
•
직선이 y축과 평행인 경우
◦
아래와 같은 경우 만나는 점이 없으므로 덧셈이 불가능하다.
◦
이 경우는 무한원점을 반환하여야 한다.
구현: 타원곡선의 점
class Point:
def __init__(self, x, y, a, b):
self.a = a
self.b = b
self.x = x
self.y = y
if self.x is None and self.y is None:
return
if self.y**2 != self.x**3 + a * x + b:
#x,y 두 점은 타원곡선 위에 있어야 한다.
raise ValueError('({}, {}) is not on the curve'.format(x, y))
# end::source1[]
def __eq__(self, other):
return self.x == other.x and self.y == other.y \
and self.a == other.a and self.b == other.b
def __ne__(self, other):
# this should be the inverse of the == operator
return not (self == other)
def __repr__(self):
if self.x is None:
return 'Point(infinity)'
elif isinstance(self.x, FieldElement):
return 'Point({},{})_{}_{} FieldElement({})'.format(
self.x.num, self.y.num, self.a.num, self.b.num, self.x.prime)
else:
return 'Point({},{})_{}_{}'.format(self.x, self.y, self.a, self.b)
def __add__(self, other):
#두 점의 타원곡선 함수가 다르면(두 점의 a,b가 다르면) 안된다.
if self.a != other.a or self.b != other.b:
raise TypeError('Points {}, {} are not on the same curve'.format(self, other))
#항등원 처리: 두 점중 하나가 무한원점이면 상대방 점을 리턴한다.
if self.x is None:
return other
if other.x is None:
return self
#두 점의 x점이 같고 y점이 다른경우 (직선이 y축과 평행)
if self.x == other.x and self.y != other.y:
return self.__class__(None, None, self.a, self.b)
#두 점이 같고, y값이 0인 경우 (직선이 y축과 평행)
if self == other and self.y == 0 * self.x:
return self.__class__(None, None, self.a, self.b)
#두 점이 다른 경우
if self.x != other.x:
s = (other.y - self.y) / (other.x - self.x)
x = s**2 - self.x - other.x
y = s * (self.x - x) - self.y
return self.__class__(x, y, self.a, self.b)
#두 점이 같은 경우
if self == other:
s = (3 * self.x**2 + self.a) / (2 * self.y)
x = s**2 - 2 * self.x
y = s * (self.x - x) - self.y
return self.__class__(x, y, self.a, self.b)
Python
복사
class PointTest(TestCase):
def test_ne(self):
a = Point(x=3, y=-7, a=5, b=7)
b = Point(x=18, y=77, a=5, b=7)
self.assertTrue(a != b)
self.assertFalse(a != a)
def test_on_curve(self):
with self.assertRaises(ValueError):
Point(x=-2, y=4, a=5, b=7)
# these should not raise an error
Point(x=3, y=-7, a=5, b=7)
Point(x=18, y=77, a=5, b=7)
def test_add0(self):
a = Point(x=None, y=None, a=5, b=7)
b = Point(x=2, y=5, a=5, b=7)
c = Point(x=2, y=-5, a=5, b=7)
self.assertEqual(a + b, b)
self.assertEqual(b + a, b)
self.assertEqual(b + c, a)
def test_add1(self):
a = Point(x=3, y=7, a=5, b=7)
b = Point(x=-1, y=-1, a=5, b=7)
self.assertEqual(a + b, Point(x=2, y=-5, a=5, b=7))
def test_add2(self):
a = Point(x=-1, y=1, a=5, b=7)
self.assertEqual(a + a, Point(x=18, y=-77, a=5, b=7))
Python
복사