aboutsummaryrefslogtreecommitdiffstats
path: root/tool/znk.zig
diff options
context:
space:
mode:
Diffstat (limited to 'tool/znk.zig')
-rw-r--r--tool/znk.zig76
1 files changed, 47 insertions, 29 deletions
diff --git a/tool/znk.zig b/tool/znk.zig
index 269e176..e086879 100644
--- a/tool/znk.zig
+++ b/tool/znk.zig
@@ -2,7 +2,7 @@ const std = @import("std");
2const Allocator = mem.Allocator; 2const Allocator = mem.Allocator;
3const ascii = std.ascii; 3const ascii = std.ascii;
4const build_options = @import("build_options"); 4const build_options = @import("build_options");
5const builtin = std.builtin; 5const builtin = @import("builtin");
6const fs = std.fs; 6const fs = std.fs;
7const io = std.io; 7const io = std.io;
8const mem = std.mem; 8const mem = std.mem;
@@ -39,17 +39,17 @@ const usage =
39pub fn main() anyerror!void { 39pub fn main() anyerror!void {
40 var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; 40 var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
41 defer std.debug.assert(!general_purpose_allocator.deinit()); 41 defer std.debug.assert(!general_purpose_allocator.deinit());
42 const gpa = &general_purpose_allocator.allocator; 42 const gpa = general_purpose_allocator.allocator();
43 43
44 var arena_instance = std.heap.ArenaAllocator.init(gpa); 44 var arena_instance = std.heap.ArenaAllocator.init(gpa);
45 defer arena_instance.deinit(); 45 defer arena_instance.deinit();
46 const arena = &arena_instance.allocator; 46 const arena = arena_instance.allocator();
47 47
48 const args = try process.argsAlloc(arena); 48 const args = try process.argsAlloc(arena);
49 return mainArgs(arena, args); 49 return mainArgs(arena, args);
50} 50}
51 51
52pub fn mainArgs(arena: *Allocator, args: []const []const u8) !void { 52pub fn mainArgs(arena: Allocator, args: []const []const u8) !void {
53 if (args.len <= 1) { 53 if (args.len <= 1) {
54 info("{s}", .{usage}); 54 info("{s}", .{usage});
55 fatal("expected command argument", .{}); 55 fatal("expected command argument", .{});
@@ -96,7 +96,7 @@ const usage_gen =
96 \\ 96 \\
97; 97;
98 98
99pub fn cmdGen(arena: *Allocator, args: []const []const u8) !void { 99pub fn cmdGen(arena: Allocator, args: []const []const u8) !void {
100 const stdin = io.getStdIn(); 100 const stdin = io.getStdIn();
101 const stdout = io.getStdOut(); 101 const stdout = io.getStdOut();
102 102
@@ -200,7 +200,7 @@ const usage_sign =
200 \\ 200 \\
201; 201;
202 202
203pub fn cmdSign(arena: *Allocator, args: []const []const u8) !void { 203pub fn cmdSign(arena: Allocator, args: []const []const u8) !void {
204 const stdin = io.getStdIn(); 204 const stdin = io.getStdIn();
205 const stdout = io.getStdOut(); 205 const stdout = io.getStdOut();
206 206
@@ -286,7 +286,7 @@ const usage_verify =
286 \\ 286 \\
287; 287;
288 288
289pub fn cmdVerify(arena: *Allocator, args: []const []const u8) !void { 289pub fn cmdVerify(arena: Allocator, args: []const []const u8) !void {
290 const stdin = io.getStdIn(); 290 const stdin = io.getStdIn();
291 const stdout = io.getStdOut(); 291 const stdout = io.getStdOut();
292 292
@@ -391,17 +391,39 @@ pub fn cmdVerify(arena: *Allocator, args: []const []const u8) !void {
391 try stdout.writeAll("good signature\n"); 391 try stdout.writeAll("good signature\n");
392} 392}
393 393
394const RandomReader = struct {
395 rand: *const std.rand.Random,
396
397 pub const Error = error{};
398 pub const Reader = io.Reader(*Self, Error, read);
399
400 const Self = @This();
401
402 pub fn init(rand: *const std.rand.Random) Self {
403 return .{ .rand = rand };
404 }
405
406 pub fn read(self: *Self, dest: []u8) Error!usize {
407 self.rand.bytes(dest);
408 return dest.len;
409 }
410
411 pub fn reader(self: *Self) Reader {
412 return .{ .context = self };
413 }
414};
415
394fn PrefixKeyGenerator(comptime EntropyReaderType: type) type { 416fn PrefixKeyGenerator(comptime EntropyReaderType: type) type {
395 return struct { 417 return struct {
396 role: nkeys.Role, 418 role: nkeys.Role,
397 prefix: []const u8, 419 prefix: []const u8,
398 allocator: *Allocator, 420 allocator: Allocator,
399 done: std.atomic.Atomic(bool), 421 done: std.atomic.Atomic(bool),
400 entropy: ?EntropyReaderType, 422 entropy: ?EntropyReaderType,
401 423
402 const Self = @This(); 424 const Self = @This();
403 425
404 pub fn init(allocator: *Allocator, role: nkeys.Role, prefix: []const u8, entropy: ?EntropyReaderType) Self { 426 pub fn init(allocator: Allocator, role: nkeys.Role, prefix: []const u8, entropy: ?EntropyReaderType) Self {
405 return .{ 427 return .{
406 .role = role, 428 .role = role,
407 .prefix = prefix, 429 .prefix = prefix,
@@ -412,28 +434,24 @@ fn PrefixKeyGenerator(comptime EntropyReaderType: type) type {
412 } 434 }
413 435
414 fn generatePrivate(self: *Self) !void { 436 fn generatePrivate(self: *Self) !void {
415 while (true) { 437 var rr = RandomReader.init(&std.crypto.random);
416 if (self.done.load(.SeqCst)) return; 438 var brr = io.BufferedReader(1024 * 4096, @TypeOf(rr.reader())){ .unbuffered_reader = rr.reader() };
417 439 while (!self.done.load(.SeqCst)) {
418 var gen_result = res: { 440 var gen_result = if (self.entropy) |entropy|
419 if (self.entropy) |entropy| { 441 nkeys.SeedKeyPair.generateWithCustomEntropy(self.role, entropy)
420 break :res nkeys.SeedKeyPair.generateWithCustomEntropy(self.role, entropy); 442 else
421 } else { 443 nkeys.SeedKeyPair.generateWithCustomEntropy(self.role, brr.reader());
422 break :res nkeys.SeedKeyPair.generate(self.role);
423 }
424 };
425 var kp = gen_result catch fatal("could not generate seed", .{}); 444 var kp = gen_result catch fatal("could not generate seed", .{});
426 445
427 defer kp.wipe();
428 var public_key = kp.publicKeyText(); 446 var public_key = kp.publicKeyText();
429 if (!mem.startsWith(u8, public_key[1..], self.prefix)) continue; 447 if (mem.startsWith(u8, public_key[1..], self.prefix)) {
430 448 if (self.done.swap(true, .SeqCst)) return; // another thread is already done
431 if (self.done.swap(true, .SeqCst)) return; // another thread is already done
432 449
433 info("{s}", .{kp.seedText()}); 450 info("{s}", .{kp.seedText()});
434 info("{s}", .{public_key}); 451 info("{s}", .{public_key});
435 452
436 return; 453 return;
454 }
437 } 455 }
438 } 456 }
439 457
@@ -444,7 +462,7 @@ fn PrefixKeyGenerator(comptime EntropyReaderType: type) type {
444 } else struct { 462 } else struct {
445 pub fn generate(self: *Self) !void { 463 pub fn generate(self: *Self) !void {
446 var cpu_count = try std.Thread.getCpuCount(); 464 var cpu_count = try std.Thread.getCpuCount();
447 var threads = try self.allocator.alloc(std.Thread, cpu_count); 465 var threads = try self.allocator.alloc(std.Thread, cpu_count*4);
448 defer self.allocator.free(threads); 466 defer self.allocator.free(threads);
449 for (threads) |*thread| thread.* = try std.Thread.spawn(.{}, Self.generatePrivate, .{self}); 467 for (threads) |*thread| thread.* = try std.Thread.spawn(.{}, Self.generatePrivate, .{self});
450 for (threads) |thread| thread.join(); 468 for (threads) |thread| thread.join();
@@ -453,7 +471,7 @@ fn PrefixKeyGenerator(comptime EntropyReaderType: type) type {
453 }; 471 };
454} 472}
455 473
456fn toUpper(allocator: *Allocator, slice: []const u8) ![]u8 { 474fn toUpper(allocator: Allocator, slice: []const u8) ![]u8 {
457 const result = try allocator.alloc(u8, slice.len); 475 const result = try allocator.alloc(u8, slice.len);
458 for (slice) |c, i| result[i] = ascii.toUpper(c); 476 for (slice) |c, i| result[i] = ascii.toUpper(c);
459 return result; 477 return result;
@@ -519,7 +537,7 @@ pub const Nkey = union(enum) {
519 } 537 }
520}; 538};
521 539
522pub fn readKeyFile(allocator: *Allocator, file: fs.File) ?Nkey { 540pub fn readKeyFile(allocator: Allocator, file: fs.File) ?Nkey {
523 var bytes = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch fatal("could not read key file", .{}); 541 var bytes = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch fatal("could not read key file", .{});
524 defer { 542 defer {
525 for (bytes) |*b| b.* = 0; 543 for (bytes) |*b| b.* = 0;