hypercore 11.7.0 → 11.8.0
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.
- package/lib/fully-remote-proof.js +126 -0
- package/package.json +1 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// this helper is for fully remote proofs, is like in a push notification where no other context exists
|
|
2
|
+
|
|
3
|
+
const { MerkleTree } = require('./merkle-tree.js')
|
|
4
|
+
const messages = require('./messages.js')
|
|
5
|
+
const b4a = require('b4a')
|
|
6
|
+
const c = require('compact-encoding')
|
|
7
|
+
const crypto = require('hypercore-crypto')
|
|
8
|
+
const flat = require('flat-tree')
|
|
9
|
+
|
|
10
|
+
class SlimSession {
|
|
11
|
+
constructor (storage, auth, head, roots) {
|
|
12
|
+
this.fork = head ? head.fork : 0
|
|
13
|
+
this.roots = roots
|
|
14
|
+
this.length = head ? head.length : 0
|
|
15
|
+
this.signature = head ? head.signature : null
|
|
16
|
+
this.ancestors = this.length
|
|
17
|
+
this.byteLength = 0
|
|
18
|
+
this.prologue = auth.manifest.prologue
|
|
19
|
+
this.storage = storage
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < roots.length; i++) this.byteLength += roots[i].size
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = { verify, proof }
|
|
26
|
+
|
|
27
|
+
async function verify (storage, buffer, { referrer = null } = {}) {
|
|
28
|
+
const state = { buffer, start: 0, end: buffer.byteLength }
|
|
29
|
+
|
|
30
|
+
const discoveryKey = c.fixed32.decode(state)
|
|
31
|
+
const proof = messages.wire.data.decode(state)
|
|
32
|
+
|
|
33
|
+
const result = {
|
|
34
|
+
key: null,
|
|
35
|
+
discoveryKey,
|
|
36
|
+
newer: true,
|
|
37
|
+
length: 0,
|
|
38
|
+
proof,
|
|
39
|
+
block: null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const core = await storage.resume(discoveryKey)
|
|
43
|
+
if (core === null) return null
|
|
44
|
+
|
|
45
|
+
let rx = core.read()
|
|
46
|
+
const authPromise = rx.getAuth()
|
|
47
|
+
const headPromise = rx.getHead()
|
|
48
|
+
const referrerPromise = rx.getUserData('referrer')
|
|
49
|
+
|
|
50
|
+
rx.tryFlush()
|
|
51
|
+
|
|
52
|
+
const [auth, head, ref] = await Promise.all([authPromise, headPromise, referrerPromise])
|
|
53
|
+
|
|
54
|
+
if (auth === null) return null
|
|
55
|
+
|
|
56
|
+
if (referrer && (!ref || !b4a.equals(ref, referrer))) return null
|
|
57
|
+
|
|
58
|
+
rx = core.read()
|
|
59
|
+
|
|
60
|
+
const rootPromises = []
|
|
61
|
+
|
|
62
|
+
for (const index of flat.fullRoots(head ? 2 * head.length : 0)) {
|
|
63
|
+
rootPromises.push(rx.getTreeNode(index))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
rx.tryFlush()
|
|
67
|
+
|
|
68
|
+
const roots = await Promise.all(rootPromises)
|
|
69
|
+
const length = head ? head.length : 0
|
|
70
|
+
|
|
71
|
+
if (!auth.manifest || !auth.manifest.signers.length) return null
|
|
72
|
+
|
|
73
|
+
const batch = await MerkleTree.verifyFullyRemote(new SlimSession(core, auth, head, roots), proof)
|
|
74
|
+
const publicKey = auth.manifest.signers[0].publicKey
|
|
75
|
+
|
|
76
|
+
let signable = null
|
|
77
|
+
let signature = null
|
|
78
|
+
|
|
79
|
+
if (auth.manifest.version === 0) {
|
|
80
|
+
signable = batch.signable(auth.manifest.signers[0].namespace)
|
|
81
|
+
signature = batch.signature
|
|
82
|
+
} else {
|
|
83
|
+
if (batch.signature[0] !== 1) return null
|
|
84
|
+
if (batch.signature[1] !== 0) return null
|
|
85
|
+
|
|
86
|
+
signable = batch.signable(auth.key)
|
|
87
|
+
signature = batch.signature.subarray(2)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!crypto.verify(signable, signature, publicKey)) {
|
|
91
|
+
return null
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
result.key = auth.key
|
|
95
|
+
result.discoveryKey = discoveryKey
|
|
96
|
+
result.newer = batch.length > length
|
|
97
|
+
result.length = batch.length
|
|
98
|
+
result.block = proof.block
|
|
99
|
+
|
|
100
|
+
return result
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function proof (sender, { index, block = null } = {}) {
|
|
104
|
+
const treeProof = await sender.proof({
|
|
105
|
+
block: block ? { index, nodes: 0 } : null,
|
|
106
|
+
upgrade: { start: 0, length: sender.length }
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const proof = await treeProof.settle()
|
|
110
|
+
|
|
111
|
+
if (block) proof.block.value = block
|
|
112
|
+
proof.manifest = sender.core.header.manifest
|
|
113
|
+
|
|
114
|
+
const state = { buffer: null, start: 0, end: 0 }
|
|
115
|
+
const data = { request: 0, ...proof }
|
|
116
|
+
|
|
117
|
+
c.fixed32.preencode(state, sender.discoveryKey)
|
|
118
|
+
messages.wire.data.preencode(state, data)
|
|
119
|
+
|
|
120
|
+
state.buffer = b4a.allocUnsafe(state.end)
|
|
121
|
+
|
|
122
|
+
c.fixed32.encode(state, sender.discoveryKey)
|
|
123
|
+
messages.wire.data.encode(state, data)
|
|
124
|
+
|
|
125
|
+
return state.buffer
|
|
126
|
+
}
|