Sign In

@otskit/core

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@otskit/core

OpenTimestamps core library — TypeScript, zero-dependency, fail-closed.

Source
npmnpm
Version
0.1.0
Version published
Weekly downloads
234
-33.9%
Maintainers
1
Weekly downloads
 
Created
Source

OTSkit Core

@otskit/core

CI CodeQL License: MIT Node ≥20

OpenTimestamps core library — TypeScript, zero-dependency, fail-closed.

The next generation of @alexalves87/opentimestamps, rewritten from the ground up with TypeScript 6 strict mode, zero external dependencies, and a fail-closed security posture.

What is OpenTimestamps?

OpenTimestamps is an open standard for decentralized timestamp proofs. It lets you prove that a document existed at a specific point in time by anchoring its cryptographic hash into the Bitcoin (or Litecoin) blockchain. The proof is stored in a compact .ots file — no trusted third party required for verification, ever.

Features

  • Zero dependencies — pure TypeScript implementation, no npm supply chain risk
  • Fail-closed by design — strict input validation; rejects ArrayBuffer, Buffer, and any malformed input by default
  • TypeScript-first — full type declarations, TypeScript 6 strict mode, ESM + CJS dual build
  • Complete protocol — create, serialize, deserialize, merge, and verify timestamps
  • Merkle tree support — batch-timestamp thousands of documents in a single blockchain transaction
  • Pure crypto — built-in SHA1, SHA256, and RIPEMD-160 with no native bindings

Installation

npm install @otskit/core

Requires Node.js ≥ 20.

Quick Start

Timestamp a file

import { DetachedTimestampFile, OpSHA256, makePending } from '@otskit/core';
import { readFileSync, writeFileSync } from 'node:fs';

// Hash your file and wrap it in a detached timestamp
const fileContent = new Uint8Array(readFileSync('document.pdf'));
const dtf = DetachedTimestampFile.fromBytes(new OpSHA256(), fileContent);

// Register with an OpenTimestamps calendar (pending — will be upgraded to Bitcoin)
dtf.timestamp.attestations.push(
  makePending('https://alice.btc.calendar.opentimestamps.org'),
);

// Save the .ots proof file alongside the original document
writeFileSync('document.pdf.ots', dtf.serializeToBytes());

Read a .ots file

import { DetachedTimestampFile } from '@otskit/core';
import { readFileSync } from 'node:fs';

const otsBytes = new Uint8Array(readFileSync('document.pdf.ots'));
const dtf = DetachedTimestampFile.deserialize(otsBytes);

console.log('Hash algorithm:', dtf.fileHashOp.tagName);
console.log('File digest:   ', Buffer.from(dtf.fileDigest()).toString('hex'));
console.log('Complete:      ', dtf.timestamp.isTimestampComplete());
console.log('Attestations:  ', dtf.timestamp.getAttestations());

Verify against a Bitcoin block header

import { DetachedTimestampFile, verifyAgainstBlockheader } from '@otskit/core';
import { readFileSync } from 'node:fs';

const dtf = DetachedTimestampFile.deserialize(
  new Uint8Array(readFileSync('document.pdf.ots')),
);

// Retrieve the block header from a full node or trusted block explorer
for (const { msg, attestation } of dtf.timestamp.allAttestations()) {
  if (attestation.kind === 'bitcoin') {
    verifyAgainstBlockheader(msg, blockHeader); // throws VerificationError if invalid
    console.log(`Verified at Bitcoin block height ${attestation.height}`);
  }
}

Batch-timestamp with a Merkle tree

Anchor thousands of documents in a single blockchain transaction:

import { DetachedTimestampFile, OpSHA256, makeMerkleTree, makePending } from '@otskit/core';
import { readFileSync, writeFileSync } from 'node:fs';

const files = ['a.pdf', 'b.pdf', 'c.pdf'];
const op = new OpSHA256();

const dtfs = files.map(f =>
  DetachedTimestampFile.fromBytes(op, new Uint8Array(readFileSync(f))),
);

// One Merkle root covers all documents — one calendar call, one blockchain entry
const root = makeMerkleTree(dtfs.map(d => d.timestamp));
root.attestations.push(makePending('https://alice.btc.calendar.opentimestamps.org'));

