structstd.crypto.25519.scalar.Scalar[src]

A scalar in unpacked representation

Fields

limbs: Limbs = undefined

Functions

FunctionfromBytes[src]

pub fn fromBytes(bytes: CompressedScalar) Scalar

Unpack a 32-byte representation of a scalar

Parameters

Source Code

Source code
pub fn fromBytes(bytes: CompressedScalar) Scalar {
    var scalar = ScalarDouble.fromBytes32(bytes);
    return scalar.reduce(5);
}

FunctionfromBytes64[src]

pub fn fromBytes64(bytes: [64]u8) Scalar

Unpack a 64-byte representation of a scalar

Parameters

bytes: [64]u8

Source Code

Source code
pub fn fromBytes64(bytes: [64]u8) Scalar {
    var scalar = ScalarDouble.fromBytes64(bytes);
    return scalar.reduce(5);
}

FunctiontoBytes[src]

pub fn toBytes(expanded: *const Scalar) CompressedScalar

Pack a scalar into bytes

Parameters

expanded: *const Scalar

Source Code

Source code
pub fn toBytes(expanded: *const Scalar) CompressedScalar {
    var bytes: CompressedScalar = undefined;
    var i: usize = 0;
    while (i < 4) : (i += 1) {
        mem.writeInt(u64, bytes[i * 7 ..][0..8], expanded.limbs[i], .little);
    }
    mem.writeInt(u32, bytes[i * 7 ..][0..4], @intCast(expanded.limbs[i]), .little);
    return bytes;
}

FunctionisZero[src]

pub fn isZero(n: Scalar) bool

Return true if the scalar is zero

Parameters

Source Code

Source code
pub fn isZero(n: Scalar) bool {
    const limbs = n.limbs;
    return (limbs[0] | limbs[1] | limbs[2] | limbs[3] | limbs[4]) == 0;
}

Functionadd[src]

pub fn add(x: Scalar, y: Scalar) Scalar

Return x+y (mod L)

Parameters

Source Code

Source code
pub fn add(x: Scalar, y: Scalar) Scalar {
    const carry0 = (x.limbs[0] + y.limbs[0]) >> 56;
    const t0 = (x.limbs[0] + y.limbs[0]) & 0xffffffffffffff;
    const t00 = t0;
    const c0 = carry0;
    const carry1 = (x.limbs[1] + y.limbs[1] + c0) >> 56;
    const t1 = (x.limbs[1] + y.limbs[1] + c0) & 0xffffffffffffff;
    const t10 = t1;
    const c1 = carry1;
    const carry2 = (x.limbs[2] + y.limbs[2] + c1) >> 56;
    const t2 = (x.limbs[2] + y.limbs[2] + c1) & 0xffffffffffffff;
    const t20 = t2;
    const c2 = carry2;
    const carry = (x.limbs[3] + y.limbs[3] + c2) >> 56;
    const t3 = (x.limbs[3] + y.limbs[3] + c2) & 0xffffffffffffff;
    const t30 = t3;
    const c3 = carry;
    const t4 = x.limbs[4] + y.limbs[4] + c3;

    const y01: u64 = 5175514460705773;
    const y11: u64 = 70332060721272408;
    const y21: u64 = 5342;
    const y31: u64 = 0;
    const y41: u64 = 268435456;

    const b5 = (t00 -% y01) >> 63;
    const t5 = ((b5 << 56) + t00) -% y01;
    const b0 = b5;
    const t01 = t5;
    const b6 = (t10 -% (y11 + b0)) >> 63;
    const t6 = ((b6 << 56) + t10) -% (y11 + b0);
    const b1 = b6;
    const t11 = t6;
    const b7 = (t20 -% (y21 + b1)) >> 63;
    const t7 = ((b7 << 56) + t20) -% (y21 + b1);
    const b2 = b7;
    const t21 = t7;
    const b8 = (t30 -% (y31 + b2)) >> 63;
    const t8 = ((b8 << 56) + t30) -% (y31 + b2);
    const b3 = b8;
    const t31 = t8;
    const b = (t4 -% (y41 + b3)) >> 63;
    const t = ((b << 56) + t4) -% (y41 + b3);
    const b4 = b;
    const t41 = t;

    const mask = (b4 -% 1);
    const z00 = t00 ^ (mask & (t00 ^ t01));
    const z10 = t10 ^ (mask & (t10 ^ t11));
    const z20 = t20 ^ (mask & (t20 ^ t21));
    const z30 = t30 ^ (mask & (t30 ^ t31));
    const z40 = t4 ^ (mask & (t4 ^ t41));

    return Scalar{ .limbs = .{ z00, z10, z20, z30, z40 } };
}

Functionmul[src]

pub fn mul(x: Scalar, y: Scalar) Scalar

Return x*r (mod L)

Parameters

Source Code

