This repository was archived by the owner on May 26, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsigner.go
More file actions
115 lines (94 loc) · 3.07 KB
/
signer.go
File metadata and controls
115 lines (94 loc) · 3.07 KB
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
105
106
107
108
109
110
111
112
113
114
115
package main
import (
"crypto/ecdsa"
"fmt"
"log"
"strings"
"github.com/erc7824/go-nitrolite"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
// Signer handles signing operations using a private key
type Signer struct {
privateKey *ecdsa.PrivateKey
}
// NewSigner creates a new signer from a hex-encoded private key
func NewSigner(privateKeyHex string) (*Signer, error) {
if len(privateKeyHex) >= 2 && privateKeyHex[:2] == "0x" {
privateKeyHex = privateKeyHex[2:]
}
privateKey, err := crypto.HexToECDSA(privateKeyHex)
if err != nil {
return nil, err
}
publicKey := privateKey.Public().(*ecdsa.PublicKey)
log.Printf("Broker signer initialized with address: %s", crypto.PubkeyToAddress(*publicKey).Hex())
return &Signer{privateKey: privateKey}, nil
}
// Sign creates an ECDSA signature for the provided data
func (s *Signer) Sign(data []byte) ([]byte, error) {
sig, err := nitrolite.Sign(data, s.privateKey)
if err != nil {
return nil, err
}
signature := make([]byte, 65)
copy(signature[0:32], sig.R[:])
copy(signature[32:64], sig.S[:])
if sig.V >= 27 {
signature[64] = sig.V - 27
}
return signature, nil
}
// NitroSign creates a signature for the provided state in nitrolite.Signature format
func (s *Signer) NitroSign(encodedState []byte) (nitrolite.Signature, error) {
sig, err := nitrolite.Sign(encodedState, s.privateKey)
if err != nil {
return nitrolite.Signature{}, fmt.Errorf("failed to sign encoded state: %w", err)
}
return nitrolite.Signature{
V: sig.V,
R: sig.R,
S: sig.S,
}, nil
}
// GetPublicKey returns the public key associated with the signer
func (s *Signer) GetPublicKey() *ecdsa.PublicKey {
return s.privateKey.Public().(*ecdsa.PublicKey)
}
// GetPrivateKey returns the private key used by the signer
func (s *Signer) GetPrivateKey() *ecdsa.PrivateKey {
return s.privateKey
}
// GetAddress returns the address derived from the signer's public key
func (s *Signer) GetAddress() common.Address {
return crypto.PubkeyToAddress(*s.GetPublicKey())
}
// ValidateSignature validates the signature of a message against the provided address
func ValidateSignature(message []byte, signatureHex, expectedAddrHex string) (bool, error) {
recoveredHex, err := RecoverAddress(message, signatureHex)
if err != nil {
return false, err
}
return strings.EqualFold(recoveredHex, expectedAddrHex), nil
}
// RecoverAddress takes the original message and its hex-encoded signature, and returns the address
func RecoverAddress(message []byte, signatureHex string) (string, error) {
sig, err := hexutil.Decode(signatureHex)
if err != nil {
return "", fmt.Errorf("invalid signature hex: %w", err)
}
if len(sig) != 65 {
return "", fmt.Errorf("invalid signature length: got %d, want 65", len(sig))
}
if sig[64] >= 27 {
sig[64] -= 27
}
msgHash := crypto.Keccak256Hash(message)
pubkey, err := crypto.SigToPub(msgHash.Bytes(), sig)
if err != nil {
return "", fmt.Errorf("signature recovery failed: %w", err)
}
addr := crypto.PubkeyToAddress(*pubkey)
return addr.Hex(), nil
}