diff --git a/lib/std/crypto/25519/curve25519.zig b/lib/std/crypto/25519/curve25519.zig index 7c3343ba8c..d5d70d00e4 100644 --- a/lib/std/crypto/25519/curve25519.zig +++ b/lib/std/crypto/25519/curve25519.zig @@ -105,7 +105,8 @@ pub const Curve25519 = struct { pub fn fromEdwards25519(p: crypto.ecc.Edwards25519) IdentityElementError!Curve25519 { try p.clearCofactor().rejectIdentity(); const one = crypto.ecc.Edwards25519.Fe.one; - const x = one.add(p.y).mul(one.sub(p.y).invert()); // xMont=(1+yEd)/(1-yEd) + const py = p.y.mul(p.z.invert()); + const x = one.add(py).mul(one.sub(py).invert()); // xMont=(1+yEd)/(1-yEd) return Curve25519{ .x = x }; } }; @@ -124,6 +125,18 @@ test "curve25519" { try std.testing.expectError(error.NonCanonical, Curve25519.rejectNonCanonical(s)); } +test "non-affine edwards25519 to curve25519 projection" { + const skh = "90e7595fc89e52fdfddce9c6a43d74dbf6047025ee0462d2d172e8b6a2841d6e"; + var sk: [32]u8 = undefined; + _ = std.fmt.hexToBytes(&sk, skh) catch unreachable; + var edp = try crypto.ecc.Edwards25519.basePoint.mul(sk); + const xp = try Curve25519.fromEdwards25519(edp); + const expected_hex = "cc4f2cdb695dd766f34118eb67b98652fed1d8bc49c330b119bbfa8a64989378"; + var expected: [32]u8 = undefined; + _ = std.fmt.hexToBytes(&expected, expected_hex) catch unreachable; + try std.testing.expectEqualSlices(u8, &xp.toBytes(), &expected); +} + test "curve25519 small order check" { var s: [32]u8 = [_]u8{1} ++ [_]u8{0} ** 31; const small_order_ss: [7][32]u8 = .{