@pezkuwi/wasm-crypto 7.5.9 → 7.5.10

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 (69) hide show
  1. package/LICENSE +201 -0
  2. package/bundle-pezkuwi-wasm-crypto.js +777 -0
  3. package/bundle.d.ts +37 -0
  4. package/bundle.js +165 -0
  5. package/cjs/bundle.d.ts +37 -0
  6. package/cjs/bundle.js +171 -0
  7. package/cjs/index.js +5 -0
  8. package/cjs/init.js +21 -0
  9. package/cjs/initNone.js +20 -0
  10. package/cjs/initOnlyAsm.js +20 -0
  11. package/cjs/initOnlyWasm.js +20 -0
  12. package/cjs/initWasmAsm.js +20 -0
  13. package/cjs/package.json +3 -0
  14. package/cjs/packageDetect.js +10 -0
  15. package/cjs/packageInfo.js +4 -0
  16. package/index.d.ts +2 -0
  17. package/index.js +2 -0
  18. package/{src/init.ts → init.d.ts} +2 -11
  19. package/init.js +17 -0
  20. package/initNone.d.ts +10 -0
  21. package/{src/initNone.ts → initNone.js} +4 -10
  22. package/initOnlyAsm.d.ts +10 -0
  23. package/{src/initOnlyAsm.ts → initOnlyAsm.js} +4 -10
  24. package/initOnlyWasm.d.ts +10 -0
  25. package/{src/initOnlyWasm.ts → initOnlyWasm.js} +4 -10
  26. package/initWasmAsm.d.ts +10 -0
  27. package/{src/initWasmAsm.ts → initWasmAsm.js} +4 -10
  28. package/package.json +162 -16
  29. package/packageDetect.d.ts +1 -0
  30. package/{src/packageDetect.ts → packageDetect.js} +0 -8
  31. package/packageInfo.d.ts +6 -0
  32. package/packageInfo.js +1 -0
  33. package/Cargo.toml +0 -50
  34. package/Xargo.toml +0 -2
  35. package/build/bundle.d.ts +0 -37
  36. package/src/bundle.ts +0 -247
  37. package/src/index.ts +0 -6
  38. package/src/lib.rs +0 -24
  39. package/src/mod.ts +0 -4
  40. package/src/packageInfo.ts +0 -6
  41. package/src/rs/.editorconfig +0 -10
  42. package/src/rs/bip39.rs +0 -139
  43. package/src/rs/ed25519.rs +0 -142
  44. package/src/rs/hashing.rs +0 -322
  45. package/src/rs/secp256k1.rs +0 -150
  46. package/src/rs/sr25519.rs +0 -331
  47. package/src/rs/vrf.rs +0 -144
  48. package/test/all/bip39.js +0 -86
  49. package/test/all/ed25519.js +0 -84
  50. package/test/all/hashing.js +0 -138
  51. package/test/all/index.js +0 -126
  52. package/test/all/secp256k1.js +0 -105
  53. package/test/all/sr25519.js +0 -211
  54. package/test/all/vrf.js +0 -74
  55. package/test/asm.js +0 -10
  56. package/test/deno.ts +0 -37
  57. package/test/jest.spec.ts +0 -24
  58. package/test/loader-build.js +0 -39
  59. package/test/wasm.js +0 -8
  60. package/tsconfig.build.json +0 -19
  61. package/tsconfig.spec.json +0 -16
  62. /package/{build → cjs}/index.d.ts +0 -0
  63. /package/{build → cjs}/init.d.ts +0 -0
  64. /package/{build → cjs}/initNone.d.ts +0 -0
  65. /package/{build → cjs}/initOnlyAsm.d.ts +0 -0
  66. /package/{build → cjs}/initOnlyWasm.d.ts +0 -0
  67. /package/{build → cjs}/initWasmAsm.d.ts +0 -0
  68. /package/{build → cjs}/packageDetect.d.ts +0 -0
  69. /package/{build → cjs}/packageInfo.d.ts +0 -0
