
Zelcore, a wallet that holds KAS next to many other coins, has released kaspa-core as open source. It is a library that builds and signs Kaspa transactions in TypeScript, a widely used form of JavaScript, the language that runs in every web browser. It needs no extra engine, only two well-known cryptography libraries. Zelcore says that switching its own wallet to kaspa-core will remove an 11.5 MB file the app has to load today, making it lighter and faster (announcement).
The library was written by Tadeas Kmenta, who describes himself as the architect of Flux, Zelcore and the SSP wallet. Version 1.0.0 came out on 25 September under the MIT licence, which lets anyone use, change and share the code (kaspa-core). It runs in web pages, browser extensions, desktop apps built with Electron, servers running Node.js and phone apps built with React Native.
Why wallets carry a big file
The rules for Kaspa transactions live in rusty-kaspa, the Rust software that runs Kaspa nodes. A wallet has to follow those rules exactly, and the safest way to do that is to reuse the node's own code.
A JavaScript app cannot run Rust directly, so the Rust code is packed into WASM, short for WebAssembly. WASM is a format that lets browsers and JavaScript apps run code written in other languages. It gives the wallet the same rules the nodes use. The price is size. Zelcore's copy is 11.5 MB, and the app has to load it before it can build a payment.
kaspa-core takes the other road. It writes the same rules again in TypeScript, so a wallet only loads ordinary code it already knows how to run. That road has its own difficulty. Two copies of the rules have to agree exactly, and they have to stay in step every time Kaspa changes. Much of the project is about showing that they do.
What the library does
It covers the jobs a wallet does for a payment. It turns keys into Kaspa addresses, picks which coins to spend, builds the transaction and signs it. It signs with Schnorr signatures in the BIP340 format that Bitcoin also uses.
It also works out the fee exactly. Kaspa prices a transaction by its mass, a measure of how much work and storage it costs the network. A rule called KIP-9 makes very small outputs cost much more, so the network does not fill up with dust. The library calculates the final mass before any key signs. By default it adds change below 0.5 KAS to the fee, because keeping such a tiny amount is so expensive under KIP-9, and it never adds more than 1 KAS this way without telling the app (design notes).
Then there are shared wallets. A shared wallet, often called multisig, holds coins that need approval from several keys. A company might set one up so that any 3 of its 5 managers must sign before money moves. kaspa-core supports every combination from 1 of 1 up to 15 of 15. It refuses more than 15 keys by default, because Kaspa nodes do not pass larger ones on to the rest of the network (shared wallets).
The keys themselves stay outside the library. A signer can be a key kept on the device, a Ledger hardware wallet or a phone's secure chip, and the library never holds a seed phrase.
Two of Zelcore's own features come with it. One creates KRC-20 token transfers, using the same pair of commit and reveal transactions that Zelcore uses today. The other sends coins into Igra, a smart-contract network built on top of Kaspa. The library also includes its own client for talking to Kaspa nodes, which replaces the one that came inside the WASM file.
Two devices, one payment
The library was built for two products. One is the Zelcore wallet. The other is SSP, a wallet from the same team where every payment needs two approvals, one from the SSP Wallet and one from a second device running SSP Key. The first device builds the payment and signs half of it. The request then travels to the second device, which checks it and adds the second signature.
A second device only helps if a hacked first device cannot trick it. The library gives the second device several guards for that. It looks up the coins being spent by itself, ideally through a different server, instead of believing what the first device says. It shows the person the recipients, the amount leaving the wallet and the fee before they approve. It only signs for the wallet it belongs to. And it keeps a record of the amounts it has already signed (co-signer guards).
That record matters because of how Kaspa signatures work. A signature covers the amount of the coin it unlocks, but not the amounts of the other coins in the same payment. Without the record, an attacker could collect signatures over several sessions, lie about a different coin each time, and combine them into one payment with a huge fee. The library can offer these guards, but an app has to use them. Its documentation says a co-signing device must use all four.
Where builders can use it
kaspa-core is not an app that people download. It is a building block for developers who make Kaspa apps, and because it is written in the language of the web, it fits almost anywhere JavaScript runs. The MIT licence lets them use it in open-source and paid products alike.
The most obvious users are wallets. A team building a Kaspa wallet as a website, a browser extension, a desktop app or a phone app can use the library to check balances and history, build and sign payments, and show the exact fee before the user confirms. Wallets built on the WASM toolkit could make the same switch Zelcore is planning.
Shops and payment services are another fit. The node client can watch an address and report the moment new coins arrive, which is what a checkout page needs to see that a customer has paid. A payment can also carry a short message, which a shop could use for an order number (node client).
Teams and companies could build their own approval apps on the shared-wallet tools. One person proposes a payment, and the others approve it on their own phones or computers, in any order, until enough of them have signed. The payment gets its final ID before anyone signs, so a server can keep track of each proposal. That server can check every signature it receives without holding any keys, so it has no way to move the money itself (shared wallets, SSP flows).
Services that collect many small payments have a different problem. Tips, rewards and mining payouts leave a wallet full of tiny coins, and one transaction can only spend so many of them. The library can sweep them together into one coin. When a payment needs more coins than fit in one transaction, it plans a chain of transactions that can all be signed in one go (sweeps and chains).
For a small team, this lowers the cost of trying an idea. A JavaScript developer can add real Kaspa payments to a web page or an app without shipping a large extra file. The whole library is ordinary TypeScript on top of two well-known cryptography libraries, so they can read all of the code that builds and signs their payments.
How the copy was checked
The main risk with a second copy of the rules is a small difference that nobody notices until a payment fails or coins get stuck. The project checks kaspa-core against the real thing in several ways.
First, a test tool links rusty-kaspa's own code, pinned to one exact version, and compares its answers with kaspa-core byte by byte. That covers addresses, scripts, transaction IDs, the data each signature covers, and mass (test tool).
Second, transactions signed by kaspa-core are run through the script engine from rusty-kaspa, the part of a node that decides whether signatures really unlock the coins. That includes all 120 shared-wallet combinations up to 15 of 15, with the signatures added in random order.
Third, the team spent real KAS with it. On 25 September it sent transactions built by the library on mainnet, including a normal payment, a two-device SSP payment, a 10-of-15 company wallet, a KRC-20 transfer and an Igra entry (mainnet test list). All twelve transactions in that list appear on the network as accepted, sent within half an hour of each other that morning (10-of-15 example).
What the security review found
Before the release, the code went through two rounds of review in which reviewers tried to break it. The write-up calls the reviews independent but does not say who did them.
The first round found two serious problems and four medium ones. The second round found six more medium ones. None were rated critical, and all were fixed, each with a test that fails if the problem comes back (findings).
The two serious ones show what is at stake. In the first, a shared company wallet accepted a key that was not a valid key at all. rusty-kaspa stops checking signatures when it reaches such a key, so one dishonest member could have locked the wallet forever by submitting one when the wallet was set up. In the second, nothing capped the fee, so a dishonest server reporting fee rates could have made a wallet spend its coins on fees. The library now rejects invalid keys, and it refuses a fee above 5 KAS unless the app raises the limit.
How developers can start
The library is one package on npm, where most JavaScript libraries are published, under the name @runonflux/kaspa-core. Its guide walks through a normal payment, a two-device payment, a connection to a Kaspa node, a KRC-20 transfer and an Igra entry, with example code for each (guide).
The safest first step is testnet-10, the practice network where coins have no value, and the library works with it as well as with mainnet (network settings). On servers, it is tested with Node.js 22 and 24 (release checks).
The write-up also lists jobs that stay with the app, because a library cannot do them on its own (builder duties). Private keys belong in the device's secure storage and should be loaded only for the moment of signing. When a user pastes an address, the app should tell the library which network it expects, so a testnet address is refused in a mainnet wallet. Phone apps built with React Native need one extra package for secure random numbers, and without it the cryptography code stops with an error instead of using weak ones. And if a payment is sent but no answer comes back, it may still have reached the network. The app should send the identical signed transaction again or look it up, and never build a new one from different coins, because that could pay twice.
What is not ready yet
kaspa-core is brand new. It was published on 25 September as a single commit, and nobody outside the team has contributed to it yet. Zelcore's announcement does not give a date for when its own wallet will switch.
Some things are missing. Messages and Igra entries have to be sent through the node client, because the simpler web connection only handles plain payments. For that node client, the team advises serious apps to run their own Kaspa node, because public servers support it today only through their current setup. The library signs with Schnorr only, not the older ECDSA method, and it passes half-signed payments in its own format rather than PSKT, the format built into rusty-kaspa (limitations).
Speed is fine for everyday use. A payment spending 1 to 20 coins signs in a few hundredths of a second, but combining 1,000 small coins into one takes about 5 seconds on a desktop computer.
The bigger long-term job is keeping up. Kaspa changes its rules through network upgrades, and the write-up expects about one a year. Each time, the team has to point its test tool at the new version of rusty-kaspa, find every difference and update the library. An app that uses kaspa-core depends on that work being done in time.
For people who use Zelcore, little should change on the surface. If the switch goes as planned, the wallet gets lighter and payments follow the same rules as before.
