Skip to content

Commit 37181bd

Browse files
spiral-laddermarkolazic01
authored andcommitted
refactor(bls): allocations around VMAS (ChainSafe#395)
rework allocations around `verifyMultipleAggregateSignatures`. - we're batching on average about ~30 signature sets per batch on our highest load fleet (according to metrics), so a cap of about 32 makes sense for stack allocations. Anything beyond that, use heap allocations. - avoid copies for `msgs` which was unnecessary
1 parent ddbf084 commit 37181bd

3 files changed

Lines changed: 51 additions & 18 deletions

File tree

bindings/napi/blst.zig

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ const ThreadPool = bls.ThreadPool;
2727
const DST = bls.DST;
2828
const MAX_AGGREGATE_PER_JOB = bls.MAX_AGGREGATE_PER_JOB;
2929

30+
/// In upstream lodestar we split batchable sets into chunks of minimum size 16.
31+
/// Cost savings after ~16 are not significant.
32+
/// In metrics, we can observe that sas fleet receives on average ~30 signature sets,
33+
/// so a safe bound is about 32.
34+
///
35+
/// See: packages/beacon-node/src/chain/bls/multithread/worker.ts
36+
const BATCH_VERIFY_SIZE = 32;
37+
3038
/// Cached thread pool reference for parallel verification.
3139
/// Initialized lazily on first use, torn down via `deinitThreadPool`.
3240
var thread_pool: ?*ThreadPool = null;
@@ -429,17 +437,40 @@ pub fn verifyMultipleAggregateSignatures(sets: js.Array, pks_validate: ?js.Boole
429437
const n_elems = try sets.length();
430438
if (n_elems == 0) return js.Boolean.from(false);
431439

432-
const msgs = try allocator.alloc([32]u8, n_elems);
433-
defer allocator.free(msgs);
434-
435-
const pks = try allocator.alloc(*NativePublicKey, n_elems);
436-
defer allocator.free(pks);
437-
438-
const sigs = try allocator.alloc(*NativeSignature, n_elems);
439-
defer allocator.free(sigs);
440-
441-
const rands = try allocator.alloc([32]u8, n_elems);
442-
defer allocator.free(rands);
440+
var msgs_stack: [BATCH_VERIFY_SIZE][]const u8 = undefined;
441+
var pks_stack: [BATCH_VERIFY_SIZE]*NativePublicKey = undefined;
442+
var sigs_stack: [BATCH_VERIFY_SIZE]*NativeSignature = undefined;
443+
var rands_stack: [BATCH_VERIFY_SIZE][32]u8 = undefined;
444+
445+
var msgs_heap: ?[][]const u8 = null;
446+
defer if (msgs_heap) |buf| allocator.free(buf);
447+
var pks_heap: ?[]*NativePublicKey = null;
448+
defer if (pks_heap) |buf| allocator.free(buf);
449+
var sigs_heap: ?[]*NativeSignature = null;
450+
defer if (sigs_heap) |buf| allocator.free(buf);
451+
var rands_heap: ?[][32]u8 = null;
452+
defer if (rands_heap) |buf| allocator.free(buf);
453+
454+
const msgs = if (n_elems <= BATCH_VERIFY_SIZE) msgs_stack[0..n_elems] else blk: {
455+
const buf = try allocator.alloc([]const u8, n_elems);
456+
msgs_heap = buf;
457+
break :blk buf;
458+
};
459+
const pks = if (n_elems <= BATCH_VERIFY_SIZE) pks_stack[0..n_elems] else blk: {
460+
const buf = try allocator.alloc(*NativePublicKey, n_elems);
461+
pks_heap = buf;
462+
break :blk buf;
463+
};
464+
const sigs = if (n_elems <= BATCH_VERIFY_SIZE) sigs_stack[0..n_elems] else blk: {
465+
const buf = try allocator.alloc(*NativeSignature, n_elems);
466+
sigs_heap = buf;
467+
break :blk buf;
468+
};
469+
const rands = if (n_elems <= BATCH_VERIFY_SIZE) rands_stack[0..n_elems] else blk: {
470+
const buf = try allocator.alloc([32]u8, n_elems);
471+
rands_heap = buf;
472+
break :blk buf;
473+
};
443474

444475
var seed_bytes: [8]u8 = undefined;
445476
const io = napi_io.get();
@@ -454,7 +485,7 @@ pub fn verifyMultipleAggregateSignatures(sets: js.Array, pks_validate: ?js.Boole
454485
const msg_napi = try set.getNamedProperty("msg");
455486
const msg_bytes = try uint8SliceFromValue(.{ .val = msg_napi });
456487
if (msg_bytes.len != 32) return error.InvalidMessageLength;
457-
@memcpy(&msgs[i], msg_bytes[0..32]);
488+
msgs[i] = msg_bytes;
458489

459490
const pk_napi = try set.getNamedProperty("pk");
460491
const wrapped_pk = try e.unwrap(PublicKey, pk_napi);

src/bls/ThreadPool.zig

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ pub fn submitAndWait(pool: *ThreadPool, io: std.Io, items: []*WorkItem) (PoolErr
196196
const VerifyMultiJob = struct {
197197
pks: []const *PublicKey,
198198
sigs: []const *Signature,
199-
msgs: []const [32]u8,
199+
msgs: []const []const u8,
200200
rands: []const [32]u8,
201201
dst: []const u8,
202202
pks_validate: bool,
@@ -231,7 +231,7 @@ const VerifyMultiWorkItem = struct {
231231
job.sigs_groupcheck,
232232
&job.rands[i],
233233
RAND_BITS,
234-
&job.msgs[i],
234+
job.msgs[i],
235235
) catch {
236236
job.err_flag.store(true, .release);
237237
break;
@@ -251,7 +251,7 @@ pub fn verifyMultipleAggregateSignatures(
251251
pool: *ThreadPool,
252252
io: std.Io,
253253
n_elems: usize,
254-
msgs: []const [32]u8,
254+
msgs: []const []const u8,
255255
dst: []const u8,
256256
pks: []const *PublicKey,
257257
pks_validate: bool,
@@ -492,6 +492,7 @@ test "verifyMultipleAggregateSignatures multi-threaded" {
492492
const num_sigs = 16;
493493

494494
var msgs: [num_sigs][32]u8 = undefined;
495+
var msg_refs: [num_sigs][]const u8 = undefined;
495496
var pks: [num_sigs]PublicKey = undefined;
496497
var sigs: [num_sigs]Signature = undefined;
497498
var pk_ptrs: [num_sigs]*PublicKey = undefined;
@@ -511,6 +512,7 @@ test "verifyMultipleAggregateSignatures multi-threaded" {
511512
const sk = try SecretKey.keyGen(&ikm_i, null);
512513
pks[i] = sk.toPublicKey();
513514
sigs[i] = sk.sign(&msgs[i], blst.DST, null);
515+
msg_refs[i] = &msgs[i];
514516
pk_ptrs[i] = &pks[i];
515517
sig_ptrs[i] = &sigs[i];
516518
}
@@ -521,7 +523,7 @@ test "verifyMultipleAggregateSignatures multi-threaded" {
521523
const result = try pool.verifyMultipleAggregateSignatures(
522524
std.testing.io,
523525
num_sigs,
524-
&msgs,
526+
&msg_refs,
525527
blst.DST,
526528
&pk_ptrs,
527529
true,

src/bls/fast_verify.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const RAND_BITS = 8 * RAND_BYTES;
1212
pub fn verifyMultipleAggregateSignatures(
1313
pairing_buf: *align(Pairing.buf_align) [Pairing.sizeOf()]u8,
1414
n_elems: usize,
15-
msgs: []const [32]u8,
15+
msgs: []const []const u8,
1616
dst: []const u8,
1717
pks: []const *PublicKey,
1818
pks_validate: bool,
@@ -38,7 +38,7 @@ pub fn verifyMultipleAggregateSignatures(
3838
sigs_groupcheck,
3939
&rands[i],
4040
RAND_BITS,
41-
&msgs[i],
41+
msgs[i],
4242
);
4343
}
4444

0 commit comments

Comments
 (0)