Skip to content

Commit

Permalink
feat: implement checksum verification on checkAddress
Browse files Browse the repository at this point in the history
  • Loading branch information
marvinroger committed Mar 26, 2018
1 parent 35e0099 commit 84c66e6
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 98 deletions.
13 changes: 3 additions & 10 deletions __tests__/common/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ const INVALID_SEEDS = [
'z947ee0115014a4d49a804e7fc7248e31690b80033ce7a6e3a07bdf93b2584ff'
]

const INVALID_INDEXES = [
'0',
-1,
1.1
]
const INVALID_INDEXES = ['0', -1, 1.1]

const INVALID_SECRET_KEYS = [
12,
Expand All @@ -28,14 +24,11 @@ const INVALID_HASHES = [
'zf7122e843b27524f4f1d6bd14aefd1c8f01d36ae8653d37417533c0d4bc2be6'
]

const INVALID_WORKS = [
12,
'000000000995bc3',
'z000000000995bc3'
]
const INVALID_WORKS = [12, '000000000995bc3', 'z000000000995bc3']

const INVALID_ADDRESSES = [
12,
'xrb_1mbj7xi6yrwcuwetzd5535pdqjea5rfpsoqo9nw4gxg8itycgntucp49i1n4', // bad checksum
'zrb_1mbj7xi6yrwcuwetzd5535pdqjea5rfpsoqo9nw4gxg8itycgntucp49i1nz',
'xrb_2mbj7xi6yrwcuwetzd5535pdqjea5rfpsoqo9nw4gxg8itycgntucp49i1nz',
'xrb_1mbj7xi6yrwcuwetzd5535pdqjea5rfpsoqo9nw4gxg8itycgntucp49i1n',
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@
},
"bugs": "https://github.com/marvinroger/nanocurrency-js/issues",
"dependencies": {
"base32-decode": "^1.0.0",
"base32-encode": "^1.0.0",
"bignumber.js": "^6.0.0",
"blakejs": "^1.1.0"
"blakejs": "^1.1.0",
"nano-base32": "^1.0.0"
},
"devDependencies": {
"cross-env": "^5.1.3",
Expand Down
16 changes: 15 additions & 1 deletion src/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
* Copyright (c) 2018 Marvin ROGER <dev at marvinroger dot fr>
* Licensed under GPL-3.0 (https://git.io/vAZsK)
*/
import { blake2b } from 'blakejs'
import nanoBase32 from 'nano-base32'

import { compareArrays } from './utils'

export function checkString (candidate) {
return typeof candidate === 'string'
}
Expand Down Expand Up @@ -79,7 +84,16 @@ export function checkKey (key) {
* @return {boolean} Valid
*/
export function checkAddress (address) {
return checkString(address) && /xrb_[13][0-9a-km-uw-z]{59}/.test(address)
if (!checkString(address) || !/xrb_[13][0-9a-km-uw-z]{59}/.test(address)) {
return false
}

const publicKeyBytes = nanoBase32.decode(address.substr(4, 52))
const checksumBytes = nanoBase32.decode(address.substr(56, 8))

const computedChecksumBytes = blake2b(publicKeyBytes, null, 5).reverse()

return compareArrays(checksumBytes, computedChecksumBytes)
}

/**
Expand Down
28 changes: 10 additions & 18 deletions src/keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,11 @@
* Licensed under GPL-3.0 (https://git.io/vAZsK)
*/
import { blake2b, blake2bInit, blake2bUpdate, blake2bFinal } from 'blakejs'
import nanoBase32 from 'nano-base32'

import { checkSeed, checkKey, checkAddress } from './check'
import { derivePublicFromSecret } from './nacl'
import {
getRandomBytes,
hexToByteArray,
byteArrayToHex,
byteArrayToBase32,
base32ToByteArray
} from './utils'
import { getRandomBytes, hexToByteArray, byteArrayToHex } from './utils'

/**
* Generate a cryptographically secure seed.
Expand Down Expand Up @@ -77,18 +72,15 @@ export function derivePublicKey (secretKeyOrAddress) {
throw new Error('Secret key or address is not valid')
}

let publicKeyBytes
if (isSecretKey) {
const secretKeyBytes = hexToByteArray(secretKeyOrAddress)
const publicKeyBytes = derivePublicFromSecret(secretKeyBytes)

return byteArrayToHex(publicKeyBytes)
publicKeyBytes = derivePublicFromSecret(secretKeyBytes)
} else if (isAddress) {
const publicKeyPart = secretKeyOrAddress.substr(4, 52) + '1'
const paddedPublicKeyBytes = base32ToByteArray(publicKeyPart)
const publicKeyHex = byteArrayToHex(paddedPublicKeyBytes).substr(1, 64)

return publicKeyHex
publicKeyBytes = nanoBase32.decode(secretKeyOrAddress.substr(4, 52))
}

return byteArrayToHex(publicKeyBytes)
}

/**
Expand All @@ -102,13 +94,13 @@ export function deriveAddress (publicKey) {
if (!checkKey(publicKey)) throw new Error('Public key is not valid')

const publicKeyBytes = hexToByteArray(publicKey)
const paddedPublicKeyBytes = hexToByteArray('0' + publicKey + '0')
const paddedPublicKeyBytes = hexToByteArray(publicKey)

const encodedPublicKey = byteArrayToBase32(paddedPublicKeyBytes).slice(0, -1)
const encodedPublicKey = nanoBase32.encode(paddedPublicKeyBytes)

const checksum = blake2b(publicKeyBytes, null, 5).reverse()

const encodedChecksum = byteArrayToBase32(checksum)
const encodedChecksum = nanoBase32.encode(checksum)

return 'xrb_' + encodedPublicKey + encodedChecksum
}
66 changes: 8 additions & 58 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
* Copyright (c) 2018 Marvin ROGER <dev at marvinroger dot fr>
* Licensed under GPL-3.0 (https://git.io/vAZsK)
*/
import base32Encode from 'base32-encode'
import base32Decode from 'base32-decode'

const IS_NODE =
Object.prototype.toString.call(
typeof process !== 'undefined' ? process : 0
Expand Down Expand Up @@ -35,61 +32,6 @@ export function getRandomBytes (count) {
})
}

const BASE32_MAPPING = {
A: '1',
B: '3',
C: '4',
D: '5',
E: '6',
F: '7',
G: '8',
H: '9',
I: 'a',
J: 'b',
K: 'c',
L: 'd',
M: 'e',
N: 'f',
O: 'g',
P: 'h',
Q: 'i',
R: 'j',
S: 'k',
T: 'm',
U: 'n',
V: 'o',
W: 'p',
X: 'q',
Y: 'r',
Z: 's',
2: 't',
3: 'u',
4: 'w',
5: 'x',
6: 'y',
7: 'z'
}

export function byteArrayToBase32 (byteArray) {
return base32Encode(byteArray, 'RFC4648')
.split('')
.map(c => BASE32_MAPPING[c])
.join('')
}

export function base32ToByteArray (base32) {
const mapped = base32
.split('')
.map(c =>
Object.keys(BASE32_MAPPING).find(key => BASE32_MAPPING[key] === c)
)
.join('')

const decoded = base32Decode(mapped, 'RFC4648')

return new Uint8Array(decoded)
}

export function byteArrayToHex (byteArray) {
if (!byteArray) {
return ''
Expand Down Expand Up @@ -117,3 +59,11 @@ export function hexToByteArray (hex) {

return new Uint8Array(a)
}

export function compareArrays (array1, array2) {
for (let i = 0; i < array1.length; i++) {
if (array1[i] !== array2[i]) return false
}

return true
}
12 changes: 4 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1073,14 +1073,6 @@ balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"

base32-decode@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/base32-decode/-/base32-decode-1.0.0.tgz#2a821d6a664890c872f20aa9aca95a4b4b80e2a7"

base32-encode@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/base32-encode/-/base32-encode-1.0.0.tgz#8fda8e42ab5e213e8ec30e5c440a26ae0507eb03"

base@^0.11.1:
version "0.11.2"
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
Expand Down Expand Up @@ -4164,6 +4156,10 @@ nan@^2.3.0:
version "2.9.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.9.2.tgz#f564d75f5f8f36a6d9456cca7a6c4fe488ab7866"

nano-base32@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/nano-base32/-/nano-base32-1.0.0.tgz#eda445dba06aeb18cff786fdb9fa4f6c5f5c6791"

nanomatch@^1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2"
Expand Down

0 comments on commit 84c66e6

Please sign in to comment.