@hashtree/core 0.1.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/LICENSE +21 -0
- package/dist/bep52.d.ts +179 -0
- package/dist/bep52.d.ts.map +1 -0
- package/dist/bep52.js +384 -0
- package/dist/bep52.js.map +1 -0
- package/dist/builder.d.ts +137 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +281 -0
- package/dist/builder.js.map +1 -0
- package/dist/codec.d.ts +37 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +109 -0
- package/dist/codec.js.map +1 -0
- package/dist/crypto.d.ts +92 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +212 -0
- package/dist/crypto.js.map +1 -0
- package/dist/encrypted.d.ts +114 -0
- package/dist/encrypted.d.ts.map +1 -0
- package/dist/encrypted.js +446 -0
- package/dist/encrypted.js.map +1 -0
- package/dist/hash.d.ts +14 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +27 -0
- package/dist/hash.js.map +1 -0
- package/dist/hashtree.d.ts +237 -0
- package/dist/hashtree.d.ts.map +1 -0
- package/dist/hashtree.js +557 -0
- package/dist/hashtree.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/nhash.d.ts +94 -0
- package/dist/nhash.d.ts.map +1 -0
- package/dist/nhash.js +293 -0
- package/dist/nhash.js.map +1 -0
- package/dist/resolver/index.d.ts +5 -0
- package/dist/resolver/index.d.ts.map +1 -0
- package/dist/resolver/index.js +5 -0
- package/dist/resolver/index.js.map +1 -0
- package/dist/resolver/nostr.d.ts +82 -0
- package/dist/resolver/nostr.d.ts.map +1 -0
- package/dist/resolver/nostr.js +868 -0
- package/dist/resolver/nostr.js.map +1 -0
- package/dist/store/blossom.d.ts +100 -0
- package/dist/store/blossom.d.ts.map +1 -0
- package/dist/store/blossom.js +355 -0
- package/dist/store/blossom.js.map +1 -0
- package/dist/store/dexie.d.ts +44 -0
- package/dist/store/dexie.d.ts.map +1 -0
- package/dist/store/dexie.js +196 -0
- package/dist/store/dexie.js.map +1 -0
- package/dist/store/fallback.d.ts +40 -0
- package/dist/store/fallback.d.ts.map +1 -0
- package/dist/store/fallback.js +71 -0
- package/dist/store/fallback.js.map +1 -0
- package/dist/store/index.d.ts +6 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +6 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/memory.d.ts +29 -0
- package/dist/store/memory.d.ts.map +1 -0
- package/dist/store/memory.js +66 -0
- package/dist/store/memory.js.map +1 -0
- package/dist/store/opfs.d.ts +56 -0
- package/dist/store/opfs.d.ts.map +1 -0
- package/dist/store/opfs.js +200 -0
- package/dist/store/opfs.js.map +1 -0
- package/dist/streaming.d.ts +74 -0
- package/dist/streaming.d.ts.map +1 -0
- package/dist/streaming.js +199 -0
- package/dist/streaming.js.map +1 -0
- package/dist/tree/create.d.ts +35 -0
- package/dist/tree/create.d.ts.map +1 -0
- package/dist/tree/create.js +90 -0
- package/dist/tree/create.js.map +1 -0
- package/dist/tree/edit.d.ts +28 -0
- package/dist/tree/edit.d.ts.map +1 -0
- package/dist/tree/edit.js +115 -0
- package/dist/tree/edit.js.map +1 -0
- package/dist/tree/editEncrypted.d.ts +46 -0
- package/dist/tree/editEncrypted.d.ts.map +1 -0
- package/dist/tree/editEncrypted.js +225 -0
- package/dist/tree/editEncrypted.js.map +1 -0
- package/dist/tree/index.d.ts +7 -0
- package/dist/tree/index.d.ts.map +1 -0
- package/dist/tree/index.js +7 -0
- package/dist/tree/index.js.map +1 -0
- package/dist/tree/read.d.ts +75 -0
- package/dist/tree/read.d.ts.map +1 -0
- package/dist/tree/read.js +389 -0
- package/dist/tree/read.js.map +1 -0
- package/dist/tree/writeAt.d.ts +44 -0
- package/dist/tree/writeAt.d.ts.map +1 -0
- package/dist/tree/writeAt.js +282 -0
- package/dist/tree/writeAt.js.map +1 -0
- package/dist/types.d.ts +274 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +47 -0
- package/dist/types.js.map +1 -0
- package/dist/verify.d.ts +12 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +32 -0
- package/dist/verify.js.map +1 -0
- package/dist/visibility.d.ts +50 -0
- package/dist/visibility.d.ts.map +1 -0
- package/dist/visibility.js +111 -0
- package/dist/visibility.js.map +1 -0
- package/dist/webrtc/index.d.ts +4 -0
- package/dist/webrtc/index.d.ts.map +1 -0
- package/dist/webrtc/index.js +4 -0
- package/dist/webrtc/index.js.map +1 -0
- package/dist/webrtc/lruCache.d.ts +20 -0
- package/dist/webrtc/lruCache.d.ts.map +1 -0
- package/dist/webrtc/lruCache.js +59 -0
- package/dist/webrtc/lruCache.js.map +1 -0
- package/dist/webrtc/peer.d.ts +122 -0
- package/dist/webrtc/peer.d.ts.map +1 -0
- package/dist/webrtc/peer.js +583 -0
- package/dist/webrtc/peer.js.map +1 -0
- package/dist/webrtc/protocol.d.ts +76 -0
- package/dist/webrtc/protocol.d.ts.map +1 -0
- package/dist/webrtc/protocol.js +167 -0
- package/dist/webrtc/protocol.js.map +1 -0
- package/dist/webrtc/store.d.ts +190 -0
- package/dist/webrtc/store.d.ts.map +1 -0
- package/dist/webrtc/store.js +1043 -0
- package/dist/webrtc/store.js.map +1 -0
- package/dist/webrtc/types.d.ts +196 -0
- package/dist/webrtc/types.d.ts.map +1 -0
- package/dist/webrtc/types.js +46 -0
- package/dist/webrtc/types.js.map +1 -0
- package/dist/worker/protocol.d.ts +493 -0
- package/dist/worker/protocol.d.ts.map +1 -0
- package/dist/worker/protocol.js +15 -0
- package/dist/worker/protocol.js.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Sirius Business Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/bep52.d.ts
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BEP52 (BitTorrent v2) compatible merkle tree implementation
|
|
3
|
+
*
|
|
4
|
+
* Key differences from default hashtree:
|
|
5
|
+
* - 16 KiB block size (vs 256KB default)
|
|
6
|
+
* - Binary tree (2 children per node, not variable fanout)
|
|
7
|
+
* - Zero-padding for incomplete trees (pads to power of 2)
|
|
8
|
+
* - SHA256 hash algorithm
|
|
9
|
+
* - Piece layers: intermediate hash layers at piece boundaries
|
|
10
|
+
*
|
|
11
|
+
* @see https://www.bittorrent.org/beps/bep_0052.html
|
|
12
|
+
*/
|
|
13
|
+
import { Hash, Store } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* BEP52 block size: 16 KiB
|
|
16
|
+
*/
|
|
17
|
+
export declare const BEP52_BLOCK_SIZE: number;
|
|
18
|
+
/**
|
|
19
|
+
* Zero hash (32 bytes of zeros) used for padding
|
|
20
|
+
*/
|
|
21
|
+
export declare const ZERO_HASH: Hash;
|
|
22
|
+
/**
|
|
23
|
+
* Result of building a BEP52 merkle tree
|
|
24
|
+
*/
|
|
25
|
+
export interface Bep52Result {
|
|
26
|
+
/** Root hash (pieces root) */
|
|
27
|
+
root: Hash;
|
|
28
|
+
/** Total file size in bytes */
|
|
29
|
+
size: number;
|
|
30
|
+
/** Number of 16KB blocks */
|
|
31
|
+
blockCount: number;
|
|
32
|
+
/** Leaf hashes (one per block) */
|
|
33
|
+
leafHashes: Hash[];
|
|
34
|
+
/**
|
|
35
|
+
* Piece layer hashes at specified piece size
|
|
36
|
+
* Only populated if pieceSize > blockSize
|
|
37
|
+
*/
|
|
38
|
+
pieceLayers?: Hash[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Configuration for BEP52 tree building
|
|
42
|
+
*/
|
|
43
|
+
export interface Bep52Config {
|
|
44
|
+
/** Store for persisting blocks (optional - if not provided, only computes hashes) */
|
|
45
|
+
store?: Store;
|
|
46
|
+
/**
|
|
47
|
+
* Piece size for piece layers (must be power of 2, >= 16KB)
|
|
48
|
+
* Common values: 16KB (same as block), 32KB, 64KB, 128KB, 256KB, 512KB, 1MB, etc.
|
|
49
|
+
* If not specified, no piece layers are computed.
|
|
50
|
+
*/
|
|
51
|
+
pieceSize?: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Compute the number of leaves needed (rounds up to power of 2)
|
|
55
|
+
*/
|
|
56
|
+
export declare function merkleNumLeafs(blocks: number): number;
|
|
57
|
+
/**
|
|
58
|
+
* Get parent index in flat tree representation
|
|
59
|
+
* Tree layout: [0=root, 1=left, 2=right, 3=left-left, 4=left-right, ...]
|
|
60
|
+
*/
|
|
61
|
+
export declare function merkleGetParent(idx: number): number;
|
|
62
|
+
/**
|
|
63
|
+
* Get sibling index
|
|
64
|
+
*/
|
|
65
|
+
export declare function merkleGetSibling(idx: number): number;
|
|
66
|
+
/**
|
|
67
|
+
* Get first child index
|
|
68
|
+
*/
|
|
69
|
+
export declare function merkleGetFirstChild(idx: number): number;
|
|
70
|
+
/**
|
|
71
|
+
* Get index of first leaf given number of leaves
|
|
72
|
+
*/
|
|
73
|
+
export declare function merkleFirstLeaf(numLeafs: number): number;
|
|
74
|
+
/**
|
|
75
|
+
* Get total number of nodes in tree given number of leaves
|
|
76
|
+
*/
|
|
77
|
+
export declare function merkleNumNodes(numLeafs: number): number;
|
|
78
|
+
/**
|
|
79
|
+
* Compute hash of two concatenated hashes (parent = H(left || right))
|
|
80
|
+
*/
|
|
81
|
+
export declare function merkleHashPair(left: Hash, right: Hash): Promise<Hash>;
|
|
82
|
+
/**
|
|
83
|
+
* Compute the pad hash for a given depth
|
|
84
|
+
* pad(0) = zero hash
|
|
85
|
+
* pad(n) = H(pad(n-1) || pad(n-1))
|
|
86
|
+
*/
|
|
87
|
+
export declare function merklePadHash(depth: number): Promise<Hash>;
|
|
88
|
+
/**
|
|
89
|
+
* Compute merkle root from leaf hashes with zero-padding
|
|
90
|
+
*
|
|
91
|
+
* @param leaves - Array of leaf hashes (one per 16KB block)
|
|
92
|
+
* @param numLeafs - Number of leaves in balanced tree (power of 2)
|
|
93
|
+
* @returns Root hash
|
|
94
|
+
*/
|
|
95
|
+
export declare function merkleRoot(leaves: Hash[], numLeafs?: number): Promise<Hash>;
|
|
96
|
+
/**
|
|
97
|
+
* Build full merkle tree from leaves, returning all nodes
|
|
98
|
+
*
|
|
99
|
+
* @param leaves - Leaf hashes
|
|
100
|
+
* @returns Flat array of tree nodes [root, layer1..., leaves]
|
|
101
|
+
*/
|
|
102
|
+
export declare function merkleBuildTree(leaves: Hash[]): Promise<Hash[]>;
|
|
103
|
+
/**
|
|
104
|
+
* Generate uncle hashes (proof) for a leaf
|
|
105
|
+
*
|
|
106
|
+
* @param tree - Full merkle tree
|
|
107
|
+
* @param leafIndex - Index of leaf in leaf layer (0-based)
|
|
108
|
+
* @param numLeafs - Number of leaves in tree
|
|
109
|
+
* @returns Array of uncle hashes from leaf to root
|
|
110
|
+
*/
|
|
111
|
+
export declare function merkleGetProof(tree: Hash[], leafIndex: number, numLeafs: number): Hash[];
|
|
112
|
+
/**
|
|
113
|
+
* Verify a merkle proof
|
|
114
|
+
*
|
|
115
|
+
* @param leaf - Leaf hash to verify
|
|
116
|
+
* @param leafIndex - Position of leaf (0-based)
|
|
117
|
+
* @param proof - Uncle hashes from leaf to root
|
|
118
|
+
* @param root - Expected root hash
|
|
119
|
+
* @param numLeafs - Number of leaves in tree
|
|
120
|
+
* @returns True if proof is valid
|
|
121
|
+
*/
|
|
122
|
+
export declare function merkleVerifyProof(leaf: Hash, leafIndex: number, proof: Hash[], root: Hash, numLeafs: number): Promise<boolean>;
|
|
123
|
+
/**
|
|
124
|
+
* BEP52 Tree Builder
|
|
125
|
+
*
|
|
126
|
+
* Builds a binary merkle tree compatible with BitTorrent v2.
|
|
127
|
+
*/
|
|
128
|
+
export declare class Bep52TreeBuilder {
|
|
129
|
+
private store?;
|
|
130
|
+
private pieceSize;
|
|
131
|
+
private blocksPerPiece;
|
|
132
|
+
constructor(config?: Bep52Config);
|
|
133
|
+
/**
|
|
134
|
+
* Build BEP52 merkle tree from file data
|
|
135
|
+
*
|
|
136
|
+
* @param data - File content
|
|
137
|
+
* @returns Tree result with root, leaf hashes, and optional piece layers
|
|
138
|
+
*/
|
|
139
|
+
buildFromData(data: Uint8Array): Promise<Bep52Result>;
|
|
140
|
+
/**
|
|
141
|
+
* Compute piece layer hashes
|
|
142
|
+
* Each piece layer hash is the root of a subtree covering blocksPerPiece blocks
|
|
143
|
+
*/
|
|
144
|
+
private computePieceLayers;
|
|
145
|
+
/**
|
|
146
|
+
* Build tree from pre-computed leaf hashes
|
|
147
|
+
*/
|
|
148
|
+
buildFromHashes(leafHashes: Hash[], size: number): Promise<Bep52Result>;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Streaming BEP52 tree builder
|
|
152
|
+
* Allows incremental hashing without loading entire file into memory
|
|
153
|
+
*/
|
|
154
|
+
export declare class Bep52StreamBuilder {
|
|
155
|
+
private store?;
|
|
156
|
+
private buffer;
|
|
157
|
+
private bufferOffset;
|
|
158
|
+
private leafHashes;
|
|
159
|
+
private totalSize;
|
|
160
|
+
constructor(config?: Bep52Config);
|
|
161
|
+
/**
|
|
162
|
+
* Append data to the stream
|
|
163
|
+
*/
|
|
164
|
+
append(data: Uint8Array): Promise<void>;
|
|
165
|
+
private flushBlock;
|
|
166
|
+
/**
|
|
167
|
+
* Finalize and return the tree result
|
|
168
|
+
*/
|
|
169
|
+
finalize(): Promise<Bep52Result>;
|
|
170
|
+
/**
|
|
171
|
+
* Get current stats
|
|
172
|
+
*/
|
|
173
|
+
get stats(): {
|
|
174
|
+
blocks: number;
|
|
175
|
+
buffered: number;
|
|
176
|
+
totalSize: number;
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=bep52.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bep52.d.ts","sourceRoot":"","sources":["../src/bep52.ts"],"names":[],"mappings":"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"}
|
package/dist/bep52.js
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BEP52 (BitTorrent v2) compatible merkle tree implementation
|
|
3
|
+
*
|
|
4
|
+
* Key differences from default hashtree:
|
|
5
|
+
* - 16 KiB block size (vs 256KB default)
|
|
6
|
+
* - Binary tree (2 children per node, not variable fanout)
|
|
7
|
+
* - Zero-padding for incomplete trees (pads to power of 2)
|
|
8
|
+
* - SHA256 hash algorithm
|
|
9
|
+
* - Piece layers: intermediate hash layers at piece boundaries
|
|
10
|
+
*
|
|
11
|
+
* @see https://www.bittorrent.org/beps/bep_0052.html
|
|
12
|
+
*/
|
|
13
|
+
import { hashEquals } from './types.js';
|
|
14
|
+
import { sha256 } from './hash.js';
|
|
15
|
+
/**
|
|
16
|
+
* BEP52 block size: 16 KiB
|
|
17
|
+
*/
|
|
18
|
+
export const BEP52_BLOCK_SIZE = 16 * 1024;
|
|
19
|
+
/**
|
|
20
|
+
* Zero hash (32 bytes of zeros) used for padding
|
|
21
|
+
*/
|
|
22
|
+
export const ZERO_HASH = new Uint8Array(32);
|
|
23
|
+
/**
|
|
24
|
+
* Compute the number of leaves needed (rounds up to power of 2)
|
|
25
|
+
*/
|
|
26
|
+
export function merkleNumLeafs(blocks) {
|
|
27
|
+
if (blocks <= 0)
|
|
28
|
+
return 0;
|
|
29
|
+
let n = 1;
|
|
30
|
+
while (n < blocks)
|
|
31
|
+
n <<= 1;
|
|
32
|
+
return n;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get parent index in flat tree representation
|
|
36
|
+
* Tree layout: [0=root, 1=left, 2=right, 3=left-left, 4=left-right, ...]
|
|
37
|
+
*/
|
|
38
|
+
export function merkleGetParent(idx) {
|
|
39
|
+
return Math.floor((idx - 1) / 2);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get sibling index
|
|
43
|
+
*/
|
|
44
|
+
export function merkleGetSibling(idx) {
|
|
45
|
+
// Even indices have sibling to left, odd to right
|
|
46
|
+
return idx + ((idx & 1) ? 1 : -1);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get first child index
|
|
50
|
+
*/
|
|
51
|
+
export function merkleGetFirstChild(idx) {
|
|
52
|
+
return idx * 2 + 1;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get index of first leaf given number of leaves
|
|
56
|
+
*/
|
|
57
|
+
export function merkleFirstLeaf(numLeafs) {
|
|
58
|
+
return numLeafs - 1;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get total number of nodes in tree given number of leaves
|
|
62
|
+
*/
|
|
63
|
+
export function merkleNumNodes(numLeafs) {
|
|
64
|
+
return numLeafs * 2 - 1;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Compute hash of two concatenated hashes (parent = H(left || right))
|
|
68
|
+
*/
|
|
69
|
+
export async function merkleHashPair(left, right) {
|
|
70
|
+
const combined = new Uint8Array(64);
|
|
71
|
+
combined.set(left, 0);
|
|
72
|
+
combined.set(right, 32);
|
|
73
|
+
return sha256(combined);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Compute the pad hash for a given depth
|
|
77
|
+
* pad(0) = zero hash
|
|
78
|
+
* pad(n) = H(pad(n-1) || pad(n-1))
|
|
79
|
+
*/
|
|
80
|
+
export async function merklePadHash(depth) {
|
|
81
|
+
let pad = ZERO_HASH;
|
|
82
|
+
for (let i = 0; i < depth; i++) {
|
|
83
|
+
pad = await merkleHashPair(pad, pad);
|
|
84
|
+
}
|
|
85
|
+
return pad;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Compute merkle root from leaf hashes with zero-padding
|
|
89
|
+
*
|
|
90
|
+
* @param leaves - Array of leaf hashes (one per 16KB block)
|
|
91
|
+
* @param numLeafs - Number of leaves in balanced tree (power of 2)
|
|
92
|
+
* @returns Root hash
|
|
93
|
+
*/
|
|
94
|
+
export async function merkleRoot(leaves, numLeafs) {
|
|
95
|
+
if (leaves.length === 0) {
|
|
96
|
+
return ZERO_HASH;
|
|
97
|
+
}
|
|
98
|
+
if (leaves.length === 1 && (numLeafs === undefined || numLeafs === 1)) {
|
|
99
|
+
return leaves[0];
|
|
100
|
+
}
|
|
101
|
+
const targetLeafs = numLeafs ?? merkleNumLeafs(leaves.length);
|
|
102
|
+
// Build tree bottom-up using scratch space
|
|
103
|
+
// This matches libtorrent's merkle_root_scratch approach
|
|
104
|
+
let current = leaves.slice();
|
|
105
|
+
let padHash = ZERO_HASH;
|
|
106
|
+
let levelSize = targetLeafs;
|
|
107
|
+
while (levelSize > 1) {
|
|
108
|
+
const nextLevel = [];
|
|
109
|
+
for (let i = 0; i < current.length; i += 2) {
|
|
110
|
+
if (i + 1 < current.length) {
|
|
111
|
+
// Both children present
|
|
112
|
+
nextLevel.push(await merkleHashPair(current[i], current[i + 1]));
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// Odd leaf - pair with pad
|
|
116
|
+
nextLevel.push(await merkleHashPair(current[i], padHash));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Compute next level's pad hash (H(pad || pad))
|
|
120
|
+
padHash = await merkleHashPair(padHash, padHash);
|
|
121
|
+
current = nextLevel;
|
|
122
|
+
levelSize = levelSize / 2;
|
|
123
|
+
}
|
|
124
|
+
return current[0];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Build full merkle tree from leaves, returning all nodes
|
|
128
|
+
*
|
|
129
|
+
* @param leaves - Leaf hashes
|
|
130
|
+
* @returns Flat array of tree nodes [root, layer1..., leaves]
|
|
131
|
+
*/
|
|
132
|
+
export async function merkleBuildTree(leaves) {
|
|
133
|
+
if (leaves.length === 0) {
|
|
134
|
+
return [ZERO_HASH];
|
|
135
|
+
}
|
|
136
|
+
const numLeafs = merkleNumLeafs(leaves.length);
|
|
137
|
+
const numNodes = merkleNumNodes(numLeafs);
|
|
138
|
+
const tree = new Array(numNodes);
|
|
139
|
+
// Fill leaves (with zero-padding)
|
|
140
|
+
const firstLeaf = merkleFirstLeaf(numLeafs);
|
|
141
|
+
for (let i = 0; i < numLeafs; i++) {
|
|
142
|
+
tree[firstLeaf + i] = i < leaves.length ? leaves[i] : ZERO_HASH;
|
|
143
|
+
}
|
|
144
|
+
// Build parents bottom-up
|
|
145
|
+
let levelStart = firstLeaf;
|
|
146
|
+
let levelSize = numLeafs;
|
|
147
|
+
while (levelSize > 1) {
|
|
148
|
+
let parent = merkleGetParent(levelStart);
|
|
149
|
+
for (let i = levelStart; i < levelStart + levelSize; i += 2) {
|
|
150
|
+
tree[parent] = await merkleHashPair(tree[i], tree[i + 1]);
|
|
151
|
+
parent++;
|
|
152
|
+
}
|
|
153
|
+
levelStart = merkleGetParent(levelStart);
|
|
154
|
+
levelSize = levelSize / 2;
|
|
155
|
+
}
|
|
156
|
+
return tree;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Generate uncle hashes (proof) for a leaf
|
|
160
|
+
*
|
|
161
|
+
* @param tree - Full merkle tree
|
|
162
|
+
* @param leafIndex - Index of leaf in leaf layer (0-based)
|
|
163
|
+
* @param numLeafs - Number of leaves in tree
|
|
164
|
+
* @returns Array of uncle hashes from leaf to root
|
|
165
|
+
*/
|
|
166
|
+
export function merkleGetProof(tree, leafIndex, numLeafs) {
|
|
167
|
+
const proofs = [];
|
|
168
|
+
let idx = merkleFirstLeaf(numLeafs) + leafIndex;
|
|
169
|
+
while (idx > 0) {
|
|
170
|
+
const siblingIdx = merkleGetSibling(idx);
|
|
171
|
+
proofs.push(tree[siblingIdx]);
|
|
172
|
+
idx = merkleGetParent(idx);
|
|
173
|
+
}
|
|
174
|
+
return proofs;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Verify a merkle proof
|
|
178
|
+
*
|
|
179
|
+
* @param leaf - Leaf hash to verify
|
|
180
|
+
* @param leafIndex - Position of leaf (0-based)
|
|
181
|
+
* @param proof - Uncle hashes from leaf to root
|
|
182
|
+
* @param root - Expected root hash
|
|
183
|
+
* @param numLeafs - Number of leaves in tree
|
|
184
|
+
* @returns True if proof is valid
|
|
185
|
+
*/
|
|
186
|
+
export async function merkleVerifyProof(leaf, leafIndex, proof, root, numLeafs) {
|
|
187
|
+
let hash = leaf;
|
|
188
|
+
let idx = merkleFirstLeaf(numLeafs) + leafIndex;
|
|
189
|
+
for (const uncle of proof) {
|
|
190
|
+
// In flat tree: children of parent P are at 2P+1 (left) and 2P+2 (right)
|
|
191
|
+
// So odd indices are LEFT children, even indices are RIGHT children
|
|
192
|
+
if (idx & 1) {
|
|
193
|
+
// Odd index - we're on the left, uncle is on right
|
|
194
|
+
hash = await merkleHashPair(hash, uncle);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// Even index - we're on the right, uncle is on left
|
|
198
|
+
hash = await merkleHashPair(uncle, hash);
|
|
199
|
+
}
|
|
200
|
+
idx = merkleGetParent(idx);
|
|
201
|
+
}
|
|
202
|
+
return hashEquals(hash, root);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* BEP52 Tree Builder
|
|
206
|
+
*
|
|
207
|
+
* Builds a binary merkle tree compatible with BitTorrent v2.
|
|
208
|
+
*/
|
|
209
|
+
export class Bep52TreeBuilder {
|
|
210
|
+
store;
|
|
211
|
+
pieceSize;
|
|
212
|
+
blocksPerPiece;
|
|
213
|
+
constructor(config = {}) {
|
|
214
|
+
this.store = config.store;
|
|
215
|
+
this.pieceSize = config.pieceSize ?? BEP52_BLOCK_SIZE;
|
|
216
|
+
if (this.pieceSize < BEP52_BLOCK_SIZE) {
|
|
217
|
+
throw new Error(`Piece size must be >= ${BEP52_BLOCK_SIZE} (16KB)`);
|
|
218
|
+
}
|
|
219
|
+
if ((this.pieceSize & (this.pieceSize - 1)) !== 0) {
|
|
220
|
+
throw new Error('Piece size must be a power of 2');
|
|
221
|
+
}
|
|
222
|
+
this.blocksPerPiece = this.pieceSize / BEP52_BLOCK_SIZE;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Build BEP52 merkle tree from file data
|
|
226
|
+
*
|
|
227
|
+
* @param data - File content
|
|
228
|
+
* @returns Tree result with root, leaf hashes, and optional piece layers
|
|
229
|
+
*/
|
|
230
|
+
async buildFromData(data) {
|
|
231
|
+
const size = data.length;
|
|
232
|
+
const blockCount = Math.ceil(size / BEP52_BLOCK_SIZE);
|
|
233
|
+
if (blockCount === 0) {
|
|
234
|
+
return {
|
|
235
|
+
root: ZERO_HASH,
|
|
236
|
+
size: 0,
|
|
237
|
+
blockCount: 0,
|
|
238
|
+
leafHashes: [],
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
// Hash each 16KB block
|
|
242
|
+
const leafHashes = [];
|
|
243
|
+
for (let i = 0; i < blockCount; i++) {
|
|
244
|
+
const start = i * BEP52_BLOCK_SIZE;
|
|
245
|
+
const end = Math.min(start + BEP52_BLOCK_SIZE, size);
|
|
246
|
+
const block = data.slice(start, end);
|
|
247
|
+
// Store block if store is provided
|
|
248
|
+
const hash = await sha256(block);
|
|
249
|
+
if (this.store) {
|
|
250
|
+
await this.store.put(hash, block);
|
|
251
|
+
}
|
|
252
|
+
leafHashes.push(hash);
|
|
253
|
+
}
|
|
254
|
+
// Compute root
|
|
255
|
+
const numLeafs = merkleNumLeafs(blockCount);
|
|
256
|
+
const root = await merkleRoot(leafHashes, numLeafs);
|
|
257
|
+
// Compute piece layers if piece size > block size
|
|
258
|
+
let pieceLayers;
|
|
259
|
+
if (this.pieceSize > BEP52_BLOCK_SIZE) {
|
|
260
|
+
pieceLayers = await this.computePieceLayers(leafHashes, numLeafs);
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
root,
|
|
264
|
+
size,
|
|
265
|
+
blockCount,
|
|
266
|
+
leafHashes,
|
|
267
|
+
pieceLayers,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Compute piece layer hashes
|
|
272
|
+
* Each piece layer hash is the root of a subtree covering blocksPerPiece blocks
|
|
273
|
+
*/
|
|
274
|
+
async computePieceLayers(leafHashes, _numLeafs) {
|
|
275
|
+
const pieceCount = Math.ceil(leafHashes.length / this.blocksPerPiece);
|
|
276
|
+
const layers = [];
|
|
277
|
+
for (let p = 0; p < pieceCount; p++) {
|
|
278
|
+
const start = p * this.blocksPerPiece;
|
|
279
|
+
const end = Math.min(start + this.blocksPerPiece, leafHashes.length);
|
|
280
|
+
const pieceLeaves = leafHashes.slice(start, end);
|
|
281
|
+
// Compute subtree root for this piece
|
|
282
|
+
const pieceRoot = await merkleRoot(pieceLeaves, this.blocksPerPiece);
|
|
283
|
+
layers.push(pieceRoot);
|
|
284
|
+
}
|
|
285
|
+
return layers;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Build tree from pre-computed leaf hashes
|
|
289
|
+
*/
|
|
290
|
+
async buildFromHashes(leafHashes, size) {
|
|
291
|
+
const blockCount = leafHashes.length;
|
|
292
|
+
const numLeafs = merkleNumLeafs(blockCount);
|
|
293
|
+
const root = await merkleRoot(leafHashes, numLeafs);
|
|
294
|
+
let pieceLayers;
|
|
295
|
+
if (this.pieceSize > BEP52_BLOCK_SIZE) {
|
|
296
|
+
pieceLayers = await this.computePieceLayers(leafHashes, numLeafs);
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
root,
|
|
300
|
+
size,
|
|
301
|
+
blockCount,
|
|
302
|
+
leafHashes,
|
|
303
|
+
pieceLayers,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Streaming BEP52 tree builder
|
|
309
|
+
* Allows incremental hashing without loading entire file into memory
|
|
310
|
+
*/
|
|
311
|
+
export class Bep52StreamBuilder {
|
|
312
|
+
store;
|
|
313
|
+
buffer;
|
|
314
|
+
bufferOffset = 0;
|
|
315
|
+
leafHashes = [];
|
|
316
|
+
totalSize = 0;
|
|
317
|
+
constructor(config = {}) {
|
|
318
|
+
this.store = config.store;
|
|
319
|
+
this.buffer = new Uint8Array(BEP52_BLOCK_SIZE);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Append data to the stream
|
|
323
|
+
*/
|
|
324
|
+
async append(data) {
|
|
325
|
+
let offset = 0;
|
|
326
|
+
while (offset < data.length) {
|
|
327
|
+
const space = BEP52_BLOCK_SIZE - this.bufferOffset;
|
|
328
|
+
const toWrite = Math.min(space, data.length - offset);
|
|
329
|
+
this.buffer.set(data.subarray(offset, offset + toWrite), this.bufferOffset);
|
|
330
|
+
this.bufferOffset += toWrite;
|
|
331
|
+
offset += toWrite;
|
|
332
|
+
if (this.bufferOffset === BEP52_BLOCK_SIZE) {
|
|
333
|
+
await this.flushBlock();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
this.totalSize += data.length;
|
|
337
|
+
}
|
|
338
|
+
async flushBlock() {
|
|
339
|
+
if (this.bufferOffset === 0)
|
|
340
|
+
return;
|
|
341
|
+
const block = this.buffer.slice(0, this.bufferOffset);
|
|
342
|
+
const hash = await sha256(block);
|
|
343
|
+
if (this.store) {
|
|
344
|
+
await this.store.put(hash, new Uint8Array(block));
|
|
345
|
+
}
|
|
346
|
+
this.leafHashes.push(hash);
|
|
347
|
+
this.bufferOffset = 0;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Finalize and return the tree result
|
|
351
|
+
*/
|
|
352
|
+
async finalize() {
|
|
353
|
+
// Flush any remaining data
|
|
354
|
+
await this.flushBlock();
|
|
355
|
+
const blockCount = this.leafHashes.length;
|
|
356
|
+
if (blockCount === 0) {
|
|
357
|
+
return {
|
|
358
|
+
root: ZERO_HASH,
|
|
359
|
+
size: 0,
|
|
360
|
+
blockCount: 0,
|
|
361
|
+
leafHashes: [],
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
const numLeafs = merkleNumLeafs(blockCount);
|
|
365
|
+
const root = await merkleRoot(this.leafHashes, numLeafs);
|
|
366
|
+
return {
|
|
367
|
+
root,
|
|
368
|
+
size: this.totalSize,
|
|
369
|
+
blockCount,
|
|
370
|
+
leafHashes: this.leafHashes,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Get current stats
|
|
375
|
+
*/
|
|
376
|
+
get stats() {
|
|
377
|
+
return {
|
|
378
|
+
blocks: this.leafHashes.length,
|
|
379
|
+
buffered: this.bufferOffset,
|
|
380
|
+
totalSize: this.totalSize,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
//# sourceMappingURL=bep52.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bep52.js","sourceRoot":"","sources":["../src/bep52.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAe,UAAU,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,CAAC;AAE1C;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAS,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;AAmClD;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,MAAM;QAAE,CAAC,KAAK,CAAC,CAAC;IAC3B,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,kDAAkD;IAClD,OAAO,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,QAAQ,GAAG,CAAC,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,OAAO,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAU,EAAE,KAAW;IAC1D,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACpC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAa;IAC/C,IAAI,GAAG,GAAG,SAAS,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAc,EAAE,QAAiB;IAChE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACtE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC;IAED,MAAM,WAAW,GAAG,QAAQ,IAAI,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAE9D,2CAA2C;IAC3C,yDAAyD;IACzD,IAAI,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;IAC7B,IAAI,OAAO,GAAG,SAAS,CAAC;IACxB,IAAI,SAAS,GAAG,WAAW,CAAC;IAE5B,OAAO,SAAS,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,SAAS,GAAW,EAAE,CAAC;QAE7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;gBAC3B,wBAAwB;gBACxB,SAAS,CAAC,IAAI,CAAC,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACnE,CAAC;iBAAM,CAAC;gBACN,2BAA2B;gBAC3B,SAAS,CAAC,IAAI,CAAC,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;QAED,gDAAgD;QAChD,OAAO,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAEjD,OAAO,GAAG,SAAS,CAAC;QACpB,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAc;IAClD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,SAAS,CAAC,CAAC;IACrB,CAAC;IAED,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAW,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEzC,kCAAkC;IAClC,MAAM,SAAS,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClE,CAAC;IAED,0BAA0B;IAC1B,IAAI,UAAU,GAAG,SAAS,CAAC;IAC3B,IAAI,SAAS,GAAG,QAAQ,CAAC;IAEzB,OAAO,SAAS,GAAG,CAAC,EAAE,CAAC;QACrB,IAAI,MAAM,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;QACzC,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,UAAU,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5D,IAAI,CAAC,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC1D,MAAM,EAAE,CAAC;QACX,CAAC;QACD,UAAU,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;QACzC,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,SAAiB,EAAE,QAAgB;IAC9E,MAAM,MAAM,GAAW,EAAE,CAAC;IAC1B,IAAI,GAAG,GAAG,eAAe,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAEhD,OAAO,GAAG,GAAG,CAAC,EAAE,CAAC;QACf,MAAM,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9B,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAU,EACV,SAAiB,EACjB,KAAa,EACb,IAAU,EACV,QAAgB;IAEhB,IAAI,IAAI,GAAG,IAAI,CAAC;IAChB,IAAI,GAAG,GAAG,eAAe,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAEhD,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,yEAAyE;QACzE,oEAAoE;QACpE,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACZ,mDAAmD;YACnD,IAAI,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,oDAAoD;YACpD,IAAI,GAAG,MAAM,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC3C,CAAC;QACD,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,gBAAgB;IACnB,KAAK,CAAS;IACd,SAAS,CAAS;IAClB,cAAc,CAAS;IAE/B,YAAY,SAAsB,EAAE;QAClC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,gBAAgB,CAAC;QAEtD,IAAI,IAAI,CAAC,SAAS,GAAG,gBAAgB,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,yBAAyB,gBAAgB,SAAS,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QAED,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,SAAS,GAAG,gBAAgB,CAAC;IAC1D,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,aAAa,CAAC,IAAgB;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;QACzB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC,CAAC;QAEtD,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,CAAC;gBACP,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,EAAE;aACf,CAAC;QACJ,CAAC;QAED,uBAAuB;QACvB,MAAM,UAAU,GAAW,EAAE,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,CAAC,GAAG,gBAAgB,CAAC;YACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,gBAAgB,EAAE,IAAI,CAAC,CAAC;YACrD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAErC,mCAAmC;YACnC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACpC,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAED,eAAe;QACf,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAEpD,kDAAkD;QAClD,IAAI,WAA+B,CAAC;QACpC,IAAI,IAAI,CAAC,SAAS,GAAG,gBAAgB,EAAE,CAAC;YACtC,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACpE,CAAC;QAED,OAAO;YACL,IAAI;YACJ,IAAI;YACJ,UAAU;YACV,UAAU;YACV,WAAW;SACZ,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,kBAAkB,CAAC,UAAkB,EAAE,SAAiB;QACpE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;QACtE,MAAM,MAAM,GAAW,EAAE,CAAC;QAE1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC;YACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;YACrE,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAEjD,sCAAsC;YACtC,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;YACrE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzB,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,UAAkB,EAAE,IAAY;QACpD,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC;QACrC,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAEpD,IAAI,WAA+B,CAAC;QACpC,IAAI,IAAI,CAAC,SAAS,GAAG,gBAAgB,EAAE,CAAC;YACtC,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACpE,CAAC;QAED,OAAO;YACL,IAAI;YACJ,IAAI;YACJ,UAAU;YACV,UAAU;YACV,WAAW;SACZ,CAAC;IACJ,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IACrB,KAAK,CAAS;IACd,MAAM,CAAa;IACnB,YAAY,GAAW,CAAC,CAAC;IACzB,UAAU,GAAW,EAAE,CAAC;IACxB,SAAS,GAAW,CAAC,CAAC;IAE9B,YAAY,SAAsB,EAAE;QAClC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,gBAAgB,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,IAAgB;QAC3B,IAAI,MAAM,GAAG,CAAC,CAAC;QAEf,OAAO,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,gBAAgB,GAAG,IAAI,CAAC,YAAY,CAAC;YACnD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;YAEtD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;YAC5E,IAAI,CAAC,YAAY,IAAI,OAAO,CAAC;YAC7B,MAAM,IAAI,OAAO,CAAC;YAElB,IAAI,IAAI,CAAC,YAAY,KAAK,gBAAgB,EAAE,CAAC;gBAC3C,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC;IAChC,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,YAAY,KAAK,CAAC;YAAE,OAAO;QAEpC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;QACpD,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ;QACZ,2BAA2B;QAC3B,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAExB,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAE1C,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,CAAC;gBACP,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,EAAE;aACf,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAEzD,OAAO;YACL,IAAI;YACJ,IAAI,EAAE,IAAI,CAAC,SAAS;YACpB,UAAU;YACV,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,IAAI,KAAK;QACP,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM;YAC9B,QAAQ,EAAE,IAAI,CAAC,YAAY;YAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;IACJ,CAAC;CACF"}
|