hypercore 10.31.12 → 10.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,272 @@
1
+ const defaultCrypto = require('hypercore-crypto')
2
+ const b4a = require('b4a')
3
+ const c = require('compact-encoding')
4
+ const flat = require('flat-tree')
5
+ const { BAD_ARGUMENT } = require('hypercore-errors')
6
+
7
+ const m = require('./messages')
8
+ const multisig = require('./multisig')
9
+ const caps = require('./caps')
10
+
11
+ class Signer {
12
+ constructor (crypto, index, { signature = 'ed25519', publicKey, namespace = caps.DEFAULT_NAMESPACE } = {}) {
13
+ if (!publicKey) throw BAD_ARGUMENT('public key is required for a signer')
14
+ if (signature !== 'ed25519') throw BAD_ARGUMENT('Only Ed25519 signatures are supported')
15
+
16
+ this.crypto = crypto
17
+ this.signer = index
18
+ this.signature = signature
19
+ this.publicKey = publicKey
20
+ this.namespace = namespace
21
+ }
22
+
23
+ verify (batch, signature) {
24
+ return this.crypto.verify(batch.signable(this.namespace), signature, this.publicKey)
25
+ }
26
+
27
+ sign (batch, keyPair) {
28
+ return this.crypto.sign(batch.signable(this.namespace), keyPair.secretKey)
29
+ }
30
+ }
31
+
32
+ class CompatSigner extends Signer {
33
+ constructor (crypto, index, signer, legacy) {
34
+ super(crypto, index, signer)
35
+ this.legacy = legacy
36
+ }
37
+
38
+ verify (batch, signature) {
39
+ return this.crypto.verify(batch.signableCompat(this.legacy), signature, this.publicKey)
40
+ }
41
+
42
+ sign (batch, keyPair) {
43
+ return this.crypto.sign(batch.signableCompat(this.legacy), keyPair.secretKey)
44
+ }
45
+ }
46
+
47
+ module.exports = class Verifier {
48
+ constructor (manifest, { compat = false, crypto = defaultCrypto, legacy = false } = {}) {
49
+ this.compat = compat || manifest === null
50
+ this.manifest = manifest
51
+ this.version = this.compat ? 0 : typeof this.manifest.version === 'number' ? this.manifest.version : 1
52
+ this.hash = manifest.hash || 'blake2b'
53
+ this.allowPatch = !this.compat && !!this.manifest.allowPatch
54
+ this.quorum = this.compat ? 1 : (this.manifest.quorum || 0)
55
+ this.signers = this.manifest.signers.map((s, index) => this.compat ? new CompatSigner(crypto, index, s, legacy) : new Signer(crypto, index, s))
56
+ this.prologue = this.compat ? null : (this.manifest.prologue || null)
57
+ }
58
+
59
+ _verifyCompat (batch, signature) {
60
+ if (!signature) return false
61
+
62
+ if (this.compat || (!this.allowPatch && this.signers.length === 1)) {
63
+ return !!signature && this.signers[0].verify(batch, signature)
64
+ }
65
+
66
+ return this._verifyMulti(batch, signature)
67
+ }
68
+
69
+ _inflate (signature) {
70
+ if (this.version >= 1) return multisig.inflate(signature)
71
+ const { proofs, patch } = multisig.inflatev0(signature)
72
+
73
+ return {
74
+ proofs: proofs.map(proofToVersion1),
75
+ patch: patch
76
+ }
77
+ }
78
+
79
+ _verifyMulti (batch, signature) {
80
+ if (!signature || this.quorum === 0) return false
81
+
82
+ const { proofs, patch } = this._inflate(signature)
83
+ if (proofs.length < this.quorum) return false
84
+
85
+ const tried = new Uint8Array(this.signers.length)
86
+ const nodes = this.allowPatch && patch.length ? toMap(patch) : null
87
+
88
+ for (let i = 0; i < this.quorum; i++) {
89
+ const inp = proofs[i]
90
+
91
+ let tree = batch
92
+
93
+ if (inp.patch && this.allowPatch) {
94
+ tree = batch.clone()
95
+
96
+ const upgrade = generateUpgrade(nodes, batch.length, inp.patch)
97
+ const proof = { fork: tree.fork, block: null, hash: null, seek: null, upgrade, manifest: null }
98
+
99
+ try {
100
+ if (!tree.verifyUpgrade(proof)) return false
101
+ } catch {
102
+ return false
103
+ }
104
+ }
105
+
106
+ if (inp.signer >= this.signers.length || tried[inp.signer]) return false
107
+ tried[inp.signer] = 1
108
+
109
+ const s = this.signers[inp.signer]
110
+ if (!s.verify(tree, inp.signature)) return false
111
+ }
112
+
113
+ return true
114
+ }
115
+
116
+ verify (batch, signature) {
117
+ if (this.version !== 1) {
118
+ return this._verifyCompat(batch, signature)
119
+ }
120
+
121
+ if (this.prologue !== null && batch.length <= this.prologue.length) {
122
+ return batch.length === this.prologue.length && b4a.equals(batch.hash(), this.prologue.hash)
123
+ }
124
+
125
+ return this._verifyMulti(batch, signature)
126
+ }
127
+
128
+ // TODO: better api for this that is more ... multisig-ey
129
+ sign (batch, keyPair) {
130
+ if (!keyPair || !keyPair.secretKey) throw BAD_ARGUMENT('No key pair was passed')
131
+ if (this.signers.length > 1 || this.allowPatch) throw BAD_ARGUMENT('Can only sign directly for single signers')
132
+
133
+ const signature = this.signers[0].sign(batch, keyPair)
134
+ if (this.version !== 1) return signature
135
+ return this.assemble([{ signer: 0, signature, patch: 0, nodes: null }])
136
+ }
137
+
138
+ assemble (inputs) {
139
+ return this.version === 0 ? multisig.assemblev0(inputs) : multisig.assemble(inputs)
140
+ }
141
+
142
+ manifestHash () {
143
+ return manifestHash(this)
144
+ }
145
+
146
+ static manifestHash (manifest) {
147
+ return manifestHash(manifest)
148
+ }
149
+
150
+ static defaultSignerManifest (publicKey) {
151
+ return {
152
+ version: 1,
153
+ hash: 'blake2b',
154
+ allowPatch: false,
155
+ quorum: 1,
156
+ signers: [{
157
+ signature: 'ed25519',
158
+ namespace: caps.DEFAULT_NAMESPACE,
159
+ publicKey
160
+ }],
161
+ prologue: null
162
+ }
163
+ }
164
+
165
+ static createManifest (inp) {
166
+ if (!inp) return null
167
+
168
+ const manifest = {
169
+ version: typeof inp.version === 'number' ? inp.version : 1,
170
+ hash: 'blake2b',
171
+ allowPatch: !!inp.allowPatch,
172
+ quorum: inp.quorum || 0,
173
+ signers: inp.signers.map(parseSigner),
174
+ prologue: null
175
+ }
176
+
177
+ if (inp.hash && inp.hash !== 'blake2b') throw BAD_ARGUMENT('Only Blake2b hashes are supported')
178
+
179
+ if (inp.prologue) {
180
+ if (!(b4a.isBuffer(inp.prologue.hash) && inp.prologue.hash.byteLength === 32) || !(inp.prologue.length >= 0)) {
181
+ throw BAD_ARGUMENT('Invalid prologue')
182
+ }
183
+ manifest.prologue = inp.prologue
184
+ }
185
+
186
+ return manifest
187
+ }
188
+
189
+ static isValidManifest (key, manifest) {
190
+ return b4a.equals(key, manifestHash(manifest))
191
+ }
192
+
193
+ static isCompat (key, manifest) {
194
+ return !!(manifest && manifest.signers.length === 1 && b4a.equals(key, manifest.signers[0].publicKey))
195
+ }
196
+
197
+ static sign (manifest, batch, keyPair, opts) {
198
+ const v = new Verifier(manifest, opts)
199
+ return v.sign(batch, keyPair)
200
+ }
201
+ }
202
+
203
+ function toMap (nodes) {
204
+ const m = new Map()
205
+ for (const node of nodes) m.set(node.index, node)
206
+ return m
207
+ }
208
+
209
+ function generateUpgrade (patch, start, length) {
210
+ const upgrade = { start, length, nodes: null, additionalNodes: [] }
211
+
212
+ const from = start * 2
213
+ const to = from + length * 2
214
+
215
+ for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
216
+ if (ite.index + ite.factor / 2 < from) continue
217
+
218
+ if (upgrade.nodes === null && ite.contains(from - 2)) {
219
+ upgrade.nodes = []
220
+
221
+ const root = ite.index
222
+ const target = from - 2
223
+
224
+ ite.seek(target)
225
+
226
+ while (ite.index !== root) {
227
+ ite.sibling()
228
+ if (ite.index > target) upgrade.nodes.push(patch.get(ite.index))
229
+ ite.parent()
230
+ }
231
+
232
+ continue
233
+ }
234
+
235
+ if (upgrade.nodes === null) upgrade.nodes = []
236
+ upgrade.nodes.push(patch.get(ite.index))
237
+ }
238
+
239
+ if (upgrade.nodes === null) upgrade.nodes = []
240
+ return upgrade
241
+ }
242
+
243
+ function parseSigner (signer) {
244
+ validateSigner(signer)
245
+ return {
246
+ signature: 'ed25519',
247
+ namespace: signer.namespace || caps.DEFAULT_NAMESPACE,
248
+ publicKey: signer.publicKey
249
+ }
250
+ }
251
+
252
+ function validateSigner (signer) {
253
+ if (!signer || !signer.publicKey) throw BAD_ARGUMENT('Signer missing public key')
254
+ if (signer.signature && signer.signature !== 'ed25519') throw BAD_ARGUMENT('Only Ed25519 signatures are supported')
255
+ }
256
+
257
+ function manifestHash (manifest) {
258
+ const state = { start: 0, end: 32, buffer: null }
259
+ m.manifest.preencode(state, manifest)
260
+ state.buffer = b4a.allocUnsafe(state.end)
261
+ c.raw.encode(state, caps.MANIFEST)
262
+ m.manifest.encode(state, manifest)
263
+ return defaultCrypto.hash(state.buffer)
264
+ }
265
+
266
+ function proofToVersion1 (proof) {
267
+ return {
268
+ signer: proof.signer,
269
+ signature: proof.signature,
270
+ patch: proof.patch ? proof.patch.length : 0
271
+ }
272
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "10.31.12",
3
+ "version": "10.32.1",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -46,6 +46,7 @@
46
46
  "hypercore-crypto": "^3.2.1",
47
47
  "hypercore-errors": "^1.1.0",
48
48
  "hypercore-id-encoding": "^1.2.0",
49
+ "hypertrace": "^1.2.1",
49
50
  "is-options": "^1.0.1",
50
51
  "protomux": "^3.5.0",
51
52
  "quickbit-universal": "^2.2.0",
package/lib/manifest.js DELETED
@@ -1,222 +0,0 @@
1
- const defaultCrypto = require('hypercore-crypto')
2
- const b4a = require('b4a')
3
- const c = require('compact-encoding')
4
- const { BAD_ARGUMENT } = require('hypercore-errors')
5
-
6
- const m = require('./messages')
7
- const multisig = require('./multisig')
8
- const caps = require('./caps')
9
-
10
- module.exports = {
11
- manifestHash,
12
- isCompat,
13
- defaultSignerManifest,
14
- createManifest,
15
- createVerifier
16
- }
17
-
18
- class StaticVerifier {
19
- constructor (treeHash) {
20
- this.treeHash = treeHash
21
- }
22
-
23
- sign () {
24
- return null
25
- }
26
-
27
- verify (batch, signature) {
28
- return b4a.equals(batch.hash(), this.treeHash)
29
- }
30
- }
31
-
32
- class CompatVerifier {
33
- constructor (crypto, signer, legacy) {
34
- validateSigner(signer)
35
-
36
- this.legacy = legacy
37
- this.crypto = crypto
38
- this.publicKey = signer.publicKey
39
- }
40
-
41
- sign (batch, keyPair) {
42
- if (!keyPair || !keyPair.secretKey) throw BAD_ARGUMENT('No signer was passed')
43
- return this.crypto.sign(batch.signableCompat(this.legacy), keyPair.secretKey)
44
- }
45
-
46
- verify (batch, signature) {
47
- if (!signature) return false
48
- return this.crypto.verify(batch.signableCompat(this.legacy), signature, this.publicKey)
49
- }
50
- }
51
-
52
- class SingleVerifier {
53
- constructor (crypto, signer) {
54
- validateSigner(signer)
55
-
56
- this.crypto = crypto
57
- this.publicKey = signer.publicKey
58
- this.namespace = signer.namespace
59
- }
60
-
61
- sign (batch, keyPair) {
62
- if (!keyPair || !keyPair.secretKey) throw BAD_ARGUMENT('No signer was passed')
63
- return this.crypto.sign(batch.signable(this.namespace), keyPair.secretKey)
64
- }
65
-
66
- verify (batch, signature) {
67
- if (!signature) return false
68
- return this.crypto.verify(batch.signable(this.namespace), signature, this.publicKey)
69
- }
70
- }
71
-
72
- class MultiVerifier {
73
- constructor (crypto, multipleSigners) {
74
- this.signers = multipleSigners.signers
75
- this.quorum = multipleSigners.quorum
76
- this.allowPatched = multipleSigners.allowPatched
77
- this.verifiers = this.signers.map(s => new SingleVerifier(crypto, s))
78
-
79
- if (this.verifiers.length < this.quorum || (this.quorum === 0)) throw BAD_ARGUMENT('Invalid quorum')
80
- }
81
-
82
- sign () {
83
- throw BAD_ARGUMENT('Multi signature must be provided')
84
- }
85
-
86
- verify (batch, signature) {
87
- if (!signature) return false
88
-
89
- const inputs = multisig.inflate(signature)
90
-
91
- if (inputs.length < this.quorum) return false
92
-
93
- const tried = new Uint8Array(this.verifiers.length)
94
-
95
- for (let i = 0; i < this.quorum; i++) {
96
- const inp = inputs[i]
97
-
98
- let tree = batch
99
-
100
- if (inp.patch) {
101
- if (!this.allowPatched) return false
102
-
103
- tree = batch.clone()
104
- const proof = { fork: tree.fork, block: null, hash: null, seek: null, upgrade: inp.patch, manifest: null }
105
-
106
- try {
107
- if (!tree.verifyUpgrade(proof)) return false
108
- } catch {
109
- return false
110
- }
111
- }
112
-
113
- if (inp.signer >= this.verifiers.length || tried[inp.signer]) return false
114
- tried[inp.signer] = 1
115
-
116
- if (!this.verifiers[inp.signer].verify(tree, inp.signature)) return false
117
- }
118
-
119
- return true
120
- }
121
- }
122
-
123
- function createVerifier (manifest, { compat = false, crypto = defaultCrypto, legacy = false } = {}) {
124
- if (compat && manifest.signer) {
125
- return new CompatVerifier(crypto, manifest.signer, legacy)
126
- }
127
-
128
- if (manifest.static) {
129
- return new StaticVerifier(manifest.static)
130
- }
131
-
132
- if (manifest.signer) {
133
- return new SingleVerifier(crypto, manifest.signer)
134
- }
135
-
136
- if (manifest.multipleSigners) {
137
- return new MultiVerifier(crypto, manifest.multipleSigners)
138
- }
139
-
140
- throw BAD_ARGUMENT('No signer was provided')
141
- }
142
-
143
- function createManifest (inp) {
144
- if (!inp) return null
145
-
146
- const manifest = {
147
- hash: 'blake2b',
148
- static: null,
149
- signer: null,
150
- multipleSigners: null
151
- }
152
-
153
- if (inp.hash && inp.hash !== 'blake2b') throw BAD_ARGUMENT('Only Blake2b hashes are supported')
154
-
155
- if (inp.static) {
156
- if (!(b4a.isBuffer(inp.static) && inp.static.byteLength === 32)) throw BAD_ARGUMENT('Invalid static manifest')
157
- manifest.static = inp.static
158
- return manifest
159
- }
160
-
161
- if (inp.signer) {
162
- manifest.signer = parseSigner(inp.signer)
163
- return manifest
164
- }
165
-
166
- if (inp.multipleSigners) {
167
- manifest.multipleSigners = parseMultipleSigners(inp.multipleSigners)
168
- return manifest
169
- }
170
-
171
- throw BAD_ARGUMENT('No signer was provided')
172
- }
173
-
174
- function parseMultipleSigners (m) {
175
- if (m.signers.length < m.quorum || !(m.quorum > 0)) throw BAD_ARGUMENT('Invalid quorum')
176
-
177
- return {
178
- allowPatched: !!m.allowPatched,
179
- quorum: m.quorum,
180
- signers: m.signers.map(parseSigner)
181
- }
182
- }
183
-
184
- function parseSigner (signer) {
185
- validateSigner(signer)
186
- return {
187
- signature: 'ed25519',
188
- namespace: signer.namespace || caps.DEFAULT_NAMESPACE,
189
- publicKey: signer.publicKey
190
- }
191
- }
192
-
193
- function validateSigner (signer) {
194
- if (!signer || !signer.publicKey) throw BAD_ARGUMENT('Signer missing public key')
195
- if (signer.signature && signer.signature !== 'ed25519') throw BAD_ARGUMENT('Only Ed25519 signatures are supported')
196
- }
197
-
198
- function defaultSignerManifest (publicKey) {
199
- return {
200
- hash: 'blake2b',
201
- static: null,
202
- signer: {
203
- signature: 'ed25519',
204
- namespace: caps.DEFAULT_NAMESPACE,
205
- publicKey
206
- },
207
- multipleSigners: null
208
- }
209
- }
210
-
211
- function manifestHash (manifest) {
212
- const state = { start: 0, end: 32, buffer: null }
213
- m.manifest.preencode(state, manifest)
214
- state.buffer = b4a.allocUnsafe(state.end)
215
- c.raw.encode(state, caps.MANIFEST)
216
- m.manifest.encode(state, manifest)
217
- return defaultCrypto.hash(state.buffer)
218
- }
219
-
220
- function isCompat (key, manifest) {
221
- return !!(manifest && manifest.signer && b4a.equals(key, manifest.signer.publicKey))
222
- }