@metamask-previews/eth-sig-util 0.0.0-stage → 9.0.0-preview-06c1d7a06

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/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Changed
11
+
12
+ - **BREAKING:** Drop CommonJS support ([#11349](https://github.com/MetaMask/core/pull/11349), [#11362](https://github.com/MetaMask/core/pull/11362))
13
+ - This package is now ESM-only, but can still be used in CommonJS projects via `require(esm)` in modern Node.js versions (22+), or dynamic imports in older Node.js versions.
14
+ - **BREAKING:** Bump TypeScript target to ES2022 ([#11348](https://github.com/MetaMask/core/pull/11348))
15
+ - Bump `@metamask/utils` from `^11.0.1` to `^12.0.1` ([#11349](https://github.com/MetaMask/core/pull/11349))
16
+ - Bump `ethereum-cryptography` from `^2.1.2` to `^3.2.0` ([#11349](https://github.com/MetaMask/core/pull/11349))
17
+ - Bump `@scure/base` from `~1.1.3` to `^1.2.6` ([#11349](https://github.com/MetaMask/core/pull/11349))
18
+ - This package was migrated from `MetaMask/eth-sig-util` to the
19
+ `MetaMask/core` monorepo ([#11327](https://github.com/MetaMask/core/pull/11327))
20
+ - See [`MetaMask/eth-sig-util`](https://github.com/MetaMask/eth-sig-util/blob/73725fc31a51e4d5f6b72d8e5f470c0b10c9d57f/CHANGELOG.md)
21
+ for the original changelog.
22
+
23
+ [Unreleased]: https://github.com/MetaMask/core/
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2020 MetaMask
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,19 @@
1
- # Temporary Holding Version
1
+ # `@metamask/eth-sig-util`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A small collection of Ethereum signing functions.
4
+
5
+ ## Installation
6
+
7
+ `yarn add @metamask/eth-sig-util`
8
+
9
+ or
10
+
11
+ `npm install @metamask/eth-sig-util`
12
+
13
+ ## API
14
+
15
+ The full API documentation for the latest published version of this library is [available here](https://metamask.github.io/eth-sig-util/latest/index.html).
16
+
17
+ ## Contributing
18
+
19
+ This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
@@ -0,0 +1,69 @@
1
+ export type EthEncryptedData = {
2
+ version: string;
3
+ nonce: string;
4
+ ephemPublicKey: string;
5
+ ciphertext: string;
6
+ };
7
+ /**
8
+ * Encrypt a message.
9
+ *
10
+ * @param options - The encryption options.
11
+ * @param options.publicKey - The public key of the message recipient.
12
+ * @param options.data - The message data.
13
+ * @param options.version - The type of encryption to use.
14
+ * @returns The encrypted data.
15
+ */
16
+ export declare function encrypt({ publicKey, data, version, }: {
17
+ publicKey: string;
18
+ data: unknown;
19
+ version: string;
20
+ }): EthEncryptedData;
21
+ /**
22
+ * Encrypt a message in a way that obscures the message length.
23
+ *
24
+ * The message is padded to a multiple of 2048 before being encrypted so that the length of the
25
+ * resulting encrypted message can't be used to guess the exact length of the original message.
26
+ *
27
+ * @param options - The encryption options.
28
+ * @param options.publicKey - The public key of the message recipient.
29
+ * @param options.data - The message data.
30
+ * @param options.version - The type of encryption to use.
31
+ * @returns The encrypted data.
32
+ */
33
+ export declare function encryptSafely({ publicKey, data, version, }: {
34
+ publicKey: string;
35
+ data: unknown;
36
+ version: string;
37
+ }): EthEncryptedData;
38
+ /**
39
+ * Decrypt a message.
40
+ *
41
+ * @param options - The decryption options.
42
+ * @param options.encryptedData - The encrypted data.
43
+ * @param options.privateKey - The private key to decrypt with.
44
+ * @returns The decrypted message.
45
+ */
46
+ export declare function decrypt({ encryptedData, privateKey, }: {
47
+ encryptedData: EthEncryptedData;
48
+ privateKey: string;
49
+ }): string;
50
+ /**
51
+ * Decrypt a message that has been encrypted using `encryptSafely`.
52
+ *
53
+ * @param options - The decryption options.
54
+ * @param options.encryptedData - The encrypted data.
55
+ * @param options.privateKey - The private key to decrypt with.
56
+ * @returns The decrypted message.
57
+ */
58
+ export declare function decryptSafely({ encryptedData, privateKey, }: {
59
+ encryptedData: EthEncryptedData;
60
+ privateKey: string;
61
+ }): string;
62
+ /**
63
+ * Get the encryption public key for the given key.
64
+ *
65
+ * @param privateKey - The private key to generate the encryption public key with.
66
+ * @returns The encryption public key.
67
+ */
68
+ export declare function getEncryptionPublicKey(privateKey: string): string;
69
+ //# sourceMappingURL=encryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,EACtB,SAAS,EACT,IAAI,EACJ,OAAO,GACR,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,gBAAgB,CAkDnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,SAAS,EACT,IAAI,EACJ,OAAO,GACR,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,gBAAgB,CAyCnB;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,EACtB,aAAa,EACb,UAAU,GACX,EAAE;IACD,aAAa,EAAE,gBAAgB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAiDT;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAC5B,aAAa,EACb,UAAU,GACX,EAAE;IACD,aAAa,EAAE,gBAAgB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAST;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAKjE"}
@@ -0,0 +1,179 @@
1
+ import { base64, utf8 } from '@scure/base';
2
+ import * as nacl from 'tweetnacl';
3
+ import { isNullish } from './utils.js';
4
+ /**
5
+ * Encrypt a message.
6
+ *
7
+ * @param options - The encryption options.
8
+ * @param options.publicKey - The public key of the message recipient.
9
+ * @param options.data - The message data.
10
+ * @param options.version - The type of encryption to use.
11
+ * @returns The encrypted data.
12
+ */
13
+ export function encrypt({ publicKey, data, version, }) {
14
+ if (isNullish(publicKey)) {
15
+ throw new Error('Missing publicKey parameter');
16
+ }
17
+ else if (isNullish(data)) {
18
+ throw new Error('Missing data parameter');
19
+ }
20
+ else if (isNullish(version)) {
21
+ throw new Error('Missing version parameter');
22
+ }
23
+ switch (version) {
24
+ case 'x25519-xsalsa20-poly1305': {
25
+ if (typeof data !== 'string') {
26
+ throw new Error('Message data must be given as a string');
27
+ }
28
+ // generate ephemeral keypair
29
+ const ephemeralKeyPair = nacl.box.keyPair();
30
+ // assemble encryption parameters - from string to UInt8
31
+ let pubKeyUInt8Array;
32
+ try {
33
+ pubKeyUInt8Array = base64.decode(publicKey);
34
+ }
35
+ catch {
36
+ throw new Error('Bad public key');
37
+ }
38
+ const msgParamsUInt8Array = utf8.decode(data);
39
+ const nonce = nacl.randomBytes(nacl.box.nonceLength);
40
+ // encrypt
41
+ const encryptedMessage = nacl.box(msgParamsUInt8Array, nonce, pubKeyUInt8Array, ephemeralKeyPair.secretKey);
42
+ // handle encrypted data
43
+ const output = {
44
+ version: 'x25519-xsalsa20-poly1305',
45
+ nonce: base64.encode(nonce),
46
+ ephemPublicKey: base64.encode(ephemeralKeyPair.publicKey),
47
+ ciphertext: base64.encode(encryptedMessage),
48
+ };
49
+ // return encrypted msg data
50
+ return output;
51
+ }
52
+ default:
53
+ throw new Error('Encryption type/version not supported');
54
+ }
55
+ }
56
+ /**
57
+ * Encrypt a message in a way that obscures the message length.
58
+ *
59
+ * The message is padded to a multiple of 2048 before being encrypted so that the length of the
60
+ * resulting encrypted message can't be used to guess the exact length of the original message.
61
+ *
62
+ * @param options - The encryption options.
63
+ * @param options.publicKey - The public key of the message recipient.
64
+ * @param options.data - The message data.
65
+ * @param options.version - The type of encryption to use.
66
+ * @returns The encrypted data.
67
+ */
68
+ export function encryptSafely({ publicKey, data, version, }) {
69
+ if (isNullish(publicKey)) {
70
+ throw new Error('Missing publicKey parameter');
71
+ }
72
+ else if (isNullish(data)) {
73
+ throw new Error('Missing data parameter');
74
+ }
75
+ else if (isNullish(version)) {
76
+ throw new Error('Missing version parameter');
77
+ }
78
+ const DEFAULT_PADDING_LENGTH = 2 ** 11;
79
+ const NACL_EXTRA_BYTES = 16;
80
+ if (typeof data === 'object' && data && 'toJSON' in data) {
81
+ // remove toJSON attack vector
82
+ // TODO, check all possible children
83
+ throw new Error('Cannot encrypt with toJSON property. Please remove toJSON property');
84
+ }
85
+ // add padding
86
+ const dataWithPadding = {
87
+ data,
88
+ padding: '',
89
+ };
90
+ // calculate padding
91
+ const dataLength = Buffer.byteLength(JSON.stringify(dataWithPadding), 'utf-8');
92
+ const modVal = dataLength % DEFAULT_PADDING_LENGTH;
93
+ let padLength = 0;
94
+ // Only pad if necessary
95
+ if (modVal > 0) {
96
+ padLength = DEFAULT_PADDING_LENGTH - modVal - NACL_EXTRA_BYTES; // nacl extra bytes
97
+ }
98
+ dataWithPadding.padding = '0'.repeat(padLength);
99
+ const paddedMessage = JSON.stringify(dataWithPadding);
100
+ return encrypt({ publicKey, data: paddedMessage, version });
101
+ }
102
+ /**
103
+ * Decrypt a message.
104
+ *
105
+ * @param options - The decryption options.
106
+ * @param options.encryptedData - The encrypted data.
107
+ * @param options.privateKey - The private key to decrypt with.
108
+ * @returns The decrypted message.
109
+ */
110
+ export function decrypt({ encryptedData, privateKey, }) {
111
+ if (isNullish(encryptedData)) {
112
+ throw new Error('Missing encryptedData parameter');
113
+ }
114
+ else if (isNullish(privateKey)) {
115
+ throw new Error('Missing privateKey parameter');
116
+ }
117
+ switch (encryptedData.version) {
118
+ case 'x25519-xsalsa20-poly1305': {
119
+ const receiverPrivateKeyUint8Array = Buffer.from(privateKey, 'hex');
120
+ const receiverEncryptionPrivateKey = nacl.box.keyPair.fromSecretKey(receiverPrivateKeyUint8Array).secretKey;
121
+ // assemble decryption parameters
122
+ const nonce = base64.decode(encryptedData.nonce);
123
+ const ciphertext = base64.decode(encryptedData.ciphertext);
124
+ const ephemPublicKey = base64.decode(encryptedData.ephemPublicKey);
125
+ // decrypt
126
+ const decryptedMessage = nacl.box.open(ciphertext, nonce, ephemPublicKey, receiverEncryptionPrivateKey);
127
+ // return decrypted msg data
128
+ try {
129
+ if (!decryptedMessage) {
130
+ throw new Error();
131
+ }
132
+ const output = utf8.encode(decryptedMessage);
133
+ // TODO: This is probably extraneous but was kept to minimize changes during refactor
134
+ if (!output) {
135
+ throw new Error();
136
+ }
137
+ return output;
138
+ }
139
+ catch (error) {
140
+ if (error instanceof Error && error.message.length) {
141
+ throw new Error(`Decryption failed: ${error.message}`);
142
+ }
143
+ throw new Error(`Decryption failed.`);
144
+ }
145
+ }
146
+ default:
147
+ throw new Error('Encryption type/version not supported.');
148
+ }
149
+ }
150
+ /**
151
+ * Decrypt a message that has been encrypted using `encryptSafely`.
152
+ *
153
+ * @param options - The decryption options.
154
+ * @param options.encryptedData - The encrypted data.
155
+ * @param options.privateKey - The private key to decrypt with.
156
+ * @returns The decrypted message.
157
+ */
158
+ export function decryptSafely({ encryptedData, privateKey, }) {
159
+ if (isNullish(encryptedData)) {
160
+ throw new Error('Missing encryptedData parameter');
161
+ }
162
+ else if (isNullish(privateKey)) {
163
+ throw new Error('Missing privateKey parameter');
164
+ }
165
+ const dataWithPadding = JSON.parse(decrypt({ encryptedData, privateKey }));
166
+ return dataWithPadding.data;
167
+ }
168
+ /**
169
+ * Get the encryption public key for the given key.
170
+ *
171
+ * @param privateKey - The private key to generate the encryption public key with.
172
+ * @returns The encryption public key.
173
+ */
174
+ export function getEncryptionPublicKey(privateKey) {
175
+ const privateKeyUint8Array = Buffer.from(privateKey, 'hex');
176
+ const encryptionPublicKey = nacl.box.keyPair.fromSecretKey(privateKeyUint8Array).publicKey;
177
+ return base64.encode(encryptionPublicKey);
178
+ }
179
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.js","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64, utf8 } from '@scure/base';\nimport * as nacl from 'tweetnacl';\n\nimport { isNullish } from './utils.js';\n\nexport type EthEncryptedData = {\n version: string;\n nonce: string;\n ephemPublicKey: string;\n ciphertext: string;\n};\n\n/**\n * Encrypt a message.\n *\n * @param options - The encryption options.\n * @param options.publicKey - The public key of the message recipient.\n * @param options.data - The message data.\n * @param options.version - The type of encryption to use.\n * @returns The encrypted data.\n */\nexport function encrypt({\n publicKey,\n data,\n version,\n}: {\n publicKey: string;\n data: unknown;\n version: string;\n}): EthEncryptedData {\n if (isNullish(publicKey)) {\n throw new Error('Missing publicKey parameter');\n } else if (isNullish(data)) {\n throw new Error('Missing data parameter');\n } else if (isNullish(version)) {\n throw new Error('Missing version parameter');\n }\n\n switch (version) {\n case 'x25519-xsalsa20-poly1305': {\n if (typeof data !== 'string') {\n throw new Error('Message data must be given as a string');\n }\n // generate ephemeral keypair\n const ephemeralKeyPair = nacl.box.keyPair();\n\n // assemble encryption parameters - from string to UInt8\n let pubKeyUInt8Array: Uint8Array;\n try {\n pubKeyUInt8Array = base64.decode(publicKey);\n } catch {\n throw new Error('Bad public key');\n }\n\n const msgParamsUInt8Array = utf8.decode(data);\n const nonce = nacl.randomBytes(nacl.box.nonceLength);\n\n // encrypt\n const encryptedMessage = nacl.box(\n msgParamsUInt8Array,\n nonce,\n pubKeyUInt8Array,\n ephemeralKeyPair.secretKey,\n );\n\n // handle encrypted data\n const output = {\n version: 'x25519-xsalsa20-poly1305',\n nonce: base64.encode(nonce),\n ephemPublicKey: base64.encode(ephemeralKeyPair.publicKey),\n ciphertext: base64.encode(encryptedMessage),\n };\n // return encrypted msg data\n return output;\n }\n\n default:\n throw new Error('Encryption type/version not supported');\n }\n}\n\n/**\n * Encrypt a message in a way that obscures the message length.\n *\n * The message is padded to a multiple of 2048 before being encrypted so that the length of the\n * resulting encrypted message can't be used to guess the exact length of the original message.\n *\n * @param options - The encryption options.\n * @param options.publicKey - The public key of the message recipient.\n * @param options.data - The message data.\n * @param options.version - The type of encryption to use.\n * @returns The encrypted data.\n */\nexport function encryptSafely({\n publicKey,\n data,\n version,\n}: {\n publicKey: string;\n data: unknown;\n version: string;\n}): EthEncryptedData {\n if (isNullish(publicKey)) {\n throw new Error('Missing publicKey parameter');\n } else if (isNullish(data)) {\n throw new Error('Missing data parameter');\n } else if (isNullish(version)) {\n throw new Error('Missing version parameter');\n }\n\n const DEFAULT_PADDING_LENGTH = 2 ** 11;\n const NACL_EXTRA_BYTES = 16;\n\n if (typeof data === 'object' && data && 'toJSON' in data) {\n // remove toJSON attack vector\n // TODO, check all possible children\n throw new Error(\n 'Cannot encrypt with toJSON property. Please remove toJSON property',\n );\n }\n\n // add padding\n const dataWithPadding = {\n data,\n padding: '',\n };\n\n // calculate padding\n const dataLength = Buffer.byteLength(\n JSON.stringify(dataWithPadding),\n 'utf-8',\n );\n const modVal = dataLength % DEFAULT_PADDING_LENGTH;\n let padLength = 0;\n // Only pad if necessary\n if (modVal > 0) {\n padLength = DEFAULT_PADDING_LENGTH - modVal - NACL_EXTRA_BYTES; // nacl extra bytes\n }\n dataWithPadding.padding = '0'.repeat(padLength);\n\n const paddedMessage = JSON.stringify(dataWithPadding);\n return encrypt({ publicKey, data: paddedMessage, version });\n}\n\n/**\n * Decrypt a message.\n *\n * @param options - The decryption options.\n * @param options.encryptedData - The encrypted data.\n * @param options.privateKey - The private key to decrypt with.\n * @returns The decrypted message.\n */\nexport function decrypt({\n encryptedData,\n privateKey,\n}: {\n encryptedData: EthEncryptedData;\n privateKey: string;\n}): string {\n if (isNullish(encryptedData)) {\n throw new Error('Missing encryptedData parameter');\n } else if (isNullish(privateKey)) {\n throw new Error('Missing privateKey parameter');\n }\n\n switch (encryptedData.version) {\n case 'x25519-xsalsa20-poly1305': {\n const receiverPrivateKeyUint8Array = Buffer.from(privateKey, 'hex');\n const receiverEncryptionPrivateKey = nacl.box.keyPair.fromSecretKey(\n receiverPrivateKeyUint8Array,\n ).secretKey;\n\n // assemble decryption parameters\n const nonce = base64.decode(encryptedData.nonce);\n const ciphertext = base64.decode(encryptedData.ciphertext);\n const ephemPublicKey = base64.decode(encryptedData.ephemPublicKey);\n\n // decrypt\n const decryptedMessage = nacl.box.open(\n ciphertext,\n nonce,\n ephemPublicKey,\n receiverEncryptionPrivateKey,\n );\n\n // return decrypted msg data\n try {\n if (!decryptedMessage) {\n throw new Error();\n }\n const output = utf8.encode(decryptedMessage);\n // TODO: This is probably extraneous but was kept to minimize changes during refactor\n if (!output) {\n throw new Error();\n }\n return output;\n } catch (error) {\n if (error instanceof Error && error.message.length) {\n throw new Error(`Decryption failed: ${error.message}`);\n }\n throw new Error(`Decryption failed.`);\n }\n }\n\n default:\n throw new Error('Encryption type/version not supported.');\n }\n}\n\n/**\n * Decrypt a message that has been encrypted using `encryptSafely`.\n *\n * @param options - The decryption options.\n * @param options.encryptedData - The encrypted data.\n * @param options.privateKey - The private key to decrypt with.\n * @returns The decrypted message.\n */\nexport function decryptSafely({\n encryptedData,\n privateKey,\n}: {\n encryptedData: EthEncryptedData;\n privateKey: string;\n}): string {\n if (isNullish(encryptedData)) {\n throw new Error('Missing encryptedData parameter');\n } else if (isNullish(privateKey)) {\n throw new Error('Missing privateKey parameter');\n }\n\n const dataWithPadding = JSON.parse(decrypt({ encryptedData, privateKey }));\n return dataWithPadding.data;\n}\n\n/**\n * Get the encryption public key for the given key.\n *\n * @param privateKey - The private key to generate the encryption public key with.\n * @returns The encryption public key.\n */\nexport function getEncryptionPublicKey(privateKey: string): string {\n const privateKeyUint8Array = Buffer.from(privateKey, 'hex');\n const encryptionPublicKey =\n nacl.box.keyPair.fromSecretKey(privateKeyUint8Array).publicKey;\n return base64.encode(encryptionPublicKey);\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export * from './personal-sign.js';
2
+ export * from './sign-typed-data.js';
3
+ export * from './encryption.js';
4
+ export * from './sign-eip7702-authorization.js';
5
+ export { concatSig, normalize } from './utils.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iCAAiC,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './personal-sign.js';
2
+ export * from './sign-typed-data.js';
3
+ export * from './encryption.js';
4
+ export * from './sign-eip7702-authorization.js';
5
+ export { concatSig, normalize } from './utils.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iCAAiC,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export * from './personal-sign.js';\nexport * from './sign-typed-data.js';\nexport * from './encryption.js';\nexport * from './sign-eip7702-authorization.js';\nexport { concatSig, normalize } from './utils.js';\n"]}
@@ -0,0 +1,43 @@
1
+ import { ToBufferInputTypes } from '@ethereumjs/util';
2
+ /**
3
+ * Create an Ethereum-specific signature for a message.
4
+ *
5
+ * This function is equivalent to the `eth_sign` Ethereum JSON-RPC method as specified in EIP-1417,
6
+ * as well as the MetaMask's `personal_sign` method.
7
+ *
8
+ * @param options - The personal sign options.
9
+ * @param options.privateKey - The key to sign with.
10
+ * @param options.data - The hex data to sign.
11
+ * @returns The '0x'-prefixed hex encoded signature.
12
+ */
13
+ export declare function personalSign({ privateKey, data, }: {
14
+ privateKey: Buffer;
15
+ data: ToBufferInputTypes;
16
+ }): string;
17
+ /**
18
+ * Recover the address of the account used to create the given Ethereum signature. The message
19
+ * must have been signed using the `personalSign` function, or an equivalent function.
20
+ *
21
+ * @param options - The signature recovery options.
22
+ * @param options.data - The hex data that was signed.
23
+ * @param options.signature - The '0x'-prefixed hex encoded message signature.
24
+ * @returns The '0x'-prefixed hex encoded address of the message signer.
25
+ */
26
+ export declare function recoverPersonalSignature({ data, signature, }: {
27
+ data: ToBufferInputTypes;
28
+ signature: string;
29
+ }): string;
30
+ /**
31
+ * Recover the public key of the account used to create the given Ethereum signature. The message
32
+ * must have been signed using the `personalSign` function, or an equivalent function.
33
+ *
34
+ * @param options - The public key recovery options.
35
+ * @param options.data - The hex data that was signed.
36
+ * @param options.signature - The '0x'-prefixed hex encoded message signature.
37
+ * @returns The '0x'-prefixed hex encoded public key of the message signer.
38
+ */
39
+ export declare function extractPublicKey({ data, signature, }: {
40
+ data: ToBufferInputTypes;
41
+ signature: string;
42
+ }): string;
43
+ //# sourceMappingURL=personal-sign.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"personal-sign.d.ts","sourceRoot":"","sources":["../src/personal-sign.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAS1B;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,EAC3B,UAAU,EACV,IAAI,GACL,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,kBAAkB,CAAC;CAC1B,GAAG,MAAM,CAWT;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,IAAI,EACJ,SAAS,GACV,EAAE;IACD,IAAI,EAAE,kBAAkB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAWT;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,SAAS,GACV,EAAE;IACD,IAAI,EAAE,kBAAkB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAST"}
@@ -0,0 +1,77 @@
1
+ import { bufferToHex, ecsign, hashPersonalMessage, publicToAddress, toBuffer, } from '@ethereumjs/util';
2
+ import { concatSig, isNullish, legacyToBuffer, recoverPublicKey, } from './utils.js';
3
+ /**
4
+ * Create an Ethereum-specific signature for a message.
5
+ *
6
+ * This function is equivalent to the `eth_sign` Ethereum JSON-RPC method as specified in EIP-1417,
7
+ * as well as the MetaMask's `personal_sign` method.
8
+ *
9
+ * @param options - The personal sign options.
10
+ * @param options.privateKey - The key to sign with.
11
+ * @param options.data - The hex data to sign.
12
+ * @returns The '0x'-prefixed hex encoded signature.
13
+ */
14
+ export function personalSign({ privateKey, data, }) {
15
+ if (isNullish(data)) {
16
+ throw new Error('Missing data parameter');
17
+ }
18
+ else if (isNullish(privateKey)) {
19
+ throw new Error('Missing privateKey parameter');
20
+ }
21
+ const message = legacyToBuffer(data);
22
+ const msgHash = hashPersonalMessage(message);
23
+ const signature = ecsign(msgHash, privateKey);
24
+ return concatSig(toBuffer(signature.v), signature.r, signature.s);
25
+ }
26
+ /**
27
+ * Recover the address of the account used to create the given Ethereum signature. The message
28
+ * must have been signed using the `personalSign` function, or an equivalent function.
29
+ *
30
+ * @param options - The signature recovery options.
31
+ * @param options.data - The hex data that was signed.
32
+ * @param options.signature - The '0x'-prefixed hex encoded message signature.
33
+ * @returns The '0x'-prefixed hex encoded address of the message signer.
34
+ */
35
+ export function recoverPersonalSignature({ data, signature, }) {
36
+ if (isNullish(data)) {
37
+ throw new Error('Missing data parameter');
38
+ }
39
+ else if (isNullish(signature)) {
40
+ throw new Error('Missing signature parameter');
41
+ }
42
+ const publicKey = getPublicKeyFor(data, signature);
43
+ const sender = publicToAddress(publicKey);
44
+ const senderHex = bufferToHex(sender);
45
+ return senderHex;
46
+ }
47
+ /**
48
+ * Recover the public key of the account used to create the given Ethereum signature. The message
49
+ * must have been signed using the `personalSign` function, or an equivalent function.
50
+ *
51
+ * @param options - The public key recovery options.
52
+ * @param options.data - The hex data that was signed.
53
+ * @param options.signature - The '0x'-prefixed hex encoded message signature.
54
+ * @returns The '0x'-prefixed hex encoded public key of the message signer.
55
+ */
56
+ export function extractPublicKey({ data, signature, }) {
57
+ if (isNullish(data)) {
58
+ throw new Error('Missing data parameter');
59
+ }
60
+ else if (isNullish(signature)) {
61
+ throw new Error('Missing signature parameter');
62
+ }
63
+ const publicKey = getPublicKeyFor(data, signature);
64
+ return `0x${publicKey.toString('hex')}`;
65
+ }
66
+ /**
67
+ * Get the public key for the given signature and message.
68
+ *
69
+ * @param message - The message that was signed.
70
+ * @param signature - The '0x'-prefixed hex encoded message signature.
71
+ * @returns The public key of the signer.
72
+ */
73
+ function getPublicKeyFor(message, signature) {
74
+ const messageHash = hashPersonalMessage(legacyToBuffer(message));
75
+ return recoverPublicKey(messageHash, signature);
76
+ }
77
+ //# sourceMappingURL=personal-sign.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"personal-sign.js","sourceRoot":"","sources":["../src/personal-sign.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,MAAM,EACN,mBAAmB,EACnB,eAAe,EACf,QAAQ,GAET,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,SAAS,EACT,SAAS,EACT,cAAc,EACd,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAC,EAC3B,UAAU,EACV,IAAI,GAIL;IACC,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;SAAM,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC9C,OAAO,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB,CAAC,EACvC,IAAI,EACJ,SAAS,GAIV;IACC,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;SAAM,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAC/B,IAAI,EACJ,SAAS,GAIV;IACC,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;SAAM,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACnD,OAAO,KAAK,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CACtB,OAA2B,EAC3B,SAAiB;IAEjB,MAAM,WAAW,GAAG,mBAAmB,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACjE,OAAO,gBAAgB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AAClD,CAAC","sourcesContent":["import {\n bufferToHex,\n ecsign,\n hashPersonalMessage,\n publicToAddress,\n toBuffer,\n ToBufferInputTypes,\n} from '@ethereumjs/util';\n\nimport {\n concatSig,\n isNullish,\n legacyToBuffer,\n recoverPublicKey,\n} from './utils.js';\n\n/**\n * Create an Ethereum-specific signature for a message.\n *\n * This function is equivalent to the `eth_sign` Ethereum JSON-RPC method as specified in EIP-1417,\n * as well as the MetaMask's `personal_sign` method.\n *\n * @param options - The personal sign options.\n * @param options.privateKey - The key to sign with.\n * @param options.data - The hex data to sign.\n * @returns The '0x'-prefixed hex encoded signature.\n */\nexport function personalSign({\n privateKey,\n data,\n}: {\n privateKey: Buffer;\n data: ToBufferInputTypes;\n}): string {\n if (isNullish(data)) {\n throw new Error('Missing data parameter');\n } else if (isNullish(privateKey)) {\n throw new Error('Missing privateKey parameter');\n }\n\n const message = legacyToBuffer(data);\n const msgHash = hashPersonalMessage(message);\n const signature = ecsign(msgHash, privateKey);\n return concatSig(toBuffer(signature.v), signature.r, signature.s);\n}\n\n/**\n * Recover the address of the account used to create the given Ethereum signature. The message\n * must have been signed using the `personalSign` function, or an equivalent function.\n *\n * @param options - The signature recovery options.\n * @param options.data - The hex data that was signed.\n * @param options.signature - The '0x'-prefixed hex encoded message signature.\n * @returns The '0x'-prefixed hex encoded address of the message signer.\n */\nexport function recoverPersonalSignature({\n data,\n signature,\n}: {\n data: ToBufferInputTypes;\n signature: string;\n}): string {\n if (isNullish(data)) {\n throw new Error('Missing data parameter');\n } else if (isNullish(signature)) {\n throw new Error('Missing signature parameter');\n }\n\n const publicKey = getPublicKeyFor(data, signature);\n const sender = publicToAddress(publicKey);\n const senderHex = bufferToHex(sender);\n return senderHex;\n}\n\n/**\n * Recover the public key of the account used to create the given Ethereum signature. The message\n * must have been signed using the `personalSign` function, or an equivalent function.\n *\n * @param options - The public key recovery options.\n * @param options.data - The hex data that was signed.\n * @param options.signature - The '0x'-prefixed hex encoded message signature.\n * @returns The '0x'-prefixed hex encoded public key of the message signer.\n */\nexport function extractPublicKey({\n data,\n signature,\n}: {\n data: ToBufferInputTypes;\n signature: string;\n}): string {\n if (isNullish(data)) {\n throw new Error('Missing data parameter');\n } else if (isNullish(signature)) {\n throw new Error('Missing signature parameter');\n }\n\n const publicKey = getPublicKeyFor(data, signature);\n return `0x${publicKey.toString('hex')}`;\n}\n\n/**\n * Get the public key for the given signature and message.\n *\n * @param message - The message that was signed.\n * @param signature - The '0x'-prefixed hex encoded message signature.\n * @returns The public key of the signer.\n */\nfunction getPublicKeyFor(\n message: ToBufferInputTypes,\n signature: string,\n): Buffer {\n const messageHash = hashPersonalMessage(legacyToBuffer(message));\n return recoverPublicKey(messageHash, signature);\n}\n"]}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The authorization struct as defined in EIP-7702.
3
+ *
4
+ * @property chainId - The chain ID or 0 for any chain.
5
+ * @property contractAddress - The address of the contract being authorized.
6
+ * @property nonce - The nonce of the signing account (at the time of submission).
7
+ */
8
+ export type EIP7702Authorization = [
9
+ chainId: number,
10
+ contractAddress: string,
11
+ nonce: number
12
+ ];
13
+ /**
14
+ * Sign an authorization message with the provided private key.
15
+ *
16
+ * @param options - The signing options.
17
+ * @param options.privateKey - The private key to sign with.
18
+ * @param options.authorization - The authorization data to sign.
19
+ * @returns The '0x'-prefixed hex encoded signature.
20
+ */
21
+ export declare function signEIP7702Authorization({ privateKey, authorization, }: {
22
+ privateKey: Buffer;
23
+ authorization: EIP7702Authorization;
24
+ }): string;
25
+ /**
26
+ * Recover the address of the account that created the given authorization
27
+ * signature.
28
+ *
29
+ * @param options - The signature recovery options.
30
+ * @param options.signature - The '0x'-prefixed hex encoded message signature.
31
+ * @param options.authorization - The authorization data that was signed.
32
+ * @returns The '0x'-prefixed hex address of the signer.
33
+ */
34
+ export declare function recoverEIP7702Authorization({ signature, authorization, }: {
35
+ signature: string;
36
+ authorization: EIP7702Authorization;
37
+ }): string;
38
+ /**
39
+ * Hash an authorization message according to the signing scheme.
40
+ * The message is encoded according to EIP-7702.
41
+ *
42
+ * @param authorization - The authorization data to hash.
43
+ * @returns The hash of the authorization message as a Buffer.
44
+ */
45
+ export declare function hashEIP7702Authorization(authorization: EIP7702Authorization): Buffer;
46
+ //# sourceMappingURL=sign-eip7702-authorization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign-eip7702-authorization.d.ts","sourceRoot":"","sources":["../src/sign-eip7702-authorization.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,MAAM;IACf,eAAe,EAAE,MAAM;IACvB,KAAK,EAAE,MAAM;CACd,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,UAAU,EACV,aAAa,GACd,EAAE;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,oBAAoB,CAAC;CACrC,GAAG,MAAM,CAeT;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,EAC1C,SAAS,EACT,aAAa,GACd,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,oBAAoB,CAAC;CACrC,GAAG,MAAM,CAcT;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,oBAAoB,GAClC,MAAM,CAWR"}
@@ -0,0 +1,97 @@
1
+ import { encode } from '@ethereumjs/rlp';
2
+ import { ecsign, publicToAddress, toBuffer } from '@ethereumjs/util';
3
+ import { bytesToHex, isValidHexAddress } from '@metamask/utils';
4
+ import { keccak256 } from 'ethereum-cryptography/keccak';
5
+ import { concatSig, isNullish, recoverPublicKey } from './utils.js';
6
+ const CHAIN_ID_MAX_BITLENGTH = 256;
7
+ const NONCE_MAX_BITLENGTH = 64;
8
+ const ADDRESS_BYTE_LENGTH = 20;
9
+ /**
10
+ * Sign an authorization message with the provided private key.
11
+ *
12
+ * @param options - The signing options.
13
+ * @param options.privateKey - The private key to sign with.
14
+ * @param options.authorization - The authorization data to sign.
15
+ * @returns The '0x'-prefixed hex encoded signature.
16
+ */
17
+ export function signEIP7702Authorization({ privateKey, authorization, }) {
18
+ validateEIP7702Authorization(authorization);
19
+ if (isNullish(privateKey)) {
20
+ throw new Error('Missing privateKey parameter');
21
+ }
22
+ const messageHash = hashEIP7702Authorization(authorization);
23
+ const { r, s, v } = ecsign(messageHash, privateKey);
24
+ // v is either 27n or 28n so is guaranteed to be a single byte
25
+ const vBuffer = toBuffer(v);
26
+ return concatSig(vBuffer, r, s);
27
+ }
28
+ /**
29
+ * Recover the address of the account that created the given authorization
30
+ * signature.
31
+ *
32
+ * @param options - The signature recovery options.
33
+ * @param options.signature - The '0x'-prefixed hex encoded message signature.
34
+ * @param options.authorization - The authorization data that was signed.
35
+ * @returns The '0x'-prefixed hex address of the signer.
36
+ */
37
+ export function recoverEIP7702Authorization({ signature, authorization, }) {
38
+ validateEIP7702Authorization(authorization);
39
+ if (isNullish(signature)) {
40
+ throw new Error('Missing signature parameter');
41
+ }
42
+ const messageHash = hashEIP7702Authorization(authorization);
43
+ const publicKey = recoverPublicKey(messageHash, signature);
44
+ const sender = publicToAddress(publicKey);
45
+ return bytesToHex(sender);
46
+ }
47
+ /**
48
+ * Hash an authorization message according to the signing scheme.
49
+ * The message is encoded according to EIP-7702.
50
+ *
51
+ * @param authorization - The authorization data to hash.
52
+ * @returns The hash of the authorization message as a Buffer.
53
+ */
54
+ export function hashEIP7702Authorization(authorization) {
55
+ validateEIP7702Authorization(authorization);
56
+ const encodedAuthorization = encode(authorization);
57
+ const message = Buffer.concat([
58
+ Buffer.from('05', 'hex'),
59
+ encodedAuthorization,
60
+ ]);
61
+ return Buffer.from(keccak256(message));
62
+ }
63
+ /**
64
+ * Validates an authorization object to ensure all required parameters are present.
65
+ *
66
+ * @param authorization - The authorization object to validate.
67
+ * @throws {Error} If the authorization object or any of its required parameters are missing.
68
+ */
69
+ function validateEIP7702Authorization(authorization) {
70
+ if (isNullish(authorization)) {
71
+ throw new Error('Missing authorization parameter');
72
+ }
73
+ const [chainId, contractAddress, nonce] = authorization;
74
+ if (isNullish(chainId)) {
75
+ throw new Error('Missing chainId parameter');
76
+ }
77
+ if (isNullish(contractAddress)) {
78
+ throw new Error('Missing contractAddress parameter');
79
+ }
80
+ if (isNullish(nonce)) {
81
+ throw new Error('Missing nonce parameter');
82
+ }
83
+ if (typeof chainId !== 'number' ||
84
+ chainId >= 2 ** CHAIN_ID_MAX_BITLENGTH ||
85
+ chainId < 0) {
86
+ throw new Error(`Invalid chainId: must be a non-negative number less than 2^${CHAIN_ID_MAX_BITLENGTH}`);
87
+ }
88
+ if (typeof nonce !== 'number' ||
89
+ nonce >= 2 ** NONCE_MAX_BITLENGTH ||
90
+ nonce < 0) {
91
+ throw new Error(`Invalid nonce: must be a non-negative number less than 2^${NONCE_MAX_BITLENGTH}`);
92
+ }
93
+ if (!isValidHexAddress(contractAddress)) {
94
+ throw new Error(`Invalid contractAddress: must be a ${ADDRESS_BYTE_LENGTH} byte hex string`);
95
+ }
96
+ }
97
+ //# sourceMappingURL=sign-eip7702-authorization.js.map