x25519 function

Uint8List x25519(
  1. Uint8List scalar32,
  2. Uint8List uCoordinate32
)

Core X25519 function: computes X25519(k, u) per RFC 7748 sec. 5.

scalar32 is the 32-byte scalar (clamped internally); uCoordinate32 is the 32-byte little-endian u-coordinate. Returns 32 bytes little-endian.

Implementation

Uint8List x25519(Uint8List scalar32, Uint8List uCoordinate32) {
  if (scalar32.length != 32) {
    throw ArgumentError('scalar must be 32 bytes, got ${scalar32.length}');
  }
  if (uCoordinate32.length != 32) {
    throw ArgumentError(
      'u-coordinate must be 32 bytes, got ${uCoordinate32.length}',
    );
  }

  final BigInt k = _decodeScalar(scalar32);
  final BigInt u = _decodeUCoordinate(uCoordinate32);

  final BigInt x1 = u;
  BigInt x2 = BigInt.one;
  BigInt z2 = BigInt.zero;
  BigInt x3 = u;
  BigInt z3 = BigInt.one;
  int swap = 0;

  for (int t = _bits - 1; t >= 0; t--) {
    final int kT = ((k >> t) & BigInt.one).toInt();
    swap ^= kT;
    List<BigInt> s;
    s = _cswap(swap, x2, x3);
    x2 = s[0];
    x3 = s[1];
    s = _cswap(swap, z2, z3);
    z2 = s[0];
    z3 = s[1];
    swap = kT;

    final BigInt a = (x2 + z2) % _p;
    final BigInt aa = (a * a) % _p;
    final BigInt b = (x2 - z2) % _p;
    final BigInt bb = (b * b) % _p;
    final BigInt e = (aa - bb) % _p;
    final BigInt c = (x3 + z3) % _p;
    final BigInt d = (x3 - z3) % _p;
    final BigInt da = (d * a) % _p;
    final BigInt cb = (c * b) % _p;

    final BigInt x3New = (da + cb) % _p;
    x3 = (x3New * x3New) % _p;
    final BigInt z3Diff = (da - cb) % _p;
    z3 = (x1 * ((z3Diff * z3Diff) % _p)) % _p;

    x2 = (aa * bb) % _p;
    z2 = (e * ((aa + (_a24 * e) % _p) % _p)) % _p;
  }

  // Final conditional swap.
  List<BigInt> s;
  s = _cswap(swap, x2, x3);
  x2 = s[0];
  x3 = s[1];
  s = _cswap(swap, z2, z3);
  z2 = s[0];
  z3 = s[1];

  // Normalize results modulo p (subtraction above can yield negatives).
  final BigInt resultNum = (x2 % _p + _p) % _p;
  final BigInt resultDen = (z2 % _p + _p) % _p;
  final BigInt result = (resultNum * _inv(resultDen)) % _p;

  return _encodeUCoordinate(result);
}