-
Notifications
You must be signed in to change notification settings - Fork 0
/
secp256k1_signer.go
104 lines (89 loc) · 3.1 KB
/
secp256k1_signer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package crypto
import (
"crypto/ecdsa"
"crypto/rand"
"errors"
"fmt"
"github.com/alphabill-org/alphabill-go-base/crypto/canonicalizer"
"github.com/alphabill-org/alphabill-go-base/hash"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
)
type (
// InMemorySecp256K1Signer for using during development
InMemorySecp256K1Signer struct {
privKey []byte
}
)
// PrivateKeySecp256K1Size is the size of the private key in bytes
const PrivateKeySecp256K1Size = 32
var errSignerNil = errors.New("signer is nil")
// NewInMemorySecp256K1Signer generates new key pair and creates a new InMemorySecp256K1Signer.
func NewInMemorySecp256K1Signer() (*InMemorySecp256K1Signer, error) {
privKey, err := generateSecp256K1PrivateKey()
if err != nil {
return nil, err
}
return NewInMemorySecp256K1SignerFromKey(privKey)
}
// NewInMemorySecp256K1SignerFromKey creates signer from an existing private key.
func NewInMemorySecp256K1SignerFromKey(privKey []byte) (*InMemorySecp256K1Signer, error) {
if len(privKey) != PrivateKeySecp256K1Size {
return nil, fmt.Errorf("invalid private key length. Is %d (expected %d)", len(privKey), PrivateKeySecp256K1Size)
}
return &InMemorySecp256K1Signer{privKey: privKey}, nil
}
// SignBytes hashes the data with SHA256 and creates a recoverable ECDSA signature.
// The produced signature is in the 65-byte [R || S || V] format where V is 0 or 1.
func (s *InMemorySecp256K1Signer) SignBytes(data []byte) ([]byte, error) {
if s == nil {
return nil, errSignerNil
}
if data == nil {
return nil, fmt.Errorf("data is nil")
}
return s.SignHash(hash.Sum256(data))
}
// SignHash creates a recoverable ECDSA signature.
// The produced signature is in the 65-byte [R || S || V] format where V is 0 or 1.
func (s *InMemorySecp256K1Signer) SignHash(hash []byte) ([]byte, error) {
if s == nil {
return nil, errSignerNil
}
if hash == nil {
return nil, fmt.Errorf("hash is nil")
}
return secp256k1.Sign(hash, s.privKey)
}
// SignObject transforms the object to canonical form and then signs the data using SignBytes method.
func (s *InMemorySecp256K1Signer) SignObject(obj canonicalizer.Canonicalizer, opts ...canonicalizer.Option) ([]byte, error) {
if s == nil {
return nil, errSignerNil
}
data, err := canonicalizer.Canonicalize(obj, opts...)
if err != nil {
return nil, fmt.Errorf("canonicalize the object failed: %w", err)
}
return s.SignBytes(data)
}
func (s *InMemorySecp256K1Signer) Verifier() (Verifier, error) {
ecdsaPrivKey, err := crypto.ToECDSA(s.privKey)
if err != nil {
return nil, err
}
compressPubkey := secp256k1.CompressPubkey(ecdsaPrivKey.PublicKey.X, ecdsaPrivKey.PublicKey.Y)
return NewVerifierSecp256k1(compressPubkey)
}
func (s *InMemorySecp256K1Signer) MarshalPrivateKey() ([]byte, error) {
return s.privKey, nil
}
func generateSecp256K1PrivateKey() (privkey []byte, err error) {
key, err := ecdsa.GenerateKey(secp256k1.S256(), rand.Reader)
if err != nil {
return nil, fmt.Errorf("random key generation failed: %w", err)
}
privkey = make([]byte, 32)
blob := key.D.Bytes()
copy(privkey[32-len(blob):], blob)
return privkey, nil
}