Skip to content

Commit f2b63fa

Browse files
author
Chris Clark
committed
Refactor base conversion
1 parent a9b7d7d commit f2b63fa

File tree

2 files changed

+86
-130
lines changed

2 files changed

+86
-130
lines changed

src/js/ripple/base.js

+54-130
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,67 @@
1-
var sjcl = require('./utils').sjcl;
2-
var utils = require('./utils');
3-
var extend = require('extend');
1+
'use strict';
2+
var _ = require('lodash');
3+
var sjcl = require('./utils').sjcl;
4+
var utils = require('./utils');
5+
var extend = require('extend');
6+
var convertBase = require('./baseconverter');
47

58
var Base = {};
69

710
var alphabets = Base.alphabets = {
8-
ripple: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz',
9-
tipple: 'RPShNAF39wBUDnEGHJKLM4pQrsT7VWXYZ2bcdeCg65jkm8ofqi1tuvaxyz',
10-
bitcoin: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
11+
ripple: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz',
12+
tipple: 'RPShNAF39wBUDnEGHJKLM4pQrsT7VWXYZ2bcdeCg65jkm8ofqi1tuvaxyz',
13+
bitcoin: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
1114
};
1215

1316
extend(Base, {
14-
VER_NONE : 1,
15-
VER_NODE_PUBLIC : 28,
16-
VER_NODE_PRIVATE : 32,
17-
VER_ACCOUNT_ID : 0,
18-
VER_ACCOUNT_PUBLIC : 35,
19-
VER_ACCOUNT_PRIVATE : 34,
20-
VER_FAMILY_GENERATOR : 41,
21-
VER_FAMILY_SEED : 33
17+
VER_NONE: 1,
18+
VER_NODE_PUBLIC: 28,
19+
VER_NODE_PRIVATE: 32,
20+
VER_ACCOUNT_ID: 0,
21+
VER_ACCOUNT_PUBLIC: 35,
22+
VER_ACCOUNT_PRIVATE: 34,
23+
VER_FAMILY_GENERATOR: 41,
24+
VER_FAMILY_SEED: 33
2225
});
2326