// Each .ots file carries its own path to the shared root
files.forEach((f, i) => writeFileSync(`${f}.ots`, dtfs[i]!.serializeToBytes()));

API Reference

DetachedTimestampFile

Immutable wrapper for a .ots proof file.

MemberDescription
DetachedTimestampFile.fromBytes(op, content)Create from raw file bytes
DetachedTimestampFile.fromHash(op, digest)Create from a pre-computed digest
DetachedTimestampFile.deserialize(bytes)Parse a .ots file (Uint8Array only — fail-closed)
.serializeToBytes()Serialize back to .ots bytes
.fileDigest()The file's hash as Uint8Array (defensive copy)
.fileHashOpThe CryptOp used to hash the file
.timestampThe root Timestamp of the proof tree

Timestamp

A node in the proof tree. Each node holds a digest (msg), direct attestations, and operation branches leading to sub-timestamps.

MemberDescription
new Timestamp(msg)Create a new leaf node
.add(op)Apply an operation and return (or reuse) the sub-timestamp
.addExisting(op, stamp)Cross-link to an existing timestamp (used internally by Merkle)
.merge(other)Absorb attestations and branches from another timestamp with the same msg
.attestationsDirect Attestation[] — push to add seals to this node
.getDigest()Defensive copy of msg
.getAttestations()All attestations anywhere in the tree
.allAttestations()All { msg, attestation } pairs in the tree
.isTimestampComplete()true if a Bitcoin or Litecoin attestation exists
.allTips()The leaf digests (nodes with no operations)
.equals(other)Deep structural equality

Operations

All operations extend Op and are serializable. Binary ops (OpAppend, OpPrepend) take a Uint8Array argument in their constructor.

ClassTagDescription
OpSHA2560x08SHA-256 hash
OpSHA10x02SHA-1 hash
OpRIPEMD1600x03RIPEMD-160 hash
OpAppend(suffix)0xf0Append bytes
OpPrepend(prefix)0xf1Prepend bytes
OpReverse0xf2Reverse byte order
OpHexlify0xf3Encode to ASCII hex

Attestations

FunctionDescription
makePending(uri)Pending calendar attestation — proof not yet upgraded to blockchain
makeBitcoin(height)Bitcoin blockchain attestation at block height
makeLitecoin(height)Litecoin blockchain attestation at block height
verifyAgainstBlockheader(digest, header)Verify a 32-byte digest against a block's Merkle root — throws VerificationError on failure

Merkle tree

FunctionDescription
makeMerkleTree(timestamps)Build a Merkle-Mountain-Range from an array of timestamps. Returns the root. Throws EmptyMerkleTreeError on empty input.

Serialization contexts

For low-level binary I/O following the OpenTimestamps wire format (LEB128 varints, length-prefixed bytes):

ClassDescription
StreamSerializationContextWrite binary data; call .getOutput() for the result
StreamDeserializationContextRead binary data with bounds checking and EOF enforcement

Utilities

FunctionDescription
hexToBytes(hex)Hex string → Uint8Array
bytesToHex(bytes)Uint8Array → lowercase hex string
textToBytes(text)UTF-8 string → Uint8Array
bytesToText(bytes)Uint8Array → UTF-8 string (throws on invalid sequences)
randBytes(n)Cryptographically secure random bytes via crypto.getRandomValues — throws if unavailable

Errors

All error classes extend Error and are exported by name for precise catch handling.

CategoryError classes
DeserializationDeserializationError, BadMagicError, TruncatedStreamError, OversizedDataError, VaruintOverflowError, TrailingGarbageError, UnknownOperationError, InvalidUriError, UnsupportedVersionError
OperationOpExecutionError, MessageTooLongError, ResultTooLongError
VerificationVerificationError
TreeEmptyTimestampError, MergeError, EmptyMerkleTreeError

Contributing

git clone https://github.com/OTSkit/OTSkit-core.git
cd OTSkit-core
npm install
npm test           # run the full test suite
npm run build      # ESM + CJS + TypeScript declarations
npm run coverage   # test coverage report

All contributions must preserve the fail-closed philosophy: strict input validation at every boundary, no silent failures, no implicit type coercion.

License

MIT © 2026 OTSkit contributors — see LICENSE.

FAQs

Package last updated on 03 Jun 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts