| ... | ... | @@ -229,15 +229,14 @@ pub const Ed25519 = struct { |
| 229 | 229 | blind_secret_key: BlindSecretKey, |
| 230 | 230 | }; |
| 231 | 231 | |
| 232 | | /// Blind an existing key pair with a blinding seed. |
| 233 | | pub fn blind(key_pair: Ed25519.KeyPair, blind_seed: [blind_seed_length]u8) !BlindKeyPair { |
| 232 | /// Blind an existing key pair with a blinding seed and a context. |
| 233 | pub fn blind(key_pair: Ed25519.KeyPair, blind_seed: [blind_seed_length]u8, ctx: []const u8) !BlindKeyPair { |
| 234 | 234 | var h: [Sha512.digest_length]u8 = undefined; |
| 235 | 235 | Sha512.hash(key_pair.secret_key[0..32], &h, .{}); |
| 236 | 236 | Curve.scalar.clamp(h[0..32]); |
| 237 | 237 | const scalar = Curve.scalar.reduce(h[0..32].*); |
| 238 | 238 | |
| 239 | | var blind_h: [Sha512.digest_length]u8 = undefined; |
| 240 | | Sha512.hash(blind_seed[0..], &blind_h, .{}); |
| 239 | const blind_h = blindCtx(blind_seed, ctx); |
| 241 | 240 | const blind_factor = Curve.scalar.reduce(blind_h[0..32].*); |
| 242 | 241 | |
| 243 | 242 | const blind_scalar = Curve.scalar.mul(scalar, blind_factor); |
| ... | ... | @@ -259,9 +258,8 @@ pub const Ed25519 = struct { |
| 259 | 258 | } |
| 260 | 259 | |
| 261 | 260 | /// Recover a public key from a blind version of it. |
| 262 | | pub fn unblindPublicKey(blind_public_key: [public_length]u8, blind_seed: [blind_seed_length]u8) ![public_length]u8 { |
| 263 | | var blind_h: [Sha512.digest_length]u8 = undefined; |
| 264 | | Sha512.hash(&blind_seed, &blind_h, .{}); |
| 261 | pub fn unblindPublicKey(blind_public_key: [public_length]u8, blind_seed: [blind_seed_length]u8, ctx: []const u8) ![public_length]u8 { |
| 262 | const blind_h = blindCtx(blind_seed, ctx); |
| 265 | 263 | const inv_blind_factor = Scalar.fromBytes(blind_h[0..32].*).invert().toBytes(); |
| 266 | 264 | const public_key = try (try Curve.fromBytes(blind_public_key)).mul(inv_blind_factor); |
| 267 | 265 | return public_key.toBytes(); |
| ... | ... | @@ -297,6 +295,17 @@ pub const Ed25519 = struct { |
| 297 | 295 | mem.copy(u8, sig[32..], s[0..]); |
| 298 | 296 | return sig; |
| 299 | 297 | } |
| 298 | |
| 299 | /// Compute a blind context from a blinding seed and a context. |
| 300 | fn blindCtx(blind_seed: [blind_seed_length]u8, ctx: []const u8) [Sha512.digest_length]u8 { |
| 301 | var blind_h: [Sha512.digest_length]u8 = undefined; |
| 302 | var hx = Sha512.init(.{}); |
| 303 | hx.update(&blind_seed); |
| 304 | hx.update(&[1]u8{0}); |
| 305 | hx.update(ctx); |
| 306 | hx.final(&blind_h); |
| 307 | return blind_h; |
| 308 | } |
| 300 | 309 | }; |
| 301 | 310 | }; |
| 302 | 311 | |
| ... | ... | @@ -458,7 +467,7 @@ test "ed25519 with blind keys" { |
| 458 | 467 | crypto.random.bytes(&blind); |
| 459 | 468 | |
| 460 | 469 | // Blind the key pair |
| 461 | | const blind_kp = try BlindKeySignatures.blind(kp, blind); |
| 470 | const blind_kp = try BlindKeySignatures.blind(kp, blind, "ctx"); |
| 462 | 471 | |
| 463 | 472 | // Sign a message and check that it can be verified with the blind public key |
| 464 | 473 | const msg = "test"; |
| ... | ... | @@ -466,6 +475,6 @@ test "ed25519 with blind keys" { |
| 466 | 475 | try Ed25519.verify(sig, msg, blind_kp.blind_public_key); |
| 467 | 476 | |
| 468 | 477 | // Unblind the public key |
| 469 | | const pk = try BlindKeySignatures.unblindPublicKey(blind_kp.blind_public_key, blind); |
| 478 | const pk = try BlindKeySignatures.unblindPublicKey(blind_kp.blind_public_key, blind, "ctx"); |
| 470 | 479 | try std.testing.expectEqualSlices(u8, &pk, &kp.public_key); |
| 471 | 480 | } |