t2z
transparent to shielded (PCZT) polyglot library
Created on 4th December 2025
•
t2z
transparent to shielded (PCZT) polyglot library
The problem t2z 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 I 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
Tracks Applied (3)
Privacy Infrastructure & Developer Tools
Electric Coin Company
Privacy Infrastructure & Developer Tools
Zcash Community Grants
General Bounty
Project Tachyon
Technologies used
