
Federated Key Management
Note: KeyPears is a work-in-progress open-source password manager and cryptocurrency wallet. The design decisions described here represent our development approach and may evolve before our official release.
Last week we completed a significant migration: replacing Blake3 with SHA-256 throughout the KeyPears codebase. This wasn't because Blake3 failed us—it worked perfectly. We switched because SHA-256 is the industry standard, and that matters more than we initially appreciated.
This post explains the technical tradeoffs and why we made this decision.
The migration touched every layer of our stack:
Dependencies:
@webbuf/blake3 → @webbuf/sha256@webbuf/acb3 → @webbuf/acs2Functions:
blake3Hash() → sha256Hash()blake3Mac() → sha256Hmac()blake3Pbkdf() → sha256Pbkdf()acb3Encrypt() / acb3Decrypt() → acs2Encrypt() / acs2Decrypt()Encryption scheme:
Both hash functions produce 32-byte (256-bit) output, so our FixedBuf<32>
types remained unchanged. The migration was primarily find-and-replace with
updated test vectors.
Let's be clear: Blake3 is a technically superior hash function in many respects.
Speed: Blake3 is significantly faster than SHA-256, especially for large data. It achieves this through a Merkle tree construction that enables parallel hashing across multiple CPU cores. Where SHA-256 processes data sequentially, Blake3 can divide large inputs into chunks and hash them simultaneously.
Modern design: Blake3 was designed in 2020 with modern cryptographic insights. It's built on the well-analyzed BLAKE2 (used in Argon2, the recommended password hashing algorithm) and incorporates lessons from decades of hash function cryptanalysis.
Versatility: Blake3 supports keyed hashing (MAC), key derivation (KDF), and extendable output (XOF) natively. SHA-256 requires wrapper constructions like HMAC and HKDF for equivalent functionality.
Simplicity: Despite its speed, Blake3 has a remarkably simple specification. The reference implementation is ~500 lines of C.
We were happy with Blake3. Our key derivation system worked flawlessly:
// Three-tier key derivation (unchanged structure, new primitives)
function sha256Pbkdf(
password: string | WebBuf,
salt: FixedBuf<32>,
rounds: number = 100_000,
): FixedBuf<32> {
const passwordBuf =
typeof password === "string" ? WebBuf.fromUtf8(password) : password;
let result = sha256Hmac(salt, passwordBuf);
for (let i = 1; i < rounds; i++) {
result = sha256Hmac(salt, result.buf);
}
return result;
}
Blake3's killer feature is parallel hashing of large data. But KeyPears doesn't hash large data. We hash:
For inputs this small, Blake3's Merkle tree construction provides no benefit. The parallelization overhead might actually make it slower than sequential hashing for tiny inputs. And even if Blake3 were faster for small data, the difference would be measured in microseconds—completely irrelevant when our key derivation performs 100,000 PBKDF rounds that dominate execution time.
When we profiled vault creation:
The hash function choice affects performance by roughly 0.0001%. Switching from Blake3 to SHA-256 has no measurable impact on user experience.
When enterprise customers evaluate password managers, they ask questions like:
With Blake3, our answers required explanation: "We use Blake3, which is a modern hash function designed in 2020. It's based on BLAKE2, which is used in Argon2. It's very fast and secure, though it's not yet widely adopted..."
With SHA-256, our answer is: "Yes."
SHA-256 is:
The security difference between Blake3 and SHA-256 is negligible for our threat model—both provide 256-bit security against preimage and collision attacks. But the compliance difference is significant.
SHA-256 has been deployed in production systems since 2001. It secures:
This deployment scale represents the most extensive real-world cryptanalysis possible. If SHA-256 had weaknesses, attackers with billions of dollars in incentive would have found them.
Blake3 is mathematically sound and designed by respected cryptographers. But it was released in 2020 and hasn't yet accumulated the same scale of real-world testing. Given that both algorithms provide equivalent security for our use case, we chose the one with 24 years of battle-testing.
SHA-256 implementations exist in every programming language, every platform, and every hardware security module. If we ever need to:
SHA-256 will be expected and supported. Blake3 might require custom integration work.
This decision is not a criticism of Blake3. We want to be explicit:
Blake3 is secure. There are no known attacks, weaknesses, or concerns about Blake3's cryptographic security. It was designed by a team including the creators of Argon2 and BLAKE2.
Blake3 is technically superior for large data. If we were building a backup system, a file integrity checker, or a content-addressed storage system, Blake3 would be the obvious choice.
Blake3 may become an industry standard. It's gaining adoption, and in five years the "unknown algorithm" concern may disappear. We might even switch back.
We switched because SHA-256 is good enough for our specific use case, and the industry standard status provides tangible benefits that Blake3's technical advantages don't. This is an engineering tradeoff, not a quality judgment.
The actual migration took about a day:
Update dependencies: Replace @webbuf/blake3 with @webbuf/sha256,
@webbuf/acb3 with @webbuf/acs2
Update function calls: Find-and-replace across lib, api-server, tauri-ts, webapp
Update test vectors: SHA-256 produces different output than Blake3, so test expectations needed updating
Update documentation: Replace Blake3 references in crypto.md, auth.md, and AGENTS.md
Run tests: All 71 tests pass (40 in lib, 31 in api-server)
Manual testing: Create vaults, sync across devices, verify encryption works
The migration was straightforward because both hash functions have identical
output sizes (32 bytes) and the @webbuf packages have matching APIs. The
hardest part was updating documentation.
Breaking change note: This migration breaks compatibility with any existing encrypted data. Since we're pre-MVP with no real user data, this was acceptable. A production migration would require a more careful versioning strategy.
After this migration, KeyPears uses:
@webbuf/sha256)sha256Hmac())@webbuf/acs2)All cryptographic primitives are NIST-standardized algorithms with decades of real-world deployment. The underlying implementations are Rust compiled to WebAssembly, providing both memory safety and cross-platform consistency.
Technical superiority isn't always the deciding factor. Blake3 is faster, more modern, and arguably more elegant. SHA-256 is more widely understood, trusted, and required. For a security product, trust and compliance matter as much as technical merit.
Know your actual use case. Blake3's parallel hashing is irrelevant when you're hashing 32-byte keys. We spent time with an optimization we couldn't benefit from.
Industry standards exist for good reasons. NIST standardization, FIPS compliance, and widespread adoption aren't bureaucratic checkboxes—they represent accumulated trust that takes decades to build. Sometimes the "boring" choice is the right choice.
Migrations are easier early. Changing cryptographic primitives after MVP launch would require careful data migration and backward compatibility. Doing it now, with no real user data, was trivial.
We switched from Blake3 to SHA-256 not because Blake3 failed, but because SHA-256 succeeds in ways that matter more for our product: industry recognition, compliance compatibility, and customer trust.
Blake3 is an excellent hash function, and we'd recommend it for use cases that benefit from its parallel performance—large file hashing, content-addressed storage, or high-throughput data processing.
For a password manager where we're hashing small secrets and deriving keys, SHA-256 provides identical practical security with better industry positioning. When both options are secure, we chose the one that makes "Do you use industry-standard cryptography?" easy to answer.
The migration is complete, all tests pass, and vaults sync correctly. We're back to building features.