UNPKG

6.56 kBJavaScriptView Raw
1"use strict";
2/**
3 * Codec class
4 */
5Object.defineProperty(exports, "__esModule", { value: true });
6const baseCodec = require("base-x");
7const utils_1 = require("./utils");
8class Codec {
9 constructor(options) {
10 this.sha256 = options.sha256;
11 this.alphabet = options.alphabet;
12 this.codec = baseCodec(this.alphabet);
13 this.base = this.alphabet.length;
14 }
15 /**
16 * Encoder.
17 *
18 * @param bytes Buffer of data to encode.
19 * @param opts Options object including the version bytes and the expected length of the data to encode.
20 */
21 encode(bytes, opts) {
22 const versions = opts.versions;
23 return this.encodeVersioned(bytes, versions, opts.expectedLength);
24 }
25 encodeVersioned(bytes, versions, expectedLength) {
26 if (expectedLength && bytes.length !== expectedLength) {
27 throw new Error('unexpected_payload_length: bytes.length does not match expectedLength.' +
28 ' Ensure that the bytes are a Buffer.');
29 }
30 return this.encodeChecked(Buffer.from(utils_1.concatArgs(versions, bytes)));
31 }
32 encodeChecked(buffer) {
33 const check = this.sha256(this.sha256(buffer)).slice(0, 4);
34 return this.encodeRaw(Buffer.from(utils_1.concatArgs(buffer, check)));
35 }
36 encodeRaw(bytes) {
37 return this.codec.encode(bytes);
38 }
39 /**
40 * Decoder.
41 *
42 * @param base58string Base58Check-encoded string to decode.
43 * @param opts Options object including the version byte(s) and the expected length of the data after decoding.
44 */
45 decode(base58string, opts) {
46 const versions = opts.versions;
47 const types = opts.versionTypes;
48 const withoutSum = this.decodeChecked(base58string);
49 if (versions.length > 1 && !opts.expectedLength) {
50 throw new Error('expectedLength is required because there are >= 2 possible versions');
51 }
52 const versionLengthGuess = typeof versions[0] === 'number' ? 1 : versions[0].length;
53 const payloadLength = opts.expectedLength || withoutSum.length - versionLengthGuess;
54 const versionBytes = withoutSum.slice(0, -payloadLength);
55 const payload = withoutSum.slice(-payloadLength);
56 for (let i = 0; i < versions.length; i++) {
57 const version = Array.isArray(versions[i]) ? versions[i] : [versions[i]];
58 if (utils_1.seqEqual(versionBytes, version)) {
59 return {
60 version,
61 bytes: payload,
62 type: types ? types[i] : null
63 };
64 }
65 }
66 throw new Error('version_invalid: version bytes do not match any of the provided version(s)');
67 }
68 decodeChecked(base58string) {
69 const buffer = this.decodeRaw(base58string);
70 if (buffer.length < 5) {
71 throw new Error('invalid_input_size: decoded data must have length >= 5');
72 }
73 if (!this.verifyCheckSum(buffer)) {
74 throw new Error('checksum_invalid');
75 }
76 return buffer.slice(0, -4);
77 }
78 decodeRaw(base58string) {
79 return this.codec.decode(base58string);
80 }
81 verifyCheckSum(bytes) {
82 const computed = this.sha256(this.sha256(bytes.slice(0, -4))).slice(0, 4);
83 const checksum = bytes.slice(-4);
84 return utils_1.seqEqual(computed, checksum);
85 }
86}
87/**
88 * XRP codec
89 */
90// Pure JavaScript hash functions in the browser, native hash functions in Node.js
91const createHash = require('create-hash');
92// base58 encodings: https://xrpl.org/base58-encodings.html
93const ACCOUNT_ID = 0; // Account address (20 bytes)
94const ACCOUNT_PUBLIC_KEY = 0x23; // Account public key (33 bytes)
95const FAMILY_SEED = 0x21; // 33; Seed value (for secret keys) (16 bytes)
96const NODE_PUBLIC = 0x1C; // 28; Validation public key (33 bytes)
97const ED25519_SEED = [0x01, 0xE1, 0x4B]; // [1, 225, 75]
98const codecOptions = {
99 sha256: function (bytes) {
100 return createHash('sha256').update(Buffer.from(bytes)).digest();
101 },
102 alphabet: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz'
103};
104const codecWithXrpAlphabet = new Codec(codecOptions);
105exports.codec = codecWithXrpAlphabet;
106// entropy is a Buffer of size 16
107// type is 'ed25519' or 'secp256k1'
108function encodeSeed(entropy, type) {
109 if (entropy.length !== 16) {
110 throw new Error('entropy must have length 16');
111 }
112 const opts = {
113 expectedLength: 16,
114 // for secp256k1, use `FAMILY_SEED`
115 versions: type === 'ed25519' ? ED25519_SEED : [FAMILY_SEED]
116 };
117 // prefixes entropy with version bytes
118 return codecWithXrpAlphabet.encode(entropy, opts);
119}
120exports.encodeSeed = encodeSeed;
121function decodeSeed(seed, opts = {
122 versionTypes: ['ed25519', 'secp256k1'],
123 versions: [ED25519_SEED, FAMILY_SEED],
124 expectedLength: 16
125}) {
126 return codecWithXrpAlphabet.decode(seed, opts);
127}
128exports.decodeSeed = decodeSeed;
129function encodeAccountID(bytes) {
130 const opts = { versions: [ACCOUNT_ID], expectedLength: 20 };
131 return codecWithXrpAlphabet.encode(bytes, opts);
132}
133exports.encodeAccountID = encodeAccountID;
134exports.encodeAddress = encodeAccountID;
135function decodeAccountID(accountId) {
136 const opts = { versions: [ACCOUNT_ID], expectedLength: 20 };
137 return codecWithXrpAlphabet.decode(accountId, opts).bytes;
138}
139exports.decodeAccountID = decodeAccountID;
140exports.decodeAddress = decodeAccountID;
141function decodeNodePublic(base58string) {
142 const opts = { versions: [NODE_PUBLIC], expectedLength: 33 };
143 return codecWithXrpAlphabet.decode(base58string, opts).bytes;
144}
145exports.decodeNodePublic = decodeNodePublic;
146function encodeNodePublic(bytes) {
147 const opts = { versions: [NODE_PUBLIC], expectedLength: 33 };
148 return codecWithXrpAlphabet.encode(bytes, opts);
149}
150exports.encodeNodePublic = encodeNodePublic;
151function encodeAccountPublic(bytes) {
152 const opts = { versions: [ACCOUNT_PUBLIC_KEY], expectedLength: 33 };
153 return codecWithXrpAlphabet.encode(bytes, opts);
154}
155exports.encodeAccountPublic = encodeAccountPublic;
156function decodeAccountPublic(base58string) {
157 const opts = { versions: [ACCOUNT_PUBLIC_KEY], expectedLength: 33 };
158 return codecWithXrpAlphabet.decode(base58string, opts).bytes;
159}
160exports.decodeAccountPublic = decodeAccountPublic;
161function isValidClassicAddress(address) {
162 try {
163 decodeAccountID(address);
164 }
165 catch (e) {
166 return false;
167 }
168 return true;
169}
170exports.isValidClassicAddress = isValidClassicAddress;
171//# sourceMappingURL=xrp-codec.js.map
\No newline at end of file