Skip to content

Conversation

@chetanyb
Copy link
Contributor

@chetanyb chetanyb commented Oct 22, 2025

Summary

Integrates Poseidon2 (KoalaBear, width‑24) as an optional SSZ Merkle hasher via the hash-zig dependency, with a SHA256-compatible API wrapper specialized for 64-byte SSZ compressions.

Features

  • SHA256-like interface (init / update / final) that enforces exactly 64 bytes per digest (no padding, no streaming).
  • Poseidon2-24 KoalaBear backend pulled from hash-zig.
  • 24-bit packing (22 limbs) → one Poseidon2 permutation → 32-byte output; no feed-forward.
  • Zero hashes are recomputed with the active hasher; SSZ semantics preserved (single-chunk leaves returned directly).
  • Backward-compatible default: SHA256; enable Poseidon with -Dposeidon=true.
  • Added Plonky3 parity test suite runs only in Poseidon mode (checks against results from exact operations using Plonky3).

Important Notes

  • SSZ-specific: Designed solely for SSZ merkleization/mix-in paths that always provide 64 bytes. final asserts buffer_len == 64.
  • Not general-purpose: No padding or variable-length support; using it outside SSZ would be unsafe.
  • Width guard: Compile-time checks ensure the Poseidon2 type is width-24 and exposes the required Field and permutation.
  • Injectivity: 24-bit limbs (< p) avoid the lossy modulo reduction issue present in the old version.

Build Examples

# Default (SHA256)
zig build

# Poseidon2 (KoalaBear, width-24)
zig build -Dposeidon=true

@chetanyb chetanyb force-pushed the poseidon-integration branch from b6ac7df to fbb1efe Compare October 22, 2025 18:13
@chetanyb chetanyb marked this pull request as ready for review December 22, 2025 16:13
@chetanyb chetanyb requested a review from gballet as a code owner December 22, 2025 16:13
Copy link
Collaborator

@gballet gballet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically what we discussed during the team meeting

const deserialize = libssz.deserialize;
const hashTreeRoot = libssz.hashTreeRoot;
const std = @import("std");
const build_options = @import("build_options");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed during the call, please get rid of that option - the user should be the one deciding what hasher they use.

}

test "Validator struct hash tree root" {
if (build_options.poseidon_enabled) return;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and so the tests can use sha256, that's fine. And you can add some poseidon-specific tests if you want, although they could also be in the zeam repo so that we don't impose a new dependency on ssz.zig

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or in the poseidon-zig repo, see what is the simplest

Comment on lines +11 to +21

// Configure the hasher based on build options
pub const Hasher = if (build_options.poseidon_enabled) blk: {
const hash_zig = @import("hash_zig");
const poseidon2 = hash_zig.poseidon2;
const poseidon_wrapper = @import("./poseidon_wrapper.zig");
const Poseidon2Type = poseidon2.Poseidon2KoalaBear24Plonky3;
// Wrap with SHA256-compatible API
break :blk poseidon_wrapper.PoseidonHasher(Poseidon2Type);
} else sha256;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you shouldn't be needing this, pass the hasher as a type or anytype into functions


pub fn mixInLength2(root: [32]u8, length: usize, out: *[32]u8) void {
var hasher = sha256.init(sha256.Options{});
var hasher = Hasher.init(Hasher.Options{});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so here, for example, do

mixInLength2(Hasher: type, root, ... ) {

  var hasher = Hasher.init(Hasher.Options{});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants