Page MenuHomePhabricator

[avalanche-lib-wasm] Introduce a new library for managing stakes, proofs and delegations
ClosedPublic

Authored by Fabien on Sep 10 2025, 21:26.

Details

Summary

This Rust library also provide bindings for WASM so it can be used in web projects.
This lib is small enough and has very limited dependencies. The implementation can be compared with the C++ and Python reference implementations. Most of the test vectors are shared with these implementations too.

The choice of Rust makes it easy to encapsulate the signature and verification processes that use the ecash-libsecp256k1, so the cryptography is secure. The remaining part being mostly serialization/deserialization, Rust is a good fit for the job.

A typescript library and a Rust CLI tool are coming in follow-up diffs.

Test Plan
cargo build
cargo test
./build-wasm.sh

Diff Detail

Repository
rABC Bitcoin ABC
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Fabien requested review of this revision.Sep 10 2025, 21:26

Fix Cargo.toml identation

why rust + wasm and not just ts? is it easier / more direct to recreate the c++ code / tests in rust?

I don't think it's bad but it is a decision, potentially complicated how the lib will work in web. for ecash-lib, only the encryption methods and things that depend on our monorepo ecash-secp256k are in rust, the rest is in the ts lib

modules/avalanche-lib-wasm/Cargo.toml
44 ↗(On Diff #55595)

is this ok or do we newline

modules/avalanche-lib-wasm/src/delegation.rs
5 ↗(On Diff #55595)

is the //! comment some kind of rust standard?

modules/avalanche-lib-wasm/src/key.rs
33 ↗(On Diff #55595)

where is this used?

does this need to be secure / entropy-driven randomness?

modules/avalanche-lib-wasm/src/lib.rs
42 ↗(On Diff #55595)

the whole initWasm() thing was a big headache in ecash-lib. I don't remember exactly how we got rid of it, would have to dive back in. But flag that, once this lib and its module are available, should probably also have a simple react app that proves it can be used in a web env, shows the dev api (i.e. do we need to do something like initWasm on page load)

why rust + wasm and not just ts? is it easier / more direct to recreate the c++ code / tests in rust?

I don't think it's bad but it is a decision, potentially complicated how the lib will work in web. for ecash-lib, only the encryption methods and things that depend on our monorepo ecash-secp256k are in rust, the rest is in the ts lib

Good question, I'll update the summary. The point was to encapsulate the signature and verification process so it uses ecash-secp256k1. Then it's easy to use rust for binary format management and this lib is mostly that, serialization/deserialization.
I prepared a ts lib as well the wraps the wasm, it be submitted in another diff. I also use the Rust interface for the CLI tool and for that usage it's much more convenient to have Rust rather than TS

modules/avalanche-lib-wasm/Cargo.toml
44 ↗(On Diff #55595)

It's not OK I will update

modules/avalanche-lib-wasm/src/delegation.rs
5 ↗(On Diff #55595)

It's standard for doxygen comments

modules/avalanche-lib-wasm/src/key.rs
33 ↗(On Diff #55595)

This is used to generate a new key pair in a suitable format, which is something commonly needed for building proofs. This is also the same method the node uses under the hood for generating its private keys

modules/avalanche-lib-wasm/src/lib.rs
42 ↗(On Diff #55595)

Yes I really left it so it's no change in the callsites if we need to do something to make this work (as you can see it's empty for now). I will try to use it in react to see how it goes, but I don't think that's a blocker for now.

This revision is now accepted and ready to land.Sep 11 2025, 15:14
PiRK added inline comments.
modules/avalanche-lib-wasm/.gitignore
12–17 ↗(On Diff #55595)

it would make sense to have these in the monorepo root's .gitignore

modules/avalanche-lib-wasm/src/pubkey.rs
14–26 ↗(On Diff #55595)

as far as i can tell the only reason of this PublickKeyFormat enum and FormattedPublicKey wrapper is so an input PublicKey can be serialized in either format on demand.
But I don't really understand the use case for this, afaict we always need to serialize a key in its original format.

modules/avalanche-lib-wasm/.gitignore
12–17 ↗(On Diff #55595)

and they probably are, I'll check for duplicates. TBH this has been generated and I didn't look closely

modules/avalanche-lib-wasm/src/pubkey.rs
14–26 ↗(On Diff #55595)

Exactly, so when you read (aka deserialize) an existing object (e.g. existing proof) your need to determine whether the contained pubkeys are in uncompressed or uncompressed format, and store the info somewhere so you can reuse the same format when serializing. This is what this FormattedPublicKey structure is for.
There is an exception: the stake committment hash always use the compressed format.

PiRK added inline comments.
modules/avalanche-lib-wasm/src/pubkey.rs
14–26 ↗(On Diff #55595)

OK. I think my objection is that the ecash_secp256k1::PublicKey should be responsible for remembering which format it is when constructed via PublicKey::from_slice and then have PublicKey::serialize automatically pick the right format. This would avoid having to implement two serialization methods when only one of them will ever be called.
But it is not directly related to this diff and to this library, it's a quirk of another module.

Newline in Cargo.toml, cleanup the .gitignore