gb method

  1. @visibleForTesting
void gb(
  1. Uint32List data,
  2. int a,
  3. int b,
  4. int c,
  5. int d,
)

RFC 9106 function GB(v0,..v3).

In the RFC, arguments are 64-bit integers. In our implementation, they are Uint32List indices.

Implementation

@visibleForTesting
void gb(Uint32List data, int a, int b, int c, int d) {
  // ---------------------------------
  // Browser-compatible implementation
  // ---------------------------------
  var v0Low = data[a];
  var v0High = data[a + 1];
  var v1Low = data[b];
  var v1High = data[b + 1];
  var v2Low = data[c];
  var v2High = data[c + 1];
  var v3Low = data[d];
  var v3High = data[d + 1];

  // a = (a + b + 2 * trunc(a) * trunc(b)) mod 2^(64)
  {
    var mLow =
        (0xFFFF & v0Low) * v1Low + (0xFFFF0000 & v0Low) * (0xFFFF & v1Low);
    var mHigh = mLow ~/ _bit32 + (v0Low >> 16) * (v1Low >> 16);
    mHigh = (_mask32 & (mHigh << 1)) + (0x1 & (mLow >> 31));
    mLow = _mask32 & (mLow << 1);
    v0Low = v0Low + v1Low + mLow;
    v0High = _mask32 & (v0High + v1High + v0Low ~/ _bit32 + mHigh);
    v0Low = _mask32 & v0Low;
  }

  // d = (d XOR a) rotr 32
  {
    final tmpLow = v3Low ^ v0Low;
    final tmpHigh = v3High ^ v0High;
    v3Low = tmpHigh;
    v3High = tmpLow;
  }

  // c = (c + d + 2 * trunc(c) * trunc(d)) mod 2^(64)
  {
    var mLow =
        (0xFFFF & v2Low) * v3Low + (0xFFFF0000 & v2Low) * (0xFFFF & v3Low);
    var mHigh = mLow ~/ _bit32 + (v2Low >> 16) * (v3Low >> 16);
    mHigh = (_mask32 & (mHigh << 1)) + (0x1 & (mLow >> 31));
    mLow = _mask32 & (mLow << 1);
    v2Low = v2Low + v3Low + mLow;
    v2High = _mask32 & (v2High + v3High + v2Low ~/ _bit32 + mHigh);
    v2Low = _mask32 & v2Low;
  }

  // b = (b XOR c) rotr 24
  {
    final tmpLow = v1Low ^ v2Low;
    final tmpHigh = v1High ^ v2High;
    v1Low = ((0xFFFFFF & tmpHigh) << 8) | (tmpLow >>> 24);
    v1High = ((0xFFFFFF & tmpLow) << 8) | (tmpHigh >>> 24);
  }

  // a = (a + b + 2 * trunc(a) * trunc(b)) mod 2^(64)
  {
    var mLow =
        (0xFFFF & v0Low) * v1Low + (0xFFFF0000 & v0Low) * (0xFFFF & v1Low);
    var mHigh = mLow ~/ _bit32 + (v0Low >> 16) * (v1Low >> 16);
    mHigh = (_mask32 & (mHigh << 1)) + (0x1 & (mLow >> 31));
    mLow = _mask32 & (mLow << 1);
    v0Low = v0Low + v1Low + mLow;
    v0High = _mask32 & (v0High + v1High + v0Low ~/ _bit32 + mHigh);
    v0Low = _mask32 & v0Low;
  }

  // d = (d XOR a) rotr 16
  {
    final tmpLow = v3Low ^ v0Low;
    final tmpHigh = v3High ^ v0High;
    v3Low = ((0xFFFF & tmpHigh) << 16) | (tmpLow >>> 16);
    v3High = ((0xFFFF & tmpLow) << 16) | (tmpHigh >>> 16);
  }

  // c = (c + d + 2 * trunc(c) * trunc(d)) mod 2^(64)
  {
    var mLow =
        (0xFFFF & v2Low) * v3Low + (0xFFFF0000 & v2Low) * (0xFFFF & v3Low);
    var mHigh = mLow ~/ _bit32 + (v2Low >> 16) * (v3Low >> 16);
    mHigh = (_mask32 & (mHigh << 1)) + (0x1 & (mLow >> 31));
    mLow = _mask32 & (mLow << 1);
    v2Low = v2Low + v3Low + mLow;
    v2High = _mask32 & (v2High + v3High + v2Low ~/ _bit32 + mHigh);
    v2Low = _mask32 & v2Low;
  }

  // b = (b XOR c) rotr 63
  {
    final tmpLow = v1Low ^ v2Low;
    final tmpHigh = v1High ^ v2High;
    v1Low = (_mask32 & (tmpLow << 1)) | (tmpHigh >>> 31);
    v1High = (tmpHigh << 1) | (tmpLow >>> 31);
  }

  data[a] = v0Low;
  data[a + 1] = v0High;
  data[b] = v1Low;
  data[b + 1] = v1High;
  data[c] = v2Low;
  data[c + 1] = v2High;
  data[d] = v3Low;
  data[d + 1] = v3High;
}