-
Notifications
You must be signed in to change notification settings - Fork 3
/
sign.go
147 lines (130 loc) · 4.62 KB
/
sign.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package main
import (
"fmt"
"math/big"
"os"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/google/uuid"
"golang.org/x/term"
)
func KeyfileFromPrivateKey(outfile string) error {
fmt.Print("Enter private key (it will not be displayed on screen): ")
privateKeyRaw, inputErr := term.ReadPassword(int(os.Stdin.Fd()))
if inputErr != nil {
return fmt.Errorf("error reading private key: %s", inputErr.Error())
}
fmt.Print("\n")
privateKey := string(privateKeyRaw)
parsedPrivateKey, parseErr := crypto.HexToECDSA(privateKey)
if parseErr != nil {
return fmt.Errorf("error parsing private key: %s", parseErr.Error())
}
keyUUID, uuidErr := uuid.NewRandom()
if uuidErr != nil {
return fmt.Errorf("error generating UUID for keystore: %s", uuidErr.Error())
}
key := &keystore.Key{
Id: keyUUID,
PrivateKey: parsedPrivateKey,
Address: crypto.PubkeyToAddress(parsedPrivateKey.PublicKey),
}
scryptN := keystore.StandardScryptN
scryptP := keystore.StandardScryptP
fmt.Printf("Enter the passphrase you would like to secure the keyfile (%s) with: ", outfile)
passphraseRaw, passphraseInputErr := term.ReadPassword(int(os.Stdin.Fd()))
if passphraseInputErr != nil {
return fmt.Errorf("error reading passphrase: %s", inputErr.Error())
}
fmt.Print("\n")
passphrase := string(passphraseRaw)
keystoreJSON, encryptErr := keystore.EncryptKey(key, passphrase, scryptN, scryptP)
if encryptErr != nil {
return fmt.Errorf("could not generate encrypted keystore: %s", encryptErr.Error())
}
err := os.WriteFile(outfile, keystoreJSON, 0600)
return err
}
func OpenKeystore(keystoreData []byte, password string) (*keystore.Key, error) {
key, err := keystore.DecryptKey(keystoreData, password)
return key, err
}
func KeyFromFile(keystoreFile string, password string) (*keystore.Key, error) {
var emptyKey *keystore.Key
keystoreContent, readErr := os.ReadFile(keystoreFile)
if readErr != nil {
return emptyKey, readErr
}
// If password is "", prompt user for password.
if password == "" {
fmt.Printf("Please provide a password for keystore (%s): ", keystoreFile)
passwordRaw, inputErr := term.ReadPassword(int(os.Stdin.Fd()))
if inputErr != nil {
return emptyKey, fmt.Errorf("error reading password: %s", inputErr.Error())
}
fmt.Print("\n")
password = string(passwordRaw)
}
key, err := OpenKeystore(keystoreContent, password)
return key, err
}
func SignRawMessage(message []byte, key *keystore.Key, sensible bool) ([]byte, error) {
signature, err := crypto.Sign(message, key.PrivateKey)
if !sensible {
// This refers to a bug in an early Ethereum client implementation where the v parameter byte was
// shifted by 27: https://github.com/ethereum/go-ethereum/issues/2053
// Default for callers should be NOT sensible.
// Defensively, we only shift if the 65th byte is 0 or 1.
if signature[64] < 2 {
signature[64] += 27
}
}
return signature, err
}
type DropperClaimMessage struct {
DropId string `json:"dropId"`
RequestID string `json:"requestID"`
Claimant string `json:"claimant"`
BlockDeadline string `json:"blockDeadline"`
Amount string `json:"amount"`
Signature string `json:"signature,omitempty"`
Signer string `json:"signer,omitempty"`
}
func DropperClaimMessageHash(chainId int64, dropperAddress string, dropId, requestId string, claimant string, blockDeadline, amount string) ([]byte, error) {
// Inspired by: https://medium.com/alpineintel/issuing-and-verifying-eip-712-challenges-with-go-32635ca78aaf
signerData := apitypes.TypedData{
Types: apitypes.Types{
"EIP712Domain": {
{Name: "name", Type: "string"},
{Name: "version", Type: "string"},
{Name: "chainId", Type: "uint256"},
{Name: "verifyingContract", Type: "address"},
},
"ClaimPayload": {
{Name: "dropId", Type: "uint256"},
{Name: "requestID", Type: "uint256"},
{Name: "claimant", Type: "address"},
{Name: "blockDeadline", Type: "uint256"},
{Name: "amount", Type: "uint256"},
},
},
PrimaryType: "ClaimPayload",
Domain: apitypes.TypedDataDomain{
Name: "Moonstream Dropper",
Version: "0.2.0",
ChainId: (*math.HexOrDecimal256)(big.NewInt(chainId)),
VerifyingContract: dropperAddress,
},
Message: apitypes.TypedDataMessage{
"dropId": dropId,
"requestID": requestId,
"claimant": claimant,
"blockDeadline": blockDeadline,
"amount": amount,
},
}
messageHash, _, err := apitypes.TypedDataAndHash(signerData)
return messageHash, err
}