authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2026-07-05 12:29:29+02:00
committergravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2026-07-05 12:29:29+02:00
log59a628c6d98d52aec394a7d270999c6349f7ec82
tree94dc9e845504aa6a2c2ccd10667ac6669dd7198e
parentd593a596185c3442afa2e1955e1157a31bd4b554
parente7bc7efda73eb68e5d599feb18e2538cc16df85e

Merge pull request 'crypto.pcurves: reject affine encodings of the point at infinity' (#35513) from jedisct1/zig:pcurvesidentity into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35513

6 files changed, 21 insertions(+), 24 deletions(-)

lib/std/crypto/pcurves/p256.zig+2-6
......@@ -49,14 +49,10 @@ pub const P256 = struct {
4949 const y = p.y;
5050 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);
5151 const yy = y.sq();
52 const on_curve = @intFromBool(x3AxB.equivalent(yy));
53 const is_identity = @intFromBool(x.equivalent(AffineCoordinates.identityElement.x)) & @intFromBool(y.equivalent(AffineCoordinates.identityElement.y));
54 if ((on_curve | is_identity) == 0) {
52 if (!x3AxB.equivalent(yy)) {
5553 return error.InvalidEncoding;
5654 }
57 var ret = P256{ .x = x, .y = y, .z = Fe.one };
58 ret.z.cMov(P256.identityElement.z, is_identity);
59 return ret;
55 return .{ .x = x, .y = y, .z = Fe.one };
6056 }
6157
6258 /// Create a point from serialized affine coordinates.
lib/std/crypto/pcurves/p384.zig+2-6
......@@ -49,14 +49,10 @@ pub const P384 = struct {
4949 const y = p.y;
5050 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);
5151 const yy = y.sq();
52 const on_curve = @intFromBool(x3AxB.equivalent(yy));
53 const is_identity = @intFromBool(x.equivalent(AffineCoordinates.identityElement.x)) & @intFromBool(y.equivalent(AffineCoordinates.identityElement.y));
54 if ((on_curve | is_identity) == 0) {
52 if (!x3AxB.equivalent(yy)) {
5553 return error.InvalidEncoding;
5654 }
57 var ret = P384{ .x = x, .y = y, .z = Fe.one };
58 ret.z.cMov(P384.identityElement.z, is_identity);
59 return ret;
55 return .{ .x = x, .y = y, .z = Fe.one };
6056 }
6157
6258 /// Create a point from serialized affine coordinates.
lib/std/crypto/pcurves/secp256k1.zig+2-6
......@@ -102,14 +102,10 @@ pub const Secp256k1 = struct {
102102 const y = p.y;
103103 const x3B = x.sq().mul(x).add(B);
104104 const yy = y.sq();
105 const on_curve = @intFromBool(x3B.equivalent(yy));
106 const is_identity = @intFromBool(x.equivalent(AffineCoordinates.identityElement.x)) & @intFromBool(y.equivalent(AffineCoordinates.identityElement.y));
107 if ((on_curve | is_identity) == 0) {
105 if (!x3B.equivalent(yy)) {
108106 return error.InvalidEncoding;
109107 }
110 var ret = Secp256k1{ .x = x, .y = y, .z = Fe.one };
111 ret.z.cMov(Secp256k1.identityElement.z, is_identity);
112 return ret;
108 return .{ .x = x, .y = y, .z = Fe.one };
113109 }
114110
115111 /// Create a point from serialized affine coordinates.
lib/std/crypto/pcurves/tests/p256.zig+2-2
......@@ -103,8 +103,8 @@ test "p256 field element non-canonical encoding" {
103103
104104test "p256 neutral element decoding" {
105105 try testing.expectError(error.InvalidEncoding, P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.zero }));
106 const p = try P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.one });
107 try testing.expectError(error.IdentityElement, p.rejectIdentity());
106 try testing.expectError(error.InvalidEncoding, P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.one }));
107 try testing.expectError(error.IdentityElement, P256.identityElement.rejectIdentity());
108108}
109109
110110test "p256 double base multiplication" {
lib/std/crypto/pcurves/tests/p384.zig+2-2
......@@ -106,8 +106,8 @@ test "p384 field element non-canonical encoding" {
106106
107107test "p384 neutral element decoding" {
108108 try testing.expectError(error.InvalidEncoding, P384.fromAffineCoordinates(.{ .x = P384.Fe.zero, .y = P384.Fe.zero }));
109 const p = try P384.fromAffineCoordinates(.{ .x = P384.Fe.zero, .y = P384.Fe.one });
110 try testing.expectError(error.IdentityElement, p.rejectIdentity());
109 try testing.expectError(error.InvalidEncoding, P384.fromAffineCoordinates(.{ .x = P384.Fe.zero, .y = P384.Fe.one }));
110 try testing.expectError(error.IdentityElement, P384.identityElement.rejectIdentity());
111111}
112112
113113test "p384 double base multiplication" {
lib/std/crypto/pcurves/tests/secp256k1.zig+11-2
......@@ -115,8 +115,17 @@ test "secp256k1 field element non-canonical encoding" {
115115
116116test "secp256k1 neutral element decoding" {
117117 try testing.expectError(error.InvalidEncoding, Secp256k1.fromAffineCoordinates(.{ .x = Secp256k1.Fe.zero, .y = Secp256k1.Fe.zero }));
118 const p = try Secp256k1.fromAffineCoordinates(.{ .x = Secp256k1.Fe.zero, .y = Secp256k1.Fe.one });
119 try testing.expectError(error.IdentityElement, p.rejectIdentity());
118 try testing.expectError(error.InvalidEncoding, Secp256k1.fromAffineCoordinates(.{ .x = Secp256k1.Fe.zero, .y = Secp256k1.Fe.one }));
119 try testing.expectError(error.IdentityElement, Secp256k1.identityElement.rejectIdentity());
120}
121
122test "secp256k1 uncompressed SEC1 must not accept infinity" {
123 var buf: [65]u8 = @splat(0);
124 buf[0] = 0x04;
125 buf[64] = 0x01;
126 try testing.expectError(error.InvalidEncoding, Secp256k1.fromSec1(&buf));
127 buf[64] = 0x00;
128 try testing.expectError(error.InvalidEncoding, Secp256k1.fromSec1(&buf));
120129}
121130
122131test "secp256k1 double base multiplication" {