UNPKG

@aggris2/ssz

Version:

Simple Serialize

149 lines 5.91 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StringBigintType = void 0; const persistent_merkle_tree_1 = require("@chainsafe/persistent-merkle-tree"); const basic_1 = require("./basic"); const BIGINT_2_POW_64 = BigInt(2) ** BigInt(64); const BIGINT_2_POW_128 = BigInt(2) ** BigInt(128); const BIGINT_2_POW_192 = BigInt(2) ** BigInt(192); /** * Uint: N-bit unsigned integer (where N in [8, 16, 32, 64, 128, 256]) * - Notation: uintN * * UintBigint is represented as the Javascript primitive value 'BigInt'. * * The BigInt type is a numeric primitive in JavaScript that can represent integers with arbitrary precision. * With BigInts, you can safely store and operate on large integers even beyond the safe integer limit for Numbers. * * As of 2021 performance of 'Number' is extremely faster than 'BigInt'. For Uint values under 53 bits use UintNumber. * For other values that may exceed 53 bits, use UintBigint. */ class StringBigintType extends basic_1.BasicType { constructor(byteLength) { super(); this.byteLength = byteLength; if (byteLength > 32) { throw Error("UintBigint byteLength limit is 32"); } if (Math.log2(byteLength) % 1 !== 0) { throw Error("byteLength must be a power of 2"); } this.typeName = `string`; this.byteLength = byteLength; this.itemsPerChunk = 32 / this.byteLength; this.fixedSize = byteLength; this.minSize = byteLength; this.maxSize = byteLength; } defaultValue() { return "0"; } // Serialization + deserialization value_serializeToBytes({ dataView }, offset, v) { let value = BigInt(v); switch (this.byteLength) { case 1: dataView.setInt8(offset, Number(value)); break; case 2: dataView.setUint16(offset, Number(value), true); break; case 4: dataView.setUint32(offset, Number(value), true); break; case 8: dataView.setBigUint64(offset, value, true); break; default: { for (let i = 0; i < this.byteLength; i += 8) { if (i > 0) value = value / BIGINT_2_POW_64; const lo = BigInt.asUintN(64, value); dataView.setBigUint64(offset + i, lo, true); } } } return offset + this.byteLength; } value_deserializeFromBytes({ dataView }, start, end) { const size = end - start; if (size !== this.byteLength) { throw Error(`Invalid size ${size} expected ${this.byteLength}`); } // Note: pre-assigning the right function at the constructor to avoid this switch is not faster switch (this.byteLength) { case 1: return BigInt(dataView.getUint8(start)).toString(); case 2: return BigInt(dataView.getUint16(start, true)).toString(); case 4: return BigInt(dataView.getUint32(start, true)).toString(); case 8: return dataView.getBigUint64(start, true).toString(); case 16: { const a = dataView.getBigUint64(start, true); const b = dataView.getBigUint64(start + 8, true); return (b * BIGINT_2_POW_64 + a).toString(); } case 32: { const a = dataView.getBigUint64(start, true); const b = dataView.getBigUint64(start + 8, true); const c = dataView.getBigUint64(start + 16, true); const d = dataView.getBigUint64(start + 24, true); return (d * BIGINT_2_POW_192 + c * BIGINT_2_POW_128 + b * BIGINT_2_POW_64 + a).toString(); } } } tree_serializeToBytes(output, offset, node) { const value = node.getUintBigint(this.byteLength, 0).toString(); this.value_serializeToBytes(output, offset, value); return offset + this.byteLength; } tree_deserializeFromBytes(data, start, end) { const size = end - start; if (size !== this.byteLength) { throw Error(`Invalid size ${size} expected ${this.byteLength}`); } const value = BigInt(this.value_deserializeFromBytes(data, start, end)); const node = persistent_merkle_tree_1.LeafNode.fromZero(); node.setUintBigint(this.byteLength, 0, value); return node; } // Fast Tree access tree_getFromNode(leafNode) { return leafNode.getUintBigint(this.byteLength, 0).toString(); } /** Mutates node to set value */ tree_setToNode(leafNode, value) { this.tree_setToPackedNode(leafNode, 0, value); } /** EXAMPLE of `tree_getFromNode` */ tree_getFromPackedNode(leafNode, index) { const offsetBytes = this.byteLength * (index % this.itemsPerChunk); return leafNode.getUintBigint(this.byteLength, offsetBytes).toString(); } /** Mutates node to set value */ tree_setToPackedNode(leafNode, index, v) { let value = BigInt(v); const offsetBytes = this.byteLength * (index % this.itemsPerChunk); // TODO: Not-optimized, copy pasted from UintNumberType leafNode.setUintBigint(this.byteLength, offsetBytes, value); } // JSON fromJson(json) { if (typeof json === "string") { return json; } else if (typeof json === "number") { return BigInt(json).toString(); } else { throw Error(`JSON invalid type ${typeof json} expected bigint`); } } toJson(value) { return value; } } exports.StringBigintType = StringBigintType; //# sourceMappingURL=string.js.map