@qrkit/bc-ur 2.0.0-beta.9-qrkit.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.
- package/LICENSE +21 -0
- package/README.md +996 -0
- package/dist/commonjs/classes/FountainDecoder.d.ts +125 -0
- package/dist/commonjs/classes/FountainDecoder.js +453 -0
- package/dist/commonjs/classes/FountainDecoder.js.map +1 -0
- package/dist/commonjs/classes/FountainEncoder.d.ts +63 -0
- package/dist/commonjs/classes/FountainEncoder.js +168 -0
- package/dist/commonjs/classes/FountainEncoder.js.map +1 -0
- package/dist/commonjs/classes/RegistryItem.d.ts +104 -0
- package/dist/commonjs/classes/RegistryItem.js +172 -0
- package/dist/commonjs/classes/RegistryItem.js.map +1 -0
- package/dist/commonjs/classes/UR.d.ts +89 -0
- package/dist/commonjs/classes/UR.js +243 -0
- package/dist/commonjs/classes/UR.js.map +1 -0
- package/dist/commonjs/classes/UrFountainDecoder.d.ts +15 -0
- package/dist/commonjs/classes/UrFountainDecoder.js +127 -0
- package/dist/commonjs/classes/UrFountainDecoder.js.map +1 -0
- package/dist/commonjs/classes/UrFountainEncoder.d.ts +42 -0
- package/dist/commonjs/classes/UrFountainEncoder.js +92 -0
- package/dist/commonjs/classes/UrFountainEncoder.js.map +1 -0
- package/dist/commonjs/classes/key.helper.d.ts +27 -0
- package/dist/commonjs/classes/key.helper.js +70 -0
- package/dist/commonjs/classes/key.helper.js.map +1 -0
- package/dist/commonjs/encodingMethods/BytewordEncoding.d.ts +11 -0
- package/dist/commonjs/encodingMethods/BytewordEncoding.js +23 -0
- package/dist/commonjs/encodingMethods/BytewordEncoding.js.map +1 -0
- package/dist/commonjs/encodingMethods/CborEncoding.d.ts +44 -0
- package/dist/commonjs/encodingMethods/CborEncoding.js +151 -0
- package/dist/commonjs/encodingMethods/CborEncoding.js.map +1 -0
- package/dist/commonjs/encodingMethods/HexEncoding.d.ts +8 -0
- package/dist/commonjs/encodingMethods/HexEncoding.js +24 -0
- package/dist/commonjs/encodingMethods/HexEncoding.js.map +1 -0
- package/dist/commonjs/encodingMethods/UrEncoding.d.ts +10 -0
- package/dist/commonjs/encodingMethods/UrEncoding.js +19 -0
- package/dist/commonjs/encodingMethods/UrEncoding.js.map +1 -0
- package/dist/commonjs/encodingMethods/bytewords.d.ts +27 -0
- package/dist/commonjs/encodingMethods/bytewords.js +152 -0
- package/dist/commonjs/encodingMethods/bytewords.js.map +1 -0
- package/dist/commonjs/encodingMethods/index.d.ts +19 -0
- package/dist/commonjs/encodingMethods/index.js +27 -0
- package/dist/commonjs/encodingMethods/index.js.map +1 -0
- package/dist/commonjs/encodingMethods/pipeline.d.ts +19 -0
- package/dist/commonjs/encodingMethods/pipeline.js +80 -0
- package/dist/commonjs/encodingMethods/pipeline.js.map +1 -0
- package/dist/commonjs/enums/EncodingMethodName.d.ts +10 -0
- package/dist/commonjs/enums/EncodingMethodName.js +15 -0
- package/dist/commonjs/enums/EncodingMethodName.js.map +1 -0
- package/dist/commonjs/errors.d.ts +15 -0
- package/dist/commonjs/errors.js +39 -0
- package/dist/commonjs/errors.js.map +1 -0
- package/dist/commonjs/helpers/aliasSampling.d.ts +6 -0
- package/dist/commonjs/helpers/aliasSampling.js +73 -0
- package/dist/commonjs/helpers/aliasSampling.js.map +1 -0
- package/dist/commonjs/helpers/crc32.d.ts +1 -0
- package/dist/commonjs/helpers/crc32.js +19 -0
- package/dist/commonjs/helpers/crc32.js.map +1 -0
- package/dist/commonjs/helpers/fountainUtils.d.ts +40 -0
- package/dist/commonjs/helpers/fountainUtils.js +124 -0
- package/dist/commonjs/helpers/fountainUtils.js.map +1 -0
- package/dist/commonjs/helpers/sha256.d.ts +1 -0
- package/dist/commonjs/helpers/sha256.js +78 -0
- package/dist/commonjs/helpers/sha256.js.map +1 -0
- package/dist/commonjs/helpers/type.helper.d.ts +3 -0
- package/dist/commonjs/helpers/type.helper.js +3 -0
- package/dist/commonjs/helpers/type.helper.js.map +1 -0
- package/dist/commonjs/helpers/uintArrayHelper.d.ts +287 -0
- package/dist/commonjs/helpers/uintArrayHelper.js +545 -0
- package/dist/commonjs/helpers/uintArrayHelper.js.map +1 -0
- package/dist/commonjs/helpers/utils.d.ts +55 -0
- package/dist/commonjs/helpers/utils.js +123 -0
- package/dist/commonjs/helpers/utils.js.map +1 -0
- package/dist/commonjs/index-react-native.d.ts +9 -0
- package/dist/commonjs/index-react-native.js +15 -0
- package/dist/commonjs/index-react-native.js.map +1 -0
- package/dist/commonjs/index.d.ts +21 -0
- package/dist/commonjs/index.js +34 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/interfaces/IEncodingMethod.d.ts +9 -0
- package/dist/commonjs/interfaces/IEncodingMethod.js +3 -0
- package/dist/commonjs/interfaces/IEncodingMethod.js.map +1 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/commonjs/registry.d.ts +26 -0
- package/dist/commonjs/registry.js +118 -0
- package/dist/commonjs/registry.js.map +1 -0
- package/dist/commonjs/test.utils.d.ts +31 -0
- package/dist/commonjs/test.utils.js +88 -0
- package/dist/commonjs/test.utils.js.map +1 -0
- package/dist/commonjs/wrappers/cbor2-cjs.cjs.map +1 -0
- package/dist/commonjs/wrappers/cbor2.d.ts +2 -0
- package/dist/commonjs/wrappers/cbor2.js +14 -0
- package/dist/commonjs/wrappers/cbor2Wrapper.d.ts +14 -0
- package/dist/commonjs/wrappers/cbor2Wrapper.js +49 -0
- package/dist/commonjs/wrappers/cbor2Wrapper.js.map +1 -0
- package/dist/commonjs/xoshiro.d.ts +12 -0
- package/dist/commonjs/xoshiro.js +52 -0
- package/dist/commonjs/xoshiro.js.map +1 -0
- package/dist/esm/classes/FountainDecoder.d.ts +125 -0
- package/dist/esm/classes/FountainDecoder.js +447 -0
- package/dist/esm/classes/FountainDecoder.js.map +1 -0
- package/dist/esm/classes/FountainEncoder.d.ts +63 -0
- package/dist/esm/classes/FountainEncoder.js +164 -0
- package/dist/esm/classes/FountainEncoder.js.map +1 -0
- package/dist/esm/classes/RegistryItem.d.ts +104 -0
- package/dist/esm/classes/RegistryItem.js +166 -0
- package/dist/esm/classes/RegistryItem.js.map +1 -0
- package/dist/esm/classes/UR.d.ts +89 -0
- package/dist/esm/classes/UR.js +239 -0
- package/dist/esm/classes/UR.js.map +1 -0
- package/dist/esm/classes/UrFountainDecoder.d.ts +15 -0
- package/dist/esm/classes/UrFountainDecoder.js +123 -0
- package/dist/esm/classes/UrFountainDecoder.js.map +1 -0
- package/dist/esm/classes/UrFountainEncoder.d.ts +42 -0
- package/dist/esm/classes/UrFountainEncoder.js +88 -0
- package/dist/esm/classes/UrFountainEncoder.js.map +1 -0
- package/dist/esm/classes/key.helper.d.ts +27 -0
- package/dist/esm/classes/key.helper.js +66 -0
- package/dist/esm/classes/key.helper.js.map +1 -0
- package/dist/esm/encodingMethods/BytewordEncoding.d.ts +11 -0
- package/dist/esm/encodingMethods/BytewordEncoding.js +19 -0
- package/dist/esm/encodingMethods/BytewordEncoding.js.map +1 -0
- package/dist/esm/encodingMethods/CborEncoding.d.ts +44 -0
- package/dist/esm/encodingMethods/CborEncoding.js +147 -0
- package/dist/esm/encodingMethods/CborEncoding.js.map +1 -0
- package/dist/esm/encodingMethods/HexEncoding.d.ts +8 -0
- package/dist/esm/encodingMethods/HexEncoding.js +20 -0
- package/dist/esm/encodingMethods/HexEncoding.js.map +1 -0
- package/dist/esm/encodingMethods/UrEncoding.d.ts +10 -0
- package/dist/esm/encodingMethods/UrEncoding.js +15 -0
- package/dist/esm/encodingMethods/UrEncoding.js.map +1 -0
- package/dist/esm/encodingMethods/bytewords.d.ts +27 -0
- package/dist/esm/encodingMethods/bytewords.js +147 -0
- package/dist/esm/encodingMethods/bytewords.js.map +1 -0
- package/dist/esm/encodingMethods/index.d.ts +19 -0
- package/dist/esm/encodingMethods/index.js +24 -0
- package/dist/esm/encodingMethods/index.js.map +1 -0
- package/dist/esm/encodingMethods/pipeline.d.ts +19 -0
- package/dist/esm/encodingMethods/pipeline.js +76 -0
- package/dist/esm/encodingMethods/pipeline.js.map +1 -0
- package/dist/esm/enums/EncodingMethodName.d.ts +10 -0
- package/dist/esm/enums/EncodingMethodName.js +12 -0
- package/dist/esm/enums/EncodingMethodName.js.map +1 -0
- package/dist/esm/errors.d.ts +15 -0
- package/dist/esm/errors.js +31 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/helpers/aliasSampling.d.ts +6 -0
- package/dist/esm/helpers/aliasSampling.js +70 -0
- package/dist/esm/helpers/aliasSampling.js.map +1 -0
- package/dist/esm/helpers/crc32.d.ts +1 -0
- package/dist/esm/helpers/crc32.js +16 -0
- package/dist/esm/helpers/crc32.js.map +1 -0
- package/dist/esm/helpers/fountainUtils.d.ts +40 -0
- package/dist/esm/helpers/fountainUtils.js +114 -0
- package/dist/esm/helpers/fountainUtils.js.map +1 -0
- package/dist/esm/helpers/sha256.d.ts +1 -0
- package/dist/esm/helpers/sha256.js +75 -0
- package/dist/esm/helpers/sha256.js.map +1 -0
- package/dist/esm/helpers/type.helper.d.ts +3 -0
- package/dist/esm/helpers/type.helper.js +2 -0
- package/dist/esm/helpers/type.helper.js.map +1 -0
- package/dist/esm/helpers/uintArrayHelper.d.ts +287 -0
- package/dist/esm/helpers/uintArrayHelper.js +526 -0
- package/dist/esm/helpers/uintArrayHelper.js.map +1 -0
- package/dist/esm/helpers/utils.d.ts +55 -0
- package/dist/esm/helpers/utils.js +102 -0
- package/dist/esm/helpers/utils.js.map +1 -0
- package/dist/esm/index-react-native.d.ts +9 -0
- package/dist/esm/index-react-native.js +12 -0
- package/dist/esm/index-react-native.js.map +1 -0
- package/dist/esm/index.d.ts +21 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/interfaces/IEncodingMethod.d.ts +9 -0
- package/dist/esm/interfaces/IEncodingMethod.js +2 -0
- package/dist/esm/interfaces/IEncodingMethod.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/registry.d.ts +26 -0
- package/dist/esm/registry.js +114 -0
- package/dist/esm/registry.js.map +1 -0
- package/dist/esm/test.utils.d.ts +31 -0
- package/dist/esm/test.utils.js +83 -0
- package/dist/esm/test.utils.js.map +1 -0
- package/dist/esm/wrappers/cbor2-deno.d.mts +2 -0
- package/dist/esm/wrappers/cbor2-deno.mjs +5 -0
- package/dist/esm/wrappers/cbor2-deno.mjs.map +1 -0
- package/dist/esm/wrappers/cbor2.d.ts +2 -0
- package/dist/esm/wrappers/cbor2.js +5 -0
- package/dist/esm/wrappers/cbor2.js.map +1 -0
- package/dist/esm/wrappers/cbor2Wrapper.d.ts +5 -0
- package/dist/esm/wrappers/cbor2Wrapper.js +6 -0
- package/dist/esm/wrappers/cbor2Wrapper.js.map +1 -0
- package/dist/esm/xoshiro.d.ts +12 -0
- package/dist/esm/xoshiro.js +47 -0
- package/dist/esm/xoshiro.js.map +1 -0
- package/dist/web/bytewords.js +335 -0
- package/index.html +98 -0
- package/package.json +94 -0
- package/src/classes/FountainDecoder.ts +539 -0
- package/src/classes/FountainEncoder.ts +211 -0
- package/src/classes/RegistryItem.ts +240 -0
- package/src/classes/UR.ts +308 -0
- package/src/classes/UrFountainDecoder.ts +142 -0
- package/src/classes/UrFountainEncoder.ts +103 -0
- package/src/classes/key.helper.ts +85 -0
- package/src/encodingMethods/BytewordEncoding.ts +23 -0
- package/src/encodingMethods/CborEncoding.ts +196 -0
- package/src/encodingMethods/HexEncoding.ts +23 -0
- package/src/encodingMethods/UrEncoding.ts +19 -0
- package/src/encodingMethods/bytewords.ts +215 -0
- package/src/encodingMethods/index.ts +26 -0
- package/src/encodingMethods/pipeline.ts +103 -0
- package/src/enums/EncodingMethodName.ts +10 -0
- package/src/errors.ts +34 -0
- package/src/helpers/aliasSampling.ts +87 -0
- package/src/helpers/crc32.ts +19 -0
- package/src/helpers/fountainUtils.ts +157 -0
- package/src/helpers/sha256.ts +88 -0
- package/src/helpers/type.helper.ts +1 -0
- package/src/helpers/uintArrayHelper.ts +611 -0
- package/src/helpers/utils.ts +135 -0
- package/src/index-react-native.ts +12 -0
- package/src/index.ts +44 -0
- package/src/interfaces/IEncodingMethod.ts +10 -0
- package/src/registry.ts +146 -0
- package/src/test.utils.ts +105 -0
- package/src/wrappers/cbor2-cjs.cts +6 -0
- package/src/wrappers/cbor2-deno.mts +6 -0
- package/src/wrappers/cbor2.ts +7 -0
- package/src/wrappers/cbor2Wrapper.ts +14 -0
- package/src/xoshiro.ts +66 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { chooseFragments, findNominalFragmentLength, mixFragments, partitionMessage } from "../helpers/fountainUtils.js";
|
|
2
|
+
import { toUint32, getCRC } from "../helpers/utils.js";
|
|
3
|
+
import { CborEncoding } from "../encodingMethods/CborEncoding.js";
|
|
4
|
+
|
|
5
|
+
const cborEncoder = new CborEncoding();
|
|
6
|
+
|
|
7
|
+
/** [seqNum, seqLength, messageLength, checksum, fragment] */
|
|
8
|
+
export type IMultipartUrPayload = [number, number, number, number, Uint8Array];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Encode data on the fly. This encoder uses an internal state to keep generating ur fragments of the payload.
|
|
12
|
+
*/
|
|
13
|
+
export class FountainEncoder {
|
|
14
|
+
public fragmentLenghtFinder = findNominalFragmentLength;
|
|
15
|
+
|
|
16
|
+
/** Total data size of the input message */
|
|
17
|
+
public _messageLength: number;
|
|
18
|
+
/** Maximum data size in the fragment */
|
|
19
|
+
protected _maxFragmentLength: number;
|
|
20
|
+
/** Minumum data size in the fragment */
|
|
21
|
+
protected _minFragmentLength: number;
|
|
22
|
+
/** Calculated data size in the fragment */
|
|
23
|
+
public _nominalFragmentLength: number;
|
|
24
|
+
/** Array of pure fragments (without any fountain encoded) */
|
|
25
|
+
public _pureFragments: Uint8Array[];
|
|
26
|
+
/** Current index of the fragment start from 1 */
|
|
27
|
+
protected _seqNum: number;
|
|
28
|
+
/** Checksum of the original data */
|
|
29
|
+
protected _checksum: number;
|
|
30
|
+
/** Original Input data as UR */
|
|
31
|
+
protected _input: Uint8Array;
|
|
32
|
+
|
|
33
|
+
constructor(
|
|
34
|
+
input: Uint8Array,
|
|
35
|
+
maxFragmentLength: number = 100,
|
|
36
|
+
minFragmentLength: number = 10,
|
|
37
|
+
firstSeqNum: number = 0
|
|
38
|
+
) {
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
// Validate the input
|
|
42
|
+
if (!input) {
|
|
43
|
+
throw new Error("input should be defined");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if(!(input instanceof Uint8Array)) {
|
|
47
|
+
throw new Error("input should be Uint8Array")
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (typeof maxFragmentLength !== "number") {
|
|
51
|
+
throw new Error("maxFragmentLength should be a number");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (typeof minFragmentLength !== "number") {
|
|
55
|
+
throw new Error("minFragmentLength should be a number");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (typeof firstSeqNum !== "number") {
|
|
59
|
+
throw new Error("firstSeqNum should be a number");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (maxFragmentLength < 1) {
|
|
63
|
+
throw new Error("maxFragmentLength should be > 0");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if(maxFragmentLength < minFragmentLength) {
|
|
67
|
+
throw new Error("maxFragmentLength should be >= minFragmentLength");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
this._input = input;
|
|
72
|
+
this._maxFragmentLength = maxFragmentLength;
|
|
73
|
+
this._minFragmentLength = minFragmentLength;
|
|
74
|
+
this._seqNum = toUint32(firstSeqNum);
|
|
75
|
+
|
|
76
|
+
// Get the length of the message
|
|
77
|
+
this._messageLength = input.length;
|
|
78
|
+
|
|
79
|
+
// Check if message is less than maxFragmentLength, then return the message as a single fragment
|
|
80
|
+
if (input.length <= maxFragmentLength) {
|
|
81
|
+
this._pureFragments = [input];
|
|
82
|
+
this._nominalFragmentLength = this._messageLength;
|
|
83
|
+
}
|
|
84
|
+
// Otherwise calciulate the nominal fragment length and neseccary fragments
|
|
85
|
+
else {
|
|
86
|
+
// Check for the nominal length of a fragment.
|
|
87
|
+
const fragmentLength = this.fragmentLenghtFinder(input.length, maxFragmentLength, minFragmentLength);
|
|
88
|
+
this._nominalFragmentLength = fragmentLength;
|
|
89
|
+
// Calculate the checksum of the message
|
|
90
|
+
this._checksum = getCRC(input);
|
|
91
|
+
// Split up the message buffer in an array of buffers, by the nominal length
|
|
92
|
+
this._pureFragments = partitionMessage(input, fragmentLength);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
setFragmentLengthFinder(fn: typeof findNominalFragmentLength) {
|
|
97
|
+
this.fragmentLenghtFinder = fn;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Return all the fragments based on the fountain ratio at once as an array of Uint8Arrays.
|
|
102
|
+
* @param fountainRatio The ratio of the fountain fragments to the pure fragments. Default is 0.
|
|
103
|
+
* @returns
|
|
104
|
+
*/
|
|
105
|
+
getAllParts(fountainRatio: number = 0): Uint8Array[] {
|
|
106
|
+
// First check if the input is a single fragment
|
|
107
|
+
if (this.isSinglePart()) {
|
|
108
|
+
return [this._input];
|
|
109
|
+
}
|
|
110
|
+
// Ceil to always get an integer
|
|
111
|
+
const numberofParts = Math.ceil(this.getPureFragmentCount() * (1 + fountainRatio));
|
|
112
|
+
// Save state
|
|
113
|
+
const oldSeqNum = this._seqNum;
|
|
114
|
+
// Reset state to start generating fragments from the beginning
|
|
115
|
+
this._seqNum = 0;
|
|
116
|
+
// Generate fragments
|
|
117
|
+
let fragments = []
|
|
118
|
+
for (let i = 0; i < numberofParts; i++) {
|
|
119
|
+
fragments.push(this.nextPart());
|
|
120
|
+
}
|
|
121
|
+
// Bring state back
|
|
122
|
+
this._seqNum = oldSeqNum;
|
|
123
|
+
return fragments;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Encode fragment with correct CBOR structure
|
|
127
|
+
protected encodeFragment(seqNum:number, fragment:Uint8Array): Uint8Array {
|
|
128
|
+
// Shape for the CBOR payload
|
|
129
|
+
const payload: IMultipartUrPayload = [seqNum, this._pureFragments.length, this._messageLength, this._checksum, fragment];
|
|
130
|
+
const encodedFragment = cborEncoder.encode(payload);
|
|
131
|
+
|
|
132
|
+
return encodedFragment;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Reset the state of the encoder to start generating fragments from the beginning.
|
|
137
|
+
*/
|
|
138
|
+
public reset() {
|
|
139
|
+
this._seqNum = 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Checks if all the pure fragments (full payload data) for this ur is generated.
|
|
145
|
+
* @returns boolean indicating if generated fragments have included all the data.
|
|
146
|
+
*/
|
|
147
|
+
public isComplete(): boolean {
|
|
148
|
+
return this._seqNum >= this.getPureFragmentCount();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Checks if there is only one fragment generated for the ur.
|
|
153
|
+
* @returns boolean if the ur payload is contained in one fragment.
|
|
154
|
+
*/
|
|
155
|
+
public isSinglePart(): boolean {
|
|
156
|
+
return this.getPureFragmentCount() === 1;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Gets the count of the "pure" fragments. These are fragments where the data is not mixed.
|
|
161
|
+
* @returns The count of the "pure" fragments.
|
|
162
|
+
*/
|
|
163
|
+
public getPureFragmentCount(): number {
|
|
164
|
+
return this._pureFragments.length;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get the pure fragments of the ur.
|
|
169
|
+
* @returns the pure fragments of the ur as an array of Uint8Arrays.
|
|
170
|
+
*/
|
|
171
|
+
public getPureFragments(): Uint8Array[] {
|
|
172
|
+
return this._pureFragments;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Give the 'next' fragment for the ur for which the fountainEncoder was created.
|
|
177
|
+
* @returns the 'next' fragment, represented as a Ur multipart string.
|
|
178
|
+
*/
|
|
179
|
+
public nextPart(): Uint8Array {
|
|
180
|
+
this._seqNum = toUint32(this._seqNum + 1);
|
|
181
|
+
|
|
182
|
+
// when the seqnum restarts because of a number bigger than Uint32, we need to make sure to skip 0 to prevent invalid Multipart URs.
|
|
183
|
+
if (this._seqNum === 0) {
|
|
184
|
+
this._seqNum = toUint32(this._seqNum + 1);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// If its single part, return the original input
|
|
188
|
+
if (this.isSinglePart()) {
|
|
189
|
+
return this._input;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// For the first seqNum of the pure fragments, return the pure fragment
|
|
193
|
+
if (!this.isComplete()) {
|
|
194
|
+
return this.encodeFragment(this._seqNum, this._pureFragments[this._seqNum - 1]);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// For the fountain fragments, mix the fragments
|
|
198
|
+
const indexes = chooseFragments(
|
|
199
|
+
this._seqNum,
|
|
200
|
+
this._pureFragments.length,
|
|
201
|
+
this._checksum
|
|
202
|
+
);
|
|
203
|
+
const mixed = mixFragments(
|
|
204
|
+
indexes,
|
|
205
|
+
this._pureFragments,
|
|
206
|
+
this._nominalFragmentLength
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
return this.encodeFragment(this._seqNum, mixed);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { UR } from "./UR.js";
|
|
2
|
+
import { encodeKeys, decodeKeys, IKeyMap } from "./key.helper.js";
|
|
3
|
+
|
|
4
|
+
// Define the symbol
|
|
5
|
+
export const registryItemSymbol = Symbol.for("RegistryItemBase");
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Static interface that RegistryItem classes should implement
|
|
9
|
+
*/
|
|
10
|
+
export interface IRegistryType {
|
|
11
|
+
/**
|
|
12
|
+
* Cbor Tags
|
|
13
|
+
* Finalized versions defined in: https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
|
|
14
|
+
*/
|
|
15
|
+
tag: number;
|
|
16
|
+
/**
|
|
17
|
+
* Uniform Resource ID
|
|
18
|
+
*
|
|
19
|
+
* Links:
|
|
20
|
+
* - https://developer.blockchaincommons.com/ur/
|
|
21
|
+
* - https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-006-urtypes.md
|
|
22
|
+
* - https://github.com/ngraveio/Research
|
|
23
|
+
* - https://github.com/KeystoneHQ/Keystone-developer-hub/tree/main/research
|
|
24
|
+
*
|
|
25
|
+
*/
|
|
26
|
+
URType: string;
|
|
27
|
+
/** CDDL definition for CBOR encoding */
|
|
28
|
+
CDDL: string;
|
|
29
|
+
/** Key name to key in integer map for smaller encoded data size */
|
|
30
|
+
keyMap?: IKeyMap;
|
|
31
|
+
/** allow the keys that are not explicitely defined in the keyMap */
|
|
32
|
+
allowKeysNotInMap?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export abstract class RegistryItemBase {
|
|
36
|
+
readonly type: IRegistryType;
|
|
37
|
+
/** If CDDL contains keys as numbers, map them to their respective values */
|
|
38
|
+
keyMap: IKeyMap;
|
|
39
|
+
/** Data that our item contains */
|
|
40
|
+
// TODO: should we force this to be a map? It is much safer that way for injection attacks
|
|
41
|
+
data: any;
|
|
42
|
+
static allowKeysNotInMap: any;
|
|
43
|
+
|
|
44
|
+
constructor(registryType: IRegistryType, data?: any, keyMap?: IKeyMap) {
|
|
45
|
+
this.type = registryType;
|
|
46
|
+
this.keyMap = keyMap;
|
|
47
|
+
|
|
48
|
+
// Verify input
|
|
49
|
+
const { valid, reasons } = this.verifyInput(data);
|
|
50
|
+
if (!valid) {
|
|
51
|
+
throw new Error(`Invalid input: ${reasons?.map((r) => r.message).join(", ")}`);
|
|
52
|
+
}
|
|
53
|
+
this.data = data;
|
|
54
|
+
(this as any)[registryItemSymbol] = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Verify the input data
|
|
59
|
+
*
|
|
60
|
+
* @param input
|
|
61
|
+
*/
|
|
62
|
+
verifyInput(input: any): { valid: boolean; reasons?: Error[] } {
|
|
63
|
+
// This should be implemented by the child class
|
|
64
|
+
return {
|
|
65
|
+
valid: true,
|
|
66
|
+
reasons: undefined,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
toString(): string {
|
|
71
|
+
return `${this.type.URType}[${this.type.tag}](${JSON.stringify(this.data)})`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
toJSON() {
|
|
75
|
+
// TODO: if there is any registry item in the data (could be nested or in array), we should call toJSON on them as well
|
|
76
|
+
return {
|
|
77
|
+
type: this.type.URType,
|
|
78
|
+
tag: this.type.tag,
|
|
79
|
+
...this.data,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Preprocess the data before encoding into CBOR Tagged instance
|
|
85
|
+
*
|
|
86
|
+
* @param data, data before keymap conversion, if left empty, it will use the this.data property
|
|
87
|
+
*/
|
|
88
|
+
preCBOR(data = this.data) {
|
|
89
|
+
// If key-map exists, convert keys to integers
|
|
90
|
+
if (this.keyMap) {
|
|
91
|
+
const allowKeysNotInMap = (this.constructor as typeof RegistryItemBase).allowKeysNotInMap;
|
|
92
|
+
return encodeKeys(data, this.keyMap, allowKeysNotInMap);
|
|
93
|
+
}
|
|
94
|
+
return data;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Called by the CBOR encoder for encoding the data
|
|
99
|
+
*
|
|
100
|
+
* [CBOR Docs](https://github.com/hildjj/cbor2?tab=readme-ov-file#tocbor-method)
|
|
101
|
+
*
|
|
102
|
+
* This is the easiest approach, if you can modify the class being encoded.
|
|
103
|
+
* Add a toCBOR() method to your class, which should return a two-element array containing the tag number and data item that encodes your class.
|
|
104
|
+
* If the tag number is NaN, no tag will be written. If you return undefined, nothing will be written.
|
|
105
|
+
* In this case you will likely write custom bytes to the Writer instance that is passed in,
|
|
106
|
+
* perhaps using the encoding options.
|
|
107
|
+
*
|
|
108
|
+
* @param encoder
|
|
109
|
+
* @returns
|
|
110
|
+
*/
|
|
111
|
+
toCBOR(_writer, _options) {
|
|
112
|
+
const processed = this.preCBOR(this.data);
|
|
113
|
+
let tag = this.type.tag;
|
|
114
|
+
// TODO: find a better way to ignore top level tag on encoder
|
|
115
|
+
if (_options?.ignoreTopLevelTag) {
|
|
116
|
+
tag = NaN; // Do not tag the top level item
|
|
117
|
+
// Set it back to false for child items
|
|
118
|
+
_options.ignoreTopLevelTag = false;
|
|
119
|
+
}
|
|
120
|
+
return [tag, processed];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
toUr() {
|
|
124
|
+
return new UR(this);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
toHex() {
|
|
128
|
+
return this.toUr().getPayloadHex();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
toBytes() {
|
|
132
|
+
return this.toUr().getPayloadCbor();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public encodeKeys = encodeKeys;
|
|
136
|
+
public decodeKeys = decodeKeys;
|
|
137
|
+
|
|
138
|
+
// Custom inspection method for Node.js
|
|
139
|
+
public [Symbol.for("nodejs.util.inspect.custom")](
|
|
140
|
+
_depth: number,
|
|
141
|
+
inspectOptions: object,
|
|
142
|
+
inspect: (val: unknown, opts: object) => unknown
|
|
143
|
+
): string {
|
|
144
|
+
return `${this.type.URType}[${this.type.tag}](${inspect(this.data, inspectOptions)})`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Factory function to create a new RegistryItem class
|
|
150
|
+
*
|
|
151
|
+
* It injects static properties to the class and does preprocessing when needed
|
|
152
|
+
*
|
|
153
|
+
* @param input
|
|
154
|
+
* @returns
|
|
155
|
+
*/
|
|
156
|
+
export function registryItemFactory<T extends RegistryItemBase>(input: IRegistryType): RegistryItemClass<T> {
|
|
157
|
+
const { tag, URType, CDDL, keyMap, allowKeysNotInMap = true } = input;
|
|
158
|
+
const _keyMap = keyMap;
|
|
159
|
+
|
|
160
|
+
return class extends RegistryItemBase {
|
|
161
|
+
// Add static properties to the class
|
|
162
|
+
static tag: number = tag;
|
|
163
|
+
static URType: string = URType;
|
|
164
|
+
static CDDL: string = CDDL;
|
|
165
|
+
static keyMap: IKeyMap = _keyMap;
|
|
166
|
+
static allowKeysNotInMap: boolean = allowKeysNotInMap;
|
|
167
|
+
|
|
168
|
+
// Initiate base class with the values
|
|
169
|
+
constructor(data?: any, keyMap: IKeyMap = _keyMap) {
|
|
170
|
+
super(input, data, keyMap);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Post process the data after decoding CBOR
|
|
175
|
+
*/
|
|
176
|
+
static postCBOR(val: any, allowKeysNotInMapOverwrite?: boolean) {
|
|
177
|
+
// If key-map exists, convert integer keys back to string keys
|
|
178
|
+
if (keyMap) {
|
|
179
|
+
return decodeKeys(val, keyMap, allowKeysNotInMapOverwrite ?? allowKeysNotInMap);
|
|
180
|
+
}
|
|
181
|
+
return val;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
static fromUr(ur: UR | string): T {
|
|
185
|
+
const urObj = typeof ur === "string" ? UR.fromString(ur) : ur;
|
|
186
|
+
const decoded = urObj.decode() as unknown;
|
|
187
|
+
|
|
188
|
+
return decoded as T;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static fromHex(hex: string): T {
|
|
192
|
+
const ur = UR.fromHex({ type: URType, payload: hex });
|
|
193
|
+
const decoded = ur.decode() as unknown;
|
|
194
|
+
|
|
195
|
+
return decoded as T;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Static method to create an instance from CBOR DataItem data.
|
|
200
|
+
* It processes the raw CBOR data if needed and returns a new instance of the class.
|
|
201
|
+
*/
|
|
202
|
+
static fromCBORData(val: any, allowKeysNotInMap?: boolean, tagged?: any) {
|
|
203
|
+
// Do some post processing data coming from the cbor decoder
|
|
204
|
+
const data = this.postCBOR(val, allowKeysNotInMap);
|
|
205
|
+
|
|
206
|
+
// Return an instance of the generated class
|
|
207
|
+
return new this(data);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
} as RegistryItemClass<T>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Helper type to define the RegistryItem class with custom constructors and static properties
|
|
214
|
+
export type RegistryItemClass<T extends RegistryItemBase = RegistryItemBase> = {
|
|
215
|
+
new (...args: any[]): T;
|
|
216
|
+
tag: number;
|
|
217
|
+
URType: string;
|
|
218
|
+
CDDL: string;
|
|
219
|
+
keyMap?: IKeyMap;
|
|
220
|
+
allowKeysNotInMap: boolean;
|
|
221
|
+
postCBOR(val: any, allowKeysNotInMapOverwrite?: boolean): any;
|
|
222
|
+
fromCBORData(val: any, allowKeysNotInMap?: boolean, tagged?: any): T;
|
|
223
|
+
fromUr(ur: UR | string): T;
|
|
224
|
+
fromHex(hex: string): T;
|
|
225
|
+
};
|
|
226
|
+
export type RegistryItem = InstanceType<RegistryItemClass>;
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Function to check if an object is an instance of RegistryItemBase or its subclasses
|
|
230
|
+
* @param obj - The object to check
|
|
231
|
+
* @returns true if the object is an instance of RegistryItemBase or its subclasses
|
|
232
|
+
*/
|
|
233
|
+
export function isRegistryItem(obj: any): obj is RegistryItem {
|
|
234
|
+
return (
|
|
235
|
+
obj instanceof RegistryItemBase ||
|
|
236
|
+
(obj && obj[registryItemSymbol] === true) ||
|
|
237
|
+
//(obj && typeof obj.toCBOR === 'function' && typeof obj.toUr === 'function' && typeof obj.toHex === 'function' && typeof obj.toBytes === 'function' && obj.type !== undefined && obj.data !== undefined)
|
|
238
|
+
(obj && typeof obj.toCBOR === 'function' && typeof obj.toUr === 'function' && typeof obj.toHex === 'function' && obj.type !== undefined && obj.data !== undefined)
|
|
239
|
+
);
|
|
240
|
+
}
|