@wallaby-cash/cryptography 1.0.0 → 1.0.1

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 (45) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/createIdentity.d.ts +18 -0
  3. package/dist/createIdentity.d.ts.map +1 -0
  4. package/dist/createIdentity.js +60 -0
  5. package/dist/decryptWithPrivateKey.d.ts +3 -0
  6. package/dist/decryptWithPrivateKey.d.ts.map +1 -0
  7. package/dist/decryptWithPrivateKey.js +7 -0
  8. package/dist/encryptWithPublicKey.d.ts +3 -0
  9. package/dist/encryptWithPublicKey.d.ts.map +1 -0
  10. package/dist/encryptWithPublicKey.js +9 -0
  11. package/dist/encryption-utils.d.ts +19 -0
  12. package/dist/encryption-utils.d.ts.map +1 -0
  13. package/dist/encryption-utils.js +82 -0
  14. package/dist/hash.d.ts +2 -0
  15. package/dist/hash.d.ts.map +1 -0
  16. package/dist/hash.js +12 -0
  17. package/dist/index.d.ts +28 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/{src/index.ts → dist/index.js} +10 -22
  20. package/dist/publicKeyByPrivateKey.d.ts +8 -0
  21. package/dist/publicKeyByPrivateKey.d.ts.map +1 -0
  22. package/dist/publicKeyByPrivateKey.js +15 -0
  23. package/dist/recoverPublicKey.d.ts +8 -0
  24. package/dist/recoverPublicKey.d.ts.map +1 -0
  25. package/dist/recoverPublicKey.js +20 -0
  26. package/dist/sign.d.ts +9 -0
  27. package/dist/sign.d.ts.map +1 -0
  28. package/dist/sign.js +24 -0
  29. package/dist/types.d.ts +10 -0
  30. package/dist/types.d.ts.map +1 -0
  31. package/dist/types.js +1 -0
  32. package/dist/util.d.ts +38 -0
  33. package/dist/util.d.ts.map +1 -0
  34. package/dist/util.js +98 -0
  35. package/package.json +15 -5
  36. package/src/createIdentity.ts +0 -66
  37. package/src/decryptWithPrivateKey.ts +0 -10
  38. package/src/encryptWithPublicKey.ts +0 -12
  39. package/src/encryption-utils.ts +0 -93
  40. package/src/hash.ts +0 -14
  41. package/src/publicKeyByPrivateKey.ts +0 -17
  42. package/src/recoverPublicKey.ts +0 -26
  43. package/src/sign.ts +0 -27
  44. package/src/types.ts +0 -10
  45. package/src/util.ts +0 -110
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @wallaby-cash/cryptography
2
2
 
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Fix package build configuration to exclude test files from published package
8
+
3
9
  ## 1.0.0
4
10
 
5
11
  ### Major Changes
