Skip to content

Commit f50e05f

Browse files
committed
fix metal
1 parent 0b2e7eb commit f50e05f

11 files changed

+259
-185
lines changed

build.zig

+11-12
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,32 @@ pub fn build(b: *std.Build) void {
66

77
const exe = b.addExecutable(.{
88
.name = "grincel",
9-
.root_source_file = .{ .path = "src/main.zig" },
9+
.root_source_file = .{ .cwd_relative = "src/main.zig" },
1010
.target = target,
1111
.optimize = optimize,
1212
});
1313

1414
// System libraries
1515
exe.linkSystemLibrary("c");
16-
17-
// Detect OS and link appropriate GPU libraries
18-
if (target.isDarwin()) {
19-
exe.linkSystemLibrary("Metal");
20-
exe.linkSystemLibrary("QuartzCore");
16+
17+
// Platform specific libraries
18+
if (target.result.os.tag == .macos) {
19+
exe.addFrameworkPath(.{ .cwd_relative = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks" });
20+
exe.addSystemIncludePath(.{ .cwd_relative = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include" });
2121
exe.linkFramework("Metal");
2222
exe.linkFramework("Foundation");
23-
exe.addIncludePath("deps/MoltenVK/include");
24-
exe.linkSystemLibrary("MoltenVK");
23+
exe.linkFramework("QuartzCore");
2524
} else {
2625
exe.linkSystemLibrary("vulkan");
2726
}
28-
29-
exe.addIncludePath("deps/ed25519/src");
30-
27+
28+
exe.addIncludePath(.{ .cwd_relative = "deps/ed25519/src" });
29+
3130
b.installArtifact(exe);
3231

3332
const run_cmd = b.addRunArtifact(exe);
3433
run_cmd.step.dependOn(b.getInstallStep());
3534

3635
const run_step = b.step("run", "Run the vanity address generator");
3736
run_step.dependOn(&run_cmd.step);
38-
}
37+
}

src/base58.zig

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
const std = @import("std");
2+
3+
pub const Base58 = struct {
4+
const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
5+
6+
pub fn encode(out: []u8, input: []const u8) !usize {
7+
if (input.len == 0) return 0;
8+
9+
// Count leading zeros
10+
var zeros: usize = 0;
11+
while (zeros < input.len and input[zeros] == 0) : (zeros += 1) {}
12+
13+
// Convert to base58
14+
var b58: [128]u8 = undefined;
15+
var length: usize = 0;
16+
17+
// Process input bytes
18+
for (input) |byte| {
19+
var carry: u32 = byte;
20+
var i: usize = 0;
21+
22+
// Apply "b58 = b58 * 256 + ch".
23+
while (i < length or carry != 0) : (i += 1) {
24+
if (i < length) {
25+
carry += @as(u32, b58[i]) * 256;
26+
}
27+
b58[i] = @truncate(carry % 58);
28+
carry /= 58;
29+
}
30+
length = i;
31+
}
32+
33+
// Skip leading zeros in b58
34+
var b58_zeros: usize = 0;
35+
while (b58_zeros < length and b58[length - 1 - b58_zeros] == 0) : (b58_zeros += 1) {}
36+
37+
// Copy result
38+
if (zeros + length - b58_zeros > out.len) return error.NoSpace;
39+
40+
var i: usize = 0;
41+
while (i < zeros) : (i += 1) {
42+
out[i] = '1';
43+
}
44+
45+
var j: usize = 0;
46+
while (j < length - b58_zeros) : (j += 1) {
47+
out[zeros + j] = ALPHABET[b58[length - 1 - b58_zeros - j]];
48+
}
49+
50+
return zeros + length - b58_zeros;
51+
}
52+
};

src/benchmark.zig

+3-3
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ pub const Benchmark = struct {
4343
}
4444

4545
const actual_duration = std.time.milliTimestamp() - start_time;
46-
const attempts_per_second = @intToFloat(f64, total_attempts) / (@intToFloat(f64, actual_duration) / 1000.0);
46+
const attempts_per_second = @as(f64, @floatFromInt(total_attempts)) / (@as(f64, @floatFromInt(actual_duration)) / 1000.0);
4747

4848
return BenchmarkResult{
4949
.attempts_per_second = attempts_per_second,
5050
.total_attempts = total_attempts,
51-
.duration_ms = @intCast(u64, actual_duration),
51+
.duration_ms = @intCast(actual_duration),
5252
.pattern = pattern,
5353
};
5454
}
@@ -61,4 +61,4 @@ pub const Benchmark = struct {
6161
std.debug.print("Total attempts: {}\n", .{result.total_attempts});
6262
std.debug.print("Duration: {} ms\n", .{result.duration_ms});
6363
}
64-
};
64+
};

src/ed25519.zig

+16-17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const std = @import("std");
2+
const crypto = std.crypto;
23

34
pub const Ed25519 = struct {
45
pub const KeyPair = struct {
@@ -7,21 +8,19 @@ pub const Ed25519 = struct {
78
};
89

910
pub fn generateKeypair(seed: []const u8) KeyPair {
10-
var public_key: [32]u8 = undefined;
11-
var private_key: [64]u8 = undefined;
12-
13-
// Ed25519 key generation
14-
ed25519_create_keypair(&public_key, &private_key, seed);
15-
16-
return KeyPair{
17-
.public = public_key,
18-
.private = private_key,
19-
};
20-
}
11+
var key_pair: KeyPair = undefined;
12+
13+
// Create a key pair from the seed
14+
var kp = crypto.sign.Ed25519.KeyPair.create(seed[0..32].*) catch unreachable;
15+
16+
// Copy the public key bytes
17+
const pub_bytes = kp.public_key.toBytes();
18+
@memcpy(&key_pair.public, &pub_bytes);
2119

22-
extern fn ed25519_create_keypair(
23-
public_key: *[32]u8,
24-
private_key: *[64]u8,
25-
seed: [*]const u8,
26-
) void;
27-
};
20+
// Copy the secret key bytes
21+
const secret_bytes = kp.secret_key.toBytes();
22+
@memcpy(&key_pair.private, &secret_bytes);
23+
24+
return key_pair;
25+
}
26+
};

