| ... | @@ -385,24 +385,23 @@ pub const Ed25519 = struct { | ... | @@ -385,24 +385,23 @@ pub const Ed25519 = struct { |
| 385 | ); | 385 | ); |
| 386 | } | 386 | } |
| 387 | | 387 | |
| 388 | /// Create a Signer, that can be used for incremental signing. | 388 | /// Create a signer that can be used for incremental signing, using a custom base nonce. |
| 389 | /// Note that the signature is not deterministic. | 389 | /// `base_nonce` must be unique for each signed message; otherwise, the secret key can |
| 390 | pub fn signer( | 390 | /// be trivially recovered by an attacker. |
| | 391 | /// It can be generated using a cryptographically secure random number generator. |
| | 392 | pub fn signerWithBaseNonce( |
| 391 | key_pair: KeyPair, | 393 | key_pair: KeyPair, |
| 392 | /// If set, should be something unique for each message, such as a | 394 | base_nonce: [32]u8, |
| 393 | /// random nonce, or a counter. | 395 | /// If set, should be something unique for each message, such as a counter. |
| 394 | noise: ?[noise_length]u8, | 396 | noise: ?[noise_length]u8, |
| 395 | io: std.Io, | | |
| 396 | ) (IdentityElementError || KeyMismatchError || NonCanonicalError || WeakPublicKeyError)!Signer { | 397 | ) (IdentityElementError || KeyMismatchError || NonCanonicalError || WeakPublicKeyError)!Signer { |
| 397 | if (!mem.eql(u8, &key_pair.secret_key.publicKeyBytes(), &key_pair.public_key.toBytes())) { | 398 | if (!mem.eql(u8, &key_pair.secret_key.publicKeyBytes(), &key_pair.public_key.toBytes())) { |
| 398 | return error.KeyMismatch; | 399 | return error.KeyMismatch; |
| 399 | } | 400 | } |
| 400 | const scalar_and_prefix = key_pair.secret_key.scalarAndPrefix(); | 401 | const scalar_and_prefix = key_pair.secret_key.scalarAndPrefix(); |
| 401 | var entropy: [noise_length]u8 = undefined; | | |
| 402 | io.random(&entropy); | | |
| 403 | var h = Sha512.init(.{}); | 402 | var h = Sha512.init(.{}); |
| 404 | h.update(&scalar_and_prefix.prefix); | 403 | h.update(&scalar_and_prefix.prefix); |
| 405 | h.update(&entropy); | 404 | h.update(&base_nonce); |
| 406 | if (noise) |*z| { | 405 | if (noise) |*z| { |
| 407 | h.update(z); | 406 | h.update(z); |
| 408 | } | 407 | } |
| ... | @@ -412,6 +411,20 @@ pub const Ed25519 = struct { | ... | @@ -412,6 +411,20 @@ pub const Ed25519 = struct { |
| 412 | | 411 | |
| 413 | return Signer.init(scalar_and_prefix.scalar, nonce, key_pair.public_key); | 412 | return Signer.init(scalar_and_prefix.scalar, nonce, key_pair.public_key); |
| 414 | } | 413 | } |
| | 414 | |
| | 415 | /// Create a Signer, that can be used for incremental signing. |
| | 416 | /// Note that the signature is not deterministic. |
| | 417 | pub fn signer( |
| | 418 | key_pair: KeyPair, |
| | 419 | /// If set, should be something unique for each message, such as a |
| | 420 | /// random nonce, or a counter. |
| | 421 | noise: ?[noise_length]u8, |
| | 422 | io: std.Io, |
| | 423 | ) (IdentityElementError || KeyMismatchError || NonCanonicalError || WeakPublicKeyError)!Signer { |
| | 424 | var base_nonce: [32]u8 = undefined; |
| | 425 | io.random(&base_nonce); |
| | 426 | return key_pair.signerWithBaseNonce(base_nonce, noise); |
| | 427 | } |
| 415 | }; | 428 | }; |
| 416 | | 429 | |
| 417 | /// A (signature, message, public_key) tuple for batch verification | 430 | /// A (signature, message, public_key) tuple for batch verification |