diff options
Diffstat (limited to 'src/nkeys.zig')
-rw-r--r-- | src/nkeys.zig | 229 |
1 files changed, 116 insertions, 113 deletions
diff --git a/src/nkeys.zig b/src/nkeys.zig index b7fd520..15605ca 100644 --- a/src/nkeys.zig +++ b/src/nkeys.zig | |||
@@ -19,67 +19,72 @@ pub const SeedDecodeError = DecodeError || InvalidSeedError || crypto.errors.Ide | |||
19 | pub const PrivateKeyDecodeError = DecodeError || InvalidPrivateKeyError || crypto.errors.IdentityElementError; | 19 | pub const PrivateKeyDecodeError = DecodeError || InvalidPrivateKeyError || crypto.errors.IdentityElementError; |
20 | pub const SignError = crypto.errors.IdentityElementError || crypto.errors.WeakPublicKeyError || crypto.errors.KeyMismatchError; | 20 | pub const SignError = crypto.errors.IdentityElementError || crypto.errors.WeakPublicKeyError || crypto.errors.KeyMismatchError; |
21 | 21 | ||
22 | pub const KeyTypePrefixByte = enum(u8) { | 22 | pub const prefix_byte_account = 0; // A |
23 | const Self = @This(); | 23 | pub const prefix_byte_cluster = 2 << 3; // C |
24 | 24 | pub const prefix_byte_operator = 14 << 3; // O | |
25 | seed = 18 << 3, // S | 25 | pub const prefix_byte_private = 15 << 3; // P |
26 | private = 15 << 3, // P | 26 | pub const prefix_byte_seed = 18 << 3; // S |
27 | 27 | pub const prefix_byte_server = 13 << 3; // N | |
28 | pub fn char(self: Self) u8 { | 28 | pub const prefix_byte_user = 20 << 3; // U |
29 | return switch (self) { | 29 | |
30 | .seed => 'S', | 30 | pub fn prefixByteLetter(prefix_byte: u8) ?u8 { |
31 | .private => 'P', | 31 | return switch (prefix_byte) { |
32 | }; | 32 | prefix_byte_account => 'A', |
33 | } | 33 | prefix_byte_cluster => 'C', |
34 | prefix_byte_operator => 'O', | ||
35 | prefix_byte_private => 'P', | ||
36 | prefix_byte_seed => 'S', | ||
37 | prefix_byte_server => 'N', | ||
38 | prefix_byte_user => 'U', | ||
39 | else => null, | ||
40 | }; | ||
41 | } | ||
34 | 42 | ||
35 | pub fn fromChar(c: u8) InvalidPrefixByteError!Self { | 43 | pub fn prefixByteFromLetter(letter: u8) ?u8 { |
36 | return switch (c) { | 44 | return switch (letter) { |
37 | 'S' => .seed, | 45 | 'A' => prefix_byte_account, |
38 | 'P' => .private, | 46 | 'C' => prefix_byte_cluster, |
39 | else => error.InvalidPrefixByte, | 47 | 'O' => prefix_byte_operator, |
40 | }; | 48 | 'P' => prefix_byte_private, |
41 | } | 49 | 'S' => prefix_byte_seed, |
42 | }; | 50 | 'N' => prefix_byte_server, |
51 | 'U' => prefix_byte_user, | ||
52 | else => null, | ||
53 | }; | ||
54 | } | ||
43 | 55 | ||
44 | pub const PublicPrefixByte = enum(u8) { | 56 | pub const Role = enum(u8) { |
45 | const Self = @This(); | 57 | const Self = @This(); |
46 | 58 | ||
47 | account = 0, // A | 59 | account, |
48 | cluster = 2 << 3, // C | 60 | cluster, |
49 | operator = 14 << 3, // O | 61 | operator, |
50 | server = 13 << 3, // N | 62 | server, |
51 | user = 20 << 3, // U | 63 | user, |
52 | 64 | ||
53 | pub fn fromU8(b: u8) InvalidPrefixByteError!PublicPrefixByte { | 65 | pub fn fromPublicPrefixByte(b: u8) ?Self { |
54 | return switch (b) { | 66 | return switch (b) { |
55 | @enumToInt(PublicPrefixByte.server) => .server, | 67 | prefix_byte_account => .account, |
56 | @enumToInt(PublicPrefixByte.cluster) => .cluster, | 68 | prefix_byte_cluster => .cluster, |
57 | @enumToInt(PublicPrefixByte.operator) => .operator, | 69 | prefix_byte_operator => .operator, |
58 | @enumToInt(PublicPrefixByte.account) => .account, | 70 | prefix_byte_server => .server, |
59 | @enumToInt(PublicPrefixByte.user) => .user, | 71 | prefix_byte_user => .user, |
60 | else => error.InvalidPrefixByte, | 72 | else => null, |
61 | }; | 73 | }; |
62 | } | 74 | } |
63 | 75 | ||
64 | pub fn char(self: Self) u8 { | 76 | pub fn publicPrefixByte(self: Self) u8 { |
65 | return switch (self) { | 77 | return switch (self) { |
66 | .account => 'A', | 78 | .account => prefix_byte_account, |
67 | .cluster => 'C', | 79 | .cluster => prefix_byte_cluster, |
68 | .operator => 'O', | 80 | .operator => prefix_byte_operator, |
69 | .server => 'N', | 81 | .server => prefix_byte_server, |
70 | .user => 'U', | 82 | .user => prefix_byte_user, |
71 | }; | 83 | }; |
72 | } | 84 | } |
73 | 85 | ||
74 | pub fn fromChar(c: u8) InvalidPrefixByteError!Self { | 86 | pub fn letter(self: Self) u8 { |
75 | return switch (c) { | 87 | return prefixByteLetter(self.publicPrefixByte()) orelse unreachable; |
76 | 'A' => .account, | ||
77 | 'C' => .cluster, | ||
78 | 'O' => .operator, | ||
79 | 'N' => .server, | ||
80 | 'U' => .user, | ||
81 | else => error.InvalidPrefixByte, | ||
82 | }; | ||
83 | } | 88 | } |
84 | }; | 89 | }; |
85 | 90 | ||
@@ -101,14 +106,14 @@ pub const text_seed = [text_seed_len]u8; | |||
101 | pub const SeedKeyPair = struct { | 106 | pub const SeedKeyPair = struct { |
102 | const Self = @This(); | 107 | const Self = @This(); |
103 | 108 | ||
104 | prefix: PublicPrefixByte, | 109 | role: Role, |
105 | kp: Ed25519.KeyPair, | 110 | kp: Ed25519.KeyPair, |
106 | 111 | ||
107 | pub fn generate(prefix: PublicPrefixByte) crypto.errors.IdentityElementError!Self { | 112 | pub fn generate(role: Role) crypto.errors.IdentityElementError!Self { |
108 | var raw_seed: [Ed25519.seed_length]u8 = undefined; | 113 | var raw_seed: [Ed25519.seed_length]u8 = undefined; |
109 | crypto.random.bytes(&raw_seed); | 114 | crypto.random.bytes(&raw_seed); |
110 | defer wipeBytes(&raw_seed); | 115 | defer wipeBytes(&raw_seed); |
111 | return Self{ .prefix = prefix, .kp = try Ed25519.KeyPair.create(raw_seed) }; | 116 | return Self{ .role = role, .kp = try Ed25519.KeyPair.create(raw_seed) }; |
112 | } | 117 | } |
113 | 118 | ||
114 | pub fn fromTextSeed(text: *const text_seed) SeedDecodeError!Self { | 119 | pub fn fromTextSeed(text: *const text_seed) SeedDecodeError!Self { |
@@ -116,22 +121,22 @@ pub const SeedKeyPair = struct { | |||
116 | defer decoded.wipe(); // gets copied | 121 | defer decoded.wipe(); // gets copied |
117 | 122 | ||
118 | var key_ty_prefix = decoded.prefix[0] & 0b11111000; | 123 | var key_ty_prefix = decoded.prefix[0] & 0b11111000; |
119 | var entity_ty_prefix = (decoded.prefix[0] << 5) | (decoded.prefix[1] >> 3); | 124 | var role_prefix = (decoded.prefix[0] << 5) | (decoded.prefix[1] >> 3); |
120 | 125 | ||
121 | if (key_ty_prefix != @enumToInt(KeyTypePrefixByte.seed)) | 126 | if (key_ty_prefix != prefix_byte_seed) |
122 | return error.InvalidSeed; | 127 | return error.InvalidSeed; |
123 | 128 | ||
124 | return Self{ | 129 | return Self{ |
125 | .prefix = try PublicPrefixByte.fromU8(entity_ty_prefix), | 130 | .role = Role.fromPublicPrefixByte(role_prefix) orelse return error.InvalidPrefixByte, |
126 | .kp = try Ed25519.KeyPair.create(decoded.data), | 131 | .kp = try Ed25519.KeyPair.create(decoded.data), |
127 | }; | 132 | }; |
128 | } | 133 | } |
129 | 134 | ||
130 | pub fn fromRawSeed( | 135 | pub fn fromRawSeed( |
131 | prefix: PublicPrefixByte, | 136 | role: Role, |
132 | raw_seed: *const [Ed25519.seed_length]u8, | 137 | raw_seed: *const [Ed25519.seed_length]u8, |
133 | ) crypto.errors.IdentityElementError!Self { | 138 | ) crypto.errors.IdentityElementError!Self { |
134 | return Self{ .prefix = prefix, .kp = try Ed25519.KeyPair.create(raw_seed.*) }; | 139 | return Self{ .role = role, .kp = try Ed25519.KeyPair.create(raw_seed.*) }; |
135 | } | 140 | } |
136 | 141 | ||
137 | pub fn sign( | 142 | pub fn sign( |
@@ -150,25 +155,26 @@ pub const SeedKeyPair = struct { | |||
150 | } | 155 | } |
151 | 156 | ||
152 | pub fn seedText(self: *const Self) text_seed { | 157 | pub fn seedText(self: *const Self) text_seed { |
158 | const public_prefix = self.role.publicPrefixByte(); | ||
153 | const full_prefix = &[_]u8{ | 159 | const full_prefix = &[_]u8{ |
154 | @enumToInt(KeyTypePrefixByte.seed) | (@enumToInt(self.prefix) >> 5), | 160 | prefix_byte_seed | (public_prefix >> 5), |
155 | (@enumToInt(self.prefix) & 0b00011111) << 3, | 161 | (public_prefix & 0b00011111) << 3, |
156 | }; | 162 | }; |
157 | const seed = self.kp.secret_key[0..Ed25519.seed_length]; | 163 | const seed = self.kp.secret_key[0..Ed25519.seed_length]; |
158 | return encode(full_prefix.len, seed.len, full_prefix, seed); | 164 | return encode(full_prefix.len, seed.len, full_prefix, seed); |
159 | } | 165 | } |
160 | 166 | ||
161 | pub fn privateKeyText(self: *const Self) text_private { | 167 | pub fn privateKeyText(self: *const Self) text_private { |
162 | return encode(1, self.kp.secret_key.len, &.{@enumToInt(KeyTypePrefixByte.private)}, &self.kp.secret_key); | 168 | return encode(1, self.kp.secret_key.len, &.{prefix_byte_private}, &self.kp.secret_key); |
163 | } | 169 | } |
164 | 170 | ||
165 | pub fn publicKeyText(self: *const Self) text_public { | 171 | pub fn publicKeyText(self: *const Self) text_public { |
166 | return encode(1, self.kp.public_key.len, &.{@enumToInt(self.prefix)}, &self.kp.public_key); | 172 | return encode(1, self.kp.public_key.len, &.{self.role.publicPrefixByte()}, &self.kp.public_key); |
167 | } | 173 | } |
168 | 174 | ||
169 | pub fn intoPublicKey(self: *const Self) PublicKey { | 175 | pub fn intoPublicKey(self: *const Self) PublicKey { |
170 | return PublicKey{ | 176 | return PublicKey{ |
171 | .prefix = self.prefix, | 177 | .role = self.role, |
172 | .key = self.kp.public_key, | 178 | .key = self.kp.public_key, |
173 | }; | 179 | }; |
174 | } | 180 | } |
@@ -178,7 +184,7 @@ pub const SeedKeyPair = struct { | |||
178 | } | 184 | } |
179 | 185 | ||
180 | pub fn wipe(self: *Self) void { | 186 | pub fn wipe(self: *Self) void { |
181 | self.prefix = .account; | 187 | self.role = .account; |
182 | wipeKeyPair(&self.kp); | 188 | wipeKeyPair(&self.kp); |
183 | } | 189 | } |
184 | }; | 190 | }; |
@@ -186,27 +192,27 @@ pub const SeedKeyPair = struct { | |||
186 | pub const PublicKey = struct { | 192 | pub const PublicKey = struct { |
187 | const Self = @This(); | 193 | const Self = @This(); |
188 | 194 | ||
189 | prefix: PublicPrefixByte, | 195 | role: Role, |
190 | key: [Ed25519.public_length]u8, | 196 | key: [Ed25519.public_length]u8, |
191 | 197 | ||
192 | pub fn fromTextPublicKey(text: *const text_public) DecodeError!Self { | 198 | pub fn fromTextPublicKey(text: *const text_public) DecodeError!Self { |
193 | var decoded = try decode(1, Ed25519.public_length, text); | 199 | var decoded = try decode(1, Ed25519.public_length, text); |
194 | defer decoded.wipe(); // gets copied | 200 | defer decoded.wipe(); // gets copied |
195 | return PublicKey{ | 201 | return PublicKey{ |
196 | .prefix = try PublicPrefixByte.fromU8(decoded.prefix[0]), | 202 | .role = Role.fromPublicPrefixByte(decoded.prefix[0]) orelse return error.InvalidPrefixByte, |
197 | .key = decoded.data, | 203 | .key = decoded.data, |
198 | }; | 204 | }; |
199 | } | 205 | } |
200 | 206 | ||
201 | pub fn fromRawPublicKey( | 207 | pub fn fromRawPublicKey( |
202 | prefix: PublicPrefixByte, | 208 | role: Role, |
203 | raw_key: *const [Ed25519.public_length]u8, | 209 | raw_key: *const [Ed25519.public_length]u8, |
204 | ) Self { | 210 | ) Self { |
205 | return Self{ .prefix = prefix, .key = raw_key.* }; | 211 | return Self{ .role = role, .key = raw_key.* }; |
206 | } | 212 | } |
207 | 213 | ||
208 | pub fn publicKeyText(self: *const Self) text_public { | 214 | pub fn publicKeyText(self: *const Self) text_public { |
209 | return encode(1, self.key.len, &.{@enumToInt(self.prefix)}, &self.key); | 215 | return encode(1, self.key.len, &.{self.role.publicPrefixByte()}, &self.key); |
210 | } | 216 | } |
211 | 217 | ||
212 | pub fn verify( | 218 | pub fn verify( |
@@ -218,7 +224,7 @@ pub const PublicKey = struct { | |||
218 | } | 224 | } |
219 | 225 | ||
220 | pub fn wipe(self: *Self) void { | 226 | pub fn wipe(self: *Self) void { |
221 | self.prefix = .account; | 227 | self.role = .account; |
222 | wipeBytes(&self.key); | 228 | wipeBytes(&self.key); |
223 | } | 229 | } |
224 | }; | 230 | }; |
@@ -231,7 +237,7 @@ pub const PrivateKey = struct { | |||
231 | pub fn fromTextPrivateKey(text: *const text_private) PrivateKeyDecodeError!Self { | 237 | pub fn fromTextPrivateKey(text: *const text_private) PrivateKeyDecodeError!Self { |
232 | var decoded = try decode(1, Ed25519.secret_length, text); | 238 | var decoded = try decode(1, Ed25519.secret_length, text); |
233 | defer decoded.wipe(); // gets copied | 239 | defer decoded.wipe(); // gets copied |
234 | if (decoded.prefix[0] != @enumToInt(KeyTypePrefixByte.private)) | 240 | if (decoded.prefix[0] != prefix_byte_private) |
235 | return error.InvalidPrivateKey; | 241 | return error.InvalidPrivateKey; |
236 | return PrivateKey{ .kp = Ed25519.KeyPair.fromSecretKey(decoded.data) }; | 242 | return PrivateKey{ .kp = Ed25519.KeyPair.fromSecretKey(decoded.data) }; |
237 | } | 243 | } |
@@ -240,22 +246,22 @@ pub const PrivateKey = struct { | |||
240 | return Self{ .kp = Ed25519.KeyPair.fromSecretKey(raw_key.*) }; | 246 | return Self{ .kp = Ed25519.KeyPair.fromSecretKey(raw_key.*) }; |
241 | } | 247 | } |
242 | 248 | ||
243 | pub fn intoSeedKeyPair(self: *const Self, prefix: PublicPrefixByte) SeedKeyPair { | 249 | pub fn intoSeedKeyPair(self: *const Self, role: Role) SeedKeyPair { |
244 | return SeedKeyPair{ | 250 | return SeedKeyPair{ |
245 | .prefix = prefix, | 251 | .role = role, |
246 | .kp = self.kp, | 252 | .kp = self.kp, |
247 | }; | 253 | }; |
248 | } | 254 | } |
249 | 255 | ||
250 | pub fn intoPublicKey(self: *const Self, prefix: PublicPrefixByte) PublicKey { | 256 | pub fn intoPublicKey(self: *const Self, role: Role) PublicKey { |
251 | return PublicKey{ | 257 | return PublicKey{ |
252 | .prefix = prefix, | 258 | .role = role, |
253 | .key = self.kp.public_key, | 259 | .key = self.kp.public_key, |
254 | }; | 260 | }; |
255 | } | 261 | } |
256 | 262 | ||
257 | pub fn privateKeyText(self: *const Self) text_private { | 263 | pub fn privateKeyText(self: *const Self) text_private { |
258 | return encode(1, self.kp.secret_key.len, &.{@enumToInt(KeyTypePrefixByte.private)}, &self.kp.secret_key); | 264 | return encode(1, self.kp.secret_key.len, &.{prefix_byte_private}, &self.kp.secret_key); |
259 | } | 265 | } |
260 | 266 | ||
261 | pub fn sign( | 267 | pub fn sign( |
@@ -311,7 +317,7 @@ fn DecodedNkey(comptime prefix_len: usize, comptime data_len: usize) type { | |||
311 | data: [data_len]u8, | 317 | data: [data_len]u8, |
312 | 318 | ||
313 | pub fn wipe(self: *Self) void { | 319 | pub fn wipe(self: *Self) void { |
314 | self.prefix[0] = @enumToInt(PublicPrefixByte.account); | 320 | self.prefix[0] = Role.account.publicPrefixByte(); |
315 | wipeBytes(&self.data); | 321 | wipeBytes(&self.data); |
316 | } | 322 | } |
317 | }; | 323 | }; |
@@ -356,18 +362,18 @@ pub fn isValidEncoding(text: []const u8) bool { | |||
356 | return made_crc == got_crc; | 362 | return made_crc == got_crc; |
357 | } | 363 | } |
358 | 364 | ||
359 | pub fn isValidSeed(text: []const u8, with_type: ?PublicPrefixByte) bool { | 365 | pub fn isValidSeed(text: []const u8, with_role: ?Role) bool { |
360 | if (text.len < text_seed_len) return false; | 366 | if (text.len < text_seed_len) return false; |
361 | var res = SeedKeyPair.fromTextSeed(text[0..text_seed_len]) catch return false; | 367 | var res = SeedKeyPair.fromTextSeed(text[0..text_seed_len]) catch return false; |
362 | defer res.wipe(); | 368 | defer res.wipe(); |
363 | return if (with_type) |ty| res.prefix == ty else true; | 369 | return if (with_role) |role| res.role == role else true; |
364 | } | 370 | } |
365 | 371 | ||
366 | pub fn isValidPublicKey(text: []const u8, with_type: ?PublicPrefixByte) bool { | 372 | pub fn isValidPublicKey(text: []const u8, with_role: ?Role) bool { |
367 | if (text.len < text_public_len) return false; | 373 | if (text.len < text_public_len) return false; |
368 | var res = PublicKey.fromTextPublicKey(text[0..text_public_len]) catch return false; | 374 | var res = PublicKey.fromTextPublicKey(text[0..text_public_len]) catch return false; |
369 | defer res.wipe(); | 375 | defer res.wipe(); |
370 | return if (with_type) |ty| res.prefix == ty else true; | 376 | return if (with_role) |role| res.role == role else true; |
371 | } | 377 | } |
372 | 378 | ||
373 | pub fn isValidPrivateKey(text: []const u8) bool { | 379 | pub fn isValidPrivateKey(text: []const u8) bool { |
@@ -474,15 +480,14 @@ fn wipeBytes(bs: []u8) void { | |||
474 | 480 | ||
475 | test { | 481 | test { |
476 | testing.refAllDecls(@This()); | 482 | testing.refAllDecls(@This()); |
477 | testing.refAllDecls(KeyTypePrefixByte); | 483 | testing.refAllDecls(Role); |
478 | testing.refAllDecls(PublicPrefixByte); | ||
479 | testing.refAllDecls(SeedKeyPair); | 484 | testing.refAllDecls(SeedKeyPair); |
480 | testing.refAllDecls(PublicKey); | 485 | testing.refAllDecls(PublicKey); |
481 | testing.refAllDecls(PrivateKey); | 486 | testing.refAllDecls(PrivateKey); |
482 | } | 487 | } |
483 | 488 | ||
484 | test { | 489 | test { |
485 | var key_pair = try SeedKeyPair.generate(PublicPrefixByte.server); | 490 | var key_pair = try SeedKeyPair.generate(.server); |
486 | var decoded_seed = try SeedKeyPair.fromTextSeed(&key_pair.seedText()); | 491 | var decoded_seed = try SeedKeyPair.fromTextSeed(&key_pair.seedText()); |
487 | try testing.expect(isValidEncoding(&decoded_seed.seedText())); | 492 | try testing.expect(isValidEncoding(&decoded_seed.seedText())); |
488 | 493 | ||
@@ -517,44 +522,42 @@ test "decode" { | |||
517 | } | 522 | } |
518 | 523 | ||
519 | test "seed" { | 524 | test "seed" { |
520 | inline for (@typeInfo(PublicPrefixByte).Enum.fields) |field| { | 525 | inline for (@typeInfo(Role).Enum.fields) |field| { |
521 | const prefix = @field(PublicPrefixByte, field.name); | 526 | const role = @field(Role, field.name); |
522 | const kp = try SeedKeyPair.generate(prefix); | 527 | const kp = try SeedKeyPair.generate(role); |
523 | const decoded = try SeedKeyPair.fromTextSeed(&kp.seedText()); | 528 | const decoded = try SeedKeyPair.fromTextSeed(&kp.seedText()); |
524 | if (decoded.prefix != prefix) { | 529 | if (decoded.role != role) { |
525 | std.debug.print("expected prefix {}, found prefix {}\n", .{ prefix, decoded.prefix }); | 530 | std.debug.print("expected role {}, found role {}\n", .{ role, decoded.role }); |
526 | return error.TestUnexpectedError; | 531 | return error.TestUnexpectedError; |
527 | } | 532 | } |
528 | } | 533 | } |
529 | } | 534 | } |
530 | 535 | ||
531 | test "public key" { | 536 | test "public key" { |
532 | inline for (@typeInfo(PublicPrefixByte).Enum.fields) |field| { | 537 | inline for (@typeInfo(Role).Enum.fields) |field| { |
533 | const prefix = @field(PublicPrefixByte, field.name); | 538 | const role = @field(Role, field.name); |
534 | const kp = try SeedKeyPair.generate(prefix); | 539 | const kp = try SeedKeyPair.generate(role); |
535 | const decoded_pub_key = try PublicKey.fromTextPublicKey(&kp.publicKeyText()); | 540 | const decoded_pub_key = try PublicKey.fromTextPublicKey(&kp.publicKeyText()); |
536 | if (decoded_pub_key.prefix != prefix) { | 541 | if (decoded_pub_key.role != role) { |
537 | std.debug.print("expected prefix {}, found prefix {}\n", .{ prefix, decoded_pub_key.prefix }); | 542 | std.debug.print("expected role {}, found role {}\n", .{ role, decoded_pub_key.role }); |
538 | return error.TestUnexpectedError; | 543 | return error.TestUnexpectedError; |
539 | } | 544 | } |
540 | } | 545 | } |
541 | } | 546 | } |
542 | 547 | ||
543 | test "different key types" { | 548 | test "different key types" { |
544 | inline for (@typeInfo(PublicPrefixByte).Enum.fields) |field| { | 549 | inline for (@typeInfo(Role).Enum.fields) |field| { |
545 | const prefix = @field(PublicPrefixByte, field.name); | 550 | const role = @field(Role, field.name); |
546 | 551 | ||
547 | const kp = try SeedKeyPair.generate(prefix); | 552 | const kp = try SeedKeyPair.generate(role); |
548 | _ = try SeedKeyPair.fromTextSeed(&kp.seedText()); | 553 | _ = try SeedKeyPair.fromTextSeed(&kp.seedText()); |
549 | 554 | ||
550 | const pub_key_str = kp.publicKeyText(); | 555 | const pub_key_str = kp.publicKeyText(); |
551 | const got_pub_key_prefix = try PublicPrefixByte.fromChar(pub_key_str[0]); | 556 | try testing.expect(pub_key_str[0] == role.letter()); |
552 | try testing.expect(got_pub_key_prefix == prefix); | 557 | try testing.expect(isValidPublicKey(&pub_key_str, role)); |
553 | try testing.expect(isValidPublicKey(&pub_key_str, prefix)); | ||
554 | 558 | ||
555 | const priv_key_str = kp.privateKeyText(); | 559 | const priv_key_str = kp.privateKeyText(); |
556 | const got_priv_key_prefix = try KeyTypePrefixByte.fromChar(priv_key_str[0]); | 560 | try testing.expect(priv_key_str[0] == 'P'); |
557 | try testing.expect(got_priv_key_prefix == .private); | ||
558 | try testing.expect(isValidPrivateKey(&priv_key_str)); | 561 | try testing.expect(isValidPrivateKey(&priv_key_str)); |
559 | 562 | ||
560 | const data = "Hello, world!"; | 563 | const data = "Hello, world!"; |
@@ -565,30 +568,30 @@ test "different key types" { | |||
565 | } | 568 | } |
566 | 569 | ||
567 | test "validation" { | 570 | test "validation" { |
568 | const prefixes = @typeInfo(PublicPrefixByte).Enum.fields; | 571 | const roles = @typeInfo(Role).Enum.fields; |
569 | inline for (prefixes) |field, i| { | 572 | inline for (roles) |field, i| { |
570 | const prefix = @field(PublicPrefixByte, field.name); | 573 | const role = @field(Role, field.name); |
571 | const next_prefix = next: { | 574 | const next_role = next: { |
572 | const next_field_i = if (i == prefixes.len - 1) 0 else i + 1; | 575 | const next_field_i = if (i == roles.len - 1) 0 else i + 1; |
573 | std.debug.assert(next_field_i != i); | 576 | std.debug.assert(next_field_i != i); |
574 | break :next @field(PublicPrefixByte, prefixes[next_field_i].name); | 577 | break :next @field(Role, roles[next_field_i].name); |
575 | }; | 578 | }; |
576 | const kp = try SeedKeyPair.generate(prefix); | 579 | const kp = try SeedKeyPair.generate(role); |
577 | 580 | ||
578 | const seed_str = kp.seedText(); | 581 | const seed_str = kp.seedText(); |
579 | const pub_key_str = kp.publicKeyText(); | 582 | const pub_key_str = kp.publicKeyText(); |
580 | const priv_key_str = kp.privateKeyText(); | 583 | const priv_key_str = kp.privateKeyText(); |
581 | 584 | ||
582 | try testing.expect(isValidSeed(&seed_str, prefix)); | 585 | try testing.expect(isValidSeed(&seed_str, role)); |
583 | try testing.expect(isValidSeed(&seed_str, null)); | 586 | try testing.expect(isValidSeed(&seed_str, null)); |
584 | try testing.expect(isValidPublicKey(&pub_key_str, null)); | 587 | try testing.expect(isValidPublicKey(&pub_key_str, null)); |
585 | try testing.expect(isValidPublicKey(&pub_key_str, prefix)); | 588 | try testing.expect(isValidPublicKey(&pub_key_str, role)); |
586 | try testing.expect(isValidPrivateKey(&priv_key_str)); | 589 | try testing.expect(isValidPrivateKey(&priv_key_str)); |
587 | 590 | ||
588 | try testing.expect(!isValidSeed(&seed_str, next_prefix)); | 591 | try testing.expect(!isValidSeed(&seed_str, next_role)); |
589 | try testing.expect(!isValidSeed(&pub_key_str, null)); | 592 | try testing.expect(!isValidSeed(&pub_key_str, null)); |
590 | try testing.expect(!isValidSeed(&priv_key_str, null)); | 593 | try testing.expect(!isValidSeed(&priv_key_str, null)); |
591 | try testing.expect(!isValidPublicKey(&pub_key_str, next_prefix)); | 594 | try testing.expect(!isValidPublicKey(&pub_key_str, next_role)); |
592 | try testing.expect(!isValidPublicKey(&seed_str, null)); | 595 | try testing.expect(!isValidPublicKey(&seed_str, null)); |
593 | try testing.expect(!isValidPublicKey(&priv_key_str, null)); | 596 | try testing.expect(!isValidPublicKey(&priv_key_str, null)); |
594 | try testing.expect(!isValidPrivateKey(&seed_str)); | 597 | try testing.expect(!isValidPrivateKey(&seed_str)); |
@@ -602,7 +605,7 @@ test "validation" { | |||
602 | 605 | ||
603 | test "from seed" { | 606 | test "from seed" { |
604 | const kp = try SeedKeyPair.generate(.account); | 607 | const kp = try SeedKeyPair.generate(.account); |
605 | const kp_from_raw = try SeedKeyPair.fromRawSeed(kp.prefix, kp.kp.secret_key[0..Ed25519.seed_length]); | 608 | const kp_from_raw = try SeedKeyPair.fromRawSeed(kp.role, kp.kp.secret_key[0..Ed25519.seed_length]); |
606 | try testing.expect(std.meta.eql(kp, kp_from_raw)); | 609 | try testing.expect(std.meta.eql(kp, kp_from_raw)); |
607 | 610 | ||
608 | const data = "Hello, World!"; | 611 | const data = "Hello, World!"; |
@@ -625,7 +628,7 @@ test "from public key" { | |||
625 | const pk = try PublicKey.fromTextPublicKey(&pk_text); | 628 | const pk = try PublicKey.fromTextPublicKey(&pk_text); |
626 | const pk_text_clone_2 = pk.publicKeyText(); | 629 | const pk_text_clone_2 = pk.publicKeyText(); |
627 | try testing.expect(std.meta.eql(pk, kp.intoPublicKey())); | 630 | try testing.expect(std.meta.eql(pk, kp.intoPublicKey())); |
628 | try testing.expect(std.meta.eql(pk, PublicKey.fromRawPublicKey(kp.prefix, &kp.kp.public_key))); | 631 | try testing.expect(std.meta.eql(pk, PublicKey.fromRawPublicKey(kp.role, &kp.kp.public_key))); |
629 | try testing.expectEqualStrings(&pk_text, &pk_text_clone_2); | 632 | try testing.expectEqualStrings(&pk_text, &pk_text_clone_2); |
630 | 633 | ||
631 | const data = "Hello, world!"; | 634 | const data = "Hello, world!"; |