@@ -1,211 +0,0 @@
1
- // Copyright 2019-2026 @pezkuwi/wasm-crypto authors & contributors
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- /* global it */
5
-
6
- import crypto from 'crypto';
7
-
8
- import { assert, hexToU8a, stringToU8a, u8aToHex } from '@pezkuwi/util';
9
-
10
- /**
11
- * @internal
12
- * @param {*} pair
13
- */
14
- function extractKeys (pair) {
15
- return [pair, pair.slice(64), pair.slice(0, 64)];
16
- }
17
-
18
- /**
19
- * @internal
20
- * @param {*} wasm
21
- */
22
- function randomPair (wasm) {
23
- return extractKeys(wasm.sr25519KeypairFromSeed(crypto.randomBytes(32)));
24
- }
25
-
26
- /**
27
- * @param {*} wasm
28
- */
29
- export function sr25519PairFromSeed (wasm) {
30
- it('creates a known pair from a known seed', () => {
31
- const pair = wasm.sr25519KeypairFromSeed(stringToU8a('12345678901234567890123456789012'));
32
-
33
- // console.log('\tSEC', u8aToHex(pair.slice(0, 64)));
34
- // console.log('\tPUB', u8aToHex(pair.slice(64)));
35
-
36
- assert(u8aToHex(pair) === '0xf0106660c3dda23f16daa9ac5b811b963077f5bc0af89f85804f0de8e424f050f98d66f39442506ff947fd911f18c7a7a5da639a63e8d3b4e233f74143d951c1741c08a06f41c596608f6774259bd9043304adfa5d3eea62760bd9be97634d63', 'ERROR: pairFromSeed() does not match');
37
- });
38
- }
39
-
40
- /**
41
- * @param {*} wasm
42
- */
43
- export function sr25519DevFromSeed (wasm) {
44
- it('creates a known development pair', () => {
45
- const pair = wasm.sr25519KeypairFromSeed(hexToU8a('0xfac7959dbfe72f052e5a0c3c8d6530f202b02fd8f9f5ca3580ec8deb7797479e'));
46
-
47
- // console.log('\tSEC', u8aToHex(pair.slice(0, 64)));
48
- // console.log('\tPUB', u8aToHex(pair.slice(64)));
49
-
50
- assert(u8aToHex(pair) === '0x28b0ae221c6bb06856b287f60d7ea0d98552ea5a16db16956849aa371db3eb51fd190cce74df356432b410bd64682309d6dedb27c76845daf388557cbac3ca3446ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a', 'ERROR: devFromSeed() does not match');
51
- });
52
- }
53
-
54
- /**
55
- * @param {*} wasm
56
- */
57
- export function sr25519VerifyExisting (wasm) {
58
- it('verifies a known signature', () => {
59
- const PK = hexToU8a('0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d');
60
- const MESSAGE = stringToU8a('I hereby verify that I control 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY');
61
- const SIGNATURE = hexToU8a('0xb83881d3bd7302981ee1c504fe5b7b394682927131fc0846fd616bb40fa14d02640fd2aca785b4cb57904765c2e4e75f59a7dd30154c209964369912091f6981');
62
-
63
- const isValid = wasm.sr25519Verify(SIGNATURE, MESSAGE, PK);
64
-
65
- // console.log('\tRES', isValid);
66
-
67
- assert(isValid, 'ERROR: Unable to verify signature');
68
- });
69
- }
70
-
71
- /**
72
- * @param {*} wasm
73
- */
74
- export function sr25519SignDeterministic (wasm) {
75
- it('creates non-deterministic signatures', () => {
76
- const [, pk, sk] = randomPair(wasm);
77
- const sig1 = u8aToHex(wasm.sr25519Sign(pk, sk, stringToU8a('this is a message')));
78
- const sig2 = u8aToHex(wasm.sr25519Sign(pk, sk, stringToU8a('this is a message')));
79
-
80
- // console.log('\tSG1', sig1);
81
- // console.log('\tSG2', sig2);
82
-
83
- assert(sig1 !== sig2, 'ERROR: Signatures are deterministic');
84
- });
85
- }
86
-
87
- /**
88
- * @param {*} wasm
89
- */
90
- export function sr25519SignAndVerify (wasm) {
91
- it('verifies a created signature', () => {
92
- const [, pk, sk] = randomPair(wasm);
93
- const signature = wasm.sr25519Sign(pk, sk, stringToU8a('this is a message'));
94
- const isValid = wasm.sr25519Verify(signature, stringToU8a('this is a message'), pk);
95
-
96
- // console.log('\tSIG', u8aToHex(signature));
97
- // console.log('\tRES', isValid);
98
-
99
- assert(isValid, 'ERROR: Unable to verify signature');
100
- });
101
- }
102
-
103
- /**
104
- * @param {*} wasm
105
- */
106
- export function sr25519DeriveHard (wasm) {
107
- it('derives using a hard path', () => {
108
- const [pair] = randomPair(wasm);
109
- const derived = wasm.sr25519DeriveKeypairHard(pair, hexToU8a('0x0c666f6f00000000000000000000000000000000000000000000000000000000'));
110
-
111
- // console.log('\tSEC', u8aToHex(derived.slice(0, 64)));
112
- // console.log('\tPUB', u8aToHex(derived.slice(64)));
113
-
114
- assert(derived.length === 96, 'Derived key length mismatch');
115
- });
116
- }
117
-
118
- /**
119
- * @param {*} wasm
120
- */
121
- export function sr25519DeriveHardKnown (wasm) {
122
- it('derives a known hard key', () => {
123
- const derived = wasm.sr25519DeriveKeypairHard(hexToU8a('0x28b0ae221c6bb06856b287f60d7ea0d98552ea5a16db16956849aa371db3eb51fd190cce74df356432b410bd64682309d6dedb27c76845daf388557cbac3ca3446ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a'), hexToU8a('0x14416c6963650000000000000000000000000000000000000000000000000000'));
124
- const publicKey = u8aToHex(derived.slice(64));
125
-
126
- // console.log('\tSEC', u8aToHex(derived.slice(0, 64)));
127
- // console.log('\tPUB', publicKey);
128
-
129
- assert(publicKey === '0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d', 'Unmatched resulting public keys');
130
- });
131
- }
132
-
133
- /**
134
- * @param {*} wasm
135
- */
136
- export function sr25519DeriveSoft (wasm) {
137
- it('derives using a soft path', () => {
138
- const [pair] = randomPair(wasm);
139
- const derived = wasm.sr25519DeriveKeypairSoft(pair, hexToU8a('0x0c666f6f00000000000000000000000000000000000000000000000000000000'));
140
-
141
- // console.log('\tSEC', u8aToHex(derived.slice(0, 64)));
142
- // console.log('\tPUB', u8aToHex(derived.slice(64)));
143
-
144
- assert(derived.length === 96, 'Derived key length mismatch');
145
- });
146
- }
147
-
148
- /**
149
- * @param {*} wasm
150
- */
151
- export function sr25519DeriveSoftKnown (wasm) {
152
- it('derives a known soft key', () => {
153
- const derived = wasm.sr25519DeriveKeypairSoft(hexToU8a('0x28b0ae221c6bb06856b287f60d7ea0d98552ea5a16db16956849aa371db3eb51fd190cce74df356432b410bd64682309d6dedb27c76845daf388557cbac3ca3446ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a'), hexToU8a('0x0c666f6f00000000000000000000000000000000000000000000000000000000'));
154
- const publicKey = u8aToHex(derived.slice(64));
155
-
156
- // console.log('\tSEC', u8aToHex(derived.slice(0, 64)));
157
- // console.log('\tPUB', publicKey);
158
-
159
- assert(publicKey === '0x40b9675df90efa6069ff623b0fdfcf706cd47ca7452a5056c7ad58194d23440a', 'Unmatched resulting public keys');
160
- });
161
- }
162
-
163
- /**
164
- * @param {*} wasm
165
- */
166
- export function sr25519DeriveSoftPubkey (wasm) {
167
- it('derives a known soft publicKey', () => {
168
- const derived = u8aToHex(wasm.sr25519DerivePublicSoft(hexToU8a('0x46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a'), hexToU8a('0x0c666f6f00000000000000000000000000000000000000000000000000000000')));
169
-
170
- // console.log('\tPUB', derived);
171
-
172
- assert(derived === '0x40b9675df90efa6069ff623b0fdfcf706cd47ca7452a5056c7ad58194d23440a', 'Unmatched resulting public keys');
173
- });
174
- }
175
-
176
- /**
177
- * @param {*} wasm
178
- */
179
- export function sr25519KeyAgreement (wasm) {
180
- it('allows for agreements', () => {
181
- const pair1 = wasm.sr25519KeypairFromSeed(hexToU8a('0x3b44c558f9a8f3dc9690d53088558c1ba2529b677e316c6054d1852595b004af'));
182
- const pair2 = wasm.sr25519KeypairFromSeed(hexToU8a('0x923b80f79c6981fe756272128ec236eb510ae016dd20bdccbd77a9416b7ab94e'));
183
- const [, pk1, sk1] = extractKeys(pair1);
184
- const [, pk2, sk2] = extractKeys(pair2);
185
-
186
- assert(u8aToHex(wasm.sr25519Agree(pk1, sk2)) === '0xfa7b90001b790fe42ff78b8cd86f6cf7a7c0a70b72f6b4c771b5d67536450222', 'Unmatched agreement keys');
187
- assert(u8aToHex(wasm.sr25519Agree(pk2, sk1)) === '0xfa7b90001b790fe42ff78b8cd86f6cf7a7c0a70b72f6b4c771b5d67536450222', 'Unmatched agreement keys');
188
-
189
- for (let i = 0; i < 256; i++) {
190
- const [, pk1, sk1] = randomPair(wasm);
191
- const [, pk2, sk2] = randomPair(wasm);
192
-
193
- assert(u8aToHex(wasm.sr25519Agree(pk1, sk2)) === u8aToHex(wasm.sr25519Agree(pk2, sk1)), 'Unmatched agreement keys');
194
- }
195
- });
196
- }
197
-
198
- /**
199
- * @param {*} wasm
200
- */
201
- export function sr25519Benchmark (wasm) {
202
- it('runs a verification benchmark', () => {
203
- const MESSAGE = stringToU8a('this is a message');
204
-
205
- for (let i = 0; i < 256; i++) {
206
- const [, pk, sk] = randomPair(wasm);
207
-
208
- assert(wasm.sr25519Verify(wasm.sr25519Sign(pk, sk, MESSAGE), MESSAGE, pk), 'ERROR: Unable to verify signature');
209
- }
210
- });
211
- }
package/test/all/vrf.js DELETED
@@ -1,74 +0,0 @@
1
- // Copyright 2019-2026 @pezkuwi/wasm-crypto authors & contributors
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- /* global it */
5
-
6
- import crypto from 'crypto';
7
-
8
- import { assert, stringToU8a, u8aToHex } from '@pezkuwi/util';
9
-
10
- /**
11
- * @internal
12
- * @param {*} pair
13
- */
14
- function extractKeys (pair) {
15
- return [pair, pair.slice(64), pair.slice(0, 64)];
16
- }
17
-
18
- /**
19
- * @internal
20
- * @param {*} wasm
21
- */
22
- function randomPair (wasm) {
23
- return extractKeys(wasm.sr25519KeypairFromSeed(crypto.randomBytes(32)));
24
- }
25
-
26
- /**
27
- * @param {*} wasm
28
- */
29
- export function vrfSignAndVerifyCompat (wasm) {
30
- it('can sign and verify (1)', () => {
31
- const [, pk, sk] = randomPair(wasm);
32
- const outAndProof = wasm.vrfSign(sk, stringToU8a('my VRF context'), stringToU8a('this is a message'), new Uint8Array());
33
- const isValid = wasm.vrfVerify(pk, stringToU8a('my VRF context'), stringToU8a('this is a message'), new Uint8Array(), outAndProof);
34
-
35
- // console.log('\tVRF', u8aToHex(outAndProof));
36
- // console.log('\tRES', isValid);
37
-
38
- assert(isValid, 'ERROR: Unable to verify VRF output & proof');
39
- });
40
- }
41
-
42
- /**
43
- * @param {*} wasm
44
- */
45
- export function vrfSignAndVerify (wasm) {
46
- it('can sign and verify (2)', () => {
47
- const [, pk, sk] = randomPair(wasm);
48
- const outAndProof = wasm.vrfSign(sk, stringToU8a('my VRF context'), stringToU8a('this is a message'), stringToU8a('extra param'));
49
- const isValid = wasm.vrfVerify(pk, stringToU8a('my VRF context'), stringToU8a('this is a message'), stringToU8a('extra param'), outAndProof);
50
-
51
- // console.log('\tVRF', u8aToHex(outAndProof));
52
- // console.log('\tRES', isValid);
53
-
54
- assert(isValid, 'ERROR: Unable to verify VRF extra output & proof');
55
- });
56
- }
57
-
58
- /**
59
- * @param {*} wasm
60
- */
61
- export function vrfSignAndVerifyDeterministic (wasm) {
62
- it('has non-deterministic outputs', () => {
63
- const [,, sk] = randomPair(wasm);
64
- const outAndProof1 = wasm.vrfSign(sk, stringToU8a('my VRF context'), stringToU8a('this is a message'), stringToU8a('extra param'));
65
- const outAndProof2 = wasm.vrfSign(sk, stringToU8a('my VRF context'), stringToU8a('this is a message'), stringToU8a('extra param'));
66
- const sig1 = u8aToHex(outAndProof1.slice(0, 32));
67
- const sig2 = u8aToHex(outAndProof2.slice(0, 32));
68
-
69
- // console.log('\tSG1', sig1);
70
- // console.log('\tSG2', sig2);
71
-
72
- assert(sig1 === sig2, 'ERROR: VRF extra outputs are non-deterministic');
73
- });
74
- }
package/test/asm.js DELETED
@@ -1,10 +0,0 @@
1
- // Copyright 2019-2026 @pezkuwi/wasm-crypto authors & contributors
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- import '@pezkuwi/wasm-crypto/initOnlyAsm';
5
-
6
- import * as wasm from '@pezkuwi/wasm-crypto';
7
-
8
- import { runUnassisted } from './all/index.js';
9
-
10
- runUnassisted('ASM', wasm);
package/test/deno.ts DELETED
@@ -1,37 +0,0 @@
1
- // Copyright 2019-2026 @pezkuwi/wasm-crypto authors & contributors
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- // This is a Deno file, so we can allow .ts imports
5
- /* eslint-disable import/extensions */
6
-
7
- // NOTE We don't use ts-expect-error here since the build folder may or may
8
- // not exist (so the error may or may not be there)
9
- //
10
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
11
- // @ts-ignore This should only run against the compiled ouput, where this should exist
12
- import * as wasm from '../build-deno/mod.ts';
13
- import { initRun, tests } from './all/index.js';
14
-
15
- type Tests = Record<string, (wasm: unknown) => void>;
16
-
17
- declare const globalThis: {
18
- it: (name: string, fn: () => void) => unknown;
19
- };
20
- declare const Deno: {
21
- test: (name: string, test: () => unknown) => unknown;
22
- };
23
-
24
- await initRun('wasm', wasm);
25
-
26
- // We use it to denote the tests
27
- globalThis.it = (name: string, fn: () => void) => Deno.test(name, () => fn());
28
-
29
- Object
30
- .entries<Tests>(tests)
31
- .forEach(([describeName, tests]) => {
32
- console.log('***', describeName);
33
-
34
- Object
35
- .values(tests)
36
- .forEach((test) => test(wasm));
37
- });
package/test/jest.spec.ts DELETED
@@ -1,24 +0,0 @@
1
- // Copyright 2019-2026 @pezkuwi/wasm-crypto authors & contributors
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- /// <reference types="@pezkuwi/dev-test/globals.d.ts" />
5
-
6
- // NOTE We don't use ts-expect-error here since the build folder may or may
7
- // not exist (so the error may or may not be there)
8
- //
9
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
10
- // @ts-ignore This should only run against the compiled ouput, where this should exist
11
- import * as wasm from '../build/index.js';
12
- import { initRun, tests } from './all/index.js';
13
-
14
- describe('wasm-crypto', (): void => {
15
- beforeAll(() => initRun('wasm', wasm));
16
-
17
- for (const name of Object.keys(tests)) {
18
- describe(`${name}`, (): void => {
19
- Object
20
- .values<(wasm: unknown) => void>(tests[name as keyof typeof tests])
21
- .forEach((fn) => fn(wasm));
22
- });
23
- }
24
- });
@@ -1,39 +0,0 @@
1
- // Copyright 2019-2026 @pezkuwi/wasm-crypto authors & contributors
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- import path from 'node:path';
5
- import process from 'node:process';
6
- import { pathToFileURL } from 'node:url';
7
-
8
- /**
9
- * Adjusts the resolver to point to the build output
10
- *
11
- * @param {*} specifier
12
- * @param {*} context
13
- * @param {*} nextResolve
14
- * @returns {*}
15
- */
16
- export function resolve (specifier, context, nextResolve) {
17
- if (specifier.startsWith('@pezkuwi/wasm-')) {
18
- const parts = specifier.split(/[\\/]/);
19
-
20
- return {
21
- format: 'module',
22
- shortCircuit: true,
23
- url: pathToFileURL(
24
- path.join(
25
- process.cwd(),
26
- ['packages', parts[1], 'build', ...parts.slice(2)]
27
- .join('/')
28
- .replace(/\/wasm-crypto-init\/build$/, '/wasm-crypto-init/build/wasm.js')
29
- .replace(/\/wasm-crypto-init\/build\/asm$/, '/wasm-crypto-init/build/asm.js')
30
- .replace(/\/wasm-crypto\/build\/initOnlyAsm$/, '/wasm-crypto/build/initOnlyAsm.js')
31
- .replace(/\/build\/packageInfo$/, '/build/packageInfo.js')
32
- .replace(/\/build$/, '/build/index.js')
33
- )
34
- ).href
35
- };
36
- }
37
-
38
- return nextResolve(specifier, context);
39
- }
package/test/wasm.js DELETED
@@ -1,8 +0,0 @@
1
- // Copyright 2019-2026 @pezkuwi/wasm-crypto authors & contributors
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- import * as wasm from '@pezkuwi/wasm-crypto';
5
-
6
- import { runUnassisted } from './all/index.js';
7
-
8
- runUnassisted('WASM', wasm);
@@ -1,19 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "baseUrl": "..",
5
- "outDir": "./build",
6
- "rootDir": "./src"
7
- },
8
- "exclude": [
9
- "**/mod.ts",
10
- "**/test/**/*"
11
- ],
12
- "references": [
13
- { "path": "../wasm-bridge/tsconfig.build.json" },
14
- { "path": "../wasm-crypto-init/tsconfig.build.json" },
15
- { "path": "../wasm-crypto-asmjs/tsconfig.build.json" },
16
- { "path": "../wasm-crypto-wasm/tsconfig.build.json" },
17
- { "path": "../wasm-util/tsconfig.build.json" }
18
- ]
19
- }
@@ -1,16 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "baseUrl": "..",
5
- "outDir": "./build",
6
- "rootDir": "./test",
7
- "emitDeclarationOnly": false,
8
- "noEmit": true
9
- },
10
- "include": [
11
- "**/test/**/*"
12
- ],
13
- "references": [
14
- { "path": "../wasm-crypto/tsconfig.build.json" }
15
- ]
16
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes