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  }