Skip to content
This repository was archived by the owner on Oct 7, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
node-version: [14.x, 16.x, 18.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
45 changes: 26 additions & 19 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
const { EventEmitter } = require('events');
const ethUtil = require('ethereumjs-util');
const {
isValidPrivate,
stripHexPrefix,
privateToPublic,
bufferToHex,
publicToAddress,
ecsign,
arrToBufArr,
} = require('@ethereumjs/util');
const randomBytes = require('randombytes');
const { keccak256 } = require('ethereum-cryptography/keccak');

const type = 'Simple Key Pair';
const {
Expand All @@ -18,7 +27,7 @@ function generateKey() {
// I don't think this is possible, but this validation was here previously,
// so it has been preserved just in case.
// istanbul ignore next
if (!ethUtil.isValidPrivate(privateKey)) {
if (!isValidPrivate(privateKey)) {
throw new Error(
'Private key does not satisfy the curve requirements (ie. it is invalid)',
);
Expand All @@ -40,9 +49,9 @@ class SimpleKeyring extends EventEmitter {

async deserialize(privateKeys = []) {
this._wallets = privateKeys.map((hexPrivateKey) => {
const strippedHexPrivateKey = ethUtil.stripHexPrefix(hexPrivateKey);
const strippedHexPrivateKey = stripHexPrefix(hexPrivateKey);
const privateKey = Buffer.from(strippedHexPrivateKey, 'hex');
const publicKey = ethUtil.privateToPublic(privateKey);
const publicKey = privateToPublic(privateKey);
return { privateKey, publicKey };
});
}
Expand All @@ -51,19 +60,19 @@ class SimpleKeyring extends EventEmitter {
const newWallets = [];
for (let i = 0; i < n; i++) {
const privateKey = generateKey();
const publicKey = ethUtil.privateToPublic(privateKey);
const publicKey = privateToPublic(privateKey);
newWallets.push({ privateKey, publicKey });
}
this._wallets = this._wallets.concat(newWallets);
const hexWallets = newWallets.map(({ publicKey }) =>
ethUtil.bufferToHex(ethUtil.publicToAddress(publicKey)),
bufferToHex(publicToAddress(publicKey)),
);
return hexWallets;
}

async getAccounts() {
return this._wallets.map(({ publicKey }) =>
ethUtil.bufferToHex(ethUtil.publicToAddress(publicKey)),
bufferToHex(publicToAddress(publicKey)),
);
}

Expand All @@ -77,9 +86,9 @@ class SimpleKeyring extends EventEmitter {

// For eth_sign, we need to sign arbitrary data:
async signMessage(address, data, opts = {}) {
const message = ethUtil.stripHexPrefix(data);
const message = stripHexPrefix(data);
const privKey = this._getPrivateKeyFor(address, opts);
const msgSig = ethUtil.ecsign(Buffer.from(message, 'hex'), privKey);
const msgSig = ecsign(Buffer.from(message, 'hex'), privKey);
const rawMsgSig = concatSig(msgSig.v, msgSig.r, msgSig.s);
return rawMsgSig;
}
Expand All @@ -95,7 +104,7 @@ class SimpleKeyring extends EventEmitter {
// For eth_decryptMessage:
async decryptMessage(withAccount, encryptedData) {
const wallet = this._getWalletForAccount(withAccount);
const privateKey = ethUtil.stripHexPrefix(wallet.privateKey);
const { privateKey } = wallet;
const sig = decrypt({ privateKey, encryptedData });
return sig;
}
Expand Down Expand Up @@ -139,7 +148,7 @@ class SimpleKeyring extends EventEmitter {
withAppKeyOrigin: origin,
});
const appKeyAddress = normalize(
ethUtil.publicToAddress(wallet.publicKey).toString('hex'),
publicToAddress(wallet.publicKey).toString('hex'),
);
return appKeyAddress;
}
Expand All @@ -154,7 +163,7 @@ class SimpleKeyring extends EventEmitter {
if (
!this._wallets
.map(({ publicKey }) =>
ethUtil.bufferToHex(ethUtil.publicToAddress(publicKey)).toLowerCase(),
bufferToHex(publicToAddress(publicKey)).toLowerCase(),
)
.includes(address.toLowerCase())
) {
Expand All @@ -163,9 +172,8 @@ class SimpleKeyring extends EventEmitter {

this._wallets = this._wallets.filter(
({ publicKey }) =>
ethUtil
.bufferToHex(ethUtil.publicToAddress(publicKey))
.toLowerCase() !== address.toLowerCase(),
bufferToHex(publicToAddress(publicKey)).toLowerCase() !==
address.toLowerCase(),
);
}

Expand All @@ -175,8 +183,7 @@ class SimpleKeyring extends EventEmitter {
_getWalletForAccount(account, opts = {}) {
const address = normalize(account);
let wallet = this._wallets.find(
({ publicKey }) =>
ethUtil.bufferToHex(ethUtil.publicToAddress(publicKey)) === address,
({ publicKey }) => bufferToHex(publicToAddress(publicKey)) === address,
);
if (!wallet) {
throw new Error('Simple Keyring - Unable to find matching address.');
Expand All @@ -186,8 +193,8 @@ class SimpleKeyring extends EventEmitter {
const { privateKey } = wallet;
const appKeyOriginBuffer = Buffer.from(opts.withAppKeyOrigin, 'utf8');
const appKeyBuffer = Buffer.concat([privateKey, appKeyOriginBuffer]);
const appKeyPrivateKey = ethUtil.keccak(appKeyBuffer, 256);
const appKeyPublicKey = ethUtil.privateToPublic(appKeyPrivateKey);
const appKeyPrivateKey = arrToBufArr(keccak256(appKeyBuffer, 256));
const appKeyPublicKey = privateToPublic(appKeyPrivateKey);
wallet = { privateKey: appKeyPrivateKey, publicKey: appKeyPublicKey };
}

Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@
"lint:fix": "yarn lint:eslint --fix && yarn lint:misc --write"
},
"dependencies": {
"@metamask/eth-sig-util": "^4.0.0",
"ethereumjs-util": "^7.0.9",
"@ethereumjs/util": "^8.0.0",
"@metamask/eth-sig-util": "^5.0.0",
"ethereum-cryptography": "^1.1.2",
"randombytes": "^2.1.0"
},
"devDependencies": {
"@ethereumjs/tx": "^3.1.1",
"@ethereumjs/tx": "^4.0.0",
"@lavamoat/allow-scripts": "^1.0.6",
"@metamask/auto-changelog": "^2.5.0",
"@metamask/eslint-config": "^8.0.0",
Expand All @@ -53,7 +54,7 @@
"prettier-plugin-packagejson": "^2.2.11"
},
"engines": {
"node": ">=12.0.0"
"node": ">=14.0.0"
},
"lavamoat": {
"allowScripts": {
Expand Down
48 changes: 26 additions & 22 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
const ethUtil = require('ethereumjs-util');
const {
stripHexPrefix,
bufferToHex,
toBuffer,
ecrecover,
pubToAddress,
isValidAddress,
} = require('@ethereumjs/util');
const { keccak256 } = require('ethereum-cryptography/keccak');
const {
encrypt,
getEncryptionPublicKey,
Expand Down Expand Up @@ -49,7 +57,7 @@ describe('simple-keyring', function () {
await keyring.deserialize([testAccount.key]);
const serialized = await keyring.serialize();
expect(serialized).toHaveLength(1);
expect(serialized[0]).toBe(ethUtil.stripHexPrefix(testAccount.key));
expect(serialized[0]).toBe(stripHexPrefix(testAccount.key));
});
});

Expand Down Expand Up @@ -127,9 +135,7 @@ describe('simple-keyring', function () {
it('reliably can decode messages it signs', async function () {
await keyring.deserialize([privateKey]);
const localMessage = 'hello there!';
const msgHashHex = ethUtil.bufferToHex(
ethUtil.keccak(Buffer.from(localMessage)),
);
const msgHashHex = bufferToHex(keccak256(Buffer.from(localMessage)));

await keyring.addAccounts(9);
const addresses = await keyring.getAccounts();
Expand All @@ -141,14 +147,12 @@ describe('simple-keyring', function () {
signatures.forEach((sgn, index) => {
const accountAddress = addresses[index];

const r = ethUtil.toBuffer(sgn.slice(0, 66));
const s = ethUtil.toBuffer(`0x${sgn.slice(66, 130)}`);
const v = ethUtil.bufferToInt(
ethUtil.toBuffer(`0x${sgn.slice(130, 132)}`),
);
const m = ethUtil.toBuffer(msgHashHex);
const pub = ethUtil.ecrecover(m, v, r, s);
const adr = `0x${ethUtil.pubToAddress(pub).toString('hex')}`;
const r = toBuffer(sgn.slice(0, 66));
const s = toBuffer(`0x${sgn.slice(66, 130)}`);
const v = BigInt(`0x${sgn.slice(130, 132)}`);
Copy link
Contributor Author

@adonesky1 adonesky1 Sep 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new version of ecrecover expects v to be a BigInt instead of Buffer: https://npmfs.com/package/@ethereumjs/util/8.0.0/src/signature.ts#L54

const m = toBuffer(msgHashHex);
const pub = ecrecover(m, v, r, s);
const adr = `0x${pubToAddress(pub).toString('hex')}`;

expect(adr).toBe(accountAddress);
});
Expand All @@ -157,7 +161,7 @@ describe('simple-keyring', function () {
it('throw error for invalid message', async function () {
await keyring.deserialize([privateKey]);
await expect(keyring.signMessage(address, '')).rejects.toThrow(
'Expected message to be an Uint8Array with length 32',
'Cannot convert 0x to a BigInt',
);
});

Expand Down Expand Up @@ -233,7 +237,7 @@ describe('simple-keyring', function () {
'6969696969696969696969696969696969696969696969696969696969696969',
'hex',
);
const privKeyHex = ethUtil.bufferToHex(privateKey);
const privKeyHex = bufferToHex(privateKey);
const message = '0x68656c6c6f20776f726c64';
const expectedSignature =
'0xce909e8ea6851bc36c007a0072d0524b07a3ff8d4e623aca4c71ca8e57250c4d0a3fc38fa8fbaaa81ead4b9f6bd03356b6f8bf18bccad167d78891636e1d69561b';
Expand Down Expand Up @@ -472,7 +476,7 @@ describe('simple-keyring', function () {
'6969696969696969696969696969696969696969696969696969696969696969',
'hex',
);
const privKeyHex = ethUtil.bufferToHex(privateKey);
const privKeyHex = bufferToHex(privateKey);
const message = 'Hello world!';
const encryptedMessage = encrypt({
publicKey: getEncryptionPublicKey(privateKey),
Expand Down Expand Up @@ -511,7 +515,7 @@ describe('simple-keyring', function () {
'hex',
);
const publicKey = 'GxuMqoE2oHsZzcQtv/WMNB3gCH2P6uzynuwO1P0MM1U=';
const privKeyHex = ethUtil.bufferToHex(privateKey);
const privKeyHex = bufferToHex(privateKey);

it('returns the expected value', async function () {
await keyring.deserialize([privKeyHex]);
Expand Down Expand Up @@ -624,7 +628,7 @@ describe('simple-keyring', function () {
);

expect(address).not.toBe(appKeyAddress);
expect(ethUtil.isValidAddress(appKeyAddress)).toBe(true);
expect(isValidAddress(appKeyAddress)).toBe(true);
});

it('should return different addresses when provided different app key origins', async function () {
Expand All @@ -636,14 +640,14 @@ describe('simple-keyring', function () {
'someapp.origin.io',
);

expect(ethUtil.isValidAddress(appKeyAddress1)).toBe(true);
expect(isValidAddress(appKeyAddress1)).toBe(true);

const appKeyAddress2 = await simpleKeyring.getAppKeyAddress(
address,
'anotherapp.origin.io',
);

expect(ethUtil.isValidAddress(appKeyAddress2)).toBe(true);
expect(isValidAddress(appKeyAddress2)).toBe(true);
expect(appKeyAddress1).not.toBe(appKeyAddress2);
});

Expand All @@ -656,14 +660,14 @@ describe('simple-keyring', function () {
'someapp.origin.io',
);

expect(ethUtil.isValidAddress(appKeyAddress1)).toBe(true);
expect(isValidAddress(appKeyAddress1)).toBe(true);

const appKeyAddress2 = await simpleKeyring.getAppKeyAddress(
address,
'someapp.origin.io',
);

expect(ethUtil.isValidAddress(appKeyAddress2)).toBe(true);
expect(isValidAddress(appKeyAddress2)).toBe(true);
expect(appKeyAddress1).toBe(appKeyAddress2);
});

Expand Down
Loading