UNPKG

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