橢圓曲線加密算法 ECC 橢圓曲線加解密算法

ECC 橢圓曲線加解密算法

一、爲什麼叫橢圓曲線

首先回憶一下直線方程式 y=ax+b ,在座標系中表示一條直線,是一次方程,圓錐曲線可以用二次方程表示。橢圓曲線是用三次方程表示,如下:

其中,a 和 b 的取值不同,橢圓曲線的形狀會有所改變,經典的形狀如下圖所示:

這時有讀者會有疑問了,“上圖中不是一個橢圓的形狀啊,爲什麼叫橢圓曲線啊?”,原因是橢圓曲線的 3 次方程式和橢圓周長公式中的一部分很像,下面是橢圓周長公式:

可以看出積分公式中分母的平方恰恰就是橢圓曲線的公式。

橢圓曲線有以下兩個特點:

  • 畫一條直線跟橢圓曲線相交,它們最多有三個交點;
  • 關於 X 軸對稱。

二、比特幣使用的橢圓曲線

比特幣中使用的橢圓曲線是 secp256k1,上文圖中的橢圓曲線是連續的,但在像比特幣這些實際應用中,都是有限域上定義的離散曲線。

橢圓曲線三次方程式中參數 a, b,基點 G 的不同,橢圓曲線的加密性能也不一樣。一些常用的使用特定參數的橢圓曲線都有特定的標識,現在世界上比較主流的有:

  • 美國國家標準與技術研究院(NIST)和美國國家安全局(NSA)的 secp256r1、secp521r1 等橢圓曲線
  • 中國國家密碼局認定的 SM2 國產密碼算法。
  • 比特幣和以太坊使用的 secp256k1。

下面來看一下 secp256k1 的所有參數和方程式: y^2 = x^3 + 7 ( a = 0,b = 7)

選擇的基點是:

可以看出方程式和參數並不複雜,反而簡單,那麼有讀者要問了“這麼簡單的方程式和參數,那這個加密算法還安全嗎?”,這個問題非常好,下面會講到它的安全性其實並不是由方程式和參數決定的,而是由橢圓曲線上的運算決定的,請繼續往下看。

三、橢圓曲線運算法則

在橢圓曲線上會定義兩種運算,加法和乘法,但是其實它們和通常意義上的加法和乘法不一樣的,只是爲了方便理解所以這麼叫,怎麼不一樣呢,下面看看具體的定義。

1. 橢圓曲線加法

根據上面介紹的橢圓曲線的特性“畫一條直線跟橢圓曲線相交,它們最多有三個交點”,可以進行以下定義:

  • 假設橢圓曲線上有 P、Q 兩個點,經過這兩個點做一條直線和橢圓曲線相交於第三點 R,然後做關於 x 軸的對稱點 -R,-R 即是 R 的逆元,根據阿貝爾羣的定義,-R 也一定在橢圓曲線上。
  • 定義 P+Q = -R,也就是說橢圓曲線上任意兩點的和也在橢圓曲線上,同樣可以引申出橢圓曲線上任意三點的和爲 0 即 P+Q+R = 0。如圖:
  • 假如 P=Q,則作橢圓曲線在 P 點的切線,與曲線相交於 R,則 R = P+P = 2P

2. 橢圓曲線乘法

根據上面橢圓曲線的加法可以得出下列等式:

  • P+P = 2P(過點 P 切線作一條直線)
  • P+2P = 3P(過點 P 和 2P 作一條直線)
  • P+3P = 4P(過點 P 和 3P 作一條直線)

假設 P 是橢圓曲線上的一個點,正整數 K 乘以 P 可以總結成公式爲:(k-1) * P + P = k * P

如果把 k 看作是兩個數相乘即 k = m * n,則可以得出滿足以下性質(在橢圓曲線密鑰交換中會用到):(m * n) * P = m * (n * P) = (n * m)p = n * (m*P)

四、橢圓曲線的難題

非對稱加密之所以難破解,根本原理就是基於一個數學上的難題,像 RSA 加密就是基於大質數因子分解困難的特性來支撐的,橢圓曲線的難題則是:橢圓曲線上的離散對數問題。

