天天看點

區塊鍊應用:橢圓曲線數字簽名算法ECDSA

作者:架構師老狼

1 橢圓曲線密碼學

  • 橢圓曲線密碼學(Elliptic Curve Cryptography,縮寫ECC),是基于橢圓曲線數學理論實作的一種非對稱加密算法。橢圓曲線在密碼學中的使用是在1985年有Neal Koblitz和Victor Miller分别提出來的。
  • 标準的橢圓曲線
區塊鍊應用:橢圓曲線數字簽名算法ECDSA

橢圓曲線

  • 橢圓曲線加密
  • 考慮K=kG,其中K、G為橢圓曲線Ep(a,b)上的點,n為G的階(n G = O∞ ),k為小于n的整數。則給定k和G,根據加法法則,計算K很容易但反過來,給定K和G,求k就非常困難。因為實際使用中的ECC原則上把p取得相當大,n也相當大,要把n個解點逐一算出來列成上表是不可能的。這就是橢圓曲線加密算法的數學依據 。

2 應用場景

  • 比特币使用橢圓曲線算法生産公鑰和私鑰,選擇的是secp256k1曲線。與RSA(Ron Rivest,Adi Shamir,Len Adleman三位天才的名字)一樣,ECC(橢圓曲線加密算法)也屬于公開秘鑰算法。
  • 橢圓曲線數字簽名算法,因其高安全性,目前已廣發應用在比特币、以太坊、超級賬本等區塊鍊項目中。

3 ECC與RSA算法的優勢對⽐

與經典的RSA、DSA等公鑰密碼體制相⽐,橢圓密碼體制有以下優點:

  • 安全性能更⾼(ECC可以使⽤更短的密鑰):
  • 160位ECC加密算法的安全強度相當于1024位RSA加密;
  • 210位ECC加密算法的安全強度相當于2048位RSA加密。
  • 處理速度快:計算量⼩,處理速度快 在私鑰的處理速度上(解密和簽名),ECC遠 ⽐RSA、DSA快得多。
  • 存儲空間占⽤⼩: ECC的密鑰尺⼨和系統參數與RSA、DSA相⽐要⼩得多, 是以占⽤的存儲空間⼩得多。
  • 帶寬要求低使得ECC具有⼴泛的應⽤前景。ECC的這些特點使它必将取代RSA,成為通⽤的公鑰加密算法。

4 數字簽名與驗證過程

  • 隻有轉賬人才能生成一段防僞造的字元串。通過驗證該字元串,一方面證明改交易是轉出方本人發起的,另一方面證明交易資訊在傳輸過程中沒有被更改。
  • 數字簽名由:數字摘要和非對稱加密技術組成。數字摘要把交易資訊hash成固定長度的字元串;再用私鑰對hash後的交易資訊進行加密成數字簽名。
  • 交易中,需要将完整的交易資訊和數字簽名一起廣播給礦工。礦工節點用轉賬人公鑰對簽名驗證,驗證成功說明改交易确實是轉賬人發起;曠工節點将交易資訊進行hash後與簽名的交易資訊摘要進行比對,如果一緻則說明交易資訊在傳輸過程中沒有被篡改。
區塊鍊應用:橢圓曲線數字簽名算法ECDSA

數字簽名及驗證過程

5 代碼驗證

  • ⽣成私鑰和公鑰,⽣成的私鑰為結構體ecdsa.PrivateKey的指針
func NewKeyPair() (ecdsa.PrivateKey, []byte) {
        // 生産secp256橢圓曲線
        curve := elliptic.P256()
        // 産生一個結構體指針,結構體類型ecdsa.PrivateKey
        private, err := ecdsa.GenerateKey(curve, rand.Reader)
        if err != nil {
        log.Panic(err)
        }
        fmt.Println("私鑰:%x\n", private)
        fmt.Println("私鑰X:%x\n", private.X.Bytes())
        fmt.Println("私鑰Y:%x\n", private.Y.Bytes())
        fmt.Println("私鑰D:%x\n", private.D.Bytes())
        // x坐标與y坐标拼接在一起生成公鑰
        publicKey := append(private.X.Bytes(), private.Y.Bytes()...)
        fmt.Println("公鑰:%x\n", publicKey)
        return *private, publicKey
}           
  • ⽣成簽名的DER格式
func MakeSignatureDerString(r, s string) string {
        // 擷取R和S的⻓度
        lenSigR := len(r) / 2
        lenSigS := len(s) / 2
        // 計算DER序列的總⻓度
        lenSequence := lenSigR + lenSigS + 4
        // 将10進制⻓度轉16進制字元串
        strLenSigR := DecimalToHex(int64(lenSigR))
        strLenSigS := DecimalToHex(int64(lenSigS))
        strLenSequence := DecimalToHex(int64(lenSequence))
        // 拼湊DER編碼
        derString := "30" + strLenSequence
        derString = derString + "02" + strLenSigR + r
        derString = derString + "02" + strLenSigS + s
        derString = derString + "01"
        return derString
}           
  • 生成簽名
privateKey, publicKey := NewKeyPair()
    msg := sha256.Sum256([]byte("ecc數組簽名"))
    r, s, _ := ecdsa.Sign(rand.Reader, &privateKey, msg[:])
    strSigR := fmt.Sprintf("%x", r) // r.MarshalText()
    strSigS := fmt.Sprintf("%x", s) // s.MarshalText()
    fmt.Printf("r、s的10進制:%#v, %#v\n", r, s)
    fmt.Println("r、s的16進制:", strSigR, strSigS)
    //r和s拼接在⼀起,形成數字簽名的der格式
    signatureDer := MakeSignatureDerString(strSigR, strSigS)
    //列印數字簽名的16進制顯示
    fmt.Println("數字簽名DER格式為:", signatureDer)           
  • 驗證簽名
func VerifySig(pubKey, message []byte, r, s *big.Int) bool {
      curve := elliptic.P256()
      //公鑰的⻓度
      keyLen := len(pubKey)
      //前⼀半為x軸坐标,後⼀半為y軸坐标
      x := big.Int{}
      y := big.Int{}
      x.SetBytes(pubKey[:(keyLen / 2)])
      y.SetBytes(pubKey[(keyLen / 2):])
      rawPubKey := ecdsa.PublicKey{curve, &x, &y}
      //根據交易哈希、公鑰、數字簽名驗證成功:
      // ecdsa.Verify func Verify(pub *PublicKey, hash[] byte, r * big.Int, s * big.Int) bool
      res := ecdsa.Verify(&rawPubKey, message, r, s)
      return res
}           

繼續閱讀