github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/crypto/signature/signature.go (about) 1 package signature 2 3 import ( 4 "crypto" 5 "crypto/ecdsa" 6 "crypto/elliptic" 7 "crypto/rand" 8 "errors" 9 "fmt" 10 "math/big" 11 ) 12 13 // Signature ... 14 type Signature struct { 15 r *big.Int 16 s *big.Int 17 } 18 19 // Marshal ... 20 func (sig *Signature) Marshal() (bytes []byte, err error) { 21 size := (curve.Params().BitSize + 7) >> 3 22 bytes = make([]byte, size*2) 23 24 r := sig.r.Bytes() 25 s := sig.s.Bytes() 26 copy(bytes[size-len(r):], r) 27 copy(bytes[size*2-len(s):], s) 28 return 29 } 30 31 // Unmarshal ... 32 func (sig *Signature) Unmarshal(data []byte) (err error) { 33 length := len(data) 34 if length&1 != 0 { 35 err = errors.New("invalid length") 36 return 37 } 38 39 sig.r = new(big.Int).SetBytes(data[0 : length/2]) 40 sig.s = new(big.Int).SetBytes(data[length/2:]) 41 return 42 } 43 44 // Sign ... 45 func Sign(privateKey crypto.PrivateKey, msg []byte) (sig *Signature, err error) { 46 switch key := privateKey.(type) { 47 case *ecdsa.PrivateKey: 48 h := getHasher() 49 _, err = h.Write(msg) 50 if err != nil { 51 return 52 } 53 digest := h.Sum(nil) 54 55 var r, s *big.Int 56 r, s, err = ecdsa.Sign(rand.Reader, key, digest) 57 if err != nil { 58 return 59 } 60 sig = &Signature{r: r, s: s} 61 default: 62 err = fmt.Errorf("only ecdsa supported") 63 } 64 return 65 } 66 67 // Verify ... 68 func Verify(publicKey crypto.PublicKey, msg []byte, sig *Signature) (ok bool, err error) { 69 switch key := publicKey.(type) { 70 case *ecdsa.PublicKey: 71 h := getHasher() 72 _, err = h.Write(msg) 73 if err != nil { 74 return 75 } 76 digest := h.Sum(nil) 77 78 ok = ecdsa.Verify(key, digest, sig.r, sig.s) 79 default: 80 err = fmt.Errorf("only ecdsa supported") 81 } 82 return 83 } 84 85 var ( 86 curve = elliptic.P256() 87 ) 88 89 // GenerateKeypair ... 90 func GenerateKeypair() (privateKey crypto.PrivateKey, publicKey crypto.PublicKey, err error) { 91 key, err := ecdsa.GenerateKey(curve, rand.Reader) 92 if err != nil { 93 return 94 } 95 96 privateKey = key 97 publicKey = &key.PublicKey 98 return 99 100 }