BTC_楕円曲線

Posted: June 23, 2022

定義

楕円曲線の式

y2=x3+ax+by^2 = x^3 + ax + b

以下のようなグラフになる

An image from Notion

ビットコインで使われる楕円曲線

secp256k1と呼ばれ、以下の式で表される

y2=x3+7y^2 = x^3 + 7

以下のようなグラフになる

An image from Notion

点の加算

楕円曲線の点の加算とは、曲線上の2つの点を演算して、同じ曲線状に3つ目の店を得ること。

点Aに点Bを加算を加算することは点Bに点Aを加算することと同じ(点の加算は交換可能)

点の加算を考えるときは、

  1. 点Aと点Bを通る直線を引き、楕円曲線と交差する第3の点を見つける
  2. 第3の点からx軸に関して対象な点をとる
An image from Notion

点の加算の特徴

  1. 同一性
  2. 可換性
  3. 結合性
  4. 可逆性

同一性とは単位元(ゼロ)があることを意味する。点Aに加算すると点Aになる点Iが存在する

この点を「無限遠点」と呼ぶ

A+I=AA + I = A

可逆性とは任意の点Aに加算すると単位元(ゼロ)になる別の-A点が存在する

A+(A)=IA + (-A) = I

グラフで見ると点Aと点-Aは以下のようになり、x軸に対して対象な位置にある

An image from Notion

無限遠点は上記の垂直線と曲線が交差する3つ目の、楕円曲線上にある1つの特殊な点と考える

可換性とは以下のような特徴をもつ

A+B=B+AA + B = B + A

結合性とは以下のような特徴をもつ

(A+B)+C=A+(B+C)(A + B) + C = A + (B + C)

x1 ≠ x2の時の点の加算

P1=(x1,y1),P2=(x2,y2),P3=(x3,y3)P1 = (x1, y1), P2 = (x2, y2), P3 = (x3, y3)P1+P2=P3P1 + P2 = P3

傾きsは以下となる

s=(y2y1)/(x2x1)s = (y2 - y1) / (x2 - x1)

x3がわかれば、y3を求めることができる。P3は以下の式を使って求めることができる(証明は省略、というかむしろ誰か教えてほしい)

x3=s2x1x2x3 = s^2 - x1 - x2y3=s(x1x3)y1y3 = s(x1 - x3) - y1

P1 = P2 のときに点の加算

P1=(x1,y1),P3=(x3,y3)P1 = (x1, y1), P3 = (x3, y3)P1+P1=P3P1 + P1 = P3s=(3x12+a)/(2y1)s = (3x1^2 + a) / (2y1)

x1 = x2なので、x3とy3は以下のように求めることができる

x3=s22x1x3 = s^2 - 2x1y3=s(x1x3)y1y3 = s(x1 - x3) - y1

上記のs(曲線に対する接線の傾き)は楕円曲線の等式の両辺における微分係数を取り出して、

dy / dxを解くことで求めることができる

y2=x3+ax+by^2 = x^3 + ax + b2ydy=(3x2+a)dx2y dy = (3x^2 + a)dxdy/dx=(3x2+a)/(2y)dy/ dx = (3x^2 + a) / (2y)

python code

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:
      raise ValueError('({}, {}) is not on the curve'.format(x, y))

  def __repr__(self):
    return 'Point({}, {})_{}_{}'.format(self.x, self.y, self.a, self.b)

  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):
    return not (self == other)

  def __add__(self, other):
    if self.a != other.a or self.b != other.b:
      raise TypeError('Points {}, {} are not on the same curve'.format(self, other))

    #無限遠点の加算の場合(ここでは無限遠点はNoneとする)
    if self.x is None:
      return other
    if other.x is None:
      return self

    #2つの点が加法逆元(xが同じでyが異なる垂直線)の場合、無限遠点を返す
    if self.x == other.x and self.y != other.y:
      return self.__class__(None, None, self.a, self.b)

    #2つの点がx1!=x2のとき
    if self.x != other.x:
      s = (other.y - self.y) / (other.x - self.x)
      x3 = s**2 - self.x - other.x
      y3 = s * (self.x - x3) - self.y
      return self.__class__(x3, y3, self.a, self.b)

    #2つの点が等しいとき(接点を通るとき)かつ、yが0のとき(接線かつ3点目がない)⇒無限遠点を返す
    if self == other and self.y == 0 * self.x:
      print('uso-n')
      return self.__class__(None, None, self.a, self.b)

    #2つの点が等しいとき(接点を通るとき)
    if self == other:
       s = (3*self.x**2 + self.a) / (2*self.y)
       x3 = s**2 - (2*self.x)
       y3 = s*(self.x - x3) - self.y
       return self.__class__(x3, y3, self.a, self.b)