-
Notifications
You must be signed in to change notification settings - Fork 31
/
vk_handler.go
90 lines (73 loc) · 2.69 KB
/
vk_handler.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
package vkhandler //nolint:typecheck
import (
"crypto/rand"
"fmt"
"io"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ten-protocol/go-ten/go/common/viewingkey"
"gitlab.com/NebulousLabs/fastrand"
"github.com/ethereum/go-ethereum/crypto/ecies"
)
// Used when the result to an eth_call is equal to nil. Attempting to encrypt then decrypt nil using ECIES throws an exception.
var placeholderResult = []byte("0x")
// AuthenticatedViewingKey - the enclave side of the viewing key. Used for authenticating requests and for encryption
type AuthenticatedViewingKey struct {
rpcVK *viewingkey.RPCSignedViewingKey
AccountAddress *gethcommon.Address
ecdsaKey *ecies.PublicKey
UserID []byte
}
func VerifyViewingKey(rpcVK *viewingkey.RPCSignedViewingKey, chainID int64) (*AuthenticatedViewingKey, error) {
err := rpcVK.Validate()
if err != nil {
return nil, err
}
vkPubKey, err := crypto.DecompressPubkey(rpcVK.PublicKey)
if err != nil {
return nil, fmt.Errorf("could not decompress viewing key bytes - %w", err)
}
rvk := &AuthenticatedViewingKey{
rpcVK: rpcVK,
ecdsaKey: ecies.ImportECDSAPublic(vkPubKey),
}
// 2. Authenticate
recoveredAccountAddress, err := checkViewingKeyAndRecoverAddress(rvk, chainID)
if err != nil {
return nil, err
}
rvk.AccountAddress = recoveredAccountAddress
return rvk, nil
}
// checkViewingKeyAndRecoverAddress checks the signature and recovers the address from the viewing key
func checkViewingKeyAndRecoverAddress(vk *AuthenticatedViewingKey, chainID int64) (*gethcommon.Address, error) {
// get userID from viewingKey public key
userID := viewingkey.CalculateUserID(vk.rpcVK.PublicKey)
vk.UserID = userID
// check the signature and recover the address assuming the message was signed with EIP712
recoveredSignerAddress, err := viewingkey.CheckSignature(userID, vk.rpcVK.SignatureWithAccountKey, chainID, vk.rpcVK.SignatureType)
if err != nil {
return nil, fmt.Errorf("signature verification failed %w", err)
}
return recoveredSignerAddress, err
}
// crypto.rand is quite slow. When this variable is true, we will use a fast CSPRNG algorithm
const useFastRand = true
func rndSource() io.Reader {
rndSource := rand.Reader
if useFastRand {
rndSource = fastrand.Reader
}
return rndSource
}
// Encrypt returns the payload encrypted with the viewingKey
func (vk *AuthenticatedViewingKey) Encrypt(bytes []byte) ([]byte, error) {
if len(bytes) == 0 {
bytes = placeholderResult
}
encryptedBytes, err := ecies.Encrypt(rndSource(), vk.ecdsaKey, bytes, nil, nil)
if err != nil {
return nil, fmt.Errorf("unable to encrypt with given public VK - %w", err)
}
return encryptedBytes, nil
}