secp256k1のベースポイントの性質をみていきます。
有理点(x, y)はおよそ256ビットの範囲内で均等に値がばらけていると考えられます。
ベースポイントGの倍数 を計算したときのx, yの値はおよそ256ビットの値がランダムに並んだようになりますが、たまたま端っこによった場合は、
0にすごく近かったり、群の位数に近かったりしますが、確率としては低いです。
sage: E = EllipticCurve(GF(2 ** 256 - 2 ** 32 - 977), [0, 7]) sage: G = E([55066263022277343669578718895168534326250603453777594175500187360389116729240,32670510020758816978083085130507043184471273380659243275938904335757337482424]) sage: Integer(E.cardinality()).hex() 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' sage: Integer(G[0]).hex() '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' sage: Integer(G[1]).hex() '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
cardinality(群の位数)の先頭にffが続いているのはコンピュータ計算を高速に行うために2のべきから近い値にするためであり当然の結果です。
Gの倍数をSageMathで少し計算してみます。
sage: Integer((2 * G)[0]).hex() 'c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5' sage: Integer((2 * G)[1]).hex() '1ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a' sage: Integer((3 * G)[0]).hex() 'f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9' sage: Integer((3 * G)[1]).hex() '388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672'
特におかしなところはないですね。 次に以下を試してみましょう。
G * Integer((E.cardinality()+1)/2) (86918276961810349294276103416548851884759982251107 : 87194829221142880348582938487511785107150118762739500766654458540580527283772 : 1) Integer((G * Integer((E.cardinality()+1)/2))[0]).hex() '3b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63'
nを群位数(奇数)として G * (n+1)/2 の点のxの値が凄く小さいです。
これは16進数で書くと'00000000000000000000003b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63'
であり、取りうる範囲に対して0に凄く近いです。
また、この点Pは 2P = G の関係を満たすことが以下の計算で確認できます。
sage: P = G * Integer((E.cardinality()+1)/2) sage: P (86918276961810349294276103416548851884759982251107 : 87194829221142880348582938487511785107150118762739500766654458540580527283772 : 1) sage: 2 * P (55066263022277343669578718895168534326250603453777594175500187360389116729240 : 32670510020758816978083085130507043184471273380659243275938904335757337482424 : 1) sage: G (55066263022277343669578718895168534326250603453777594175500187360389116729240 : 32670510020758816978083085130507043184471273380659243275938904335757337482424 : 1)
なぜこのようなことがおきるかというとベースポイントGは166bitに相当する文字列のx値の点を2倍して定められたからです。
secp256k1だけでなく、secp224k1も同じようにベースポイントが定められたようです。
試しに、Gを倍にしてxの値が200bit以下のものを見つけようとしてみましたが、簡単には見つかりません。
これにより、Pのxの値が0に近いのが特別なことであることがわかります。
E = EllipticCurve(GF(2 ** 256 - 2 ** 32 - 977), [0, 7]) G = E([55066263022277343669578718895168534326250603453777594175500187360389116729240,32670510020758816978083085130507043184471273380659243275938904335757337482424]) i = 1 t = 2 ** 200 while True: P = i * G if Integer(P[0]) < t: print i, P break if i % 1000 == 0: print i i = i + 1
参考: The most repeated R value on the blockchain
この記事は別の以下の論文を読んでいて発見しました。
https://eprint.iacr.org/2019/023.pdf
ECDSAのnonceの値がフルランダム(256ビットの精度)でない場合は、ある攻撃方法によってECDSAが破られるよという内容です。
160bit以下のランダムネスだと危ないよということらしいです。
なぜそんな実装になるのか謎すぎますが、このような脆弱性指摘論文はなかなか面白く、暗号分野の研究が活発で健全だなあという印象です。