@@ -0,0 +1,18 @@
1
+ export declare const DEFAULT_ENTROPY_BYTES = 32;
2
+ export declare const MINIMUM_SHANNON_ENTROPY = 4;
3
+ /**
4
+ * creates a new private key
5
+ * @param { Uint8Array } entropy - optional entropy to create the private key
6
+ * @returns a new private key
7
+ */
8
+ export declare const createPrivateKey: (entropy?: Uint8Array) => string;
9
+ /**
10
+ * creates a new identity
11
+ * @param { Uint8Array } entropy - optional entropy to create the private key
12
+ * @returns a new pair of private and public key
13
+ */
14
+ export declare const createIdentity: (entropy?: Uint8Array) => {
15
+ privateKey: string;
16
+ publicKey: string;
17
+ };
18
+ //# sourceMappingURL=createIdentity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createIdentity.d.ts","sourceRoot":"","sources":["../src/createIdentity.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,UAAU,UAAU,WAmCpD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,UAAU,UAAU;;;CASlD,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { getRandomBytesSync as randomBytes } from 'ethereum-cryptography/random.js';
2
+ import { addLeading0x, stripHexPrefix, concatUint8Arrays } from './util';
3
+ import { publicKeyByPrivateKey } from './publicKeyByPrivateKey';
4
+ import { bytesToHex } from 'ethereum-cryptography/utils';
5
+ import { keccak256 } from 'ethereum-cryptography/keccak';
6
+ export const DEFAULT_ENTROPY_BYTES = 32;
7
+ export const MINIMUM_SHANNON_ENTROPY = 4;
8
+ /**
9
+ * creates a new private key
10
+ * @param { Uint8Array } entropy - optional entropy to create the private key
11
+ * @returns a new private key
12
+ */
13
+ export const createPrivateKey = (entropy) => {
14
+ if (entropy) {
15
+ if (!(entropy instanceof Uint8Array) || entropy.length < DEFAULT_ENTROPY_BYTES) {
16
+ throw new Error(`entropy must be a Uint8Array of at least ${DEFAULT_ENTROPY_BYTES} bytes`);
17
+ }
18
+ // Check byte diversity
19
+ const uniqueBytes = new Set(entropy);
20
+ if (uniqueBytes.size < Math.min(8, entropy.length / 4)) {
21
+ throw new Error(`entropy is too repetitive (only ${uniqueBytes.size} unique byte values)`);
22
+ }
23
+ // Estimate Shannon entropy
24
+ const byteCounts = new Uint32Array(256);
25
+ entropy.forEach((b) => byteCounts[b]++);
26
+ const total = entropy.length;
27
+ let shannonEntropy = 0;
28
+ for (let i = 0; i < 256; i++) {
29
+ if (byteCounts[i] > 0) {
30
+ const p = byteCounts[i] / total;
31
+ shannonEntropy -= p * Math.log2(p);
32
+ }
33
+ }
34
+ if (shannonEntropy < MINIMUM_SHANNON_ENTROPY) {
35
+ throw new Error(`entropy has low Shannon entropy (${shannonEntropy.toFixed(2)} bits/byte)`);
36
+ }
37
+ const outerHex = keccak256(entropy);
38
+ return addLeading0x(bytesToHex(outerHex));
39
+ }
40
+ else {
41
+ const innerHex = keccak256(concatUint8Arrays([randomBytes(32), randomBytes(32)]));
42
+ const middleHex = concatUint8Arrays([concatUint8Arrays([randomBytes(32), innerHex]), randomBytes(32)]);
43
+ const outerHex = keccak256(middleHex);
44
+ return addLeading0x(bytesToHex(outerHex));
45
+ }
46
+ };
47
+ /**
48
+ * creates a new identity
49
+ * @param { Uint8Array } entropy - optional entropy to create the private key
50
+ * @returns a new pair of private and public key
51
+ */
52
+ export const createIdentity = (entropy) => {
53
+ const privateKey = createPrivateKey(entropy);
54
+ const walletPublicKey = publicKeyByPrivateKey(privateKey);
55
+ const identity = {
56
+ privateKey: privateKey,
57
+ publicKey: stripHexPrefix(walletPublicKey),
58
+ };
59
+ return identity;
60
+ };
@@ -0,0 +1,3 @@
1
+ import { Encrypted } from './types';
2
+ export declare const decryptWithPrivateKey: (privateKey: string, encrypted: Encrypted) => string;
3
+ //# sourceMappingURL=decryptWithPrivateKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decryptWithPrivateKey.d.ts","sourceRoot":"","sources":["../src/decryptWithPrivateKey.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,eAAO,MAAM,qBAAqB,GAAI,YAAY,MAAM,EAAE,WAAW,SAAS,WAK7E,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { stripHexPrefix } from './util';
2
+ import { decrypt } from './encryption-utils';
3
+ export const decryptWithPrivateKey = (privateKey, encrypted) => {
4
+ // remove '0x' from privateKey
5
+ const twoStripped = stripHexPrefix(privateKey);
6
+ return decrypt(twoStripped, encrypted);
7
+ };
@@ -0,0 +1,3 @@
1
+ import { EncryptionOptions } from './types';
2
+ export declare const encryptWithPublicKey: (publicKey: string, message: string, options?: EncryptionOptions) => import("./types").Encrypted;
3
+ //# sourceMappingURL=encryptWithPublicKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryptWithPublicKey.d.ts","sourceRoot":"","sources":["../src/encryptWithPublicKey.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,oBAAoB,GAAI,WAAW,MAAM,EAAE,SAAS,MAAM,EAAE,UAAU,iBAAiB,gCAOnG,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { decompress } from './util';
2
+ import { encrypt } from './encryption-utils';
3
+ export const encryptWithPublicKey = (publicKey, message, options) => {
4
+ // ensure its an uncompressed publicKey
5
+ const decompressedKey = decompress(publicKey);
6
+ // re-add the compression-flag
7
+ const pubString = '04' + decompressedKey;
8
+ return encrypt(pubString, message, options);
9
+ };
@@ -0,0 +1,19 @@
1
+ import { Encrypted, EncryptionOptions } from './types';
2
+ /**
3
+ * See https://github.com/bitchan/eccrypto for the original implementation that eth-crypto used, it's ancient and not maintained.
4
+ */
5
+ /**
6
+ * Encrypts a message using the recipient's public key.
7
+ * @param {string} publicKeyTo - The recipient's public key.
8
+ * @param {string} msg - The message to encrypt.
9
+ * @returns {Encrypted} The encrypted message.
10
+ */
11
+ export declare const encrypt: (publicKeyTo: string, msg: string, options?: EncryptionOptions) => Encrypted;
12
+ /**
13
+ * Decrypts an encrypted message using the recipient's private key.
14
+ * @param {string} privateKey - The recipient's private key.
15
+ * @param {Encrypted} opts - The encrypted message.
16
+ * @returns {string} The decrypted message.
17
+ */
18
+ export declare const decrypt: (privateKey: string, opts: Encrypted) => string;
19
+ //# sourceMappingURL=encryption-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption-utils.d.ts","sourceRoot":"","sources":["../src/encryption-utils.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAIvD;;GAEG;AAEH;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,GAAI,aAAa,MAAM,EAAE,KAAK,MAAM,EAAE,UAAU,iBAAiB,KAAG,SAsBvF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,YAAY,MAAM,EAAE,MAAM,SAAS,WA2B1D,CAAC"}
@@ -0,0 +1,82 @@
1
+ import { sha512 } from 'ethereum-cryptography/sha512.js';
2
+ import { secp256k1 } from 'ethereum-cryptography/secp256k1';
3
+ import { getRandomBytesSync as randomBytes } from 'ethereum-cryptography/random.js';
4
+ import { hexToBytes, bytesToHex, bytesToUtf8 } from 'ethereum-cryptography/utils.js';
5
+ import { encrypt as aesEncrypt, decrypt as aesDecrypt } from 'ethereum-cryptography/aes.js';
6
+ import { hmacSha256Sign } from './sign';
7
+ import { concatUint8Arrays, utf8ToBytes } from './util';
8
+ /**
9
+ * See https://github.com/bitchan/eccrypto for the original implementation that eth-crypto used, it's ancient and not maintained.
10
+ */
11
+ /**
12
+ * Encrypts a message using the recipient's public key.
13
+ * @param {string} publicKeyTo - The recipient's public key.
14
+ * @param {string} msg - The message to encrypt.
15
+ * @returns {Encrypted} The encrypted message.
16
+ */
17
+ export const encrypt = (publicKeyTo, msg, options) => {
18
+ const ephemPrivateKey = options?.ephemPrivateKey ? hexToBytes(options.ephemPrivateKey) : randomBytes(32);
19
+ const iv = randomBytes(16);
20
+ const compressedPub = secp256k1.getPublicKey(ephemPrivateKey); // defaults to compressed format
21
+ const point = secp256k1.ProjectivePoint.fromHex(compressedPub); // decompress the pub into an EC point
22
+ const ephemPublicKey = point.toRawBytes(false); // Get uncompressed SEC1 format pub
23
+ const sharedSecret = secp256k1.getSharedSecret(ephemPrivateKey, hexToBytes(publicKeyTo), true).slice(1);
24
+ const hash = sha512(sharedSecret);
25
+ const encryptionKey = hash.subarray(0, 32);
26
+ const macKey = hash.subarray(32);
27
+ const message = utf8ToBytes(msg);
28
+ const data = aesEncrypt(message, encryptionKey, iv, 'aes-256-cbc');
29
+ const dataToMac = concatUint8Arrays([iv, ephemPublicKey, data]);
30
+ const mac = hmacSha256Sign(macKey, dataToMac);
31
+ return {
32
+ iv: bytesToHex(iv),
33
+ ephemPublicKey: bytesToHex(ephemPublicKey),
34
+ ciphertext: bytesToHex(data),
35
+ mac: bytesToHex(mac),
36
+ };
37
+ };
38
+ /**
39
+ * Decrypts an encrypted message using the recipient's private key.
40
+ * @param {string} privateKey - The recipient's private key.
41
+ * @param {Encrypted} opts - The encrypted message.
42
+ * @returns {string} The decrypted message.
43
+ */
44
+ export const decrypt = (privateKey, opts) => {
45
+ let sharedSecret;
46
+ try {
47
+ sharedSecret = secp256k1.getSharedSecret(hexToBytes(privateKey), opts.ephemPublicKey, true).slice(1);
48
+ }
49
+ catch (e) {
50
+ throw new Error(`Invalid MAC: data integrity check failed: ${e}`);
51
+ }
52
+ const hash = sha512(sharedSecret);
53
+ const encryptionKey = hash.subarray(0, 32);
54
+ const macKey = hash.subarray(32);
55
+ const ciphertext = hexToBytes(opts.ciphertext);
56
+ const iv = hexToBytes(opts.iv);
57
+ const ephemPublicKey = hexToBytes(opts.ephemPublicKey);
58
+ const receivedMac = hexToBytes(opts.mac);
59
+ // Recompute MAC
60
+ const dataToMac = concatUint8Arrays([iv, ephemPublicKey, ciphertext]);
61
+ const expectedMac = hmacSha256Sign(macKey, dataToMac);
62
+ if (!constantTimeEqual(expectedMac, receivedMac)) {
63
+ throw new Error('Invalid MAC: data integrity check failed');
64
+ }
65
+ const decrypted = aesDecrypt(ciphertext, encryptionKey, iv, 'aes-256-cbc');
66
+ return bytesToUtf8(decrypted);
67
+ };
68
+ /**
69
+ * Compares two Uint8Arrays in constant time to prevent timing attacks.
70
+ * @param {Uint8Array} a - The first array.
71
+ * @param {Uint8Array} b - The second array.
72
+ * @returns {boolean} True if the arrays are equal, false otherwise.
73
+ */
74
+ function constantTimeEqual(a, b) {
75
+ if (a.length !== b.length)
76
+ return false;
77
+ let result = 0;
78
+ for (let i = 0; i < a.length; i++) {
79
+ result |= a[i] ^ b[i];
80
+ }
81
+ return result === 0;
82
+ }
package/dist/hash.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare const keccak256: (params: string) => string;
2
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,WAEvC,CAAC"}
package/dist/hash.js ADDED
@@ -0,0 +1,12 @@
1
+ import { bytesToHex, hexToBytes } from 'ethereum-cryptography/utils.js';
2
+ import { keccak256 as _keccak256 } from 'ethereum-cryptography/keccak.js';
3
+ import { addLeading0x, utf8ToBytes } from './util';
4
+ const solidityPackedKeccak256 = (value) => {
5
+ const bytes = utf8ToBytes(value);
6
+ const hex = addLeading0x(bytesToHex(bytes));
7
+ const hash = _keccak256(hexToBytes(hex));
8
+ return addLeading0x(bytesToHex(hash));
9
+ };
10
+ export const keccak256 = (params) => {
11
+ return solidityPackedKeccak256(params);
12
+ };
@@ -0,0 +1,28 @@
1
+ import { createIdentity } from './createIdentity';
2
+ import { sign } from './sign';
3
+ import { encryptWithPublicKey } from './encryptWithPublicKey';
4
+ import { decryptWithPrivateKey } from './decryptWithPrivateKey';
5
+ import { keccak256 } from './hash';
6
+ import { publicKeyByPrivateKey } from './publicKeyByPrivateKey';
7
+ import { recoverPublicKey } from './recoverPublicKey';
8
+ declare const hash: {
9
+ keccak256: (params: string) => string;
10
+ };
11
+ export { createIdentity, decryptWithPrivateKey, encryptWithPublicKey, hash, keccak256, publicKeyByPrivateKey, recoverPublicKey, sign, };
12
+ declare const _default: {
13
+ createIdentity: (entropy?: Uint8Array) => {
14
+ privateKey: string;
15
+ publicKey: string;
16
+ };
17
+ decryptWithPrivateKey: (privateKey: string, encrypted: import("./types").Encrypted) => string;
18
+ encryptWithPublicKey: (publicKey: string, message: string, options?: import("./types").EncryptionOptions) => import("./types").Encrypted;
19
+ hash: {
20
+ keccak256: (params: string) => string;
21
+ };
22
+ keccak256: (params: string) => string;
23
+ publicKeyByPrivateKey: (privateKey: string) => string;
24
+ recoverPublicKey: (signature: string, hash: string) => string;
25
+ sign: (privateKey: string, hash: string) => string;
26
+ };
27
+ export default _default;
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,QAAA,MAAM,IAAI;;CAET,CAAC;AAEF,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,IAAI,EACJ,SAAS,EACT,qBAAqB,EACrB,gBAAgB,EAChB,IAAI,GACL,CAAC;;;;;;;;;;;;;;;;AAEF,wBASE"}
@@ -5,29 +5,17 @@ import { decryptWithPrivateKey } from './decryptWithPrivateKey';
5
5
  import { keccak256 } from './hash';
