UNPKG

@stellar/stellar-sdk

Version:

A library for working with the Stellar network, including communication with the Horizon and Soroban RPC servers.

653 lines (650 loc) 13.2 kB
import { Buffer } from 'buffer'; import base32 from 'base32.js'; import { verifyChecksum } from './util/checksum.js'; const versionBytes = { ed25519PublicKey: 6 << 3, // G (when encoded in base32) ed25519SecretSeed: 18 << 3, // S med25519PublicKey: 12 << 3, // M preAuthTx: 19 << 3, // T sha256Hash: 23 << 3, // X signedPayload: 15 << 3, // P contract: 2 << 3, // C liquidityPool: 11 << 3, // L claimableBalance: 1 << 3 // B }; const strkeyTypes = { G: "ed25519PublicKey", S: "ed25519SecretSeed", M: "med25519PublicKey", T: "preAuthTx", X: "sha256Hash", P: "signedPayload", C: "contract", L: "liquidityPool", B: "claimableBalance" }; function hasVersionByteName(versionByteName) { return Object.prototype.hasOwnProperty.call(versionBytes, versionByteName); } class StrKey { static types = strkeyTypes; /** * Encodes `data` to strkey ed25519 public key. * * @param data - raw data to encode */ static encodeEd25519PublicKey(data) { return encodeCheck("ed25519PublicKey", data); } /** * Decodes strkey ed25519 public key to raw data. * * If the parameter is a muxed account key ("M..."), this will only encode it * as a basic Ed25519 key (as if in "G..." format). * * @param data - "G..." (or "M...") key representation to decode */ static decodeEd25519PublicKey(data) { return decodeCheck("ed25519PublicKey", data); } /** * Returns true if the given Stellar public key is a valid ed25519 public key. * * @param publicKey - public key to check */ static isValidEd25519PublicKey(publicKey) { return isValid("ed25519PublicKey", publicKey); } /** * Encodes data to strkey ed25519 seed. * * @param data - data to encode */ static encodeEd25519SecretSeed(data) { return encodeCheck("ed25519SecretSeed", data); } /** * Decodes strkey ed25519 seed to raw data. * * @param address - data to decode */ static decodeEd25519SecretSeed(address) { return decodeCheck("ed25519SecretSeed", address); } /** * Returns true if the given Stellar secret key is a valid ed25519 secret seed. * * @param seed - seed to check */ static isValidEd25519SecretSeed(seed) { return isValid("ed25519SecretSeed", seed); } /** * Encodes data to strkey med25519 public key. * * @param data - data to encode */ static encodeMed25519PublicKey(data) { return encodeCheck("med25519PublicKey", data); } /** * Decodes strkey med25519 public key to raw data. * * @param address - data to decode */ static decodeMed25519PublicKey(address) { return decodeCheck("med25519PublicKey", address); } /** * Returns true if the given Stellar public key is a valid med25519 public key. * * @param publicKey - public key to check */ static isValidMed25519PublicKey(publicKey) { return isValid("med25519PublicKey", publicKey); } /** * Encodes data to strkey preAuthTx. * * @param data - data to encode */ static encodePreAuthTx(data) { return encodeCheck("preAuthTx", data); } /** * Decodes strkey PreAuthTx to raw data. * * @param address - data to decode */ static decodePreAuthTx(address) { return decodeCheck("preAuthTx", address); } /** * Encodes data to strkey sha256 hash. * * @param data - data to encode */ static encodeSha256Hash(data) { return encodeCheck("sha256Hash", data); } /** * Decodes strkey sha256 hash to raw data. * * @param address - data to decode */ static decodeSha256Hash(address) { return decodeCheck("sha256Hash", address); } /** * Encodes raw data to strkey signed payload (P...). * * @param data - data to encode */ static encodeSignedPayload(data) { return encodeCheck("signedPayload", data); } /** * Decodes strkey signed payload (P...) to raw data. * * @param address - address to decode */ static decodeSignedPayload(address) { return decodeCheck("signedPayload", address); } /** * Checks validity of alleged signed payload (P...) strkey address. * * @param address - signer key to check */ static isValidSignedPayload(address) { return isValid("signedPayload", address); } /** * Encodes raw data to strkey contract (C...). * * @param data - data to encode */ static encodeContract(data) { return encodeCheck("contract", data); } /** * Decodes strkey contract (C...) to raw data. * * @param address - address to decode */ static decodeContract(address) { return decodeCheck("contract", address); } /** * Checks validity of alleged contract (C...) strkey address. * * @param address - signer key to check */ static isValidContract(address) { return isValid("contract", address); } /** * Encodes raw data to strkey claimable balance (B...). * * @param data - data to encode */ static encodeClaimableBalance(data) { return encodeCheck("claimableBalance", data); } /** * Decodes strkey claimable balance (B...) to raw data. * * @param address - balance to decode */ static decodeClaimableBalance(address) { return decodeCheck("claimableBalance", address); } /** * Checks validity of alleged claimable balance (B...) strkey address. * * @param address - balance to check */ static isValidClaimableBalance(address) { return isValid("claimableBalance", address); } /** * Encodes raw data to strkey liquidity pool (L...). * * @param data - data to encode */ static encodeLiquidityPool(data) { return encodeCheck("liquidityPool", data); } /** * Decodes strkey liquidity pool (L...) to raw data. * * @param address - address to decode */ static decodeLiquidityPool(address) { return decodeCheck("liquidityPool", address); } /** * Checks validity of alleged liquidity pool (L...) strkey address. * * @param address - pool to check */ static isValidLiquidityPool(address) { return isValid("liquidityPool", address); } /** * Returns the strkey type based on the prefix of the given strkey address, * or undefined if the prefix is invalid. * * @param address - the strkey address to check */ static getVersionByteForPrefix(address) { if (address.length < 1) { return void 0; } const prefix = address[0]; return strkeyTypes[prefix]; } } function isValid(versionByteName, encoded) { if (typeof encoded !== "string") { return false; } switch (versionByteName) { case "ed25519PublicKey": // falls through case "ed25519SecretSeed": // falls through case "preAuthTx": // falls through case "sha256Hash": // falls through case "contract": // falls through case "liquidityPool": if (encoded.length !== 56) { return false; } break; case "claimableBalance": if (encoded.length !== 58) { return false; } break; case "med25519PublicKey": if (encoded.length !== 69) { return false; } break; case "signedPayload": if (encoded.length < 56 || encoded.length > 165) { return false; } break; default: return false; } let decoded; try { decoded = decodeCheck(versionByteName, encoded); } catch { return false; } switch (versionByteName) { case "ed25519PublicKey": // falls through case "ed25519SecretSeed": // falls through case "preAuthTx": // falls through case "sha256Hash": // falls through case "contract": case "liquidityPool": return decoded.length === 32; case "claimableBalance": return decoded.length === 32 + 1; // +1 byte for discriminant case "med25519PublicKey": return decoded.length === 40; // +8 bytes for the ID case "signedPayload": return ( // 32 for the signer, +4 for the payload size, then either +4 for the // min or +64 for the max payload decoded.length >= 32 + 4 + 4 && decoded.length <= 32 + 4 + 64 ); default: return false; } } function decodeCheck(versionByteName, encoded) { if (typeof encoded !== "string") { throw new TypeError("encoded argument must be of type String"); } const decoded = base32.decode(encoded); const versionByte = decoded[0]; const payload = decoded.slice(0, -2); const data = payload.slice(1); const checksum = decoded.slice(-2); if (encoded !== base32.encode(decoded)) { throw new Error("invalid encoded string"); } if (!hasVersionByteName(versionByteName)) { throw new Error( `${versionByteName} is not a valid version byte name. Expected one of ${Object.keys(versionBytes).join(", ")}` ); } const expectedVersion = versionBytes[versionByteName]; if (versionByte !== expectedVersion) { throw new Error( `invalid version byte. expected ${expectedVersion}, got ${versionByte}` ); } const expectedChecksum = calculateChecksum(payload); if (!verifyChecksum(expectedChecksum, checksum)) { throw new Error(`invalid checksum`); } return Buffer.from(data); } function encodeCheck(versionByteName, data) { if (data === null || data === void 0) { throw new Error("cannot encode null data"); } if (!hasVersionByteName(versionByteName)) { throw new Error( `${versionByteName} is not a valid version byte name. Expected one of ${Object.keys(versionBytes).join(", ")}` ); } const versionByte = versionBytes[versionByteName]; data = Buffer.from(data); const versionBuffer = Buffer.from([versionByte]); const payload = Buffer.concat([versionBuffer, data]); const checksum = Buffer.from(calculateChecksum(payload)); const unencoded = Buffer.concat([payload, checksum]); return base32.encode(unencoded); } function calculateChecksum(payload) { const crcTable = [ 0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 41290, 45419, 49548, 53677, 57806, 61935, 4657, 528, 12915, 8786, 21173, 17044, 29431, 25302, 37689, 33560, 45947, 41818, 54205, 50076, 62463, 58334, 9314, 13379, 1056, 5121, 25830, 29895, 17572, 21637, 42346, 46411, 34088, 38153, 58862, 62927, 50604, 54669, 13907, 9842, 5649, 1584, 30423, 26358, 22165, 18100, 46939, 42874, 38681, 34616, 63455, 59390, 55197, 51132, 18628, 22757, 26758, 30887, 2112, 6241, 10242, 14371, 51660, 55789, 59790, 63919, 35144, 39273, 43274, 47403, 23285, 19156, 31415, 27286, 6769, 2640, 14899, 10770, 56317, 52188, 64447, 60318, 39801, 35672, 47931, 43802, 27814, 31879, 19684, 23749, 11298, 15363, 3168, 7233, 60846, 64911, 52716, 56781, 44330, 48395, 36200, 40265, 32407, 28342, 24277, 20212, 15891, 11826, 7761, 3696, 65439, 61374, 57309, 53244, 48923, 44858, 40793, 36728, 37256, 33193, 45514, 41451, 53516, 49453, 61774, 57711, 4224, 161, 12482, 8419, 20484, 16421, 28742, 24679, 33721, 37784, 41979, 46042, 49981, 54044, 58239, 62302, 689, 4752, 8947, 13010, 16949, 21012, 25207, 29270, 46570, 42443, 38312, 34185, 62830, 58703, 54572, 50445, 13538, 9411, 5280, 1153, 29798, 25671, 21540, 17413, 42971, 47098, 34713, 38840, 59231, 63358, 50973, 55100, 9939, 14066, 1681, 5808, 26199, 30326, 17941, 22068, 55628, 51565, 63758, 59695, 39368, 35305, 47498, 43435, 22596, 18533, 30726, 26663, 6336, 2273, 14466, 10403, 52093, 56156, 60223, 64286, 35833, 39896, 43963, 48026, 19061, 23124, 27191, 31254, 2801, 6864, 10931, 14994, 64814, 60687, 56684, 52557, 48554, 44427, 40424, 36297, 31782, 27655, 23652, 19525, 15522, 11395, 7392, 3265, 61215, 65342, 53085, 57212, 44955, 49082, 36825, 40952, 28183, 32310, 20053, 24180, 11923, 16050, 3793, 7920 ]; let crc16 = 0; for (let i = 0; i < payload.length; i += 1) { const byte = payload[i]; if (byte === void 0) { continue; } const lookupIndex = crc16 >> 8 ^ byte; crc16 = crc16 << 8 ^ (crcTable[lookupIndex] ?? 0); crc16 &= 65535; } const checksum = new Uint8Array(2); checksum[0] = crc16 & 255; checksum[1] = crc16 >> 8 & 255; return checksum; } export { StrKey, decodeCheck, encodeCheck }; //# sourceMappingURL=strkey.js.map