1. 程式人生 > 實用技巧 >ECDSA橢圓曲線數字簽名演算法

ECDSA橢圓曲線數字簽名演算法

ECDSA橢圓曲線數字簽名演算法

Rust實現;


目錄

符號說明

橢圓加密數學基礎

  • \(F_p\): \(y^2 = x^3 + ax + b, (4a^3+27b^2)\mod p \ne 0, (x,y)\in F_p\);
  • \(F_{2^m}\): \(y^2 + xy = x^3 + ax^2+b, b \ne 0, (x,y) \in F_{2^m}\);
  • \(G\): 橢圓曲線域引數的基點或生成子;
  • \((x_P, y_P)\): 橢圓曲線點\(P\)的座標表示;
  • \((r,s)\): 數字簽名, 整數對;
  • \(Q\): 公鑰;
  • \(d\): 私鑰, \(Q = d\cdot G\);
  • \(\mathcal{O}\)
    : 無限遠點, 充當橢圓曲線群的零元素;
  • \(n\): 素數, 生成子\(G\)的階;
  • \(E(F_q)\): 定義在\(F_q\)域上的橢圓曲線;
  • \((a, b)\): 橢圓曲線的係數;
  • \(q\): 有限域的大小;
  • \(truncate_l(X)\): 取位字串\(X\)的最左邊\(l\)位/位元組;
  • 域引數:
    • \(q\);
    • \(a\);
    • \(b\);
    • \(x_G\);
    • \(y_G\);
    • \(n\);
    • \(SEED\): (可選), 用於生成可驗證的隨機域引數的位字串;
    • \(h\): (可選), 餘因子\(h=|E|/n\);

資料轉換

整數和八位串之間的轉換

記有自然數\(x\), 與其對應的八位串記為\(M\)

. 其中, \(len(M) = k, 2^{8\cdot k} \gt x\), 那麼整數和八位串之間的轉換可使用如下公式:

  • \(x = \sum_{i=1}^{k}2^{8\cdot (k-i)} \cdot m_i\);
  • \(M = m_1 || m_2 || \dots || m_k\);

域元素轉為八位串

記有域元素\(\alpha, \alpha \in F_q\), 將其轉換為八位串\(M\):

  • \(t = \lceil \log_2(q) \rceil, l = \lceil t/8 \rceil\);
  • \(q \mod 2 = 1\):
    • \(\alpha \in [0,q-1]\)的整數, 按照整數將其轉為八位串;
  • \(q \mod 2 = 0, q = 2^m\):
    • \(\alpha = s_1 || s_2 || \dots || s_m\);
    • \(S = 0||\dots||0, bitslen(S) = 8\cdot l - m\);
    • \(M = S || s_1 || s_2 || \dots || s_m\);

八位串轉為域元素

記有域\(F_q\), 八位串\(M, len(M) = l, l = \lceil t/8 \rceil, t = \lceil \log_2(q) \rceil\), 將其轉為域元素\(\alpha\):

  • \(q \mod 2 = 1\):
    • \(M\)轉為整數\(x\), 若\(x \in [0,q-1]\), 則\(\alpha = x\);
  • \(q \mod 2 = 0, q = 2^m\):
    • \(M = S || m_1 || m_2 || \dots || m_m, bitslen(S) = 8\cdot l - m\);
    • \(\alpha = m_1 || m_2 ||\dots ||m_m\);

域元素轉為整數

記有域元素\(\alpha \in F_q\), 將其轉為整數\(x\):

  • \(q \mod 2 = 1\):
    • \(x = \alpha\);
  • \(q \mod 2 = 0, q = 2^m\):
    • \(\alpha = s_1 || s_2 || \dots || s_m\);
    • \(x = \sum_{i=1}^{m} 2^{m-i} s_i\);

曲線點轉為八位串

無窮遠點\(\mathcal{O}\)轉為\(M = 0x00\);

