Version 1.3.3
* New feature: verify signatures with the public key * New feature: convert nano address to a public key * Add documentation about how to verify ownership of user's Nano address by doing a signature challenge * npm audit fix
This commit is contained in:
parent
1134d96e28
commit
51966303ec
10 changed files with 230 additions and 57 deletions
28
README.md
28
README.md
|
|
@ -174,6 +174,32 @@ const data = {
|
||||||
|
|
||||||
// Returns a correctly formatted and signed block ready to be sent to the blockchain
|
// Returns a correctly formatted and signed block ready to be sent to the blockchain
|
||||||
const signedBlock = block.representative(data, privateKey)
|
const signedBlock = block.representative(data, privateKey)
|
||||||
|
```
|
||||||
|
#### Verifying signatures
|
||||||
|
Cryptocurrencies rely on public key cryptographgy. This means that you can use the public key to validate the signature of the block that is signed with the private key.
|
||||||
|
```javascript
|
||||||
|
import { tools } from 'nanocurrency-web'
|
||||||
|
|
||||||
|
const valid = tools.verifyBlock(publicKey, block)
|
||||||
|
```
|
||||||
|
##### Using signature verification to prove ownership of the address
|
||||||
|
You are able to challenge an user to prove ownership of a Nano address simply by making the user sign any string with the private key and validating the signature.
|
||||||
|
```javascript
|
||||||
|
import { tools } from 'nanocurrency-web'
|
||||||
|
|
||||||
|
const nanoAddress = 'nano_1pu7p5n3ghq1i1p4rhmek41f5add1uh34xpb94nkbxe8g4a6x1p69emk8y1d'
|
||||||
|
const privateKey = '3be4fc2ef3f3b7374e6fc4fb6e7bb153f8a2998b3b3dab50853eabe128024143'
|
||||||
|
const data = 'sign this'
|
||||||
|
|
||||||
|
// Make the user sign the data
|
||||||
|
const signature = tools.sign(privateKey, data)
|
||||||
|
|
||||||
|
// Infer the user's public key from the address (if not already known)
|
||||||
|
const publicKey = tools.addressToPublicKey(nanoAddress)
|
||||||
|
|
||||||
|
// Verify the signature using the public key, the signature and the original data
|
||||||
|
const validSignature = tools.verify(publicKey, signature, data)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Converting units
|
#### Converting units
|
||||||
|
|
@ -217,7 +243,7 @@ const valid = tools.validateMnemonic('edge defense waste choose enrich upon flee
|
||||||
### In web
|
### In web
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="https://unpkg.com/nanocurrency-web@1.3.2" type="text/javascript"></script>
|
<script src="https://unpkg.com/nanocurrency-web@1.3.3" type="text/javascript"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
NanocurrencyWeb.wallet.generate(...);
|
NanocurrencyWeb.wallet.generate(...);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
54
index.ts
54
index.ts
|
|
@ -1,8 +1,10 @@
|
||||||
|
import { TextDecoder } from 'util'
|
||||||
|
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
|
|
||||||
import AddressGenerator from './lib/address-generator'
|
import AddressGenerator from './lib/address-generator'
|
||||||
import AddressImporter, { Account, Wallet } from './lib/address-importer'
|
import AddressImporter, { Account, Wallet } from './lib/address-importer'
|
||||||
import BlockSigner, { ReceiveBlock, RepresentativeBlock, SendBlock, SignedBlock } from './lib/block-signer'
|
import BlockSigner, { BlockData, ReceiveBlock, RepresentativeBlock, SendBlock, SignedBlock } from './lib/block-signer'
|
||||||
import NanoAddress from './lib/nano-address'
|
import NanoAddress from './lib/nano-address'
|
||||||
import NanoConverter from './lib/nano-converter'
|
import NanoConverter from './lib/nano-converter'
|
||||||
import Signer from './lib/signer'
|
import Signer from './lib/signer'
|
||||||
|
|
@ -127,7 +129,7 @@ const wallet = {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
fromLegacySeed: (seed: string): Wallet => {
|
fromLegacySeed: (seed: string): Wallet => {
|
||||||
return importer.fromLegacySeed(seed);
|
return importer.fromLegacySeed(seed)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -260,7 +262,36 @@ const tools = {
|
||||||
*/
|
*/
|
||||||
sign: (privateKey: string, ...input: string[]): string => {
|
sign: (privateKey: string, ...input: string[]): string => {
|
||||||
const data = input.map(Convert.stringToHex)
|
const data = input.map(Convert.stringToHex)
|
||||||
return signer.sign(privateKey, ...data);
|
return signer.sign(privateKey, ...data)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the signature of any input string
|
||||||
|
*
|
||||||
|
* @param {string} publicKey The public key to verify with
|
||||||
|
* @param {string} signature The signature to verify
|
||||||
|
* @param {...string} input Data to verify
|
||||||
|
*/
|
||||||
|
verify: (publicKey: string, signature: string, ...input: string[]): boolean => {
|
||||||
|
const data = input.map(Convert.stringToHex)
|
||||||
|
return signer.verify(publicKey, signature, ...data)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the signature of any input string
|
||||||
|
*
|
||||||
|
* @param {string} publicKey The public key to verify with
|
||||||
|
* @param {BlockData} block The block to verify
|
||||||
|
*/
|
||||||
|
verifyBlock: (publicKey: string, block: BlockData) => {
|
||||||
|
const preamble = 0x6.toString().padStart(64, '0')
|
||||||
|
return signer.verify(publicKey, block.signature,
|
||||||
|
preamble,
|
||||||
|
nanoAddress.nanoAddressToHexString(block.account),
|
||||||
|
block.previous,
|
||||||
|
nanoAddress.nanoAddressToHexString(block.representative),
|
||||||
|
Convert.dec2hex(block.balance, 16).toUpperCase(),
|
||||||
|
block.link)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -269,7 +300,7 @@ const tools = {
|
||||||
* @param {string} input The address to validate
|
* @param {string} input The address to validate
|
||||||
*/
|
*/
|
||||||
validateAddress: (input: string): boolean => {
|
validateAddress: (input: string): boolean => {
|
||||||
return nanoAddress.validateNanoAddress(input);
|
return nanoAddress.validateNanoAddress(input)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -278,7 +309,20 @@ const tools = {
|
||||||
* @param {string} input The address to validate
|
* @param {string} input The address to validate
|
||||||
*/
|
*/
|
||||||
validateMnemonic: (input: string): boolean => {
|
validateMnemonic: (input: string): boolean => {
|
||||||
return importer.validateMnemonic(input);
|
return importer.validateMnemonic(input)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Nano address to a public key
|
||||||
|
*
|
||||||
|
* @param {string} input Nano address to convert
|
||||||
|
*/
|
||||||
|
addressToPublicKey: (input: string): string => {
|
||||||
|
const cleaned = input
|
||||||
|
.replace('nano_', '')
|
||||||
|
.replace('xrb_', '')
|
||||||
|
const publicKeyBytes = nanoAddress.decodeNanoBase32(cleaned)
|
||||||
|
return Convert.ab2hex(publicKeyBytes).slice(0, 64)
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
import { enc, algo } from 'crypto-js'
|
import { algo, enc } from 'crypto-js'
|
||||||
|
|
||||||
import Convert from './util/convert'
|
import Convert from './util/convert'
|
||||||
|
|
||||||
const ED25519_CURVE = 'ed25519 seed'
|
const ED25519_CURVE = 'ed25519 seed'
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ export default class BlockSigner {
|
||||||
const newBalanceNano = new BigNumber(balanceNano).plus(new BigNumber(amountNano))
|
const newBalanceNano = new BigNumber(balanceNano).plus(new BigNumber(amountNano))
|
||||||
const newBalanceRaw = NanoConverter.convert(newBalanceNano, 'NANO', 'RAW')
|
const newBalanceRaw = NanoConverter.convert(newBalanceNano, 'NANO', 'RAW')
|
||||||
const newBalanceHex = Convert.dec2hex(newBalanceRaw, 16).toUpperCase()
|
const newBalanceHex = Convert.dec2hex(newBalanceRaw, 16).toUpperCase()
|
||||||
const account = this.nanoAddressToHexString(data.toAddress)
|
const account = this.nanoAddress.nanoAddressToHexString(data.toAddress)
|
||||||
const link = data.transactionHash
|
const link = data.transactionHash
|
||||||
const representative = this.nanoAddressToHexString(data.representativeAddress)
|
const representative = this.nanoAddress.nanoAddressToHexString(data.representativeAddress)
|
||||||
|
|
||||||
const signature = this.signer.sign(
|
const signature = this.signer.sign(
|
||||||
privateKey,
|
privateKey,
|
||||||
|
|
@ -125,9 +125,9 @@ export default class BlockSigner {
|
||||||
const newBalanceNano = new BigNumber(balanceNano).minus(new BigNumber(amountNano))
|
const newBalanceNano = new BigNumber(balanceNano).minus(new BigNumber(amountNano))
|
||||||
const newBalanceRaw = NanoConverter.convert(newBalanceNano, 'NANO', 'RAW')
|
const newBalanceRaw = NanoConverter.convert(newBalanceNano, 'NANO', 'RAW')
|
||||||
const newBalanceHex = Convert.dec2hex(newBalanceRaw, 16).toUpperCase()
|
const newBalanceHex = Convert.dec2hex(newBalanceRaw, 16).toUpperCase()
|
||||||
const account = this.nanoAddressToHexString(data.fromAddress)
|
const account = this.nanoAddress.nanoAddressToHexString(data.fromAddress)
|
||||||
const link = this.nanoAddressToHexString(data.toAddress)
|
const link = this.nanoAddress.nanoAddressToHexString(data.toAddress)
|
||||||
const representative = this.nanoAddressToHexString(data.representativeAddress)
|
const representative = this.nanoAddress.nanoAddressToHexString(data.representativeAddress)
|
||||||
|
|
||||||
const signature = this.signer.sign(
|
const signature = this.signer.sign(
|
||||||
privateKey,
|
privateKey,
|
||||||
|
|
@ -150,23 +150,6 @@ export default class BlockSigner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private nanoAddressToHexString(addr: string): string {
|
|
||||||
addr = addr.slice(-60)
|
|
||||||
const isValid = /^[13456789abcdefghijkmnopqrstuwxyz]+$/.test(addr)
|
|
||||||
if (isValid) {
|
|
||||||
const keyBytes = this.nanoAddress.decodeNanoBase32(addr.substring(0, 52))
|
|
||||||
const hashBytes = this.nanoAddress.decodeNanoBase32(addr.substring(52, 60))
|
|
||||||
const blakeHash = blake2b(keyBytes, undefined, 5).reverse()
|
|
||||||
if (Convert.ab2hex(hashBytes) == Convert.ab2hex(blakeHash)) {
|
|
||||||
const key = Convert.ab2hex(keyBytes).toUpperCase()
|
|
||||||
return key
|
|
||||||
}
|
|
||||||
throw new Error('Checksum mismatch in address')
|
|
||||||
} else {
|
|
||||||
throw new Error('Illegal characters in address')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReceiveBlock {
|
export interface ReceiveBlock {
|
||||||
|
|
@ -197,13 +180,16 @@ export interface RepresentativeBlock {
|
||||||
work?: string
|
work?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SignedBlock {
|
export interface SignedBlock extends BlockData {
|
||||||
type: 'state'
|
type: 'state'
|
||||||
|
work?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BlockData {
|
||||||
account: string
|
account: string
|
||||||
previous: string
|
previous: string
|
||||||
representative: string
|
representative: string
|
||||||
balance: string
|
balance: string
|
||||||
link: string
|
link: string
|
||||||
signature: string
|
signature: string
|
||||||
work: string
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
//@ts-ignore
|
||||||
|
import { blake2b, blake2bFinal, blake2bInit, blake2bUpdate } from 'blakejs'
|
||||||
|
|
||||||
import Convert from './util/convert'
|
import Convert from './util/convert'
|
||||||
import Curve25519 from './util/curve25519'
|
import Curve25519 from './util/curve25519'
|
||||||
|
import Util from './util/util'
|
||||||
//@ts-ignore
|
|
||||||
import { blake2b } from 'blakejs'
|
|
||||||
|
|
||||||
export default class Ed25519 {
|
export default class Ed25519 {
|
||||||
|
|
||||||
|
|
@ -120,11 +121,11 @@ export default class Ed25519 {
|
||||||
/**
|
/**
|
||||||
* Generate a message signature
|
* Generate a message signature
|
||||||
* @param {Uint8Array} msg Message to be signed as byte array
|
* @param {Uint8Array} msg Message to be signed as byte array
|
||||||
* @param {Uint8Array} secretKey Secret key as byte array
|
* @param {Uint8Array} privateKey Secret key as byte array
|
||||||
* @param {Uint8Array} Returns the signature as 64 byte typed array
|
* @param {Uint8Array} Returns the signature as 64 byte typed array
|
||||||
*/
|
*/
|
||||||
sign(msg: Uint8Array, secretKey: Uint8Array): Uint8Array {
|
sign(msg: Uint8Array, privateKey: Uint8Array): Uint8Array {
|
||||||
const signedMsg = this.naclSign(msg, secretKey)
|
const signedMsg = this.naclSign(msg, privateKey)
|
||||||
const sig = new Uint8Array(64)
|
const sig = new Uint8Array(64)
|
||||||
|
|
||||||
for (let i = 0; i < sig.length; i++) {
|
for (let i = 0; i < sig.length; i++) {
|
||||||
|
|
@ -134,6 +135,44 @@ export default class Ed25519 {
|
||||||
return sig
|
return sig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a message signature
|
||||||
|
* @param {Uint8Array} msg Message to be signed as byte array
|
||||||
|
* @param {Uint8Array} publicKey Public key as byte array
|
||||||
|
* @param {Uint8Array} signature Signature as byte array
|
||||||
|
* @param {Uint8Array} Returns the signature as 64 byte typed array
|
||||||
|
*/
|
||||||
|
verify(msg: Uint8Array, publicKey: Uint8Array, signature: Uint8Array): boolean {
|
||||||
|
const CURVE = this.curve;
|
||||||
|
const p = [CURVE.gf(), CURVE.gf(), CURVE.gf(), CURVE.gf()]
|
||||||
|
const q = [CURVE.gf(), CURVE.gf(), CURVE.gf(), CURVE.gf()]
|
||||||
|
|
||||||
|
if (signature.length !== 64) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (publicKey.length !== 32) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (CURVE.unpackNeg(q, publicKey)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = blake2bInit(64, undefined)
|
||||||
|
blake2bUpdate(ctx, signature.subarray(0, 32))
|
||||||
|
blake2bUpdate(ctx, publicKey)
|
||||||
|
blake2bUpdate(ctx, msg)
|
||||||
|
let k = blake2bFinal(ctx)
|
||||||
|
this.reduce(k)
|
||||||
|
this.scalarmult(p, q, k)
|
||||||
|
|
||||||
|
let t = new Uint8Array(32)
|
||||||
|
this.scalarbase(q, signature.subarray(32))
|
||||||
|
CURVE.add(p, q)
|
||||||
|
this.pack(t, p)
|
||||||
|
|
||||||
|
return Util.compare(signature.subarray(0, 32), t)
|
||||||
|
}
|
||||||
|
|
||||||
private naclSign(msg: Uint8Array, secretKey: Uint8Array): Uint8Array {
|
private naclSign(msg: Uint8Array, secretKey: Uint8Array): Uint8Array {
|
||||||
if (secretKey.length !== 32) {
|
if (secretKey.length !== 32) {
|
||||||
throw new Error('bad secret key size')
|
throw new Error('bad secret key size')
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,24 @@ export default class NanoAddress {
|
||||||
return expectedChecksum === actualChecksum
|
return expectedChecksum === actualChecksum
|
||||||
}
|
}
|
||||||
|
|
||||||
readChar(char: string): number {
|
nanoAddressToHexString = (addr: string): string => {
|
||||||
|
addr = addr.slice(-60)
|
||||||
|
const isValid = /^[13456789abcdefghijkmnopqrstuwxyz]+$/.test(addr)
|
||||||
|
if (isValid) {
|
||||||
|
const keyBytes = this.decodeNanoBase32(addr.substring(0, 52))
|
||||||
|
const hashBytes = this.decodeNanoBase32(addr.substring(52, 60))
|
||||||
|
const blakeHash = blake2b(keyBytes, undefined, 5).reverse()
|
||||||
|
if (Convert.ab2hex(hashBytes) == Convert.ab2hex(blakeHash)) {
|
||||||
|
const key = Convert.ab2hex(keyBytes).toUpperCase()
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
throw new Error('Checksum mismatch in address')
|
||||||
|
} else {
|
||||||
|
throw new Error('Illegal characters in address')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readChar(char: string): number {
|
||||||
const idx = this.alphabet.indexOf(char)
|
const idx = this.alphabet.indexOf(char)
|
||||||
|
|
||||||
if (idx === -1) {
|
if (idx === -1) {
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
import Convert from './util/convert'
|
|
||||||
import Ed25519 from './ed25519'
|
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
import { blake2bInit, blake2bUpdate, blake2bFinal } from 'blakejs'
|
|
||||||
|
import { blake2bFinal, blake2bInit, blake2bUpdate } from 'blakejs'
|
||||||
|
|
||||||
|
import Ed25519 from './ed25519'
|
||||||
|
import Convert from './util/convert'
|
||||||
|
|
||||||
export default class Signer {
|
export default class Signer {
|
||||||
|
|
||||||
ed25519 = new Ed25519()
|
ed25519 = new Ed25519()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs any data using the ed25519 signature system
|
* Signs any data using the ed25519 signature system
|
||||||
*
|
*
|
||||||
* @param privateKey Private key to sign the data with
|
* @param privateKey Private key to sign the data with
|
||||||
* @param data Data to sign
|
* @param data Data to sign
|
||||||
*/
|
*/
|
||||||
|
|
@ -21,9 +22,23 @@ export default class Signer {
|
||||||
return Convert.ab2hex(signature)
|
return Convert.ab2hex(signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the signature with a public key
|
||||||
|
*
|
||||||
|
* @param publicKey Public key to verify the data with
|
||||||
|
* @param signature Signature to verify
|
||||||
|
* @param data Data to verify
|
||||||
|
*/
|
||||||
|
verify(publicKey: string, signature: string, ...data: string[]): boolean {
|
||||||
|
return this.ed25519.verify(
|
||||||
|
this.generateHash(data),
|
||||||
|
Convert.hex2ab(publicKey),
|
||||||
|
Convert.hex2ab(signature));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a blake2b hash of the input data
|
* Creates a blake2b hash of the input data
|
||||||
*
|
*
|
||||||
* @param data Data to hash
|
* @param data Data to hash
|
||||||
*/
|
*/
|
||||||
generateHash(data: string[]): Uint8Array {
|
generateHash(data: string[]): Uint8Array {
|
||||||
|
|
|
||||||
14
package-lock.json
generated
14
package-lock.json
generated
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "nanocurrency-web",
|
"name": "nanocurrency-web",
|
||||||
"version": "1.3.2",
|
"version": "1.3.3",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -2247,9 +2247,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.20",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"log-symbols": {
|
"log-symbols": {
|
||||||
|
|
@ -3463,9 +3463,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ssri": {
|
"ssri": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
|
||||||
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
|
"integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"figgy-pudding": "^3.5.1"
|
"figgy-pudding": "^3.5.1"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "nanocurrency-web",
|
"name": "nanocurrency-web",
|
||||||
"version": "1.3.2",
|
"version": "1.3.3",
|
||||||
"description": "Toolkit for Nano cryptocurrency client side offline integrations",
|
"description": "Toolkit for Nano cryptocurrency client side offline integrations",
|
||||||
"author": "Miro Metsänheimo <miro@metsanheimo.fi>",
|
"author": "Miro Metsänheimo <miro@metsanheimo.fi>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
||||||
53
test/test.js
53
test/test.js
|
|
@ -256,14 +256,59 @@ describe('unit conversion tests', () => {
|
||||||
|
|
||||||
describe('Signer tests', () => {
|
describe('Signer tests', () => {
|
||||||
|
|
||||||
|
let testWallet;
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
this.testWallet = wallet.generate();
|
||||||
|
})
|
||||||
|
|
||||||
|
// Private key: 3be4fc2ef3f3b7374e6fc4fb6e7bb153f8a2998b3b3dab50853eabe128024143
|
||||||
|
// Public key: 5b65b0e8173ee0802c2c3e6c9080d1a16b06de1176c938a924f58670904e82c4
|
||||||
|
|
||||||
it('should sign data with a single parameter', () => {
|
it('should sign data with a single parameter', () => {
|
||||||
const result = tools.sign('781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3', 'miro@metsanheimo.fi')
|
const result = tools.sign('3be4fc2ef3f3b7374e6fc4fb6e7bb153f8a2998b3b3dab50853eabe128024143', 'miro@metsanheimo.fi')
|
||||||
expect(result).to.equal('0ede9f287b7d58a053aa9ad84419c856ac39ec4c2453098ef19abf9638b07b1993e0cd3747723aada71602e92e781060dc3b91c410d32def1b4780a62fd0eb02')
|
expect(result).to.equal('fecb9b084065adc969904b55a0099c63746b68df41fecb713244d387eed83a80b9d4907278c5ebc0998a5fc8ba597fbaaabbfce0abd2ca2212acfe788637040c')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should sign data with multiple parameters', () => {
|
it('should sign data with multiple parameters', () => {
|
||||||
const result = tools.sign('781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3', 'miro@metsanheimo.fi', 'somePassword')
|
const result = tools.sign('3be4fc2ef3f3b7374e6fc4fb6e7bb153f8a2998b3b3dab50853eabe128024143', 'miro@metsanheimo.fi', 'somePassword')
|
||||||
expect(result).to.equal('a7b88357a160f54cf4db2826c86483eb60e66e8ccb36f9a37f3fb636c9d80f7b59d1fba88d0be27f85ac3fcbe5c6e13f911d7e5b713e86fb8e9a635932a2af05')
|
expect(result).to.equal('bb534f9b469af451b1941ffef8ee461fc5d284b5d393140900c6e13a65ef08d0ae2bc77131ee182922f66c250c7237a83878160457d5c39a70e55f7fce925804')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should verify a signature using the public key', () => {
|
||||||
|
const result = tools.verify('5b65b0e8173ee0802c2c3e6c9080d1a16b06de1176c938a924f58670904e82c4', 'fecb9b084065adc969904b55a0099c63746b68df41fecb713244d387eed83a80b9d4907278c5ebc0998a5fc8ba597fbaaabbfce0abd2ca2212acfe788637040c', 'miro@metsanheimo.fi')
|
||||||
|
expect(result).to.be.true
|
||||||
|
|
||||||
|
const result2 = tools.verify('5b65b0e8173ee0802c2c3e6c9080d1a16b06de1176c938a924f58670904e82c4', 'fecb9b084065adc969904b55a0099c63746b68df41fecb713244d387eed83a80b9d4907278c5ebc0998a5fc8ba597fbaaabbfce0abd2ca2212acfe788637040c', 'mir@metsanheimo.fi')
|
||||||
|
expect(result2).to.be.false
|
||||||
|
|
||||||
|
const result3 = tools.verify('5b65b0e8173ee0802c2c3e6c9080d1a16b06de1176c938a924f58670904e82c4', 'aecb9b084065adc969904b55a0099c63746b68df41fecb713244d387eed83a80b9d4907278c5ebc0998a5fc8ba597fbaaabbfce0abd2ca2212acfe788637040c', 'miro@metsanheimo.fi')
|
||||||
|
expect(result3).to.be.false
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should verify a block using the public key', () => {
|
||||||
|
const sendBlock = block.send({
|
||||||
|
walletBalanceRaw: '5618869000000000000000000000000',
|
||||||
|
fromAddress: this.testWallet.accounts[0].address,
|
||||||
|
toAddress: 'nano_1q3hqecaw15cjt7thbtxu3pbzr1eihtzzpzxguoc37bj1wc5ffoh7w74gi6p',
|
||||||
|
representativeAddress: 'nano_1stofnrxuz3cai7ze75o174bpm7scwj9jn3nxsn8ntzg784jf1gzn1jjdkou',
|
||||||
|
frontier: '92BA74A7D6DC7557F3EDA95ADC6341D51AC777A0A6FF0688A5C492AB2B2CB40D',
|
||||||
|
amountRaw: '2000000000000000000000000000000',
|
||||||
|
}, this.testWallet.accounts[0].privateKey)
|
||||||
|
|
||||||
|
const publicKey = tools.addressToPublicKey(this.testWallet.accounts[0].address)
|
||||||
|
|
||||||
|
const valid = tools.verifyBlock(publicKey, sendBlock)
|
||||||
|
expect(valid).to.be.true
|
||||||
|
|
||||||
|
sendBlock.account = 'nano_1q3hqecaw15cjt7thbtxu3pbzr1eihtzzpzxguoc37bj1wc5ffoh7w74gi6p'
|
||||||
|
const valid2 = tools.verifyBlock(this.testWallet.accounts[0].publicKey, sendBlock)
|
||||||
|
expect(valid2).to.be.false
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should convert a Nano address to public key', () => {
|
||||||
|
const publicKey = tools.addressToPublicKey('nano_1pu7p5n3ghq1i1p4rhmek41f5add1uh34xpb94nkbxe8g4a6x1p69emk8y1d')
|
||||||
|
expect(publicKey).to.equal('5b65b0e8173ee0802c2c3e6c9080d1a16b06de1176c938a924f58670904e82c4')
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue