@@ -9,29 +9,35 @@ const multisig = require('./multisig')
9
9
const caps = require ( './caps' )
10
10
11
11
class Signer {
12
- constructor ( crypto , index , { signature = 'ed25519' , publicKey, namespace = caps . DEFAULT_NAMESPACE } = { } ) {
12
+ constructor ( crypto , manifestHash , version , index , { signature = 'ed25519' , publicKey, namespace = caps . DEFAULT_NAMESPACE } = { } ) {
13
13
if ( ! publicKey ) throw BAD_ARGUMENT ( 'public key is required for a signer' )
14
14
if ( signature !== 'ed25519' ) throw BAD_ARGUMENT ( 'Only Ed25519 signatures are supported' )
15
15
16
16
this . crypto = crypto
17
+ this . manifestHash = manifestHash
18
+ this . version = version
17
19
this . signer = index
18
20
this . signature = signature
19
21
this . publicKey = publicKey
20
22
this . namespace = namespace
21
23
}
22
24
25
+ _ctx ( ) {
26
+ return this . version === 0 ? this . namespace : this . manifestHash
27
+ }
28
+
23
29
verify ( batch , signature ) {
24
- return this . crypto . verify ( batch . signable ( this . namespace ) , signature , this . publicKey )
30
+ return this . crypto . verify ( batch . signable ( this . _ctx ( ) ) , signature , this . publicKey )
25
31
}
26
32
27
33
sign ( batch , keyPair ) {
28
- return this . crypto . sign ( batch . signable ( this . namespace ) , keyPair . secretKey )
34
+ return this . crypto . sign ( batch . signable ( this . _ctx ( ) ) , keyPair . secretKey )
29
35
}
30
36
}
31
37
32
38
class CompatSigner extends Signer {
33
39
constructor ( crypto , index , signer , legacy ) {
34
- super ( crypto , index , signer )
40
+ super ( crypto , null , 0 , index , signer )
35
41
this . legacy = legacy
36
42
}
37
43
@@ -45,16 +51,24 @@ class CompatSigner extends Signer {
45
51
}
46
52
47
53
module . exports = class Verifier {
48
- constructor ( manifest , { compat = false , crypto = defaultCrypto , legacy = false } = { } ) {
54
+ constructor ( manifestHash , manifest , { compat = isCompat ( manifestHash , manifest ) , crypto = defaultCrypto , legacy = false } = { } ) {
55
+ const self = this
56
+
57
+ this . manifestHash = manifestHash
49
58
this . compat = compat || manifest === null
50
59
this . version = this . compat ? 0 : typeof manifest . version === 'number' ? manifest . version : 1
51
60
this . hash = manifest . hash || 'blake2b'
52
61
this . allowPatch = ! this . compat && ! ! manifest . allowPatch
53
62
this . quorum = this . compat ? 1 : defaultQuorum ( manifest )
54
- this . signers = manifest . signers
55
- ? manifest . signers . map ( ( s , index ) => this . compat ? new CompatSigner ( crypto , index , s , legacy ) : new Signer ( crypto , index , s ) )
56
- : [ ]
63
+
64
+ this . signers = manifest . signers ? manifest . signers . map ( createSigner ) : [ ]
57
65
this . prologue = this . compat ? null : ( manifest . prologue || null )
66
+
67
+ function createSigner ( signer , index ) {
68
+ return self . compat
69
+ ? new CompatSigner ( crypto , index , signer , legacy )
70
+ : new Signer ( crypto , manifestHash , self . version , index , signer )
71
+ }
58
72
}
59
73
60
74
_verifyCompat ( batch , signature ) {
@@ -129,21 +143,22 @@ module.exports = class Verifier {
129
143
// TODO: better api for this that is more ... multisig-ey
130
144
sign ( batch , keyPair ) {
131
145
if ( ! keyPair || ! keyPair . secretKey ) throw BAD_ARGUMENT ( 'No key pair was passed' )
132
- if ( this . signers . length > 1 || this . allowPatch ) throw BAD_ARGUMENT ( 'Can only sign directly for single signers' )
133
146
134
- const signature = this . signers [ 0 ] . sign ( batch , keyPair )
135
- if ( this . version !== 1 ) return signature
136
- return this . assemble ( [ { signer : 0 , signature, patch : 0 , nodes : null } ] )
147
+ for ( const s of this . signers ) {
148
+ if ( b4a . equals ( s . publicKey , keyPair . publicKey ) ) {
149
+ const signature = s . sign ( batch , keyPair )
150
+ if ( this . signers . length !== 1 || this . version === 0 ) return signature
151
+ return this . assemble ( [ { signer : 0 , signature, patch : 0 , nodes : null } ] )
152
+ }
153
+ }
154
+
155
+ throw new BAD_ARGUMENT ( 'Public key is not a declared signer' )
137
156
}
138
157
139
158
assemble ( inputs ) {
140
159
return this . version === 0 ? multisig . assemblev0 ( inputs ) : multisig . assemble ( inputs )
141
160
}
142
161
143
- manifestHash ( ) {
144
- return manifestHash ( this )
145
- }
146
-
147
162
static manifestHash ( manifest ) {
148
163
return manifestHash ( manifest )
149
164
}
@@ -163,6 +178,11 @@ module.exports = class Verifier {
163
178
}
164
179
}
165
180
181
+ static fromManifest ( manifest , opts ) {
182
+ const m = this . createManifest ( manifest )
183
+ return new this ( manifestHash ( m ) , m , opts )
184
+ }
185
+
166
186
static createManifest ( inp ) {
167
187
if ( ! inp ) return null
168
188
@@ -192,12 +212,11 @@ module.exports = class Verifier {
192
212
}
193
213
194
214
static isCompat ( key , manifest ) {
195
- return ! ! ( manifest && manifest . signers . length === 1 && b4a . equals ( key , manifest . signers [ 0 ] . publicKey ) )
215
+ return isCompat ( key , manifest )
196
216
}
197
217
198
218
static sign ( manifest , batch , keyPair , opts ) {
199
- const v = new Verifier ( manifest , opts )
200
- return v . sign ( batch , keyPair )
219
+ return Verifier . fromManifest ( manifest , opts ) . sign ( batch , keyPair )
201
220
}
202
221
}
203
222
@@ -207,6 +226,10 @@ function toMap (nodes) {
207
226
return m
208
227
}
209
228
229
+ function isCompat ( key , manifest ) {
230
+ return ! ! ( manifest && manifest . signers . length === 1 && b4a . equals ( key , manifest . signers [ 0 ] . publicKey ) )
231
+ }
232
+
210
233
function defaultQuorum ( man ) {
211
234
if ( typeof man . quorum === 'number' ) return man . quorum
212
235
if ( ! man . signers || ! man . signers . length ) return 0
0 commit comments