2427
function sha256(bytes) {
25-
return sjcl.codec.bytes.fromBits(sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
28+
return sjcl.codec.bytes.fromBits(
29+
sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
2630
}
2731

28-
function sha256hash(bytes) {
29-
return sha256(sha256(bytes));
30-
}
31-
32-
function divmod58(number, startAt) {
33-
var remainder = 0;
34-
for (var i = startAt; i < number.length; i++) {
35-
var digit256 = number[i] & 0xFF;
36-
var temp = remainder * 256 + digit256;
37-
number[i] = (temp / 58);
38-
remainder = temp % 58;
39-
}
40-
return remainder;
41-
}
42-
43-
function divmod256(number58, startAt) {
44-
var remainder = 0;
45-
for (var i = startAt; i < number58.length; i++) {
46-
var digit58 = number58[i] & 0xFF;
47-
var temp = remainder * 58 + digit58;
48-
number58[i] = (temp / 256);
49-
remainder = temp % 256;
50-
}
51-
return remainder;
52-
}
53-
54-
function encodeString (alphabet, input) {
55-
if (input.length == 0) {
32+
function encodeString(alphabet, input) {
33+
if (input.length === 0) {
5634
return [];
5735
}
5836

59-
// we need to copy the buffer for calc
60-
scratch = input.slice();
61-
62-
// Count leading zeroes.
63-
var zeroCount = 0;
64-
while (zeroCount < scratch.length &&
65-
scratch[zeroCount] == 0)
66-
++zeroCount;
67-
68-
// The actual encoding.
69-
var out = new Array(scratch.length * 2);
70-
var j = out.length;
71-
var startAt = zeroCount;
72-
73-
while (startAt < scratch.length) {
74-
var mod = divmod58(scratch, startAt);
75-
if (scratch[startAt] == 0) {
76-
++startAt;
77-
}
78-
out[--j] = alphabet[mod];
79-
}
80-
81-
// Strip extra 'r' if there are some after decoding.
82-
while (j < out.length && out[j] == alphabet[0]) ++j;
83-
// Add as many leading 'r' as there were leading zeros.
84-
while (--zeroCount >= 0) out[--j] = alphabet[0];
85-
while(j--) out.shift();
86-
87-
return out.join('');
37+
var leadingZeros = _.takeWhile(input, function(d) {
38+
return d === 0;
39+
});
40+
var out = convertBase(input, 256, 58).map(function(digit) {
41+
return alphabet[digit];
42+
});
43+
var prefix = leadingZeros.map(function() {
44+
return alphabet[0];
45+
});
46+
return prefix.concat(out).join('');
8847
}
8948

90-
function decodeString(indexes, input) {
91-
var isString = typeof input === 'string';
92-
93-
if (input.length == 0) {
49+
function decodeString(indexes, input) {
50+
if (input.length === 0) {
9451
return [];
9552
}
9653

97-
input58 = new Array(input.length);
98-
99-
// Transform the String to a base58 byte sequence
100-
for (var i = 0; i < input.length; ++i) {
101-
if (isString) {
102-
var c = input.charCodeAt(i);
103-
}
104-
105-
var digit58 = -1;
106-
if (c >= 0 && c < 128) {
107-
digit58 = indexes[c];
108-
}
109-
if (digit58 < 0) {
110-
throw new Error("Illegal character " + c + " at " + i);
111-
}
112-
113-
input58[i] = digit58;
114-
}
115-
// Count leading zeroes
116-
var zeroCount = 0;
117-
while (zeroCount < input58.length && input58[zeroCount] == 0) {
118-
++zeroCount;
119-
}
120-
// The encoding
121-
out = utils.arraySet(input.length, 0);
122-
var j = out.length;
123-
124-
var startAt = zeroCount;
125-
while (startAt < input58.length) {
126-
var mod = divmod256(input58, startAt);
127-
if (input58[startAt] == 0) {
128-
++startAt;
129-
}
130-
out[--j] = mod;
131-
}
132-
133-
// Do no add extra leading zeroes, move j to first non null byte.
134-
while (j < out.length && (out[j] == 0)) ++j;
135-
136-
j -= zeroCount;
137-
while(j--) out.shift();
138-
139-
return out;
54+
var input58 = input.split('').map(function(c) {
55+
return indexes[c.charCodeAt(0)];
56+
});
57+
var leadingZeros = _.takeWhile(input58, function(d) {
58+
return d === 0;
59+
});
60+
var out = convertBase(input58, 58, 256);
61+
var prefix = leadingZeros.map(function() {
62+
return 0;
63+
});
64+
return prefix.concat(out);
14065
}
14166

14267
function Base58(alphabet) {
@@ -151,8 +76,8 @@ function Base58(alphabet) {
15176
}
15277

15378
Base.encoders = {};
154-
Object.keys(alphabets).forEach(function(alphabet){
155-
Base.encoders[alphabet] = Base58(alphabets[alphabet]);
79+
Object.keys(alphabets).forEach(function(alphabet) {
80+
Base.encoders[alphabet] = new Base58(alphabets[alphabet]);
15681
});
15782

15883
// --> input: big-endian array of bytes.
@@ -165,22 +90,21 @@ Base.encode = function(input, alpha) {
16590
// <-- array of bytes or undefined.
16691
Base.decode = function(input, alpha) {
16792
if (typeof input !== 'string') {
168-
return void(0);
93+
return undefined;
16994
}
17095
try {
17196
return this.encoders[alpha || 'ripple'].decode(input);
172-
}
173-
catch(e) {
174-
return (void 0);
97+
} catch (e) {
98+
return undefined;
17599
}
176100
};
177101

178102
Base.verify_checksum = function(bytes) {
179-
var computed = sha256hash(bytes.slice(0, -4)).slice(0, 4);
103+
var computed = sha256(sha256(bytes.slice(0, -4))).slice(0, 4);
180104
var checksum = bytes.slice(-4);
181105
var result = true;
182106

183-
for (var i=0; i<4; i++) {
107+
for (var i = 0; i < 4; i++) {
184108
if (computed[i] !== checksum[i]) {
185109
result = false;
186110
break;
@@ -194,7 +118,7 @@ Base.verify_checksum = function(bytes) {
194118
// <-- String
195119
Base.encode_check = function(version, input, alphabet) {
196120
var buffer = [].concat(version, input);
197-
var check = sha256(sha256(buffer)).slice(0, 4);
121+
var check = sha256(sha256(buffer)).slice(0, 4);
198122

199123
return Base.encode([].concat(buffer, check), alphabet);
200124
};
@@ -217,7 +141,7 @@ Base.decode_check = function(version, input, alphabet) {
217141
if (Array.isArray(version)) {
218142
var match = false;
219143

220-
for (var i=0, l=version.length; i<l; i++) {
144+
for (var i = 0, l = version.length; i < l; i++) {
221145
match |= version[i] === buffer[0];
222146
}
223147

@@ -234,7 +158,7 @@ Base.decode_check = function(version, input, alphabet) {
234158
// intrepret the value as a negative number
235159
buffer[0] = 0;
236160

237-
return sjcl.bn.fromBits (
161+
return sjcl.bn.fromBits(
238162
sjcl.codec.bytes.toBits(buffer.slice(0, -4)));
239163
};
240164

src/js/ripple/baseconverter.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use strict';
2+
3+
function normalize(digitArray) {
4+
while (digitArray[0] === 0) {
5+
digitArray.shift();
6+
}
7+
return digitArray;
8+
}
9+
10+
function divmod(digitArray, base, divisor) {
11+
var remainder = 0;
12+
var quotient = [];
13+
for (var j = 0; j < digitArray.length; j++) {
14+
var temp = remainder * base + parseInt(digitArray[j], 10);
15+
quotient.push(Math.floor(temp / divisor));
16+
remainder = temp % divisor;
17+
}
18+
return {quotient: normalize(quotient), remainder: remainder};
19+
}
20+
21+
function convertBase(digitArray, fromBase, toBase) {
22+
var result = [];
23+
var dividend = digitArray;
24+
while (dividend.length > 0) {
25+
var qr = divmod(dividend, fromBase, toBase);
26+
result.unshift(qr.remainder);
27+
dividend = qr.quotient;
28+
}
29+
return normalize(result);
30+
}
31+
32+
module.exports = convertBase;

0 commit comments

Comments
 (0)