Smart Contract
FCLCrypto
A.5d4604a414ba4155.FCLCrypto
1/*
2 FCLCrypto
3
4 The FCLCrypto contract provides functions which allow to verify signatures and check for signing power.
5*/
6
7access(all) contract FCLCrypto {
8
9 /// verifyUserSignatures allows to verify the user signatures for the given account.
10 ///
11 /// @param address: The address of the account
12 /// @param message: The signed data
13 /// @param keyIndices: This integer array maps the signatures to the account keys by index
14 /// @param signatures: The signatures belonging to the account keys
15 ///
16 /// @return Whether all signatures are valid and the combined total key weight reaches signing power
17 ///
18 access(all) view fun verifyUserSignatures(
19 address: Address,
20 message: String,
21 keyIndices: [Int],
22 signatures: [String]
23 ): Bool {
24 return self.verifySignatures(
25 address: address,
26 message: message,
27 keyIndices: keyIndices,
28 signatures: signatures,
29 domainSeparationTag: self.domainSeparationTagFlowUser,
30 )
31 }
32
33 /// verifyAccountProofSignatures allows to verify the account proof signatures for the given account.
34 ///
35 /// @param address: The address of the account
36 /// @param message: The signed data
37 /// @param keyIndices: This integer array maps the signatures to the account keys by index
38 /// @param signatures: The signatures belonging to the account keys
39 ///
40 /// @return Whether all signatures are valid and the combined total key weight reaches signing power
41 ///
42 access(all) view fun verifyAccountProofSignatures(
43 address: Address,
44 message: String,
45 keyIndices: [Int],
46 signatures: [String]
47 ): Bool {
48 return self.verifySignatures(
49 address: address,
50 message: message,
51 keyIndices: keyIndices,
52 signatures: signatures,
53 domainSeparationTag: self.domainSeparationTagAccountProof,
54 ) ||
55 self.verifySignatures(
56 address: address,
57 message: message,
58 keyIndices: keyIndices,
59 signatures: signatures,
60 domainSeparationTag: self.domainSeparationTagFlowUser,
61 )
62 }
63
64 /// verifySignatures is a private function which provides the functionality to verify
65 /// signatures for the public functions.
66 ///
67 /// @param address: The address of the account
68 /// @param message: The signed data
69 /// @param keyIndices: This integer array maps the signatures to the account keys by index
70 /// @param signatures: The signatures belonging to the account keys
71 /// @param domainSeparationTag: The domain tag originally used for the signatures
72 ///
73 /// @return Whether all signatures are valid and the combined total key weight reaches signing power
74 ///
75 access(self) view fun verifySignatures(
76 address: Address,
77 message: String,
78 keyIndices: [Int],
79 signatures: [String],
80 domainSeparationTag: String,
81 ): Bool {
82 pre {
83 keyIndices.length == signatures.length : "Key index list length does not match signature list length"
84 }
85
86 let account = getAccount(address)
87 let messageBytes = message.decodeHex()
88
89 var totalWeight: UFix64 = 0.0
90 let seenKeyIndices: {Int: Bool} = {}
91
92 var i = 0
93
94 for keyIndex in keyIndices {
95
96 let accountKey = account.keys.get(keyIndex: keyIndex) ?? panic("Key provided does not exist on account")
97 let signature = signatures[i].decodeHex()
98
99 // Ensure this key index has not already been seen
100
101 if seenKeyIndices[accountKey.keyIndex] ?? false {
102 return false
103 }
104
105 // Record the key index was seen
106
107 seenKeyIndices[accountKey.keyIndex] = true
108
109 // Ensure the key is not revoked
110
111 if accountKey.isRevoked {
112 return false
113 }
114
115 // Ensure the signature is valid
116
117 if !accountKey.publicKey.verify(
118 signature: signature,
119 signedData: messageBytes,
120 domainSeparationTag: domainSeparationTag,
121 hashAlgorithm: accountKey.hashAlgorithm
122 ) {
123 return false
124 }
125
126 totalWeight = totalWeight + accountKey.weight
127
128 i = i + 1
129 }
130
131 return totalWeight >= 999.0
132 }
133
134 access(self) let domainSeparationTagFlowUser: String
135 access(self) let domainSeparationTagFCLUser: String
136 access(self) let domainSeparationTagAccountProof: String
137
138 init() {
139 self.domainSeparationTagFlowUser = "FLOW-V0.0-user"
140 self.domainSeparationTagFCLUser = "FCL-USER-V0.0"
141 self.domainSeparationTagAccountProof = "FCL-ACCOUNT-PROOF-V0.0"
142 }
143}