Created
July 14, 2023 09:13
-
-
Save jedisct1/40e4d4d82af831bc13ffa4cee792856f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/lib/std/crypto/ecdsa.zig b/lib/std/crypto/ecdsa.zig | |
index 1a5335b07..b78cf6f6e 100644 | |
--- a/lib/std/crypto/ecdsa.zig | |
+++ b/lib/std/crypto/ecdsa.zig | |
@@ -196,8 +196,11 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { | |
self.h.update(data); | |
} | |
- /// Compute a signature over the entire message. | |
- pub fn finalize(self: *Signer) (IdentityElementError || NonCanonicalError)!Signature { | |
+ /// Recovery ID. | |
+ pub const RecoveryId = u2; | |
+ | |
+ /// Compute a signature over the entire message, returning the signature as well as a recovery ID that can be used to recover the public key. | |
+ pub fn finalizeForPublicKeyRecovery(self: *Signer) (IdentityElementError || NonCanonicalError)!struct { Signature, RecoveryId } { | |
const scalar_encoded_length = Curve.scalar.encoded_length; | |
const h_len = @max(Hash.digest_length, scalar_encoded_length); | |
var h: [h_len]u8 = [_]u8{0} ** h_len; | |
@@ -210,7 +213,8 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { | |
const k = deterministicScalar(h_slice.*, self.secret_key.bytes, self.noise); | |
const p = try Curve.basePoint.mul(k.toBytes(.Big), .Big); | |
- const xs = p.affineCoordinates().x.toBytes(.Big); | |
+ const p_affine = p.affineCoordinates(); | |
+ const xs = p_affine.x.toBytes(.Big); | |
const r = reduceToScalar(Curve.Fe.encoded_length, xs); | |
if (r.isZero()) return error.IdentityElement; | |
@@ -219,7 +223,21 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { | |
const s = k_inv.mul(zrs); | |
if (s.isZero()) return error.IdentityElement; | |
- return Signature{ .r = r.toBytes(.Big), .s = s.toBytes(.Big) }; | |
+ const r_bytes = r.toBytes(.Big); | |
+ | |
+ const x_is_canonical = crypto.utils.timingSafeEql(@TypeOf(xs), xs, r_bytes); | |
+ const y_is_odd = p_affine.y.isOdd(); | |
+ const sig = Signature{ .r = r_bytes, .s = s.toBytes(.Big) }; | |
+ var recovery_id = @as(RecoveryId, @as(u1, @bitCast(x_is_canonical)) ^ 1) << 1; | |
+ recovery_id |= @as(u1, @bitCast(y_is_odd)); | |
+ | |
+ return .{ sig, recovery_id }; | |
+ } | |
+ | |
+ /// Compute a signature over the entire message. | |
+ pub fn finalize(self: *Signer) (IdentityElementError || NonCanonicalError)!Signature { | |
+ const ret = try self.finalizeForPublicKeyRecovery(); | |
+ return ret[0]; | |
} | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment