Skip to content

Commit

Permalink
Merge pull request #13 from numsu/encryption
Browse files Browse the repository at this point in the history
Version 1.4.0
  • Loading branch information
numsu authored Apr 24, 2022
2 parents cd50b77 + 7f5cdc3 commit 6fefc48
Show file tree
Hide file tree
Showing 18 changed files with 1,138 additions and 265 deletions.
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ npm install nanocurrency-web
### In web

```html
<script src="https://unpkg.com/nanocurrency-web@1.3.6" type="text/javascript"></script>
<script src="https://unpkg.com/nanocurrency-web@1.4.0" type="text/javascript"></script>
<script type="text/javascript">
NanocurrencyWeb.wallet.generate(...);
</script>
Expand Down Expand Up @@ -114,7 +114,7 @@ If the account hasn't been opened yet (this is the first block), you will need t
```javascript
import { block } from 'nanocurrency-web'

const privateKey = '781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3';
const privateKey = '781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3'
const data = {
// Current balance from account info
walletBalanceRaw: '5618869000000000000000000000000',
Expand Down Expand Up @@ -147,7 +147,7 @@ const signedBlock = block.send(data, privateKey)
```javascript
import { block } from 'nanocurrency-web'

const privateKey = '781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3';
const privateKey = '781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3'
const data = {
// Your current balance in RAW from account info
walletBalanceRaw: '18618869000000000000000000000000',
Expand Down Expand Up @@ -180,7 +180,7 @@ const signedBlock = block.receive(data, privateKey)
```javascript
import { block } from 'nanocurrency-web'

const privateKey = '781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3';
const privateKey = '781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3'
const data = {
// Your current balance, from account info
walletBalanceRaw: '3000000000000000000000000000000',
Expand Down Expand Up @@ -270,6 +270,19 @@ const valid = tools.validateAddress('nano_1pu7p5n3ghq1i1p4rhmek41f5add1uh34xpb94
const valid = tools.validateMnemonic('edge defense waste choose enrich upon flee junk siren film clown finish luggage leader kid quick brick print evidence swap drill paddle truly occur')
```
#### Encrypting and decrypting strings
You are able to encrypt and decrypt strings to implement end-to-end encryption using the Diffie-Hellman key exchange by using the Nano address and private key. The public and private keys are converted to Curve25519 keys which are suitable for encryption within the library.
```javascript
import { box } from 'nanocurrency-web'

// Encrypt on device 1
const encrypted = box.encrypt(message, recipientAddress, senderPrivateKey)

// Send the encrypted message to the recipient and decrypt on device 2
const decrypted = box.decrypt(encrypted, senderAddress, recipientPrivateKey)
```
## Contributions
You are welcome to contribute to the module. To develop, use the following commands.
Expand Down
95 changes: 63 additions & 32 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ import BigNumber from 'bignumber.js'
import AddressGenerator from './lib/address-generator'
import AddressImporter, { Account, Wallet } from './lib/address-importer'
import BlockSigner, { BlockData, ReceiveBlock, RepresentativeBlock, SendBlock, SignedBlock } from './lib/block-signer'
import Box from './lib/box'
import NanoAddress from './lib/nano-address'
import NanoConverter from './lib/nano-converter'
import Signer from './lib/signer'
import Convert from './lib/util/convert'

const nanoAddress = new NanoAddress()
const generator = new AddressGenerator()
const importer = new AddressImporter()
const signer = new Signer()

const wallet = {

/**
Expand All @@ -38,7 +34,7 @@ const wallet = {
* @returns {Wallet} The wallet
*/
generate: (entropy?: string, seedPassword?: string): Wallet => {
return generator.generateWallet(entropy, seedPassword)
return AddressGenerator.generateWallet(entropy, seedPassword)
},

/**
Expand All @@ -57,7 +53,7 @@ const wallet = {
* @returns {Wallet} The wallet
*/
generateLegacy: (seed?: string): Wallet => {
return generator.generateLegacyWallet(seed)
return AddressGenerator.generateLegacyWallet(seed)
},

/**
Expand All @@ -76,7 +72,7 @@ const wallet = {
* @returns {Wallet} The wallet
*/
fromMnemonic: (mnemonic: string, seedPassword?: string): Wallet => {
return importer.fromMnemonic(mnemonic, seedPassword)
return AddressImporter.fromMnemonic(mnemonic, seedPassword)
},

/**
Expand All @@ -93,7 +89,7 @@ const wallet = {
* @returns {Wallet} The wallet
*/
fromLegacyMnemonic: (mnemonic: string): Wallet => {
return importer.fromLegacyMnemonic(mnemonic)
return AddressImporter.fromLegacyMnemonic(mnemonic)
},

/**
Expand All @@ -110,7 +106,7 @@ const wallet = {
* @returns {Wallet} The wallet, without the mnemonic phrase because it's not possible to infer backwards
*/
fromSeed: (seed: string): Wallet => {
return importer.fromSeed(seed)
return AddressImporter.fromSeed(seed)
},

/**
Expand All @@ -127,7 +123,7 @@ const wallet = {
* @returns {Wallet} The wallet
*/
fromLegacySeed: (seed: string): Wallet => {
return importer.fromLegacySeed(seed)
return AddressImporter.fromLegacySeed(seed)
},

/**
Expand All @@ -143,7 +139,7 @@ const wallet = {
* @returns {Account[]} a list of accounts
*/
accounts: (seed: string, from: number, to: number): Account[] => {
return importer.fromSeed(seed, from, to).accounts
return AddressImporter.fromSeed(seed, from, to).accounts
},

/**
Expand All @@ -158,12 +154,11 @@ const wallet = {
* @returns {Account[]} a list of accounts
*/
legacyAccounts: (seed: string, from: number, to: number): Account[] => {
return importer.fromLegacySeed(seed, from, to).accounts
return AddressImporter.fromLegacySeed(seed, from, to).accounts
},

}

const blockSigner = new BlockSigner()
const block = {

/**
Expand All @@ -185,7 +180,7 @@ const block = {
* @returns {SignedBlock} the signed block
*/
send: (data: SendBlock, privateKey: string): SignedBlock => {
return blockSigner.send(data, privateKey)
return BlockSigner.send(data, privateKey)
},


Expand All @@ -208,7 +203,7 @@ const block = {
* @returns {SignedBlock} the signed block
*/
receive: (data: ReceiveBlock, privateKey: string): SignedBlock => {
return blockSigner.receive(data, privateKey)
return BlockSigner.receive(data, privateKey)
},


Expand Down Expand Up @@ -236,7 +231,7 @@ const block = {
toAddress: 'nano_1111111111111111111111111111111111111111111111111111hifc8npp', // Burn address
}

return blockSigner.send(block, privateKey)
return BlockSigner.send(block, privateKey)
},

}
Expand Down Expand Up @@ -266,7 +261,7 @@ const tools = {
*/
sign: (privateKey: string, ...input: string[]): string => {
const data = input.map(Convert.stringToHex)
return signer.sign(privateKey, ...data)
return Signer.sign(privateKey, ...data)
},

/**
Expand All @@ -279,7 +274,7 @@ const tools = {
*/
verify: (publicKey: string, signature: string, ...input: string[]): boolean => {
const data = input.map(Convert.stringToHex)
return signer.verify(publicKey, signature, ...data)
return Signer.verify(publicKey, signature, ...data)
},

/**
Expand All @@ -291,11 +286,11 @@ const tools = {
*/
verifyBlock: (publicKey: string, block: BlockData): boolean => {
const preamble = 0x6.toString().padStart(64, '0')
return signer.verify(publicKey, block.signature,
return Signer.verify(publicKey, block.signature,
preamble,
nanoAddress.nanoAddressToHexString(block.account),
NanoAddress.nanoAddressToHexString(block.account),
block.previous,
nanoAddress.nanoAddressToHexString(block.representative),
NanoAddress.nanoAddressToHexString(block.representative),
Convert.dec2hex(block.balance, 16).toUpperCase(),
block.link)
},
Expand All @@ -307,7 +302,7 @@ const tools = {
* @returns {boolean} valid or not
*/
validateAddress: (input: string): boolean => {
return nanoAddress.validateNanoAddress(input)
return NanoAddress.validateNanoAddress(input)
},

/**
Expand All @@ -317,7 +312,7 @@ const tools = {
* @returns {boolean} valid or not
*/
validateMnemonic: (input: string): boolean => {
return importer.validateMnemonic(input)
return AddressImporter.validateMnemonic(input)
},

/**
Expand All @@ -327,11 +322,7 @@ const tools = {
* @returns {string} the public key
*/
addressToPublicKey: (input: string): string => {
const cleaned = input
.replace('nano_', '')
.replace('xrb_', '')
const publicKeyBytes = nanoAddress.decodeNanoBase32(cleaned)
return Convert.ab2hex(publicKeyBytes).slice(0, 64)
return NanoAddress.addressToPublicKey(input)
},

/**
Expand All @@ -341,7 +332,7 @@ const tools = {
* @returns {string} the nano address
*/
publicKeyToAddress: (input: string): string => {
return nanoAddress.deriveAddress(input)
return NanoAddress.deriveAddress(input)
},

/**
Expand All @@ -352,16 +343,56 @@ const tools = {
*/
blake2b: (input: string | string[]): string => {
if (Array.isArray(input)) {
return Convert.ab2hex(signer.generateHash(input.map(Convert.stringToHex)))
return Convert.ab2hex(Signer.generateHash(input.map(Convert.stringToHex)))
} else {
return Convert.ab2hex(signer.generateHash([Convert.stringToHex(input)]))
return Convert.ab2hex(Signer.generateHash([Convert.stringToHex(input)]))
}
},

}

const box = {

/**
* Encrypt a message using a Nano address private key for
* end-to-end encrypted messaging.
*
* Encrypts the message using the recipient's public key,
* the sender's private key and a random nonce generated
* inside the library. The message can be opened with the
* recipient's private key and the sender's public key by
* using the decrypt method.
*
* @param {string} message string to encrypt
* @param {string} address nano address of the recipient
* @param {string} privateKey private key of the sender
* @returns {string} encrypted message encoded in Base64
*/
encrypt: (message: string, address: string, privateKey: string): string => {
return Box.encrypt(message, address, privateKey)
},

/**
* Decrypt a message using a Nano address private key.
*
* Decrypts the message by using the sender's public key,
* the recipient's private key and the nonce which is included
* in the encrypted message.
*
* @param {string} encrypted string to decrypt
* @param {string} address nano address of the sender
* @param {string} privateKey private key of the recipient
* @returns {string} decrypted message encoded in UTF-8
*/
decrypt: (encrypted: string, address: string, privateKey: string): string => {
return Box.decrypt(encrypted, address, privateKey)
}

}

export {
wallet,
block,
tools,
box,
}
18 changes: 6 additions & 12 deletions lib/address-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ export default class AddressGenerator {
* @param {string} [entropy] - (Optional) Custom entropy if the caller doesn't want a default generated entropy
* @param {string} [seedPassword] - (Optional) Password for the seed
*/
generateWallet(entropy = '', seedPassword: string = ''): Wallet {
const bip39 = new Bip39Mnemonic(seedPassword)
const mnemonicSeed = bip39.createWallet(entropy)
const wallet = new AddressImporter().fromSeed(mnemonicSeed.seed, 0, 0)

static generateWallet = (entropy = '', seedPassword: string = ''): Wallet => {
const mnemonicSeed = Bip39Mnemonic.createWallet(entropy, seedPassword)
const wallet = AddressImporter.fromSeed(mnemonicSeed.seed, 0, 0)
return {
...wallet,
mnemonic: mnemonicSeed.mnemonic,
Expand All @@ -22,14 +20,10 @@ export default class AddressGenerator {

/**
* Generates a legacy Nano wallet
*
*/
generateLegacyWallet(seed?: string): Wallet {
const bip39 = new Bip39Mnemonic()
const mnemonicSeed = bip39.createLegacyWallet(seed)
const wallet = new AddressImporter().fromLegacySeed(mnemonicSeed.seed, 0, 0, mnemonicSeed.mnemonic)

return wallet
static generateLegacyWallet = (seed?: string): Wallet => {
const mnemonicSeed = Bip39Mnemonic.createLegacyWallet(seed)
return AddressImporter.fromLegacySeed(mnemonicSeed.seed, 0, 0, mnemonicSeed.mnemonic)
}

}
Loading

0 comments on commit 6fefc48

Please sign in to comment.