1
0

楕円曲線をsympyのplot_implicitでグラフにする(その2)

Last updated at Posted at 2023-12-25

前回ではsympyのplot_implicitが生成した座標を取り出してmatplotlibで描く方法を紹介しました。今回はそれを使って楕円曲線暗号の基礎の基礎となる2点の和と2倍したときの点の座標を描いてみます。

楕円曲線上の2点の和

例題1: 楕円曲線$y^2=x^3+17$上の2点$P_1(-1,4), P_2(2,5)$の和を求めてグラフに描け

楕円曲線暗号 (Wikipedia) の楕円曲線の加算公式より

\begin{align}
&楕円曲線 y^2 = x^3+ax+b 上の\\
&2点P_1=(x_1,y_1), P_2=(x_2,y_2)\\
&を通る直線が楕円曲線と交わる点をP_1*P_2= (x_3, y_3)とすると\\
&P_1+P_2 = (x_3,-y_3)となる \\ \\
&直線の式をy = λx+νとすると\\
&λ= (y_2-y_1)/(x_2-x_1) \\
&ν= y_1-λx_1=y_2-λx_2 \\
&これからx_3, y_3は以下のように求まる \\ \\
&x_3=λ^2-x_1-x_2 \\
&y_3 = λ(x_3-x_1)+y_1
\end{align}

これをそのままコードに下のがこれです。キャンバスの定義と楕円曲線の座標の取得は前回の投稿のinit_subplotplot_fxyを使っています。

import sympy as sp
import matplotlib.pyplot as plt

def draw_line(ax, p1, a, CY): # p1上の傾きaの直線をキャンバスいっぱいに描く 
  (x, y), (cb, ct) = p1, CY
  ax.plot([x+(cb-y)/a, x+(ct-y)/a], CY,  lw=0.5, color='green')
  return

def plot_dot(x,y,dx,dy,pn):
  ax.plot(x,y, marker='o',  ms=3,color='blue')
  ax.text(x+dx,y+dy, pn+f"({x},{y})", fontsize="xx-small")
  return

x, y = sp.symbols("x y")
# キャンバスの定義
sizex = 6
CX, CY = (-sizex, sizex), (-sizex, sizex)
ax = init_subplot(plt, CX, CY)
plt.rcParams["font.size"] = 12
# 楕円曲線を描く
a, b = 0, 17
ax.fill(*plot_fxy(x**3+a*x+b-y**2, CX, CY), facecolor='blue')

x1, y1, x2, y2 = -1, 4, 2, 5
plot_dot(x1,y1,-2.5,0.5, r"$P_1$")  #  Plot P1
plot_dot(x2,y2,1,-0.5, r"$P_2$")    #  Plot P2
# ----------- P*Qを計算する --------------
l = sp.Rational(y2-y1,x2-x1)
x3 = l**2-x1-x2
y3 = l*(x3-x1)+y1

draw_line(ax, (x1,y1), l, CY)
plot_dot(x3,y3,0.5,-0.5, r"$P_1*P_2$")    #  Plot P1*P2
plot_dot(x3,-y3,0.5,-0.5, r"$P_1+P_2$")    #  Plot P1+P2
draw_line(ax, (x3,y3), sp.oo, CY)
plt.show

image.png

楕円曲線上の点Pから2Pを求める

例題1: 楕円曲線$y^2=x^3+17$上の点が$P(-1,4)$のとき$2P$をグラフ上に描け

これはPとQが重なったと考えればよいので傾き$\lambda$を微分で求めるだけが違いとなります。

\begin{align}
&楕円曲線 y^2 = x^3+ax+b 上の\\
&点P_1=(x_1,y_1)で接する直線\\
&楕円曲線と交わる点をP_1*P_2= (x_3, y_3)とする\\
&直線の式をy = λx+νとすると\\
&λ = (3x^2+a)/2y  \\
&ν= y_1-λx_1=y_2-λx_2 \\
&これからx_3, y_3は以下のように求まる\\ \\
&x_3=λ^2-2x_1\\
&y_3 = λ(x_3-x1)+ν
\end{align}

したがって上記のコードの$P_2$関連を削除し「P*Qを計算する」部分を以下に変えればよいですね。

# ----------- P*Qを計算する --------------
l = sp.Rational((3*x1**2+a),2*y1)
x3 = l**2-2*x1
y3 = l*(x3-x1)+y1

image.png

(開発環境:Google Colab)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0