zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit e8ca9229c8aa6bd2d8abb1f91a8662eed2e68fd5 (tree)
parent 27ef6e9a9b21ff7ca4e349af4384a3a23a1e3cde
Author: Frank Denis <github@pureftpd.org>
Date:   Mon, 23 Feb 2026 23:04:26 +0100

Expose the elligator map for Curve25519

This is the same as for Edwards25519 without the y coordinate,
since it returns Montgomery coordinates, but it can be confusing
to call the Edwards25519 function while working on the
Curve25519 representation.

New protocols such as CPACE requires the map over Curve25519.

Diffstat:
Mlib/std/crypto/25519/curve25519.zig | 22++++++++++++++++++++++
1 file changed, 22 insertions(+), 0 deletions(-)

diff --git a/lib/std/crypto/25519/curve25519.zig b/lib/std/crypto/25519/curve25519.zig @@ -101,6 +101,11 @@ pub const Curve25519 = struct { return try ladder(p, s, 256); } + /// Elligator2 map for Curve25519. + pub fn elligator2(r: Fe) Curve25519 { + return .{ .x = crypto.ecc.Edwards25519.elligator2(r).x }; + } + /// Compute the Curve25519 equivalent to an Edwards25519 point. /// /// Note that the function doesn't check that the input point is @@ -145,6 +150,23 @@ test "non-affine edwards25519 to curve25519 projection" { try std.testing.expectEqualSlices(u8, &xp.toBytes(), &expected); } +test "elligator2" { + const Fe = Curve25519.Fe; + + // RFC 9380 Appendix J.4.2 test vector (curve25519_XMD:SHA-512_ELL2_NU_) + // u = 0x608d892b641f0328523802a6603427c26e55e6f27e71a91a478148d45b5093cd + // Q.x = 0x51125222da5e763d97f3c10fcc92ea6860b9ccbbd2eb1285728f566721c1e65b + const u = Fe.fromBytes(.{ + 0xcd, 0x93, 0x50, 0x5b, 0xd4, 0x48, 0x81, 0x47, 0x1a, 0xa9, 0x71, 0x7e, 0xf2, 0xe6, 0x55, 0x6e, + 0xc2, 0x27, 0x34, 0x60, 0xa6, 0x02, 0x38, 0x52, 0x28, 0x03, 0x1f, 0x64, 0x2b, 0x89, 0x8d, 0x60, + }); + const p = Curve25519.elligator2(u); + try std.testing.expectEqual([32]u8{ + 0x5b, 0xe6, 0xc1, 0x21, 0x67, 0x56, 0x8f, 0x72, 0x85, 0x12, 0xeb, 0xd2, 0xbb, 0xcc, 0xb9, 0x60, + 0x68, 0xea, 0x92, 0xcc, 0x0f, 0xc1, 0xf3, 0x97, 0x3d, 0x76, 0x5e, 0xda, 0x22, 0x52, 0x12, 0x51, + }, p.toBytes()); +} + test "small order check" { var s: [32]u8 = [_]u8{1} ++ [_]u8{0} ** 31; const small_order_ss: [7][32]u8 = .{