Skip to content

Commit e9be620

Browse files
committed
fix: separate on-chain/off-chain paths in hasher modules to prevent stack overflow
Applied the same fix pattern to all hasher modules: - sha256_hasher.zig - keccak_hasher.zig - blake3.zig Each hashv() function now uses `if (comptime is_bpf_program)` to dispatch to separate implementation functions: - hashvSyscall() - on-chain, uses syscall, minimal stack - hashvNative() - off-chain, uses Zig crypto, only compiled for native This ensures the crypto hasher state (which can be several KB) is never allocated on stack in BPF programs. All 361 tests pass.
1 parent c0da6f9 commit e9be620

3 files changed

Lines changed: 72 additions & 45 deletions

File tree

src/blake3.zig

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,33 @@ const Hash = @import("solana_sdk").Hash;
1818
/// Rust equivalent: `solana_blake3_hasher::hashv`
1919
/// Source: https://github.com/anza-xyz/solana-sdk/blob/master/blake3-hasher/src/lib.rs
2020
pub fn hashv(vals: []const []const u8) Hash {
21-
var result_hash: Hash = undefined;
22-
23-
if (syscalls.is_bpf_program) {
24-
// BPF context: use syscall
25-
const syscall_result = syscalls.sol_blake3(@ptrCast(vals.ptr), vals.len, &result_hash.bytes);
26-
if (syscall_result != 0) {
27-
log.print("failed to get blake3 hash: error code {}", .{syscall_result});
28-
@panic("blake3 syscall failed");
29-
}
21+
// Use comptime to ensure off-chain code is not compiled into BPF
22+
if (comptime syscalls.is_bpf_program) {
23+
return hashvSyscall(vals);
3024
} else {
31-
// Native context: use Zig's crypto library
32-
var hasher = std.crypto.hash.Blake3.init(.{});
33-
for (vals) |val| {
34-
hasher.update(val);
35-
}
36-
hasher.final(&result_hash.bytes);
25+
return hashvNative(vals);
26+
}
27+
}
28+
29+
/// On-chain implementation using syscall - minimal stack usage
30+
fn hashvSyscall(vals: []const []const u8) Hash {
31+
var result_hash: Hash = undefined;
32+
const syscall_result = syscalls.sol_blake3(@ptrCast(vals.ptr), vals.len, &result_hash.bytes);
33+
if (syscall_result != 0) {
34+
log.print("failed to get blake3 hash: error code {}", .{syscall_result});
35+
@panic("blake3 syscall failed");
3736
}
37+
return result_hash;
38+
}
3839

40+
/// Off-chain implementation using Zig's crypto library - only compiled for native
41+
fn hashvNative(vals: []const []const u8) Hash {
42+
var result_hash: Hash = undefined;
43+
var hasher = std.crypto.hash.Blake3.init(.{});
44+
for (vals) |val| {
45+
hasher.update(val);
46+
}
47+
hasher.final(&result_hash.bytes);
3948
return result_hash;
4049
}
4150

src/keccak_hasher.zig

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,33 @@ const Hash = @import("solana_sdk").Hash;
2020
/// Rust equivalent: `solana_keccak_hasher::hashv`
2121
/// Source: https://github.com/anza-xyz/solana-sdk/blob/master/keccak-hasher/src/lib.rs
2222
pub fn hashv(vals: []const []const u8) Hash {
23-
var result_hash: Hash = undefined;
24-
25-
if (syscalls.is_bpf_program) {
26-
// BPF context: use syscall
27-
const syscall_result = syscalls.sol_keccak256(@ptrCast(vals.ptr), vals.len, &result_hash.bytes);
28-
if (syscall_result != 0) {
29-
log.print("failed to get keccak256 hash: error code {}", .{syscall_result});
30-
@panic("keccak256 syscall failed");
31-
}
23+
// Use comptime to ensure off-chain code is not compiled into BPF
24+
if (comptime syscalls.is_bpf_program) {
25+
return hashvSyscall(vals);
3226
} else {
33-
// Native context: use Zig's crypto library
34-
var hasher = std.crypto.hash.sha3.Keccak256.init(.{});
35-
for (vals) |val| {
36-
hasher.update(val);
37-
}
38-
hasher.final(&result_hash.bytes);
27+
return hashvNative(vals);
28+
}
29+
}
30+
31+
/// On-chain implementation using syscall - minimal stack usage
32+
fn hashvSyscall(vals: []const []const u8) Hash {
33+
var result_hash: Hash = undefined;
34+
const syscall_result = syscalls.sol_keccak256(@ptrCast(vals.ptr), vals.len, &result_hash.bytes);
35+
if (syscall_result != 0) {
36+
log.print("failed to get keccak256 hash: error code {}", .{syscall_result});
37+
@panic("keccak256 syscall failed");
3938
}
39+
return result_hash;
40+
}
4041

42+
/// Off-chain implementation using Zig's crypto library - only compiled for native
43+
fn hashvNative(vals: []const []const u8) Hash {
44+
var result_hash: Hash = undefined;
45+
var hasher = std.crypto.hash.sha3.Keccak256.init(.{});
46+
for (vals) |val| {
47+
hasher.update(val);
48+
}
49+
hasher.final(&result_hash.bytes);
4150
return result_hash;
4251
}
4352

src/sha256_hasher.zig

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,33 @@ const Hash = @import("solana_sdk").Hash;
1818
/// Rust equivalent: `solana_sha256_hasher::hashv`
1919
/// Source: https://github.com/anza-xyz/solana-sdk/blob/master/sha256-hasher/src/lib.rs
2020
pub fn hashv(vals: []const []const u8) Hash {
21-
var result_hash: Hash = undefined;
22-
23-
if (syscalls.is_bpf_program) {
24-
// BPF context: use syscall
25-
const syscall_result = syscalls.sol_sha256(@ptrCast(vals.ptr), vals.len, &result_hash.bytes);
26-
if (syscall_result != 0) {
27-
log.print("failed to get sha256 hash: error code {}", .{syscall_result});
28-
@panic("sha256 syscall failed");
29-
}
21+
// Use comptime to ensure off-chain code is not compiled into BPF
22+
if (comptime syscalls.is_bpf_program) {
23+
return hashvSyscall(vals);
3024
} else {
31-
// Native context: use Zig's crypto library
32-
var hasher = std.crypto.hash.sha2.Sha256.init(.{});
33-
for (vals) |val| {
34-
hasher.update(val);
35-
}
36-
hasher.final(&result_hash.bytes);
25+
return hashvNative(vals);
26+
}
27+
}
28+
29+
/// On-chain implementation using syscall - minimal stack usage
30+
fn hashvSyscall(vals: []const []const u8) Hash {
31+
var result_hash: Hash = undefined;
32+
const syscall_result = syscalls.sol_sha256(@ptrCast(vals.ptr), vals.len, &result_hash.bytes);
33+
if (syscall_result != 0) {
34+
log.print("failed to get sha256 hash: error code {}", .{syscall_result});
35+
@panic("sha256 syscall failed");
3736
}
37+
return result_hash;
38+
}
3839

40+
/// Off-chain implementation using Zig's crypto library - only compiled for native
41+
fn hashvNative(vals: []const []const u8) Hash {
42+
var result_hash: Hash = undefined;
43+
var hasher = std.crypto.hash.sha2.Sha256.init(.{});
44+
for (vals) |val| {
45+
hasher.update(val);
46+
}
47+
hasher.final(&result_hash.bytes);
3948
return result_hash;
4049
}
4150

0 commit comments

Comments
 (0)