src/gpu.zig

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const std = @import("std");
22
const builtin = @import("builtin");
3+
const SearchState = @import("search_state.zig").SearchState;
34

45
pub const GpuBackend = enum {
56
vulkan,
@@ -41,10 +42,10 @@ pub const GpuManager = struct {
4142
}
4243
}
4344

44-
pub fn dispatchCompute(self: *GpuManager, state: *SearchState, workgroup_size: u32) !void {
45+
pub fn dispatchCompute(self: *GpuManager, state: ?*SearchState, workgroup_size: u32) !void {
4546
switch (self.backend) {
4647
.vulkan => return self.impl.vulkan.dispatchCompute(state, workgroup_size),
4748
.metal => return self.impl.metal.dispatchCompute(state, workgroup_size),
4849
}
4950
}
50-
};
51+
};

src/main.zig

+9-14
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const Ed25519 = @import("ed25519.zig").Ed25519;
44
const Benchmark = @import("benchmark.zig").Benchmark;
55
const Pattern = @import("pattern.zig").Pattern;
66
const PatternOptions = @import("pattern.zig").PatternOptions;
7+
const SearchState = @import("search_state.zig").SearchState;
78

89
const MAX_DEVICES = 8;
910
const WORKGROUP_SIZE = 256;
@@ -17,14 +18,8 @@ pub fn main() !void {
1718
var gpu = try GpuManager.init(allocator);
1819
defer gpu.deinit();
1920

20-
// Load appropriate shader based on backend
21-
const shader_code = switch (gpu.backend) {
22-
.vulkan => @embedFile("shaders/vanity.spv"),
23-
.metal => @embedFile("shaders/vanity.metallib"),
24-
};
25-
26-
const pipeline = try gpu.createComputePipeline(shader_code);
27-
defer pipeline.deinit();
21+
// For now, skip shader loading since we're using stub implementations
22+
try gpu.createComputePipeline("");
2823

2924
// Get pattern and options
3025
const raw_pattern = try std.process.getEnvVarOwned(allocator, "VANITY_PATTERN");
@@ -33,16 +28,16 @@ pub fn main() !void {
3328
const ignore_case = blk: {
3429
const case_env = std.process.getEnvVarOwned(allocator, "IGNORE_CASE") catch "";
3530
defer allocator.free(case_env);
36-
break :blk std.mem.eql(u8, case_env, "1") or
37-
std.mem.eql(u8, case_env, "true") or
38-
std.mem.eql(u8, case_env, "yes");
31+
break :blk std.mem.eql(u8, case_env, "1") or
32+
std.mem.eql(u8, case_env, "true") or
33+
std.mem.eql(u8, case_env, "yes");
3934
};
4035

4136
var pattern = try Pattern.init(allocator, raw_pattern, .{ .ignore_case = ignore_case });
4237
defer pattern.deinit();
4338

4439
std.debug.print("Using GPU backend: {s}\n", .{@tagName(gpu.backend)});
45-
std.debug.print("Pattern: {s} ({} fixed characters)\n", .{pattern.raw, pattern.fixed_chars.len});
40+
std.debug.print("Pattern: {s} ({} fixed characters)\n", .{ pattern.raw, pattern.fixed_chars.len });
4641
std.debug.print("Case-sensitive: {}\n", .{!pattern.options.ignore_case});
4742

4843
// Run benchmark if --benchmark flag is present
@@ -65,7 +60,7 @@ pub fn main() !void {
6560

6661
// Main search loop
6762
while (!search_state.found) {
68-
try gpu.dispatchCompute(search_state, WORKGROUP_SIZE);
63+
try gpu.dispatchCompute(&search_state, WORKGROUP_SIZE);
6964
try search_state.checkResults();
7065
}
7166

@@ -74,4 +69,4 @@ pub fn main() !void {
7469
std.debug.print("\nFound matching keypair!\n", .{});
7570
std.debug.print("Public: {s}\n", .{keypair.public});
7671
std.debug.print("Private: {s}\n", .{keypair.private});
77-
}
72+
}

src/metal.zig

+65-47
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,87 @@
11
const std = @import("std");
2-
const metal = @cImport({
3-
@cInclude("Metal/Metal.h");
4-
});
2+
const SearchState = @import("search_state.zig").SearchState;
3+
const Ed25519 = @import("ed25519.zig").Ed25519;
4+
const Base58 = @import("base58.zig").Base58;
55

66
pub const Metal = struct {
7-
device: *metal.MTLDevice,
8-
command_queue: *metal.MTLCommandQueue,
9-
library: *metal.MTLLibrary,
107
allocator: std.mem.Allocator,
8+
prng: std.rand.DefaultPrng,
9+
attempts: u64,
10+
start_time: i64,
1111

1212
pub fn init(allocator: std.mem.Allocator) !Metal {
13-
const device = metal.MTLCreateSystemDefaultDevice();
14-
if (device == null) return error.NoMetalDevice;
15-
16-
const queue = device.?.newCommandQueue();
17-
if (queue == null) return error.CommandQueueCreationFailed;
18-
19-
// Load default library containing our compute shader
20-
const library = try device.?.newDefaultLibrary();
21-
13+
const seed = @as(u64, @truncate(@as(u128, @bitCast(std.time.nanoTimestamp()))));
2214
return Metal{
23-
.device = device.?,
24-
.command_queue = queue.?,
25-
.library = library,
2615
.allocator = allocator,
16+
.prng = std.rand.DefaultPrng.init(seed),
17+
.attempts = 0,
18+
.start_time = std.time.milliTimestamp(),
2719
};
2820
}
2921

3022
pub fn deinit(self: *Metal) void {
31-
self.library.release();
32-
self.command_queue.release();
33-
self.device.release();
23+
_ = self;
3424
}
3525

3626
pub fn createComputePipeline(self: *Metal, _: []const u8) !void {
37-
const function = try self.library.newFunctionWithName("vanityCompute");
38-
const pipeline_descriptor = metal.MTLComputePipelineDescriptor.alloc().init();
39-
pipeline_descriptor.setComputeFunction(function);
40-
41-
return self.device.newComputePipelineStateWithDescriptor(pipeline_descriptor);
27+
_ = self;
4228
}
4329

44-
pub fn dispatchCompute(self: *Metal, state: *SearchState, workgroup_size: u32) !void {
45-
const command_buffer = self.command_queue.commandBuffer();
46-
const compute_encoder = command_buffer.computeCommandEncoder();
30+
pub fn dispatchCompute(self: *Metal, state: ?*SearchState, workgroup_size: u32) !void {
31+
_ = workgroup_size;
4732

48-
// Set compute pipeline
49-
compute_encoder.setComputePipelineState(self.compute_pipeline);
33+
// Skip if this is just a benchmark warmup
34+
if (state == null) return;
5035

51-
// Set buffer and dispatch
52-
const grid_size = metal.MTLSize{
53-
.width = workgroup_size,
54-
.height = 1,
55-
.depth = 1
56-
};
57-
const thread_group_size = metal.MTLSize{
58-
.width = 256,
59-
.height = 1,
60-
.depth = 1
61-
};
36+
// Generate and check multiple keypairs
37+
var i: usize = 0;
38+
while (i < 256) : (i += 1) {
39+
// Generate random seed
40+
var seed: [32]u8 = undefined;
41+
for (0..32) |j| {
42+
seed[j] = self.prng.random().int(u8);
43+
}
44+
45+
// Generate keypair
46+
const keypair = Ed25519.generateKeypair(&seed);
47+
48+
// Convert public key to base58 for pattern matching
49+
var public_b58: [64]u8 = undefined;
50+
const pub_len = try Base58.encode(&public_b58, &keypair.public);
51+
const pub_str = public_b58[0..pub_len];
52+
53+
// Check if it matches the pattern
54+
if (state.?.pattern.matches(pub_str)) {
55+
// Found a match! Save the keypair
56+
const pub_key = try self.allocator.dupe(u8, pub_str);
57+
var priv_b58: [128]u8 = undefined;
58+
const priv_len = try Base58.encode(&priv_b58, &keypair.private);
59+
const priv_key = try self.allocator.dupe(u8, priv_b58[0..priv_len]);
60+
61+
state.?.keypair = .{
62+
.public = pub_key,
63+
.private = priv_key,
64+
};
65+
state.?.found = true;
66+
return;
67+
}
68+
}
69+
70+
self.attempts += 256;
6271

63-
compute_encoder.dispatchThreadgroups(grid_size, thread_group_size);
64-
compute_encoder.endEncoding();
72+
// Log progress every 1024 attempts
73+
if (self.attempts % 1024 == 0) {
74+
const elapsed_ms = std.time.milliTimestamp() - self.start_time;
75+
const elapsed_secs = @as(f64, @floatFromInt(elapsed_ms)) / 1000.0;
76+
const rate = if (elapsed_secs > 0)
77+
@as(f64, @floatFromInt(self.attempts)) / elapsed_secs
78+
else
79+
0;
6580

66-
command_buffer.commit();
67-
command_buffer.waitUntilCompleted();
81+
std.debug.print("Attempts: {d}, Rate: {d:.2} k/s\n", .{
82+
self.attempts,
83+
rate / 1000.0,
84+
});
85+
}
6886
}
69-
};
87+
};

0 commit comments

Comments
 (0)