@aidc-toolkit/utility 1.0.25-beta → 1.0.27-beta

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.
Files changed (71) hide show
  1. package/dist/character-set.d.ts +222 -0
  2. package/dist/character-set.d.ts.map +1 -0
  3. package/dist/character-set.js +568 -0
  4. package/dist/character-set.js.map +1 -0
  5. package/dist/exclusion.d.ts +26 -0
  6. package/dist/exclusion.d.ts.map +1 -0
  7. package/dist/exclusion.js +18 -0
  8. package/dist/exclusion.js.map +1 -0
  9. package/dist/index.d.ts +26 -953
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +8 -3505
  12. package/dist/index.js.map +1 -1
  13. package/dist/iterable-utility.d.ts +39 -0
  14. package/dist/iterable-utility.d.ts.map +1 -0
  15. package/dist/iterable-utility.js +35 -0
  16. package/dist/iterable-utility.js.map +1 -0
  17. package/dist/locale/en/locale-resources.d.ts +33 -0
  18. package/dist/locale/en/locale-resources.d.ts.map +1 -0
  19. package/dist/locale/en/locale-resources.js +32 -0
  20. package/dist/locale/en/locale-resources.js.map +1 -0
  21. package/dist/locale/fr/locale-resources.d.ts +33 -0
  22. package/dist/locale/fr/locale-resources.d.ts.map +1 -0
  23. package/dist/locale/fr/locale-resources.js +32 -0
  24. package/dist/locale/fr/locale-resources.js.map +1 -0
  25. package/dist/locale/i18n.d.ts +27 -0
  26. package/dist/locale/i18n.d.ts.map +1 -0
  27. package/dist/locale/i18n.js +34 -0
  28. package/dist/locale/i18n.js.map +1 -0
  29. package/dist/record.d.ts +37 -0
  30. package/dist/record.d.ts.map +1 -0
  31. package/dist/record.js +58 -0
  32. package/dist/record.js.map +1 -0
  33. package/dist/reg-exp.d.ts +40 -0
  34. package/dist/reg-exp.d.ts.map +1 -0
  35. package/dist/reg-exp.js +55 -0
  36. package/dist/reg-exp.js.map +1 -0
  37. package/dist/sequence.d.ts +45 -0
  38. package/dist/sequence.d.ts.map +1 -0
  39. package/dist/sequence.js +96 -0
  40. package/dist/sequence.js.map +1 -0
  41. package/dist/string.d.ts +25 -0
  42. package/dist/string.d.ts.map +1 -0
  43. package/dist/string.js +2 -0
  44. package/dist/string.js.map +1 -0
  45. package/dist/transformer.d.ts +196 -0
  46. package/dist/transformer.d.ts.map +1 -0
  47. package/dist/transformer.js +457 -0
  48. package/dist/transformer.js.map +1 -0
  49. package/package.json +10 -6
  50. package/src/character-set.ts +62 -59
  51. package/src/index.ts +9 -9
  52. package/src/locale/i18n.ts +3 -3
  53. package/src/locale/i18next.d.ts +1 -1
  54. package/src/record.ts +8 -8
  55. package/src/reg-exp.ts +6 -6
  56. package/src/sequence.ts +21 -21
  57. package/src/transformer.ts +54 -54
  58. package/test/character-set.test.ts +1 -1
  59. package/test/record.test.ts +1 -1
  60. package/test/reg-exp.test.ts +1 -1
  61. package/test/sequence.test.ts +1 -1
  62. package/test/setup.ts +1 -1
  63. package/test/transformer.test.ts +1 -6
  64. package/tsconfig-config.json +4 -0
  65. package/tsconfig-src.json +8 -0
  66. package/tsconfig-test.json +9 -0
  67. package/tsconfig.json +12 -1
  68. package/tsup.config.ts +3 -2
  69. package/dist/index.cjs +0 -3570
  70. package/dist/index.cjs.map +0 -1
  71. package/dist/index.d.cts +0 -953
