Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: import keychain #5

Merged
merged 19 commits into from
Nov 10, 2023
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
9 changes: 9 additions & 0 deletions features/keychain/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const path = require('path')
module.exports = {
extends: '../../.eslintrc.js',
parserOptions: {
babelOptions: {
configFile: path.join(path.dirname(__filename), 'babel.config.js'),
},
},
}
148 changes: 148 additions & 0 deletions features/keychain/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [4.3.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@4.2.0...@exodus/keychain@4.3.0) (2023-10-23)

### Features

- **keychain:** add compare function for keyidentifier ([#4540](https://github.com/ExodusMovement/exodus-hydra/issues/4540)) ([71e32cc](https://github.com/ExodusMovement/exodus-hydra/commit/71e32ccb6bbb0989cb9b2d2006cbc0ea8c64f517))

## [4.2.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@4.1.0...@exodus/keychain@4.2.0) (2023-10-20)

### Features

- move keychain to feature dir ([#2374](https://github.com/ExodusMovement/exodus-hydra/issues/2374)) ([c8373a8](https://github.com/ExodusMovement/exodus-hydra/commit/c8373a84190d7861072a1cf5659f1fce227befee))

### Bug Fixes

- import from atoms index ([#4508](https://github.com/ExodusMovement/exodus-hydra/issues/4508)) ([923fb99](https://github.com/ExodusMovement/exodus-hydra/commit/923fb992328b63e45401c78176b5a6ef7b666eee))

## [4.1.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@4.1.0...@exodus/keychain@4.1.1) (2023-07-05)

### Bug Fixes

- **keychain:** plugin not published on npm ([#2278](https://github.com/ExodusMovement/exodus-hydra/issues/2278)) ([0e37c8a](https://github.com/ExodusMovement/exodus-hydra/commit/0e37c8ab8c44b08dd17cb89f1f29784e4cee8e86))

## [4.1.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@4.0.2...@exodus/keychain@4.1.0) (2023-07-03)

### Features

- memoizedKeychain module ([#2106](https://github.com/ExodusMovement/exodus-hydra/issues/2106)) ([ba92e86](https://github.com/ExodusMovement/exodus-hydra/commit/ba92e86b97eeef613d642837dc52702debd7e723))

## [4.0.2](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@4.0.1...@exodus/keychain@4.0.2) (2023-06-21)

### Bug Fixes

- **keychain:** enable tests & verify analytics id ([#1118](https://github.com/ExodusMovement/exodus-hydra/issues/1118)) ([4768265](https://github.com/ExodusMovement/exodus-hydra/commit/4768265ca43295b6619b7da82d2b4d7b8c422777))
- master ci ([#1613](https://github.com/ExodusMovement/exodus-hydra/issues/1613)) ([44e3063](https://github.com/ExodusMovement/exodus-hydra/commit/44e306304338d5ce3cbc21757b6b3e91f5d95210))

## [4.0.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@4.0.0...@exodus/keychain@4.0.1) (2023-04-27)

**Note:** Version bump only for package @exodus/keychain

## [4.0.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@3.5.0...@exodus/keychain@4.0.0) (2023-04-25)

### ⚠ BREAKING CHANGES

- **keychain)(3:** remove seed from constructor (#1337)
- **keychain)(2:** export module definition (#1133)
- **keychain:** differentiate module/atoms (#1094)

### Code Refactoring

- **keychain)(2:** export module definition ([#1133](https://github.com/ExodusMovement/exodus-hydra/issues/1133)) ([4c1117d](https://github.com/ExodusMovement/exodus-hydra/commit/4c1117d17c84c5a600e0883ce3de43b87fdcaa42))
- **keychain)(3:** remove seed from constructor ([#1337](https://github.com/ExodusMovement/exodus-hydra/issues/1337)) ([8ecccd4](https://github.com/ExodusMovement/exodus-hydra/commit/8ecccd4bf9f9089f585d8b70b0d4b1265328115f))
- **keychain:** differentiate module/atoms ([#1094](https://github.com/ExodusMovement/exodus-hydra/issues/1094)) ([10c38bb](https://github.com/ExodusMovement/exodus-hydra/commit/10c38bb33f340bd9a0369f540b2cfcd354988e77))

## [3.5.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@3.4.0...@exodus/keychain@3.5.0) (2023-04-13)

### Features

- keychain.clone for compatibility modes ([#1218](https://github.com/ExodusMovement/exodus-hydra/issues/1218)) ([b0cc050](https://github.com/ExodusMovement/exodus-hydra/commit/b0cc050eeced8b43fb0a973fa50e3c16f667a327))

## [3.4.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@3.3.1...@exodus/keychain@3.4.0) (2023-04-10)

### Features

- atom/waitUntil ([#1142](https://github.com/ExodusMovement/exodus-hydra/issues/1142)) ([4432b3c](https://github.com/ExodusMovement/exodus-hydra/commit/4432b3c645f37fc1de002b845c4253a684235d3e))

## [3.3.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@3.3.0...@exodus/keychain@3.3.1) (2023-04-04)

**Note:** Version bump only for package @exodus/keychain

## [3.3.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@3.2.1...@exodus/keychain@3.3.0) (2023-03-31)

### Features

- add seedDerivedId atom ([#1071](https://github.com/ExodusMovement/exodus-hydra/issues/1071)) ([05befdb](https://github.com/ExodusMovement/exodus-hydra/commit/05befdb525de7925b4bb5f0b544adbfeaf4641e3))

## [3.2.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@3.2.0...@exodus/keychain@3.2.1) (2023-03-23)

### Bug Fixes

- add privateKey shortcut to signTx param ([#993](https://github.com/ExodusMovement/exodus-hydra/issues/993)) ([c7f993c](https://github.com/ExodusMovement/exodus-hydra/commit/c7f993c16a125e869d5cb7337606a77d8a4879d1))
- **keychain:** update seedless derivationPath from 2'/4' to 5'/0' ([#1017](https://github.com/ExodusMovement/exodus-hydra/issues/1017)) ([05a15f6](https://github.com/ExodusMovement/exodus-hydra/commit/05a15f6b9e62972d99447661baca317865c08971))

## [3.2.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@3.1.0...@exodus/keychain@3.2.0) (2023-02-28)

### Features

- **keychain:** add signOpen and verifyDetached to sodiumEncryptor ([#939](https://github.com/ExodusMovement/exodus-hydra/issues/939)) ([3a36086](https://github.com/ExodusMovement/exodus-hydra/commit/3a36086541129a1afcdf1ffb7248c0bd24167c8d))

## [3.1.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@3.0.0...@exodus/keychain@3.1.0) (2023-02-23)

### Features

- add `restricted-imports` eslint rule ([#719](https://github.com/ExodusMovement/exodus-hydra/issues/719)) ([175de9c](https://github.com/ExodusMovement/exodus-hydra/commit/175de9c19ec00e5a12441022c313837d58f38882))
- **keychain:** add seedless key identifier ([#925](https://github.com/ExodusMovement/exodus-hydra/issues/925)) ([d62561b](https://github.com/ExodusMovement/exodus-hydra/commit/d62561bb9fd5d32ce2ad74508123c03d7a077ae5))

## 3.0.0 (2022-12-21)

### ⚠ BREAKING CHANGES

- new keychain.signTx method (#629)

### Refactor

- new keychain.signTx method ([#629](https://github.com/ExodusMovement/exodus-hydra/issues/629)) ([e4216a](https://github.com/ExodusMovement/exodus-hydra/commit/e4216a74edb384cf485a3574f60f699d390bd118))

## [2.1.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@2.0.0...@exodus/keychain@2.1.0) (2022-12-15)

### Features

- keychain.exportKey to return hdkey ([#610](https://github.com/ExodusMovement/exodus-hydra/issues/610)) ([23004cb](https://github.com/ExodusMovement/exodus-hydra/commit/23004cb67ec89dd4d8de0a15f2e4e90e9615c54f))

## [2.0.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@1.2.2...@exodus/keychain@2.0.0) (2022-10-25)

### ⚠ BREAKING CHANGES

- **keychain:** do not pass assetName to signTx function

### Features

- **keychain:** do not pass assetName to signTx function ([1899d6f](https://github.com/ExodusMovement/exodus-hydra/commit/1899d6f0d76de20d028082dfd64bd60068d62021))
- **keychain:** freeze all exported objects ([#168](https://github.com/ExodusMovement/exodus-hydra/issues/168)) ([179ab24](https://github.com/ExodusMovement/exodus-hydra/commit/179ab24186f062c64ea62070971250a716db85e9))
- **keychain:** rework privToPub mappers ([#181](https://github.com/ExodusMovement/exodus-hydra/issues/181)) ([0df08e6](https://github.com/ExodusMovement/exodus-hydra/commit/0df08e6fdd4c4790c019b40e4e6f95d2765e27e8))
- simplify `KeyIdentifierProvider` ([#262](https://github.com/ExodusMovement/exodus-hydra/issues/262)) ([f7e68e5](https://github.com/ExodusMovement/exodus-hydra/commit/f7e68e525088cd18d4aa1879036624467a46d539))

### Bug Fixes

- pin 0.0.1 versions back in keychain ([#149](https://github.com/ExodusMovement/exodus-hydra/issues/149)) ([588f1ce](https://github.com/ExodusMovement/exodus-hydra/commit/588f1ce30c43eebe1134af4c20905f1af5d15b13))

## [1.2.2](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@1.2.1...@exodus/keychain@1.2.2) (2022-08-08)

## [1.2.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/keychain@1.1.1...@exodus/keychain@1.2.1) (2022-07-28)

### Bug Fixes

- buildBip32Path addressIndex/chainIndex validation ([#99](https://github.com/ExodusMovement/exodus-hydra/issues/99)) ([1b6869f](https://github.com/ExodusMovement/exodus-hydra/commit/1b6869fbe11053467b0db0ed157b954ea52ed367))
- use null prototype for Keychain masters ([#100](https://github.com/ExodusMovement/exodus-hydra/issues/100)) ([01265e1](https://github.com/ExodusMovement/exodus-hydra/commit/01265e10e8d79fbe53127c5e9528ff9b88f510ec))
- use null prototype in privToPub ([#101](https://github.com/ExodusMovement/exodus-hydra/issues/101)) ([fb89442](https://github.com/ExodusMovement/exodus-hydra/commit/fb8944238f47d273d4422b4aace0c5579cce4c32))

### Reverts

- Revert "Publish" ([7bfc339](https://github.com/ExodusMovement/exodus-hydra/commit/7bfc339f6229b11110e6936422b935b8820abd8a))
- Revert "Publish" ([da7967e](https://github.com/ExodusMovement/exodus-hydra/commit/da7967ebfef69853d932a5ec3d71a5d4eea391a2))
- Revert "Publish" ([7e8a72b](https://github.com/ExodusMovement/exodus-hydra/commit/7e8a72b77aad4f2b7590439db9556f31dec530a7))
206 changes: 206 additions & 0 deletions features/keychain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
# `@exodus/keychain`

The keychain is a module designed to work more securely with private key material. It can be compared with a walled garden from which private keys can not escape (unless explicitly exported). All operations using the private key, such as signing and encryption data, are executed within the module. `KeyIdentifier`'s specify which private key to use for a particular operation.

## Install

```
yarn add @exodus/keychain
```

## Usage

See examples in [./modules/\_\_tests\_\_/example.test.js](./module/__tests__/example.test.js).

### Documented Usage Paths

Check [here](https://github.com/ExodusMovement/exodus-desktop/tree/master/src/app/_local_modules/constants/bip43#documented-usage-paths)

### Create A Key Identifier

In order to interact with a private key, you must first specify how it's accessed. A `KeyIdentifier` must be created, for assets there is a helpful `KeyIdentifier` class that will do the heavy lifting.

```js
import { KeyIdentifier } from '@exodus/keychain/module'

const keyId = new KeyIdentifier({
assetName: 'solana',
derivationAlgorithm: 'BIP32',
derivationPath: "m/44'/501'/0'/0/0",
keyType: 'nacl',
})
```

### Lock/Unlock the Keychain

Before you can perform keychain operations, you must unlock the keychain by providing it a `seed`. Calling `keychain.lock()` will lock the keychain again and remove the seed and any derived cryptographic material from its internal fields.

```js
const seed = mnemonicToSeed(
'menu memory fury language physical wonder dog valid smart edge decrease worth'
)

keychain.unlock({ seed })
```

### Sign a transaction

The function `keychain.signTx(...)` can sign transactions for you for a given key identifier.

```js
import {
signUnsignedTx as signSolanaTx,
createUnsignedTx as createUnsignedSolanaTx,
} from '@exodus/solana-lib'
import solanaAssets from '@exodus/solana-meta'
import { connectAssetsList } from '@exodus/assets'
import { mnemonicToSeed } from 'bip39'
import assert from 'minimalistic-assert'
import keychainDefinition, { KeyIdentifier } from '..'

const { solana: asset } = connectAssetsList(solanaAssets)

const unsignedTx = await createUnsignedSolanaTx({
asset,
from: 'nsn7DmCMsKWGUWcL92XfPKXFbUz7KtFDRa4nnkc3RiF',
to: '7SmaJ41gFZ1LPsZJfb57npzdCFuqBRmgj3CScjbmkQwA',
amount: asset.currency.SOL('5'),
fee: asset.currency.SOL('0.000005'),
recentBlockhash: '6yWbfvhoDrgzStVnvpRvib2Q1LpuTYc6TtdMPPofCPh8',
})

const signedTx = await keychain.signTx(
// Note: this is an array as some assets require multiple keys to sign a single transaction,
// e.g. bitcoin needs a keyId per UTXO
[keyId],
// in Exodus mobile/desktop/browser-extension clients, this is typically aggregated
// for all assets into a single delegator function
function signTx({ unsignedTx, hdkeys, privateKey }) {
assert(unsignedTx.txMeta.assetName === 'solana', `expected "solana" tx`)
return signSolanaTx(unsignedTx, privateKey)
},
unsignedTx
)

// signedTx.txId === 'Lj2iFo1MKx3cWTLH1GbvxZjCtNTMBmB2rXR5JV7EFQnPySyxKssAReBJF56e7XzXiAFeYdMCwFvyR3NkFVbh8rS'
```

### Encrypt/Decrypt Data

Note: the below follow libsodium terminology for `encryptSecretBox`/`encryptBox`/`encryptSealedBox`.

#### encryptSecretBox/decryptSecretBox

```js
const ALICE_KEY = new KeyIdentifier({
derivationAlgorithm: 'SLIP10',
derivationPath: `m/0'/2'/0'`,
keyType: 'nacl',
})

const sodiumEncryptor = await keychain.createSodiumEncryptor(ALICE_KEY)
const plaintext = 'I really love keychains'
const ciphertext = await sodiumEncryptor.encryptSecretBox({
data: plaintext,
})

const decrypted = await sodiumEncryptor.decryptSecretBox({
data: ciphertext,
})

// decrypted.toString() === plaintext
```

#### encryptBox/decryptBox

```js
const aliceSodiumEncryptor = await keychain.createSodiumEncryptor(ALICE_KEY)
const bobSodiumEncryptor = await keychain.createSodiumEncryptor(BOB_KEY)
const plaintext = 'I really love keychains'
const {
box: { publicKey: bobPublicKey },
} = await bobSodiumEncryptor.getSodiumKeysFromSeed()
const ciphertext = await aliceSodiumEncryptor.encryptBox({
data: plaintext,
toPublicKey: bobPublicKey,
})
const {
box: { publicKey: alicePublicKey },
} = await aliceSodiumEncryptor.getSodiumKeysFromSeed()

const decrypted = await bobSodiumEncryptor.decryptBox({
data: ciphertext,
fromPublicKey: alicePublicKey,
})

// decrypted.toString() === plaintext
```

#### encryptSealedBox/decryptSealedBox

```js
const aliceSodiumEncryptor = await keychain.createSodiumEncryptor(ALICE_KEY)
const bobSodiumEncryptor = await keychain.createSodiumEncryptor(BOB_KEY)
const plaintext = 'I really love keychains'
const {
box: { publicKey: bobPublicKey },
} = await bobSodiumEncryptor.getSodiumKeysFromSeed()

const ciphertext = await aliceSodiumEncryptor.encryptSealedBox({
data: plaintext,
toPublicKey: bobPublicKey,
})

const decrypted = await bobSodiumEncryptor.decryptSealedBox({
data: ciphertext,
})

// decrypted.toString() === plaintext
```

### Export A Key

Export public and/or private key material.

```js
// { xpub, publicKey }
const publicKey = await keychain.exportKey(keyId)
// { xpub, xpriv, publicKey, privateKey }
const privateKey = await keychain.exportKey(keyId, { exportPrivate: true })
```

### Clone the Keychain Instance

Clone the keychain, _minus any cryptographic material_. This is equivalent to re-invoking the keychain factory with the same parameters.

### secp256k1 signer

Sign a buffer using ECDSA with curve `secp256k1`.

```js
const keyId = new KeyIdentifier({
derivationAlgorithm: 'SLIP10',
derivationPath: `m/73'/2'/0'`,
keyType: 'nacl',
})

const signer = keychain.createSecp256k1Signer(keyId)
const plaintext = Buffer.from('I really love keychains')
const signature = await signer.signBuffer({ data: plaintext })
```

### ed25519 signer

Sign a buffer using EdDSA with curve `ed25519`.

```js
const keyId = new KeyIdentifier({
derivationAlgorithm: 'SLIP10',
derivationPath: `m/73'/2'/0'`,
keyType: 'nacl',
})

const signer = keychain.createEd25519Signer(keyId)
const plaintext = Buffer.from('I really love keychains')
const signature = await signer.signBuffer({ data: plaintext })
```
Loading
Loading