Group operations over Curve25519.
x: FeThe Curve25519 base point.
pub const basePoint = Curve25519{ .x = Fe.curve25519BasePoint }pub inline fn fromBytes(s: [32]u8) Curve25519Decode a Curve25519 point from its compressed (X) coordinates.
s: [32]u8pub inline fn fromBytes(s: [32]u8) Curve25519 {
return .{ .x = Fe.fromBytes(s) };
}pub inline fn toBytes(p: Curve25519) [32]u8Encode a Curve25519 point.
p: Curve25519pub inline fn toBytes(p: Curve25519) [32]u8 {
return p.x.toBytes();
}pub fn rejectNonCanonical(s: [32]u8) NonCanonicalError!voidCheck that the encoding of a Curve25519 point is canonical.
s: [32]u8pub fn rejectNonCanonical(s: [32]u8) NonCanonicalError!void {
return Fe.rejectNonCanonical(s, false);
}pub fn rejectIdentity(p: Curve25519) IdentityElementError!voidReject the neutral element.
p: Curve25519pub fn rejectIdentity(p: Curve25519) IdentityElementError!void {
if (p.x.isZero()) {
return error.IdentityElement;
}
}pub fn clearCofactor(p: Curve25519) WeakPublicKeyError!Curve25519Multiply a point by the cofactor, returning WeakPublicKey if the element is in a small-order group.
p: Curve25519pub fn clearCofactor(p: Curve25519) WeakPublicKeyError!Curve25519 {
const cofactor = [_]u8{8} ++ [_]u8{0} ** 31;
return ladder(p, cofactor, 4) catch return error.WeakPublicKey;
}pub fn clampedMul(p: Curve25519, s: [32]u8) IdentityElementError!Curve25519Multiply 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.
p: Curve25519s: [32]u8pub fn clampedMul(p: Curve25519, s: [32]u8) IdentityElementError!Curve25519 {
var t: [32]u8 = s;
scalar.clamp(&t);
return try ladder(p, t, 255);
}pub fn mul(p: Curve25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Curve25519Multiply 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.
p: Curve25519s: [32]u8pub fn mul(p: Curve25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Curve25519 {
_ = try p.clearCofactor();
return try ladder(p, s, 256);
}pub fn fromEdwards25519(p: crypto.ecc.Edwards25519) IdentityElementError!Curve25519Compute 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 };
}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 inline fn fromBytes(s: [32]u8) Curve25519 {
return .{ .x = Fe.fromBytes(s) };
}
/// Encode a Curve25519 point.
pub inline 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} ++ [_]u8{0} ** 31;
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);
}
/// 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 };
}
}