package/dist/string.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=string.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string.js","sourceRoot":"","sources":["../src/string.ts"],"names":[],"mappings":""}
@@ -0,0 +1,196 @@
1
+ import { type IndexedCallback } from "./iterable-utility.js";
2
+ /**
3
+ * Transformer primitive type.
4
+ */
5
+ export type TransformerPrimitive = string | number | bigint | boolean;
6
+ /**
7
+ * Transformer input type, one of:
8
+ *
9
+ * - TInput (primitive type)
10
+ * - Iterable\<TInput\>
11
+ *
12
+ * @template TInput
13
+ * Transformer input primitive type.
14
+ */
15
+ export type TransformerInput<TInput extends TransformerPrimitive> = TInput | Iterable<TInput>;
16
+ /**
17
+ * Transformer output, based on transformer input:
18
+ *
19
+ * - If type TTransformerInput is primitive, result is type TOutput.
20
+ * - If type TTransformerInput is Iterable, result is type Iterable\<TOutput\>.
21
+ *
22
+ * @template TTransformerInput
23
+ * Transformer input type.
24
+ *
25
+ * @template TOutput
26
+ * Output base type.
27
+ */
28
+ export type TransformerOutput<TTransformerInput extends TransformerInput<TransformerPrimitive>, TOutput> = TTransformerInput extends (TTransformerInput extends TransformerInput<infer TInput> ? TInput : never) ? TOutput : Iterable<TOutput>;
29
+ /**
30
+ * Transformer that transforms values in a numeric domain to values in a range equal to the domain or to another range
31
+ * defined by a callback function. In other words, the domain determines valid input values and, without a callback, the
32
+ * range of valid output values.
33
+ *
34
+ * The concept is similar to {@link https://en.wikipedia.org/wiki/Format-preserving_encryption | format-preserving
35
+ * encryption}, where input values within a specified domain (e.g., {@link
36
+ * https://en.wikipedia.org/wiki/Payment_card_number | payment card numbers} ranging from 8-19 digits) are transformed
37
+ * into values in the same domain, typically for storage in a database where the data type and length are already fixed
38
+ * and exfiltration of the data can have significant repercussions.
39
+ *
40
+ * Two subclasses are supported directly by this class: {@linkcode IdentityTransformer} (which operates based on a
41
+ * domain only) and {@linkcode EncryptionTransformer} (which operates based on a domain and a tweak). If an application
42
+ * is expected to make repeated use of a transformer with the same domain and (optional) tweak and can't manage the
43
+ * transformer object, an in-memory cache is available via the {@linkcode get | get()} method. Properties in {@linkcode
44
+ * IdentityTransformer} and {@linkcode EncryptionTransformer} are read-only once constructed, so there is no issue with
45
+ * their shared use.
46
+ */
47
+ export declare abstract class Transformer {
48
+ #private;
49
+ /**
50
+ * Constructor.
51
+ *
52
+ * @param domain
53
+ * Domain.
54
+ */
55
+ constructor(domain: number | bigint);
56
+ /**
57
+ * Get a transformer, constructing it if necessary. The type returned is {@linkcode IdentityTransformer} if tweak is
58
+ * undefined, {@linkcode EncryptionTransformer} if tweak is defined. Note that although an {@linkcode
59
+ * EncryptionTransformer} with a zero tweak operates as an {@linkcode IdentityTransformer}, {@linkcode
60
+ * EncryptionTransformer} is still the type returned if a zero tweak is explicitly specified.
61
+ *
62
+ * @param domain
63
+ * Domain.
64
+ *
65
+ * @param tweak
66
+ * Tweak.
67
+ *
68
+ * @returns
69
+ * {@linkcode IdentityTransformer} if tweak is undefined, {@linkcode EncryptionTransformer} if tweak is defined.
70
+ */
71
+ static get(domain: number | bigint, tweak?: number | bigint): Transformer;
72
+ /**
73
+ * Get the domain.
74
+ */
75
+ get domain(): bigint;
76
+ /**
77
+ * Do the work of transforming a value forward.
78
+ *
79
+ * @param value
80
+ * Value.
81
+ *
82
+ * @returns
83
+ * Transformed value.
84
+ */
85
+ protected abstract doForward(value: bigint): bigint;
86
+ /**
87
+ * Transform value(s) forward.
88
+ *
89
+ * @template TTransformerInput
90
+ * Value(s) input type.
91
+ *
92
+ * @param valueOrValues
93
+ * Value(s). If this is an instance of {@linkcode Sequence}, the minimum and maximum values are validated prior to
94
+ * transformation. Otherwise, the individual value(s) is/are validated at the time of transformation.
95
+ *
96
+ * @returns
97
+ * Transformed value(s).
98
+ */
99
+ forward<TTransformerInput extends TransformerInput<number | bigint>>(valueOrValues: TTransformerInput): TransformerOutput<TTransformerInput, bigint>;
100
+ /**
101
+ * Transform value(s) forward, optionally applying a transformation.
102
+ *
103
+ * @template TTransformerInput
104
+ * Value(s) input type.
105
+ *
106
+ * @template TOutput
107
+ * Transformation callback output type.
108
+ *
109
+ * @param valueOrValues
110
+ * Value(s). If this is an instance of {@linkcode Sequence}, the minimum and maximum values are validated prior to
111
+ * transformation. Otherwise, the individual value(s) is/are validated at the time of transformation.
112
+ *
113
+ * @param transformerCallback
114
+ * Called after each value is transformed to convert it to its final value.
115
+ *
116
+ * @returns
117
+ * Transformed value(s).
118
+ */
119
+ forward<TTransformerInput extends TransformerInput<number | bigint>, TOutput>(valueOrValues: TTransformerInput, transformerCallback: IndexedCallback<bigint, TOutput>): TransformerOutput<TTransformerInput, TOutput>;
120
+ /**
121
+ * Do the work of transforming a value in reverse.
122
+ *
123
+ * @param transformedValue
124
+ * Transformed value.
125
+ *
126
+ * @returns
127
+ * Value.
128
+ */
129
+ protected abstract doReverse(transformedValue: bigint): bigint;
130
+ /**
131
+ * Transform a value in reverse.
132
+ *
133
+ * @param transformedValue
134
+ * Transformed value.
135
+ *
136
+ * @returns
137
+ * Value.
138
+ */
139
+ reverse(transformedValue: number | bigint): bigint;
140
+ }
141
+ /**
142
+ * Identity transformer. Values are transformed to themselves.
143
+ */
144
+ export declare class IdentityTransformer extends Transformer {
145
+ /**
146
+ * @inheritDoc
147
+ */
148
+ protected doForward(value: bigint): bigint;
149
+ /**
150
+ * @inheritDoc
151
+ */
152
+ protected doReverse(transformedValue: bigint): bigint;
153
+ }
154
+ /**
155
+ * Encryption transformer. Values are transformed using repeated shuffle and xor operations, similar to those found in
156
+ * many cryptography algorithms, particularly AES. While sufficient for obfuscation of numeric sequences (e.g., serial
157
+ * number generation, below), if true format-preserving encryption is required, a more robust algorithm such as {@link
158
+ * https://doi.org/10.6028/NIST.SP.800-38Gr1.2pd | FF1} is recommended. Furthermore, no work has been done to mitigate
159
+ * {@link https://timing.attacks.cr.yp.to/index.html | timing attacks} for key detection.
160
+ *
161
+ * The purpose of the encryption transformer is to generate pseudo-random values in a deterministic manner to obscure
162
+ * the sequence of values generated over time. A typical example is for serial number generation, where knowledge of the
163
+ * sequence can infer production volumes (e.g., serial number 1000 implies that at least 1,000 units have been
164
+ * manufactured) or can be used in counterfeiting (e.g., a counterfeiter can generate serial numbers 1001, 1002, ...
165
+ * with reasonable confidence that they would be valid if queried).
166
+ *
167
+ * The domain and the tweak together determine the encryption key, which in turn determines the number of rounds of
168
+ * shuffle and xor operations. The minimum number of rounds is 4, except where the domain is less than or equal to 256,
169
+ * which results in single-byte operations. To ensure that the operations are effective for single-byte domains, the
170
+ * number of rounds is 1 and only the xor operation is applied (shuffling a single byte is an identity operation).
171
+ *
172
+ * Another exception is when there is a tweak value of 0; this results in identity operations where the output value is
173
+ * identical to the input value, as no shuffle or xor takes place.
174
+ */
175
+ export declare class EncryptionTransformer extends Transformer {
176
+ #private;
177
+ /**
178
+ * Constructor.
179
+ *
180
+ * @param domain
181
+ * Domain.
182
+ *
183
+ * @param tweak
184
+ * Tweak.
185
+ */
186
+ constructor(domain: number | bigint, tweak: number | bigint);
187
+ /**
188
+ * @inheritDoc
189
+ */
190
+ protected doForward(value: bigint): bigint;
191
+ /**
192
+ * @inheritDoc
193
+ */
194
+ protected doReverse(transformedValue: bigint): bigint;
195
+ }
196
+ //# sourceMappingURL=transformer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformer.d.ts","sourceRoot":"","sources":["../src/transformer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAe,MAAM,uBAAuB,CAAC;AAI1E;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtE;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,CAAC,MAAM,SAAS,oBAAoB,IAAI,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;AAE9F;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,iBAAiB,CAAC,iBAAiB,SAAS,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,OAAO,IAAI,iBAAiB,SAAS,CAAC,iBAAiB,SAAS,gBAAgB,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC,GAAG,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;AAE/O;;;;;;;;;;;;;;;;;GAiBG;AACH,8BAAsB,WAAW;;IAW7B;;;;;OAKG;gBACS,MAAM,EAAE,MAAM,GAAG,MAAM;IAUnC;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW;IAsBzE;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;IAuBD;;;;;;;;OAQG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAsCnD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,iBAAiB,SAAS,gBAAgB,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,aAAa,EAAE,iBAAiB,GAAG,iBAAiB,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAEpJ;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,iBAAiB,SAAS,gBAAgB,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,iBAAiB,CAAC,iBAAiB,EAAE,OAAO,CAAC;IAgCrN;;;;;;;;OAQG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM;IAE9D;;;;;;;;OAQG;IACH,OAAO,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM;CAOrD;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;IAChD;;OAEG;IACH,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAI1C;;OAEG;IACH,SAAS,CAAC,SAAS,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM;CAGxD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,qBAAsB,SAAQ,WAAW;;IAwClD;;;;;;;;OAQG;gBACS,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAuM3D;;OAEG;IACH,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAiB1C;;OAEG;IACH,SAAS,CAAC,SAAS,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM;CAgBxD"}
@@ -0,0 +1,457 @@
1
+ import { mapIterable } from "./iterable-utility.js";
2
+ import { i18nextUtility } from "./locale/i18n.js";
3
+ import { Sequence } from "./sequence.js";
4
+ /**
5
+ * Transformer that transforms values in a numeric domain to values in a range equal to the domain or to another range
6
+ * defined by a callback function. In other words, the domain determines valid input values and, without a callback, the
7
+ * range of valid output values.
8
+ *
9
+ * The concept is similar to {@link https://en.wikipedia.org/wiki/Format-preserving_encryption | format-preserving
10
+ * encryption}, where input values within a specified domain (e.g., {@link
11
+ * https://en.wikipedia.org/wiki/Payment_card_number | payment card numbers} ranging from 8-19 digits) are transformed
12
+ * into values in the same domain, typically for storage in a database where the data type and length are already fixed
13
+ * and exfiltration of the data can have significant repercussions.
14
+ *
15
+ * Two subclasses are supported directly by this class: {@linkcode IdentityTransformer} (which operates based on a
16
+ * domain only) and {@linkcode EncryptionTransformer} (which operates based on a domain and a tweak). If an application
17
+ * is expected to make repeated use of a transformer with the same domain and (optional) tweak and can't manage the
18
+ * transformer object, an in-memory cache is available via the {@linkcode get | get()} method. Properties in {@linkcode
19
+ * IdentityTransformer} and {@linkcode EncryptionTransformer} are read-only once constructed, so there is no issue with
20
+ * their shared use.
21
+ */
22
+ export class Transformer {
23
+ /**
24
+ * Transformers cache, mapping a domain to another map, which maps an optional tweak to a transformer.
25
+ */
26
+ static #TRANSFORMER_MAPS_MAP = new Map();
27
+ /**
28
+ * Domain.
29
+ */
30
+ #domain;
31
+ /**
32
+ * Constructor.
33
+ *
34
+ * @param domain
35
+ * Domain.
36
+ */
37
+ constructor(domain) {
38
+ this.#domain = BigInt(domain);
39
+ if (this.#domain <= 0n) {
40
+ throw new RangeError(i18nextUtility.t("Transformer.domainMustBeGreaterThanZero", {
41
+ domain
42
+ }));
43
+ }
44
+ }
45
+ /**
46
+ * Get a transformer, constructing it if necessary. The type returned is {@linkcode IdentityTransformer} if tweak is
47
+ * undefined, {@linkcode EncryptionTransformer} if tweak is defined. Note that although an {@linkcode
48
+ * EncryptionTransformer} with a zero tweak operates as an {@linkcode IdentityTransformer}, {@linkcode
49
+ * EncryptionTransformer} is still the type returned if a zero tweak is explicitly specified.
50
+ *
51
+ * @param domain
52
+ * Domain.
53
+ *
54
+ * @param tweak
55
+ * Tweak.
56
+ *
57
+ * @returns
58
+ * {@linkcode IdentityTransformer} if tweak is undefined, {@linkcode EncryptionTransformer} if tweak is defined.
59
+ */
60
+ static get(domain, tweak) {
61
+ const domainN = BigInt(domain);
62
+ let transformersMap = Transformer.#TRANSFORMER_MAPS_MAP.get(domainN);
63
+ if (transformersMap === undefined) {
64
+ transformersMap = new Map();
65
+ Transformer.#TRANSFORMER_MAPS_MAP.set(domainN, transformersMap);
66
+ }
67
+ const tweakN = tweak === undefined ? undefined : BigInt(tweak);
68
+ let transformer = transformersMap.get(tweakN);
69
+ if (transformer === undefined) {
70
+ transformer = tweakN === undefined ? new IdentityTransformer(domainN) : new EncryptionTransformer(domainN, tweakN);
71
+ transformersMap.set(tweakN, transformer);
72
+ }
73
+ return transformer;
74
+ }
75
+ /**
76
+ * Get the domain.
77
+ */
78
+ get domain() {
79
+ return this.#domain;
80
+ }
81
+ /**
82
+ * Validate that a value is within the domain.
83
+ *
84
+ * @param value
85
+ * Value.
86
+ */
87
+ #validate(value) {
88
+ if (value < 0n) {
89
+ throw new RangeError(i18nextUtility.t("Transformer.valueMustBeGreaterThanOrEqualToZero", {
90
+ value
91
+ }));
92
+ }
93
+ if (value >= this.domain) {
94
+ throw new RangeError(i18nextUtility.t("Transformer.valueMustBeLessThan", {
95
+ value,
96
+ domain: this.domain
97
+ }));
98
+ }
99
+ }
100
+ /**
101
+ * Validate that a value is within the domain and do the work of transforming it forward.
102
+ *
103
+ * @param value
104
+ * Value.
105
+ *
106
+ * @returns
107
+ * Transformed value.
108
+ */
109
+ #validateDoForward(value) {
110
+ const valueN = BigInt(value);
111
+ this.#validate(valueN);
112
+ return this.doForward(valueN);
113
+ }
114
+ /**
115
+ * Validate that a value is within the domain, do the work of transforming it forward, and apply a callback.
116
+ *
117
+ * @param transformerCallback
118
+ * Called after each value is transformed to convert it to its final value.
119
+ *
120
+ * @param value
121
+ * Value.
122
+ *
123
+ * @param index
124
+ * Index in sequence (0 for single transformation).
125
+ *
126
+ * @returns
127
+ * Transformed value.
128
+ */
129
+ #validateDoForwardCallback(transformerCallback, value, index) {
130
+ return transformerCallback(this.#validateDoForward(value), index);
131
+ }
132
+ ;
133
+ // eslint-disable-next-line jsdoc/require-jsdoc -- Implementation of overloaded signatures.
134
+ forward(valueOrValues, transformerCallback) {
135
+ // TODO Refactor type when https://github.com/microsoft/TypeScript/pull/56941 released.
136
+ let result;
137
+ if (typeof valueOrValues !== "object") {
138
+ result = transformerCallback === undefined ? this.#validateDoForward(valueOrValues) : this.#validateDoForwardCallback(transformerCallback, valueOrValues);
139
+ }
140
+ else if (valueOrValues instanceof Sequence) {
141
+ if (valueOrValues.minimumValue < 0n) {
142
+ throw new RangeError(i18nextUtility.t("Transformer.minimumValueMustBeGreaterThanOrEqualToZero", {
143
+ minimumValue: valueOrValues.minimumValue
144
+ }));
145
+ }
146
+ if (valueOrValues.maximumValue >= this.domain) {
147
+ throw new RangeError(i18nextUtility.t("Transformer.maximumValueMustBeLessThan", {
148
+ maximumValue: valueOrValues.maximumValue,
149
+ domain: this.domain
150
+ }));
151
+ }
152
+ result = transformerCallback === undefined ? mapIterable(valueOrValues, value => this.doForward(value)) : mapIterable(valueOrValues, (value, index) => transformerCallback(this.doForward(value), index));
153
+ }
154
+ else {
155
+ result = transformerCallback === undefined ? mapIterable(valueOrValues, value => this.#validateDoForward(value)) : mapIterable(valueOrValues, (value, index) => this.#validateDoForwardCallback(transformerCallback, value, index));
156
+ }
157
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type determination is handled above.
158
+ return result;
159
+ }
160
+ /**
161
+ * Transform a value in reverse.
162
+ *
163
+ * @param transformedValue
164
+ * Transformed value.
165
+ *
166
+ * @returns
167
+ * Value.
168
+ */
169
+ reverse(transformedValue) {
170
+ const transformedValueN = BigInt(transformedValue);
171
+ this.#validate(transformedValueN);
172
+ return this.doReverse(transformedValueN);
173
+ }
174
+ }
175
+ /**
176
+ * Identity transformer. Values are transformed to themselves.
177
+ */
178
+ export class IdentityTransformer extends Transformer {
179
+ /**
180
+ * @inheritDoc
181
+ */
182
+ doForward(value) {
183
+ return value;
184
+ }
185
+ /**
186
+ * @inheritDoc
187
+ */
188
+ doReverse(transformedValue) {
189
+ return transformedValue;
190
+ }
191
+ }
192
+ /**
193
+ * Encryption transformer. Values are transformed using repeated shuffle and xor operations, similar to those found in
194
+ * many cryptography algorithms, particularly AES. While sufficient for obfuscation of numeric sequences (e.g., serial
195
+ * number generation, below), if true format-preserving encryption is required, a more robust algorithm such as {@link
196
+ * https://doi.org/10.6028/NIST.SP.800-38Gr1.2pd | FF1} is recommended. Furthermore, no work has been done to mitigate
197
+ * {@link https://timing.attacks.cr.yp.to/index.html | timing attacks} for key detection.
198
+ *
199
+ * The purpose of the encryption transformer is to generate pseudo-random values in a deterministic manner to obscure
200
+ * the sequence of values generated over time. A typical example is for serial number generation, where knowledge of the
201
+ * sequence can infer production volumes (e.g., serial number 1000 implies that at least 1,000 units have been
202
+ * manufactured) or can be used in counterfeiting (e.g., a counterfeiter can generate serial numbers 1001, 1002, ...
203
+ * with reasonable confidence that they would be valid if queried).
204
+ *
205
+ * The domain and the tweak together determine the encryption key, which in turn determines the number of rounds of
206
+ * shuffle and xor operations. The minimum number of rounds is 4, except where the domain is less than or equal to 256,
207
+ * which results in single-byte operations. To ensure that the operations are effective for single-byte domains, the
208
+ * number of rounds is 1 and only the xor operation is applied (shuffling a single byte is an identity operation).
209
+ *
210
+ * Another exception is when there is a tweak value of 0; this results in identity operations where the output value is
211
+ * identical to the input value, as no shuffle or xor takes place.
212
+ */
213
+ export class EncryptionTransformer extends Transformer {
214
+ /**
215
+ * Individual bits, pre-calculated for performance.
216
+ */
217
+ static #BITS = new Uint8Array([
218
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
219
+ ]);
220
+ /**
221
+ * Inverse individual bits, pre-calculated for performance.
222
+ */
223
+ static #INVERSE_BITS = new Uint8Array([
224
+ 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F
225
+ ]);
226
+ /**
227
+ * Number of bytes covered by the domain.
228
+ */
229
+ #domainBytes;
230
+ /**
231
+ * Xor bytes array generated from the domain and tweak.
232
+ */
233
+ #xorBytes;
234
+ /**
235
+ * Bits array generated from the domain and tweak.
236
+ */
237
+ #bits;
238
+ /**
239
+ * Inverse bits array generated from the domain and tweak.
240
+ */
241
+ #inverseBits;
242
+ /**
243
+ * Number of rounds (length of arrays) generated from the domain and tweak.
244
+ */
245
+ #rounds;
246
+ /**
247
+ * Constructor.
248
+ *
249
+ * @param domain
250
+ * Domain.
251
+ *
252
+ * @param tweak
253
+ * Tweak.
254
+ */
255
+ constructor(domain, tweak) {
256
+ super(domain);
257
+ if (tweak < 0n) {
258
+ throw new RangeError(i18nextUtility.t("Transformer.tweakMustBeGreaterThanOrEqualToZero", {
259
+ tweak
260
+ }));
261
+ }
262
+ let domainBytes = 0;
263
+ // The number of bytes in the domain determines the size of the shuffle and xor operations.
264
+ for (let reducedDomainMinusOne = this.domain - 1n; reducedDomainMinusOne !== 0n; reducedDomainMinusOne >>= 8n) {
265
+ domainBytes++;
266
+ }
267
+ this.#domainBytes = domainBytes;
268
+ const xorBytes = new Array();
269
+ const bits = new Array();
270
+ const inverseBits = new Array();
271
+ // Key is the product of domain, tweak, and an 8-digit prime to force at least four rounds.
272
+ for (let reducedKey = this.domain * BigInt(tweak) * 603868999n; reducedKey !== 0n; reducedKey >>= 8n) {
273
+ // Extract the least significant byte.
274
+ xorBytes.unshift(Number(BigInt.asUintN(8, reducedKey)));
275
+ // Bit number is the reduced key mod 8.
276
+ const bitNumber = Number(BigInt.asUintN(3, reducedKey));
277
+ // Bits are applied in reverse order so that they don't correlate directly with the key bytes at the same index.
278
+ bits.push(EncryptionTransformer.#BITS[bitNumber]);
279
+ inverseBits.push(EncryptionTransformer.#INVERSE_BITS[bitNumber]);
280
+ }
281
+ // Domains occupying a single byte will not shuffle and will map all values to themselves for very small domains.
282
+ if (domainBytes === 1) {
283
+ // Determine the lowest possible mask that will cover all values in the domain.
284
+ const domainMask = EncryptionTransformer.#BITS.filter(bit => bit < domain).reduce((accumulator, bit) => accumulator | bit, 0);
285
+ // Reduce all xor bytes to a single byte and strip higher bits.
286
+ this.#xorBytes = new Uint8Array([xorBytes.reduce((accumulator, xorByte) => accumulator ^ xorByte, 0) & domainMask]);
287
+ // Bits and inverse bits are irrelevant as there will be no shuffling; choose first bit arbitrarily.
288
+ this.#bits = new Uint8Array([EncryptionTransformer.#BITS[0]]);
289
+ this.#inverseBits = new Uint8Array([EncryptionTransformer.#INVERSE_BITS[0]]);
290
+ // Everything will be done in one round.
291
+ this.#rounds = 1;
292
+ }
293
+ else {
294
+ this.#xorBytes = new Uint8Array(xorBytes);
295
+ this.#bits = new Uint8Array(bits);
296
+ this.#inverseBits = new Uint8Array(inverseBits);
297
+ this.#rounds = xorBytes.length;
298
+ }
299
+ }
300
+ /**
301
+ * Convert a value to a byte array big enough to handle the entire domain.
302
+ *
303
+ * @param value
304
+ * Value.
305
+ *
306
+ * @returns
307
+ * Big-endian byte array equivalent to the value.
308
+ */
309
+ #valueToBytes(value) {
310
+ const bytes = new Uint8Array(this.#domainBytes);
311
+ // Build byte array in reverse order to get as big-endian.
312
+ for (let index = this.#domainBytes - 1, reducedValue = value; index >= 0 && reducedValue !== 0n; index--, reducedValue >>= 8n) {
313
+ bytes[index] = Number(BigInt.asUintN(8, reducedValue));
314
+ }
315
+ return bytes;
316
+ }
317
+ /**
318
+ * Convert a byte array to a value.
319
+ *
320
+ * @param bytes
321
+ * Big-endian byte array equivalent to the value.
322
+ *
323
+ * @returns
324
+ * Value.
325
+ */
326
+ static #bytesToValue(bytes) {
327
+ return bytes.reduce((accumulator, byte) => accumulator << 8n | BigInt(byte), 0n);
328
+ }
329
+ /**
330
+ * Shuffle a byte array.
331
+ *
332
+ * The input array to the forward operation (output from the reverse operation) is `bytes` and the output array from
333
+ * the forward operation (input to the reverse operation) is `bytes'`.
334
+ *
335
+ * The shuffle operation starts by testing the bit at `bits[round]` for each `byte` in `bytes`. The indexes for all
336
+ * bytes with that bit set are put into one array (`shuffleIndexes1`) and the rest are put into another
337
+ * (`shuffleIndexes0`). The two arrays are concatenated and used to shuffle the input array, using their values
338
+ * (`shuffleIndex`) and the indexes of those values (`index`) in the concatenated array.
339
+ *
340
+ * Forward shuffling moves the entry at `shuffleIndex` to the `index` position.
341
+ *
342
+ * Reverse shuffling moves the entry at `index` to the `shuffleIndex` position.
343
+ *
344
+ * As each byte is moved, the bit at `bits[round]` is preserved in its original position. This ensures that the
345
+ * process is reversible.
346
+ *
347
+ * @param bytes
348
+ * Byte array.
349
+ *
350
+ * @param round
351
+ * Round number.
352
+ *
353
+ * @param forward
354
+ * True if operating forward (encrypting), false if operating in reverse (decrypting).
355
+ *
356
+ * @returns
357
+ * Shuffled byte array.
358
+ */
359
+ #shuffle(bytes, round, forward) {
360
+ const bytesLength = bytes.length;
361
+ const determinants = new Uint8Array(bytesLength);
362
+ const shuffleIndexes1 = new Array();
363
+ const shuffleIndexes0 = new Array();
364
+ const bit = this.#bits[round];
365
+ bytes.forEach((byte, index) => {
366
+ const determinant = byte & bit;
367
+ determinants[index] = determinant;
368
+ // Place byte in array chosen by bit state.
369
+ (determinant !== 0 ? shuffleIndexes1 : shuffleIndexes0).push(index);
370
+ });
371
+ const inverseBit = this.#inverseBits[round];
372
+ const shuffleBytes = new Uint8Array(bytesLength);
373
+ // Concatenate shuffle indexes arrays and complete shuffle.
374
+ [...shuffleIndexes1, ...shuffleIndexes0].forEach((shuffleIndex, index) => {
375
+ if (forward) {
376
+ shuffleBytes[index] = (bytes[shuffleIndex] & inverseBit) | determinants[index];
377
+ }
378
+ else {
379
+ shuffleBytes[shuffleIndex] = (bytes[index] & inverseBit) | determinants[shuffleIndex];
380
+ }
381
+ });
382
+ return shuffleBytes;
383
+ }
384
+ /**
385
+ * Xor a byte array.
386
+ *
387
+ * The input array to the forward operation (output from the reverse operation) is `bytes` and the output array from
388
+ * the forward operation (input to the reverse operation) is `bytes'`.
389
+ *
390
+ * Forward:
391
+ * - `bytes'[0] = bytes[0] ^ xorBytes[round]`
392
+ * - `bytes'[1] = bytes[1] ^ bytes'[0]`
393
+ * - `bytes'[2] = bytes[2] ^ bytes'[1]`
394
+ * - `...`
395
+ * - `bytes'[domainBytes - 1] = bytes[domainBytes - 1] ^ bytes'[domainBytes - 2]`
396
+ *
397
+ * Reverse:
398
+ * - `bytes[0] = bytes'[0] ^ xorBytes[round]`
399
+ * - `bytes[1] = bytes'[1] ^ bytes'[0]`
400
+ * - `bytes[2] = bytes'[2] ^ bytes'[1]`
401
+ * - `...`
402
+ * - `bytes[domainBytes - 1] = bytes'[domainBytes - 1] ^ bytes'[domainBytes - 2]`
403
+ *
404
+ * @param bytes
405
+ * Byte array.
406
+ *
407
+ * @param round
408
+ * Round number.
409
+ *
410
+ * @param forward
411
+ * True if operating forward (encrypting), false if operating in reverse (decrypting).
412
+ *
413
+ * @returns
414
+ * Xored byte array.
415
+ */
416
+ #xor(bytes, round, forward) {
417
+ let cumulativeXorByte = this.#xorBytes[round];
418
+ return bytes.map((byte) => {
419
+ const xorByte = byte ^ cumulativeXorByte;
420
+ cumulativeXorByte = forward ? xorByte : byte;
421
+ return xorByte;
422
+ });
423
+ }
424
+ /**
425
+ * @inheritDoc
426
+ */
427
+ doForward(value) {
428
+ let bytes = this.#valueToBytes(value);
429
+ let transformedValue;
430
+ // Loop repeats until transformed value is within domain.
431
+ do {
432
+ // Forward operation is shuffle then xor for the number of rounds.
433
+ for (let round = 0; round < this.#rounds; round++) {
434
+ bytes = this.#xor(this.#shuffle(bytes, round, true), round, true);
435
+ }
436
+ transformedValue = EncryptionTransformer.#bytesToValue(bytes);
437
+ } while (transformedValue >= this.domain);
438
+ return transformedValue;
439
+ }
440
+ /**
441
+ * @inheritDoc
442
+ */
443
+ doReverse(transformedValue) {
444
+ let bytes = this.#valueToBytes(transformedValue);
445
+ let value;
446
+ // Loop repeats until value is within domain.
447
+ do {
448
+ // Reverse operation is xor then shuffle for the number of rounds in reverse.
449
+ for (let round = this.#rounds - 1; round >= 0; round--) {
450
+ bytes = this.#shuffle(this.#xor(bytes, round, false), round, false);
451
+ }
452
+ value = EncryptionTransformer.#bytesToValue(bytes);
453
+ } while (value >= this.domain);
454
+ return value;
455
+ }
456
+ }
457
+ //# sourceMappingURL=transformer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformer.js","sourceRoot":"","sources":["../src/transformer.ts"],"names":[],"mappings":"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"}