Category talk:Wren-crypto

From Rosetta Code
Revision as of 14:57, 12 May 2021 by PureFox (talk | contribs) (Added source code for new 'Wren-crypto' module.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Source code

<lang ecmascript>/* Module "crypto.wren" */

/*

   Bits contains bit manipulation routines which are useful for cryptograpgic purposes.
   To make these as fast as possible no checks are performed on the inputs.
  • /

class Bits {

   // Rotates the bits in a 32-bit unsigned integer 'x' to the left by 'c' places between 1 and 31.
   static leftRotate (x, c) { (x << c) | (x >> (32 - c)) }
   // Rotates the bits in a 32-bit unsigned integer 'x' to the right by 'c' places between 1 and 31.
   static rightRotate(x, c) { (x >> c) | (x << (32 - c)) }

}

/*

   Bytes contains byte manipulation routines which are useful for cryptograpgic purposes.
   To make these as fast as possible no checks are performed on the inputs.
  • /

class Bytes {

   // Converts a 32-bit unsigned integer 'x' to a list of 4 bytes in big-endian format.
   static fromIntBE(x) {
       var bytes = List.filled(4, 0)
       bytes[3] = x         & 255
       bytes[2] = (x >> 8)  & 255
       bytes[1] = (x >> 16) & 255
       bytes[0] = (x >> 24) & 255
       return bytes
   }
   // Converts a 32-bit unsigned integer 'x' to a list of 4 bytes in little-endian format.
   static fromIntLE(x) {
       var bytes = List.filled(4, 0)
       bytes[0] = x         & 255
       bytes[1] = (x >> 8)  & 255
       bytes[2] = (x >> 16) & 255
       bytes[3] = (x >> 24) & 255
       return bytes
   }
   // Converts a list of 4 bytes in big-endian format to a 32-bit unsigned integer.
   static toIntBE(bytes) { bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3] }
   // Converts a list of 4 bytes in little-endian format to a 32-bit unsigned integer.
   static toIntLE(bytes) { bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24 }
   // Converts a list of 4 bytes or a 32-bit unsigned integer
   // into an 8 digit hexadecimal string.
   static toHexString(bytes) {
      if (bytes is Num) bytes = fromIntBE(bytes)
      var digits = "0123456789abcdef"
      var res = []
      for (byte in bytes) {
           var d = (byte != 0) ? [] : [0]
           while (byte > 0) {
               d.add(digits[byte % 16])
               byte = (byte/16).floor
           }
           res.add((d.count == 2) ? d[1] : 0)
           res.add(d[0])
      }
      return res.join()
   }

}

/* Md5 implements the MD5 hashing algorithm. */ class Md5 {

   static init_() {
       __k = [
           0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
           0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
           0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
           0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
           0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
           0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
           0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
           0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
           0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
           0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
           0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
           0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
           0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
           0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
           0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
           0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
       ]
       __r = [
           7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
           5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
           4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
           6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
       ]
   }
   // Computes the MD5 message digest of a byte sequence or string.
   static digest(initBytes) {
       if (!__k) init_()
       var h0 = 0x67452301
       var h1 = 0xefcdab89
       var h2 = 0x98badcfe
       var h3 = 0x10325476
       if (initBytes is String) initBytes = initBytes.bytes
       var initLen = initBytes.count
       var newLen = initLen + 1
       while (newLen % 64 != 56) newLen = newLen + 1
       var msg = List.filled(newLen + 8, 0)
       for (i in 0...initLen) msg[i] = initBytes[i]
       msg[initLen] = 0x80 // remaining bytes already 0
       var lenBits = Bytes.fromIntLE(initLen * 8)
       for (i in newLen...newLen+4) msg[i] = lenBits[i-newLen]
       var extraBits = Bytes.fromIntLE(initLen >> 29)
       for (i in newLen+4...newLen+8) msg[i] = extraBits[i-newLen-4]
       var offset = 0
       var w = List.filled(16, 0)
       while (offset < newLen) {
           for (i in 0...16) w[i] = Bytes.toIntLE(msg[offset+i*4...offset + i*4 + 4])
           var a = h0
           var b = h1
           var c = h2
           var d = h3
           var f
           var g
           for (i in 0...64) {
               if (i < 16) {
                   f = (b & c) | ((~b) & d)
                   g = i
               } else if (i < 32) {
                   f = (d & b) | ((~d) & c)
                   g = (5*i + 1) % 16
               } else if (i < 48) {
                   f = b ^ c ^ d
                   g = (3*i + 5) % 16
               } else {
                   f = c ^ (b | (~d))
                   g = (7*i) % 16
               }
               var temp = d
               d = c
               c = b
               b = b + Bits.leftRotate((a + f + __k[i] + w[g]), __r[i])
               a = temp
           }
           h0 = h0 + a
           h1 = h1 + b
           h2 = h2 + c
           h3 = h3 + d
           offset = offset + 64
       }
       h0 = Bytes.toHexString(Bytes.fromIntLE(h0))
       h1 = Bytes.toHexString(Bytes.fromIntLE(h1))
       h2 = Bytes.toHexString(Bytes.fromIntLE(h2))
       h3 = Bytes.toHexString(Bytes.fromIntLE(h3))
       return h0 + h1 + h2 + h3
   }

}

/* Sha256 implements the SHA-256 hashing algorithm. */ class Sha256 {

   static init_() {
       __k = [
           0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
           0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
           0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
           0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
           0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
           0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
           0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
           0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
       ]
   }
   // Computes the SHA-256 message digest of a byte sequence or string.
   static digest(initBytes) {
       if (!__k) init_()
       var h0 = 0x6a09e667
       var h1 = 0xbb67ae85
       var h2 = 0x3c6ef372
       var h3 = 0xa54ff53a
       var h4 = 0x510e527f
       var h5 = 0x9b05688c
       var h6 = 0x1f83d9ab
       var h7 = 0x5be0cd19
       if (initBytes is String) initBytes = initBytes.bytes
       var initLen = initBytes.count
       var newLen = initLen + 1
       while (newLen % 64 != 56) newLen = newLen + 1
       var msg = List.filled(newLen + 8, 0)
       for (i in 0...initLen) msg[i] = initBytes[i]
       msg[initLen] = 0x80 // remaining bytes already 0
       var initBits = initLen * 8
       var p = 2.pow(32)
       var u = (initBits/p).floor
       var l = initBits % p
       var bytesU = Bytes.fromIntBE(u)
       var bytesL = Bytes.fromIntBE(l)
       for (i in 0..3) msg[newLen+i]   = bytesU[i]
       for (i in 0..3) msg[newLen+i+4] = bytesL[i]
       var offset = 0
       var w = List.filled(64, 0)
       var mask = 0xffffffff
       while (offset < newLen) {
           for (i in 0..15) w[i] = Bytes.toIntBE(msg[offset+i*4...offset + i*4 + 4])
           for (i in 16..63) {
               var s0 = Bits.rightRotate(w[i-15],  7) ^ Bits.rightRotate(w[i-15], 18) ^ (w[i-15] >>  3)
               var s1 = Bits.rightRotate(w[i- 2], 17) ^ Bits.rightRotate(w[i- 2], 19) ^ (w[i- 2] >> 10)
               w[i] = w[i-16] + s0 + w[i-7] + s1
           }
           var a = h0
           var b = h1
           var c = h2
           var d = h3
           var e = h4
           var f = h5
           var g = h6
           var h = h7
           for (i in 0..63) {
               var s1 = Bits.rightRotate(e, 6) ^ Bits.rightRotate(e, 11) ^ Bits.rightRotate(e, 25)
               var ch = (e & f) ^ ((~e) & g)
               var temp1 = h + s1 + ch + __k[i] + w[i]
               var s0 = Bits.rightRotate(a, 2) ^ Bits.rightRotate(a, 13) ^ Bits.rightRotate(a, 22)
               var maj = (a & b) ^ (a & c) ^ (b & c)
               var temp2 = s0 + maj
               h = g
               g = f
               f = e
               e = d + temp1
               d = c
               c = b
               b = a
               a = temp1 + temp2
           }
           h0 = (h0 + a) & mask
           h1 = (h1 + b) & mask
           h2 = (h2 + c) & mask
           h3 = (h3 + d) & mask
           h4 = (h4 + e) & mask
           h5 = (h5 + f) & mask
           h6 = (h6 + g) & mask
           h7 = (h7 + h) & mask
           offset = offset + 64
       }
       h0 = Bytes.toHexString(h0)
       h1 = Bytes.toHexString(h1)
       h2 = Bytes.toHexString(h2)
       h3 = Bytes.toHexString(h3)
       h4 = Bytes.toHexString(h4)
       h5 = Bytes.toHexString(h5)
       h6 = Bytes.toHexString(h6)
       h7 = Bytes.toHexString(h7)
       return h0 + h1 + h2 + h3 + h4 + h5 + h6 + h7
   }

}

/* Sha224 implements the SHA-224 hashing algorithm. */ class Sha224 {

   static init_() {
       __k = [
           0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
           0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
           0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
           0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
           0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
           0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
           0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
           0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
       ]
   }
   // Computes the SHA-224 message digest of a byte sequence or string.
   static digest(initBytes) {
       if (!__k) init_()
       var h0 = 0xc1059ed8
       var h1 = 0x367cd507
       var h2 = 0x3070dd17
       var h3 = 0xf70e5939
       var h4 = 0xffc00b31
       var h5 = 0x68581511
       var h6 = 0x64f98fa7
       var h7 = 0xbefa4fa4
       if (initBytes is String) initBytes = initBytes.bytes
       var initLen = initBytes.count
       var newLen = initLen + 1
       while (newLen % 64 != 56) newLen = newLen + 1
       var msg = List.filled(newLen + 8, 0)
       for (i in 0...initLen) msg[i] = initBytes[i]
       msg[initLen] = 0x80 // remaining bytes already 0
       var initBits = initLen * 8
       var p = 2.pow(32)
       var u = (initBits/p).floor
       var l = initBits % p
       var bytesU = Bytes.fromIntBE(u)
       var bytesL = Bytes.fromIntBE(l)
       for (i in 0..3) msg[newLen+i]   = bytesU[i]
       for (i in 0..3) msg[newLen+i+4] = bytesL[i]
       var offset = 0
       var w = List.filled(64, 0)
       var mask = 0xffffffff
       while (offset < newLen) {
           for (i in 0..15) w[i] = Bytes.toIntBE(msg[offset+i*4...offset + i*4 + 4])
           for (i in 16..63) {
               var s0 = Bits.rightRotate(w[i-15],  7) ^ Bits.rightRotate(w[i-15], 18) ^ (w[i-15] >>  3)
               var s1 = Bits.rightRotate(w[i- 2], 17) ^ Bits.rightRotate(w[i- 2], 19) ^ (w[i- 2] >> 10)
               w[i] = w[i-16] + s0 + w[i-7] + s1
           }
           var a = h0
           var b = h1
           var c = h2
           var d = h3
           var e = h4
           var f = h5
           var g = h6
           var h = h7
           for (i in 0..63) {
               var s1 = Bits.rightRotate(e, 6) ^ Bits.rightRotate(e, 11) ^ Bits.rightRotate(e, 25)
               var ch = (e & f) ^ ((~e) & g)
               var temp1 = h + s1 + ch + __k[i] + w[i]
               var s0 = Bits.rightRotate(a, 2) ^ Bits.rightRotate(a, 13) ^ Bits.rightRotate(a, 22)
               var maj = (a & b) ^ (a & c) ^ (b & c)
               var temp2 = s0 + maj
               h = g
               g = f
               f = e
               e = d + temp1
               d = c
               c = b
               b = a
               a = temp1 + temp2
           }
           h0 = (h0 + a) & mask
           h1 = (h1 + b) & mask
           h2 = (h2 + c) & mask
           h3 = (h3 + d) & mask
           h4 = (h4 + e) & mask
           h5 = (h5 + f) & mask
           h6 = (h6 + g) & mask
           h7 = (h7 + h) & mask
           offset = offset + 64
       }
       h0 = Bytes.toHexString(h0)
       h1 = Bytes.toHexString(h1)
       h2 = Bytes.toHexString(h2)
       h3 = Bytes.toHexString(h3)
       h4 = Bytes.toHexString(h4)
       h5 = Bytes.toHexString(h5)
       h6 = Bytes.toHexString(h6)
       return h0 + h1 + h2 + h3 + h4 + h5 + h6
   }

}

/* Sha1 implements the SHA-1 hashing algorithm. */ class Sha1 {

   // Computes the SHA-1 message digest of a byte sequence or string.
   static digest(initBytes) {
       var h0 = 0x67452301
       var h1 = 0xefcdab89
       var h2 = 0x98badcfe
       var h3 = 0x10325476
       var h4 = 0xc3d2e1f0
       if (initBytes is String) initBytes = initBytes.bytes
       var initLen = initBytes.count
       var newLen = initLen + 1
       while (newLen % 64 != 56) newLen = newLen + 1
       var msg = List.filled(newLen + 8, 0)
       for (i in 0...initLen) msg[i] = initBytes[i]
       msg[initLen] = 0x80 // remaining bytes already 0
       var initBits = initLen * 8
       var p = 2.pow(32)
       var u = (initBits/p).floor
       var l = initBits % p
       var bytesU = Bytes.fromIntBE(u)
       var bytesL = Bytes.fromIntBE(l)
       for (i in 0..3) msg[newLen+i]   = bytesU[i]
       for (i in 0..3) msg[newLen+i+4] = bytesL[i]
       var offset = 0
       var w = List.filled(80, 0)
       var mask = 0xffffffff
       while (offset < newLen) {
           for (i in 0..15) w[i] = Bytes.toIntBE(msg[offset+i*4...offset + i*4 + 4])
           for (i in 16..79) {
               w[i] = Bits.leftRotate(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1)
           }
           var a = h0
           var b = h1
           var c = h2
           var d = h3
           var e = h4
           var f
           var k
           for (i in 0..79) {
               if (i <= 19) {
                   f = (b & c) | ((~b) & d)
                   k = 0x5a827999
               } else if (i <= 39) {
                   f = b ^ c ^ d
                   k = 0x6ed9eba1
               } else if (i <= 59) {
                   f = (b & c) | (b & d) | (c & d)
                   k = 0x8f1bbcdc
               } else {
                   f = b ^ c ^ d
                   k = 0xca62c1d6
               }
               var temp = Bits.leftRotate(a, 5) + f + e + k + w[i]
               e = d
               d = c
               c = Bits.leftRotate(b, 30)
               b = a
               a = temp
           }
           h0 = (h0 + a) & mask
           h1 = (h1 + b) & mask
           h2 = (h2 + c) & mask
           h3 = (h3 + d) & mask
           h4 = (h4 + e) & mask
           offset = offset + 64
       }
       h0 = Bytes.toHexString(h0)
       h1 = Bytes.toHexString(h1)
       h2 = Bytes.toHexString(h2)
       h3 = Bytes.toHexString(h3)
       h4 = Bytes.toHexString(h4)
       return h0 + h1 + h2 + h3 + h4
   }

}

/* Ripemd160 implements the RIPEMD-160 hashing algorithm. */ class Ripemd160 {

   static init_() {
       __f = [
           Fn.new { |x, y, z| x ^ y ^ z },
           Fn.new { |x, y, z| (x & y) | ((~x) & z) },
           Fn.new { |x, y, z| (x | (~y)) ^ z },
           Fn.new { |x, y, z| (x & z) | (y & (~z)) },
           Fn.new { |x, y, z| x ^ (y | (~z)) }
       ]
       __k  = [ 0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e ]
       __kk = [ 0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000 ]
       __r = [
           0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
           7,  4, 13,  1, 10,  6, 15,  3, 12,  0,  9,  5,  2, 14, 11,  8,
           3, 10, 14,  4,  9, 15,  8,  1,  2,  7,  0,  6, 13, 11,  5, 12,
           1,  9, 11, 10,  0,  8, 12,  4, 13,  3,  7, 15, 14,  5,  6,  2,
           4,  0,  5,  9,  7, 12,  2, 10, 14,  1,  3,  8, 11,  6, 15, 13
       ]
       __rr = [
            5, 14,  7,  0,  9,  2, 11,  4, 13,  6, 15,  8,  1, 10,  3, 12,
            6, 11,  3,  7,  0, 13,  5, 10, 14, 15,  8, 12,  4,  9,  1,  2,
           15,  5,  1,  3,  7, 14,  6,  9, 11,  8, 12,  2, 10,  0,  4, 13,
            8,  6,  4,  1,  3, 11, 15,  0,  5, 12,  2, 13,  9,  7, 10, 14,
           12, 15, 10,  4,  1,  5,  8,  7,  6,  2, 13, 14,  0,  3,  9, 11
       ]
       __s = [
           11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
            7,  6,  8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
           11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
           11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
            9, 15,  5, 11,  6,  8, 13, 12,  5, 12, 13, 14, 11,  8,  5,  6
       ]
       __ss = [
            8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
            9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
            9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
           15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
            8,  5, 12,  9, 12,  5, 14,  6,  8, 13,  6,  5, 15, 13, 11, 11
       ]
   }
   // Computes the RIPEMD-160 message digest of a byte sequence or string.
   static digest(initBytes) {
       if (!__f) init_()
       var h0 = 0x67452301
       var h1 = 0xefcdab89
       var h2 = 0x98badcfe
       var h3 = 0x10325476
       var h4 = 0xc3d2e1f0
       if (initBytes is String) initBytes = initBytes.bytes
       var initLen = initBytes.count
       var newLen = initLen + 1
       while (newLen % 64 != 56) newLen = newLen + 1
       var msg = List.filled(newLen + 8, 0)
       for (i in 0...initLen) msg[i] = initBytes[i]
       msg[initLen] = 0x80 // remaining bytes already 0
       var lenBits = Bytes.fromIntLE(initLen * 8)
       for (i in newLen...newLen+4) msg[i] = lenBits[i-newLen]
       var extraBits = Bytes.fromIntLE(initLen >> 29)
       for (i in newLen+4...newLen+8) msg[i] = extraBits[i-newLen-4]
       var offset = 0
       var x = List.filled(16, 0)
       var mask = 0xffffffff
       while (offset < newLen) {
           for (i in 0...16) x[i] = Bytes.toIntLE(msg[offset+i*4...offset + i*4 + 4])
           var a = h0
           var b = h1
           var c = h2
           var d = h3
           var e = h4
           var aa = h0
           var bb = h1
           var cc = h2
           var dd = h3
           var ee = h4
           for (j in 0..79) {
               var i = (j/16).floor
               var t = a + __f[i].call(b, c, d) + x[__r[j]] + __k[i]
               t = (Bits.leftRotate(t & mask, __s[j]) + e) & mask
               a = e
               e = d
               d = Bits.leftRotate(c, 10)
               c = b
               b = t
               t = aa + __f[4-i].call(bb, cc, dd) + x[__rr[j]] + __kk[i]
               t = (Bits.leftRotate(t & mask, __ss[j]) + ee) & mask
               aa = ee
               ee = dd
               dd = Bits.leftRotate(cc, 10)
               cc = bb
               bb = t
           }
           var temp = (h1 + c + dd) & mask
           h1 = (h2 + d + ee) & mask
           h2 = (h3 + e + aa) & mask
           h3 = (h4 + a + bb) & mask
           h4 = (h0 + b + cc) & mask
           h0 = temp
           offset = offset + 64
       }
       h0 = Bytes.toHexString(Bytes.fromIntLE(h0))
       h1 = Bytes.toHexString(Bytes.fromIntLE(h1))
       h2 = Bytes.toHexString(Bytes.fromIntLE(h2))
       h3 = Bytes.toHexString(Bytes.fromIntLE(h3))
       h4 = Bytes.toHexString(Bytes.fromIntLE(h4))
       return h0 + h1 + h2 + h3 + h4
   }

}</lang>