Smart Contract
Crypto
A.e467b9dd11fa00df.Crypto
1
2access(all) contract Crypto {
3
4 access(all)
5 fun hash(_ data: [UInt8], algorithm: HashAlgorithm): [UInt8] {
6 return algorithm.hash(data)
7 }
8
9 access(all)
10 fun hashWithTag(_ data: [UInt8], tag: String, algorithm: HashAlgorithm): [UInt8] {
11 return algorithm.hashWithTag(data, tag: tag)
12 }
13
14 access(all)
15 struct KeyListEntry {
16
17 access(all)
18 let keyIndex: Int
19
20 access(all)
21 let publicKey: PublicKey
22
23 access(all)
24 let hashAlgorithm: HashAlgorithm
25
26 access(all)
27 let weight: UFix64
28
29 access(all)
30 let isRevoked: Bool
31
32 init(
33 keyIndex: Int,
34 publicKey: PublicKey,
35 hashAlgorithm: HashAlgorithm,
36 weight: UFix64,
37 isRevoked: Bool
38 ) {
39 self.keyIndex = keyIndex
40 self.publicKey = publicKey
41 self.hashAlgorithm = hashAlgorithm
42 self.weight = weight
43 self.isRevoked = isRevoked
44 }
45 }
46
47 access(all)
48 struct KeyList {
49
50 access(self)
51 let entries: [KeyListEntry]
52
53 init() {
54 self.entries = []
55 }
56
57 /// Adds a new key with the given weight
58 access(all)
59 fun add(
60 _ publicKey: PublicKey,
61 hashAlgorithm: HashAlgorithm,
62 weight: UFix64
63 ): KeyListEntry {
64
65 let keyIndex = self.entries.length
66 let entry = KeyListEntry(
67 keyIndex: keyIndex,
68 publicKey: publicKey,
69 hashAlgorithm: hashAlgorithm,
70 weight: weight,
71 isRevoked: false
72 )
73 self.entries.append(entry)
74 return entry
75 }
76
77 /// Returns the key at the given index, if it exists.
78 /// Revoked keys are always returned, but they have the `isRevoked` field set to true
79 access(all)
80 fun get(keyIndex: Int): KeyListEntry? {
81 if keyIndex >= self.entries.length {
82 return nil
83 }
84
85 return self.entries[keyIndex]
86 }
87
88 /// Marks the key at the given index revoked, but does not delete it
89 access(all)
90 fun revoke(keyIndex: Int) {
91 if keyIndex >= self.entries.length {
92 return
93 }
94
95 let currentEntry = self.entries[keyIndex]
96 self.entries[keyIndex] = KeyListEntry(
97 keyIndex: currentEntry.keyIndex,
98 publicKey: currentEntry.publicKey,
99 hashAlgorithm: currentEntry.hashAlgorithm,
100 weight: currentEntry.weight,
101 isRevoked: true
102 )
103 }
104
105 /// Returns true if the given signatures are valid for the given signed data
106 access(all)
107 fun verify(
108 signatureSet: [KeyListSignature],
109 signedData: [UInt8],
110 domainSeparationTag: String
111 ): Bool {
112
113 var validWeights: UFix64 = 0.0
114
115 let seenKeyIndices: {Int: Bool} = {}
116
117 for signature in signatureSet {
118
119 // Ensure the key index is valid
120 if signature.keyIndex >= self.entries.length {
121 return false
122 }
123
124 // Ensure this key index has not already been seen
125 if seenKeyIndices[signature.keyIndex] ?? false {
126 return false
127 }
128
129 // Record the key index was seen
130 seenKeyIndices[signature.keyIndex] = true
131
132 // Get the actual key
133 let key = self.entries[signature.keyIndex]
134
135 // Ensure the key is not revoked
136 if key.isRevoked {
137 return false
138 }
139
140 // Ensure the signature is valid
141 if !key.publicKey.verify(
142 signature: signature.signature,
143 signedData: signedData,
144 domainSeparationTag: domainSeparationTag,
145 hashAlgorithm:key.hashAlgorithm
146 ) {
147 return false
148 }
149
150 validWeights = validWeights + key.weight
151 }
152
153 return validWeights >= 1.0
154 }
155 }
156
157 access(all)
158 struct KeyListSignature {
159
160 access(all)
161 let keyIndex: Int
162
163 access(all)
164 let signature: [UInt8]
165
166 init(keyIndex: Int, signature: [UInt8]) {
167 self.keyIndex = keyIndex
168 self.signature = signature
169 }
170 }
171}