楕円曲線暗号のための数学6(GLV法と自己準同型写像)
初めに
今回は、楕円曲線の数学的な性質を用いたスカラー倍算の高速化手法の一つ、GLV法(Gallant-Lambert-Vanstone)を紹介します。
GLV法は小さいマルチスカラー倍算を利用するので、まずそちらから解説しましょう。
マルチスカラー倍算
一般に、楕円曲線の点
を求める操作をマルチスカラー倍算 (MSM : multi-scalar multiplication)といいます。
zk-SNARKなどでは大きな
もちろん、
# return P * x
def mul(P, x, w):
# w ビットNAFテーブル作成
naf = make_NAF(x, w)
tbl = make_table(P, w)
Q = Ec()
for v in range(naf):
Q = dbl(Q)
if v:
Q = add(Q, tbl[v]) if v > 0 else sub(Q, tbl[-v])
return Q
ループの中で
# return P1 * x1 + P2 * x2
def mul(P1, x1, P2, x2, w):
# w ビットNAFテーブル作成
naf1 = make_NAF(x1, w)
naf2 = make_NAF(x2, w)
tbl1 = make_table(P1, w)
tbl2 = make_table(P2, w)
Q = Ec()
for i in range(len(naf1)):
Q = dbl(Q)
v = naf1[i]
if v:
Q = add(Q, tbl1[v]) if v > 0 else sub(Q, tbl1[-v])
v = naf2[i]
if v:
Q = add(Q, tbl2[v]) if v > 0 else sub(Q, tbl2[-v])
return Q
このようにすると、
ECDSAの検証では、Q=P * u1 + S * u2
という処理があります。
実は、ここでもマルチスカラー倍算のテクニックが利用できます。
GLV法のコアアイデア
楕円曲線が与えられたときに、
- ある特殊な定数
があって、任意の楕円曲線の点L のP 倍L が高速に求めらる(algo1)L P - 任意の整数
に対してx となる整数x = a + b L ,a でビット長がb の半分ぐらいのサイズになるものを見つけられる(algo2)x
とします。
このとき、
とても面白いアイデアです。が、そのような都合のよいalgo1, algo2は見つかるのでしょうか。
以下では、特に曲線BLS12-381を念頭に説明します。
BLS12-381曲線パラメータ
BLS12曲線と呼ばれる楕円曲線のファミリーは、
- パラメータ
をとり、z -
,r=z^4-z^2+1 -
,p=(z-1)^2 r / 3 + z
で定まる素数
BLS12-381は z= -0xd201000000010000
で
r=0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
p=0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
です。
自己準同型写像
φ の定義
天下りですが、
という写像を考えます。
φ の準同型性
次に、楕円曲線の加算公式を思い出します。
したがって
よって
これは
注意 : 実は射(morphism)
定数倍写像
前節で定義した
つまり、ある定数
定数
ここで注意 :
w=0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac
L=0xac45a4010001a40200000000ffffffff
となりました。実は
注意 :
-
=w'=-1-w 0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe
-
=L'=-L-1 0x73eda753299d7d483339d80809a1d804a7780001fffcb7fcfffffffe00000001
です(今回はこちらは使わない)。
話をまとめると、
mcl-wasmで確認する
mcl-wasmを使って確認しましょう。
次の test.js
というファイルを作ります。
const mcl = require('mcl-wasm');
(async () => {
await mcl.init(mcl.BLS12_381) // BLS12-381曲線で初期化
const P = mcl.hashAndMapToG1("abc") // 適当な楕円曲線の点を作る
P.normalize() // アフィン座標に変換
console.log(`P.x=${P.getX().getStr(16)}`) // Pの(x, y)座標を表示
console.log(`P.y=${P.getY().getStr(16)}`)
const L = new mcl.Fr()
L.setStr('0xac45a4010001a40200000000ffffffff') // L を設定
console.log(`L=${L.getStr(16)}`)
const Q = mcl.mul(P, L) // Q = P * L
Q.normalize()
console.log(`Q.x=${Q.getX().getStr(16)}`) // Qの(x, y)座標を表示
console.log(`Q.y=${Q.getY().getStr(16)}`)
const w = mcl.div(Q.getX(), P.getX()) // w = Q.x / P.x
console.log(`w=${w.getStr(16)}`)
})()
mkdir work
cd work
npm install -D mcl-wasm
node test.js
で
P.x=16379044479e745e2a14731fee35274308addf04b9e2cd0ef838069689333c4460054b518cc1ec87fce8b9144262e206
P.y=168c083fc11839bd7ef7e655364f65000b6c3e0bf41c60b835a2dd9991aabeefc10b943c0469f211632c62ddf706ee54
L=ac45a4010001a40200000000ffffffff
Q.x=15dd3a9d916f38f45f05dfdce5a795782cffb502859edfd7414f24f474a378f86b8ab2da8becb4ba2e57a0a032b00046
Q.y=168c083fc11839bd7ef7e655364f65000b6c3e0bf41c60b835a2dd9991aabeefc10b943c0469f211632c62ddf706ee54
w=1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac
という結果になりました。Q.y
は P.y
に等しく Q.x
は P.x
の
他の
これでGLV法のコアアイデアのalgo1は解決しました。次にalgo2に移ります。
x の分解
これを (a, b) = split(x)
と書くことにします。
これでalgo2も解決です。
GLV法のまとめ
BLS12-381曲線について今までのパラメータを使ってPythonで書くと
def mul(P, x):
(a, b) = split(x)
naf1 = make_NAF(a, w)
naf2 = make_NAF(b, w)
tbl1 = make_table(P, w)
tbl2 = []
for v in tbl1:
tbl2.append(φ(v)) # L 倍する
# a P + b (L P) をMSMする
# このページの2個目のMSMと同じ
return Q
tbl2
は楕円曲線加算 add
を使って make_table
するよりも、作った tbl1
の各要素に
最初に述べたように、dbl
の回数が256回から128回と半減しました。今まで紹介したウィンドウ法やその改善、NAFでは dbl
の回数は減らせなかったのでこれは大きな改善です。
Discussion