Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

Curve25519

Group operations over Curve25519.

curve25519.Curve25519
pub const Curve25519 = struct

File

lib/std/crypto/25519/curve25519.zig:9

Code

pub const Curve25519 = struct {
    /// The underlying prime field.
    pub const Fe = @import("field.zig").Fe;
    /// Field arithmetic mod the order of the main subgroup.
    pub const scalar = @import("scalar.zig");

    x: Fe,

    /// Decode a Curve25519 point from its compressed (X) coordinates.
    pub fn fromBytes(s: [32]u8) Curve25519 {
        return .{ .x = Fe.fromBytes(s) };
    }

    /// Encode a Curve25519 point.
    pub fn toBytes(p: Curve25519) [32]u8 {
        return p.x.toBytes();
    }

    /// The Curve25519 base point.
    pub const basePoint = Curve25519{ .x = Fe.curve25519BasePoint };

    /// Check that the encoding of a Curve25519 point is canonical.
    pub fn rejectNonCanonical(s: [32]u8) NonCanonicalError!void {
        return Fe.rejectNonCanonical(s, false);
    }

    /// Reject the neutral element.
    pub fn rejectIdentity(p: Curve25519) IdentityElementError!void {
        if (p.x.isZero()) {
            return error.IdentityElement;
        }
    }

    /// Multiply a point by the cofactor, returning WeakPublicKey if the element is in a small-order group.
    pub fn clearCofactor(p: Curve25519) WeakPublicKeyError!Curve25519 {
        const cofactor = [_]u8{8} ++ @as([31]u8, @splat(0));
        return ladder(p, cofactor, 4) catch return error.WeakPublicKey;
    }

    fn ladder(p: Curve25519, s: [32]u8, comptime bits: usize) IdentityElementError!Curve25519 {
        var x1 = p.x;
        var x2 = Fe.one;
        var z2 = Fe.zero;
        var x3 = x1;
        var z3 = Fe.one;
        var swap: u8 = 0;
        var pos: usize = bits - 1;
        while (true) : (pos -= 1) {
            const bit = (s[pos >> 3] >> @as(u3, @truncate(pos))) & 1;
            swap ^= bit;
            Fe.cSwap2(&x2, &x3, &z2, &z3, swap);
            swap = bit;
            const a = x2.add(z2);
            const b = x2.sub(z2);
            const aa = a.sq();
            const bb = b.sq();
            x2 = aa.mul(bb);
            const e = aa.sub(bb);
            const da = x3.sub(z3).mul(a);
            const cb = x3.add(z3).mul(b);
            x3 = da.add(cb).sq();
            z3 = x1.mul(da.sub(cb).sq());
            z2 = e.mul(bb.add(e.mul32(121666)));
            if (pos == 0) break;
        }
        Fe.cSwap2(&x2, &x3, &z2, &z3, swap);
        z2 = z2.invert();
        x2 = x2.mul(z2);
        if (x2.isZero()) {
            return error.IdentityElement;
        }
        return Curve25519{ .x = x2 };
    }

    /// Multiply a Curve25519 point by a scalar after "clamping" it.
    /// Clamping forces the scalar to be a multiple of the cofactor in
    /// order to prevent small subgroups attacks. This is the standard
    /// way to use Curve25519 for a DH operation.
    /// Return error.IdentityElement if the resulting point is
    /// the identity element.
    pub fn clampedMul(p: Curve25519, s: [32]u8) IdentityElementError!Curve25519 {
        var t: [32]u8 = s;
        scalar.clamp(&t);
        return try ladder(p, t, 255);
    }

    /// Multiply a Curve25519 point by a scalar without clamping it.
    /// Return error.IdentityElement if the resulting point is
    /// the identity element or error.WeakPublicKey if the public
    /// key is a low-order point.
    pub fn mul(p: Curve25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Curve25519 {
        _ = try p.clearCofactor();
        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
    /// on the prime order group, e.g. that it is an Ed25519 public key
    /// for which an Ed25519 secret key exists.
    ///
    /// If this is required, for example for compatibility with libsodium's strict
    /// validation policy, the caller can call the `rejectUnexpectedSubgroup` function
    /// on the input point before calling this function.
    pub fn fromEdwards25519(p: crypto.ecc.Edwards25519) IdentityElementError!Curve25519 {
        try p.clearCofactor().rejectIdentity();
        const one = crypto.ecc.Edwards25519.Fe.one;
        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 };
    }
}