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