amashukov/ton-crypto-php
Correct TON mnemonic and Ed25519 keypair derivation in pure PHP. Uses PBKDF2-HMAC-SHA512 with the "TON default seed" salt, not BIP-39, so 24-word phrases produce matching TON wallets. Sign and verify via libsodium, zero composer dependencies.
ext-sodium only, zero composer dependencies. That single answer determines whether a TON login, custodial wallet, or payment flow is a two-week spike or a multi-quarter platform project.KeyPair::generate() and deterministic Mnemonic::toKeyPair(), which is enough to model both onboarding paths: a user-supplied 24-word phrase (import/restore flow) or a server-generated keypair with the seed encrypted at rest. This is the core decision in any wallet product; it is normally made months before engineering starts, and it is normally made wrong because the team assumes BIP-39 works everywhere.amashukov/ton-wallet-php; chain reads/writes need toncenter-client-php. Deciding to adopt this as a trio rather than a single dependency is a resourcing decision — plan three integrations, not one, and budget the wallet contract work separately from day one.Adopt it when all of the following hold:
ext-sodium (Sail/Herd have it; slim Docker images and many distro packages do not — verify before committing, this is the most common install failure).ton-crypto-php + ton-wallet-php + toncenter-client-php).TonKeyService), encrypted seed storage and $hidden model attributes, base64 at API boundaries, seed material excluded from logs, Telescope payloads, and queued job properties.Look elsewhere (or build) when:
"TON default seed" at 100,000 iterations plus an extra HMAC pass — a generic BIP-39 helper will produce a valid-looking keypair and an address no TON wallet recognises. That failure is invisible until a user tries to restore.toKeyPair() accepts an arbitrary string and returns some 32-byte seed. If you need validation, you build it — exactly 24 words, all in the TON/BIP-39 English wordlist, checksum bit set — before handing anything to the library.For executives, one paragraph: TON is a growing chain and this package makes it possible for our Laravel product to derive TON keys and sign payloads server-side, with no new infrastructure, no new runtime, and no vendor contract. It is MIT-licensed, has zero composer dependencies, and is deliberately scoped: it produces keys, not addresses, so it is one piece of an integration rather than a complete wallet solution. The commercial case is time-to-market — it converts a genuinely risky build (getting TON cryptography subtly wrong, and shipping wallets that users cannot restore) into a reviewed integration of a few hundred lines we can wrap in our own interface and swap out without touching product code.
For engineering, the honest framing: the code is small, correct where it counts, and well-disciplined — final readonly value objects, strict_types, PHPStan level 9, CI, and derived seeds validated against the TON reference implementation. The risk is not the code, it's the dependency: one maintainer, no dependents, readme-level maturity. So we adopt it behind an interface we own, we pay for the derivation review up front, and we build a test suite pinned to a real TON address so any regression or upstream abandonment is caught loudly. Requirements first: PHP 8.3+ and ext-sodium present in every environment including CI and production images.
For security and compliance: this package holds key material, so it inherits every obligation that implies. Seeds are encrypted at rest (Laravel Crypt), excluded from $hidden-less serialisation, kept out of logs, dumps, Telescope payloads, and queued job constructors, and never passed as raw byte strings across a JSON boundary. The $password argument to mnemonic derivation is a second factor that permanently changes the derived key — a UI "password" field must never be wired to it by accident, or we mint unrecoverable wallets. Mnemonic validation is ours to implement, not theirs. These are sprint-one acceptance criteria, not hardening tickets.
How can I help you explore Laravel packages today?