docs: function bcryptAsm(stdlib, foreign, heap) {
          "use asm";
  
          var HEAP32 = new stdlib.Uint32Array(heap);
  
          var BLOWFISH_NUM_ROUNDS = 16;
          var S_offset = 0x0000;          // length 0x1000 octets
          var S1_offset = 0x0400;
          var S2_offset = 0x0800;
          var S3_offset = 0x0C00;
          var P_offset = 0x1000;          // length 0x0048 (72) octets
          var P_last_offset = 0x1044;
          var crypt_ciphertext_offset = 0x1048;    // length 0x0018 (24) octets
          var LR_offset = 0x01060;        // length 8 octets
          var password_offset = 0x1068;   // length 0x0048 (72) octets
          var salt_offset = 0x10b0;       // length 0x0048 (72) octets, 18 uint32
          var P_LEN = 18;
          var S_LEN = 1024;
  
          function encrypt(offset) {
              offset = offset|0;
              var i = 0;
              var n = 0;
              var L = 0;
              var R = 0;
              var imax = 0;
              imax = P_offset | BLOWFISH_NUM_ROUNDS << 2;
              
              L = HEAP32[offset >> 2]|0;
              R = HEAP32[offset + 4 >> 2]|0;
  
              L = L ^ HEAP32[P_offset>>2];
              for (i = P_offset; (i|0) < (imax|0);) {
                  // Feistel substitution on left word
                  i = (i + 4)>>>0;
                  R = R ^ (
                      ((HEAP32[(L >>> 22)>>2] >>> 0) +
                      (HEAP32[(S1_offset | (L >>> 14 & 0x3ff))>>2] >>> 0) ^
                      (HEAP32[(S2_offset | (L >>> 6 & 0x3ff))>>2])) +
                      (HEAP32[(S3_offset | (L << 2 & 0x3ff))>>2] >>> 0)
                  ) ^ HEAP32[i>>2];
  
                  // Feistel substitution on right word
                  i = (i + 4)>>>0;
                  L = L ^ (
                      ((HEAP32[(R >>> 22)>>2] >>> 0) +
                      (HEAP32[(S1_offset | (R >>> 14 & 0x3ff))>>2] >>> 0) ^
                      (HEAP32[(S2_offset | (R >>> 6 & 0x3ff))>>2])) +
                      (HEAP32[(S3_offset | (R << 2 & 0x3ff))>>2] >>> 0)
                  ) ^ HEAP32[i>>2];
              }
              HEAP32[offset>>2] = R ^ HEAP32[P_last_offset>>2];
              HEAP32[(offset+4)>>2] = L;
          }
  
          function expandKey(offset) {
              offset = offset|0;
              var i = 0;
              var off = 0;
  
              off = P_offset|0;
              for (i = 0; (i|0) < (P_LEN|0); i = (i+1)|0) {
                  HEAP32[off >> 2] = HEAP32[off >> 2] ^ HEAP32[offset >> 2];
                  offset = (offset + 4)|0;
                  off = (off + 4)|0;
              }
  
              HEAP32[LR_offset >> 2] = 0;
              HEAP32[LR_offset + 4 >> 2] = 0;
  
              off = P_offset;
              for (i = 0; (i|0) < (P_LEN|0); i = (i+2)|0) {
                  encrypt(LR_offset);
                  HEAP32[off >> 2] = HEAP32[LR_offset >> 2];
                  HEAP32[off + 4 >> 2] = HEAP32[LR_offset + 4 >> 2];
                  off = (off + 8)|0;
              }
  
              off = S_offset;
              for (i = 0; (i|0) < (S_LEN|0); i = (i+2)|0) {
                  encrypt(LR_offset);
                  HEAP32[off >> 2] = HEAP32[LR_offset >> 2];
                  HEAP32[off + 4 >> 2] = HEAP32[LR_offset + 4 >> 2];
                  off = (off + 8)|0;
              }
          }
  
          function expandLoop(i, counterEnd, maxIterations) {
              i = i|0;
              counterEnd = counterEnd|0;
              maxIterations = maxIterations|0;
              var j = 0;
  
              for (j = 0; (j|0) <= (maxIterations|0); j = (j+1)|0) {
                  if ((i>>>0) > (counterEnd>>>0)) break;
                  expandKey(password_offset);
                  expandKey(salt_offset);
                  i = (i+1)>>>0;
              }
              return i|0;
          }
  
          return {
              encrypt: encrypt,
              expandLoop: expandLoop
          };
      }