/*
 * A WML Script implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Copyright (C) Simon Wistow, 2001
 * 
 * Auxillary functions - split into seperate files to keep each compiled
 * script down below the size of one UDP packet so all phones can use it
 */



use url ordlib "ord.wmlsc";


/*
 * Extract a value from one of our arrays. These are strings separated by the '|' character.
 */
extern function elt(str, index)
{
  return String.elementAt (str, index, '|');
}

/*
 * Extract a value from an array at offset:
 *      base + ((group + offset) & 0xF)
 */
extern function elt2(str, base, group, offset)
{
  return elt(str, base + ((group + offset) & 0xF));
}

/*
 * Reduce size by turning this into a function.
 */
extern function combine (a, b, c, d)
{
  return a + "|" + b + "|" + c + "|" + d;
}

/*
 * Take a string and return the hex representation of its MD5.
 */
extern function rhex(num)
{
  var hex_chr = "0123456789abcdef";

  var str = "";

  for(var j = 0; j <= 3; j++)
    str += String.charAt(hex_chr, (num >> (j * 8 + 4)) & 0x0F) +
           String.charAt(hex_chr, (num >> (j * 8)) & 0x0F);


  return str;
}

/*
 * Convert a string to a sequence of 16-word blocks, stored as an array.
 * Append padding bits and the length, as described in the MD5 standard.
 */
extern function str2blks_MD5(str)
{

  var nblk = ((String.length(str) + 8) >> 6) + 1;
  var blks = "0";



  for(var i = 1; i < (nblk * 16); i++)
        blks += '|0';




  for(i = 0; i <= String.length(str); i++)
  {
        var temp    =  String.elementAt(blks, i>>2, '|');
        var ord_str = ordlib#ord_string(str);

        if (i != String.length(str))
                temp |= String.elementAt(ord_str,i, '|') << ((i % 4) * 8);
        else
                temp |= 0x80 << ((i % 4) * 8);

        blks = String.replaceAt(blks, temp, i>>2, '|');

  }



  blks =  String.replaceAt(blks, String.length(str) * 8, nblk * 16 - 2, '|');

  return blks;
}

/*
 * Add integers, wrapping at 2^32
 */
extern function add(x, y)
{
  return ((x&0x7FFFFFFF) + (y&0x7FFFFFFF)) ^ (x&0x80000000) ^ (y&0x80000000);
}

/*
 * Bitwise rotate a 32-bit number to the left
 */
extern function rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * These functions implement the basic operation for each round of the
 * algorithm.
 */
extern function cmn(q, a, b, x, s, t)
{
  return add(rol(add(add(a, q), add(x, t)), s), b);
}

extern function ff(a, b, c, d, x, s, t)
{
  return cmn((b & c) | ((~b) & d), a, b, x, s, t);
}

extern function gg(a, b, c, d, x, s, t)
{
  return cmn((b & d) | (c & (~d)), a, b, x, s, t);
}

extern function hh(a, b, c, d, x, s, t)
{
  return cmn(b ^ c ^ d, a, b, x, s, t);
}

extern function ii(a, b, c, d, x, s, t)
{
  return cmn(c ^ (b | (~d)), a, b, x, s, t);
}

extern function ff_four (abcd, x, i, offset, t1, t2, t3, t4)
{
        var a = String.elementAt(abcd, 0, '|');
        var b = String.elementAt(abcd, 1, '|');
        var c = String.elementAt(abcd, 2, '|');
        var d = String.elementAt(abcd, 3, '|');

        i+=offset;

        a = ff(a, b, c, d, String.elementAt(x, i+ 0, '|'), 7, t1);
        d = ff(d, a, b, c, String.elementAt(x, i+ 1, '|'),12, t2);
        c = ff(c, d, a, b, String.elementAt(x, i+ 2, '|'),17, t3);
        b = ff(b, c, d, a, String.elementAt(x, i+ 3, '|'),22, t4);


        return a + '|' + b + '|' + c + '|' + d;

}

extern function gg_four (abcd, x, i, offset, t1, t2, t3, t4)
{

        var a = elt(abcd, 0);
        var b = elt(abcd, 1);
        var c = elt(abcd, 2);
        var d = elt(abcd, 3);

        a = gg(a, b, c, d, elt2(x, i, offset,  0),  5, t1);
        d = gg(d, a, b, c, elt2(x, i, offset,  5),  9, t2);
        c = gg(c, d, a, b, elt2(x, i, offset, 10), 14, t3);
        b = gg(b, c, d, a, elt2(x, i, offset, 15), 20, t4);

        return combine (a, b, c, d);


}


/*
 * Do four hh calculations at once.
 */
extern function hh_four (abcd, x, i, offset, t1, t2, t3, t4)
{
        var a = elt(abcd, 0);
        var b = elt(abcd, 1);
        var c = elt(abcd, 2);
        var d = elt(abcd, 3);


        a = hh(a, b, c, d, elt2(x, i, offset, 0),  4, t1);
        d = hh(d, a, b, c, elt2(x, i, offset, 3), 11, t2);
        c = hh(c, d, a, b, elt2(x, i, offset, 6), 16, t3);
        b = hh(b, c, d, a, elt2(x, i, offset, 9), 23, t4);

        return combine (a, b, c, d);
}

/*
 * Do four ii calculations at once.
 */
extern function ii_four (abcd, x, i, offset, t1, t2, t3, t4)
{
        var a = elt(abcd, 0);
        var b = elt(abcd, 1);
        var c = elt(abcd, 2);
        var d = elt(abcd, 3);


        a = ii(a, b, c, d, elt2(x, i, offset,  0),  6, t1);
        d = ii(d, a, b, c, elt2(x, i, offset,  7), 10, t2);
        c = ii(c, d, a, b, elt2(x, i, offset, 14), 15, t3);
        b = ii(b, c, d, a, elt2(x, i, offset, 21), 21, t4);

        return combine (a, b, c, d);
}