看過 RSA 加密算法原理那篇文章的讀者可能會記得它是基於取模運算,橢圓曲線也是一樣的,滿足下面公式的曲線,其中 p 是質數,x、y、a、b 都是小於 p 的非負整數:

y^2 = x^3 + ax + b (mod p) { (4a^3 + 27b^2!)=0 }

來看一下 y^2 = x^3 - x 這個公式取模後的的圖像(p=71):

可以看出,雖然很散亂,但是仔細看這些點都是關於一條直線對稱的,這條直線就是 y=71/2 這條水平直線,並且原來橢圓曲線上定義的加法和乘法都可用。

假如選擇一個點 P(4,8) 爲基點,按照橢圓曲線的加法去運算 2P、3P… 這樣的話,最後得到一個 k 次加法後的結果 kP(44,44),請問 k 是多少?

這時看一下上面的散點圖,找到 (4,8) 和(44,44)這兩個點,很難找出來通過幾次橢圓曲線加法轉變過去的,更何況這個是在公式中取模的那個質數等於 71 的情況下,如果把這個質數取得很大,難度就更大了,比特幣中使用的 Secp256k1 這條曲線中取模的質數 p 等於:

p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1

這樣一個數,要逐一算出可能性取匹配幾乎是不可能的。

總結一下橢圓曲線的數學依據:

K = kG

  • G 爲橢圓曲線上的一個點,叫基點;
  • k 爲正整數;
  • 如果給定小 k 和 G,通過橢圓曲線加法法則去計算 K 很容易;
  • 如果給定 K 和 G,求小 k 就非常困難。

一般規定大 K 爲公開密鑰,小 k 爲私鑰。

五、橢圓曲線的加密強度

這裏我們那攻擊分組對稱加密 AES 算法的難度來做對比,如下表所示:

  AES	RSA  	ECC
  80	1024	163
  112	2240	233
  128	3072	283

這組數據是國際期刊和一些學術論文中公認的結果,具體的實現步驟這裏就不介紹,重點是要明白 ECC 的強度高,像 AES-128 位的密碼強度和 RSA 的 3072 位密碼強度大約相同,同樣和 ECC 的 283 位密碼強度相同,密碼強度其實就是攻擊的難度,也就是說攻擊 128 位密鑰的 AES 的算法的難度和 ECC283 位密鑰的難度相當。

從圖表中可以觀察到 RSA 的密鑰長度增長的很多,ECC 的密鑰長度增長並不大,考慮到實際使用過程中的性能和未來能持續的安全行,ECC 是更好的選擇。

六、Go語言使用橢圓曲線簽名認證實現

package main
import (
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "crypto/sha256"
    "math/big"
    "fmt"
)
//通過橢圓曲線完成簽名和驗證
func main() {
    //聲明明文
    message := []byte("hello world")
    //生成私鑰
    privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    //生成公鑰
    pub := privateKey.PublicKey
    //將明文散列
    digest := sha256.Sum256(message)
    //簽名
    r, s, _ := ecdsa.Sign(rand.Reader, privateKey, digest[:])
    //設置私鑰的參數類型爲曲線類型
    param := privateKey.Curve.Params()
    //獲得私鑰byte長度
    curveOrderByteSize := param.P.BitLen() / 8
    //獲得簽名返回值的字節
    rByte, sByte := r.Bytes(), s.Bytes()
    //創建數組
    signature := make([]byte, curveOrderByteSize*2)
    //通過數組保存了簽名結果的返回值
    copy(signature[curveOrderByteSize-len(rByte):], rByte)
    copy(signature[curveOrderByteSize*2-len(sByte):], sByte)
    //認證
    //將明文做hash散列,爲了驗證的內容對比
    digest = sha256.Sum256(message)
    curveOrderByteSize = pub.Curve.Params().P.BitLen() / 8
    //創建兩個整形對象
    r, s = new(big.Int), new(big.Int)
    //設置證書值
    r.SetBytes(signature[:curveOrderByteSize])
    s.SetBytes(signature[curveOrderByteSize:])
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章