Source code
pub fn mul(x: Scalar, y: Scalar) Scalar {
    const xy000 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[0]);
    const xy010 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[1]);
    const xy020 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[2]);
    const xy030 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[3]);
    const xy040 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[4]);
    const xy100 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[0]);
    const xy110 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[1]);
    const xy120 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[2]);
    const xy130 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[3]);
    const xy140 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[4]);
    const xy200 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[0]);
    const xy210 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[1]);
    const xy220 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[2]);
    const xy230 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[3]);
    const xy240 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[4]);
    const xy300 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[0]);
    const xy310 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[1]);
    const xy320 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[2]);
    const xy330 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[3]);
    const xy340 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[4]);
    const xy400 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[0]);
    const xy410 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[1]);
    const xy420 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[2]);
    const xy430 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[3]);
    const xy440 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[4]);
    const z00 = xy000;
    const z10 = xy010 + xy100;
    const z20 = xy020 + xy110 + xy200;
    const z30 = xy030 + xy120 + xy210 + xy300;
    const z40 = xy040 + xy130 + xy220 + xy310 + xy400;
    const z50 = xy140 + xy230 + xy320 + xy410;
    const z60 = xy240 + xy330 + xy420;
    const z70 = xy340 + xy430;
    const z80 = xy440;

    const carry0 = z00 >> 56;
    const t10 = @as(u64, @truncate(z00)) & 0xffffffffffffff;
    const c00 = carry0;
    const t00 = t10;
    const carry1 = (z10 + c00) >> 56;
    const t11 = @as(u64, @truncate((z10 + c00))) & 0xffffffffffffff;
    const c10 = carry1;
    const t12 = t11;
    const carry2 = (z20 + c10) >> 56;
    const t13 = @as(u64, @truncate((z20 + c10))) & 0xffffffffffffff;
    const c20 = carry2;
    const t20 = t13;
    const carry3 = (z30 + c20) >> 56;
    const t14 = @as(u64, @truncate((z30 + c20))) & 0xffffffffffffff;
    const c30 = carry3;
    const t30 = t14;
    const carry4 = (z40 + c30) >> 56;
    const t15 = @as(u64, @truncate((z40 + c30))) & 0xffffffffffffff;
    const c40 = carry4;
    const t40 = t15;
    const carry5 = (z50 + c40) >> 56;
    const t16 = @as(u64, @truncate((z50 + c40))) & 0xffffffffffffff;
    const c50 = carry5;
    const t50 = t16;
    const carry6 = (z60 + c50) >> 56;
    const t17 = @as(u64, @truncate((z60 + c50))) & 0xffffffffffffff;
    const c60 = carry6;
    const t60 = t17;
    const carry7 = (z70 + c60) >> 56;
    const t18 = @as(u64, @truncate((z70 + c60))) & 0xffffffffffffff;
    const c70 = carry7;
    const t70 = t18;
    const carry8 = (z80 + c70) >> 56;
    const t19 = @as(u64, @truncate((z80 + c70))) & 0xffffffffffffff;
    const c80 = carry8;
    const t80 = t19;
    const t90 = (@as(u64, @truncate(c80)));
    const r0 = t00;
    const r1 = t12;
    const r2 = t20;
    const r3 = t30;
    const r4 = t40;
    const r5 = t50;
    const r6 = t60;
    const r7 = t70;
    const r8 = t80;
    const r9 = t90;

    const m0: u64 = 5175514460705773;
    const m1: u64 = 70332060721272408;
    const m2: u64 = 5342;
    const m3: u64 = 0;
    const m4: u64 = 268435456;
    const mu0: u64 = 44162584779952923;
    const mu1: u64 = 9390964836247533;
    const mu2: u64 = 72057594036560134;
    const mu3: u64 = 72057594037927935;
    const mu4: u64 = 68719476735;

    const y_ = (r5 & 0xffffff) << 32;
    const x_ = r4 >> 24;
    const z01 = (x_ | y_);
    const y_0 = (r6 & 0xffffff) << 32;
    const x_0 = r5 >> 24;
    const z11 = (x_0 | y_0);
    const y_1 = (r7 & 0xffffff) << 32;
    const x_1 = r6 >> 24;
    const z21 = (x_1 | y_1);
    const y_2 = (r8 & 0xffffff) << 32;
    const x_2 = r7 >> 24;
    const z31 = (x_2 | y_2);
    const y_3 = (r9 & 0xffffff) << 32;
    const x_3 = r8 >> 24;
    const z41 = (x_3 | y_3);
    const q0 = z01;
    const q1 = z11;
    const q2 = z21;
    const q3 = z31;
    const q4 = z41;
    const xy001 = @as(u128, q0) * @as(u128, mu0);
    const xy011 = @as(u128, q0) * @as(u128, mu1);
    const xy021 = @as(u128, q0) * @as(u128, mu2);
    const xy031 = @as(u128, q0) * @as(u128, mu3);
    const xy041 = @as(u128, q0) * @as(u128, mu4);
    const xy101 = @as(u128, q1) * @as(u128, mu0);
    const xy111 = @as(u128, q1) * @as(u128, mu1);
    const xy121 = @as(u128, q1) * @as(u128, mu2);
    const xy131 = @as(u128, q1) * @as(u128, mu3);
    const xy14 = @as(u128, q1) * @as(u128, mu4);
    const xy201 = @as(u128, q2) * @as(u128, mu0);
    const xy211 = @as(u128, q2) * @as(u128, mu1);
    const xy221 = @as(u128, q2) * @as(u128, mu2);
    const xy23 = @as(u128, q2) * @as(u128, mu3);
    const xy24 = @as(u128, q2) * @as(u128, mu4);
    const xy301 = @as(u128, q3) * @as(u128, mu0);
    const xy311 = @as(u128, q3) * @as(u128, mu1);
    const xy32 = @as(u128, q3) * @as(u128, mu2);
    const xy33 = @as(u128, q3) * @as(u128, mu3);
    const xy34 = @as(u128, q3) * @as(u128, mu4);
    const xy401 = @as(u128, q4) * @as(u128, mu0);
    const xy41 = @as(u128, q4) * @as(u128, mu1);
    const xy42 = @as(u128, q4) * @as(u128, mu2);
    const xy43 = @as(u128, q4) * @as(u128, mu3);
    const xy44 = @as(u128, q4) * @as(u128, mu4);
    const z02 = xy001;
    const z12 = xy011 + xy101;
    const z22 = xy021 + xy111 + xy201;
    const z32 = xy031 + xy121 + xy211 + xy301;
    const z42 = xy041 + xy131 + xy221 + xy311 + xy401;
    const z5 = xy14 + xy23 + xy32 + xy41;
    const z6 = xy24 + xy33 + xy42;
    const z7 = xy34 + xy43;
    const z8 = xy44;

    const carry9 = z02 >> 56;
    const c01 = carry9;
    const carry10 = (z12 + c01) >> 56;
    const c11 = carry10;
    const carry11 = (z22 + c11) >> 56;
    const c21 = carry11;
    const carry12 = (z32 + c21) >> 56;
    const c31 = carry12;
    const carry13 = (z42 + c31) >> 56;
    const t24 = @as(u64, @truncate(z42 + c31)) & 0xffffffffffffff;
    const c41 = carry13;
    const t41 = t24;
    const carry14 = (z5 + c41) >> 56;
    const t25 = @as(u64, @truncate(z5 + c41)) & 0xffffffffffffff;
    const c5 = carry14;
    const t5 = t25;
    const carry15 = (z6 + c5) >> 56;
    const t26 = @as(u64, @truncate(z6 + c5)) & 0xffffffffffffff;
    const c6 = carry15;
    const t6 = t26;
    const carry16 = (z7 + c6) >> 56;
    const t27 = @as(u64, @truncate(z7 + c6)) & 0xffffffffffffff;
    const c7 = carry16;
    const t7 = t27;
    const carry17 = (z8 + c7) >> 56;
    const t28 = @as(u64, @truncate(z8 + c7)) & 0xffffffffffffff;
    const c8 = carry17;
    const t8 = t28;
    const t9 = @as(u64, @truncate(c8));

    const qmu4_ = t41;
    const qmu5_ = t5;
    const qmu6_ = t6;
    const qmu7_ = t7;
    const qmu8_ = t8;
    const qmu9_ = t9;
    const y_4 = (qmu5_ & 0xffffffffff) << 16;
    const x_4 = qmu4_ >> 40;
    const z03 = (x_4 | y_4);
    const y_5 = (qmu6_ & 0xffffffffff) << 16;
    const x_5 = qmu5_ >> 40;
    const z13 = (x_5 | y_5);
    const y_6 = (qmu7_ & 0xffffffffff) << 16;
    const x_6 = qmu6_ >> 40;
    const z23 = (x_6 | y_6);
    const y_7 = (qmu8_ & 0xffffffffff) << 16;
    const x_7 = qmu7_ >> 40;
    const z33 = (x_7 | y_7);
    const y_8 = (qmu9_ & 0xffffffffff) << 16;
    const x_8 = qmu8_ >> 40;
    const z43 = (x_8 | y_8);
    const qdiv0 = z03;
    const qdiv1 = z13;
    const qdiv2 = z23;
    const qdiv3 = z33;
    const qdiv4 = z43;
    const r01 = r0;
    const r11 = r1;
    const r21 = r2;
    const r31 = r3;
    const r41 = (r4 & 0xffffffffff);

    const xy00 = @as(u128, qdiv0) * @as(u128, m0);
    const xy01 = @as(u128, qdiv0) * @as(u128, m1);
    const xy02 = @as(u128, qdiv0) * @as(u128, m2);
    const xy03 = @as(u128, qdiv0) * @as(u128, m3);
    const xy04 = @as(u128, qdiv0) * @as(u128, m4);
    const xy10 = @as(u128, qdiv1) * @as(u128, m0);
    const xy11 = @as(u128, qdiv1) * @as(u128, m1);
    const xy12 = @as(u128, qdiv1) * @as(u128, m2);
    const xy13 = @as(u128, qdiv1) * @as(u128, m3);
    const xy20 = @as(u128, qdiv2) * @as(u128, m0);
    const xy21 = @as(u128, qdiv2) * @as(u128, m1);
    const xy22 = @as(u128, qdiv2) * @as(u128, m2);
    const xy30 = @as(u128, qdiv3) * @as(u128, m0);
    const xy31 = @as(u128, qdiv3) * @as(u128, m1);
    const xy40 = @as(u128, qdiv4) * @as(u128, m0);
    const carry18 = xy00 >> 56;
    const t29 = @as(u64, @truncate(xy00)) & 0xffffffffffffff;
    const c0 = carry18;
    const t01 = t29;
    const carry19 = (xy01 + xy10 + c0) >> 56;
    const t31 = @as(u64, @truncate(xy01 + xy10 + c0)) & 0xffffffffffffff;
    const c12 = carry19;
    const t110 = t31;
    const carry20 = (xy02 + xy11 + xy20 + c12) >> 56;
    const t32 = @as(u64, @truncate(xy02 + xy11 + xy20 + c12)) & 0xffffffffffffff;
    const c22 = carry20;
    const t210 = t32;
    const carry = (xy03 + xy12 + xy21 + xy30 + c22) >> 56;
    const t33 = @as(u64, @truncate(xy03 + xy12 + xy21 + xy30 + c22)) & 0xffffffffffffff;
    const c32 = carry;
    const t34 = t33;
    const t42 = @as(u64, @truncate(xy04 + xy13 + xy22 + xy31 + xy40 + c32)) & 0xffffffffff;

    const qmul0 = t01;
    const qmul1 = t110;
    const qmul2 = t210;
    const qmul3 = t34;
    const qmul4 = t42;
    const b5 = (r01 -% qmul0) >> 63;
    const t35 = ((b5 << 56) + r01) -% qmul0;
    const c1 = b5;
    const t02 = t35;
    const b6 = (r11 -% (qmul1 + c1)) >> 63;
    const t36 = ((b6 << 56) + r11) -% (qmul1 + c1);
    const c2 = b6;
    const t111 = t36;
    const b7 = (r21 -% (qmul2 + c2)) >> 63;
    const t37 = ((b7 << 56) + r21) -% (qmul2 + c2);
    const c3 = b7;
    const t211 = t37;
    const b8 = (r31 -% (qmul3 + c3)) >> 63;
    const t38 = ((b8 << 56) + r31) -% (qmul3 + c3);
    const c4 = b8;
    const t39 = t38;
    const b9 = (r41 -% (qmul4 + c4)) >> 63;
    const t43 = ((b9 << 40) + r41) -% (qmul4 + c4);
    const t44 = t43;
    const s0 = t02;
    const s1 = t111;
    const s2 = t211;
    const s3 = t39;
    const s4 = t44;

    const y01: u64 = 5175514460705773;
    const y11: u64 = 70332060721272408;
    const y21: u64 = 5342;
    const y31: u64 = 0;
    const y41: u64 = 268435456;

    const b10 = (s0 -% y01) >> 63;
    const t45 = ((b10 << 56) + s0) -% y01;
    const b0 = b10;
    const t0 = t45;
    const b11 = (s1 -% (y11 + b0)) >> 63;
    const t46 = ((b11 << 56) + s1) -% (y11 + b0);
    const b1 = b11;
    const t1 = t46;
    const b12 = (s2 -% (y21 + b1)) >> 63;
    const t47 = ((b12 << 56) + s2) -% (y21 + b1);
    const b2 = b12;
    const t2 = t47;
    const b13 = (s3 -% (y31 + b2)) >> 63;
    const t48 = ((b13 << 56) + s3) -% (y31 + b2);
    const b3 = b13;
    const t3 = t48;
    const b = (s4 -% (y41 + b3)) >> 63;
    const t = ((b << 56) + s4) -% (y41 + b3);
    const b4 = b;
    const t4 = t;
    const mask = (b4 -% @as(u64, @intCast(((1)))));
    const z04 = s0 ^ (mask & (s0 ^ t0));
    const z14 = s1 ^ (mask & (s1 ^ t1));
    const z24 = s2 ^ (mask & (s2 ^ t2));
    const z34 = s3 ^ (mask & (s3 ^ t3));
    const z44 = s4 ^ (mask & (s4 ^ t4));

    return Scalar{ .limbs = .{ z04, z14, z24, z34, z44 } };
}

