From a9ecaf5e77fb0c672e34a53534091ec34ebf7a53 Mon Sep 17 00:00:00 2001 From: David Rubin Date: Wed, 11 Jun 2025 01:25:00 -0700 Subject: [PATCH 1/2] refactor sha256 hash api --- conformance/src/txn_execute.zig | 29 +++++----- src/consensus/optimistic_vote_verifier.zig | 12 ++--- src/consensus/vote_listener.zig | 4 +- src/core/blockhash_queue.zig | 6 +-- src/core/entry.zig | 25 +++++---- src/core/hash.zig | 61 +++++++--------------- src/core/poh.zig | 10 ++-- src/core/shred.zig | 2 +- src/gossip/fuzz_service.zig | 12 ++--- src/gossip/ping_pong.zig | 4 +- src/gossip/service.zig | 2 +- src/gossip/table.zig | 2 +- src/ledger/database/hashmap.zig | 1 + src/ledger/database/interface.zig | 7 +-- src/ledger/database/rocksdb.zig | 2 +- src/ledger/shred.zig | 6 +-- src/replay/freeze.zig | 35 +++++++------ src/runtime/check_transactions.zig | 4 +- src/runtime/nonce.zig | 5 +- src/runtime/program/vote/state.zig | 7 +-- src/runtime/pubkey_utils.zig | 12 ++--- 21 files changed, 116 insertions(+), 132 deletions(-) diff --git a/conformance/src/txn_execute.zig b/conformance/src/txn_execute.zig index 9be83cfd1d..464043f381 100644 --- a/conformance/src/txn_execute.zig +++ b/conformance/src/txn_execute.zig @@ -1397,25 +1397,22 @@ pub fn hashSlot( var signature_count_bytes: [8]u8 = undefined; std.mem.writeInt(u64, &signature_count_bytes, 0, .little); - const initial_hash = - if (feature_set.active(.remove_accounts_delta_hash, 0)) - Hash.generateSha256(.{ - Hash.ZEROES, - &signature_count_bytes, - blockhash, - }) - else - Hash.generateSha256(.{ - Hash.ZEROES, - try freeze.deltaMerkleHash(account_reader, allocator, 0), - &signature_count_bytes, - blockhash, - }); + var hash = std.crypto.hash.sha2.Sha256.init(.{}); + hash.update(&sig.core.Hash.ZEROES.data); // no parent lt hash, start with zeroes + if (!feature_set.active(.remove_accounts_delta_hash, 0)) { + const delta_hash = try freeze.deltaMerkleHash(account_reader, allocator, 0); + hash.update(&delta_hash.data); + } + hash.update(&blockhash.data); + const initial_hash = hash.finalResult(); return if (feature_set.active(.accounts_lt_hash, 0)) - Hash.generateSha256(.{ initial_hash, sig.core.hash.LtHash.IDENTITY.constBytes() }) + Hash.initMany(&.{ + &initial_hash, + sig.core.hash.LtHash.IDENTITY.constBytes(), + }) else - initial_hash; + .{ .data = initial_hash }; } const State = struct { diff --git a/src/consensus/optimistic_vote_verifier.zig b/src/consensus/optimistic_vote_verifier.zig index 9d8133b721..5f7d4a9226 100644 --- a/src/consensus/optimistic_vote_verifier.zig +++ b/src/consensus/optimistic_vote_verifier.zig @@ -306,9 +306,9 @@ test "OptimisticConfirmationVerifier.verifyForUnrootedOptimisticSlots: unrooted ); // Hashes for slots 1,3,5 - const h1 = Hash.generateSha256("1"); - const h3 = Hash.generateSha256("3"); - const h5 = Hash.generateSha256("5"); + const h1 = Hash.init("1"); + const h3 = Hash.init("3"); + const h5 = Hash.init("5"); var verifier = OptimisticConfirmationVerifier.init( sig.time.Instant.now(), @@ -369,7 +369,7 @@ test "OptimisticConfirmationVerifier.verifyForUnrootedOptimisticSlots: unrooted const unrooted = try verifier.verifyForUnrootedOptimisticSlots( allocator, &ledger_reader, - .{ .slot = 4, .hash = Hash.generateSha256("4"), .ancestors = &anc4 }, + .{ .slot = 4, .hash = Hash.init("4"), .ancestors = &anc4 }, ); defer allocator.free(unrooted); try std.testing.expectEqual(1, unrooted.len); @@ -395,7 +395,7 @@ test "OptimisticConfirmationVerifier.verifyForUnrootedOptimisticSlots: unrooted const unrooted = try verifier.verifyForUnrootedOptimisticSlots( allocator, &ledger_reader, - .{ .slot = 7, .hash = Hash.generateSha256("7"), .ancestors = &anc7 }, + .{ .slot = 7, .hash = Hash.init("7"), .ancestors = &anc7 }, ); defer allocator.free(unrooted); // Expect two entries (1 and 3), order by slot ascending due to set ordering @@ -423,7 +423,7 @@ test "OptimisticConfirmationVerifier.verifyForUnrootedOptimisticSlots: unrooted const unrooted = try verifier.verifyForUnrootedOptimisticSlots( allocator, &ledger_reader, - .{ .slot = 7, .hash = Hash.generateSha256("7"), .ancestors = &anc7 }, + .{ .slot = 7, .hash = Hash.init("7"), .ancestors = &anc7 }, ); defer allocator.free(unrooted); try std.testing.expectEqual(0, unrooted.len); diff --git a/src/consensus/vote_listener.zig b/src/consensus/vote_listener.zig index fa6e0a27b6..6aecb40252 100644 --- a/src/consensus/vote_listener.zig +++ b/src/consensus/vote_listener.zig @@ -1601,14 +1601,14 @@ test "vote_parser.parseVoteTransaction" { var prng = std.Random.DefaultPrng.init(42); const random = prng.random(); try vote_parser.testParseVoteTransaction(null, random); - try vote_parser.testParseVoteTransaction(Hash.generateSha256(&[_]u8{42}), random); + try vote_parser.testParseVoteTransaction(Hash.init(&.{42}), random); } test "vote_parser.parseSanitizedVoteTransaction" { var prng = std.Random.DefaultPrng.init(43); const random = prng.random(); try vote_parser.testParseSanitizedVoteTransaction(null, random); - try vote_parser.testParseSanitizedVoteTransaction(Hash.generateSha256(&[_]u8{43}), random); + try vote_parser.testParseSanitizedVoteTransaction(Hash.init(&.{43}), random); } test verifyVoteTransaction { diff --git a/src/core/blockhash_queue.zig b/src/core/blockhash_queue.zig index 931ab4e3c3..997a9fff61 100644 --- a/src/core/blockhash_queue.zig +++ b/src/core/blockhash_queue.zig @@ -212,15 +212,15 @@ test "reject old last hash" { defer queue.deinit(allocator); for (0..102) |i| { - const last_hash_i = Hash.ZEROES.extendAndHash(&[_]u8{@intCast(i)}); + const last_hash_i = Hash.ZEROES.extend(&[_]u8{@intCast(i)}); try queue.insertHash(allocator, last_hash_i, 0); } - const hash_0 = Hash.ZEROES.extendAndHash(&[_]u8{@intCast(0)}); + const hash_0 = Hash.ZEROES.extend(&[_]u8{@intCast(0)}); try std.testing.expect(!queue.isHashValidForAge(hash_0, max_age)); try std.testing.expect(!queue.isHashValidForAge(hash_0, 0)); - const hash_1 = Hash.ZEROES.extendAndHash(&[_]u8{@intCast(1)}); + const hash_1 = Hash.ZEROES.extend(&[_]u8{@intCast(1)}); try std.testing.expect(queue.isHashValidForAge(hash_1, max_age)); try std.testing.expect(!queue.isHashValidForAge(hash_1, 0)); } diff --git a/src/core/entry.zig b/src/core/entry.zig index 09768ec4c6..65f364c367 100644 --- a/src/core/entry.zig +++ b/src/core/entry.zig @@ -110,20 +110,19 @@ pub fn verifyPoh( if (entry.num_hashes == 0) continue; for (1..entry.num_hashes) |_| { - current_hash = Hash.generateSha256(¤t_hash.data); + current_hash = Hash.init(¤t_hash.data); } if (entry.transactions.len > 0) { - const mixin = - try hashTransactions(allocator, optional.preallocated_nodes, entry.transactions); - current_hash = current_hash.extendAndHash(&mixin.data); - } else { - current_hash = Hash.generateSha256(¤t_hash.data); - } - - if (!current_hash.eql(entry.hash)) { - return false; - } + const mixin = try hashTransactions( + allocator, + optional.preallocated_nodes, + entry.transactions, + ); + current_hash = current_hash.extend(&mixin.data); + } else current_hash = Hash.init(¤t_hash.data); + + if (!current_hash.eql(entry.hash)) return false; } return true; @@ -159,7 +158,7 @@ pub fn hashTransactions( try nodes.ensureTotalCapacity(allocator, capacity); for (transactions) |tx| for (tx.signatures) |signature| { - const hash = Hash.generateSha256(.{ LEAF_PREFIX, &signature.data }); + const hash = Hash.initMany(&.{ LEAF_PREFIX, &signature.data }); nodes.appendAssumeCapacity(hash); }; @@ -177,7 +176,7 @@ pub fn hashTransactions( // Duplicate last entry if the level length is odd &nodes.items[prev_level_start + prev_level_idx]; - const hash = Hash.generateSha256(.{ INTERMEDIATE_PREFIX, &lsib.data, &rsib.data }); + const hash = Hash.initMany(&.{ INTERMEDIATE_PREFIX, &lsib.data, &rsib.data }); nodes.appendAssumeCapacity(hash); } prev_level_start = level_start; diff --git a/src/core/hash.zig b/src/core/hash.zig index 8354429af1..cb85c3ed70 100644 --- a/src/core/hash.zig +++ b/src/core/hash.zig @@ -36,54 +36,33 @@ pub const Hash = extern struct { pub const SIZE = 32; - pub const ZEROES: Hash = .{ .data = .{0} ** SIZE }; - - /// Hashes the input byte slice(s) using SHA 256. - /// - /// If the passed-in type contains multiple byte slices, it will - /// iterate/recurse over them in order, updating the hasher for all of them - /// before finalizing at the end. - pub fn generateSha256( - /// May be a slice or array of bytes, or a slice, array, or tuple - /// containing slices or arrays of bytes nested with arbitrary depth. - /// - /// for example: - /// - []const u8 - /// - []const []const u8 - /// - [2]u8 - /// - *[13]u8 - /// - struct { [128]u8, []const []const u8, struct { []const u8 }, ... } - data: anytype, - ) Hash { - var hasher = Sha256.init(.{}); - update(&hasher, data); - return .{ .data = hasher.finalResult() }; + pub const ZEROES: Hash = .{ .data = @splat(0) }; + + /// Creates a `Hash` by applying SHA256 to the input `data` and using + /// the result of that as the output. + pub fn init(data: []const u8) Hash { + var out: [32]u8 = undefined; + Sha256.hash(data, &out, .{}); + return .{ .data = out }; } - /// re-hashes the current hash with the mixed-in byte slice(s). - pub fn extendAndHash(self: Hash, data: anytype) Hash { - return generateSha256(.{ self.data, data }); + /// Does the same thing as `init`, but updates the hash with each + /// input slice from the `data` list. + pub fn initMany(data: []const []const u8) Hash { + var new = Sha256.init(.{}); + for (data) |d| new.update(d); + return .{ .data = new.finalResult() }; } - fn update(hasher: *Sha256, data: anytype) void { - const T = @TypeOf(data); - - if (T == Hash or T == *const Hash or T == *Hash) { - hasher.update(&data.data); - } else if (@typeInfo(T) == .@"struct") { - inline for (data) |val| update(hasher, val); - } else if (std.meta.Elem(T) == u8) switch (@typeInfo(T)) { - .array => hasher.update(&data), - else => hasher.update(data), - } else { - for (data) |val| update(hasher, val); - } + /// re-hashes the current hash with the mixed-in byte slice(s). + pub fn extend(self: Hash, data: []const u8) Hash { + return .initMany(&.{ &self.data, data }); } pub fn eql(self: Hash, other: Hash) bool { - const xx: @Vector(SIZE, u8) = self.data; - const yy: @Vector(SIZE, u8) = other.data; - return @reduce(.And, xx == yy); + const x: @Vector(SIZE, u8) = self.data; + const y: @Vector(SIZE, u8) = other.data; + return @reduce(.And, x == y); } pub fn order(self: *const Hash, other: *const Hash) std.math.Order { diff --git a/src/core/poh.zig b/src/core/poh.zig index a92a9554ed..65ae57622b 100644 --- a/src/core/poh.zig +++ b/src/core/poh.zig @@ -36,7 +36,7 @@ pub const Poh = struct { pub fn hash(self: *Poh, max_num_hashes: u64) bool { const num_hashes = @min(self.remaining_hashes -| 1, max_num_hashes); for (0..num_hashes) |_| { - self.latest_hash = self.latest_hash.extendAndHash(.{}); + self.latest_hash = .init(&self.latest_hash.data); } self.num_hashes += num_hashes; self.remaining_hashes -= num_hashes; @@ -70,12 +70,12 @@ pub const Poh = struct { return null; // needs a tick first } - self.latest_hash = self.latest_hash.extendAndHash(mixin.data); + self.latest_hash = self.latest_hash.extend(&mixin.data); const num_hashes = self.num_hashes + 1; self.num_hashes = 0; self.remaining_hashes -= 1; - return PohEntry{ + return .{ .num_hashes = num_hashes, .hash = self.latest_hash, }; @@ -84,7 +84,7 @@ pub const Poh = struct { /// Calculate the hash for a tick entry, without a mixin hash, and increment /// the tick counter pub fn tick(self: *Poh) ?PohEntry { - self.latest_hash = self.latest_hash.extendAndHash(.{}); + self.latest_hash = .init(&self.latest_hash.data); self.num_hashes += 1; self.remaining_hashes -= 1; @@ -98,7 +98,7 @@ pub const Poh = struct { self.num_hashes = 0; self.tick_count += 1; - return PohEntry{ + return .{ .num_hashes = num_hashes, .hash = self.latest_hash, }; diff --git a/src/core/shred.zig b/src/core/shred.zig index be3f56f407..80f3349d07 100644 --- a/src/core/shred.zig +++ b/src/core/shred.zig @@ -25,7 +25,7 @@ pub const ShredVersion = struct { var hash = genesis_hash; if (maybe_hard_forks) |hard_forks| { for (hard_forks.entries.items) |*hard_fork| { - hash = Hash.extendAndHash( + hash = Hash.extend( hash, std.mem.asBytes(hard_fork), ); diff --git a/src/gossip/fuzz_service.zig b/src/gossip/fuzz_service.zig index ff004dd32c..def35f8868 100644 --- a/src/gossip/fuzz_service.zig +++ b/src/gossip/fuzz_service.zig @@ -448,9 +448,9 @@ pub fn randomPullRequestWithContactInfo( // add more random hashes for (0..5) |_| { const rand_value = try randomSignedGossipData(allocator, random, true); - var buf: [PACKET_DATA_SIZE]u8 = undefined; - const bytes = try bincode.writeToSlice(&buf, rand_value, bincode.Params.standard); - const value_hash = Hash.generateSha256(bytes); + var buffer: [PACKET_DATA_SIZE]u8 = undefined; + const bytes = try bincode.writeToSlice(&buffer, rand_value, bincode.Params.standard); + const value_hash = Hash.init(bytes); filter.filter.add(&value_hash.data); } } else { @@ -459,9 +459,9 @@ pub fn randomPullRequestWithContactInfo( for (0..5) |_| { const rand_value = try randomSignedGossipData(allocator, random, true); - var buf: [PACKET_DATA_SIZE]u8 = undefined; - const bytes = try bincode.writeToSlice(&buf, rand_value, bincode.Params.standard); - const value_hash = Hash.generateSha256(bytes); + var buffer: [PACKET_DATA_SIZE]u8 = undefined; + const bytes = try bincode.writeToSlice(&buffer, rand_value, bincode.Params.standard); + const value_hash = Hash.init(bytes); filter_set.add(&value_hash); } diff --git a/src/gossip/ping_pong.zig b/src/gossip/ping_pong.zig index 8a1e41b859..8141c8f52f 100644 --- a/src/gossip/ping_pong.zig +++ b/src/gossip/ping_pong.zig @@ -60,7 +60,7 @@ pub const Pong = struct { pub fn init(ping: *const Ping, keypair: *const KeyPair) !Pong { const token_with_prefix = PING_PONG_HASH_PREFIX ++ ping.token; - const hash = Hash.generateSha256(token_with_prefix); + const hash = Hash.init(&token_with_prefix); const signature = keypair.sign(&hash.data, null) catch return error.SignatureError; return .{ @@ -172,7 +172,7 @@ pub const PingCache = struct { var prng = DefaultPrng.init(0); const ping = Ping.initRandom(prng.random(), keypair) catch return null; var token_with_prefix = PING_PONG_HASH_PREFIX ++ ping.token; - const hash = Hash.generateSha256(token_with_prefix[0..]); + const hash = Hash.init(&token_with_prefix); _ = self.pending_cache.put(hash, peer_and_addr); _ = self.pings.put(peer_and_addr, now); return ping; diff --git a/src/gossip/service.zig b/src/gossip/service.zig index 08e5ec8740..cadb62d607 100644 --- a/src/gossip/service.zig +++ b/src/gossip/service.zig @@ -1617,7 +1617,7 @@ pub const GossipService = struct { const bytes = bincode.writeToSlice(&buf, gossip_value_ptr.*, bincode.Params.standard) catch { continue; }; - const value_hash = Hash.generateSha256(bytes); + const value_hash = Hash.init(bytes); try failed_pull_hashes.insert(value_hash, now); gossip_value_ptr.deinit(self.gossip_data_allocator); } diff --git a/src/gossip/table.zig b/src/gossip/table.zig index 60cbab9a6b..677eaad897 100644 --- a/src/gossip/table.zig +++ b/src/gossip/table.zig @@ -156,7 +156,7 @@ pub const GossipTable = struct { pub fn insert(self: *Self, value: SignedGossipData, now: u64) !InsertResult { var buf: [PACKET_DATA_SIZE]u8 = undefined; const bytes = try bincode.writeToSlice(&buf, value, bincode.Params.standard); - const value_hash = Hash.generateSha256(bytes); + const value_hash = Hash.init(bytes); const metadata = GossipMetadata{ .signature = value.signature, .value_hash = value_hash, diff --git a/src/ledger/database/hashmap.zig b/src/ledger/database/hashmap.zig index 5b1d85b1db..9b7be779eb 100644 --- a/src/ledger/database/hashmap.zig +++ b/src/ledger/database/hashmap.zig @@ -34,6 +34,7 @@ pub fn SharedHashMapDB(comptime column_families: []const ColumnFamily) type { transaction_lock: *RwLock, const Self = @This(); + pub const name: []const u8 = "SharedHashMapDB"; pub fn open( allocator: Allocator, diff --git a/src/ledger/database/interface.zig b/src/ledger/database/interface.zig index 07a0d2f7b4..7a701651fe 100644 --- a/src/ledger/database/interface.zig +++ b/src/ledger/database/interface.zig @@ -23,6 +23,7 @@ pub fn Database(comptime Impl: type) type { impl: Impl, const Self = @This(); + pub const name: []const u8 = Impl.name; pub fn open( allocator: Allocator, @@ -309,11 +310,11 @@ pub const BytesRef = struct { /// Test cases that can be applied to any implementation of Database pub fn testDatabase(comptime Impl: fn ([]const ColumnFamily) type) type { - assertIsDatabase(Impl(&.{})); + const T = Impl(&.{}); + assertIsDatabase(T); @setEvalBranchQuota(10_000); - const impl_id = sig.core.Hash.generateSha256(@typeName(Impl(&.{}))).base58String(); - const test_dir = sig.TEST_STATE_DIR ++ "ledger/database/" ++ impl_id.buffer ++ "/"; + const test_dir = sig.TEST_STATE_DIR ++ "ledger/database/" ++ T.name ++ "/"; const Value1 = struct { hello: u16 }; const Value2 = struct { world: u16 }; diff --git a/src/ledger/database/rocksdb.zig b/src/ledger/database/rocksdb.zig index 48adb97630..2cde4ce3a1 100644 --- a/src/ledger/database/rocksdb.zig +++ b/src/ledger/database/rocksdb.zig @@ -24,8 +24,8 @@ pub fn RocksDB(comptime column_families: []const ColumnFamily) type { path: [:0]const u8, const Self = @This(); - const OpenError = Error || std.posix.MakeDirError || std.fs.Dir.StatFileError; + pub const name: []const u8 = "RocksDB"; pub fn open( allocator: Allocator, diff --git a/src/ledger/shred.zig b/src/ledger/shred.zig index 106ced32a2..ed5d399f86 100644 --- a/src/ledger/shred.zig +++ b/src/ledger/shred.zig @@ -659,7 +659,7 @@ pub fn getMerkleNode(shred: []const u8) !Hash { fn getMerkleNodeAt(shred: []const u8, start: usize, end: usize) !Hash { if (shred.len < end) return error.InvalidPayloadSize; - return Hash.generateSha256(.{ MERKLE_HASH_PREFIX_LEAF, shred[start..end] }); + return Hash.initMany(&.{ MERKLE_HASH_PREFIX_LEAF, shred[start..end] }); } /// [get_merkle_root](https://github.com/anza-xyz/agave/blob/ed500b5afc77bc78d9890d96455ea7a7f28edbf9/ledger/src/shred/merkle.rs#L702) @@ -745,9 +745,9 @@ pub fn makeMerkleProof( } } +/// [agave] https://github.com/anza-xyz/agave/blob/f7f2f5f5acfdf83c2ee2fbc16da998acc06146ff/ledger/src/shred/merkle_tree.rs#L78 fn joinNodes(lhs: []const u8, rhs: []const u8) Hash { - // TODO check - return Hash.generateSha256(.{ + return .initMany(&.{ MERKLE_HASH_PREFIX_NODE, lhs[0..merkle_proof_entry_size], rhs[0..merkle_proof_entry_size], diff --git a/src/replay/freeze.zig b/src/replay/freeze.zig index fab7e1034f..8364e1a8a2 100644 --- a/src/replay/freeze.zig +++ b/src/replay/freeze.zig @@ -273,20 +273,17 @@ pub fn hashSlot(allocator: Allocator, params: HashSlotParams) !struct { ?LtHash, var signature_count_bytes: [8]u8 = undefined; std.mem.writeInt(u64, &signature_count_bytes, params.signature_count, .little); - const initial_hash = - if (params.feature_set.active(.remove_accounts_delta_hash, params.slot)) - Hash.generateSha256(.{ - params.parent_slot_hash, - &signature_count_bytes, - params.blockhash, - }) - else - Hash.generateSha256(.{ - params.parent_slot_hash, - try deltaMerkleHash(params.account_reader, allocator, params.slot), - &signature_count_bytes, - params.blockhash, - }); + var hasher = std.crypto.hash.sha2.Sha256.init(.{}); + hasher.update(¶ms.parent_slot_hash.data); + const remove_delta_hash = params.feature_set.active(.remove_accounts_delta_hash, params.slot); + if (!remove_delta_hash) { + const merkle_hash = try deltaMerkleHash(params.account_reader, allocator, params.slot); + hasher.update(&merkle_hash.data); + } + hasher.update(&signature_count_bytes); + hasher.update(¶ms.blockhash.data); + + const initial_hash = hasher.finalResult(); if (params.feature_set.active(.accounts_lt_hash, params.slot)) { var parent_ancestors = try params.ancestors.clone(allocator); @@ -296,9 +293,15 @@ pub fn hashSlot(allocator: Allocator, params: HashSlotParams) !struct { ?LtHash, var lt_hash = params.parent_lt_hash.* orelse return error.UnknownParentLtHash; lt_hash.mixIn(try deltaLtHash(params.account_reader, params.slot, &parent_ancestors)); - return .{ lt_hash, Hash.generateSha256(.{ initial_hash, lt_hash.bytes() }) }; + return .{ + lt_hash, + Hash.initMany(&.{ &initial_hash, lt_hash.constBytes() }), + }; } else { - return .{ null, initial_hash }; + return .{ + null, + .{ .data = initial_hash }, + }; } } diff --git a/src/runtime/check_transactions.zig b/src/runtime/check_transactions.zig index 5532a10201..e5f84ccd17 100644 --- a/src/runtime/check_transactions.zig +++ b/src/runtime/check_transactions.zig @@ -450,8 +450,8 @@ test checkStatusCache { var status_cache: sig.core.StatusCache = .DEFAULT; defer status_cache.deinit(allocator); - const msg_hash = Hash.generateSha256("msg hash"); - const recent_blockhash = Hash.generateSha256("recent blockhash"); + const msg_hash = Hash.init("msg hash"); + const recent_blockhash = Hash.init("recent blockhash"); try std.testing.expectEqual( null, diff --git a/src/runtime/nonce.zig b/src/runtime/nonce.zig index 1d4d8b6559..b56803e585 100644 --- a/src/runtime/nonce.zig +++ b/src/runtime/nonce.zig @@ -99,7 +99,10 @@ pub const Data = struct { }; pub fn initDurableNonceFromHash(blockhash: Hash) Hash { - return sig.core.Hash.generateSha256(.{ DURABLE_NONCE_HASH_PREFIX, &blockhash.data }); + return .initMany(&.{ + DURABLE_NONCE_HASH_PREFIX, + &blockhash.data, + }); } test "verify_durable_nonce" { diff --git a/src/runtime/program/vote/state.zig b/src/runtime/program/vote/state.zig index f74668d501..1f30780013 100644 --- a/src/runtime/program/vote/state.zig +++ b/src/runtime/program/vote/state.zig @@ -3191,9 +3191,10 @@ test "state.VoteState.checkSlotsAreValid bad hash" { .timestamp = null, }; - const slot_hashes = try SlotHashes.initWithEntries(allocator, &.{ - .{ .slot = vote.slots[vote.slots.len - 1], .hash = Hash.generateSha256(&vote.hash.data) }, - }); + const slot_hashes = try SlotHashes.initWithEntries(allocator, &.{.{ + .slot = vote.slots[vote.slots.len - 1], + .hash = Hash.init(&vote.hash.data), + }}); defer slot_hashes.deinit(allocator); const result = try vote_state.checkSlotsAreValid(&vote, vote.slots, &slot_hashes); diff --git a/src/runtime/pubkey_utils.zig b/src/runtime/pubkey_utils.zig index f35ddf4cb0..991f93d278 100644 --- a/src/runtime/pubkey_utils.zig +++ b/src/runtime/pubkey_utils.zig @@ -37,17 +37,17 @@ pub fn createWithSeed( seed: []const u8, owner: Pubkey, ) PubkeyError!Pubkey { - if (seed.len > MAX_SEED_LEN) { - return PubkeyError.MaxSeedLenExceeded; - } + if (seed.len > MAX_SEED_LEN) return PubkeyError.MaxSeedLenExceeded; const offset = owner.data.len - PDA_MARKER.len; if (std.mem.eql(u8, owner.data[offset..], PDA_MARKER)) return PubkeyError.IllegalOwner; - return .{ - .data = sig.core.Hash.generateSha256(.{ &base.data, seed, &owner.data }).data, - }; + return .{ .data = sig.core.Hash.initMany(&.{ + &base.data, + seed, + &owner.data, + }).data }; } /// [agave] https://github.com/anza-xyz/agave/blob/c5ed1663a1218e9e088e30c81677bc88059cc62b/sdk/pubkey/src/lib.rs#L633 From be5589e753f2862c3bfe17fec96c1bade71c676b Mon Sep 17 00:00:00 2001 From: David Rubin Date: Mon, 29 Sep 2025 02:57:10 -0700 Subject: [PATCH 2/2] add missing hash --- conformance/src/txn_execute.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/conformance/src/txn_execute.zig b/conformance/src/txn_execute.zig index 464043f381..8f3265c410 100644 --- a/conformance/src/txn_execute.zig +++ b/conformance/src/txn_execute.zig @@ -1403,6 +1403,7 @@ pub fn hashSlot( const delta_hash = try freeze.deltaMerkleHash(account_reader, allocator, 0); hash.update(&delta_hash.data); } + hash.update(&signature_count_bytes); hash.update(&blockhash.data); const initial_hash = hash.finalResult();