電商網(wǎng)站建設(shè)開發(fā)維護ps怎么做網(wǎng)站
鶴壁市浩天電氣有限公司
2026/01/24 14:13:29
電商網(wǎng)站建設(shè)開發(fā)維護,ps怎么做網(wǎng)站,怎么自己制作網(wǎng)站平臺,家私網(wǎng)站欄目和功能需求策劃這張圖把 ECDSA 的簽名/驗簽數(shù)據(jù)流畫得很直觀#xff1a;左邊 Bob#xff08;持有密鑰對#xff09;#xff0c;右邊 Alice#xff08;只拿到消息簽名公鑰來驗證#xff09;。1) 圖里在講什么#xff1a;標(biāo)準(zhǔn) ECDSA 流程簽名端#xff08;Bob#xff09;對消息做哈希左邊 Bob持有密鑰對右邊 Alice只拿到消息簽名公鑰來驗證。1) 圖里在講什么標(biāo)準(zhǔn) ECDSA 流程簽名端Bob對消息做哈希eH(M)取一個一次性隨機數(shù)noncek圖中單獨畫出來的k橢圓曲線標(biāo)量乘RkG取 R 的 x 坐標(biāo)再 mod 曲線階 n得到計算輸出簽名 (r,s)圖中寫的r k.G、就是這兩步。驗簽端Alice同樣哈希eH(M)計算很多教材寫計算計算點驗證圖右下角的、u1/u2、Pu1.Gu2.pk、Prove rP就是這套驗簽。2) 為什么會引出“確定性簽名”問題全在 kECDSA 里k 的質(zhì)量是生死線如果 k 重復(fù)用在兩次不同消息上或者被攻擊者猜到/泄露一部分私鑰 sksksk 會被直接解出來。歷史上很多真實事故都不是算法錯而是隨機數(shù)發(fā)生器不可靠、實現(xiàn) bug、虛擬機熵不足、設(shè)備啟動早期熵不夠等導(dǎo)致 k 出問題。所以“確定性 ECDSADeterministic ECDSA”的核心思想是k 不再靠外部 RNG 隨機生成而是由 (私鑰 sk 消息哈希 e) 通過標(biāo)準(zhǔn)算法確定性地產(chǎn)生。這樣 RNG 掛了也不至于把私鑰送出去。3) ECDSA 的“確定性簽名”到底確定在哪里確定性 ECDSA 并不是改了 r,s 公式公式完全一樣而是把隨機選 k換成確定性推導(dǎo) k最常見、事實標(biāo)準(zhǔn)是RFC 6979用HMAC_DRBG從 sk 與 eH(M) 推導(dǎo)出 k??梢园阉斫獬扇缓笳张f算結(jié)果是什么同一個私鑰 sk 對同一條消息 M每次簽名得到的 (r,s)完全一致如果不額外加鹽。不依賴系統(tǒng) RNG也就規(guī)避了“爛隨機數(shù)導(dǎo)致私鑰泄露”的大坑。4) 確定性簽名的優(yōu)缺點優(yōu)點強抗 RNG 故障最大價值點??蓮?fù)現(xiàn)調(diào)試、審計、硬件實現(xiàn)一致性更好。協(xié)議層不用改驗簽方完全無感還是標(biāo)準(zhǔn) ECDSA 簽名。注意點 / 風(fēng)險仍然要防側(cè)信道計時/功耗/緩存因為 k 雖然不靠 RNG但它依然是“必須保密的一次性秘密”。有些系統(tǒng)會在 RFC6979 的基礎(chǔ)上再混入少量隨機性“deterministic but randomized”來增強側(cè)信道防護——這不影響正確性但會讓簽名不再完全可復(fù)現(xiàn)。5) 你可以用一句話記住確定性 ECDSA 標(biāo)準(zhǔn) ECDSA 用 RFC6979 從(私鑰消息哈希)確定性生成 k公式不變安全性大幅降低對隨機數(shù)的依賴避免“k 出事私鑰就沒了”。下面按圖里的變量k、r、s、c、u1、u2、P把 **“確定性 ECDSARFC6979”**講透并給出一份可直接照著寫 Delphi 的偽代碼 單元骨架。1) 關(guān)鍵點確定性 ECDSA 只“換掉 k 的來源”ECDSA 的簽名公式不變其中 e 是消息哈希按規(guī)則截斷/折疊確定性的地方在于不再用 RNG 隨機挑 k而是用 RFC6979 的 HMAC_DRBG 從(sk, e)推導(dǎo)出 k。同一私鑰 同一消息 → 推導(dǎo)出的 k 固定 → 簽名 (r,s) 固定。2) RFC6979 的 k 推導(dǎo)流程HMAC_DRBG2.1 需要的輔助函數(shù)RFC6979 術(shù)語設(shè)曲線階為 nnn其字節(jié)長度qlen bit_length(n)rolen ceil(qlen / 8)n 的定長字節(jié)數(shù)定義int2octets(x)把整數(shù) x 編成固定 rolen 字節(jié)的大端序不足左補 0bits2int(b)把哈希輸出 b比特串取左側(cè) qlen 位如果 b 比 qlen 長就截斷得到整數(shù)bits2octets(b)z1 bits2int(b)z2 z1 mod n返回int2octets(z2)注意這一步就是“把 H(M) 變成適合模 n 的 e”。很多實現(xiàn)錯在沒做 bits2octets / truncation。2.2 HMAC_DRBG 狀態(tài)機K、V選擇哈希函數(shù)常見P-256 用 SHA-256secp256k1 也常用 SHA-256P-384 用 SHA-384…初始化V 0x01重復(fù)hlen次K 0x00重復(fù)hlen次bx int2octets(sk) || bits2octets(h1)其中h1 H(M)的原始哈希字節(jié)串更新K HMAC(K, V || 0x00 || bx)V HMAC(K, V)K HMAC(K, V || 0x01 || bx)V HMAC(K, V)生成候選 k循環(huán)T emptywhile len(T) rolen:V HMAC(K, V)T T || Vk bits2int(T)同樣按 qlen 截斷if1 k n-1成功返回 k否則極少發(fā)生K HMAC(K, V || 0x00)V HMAC(K, V)繼續(xù)循環(huán)3) 把 k 塞回你圖里的 ECDSA 簽名公式得到 k 后就是標(biāo)準(zhǔn) ECDSAR k*Gr R.x mod n若r0重新生成 kRFC6979 循環(huán)繼續(xù)即可e bits2int(H(M))或者直接用上面 bits2octets 產(chǎn)生的 z 再轉(zhuǎn)整數(shù)兩者要一致s k^{-1} * (e r*sk) mod n若s0重新生成 k推薦額外做一步 “l(fā)ow-s 規(guī)范化”防簽名可塑性如果s n/2就s n - s4) Delphi 實現(xiàn)要點你寫代碼時最容易踩坑的地方4.1 哈希與 HMAC你需要Hash(M) - bytesHMAC(K, data) - bytes你可以選System.Hash新 Delphi 版本常見mORMot 的 SHA/HMACOpenSSL 的 HMAC 接口最穩(wěn)我下面給骨架時把 HMAC/SHA 當(dāng)作可替換的函數(shù)。4.2 大整數(shù)簽名過程里必需modInv(k, n)modMul / modAdd / mod建議用System.Math.BigNumbers的TBigInteger如果你版本有否則用你自己的大數(shù)庫/openssl BN。4.3 橢圓曲線運算你需要ScalarMul(G, k) - ECPointECAdd(P,Q)驗簽要用如果你不想自己寫橢圓曲線算術(shù)最省事是用 OpenSSL 的 EC_GROUP/EC_POINT 做乘法與加法r,s 的計算用 BN 做5) Delphi 偽代碼 單元骨架照著填就能跑下面把RFC6979 派生 k寫成 Delphi 風(fēng)格骨架ECC 點乘那部分你可以接 OpenSSL 或你已有的曲線庫。unit DeterministicECDSA_RFC6979; interface uses System.SysUtils, System.Classes {$IFDEF HAS_BIGINTEGER} , System.Math.BigNumbers {$ENDIF} ; type TBytes System.SysUtils.TBytes; // 你需要提供HMAC(Hash) 與 Hash // 推薦HMAC-SHA256 / SHA256以 P-256 或 secp256k1 為例 THashFunc reference to function(const Data: TBytes): TBytes; THmacFunc reference to function(const Key, Data: TBytes): TBytes; // 曲線參數(shù)需要n階G基點以及點乘函數(shù) // 這里把點類型抽象掉方便你接 OpenSSL 或自寫實現(xiàn) TECPoint record X, Y: TBytes; // 或者你用 BN/BigInteger 保存 end; function RFC6979_DeriveK( const PrivKeyInt2Octets: TBytes; // int2octets(sk), fixed rolen bytes const MsgHash: TBytes; // h1 H(M) const N_BigEndian: TBytes; // n 的大端字節(jié)固定 rolen 也行 QLenBits: Integer; const Hmac: THmacFunc; HLen: Integer ): TBytes; // 返回 k 的 int2octets(k), fixed rolen bytes implementation function CeilDiv(A, B: Integer): Integer; begin Result : (A B - 1) div B; end; function ConcatBytes(const A, B: TBytes): TBytes; var L1, L2: Integer; begin L1 : Length(A); L2 : Length(B); SetLength(Result, L1 L2); if L1 0 then Move(A[0], Result[0], L1); if L2 0 then Move(B[0], Result[L1], L2); end; function Concat3(const A, B, C: TBytes): TBytes; begin Result : ConcatBytes(ConcatBytes(A, B), C); end; function RepeatByte(B: Byte; Count: Integer): TBytes; var i: Integer; begin SetLength(Result, Count); for i : 0 to Count - 1 do Result[i] : B; end; // bits2int取左邊 qlen 位 function Bits2Int(const Bits: TBytes; QLenBits: Integer): TBytes; var qlenBytes, shiftBits: Integer; tmp: TBytes; i: Integer; begin qlenBytes : CeilDiv(QLenBits, 8); SetLength(tmp, qlenBytes); // 先取前 qlenBytes for i : 0 to qlenBytes - 1 do if i Length(Bits) then tmp[i] : Bits[i] else tmp[i] : 0; shiftBits : (qlenBytes * 8) - QLenBits; if shiftBits 0 then begin // 右移 shiftBits僅對最后一個字節(jié)區(qū)域不夠時的截斷 // 簡化實現(xiàn)整體右移 shiftBits // 你也可以換成大整數(shù)處理更穩(wěn) // 下面給一個字節(jié)級右移 var carry: Byte : 0; for i : 0 to qlenBytes - 1 do begin var newCarry : tmp[i] shl (8 - shiftBits); tmp[i] : (tmp[i] shr shiftBits) or carry; carry : newCarry; end; end; Result : tmp; end; // 這里的 ModN / Compare / SubN / AddN 等最好用大整數(shù)實現(xiàn) // 為了給你結(jié)構(gòu)清晰我只留接口說明。 // 你實際實現(xiàn)時把字節(jié)串轉(zhuǎn) BN/BigInteger做 mod 運算再轉(zhuǎn)回定長 rolen bytes。 function RFC6979_DeriveK( const PrivKeyInt2Octets: TBytes; const MsgHash: TBytes; const N_BigEndian: TBytes; QLenBits: Integer; const Hmac: THmacFunc; HLen: Integer ): TBytes; var rolen: Integer; K, V, bx: TBytes; h1_b2o: TBytes; Tacc: TBytes; begin rolen : Length(PrivKeyInt2Octets); // 定長 // h1_b2o bits2octets(h1) int2octets(bits2int(h1) mod n) // 你需要在這里做Bits2Int(MsgHash) - integer - mod n - int2octets // 暫用占位請?zhí)鎿Q為正確的 mod n 邏輯 h1_b2o : Bits2Int(MsgHash, QLenBits); // TODO: h1_b2o : Int2Octets( (BigInt(h1_b2o) mod n), rolen ) bx : ConcatBytes(PrivKeyInt2Octets, h1_b2o); V : RepeatByte($01, HLen); K : RepeatByte($00, HLen); // K HMAC(K, V || 0x00 || bx) K : Hmac(K, Concat3(V, TBytes.Create($00), bx)); V : Hmac(K, V); // K HMAC(K, V || 0x01 || bx) K : Hmac(K, Concat3(V, TBytes.Create($01), bx)); V : Hmac(K, V); while True do begin SetLength(Tacc, 0); while Length(Tacc) rolen do begin V : Hmac(K, V); Tacc : ConcatBytes(Tacc, V); end; // k bits2int(Tacc) Result : Bits2Int(Tacc, QLenBits); // TODO: 把 Result 作為整數(shù)檢查 1..n-1 // if 1 k n-1 then // Result : Int2Octets(k, rolen); Exit; // 失敗分支極少 K : Hmac(K, ConcatBytes(V, TBytes.Create($00))); V : Hmac(K, V); end; end; end.上面這份骨架里我刻意把“mod n / 比較 1..n-1 / int2octets 定長輸出”留成 TODO因為這部分你肯定會用你自己的大數(shù)TBigInteger 或 OpenSSL BN這樣最穩(wěn)、也最貼合你現(xiàn)有工程。6) 你接下來怎么落地兩條路線路線 A全用 OpenSSL最省心、最不容易錯HMAC/SHAOpenSSL大數(shù) BNOpenSSLEC 點乘/加法OpenSSL你只負責(zé) RFC6979 輸出 k然后用 OpenSSL 做k*G取 r再算 s。路線 B你有自己的 ECC / 大數(shù)庫直接把 RFC6979 的 k 接到你現(xiàn)有的ScalarMul(G,k)上