| author | |
| committer | |
| log | e7bc7efda73eb68e5d599feb18e2538cc16df85e |
| tree | 94dc9e845504aa6a2c2ccd10667ac6669dd7198e |
| parent | d593a596185c3442afa2e1955e1157a31bd4b554 |
According to SEC1, the point at infinity has a unique
representation (encoded as single 00 byte); it's not supposed to be
representable in affine coordinates.
So we can simplify the function to just check the equation.
The point at infinity can still be decoded by the regular fromSec1()
function.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 | } |
| 61 | 57 | ||
| 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 | } |
| 61 | 57 | ||
| 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 | } |
| 114 | 110 | ||
| 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" { |
| 103 | 103 | ||
| 104 | test "p256 neutral element decoding" { | 104 | test "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 | } |
| 109 | 109 | ||
| 110 | test "p256 double base multiplication" { | 110 | test "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" { |
| 106 | 106 | ||
| 107 | test "p384 neutral element decoding" { | 107 | test "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 | } |
| 112 | 112 | ||
| 113 | test "p384 double base multiplication" { | 113 | test "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" { |
| 115 | 115 | ||
| 116 | test "secp256k1 neutral element decoding" { | 116 | test "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 | |||
| 122 | test "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 | } |
| 121 | 130 | ||
| 122 | test "secp256k1 double base multiplication" { | 131 | test "secp256k1 double base multiplication" { |