aviation-chart 2.0.10 → 2.0.12
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/nav-sdk.esm.js +2143 -54
- package/package.json +4 -1
package/dist/nav-sdk.esm.js
CHANGED
|
@@ -1606,7 +1606,7 @@ function buildAMMLayersLight(sourceId = 'amm') {
|
|
|
1606
1606
|
layout: {
|
|
1607
1607
|
'text-field': ['get', 'idlin'],
|
|
1608
1608
|
'text-size': 10,
|
|
1609
|
-
"icon-image": "text_bg",
|
|
1609
|
+
"icon-image": "stretch:text_bg",
|
|
1610
1610
|
"icon-text-fit": "both",
|
|
1611
1611
|
"icon-text-fit-padding": [
|
|
1612
1612
|
1,
|
|
@@ -1632,7 +1632,7 @@ function buildAMMLayersLight(sourceId = 'amm') {
|
|
|
1632
1632
|
'source-layer': 'amm-runway-threshold',
|
|
1633
1633
|
minzoom: 12,
|
|
1634
1634
|
layout: {
|
|
1635
|
-
"icon-image": "text_bg",
|
|
1635
|
+
"icon-image": "stretch:text_bg",
|
|
1636
1636
|
"icon-text-fit": "both",
|
|
1637
1637
|
"icon-text-fit-padding": [
|
|
1638
1638
|
1,
|
|
@@ -1834,12 +1834,12 @@ function buildAMMLayersDark(sourceId = 'amm') {
|
|
|
1834
1834
|
{ id: 'amm-stand-line', type: 'line', source: sourceId, 'source-layer': 'amm-stand-line', minzoom: 13, paint: { 'line-color': C.standLine, 'line-width': 1 } },
|
|
1835
1835
|
{
|
|
1836
1836
|
id: 'amm-taxiway-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-taxiway-line', minzoom: 14,
|
|
1837
|
-
layout: { 'text-field': ['get', 'idlin'], 'text-size': 10, "icon-image": "text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'symbol-placement': 'line', 'text-keep-upright': true, 'text-allow-overlap': false },
|
|
1837
|
+
layout: { 'text-field': ['get', 'idlin'], 'text-size': 10, "icon-image": "stretch:text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'symbol-placement': 'line', 'text-keep-upright': true, 'text-allow-overlap': false },
|
|
1838
1838
|
paint: { 'text-color': "#0f172a", "icon-color": C.taxiwayLine },
|
|
1839
1839
|
},
|
|
1840
1840
|
{
|
|
1841
1841
|
id: 'amm-runway-threshold-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-runway-threshold', minzoom: 12,
|
|
1842
|
-
layout: { "icon-image": "text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'text-field': ['get', 'idthr'], 'text-size': 14, 'text-allow-overlap': true, 'text-rotation-alignment': 'map', 'icon-rotation-alignment': 'map' },
|
|
1842
|
+
layout: { "icon-image": "stretch:text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'text-field': ['get', 'idthr'], 'text-size': 14, 'text-allow-overlap': true, 'text-rotation-alignment': 'map', 'icon-rotation-alignment': 'map' },
|
|
1843
1843
|
paint: { 'text-color': '#ffffff', "icon-color": "#ef4444" },
|
|
1844
1844
|
},
|
|
1845
1845
|
{ id: 'amm-stand', type: 'circle', source: sourceId, 'source-layer': 'amm-stand', minzoom: 12, paint: { 'circle-color': C.stand, 'circle-radius': 1.5 } },
|
|
@@ -1897,7 +1897,7 @@ function buildAMMLayersNeutral(sourceId = 'amm') {
|
|
|
1897
1897
|
{ id: 'amm-taxiway-line', type: 'line', source: sourceId, 'source-layer': 'amm-taxiway-line', minzoom: 11, paint: { 'line-color': C.taxiwayLine, 'line-width': ['interpolate', ['linear'], ['zoom'], 15, 0.8, 18, 2] } },
|
|
1898
1898
|
{
|
|
1899
1899
|
id: 'amm-taxiway-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-taxiway-line', minzoom: 14,
|
|
1900
|
-
layout: { 'text-field': ['get', 'idlin'], 'text-size': 10, "icon-image": "text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'symbol-placement': 'line', 'text-keep-upright': true, 'text-allow-overlap': false },
|
|
1900
|
+
layout: { 'text-field': ['get', 'idlin'], 'text-size': 10, "icon-image": "stretch:text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'symbol-placement': 'line', 'text-keep-upright': true, 'text-allow-overlap': false },
|
|
1901
1901
|
paint: { 'text-color': H, "icon-color": C.taxiwayLine },
|
|
1902
1902
|
},
|
|
1903
1903
|
{ id: 'amm-holding', type: 'line', source: sourceId, 'source-layer': 'amm-holding', minzoom: 11, paint: { 'line-color': C.holding, 'line-width': 1.5 } },
|
|
@@ -1915,7 +1915,7 @@ function buildAMMLayersNeutral(sourceId = 'amm') {
|
|
|
1915
1915
|
{ id: 'amm-stand-line', type: 'line', source: sourceId, 'source-layer': 'amm-stand-line', minzoom: 13, paint: { 'line-color': C.standLine, 'line-width': 1 } },
|
|
1916
1916
|
{
|
|
1917
1917
|
id: 'amm-runway-threshold-label', type: 'symbol', source: sourceId, 'source-layer': 'amm-runway-threshold', minzoom: 12,
|
|
1918
|
-
layout: { "icon-image": "text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'text-field': ['get', 'idthr'], 'text-size': 14, 'text-allow-overlap': true, 'text-rotation-alignment': 'map', 'icon-rotation-alignment': 'map' },
|
|
1918
|
+
layout: { "icon-image": "stretch:text_bg", "icon-text-fit": "both", "icon-text-fit-padding": [1, 2, 1, 2], 'text-field': ['get', 'idthr'], 'text-size': 14, 'text-allow-overlap': true, 'text-rotation-alignment': 'map', 'icon-rotation-alignment': 'map' },
|
|
1919
1919
|
paint: { 'text-color': '#ffffff', "icon-color": C.threshold },
|
|
1920
1920
|
},
|
|
1921
1921
|
{ id: 'amm-stand', type: 'circle', source: sourceId, 'source-layer': 'amm-stand', minzoom: 12, paint: { 'circle-color': C.stand, 'circle-radius': 1.5 } },
|
|
@@ -7430,6 +7430,7 @@ function getAviationBaseStyle(opts) {
|
|
|
7430
7430
|
{ id: "v2", url: `${spriteBase}/sprites/sprite-v2` },
|
|
7431
7431
|
{ id: "vor", url: `${spriteBase}/sprites/sprite-vor` },
|
|
7432
7432
|
{ id: "runway", url: `${spriteBase}/sprites/sprite-runway` },
|
|
7433
|
+
{ id: "stretch", url: `${spriteBase}/sprites/sprite-stretch` },
|
|
7433
7434
|
],
|
|
7434
7435
|
sources: {
|
|
7435
7436
|
land: { type: "geojson", data: { type: "FeatureCollection", features: [] } },
|
|
@@ -7596,6 +7597,2041 @@ async function fetchGzJson(url, headers = {}) {
|
|
|
7596
7597
|
return new Response(stream).json();
|
|
7597
7598
|
}
|
|
7598
7599
|
|
|
7600
|
+
/**
|
|
7601
|
+
* Utilities for hex, bytes, CSPRNG.
|
|
7602
|
+
* @module
|
|
7603
|
+
*/
|
|
7604
|
+
/*! noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com) */
|
|
7605
|
+
/**
|
|
7606
|
+
* Checks if something is Uint8Array. Be careful: nodejs Buffer will return true.
|
|
7607
|
+
* @param a - Value to inspect.
|
|
7608
|
+
* @returns `true` when the value is a Uint8Array view, including Node's `Buffer`.
|
|
7609
|
+
* @example
|
|
7610
|
+
* Guards a value before treating it as raw key material.
|
|
7611
|
+
*
|
|
7612
|
+
* ```ts
|
|
7613
|
+
* isBytes(new Uint8Array());
|
|
7614
|
+
* ```
|
|
7615
|
+
*/
|
|
7616
|
+
function isBytes$1(a) {
|
|
7617
|
+
// Plain `instanceof Uint8Array` is too strict for some Buffer / proxy /
|
|
7618
|
+
// cross-realm cases. The fallback still requires a real ArrayBuffer view
|
|
7619
|
+
// so plain JSON-deserialized `{ constructor: ... }`
|
|
7620
|
+
// spoofing is rejected, and `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views.
|
|
7621
|
+
return (a instanceof Uint8Array ||
|
|
7622
|
+
(ArrayBuffer.isView(a) &&
|
|
7623
|
+
a.constructor.name === 'Uint8Array' &&
|
|
7624
|
+
'BYTES_PER_ELEMENT' in a &&
|
|
7625
|
+
a.BYTES_PER_ELEMENT === 1));
|
|
7626
|
+
}
|
|
7627
|
+
/**
|
|
7628
|
+
* Asserts something is boolean.
|
|
7629
|
+
* @param b - Value to validate.
|
|
7630
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
7631
|
+
* @example
|
|
7632
|
+
* Validates a boolean option before branching on it.
|
|
7633
|
+
*
|
|
7634
|
+
* ```ts
|
|
7635
|
+
* abool(true);
|
|
7636
|
+
* ```
|
|
7637
|
+
*/
|
|
7638
|
+
function abool(b) {
|
|
7639
|
+
if (typeof b !== 'boolean')
|
|
7640
|
+
throw new TypeError(`boolean expected, not ${b}`);
|
|
7641
|
+
}
|
|
7642
|
+
/**
|
|
7643
|
+
* Asserts something is a non-negative safe integer.
|
|
7644
|
+
* @param n - Value to validate.
|
|
7645
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
7646
|
+
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
7647
|
+
* @example
|
|
7648
|
+
* Validates a non-negative length or counter.
|
|
7649
|
+
*
|
|
7650
|
+
* ```ts
|
|
7651
|
+
* anumber(1);
|
|
7652
|
+
* ```
|
|
7653
|
+
*/
|
|
7654
|
+
function anumber$1(n) {
|
|
7655
|
+
if (typeof n !== 'number')
|
|
7656
|
+
throw new TypeError('number expected, got ' + typeof n);
|
|
7657
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
7658
|
+
throw new RangeError('positive integer expected, got ' + n);
|
|
7659
|
+
}
|
|
7660
|
+
/**
|
|
7661
|
+
* Asserts something is Uint8Array.
|
|
7662
|
+
* @param value - Value to validate.
|
|
7663
|
+
* @param length - Expected byte length.
|
|
7664
|
+
* @param title - Optional label used in error messages.
|
|
7665
|
+
* @returns The validated byte array.
|
|
7666
|
+
* On Node, `Buffer` is accepted too because it is a Uint8Array view.
|
|
7667
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
7668
|
+
* @throws On wrong argument lengths. {@link RangeError}
|
|
7669
|
+
* @example
|
|
7670
|
+
* Validates a fixed-length nonce or key buffer.
|
|
7671
|
+
*
|
|
7672
|
+
* ```ts
|
|
7673
|
+
* abytes(new Uint8Array([1, 2]), 2);
|
|
7674
|
+
* ```
|
|
7675
|
+
*/
|
|
7676
|
+
function abytes$1(value, length, title = '') {
|
|
7677
|
+
const bytes = isBytes$1(value);
|
|
7678
|
+
const len = value?.length;
|
|
7679
|
+
const needsLen = length !== undefined;
|
|
7680
|
+
if (!bytes || (needsLen && len !== length)) {
|
|
7681
|
+
const prefix = title && `"${title}" `;
|
|
7682
|
+
const ofLen = needsLen ? ` of length ${length}` : '';
|
|
7683
|
+
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
7684
|
+
const message = prefix + 'expected Uint8Array' + ofLen + ', got ' + got;
|
|
7685
|
+
if (!bytes)
|
|
7686
|
+
throw new TypeError(message);
|
|
7687
|
+
throw new RangeError(message);
|
|
7688
|
+
}
|
|
7689
|
+
return value;
|
|
7690
|
+
}
|
|
7691
|
+
/**
|
|
7692
|
+
* Asserts a hash- or MAC-like instance has not been destroyed or finished.
|
|
7693
|
+
* @param instance - Stateful instance to validate.
|
|
7694
|
+
* @param checkFinished - Whether to reject finished instances.
|
|
7695
|
+
* When `false`, only `destroyed` is checked.
|
|
7696
|
+
* @throws If the hash instance has already been destroyed or finalized. {@link Error}
|
|
7697
|
+
* @example
|
|
7698
|
+
* Guards against calling `update()` or `digest()` on a finished hash.
|
|
7699
|
+
*
|
|
7700
|
+
* ```ts
|
|
7701
|
+
* aexists({ destroyed: false, finished: false });
|
|
7702
|
+
* ```
|
|
7703
|
+
*/
|
|
7704
|
+
function aexists$1(instance, checkFinished = true) {
|
|
7705
|
+
if (instance.destroyed)
|
|
7706
|
+
throw new Error('Hash instance has been destroyed');
|
|
7707
|
+
if (checkFinished && instance.finished)
|
|
7708
|
+
throw new Error('Hash#digest() has already been called');
|
|
7709
|
+
}
|
|
7710
|
+
/**
|
|
7711
|
+
* Asserts output is a properly-sized byte array.
|
|
7712
|
+
* @param out - Output buffer to validate.
|
|
7713
|
+
* @param instance - Hash-like instance providing `outputLen`.
|
|
7714
|
+
* This is the relaxed `digestInto()`-style contract: output must be at least `outputLen`,
|
|
7715
|
+
* unlike one-shot cipher helpers elsewhere in the repo that often require exact lengths.
|
|
7716
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
7717
|
+
* @param onlyAligned - Whether `out` must be 4-byte aligned for zero-allocation word views.
|
|
7718
|
+
* @throws On wrong output buffer lengths. {@link RangeError}
|
|
7719
|
+
* @throws On wrong output buffer alignment. {@link Error}
|
|
7720
|
+
* @example
|
|
7721
|
+
* Verifies that a caller-provided output buffer is large enough.
|
|
7722
|
+
*
|
|
7723
|
+
* ```ts
|
|
7724
|
+
* aoutput(new Uint8Array(16), { outputLen: 16 });
|
|
7725
|
+
* ```
|
|
7726
|
+
*/
|
|
7727
|
+
function aoutput$1(out, instance, onlyAligned = false) {
|
|
7728
|
+
abytes$1(out, undefined, 'output');
|
|
7729
|
+
const min = instance.outputLen;
|
|
7730
|
+
if (out.length < min) {
|
|
7731
|
+
throw new RangeError('digestInto() expects output buffer of length at least ' + min);
|
|
7732
|
+
}
|
|
7733
|
+
if (onlyAligned && !isAligned32(out))
|
|
7734
|
+
throw new Error('invalid output, must be aligned');
|
|
7735
|
+
}
|
|
7736
|
+
/**
|
|
7737
|
+
* Casts a typed-array view to Uint8Array.
|
|
7738
|
+
* @param arr - Typed-array view to reinterpret.
|
|
7739
|
+
* @returns Uint8Array view over the same bytes.
|
|
7740
|
+
* @example
|
|
7741
|
+
* Views 32-bit words as raw bytes without copying.
|
|
7742
|
+
*
|
|
7743
|
+
* ```ts
|
|
7744
|
+
* u8(new Uint32Array([1]));
|
|
7745
|
+
* ```
|
|
7746
|
+
*/
|
|
7747
|
+
function u8$1(arr) {
|
|
7748
|
+
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
7749
|
+
}
|
|
7750
|
+
/**
|
|
7751
|
+
* Casts a typed-array view to Uint32Array.
|
|
7752
|
+
* @param arr - Typed-array view to reinterpret.
|
|
7753
|
+
* @returns Uint32Array view over the same bytes. Callers are expected to provide a
|
|
7754
|
+
* 4-byte-aligned offset; trailing `1..3` bytes are silently dropped.
|
|
7755
|
+
* @example
|
|
7756
|
+
* Views a byte buffer as 32-bit words for block processing.
|
|
7757
|
+
*
|
|
7758
|
+
* ```ts
|
|
7759
|
+
* u32(new Uint8Array(4));
|
|
7760
|
+
* ```
|
|
7761
|
+
*/
|
|
7762
|
+
function u32(arr) {
|
|
7763
|
+
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
|
7764
|
+
}
|
|
7765
|
+
/**
|
|
7766
|
+
* Zeroizes typed arrays in place.
|
|
7767
|
+
* Warning: JS provides no guarantees.
|
|
7768
|
+
* @param arrays - Arrays to wipe.
|
|
7769
|
+
* @example
|
|
7770
|
+
* Wipes a temporary key buffer after use.
|
|
7771
|
+
*
|
|
7772
|
+
* ```ts
|
|
7773
|
+
* const bytes = new Uint8Array([1]);
|
|
7774
|
+
* clean(bytes);
|
|
7775
|
+
* ```
|
|
7776
|
+
*/
|
|
7777
|
+
function clean$1(...arrays) {
|
|
7778
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
7779
|
+
arrays[i].fill(0);
|
|
7780
|
+
}
|
|
7781
|
+
}
|
|
7782
|
+
/**
|
|
7783
|
+
* Creates a DataView for byte-level manipulation.
|
|
7784
|
+
* @param arr - Typed-array view to wrap.
|
|
7785
|
+
* @returns DataView over the same bytes.
|
|
7786
|
+
* @example
|
|
7787
|
+
* Creates an endian-aware view for length encoding.
|
|
7788
|
+
*
|
|
7789
|
+
* ```ts
|
|
7790
|
+
* createView(new Uint8Array(4));
|
|
7791
|
+
* ```
|
|
7792
|
+
*/
|
|
7793
|
+
function createView$1(arr) {
|
|
7794
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
7795
|
+
}
|
|
7796
|
+
/**
|
|
7797
|
+
* Whether the current platform is little-endian.
|
|
7798
|
+
* Most are; some IBM systems are not.
|
|
7799
|
+
*/
|
|
7800
|
+
const isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();
|
|
7801
|
+
/**
|
|
7802
|
+
* Reverses byte order of one 32-bit word.
|
|
7803
|
+
* @param word - Unsigned 32-bit word to swap.
|
|
7804
|
+
* @returns The same word with bytes reversed.
|
|
7805
|
+
* @example
|
|
7806
|
+
* Swaps a big-endian word into little-endian byte order.
|
|
7807
|
+
*
|
|
7808
|
+
* ```ts
|
|
7809
|
+
* byteSwap(0x11223344);
|
|
7810
|
+
* ```
|
|
7811
|
+
*/
|
|
7812
|
+
const byteSwap = (word) => ((word << 24) & 0xff000000) |
|
|
7813
|
+
((word << 8) & 0xff0000) |
|
|
7814
|
+
((word >>> 8) & 0xff00) |
|
|
7815
|
+
((word >>> 24) & 0xff);
|
|
7816
|
+
/**
|
|
7817
|
+
* Normalizes one 32-bit word to the little-endian representation expected by cipher cores.
|
|
7818
|
+
* @param n - Unsigned 32-bit word to normalize.
|
|
7819
|
+
* @returns Little-endian normalized word on big-endian hosts, else the input word unchanged.
|
|
7820
|
+
* @example
|
|
7821
|
+
* Normalizes a host-endian word before passing it into an ARX/AES core.
|
|
7822
|
+
*
|
|
7823
|
+
* ```ts
|
|
7824
|
+
* swap8IfBE(0x11223344);
|
|
7825
|
+
* ```
|
|
7826
|
+
*/
|
|
7827
|
+
const swap8IfBE = isLE
|
|
7828
|
+
? (n) => n
|
|
7829
|
+
: (n) => byteSwap(n) >>> 0;
|
|
7830
|
+
/**
|
|
7831
|
+
* Byte-swaps every word of a Uint32Array in place.
|
|
7832
|
+
* @param arr - Uint32Array whose words should be swapped.
|
|
7833
|
+
* @returns The same array after in-place byte swapping.
|
|
7834
|
+
* @example
|
|
7835
|
+
* Swaps every 32-bit word in a word-view buffer.
|
|
7836
|
+
*
|
|
7837
|
+
* ```ts
|
|
7838
|
+
* byteSwap32(new Uint32Array([0x11223344]));
|
|
7839
|
+
* ```
|
|
7840
|
+
*/
|
|
7841
|
+
const byteSwap32 = (arr) => {
|
|
7842
|
+
for (let i = 0; i < arr.length; i++)
|
|
7843
|
+
arr[i] = byteSwap(arr[i]);
|
|
7844
|
+
return arr;
|
|
7845
|
+
};
|
|
7846
|
+
/**
|
|
7847
|
+
* Normalizes a Uint32Array view to the little-endian representation expected by cipher cores.
|
|
7848
|
+
* @param u - Word view to normalize in place.
|
|
7849
|
+
* @returns Little-endian normalized word view.
|
|
7850
|
+
* @example
|
|
7851
|
+
* Normalizes a word-view buffer before block processing.
|
|
7852
|
+
*
|
|
7853
|
+
* ```ts
|
|
7854
|
+
* swap32IfBE(new Uint32Array([0x11223344]));
|
|
7855
|
+
* ```
|
|
7856
|
+
*/
|
|
7857
|
+
const swap32IfBE = isLE
|
|
7858
|
+
? (u) => u
|
|
7859
|
+
: byteSwap32;
|
|
7860
|
+
/**
|
|
7861
|
+
* Compares two byte arrays in kinda constant time once lengths already match.
|
|
7862
|
+
* @param a - First byte array.
|
|
7863
|
+
* @param b - Second byte array.
|
|
7864
|
+
* @returns `true` when the arrays contain the same bytes. Different lengths still return early.
|
|
7865
|
+
* @example
|
|
7866
|
+
* Compares an expected authentication tag with the received one.
|
|
7867
|
+
*
|
|
7868
|
+
* ```ts
|
|
7869
|
+
* equalBytes(new Uint8Array([1]), new Uint8Array([1]));
|
|
7870
|
+
* ```
|
|
7871
|
+
*/
|
|
7872
|
+
function equalBytes(a, b) {
|
|
7873
|
+
if (a.length !== b.length)
|
|
7874
|
+
return false;
|
|
7875
|
+
let diff = 0;
|
|
7876
|
+
for (let i = 0; i < a.length; i++)
|
|
7877
|
+
diff |= a[i] ^ b[i];
|
|
7878
|
+
return diff === 0;
|
|
7879
|
+
}
|
|
7880
|
+
/**
|
|
7881
|
+
* Wraps a keyed MAC constructor into a one-shot helper with `.create()`.
|
|
7882
|
+
* @param keyLen - Valid probe-key length used to read static metadata once.
|
|
7883
|
+
* The probe key is only used for `outputLen` / `blockLen`, so callers with several valid key sizes
|
|
7884
|
+
* can pass any representative size as long as those values stay fixed.
|
|
7885
|
+
* @param macCons - Keyed MAC constructor or factory.
|
|
7886
|
+
* @param fromMsg - Optional adapter that derives extra constructor args from the one-shot message.
|
|
7887
|
+
* @returns Callable MAC helper with `.create()`.
|
|
7888
|
+
*/
|
|
7889
|
+
function wrapMacConstructor(keyLen, macCons, fromMsg) {
|
|
7890
|
+
const mac = macCons;
|
|
7891
|
+
const getArgs = (fromMsg || (() => []));
|
|
7892
|
+
const macC = (msg, key) => mac(key, ...getArgs(msg))
|
|
7893
|
+
.update(msg)
|
|
7894
|
+
.digest();
|
|
7895
|
+
const tmp = mac(new Uint8Array(keyLen), ...getArgs(new Uint8Array(0)));
|
|
7896
|
+
macC.outputLen = tmp.outputLen;
|
|
7897
|
+
macC.blockLen = tmp.blockLen;
|
|
7898
|
+
macC.create = (key, ...args) => mac(key, ...args);
|
|
7899
|
+
return macC;
|
|
7900
|
+
}
|
|
7901
|
+
/**
|
|
7902
|
+
* Wraps a cipher: validates args, ensures encrypt() can only be called once.
|
|
7903
|
+
* Used internally by the exported cipher constructors.
|
|
7904
|
+
* Output-buffer support is inferred from the wrapped `encrypt` / `decrypt`
|
|
7905
|
+
* arity (`fn.length === 2`), and tag-bearing constructors are expected to use
|
|
7906
|
+
* `args[1]` for optional AAD.
|
|
7907
|
+
* @__NO_SIDE_EFFECTS__
|
|
7908
|
+
* @param params - Static cipher metadata. See {@link CipherParams}.
|
|
7909
|
+
* @param constructor - Cipher constructor.
|
|
7910
|
+
* @returns Wrapped constructor with validation.
|
|
7911
|
+
*/
|
|
7912
|
+
const wrapCipher = (params, constructor) => {
|
|
7913
|
+
function wrappedCipher(key, ...args) {
|
|
7914
|
+
// Validate key
|
|
7915
|
+
abytes$1(key, undefined, 'key');
|
|
7916
|
+
// Validate nonce if nonceLength is present
|
|
7917
|
+
if (params.nonceLength !== undefined) {
|
|
7918
|
+
const nonce = args[0];
|
|
7919
|
+
abytes$1(nonce, params.varSizeNonce ? undefined : params.nonceLength, 'nonce');
|
|
7920
|
+
}
|
|
7921
|
+
// Validate AAD if tagLength present
|
|
7922
|
+
const tagl = params.tagLength;
|
|
7923
|
+
if (tagl && args[1] !== undefined)
|
|
7924
|
+
abytes$1(args[1], undefined, 'AAD');
|
|
7925
|
+
const cipher = constructor(key, ...args);
|
|
7926
|
+
const checkOutput = (fnLength, output) => {
|
|
7927
|
+
if (output !== undefined) {
|
|
7928
|
+
if (fnLength !== 2)
|
|
7929
|
+
throw new Error('cipher output not supported');
|
|
7930
|
+
abytes$1(output, undefined, 'output');
|
|
7931
|
+
}
|
|
7932
|
+
};
|
|
7933
|
+
// Create wrapped cipher with validation and single-use encryption
|
|
7934
|
+
let called = false;
|
|
7935
|
+
const wrCipher = {
|
|
7936
|
+
encrypt(data, output) {
|
|
7937
|
+
if (called)
|
|
7938
|
+
throw new Error('cannot encrypt() twice with same key + nonce');
|
|
7939
|
+
called = true;
|
|
7940
|
+
abytes$1(data);
|
|
7941
|
+
checkOutput(cipher.encrypt.length, output);
|
|
7942
|
+
return cipher.encrypt(data, output);
|
|
7943
|
+
},
|
|
7944
|
+
decrypt(data, output) {
|
|
7945
|
+
abytes$1(data);
|
|
7946
|
+
if (tagl && data.length < tagl)
|
|
7947
|
+
throw new Error('"ciphertext" expected length bigger than tagLength=' + tagl);
|
|
7948
|
+
checkOutput(cipher.decrypt.length, output);
|
|
7949
|
+
return cipher.decrypt(data, output);
|
|
7950
|
+
},
|
|
7951
|
+
};
|
|
7952
|
+
return wrCipher;
|
|
7953
|
+
}
|
|
7954
|
+
Object.assign(wrappedCipher, params);
|
|
7955
|
+
return wrappedCipher;
|
|
7956
|
+
};
|
|
7957
|
+
/**
|
|
7958
|
+
* By default, returns u8a of length.
|
|
7959
|
+
* When out is available, it checks it for validity and uses it.
|
|
7960
|
+
* @param expectedLength - Required output length.
|
|
7961
|
+
* @param out - Optional destination buffer.
|
|
7962
|
+
* @param onlyAligned - Whether `out` must be 4-byte aligned.
|
|
7963
|
+
* @returns Output buffer ready for writing.
|
|
7964
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
7965
|
+
* @throws If the provided output buffer has the wrong size or alignment. {@link Error}
|
|
7966
|
+
* @example
|
|
7967
|
+
* Reuses a caller-provided output buffer when lengths match.
|
|
7968
|
+
*
|
|
7969
|
+
* ```ts
|
|
7970
|
+
* getOutput(16, new Uint8Array(16));
|
|
7971
|
+
* ```
|
|
7972
|
+
*/
|
|
7973
|
+
function getOutput(expectedLength, out, onlyAligned = true) {
|
|
7974
|
+
if (out === undefined)
|
|
7975
|
+
return new Uint8Array(expectedLength);
|
|
7976
|
+
// Keep Buffer/cross-realm Uint8Array support here instead of trusting a shape-compatible object.
|
|
7977
|
+
abytes$1(out, undefined, 'output');
|
|
7978
|
+
if (out.length !== expectedLength)
|
|
7979
|
+
throw new Error('"output" expected Uint8Array of length ' + expectedLength + ', got: ' + out.length);
|
|
7980
|
+
if (onlyAligned && !isAligned32(out))
|
|
7981
|
+
throw new Error('invalid output, must be aligned');
|
|
7982
|
+
return out;
|
|
7983
|
+
}
|
|
7984
|
+
/**
|
|
7985
|
+
* Encodes data and AAD bit lengths into a 16-byte buffer.
|
|
7986
|
+
* @param dataLength - Data length in bits.
|
|
7987
|
+
* @param aadLength - AAD length in bits.
|
|
7988
|
+
* The serialized block is still `aadLength || dataLength`, matching GCM/Poly1305
|
|
7989
|
+
* conventions even though the helper parameter order is `(dataLength, aadLength)`.
|
|
7990
|
+
* @param isLE - Whether to encode lengths as little-endian.
|
|
7991
|
+
* @returns 16-byte length block.
|
|
7992
|
+
* @throws On wrong argument types passed to the endian validator. {@link TypeError}
|
|
7993
|
+
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
7994
|
+
* @example
|
|
7995
|
+
* Builds the length block appended by GCM and Poly1305.
|
|
7996
|
+
*
|
|
7997
|
+
* ```ts
|
|
7998
|
+
* u64Lengths(16, 8, true);
|
|
7999
|
+
* ```
|
|
8000
|
+
*/
|
|
8001
|
+
function u64Lengths(dataLength, aadLength, isLE) {
|
|
8002
|
+
// Reject coercible non-number lengths like '10' and true before BigInt(...) accepts them.
|
|
8003
|
+
anumber$1(dataLength);
|
|
8004
|
+
anumber$1(aadLength);
|
|
8005
|
+
abool(isLE);
|
|
8006
|
+
const num = new Uint8Array(16);
|
|
8007
|
+
const view = createView$1(num);
|
|
8008
|
+
view.setBigUint64(0, BigInt(aadLength), isLE);
|
|
8009
|
+
view.setBigUint64(8, BigInt(dataLength), isLE);
|
|
8010
|
+
return num;
|
|
8011
|
+
}
|
|
8012
|
+
/**
|
|
8013
|
+
* Checks whether a byte array is aligned to a 4-byte offset.
|
|
8014
|
+
* @param bytes - Byte array to inspect.
|
|
8015
|
+
* @returns `true` when the view is 4-byte aligned.
|
|
8016
|
+
* @example
|
|
8017
|
+
* Checks whether a buffer can be safely viewed as Uint32Array.
|
|
8018
|
+
*
|
|
8019
|
+
* ```ts
|
|
8020
|
+
* isAligned32(new Uint8Array(4));
|
|
8021
|
+
* ```
|
|
8022
|
+
*/
|
|
8023
|
+
function isAligned32(bytes) {
|
|
8024
|
+
return bytes.byteOffset % 4 === 0;
|
|
8025
|
+
}
|
|
8026
|
+
/**
|
|
8027
|
+
* Copies bytes into a new Uint8Array.
|
|
8028
|
+
* @param bytes - Bytes to copy.
|
|
8029
|
+
* @returns Copied byte array.
|
|
8030
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
8031
|
+
* @example
|
|
8032
|
+
* Copies input into an aligned Uint8Array before block processing.
|
|
8033
|
+
*
|
|
8034
|
+
* ```ts
|
|
8035
|
+
* copyBytes(new Uint8Array([1, 2]));
|
|
8036
|
+
* ```
|
|
8037
|
+
*/
|
|
8038
|
+
function copyBytes(bytes) {
|
|
8039
|
+
// `Uint8Array.from(...)` would also accept arrays / other typed arrays. Keep this helper strict
|
|
8040
|
+
// because callers use it at byte-validation boundaries before mutating the detached copy.
|
|
8041
|
+
return Uint8Array.from(abytes$1(bytes));
|
|
8042
|
+
}
|
|
8043
|
+
|
|
8044
|
+
/**
|
|
8045
|
+
* GHash from AES-GCM and its little-endian "mirror image" Polyval from AES-SIV.
|
|
8046
|
+
*
|
|
8047
|
+
* Implemented in terms of GHash with conversion function for keys
|
|
8048
|
+
* GCM GHASH from
|
|
8049
|
+
* {@link https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf | NIST SP800-38d},
|
|
8050
|
+
* SIV from
|
|
8051
|
+
* {@link https://www.rfc-editor.org/rfc/rfc8452 | RFC 8452}.
|
|
8052
|
+
*
|
|
8053
|
+
* GHASH modulo: x^128 + x^7 + x^2 + x + 1
|
|
8054
|
+
* POLYVAL modulo: x^128 + x^127 + x^126 + x^121 + 1
|
|
8055
|
+
*
|
|
8056
|
+
* @module
|
|
8057
|
+
*/
|
|
8058
|
+
const BLOCK_SIZE$1 = 16;
|
|
8059
|
+
// TODO: rewrite
|
|
8060
|
+
// temporary padding buffer
|
|
8061
|
+
// ZEROS32 aliases these bytes, so clean(ZEROS32) also resets this shared tail-padding scratch.
|
|
8062
|
+
const ZEROS16 = /* @__PURE__ */ new Uint8Array(16);
|
|
8063
|
+
const ZEROS32 = /* @__PURE__ */ u32(ZEROS16);
|
|
8064
|
+
// GHASH reduces modulo x^128 + x^7 + x^2 + x + 1, so the low-degree terms
|
|
8065
|
+
// x^7 + x^2 + x + 1 become bits `11100001` = 0xe1 in R = 0xe1 || 0^120.
|
|
8066
|
+
const POLY$1 = 0xe1;
|
|
8067
|
+
// v = 2*v % POLY
|
|
8068
|
+
// NOTE: because x + x = 0 (add/sub is same), mul2(x) != x+x
|
|
8069
|
+
// Montgomery ladder can multiply any field element with this doubling step;
|
|
8070
|
+
// addition stays simple xor.
|
|
8071
|
+
const mul2$1 = (s0, s1, s2, s3) => {
|
|
8072
|
+
const hiBit = s3 & 1;
|
|
8073
|
+
return {
|
|
8074
|
+
s3: (s2 << 31) | (s3 >>> 1),
|
|
8075
|
+
s2: (s1 << 31) | (s2 >>> 1),
|
|
8076
|
+
s1: (s0 << 31) | (s1 >>> 1),
|
|
8077
|
+
// NIST SP 800-38D §6.3 applies `V >> 1` and XORs R on carry. In this
|
|
8078
|
+
// 4x32-bit split, R = 0xe1 || 0^120 lives in the top byte of s0.
|
|
8079
|
+
s0: (s0 >>> 1) ^ ((POLY$1 << 24) & -(hiBit & 1)), // reduce % poly
|
|
8080
|
+
};
|
|
8081
|
+
};
|
|
8082
|
+
// Per-word part of RFC 8452 `ByteReverse`; callers also reverse the 32-bit word order.
|
|
8083
|
+
const swapLE = (n) => (((n >>> 0) & 0xff) << 24) |
|
|
8084
|
+
(((n >>> 8) & 0xff) << 16) |
|
|
8085
|
+
(((n >>> 16) & 0xff) << 8) |
|
|
8086
|
+
((n >>> 24) & 0xff) |
|
|
8087
|
+
0;
|
|
8088
|
+
// Precompute-window heuristic only: larger inputs trade memory for fewer table lookups.
|
|
8089
|
+
// Any caller-provided length hint still collapses to one of the supported windows {2, 4, 8}.
|
|
8090
|
+
const estimateWindow = (bytes) => {
|
|
8091
|
+
if (bytes > 64 * 1024)
|
|
8092
|
+
return 8;
|
|
8093
|
+
if (bytes > 1024)
|
|
8094
|
+
return 4;
|
|
8095
|
+
return 2;
|
|
8096
|
+
};
|
|
8097
|
+
/**
|
|
8098
|
+
* Incremental GHASH state for AES-GCM.
|
|
8099
|
+
* @param key - 16-byte GHASH key.
|
|
8100
|
+
* @param expectedLength - Expected message length for table sizing.
|
|
8101
|
+
* Chunking is segment-based, not hash-streaming: every `update()` call is zero-padded
|
|
8102
|
+
* to the next 16-byte boundary before it is absorbed. This matches the internal AES/GCM
|
|
8103
|
+
* use where AAD, payload, and length block are separate padded segments.
|
|
8104
|
+
* @example
|
|
8105
|
+
* Feeds one ciphertext block into an incremental GHASH state with a fresh hash key.
|
|
8106
|
+
*
|
|
8107
|
+
* ```ts
|
|
8108
|
+
* import { GHASH } from '@noble/ciphers/_polyval.js';
|
|
8109
|
+
* import { randomBytes } from '@noble/ciphers/utils.js';
|
|
8110
|
+
* const key = randomBytes(16);
|
|
8111
|
+
* const mac = new GHASH(key);
|
|
8112
|
+
* mac.update(new Uint8Array(16));
|
|
8113
|
+
* mac.digest();
|
|
8114
|
+
* ```
|
|
8115
|
+
*/
|
|
8116
|
+
class GHASH {
|
|
8117
|
+
blockLen = BLOCK_SIZE$1;
|
|
8118
|
+
outputLen = BLOCK_SIZE$1;
|
|
8119
|
+
s0 = 0;
|
|
8120
|
+
s1 = 0;
|
|
8121
|
+
s2 = 0;
|
|
8122
|
+
s3 = 0;
|
|
8123
|
+
finished = false;
|
|
8124
|
+
destroyed = false;
|
|
8125
|
+
t;
|
|
8126
|
+
W;
|
|
8127
|
+
windowSize;
|
|
8128
|
+
// We select bits per window adaptively based on expectedLength
|
|
8129
|
+
constructor(key, expectedLength) {
|
|
8130
|
+
abytes$1(key, 16, 'key');
|
|
8131
|
+
key = copyBytes(key);
|
|
8132
|
+
const kView = createView$1(key);
|
|
8133
|
+
let k0 = kView.getUint32(0, false);
|
|
8134
|
+
let k1 = kView.getUint32(4, false);
|
|
8135
|
+
let k2 = kView.getUint32(8, false);
|
|
8136
|
+
let k3 = kView.getUint32(12, false);
|
|
8137
|
+
// generate table of doubled keys (half of montgomery ladder)
|
|
8138
|
+
const doubles = [];
|
|
8139
|
+
for (let i = 0; i < 128; i++) {
|
|
8140
|
+
doubles.push({ s0: swapLE(k0), s1: swapLE(k1), s2: swapLE(k2), s3: swapLE(k3) });
|
|
8141
|
+
({ s0: k0, s1: k1, s2: k2, s3: k3 } = mul2$1(k0, k1, k2, k3));
|
|
8142
|
+
}
|
|
8143
|
+
const W = estimateWindow(expectedLength || 1024);
|
|
8144
|
+
if (![1, 2, 4, 8].includes(W))
|
|
8145
|
+
throw new Error('ghash: invalid window size, expected 2, 4 or 8');
|
|
8146
|
+
this.W = W;
|
|
8147
|
+
const bits = 128; // always 128 bits;
|
|
8148
|
+
const windows = bits / W;
|
|
8149
|
+
const windowSize = (this.windowSize = 2 ** W);
|
|
8150
|
+
const items = [];
|
|
8151
|
+
// Create precompute table for window of W bits
|
|
8152
|
+
for (let w = 0; w < windows; w++) {
|
|
8153
|
+
// truth table: 00, 01, 10, 11
|
|
8154
|
+
for (let byte = 0; byte < windowSize; byte++) {
|
|
8155
|
+
// prettier-ignore
|
|
8156
|
+
let s0 = 0, s1 = 0, s2 = 0, s3 = 0;
|
|
8157
|
+
for (let j = 0; j < W; j++) {
|
|
8158
|
+
const bit = (byte >>> (W - j - 1)) & 1;
|
|
8159
|
+
if (!bit)
|
|
8160
|
+
continue;
|
|
8161
|
+
const { s0: d0, s1: d1, s2: d2, s3: d3 } = doubles[W * w + j];
|
|
8162
|
+
((s0 ^= d0), (s1 ^= d1), (s2 ^= d2), (s3 ^= d3));
|
|
8163
|
+
}
|
|
8164
|
+
items.push({ s0, s1, s2, s3 });
|
|
8165
|
+
}
|
|
8166
|
+
}
|
|
8167
|
+
this.t = items;
|
|
8168
|
+
}
|
|
8169
|
+
_updateBlock(s0, s1, s2, s3) {
|
|
8170
|
+
((s0 ^= this.s0), (s1 ^= this.s1), (s2 ^= this.s2), (s3 ^= this.s3));
|
|
8171
|
+
const { W, t, windowSize } = this;
|
|
8172
|
+
// prettier-ignore
|
|
8173
|
+
let o0 = 0, o1 = 0, o2 = 0, o3 = 0;
|
|
8174
|
+
const mask = (1 << W) - 1; // 2**W will kill performance.
|
|
8175
|
+
let w = 0;
|
|
8176
|
+
// NIST SP 800-38D §6.3 interprets blocks as little-endian polynomials,
|
|
8177
|
+
// so the lookup walk consumes each word byte-by-byte from
|
|
8178
|
+
// least-significant to most-significant bits.
|
|
8179
|
+
for (const num of [s0, s1, s2, s3]) {
|
|
8180
|
+
for (let bytePos = 0; bytePos < 4; bytePos++) {
|
|
8181
|
+
const byte = (num >>> (8 * bytePos)) & 0xff;
|
|
8182
|
+
for (let bitPos = 8 / W - 1; bitPos >= 0; bitPos--) {
|
|
8183
|
+
const bit = (byte >>> (W * bitPos)) & mask;
|
|
8184
|
+
const { s0: e0, s1: e1, s2: e2, s3: e3 } = t[w * windowSize + bit];
|
|
8185
|
+
((o0 ^= e0), (o1 ^= e1), (o2 ^= e2), (o3 ^= e3));
|
|
8186
|
+
w += 1;
|
|
8187
|
+
}
|
|
8188
|
+
}
|
|
8189
|
+
}
|
|
8190
|
+
this.s0 = o0;
|
|
8191
|
+
this.s1 = o1;
|
|
8192
|
+
this.s2 = o2;
|
|
8193
|
+
this.s3 = o3;
|
|
8194
|
+
}
|
|
8195
|
+
update(data) {
|
|
8196
|
+
aexists$1(this);
|
|
8197
|
+
abytes$1(data);
|
|
8198
|
+
data = copyBytes(data);
|
|
8199
|
+
const b32 = u32(data);
|
|
8200
|
+
const blocks = Math.floor(data.length / BLOCK_SIZE$1);
|
|
8201
|
+
const left = data.length % BLOCK_SIZE$1;
|
|
8202
|
+
for (let i = 0; i < blocks; i++) {
|
|
8203
|
+
this._updateBlock(swap8IfBE(b32[i * 4 + 0]), swap8IfBE(b32[i * 4 + 1]), swap8IfBE(b32[i * 4 + 2]), swap8IfBE(b32[i * 4 + 3]));
|
|
8204
|
+
}
|
|
8205
|
+
if (left) {
|
|
8206
|
+
ZEROS16.set(data.subarray(blocks * BLOCK_SIZE$1));
|
|
8207
|
+
// Tail blocks go through the shared ZEROS32 scratch, so they need the same host-endian
|
|
8208
|
+
// normalization as full blocks; otherwise segmented GHASH/POLYVAL updates diverge on BE.
|
|
8209
|
+
this._updateBlock(swap8IfBE(ZEROS32[0]), swap8IfBE(ZEROS32[1]), swap8IfBE(ZEROS32[2]), swap8IfBE(ZEROS32[3]));
|
|
8210
|
+
clean$1(ZEROS32); // clean tmp buffer
|
|
8211
|
+
}
|
|
8212
|
+
return this;
|
|
8213
|
+
}
|
|
8214
|
+
destroy() {
|
|
8215
|
+
// `aexists(this)` guards update/digest paths, so destroy must mark the instance unusable too.
|
|
8216
|
+
this.destroyed = true;
|
|
8217
|
+
const { t } = this;
|
|
8218
|
+
// Wipe the key-derived precompute table; scalar accumulator words remain,
|
|
8219
|
+
// but the destroyed guard blocks further use.
|
|
8220
|
+
// clean precompute table
|
|
8221
|
+
for (const elm of t) {
|
|
8222
|
+
((elm.s0 = 0), (elm.s1 = 0), (elm.s2 = 0), (elm.s3 = 0));
|
|
8223
|
+
}
|
|
8224
|
+
}
|
|
8225
|
+
digestInto(out) {
|
|
8226
|
+
aexists$1(this);
|
|
8227
|
+
// `digestInto(out)` is the no-allocation fast path, so callers must pass a
|
|
8228
|
+
// 32-bit-aligned buffer before we reinterpret it with `u32(out)`.
|
|
8229
|
+
aoutput$1(out, this, true);
|
|
8230
|
+
this.finished = true;
|
|
8231
|
+
// NIST SP 800-38D §6.4 returns the final 128-bit block Y_m.
|
|
8232
|
+
// `digestInto()` follows the relaxed `aoutput()` contract, so only
|
|
8233
|
+
// out[0..15] may be touched.
|
|
8234
|
+
const { s0, s1, s2, s3 } = this;
|
|
8235
|
+
const o32 = u32(out);
|
|
8236
|
+
o32[0] = s0;
|
|
8237
|
+
o32[1] = s1;
|
|
8238
|
+
o32[2] = s2;
|
|
8239
|
+
o32[3] = s3;
|
|
8240
|
+
swap32IfBE(o32);
|
|
8241
|
+
}
|
|
8242
|
+
digest() {
|
|
8243
|
+
const res = new Uint8Array(BLOCK_SIZE$1);
|
|
8244
|
+
this.digestInto(res);
|
|
8245
|
+
// `res` is independent of internal state, so it stays valid after destroy() wipes the table.
|
|
8246
|
+
this.destroy();
|
|
8247
|
+
return res;
|
|
8248
|
+
}
|
|
8249
|
+
}
|
|
8250
|
+
/**
|
|
8251
|
+
* GHash MAC for AES-GCM.
|
|
8252
|
+
* @param msg - Message bytes to authenticate.
|
|
8253
|
+
* @param key - 16-byte GHASH key.
|
|
8254
|
+
* @returns 16-byte authentication tag.
|
|
8255
|
+
* @example
|
|
8256
|
+
* Authenticates a short message with GHASH and a fresh hash key.
|
|
8257
|
+
*
|
|
8258
|
+
* ```ts
|
|
8259
|
+
* import { ghash } from '@noble/ciphers/_polyval.js';
|
|
8260
|
+
* import { randomBytes } from '@noble/ciphers/utils.js';
|
|
8261
|
+
* const key = randomBytes(16);
|
|
8262
|
+
* ghash(new Uint8Array(), key);
|
|
8263
|
+
* ```
|
|
8264
|
+
*/
|
|
8265
|
+
const ghash =
|
|
8266
|
+
/* @__PURE__ */ wrapMacConstructor(16, (key, expectedLength) => new GHASH(key, expectedLength), (msg) => [msg.length]);
|
|
8267
|
+
|
|
8268
|
+
/**
|
|
8269
|
+
* {@link https://en.wikipedia.org/wiki/Advanced_Encryption_Standard | AES}
|
|
8270
|
+
* a.k.a. Advanced Encryption Standard
|
|
8271
|
+
* is a variant of Rijndael block cipher, standardized by NIST in 2001.
|
|
8272
|
+
* We provide the fastest available pure JS implementation.
|
|
8273
|
+
*
|
|
8274
|
+
* `cipher = encrypt(block, key)`
|
|
8275
|
+
*
|
|
8276
|
+
* Data is split into 128-bit blocks.
|
|
8277
|
+
* Encrypted in 10/12/14 rounds (128/192/256 bits). In every round:
|
|
8278
|
+
* 1. **S-box**, table substitution
|
|
8279
|
+
* 2. **Shift rows**, cyclic shift left of all rows of data array
|
|
8280
|
+
* 3. **Mix columns**, multiplying every column by fixed polynomial
|
|
8281
|
+
* 4. **Add round key**, round_key xor i-th column of array
|
|
8282
|
+
*
|
|
8283
|
+
* Check out
|
|
8284
|
+
* {@link https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf | FIPS-197},
|
|
8285
|
+
* {@link https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf | NIST 800-38G},
|
|
8286
|
+
* and {@link https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf | original proposal}.
|
|
8287
|
+
* @module
|
|
8288
|
+
*/
|
|
8289
|
+
const BLOCK_SIZE = 16;
|
|
8290
|
+
// AES operates on 16-byte blocks, i.e. 4 32-bit words.
|
|
8291
|
+
const BLOCK_SIZE32 = 4;
|
|
8292
|
+
// Shared zero block (`0^128`) used by GCM's `H = CIPH_K(0^128)` / J0 scratch
|
|
8293
|
+
// and by CMAC / SIV helpers; callers take `.slice()` before mutating it.
|
|
8294
|
+
const EMPTY_BLOCK = /* @__PURE__ */ new Uint8Array(BLOCK_SIZE);
|
|
8295
|
+
const POLY = 0x11b; // 1 + x + x**3 + x**4 + x**8
|
|
8296
|
+
// Validates plain AES key sizes only; AES-SIV's doubled-key contract is checked elsewhere.
|
|
8297
|
+
function validateKeyLength(key) {
|
|
8298
|
+
if (![16, 24, 32].includes(key.length))
|
|
8299
|
+
throw new Error('"aes key" expected Uint8Array of length 16/24/32, got length=' + key.length);
|
|
8300
|
+
}
|
|
8301
|
+
// TODO: remove multiplication, binary ops only
|
|
8302
|
+
// Doubles one GF(2^8) field element; callers are expected to stay in byte range.
|
|
8303
|
+
// FIPS 197 upd1 §4.3 equation (4.5): XTIMES(b) left-shifts by one and, when
|
|
8304
|
+
// b7=1, reduces by m(x); using POLY=0x11b here yields the same byte result
|
|
8305
|
+
// as XORing with {1b} after the shift.
|
|
8306
|
+
function mul2(n) {
|
|
8307
|
+
return (n << 1) ^ (POLY & -(n >> 7));
|
|
8308
|
+
}
|
|
8309
|
+
// Shift-and-add multiplication in GF(2^8); callers are expected to pass byte values.
|
|
8310
|
+
// FIPS 197 upd1 §4.3 equation (4.7): general products are XORs of repeated
|
|
8311
|
+
// XTIMES() multiples, e.g. {57}•{13} = {57}⊕{ae}⊕{07}.
|
|
8312
|
+
function mul(a, b) {
|
|
8313
|
+
let res = 0;
|
|
8314
|
+
for (; b > 0; b >>= 1) {
|
|
8315
|
+
// Usual shift-and-add step in GF(2^8), not a scalar-multiplication ladder.
|
|
8316
|
+
res ^= a & -(b & 1); // if (b&1) res ^=a (but const-time).
|
|
8317
|
+
a = mul2(a); // a = 2*a
|
|
8318
|
+
}
|
|
8319
|
+
return res;
|
|
8320
|
+
}
|
|
8321
|
+
// AES S-box is generated using finite field inversion,
|
|
8322
|
+
// an affine transform, and xor of a constant 0x63.
|
|
8323
|
+
const sbox = /* @__PURE__ */ (() => {
|
|
8324
|
+
const t = new Uint8Array(256);
|
|
8325
|
+
// Repeated multiplication by {03} walks all 255 nonzero field elements
|
|
8326
|
+
// once, so t[255 - i] is the multiplicative inverse of t[i] for the
|
|
8327
|
+
// affine step.
|
|
8328
|
+
for (let i = 0, x = 1; i < 256; i++, x ^= mul2(x))
|
|
8329
|
+
t[i] = x;
|
|
8330
|
+
const box = new Uint8Array(256);
|
|
8331
|
+
// FIPS 197 upd1 §5.1.1: SBOX({00}) = {63} because the inverse step leaves
|
|
8332
|
+
// {00} at {00}, then the affine transform xors in c = {63}.
|
|
8333
|
+
box[0] = 0x63;
|
|
8334
|
+
for (let i = 0; i < 255; i++) {
|
|
8335
|
+
let x = t[255 - i];
|
|
8336
|
+
x |= x << 8;
|
|
8337
|
+
box[t[i]] = (x ^ (x >> 4) ^ (x >> 5) ^ (x >> 6) ^ (x >> 7) ^ 0x63) & 0xff;
|
|
8338
|
+
}
|
|
8339
|
+
clean$1(t);
|
|
8340
|
+
return box;
|
|
8341
|
+
})();
|
|
8342
|
+
// FIPS 197 upd1 §5.2: ROTWORD([a0,a1,a2,a3]) = [a1,a2,a3,a0]; with this LE
|
|
8343
|
+
// word packing that is a right rotate by 8 bits.
|
|
8344
|
+
const rotr32_8 = (n) => (n << 24) | (n >>> 8);
|
|
8345
|
+
// LE T-table helper: rotates one precomputed word by one byte so T1/T2/T3
|
|
8346
|
+
// reuse T0's substitution/mix result in the other byte lanes.
|
|
8347
|
+
const rotl32_8 = (n) => (n << 8) | (n >>> 24);
|
|
8348
|
+
// T-table is optimization suggested in 5.2 of original proposal (missed from FIPS-197). Changes:
|
|
8349
|
+
// - LE instead of BE
|
|
8350
|
+
// - bigger tables: T0 and T1 are merged into T01 table and T2 & T3 into T23;
|
|
8351
|
+
// so index is u16, instead of u8. This speeds up things, unexpectedly
|
|
8352
|
+
function genTtable(sbox, fn) {
|
|
8353
|
+
if (sbox.length !== 256)
|
|
8354
|
+
throw new Error('Wrong sbox length');
|
|
8355
|
+
const T0 = new Uint32Array(256).map((_, j) => fn(sbox[j]));
|
|
8356
|
+
const T1 = T0.map(rotl32_8);
|
|
8357
|
+
const T2 = T1.map(rotl32_8);
|
|
8358
|
+
const T3 = T2.map(rotl32_8);
|
|
8359
|
+
// Pre-xor adjacent lanes so apply0123/applySbox can fetch two substituted
|
|
8360
|
+
// byte lanes per lookup in the LE round layout.
|
|
8361
|
+
const T01 = new Uint32Array(256 * 256);
|
|
8362
|
+
const T23 = new Uint32Array(256 * 256);
|
|
8363
|
+
const sbox2 = new Uint16Array(256 * 256);
|
|
8364
|
+
for (let i = 0; i < 256; i++) {
|
|
8365
|
+
for (let j = 0; j < 256; j++) {
|
|
8366
|
+
const idx = i * 256 + j;
|
|
8367
|
+
T01[idx] = T0[i] ^ T1[j];
|
|
8368
|
+
T23[idx] = T2[i] ^ T3[j];
|
|
8369
|
+
sbox2[idx] = (sbox[i] << 8) | sbox[j];
|
|
8370
|
+
}
|
|
8371
|
+
}
|
|
8372
|
+
return { sbox, sbox2, T0, T1, T2, T3, T01, T23 };
|
|
8373
|
+
}
|
|
8374
|
+
// Forward round precompute: the packed word stores the MIXCOLUMNS row
|
|
8375
|
+
// [{02},{01},{01},{03}] in LE byte-lane order, and the returned `sbox2`
|
|
8376
|
+
// is also reused by key expansion and the final round.
|
|
8377
|
+
const tableEncoding = /* @__PURE__ */ genTtable(sbox, (s) => (mul(s, 3) << 24) | (s << 16) | (s << 8) | mul(s, 2));
|
|
8378
|
+
// FIPS 197 upd1 §5.2 Table 5: left-most bytes of Rcon[j] = x^(j-1), generated by repeated XTIMES().
|
|
8379
|
+
const xPowers = /* @__PURE__ */ (() => {
|
|
8380
|
+
const p = new Uint8Array(16);
|
|
8381
|
+
for (let i = 0, x = 1; i < 16; i++, x = mul2(x))
|
|
8382
|
+
p[i] = x;
|
|
8383
|
+
return p;
|
|
8384
|
+
})();
|
|
8385
|
+
/** Forward AES key expansion used across ECB/CBC/CTR/GCM/CMAC/KW-style paths. */
|
|
8386
|
+
function expandKeyLE(key) {
|
|
8387
|
+
abytes$1(key);
|
|
8388
|
+
const len = key.length;
|
|
8389
|
+
validateKeyLength(key);
|
|
8390
|
+
const { sbox2 } = tableEncoding;
|
|
8391
|
+
const toClean = [];
|
|
8392
|
+
// Copy on BE or misaligned inputs so the LE word normalization below never
|
|
8393
|
+
// mutates caller key bytes in place.
|
|
8394
|
+
if (!isLE || !isAligned32(key))
|
|
8395
|
+
toClean.push((key = copyBytes(key)));
|
|
8396
|
+
const k32 = swap32IfBE(u32(key));
|
|
8397
|
+
const Nk = k32.length;
|
|
8398
|
+
// `applySbox` normally reads one byte lane from each argument; repeating
|
|
8399
|
+
// `n` across all four lanes turns it into SUBWORD(n).
|
|
8400
|
+
const subByte = (n) => applySbox(sbox2, n, n, n, n);
|
|
8401
|
+
// AES key sizes are 16/24/32 bytes, so len + 28 yields the 44/52/60
|
|
8402
|
+
// schedule words from FIPS 197 §5.2 / Table 3.
|
|
8403
|
+
const xk = new Uint32Array(len + 28); // expanded key
|
|
8404
|
+
xk.set(k32);
|
|
8405
|
+
// 4.3.1 Key expansion
|
|
8406
|
+
for (let i = Nk; i < xk.length; i++) {
|
|
8407
|
+
let t = xk[i - 1];
|
|
8408
|
+
if (i % Nk === 0)
|
|
8409
|
+
t = subByte(rotr32_8(t)) ^ xPowers[i / Nk - 1];
|
|
8410
|
+
else if (Nk > 6 && i % Nk === 4)
|
|
8411
|
+
t = subByte(t);
|
|
8412
|
+
xk[i] = xk[i - Nk] ^ t;
|
|
8413
|
+
}
|
|
8414
|
+
clean$1(...toClean);
|
|
8415
|
+
return xk;
|
|
8416
|
+
}
|
|
8417
|
+
// Apply tables
|
|
8418
|
+
function apply0123(T01, T23, s0, s1, s2, s3) {
|
|
8419
|
+
// `T01` takes the low byte lane from `s0` plus the next lane from `s1`;
|
|
8420
|
+
// `T23` does the same for `s2`/`s3`.
|
|
8421
|
+
// Equivalent to `T0[s0&0xff] ^ T1[(s1>>>8)&0xff] ^ T2[(s2>>>16)&0xff] ^
|
|
8422
|
+
// T3[s3>>>24]`, but with two merged-table fetches.
|
|
8423
|
+
return (T01[((s0 << 8) & 0xff00) | ((s1 >>> 8) & 0xff)] ^
|
|
8424
|
+
T23[((s2 >>> 8) & 0xff00) | ((s3 >>> 24) & 0xff)]);
|
|
8425
|
+
}
|
|
8426
|
+
function applySbox(sbox2, s0, s1, s2, s3) {
|
|
8427
|
+
// `sbox2` packs two substituted byte lanes at a time in the same LE
|
|
8428
|
+
// layout used by the round code.
|
|
8429
|
+
// Equivalent to `SBOX(byte0(s0)) | SBOX(byte1(s1))<<8 |
|
|
8430
|
+
// SBOX(byte2(s2))<<16 | SBOX(byte3(s3))<<24`.
|
|
8431
|
+
return (sbox2[(s0 & 0xff) | (s1 & 0xff00)] |
|
|
8432
|
+
(sbox2[((s2 >>> 16) & 0xff) | ((s3 >>> 16) & 0xff00)] << 16));
|
|
8433
|
+
}
|
|
8434
|
+
function encrypt(xk, s0, s1, s2, s3) {
|
|
8435
|
+
const { sbox2, T01, T23 } = tableEncoding;
|
|
8436
|
+
let k = 0;
|
|
8437
|
+
((s0 ^= xk[k++]), (s1 ^= xk[k++]), (s2 ^= xk[k++]), (s3 ^= xk[k++]));
|
|
8438
|
+
// `xk` has Nr+1 round-key blocks, so after the initial AddRoundKey and the
|
|
8439
|
+
// final S-box-only round there are Nr-1 full table/MixColumns rounds left.
|
|
8440
|
+
const rounds = xk.length / 4 - 2;
|
|
8441
|
+
for (let i = 0; i < rounds; i++) {
|
|
8442
|
+
const t0 = xk[k++] ^ apply0123(T01, T23, s0, s1, s2, s3);
|
|
8443
|
+
const t1 = xk[k++] ^ apply0123(T01, T23, s1, s2, s3, s0);
|
|
8444
|
+
const t2 = xk[k++] ^ apply0123(T01, T23, s2, s3, s0, s1);
|
|
8445
|
+
const t3 = xk[k++] ^ apply0123(T01, T23, s3, s0, s1, s2);
|
|
8446
|
+
((s0 = t0), (s1 = t1), (s2 = t2), (s3 = t3));
|
|
8447
|
+
}
|
|
8448
|
+
// last round (without mixcolumns, so using SBOX2 table)
|
|
8449
|
+
const t0 = xk[k++] ^ applySbox(sbox2, s0, s1, s2, s3);
|
|
8450
|
+
const t1 = xk[k++] ^ applySbox(sbox2, s1, s2, s3, s0);
|
|
8451
|
+
const t2 = xk[k++] ^ applySbox(sbox2, s2, s3, s0, s1);
|
|
8452
|
+
const t3 = xk[k++] ^ applySbox(sbox2, s3, s0, s1, s2);
|
|
8453
|
+
return { s0: t0, s1: t1, s2: t2, s3: t3 };
|
|
8454
|
+
}
|
|
8455
|
+
// AES CTR with overflowing 32 bit counter
|
|
8456
|
+
// It's possible to do 32le significantly simpler (and probably faster) by using u32.
|
|
8457
|
+
// But, we need both, and perf bottleneck is in ghash anyway.
|
|
8458
|
+
// Unsafe 32-bit CTR helper: mutates `nonce` in place, expects aligned `src`/`dst`,
|
|
8459
|
+
// and uses `isLE` to choose which 32-bit counter word is incremented.
|
|
8460
|
+
function ctr32(xk, isLE, nonce, src, dst) {
|
|
8461
|
+
abytes$1(nonce, BLOCK_SIZE, 'nonce');
|
|
8462
|
+
abytes$1(src);
|
|
8463
|
+
dst = getOutput(src.length, dst);
|
|
8464
|
+
const ctr = nonce; // write new value to nonce, so it can be re-used
|
|
8465
|
+
const c32 = u32(ctr);
|
|
8466
|
+
const view = createView$1(ctr);
|
|
8467
|
+
const src32 = u32(src);
|
|
8468
|
+
const dst32 = u32(dst);
|
|
8469
|
+
// NIST SP 800-38D GCTR increments the rightmost 32 bits of J0, while
|
|
8470
|
+
// RFC 8452 AES-GCM-SIV increments the first 32 bits as a little-endian u32.
|
|
8471
|
+
const ctrPos = isLE ? 0 : 12;
|
|
8472
|
+
const srcLen = src.length;
|
|
8473
|
+
// Fill block (empty, ctr=0)
|
|
8474
|
+
let ctrNum = view.getUint32(ctrPos, isLE); // read current counter value
|
|
8475
|
+
let { s0, s1, s2, s3 } = encrypt(xk, swap8IfBE(c32[0]), swap8IfBE(c32[1]), swap8IfBE(c32[2]), swap8IfBE(c32[3]));
|
|
8476
|
+
// process blocks
|
|
8477
|
+
for (let i = 0; i + 4 <= src32.length; i += 4) {
|
|
8478
|
+
dst32[i + 0] = src32[i + 0] ^ swap8IfBE(s0);
|
|
8479
|
+
dst32[i + 1] = src32[i + 1] ^ swap8IfBE(s1);
|
|
8480
|
+
dst32[i + 2] = src32[i + 2] ^ swap8IfBE(s2);
|
|
8481
|
+
dst32[i + 3] = src32[i + 3] ^ swap8IfBE(s3);
|
|
8482
|
+
ctrNum = (ctrNum + 1) >>> 0; // u32 wrap
|
|
8483
|
+
view.setUint32(ctrPos, ctrNum, isLE);
|
|
8484
|
+
({ s0, s1, s2, s3 } = encrypt(xk, swap8IfBE(c32[0]), swap8IfBE(c32[1]), swap8IfBE(c32[2]), swap8IfBE(c32[3])));
|
|
8485
|
+
}
|
|
8486
|
+
// leftovers (less than a block)
|
|
8487
|
+
const start = BLOCK_SIZE * Math.floor(src32.length / BLOCK_SIZE32);
|
|
8488
|
+
if (start < srcLen) {
|
|
8489
|
+
const b32 = new Uint32Array([s0, s1, s2, s3]);
|
|
8490
|
+
swap32IfBE(b32);
|
|
8491
|
+
const buf = u8$1(b32);
|
|
8492
|
+
for (let i = start, pos = 0; i < srcLen; i++, pos++)
|
|
8493
|
+
dst[i] = src[i] ^ buf[pos];
|
|
8494
|
+
clean$1(b32);
|
|
8495
|
+
}
|
|
8496
|
+
// Same unsafe contract as ctrCounter(): only full blocks advance the stored
|
|
8497
|
+
// mutable counter state; partial-block continuation is caller-managed.
|
|
8498
|
+
return dst;
|
|
8499
|
+
}
|
|
8500
|
+
// TODO: merge with chacha, however gcm has bitLen while chacha has byteLen
|
|
8501
|
+
// `data` is the payload covered by the polynomial MAC: ciphertext for GCM,
|
|
8502
|
+
// plaintext for GCM-SIV. Keep AAD/data/length as separate updates because
|
|
8503
|
+
// GHASH/POLYVAL pad each call to block boundaries, so the chunks must match the
|
|
8504
|
+
// spec-defined segments instead of arbitrary concatenation boundaries.
|
|
8505
|
+
function computeTag(fn, isLE, key, data, AAD) {
|
|
8506
|
+
const aadLength = AAD ? AAD.length : 0;
|
|
8507
|
+
const h = fn.create(key, data.length + aadLength);
|
|
8508
|
+
if (AAD)
|
|
8509
|
+
h.update(AAD);
|
|
8510
|
+
// u64Lengths() takes (dataBits, aadBits) but still serializes the final
|
|
8511
|
+
// block as len(AAD) || len(data), matching both GCM and GCM-SIV.
|
|
8512
|
+
const num = u64Lengths(8 * data.length, 8 * aadLength, isLE);
|
|
8513
|
+
h.update(data);
|
|
8514
|
+
h.update(num);
|
|
8515
|
+
const res = h.digest();
|
|
8516
|
+
clean$1(num);
|
|
8517
|
+
return res;
|
|
8518
|
+
}
|
|
8519
|
+
/**
|
|
8520
|
+
* **GCM** (Galois/Counter Mode): Combines CTR mode with polynomial MAC. Efficient and widely used.
|
|
8521
|
+
* Not perfect:
|
|
8522
|
+
* a) conservative key wear-out is `2**32` (4B) msgs.
|
|
8523
|
+
* b) key wear-out under random nonces is even smaller: `2**23` (8M) messages for `2**-50` chance.
|
|
8524
|
+
* c) MAC can be forged: see Poly1305 documentation.
|
|
8525
|
+
* @param key - AES key bytes.
|
|
8526
|
+
* @param nonce - Nonce bytes (12 recommended, minimum 8; other lengths use GHASH J0 derivation).
|
|
8527
|
+
* @param AAD - Additional authenticated data.
|
|
8528
|
+
* @returns AEAD cipher instance with a fixed 16-byte tag.
|
|
8529
|
+
* @example
|
|
8530
|
+
* Encrypts and authenticates plaintext with a fresh key and 12-byte nonce.
|
|
8531
|
+
*
|
|
8532
|
+
* ```ts
|
|
8533
|
+
* import { gcm } from '@noble/ciphers/aes.js';
|
|
8534
|
+
* import { randomBytes } from '@noble/ciphers/utils.js';
|
|
8535
|
+
* const key = randomBytes(16);
|
|
8536
|
+
* const nonce = randomBytes(12);
|
|
8537
|
+
* const cipher = gcm(key, nonce);
|
|
8538
|
+
* cipher.encrypt(new Uint8Array([1, 2, 3]));
|
|
8539
|
+
* ```
|
|
8540
|
+
*/
|
|
8541
|
+
const gcm = /* @__PURE__ */ wrapCipher({ blockSize: 16, nonceLength: 12, tagLength: 16, varSizeNonce: true }, function aesgcm(key, nonce, AAD) {
|
|
8542
|
+
// SP 800-38D lets implementations narrow supported IV lengths.
|
|
8543
|
+
// This wrapper intentionally requires at least 8 bytes; OpenSSL accepts shorter IVs too.
|
|
8544
|
+
// 12-byte nonces take the fast path; other allowed lengths use GHASH to derive J0.
|
|
8545
|
+
if (nonce.length < 8)
|
|
8546
|
+
throw new Error('aes/gcm: invalid nonce length');
|
|
8547
|
+
const tagLength = 16;
|
|
8548
|
+
function _computeTag(authKey, tagMask, data) {
|
|
8549
|
+
const tag = computeTag(ghash, false, authKey, data, AAD);
|
|
8550
|
+
for (let i = 0; i < tagMask.length; i++)
|
|
8551
|
+
tag[i] ^= tagMask[i];
|
|
8552
|
+
return tag;
|
|
8553
|
+
}
|
|
8554
|
+
function deriveKeys() {
|
|
8555
|
+
const xk = expandKeyLE(key);
|
|
8556
|
+
const authKey = EMPTY_BLOCK.slice();
|
|
8557
|
+
const counter = EMPTY_BLOCK.slice();
|
|
8558
|
+
ctr32(xk, false, counter, counter, authKey);
|
|
8559
|
+
// NIST 800-38d, page 15: different behavior for 96-bit and non-96-bit nonces
|
|
8560
|
+
if (nonce.length === 12) {
|
|
8561
|
+
counter.set(nonce);
|
|
8562
|
+
}
|
|
8563
|
+
else {
|
|
8564
|
+
const nonceLen = EMPTY_BLOCK.slice();
|
|
8565
|
+
const view = createView$1(nonceLen);
|
|
8566
|
+
view.setBigUint64(8, BigInt(nonce.length * 8), false);
|
|
8567
|
+
// GHASH.update() pads each call to 16 bytes, so
|
|
8568
|
+
// update(nonce).update(nonceLen) realizes
|
|
8569
|
+
// IV || 0^s || 0^64 || [len(IV)]_64 for non-96-bit nonces.
|
|
8570
|
+
// ghash(nonce || u64be(0) || u64be(nonceLen*8))
|
|
8571
|
+
const g = ghash.create(authKey).update(nonce).update(nonceLen);
|
|
8572
|
+
g.digestInto(counter); // digestInto doesn't trigger '.destroy'
|
|
8573
|
+
g.destroy();
|
|
8574
|
+
}
|
|
8575
|
+
// GCTR_K(J0, 0^128) = E_K(J0); reusing ctr32() here extracts that tag
|
|
8576
|
+
// mask and leaves `counter` advanced to inc32(J0) for payload GCTR.
|
|
8577
|
+
const tagMask = ctr32(xk, false, counter, EMPTY_BLOCK);
|
|
8578
|
+
return { xk, authKey, counter, tagMask };
|
|
8579
|
+
}
|
|
8580
|
+
return {
|
|
8581
|
+
encrypt(plaintext) {
|
|
8582
|
+
const { xk, authKey, counter, tagMask } = deriveKeys();
|
|
8583
|
+
const out = new Uint8Array(plaintext.length + tagLength);
|
|
8584
|
+
const toClean = [xk, authKey, counter, tagMask];
|
|
8585
|
+
if (!isAligned32(plaintext))
|
|
8586
|
+
toClean.push((plaintext = copyBytes(plaintext)));
|
|
8587
|
+
ctr32(xk, false, counter, plaintext, out.subarray(0, plaintext.length));
|
|
8588
|
+
const tag = _computeTag(authKey, tagMask, out.subarray(0, out.length - tagLength));
|
|
8589
|
+
toClean.push(tag);
|
|
8590
|
+
out.set(tag, plaintext.length);
|
|
8591
|
+
clean$1(...toClean);
|
|
8592
|
+
return out;
|
|
8593
|
+
},
|
|
8594
|
+
decrypt(ciphertext) {
|
|
8595
|
+
const { xk, authKey, counter, tagMask } = deriveKeys();
|
|
8596
|
+
const toClean = [xk, authKey, tagMask, counter];
|
|
8597
|
+
if (!isAligned32(ciphertext))
|
|
8598
|
+
toClean.push((ciphertext = copyBytes(ciphertext)));
|
|
8599
|
+
const data = ciphertext.subarray(0, -tagLength);
|
|
8600
|
+
const passedTag = ciphertext.subarray(-tagLength);
|
|
8601
|
+
const tag = _computeTag(authKey, tagMask, data);
|
|
8602
|
+
toClean.push(tag);
|
|
8603
|
+
// NIST SP 800-38D §7.2 permits equivalent step orderings; verify the
|
|
8604
|
+
// tag before CTR so unauthenticated plaintext is never materialized.
|
|
8605
|
+
if (!equalBytes(tag, passedTag)) {
|
|
8606
|
+
clean$1(...toClean);
|
|
8607
|
+
throw new Error('aes/gcm: invalid ghash tag');
|
|
8608
|
+
}
|
|
8609
|
+
const out = ctr32(xk, false, counter, data);
|
|
8610
|
+
clean$1(...toClean);
|
|
8611
|
+
return out;
|
|
8612
|
+
},
|
|
8613
|
+
};
|
|
8614
|
+
});
|
|
8615
|
+
|
|
8616
|
+
/**
|
|
8617
|
+
* Checks if something is Uint8Array. Be careful: nodejs Buffer will return true.
|
|
8618
|
+
* @param a - value to test
|
|
8619
|
+
* @returns `true` when the value is a Uint8Array-compatible view.
|
|
8620
|
+
* @example
|
|
8621
|
+
* Check whether a value is a Uint8Array-compatible view.
|
|
8622
|
+
* ```ts
|
|
8623
|
+
* isBytes(new Uint8Array([1, 2, 3]));
|
|
8624
|
+
* ```
|
|
8625
|
+
*/
|
|
8626
|
+
function isBytes(a) {
|
|
8627
|
+
// Plain `instanceof Uint8Array` is too strict for some Buffer / proxy / cross-realm cases.
|
|
8628
|
+
// The fallback still requires a real ArrayBuffer view, so plain
|
|
8629
|
+
// JSON-deserialized `{ constructor: ... }` spoofing is rejected, and
|
|
8630
|
+
// `BYTES_PER_ELEMENT === 1` keeps the fallback on byte-oriented views.
|
|
8631
|
+
return (a instanceof Uint8Array ||
|
|
8632
|
+
(ArrayBuffer.isView(a) &&
|
|
8633
|
+
a.constructor.name === 'Uint8Array' &&
|
|
8634
|
+
'BYTES_PER_ELEMENT' in a &&
|
|
8635
|
+
a.BYTES_PER_ELEMENT === 1));
|
|
8636
|
+
}
|
|
8637
|
+
/**
|
|
8638
|
+
* Asserts something is a non-negative integer.
|
|
8639
|
+
* @param n - number to validate
|
|
8640
|
+
* @param title - label included in thrown errors
|
|
8641
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
8642
|
+
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
8643
|
+
* @example
|
|
8644
|
+
* Validate a non-negative integer option.
|
|
8645
|
+
* ```ts
|
|
8646
|
+
* anumber(32, 'length');
|
|
8647
|
+
* ```
|
|
8648
|
+
*/
|
|
8649
|
+
function anumber(n, title = '') {
|
|
8650
|
+
if (typeof n !== 'number') {
|
|
8651
|
+
const prefix = title && `"${title}" `;
|
|
8652
|
+
throw new TypeError(`${prefix}expected number, got ${typeof n}`);
|
|
8653
|
+
}
|
|
8654
|
+
if (!Number.isSafeInteger(n) || n < 0) {
|
|
8655
|
+
const prefix = title && `"${title}" `;
|
|
8656
|
+
throw new RangeError(`${prefix}expected integer >= 0, got ${n}`);
|
|
8657
|
+
}
|
|
8658
|
+
}
|
|
8659
|
+
/**
|
|
8660
|
+
* Asserts something is Uint8Array.
|
|
8661
|
+
* @param value - value to validate
|
|
8662
|
+
* @param length - optional exact length constraint
|
|
8663
|
+
* @param title - label included in thrown errors
|
|
8664
|
+
* @returns The validated byte array.
|
|
8665
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
8666
|
+
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
8667
|
+
* @example
|
|
8668
|
+
* Validate that a value is a byte array.
|
|
8669
|
+
* ```ts
|
|
8670
|
+
* abytes(new Uint8Array([1, 2, 3]));
|
|
8671
|
+
* ```
|
|
8672
|
+
*/
|
|
8673
|
+
function abytes(value, length, title = '') {
|
|
8674
|
+
const bytes = isBytes(value);
|
|
8675
|
+
const len = value?.length;
|
|
8676
|
+
const needsLen = length !== undefined;
|
|
8677
|
+
if (!bytes || (needsLen && len !== length)) {
|
|
8678
|
+
const prefix = title && `"${title}" `;
|
|
8679
|
+
const ofLen = needsLen ? ` of length ${length}` : '';
|
|
8680
|
+
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
8681
|
+
const message = prefix + 'expected Uint8Array' + ofLen + ', got ' + got;
|
|
8682
|
+
if (!bytes)
|
|
8683
|
+
throw new TypeError(message);
|
|
8684
|
+
throw new RangeError(message);
|
|
8685
|
+
}
|
|
8686
|
+
return value;
|
|
8687
|
+
}
|
|
8688
|
+
/**
|
|
8689
|
+
* Asserts something is a wrapped hash constructor.
|
|
8690
|
+
* @param h - hash constructor to validate
|
|
8691
|
+
* @throws On wrong argument types or invalid hash wrapper shape. {@link TypeError}
|
|
8692
|
+
* @throws On invalid hash metadata ranges or values. {@link RangeError}
|
|
8693
|
+
* @throws If the hash metadata allows empty outputs or block sizes. {@link Error}
|
|
8694
|
+
* @example
|
|
8695
|
+
* Validate a callable hash wrapper.
|
|
8696
|
+
* ```ts
|
|
8697
|
+
* import { ahash } from '@noble/hashes/utils.js';
|
|
8698
|
+
* import { sha256 } from '@noble/hashes/sha2.js';
|
|
8699
|
+
* ahash(sha256);
|
|
8700
|
+
* ```
|
|
8701
|
+
*/
|
|
8702
|
+
function ahash(h) {
|
|
8703
|
+
if (typeof h !== 'function' || typeof h.create !== 'function')
|
|
8704
|
+
throw new TypeError('Hash must wrapped by utils.createHasher');
|
|
8705
|
+
anumber(h.outputLen);
|
|
8706
|
+
anumber(h.blockLen);
|
|
8707
|
+
// HMAC and KDF callers treat these as real byte lengths; allowing zero lets fake wrappers pass
|
|
8708
|
+
// validation and can produce empty outputs instead of failing fast.
|
|
8709
|
+
if (h.outputLen < 1)
|
|
8710
|
+
throw new Error('"outputLen" must be >= 1');
|
|
8711
|
+
if (h.blockLen < 1)
|
|
8712
|
+
throw new Error('"blockLen" must be >= 1');
|
|
8713
|
+
}
|
|
8714
|
+
/**
|
|
8715
|
+
* Asserts a hash instance has not been destroyed or finished.
|
|
8716
|
+
* @param instance - hash instance to validate
|
|
8717
|
+
* @param checkFinished - whether to reject finalized instances
|
|
8718
|
+
* @throws If the hash instance has already been destroyed or finalized. {@link Error}
|
|
8719
|
+
* @example
|
|
8720
|
+
* Validate that a hash instance is still usable.
|
|
8721
|
+
* ```ts
|
|
8722
|
+
* import { aexists } from '@noble/hashes/utils.js';
|
|
8723
|
+
* import { sha256 } from '@noble/hashes/sha2.js';
|
|
8724
|
+
* const hash = sha256.create();
|
|
8725
|
+
* aexists(hash);
|
|
8726
|
+
* ```
|
|
8727
|
+
*/
|
|
8728
|
+
function aexists(instance, checkFinished = true) {
|
|
8729
|
+
if (instance.destroyed)
|
|
8730
|
+
throw new Error('Hash instance has been destroyed');
|
|
8731
|
+
if (checkFinished && instance.finished)
|
|
8732
|
+
throw new Error('Hash#digest() has already been called');
|
|
8733
|
+
}
|
|
8734
|
+
/**
|
|
8735
|
+
* Asserts output is a sufficiently-sized byte array.
|
|
8736
|
+
* @param out - destination buffer
|
|
8737
|
+
* @param instance - hash instance providing output length
|
|
8738
|
+
* Oversized buffers are allowed; downstream code only promises to fill the first `outputLen` bytes.
|
|
8739
|
+
* @throws On wrong argument types. {@link TypeError}
|
|
8740
|
+
* @throws On wrong argument ranges or values. {@link RangeError}
|
|
8741
|
+
* @example
|
|
8742
|
+
* Validate a caller-provided digest buffer.
|
|
8743
|
+
* ```ts
|
|
8744
|
+
* import { aoutput } from '@noble/hashes/utils.js';
|
|
8745
|
+
* import { sha256 } from '@noble/hashes/sha2.js';
|
|
8746
|
+
* const hash = sha256.create();
|
|
8747
|
+
* aoutput(new Uint8Array(hash.outputLen), hash);
|
|
8748
|
+
* ```
|
|
8749
|
+
*/
|
|
8750
|
+
function aoutput(out, instance) {
|
|
8751
|
+
abytes(out, undefined, 'digestInto() output');
|
|
8752
|
+
const min = instance.outputLen;
|
|
8753
|
+
if (out.length < min) {
|
|
8754
|
+
throw new RangeError('"digestInto() output" expected to be of length >=' + min);
|
|
8755
|
+
}
|
|
8756
|
+
}
|
|
8757
|
+
/**
|
|
8758
|
+
* Zeroizes typed arrays in place. Warning: JS provides no guarantees.
|
|
8759
|
+
* @param arrays - arrays to overwrite with zeros
|
|
8760
|
+
* @example
|
|
8761
|
+
* Zeroize sensitive buffers in place.
|
|
8762
|
+
* ```ts
|
|
8763
|
+
* clean(new Uint8Array([1, 2, 3]));
|
|
8764
|
+
* ```
|
|
8765
|
+
*/
|
|
8766
|
+
function clean(...arrays) {
|
|
8767
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
8768
|
+
arrays[i].fill(0);
|
|
8769
|
+
}
|
|
8770
|
+
}
|
|
8771
|
+
/**
|
|
8772
|
+
* Creates a DataView for byte-level manipulation.
|
|
8773
|
+
* @param arr - source typed array
|
|
8774
|
+
* @returns DataView over the same buffer region.
|
|
8775
|
+
* @example
|
|
8776
|
+
* Create a DataView over an existing buffer.
|
|
8777
|
+
* ```ts
|
|
8778
|
+
* createView(new Uint8Array(4));
|
|
8779
|
+
* ```
|
|
8780
|
+
*/
|
|
8781
|
+
function createView(arr) {
|
|
8782
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
8783
|
+
}
|
|
8784
|
+
/**
|
|
8785
|
+
* Rotate-right operation for uint32 values.
|
|
8786
|
+
* @param word - source word
|
|
8787
|
+
* @param shift - shift amount in bits
|
|
8788
|
+
* @returns Rotated word.
|
|
8789
|
+
* @example
|
|
8790
|
+
* Rotate a 32-bit word to the right.
|
|
8791
|
+
* ```ts
|
|
8792
|
+
* rotr(0x12345678, 8);
|
|
8793
|
+
* ```
|
|
8794
|
+
*/
|
|
8795
|
+
function rotr(word, shift) {
|
|
8796
|
+
return (word << (32 - shift)) | (word >>> shift);
|
|
8797
|
+
}
|
|
8798
|
+
/**
|
|
8799
|
+
* Creates a callable hash function from a stateful class constructor.
|
|
8800
|
+
* @param hashCons - hash constructor or factory
|
|
8801
|
+
* @param info - optional metadata such as DER OID
|
|
8802
|
+
* @returns Frozen callable hash wrapper with `.create()`.
|
|
8803
|
+
* Wrapper construction eagerly calls `hashCons(undefined)` once to read
|
|
8804
|
+
* `outputLen` / `blockLen`, so constructor side effects happen at module
|
|
8805
|
+
* init time.
|
|
8806
|
+
* @example
|
|
8807
|
+
* Wrap a stateful hash constructor into a callable helper.
|
|
8808
|
+
* ```ts
|
|
8809
|
+
* import { createHasher } from '@noble/hashes/utils.js';
|
|
8810
|
+
* import { sha256 } from '@noble/hashes/sha2.js';
|
|
8811
|
+
* const wrapped = createHasher(sha256.create, { oid: sha256.oid });
|
|
8812
|
+
* wrapped(new Uint8Array([1]));
|
|
8813
|
+
* ```
|
|
8814
|
+
*/
|
|
8815
|
+
function createHasher(hashCons, info = {}) {
|
|
8816
|
+
const hashC = (msg, opts) => hashCons(opts)
|
|
8817
|
+
.update(msg)
|
|
8818
|
+
.digest();
|
|
8819
|
+
const tmp = hashCons(undefined);
|
|
8820
|
+
hashC.outputLen = tmp.outputLen;
|
|
8821
|
+
hashC.blockLen = tmp.blockLen;
|
|
8822
|
+
hashC.canXOF = tmp.canXOF;
|
|
8823
|
+
hashC.create = (opts) => hashCons(opts);
|
|
8824
|
+
Object.assign(hashC, info);
|
|
8825
|
+
return Object.freeze(hashC);
|
|
8826
|
+
}
|
|
8827
|
+
/**
|
|
8828
|
+
* Creates OID metadata for NIST hashes with prefix `06 09 60 86 48 01 65 03 04 02`.
|
|
8829
|
+
* @param suffix - final OID byte for the selected hash.
|
|
8830
|
+
* The helper accepts any byte even though only the documented NIST hash
|
|
8831
|
+
* suffixes are meaningful downstream.
|
|
8832
|
+
* @returns Object containing the DER-encoded OID.
|
|
8833
|
+
* @example
|
|
8834
|
+
* Build OID metadata for a NIST hash.
|
|
8835
|
+
* ```ts
|
|
8836
|
+
* oidNist(0x01);
|
|
8837
|
+
* ```
|
|
8838
|
+
*/
|
|
8839
|
+
const oidNist = (suffix) => ({
|
|
8840
|
+
// Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
|
|
8841
|
+
// Larger suffix values would need base-128 OID encoding and a different length byte.
|
|
8842
|
+
oid: Uint8Array.from([0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, suffix]),
|
|
8843
|
+
});
|
|
8844
|
+
|
|
8845
|
+
/**
|
|
8846
|
+
* HMAC: RFC2104 message authentication code.
|
|
8847
|
+
* @module
|
|
8848
|
+
*/
|
|
8849
|
+
/**
|
|
8850
|
+
* Internal class for HMAC.
|
|
8851
|
+
* Accepts any byte key, although RFC 2104 §3 recommends keys at least
|
|
8852
|
+
* `HashLen` bytes long.
|
|
8853
|
+
*/
|
|
8854
|
+
class _HMAC {
|
|
8855
|
+
oHash;
|
|
8856
|
+
iHash;
|
|
8857
|
+
blockLen;
|
|
8858
|
+
outputLen;
|
|
8859
|
+
canXOF = false;
|
|
8860
|
+
finished = false;
|
|
8861
|
+
destroyed = false;
|
|
8862
|
+
constructor(hash, key) {
|
|
8863
|
+
ahash(hash);
|
|
8864
|
+
abytes(key, undefined, 'key');
|
|
8865
|
+
this.iHash = hash.create();
|
|
8866
|
+
if (typeof this.iHash.update !== 'function')
|
|
8867
|
+
throw new Error('Expected instance of class which extends utils.Hash');
|
|
8868
|
+
this.blockLen = this.iHash.blockLen;
|
|
8869
|
+
this.outputLen = this.iHash.outputLen;
|
|
8870
|
+
const blockLen = this.blockLen;
|
|
8871
|
+
const pad = new Uint8Array(blockLen);
|
|
8872
|
+
// blockLen can be bigger than outputLen
|
|
8873
|
+
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
8874
|
+
for (let i = 0; i < pad.length; i++)
|
|
8875
|
+
pad[i] ^= 0x36;
|
|
8876
|
+
this.iHash.update(pad);
|
|
8877
|
+
// By doing update (processing of the first block) of the outer hash here,
|
|
8878
|
+
// we can re-use it between multiple calls via clone.
|
|
8879
|
+
this.oHash = hash.create();
|
|
8880
|
+
// Undo internal XOR && apply outer XOR
|
|
8881
|
+
for (let i = 0; i < pad.length; i++)
|
|
8882
|
+
pad[i] ^= 0x36 ^ 0x5c;
|
|
8883
|
+
this.oHash.update(pad);
|
|
8884
|
+
clean(pad);
|
|
8885
|
+
}
|
|
8886
|
+
update(buf) {
|
|
8887
|
+
aexists(this);
|
|
8888
|
+
this.iHash.update(buf);
|
|
8889
|
+
return this;
|
|
8890
|
+
}
|
|
8891
|
+
digestInto(out) {
|
|
8892
|
+
aexists(this);
|
|
8893
|
+
aoutput(out, this);
|
|
8894
|
+
this.finished = true;
|
|
8895
|
+
const buf = out.subarray(0, this.outputLen);
|
|
8896
|
+
// Reuse the first outputLen bytes for the inner digest; the outer hash consumes them before
|
|
8897
|
+
// overwriting that same prefix with the final tag, leaving any oversized tail untouched.
|
|
8898
|
+
this.iHash.digestInto(buf);
|
|
8899
|
+
this.oHash.update(buf);
|
|
8900
|
+
this.oHash.digestInto(buf);
|
|
8901
|
+
this.destroy();
|
|
8902
|
+
}
|
|
8903
|
+
digest() {
|
|
8904
|
+
const out = new Uint8Array(this.oHash.outputLen);
|
|
8905
|
+
this.digestInto(out);
|
|
8906
|
+
return out;
|
|
8907
|
+
}
|
|
8908
|
+
_cloneInto(to) {
|
|
8909
|
+
// Create new instance without calling constructor since the key
|
|
8910
|
+
// is already in state and we don't know it.
|
|
8911
|
+
to ||= Object.create(Object.getPrototypeOf(this), {});
|
|
8912
|
+
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
|
8913
|
+
to = to;
|
|
8914
|
+
to.finished = finished;
|
|
8915
|
+
to.destroyed = destroyed;
|
|
8916
|
+
to.blockLen = blockLen;
|
|
8917
|
+
to.outputLen = outputLen;
|
|
8918
|
+
to.oHash = oHash._cloneInto(to.oHash);
|
|
8919
|
+
to.iHash = iHash._cloneInto(to.iHash);
|
|
8920
|
+
return to;
|
|
8921
|
+
}
|
|
8922
|
+
clone() {
|
|
8923
|
+
return this._cloneInto();
|
|
8924
|
+
}
|
|
8925
|
+
destroy() {
|
|
8926
|
+
this.destroyed = true;
|
|
8927
|
+
this.oHash.destroy();
|
|
8928
|
+
this.iHash.destroy();
|
|
8929
|
+
}
|
|
8930
|
+
}
|
|
8931
|
+
const hmac = /* @__PURE__ */ (() => {
|
|
8932
|
+
const hmac_ = ((hash, key, message) => new _HMAC(hash, key).update(message).digest());
|
|
8933
|
+
hmac_.create = (hash, key) => new _HMAC(hash, key);
|
|
8934
|
+
return hmac_;
|
|
8935
|
+
})();
|
|
8936
|
+
|
|
8937
|
+
/**
|
|
8938
|
+
* Internal Merkle-Damgard hash utils.
|
|
8939
|
+
* @module
|
|
8940
|
+
*/
|
|
8941
|
+
/**
|
|
8942
|
+
* Shared 32-bit conditional boolean primitive reused by SHA-256, SHA-1, and MD5 `F`.
|
|
8943
|
+
* Returns bits from `b` when `a` is set, otherwise from `c`.
|
|
8944
|
+
* The XOR form is equivalent to MD5's `F(X,Y,Z) = XY v not(X)Z` because the masked terms never
|
|
8945
|
+
* set the same bit.
|
|
8946
|
+
* @param a - selector word
|
|
8947
|
+
* @param b - word chosen when selector bit is set
|
|
8948
|
+
* @param c - word chosen when selector bit is clear
|
|
8949
|
+
* @returns Mixed 32-bit word.
|
|
8950
|
+
* @example
|
|
8951
|
+
* Combine three words with the shared 32-bit choice primitive.
|
|
8952
|
+
* ```ts
|
|
8953
|
+
* Chi(0xffffffff, 0x12345678, 0x87654321);
|
|
8954
|
+
* ```
|
|
8955
|
+
*/
|
|
8956
|
+
function Chi(a, b, c) {
|
|
8957
|
+
return (a & b) ^ (~a & c);
|
|
8958
|
+
}
|
|
8959
|
+
/**
|
|
8960
|
+
* Shared 32-bit majority primitive reused by SHA-256 and SHA-1.
|
|
8961
|
+
* Returns bits shared by at least two inputs.
|
|
8962
|
+
* @param a - first input word
|
|
8963
|
+
* @param b - second input word
|
|
8964
|
+
* @param c - third input word
|
|
8965
|
+
* @returns Mixed 32-bit word.
|
|
8966
|
+
* @example
|
|
8967
|
+
* Combine three words with the shared 32-bit majority primitive.
|
|
8968
|
+
* ```ts
|
|
8969
|
+
* Maj(0xffffffff, 0x12345678, 0x87654321);
|
|
8970
|
+
* ```
|
|
8971
|
+
*/
|
|
8972
|
+
function Maj(a, b, c) {
|
|
8973
|
+
return (a & b) ^ (a & c) ^ (b & c);
|
|
8974
|
+
}
|
|
8975
|
+
/**
|
|
8976
|
+
* Merkle-Damgard hash construction base class.
|
|
8977
|
+
* Could be used to create MD5, RIPEMD, SHA1, SHA2.
|
|
8978
|
+
* Accepts only byte-aligned `Uint8Array` input, even when the underlying spec describes bit
|
|
8979
|
+
* strings with partial-byte tails.
|
|
8980
|
+
* @param blockLen - internal block size in bytes
|
|
8981
|
+
* @param outputLen - digest size in bytes
|
|
8982
|
+
* @param padOffset - trailing length field size in bytes
|
|
8983
|
+
* @param isLE - whether length and state words are encoded in little-endian
|
|
8984
|
+
* @example
|
|
8985
|
+
* Use a concrete subclass to get the shared Merkle-Damgard update/digest flow.
|
|
8986
|
+
* ```ts
|
|
8987
|
+
* import { _SHA1 } from '@noble/hashes/legacy.js';
|
|
8988
|
+
* const hash = new _SHA1();
|
|
8989
|
+
* hash.update(new Uint8Array([97, 98, 99]));
|
|
8990
|
+
* hash.digest();
|
|
8991
|
+
* ```
|
|
8992
|
+
*/
|
|
8993
|
+
class HashMD {
|
|
8994
|
+
blockLen;
|
|
8995
|
+
outputLen;
|
|
8996
|
+
canXOF = false;
|
|
8997
|
+
padOffset;
|
|
8998
|
+
isLE;
|
|
8999
|
+
// For partial updates less than block size
|
|
9000
|
+
buffer;
|
|
9001
|
+
view;
|
|
9002
|
+
finished = false;
|
|
9003
|
+
length = 0;
|
|
9004
|
+
pos = 0;
|
|
9005
|
+
destroyed = false;
|
|
9006
|
+
constructor(blockLen, outputLen, padOffset, isLE) {
|
|
9007
|
+
this.blockLen = blockLen;
|
|
9008
|
+
this.outputLen = outputLen;
|
|
9009
|
+
this.padOffset = padOffset;
|
|
9010
|
+
this.isLE = isLE;
|
|
9011
|
+
this.buffer = new Uint8Array(blockLen);
|
|
9012
|
+
this.view = createView(this.buffer);
|
|
9013
|
+
}
|
|
9014
|
+
update(data) {
|
|
9015
|
+
aexists(this);
|
|
9016
|
+
abytes(data);
|
|
9017
|
+
const { view, buffer, blockLen } = this;
|
|
9018
|
+
const len = data.length;
|
|
9019
|
+
for (let pos = 0; pos < len;) {
|
|
9020
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
9021
|
+
// Fast path only when there is no buffered partial block: `take === blockLen` implies
|
|
9022
|
+
// `this.pos === 0`, so we can process full blocks directly from the input view.
|
|
9023
|
+
if (take === blockLen) {
|
|
9024
|
+
const dataView = createView(data);
|
|
9025
|
+
for (; blockLen <= len - pos; pos += blockLen)
|
|
9026
|
+
this.process(dataView, pos);
|
|
9027
|
+
continue;
|
|
9028
|
+
}
|
|
9029
|
+
buffer.set(data.subarray(pos, pos + take), this.pos);
|
|
9030
|
+
this.pos += take;
|
|
9031
|
+
pos += take;
|
|
9032
|
+
if (this.pos === blockLen) {
|
|
9033
|
+
this.process(view, 0);
|
|
9034
|
+
this.pos = 0;
|
|
9035
|
+
}
|
|
9036
|
+
}
|
|
9037
|
+
this.length += data.length;
|
|
9038
|
+
this.roundClean();
|
|
9039
|
+
return this;
|
|
9040
|
+
}
|
|
9041
|
+
digestInto(out) {
|
|
9042
|
+
aexists(this);
|
|
9043
|
+
aoutput(out, this);
|
|
9044
|
+
this.finished = true;
|
|
9045
|
+
// Padding
|
|
9046
|
+
// We can avoid allocation of buffer for padding completely if it
|
|
9047
|
+
// was previously not allocated here. But it won't change performance.
|
|
9048
|
+
const { buffer, view, blockLen, isLE } = this;
|
|
9049
|
+
let { pos } = this;
|
|
9050
|
+
// append the bit '1' to the message
|
|
9051
|
+
buffer[pos++] = 0b10000000;
|
|
9052
|
+
clean(this.buffer.subarray(pos));
|
|
9053
|
+
// we have less than padOffset left in buffer, so we cannot put length in
|
|
9054
|
+
// current block, need process it and pad again
|
|
9055
|
+
if (this.padOffset > blockLen - pos) {
|
|
9056
|
+
this.process(view, 0);
|
|
9057
|
+
pos = 0;
|
|
9058
|
+
}
|
|
9059
|
+
// Pad until full block byte with zeros
|
|
9060
|
+
for (let i = pos; i < blockLen; i++)
|
|
9061
|
+
buffer[i] = 0;
|
|
9062
|
+
// `padOffset` reserves the whole length field. For SHA-384/512 the high 64 bits stay zero from
|
|
9063
|
+
// the padding fill above, and JS will overflow before user input can make that half non-zero.
|
|
9064
|
+
// So we only need to write the low 64 bits here.
|
|
9065
|
+
view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
|
|
9066
|
+
this.process(view, 0);
|
|
9067
|
+
const oview = createView(out);
|
|
9068
|
+
const len = this.outputLen;
|
|
9069
|
+
// NOTE: we do division by 4 later, which must be fused in single op with modulo by JIT
|
|
9070
|
+
if (len % 4)
|
|
9071
|
+
throw new Error('_sha2: outputLen must be aligned to 32bit');
|
|
9072
|
+
const outLen = len / 4;
|
|
9073
|
+
const state = this.get();
|
|
9074
|
+
if (outLen > state.length)
|
|
9075
|
+
throw new Error('_sha2: outputLen bigger than state');
|
|
9076
|
+
for (let i = 0; i < outLen; i++)
|
|
9077
|
+
oview.setUint32(4 * i, state[i], isLE);
|
|
9078
|
+
}
|
|
9079
|
+
digest() {
|
|
9080
|
+
const { buffer, outputLen } = this;
|
|
9081
|
+
this.digestInto(buffer);
|
|
9082
|
+
// Copy before destroy(): subclasses wipe `buffer` during cleanup, but `digest()` must return
|
|
9083
|
+
// fresh bytes to the caller.
|
|
9084
|
+
const res = buffer.slice(0, outputLen);
|
|
9085
|
+
this.destroy();
|
|
9086
|
+
return res;
|
|
9087
|
+
}
|
|
9088
|
+
_cloneInto(to) {
|
|
9089
|
+
to ||= new this.constructor();
|
|
9090
|
+
to.set(...this.get());
|
|
9091
|
+
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
|
9092
|
+
to.destroyed = destroyed;
|
|
9093
|
+
to.finished = finished;
|
|
9094
|
+
to.length = length;
|
|
9095
|
+
to.pos = pos;
|
|
9096
|
+
// Only partial-block bytes need copying: when `length % blockLen === 0`, `pos === 0` and
|
|
9097
|
+
// later `update()` / `digestInto()` overwrite `to.buffer` from the start before reading it.
|
|
9098
|
+
if (length % blockLen)
|
|
9099
|
+
to.buffer.set(buffer);
|
|
9100
|
+
return to;
|
|
9101
|
+
}
|
|
9102
|
+
clone() {
|
|
9103
|
+
return this._cloneInto();
|
|
9104
|
+
}
|
|
9105
|
+
}
|
|
9106
|
+
/**
|
|
9107
|
+
* Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.
|
|
9108
|
+
* Check out `test/misc/sha2-gen-iv.js` for recomputation guide.
|
|
9109
|
+
*/
|
|
9110
|
+
/** Initial SHA256 state from RFC 6234 §6.1: the first 32 bits of the fractional parts of the
|
|
9111
|
+
* square roots of the first eight prime numbers. Exported as a shared table; callers must treat
|
|
9112
|
+
* it as read-only because constructors copy words from it by index. */
|
|
9113
|
+
const SHA256_IV = /* @__PURE__ */ Uint32Array.from([
|
|
9114
|
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
|
9115
|
+
]);
|
|
9116
|
+
|
|
9117
|
+
/**
|
|
9118
|
+
* SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.
|
|
9119
|
+
* SHA256 is the fastest hash implementable in JS, even faster than Blake3.
|
|
9120
|
+
* Check out {@link https://www.rfc-editor.org/rfc/rfc4634 | RFC 4634} and
|
|
9121
|
+
* {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf | FIPS 180-4}.
|
|
9122
|
+
* @module
|
|
9123
|
+
*/
|
|
9124
|
+
/**
|
|
9125
|
+
* SHA-224 / SHA-256 round constants from RFC 6234 §5.1: the first 32 bits
|
|
9126
|
+
* of the cube roots of the first 64 primes (2..311).
|
|
9127
|
+
*/
|
|
9128
|
+
// prettier-ignore
|
|
9129
|
+
const SHA256_K = /* @__PURE__ */ Uint32Array.from([
|
|
9130
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
9131
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
9132
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
9133
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
9134
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
9135
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
9136
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
9137
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
|
9138
|
+
]);
|
|
9139
|
+
/** Reusable SHA-224 / SHA-256 message schedule buffer `W_t` from RFC 6234 §6.2 step 1. */
|
|
9140
|
+
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
|
|
9141
|
+
/** Internal SHA-224 / SHA-256 compression engine from RFC 6234 §6.2. */
|
|
9142
|
+
class SHA2_32B extends HashMD {
|
|
9143
|
+
constructor(outputLen) {
|
|
9144
|
+
super(64, outputLen, 8, false);
|
|
9145
|
+
}
|
|
9146
|
+
get() {
|
|
9147
|
+
const { A, B, C, D, E, F, G, H } = this;
|
|
9148
|
+
return [A, B, C, D, E, F, G, H];
|
|
9149
|
+
}
|
|
9150
|
+
// prettier-ignore
|
|
9151
|
+
set(A, B, C, D, E, F, G, H) {
|
|
9152
|
+
this.A = A | 0;
|
|
9153
|
+
this.B = B | 0;
|
|
9154
|
+
this.C = C | 0;
|
|
9155
|
+
this.D = D | 0;
|
|
9156
|
+
this.E = E | 0;
|
|
9157
|
+
this.F = F | 0;
|
|
9158
|
+
this.G = G | 0;
|
|
9159
|
+
this.H = H | 0;
|
|
9160
|
+
}
|
|
9161
|
+
process(view, offset) {
|
|
9162
|
+
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
|
|
9163
|
+
for (let i = 0; i < 16; i++, offset += 4)
|
|
9164
|
+
SHA256_W[i] = view.getUint32(offset, false);
|
|
9165
|
+
for (let i = 16; i < 64; i++) {
|
|
9166
|
+
const W15 = SHA256_W[i - 15];
|
|
9167
|
+
const W2 = SHA256_W[i - 2];
|
|
9168
|
+
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
|
|
9169
|
+
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
|
|
9170
|
+
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
|
|
9171
|
+
}
|
|
9172
|
+
// Compression function main loop, 64 rounds
|
|
9173
|
+
let { A, B, C, D, E, F, G, H } = this;
|
|
9174
|
+
for (let i = 0; i < 64; i++) {
|
|
9175
|
+
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
|
|
9176
|
+
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
|
|
9177
|
+
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
|
|
9178
|
+
const T2 = (sigma0 + Maj(A, B, C)) | 0;
|
|
9179
|
+
H = G;
|
|
9180
|
+
G = F;
|
|
9181
|
+
F = E;
|
|
9182
|
+
E = (D + T1) | 0;
|
|
9183
|
+
D = C;
|
|
9184
|
+
C = B;
|
|
9185
|
+
B = A;
|
|
9186
|
+
A = (T1 + T2) | 0;
|
|
9187
|
+
}
|
|
9188
|
+
// Add the compressed chunk to the current hash value
|
|
9189
|
+
A = (A + this.A) | 0;
|
|
9190
|
+
B = (B + this.B) | 0;
|
|
9191
|
+
C = (C + this.C) | 0;
|
|
9192
|
+
D = (D + this.D) | 0;
|
|
9193
|
+
E = (E + this.E) | 0;
|
|
9194
|
+
F = (F + this.F) | 0;
|
|
9195
|
+
G = (G + this.G) | 0;
|
|
9196
|
+
H = (H + this.H) | 0;
|
|
9197
|
+
this.set(A, B, C, D, E, F, G, H);
|
|
9198
|
+
}
|
|
9199
|
+
roundClean() {
|
|
9200
|
+
clean(SHA256_W);
|
|
9201
|
+
}
|
|
9202
|
+
destroy() {
|
|
9203
|
+
// HashMD callers route post-destroy usability through `destroyed`; zeroizing alone still leaves
|
|
9204
|
+
// update()/digest() callable on reused instances.
|
|
9205
|
+
this.destroyed = true;
|
|
9206
|
+
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
|
9207
|
+
clean(this.buffer);
|
|
9208
|
+
}
|
|
9209
|
+
}
|
|
9210
|
+
/** Internal SHA-256 hash class grounded in RFC 6234 §6.2. */
|
|
9211
|
+
class _SHA256 extends SHA2_32B {
|
|
9212
|
+
// We cannot use array here since array allows indexing by variable
|
|
9213
|
+
// which means optimizer/compiler cannot use registers.
|
|
9214
|
+
A = SHA256_IV[0] | 0;
|
|
9215
|
+
B = SHA256_IV[1] | 0;
|
|
9216
|
+
C = SHA256_IV[2] | 0;
|
|
9217
|
+
D = SHA256_IV[3] | 0;
|
|
9218
|
+
E = SHA256_IV[4] | 0;
|
|
9219
|
+
F = SHA256_IV[5] | 0;
|
|
9220
|
+
G = SHA256_IV[6] | 0;
|
|
9221
|
+
H = SHA256_IV[7] | 0;
|
|
9222
|
+
constructor() {
|
|
9223
|
+
super(32);
|
|
9224
|
+
}
|
|
9225
|
+
}
|
|
9226
|
+
/**
|
|
9227
|
+
* SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info:
|
|
9228
|
+
*
|
|
9229
|
+
* - Trying 2^128 hashes would get 50% chance of collision, using birthday attack.
|
|
9230
|
+
* - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.
|
|
9231
|
+
* - Each sha256 hash is executing 2^18 bit operations.
|
|
9232
|
+
* - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule.
|
|
9233
|
+
* @param msg - message bytes to hash
|
|
9234
|
+
* @returns Digest bytes.
|
|
9235
|
+
* @example
|
|
9236
|
+
* Hash a message with SHA2-256.
|
|
9237
|
+
* ```ts
|
|
9238
|
+
* sha256(new Uint8Array([97, 98, 99]));
|
|
9239
|
+
* ```
|
|
9240
|
+
*/
|
|
9241
|
+
const sha256 = /* @__PURE__ */ createHasher(() => new _SHA256(),
|
|
9242
|
+
/* @__PURE__ */ oidNist(0x01));
|
|
9243
|
+
|
|
9244
|
+
// DEFLATE is a complex format; to read this code, you should probably check the RFC first:
|
|
9245
|
+
// https://tools.ietf.org/html/rfc1951
|
|
9246
|
+
// You may also wish to take a look at the guide I made about this program:
|
|
9247
|
+
// https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad
|
|
9248
|
+
// Some of the following code is similar to that of UZIP.js:
|
|
9249
|
+
// https://github.com/photopea/UZIP.js
|
|
9250
|
+
// However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size.
|
|
9251
|
+
// Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint
|
|
9252
|
+
// is better for memory in most engines (I *think*).
|
|
9253
|
+
|
|
9254
|
+
// aliases for shorter compressed code (most minifers don't do this)
|
|
9255
|
+
var u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array;
|
|
9256
|
+
// fixed length extra bits
|
|
9257
|
+
var fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]);
|
|
9258
|
+
// fixed distance extra bits
|
|
9259
|
+
var fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]);
|
|
9260
|
+
// code length index map
|
|
9261
|
+
var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
9262
|
+
// get base, reverse index map from extra bits
|
|
9263
|
+
var freb = function (eb, start) {
|
|
9264
|
+
var b = new u16(31);
|
|
9265
|
+
for (var i = 0; i < 31; ++i) {
|
|
9266
|
+
b[i] = start += 1 << eb[i - 1];
|
|
9267
|
+
}
|
|
9268
|
+
// numbers here are at max 18 bits
|
|
9269
|
+
var r = new i32(b[30]);
|
|
9270
|
+
for (var i = 1; i < 30; ++i) {
|
|
9271
|
+
for (var j = b[i]; j < b[i + 1]; ++j) {
|
|
9272
|
+
r[j] = ((j - b[i]) << 5) | i;
|
|
9273
|
+
}
|
|
9274
|
+
}
|
|
9275
|
+
return { b: b, r: r };
|
|
9276
|
+
};
|
|
9277
|
+
var _a$1 = freb(fleb, 2), fl$1 = _a$1.b, revfl = _a$1.r;
|
|
9278
|
+
// we can ignore the fact that the other numbers are wrong; they never happen anyway
|
|
9279
|
+
fl$1[28] = 258, revfl[258] = 28;
|
|
9280
|
+
var _b = freb(fdeb, 0), fd$1 = _b.b;
|
|
9281
|
+
// map of value to reverse (assuming 16 bits)
|
|
9282
|
+
var rev = new u16(32768);
|
|
9283
|
+
for (var i = 0; i < 32768; ++i) {
|
|
9284
|
+
// reverse table algorithm from SO
|
|
9285
|
+
var x = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1);
|
|
9286
|
+
x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2);
|
|
9287
|
+
x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4);
|
|
9288
|
+
rev[i] = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) >> 1;
|
|
9289
|
+
}
|
|
9290
|
+
// create huffman tree from u8 "map": index -> code length for code index
|
|
9291
|
+
// mb (max bits) must be at most 15
|
|
9292
|
+
// TODO: optimize/split up?
|
|
9293
|
+
var hMap = (function (cd, mb, r) {
|
|
9294
|
+
var s = cd.length;
|
|
9295
|
+
// index
|
|
9296
|
+
var i = 0;
|
|
9297
|
+
// u16 "map": index -> # of codes with bit length = index
|
|
9298
|
+
var l = new u16(mb);
|
|
9299
|
+
// length of cd must be 288 (total # of codes)
|
|
9300
|
+
for (; i < s; ++i) {
|
|
9301
|
+
if (cd[i])
|
|
9302
|
+
++l[cd[i] - 1];
|
|
9303
|
+
}
|
|
9304
|
+
// u16 "map": index -> minimum code for bit length = index
|
|
9305
|
+
var le = new u16(mb);
|
|
9306
|
+
for (i = 1; i < mb; ++i) {
|
|
9307
|
+
le[i] = (le[i - 1] + l[i - 1]) << 1;
|
|
9308
|
+
}
|
|
9309
|
+
var co;
|
|
9310
|
+
if (r) {
|
|
9311
|
+
// u16 "map": index -> number of actual bits, symbol for code
|
|
9312
|
+
co = new u16(1 << mb);
|
|
9313
|
+
// bits to remove for reverser
|
|
9314
|
+
var rvb = 15 - mb;
|
|
9315
|
+
for (i = 0; i < s; ++i) {
|
|
9316
|
+
// ignore 0 lengths
|
|
9317
|
+
if (cd[i]) {
|
|
9318
|
+
// num encoding both symbol and bits read
|
|
9319
|
+
var sv = (i << 4) | cd[i];
|
|
9320
|
+
// free bits
|
|
9321
|
+
var r_1 = mb - cd[i];
|
|
9322
|
+
// start value
|
|
9323
|
+
var v = le[cd[i] - 1]++ << r_1;
|
|
9324
|
+
// m is end value
|
|
9325
|
+
for (var m = v | ((1 << r_1) - 1); v <= m; ++v) {
|
|
9326
|
+
// every 16 bit value starting with the code yields the same result
|
|
9327
|
+
co[rev[v] >> rvb] = sv;
|
|
9328
|
+
}
|
|
9329
|
+
}
|
|
9330
|
+
}
|
|
9331
|
+
}
|
|
9332
|
+
else {
|
|
9333
|
+
co = new u16(s);
|
|
9334
|
+
for (i = 0; i < s; ++i) {
|
|
9335
|
+
if (cd[i]) {
|
|
9336
|
+
co[i] = rev[le[cd[i] - 1]++] >> (15 - cd[i]);
|
|
9337
|
+
}
|
|
9338
|
+
}
|
|
9339
|
+
}
|
|
9340
|
+
return co;
|
|
9341
|
+
});
|
|
9342
|
+
// fixed length tree
|
|
9343
|
+
var flt = new u8(288);
|
|
9344
|
+
for (var i = 0; i < 144; ++i)
|
|
9345
|
+
flt[i] = 8;
|
|
9346
|
+
for (var i = 144; i < 256; ++i)
|
|
9347
|
+
flt[i] = 9;
|
|
9348
|
+
for (var i = 256; i < 280; ++i)
|
|
9349
|
+
flt[i] = 7;
|
|
9350
|
+
for (var i = 280; i < 288; ++i)
|
|
9351
|
+
flt[i] = 8;
|
|
9352
|
+
// fixed distance tree
|
|
9353
|
+
var fdt = new u8(32);
|
|
9354
|
+
for (var i = 0; i < 32; ++i)
|
|
9355
|
+
fdt[i] = 5;
|
|
9356
|
+
// fixed length map
|
|
9357
|
+
var flrm = /*#__PURE__*/ hMap(flt, 9, 1);
|
|
9358
|
+
// fixed distance map
|
|
9359
|
+
var fdrm = /*#__PURE__*/ hMap(fdt, 5, 1);
|
|
9360
|
+
// find max of array
|
|
9361
|
+
var max = function (a) {
|
|
9362
|
+
var m = a[0];
|
|
9363
|
+
for (var i = 1; i < a.length; ++i) {
|
|
9364
|
+
if (a[i] > m)
|
|
9365
|
+
m = a[i];
|
|
9366
|
+
}
|
|
9367
|
+
return m;
|
|
9368
|
+
};
|
|
9369
|
+
// read d, starting at bit p and mask with m
|
|
9370
|
+
var bits = function (d, p, m) {
|
|
9371
|
+
var o = (p / 8) | 0;
|
|
9372
|
+
return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m;
|
|
9373
|
+
};
|
|
9374
|
+
// read d, starting at bit p continuing for at least 16 bits
|
|
9375
|
+
var bits16 = function (d, p) {
|
|
9376
|
+
var o = (p / 8) | 0;
|
|
9377
|
+
return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7));
|
|
9378
|
+
};
|
|
9379
|
+
// get end of byte
|
|
9380
|
+
var shft = function (p) { return ((p + 7) / 8) | 0; };
|
|
9381
|
+
// typed array slice - allows garbage collector to free original reference,
|
|
9382
|
+
// while being more compatible than .slice
|
|
9383
|
+
var slc = function (v, s, e) {
|
|
9384
|
+
if (s == null || s < 0)
|
|
9385
|
+
s = 0;
|
|
9386
|
+
if (e == null || e > v.length)
|
|
9387
|
+
e = v.length;
|
|
9388
|
+
// can't use .constructor in case user-supplied
|
|
9389
|
+
return new u8(v.subarray(s, e));
|
|
9390
|
+
};
|
|
9391
|
+
// error codes
|
|
9392
|
+
var ec$1 = [
|
|
9393
|
+
'unexpected EOF',
|
|
9394
|
+
'invalid block type',
|
|
9395
|
+
'invalid length/literal',
|
|
9396
|
+
'invalid distance',
|
|
9397
|
+
'stream finished',
|
|
9398
|
+
'no stream handler',
|
|
9399
|
+
, // determined by compression function
|
|
9400
|
+
'no callback',
|
|
9401
|
+
'invalid UTF-8 data',
|
|
9402
|
+
'extra field too long',
|
|
9403
|
+
'date not in range 1980-2099',
|
|
9404
|
+
'filename too long',
|
|
9405
|
+
'stream finishing',
|
|
9406
|
+
'invalid zip data'
|
|
9407
|
+
// determined by unknown compression method
|
|
9408
|
+
];
|
|
9409
|
+
var err = function (ind, msg, nt) {
|
|
9410
|
+
var e = new Error(msg || ec$1[ind]);
|
|
9411
|
+
e.code = ind;
|
|
9412
|
+
if (Error.captureStackTrace)
|
|
9413
|
+
Error.captureStackTrace(e, err);
|
|
9414
|
+
if (!nt)
|
|
9415
|
+
throw e;
|
|
9416
|
+
return e;
|
|
9417
|
+
};
|
|
9418
|
+
// expands raw DEFLATE data
|
|
9419
|
+
var inflt = function (dat, st, buf, dict) {
|
|
9420
|
+
// source length dict length
|
|
9421
|
+
var sl = dat.length, dl = dict ? dict.length : 0;
|
|
9422
|
+
if (!sl || st.f && !st.l)
|
|
9423
|
+
return buf || new u8(0);
|
|
9424
|
+
var noBuf = !buf;
|
|
9425
|
+
// have to estimate size
|
|
9426
|
+
var resize = noBuf || st.i != 2;
|
|
9427
|
+
// no state
|
|
9428
|
+
var noSt = st.i;
|
|
9429
|
+
// Assumes roughly 33% compression ratio average
|
|
9430
|
+
if (noBuf)
|
|
9431
|
+
buf = new u8(sl * 3);
|
|
9432
|
+
// ensure buffer can fit at least l elements
|
|
9433
|
+
var cbuf = function (l) {
|
|
9434
|
+
var bl = buf.length;
|
|
9435
|
+
// need to increase size to fit
|
|
9436
|
+
if (l > bl) {
|
|
9437
|
+
// Double or set to necessary, whichever is greater
|
|
9438
|
+
var nbuf = new u8(Math.max(bl * 2, l));
|
|
9439
|
+
nbuf.set(buf);
|
|
9440
|
+
buf = nbuf;
|
|
9441
|
+
}
|
|
9442
|
+
};
|
|
9443
|
+
// last chunk bitpos bytes
|
|
9444
|
+
var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
|
|
9445
|
+
// total bits
|
|
9446
|
+
var tbts = sl * 8;
|
|
9447
|
+
do {
|
|
9448
|
+
if (!lm) {
|
|
9449
|
+
// BFINAL - this is only 1 when last chunk is next
|
|
9450
|
+
final = bits(dat, pos, 1);
|
|
9451
|
+
// type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman
|
|
9452
|
+
var type = bits(dat, pos + 1, 3);
|
|
9453
|
+
pos += 3;
|
|
9454
|
+
if (!type) {
|
|
9455
|
+
// go to end of byte boundary
|
|
9456
|
+
var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l;
|
|
9457
|
+
if (t > sl) {
|
|
9458
|
+
if (noSt)
|
|
9459
|
+
err(0);
|
|
9460
|
+
break;
|
|
9461
|
+
}
|
|
9462
|
+
// ensure size
|
|
9463
|
+
if (resize)
|
|
9464
|
+
cbuf(bt + l);
|
|
9465
|
+
// Copy over uncompressed data
|
|
9466
|
+
buf.set(dat.subarray(s, t), bt);
|
|
9467
|
+
// Get new bitpos, update byte count
|
|
9468
|
+
st.b = bt += l, st.p = pos = t * 8, st.f = final;
|
|
9469
|
+
continue;
|
|
9470
|
+
}
|
|
9471
|
+
else if (type == 1)
|
|
9472
|
+
lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
|
|
9473
|
+
else if (type == 2) {
|
|
9474
|
+
// literal lengths
|
|
9475
|
+
var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
|
|
9476
|
+
var tl = hLit + bits(dat, pos + 5, 31) + 1;
|
|
9477
|
+
pos += 14;
|
|
9478
|
+
// length+distance tree
|
|
9479
|
+
var ldt = new u8(tl);
|
|
9480
|
+
// code length tree
|
|
9481
|
+
var clt = new u8(19);
|
|
9482
|
+
for (var i = 0; i < hcLen; ++i) {
|
|
9483
|
+
// use index map to get real code
|
|
9484
|
+
clt[clim[i]] = bits(dat, pos + i * 3, 7);
|
|
9485
|
+
}
|
|
9486
|
+
pos += hcLen * 3;
|
|
9487
|
+
// code lengths bits
|
|
9488
|
+
var clb = max(clt), clbmsk = (1 << clb) - 1;
|
|
9489
|
+
// code lengths map
|
|
9490
|
+
var clm = hMap(clt, clb, 1);
|
|
9491
|
+
for (var i = 0; i < tl;) {
|
|
9492
|
+
var r = clm[bits(dat, pos, clbmsk)];
|
|
9493
|
+
// bits read
|
|
9494
|
+
pos += r & 15;
|
|
9495
|
+
// symbol
|
|
9496
|
+
var s = r >> 4;
|
|
9497
|
+
// code length to copy
|
|
9498
|
+
if (s < 16) {
|
|
9499
|
+
ldt[i++] = s;
|
|
9500
|
+
}
|
|
9501
|
+
else {
|
|
9502
|
+
// copy count
|
|
9503
|
+
var c = 0, n = 0;
|
|
9504
|
+
if (s == 16)
|
|
9505
|
+
n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
|
|
9506
|
+
else if (s == 17)
|
|
9507
|
+
n = 3 + bits(dat, pos, 7), pos += 3;
|
|
9508
|
+
else if (s == 18)
|
|
9509
|
+
n = 11 + bits(dat, pos, 127), pos += 7;
|
|
9510
|
+
while (n--)
|
|
9511
|
+
ldt[i++] = c;
|
|
9512
|
+
}
|
|
9513
|
+
}
|
|
9514
|
+
// length tree distance tree
|
|
9515
|
+
var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
|
|
9516
|
+
// max length bits
|
|
9517
|
+
lbt = max(lt);
|
|
9518
|
+
// max dist bits
|
|
9519
|
+
dbt = max(dt);
|
|
9520
|
+
lm = hMap(lt, lbt, 1);
|
|
9521
|
+
dm = hMap(dt, dbt, 1);
|
|
9522
|
+
}
|
|
9523
|
+
else
|
|
9524
|
+
err(1);
|
|
9525
|
+
if (pos > tbts) {
|
|
9526
|
+
if (noSt)
|
|
9527
|
+
err(0);
|
|
9528
|
+
break;
|
|
9529
|
+
}
|
|
9530
|
+
}
|
|
9531
|
+
// Make sure the buffer can hold this + the largest possible addition
|
|
9532
|
+
// Maximum chunk size (practically, theoretically infinite) is 2^17
|
|
9533
|
+
if (resize)
|
|
9534
|
+
cbuf(bt + 131072);
|
|
9535
|
+
var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
|
|
9536
|
+
var lpos = pos;
|
|
9537
|
+
for (;; lpos = pos) {
|
|
9538
|
+
// bits read, code
|
|
9539
|
+
var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
|
|
9540
|
+
pos += c & 15;
|
|
9541
|
+
if (pos > tbts) {
|
|
9542
|
+
if (noSt)
|
|
9543
|
+
err(0);
|
|
9544
|
+
break;
|
|
9545
|
+
}
|
|
9546
|
+
if (!c)
|
|
9547
|
+
err(2);
|
|
9548
|
+
if (sym < 256)
|
|
9549
|
+
buf[bt++] = sym;
|
|
9550
|
+
else if (sym == 256) {
|
|
9551
|
+
lpos = pos, lm = null;
|
|
9552
|
+
break;
|
|
9553
|
+
}
|
|
9554
|
+
else {
|
|
9555
|
+
var add = sym - 254;
|
|
9556
|
+
// no extra bits needed if less
|
|
9557
|
+
if (sym > 264) {
|
|
9558
|
+
// index
|
|
9559
|
+
var i = sym - 257, b = fleb[i];
|
|
9560
|
+
add = bits(dat, pos, (1 << b) - 1) + fl$1[i];
|
|
9561
|
+
pos += b;
|
|
9562
|
+
}
|
|
9563
|
+
// dist
|
|
9564
|
+
var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
|
|
9565
|
+
if (!d)
|
|
9566
|
+
err(3);
|
|
9567
|
+
pos += d & 15;
|
|
9568
|
+
var dt = fd$1[dsym];
|
|
9569
|
+
if (dsym > 3) {
|
|
9570
|
+
var b = fdeb[dsym];
|
|
9571
|
+
dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
|
|
9572
|
+
}
|
|
9573
|
+
if (pos > tbts) {
|
|
9574
|
+
if (noSt)
|
|
9575
|
+
err(0);
|
|
9576
|
+
break;
|
|
9577
|
+
}
|
|
9578
|
+
if (resize)
|
|
9579
|
+
cbuf(bt + 131072);
|
|
9580
|
+
var end = bt + add;
|
|
9581
|
+
if (bt < dt) {
|
|
9582
|
+
var shift = dl - dt, dend = Math.min(dt, end);
|
|
9583
|
+
if (shift + bt < 0)
|
|
9584
|
+
err(3);
|
|
9585
|
+
for (; bt < dend; ++bt)
|
|
9586
|
+
buf[bt] = dict[shift + bt];
|
|
9587
|
+
}
|
|
9588
|
+
for (; bt < end; ++bt)
|
|
9589
|
+
buf[bt] = buf[bt - dt];
|
|
9590
|
+
}
|
|
9591
|
+
}
|
|
9592
|
+
st.l = lm, st.p = lpos, st.b = bt, st.f = final;
|
|
9593
|
+
if (lm)
|
|
9594
|
+
final = 1, st.m = lbt, st.d = dm, st.n = dbt;
|
|
9595
|
+
} while (!final);
|
|
9596
|
+
// don't reallocate for streams or user buffers
|
|
9597
|
+
return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
|
|
9598
|
+
};
|
|
9599
|
+
// empty
|
|
9600
|
+
var et = /*#__PURE__*/ new u8(0);
|
|
9601
|
+
// gzip footer: -8 to -4 = CRC, -4 to -0 is length
|
|
9602
|
+
// gzip start
|
|
9603
|
+
var gzs = function (d) {
|
|
9604
|
+
if (d[0] != 31 || d[1] != 139 || d[2] != 8)
|
|
9605
|
+
err(6, 'invalid gzip data');
|
|
9606
|
+
var flg = d[3];
|
|
9607
|
+
var st = 10;
|
|
9608
|
+
if (flg & 4)
|
|
9609
|
+
st += (d[10] | d[11] << 8) + 2;
|
|
9610
|
+
for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++])
|
|
9611
|
+
;
|
|
9612
|
+
return st + (flg & 2);
|
|
9613
|
+
};
|
|
9614
|
+
// gzip length
|
|
9615
|
+
var gzl = function (d) {
|
|
9616
|
+
var l = d.length;
|
|
9617
|
+
return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0;
|
|
9618
|
+
};
|
|
9619
|
+
function gunzipSync(data, opts) {
|
|
9620
|
+
var st = gzs(data);
|
|
9621
|
+
if (st + 8 > data.length)
|
|
9622
|
+
err(6, 'invalid gzip data');
|
|
9623
|
+
return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary);
|
|
9624
|
+
}
|
|
9625
|
+
// text decoder
|
|
9626
|
+
var td$1 = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder();
|
|
9627
|
+
// text decoder stream
|
|
9628
|
+
var tds = 0;
|
|
9629
|
+
try {
|
|
9630
|
+
td$1.decode(et, { stream: true });
|
|
9631
|
+
tds = 1;
|
|
9632
|
+
}
|
|
9633
|
+
catch (e) { }
|
|
9634
|
+
|
|
7599
9635
|
const MAGIC = "KYT1";
|
|
7600
9636
|
const IV_LEN = 12;
|
|
7601
9637
|
const HEADER_LEN = 6;
|
|
@@ -7607,10 +9643,39 @@ function b64ToBytes(b64) {
|
|
|
7607
9643
|
out[i] = bin.charCodeAt(i);
|
|
7608
9644
|
return out;
|
|
7609
9645
|
}
|
|
9646
|
+
const hasSubtle = typeof crypto !== "undefined" && !!crypto.subtle;
|
|
9647
|
+
async function aesGcmDecrypt(keyRaw, iv, ct, aad) {
|
|
9648
|
+
if (hasSubtle) {
|
|
9649
|
+
const key = await crypto.subtle.importKey("raw", keyRaw, { name: "AES-GCM" }, false, ["decrypt"]);
|
|
9650
|
+
const params = aad
|
|
9651
|
+
? { name: "AES-GCM", iv: iv, additionalData: aad }
|
|
9652
|
+
: { name: "AES-GCM", iv: iv };
|
|
9653
|
+
const pt = await crypto.subtle.decrypt(params, key, ct);
|
|
9654
|
+
return new Uint8Array(pt);
|
|
9655
|
+
}
|
|
9656
|
+
return gcm(keyRaw, iv, aad).decrypt(ct);
|
|
9657
|
+
}
|
|
9658
|
+
async function hmacSha256(keyRaw, msg) {
|
|
9659
|
+
if (hasSubtle) {
|
|
9660
|
+
const key = await crypto.subtle.importKey("raw", keyRaw, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
9661
|
+
const sig = await crypto.subtle.sign("HMAC", key, msg);
|
|
9662
|
+
return new Uint8Array(sig);
|
|
9663
|
+
}
|
|
9664
|
+
return hmac(sha256, keyRaw, msg);
|
|
9665
|
+
}
|
|
7610
9666
|
async function gunzip(buf) {
|
|
7611
|
-
const
|
|
7612
|
-
|
|
7613
|
-
|
|
9667
|
+
const DS = globalThis.DecompressionStream;
|
|
9668
|
+
if (DS) {
|
|
9669
|
+
const stream = new Blob([buf]).stream().pipeThrough(new DS("gzip"));
|
|
9670
|
+
return new Uint8Array(await new Response(stream).arrayBuffer());
|
|
9671
|
+
}
|
|
9672
|
+
return gunzipSync(buf);
|
|
9673
|
+
}
|
|
9674
|
+
function toHex(bytes) {
|
|
9675
|
+
let s = "";
|
|
9676
|
+
for (const b of bytes)
|
|
9677
|
+
s += b.toString(16).padStart(2, "0");
|
|
9678
|
+
return s;
|
|
7614
9679
|
}
|
|
7615
9680
|
class TileCipher {
|
|
7616
9681
|
constructor(apiUrl, version, licenseKey) {
|
|
@@ -7620,27 +9685,18 @@ class TileCipher {
|
|
|
7620
9685
|
throw new Error("[MapSDK] 无效的 licenseKey,应为 \"customerId.base64Key\"");
|
|
7621
9686
|
}
|
|
7622
9687
|
this.cid = licenseKey.slice(0, dot);
|
|
7623
|
-
|
|
7624
|
-
this.customerKeyRaw = raw;
|
|
7625
|
-
this.customerKey = crypto.subtle.importKey("raw", raw, { name: "AES-GCM" }, false, ["decrypt"]);
|
|
9688
|
+
this.customerKeyRaw = b64ToBytes(licenseKey.slice(dot + 1));
|
|
7626
9689
|
this.wrapBase = apiPrefix(apiUrl, version);
|
|
7627
9690
|
}
|
|
7628
9691
|
async apiAuthHeaders() {
|
|
7629
|
-
const
|
|
9692
|
+
const authKey = await this.authKey();
|
|
7630
9693
|
const ts = Math.floor(Date.now() / 1000);
|
|
7631
|
-
const
|
|
7632
|
-
|
|
7633
|
-
.map((b) => b.toString(16).padStart(2, "0"))
|
|
7634
|
-
.join("");
|
|
7635
|
-
return { "X-Cid": this.cid, "X-Ts": String(ts), "X-Sig": sig };
|
|
9694
|
+
const sig = await hmacSha256(authKey, new TextEncoder().encode(`${this.cid}|${ts}`));
|
|
9695
|
+
return { "X-Cid": this.cid, "X-Ts": String(ts), "X-Sig": toHex(sig) };
|
|
7636
9696
|
}
|
|
7637
9697
|
authKey() {
|
|
7638
9698
|
if (!this.authKeyPromise) {
|
|
7639
|
-
this.authKeyPromise = (
|
|
7640
|
-
const ck = await crypto.subtle.importKey("raw", this.customerKeyRaw, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
7641
|
-
const derived = await crypto.subtle.sign("HMAC", ck, new TextEncoder().encode("kunyu-api-auth-v1"));
|
|
7642
|
-
return crypto.subtle.importKey("raw", derived, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
7643
|
-
})();
|
|
9699
|
+
this.authKeyPromise = hmacSha256(this.customerKeyRaw, new TextEncoder().encode("kunyu-api-auth-v1"));
|
|
7644
9700
|
}
|
|
7645
9701
|
return this.authKeyPromise;
|
|
7646
9702
|
}
|
|
@@ -7663,11 +9719,7 @@ class TileCipher {
|
|
|
7663
9719
|
}
|
|
7664
9720
|
const { wrapped } = (await resp.json());
|
|
7665
9721
|
const blob = b64ToBytes(wrapped);
|
|
7666
|
-
|
|
7667
|
-
const ct = blob.slice(IV_LEN);
|
|
7668
|
-
const ck = await this.customerKey;
|
|
7669
|
-
const rawPeriodKey = await crypto.subtle.decrypt({ name: "AES-GCM", iv: iv }, ck, ct);
|
|
7670
|
-
return crypto.subtle.importKey("raw", rawPeriodKey, { name: "AES-GCM" }, false, ["decrypt"]);
|
|
9722
|
+
return aesGcmDecrypt(this.customerKeyRaw, blob.slice(0, IV_LEN), blob.slice(IV_LEN));
|
|
7671
9723
|
}
|
|
7672
9724
|
async decrypt(realUrl, envelope) {
|
|
7673
9725
|
const m = realUrl.match(/\/tiles\/e\/([^/]+)\//);
|
|
@@ -7684,10 +9736,10 @@ class TileCipher {
|
|
|
7684
9736
|
const iv = bytes.slice(HEADER_LEN, HEADER_LEN + IV_LEN);
|
|
7685
9737
|
const ct = bytes.slice(HEADER_LEN + IV_LEN);
|
|
7686
9738
|
const key = await this.periodKey(period);
|
|
7687
|
-
let plain = await
|
|
9739
|
+
let plain = await aesGcmDecrypt(key, iv, ct, aad);
|
|
7688
9740
|
if (flags & FLAG_GZIP)
|
|
7689
9741
|
plain = await gunzip(plain);
|
|
7690
|
-
return plain;
|
|
9742
|
+
return plain.buffer.slice(plain.byteOffset, plain.byteOffset + plain.byteLength);
|
|
7691
9743
|
}
|
|
7692
9744
|
}
|
|
7693
9745
|
|
|
@@ -7727,7 +9779,7 @@ const THEME_TOKENS = {
|
|
|
7727
9779
|
segmentRemark: '#E8A020', // HAS_REMARK 航段
|
|
7728
9780
|
airport: '#006400', // 机场图标色
|
|
7729
9781
|
airportText: '#006400', // 机场文字色(非 AMM)
|
|
7730
|
-
runway: '#
|
|
9782
|
+
runway: '#006400',
|
|
7731
9783
|
vorDial: '#0b417a',
|
|
7732
9784
|
vorNormal: '#3874cb',
|
|
7733
9785
|
vor: '#00008B',
|
|
@@ -7763,7 +9815,7 @@ const THEME_TOKENS = {
|
|
|
7763
9815
|
segmentRemark: '#fbbf24',
|
|
7764
9816
|
airport: '#73ccdd',
|
|
7765
9817
|
airportText: '#E0F7FA',
|
|
7766
|
-
runway: '#
|
|
9818
|
+
runway: '#73ccdd',
|
|
7767
9819
|
vorDial: '#38bdf8',
|
|
7768
9820
|
vorNormal: '#38bdf8',
|
|
7769
9821
|
vor: '#72aae5',
|
|
@@ -7800,7 +9852,7 @@ const THEME_TOKENS = {
|
|
|
7800
9852
|
segmentRemark: '#f4c542',
|
|
7801
9853
|
airport: '#7fd1ae',
|
|
7802
9854
|
airportText: '#dce9f0',
|
|
7803
|
-
runway: '#
|
|
9855
|
+
runway: '#7fd1ae',
|
|
7804
9856
|
vorDial: '#5dade2',
|
|
7805
9857
|
vorNormal: '#5dade2',
|
|
7806
9858
|
vor: '#85a9e0',
|
|
@@ -7838,7 +9890,7 @@ const THEME_TOKENS = {
|
|
|
7838
9890
|
segmentRemark: '#D68910',
|
|
7839
9891
|
airport: '#B03060',
|
|
7840
9892
|
airportText: '#1B2631',
|
|
7841
|
-
runway: '#
|
|
9893
|
+
runway: '#B03060',
|
|
7842
9894
|
vorDial: '#2E5C8A',
|
|
7843
9895
|
vorNormal: '#2E5C8A',
|
|
7844
9896
|
vor: '#154360',
|
|
@@ -7960,7 +10012,7 @@ function buildLayers(themeId = 'light') {
|
|
|
7960
10012
|
{
|
|
7961
10013
|
id: 'airline_label', type: 'symbol', source: sourceId, 'source-layer': 'segment', minzoom: 6,
|
|
7962
10014
|
layout: {
|
|
7963
|
-
"icon-image": ["case", ["all", ["has", "TXT_DESIG"], ["!=", ["get", "TXT_DESIG"], ""], ["!=", ["get", "TXT_DESIG"], " "], ["!=", ["get", "TXT_DESIG"], null]], "segment-both", ["all", ["has", "TXT_DESIG_FORWARD"]], "segment-right", ["all", ["has", "TXT_DESIG_BACKWARD"]], "segment-left", "segment-both"],
|
|
10015
|
+
"icon-image": ["case", ["all", ["has", "TXT_DESIG"], ["!=", ["get", "TXT_DESIG"], ""], ["!=", ["get", "TXT_DESIG"], " "], ["!=", ["get", "TXT_DESIG"], null]], "stretch:segment-both", ["all", ["has", "TXT_DESIG_FORWARD"]], "stretch:segment-right", ["all", ["has", "TXT_DESIG_BACKWARD"]], "stretch:segment-left", "stretch:segment-both"],
|
|
7964
10016
|
"icon-anchor": "center", "symbol-placement": "line", "icon-text-fit": "width", "icon-size": 1,
|
|
7965
10017
|
"text-allow-overlap": false, "icon-allow-overlap": false, "text-optional": false,
|
|
7966
10018
|
"text-anchor": "center", "text-justify": "center", "text-line-height": 1.3, "text-letter-spacing": 0.1,
|
|
@@ -8007,19 +10059,19 @@ function buildLayers(themeId = 'light') {
|
|
|
8007
10059
|
// 4级前就显示大型机场+中型,5级后全部显示
|
|
8008
10060
|
filter:
|
|
8009
10061
|
['case',
|
|
8010
|
-
['<=', ['zoom'], 3], ['<=', ['get', 'level'],
|
|
8011
|
-
|
|
10062
|
+
['<=', ['zoom'], 3], ['<=', ['get', 'level'], 1], // zoom ≤3,只显示 level=1(大型)
|
|
10063
|
+
['<=', ['zoom'], 4], ['<=', ['get', 'level'], 2], // zoom ≤4,显示 level≤2(大型+中型)
|
|
10064
|
+
['<=', ['zoom'], 5], ['<=', ['get', 'level'], 3], // zoom ≤5,显示 level≤3(大型+中型+小型)
|
|
10065
|
+
true // zoom >5,全部显示
|
|
8012
10066
|
],
|
|
8013
10067
|
layout: {
|
|
8014
10068
|
"icon-image": ["case", ["==", ["get", "CODE_TYPE_MIL_OPS"], "MIL"], "airport-mil", ["==", ["get", "CODE_TYPE_MIL_OPS"], "MILEXT"], "airport-milext", "airport-civ"],
|
|
8015
|
-
"icon-size": ["interpolate", ["linear"], ["zoom"], 4, 0.5, 10, 0.7],
|
|
8016
10069
|
"symbol-z-order": "viewport-y",
|
|
8017
|
-
"text-field": ["get", "codeId"],
|
|
8018
10070
|
"text-letter-spacing": 0.05,
|
|
8019
10071
|
'text-field': ['get', 'CODE_ID'],
|
|
8020
10072
|
"text-anchor": "bottom",
|
|
8021
10073
|
"text-justify": "center",
|
|
8022
|
-
"text-size": ["interpolate", ["linear"], ["zoom"], 4, 0, 5, 10
|
|
10074
|
+
"text-size": ["interpolate", ["linear"], ["zoom"], 4, 0, 5, 10],
|
|
8023
10075
|
"text-offset": [
|
|
8024
10076
|
"interpolate", ["linear"], ["zoom"],
|
|
8025
10077
|
5, ["literal", [0, -0.8]],
|
|
@@ -8028,14 +10080,33 @@ function buildLayers(themeId = 'light') {
|
|
|
8028
10080
|
],
|
|
8029
10081
|
"icon-allow-overlap": true,
|
|
8030
10082
|
"icon-ignore-placement": true,
|
|
8031
|
-
"text-allow-overlap":
|
|
8032
|
-
"text-ignore-placement":
|
|
10083
|
+
"text-allow-overlap": false,
|
|
10084
|
+
"text-ignore-placement": false,
|
|
10085
|
+
"text-optional": true,
|
|
8033
10086
|
"visibility": "none",
|
|
8034
|
-
"icon-size": ["interpolate", ["linear"], ["zoom"], 5, 0.7, 9, 1
|
|
10087
|
+
"icon-size": ["interpolate", ["linear"], ["zoom"], 2, 0.6, 5, 0.7, 9, 1, 12, 1.1]
|
|
8035
10088
|
},
|
|
8036
10089
|
paint: {
|
|
8037
10090
|
'icon-color': ['case', ['has', 'has_amm'], '#4B2D6E', T.airport],
|
|
8038
|
-
"icon-opacity": [
|
|
10091
|
+
"icon-opacity": [
|
|
10092
|
+
"interpolate",
|
|
10093
|
+
[
|
|
10094
|
+
"linear"
|
|
10095
|
+
],
|
|
10096
|
+
[
|
|
10097
|
+
"zoom"
|
|
10098
|
+
],
|
|
10099
|
+
2,
|
|
10100
|
+
0.75,
|
|
10101
|
+
3,
|
|
10102
|
+
0.95,
|
|
10103
|
+
5,
|
|
10104
|
+
1,
|
|
10105
|
+
9,
|
|
10106
|
+
1,
|
|
10107
|
+
11,
|
|
10108
|
+
0.2
|
|
10109
|
+
],
|
|
8039
10110
|
"text-color": ['case', ['has', 'has_amm'], '#4B2D6E', T.airportText],
|
|
8040
10111
|
"text-opacity": ["interpolate", ["linear"], ["zoom"], 4, 0.95, 5, 1, 9, 1, 11, 0.2],
|
|
8041
10112
|
},
|
|
@@ -8047,37 +10118,55 @@ function buildLayers(themeId = 'light') {
|
|
|
8047
10118
|
// keeps the strip aligned to the ground as the map rotates. The `runway-strip`
|
|
8048
10119
|
// sprite is supplied by the host sprite sheet.
|
|
8049
10120
|
{
|
|
8050
|
-
id: 'airport-runway', type: 'symbol', source: sourceId, minzoom:
|
|
8051
|
-
filter: [
|
|
10121
|
+
id: 'airport-runway', type: 'symbol', source: sourceId, minzoom: 4, 'source-layer': 'airport',
|
|
10122
|
+
filter: [
|
|
10123
|
+
'all',
|
|
10124
|
+
['has', 'RWY_BRG1'],
|
|
10125
|
+
['case',
|
|
10126
|
+
['<=', ['zoom'], 3], ['<=', ['get', 'level'], 1],
|
|
10127
|
+
['<=', ['zoom'], 4], ['<=', ['get', 'level'], 2],
|
|
10128
|
+
['<=', ['zoom'], 5], ['<=', ['get', 'level'], 3],
|
|
10129
|
+
true
|
|
10130
|
+
]
|
|
10131
|
+
],
|
|
8052
10132
|
layout: {
|
|
8053
10133
|
'icon-image': 'runway:runway-strip',
|
|
8054
10134
|
'icon-rotate': ['get', 'RWY_BRG1'],
|
|
8055
10135
|
'icon-rotation-alignment': 'map',
|
|
8056
|
-
'icon-size': ['interpolate', ['linear'], ['zoom'],
|
|
10136
|
+
'icon-size': ['interpolate', ['linear'], ['zoom'], 2, 0.3, 9, 0.7, 12, 0.7],
|
|
8057
10137
|
'icon-allow-overlap': true,
|
|
8058
10138
|
'icon-ignore-placement': true,
|
|
8059
10139
|
'visibility': 'none',
|
|
8060
10140
|
},
|
|
8061
10141
|
paint: {
|
|
8062
|
-
"icon-color": T.
|
|
8063
|
-
"icon-opacity": ["interpolate", ["linear"], ["zoom"], 2, 0.
|
|
10142
|
+
"icon-color": T.runway,
|
|
10143
|
+
"icon-opacity": ["interpolate", ["linear"], ["zoom"], 2, 0.75, 9, 1, 11, 0.2],
|
|
8064
10144
|
},
|
|
8065
10145
|
},
|
|
8066
10146
|
{
|
|
8067
|
-
id: 'airport-runway-cross', type: 'symbol', source: sourceId, minzoom:
|
|
8068
|
-
filter: [
|
|
10147
|
+
id: 'airport-runway-cross', type: 'symbol', source: sourceId, minzoom: 4, 'source-layer': 'airport',
|
|
10148
|
+
filter: [
|
|
10149
|
+
'all',
|
|
10150
|
+
['has', 'RWY_BRG2'],
|
|
10151
|
+
['case',
|
|
10152
|
+
['<=', ['zoom'], 3], ['<=', ['get', 'level'], 1],
|
|
10153
|
+
['<=', ['zoom'], 4], ['<=', ['get', 'level'], 2],
|
|
10154
|
+
['<=', ['zoom'], 5], ['<=', ['get', 'level'], 3],
|
|
10155
|
+
true
|
|
10156
|
+
]
|
|
10157
|
+
],
|
|
8069
10158
|
layout: {
|
|
8070
10159
|
'icon-image': 'runway:runway-strip',
|
|
8071
10160
|
'icon-rotate': ['get', 'RWY_BRG2'],
|
|
8072
10161
|
'icon-rotation-alignment': 'map',
|
|
8073
|
-
'icon-size': ['interpolate', ['linear'], ['zoom'],
|
|
10162
|
+
'icon-size': ['interpolate', ['linear'], ['zoom'], 2, 0.3, 9, 0.7, 12, 0.7],
|
|
8074
10163
|
'icon-allow-overlap': true,
|
|
8075
10164
|
'icon-ignore-placement': true,
|
|
8076
10165
|
'visibility': 'none',
|
|
8077
10166
|
},
|
|
8078
10167
|
paint: {
|
|
8079
|
-
"icon-color": T.
|
|
8080
|
-
"icon-opacity": ["interpolate", ["linear"], ["zoom"], 2, 0.
|
|
10168
|
+
"icon-color": T.runway,
|
|
10169
|
+
"icon-opacity": ["interpolate", ["linear"], ["zoom"], 2, 0.75, 9, 1, 11, 0.2],
|
|
8081
10170
|
},
|
|
8082
10171
|
},
|
|
8083
10172
|
{
|