Functionsq[src]

pub fn sq(x: Scalar) Scalar

Return x^2 (mod L)

Parameters

Source Code

Source code
pub fn sq(x: Scalar) Scalar {
    return x.mul(x);
}

Functioninvert[src]

pub fn invert(x: Scalar) Scalar

Return the inverse of a scalar (mod L), or 0 if x=0.

Parameters

Source Code

Source code
pub fn invert(x: Scalar) Scalar {
    const _10 = x.sq();
    const _11 = x.mul(_10);
    const _100 = x.mul(_11);
    const _1000 = _100.sq();
    const _1010 = _10.mul(_1000);
    const _1011 = x.mul(_1010);
    const _10000 = _1000.sq();
    const _10110 = _1011.sq();
    const _100000 = _1010.mul(_10110);
    const _100110 = _10000.mul(_10110);
    const _1000000 = _100000.sq();
    const _1010000 = _10000.mul(_1000000);
    const _1010011 = _11.mul(_1010000);
    const _1100011 = _10000.mul(_1010011);
    const _1100111 = _100.mul(_1100011);
    const _1101011 = _100.mul(_1100111);
    const _10010011 = _1000000.mul(_1010011);
    const _10010111 = _100.mul(_10010011);
    const _10111101 = _100110.mul(_10010111);
    const _11010011 = _10110.mul(_10111101);
    const _11100111 = _1010000.mul(_10010111);
    const _11101011 = _100.mul(_11100111);
    const _11110101 = _1010.mul(_11101011);
    return _1011.mul(_11110101).sqn_mul(126, _1010011).sqn_mul(9, _10).mul(_11110101)
        .sqn_mul(7, _1100111).sqn_mul(9, _11110101).sqn_mul(11, _10111101).sqn_mul(8, _11100111)
        .sqn_mul(9, _1101011).sqn_mul(6, _1011).sqn_mul(14, _10010011).sqn_mul(10, _1100011)
        .sqn_mul(9, _10010111).sqn_mul(10, _11110101).sqn_mul(8, _11010011).sqn_mul(8, _11101011);
}

