@bcts/uniform-resources 1.0.0-alpha.12 → 1.0.0-alpha.14
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/dist/index.cjs +191 -213
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -249
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +13 -249
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +192 -215
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +192 -200
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -5
- package/src/error.ts +11 -0
- package/src/fountain.ts +15 -35
- package/src/index.ts +5 -24
- package/src/multipart-decoder.ts +30 -36
- package/src/multipart-encoder.ts +6 -46
- package/src/utils.ts +7 -10
- package/src/xoshiro.ts +170 -76
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/error.ts","../src/ur-type.ts","../src/ur.ts","../src/ur-encodable.ts","../src/ur-decodable.ts","../src/ur-codable.ts","../src/multipart-encoder.ts","../src/multipart-decoder.ts","../src/
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/error.ts","../src/ur-type.ts","../src/ur.ts","../src/ur-encodable.ts","../src/ur-decodable.ts","../src/ur-codable.ts","../src/multipart-encoder.ts","../src/multipart-decoder.ts","../src/utils.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.iife.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var bctsUniformResources = (function(exports) {
|
|
1
|
+
var bctsUniformResources = (function(exports, _bcts_crypto) {
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
//#region ../dcbor/dist/index.mjs
|
|
@@ -4900,7 +4900,13 @@ var bctsUniformResources = (function(exports) {
|
|
|
4900
4900
|
/**
|
|
4901
4901
|
* Insert a tag into the registry.
|
|
4902
4902
|
*
|
|
4903
|
-
*
|
|
4903
|
+
* Matches Rust's TagsStore::insert() behavior:
|
|
4904
|
+
* - Throws if the tag name is undefined or empty
|
|
4905
|
+
* - Throws if a tag with the same value exists with a different name
|
|
4906
|
+
* - Allows re-registering the same tag value with the same name
|
|
4907
|
+
*
|
|
4908
|
+
* @param tag - The tag to register (must have a non-empty name)
|
|
4909
|
+
* @throws Error if tag has no name, empty name, or conflicts with existing registration
|
|
4904
4910
|
*
|
|
4905
4911
|
* @example
|
|
4906
4912
|
* ```typescript
|
|
@@ -4909,9 +4915,13 @@ var bctsUniformResources = (function(exports) {
|
|
|
4909
4915
|
* ```
|
|
4910
4916
|
*/
|
|
4911
4917
|
insert(tag) {
|
|
4918
|
+
const name = tag.name;
|
|
4919
|
+
if (name === void 0 || name === "") throw new Error(`Tag ${tag.value} must have a non-empty name`);
|
|
4912
4920
|
const key = this.#valueKey(tag.value);
|
|
4921
|
+
const existing = this.#tagsByValue.get(key);
|
|
4922
|
+
if (existing?.name !== void 0 && existing.name !== name) throw new Error(`Attempt to register tag: ${tag.value} '${existing.name}' with different name: '${name}'`);
|
|
4913
4923
|
this.#tagsByValue.set(key, tag);
|
|
4914
|
-
|
|
4924
|
+
this.#tagsByName.set(name, tag);
|
|
4915
4925
|
}
|
|
4916
4926
|
/**
|
|
4917
4927
|
* Insert multiple tags into the registry.
|
|
@@ -4949,21 +4959,6 @@ var bctsUniformResources = (function(exports) {
|
|
|
4949
4959
|
const key = this.#valueKey(tagValue$1);
|
|
4950
4960
|
this.#summarizers.set(key, summarizer);
|
|
4951
4961
|
}
|
|
4952
|
-
/**
|
|
4953
|
-
* Remove a tag from the registry.
|
|
4954
|
-
*
|
|
4955
|
-
* @param tagValue - The numeric tag value to remove
|
|
4956
|
-
* @returns true if a tag was removed, false otherwise
|
|
4957
|
-
*/
|
|
4958
|
-
remove(tagValue$1) {
|
|
4959
|
-
const key = this.#valueKey(tagValue$1);
|
|
4960
|
-
const tag = this.#tagsByValue.get(key);
|
|
4961
|
-
if (tag === void 0) return false;
|
|
4962
|
-
this.#tagsByValue.delete(key);
|
|
4963
|
-
if (tag.name !== void 0) this.#tagsByName.delete(tag.name);
|
|
4964
|
-
this.#summarizers.delete(key);
|
|
4965
|
-
return true;
|
|
4966
|
-
}
|
|
4967
4962
|
assignedNameForTag(tag) {
|
|
4968
4963
|
const key = this.#valueKey(tag.value);
|
|
4969
4964
|
return this.#tagsByValue.get(key)?.name;
|
|
@@ -4987,30 +4982,6 @@ var bctsUniformResources = (function(exports) {
|
|
|
4987
4982
|
return this.#summarizers.get(key);
|
|
4988
4983
|
}
|
|
4989
4984
|
/**
|
|
4990
|
-
* Get all registered tags.
|
|
4991
|
-
*
|
|
4992
|
-
* @returns Array of all registered tags
|
|
4993
|
-
*/
|
|
4994
|
-
getAllTags() {
|
|
4995
|
-
return Array.from(this.#tagsByValue.values());
|
|
4996
|
-
}
|
|
4997
|
-
/**
|
|
4998
|
-
* Clear all registered tags and summarizers.
|
|
4999
|
-
*/
|
|
5000
|
-
clear() {
|
|
5001
|
-
this.#tagsByValue.clear();
|
|
5002
|
-
this.#tagsByName.clear();
|
|
5003
|
-
this.#summarizers.clear();
|
|
5004
|
-
}
|
|
5005
|
-
/**
|
|
5006
|
-
* Get the number of registered tags.
|
|
5007
|
-
*
|
|
5008
|
-
* @returns Number of tags in the registry
|
|
5009
|
-
*/
|
|
5010
|
-
get size() {
|
|
5011
|
-
return this.#tagsByValue.size;
|
|
5012
|
-
}
|
|
5013
|
-
/**
|
|
5014
4985
|
* Create a string key for a numeric tag value.
|
|
5015
4986
|
* Handles both number and bigint types.
|
|
5016
4987
|
*
|
|
@@ -5373,11 +5344,17 @@ var bctsUniformResources = (function(exports) {
|
|
|
5373
5344
|
}
|
|
5374
5345
|
/**
|
|
5375
5346
|
* Format tagged value.
|
|
5347
|
+
*
|
|
5348
|
+
* Matches Rust's diag_item() for Tagged case.
|
|
5376
5349
|
*/
|
|
5377
5350
|
function formatTagged(tag, content, opts) {
|
|
5378
5351
|
if (opts.summarize === true) {
|
|
5379
5352
|
const summarizer = resolveTagsStore(opts.tags)?.summarizer(tag);
|
|
5380
|
-
if (summarizer !== void 0)
|
|
5353
|
+
if (summarizer !== void 0) {
|
|
5354
|
+
const result$1 = summarizer(content, opts.flat ?? false);
|
|
5355
|
+
if (result$1.ok) return result$1.value;
|
|
5356
|
+
else return `<error: ${result$1.error.type === "Custom" ? result$1.error.message : result$1.error.type === "WrongTag" ? `expected CBOR tag ${result$1.error.expected.value}, but got ${result$1.error.actual.value}` : result$1.error.type}>`;
|
|
5357
|
+
}
|
|
5381
5358
|
}
|
|
5382
5359
|
let comment;
|
|
5383
5360
|
if (opts.annotate === true) {
|
|
@@ -6008,21 +5985,20 @@ var bctsUniformResources = (function(exports) {
|
|
|
6008
5985
|
* @param cbor - The CBOR value to traverse
|
|
6009
5986
|
* @param initialState - Initial state value
|
|
6010
5987
|
* @param visitor - Function to call for each element
|
|
6011
|
-
* @returns Final state after traversal
|
|
6012
5988
|
*
|
|
6013
5989
|
* @example
|
|
6014
5990
|
* ```typescript
|
|
6015
|
-
* // Count all text strings in a structure
|
|
6016
|
-
*
|
|
5991
|
+
* // Count all text strings in a structure using RefCell-like pattern
|
|
5992
|
+
* const count = { value: 0 };
|
|
6017
5993
|
*
|
|
6018
5994
|
* const structure = cbor({ name: 'Alice', tags: ['urgent', 'draft'] });
|
|
6019
|
-
*
|
|
5995
|
+
* walk(structure, null, (element, level, edge, state) => {
|
|
6020
5996
|
* if (element.type === 'single' && element.cbor.type === MajorType.Text) {
|
|
6021
|
-
*
|
|
5997
|
+
* count.value++;
|
|
6022
5998
|
* }
|
|
6023
5999
|
* return [state, false];
|
|
6024
6000
|
* });
|
|
6025
|
-
* console.log(
|
|
6001
|
+
* console.log(count.value); // 3 (name, urgent, draft)
|
|
6026
6002
|
* ```
|
|
6027
6003
|
*
|
|
6028
6004
|
* @example
|
|
@@ -6031,7 +6007,7 @@ var bctsUniformResources = (function(exports) {
|
|
|
6031
6007
|
* const structure = cbor([1, 2, 3, 'found', 5, 6]);
|
|
6032
6008
|
* let found = false;
|
|
6033
6009
|
*
|
|
6034
|
-
* walk(structure, null, (element, level, edge) => {
|
|
6010
|
+
* walk(structure, null, (element, level, edge, state) => {
|
|
6035
6011
|
* if (element.type === 'single' &&
|
|
6036
6012
|
* element.cbor.type === MajorType.Text &&
|
|
6037
6013
|
* element.cbor.value === 'found') {
|
|
@@ -6043,7 +6019,7 @@ var bctsUniformResources = (function(exports) {
|
|
|
6043
6019
|
* ```
|
|
6044
6020
|
*/
|
|
6045
6021
|
const walk = (cbor$1, initialState, visitor) => {
|
|
6046
|
-
|
|
6022
|
+
walkInternal(cbor$1, 0, { type: EdgeType.None }, initialState, visitor);
|
|
6047
6023
|
};
|
|
6048
6024
|
/**
|
|
6049
6025
|
* Internal recursive walk implementation.
|
|
@@ -6527,7 +6503,7 @@ var bctsUniformResources = (function(exports) {
|
|
|
6527
6503
|
return this.value;
|
|
6528
6504
|
},
|
|
6529
6505
|
walk(initialState, visitor) {
|
|
6530
|
-
|
|
6506
|
+
walk(this, initialState, visitor);
|
|
6531
6507
|
},
|
|
6532
6508
|
validateTag(expectedTags) {
|
|
6533
6509
|
if (this.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" });
|
|
@@ -6663,6 +6639,16 @@ var bctsUniformResources = (function(exports) {
|
|
|
6663
6639
|
}
|
|
6664
6640
|
};
|
|
6665
6641
|
/**
|
|
6642
|
+
* Error type for UR decoder errors.
|
|
6643
|
+
* Matches Rust's Error::UR(String) variant.
|
|
6644
|
+
*/
|
|
6645
|
+
var URDecodeError = class extends URError {
|
|
6646
|
+
constructor(message) {
|
|
6647
|
+
super(`UR decoder error (${message})`);
|
|
6648
|
+
this.name = "URDecodeError";
|
|
6649
|
+
}
|
|
6650
|
+
};
|
|
6651
|
+
/**
|
|
6666
6652
|
* Helper function to check if a result is an error.
|
|
6667
6653
|
*/
|
|
6668
6654
|
function isError(result) {
|
|
@@ -6691,13 +6677,6 @@ var bctsUniformResources = (function(exports) {
|
|
|
6691
6677
|
return Array.from(urType).every((char) => isURTypeChar(char));
|
|
6692
6678
|
}
|
|
6693
6679
|
/**
|
|
6694
|
-
* Validates and returns a UR type, or throws an error if invalid.
|
|
6695
|
-
*/
|
|
6696
|
-
function validateURType(urType) {
|
|
6697
|
-
if (!isValidURType(urType)) throw new InvalidTypeError();
|
|
6698
|
-
return urType;
|
|
6699
|
-
}
|
|
6700
|
-
/**
|
|
6701
6680
|
* Bytewords for encoding/decoding bytes as words.
|
|
6702
6681
|
* See: https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-004-bytewords.md
|
|
6703
6682
|
*/
|
|
@@ -7268,7 +7247,7 @@ var bctsUniformResources = (function(exports) {
|
|
|
7268
7247
|
let BytewordsStyle = /* @__PURE__ */ function(BytewordsStyle$1) {
|
|
7269
7248
|
/** Full 4-letter words separated by spaces */
|
|
7270
7249
|
BytewordsStyle$1["Standard"] = "standard";
|
|
7271
|
-
/** Full 4-letter words
|
|
7250
|
+
/** Full 4-letter words separated by hyphens (URI-safe) */
|
|
7272
7251
|
BytewordsStyle$1["Uri"] = "uri";
|
|
7273
7252
|
/** First and last character only (minimal) - used by UR encoding */
|
|
7274
7253
|
BytewordsStyle$1["Minimal"] = "minimal";
|
|
@@ -7344,7 +7323,7 @@ var bctsUniformResources = (function(exports) {
|
|
|
7344
7323
|
}
|
|
7345
7324
|
switch (style) {
|
|
7346
7325
|
case BytewordsStyle.Standard: return words.join(" ");
|
|
7347
|
-
case BytewordsStyle.Uri:
|
|
7326
|
+
case BytewordsStyle.Uri: return words.join("-");
|
|
7348
7327
|
case BytewordsStyle.Minimal: return words.join("");
|
|
7349
7328
|
}
|
|
7350
7329
|
}
|
|
@@ -7364,14 +7343,11 @@ var bctsUniformResources = (function(exports) {
|
|
|
7364
7343
|
});
|
|
7365
7344
|
break;
|
|
7366
7345
|
case BytewordsStyle.Uri:
|
|
7367
|
-
|
|
7368
|
-
bytes = [];
|
|
7369
|
-
for (let i = 0; i < lowercased.length; i += 4) {
|
|
7370
|
-
const word = lowercased.slice(i, i + 4);
|
|
7346
|
+
bytes = lowercased.split("-").map((word) => {
|
|
7371
7347
|
const index = BYTEWORDS_MAP.get(word);
|
|
7372
7348
|
if (index === void 0) throw new Error(`Invalid byteword: ${word}`);
|
|
7373
|
-
|
|
7374
|
-
}
|
|
7349
|
+
return index;
|
|
7350
|
+
});
|
|
7375
7351
|
break;
|
|
7376
7352
|
case BytewordsStyle.Minimal:
|
|
7377
7353
|
if (lowercased.length % 2 !== 0) throw new Error("Invalid minimal bytewords length");
|
|
@@ -7676,6 +7652,7 @@ var bctsUniformResources = (function(exports) {
|
|
|
7676
7652
|
* for deterministic fragment selection in fountain codes.
|
|
7677
7653
|
*
|
|
7678
7654
|
* Reference: https://prng.di.unimi.it/
|
|
7655
|
+
* BC-UR Reference: https://github.com/nicklockwood/fountain-codes
|
|
7679
7656
|
*/
|
|
7680
7657
|
const MAX_UINT64 = BigInt("0xffffffffffffffff");
|
|
7681
7658
|
/**
|
|
@@ -7695,21 +7672,28 @@ var bctsUniformResources = (function(exports) {
|
|
|
7695
7672
|
var Xoshiro256 = class Xoshiro256 {
|
|
7696
7673
|
s;
|
|
7697
7674
|
/**
|
|
7698
|
-
* Creates a new Xoshiro256** instance from a seed.
|
|
7675
|
+
* Creates a new Xoshiro256** instance from a 32-byte seed.
|
|
7699
7676
|
*
|
|
7700
|
-
* The seed
|
|
7701
|
-
*
|
|
7677
|
+
* The seed must be exactly 32 bytes (256 bits). The bytes are interpreted
|
|
7678
|
+
* using the BC-UR reference algorithm: each 8-byte chunk is read as
|
|
7679
|
+
* big-endian then stored as little-endian for the state.
|
|
7702
7680
|
*
|
|
7703
|
-
* @param seed - The seed bytes (
|
|
7681
|
+
* @param seed - The seed bytes (must be exactly 32 bytes)
|
|
7704
7682
|
*/
|
|
7705
7683
|
constructor(seed) {
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7684
|
+
if (seed.length !== 32) throw new Error(`Seed must be 32 bytes, got ${seed.length}`);
|
|
7685
|
+
const s = [
|
|
7686
|
+
0n,
|
|
7687
|
+
0n,
|
|
7688
|
+
0n,
|
|
7689
|
+
0n
|
|
7712
7690
|
];
|
|
7691
|
+
for (let i = 0; i < 4; i++) {
|
|
7692
|
+
let v = 0n;
|
|
7693
|
+
for (let n = 0; n < 8; n++) v = v << 8n | BigInt(seed[8 * i + n] ?? 0);
|
|
7694
|
+
s[i] = v;
|
|
7695
|
+
}
|
|
7696
|
+
this.s = s;
|
|
7713
7697
|
}
|
|
7714
7698
|
/**
|
|
7715
7699
|
* Creates a Xoshiro256** instance from raw state values.
|
|
@@ -7726,33 +7710,6 @@ var bctsUniformResources = (function(exports) {
|
|
|
7726
7710
|
return instance;
|
|
7727
7711
|
}
|
|
7728
7712
|
/**
|
|
7729
|
-
* Simple hash function for seeding.
|
|
7730
|
-
* This is a basic implementation - in production use SHA-256.
|
|
7731
|
-
*/
|
|
7732
|
-
hashSeed(seed) {
|
|
7733
|
-
const result = new Uint8Array(32);
|
|
7734
|
-
if (seed.length === 0) return result;
|
|
7735
|
-
for (let i = 0; i < 32; i++) {
|
|
7736
|
-
let hash = 0;
|
|
7737
|
-
for (const byte of seed) hash = hash * 31 + byte + i >>> 0;
|
|
7738
|
-
hash ^= hash >>> 16;
|
|
7739
|
-
hash = hash * 2246822507 >>> 0;
|
|
7740
|
-
hash ^= hash >>> 13;
|
|
7741
|
-
hash = hash * 3266489909 >>> 0;
|
|
7742
|
-
hash ^= hash >>> 16;
|
|
7743
|
-
result[i] = hash & 255;
|
|
7744
|
-
}
|
|
7745
|
-
return result;
|
|
7746
|
-
}
|
|
7747
|
-
/**
|
|
7748
|
-
* Converts 8 bytes to a 64-bit BigInt (little-endian).
|
|
7749
|
-
*/
|
|
7750
|
-
bytesToBigInt(bytes) {
|
|
7751
|
-
let result = 0n;
|
|
7752
|
-
for (let i = 7; i >= 0; i--) result = result << 8n | BigInt(bytes[i] ?? 0);
|
|
7753
|
-
return result;
|
|
7754
|
-
}
|
|
7755
|
-
/**
|
|
7756
7713
|
* Generates the next 64-bit random value.
|
|
7757
7714
|
*/
|
|
7758
7715
|
next() {
|
|
@@ -7768,17 +7725,19 @@ var bctsUniformResources = (function(exports) {
|
|
|
7768
7725
|
}
|
|
7769
7726
|
/**
|
|
7770
7727
|
* Generates a random double in [0, 1).
|
|
7728
|
+
* Matches BC-UR reference: self.next() as f64 / (u64::MAX as f64 + 1.0)
|
|
7771
7729
|
*/
|
|
7772
7730
|
nextDouble() {
|
|
7773
7731
|
const value = this.next();
|
|
7774
|
-
return Number(value
|
|
7732
|
+
return Number(value) / 0x10000000000000000;
|
|
7775
7733
|
}
|
|
7776
7734
|
/**
|
|
7777
|
-
* Generates a random integer in [low, high).
|
|
7735
|
+
* Generates a random integer in [low, high] (inclusive).
|
|
7736
|
+
* Matches BC-UR reference: (self.next_double() * ((high - low + 1) as f64)) as u64 + low
|
|
7778
7737
|
*/
|
|
7779
7738
|
nextInt(low, high) {
|
|
7780
|
-
const range$1 = high - low;
|
|
7781
|
-
return
|
|
7739
|
+
const range$1 = high - low + 1;
|
|
7740
|
+
return Math.floor(this.nextDouble() * range$1) + low;
|
|
7782
7741
|
}
|
|
7783
7742
|
/**
|
|
7784
7743
|
* Generates a random byte [0, 255].
|
|
@@ -7794,24 +7753,102 @@ var bctsUniformResources = (function(exports) {
|
|
|
7794
7753
|
for (let i = 0; i < count; i++) result[i] = this.nextByte();
|
|
7795
7754
|
return result;
|
|
7796
7755
|
}
|
|
7756
|
+
/**
|
|
7757
|
+
* Shuffles items by repeatedly picking random indices.
|
|
7758
|
+
* Matches BC-UR reference implementation.
|
|
7759
|
+
*/
|
|
7760
|
+
shuffled(items) {
|
|
7761
|
+
const source = [...items];
|
|
7762
|
+
const shuffled = [];
|
|
7763
|
+
while (source.length > 0) {
|
|
7764
|
+
const index = this.nextInt(0, source.length - 1);
|
|
7765
|
+
const item = source.splice(index, 1)[0];
|
|
7766
|
+
if (item !== void 0) shuffled.push(item);
|
|
7767
|
+
}
|
|
7768
|
+
return shuffled;
|
|
7769
|
+
}
|
|
7770
|
+
/**
|
|
7771
|
+
* Chooses the degree (number of fragments to mix) using a weighted sampler.
|
|
7772
|
+
* Uses the robust soliton distribution with weights [1/1, 1/2, 1/3, ..., 1/n].
|
|
7773
|
+
* Matches BC-UR reference implementation.
|
|
7774
|
+
*/
|
|
7775
|
+
chooseDegree(seqLen) {
|
|
7776
|
+
const weights = [];
|
|
7777
|
+
for (let i = 1; i <= seqLen; i++) weights.push(1 / i);
|
|
7778
|
+
return new WeightedSampler(weights).next(this) + 1;
|
|
7779
|
+
}
|
|
7780
|
+
};
|
|
7781
|
+
/**
|
|
7782
|
+
* Weighted sampler using Vose's alias method.
|
|
7783
|
+
* Allows O(1) sampling from a discrete probability distribution.
|
|
7784
|
+
*/
|
|
7785
|
+
var WeightedSampler = class {
|
|
7786
|
+
aliases;
|
|
7787
|
+
probs;
|
|
7788
|
+
constructor(weights) {
|
|
7789
|
+
const n = weights.length;
|
|
7790
|
+
if (n === 0) throw new Error("Weights array cannot be empty");
|
|
7791
|
+
const sum = weights.reduce((a, b) => a + b, 0);
|
|
7792
|
+
if (sum <= 0) throw new Error("Weights must sum to a positive value");
|
|
7793
|
+
const normalized = weights.map((w) => w * n / sum);
|
|
7794
|
+
this.aliases = Array.from({ length: n }).fill(0);
|
|
7795
|
+
this.probs = Array.from({ length: n }).fill(0);
|
|
7796
|
+
const small = [];
|
|
7797
|
+
const large = [];
|
|
7798
|
+
for (let i = n - 1; i >= 0; i--) if (normalized[i] < 1) small.push(i);
|
|
7799
|
+
else large.push(i);
|
|
7800
|
+
while (small.length > 0 && large.length > 0) {
|
|
7801
|
+
const a = small.pop();
|
|
7802
|
+
const g = large.pop();
|
|
7803
|
+
if (a === void 0 || g === void 0) break;
|
|
7804
|
+
this.probs[a] = normalized[a] ?? 0;
|
|
7805
|
+
this.aliases[a] = g;
|
|
7806
|
+
normalized[g] = (normalized[g] ?? 0) + (normalized[a] ?? 0) - 1;
|
|
7807
|
+
if (normalized[g] !== void 0 && normalized[g] < 1) small.push(g);
|
|
7808
|
+
else large.push(g);
|
|
7809
|
+
}
|
|
7810
|
+
while (large.length > 0) {
|
|
7811
|
+
const g = large.pop();
|
|
7812
|
+
if (g === void 0) break;
|
|
7813
|
+
this.probs[g] = 1;
|
|
7814
|
+
}
|
|
7815
|
+
while (small.length > 0) {
|
|
7816
|
+
const a = small.pop();
|
|
7817
|
+
if (a === void 0) break;
|
|
7818
|
+
this.probs[a] = 1;
|
|
7819
|
+
}
|
|
7820
|
+
}
|
|
7821
|
+
/**
|
|
7822
|
+
* Sample from the distribution.
|
|
7823
|
+
*/
|
|
7824
|
+
next(rng) {
|
|
7825
|
+
const r1 = rng.nextDouble();
|
|
7826
|
+
const r2 = rng.nextDouble();
|
|
7827
|
+
const n = this.probs.length;
|
|
7828
|
+
const i = Math.floor(n * r1);
|
|
7829
|
+
if (r2 < this.probs[i]) return i;
|
|
7830
|
+
else return this.aliases[i];
|
|
7831
|
+
}
|
|
7797
7832
|
};
|
|
7798
7833
|
/**
|
|
7799
|
-
* Creates a
|
|
7834
|
+
* Creates a Xoshiro256 PRNG instance from message checksum and sequence number.
|
|
7835
|
+
*
|
|
7836
|
+
* This creates an 8-byte seed by concatenating seqNum and checksum (both in
|
|
7837
|
+
* big-endian), then hashes it with SHA-256 to get the 32-byte seed for Xoshiro.
|
|
7800
7838
|
*
|
|
7801
|
-
* This
|
|
7802
|
-
* for a given message and part number.
|
|
7839
|
+
* This matches the BC-UR reference implementation.
|
|
7803
7840
|
*/
|
|
7804
7841
|
function createSeed(checksum, seqNum) {
|
|
7805
|
-
const
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
return
|
|
7842
|
+
const seed8 = new Uint8Array(8);
|
|
7843
|
+
seed8[0] = seqNum >>> 24 & 255;
|
|
7844
|
+
seed8[1] = seqNum >>> 16 & 255;
|
|
7845
|
+
seed8[2] = seqNum >>> 8 & 255;
|
|
7846
|
+
seed8[3] = seqNum & 255;
|
|
7847
|
+
seed8[4] = checksum >>> 24 & 255;
|
|
7848
|
+
seed8[5] = checksum >>> 16 & 255;
|
|
7849
|
+
seed8[6] = checksum >>> 8 & 255;
|
|
7850
|
+
seed8[7] = checksum & 255;
|
|
7851
|
+
return (0, _bcts_crypto.sha256)(seed8);
|
|
7815
7852
|
}
|
|
7816
7853
|
|
|
7817
7854
|
//#endregion
|
|
@@ -7858,6 +7895,11 @@ var bctsUniformResources = (function(exports) {
|
|
|
7858
7895
|
* This uses a seeded Xoshiro256** PRNG to deterministically select fragments,
|
|
7859
7896
|
* ensuring encoder and decoder agree without explicit coordination.
|
|
7860
7897
|
*
|
|
7898
|
+
* The algorithm matches the BC-UR reference implementation:
|
|
7899
|
+
* 1. For pure parts (seqNum <= seqLen), return single fragment index
|
|
7900
|
+
* 2. For mixed parts, use weighted sampling to choose degree
|
|
7901
|
+
* 3. Shuffle all indices and take the first 'degree' indices
|
|
7902
|
+
*
|
|
7861
7903
|
* @param seqNum - The sequence number (1-based)
|
|
7862
7904
|
* @param seqLen - Total number of pure fragments
|
|
7863
7905
|
* @param checksum - CRC32 checksum of the message
|
|
@@ -7866,26 +7908,10 @@ var bctsUniformResources = (function(exports) {
|
|
|
7866
7908
|
function chooseFragments(seqNum, seqLen, checksum) {
|
|
7867
7909
|
if (seqNum <= seqLen) return [seqNum - 1];
|
|
7868
7910
|
const rng = new Xoshiro256(createSeed(checksum, seqNum));
|
|
7869
|
-
const degree = chooseDegree(
|
|
7870
|
-
const
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
indices.add(index);
|
|
7874
|
-
}
|
|
7875
|
-
return Array.from(indices).sort((a, b) => a - b);
|
|
7876
|
-
}
|
|
7877
|
-
/**
|
|
7878
|
-
* Chooses the degree (number of fragments to mix) using a simplified
|
|
7879
|
-
* robust soliton distribution.
|
|
7880
|
-
*
|
|
7881
|
-
* This ensures good coverage of fragments for efficient decoding.
|
|
7882
|
-
*/
|
|
7883
|
-
function chooseDegree(rng, seqLen) {
|
|
7884
|
-
const r = rng.nextDouble();
|
|
7885
|
-
if (r < .5) return 1;
|
|
7886
|
-
else if (r < .75) return 2;
|
|
7887
|
-
else if (r < .9) return Math.min(3, seqLen);
|
|
7888
|
-
else return Math.min(rng.nextInt(4, seqLen + 1), seqLen);
|
|
7911
|
+
const degree = rng.chooseDegree(seqLen);
|
|
7912
|
+
const allIndices = [];
|
|
7913
|
+
for (let i = 0; i < seqLen; i++) allIndices.push(i);
|
|
7914
|
+
return rng.shuffled(allIndices).slice(0, degree);
|
|
7889
7915
|
}
|
|
7890
7916
|
/**
|
|
7891
7917
|
* Mixes the selected fragments using XOR.
|
|
@@ -8125,14 +8151,6 @@ var bctsUniformResources = (function(exports) {
|
|
|
8125
8151
|
this._fountainEncoder = new FountainEncoder(ur.cbor().toData(), maxFragmentLen);
|
|
8126
8152
|
}
|
|
8127
8153
|
/**
|
|
8128
|
-
* Returns whether the message fits in a single part.
|
|
8129
|
-
*
|
|
8130
|
-
* For single-part messages, consider using UR.string() directly.
|
|
8131
|
-
*/
|
|
8132
|
-
isSinglePart() {
|
|
8133
|
-
return this._fountainEncoder.isSinglePart();
|
|
8134
|
-
}
|
|
8135
|
-
/**
|
|
8136
8154
|
* Gets the next part of the encoding.
|
|
8137
8155
|
*
|
|
8138
8156
|
* Parts 1 through seqLen are "pure" fragments containing one piece each.
|
|
@@ -8160,20 +8178,17 @@ var bctsUniformResources = (function(exports) {
|
|
|
8160
8178
|
return `ur:${this._ur.urTypeStr()}/${part.seqNum}-${part.seqLen}/${encoded}`;
|
|
8161
8179
|
}
|
|
8162
8180
|
/**
|
|
8163
|
-
* Encodes part metadata and data
|
|
8181
|
+
* Encodes part metadata and data as CBOR for bytewords encoding.
|
|
8182
|
+
* Format: CBOR array [seqNum, seqLen, messageLen, checksum, data]
|
|
8164
8183
|
*/
|
|
8165
8184
|
_encodePartData(part) {
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
result[6] = part.checksum >>> 8 & 255;
|
|
8174
|
-
result[7] = part.checksum & 255;
|
|
8175
|
-
result.set(part.data, 8);
|
|
8176
|
-
return result;
|
|
8185
|
+
return cbor([
|
|
8186
|
+
part.seqNum,
|
|
8187
|
+
part.seqLen,
|
|
8188
|
+
part.messageLen,
|
|
8189
|
+
part.checksum,
|
|
8190
|
+
part.data
|
|
8191
|
+
]).toData();
|
|
8177
8192
|
}
|
|
8178
8193
|
/**
|
|
8179
8194
|
* Gets the current part index.
|
|
@@ -8190,22 +8205,6 @@ var bctsUniformResources = (function(exports) {
|
|
|
8190
8205
|
partsCount() {
|
|
8191
8206
|
return this._fountainEncoder.seqLen;
|
|
8192
8207
|
}
|
|
8193
|
-
/**
|
|
8194
|
-
* Checks if all pure parts have been emitted.
|
|
8195
|
-
*
|
|
8196
|
-
* Even after this returns true, you can continue calling nextPart()
|
|
8197
|
-
* to generate additional rateless parts for redundancy.
|
|
8198
|
-
*/
|
|
8199
|
-
isComplete() {
|
|
8200
|
-
return this._fountainEncoder.isComplete();
|
|
8201
|
-
}
|
|
8202
|
-
/**
|
|
8203
|
-
* Resets the encoder to start from the beginning.
|
|
8204
|
-
*/
|
|
8205
|
-
reset() {
|
|
8206
|
-
this._currentIndex = 0;
|
|
8207
|
-
this._fountainEncoder.reset();
|
|
8208
|
-
}
|
|
8209
8208
|
};
|
|
8210
8209
|
|
|
8211
8210
|
//#endregion
|
|
@@ -8287,16 +8286,23 @@ var bctsUniformResources = (function(exports) {
|
|
|
8287
8286
|
}
|
|
8288
8287
|
/**
|
|
8289
8288
|
* Decodes a multipart UR's fountain part data.
|
|
8289
|
+
*
|
|
8290
|
+
* The multipart body is a CBOR array: [seqNum, seqLen, messageLen, checksum, data]
|
|
8290
8291
|
*/
|
|
8291
8292
|
_decodeFountainPart(partInfo) {
|
|
8292
|
-
const
|
|
8293
|
-
if (
|
|
8294
|
-
const
|
|
8295
|
-
|
|
8296
|
-
const
|
|
8293
|
+
const decoded = decodeCbor(decodeBytewords(partInfo.encodedData, BytewordsStyle.Minimal));
|
|
8294
|
+
if (decoded.type !== MajorType.Array) throw new URError("Invalid multipart data: expected CBOR array");
|
|
8295
|
+
const items = decoded.value;
|
|
8296
|
+
if (items.length !== 5) throw new URError(`Invalid multipart data: expected 5 elements, got ${items.length}`);
|
|
8297
|
+
const seqNum = Number(items[0].value);
|
|
8298
|
+
const seqLen = Number(items[1].value);
|
|
8299
|
+
const messageLen = Number(items[2].value);
|
|
8300
|
+
const checksum = Number(items[3].value);
|
|
8301
|
+
const data = items[4].value;
|
|
8302
|
+
if (seqNum !== partInfo.seqNum || seqLen !== partInfo.seqLen) throw new URError(`Multipart metadata mismatch: URL says ${partInfo.seqNum}-${partInfo.seqLen}, CBOR says ${seqNum}-${seqLen}`);
|
|
8297
8303
|
return {
|
|
8298
|
-
seqNum
|
|
8299
|
-
seqLen
|
|
8304
|
+
seqNum,
|
|
8305
|
+
seqLen,
|
|
8300
8306
|
messageLen,
|
|
8301
8307
|
checksum,
|
|
8302
8308
|
data
|
|
@@ -8316,48 +8322,25 @@ var bctsUniformResources = (function(exports) {
|
|
|
8316
8322
|
message() {
|
|
8317
8323
|
return this._decodedMessage;
|
|
8318
8324
|
}
|
|
8319
|
-
/**
|
|
8320
|
-
* Returns the decoding progress as a fraction (0 to 1).
|
|
8321
|
-
*/
|
|
8322
|
-
progress() {
|
|
8323
|
-
if (this._decodedMessage !== null) return 1;
|
|
8324
|
-
if (this._fountainDecoder === null) return 0;
|
|
8325
|
-
return this._fountainDecoder.progress();
|
|
8326
|
-
}
|
|
8327
|
-
/**
|
|
8328
|
-
* Resets the decoder to receive a new message.
|
|
8329
|
-
*/
|
|
8330
|
-
reset() {
|
|
8331
|
-
this._urType = null;
|
|
8332
|
-
this._fountainDecoder = null;
|
|
8333
|
-
this._decodedMessage = null;
|
|
8334
|
-
}
|
|
8335
8325
|
};
|
|
8336
8326
|
|
|
8337
8327
|
//#endregion
|
|
8338
8328
|
exports.BYTEMOJIS = BYTEMOJIS;
|
|
8339
8329
|
exports.BYTEWORDS = BYTEWORDS;
|
|
8340
|
-
exports.BYTEWORDS_MAP = BYTEWORDS_MAP;
|
|
8341
8330
|
exports.BytewordsError = BytewordsError;
|
|
8342
8331
|
exports.BytewordsStyle = BytewordsStyle;
|
|
8343
8332
|
exports.CBORError = CBORError;
|
|
8344
|
-
exports.FountainDecoder = FountainDecoder;
|
|
8345
|
-
exports.FountainEncoder = FountainEncoder;
|
|
8346
8333
|
exports.InvalidSchemeError = InvalidSchemeError;
|
|
8347
8334
|
exports.InvalidTypeError = InvalidTypeError;
|
|
8348
|
-
exports.MINIMAL_BYTEWORDS_MAP = MINIMAL_BYTEWORDS_MAP;
|
|
8349
8335
|
exports.MultipartDecoder = MultipartDecoder;
|
|
8350
8336
|
exports.MultipartEncoder = MultipartEncoder;
|
|
8351
8337
|
exports.NotSinglePartError = NotSinglePartError;
|
|
8352
8338
|
exports.TypeUnspecifiedError = TypeUnspecifiedError;
|
|
8353
8339
|
exports.UR = UR;
|
|
8340
|
+
exports.URDecodeError = URDecodeError;
|
|
8354
8341
|
exports.URError = URError;
|
|
8355
8342
|
exports.URType = URType;
|
|
8356
8343
|
exports.UnexpectedTypeError = UnexpectedTypeError;
|
|
8357
|
-
exports.Xoshiro256 = Xoshiro256;
|
|
8358
|
-
exports.chooseFragments = chooseFragments;
|
|
8359
|
-
exports.crc32 = crc32;
|
|
8360
|
-
exports.createSeed = createSeed;
|
|
8361
8344
|
exports.decodeBytewords = decodeBytewords;
|
|
8362
8345
|
exports.encodeBytemojisIdentifier = encodeBytemojisIdentifier;
|
|
8363
8346
|
exports.encodeBytewords = encodeBytewords;
|
|
@@ -8366,12 +8349,6 @@ exports.isError = isError;
|
|
|
8366
8349
|
exports.isURCodable = isURCodable;
|
|
8367
8350
|
exports.isURDecodable = isURDecodable;
|
|
8368
8351
|
exports.isUREncodable = isUREncodable;
|
|
8369
|
-
exports.isURTypeChar = isURTypeChar;
|
|
8370
|
-
exports.isValidURType = isValidURType;
|
|
8371
|
-
exports.mixFragments = mixFragments;
|
|
8372
|
-
exports.splitMessage = splitMessage;
|
|
8373
|
-
exports.validateURType = validateURType;
|
|
8374
|
-
exports.xorBytes = xorBytes;
|
|
8375
8352
|
return exports;
|
|
8376
|
-
})({});
|
|
8353
|
+
})({}, bctsCrypto);
|
|
8377
8354
|
//# sourceMappingURL=index.iife.js.map
|