UNPKG

ox

Version:

Ethereum Standard Library

244 lines 9.33 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InvalidVersionedHashVersionError = exports.InvalidVersionedHashSizeError = exports.EmptyBlobVersionedHashesError = exports.EmptyBlobError = exports.BlobSizeTooLargeError = exports.maxBytesPerTransaction = exports.bytesPerBlob = exports.fieldElementsPerBlob = exports.bytesPerFieldElement = void 0; exports.commitmentsToVersionedHashes = commitmentsToVersionedHashes; exports.commitmentToVersionedHash = commitmentToVersionedHash; exports.from = from; exports.sidecarsToVersionedHashes = sidecarsToVersionedHashes; exports.to = to; exports.toHex = toHex; exports.toBytes = toBytes; exports.toCommitments = toCommitments; exports.toProofs = toProofs; exports.toSidecars = toSidecars; exports.toVersionedHashes = toVersionedHashes; const Bytes = require("./Bytes.js"); const Errors = require("./Errors.js"); const Hash = require("./Hash.js"); const Hex = require("./Hex.js"); const Cursor = require("./internal/cursor.js"); const Kzg = require("./Kzg.js"); const blobsPerTransaction = 6; exports.bytesPerFieldElement = 32; exports.fieldElementsPerBlob = 4096; exports.bytesPerBlob = exports.bytesPerFieldElement * exports.fieldElementsPerBlob; exports.maxBytesPerTransaction = exports.bytesPerBlob * blobsPerTransaction - 1 - 1 * exports.fieldElementsPerBlob * blobsPerTransaction; function commitmentsToVersionedHashes(commitments, options = {}) { const { version } = options; const as = options.as ?? (typeof commitments[0] === 'string' ? 'Hex' : 'Bytes'); const hashes = []; for (const commitment of commitments) { hashes.push(commitmentToVersionedHash(commitment, { as, version, })); } return hashes; } function commitmentToVersionedHash(commitment, options = {}) { const { version = 1 } = options; const as = options.as ?? (typeof commitment === 'string' ? 'Hex' : 'Bytes'); const versionedHash = Hash.sha256(commitment, { as: 'Bytes' }); versionedHash.set([version], 0); return (as === 'Bytes' ? versionedHash : Hex.fromBytes(versionedHash)); } function from(data, options = {}) { const as = options.as ?? (typeof data === 'string' ? 'Hex' : 'Bytes'); const data_ = (typeof data === 'string' ? Bytes.fromHex(data) : data); const size_ = Bytes.size(data_); if (!size_) throw new EmptyBlobError(); if (size_ > exports.maxBytesPerTransaction) throw new BlobSizeTooLargeError({ maxSize: exports.maxBytesPerTransaction, size: size_, }); const blobs = []; let active = true; let position = 0; while (active) { const blob = Cursor.create(new Uint8Array(exports.bytesPerBlob)); let size = 0; while (size < exports.fieldElementsPerBlob) { const bytes = data_.slice(position, position + (exports.bytesPerFieldElement - 1)); blob.pushByte(0x00); blob.pushBytes(bytes); if (bytes.length < 31) { blob.pushByte(0x80); active = false; break; } size++; position += 31; } blobs.push(blob); } return (as === 'Bytes' ? blobs.map((x) => x.bytes) : blobs.map((x) => Hex.fromBytes(x.bytes))); } function sidecarsToVersionedHashes(sidecars, options = {}) { const { version } = options; const as = options.as ?? (typeof sidecars[0].blob === 'string' ? 'Hex' : 'Bytes'); const hashes = []; for (const { commitment } of sidecars) { hashes.push(commitmentToVersionedHash(commitment, { as, version, })); } return hashes; } function to(blobs, to) { const to_ = to ?? (typeof blobs[0] === 'string' ? 'Hex' : 'Bytes'); const blobs_ = (typeof blobs[0] === 'string' ? blobs.map((x) => Bytes.fromHex(x)) : blobs); const length = blobs_.reduce((length, blob) => length + blob.length, 0); const data = Cursor.create(new Uint8Array(length)); let active = true; for (const blob of blobs_) { const cursor = Cursor.create(blob); while (active && cursor.position < blob.length) { cursor.incrementPosition(1); let consume = 31; if (blob.length - cursor.position < 31) consume = blob.length - cursor.position; for (const _ in Array.from({ length: consume })) { const byte = cursor.readByte(); const isTerminator = byte === 0x80 && !cursor.inspectBytes(cursor.remaining).includes(0x80); if (isTerminator) { active = false; break; } data.pushByte(byte); } } } const trimmedData = data.bytes.slice(0, data.position); return (to_ === 'Hex' ? Hex.fromBytes(trimmedData) : trimmedData); } function toHex(blobs) { return to(blobs, 'Hex'); } function toBytes(blobs) { return to(blobs, 'Bytes'); } function toCommitments(blobs, options) { const { kzg } = options; const as = options.as ?? (typeof blobs[0] === 'string' ? 'Hex' : 'Bytes'); const blobs_ = (typeof blobs[0] === 'string' ? blobs.map((x) => Bytes.fromHex(x)) : blobs); const commitments = []; for (const blob of blobs_) commitments.push(Uint8Array.from(kzg.blobToKzgCommitment(blob))); return (as === 'Bytes' ? commitments : commitments.map((x) => Hex.fromBytes(x))); } function toProofs(blobs, options) { const { kzg } = options; const as = options.as ?? (typeof blobs[0] === 'string' ? 'Hex' : 'Bytes'); const blobs_ = (typeof blobs[0] === 'string' ? blobs.map((x) => Bytes.fromHex(x)) : blobs); const commitments = (typeof options.commitments[0] === 'string' ? options.commitments.map((x) => Bytes.fromHex(x)) : options.commitments); const proofs = []; for (let i = 0; i < blobs_.length; i++) { const blob = blobs_[i]; const commitment = commitments[i]; proofs.push(Uint8Array.from(kzg.computeBlobKzgProof(blob, commitment))); } return (as === 'Bytes' ? proofs : proofs.map((x) => Hex.fromBytes(x))); } function toSidecars(blobs, options) { const { kzg } = options; const commitments = options.commitments ?? toCommitments(blobs, { kzg: kzg }); const proofs = options.proofs ?? toProofs(blobs, { commitments: commitments, kzg: kzg }); const sidecars = []; for (let i = 0; i < blobs.length; i++) sidecars.push({ blob: blobs[i], commitment: commitments[i], proof: proofs[i], }); return sidecars; } function toVersionedHashes(blobs, options) { const commitments = toCommitments(blobs, options); return commitmentsToVersionedHashes(commitments, options); } class BlobSizeTooLargeError extends Errors.BaseError { constructor({ maxSize, size }) { super('Blob size is too large.', { metaMessages: [`Max: ${maxSize} bytes`, `Given: ${size} bytes`], }); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Blobs.BlobSizeTooLargeError' }); } } exports.BlobSizeTooLargeError = BlobSizeTooLargeError; class EmptyBlobError extends Errors.BaseError { constructor() { super('Blob data must not be empty.'); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Blobs.EmptyBlobError' }); } } exports.EmptyBlobError = EmptyBlobError; class EmptyBlobVersionedHashesError extends Errors.BaseError { constructor() { super('Blob versioned hashes must not be empty.'); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Blobs.EmptyBlobVersionedHashesError' }); } } exports.EmptyBlobVersionedHashesError = EmptyBlobVersionedHashesError; class InvalidVersionedHashSizeError extends Errors.BaseError { constructor({ hash, size, }) { super(`Versioned hash "${hash}" size is invalid.`, { metaMessages: ['Expected: 32', `Received: ${size}`], }); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Blobs.InvalidVersionedHashSizeError' }); } } exports.InvalidVersionedHashSizeError = InvalidVersionedHashSizeError; class InvalidVersionedHashVersionError extends Errors.BaseError { constructor({ hash, version, }) { super(`Versioned hash "${hash}" version is invalid.`, { metaMessages: [ `Expected: ${Kzg.versionedHashVersion}`, `Received: ${version}`, ], }); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'Blobs.InvalidVersionedHashVersionError' }); } } exports.InvalidVersionedHashVersionError = InvalidVersionedHashVersionError; //# sourceMappingURL=Blobs.js.map