github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/crypto/signature_nocgo.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:36</date>
    10  //</624450085589094400>
    11  
    12  
    13  //+构建Nacl JS Nocgo
    14  
    15  package crypto
    16  
    17  import (
    18  	"crypto/ecdsa"
    19  	"crypto/elliptic"
    20  	"errors"
    21  	"fmt"
    22  	"math/big"
    23  
    24  	"github.com/btcsuite/btcd/btcec"
    25  )
    26  
    27  //ecrecover返回创建给定签名的未压缩公钥。
    28  func Ecrecover(hash, sig []byte) ([]byte, error) {
    29  	pub, err := SigToPub(hash, sig)
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  	bytes := (*btcec.PublicKey)(pub).SerializeUncompressed()
    34  	return bytes, err
    35  }
    36  
    37  //sigtopub返回创建给定签名的公钥。
    38  func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
    39  //转换为btcec输入格式,开始时使用“recovery id”v。
    40  	btcsig := make([]byte, 65)
    41  	btcsig[0] = sig[64] + 27
    42  	copy(btcsig[1:], sig)
    43  
    44  	pub, _, err := btcec.RecoverCompact(btcec.S256(), btcsig, hash)
    45  	return (*ecdsa.PublicKey)(pub), err
    46  }
    47  
    48  //sign计算ECDSA签名。
    49  //
    50  //此函数容易受到选中的可能泄漏的明文攻击
    51  //有关用于签名的私钥的信息。来电者必须
    52  //请注意,给定的哈希不能由对手选择。共同的
    53  //解决方案是在计算签名之前散列任何输入。
    54  //
    55  //生成的签名采用[R V]格式,其中V为0或1。
    56  func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
    57  	if len(hash) != 32 {
    58  		return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
    59  	}
    60  	if prv.Curve != btcec.S256() {
    61  		return nil, fmt.Errorf("private key curve is not secp256k1")
    62  	}
    63  	sig, err := btcec.SignCompact(btcec.S256(), (*btcec.PrivateKey)(prv), hash, false)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  //转换为末尾带有'recovery id'v的以太坊签名格式。
    68  	v := sig[0] - 27
    69  	copy(sig, sig[1:])
    70  	sig[64] = v
    71  	return sig, nil
    72  }
    73  
    74  //VerifySignature检查给定的公钥是否通过哈希创建了签名。
    75  //公钥应为压缩(33字节)或未压缩(65字节)格式。
    76  //签名应采用64字节[r_s]格式。
    77  func VerifySignature(pubkey, hash, signature []byte) bool {
    78  	if len(signature) != 64 {
    79  		return false
    80  	}
    81  	sig := &btcec.Signature{R: new(big.Int).SetBytes(signature[:32]), S: new(big.Int).SetBytes(signature[32:])}
    82  	key, err := btcec.ParsePubKey(pubkey, btcec.S256())
    83  	if err != nil {
    84  		return false
    85  	}
    86  //拒绝可延展签名。libsecp256k1执行此检查,但btcec不执行。
    87  	if sig.S.Cmp(secp256k1halfN) > 0 {
    88  		return false
    89  	}
    90  	return sig.Verify(hash, key)
    91  }
    92  
    93  //解压缩PubKey以33字节的压缩格式解析公钥。
    94  func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
    95  	if len(pubkey) != 33 {
    96  		return nil, errors.New("invalid compressed public key length")
    97  	}
    98  	key, err := btcec.ParsePubKey(pubkey, btcec.S256())
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	return key.ToECDSA(), nil
   103  }
   104  
   105  //compresspubkey将公钥编码为33字节的压缩格式。
   106  func CompressPubkey(pubkey *ecdsa.PublicKey) []byte {
   107  	return (*btcec.PublicKey)(pubkey).SerializeCompressed()
   108  }
   109  
   110  //s256返回secp256k1曲线的一个实例。
   111  func S256() elliptic.Curve {
   112  	return btcec.S256()
   113  }
   114