condorcet-vote/elephstamp
Composer 安装命令:
composer require condorcet-vote/elephstamp
包简介
Modern, object-oriented PHP library for OpenTimestamps: register timestamp proofs with calendar servers and collect the completed .ots certification.
README 文档
README
A modern, object-oriented PHP library for OpenTimestamps. It lets you register a timestamp proof for a file with the public calendar servers and track/collect the completed proof once it has been anchored in the Bitcoin blockchain.
ElephStamp is a focused, partial port of the Python
opentimestamps-client:
it is not a line-by-line translation but an expressive PHP API. The .ots
proof files it produces and reads are byte-for-byte interoperable with the
reference tooling.
Scope
In scope
- Creating timestamp requests and submitting them to calendar servers.
- Following a proof's status and fetching the completed
.otsonce the calendars can provide a blockchain attestation. - A built-in fake mode for tests and local/integration environments.
Out of scope (by design)
- No command-line tool — this is a library only.
- No on-chain verification. ElephStamp reports what a proof claims (e.g. the Bitcoin block height) but never talks to a Bitcoin node to verify it. Use a dedicated verifier for that.
Requirements
- PHP 8.5+ with the
mbstringextension. symfony/http-client(pulled in automatically) for talking to calendar servers.
Installation
composer require condorcet-vote/elephstamp
Quick start
Stamp a file
use CondorcetVote\ElephStamp\ElephStamp; use CondorcetVote\ElephStamp\FileToStamp; $client = new ElephStamp(); $receipt = $client->stamp(FileToStamp::fromPath('contract.pdf')); // Persist the proof next to your file. $receipt->saveToPath('contract.pdf.ots'); echo $receipt->status()->name; // "Pending" echo $receipt->fileDigestHex(); // sha256 of contract.pdf
A freshly created timestamp is pending: the calendars have recorded your commitment but Bitcoin has not confirmed it yet (this usually takes a few hours).
All calendars are contacted concurrently, and a calendar that is
unreachable or misbehaves is tolerated: a stamp succeeds as long as at least
requiredCalendars of them accept it (see Configuration).
Follow up and collect the completed proof
use CondorcetVote\ElephStamp\ElephStamp; use CondorcetVote\ElephStamp\Receipt; $client = new ElephStamp(); $receipt = Receipt::fromPath('contract.pdf.ots'); if ($client->upgrade($receipt)) { // Something changed: persist the richer proof. $receipt->saveToPath('contract.pdf.ots'); } if ($receipt->isComplete()) { echo 'Anchored in Bitcoin block ' . $receipt->bitcoinBlockHeight(); }
upgrade() performs a single polling pass and returns whether the proof
changed. Call it again later while the receipt is still pending.
Describing what to stamp
FileToStamp has one explicit, typed constructor per source. Files are always
hashed as a stream — their content is never loaded into memory in full.
use CondorcetVote\ElephStamp\FileToStamp; FileToStamp::fromPath('invoice.pdf'); // a file on disk FileToStamp::fromSplFileObject(new SplFileObject('a.bin')); // an open handle FileToStamp::fromContent('some in-memory string'); // raw bytes FileToStamp::fromDigest($sha256); // a digest you already computed
fromDigest() uses the digest verbatim; its length must match the client's
hash operation (SHA-256 by default).
Privacy nonce
By default a random nonce is mixed into the digest before it reaches a calendar,
so the calendar never learns the real file hash. When linkability is acceptable
— or desirable, e.g. so the commitment equals the file's plain SHA-256 and can
be recomputed without the .ots — disable it:
FileToStamp::fromPath('public-release.zip')->withoutNonce();
Note that inside a stampMany() batch, a file stamped without nonce also
exposes its plain digest in the sibling receipts of the batch (the merkle
tree embeds each leaf's message into its neighbours' proofs) — not only to the
calendars.
Stamping several files at once
stampMany() binds all files into a single merkle tree, so one calendar
submission covers them, while each file still gets its own independent receipt.
$receipts = $client->stampMany( FileToStamp::fromPath('a.pdf'), FileToStamp::fromPath('b.pdf'), FileToStamp::fromPath('c.pdf'), );
Reading a receipt
$receipt->status(); // Status::Pending | Status::Complete $receipt->isComplete(); $receipt->isPending(); $receipt->fileDigest(); // raw digest bytes $receipt->fileDigestHex(); // lower-case hex $receipt->pendingCalendarUris(); // list<string> of calendars still to poll $receipt->bitcoinBlockHeight(); // int|null (claimed, not verified) $receipt->toBytes(); // the raw .ots content $receipt->describe(); // human-readable proof tree (for inspection)
describe() renders the proof as an indented tree, handy for debugging:
file sha256 digest: da7badf6…f655
append d6c877a9…
sha256
-> append 014870d0…
sha256
prepend f23482df…
sha256
pending attestation → https://finney.calendar.eternitywall.com
-> …
Testing: fake mode
ElephStamp::fake() returns a fully offline client. Proofs are deterministic
and the fake calendar lets you simulate Bitcoin confirmation, so you can test
both the pending and complete states without any network.
use CondorcetVote\ElephStamp\ElephStamp; use CondorcetVote\ElephStamp\FileToStamp; $client = ElephStamp::fake(); $receipt = $client->stamp(FileToStamp::fromContent('hello world')); $receipt->isPending(); // true // Simulate Bitcoin confirming the commitment. $client->fakeCalendar()->confirmAll(blockHeight: 812_345); $client->upgrade($receipt); $receipt->isComplete(); // true $receipt->bitcoinBlockHeight(); // 812345
Confirm a specific receipt, or everything submitted so far:
use CondorcetVote\ElephStamp\Calendar\FakeCalendarClient; $calendar = new FakeCalendarClient(); $client = ElephStamp::fake($calendar); $receipt = $client->stamp(FileToStamp::fromContent('data')); $calendar->confirm($receipt); // confirm just this receipt // or $calendar->confirmAll(); // confirm every commitment submitted so far
Configuration
use CondorcetVote\ElephStamp\ElephStamp; $client = new ElephStamp( calendarUrls: ['https://a.pool.opentimestamps.org', 'https://b.pool.opentimestamps.org'], requiredCalendars: 2, // the "m" of an m-of-n policy );
Calendar URLs must be unique and use https (a plaintext connection would
let a network attacker inject forged responses); the same goes for whitelist
patterns. When requiredCalendars is omitted it defaults to 2 — like the
reference client — or to 1 when a single calendar is configured.
Upgrade whitelist (security)
An .ots proof embeds the calendar URIs to poll when upgrading. Because a proof
may come from an untrusted source, upgrade() only contacts hosts on an
allowlist — otherwise a hostile proof could point the process at arbitrary hosts
(an SSRF risk). The default covers the known public operators
(*.calendar.opentimestamps.org, *.calendar.eternitywall.com,
*.calendar.catallaxy.com). Override it when you use private calendars:
$client = new ElephStamp( calendarUrls: ['https://ots.internal.example'], upgradeWhitelist: ['https://*.internal.example'], );
Host patterns accept shell-style globs; URLs with a query, fragment or credentials are always rejected.
Customising the HTTP client
The default transport is the Symfony HTTP client, hardened for calendar traffic: redirects are never followed, responses are capped at 10 kB, and requests time out after 10 s of silence (30 s in total). Tune the timeouts, or inject your own configured instance (proxy, retries, ...) when needed:
use CondorcetVote\ElephStamp\Calendar\HttpCalendarClient; use CondorcetVote\ElephStamp\ElephStamp; use Symfony\Component\HttpClient\HttpClient; $calendarClient = new HttpCalendarClient( HttpClient::create(['proxy' => 'http://proxy.internal:3128']), timeout: 5.0, // idle timeout, seconds maxDuration: 15.0, // hard cap per request, seconds ); $client = new ElephStamp(calendarClient: $calendarClient);
Exceptions
Every exception implements CondorcetVote\ElephStamp\Exception\ElephStampException:
InvalidInputException— bad caller input (unreadable file, invalid options).SerializationException— malformed or unsupported.otsdata.CalendarException— a calendar was unreachable or misbehaved.StampingException— too few calendars accepted a stamp (m-of-n not met).
License
MIT — see LICENSE.
condorcet-vote/elephstamp 适用场景与选型建议
condorcet-vote/elephstamp 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 1, 最近一次更新时间为 2026 年 07 月 15 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「timestamp」 「bitcoin」 「proof」 「certification」 「ots」 「opentimestamps」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 condorcet-vote/elephstamp 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 condorcet-vote/elephstamp 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 condorcet-vote/elephstamp 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Magento 2 Social Login extension is designed for quick login to your Magento 2 store without procesing complex register steps
Fomo PHP SDK is the official SDK wrapper for the Fomo API service
The BlockTrail PHP SDK, for integration of Bitcoin functionality through the BlockTrail API
Laravel Eloquent boolean & timestamp flagged attributes behavior.
Timestamp parameter in public file uri
A library to extend Object capabilities.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-07-15