6
6
  import { publicKeyByPrivateKey } from './publicKeyByPrivateKey';
7
7
  import { recoverPublicKey } from './recoverPublicKey';
8
-
9
8
  const hash = {
10
- keccak256,
9
+ keccak256,
11
10
  };
12
-
13
- export {
14
- createIdentity,
15
- decryptWithPrivateKey,
16
- encryptWithPublicKey,
17
- hash,
18
- keccak256,
19
- publicKeyByPrivateKey,
20
- recoverPublicKey,
21
- sign,
22
- };
23
-
11
+ export { createIdentity, decryptWithPrivateKey, encryptWithPublicKey, hash, keccak256, publicKeyByPrivateKey, recoverPublicKey, sign, };
24
12
  export default {
25
- createIdentity,
26
- decryptWithPrivateKey,
27
- encryptWithPublicKey,
28
- hash,
29
- keccak256,
30
- publicKeyByPrivateKey,
31
- recoverPublicKey,
32
- sign,
13
+ createIdentity,
14
+ decryptWithPrivateKey,
15
+ encryptWithPublicKey,
16
+ hash,
17
+ keccak256,
18
+ publicKeyByPrivateKey,
19
+ recoverPublicKey,
20
+ sign,
33
21
  };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Generate publicKey from the privateKey.
