Back to projects
t2z icon

t2z

transparent to shielded (PCZT) polyglot library

$3,000
Total awarded
Dominik
Builder
Node.js JavaScript Java Docker Kotlin Golang Rust TypeScript

Awards

The problem it solves

Problem

Zcash shielded transactions require Rust-based tooling, locking out developers working in Go, TypeScript, Kotlin, and Java. There’s no cross-language solution for building and signing shielded transactions (PCZTs).

until now

Solution

Rust core with idiomatic native bindings for Go, TypeScript, Kotlin, and Java.

Build and sign shielded Zcash transactions in your language. No Rust knowledge needed. The crypto stays in battle-tested Rust, you just call it from whatever stack you’re already using.

More devs can build on Zcash without learning a new language.

Challenges we ran into

CHALLANGES

Understanding the ecosystem

I started from 0 the only thing I knew of ZEC was that it has privacy features, the ticker and my balance on CEX. The zcash ecosystem can be a bit confusing, nodes, wallets, libraries.

I acquired the knowledge for the appropriate and up2date tools. (And thx to NEAR intents I was confident to fully offboard from CEX)


ZIP-317 Fee Calculation Mismatch

I calculated fees differently than the Builder, causing “ChangeRequired” errors when amounts didn’t balance

I matched the Builder’s exact formula: 5000 * max(2, logical_actions).


Upstream Library Breaking Changes

Initially I created a fork and fixed the bugs (https://github.com/gstohl/librustzcash/tree/pczt-append-transparent-sigs) and added needed features of library branch https://github.com/zcash/librustzcash/tree/pczt-append-transparent-sigs. When upstream fixed things and added features, method names and signatures changed.

After upstream updated I had to migrated to it, so I needed to update renamed methods and new error variants.


Cross-Language Memory Management

Rust uses ownership/borrowing, but Go/TypeScript/Kotlin/Java have garbage collection.

I serialize PCZT to bytes at FFI boundary, each language manages its own copy.


Bridge Solution Selection

I had to choose from multiple options for each language (cgo vs pure Go, N-API vs WASM vs KOFFI, JNI vs JNA) with different tradeoffs.

I selected based on maintainability:

  • Go → cgo
  • TypeScript → koffi
  • Kotlin/Java → JNA

Unified Workflow Across Languages

Each language has different idioms for error handling, async, and byte arrays.

I wrapped the same C FFI but made each binding feel native, for example:

  • Go: multiple return values for errors
  • TypeScript: promises and thrown exceptions
  • Kotlin/Java: exceptions with ByteArray/byte[]

Submission Video

The hardest challenge was to make the submission video

Gallery