Skip to content

Commit 5a7e2fd

Browse files
Add linked field to manifest (#679)
* remove unencrypted flag * introduce linked field to manifest * add flag for linked field * review by @mafintosh * fix typos * simplify encoding * throw on incompatible linked manifest * default manifest version to 1 * explicit version wins * linked is passed as null if optional
1 parent 48624a8 commit 5a7e2fd

File tree

5 files changed

+70
-26
lines changed

5 files changed

+70
-26
lines changed

index.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,6 @@ class Hypercore extends EventEmitter {
241241

242242
async setEncryption (encryption, opts) {
243243
if (!this.opened) await this.opening
244-
if (this.core.unencrypted) return
245244

246245
if (encryption === null) {
247246
this.encryption = encryption
@@ -329,7 +328,7 @@ class Hypercore extends EventEmitter {
329328

330329
if (this.keyPair === null) this.keyPair = opts.keyPair || this.core.header.keyPair
331330

332-
if (!this.core.encryption && !this.core.unencrypted) {
331+
if (!this.core.encryption) {
333332
const e = getEncryptionOption(opts)
334333

335334
if (HypercoreEncryption.isHypercoreEncryption(e)) {
@@ -774,8 +773,8 @@ class Hypercore extends EventEmitter {
774773
block = b4a.from(block)
775774

776775
if (this.encryption.compat !== this.core.compat) this._updateEncryption()
777-
if (this.core.unencrypted) this.encryption = null
778-
else await this.encryption.decrypt(index, block)
776+
777+
await this.encryption.decrypt(index, block)
779778
}
780779

781780
return this._decode(encoding, block)
@@ -923,7 +922,7 @@ class Hypercore extends EventEmitter {
923922

924923
blocks = Array.isArray(blocks) ? blocks : [blocks]
925924

926-
const preappend = this.core.unencrypted ? null : (this.encryption && this._preappend)
925+
const preappend = this.encryption && this._preappend
927926
if (preappend) await this.encryption.ready()
928927

929928
const buffers = this.encodeBatch !== null ? this.encodeBatch(blocks) : new Array(blocks.length)

lib/core.js

-3
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ module.exports = class Core {
3939
this.verifier = null
4040
this.truncating = 0
4141
this.updating = false
42-
this.unencrypted = false
4342
this.skipBitfield = null
4443
this.globalCache = opts.globalCache || null
4544
this.autoClose = opts.autoClose !== false
@@ -271,7 +270,6 @@ module.exports = class Core {
271270
// to unslab
272271
if (header.manifest) {
273272
header.manifest = Verifier.createManifest(header.manifest)
274-
this.unencrypted = header.manifest.unencrypted
275273
}
276274

277275
const verifier = header.manifest ? new Verifier(header.key, header.manifest, { crypto, legacy }) : null
@@ -326,7 +324,6 @@ module.exports = class Core {
326324
if (verifier.prologue) this.state.prologue = Object.assign({}, verifier.prologue)
327325

328326
this.manifest = this.header.manifest = manifest
329-
this.unencrypted = this.manifest.unencrypted
330327

331328
tx.setAuth({
332329
key: this.header.key,

lib/messages.js

+34-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ const unslab = require('unslab')
66

77
const EMPTY = b4a.alloc(0)
88

9+
const MANIFEST_PATCH = 0b00000001
10+
const MANIFEST_PROLOGUE = 0b00000010
11+
const MANIFEST_LINKED = 0b00000100
12+
913
const hashes = {
1014
preencode (state, m) {
1115
state.end++ // small uint
@@ -137,7 +141,7 @@ const manifestv0 = {
137141
hash: c.fixed32.decode(state),
138142
length: 0
139143
},
140-
unencrypted: false
144+
linked: []
141145
}
142146
}
143147

@@ -149,7 +153,7 @@ const manifestv0 = {
149153
quorum: 1,
150154
signers: [signer.decode(state)],
151155
prologue: null,
152-
unencrypted: false
156+
linked: []
153157
}
154158
}
155159

@@ -162,11 +166,13 @@ const manifestv0 = {
162166
quorum: c.uint.decode(state),
163167
signers: signerArray.decode(state),
164168
prologue: null,
165-
unencrypted: false
169+
linked: []
166170
}
167171
}
168172
}
169173

174+
const fixed32Array = c.array(c.fixed32)
175+
170176
const manifest = exports.manifest = {
171177
preencode (state, m) {
172178
state.end++ // version
@@ -178,37 +184,53 @@ const manifest = exports.manifest = {
178184
c.uint.preencode(state, m.quorum)
179185
signerArray.preencode(state, m.signers)
180186
if (m.prologue) prologue.preencode(state, m.prologue)
187+
188+
if (m.linked) {
189+
fixed32Array.preencode(state, m.linked)
190+
}
181191
},
182192
encode (state, m) {
183193
c.uint.encode(state, m.version)
184194
if (m.version === 0) return manifestv0.encode(state, m)
185195

186-
c.uint.encode(state, (m.allowPatch ? 1 : 0) | (m.prologue ? 2 : 0) | (m.unencrypted ? 4 : 0))
196+
let flags = 0
197+
if (m.allowPatch) flags |= MANIFEST_PATCH
198+
if (m.prologue) flags |= MANIFEST_PROLOGUE
199+
if (m.linked) flags |= MANIFEST_LINKED
200+
201+
c.uint.encode(state, flags)
187202
hashes.encode(state, m.hash)
188203

189204
c.uint.encode(state, m.quorum)
190205
signerArray.encode(state, m.signers)
191206
if (m.prologue) prologue.encode(state, m.prologue)
207+
208+
if (m.linked) {
209+
fixed32Array.encode(state, m.linked)
210+
}
192211
},
193212
decode (state) {
194-
const v = c.uint.decode(state)
195-
if (v === 0) return manifestv0.decode(state)
196-
if (v !== 1) throw new Error('Unknown version: ' + v)
213+
const version = c.uint.decode(state)
214+
if (version === 0) return manifestv0.decode(state)
215+
if (version > 2) throw new Error('Unknown version: ' + version)
197216

198217
const flags = c.uint.decode(state)
199218
const hash = hashes.decode(state)
200219
const quorum = c.uint.decode(state)
201220
const signers = signerArray.decode(state)
202-
const unencrypted = (flags & 4) !== 0
221+
222+
const hasPatch = (flags & MANIFEST_PATCH) !== 0
223+
const hasPrologue = (flags & MANIFEST_PROLOGUE) !== 0
224+
const hasLinked = (flags & MANIFEST_LINKED) !== 0
203225

204226
return {
205-
version: 1,
227+
version,
206228
hash,
207-
allowPatch: (flags & 1) !== 0,
229+
allowPatch: hasPatch,
208230
quorum,
209231
signers,
210-
prologue: (flags & 2) === 0 ? null : prologue.decode(state),
211-
unencrypted
232+
prologue: hasPrologue ? prologue.decode(state) : null,
233+
linked: hasLinked ? fixed32Array.decode(state) : null
212234
}
213235
}
214236
}

lib/verifier.js

+23-4
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ module.exports = class Verifier {
129129
}
130130

131131
verify (batch, signature) {
132-
if (this.version !== 1) {
132+
if (this.version === 0) {
133133
return this._verifyCompat(batch, signature)
134134
}
135135

@@ -182,7 +182,8 @@ module.exports = class Verifier {
182182
namespace: caps.DEFAULT_NAMESPACE,
183183
publicKey
184184
}],
185-
prologue: null
185+
prologue: null,
186+
linked: null
186187
}
187188
}
188189

@@ -195,13 +196,13 @@ module.exports = class Verifier {
195196
if (!inp) return null
196197

197198
const manifest = {
198-
version: typeof inp.version === 'number' ? inp.version : 1,
199+
version: getManifestVersion(inp), // only v2 if linked are present
199200
hash: 'blake2b',
200201
allowPatch: !!inp.allowPatch,
201202
quorum: defaultQuorum(inp),
202203
signers: inp.signers ? inp.signers.map(parseSigner) : [],
203204
prologue: null,
204-
unencrypted: !!inp.unencrypted
205+
linked: null
205206
}
206207

207208
if (inp.hash && inp.hash !== 'blake2b') throw BAD_ARGUMENT('Only Blake2b hashes are supported')
@@ -215,6 +216,18 @@ module.exports = class Verifier {
215216
manifest.prologue.hash = unslab(manifest.prologue.hash)
216217
}
217218

219+
if (inp.linked && inp.linked.length) {
220+
if (manifest.version < 2) throw BAD_ARGUMENT('Invalid field')
221+
222+
for (const key of inp.linked) {
223+
if (!(b4a.isBuffer(key) && key.byteLength === 32)) {
224+
throw BAD_ARGUMENT('Invalid key')
225+
}
226+
}
227+
228+
manifest.linked = inp.linked
229+
}
230+
218231
return manifest
219232
}
220233

@@ -311,3 +324,9 @@ function proofToVersion1 (proof) {
311324
patch: proof.patch ? proof.patch.length : 0
312325
}
313326
}
327+
328+
function getManifestVersion (inp) {
329+
if (typeof inp.version === 'number') return inp.version
330+
if (inp.linked && inp.linked.length) return 2
331+
return 1
332+
}

test/manifest.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,7 @@ test('manifest encoding', t => {
13431343
namespace: b4a.alloc(32, 1),
13441344
publicKey: keyPair.publicKey
13451345
}],
1346-
unencrypted: false
1346+
linked: []
13471347
}
13481348

13491349
t.alike(reencode(manifest), manifest)
@@ -1427,6 +1427,12 @@ test('manifest encoding', t => {
14271427
manifest.allowPatch = false
14281428
t.alike(reencode(manifest), manifest)
14291429

1430+
// with linked cores
1431+
manifest.version = 2
1432+
manifest.linked.push(b4a.alloc(32, 4))
1433+
1434+
t.alike(reencode(manifest), manifest)
1435+
14301436
function reencode (m) {
14311437
return c.decode(enc.manifest, c.encode(enc.manifest, m))
14321438
}
@@ -1487,7 +1493,8 @@ function createMultiManifest (signers, prologue = null) {
14871493
namespace: caps.DEFAULT_NAMESPACE,
14881494
publicKey: s.manifest.signers[0].publicKey
14891495
})),
1490-
prologue
1496+
prologue,
1497+
linked: []
14911498
}
14921499
}
14931500

0 commit comments

Comments
 (0)