Functionrandom[src]

pub fn random() Scalar

Return a random scalar < L.

Source Code

Source code
pub fn random() Scalar {
    var s: [64]u8 = undefined;
    while (true) {
        crypto.random.bytes(&s);
        const n = Scalar.fromBytes64(s);
        if (!n.isZero()) {
            return n;
        }
    }
}

Source Code

Source code
pub const Scalar = struct {
    const Limbs = [5]u64;
    limbs: Limbs = undefined,

    /// Unpack a 32-byte representation of a scalar
    pub fn fromBytes(bytes: CompressedScalar) Scalar {
        var scalar = ScalarDouble.fromBytes32(bytes);
        return scalar.reduce(5);
    }

    /// Unpack a 64-byte representation of a scalar
    pub fn fromBytes64(bytes: [64]u8) Scalar {
        var scalar = ScalarDouble.fromBytes64(bytes);
        return scalar.reduce(5);
    }

    /// Pack a scalar into bytes
    pub fn toBytes(expanded: *const Scalar) CompressedScalar {
        var bytes: CompressedScalar = undefined;
        var i: usize = 0;
        while (i < 4) : (i += 1) {
            mem.writeInt(u64, bytes[i * 7 ..][0..8], expanded.limbs[i], .little);
        }
        mem.writeInt(u32, bytes[i * 7 ..][0..4], @intCast(expanded.limbs[i]), .little);
        return bytes;
    }

    /// Return true if the scalar is zero
    pub fn isZero(n: Scalar) bool {
        const limbs = n.limbs;
        return (limbs[0] | limbs[1] | limbs[2] | limbs[3] | limbs[4]) == 0;
    }

    /// Return x+y (mod L)
    pub fn add(x: Scalar, y: Scalar) Scalar {
        const carry0 = (x.limbs[0] + y.limbs[0]) >> 56;
        const t0 = (x.limbs[0] + y.limbs[0]) & 0xffffffffffffff;
        const t00 = t0;
        const c0 = carry0;
        const carry1 = (x.limbs[1] + y.limbs[1] + c0) >> 56;
        const t1 = (x.limbs[1] + y.limbs[1] + c0) & 0xffffffffffffff;
        const t10 = t1;
        const c1 = carry1;
        const carry2 = (x.limbs[2] + y.limbs[2] + c1) >> 56;
        const t2 = (x.limbs[2] + y.limbs[2] + c1) & 0xffffffffffffff;
        const t20 = t2;
        const c2 = carry2;
        const carry = (x.limbs[3] + y.limbs[3] + c2) >> 56;
        const t3 = (x.limbs[3] + y.limbs[3] + c2) & 0xffffffffffffff;
        const t30 = t3;
        const c3 = carry;
        const t4 = x.limbs[4] + y.limbs[4] + c3;

        const y01: u64 = 5175514460705773;
        const y11: u64 = 70332060721272408;
        const y21: u64 = 5342;
        const y31: u64 = 0;
        const y41: u64 = 268435456;

        const b5 = (t00 -% y01) >> 63;
        const t5 = ((b5 << 56) + t00) -% y01;
        const b0 = b5;
        const t01 = t5;
        const b6 = (t10 -% (y11 + b0)) >> 63;
        const t6 = ((b6 << 56) + t10) -% (y11 + b0);
        const b1 = b6;
        const t11 = t6;
        const b7 = (t20 -% (y21 + b1)) >> 63;
        const t7 = ((b7 << 56) + t20) -% (y21 + b1);
        const b2 = b7;
        const t21 = t7;
        const b8 = (t30 -% (y31 + b2)) >> 63;
        const t8 = ((b8 << 56) + t30) -% (y31 + b2);
        const b3 = b8;
        const t31 = t8;
        const b = (t4 -% (y41 + b3)) >> 63;
        const t = ((b << 56) + t4) -% (y41 + b3);
        const b4 = b;
        const t41 = t;

        const mask = (b4 -% 1);
        const z00 = t00 ^ (mask & (t00 ^ t01));
        const z10 = t10 ^ (mask & (t10 ^ t11));
        const z20 = t20 ^ (mask & (t20 ^ t21));
        const z30 = t30 ^ (mask & (t30 ^ t31));
        const z40 = t4 ^ (mask & (t4 ^ t41));

        return Scalar{ .limbs = .{ z00, z10, z20, z30, z40 } };
    }

    /// Return x*r (mod L)
    pub fn mul(x: Scalar, y: Scalar) Scalar {
        const xy000 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[0]);
        const xy010 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[1]);
        const xy020 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[2]);
        const xy030 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[3]);
        const xy040 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[4]);
        const xy100 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[0]);
        const xy110 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[1]);
        const xy120 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[2]);
        const xy130 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[3]);
        const xy140 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[4]);
        const xy200 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[0]);
        const xy210 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[1]);
        const xy220 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[2]);
        const xy230 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[3]);
        const xy240 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[4]);
        const xy300 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[0]);
        const xy310 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[1]);
        const xy320 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[2]);
        const xy330 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[3]);
        const xy340 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[4]);
        const xy400 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[0]);
        const xy410 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[1]);
        const xy420 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[2]);
        const xy430 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[3]);
        const xy440 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[4]);
        const z00 = xy000;
        const z10 = xy010 + xy100;
        const z20 = xy020 + xy110 + xy200;
        const z30 = xy030 + xy120 + xy210 + xy300;
        const z40 = xy040 + xy130 + xy220 + xy310 + xy400;
        const z50 = xy140 + xy230 + xy320 + xy410;
        const z60 = xy240 + xy330 + xy420;
        const z70 = xy340 + xy430;
        const z80 = xy440;

        const carry0 = z00 >> 56;
        const t10 = @as(u64, @truncate(z00)) & 0xffffffffffffff;
        const c00 = carry0;
        const t00 = t10;
        const carry1 = (z10 + c00) >> 56;
        const t11 = @as(u64, @truncate((z10 + c00))) & 0xffffffffffffff;
        const c10 = carry1;
        const t12 = t11;
        const carry2 = (z20 + c10) >> 56;
        const t13 = @as(u64, @truncate((z20 + c10))) & 0xffffffffffffff;
        const c20 = carry2;
        const t20 = t13;
        const carry3 = (z30 + c20) >> 56;
        const t14 = @as(u64, @truncate((z30 + c20))) & 0xffffffffffffff;
        const c30 = carry3;
        const t30 = t14;
        const carry4 = (z40 + c30) >> 56;
        const t15 = @as(u64, @truncate((z40 + c30))) & 0xffffffffffffff;
        const c40 = carry4;
        const t40 = t15;
        const carry5 = (z50 + c40) >> 56;
        const t16 = @as(u64, @truncate((z50 + c40))) & 0xffffffffffffff;
        const c50 = carry5;
        const t50 = t16;
        const carry6 = (z60 + c50) >> 56;
        const t17 = @as(u64, @truncate((z60 + c50))) & 0xffffffffffffff;
        const c60 = carry6;
        const t60 = t17;
        const carry7 = (z70 + c60) >> 56;
        const t18 = @as(u64, @truncate((z70 + c60))) & 0xffffffffffffff;
        const c70 = carry7;
        const t70 = t18;
        const carry8 = (z80 + c70) >> 56;
        const t19 = @as(u64, @truncate((z80 + c70))) & 0xffffffffffffff;
        const c80 = carry8;
        const t80 = t19;
        const t90 = (@as(u64, @truncate(c80)));
        const r0 = t00;
        const r1 = t12;
        const r2 = t20;
        const r3 = t30;
        const r4 = t40;
        const r5 = t50;
        const r6 = t60;
        const r7 = t70;
        const r8 = t80;
        const r9 = t90;

        const m0: u64 = 5175514460705773;
        const m1: u64 = 70332060721272408;
        const m2: u64 = 5342;
        const m3: u64 = 0;
        const m4: u64 = 268435456;
        const mu0: u64 = 44162584779952923;
        const mu1: u64 = 9390964836247533;
        const mu2: u64 = 72057594036560134;
        const mu3: u64 = 72057594037927935;
        const mu4: u64 = 68719476735;

        const y_ = (r5 & 0xffffff) << 32;
        const x_ = r4 >> 24;
        const z01 = (x_ | y_);
        const y_0 = (r6 & 0xffffff) << 32;
        const x_0 = r5 >> 24;
        const z11 = (x_0 | y_0);
        const y_1 = (r7 & 0xffffff) << 32;
        const x_1 = r6 >> 24;
        const z21 = (x_1 | y_1);
        const y_2 = (r8 & 0xffffff) << 32;
        const x_2 = r7 >> 24;
        const z31 = (x_2 | y_2);
        const y_3 = (r9 & 0xffffff) << 32;
        const x_3 = r8 >> 24;
        const z41 = (x_3 | y_3);
        const q0 = z01;
        const q1 = z11;
        const q2 = z21;
        const q3 = z31;
        const q4 = z41;
        const xy001 = @as(u128, q0) * @as(u128, mu0);
        const xy011 = @as(u128, q0) * @as(u128, mu1);
        const xy021 = @as(u128, q0) * @as(u128, mu2);
        const xy031 = @as(u128, q0) * @as(u128, mu3);
        const xy041 = @as(u128, q0) * @as(u128, mu4);
        const xy101 = @as(u128, q1) * @as(u128, mu0);
        const xy111 = @as(u128, q1) * @as(u128, mu1);
        const xy121 = @as(u128, q1) * @as(u128, mu2);
        const xy131 = @as(u128, q1) * @as(u128, mu3);
        const xy14 = @as(u128, q1) * @as(u128, mu4);
        const xy201 = @as(u128, q2) * @as(u128, mu0);
        const xy211 = @as(u128, q2) * @as(u128, mu1);
        const xy221 = @as(u128, q2) * @as(u128, mu2);
        const xy23 = @as(u128, q2) * @as(u128, mu3);
        const xy24 = @as(u128, q2) * @as(u128, mu4);
        const xy301 = @as(u128, q3) * @as(u128, mu0);
        const xy311 = @as(u128, q3) * @as(u128, mu1);
        const xy32 = @as(u128, q3) * @as(u128, mu2);
        const xy33 = @as(u128, q3) * @as(u128, mu3);
        const xy34 = @as(u128, q3) * @as(u128, mu4);
        const xy401 = @as(u128, q4) * @as(u128, mu0);
        const xy41 = @as(u128, q4) * @as(u128, mu1);
        const xy42 = @as(u128, q4) * @as(u128, mu2);
        const xy43 = @as(u128, q4) * @as(u128, mu3);
        const xy44 = @as(u128, q4) * @as(u128, mu4);
        const z02 = xy001;
        const z12 = xy011 + xy101;
        const z22 = xy021 + xy111 + xy201;
        const z32 = xy031 + xy121 + xy211 + xy301;
        const z42 = xy041 + xy131 + xy221 + xy311 + xy401;
        const z5 = xy14 + xy23 + xy32 + xy41;
        const z6 = xy24 + xy33 + xy42;
        const z7 = xy34 + xy43;
        const z8 = xy44;

        const carry9 = z02 >> 56;
        const c01 = carry9;
        const carry10 = (z12 + c01) >> 56;
        const c11 = carry10;
        const carry11 = (z22 + c11) >> 56;
        const c21 = carry11;
        const carry12 = (z32 + c21) >> 56;
        const c31 = carry12;
        const carry13 = (z42 + c31) >> 56;
        const t24 = @as(u64, @truncate(z42 + c31)) & 0xffffffffffffff;
        const c41 = carry13;
        const t41 = t24;
        const carry14 = (z5 + c41) >> 56;
        const t25 = @as(u64, @truncate(z5 + c41)) & 0xffffffffffffff;
        const c5 = carry14;
        const t5 = t25;
        const carry15 = (z6 + c5) >> 56;
        const t26 = @as(u64, @truncate(z6 + c5)) & 0xffffffffffffff;
        const c6 = carry15;
        const t6 = t26;
        const carry16 = (z7 + c6) >> 56;
        const t27 = @as(u64, @truncate(z7 + c6)) & 0xffffffffffffff;
        const c7 = carry16;
        const t7 = t27;
        const carry17 = (z8 + c7) >> 56;
        const t28 = @as(u64, @truncate(z8 + c7)) & 0xffffffffffffff;
        const c8 = carry17;
        const t8 = t28;
        const t9 = @as(u64, @truncate(c8));

        const qmu4_ = t41;
        const qmu5_ = t5;
        const qmu6_ = t6;
        const qmu7_ = t7;
        const qmu8_ = t8;
        const qmu9_ = t9;
        const y_4 = (qmu5_ & 0xffffffffff) << 16;
        const x_4 = qmu4_ >> 40;
        const z03 = (x_4 | y_4);
        const y_5 = (qmu6_ & 0xffffffffff) << 16;
        const x_5 = qmu5_ >> 40;
        const z13 = (x_5 | y_5);
        const y_6 = (qmu7_ & 0xffffffffff) << 16;
        const x_6 = qmu6_ >> 40;
        const z23 = (x_6 | y_6);
        const y_7 = (qmu8_ & 0xffffffffff) << 16;
        const x_7 = qmu7_ >> 40;
        const z33 = (x_7 | y_7);
        const y_8 = (qmu9_ & 0xffffffffff) << 16;
        const x_8 = qmu8_ >> 40;
        const z43 = (x_8 | y_8);
        const qdiv0 = z03;
        const qdiv1 = z13;
        const qdiv2 = z23;
        const qdiv3 = z33;
        const qdiv4 = z43;
        const r01 = r0;
        const r11 = r1;
        const r21 = r2;
        const r31 = r3;
        const r41 = (r4 & 0xffffffffff);

        const xy00 = @as(u128, qdiv0) * @as(u128, m0);
        const xy01 = @as(u128, qdiv0) * @as(u128, m1);
        const xy02 = @as(u128, qdiv0) * @as(u128, m2);
        const xy03 = @as(u128, qdiv0) * @as(u128, m3);
        const xy04 = @as(u128, qdiv0) * @as(u128, m4);
        const xy10 = @as(u128, qdiv1) * @as(u128, m0);
        const xy11 = @as(u128, qdiv1) * @as(u128, m1);
        const xy12 = @as(u128, qdiv1) * @as(u128, m2);
        const xy13 = @as(u128, qdiv1) * @as(u128, m3);
        const xy20 = @as(u128, qdiv2) * @as(u128, m0);
        const xy21 = @as(u128, qdiv2) * @as(u128, m1);
        const xy22 = @as(u128, qdiv2) * @as(u128, m2);
        const xy30 = @as(u128, qdiv3) * @as(u128, m0);
        const xy31 = @as(u128, qdiv3) * @as(u128, m1);
        const xy40 = @as(u128, qdiv4) * @as(u128, m0);
        const carry18 = xy00 >> 56;
        const t29 = @as(u64, @truncate(xy00)) & 0xffffffffffffff;
        const c0 = carry18;
        const t01 = t29;
        const carry19 = (xy01 + xy10 + c0) >> 56;
        const t31 = @as(u64, @truncate(xy01 + xy10 + c0)) & 0xffffffffffffff;
        const c12 = carry19;
        const t110 = t31;
        const carry20 = (xy02 + xy11 + xy20 + c12) >> 56;
        const t32 = @as(u64, @truncate(xy02 + xy11 + xy20 + c12)) & 0xffffffffffffff;
        const c22 = carry20;
        const t210 = t32;
        const carry = (xy03 + xy12 + xy21 + xy30 + c22) >> 56;
        const t33 = @as(u64, @truncate(xy03 + xy12 + xy21 + xy30 + c22)) & 0xffffffffffffff;
        const c32 = carry;
        const t34 = t33;
        const t42 = @as(u64, @truncate(xy04 + xy13 + xy22 + xy31 + xy40 + c32)) & 0xffffffffff;

        const qmul0 = t01;
        const qmul1 = t110;
        const qmul2 = t210;
        const qmul3 = t34;
        const qmul4 = t42;
        const b5 = (r01 -% qmul0) >> 63;
        const t35 = ((b5 << 56) + r01) -% qmul0;
        const c1 = b5;
        const t02 = t35;
        const b6 = (r11 -% (qmul1 + c1)) >> 63;
        const t36 = ((b6 << 56) + r11) -% (qmul1 + c1);
        const c2 = b6;
        const t111 = t36;
        const b7 = (r21 -% (qmul2 + c2)) >> 63;
        const t37 = ((b7 << 56) + r21) -% (qmul2 + c2);
        const c3 = b7;
        const t211 = t37;
        const b8 = (r31 -% (qmul3 + c3)) >> 63;
        const t38 = ((b8 << 56) + r31) -% (qmul3 + c3);
        const c4 = b8;
        const t39 = t38;
        const b9 = (r41 -% (qmul4 + c4)) >> 63;
        const t43 = ((b9 << 40) + r41) -% (qmul4 + c4);
        const t44 = t43;
        const s0 = t02;
        const s1 = t111;
        const s2 = t211;
        const s3 = t39;
        const s4 = t44;

        const y01: u64 = 5175514460705773;
        const y11: u64 = 70332060721272408;
        const y21: u64 = 5342;
        const y31: u64 = 0;
        const y41: u64 = 268435456;

        const b10 = (s0 -% y01) >> 63;
        const t45 = ((b10 << 56) + s0) -% y01;
        const b0 = b10;
        const t0 = t45;
        const b11 = (s1 -% (y11 + b0)) >> 63;
        const t46 = ((b11 << 56) + s1) -% (y11 + b0);
        const b1 = b11;
        const t1 = t46;
        const b12 = (s2 -% (y21 + b1)) >> 63;
        const t47 = ((b12 << 56) + s2) -% (y21 + b1);
        const b2 = b12;
        const t2 = t47;
        const b13 = (s3 -% (y31 + b2)) >> 63;
        const t48 = ((b13 << 56) + s3) -% (y31 + b2);
        const b3 = b13;
        const t3 = t48;
        const b = (s4 -% (y41 + b3)) >> 63;
        const t = ((b << 56) + s4) -% (y41 + b3);
        const b4 = b;
        const t4 = t;
        const mask = (b4 -% @as(u64, @intCast(((1)))));
        const z04 = s0 ^ (mask & (s0 ^ t0));
        const z14 = s1 ^ (mask & (s1 ^ t1));
        const z24 = s2 ^ (mask & (s2 ^ t2));
        const z34 = s3 ^ (mask & (s3 ^ t3));
        const z44 = s4 ^ (mask & (s4 ^ t4));

        return Scalar{ .limbs = .{ z04, z14, z24, z34, z44 } };
    }

    /// Return x^2 (mod L)
    pub fn sq(x: Scalar) Scalar {
        return x.mul(x);
    }

    /// Square a scalar `n` times
    inline fn sqn(x: Scalar, comptime n: comptime_int) Scalar {
        var i: usize = 0;
        var t = x;
        while (i < n) : (i += 1) {
            t = t.sq();
        }
        return t;
    }

    /// Square and multiply
    fn sqn_mul(x: Scalar, comptime n: comptime_int, y: Scalar) Scalar {
        return x.sqn(n).mul(y);
    }

    /// Return the inverse of a scalar (mod L), or 0 if x=0.
    pub fn invert(x: Scalar) Scalar {
        const _10 = x.sq();
        const _11 = x.mul(_10);
        const _100 = x.mul(_11);
        const _1000 = _100.sq();
        const _1010 = _10.mul(_1000);
        const _1011 = x.mul(_1010);
        const _10000 = _1000.sq();
        const _10110 = _1011.sq();
        const _100000 = _1010.mul(_10110);
        const _100110 = _10000.mul(_10110);
        const _1000000 = _100000.sq();
        const _1010000 = _10000.mul(_1000000);
        const _1010011 = _11.mul(_1010000);
        const _1100011 = _10000.mul(_1010011);
        const _1100111 = _100.mul(_1100011);
        const _1101011 = _100.mul(_1100111);
        const _10010011 = _1000000.mul(_1010011);
        const _10010111 = _100.mul(_10010011);
        const _10111101 = _100110.mul(_10010111);
        const _11010011 = _10110.mul(_10111101);
        const _11100111 = _1010000.mul(_10010111);
        const _11101011 = _100.mul(_11100111);
        const _11110101 = _1010.mul(_11101011);
        return _1011.mul(_11110101).sqn_mul(126, _1010011).sqn_mul(9, _10).mul(_11110101)
            .sqn_mul(7, _1100111).sqn_mul(9, _11110101).sqn_mul(11, _10111101).sqn_mul(8, _11100111)
            .sqn_mul(9, _1101011).sqn_mul(6, _1011).sqn_mul(14, _10010011).sqn_mul(10, _1100011)
            .sqn_mul(9, _10010111).sqn_mul(10, _11110101).sqn_mul(8, _11010011).sqn_mul(8, _11101011);
    }

    /// Return a random scalar < L.
    pub fn random() Scalar {
        var s: [64]u8 = undefined;
        while (true) {
            crypto.random.bytes(&s);
            const n = Scalar.fromBytes64(s);
            if (!n.isZero()) {
                return n;
            }
        }
    }
}