記有橢圓曲線\(E(F_q)\)上的非無窮遠點\(P=(x_P, y_P)\), 將其轉為八位串\(M\):

  • 將域元素\(x_P\)轉為八位串\(M_x\);
  • 若以壓縮形式表示點, 則:
    • 計算壓縮形式\((x_P, z_P)\);
    • \(z_P = 0\):
      • \(M = 0x02 || M_x\);
    • \(z_P = 1\):
      • \(M = 0x03 || M_x\);
  • 若以非壓縮形式表示點, 則:
    • 將域元素\(y_P\)轉為八位串\(M_y\);
    • \(M = 0x04 || M_x || M_y\);
  • 若以混合形式表示點, 則:
    • 將域元素\(y_P\)轉為八位串\(M_y\);
    • 計算\(z_P\);
    • \(z_P = 0\):
      • \(M= 0x06 || M_x || M_y\);
    • \(z_P = 1\):
      • \(M= 0x07 || M_x || M_y\);

八位串轉為曲線點

記有域\(F_q\), 和合法的八位串\(M\), 將其轉為點$P=(x_P, y_P);:

  • \(l = \lceil \log_2(q) / 8 \rceil\);
  • \(len(M) = 1 \land M = 0x00\):
    • \(P = \mathcal{O}\);
  • \(len(M) = l + 1\):
    • \(M = S || M_x, len(S) = 1\);
    • 驗證\(S = 0x02 \lor S = 0x03\);
    • \(S = 0x02\):
      • \(z_P = 0\);
    • \(S = 0x03\);
      • \(z_P = 1\);
    • 將八位串\(M_x\)轉為域元素\(x_P\);
    • 壓縮形式的點\((x_P, z_P)\)轉為點\((x_P, y_P)\);
  • \(len(M) = 2\cdot l + 1\):
    • \(M = S || M_x || M_y, len(S) = 1, len(M_x) = l\);
    • 驗證\(S = 0x04 \lor S = 0x06 \lor S = 0x07\);
    • 將八位串\(M_x\)轉為域元素\(x_P\);
    • 將八位串\(M_y\)轉為域元素\(x_P\);
    • \(S = 0x06 \lor S = 0x07\):
      • \(S = 0x06\)
        • \(z_P = 0\)
      • \(S = 0x07\)
        • \(z_P = 1\)
      • \((x_P, y_P)\)計算\(z_{P}^{'}\), 驗證\(z_P = z_{P}^{'}\);
      • \((x_P, z_P)\)計算\((x_P, y_{P}^{'})\), 驗證\(y_P = y_{P}^{'}\);

簽名

  • 記有位字串訊息\(M\);
  • 由域引數生成臨時金鑰對\((k, R)\);
  • \(x_R\)轉為整數\(j\);
  • \(r = j \mod n, r \ne 0\);
  • \(H = Hash(M)\);
  • \(H\)轉為整數\(e\):
    • \(E = truncate_l(H), l = \min(log_2(n), bitslen(H))\);
    • 將位字串轉為整數\(e\);
  • \(s = k^{-1}\cdot (e+d\cdot r) \mod n,\quad s \ne 0\);
  • 輸出\((r, s), r\in [1,n-1], s\in [1,n-1]\);

驗證

通過公鑰驗證

  • 記收到訊息\(M'\), 簽名\((r', s')\);
  • 驗證\((r' \in [1,n-1]) \land (s' \in [1,n-1])\);
  • \(H' = Hash(M')\);
  • \(H'\)轉為整數\(e\):
    • \(E = truncate_l(H'), l = \min(log_2(n), bitslen(H))\);
    • 將位字串\(E\)轉為整數\(e\);
  • \(u_1 = e' \cdot (s')^{-1} \mod n, u_2 = r' (s')^{-1}\mod n\);
  • 計算橢圓曲線點\(R=(x_R, y_R) = u_1\cdot G + u_2\cdot Q\);
  • 驗證\(R \ne \mathcal{O}\);
  • \(x_R\)轉為整數\(j\);
  • \(v = j\mod n\);
  • 驗證\(v = r'\);

通過私鑰驗證

  • 記收到訊息\(M'\), 簽名\((r', s')\);
  • 驗證\((r' \in [1,n-1]) \land (s' \in [1,n-1])\);
  • \(H' = Hash(M')\);
  • \(H'\)轉為整數\(e\):
    • \(E = truncate_l(H'), l = \min(log_2(n), bitslen(H))\);
    • 將位字串\(E\)轉為整數\(e\);
  • \(u_1 = e' \cdot (s')^{-1} \mod n, u_2 = r' (s')^{-1}\mod n\);
  • \(k' = (u_1 + u_2\cdot d) \mod n\);
  • \(R = k'\cdot G\);
  • 驗證\(R \ne \mathcal{O}\);
  • \(v = j\mod n\);
  • 驗證\(v = r'\);

橢圓曲線域引數

點壓縮

記由橢圓曲線上的一點\(P=(x_P, y_P)\), 則點可以壓縮為\(x_P\)\(y_P\)的某些位\(z_P\);

  • \(rightmost_l(y)\)表示\(y\)的最右邊的\(l\)位;
  • \(leftmost_l(y)\)表示\(y\)的最左邊的\(l\)位;

\(F_p\)上點壓縮

\(P=(x_P,y_P), y^2 = x^3 + a\cdot x+b,\quad x,y\in F_p,\ z_P = rightmost_1(y_P)\);

  • 已知\((x_P, z_P)\)\(y_P\);
    • \(\alpha = x_P^3 + a\cdot x_P + b \mod p\);
    • \(\beta = \sqrt{\alpha} \mod p\);
    • \(y_P = \beta\quad if\ rightmost_1(\beta)=y_P\quad else\ y_P = p-\beta\);

\(F_{2^m}\)上點壓縮

\(P=(x_P,y_P), y^2 + x\cdot y = x^3 + a\cdot x^2 + b,\quad x,y\in F_{2^m}\). 若\(x_P=0\), 則\(z_P=0\). 否則, \(z_P = rightmost_1(y_P\cdot x_{P}^{-1})\);

  • 已知\((x_P, z_P)\)\(y_P\);
    • \(x_P=0\), \(y_P = b^{2^{m-1}}\);
    • 若$x_P\ne 0 $:
      • \(\alpha = x_P + a + b\cdot x_P^{-2}\);
      • \(\beta^2 + \beta = \alpha\);
      • \(z_{P}^{'} = rightmost_1(\beta)\);
      • \(z_{P}^{'} \ne z_P\);
      • \(y_P = x_P\cdot \beta\);

保證橢圓曲線安全性的一些必要條件

MOV條件

Menezes-Okamoto-Vanstone(MOV): \(F_q \rightarrow F_{q^B}, B\ge 1\), ANS X9.62中選擇\(B\)大於等於100;

  • 給定MOV閾值\(B\), 素數\(q\), 素數\(n, n=|E(F_q)|\), 驗證MOV條件是否合法:
    • \(t = 1\);
    • for i in 1..=B:
      • \(t = t\cdot q \mod n\);
      • return false, if \(t = 1\);
    • return true;

異常條件(The Anomalous condition)

\(|E(F_q)| = q\), 則稱定義在\(F_q\)上的橢圓曲線\(E(F_q)\)\(F_q-anomalous\), 該種情況下橢圓曲線的離散對數問題很容易被解出.

  • 給定\(E(F_q)\), 及橢圓曲線的階\(u=|E(F_q)|\), 驗證是否滿足Anomalous條件:
    • return u != q;

橢圓曲線的選擇

可驗證隨機橢圓曲線

給定隨機種子\(SEED\), \(t=bitslen(HashVal)\), \(|F_q|=q\), 求橢圓曲線的係數\((a,b)\);

  • \(m = \lceil \log_2(q) \rceil\);
  • \(s = \lfloor (m-1)/t \rfloor\);
  • \(k = m - st - (q \mod 2)\);
  • \(H = Hash(SEED)\);
  • \(H\)轉為整數\(e\);
  • \(c_0 = e \mod 2^k\);
  • for j in 1..=s:
    • \(c_j = Hash((SEED + j)\mod 2^g)\)
  • \(c = c_0\cdot 2^{ts} + c_1\cdot 2^{t\cdot (s-1)}+\dots + c_s\);
  • 將整數\(c\)轉為域元素\(r\);
  • \(F_q\)中隨機選擇一個元素\(a\);
  • \(q \mod 2 = 0\):
    • \(b = r\);
    • return error, if \(b = 0\);
  • \(q \mod 2 = 1\):
    • \(b^2\cdot r = a^3\)
    • return error, if \(4\cdot a^3 + 27\cdot b^2 = 0\);
  • return (a,b);

橢圓曲線的驗證

  • 給定橢圓曲線\(E(F_q, a, b)\), 可選的種子\(SEED\), 驗證該橢圓曲線是否合法:
    • \(q\)是奇數, 若:
      • \(q\)不是素數:
        • return false;
      • \(a \notin [0,q-1], b \notin [0,q-1]\):
        • return false;
      • \(4\cdot a^3 + 27\cdot b^2 = 0\):
        • return false;
    • \(q\)是偶數, 若:
      • \(q\)不滿足\(q = 2^m\), \(m\)是素數;
        • return false;
      • \(bitslen(a) \ne m, bitslen(b) \ne m\):
        • return false;
    • \(SEED\)提供, 驗證更具上一節的橢圓曲線生成演算法生成\((a', b')\):
      • return a=a' && b=b';
    • return true;

基點的選擇

可驗證隨機基點

給定隨機種子\(SEED\), 整數計數器\(base\), \(hashlen = bitslen(HashVal)\), 域大小\(q\), 餘因子\(h\), 求基點\(x_G, y_G\);

  • \(element = 1\);
  • loop:
    • 將計數器\(base\)的值和\(element\)轉為位字串\(Base, Element\);
    • \(H = Hash("Base point" || Base || Element || SEED)\);
    • \(H\)轉為整數\(e\);
    • \(element = element + 1\);
    • break, if \(\lfloor e/2\cdot q \rfloor \ne \lfloor 2^{hashlen} / (2\cdot q) \rfloor\);
  • \(t = e \mod (2\cdot q)\);
  • \(x = t\mod q, z = \lfloor t/q \rfloor\);
  • \(x\)轉為域元素\(x_G\);
  • \((x_G, z)\)計算出\(y_G\);
  • 輸出\((x_G, y_G)\);

基點的驗證

給定域引數, 驗證基點\(G\)是否合法;

  • \(G = \mathcal{O}\):
    • return false;
  • \(q\)奇數, 若:
    • \(x_G \notin [0,q-1], y_G \notin [0,q-1]\):
      • return false;
    • \(y_{G}^2 \ne x_{G}^3 + a\cdot x_G + b\):
      • return false;
  • \(q=2^m\)偶數, 若:
    • \(bitslen(x_G) \ne m, bitslen(y_G) \ne m\):
      • return false;
    • \(y_{G}^2 + x_G\cdot y_G \ne x_{G}^3 + a\cdot x_{G}^2 + b\):
      • return false;
  • \(n\cdot G \ne \mathcal{O}\):
    • return false;
  • 若提供了隨機種子\(SEED\):
    • \(base = 1\):
    • loop:
      • return false, if \(base \gt 10\cdot h^2\);
      • 通過\(SEED\)\(base\)生成基點\(R=(x,y)\);
      • \(G' = h\cdot R\);
      • \(base = base + 1\);
      • break, if \(n\cdot G' = \mathcal{O}\);
    • return G' = G;
  • return true;

橢圓曲線域引數的選擇

生成隨機種子\(SEED\), 生成基點/曲線係數;

EC域引數的驗證

給定安全級別\(s\);

  • \(n \lt \max(2^{2\cdot s - 1}, 2^{160})\):
    • return false;
  • \(n\)不是素數:
    • return false;
  • 橢圓曲線\(E(F_q, a, b)\)不合法:
    • return false;
  • \(h' = \lfloor (q^{1/2} + 1)^2 / n\);
  • 如果域引數提供了\(h\), 若\(h \ne h'\):
    • return false;
  • \(h' \gt 2^{s/8}\):
    • return false;
  • MOV條件不合法:
    • return false;
  • Anomalous條件不合法:
    • return false;
  • 基點\(G\)不合法:
    • return false;
  • return true;

EC域引數的生成

給定安全級別\(s\), 和可選的一些限制: 最大的餘因子值\(h_max\), 準素性驗證中的素除數界\(I_max\), MOV條件的閾值\(B\);

  • 生成\(SEED\);
  • 選擇一個符合安全級別的域大小\(q\);
  • 生成\(E(F_q, a, b)\);
  • 計算橢圓曲線的大小\(u=|E|\);
  • 生成\(n, h\);
  • 生成基點\(G\);
  • 驗證域引數的合法性;
  • 輸出域引數;

橢圓曲線金鑰對

\((d, Q), d\in [1,n-1], Q = d\cdot G\);

橢圓曲線公鑰驗證

給定公鑰\(Q\)和已經驗證正確的域引數, 驗證\(Q\)的合法性:

  • \(Q = \mathcal{O}\):
    • return false;
  • \(q \mod 2 = 1\):
    • \(x_Q \not in [0,q-1], y_Q \notin [0,q-1]\):
      • return false;
    • \(y_Q^2 \ne x_Q^3 + a\cdot x_Q + b\):
      • return false;
  • \(q \mod 2 = 0, q = 2^m\):
    • \(bitslen(x_Q) \ne m, bitslen(y_Q) \ne m\):
      • return false;
  • \(y_Q^2 + x_Q \cdot y_Q \ne x_Q^3 + a\cdot x_Q^2 + b\):
    • return false
  • \(n\cdot Q \ne \mathcal{O}\):
    • return false;
  • \(n\cdot Q = \mathcal{O}\):
    • return true;

橢圓曲線金鑰對的生成

給定已經驗證正確的域引數, 金鑰對\((d, Q)\)生成如下:

  • 隨機選擇一個整數作為私鑰\(d\in [1,n-1]\);
  • 計算公鑰\(Q = d\cdot G\);

素性

概率素性測試-ProbabilisticPrimalityTest

Miller-Rabin測試;

由於早期部落格符號不統一, 這裡重新描述下:

  • 記由一個奇數\(n\), 和正整數\(T\), 現需判斷\(n\)是合數, 還是可能是一個素數(注意這裡是可能, Miller-Rabin測試出錯的概率和測試次數有關, 至多為\(2^{-T}\));
    • 計算非負整數\(v\)和奇正數\(w\), 滿足\(n-1 = 2^v \cdot w\);
    • rust: for j in 1..=T:
      • 隨機選擇一個整數\(a, a\in [2, n-1]\);
      • \(b = a^w \mod n\);
      • continue, if \(b = 1\) or \(b = n-1\);
      • \(cnt = 0\);
      • for i in 1..=(v-1):
        • \(b = b^2 \mod n\);
        • break, if \(b = n-1\);
        • return 合數 if \(b = 1\);
        • \(cnt = cnt + 1\);
      • return 合數, if \(cnt = v-1\);
    • return 可能是素數;

準素性(near primality)測試

  • 概念說明:

    • 記有正整數\(I_{max}\), 若正整數\(h\)的每個素除數都不超過\(I_{max}\), 那麼稱\(h\)\(I_{max}-smooth\);
    • 記有兩個素數\(p_1, p_2\), 有\(p=p_1\cdot p_2\), 那麼稱\(p\)是準素數;
    • 記有正整數\(r_{min}\), \(I_{max}-smooth\)的正整數\(h\), 及可能是素數的正整數\(n, n\ge r_{min}\). 若正整數\(u\)滿足\(u=h\cdot n\), 那麼\(u\)是一個準素數;
  • 準素性測試:

    • 記有正整數\(r_{min}, I_{max}, u\), 判斷\(u\)是否是一個準素數:
      • \(n = u, h = 1\);
      • for i in 2..=I_max:
        • while \(n / i \gt 0\):
          • \(n = n / i,\quad h = h\cdot i\);
          • return 非準素數, if \(n \lt r_{min}\);
      • return (準素數, h, n), if \(n\)滿足概率素性測試;
      • return 非準素數;

參考資料

  • ANS X9.62-2005;