3
+ * This creates the uncompressed publicKey,
4
+ * where 04 has stripped from left
5
+ * @returns {string}
6
+ */
7
+ export declare const publicKeyByPrivateKey: (privateKey: string) => string;
8
+ //# sourceMappingURL=publicKeyByPrivateKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicKeyByPrivateKey.d.ts","sourceRoot":"","sources":["../src/publicKeyByPrivateKey.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,eAAO,MAAM,qBAAqB,GAAI,YAAY,MAAM,WAKvD,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { decompress, stripHexPrefix } from './util';
2
+ import { secp256k1 } from 'ethereum-cryptography/secp256k1.js';
3
+ import { bytesToHex } from 'ethereum-cryptography/utils';
4
+ /**
5
+ * Generate publicKey from the privateKey.
6
+ * This creates the uncompressed publicKey,
7
+ * where 04 has stripped from left
8
+ * @returns {string}
9
+ */
10
+ export const publicKeyByPrivateKey = (privateKey) => {
11
+ const key = stripHexPrefix(privateKey);
12
+ const compressedPub = secp256k1.getPublicKey(key); // defaults to compressed format
13
+ const point = secp256k1.ProjectivePoint.fromHex(compressedPub); // decompress the pub into an EC point
14
+ return decompress(bytesToHex(point.toRawBytes(false))); // Get uncompressed SEC1 format pub
15
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * returns the publicKey for the privateKey with which the messageHash was signed
3
+ * @param {string} signature
4
+ * @param {string} hash
5
+ * @return {string} publicKey
6
+ */
7
+ export declare const recoverPublicKey: (signature: string, hash: string) => string;
8
+ //# sourceMappingURL=recoverPublicKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recoverPublicKey.d.ts","sourceRoot":"","sources":["../src/recoverPublicKey.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,MAAM,EAAE,MAAM,MAAM,WAe/D,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { ecdsaRecover } from 'ethereum-cryptography/secp256k1-compat';
2
+ import { stripHexPrefix } from './util';
3
+ import { bytesToHex, hexToBytes } from 'ethereum-cryptography/utils';
4
+ /**
5
+ * returns the publicKey for the privateKey with which the messageHash was signed
6
+ * @param {string} signature
7
+ * @param {string} hash
8
+ * @return {string} publicKey
9
+ */
10
+ export const recoverPublicKey = (signature, hash) => {
11
+ const noHex = stripHexPrefix(signature);
12
+ // split into v-value and sig
13
+ const sigOnly = noHex.substring(0, noHex.length - 2); // all but last 2 chars
14
+ const vValue = noHex.slice(-2); // last 2 chars
15
+ const recoveryNumber = vValue === '1c' ? 1 : 0;
16
+ let pubKey = bytesToHex(ecdsaRecover(hexToBytes(sigOnly), recoveryNumber, hexToBytes(stripHexPrefix(hash)), false));
17
+ // remove trailing '04'
18
+ pubKey = pubKey.slice(2);
19
+ return pubKey;
20
+ };
package/dist/sign.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * signs the given message
3
+ * @param {string} privateKey
4
+ * @param {string} hash
5
+ * @return {string} hexString
6
+ */
7
+ export declare const sign: (privateKey: string, hash: string) => string;
8
+ export declare const hmacSha256Sign: (key: Uint8Array, msg: Uint8Array) => Uint8Array<ArrayBufferLike>;
9
+ //# sourceMappingURL=sign.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,eAAO,MAAM,IAAI,GAAI,YAAY,MAAM,EAAE,MAAM,MAAM,WASpD,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,KAAK,UAAU,EAAE,KAAK,UAAU,gCAG9D,CAAC"}
package/dist/sign.js ADDED
@@ -0,0 +1,24 @@
1
+ import { secp256k1 } from 'ethereum-cryptography/secp256k1.js';
2
+ import { hmac } from '@noble/hashes/hmac.js';
3
+ import { sha256 } from '@noble/hashes/sha2.js';
4
+ import { hexToBytes } from 'ethereum-cryptography/utils';
5
+ import { addLeading0x, isHexString, stripHexPrefix } from './util';
6
+ /**
7
+ * signs the given message
8
+ * @param {string} privateKey
9
+ * @param {string} hash
10
+ * @return {string} hexString
11
+ */
12
+ export const sign = (privateKey, hash) => {
13
+ const hashWith0x = addLeading0x(hash);
14
+ if (hashWith0x.length !== 66 || !isHexString(hashWith0x))
15
+ throw new Error('Can only sign hashes, given: ' + hash);
16
+ const sigObj = secp256k1.sign(hexToBytes(stripHexPrefix(hash)), hexToBytes(stripHexPrefix(privateKey)));
17
+ const recoveryId = sigObj.recovery === 1 ? '1c' : '1b';
18
+ const newSignature = '0x' + sigObj.toCompactHex() + recoveryId;
19
+ return newSignature;
20
+ };
21
+ export const hmacSha256Sign = (key, msg) => {
22
+ const result = hmac(sha256, key, msg);
23
+ return result;
24
+ };
@@ -0,0 +1,10 @@
1
+ export type Encrypted = {
2
+ iv: string;
3
+ ephemPublicKey: string;
4
+ ciphertext: string;
5
+ mac: string;
6
+ };
7
+ export type EncryptionOptions = {
8
+ ephemPrivateKey?: string;
9
+ };
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/util.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Returns a `Boolean` on whether or not the a `String` starts with '0x'
3
+ * @param str the string input value
4
+ * @return a boolean if it is or is not hex prefixed
5
+ * @throws if the str input is not a string
6
+ */
7
+ export declare const isHexPrefixed: (str: string) => boolean;
8
+ /**
9
+ * Removes '0x' from a given `String` if present
10
+ * @param str the string value
11
+ * @returns the string without 0x prefix
12
+ */
13
+ export declare const stripHexPrefix: (str: string) => string;
14
+ /**
15
+ * Is the string a hex string.
16
+ *
17
+ * @param value
18
+ * @param length
19
+ * @returns output the string is a hex string
20
+ */
21
+ export declare const isHexString: (value: string, length?: number) => boolean;
22
+ /**
23
+ * Adds '0x' to a given `String` if not present
24
+ * @param str the string input value
25
+ * @return the string with a 0x prefix
26
+ */
27
+ export declare const addLeading0x: (str: string) => string;
28
+ export declare const decompress: (startsWith02Or03: string) => string;
29
+ /** Helper function to concat UInt8Arrays mimicking the behaviour of the
30
+ * Buffer.concat function in Node.js
31
+ */
32
+ export declare const concatUint8Arrays: (uint8arrays: Uint8Array[]) => Uint8Array<ArrayBuffer>;
33
+ /**
34
+ * Converts a UTF-8 string to a Uint8Array without using TextEncoder, which is not available in mobile
35
+ * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
36
+ */
37
+ export declare const utf8ToBytes: (str: string) => Uint8Array;
38
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,KAAK,MAAM,YAMxC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAI5C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,EAAE,SAAS,MAAM,KAAG,OAM5D,CAAC;AAEF;;;;GAIG;AAEH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,WAGvC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,kBAAkB,MAAM,WAOlD,CAAC;AAEF;;GAEG;AAEH,eAAO,MAAM,iBAAiB,GAAI,aAAa,UAAU,EAAE,4BAS1D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,UA4BzC,CAAC"}
package/dist/util.js ADDED
@@ -0,0 +1,98 @@
1
+ import { hexToBytes } from 'ethereum-cryptography/utils';
2
+ /**
3
+ * Returns a `Boolean` on whether or not the a `String` starts with '0x'
4
+ * @param str the string input value
5
+ * @return a boolean if it is or is not hex prefixed
6
+ * @throws if the str input is not a string
7
+ */
8
+ export const isHexPrefixed = (str) => {
9
+ if (typeof str !== 'string') {
10
+ throw new Error(`[isHexPrefixed] input must be type 'string', received type ${typeof str}`);
11
+ }
12
+ return str[0] === '0' && str[1] === 'x';
13
+ };
14
+ /**
15
+ * Removes '0x' from a given `String` if present
16
+ * @param str the string value
17
+ * @returns the string without 0x prefix
18
+ */
19
+ export const stripHexPrefix = (str) => {
20
+ if (typeof str !== 'string')
21
+ throw new Error(`[stripHexPrefix] input must be type 'string', received ${typeof str}`);
22
+ return isHexPrefixed(str) ? str.slice(2) : str;
23
+ };
24
+ /**
25
+ * Is the string a hex string.
26
+ *
27
+ * @param value
28
+ * @param length
29
+ * @returns output the string is a hex string
30
+ */
31
+ export const isHexString = (value, length) => {
32
+ if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]+$/))
33
+ return false;
34
+ if (length && value.length !== 2 + 2 * length)
35
+ return false;
36
+ return true;
37
+ };
38
+ /**
39
+ * Adds '0x' to a given `String` if not present
40
+ * @param str the string input value
41
+ * @return the string with a 0x prefix
42
+ */
43
+ export const addLeading0x = (str) => {
44
+ if (!str.startsWith('0x'))
45
+ return '0x' + str;
46
+ else
47
+ return str;
48
+ };
49
+ export const decompress = (startsWith02Or03) => {
50
+ const testByteArray = hexToBytes(startsWith02Or03);
51
+ let startsWith04 = startsWith02Or03;
52
+ if (testByteArray.length === 64) {
53
+ startsWith04 = '04' + startsWith02Or03;
54
+ }
55
+ return startsWith04.substring(2);
56
+ };
57
+ /** Helper function to concat UInt8Arrays mimicking the behaviour of the
58
+ * Buffer.concat function in Node.js
59
+ */
60
+ export const concatUint8Arrays = (uint8arrays) => {
61
+ const totalLength = uint8arrays.reduce((total, uint8array) => total + uint8array.byteLength, 0);
62
+ const result = new Uint8Array(totalLength);
63
+ let offset = 0;
64
+ uint8arrays.forEach((uint8array) => {
65
+ result.set(uint8array, offset);
66
+ offset += uint8array.byteLength;
67
+ });
68
+ return result;
69
+ };
70
+ /**
71
+ * Converts a UTF-8 string to a Uint8Array without using TextEncoder, which is not available in mobile
72
+ * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
73
+ */
74
+ export const utf8ToBytes = (str) => {
75
+ if (typeof str !== 'string')
76
+ throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
77
+ const bytes = [];
78
+ for (let i = 0; i < str.length; i++) {
79
+ const codePoint = str.codePointAt(i);
80
+ if (!codePoint) {
81
+ throw new Error('Invalid code point');
82
+ }
83
+ if (codePoint < 0x80) {
84
+ bytes.push(codePoint);
85
+ }
86
+ else if (codePoint < 0x800) {
87
+ bytes.push(0xc0 | (codePoint >> 6), 0x80 | (codePoint & 0x3f));
88
+ }
89
+ else if (codePoint < 0x10000) {
90
+ bytes.push(0xe0 | (codePoint >> 12), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
91
+ }
92
+ else {
93
+ i++; // skip one iteration since we have a surrogate pair
94
+ bytes.push(0xf0 | (codePoint >> 18), 0x80 | ((codePoint >> 12) & 0x3f), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
95
+ }
96
+ }
97
+ return new Uint8Array(bytes);
98
+ };
package/package.json CHANGED
@@ -1,13 +1,20 @@
1
1
  {
2
2
  "name": "@wallaby-cash/cryptography",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Cryptography utilities for Wallaby Cash",
5
- "main": "./src/index.ts",
6
- "types": "./src/index.ts",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
7
  "exports": {
8
- ".": "./src/index.ts",
9
- "./*": "./src/*.ts"
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
10
12
  },
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "CHANGELOG.md"
17
+ ],
11
18
  "publishConfig": {
12
19
  "access": "public"
13
20
  },
@@ -25,6 +32,8 @@
25
32
  "directory": "packages/cryptography"
26
33
  },
27
34
  "scripts": {
35
+ "build": "tsc",
36
+ "prepublishOnly": "npm run build",
28
37
  "lint": "eslint . --max-warnings 0",
29
38
  "generate:component": "turbo gen react-component",
30
39
  "check-types": "tsc --noEmit"
@@ -39,6 +48,7 @@
39
48
  "typescript": "5.9.2"
40
49
  },
41
50
  "dependencies": {
51
+ "@noble/hashes": "^2.0.1",
42
52
  "ethereum-cryptography": "^3.2.0",
43
53
  "react": "^19.2.0",
44
54
  "react-dom": "^19.2.0"
@@ -1,66 +0,0 @@
1
- import { getRandomBytesSync as randomBytes } from 'ethereum-cryptography/random.js';
2
- import { addLeading0x, stripHexPrefix, concatUint8Arrays } from './util';
3
- import { publicKeyByPrivateKey } from './publicKeyByPrivateKey';
4
- import { bytesToHex } from 'ethereum-cryptography/utils';
5
- import { keccak256 } from 'ethereum-cryptography/keccak';
6
-
7
- export const DEFAULT_ENTROPY_BYTES = 32;
8
- export const MINIMUM_SHANNON_ENTROPY = 4;
9
-
10
- /**
11
- * creates a new private key
12
- * @param { Uint8Array } entropy - optional entropy to create the private key
13
- * @returns a new private key
14
- */
15
- export const createPrivateKey = (entropy?: Uint8Array) => {
16
- if (entropy) {
17
- if (!(entropy instanceof Uint8Array) || entropy.length < DEFAULT_ENTROPY_BYTES) {
18
- throw new Error(`entropy must be a Uint8Array of at least ${DEFAULT_ENTROPY_BYTES} bytes`);
19
- }
20
-
21
- // Check byte diversity
22
- const uniqueBytes = new Set(entropy);
23
- if (uniqueBytes.size < Math.min(8, entropy.length / 4)) {
24
- throw new Error(`entropy is too repetitive (only ${uniqueBytes.size} unique byte values)`);
25
- }
26
-
27
- // Estimate Shannon entropy
28
- const byteCounts = new Uint32Array(256);
29
- entropy.forEach((b) => byteCounts[b]!++);
30
- const total = entropy.length;
31
- let shannonEntropy = 0;
32
- for (let i = 0; i < 256; i++) {
33
- if (byteCounts[i]! > 0) {
34
- const p = byteCounts[i]! / total;
35
- shannonEntropy -= p * Math.log2(p);
36
- }
37
- }
38
- if (shannonEntropy < MINIMUM_SHANNON_ENTROPY) {
39
- throw new Error(`entropy has low Shannon entropy (${shannonEntropy.toFixed(2)} bits/byte)`);
40
- }
41
-
42
- const outerHex = keccak256(entropy);
43
- return addLeading0x(bytesToHex(outerHex));
44
- } else {
45
- const innerHex = keccak256(concatUint8Arrays([randomBytes(32), randomBytes(32)]));
46
- const middleHex = concatUint8Arrays([concatUint8Arrays([randomBytes(32), innerHex]), randomBytes(32)]);
47
- const outerHex = keccak256(middleHex);
48
- return addLeading0x(bytesToHex(outerHex));
49
- }
50
- };
51
-
52
- /**
53
- * creates a new identity
54
- * @param { Uint8Array } entropy - optional entropy to create the private key
55
- * @returns a new pair of private and public key
56
- */
57
- export const createIdentity = (entropy?: Uint8Array) => {
58
- const privateKey = createPrivateKey(entropy);
59
-
60
- const walletPublicKey = publicKeyByPrivateKey(privateKey);
61
- const identity = {
62
- privateKey: privateKey,
63
- publicKey: stripHexPrefix(walletPublicKey),
64
- };
65
- return identity;
66
- };
@@ -1,10 +0,0 @@
1
- import { stripHexPrefix } from './util';
2
- import { decrypt } from './encryption-utils';
3
- import { Encrypted } from './types';
4
-
5
- export const decryptWithPrivateKey = (privateKey: string, encrypted: Encrypted) => {
6
- // remove '0x' from privateKey
7
- const twoStripped = stripHexPrefix(privateKey);
8
-
9
- return decrypt(twoStripped, encrypted);
10
- };
@@ -1,12 +0,0 @@
1
- import { decompress } from './util';
2
- import { encrypt } from './encryption-utils';
3
- import { EncryptionOptions } from './types';
4
-
5
- export const encryptWithPublicKey = (publicKey: string, message: string, options?: EncryptionOptions) => {
6
- // ensure its an uncompressed publicKey
7
- const decompressedKey = decompress(publicKey);
8
-
9
- // re-add the compression-flag
10
- const pubString = '04' + decompressedKey;
11
- return encrypt(pubString, message, options);
12
- };
@@ -1,93 +0,0 @@
1
- import { sha512 } from 'ethereum-cryptography/sha512.js';
2
- import { secp256k1 } from 'ethereum-cryptography/secp256k1';
3
- import { getRandomBytesSync as randomBytes } from 'ethereum-cryptography/random.js';
4
- import { hexToBytes, bytesToHex, bytesToUtf8 } from 'ethereum-cryptography/utils.js';
5
- import { encrypt as aesEncrypt, decrypt as aesDecrypt } from 'ethereum-cryptography/aes.js';
6
- import { Encrypted, EncryptionOptions } from './types';
7
- import { hmacSha256Sign } from './sign';
8
- import { concatUint8Arrays, utf8ToBytes } from './util';
9
-
10
- /**
11
- * See https://github.com/bitchan/eccrypto for the original implementation that eth-crypto used, it's ancient and not maintained.
12
- */
13
-
14
- /**
15
- * Encrypts a message using the recipient's public key.
16
- * @param {string} publicKeyTo - The recipient's public key.
17
- * @param {string} msg - The message to encrypt.
18
- * @returns {Encrypted} The encrypted message.
19
- */
20
-
21
- export const encrypt = (publicKeyTo: string, msg: string, options?: EncryptionOptions): Encrypted => {
22
- const ephemPrivateKey = options?.ephemPrivateKey ? hexToBytes(options.ephemPrivateKey) : randomBytes(32);
23
- const iv = randomBytes(16);
24
-
25
- const compressedPub = secp256k1.getPublicKey(ephemPrivateKey); // defaults to compressed format
26
- const point = secp256k1.ProjectivePoint.fromHex(compressedPub); // decompress the pub into an EC point
27
- const ephemPublicKey = point.toRawBytes(false); // Get uncompressed SEC1 format pub
28
- const sharedSecret = secp256k1.getSharedSecret(ephemPrivateKey, hexToBytes(publicKeyTo), true).slice(1);
29
- const hash = sha512(sharedSecret);
30
- const encryptionKey = hash.subarray(0, 32);
31
- const macKey = hash.subarray(32);
32
- const message = utf8ToBytes(msg);
33
- const data = aesEncrypt(message, encryptionKey, iv, 'aes-256-cbc');
34
- const dataToMac = concatUint8Arrays([iv, ephemPublicKey, data]);
35
- const mac = hmacSha256Sign(macKey, dataToMac);
36
-
37
- return {
38
- iv: bytesToHex(iv),
39
- ephemPublicKey: bytesToHex(ephemPublicKey),
40
- ciphertext: bytesToHex(data),
41
- mac: bytesToHex(mac),
42
- };
43
- };
44
-
45
- /**
46
- * Decrypts an encrypted message using the recipient's private key.
47
- * @param {string} privateKey - The recipient's private key.
48
- * @param {Encrypted} opts - The encrypted message.
49
- * @returns {string} The decrypted message.
50
- */
51
- export const decrypt = (privateKey: string, opts: Encrypted) => {
52
- let sharedSecret: Uint8Array;
53
- try {
54
- sharedSecret = secp256k1.getSharedSecret(hexToBytes(privateKey), opts.ephemPublicKey, true).slice(1);
55
- } catch (e) {
56
- throw new Error(`Invalid MAC: data integrity check failed: ${e}`);
57
- }
58
-
59
- const hash = sha512(sharedSecret);
60
- const encryptionKey = hash.subarray(0, 32);
61
- const macKey = hash.subarray(32);
62
-
63
- const ciphertext = hexToBytes(opts.ciphertext);
64
- const iv = hexToBytes(opts.iv);
65
- const ephemPublicKey = hexToBytes(opts.ephemPublicKey);
66
- const receivedMac = hexToBytes(opts.mac);
67
-
68
- // Recompute MAC
69
- const dataToMac = concatUint8Arrays([iv, ephemPublicKey, ciphertext]);
70
- const expectedMac = hmacSha256Sign(macKey, dataToMac);
71
-
72
- if (!constantTimeEqual(expectedMac, receivedMac)) {
73
- throw new Error('Invalid MAC: data integrity check failed');
74
- }
75
-
76
- const decrypted = aesDecrypt(ciphertext, encryptionKey, iv, 'aes-256-cbc');
77
- return bytesToUtf8(decrypted);
78
- };
79
-
80
- /**
81
- * Compares two Uint8Arrays in constant time to prevent timing attacks.
82
- * @param {Uint8Array} a - The first array.
83
- * @param {Uint8Array} b - The second array.
84
- * @returns {boolean} True if the arrays are equal, false otherwise.
85
- */
86
- function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {
87
- if (a.length !== b.length) return false;
88
- let result = 0;
89
- for (let i = 0; i < a.length; i++) {
90
- result |= a[i]! ^ b[i]!;
91
- }
92
- return result === 0;
93
- }
package/src/hash.ts DELETED
@@ -1,14 +0,0 @@
1
- import { bytesToHex, hexToBytes } from 'ethereum-cryptography/utils.js';
2
- import { keccak256 as _keccak256 } from 'ethereum-cryptography/keccak.js';
3
- import { addLeading0x, utf8ToBytes } from './util';
4
-
5
- const solidityPackedKeccak256 = (value: string) => {
6
- const bytes = utf8ToBytes(value);
7
- const hex = addLeading0x(bytesToHex(bytes));
8
- const hash = _keccak256(hexToBytes(hex));
9
- return addLeading0x(bytesToHex(hash));
10
- };
11
-
12
- export const keccak256 = (params: string) => {
13
- return solidityPackedKeccak256(params);
14
- };
@@ -1,17 +0,0 @@
1
- import { decompress, stripHexPrefix } from './util';
2
- import { secp256k1 } from 'ethereum-cryptography/secp256k1.js';
3
- import { bytesToHex } from 'ethereum-cryptography/utils';
4
-
5
- /**
6
- * Generate publicKey from the privateKey.
7
- * This creates the uncompressed publicKey,
8
- * where 04 has stripped from left
9
- * @returns {string}
10
- */
11
-
12
- export const publicKeyByPrivateKey = (privateKey: string) => {
13
- const key = stripHexPrefix(privateKey);
14
- const compressedPub = secp256k1.getPublicKey(key); // defaults to compressed format
15
- const point = secp256k1.ProjectivePoint.fromHex(compressedPub); // decompress the pub into an EC point
16
- return decompress(bytesToHex(point.toRawBytes(false))); // Get uncompressed SEC1 format pub
17
- };
@@ -1,26 +0,0 @@
1
- import { ecdsaRecover } from 'ethereum-cryptography/secp256k1-compat';
2
- import { stripHexPrefix } from './util';
3
- import { bytesToHex, hexToBytes } from 'ethereum-cryptography/utils';
4
-
5
- /**
6
- * returns the publicKey for the privateKey with which the messageHash was signed
7
- * @param {string} signature
8
- * @param {string} hash
9
- * @return {string} publicKey
10
- */
11
- export const recoverPublicKey = (signature: string, hash: string) => {
12
- const noHex = stripHexPrefix(signature);
13
-
14
- // split into v-value and sig
15
- const sigOnly = noHex.substring(0, noHex.length - 2); // all but last 2 chars
16
- const vValue = noHex.slice(-2); // last 2 chars
17
-
18
- const recoveryNumber = vValue === '1c' ? 1 : 0;
19
-
20
- let pubKey = bytesToHex(ecdsaRecover(hexToBytes(sigOnly), recoveryNumber, hexToBytes(stripHexPrefix(hash)), false));
21
-
22
- // remove trailing '04'
23
- pubKey = pubKey.slice(2);
24
-
25
- return pubKey;
26
- };
package/src/sign.ts DELETED
@@ -1,27 +0,0 @@
1
- import { secp256k1 } from 'ethereum-cryptography/secp256k1.js';
2
- import { hmac } from '@noble/hashes/hmac';
3
- import { sha256 } from '@noble/hashes/sha2';
4
- import { hexToBytes } from 'ethereum-cryptography/utils';
5
- import { addLeading0x, isHexString, stripHexPrefix } from './util';
6
-
7
- /**
8
- * signs the given message
9
- * @param {string} privateKey
10
- * @param {string} hash
11
- * @return {string} hexString
12
- */
13
- export const sign = (privateKey: string, hash: string) => {
14
- const hashWith0x = addLeading0x(hash);
15
- if (hashWith0x.length !== 66 || !isHexString(hashWith0x)) throw new Error('Can only sign hashes, given: ' + hash);
16
-
17
- const sigObj = secp256k1.sign(hexToBytes(stripHexPrefix(hash)), hexToBytes(stripHexPrefix(privateKey)));
18
-
19
- const recoveryId = sigObj.recovery === 1 ? '1c' : '1b';
20
- const newSignature = '0x' + sigObj.toCompactHex() + recoveryId;
21
- return newSignature;
22
- };
23
-
24
- export const hmacSha256Sign = (key: Uint8Array, msg: Uint8Array) => {
25
- const result = hmac(sha256, key, msg);
26
- return result;
27
- };
package/src/types.ts DELETED
@@ -1,10 +0,0 @@
1
- export type Encrypted = {
2
- iv: string;
3
- ephemPublicKey: string;
4
- ciphertext: string;
5
- mac: string;
6
- };
7
-
8
- export type EncryptionOptions = {
9
- ephemPrivateKey?: string;
10
- };
package/src/util.ts DELETED
@@ -1,110 +0,0 @@
1
- import { hexToBytes } from 'ethereum-cryptography/utils';
2
-
3
- /**
4
- * Returns a `Boolean` on whether or not the a `String` starts with '0x'
5
- * @param str the string input value
6
- * @return a boolean if it is or is not hex prefixed
7
- * @throws if the str input is not a string
8
- */
9
- export const isHexPrefixed = (str: string) => {
10
- if (typeof str !== 'string') {
11
- throw new Error(`[isHexPrefixed] input must be type 'string', received type ${typeof str}`);
12
- }
13
-
14
- return str[0] === '0' && str[1] === 'x';
15
- };
16
-
17
- /**
18
- * Removes '0x' from a given `String` if present
19
- * @param str the string value
20
- * @returns the string without 0x prefix
21
- */
22
- export const stripHexPrefix = (str: string): string => {
23
- if (typeof str !== 'string') throw new Error(`[stripHexPrefix] input must be type 'string', received ${typeof str}`);
24
-
25
- return isHexPrefixed(str) ? str.slice(2) : str;
26
- };
27
-
28
- /**
29
- * Is the string a hex string.
30
- *
31
- * @param value
32
- * @param length
33
- * @returns output the string is a hex string
34
- */
35
- export const isHexString = (value: string, length?: number): boolean => {
36
- if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]+$/)) return false;
37
-
38
- if (length && value.length !== 2 + 2 * length) return false;
39
-
40
- return true;
41
- };
42
-
43
- /**
44
- * Adds '0x' to a given `String` if not present
45
- * @param str the string input value
46
- * @return the string with a 0x prefix
47
- */
48
-
49
- export const addLeading0x = (str: string) => {
50
- if (!str.startsWith('0x')) return '0x' + str;
51
- else return str;
52
- };
53
-
54
- export const decompress = (startsWith02Or03: string) => {
55
- const testByteArray = hexToBytes(startsWith02Or03);
56
- let startsWith04 = startsWith02Or03;
57
- if (testByteArray.length === 64) {
58
- startsWith04 = '04' + startsWith02Or03;
59
- }
60
- return startsWith04.substring(2);
61
- };
62
-
63
- /** Helper function to concat UInt8Arrays mimicking the behaviour of the
64
- * Buffer.concat function in Node.js
65
- */
66
-
67
- export const concatUint8Arrays = (uint8arrays: Uint8Array[]) => {
68
- const totalLength = uint8arrays.reduce((total, uint8array) => total + uint8array.byteLength, 0);
69
- const result = new Uint8Array(totalLength);
70
- let offset = 0;
71
- uint8arrays.forEach((uint8array) => {
72
- result.set(uint8array, offset);
73
- offset += uint8array.byteLength;
74
- });
75
- return result;
76
- };
77
-
78
- /**
79
- * Converts a UTF-8 string to a Uint8Array without using TextEncoder, which is not available in mobile
80
- * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
81
- */
82
- export const utf8ToBytes = (str: string): Uint8Array => {
83
- if (typeof str !== 'string') throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
84
- const bytes = [];
85
-
86
- for (let i = 0; i < str.length; i++) {
87
- const codePoint = str.codePointAt(i);
88
-
89
- if (!codePoint) {
90
- throw new Error('Invalid code point');
91
- }
92
-
93
- if (codePoint < 0x80) {
94
- bytes.push(codePoint);
95
- } else if (codePoint < 0x800) {
96
- bytes.push(0xc0 | (codePoint >> 6), 0x80 | (codePoint & 0x3f));
97
- } else if (codePoint < 0x10000) {
98
- bytes.push(0xe0 | (codePoint >> 12), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
99
- } else {
100
- i++; // skip one iteration since we have a surrogate pair
101
- bytes.push(
102
- 0xf0 | (codePoint >> 18),
103
- 0x80 | ((codePoint >> 12) & 0x3f),
104
- 0x80 | ((codePoint >> 6) & 0x3f),
105
- 0x80 | (codePoint & 0x3f),
106
- );
107
- }
108
- }
109
- return new Uint8Array(bytes);
110
- };