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 {...@@ -49,14 +49,10 @@ pub const P256 = struct {
49 const y = p.y;49 const y = p.y;
50 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);50 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);
51 const yy = y.sq();51 const yy = y.sq();
52 const on_curve = @intFromBool(x3AxB.equivalent(yy));52 if (!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) {
55 return error.InvalidEncoding;53 return error.InvalidEncoding;
56 }54 }
57 var ret = P256{ .x = x, .y = y, .z = Fe.one };55 return .{ .x = x, .y = y, .z = Fe.one };
58 ret.z.cMov(P256.identityElement.z, is_identity);
59 return ret;
60 }56 }
6157
62 /// Create a point from serialized affine coordinates.58 /// Create a point from serialized affine coordinates.
lib/std/crypto/pcurves/p384.zig+2-6
...@@ -49,14 +49,10 @@ pub const P384 = struct {...@@ -49,14 +49,10 @@ pub const P384 = struct {
49 const y = p.y;49 const y = p.y;
50 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);50 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);
51 const yy = y.sq();51 const yy = y.sq();
52 const on_curve = @intFromBool(x3AxB.equivalent(yy));52 if (!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) {
55 return error.InvalidEncoding;53 return error.InvalidEncoding;
56 }54 }
57 var ret = P384{ .x = x, .y = y, .z = Fe.one };55 return .{ .x = x, .y = y, .z = Fe.one };
58 ret.z.cMov(P384.identityElement.z, is_identity);
59 return ret;
60 }56 }
6157
62 /// Create a point from serialized affine coordinates.58 /// Create a point from serialized affine coordinates.
lib/std/crypto/pcurves/secp256k1.zig+2-6
...@@ -102,14 +102,10 @@ pub const Secp256k1 = struct {...@@ -102,14 +102,10 @@ pub const Secp256k1 = struct {
102 const y = p.y;102 const y = p.y;
103 const x3B = x.sq().mul(x).add(B);103 const x3B = x.sq().mul(x).add(B);
104 const yy = y.sq();104 const yy = y.sq();
105 const on_curve = @intFromBool(x3B.equivalent(yy));105 if (!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) {
108 return error.InvalidEncoding;106 return error.InvalidEncoding;
109 }107 }
110 var ret = Secp256k1{ .x = x, .y = y, .z = Fe.one };108 return .{ .x = x, .y = y, .z = Fe.one };
111 ret.z.cMov(Secp256k1.identityElement.z, is_identity);
112 return ret;
113 }109 }
114110
115 /// Create a point from serialized affine coordinates.111 /// 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" {...@@ -103,8 +103,8 @@ test "p256 field element non-canonical encoding" {
103103
104test "p256 neutral element decoding" {104test "p256 neutral element decoding" {
105 try testing.expectError(error.InvalidEncoding, P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.zero }));105 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 });106 try testing.expectError(error.InvalidEncoding, P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.one }));
107 try testing.expectError(error.IdentityElement, p.rejectIdentity());107 try testing.expectError(error.IdentityElement, P256.identityElement.rejectIdentity());
108}108}
109109
110test "p256 double base multiplication" {110test "p256 double base multiplication" {
lib/std/crypto/pcurves/tests/p384.zig+2-2
...@@ -106,8 +106,8 @@ test "p384 field element non-canonical encoding" {...@@ -106,8 +106,8 @@ test "p384 field element non-canonical encoding" {
106106
107test "p384 neutral element decoding" {107test "p384 neutral element decoding" {
108 try testing.expectError(error.InvalidEncoding, P384.fromAffineCoordinates(.{ .x = P384.Fe.zero, .y = P384.Fe.zero }));108 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 });109 try testing.expectError(error.InvalidEncoding, P384.fromAffineCoordinates(.{ .x = P384.Fe.zero, .y = P384.Fe.one }));
110 try testing.expectError(error.IdentityElement, p.rejectIdentity());110 try testing.expectError(error.IdentityElement, P384.identityElement.rejectIdentity());
111}111}
112112
113test "p384 double base multiplication" {113test "p384 double base multiplication" {
lib/std/crypto/pcurves/tests/secp256k1.zig+11-2
...@@ -115,8 +115,17 @@ test "secp256k1 field element non-canonical encoding" {...@@ -115,8 +115,17 @@ test "secp256k1 field element non-canonical encoding" {
115115
116test "secp256k1 neutral element decoding" {116test "secp256k1 neutral element decoding" {
117 try testing.expectError(error.InvalidEncoding, Secp256k1.fromAffineCoordinates(.{ .x = Secp256k1.Fe.zero, .y = Secp256k1.Fe.zero }));117 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 });118 try testing.expectError(error.InvalidEncoding, Secp256k1.fromAffineCoordinates(.{ .x = Secp256k1.Fe.zero, .y = Secp256k1.Fe.one }));
119 try testing.expectError(error.IdentityElement, p.rejectIdentity());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));
120}129}
121130
122test "secp256k1 double base multiplication" {131test "secp256k1 double base multiplication" {