/*
 *
 *      Author: George Mossessian
 *
 *      The MD4 hash algorithm, as described in https://tools.ietf.org/html/rfc1320
 */

#include <stdlib.h>
#include <string.h>
#include <stdint.h>

char *MD4(char *str, int len); //this is the prototype you want to call. Everything else is internal.

typedef struct string{
        char *c;
        int len;
        char sign;
}string;

static uint32_t *MD4Digest(uint32_t *w, int len);
static void setMD4Registers(uint32_t AA, uint32_t BB, uint32_t CC, uint32_t DD);
static uint32_t changeEndianness(uint32_t x);
static void resetMD4Registers(void);
static string stringCat(string first, string second);
static string uint32ToString(uint32_t l);
static uint32_t stringToUint32(string s);

static const char *BASE16 = "0123456789abcdef=";

#define F(X,Y,Z) (((X)&(Y))|((~(X))&(Z)))
#define G(X,Y,Z) (((X)&(Y))|((X)&(Z))|((Y)&(Z)))
#define H(X,Y,Z) ((X)^(Y)^(Z))

#define LEFTROTATE(A,N) ((A)<<(N))|((A)>>(32-(N)))

#define MD4ROUND1(a,b,c,d,x,s) a += F(b,c,d) + x; a = LEFTROTATE(a, s);
#define MD4ROUND2(a,b,c,d,x,s) a += G(b,c,d) + x + (uint32_t)0x5A827999; a = LEFTROTATE(a, s);
#define MD4ROUND3(a,b,c,d,x,s) a += H(b,c,d) + x + (uint32_t)0x6ED9EBA1; a = LEFTROTATE(a, s);

static uint32_t A = 0x67452301;
static uint32_t B = 0xefcdab89;
static uint32_t C = 0x98badcfe;
static uint32_t D = 0x10325476;

string newString(char * c, int t){
	string r;
	int i;
	if(c!=NULL){
		r.len = (t<=0)?strlen(c):t;
		r.c=(char *)malloc(sizeof(char)*(r.len+1));
		for(i=0; i<r.len; i++) r.c[i]=c[i];
		r.c[r.len]='\0';
		return r;
	}
	r.len=t;
	r.c=(char *)malloc(sizeof(char)*(r.len+1));
	memset(r.c,(char)0,sizeof(char)*(t+1));
	r.sign = 1;
	return r;
}

string stringCat(string first, string second){
	string str=newString(NULL, first.len+second.len);
	int i;

	for(i=0; i<first.len; i++){
		str.c[i]=first.c[i];
	}
	for(i=first.len; i<str.len; i++){
		str.c[i]=second.c[i-first.len];
	}
	return str;
}

string base16Encode(string in){
	string out=newString(NULL, in.len*2);
	int i,j;

	j=0;
	for(i=0; i<in.len; i++){
		out.c[j++]=BASE16[((in.c[i] & 0xF0)>>4)];
		out.c[j++]=BASE16[(in.c[i] & 0x0F)];
	}
	out.c[j]='\0';
	return out;
}

string uint32ToString(uint32_t l){
	string s = newString(NULL,4);
	int i;
	for(i=0; i<4; i++){
		s.c[i] = (l >> (8*(3-i))) & 0xFF;
	}
	return s;
}

uint32_t stringToUint32(string s){
	uint32_t l;
	int i;
	l=0;
	for(i=0; i<4; i++){
		l = l|(((uint32_t)((unsigned char)s.c[i]))<<(8*(3-i)));
	}
	return l;
}

char *MD4(char *str, int len){
	string m=newString(str, len);
	string digest;
	uint32_t *w;
	uint32_t *hash;
	uint64_t mlen=m.len;
	unsigned char oneBit = 0x80;
	int i, wlen;

	m=stringCat(m, newString((char *)&oneBit,1));

	//append 0 ≤ k < 512 bits '0', such that the resulting message length in bits
	//	is congruent to −64 ≡ 448 (mod 512)4
	i=((56-m.len)%64);
	if(i<0) i+=64;
	m=stringCat(m,newString(NULL, i));

	w = malloc(sizeof(uint32_t)*(m.len/4+2));

	//append length, in bits (hence <<3), least significant word first
	for(i=0; i<m.len/4; i++){
		w[i]=stringToUint32(newString(&(m.c[4*i]), 4));
	}
	w[i++] = (mlen<<3) & 0xFFFFFFFF;
	w[i++] = (mlen>>29) & 0xFFFFFFFF;

	wlen=i;

	//change endianness, but not for the appended message length, for some reason?
	for(i=0; i<wlen-2; i++){
		w[i]=changeEndianness(w[i]);
	}

	hash = MD4Digest(w,wlen);

	digest=newString(NULL,0);
	for(i=0; i<4; i++){
		hash[i]=changeEndianness(hash[i]);
		digest=stringCat(digest,uint32ToString(hash[i]));
	}

	return base16Encode(digest).c;
}

uint32_t *MD4Digest(uint32_t *w, int len){
	//assumes message.len is a multiple of 64 bytes.
	int i,j;
	uint32_t X[16];
	uint32_t *digest = malloc(sizeof(uint32_t)*4);
	uint32_t AA, BB, CC, DD;

	for(i=0; i<len/16; i++){
		for(j=0; j<16; j++){
			X[j]=w[i*16+j];
		}

		AA=A;
		BB=B;
		CC=C;
		DD=D;

		MD4ROUND1(A,B,C,D,X[0],3);
		MD4ROUND1(D,A,B,C,X[1],7);
		MD4ROUND1(C,D,A,B,X[2],11);
		MD4ROUND1(B,C,D,A,X[3],19);
		MD4ROUND1(A,B,C,D,X[4],3);
		MD4ROUND1(D,A,B,C,X[5],7);
		MD4ROUND1(C,D,A,B,X[6],11);
		MD4ROUND1(B,C,D,A,X[7],19);
		MD4ROUND1(A,B,C,D,X[8],3);
		MD4ROUND1(D,A,B,C,X[9],7);
		MD4ROUND1(C,D,A,B,X[10],11);
		MD4ROUND1(B,C,D,A,X[11],19);
		MD4ROUND1(A,B,C,D,X[12],3);
		MD4ROUND1(D,A,B,C,X[13],7);
		MD4ROUND1(C,D,A,B,X[14],11);
		MD4ROUND1(B,C,D,A,X[15],19);

		MD4ROUND2(A,B,C,D,X[0],3);
		MD4ROUND2(D,A,B,C,X[4],5);
		MD4ROUND2(C,D,A,B,X[8],9);
		MD4ROUND2(B,C,D,A,X[12],13);
		MD4ROUND2(A,B,C,D,X[1],3);
		MD4ROUND2(D,A,B,C,X[5],5);
		MD4ROUND2(C,D,A,B,X[9],9);
		MD4ROUND2(B,C,D,A,X[13],13);
		MD4ROUND2(A,B,C,D,X[2],3);
		MD4ROUND2(D,A,B,C,X[6],5);
		MD4ROUND2(C,D,A,B,X[10],9);
		MD4ROUND2(B,C,D,A,X[14],13);
		MD4ROUND2(A,B,C,D,X[3],3);
		MD4ROUND2(D,A,B,C,X[7],5);
		MD4ROUND2(C,D,A,B,X[11],9);
		MD4ROUND2(B,C,D,A,X[15],13);

		MD4ROUND3(A,B,C,D,X[0],3);
		MD4ROUND3(D,A,B,C,X[8],9);
		MD4ROUND3(C,D,A,B,X[4],11);
		MD4ROUND3(B,C,D,A,X[12],15);
		MD4ROUND3(A,B,C,D,X[2],3);
		MD4ROUND3(D,A,B,C,X[10],9);
		MD4ROUND3(C,D,A,B,X[6],11);
		MD4ROUND3(B,C,D,A,X[14],15);
		MD4ROUND3(A,B,C,D,X[1],3);
		MD4ROUND3(D,A,B,C,X[9],9);
		MD4ROUND3(C,D,A,B,X[5],11);
		MD4ROUND3(B,C,D,A,X[13],15);
		MD4ROUND3(A,B,C,D,X[3],3);
		MD4ROUND3(D,A,B,C,X[11],9);
		MD4ROUND3(C,D,A,B,X[7],11);
		MD4ROUND3(B,C,D,A,X[15],15);

		A+=AA;
		B+=BB;
		C+=CC;
		D+=DD;
	}

	digest[0]=A;
	digest[1]=B;
	digest[2]=C;
	digest[3]=D;
	resetMD4Registers();
	return digest;
}

uint32_t changeEndianness(uint32_t x){
	return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | ((x & 0xFF000000) >> 24);
}

void setMD4Registers(uint32_t AA, uint32_t BB, uint32_t CC, uint32_t DD){
	A=AA;
	B=BB;
	C=CC;
	D=DD;
}

void resetMD4Registers(void){
	setMD4Registers(0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476);
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
static class Md4
{
    public static string Md4Hash(this string input)
    {
        // get padded uints from bytes
        List<byte> bytes = Encoding.ASCII.GetBytes(input).ToList();
        uint bitCount = (uint)(bytes.Count) * 8;
        bytes.Add(128);
        while (bytes.Count % 64 != 56) bytes.Add(0);
        var uints = new List<uint>();
        for (int i = 0; i + 3 < bytes.Count; i += 4)
            uints.Add(bytes[i] | (uint)bytes[i + 1] << 8 | (uint)bytes[i + 2] << 16 | (uint)bytes[i + 3] << 24);
        uints.Add(bitCount);
        uints.Add(0);

        // run rounds
        uint a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476;
        Func<uint, uint, uint> rol = (x, y) => x << (int)y | x >> 32 - (int)y;
        for (int q = 0; q + 15 < uints.Count; q += 16)
        {
            var chunk = uints.GetRange(q, 16);
            uint aa = a, bb = b, cc = c, dd = d;
            Action<Func<uint, uint, uint, uint>, uint[]> round = (f, y) =>
            {
                foreach (uint i in new[] { y[0], y[1], y[2], y[3] })
                {
                    a = rol(a + f(b, c, d) + chunk[(int)(i + y[4])] + y[12], y[8]);
                    d = rol(d + f(a, b, c) + chunk[(int)(i + y[5])] + y[12], y[9]);
                    c = rol(c + f(d, a, b) + chunk[(int)(i + y[6])] + y[12], y[10]);
                    b = rol(b + f(c, d, a) + chunk[(int)(i + y[7])] + y[12], y[11]);
                }
            };
            round((x, y, z) => (x & y) | (~x & z), new uint[] { 0, 4, 8, 12, 0, 1, 2, 3, 3, 7, 11, 19, 0 });
            round((x, y, z) => (x & y) | (x & z) | (y & z), new uint[] { 0, 1, 2, 3, 0, 4, 8, 12, 3, 5, 9, 13, 0x5a827999 });
            round((x, y, z) => x ^ y ^ z, new uint[] { 0, 2, 1, 3, 0, 8, 4, 12, 3, 9, 11, 15, 0x6ed9eba1 });
            a += aa; b += bb; c += cc; d += dd;
        }

        // return hex encoded string
        byte[] outBytes = new[] { a, b, c, d }.SelectMany(BitConverter.GetBytes).ToArray();
        return BitConverter.ToString(outBytes).Replace("-", "").ToLower();
    }
    static void Main() { Console.WriteLine("Rosetta Code".Md4Hash()); }
}


(use 'pandect.core)
(md4 "Rosetta Code")


(ql:quickload 'ironclad)
(defun md4 (str)
  (ironclad:byte-array-to-hex-string
    (ironclad:digest-sequence :md4
                              (ironclad:ascii-string-to-byte-array str))))

(md4 "Rosetta Code")


import std.stdio, std.string, std.range;

ubyte[16] md4(const(ubyte)[] inData) pure nothrow {
    enum f = (uint x, uint y, uint z) => (x & y) | (~x & z);
    enum g = (uint x, uint y, uint z) => (x & y) | (x & z) | (y & z);
    enum h = (uint x, uint y, uint z) => x ^ y ^ z;
    enum r = (uint v, uint s) => (v << s) | (v >> (32 - s));

    immutable bitLen = ulong(inData.length) << 3;
    inData ~= 0x80;
    while (inData.length % 64 != 56)
        inData ~= 0;
    const data = cast(uint[])inData ~ [uint(bitLen & uint.max), uint(bitLen >> 32)];

    uint a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476;

    foreach (const x; data.chunks(16)) {
        immutable a2 = a, b2 = b, c2 = c, d2 = d;
        foreach (immutable i; [0, 4, 8, 12]) {
            a = r(a + f(b, c, d) + x[i+0],  3);
            d = r(d + f(a, b, c) + x[i+1],  7);
            c = r(c + f(d, a, b) + x[i+2], 11);
            b = r(b + f(c, d, a) + x[i+3], 19);
        }
        foreach (immutable i; [0, 1, 2, 3]) {
            a = r(a + g(b, c, d) + x[i+0] + 0x5a827999,  3);
            d = r(d + g(a, b, c) + x[i+4] + 0x5a827999,  5);
            c = r(c + g(d, a, b) + x[i+8] + 0x5a827999,  9);
            b = r(b + g(c, d, a) + x[i+12] + 0x5a827999, 13);
        }
        foreach (immutable i; [0, 2, 1, 3]) {
            a = r(a + h(b, c, d) + x[i+0] + 0x6ed9eba1,  3);
            d = r(d + h(a, b, c) + x[i+8] + 0x6ed9eba1,  9);
            c = r(c + h(d, a, b) + x[i+4] + 0x6ed9eba1, 11);
            b = r(b + h(c, d, a) + x[i+12] + 0x6ed9eba1, 15);
        }
        a += a2, b += b2, c += c2, d += d2;
    }

    //return cast(ubyte[16])[a, b, c, d];
    immutable uint[4] result = [a, b, c, d];
    return cast(ubyte[16])result;
}

void main() {
    writefln("%(%02x%)", "Rosetta Code".representation.md4);
}


program CalcMD4;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  DCPmd4;

function MD4(const Str: string): string;
var
  HashDigest: array of byte;
  d: Byte;
begin
  Result := '';
  with TDCP_md4.Create(nil) do
  begin
    Init;
    UpdateStr(Str);
    SetLength(HashDigest, GetHashSize div 8);
    final(HashDigest[0]);
    for d in HashDigest do
      Result := Result + d.ToHexString(2);
    Free;
  end;
end;

begin
  Writeln(MD4('Rosetta Code'));
  readln;
end.


(require 'md4)
(require 'hex-util)
(let* ((s  "Rosetta Code")
       (m  (md4 s (length s)))) ;; m = 16 binary bytes
  (encode-hex-string m))
=>
"a52bcfc6a0d0d300cdc5ddbfbefe478b"


-module(md4).
-export([md4/0]).

md4() ->
    <<MD4:128>> = crypto:md4("Rosetta Code"),
    io:fwrite("Rosetta Code => ~.16B~n",[MD4]).


' version 19-10-2016
' translation of the (pseudo) code in RFC 1320
' compile with: fbc -s console

Function MD4(test_str As String) As String

  Dim As String message = test_str ' string are passed as ByRef

  ' some macro's
  #Macro F(X, Y, Z)
    (((X) And (Y)) Or ((Not(X)) And (Z)))
  #EndMacro

  #Macro G(X, Y, Z)
    (((X) And (Y)) Or (((X) And (Z)) Or ((Y) And (Z))))
  #EndMacro

  #Macro H(X, Y, Z)
    ((X) Xor (Y) Xor (Z))
  #EndMacro

  ' a little piece of inline asm to do a rotate left on a 32bit variable
  #Macro ROtate_Left(x, n) ' rotate left
    Asm
      rol dword Ptr [x], n
    End Asm
  #EndMacro

  ' #Macro ROtate_left(x, n)
    ' x = x Shl n + x Shr (32 - n)
  ' #EndMacro

  Dim As Long i
  Dim As String answer, s1

  Dim As ULongInt l = Len(message)
  ' set the first bit after the message to 1
  message = message + Chr(1 Shl 7)
  ' add one char to the length
  Dim As ULong padding = 64 - ((l +1) Mod (512 \ 8)) ' 512 \ 8 = 64 char.

  ' check if we have enough room for inserting the length
  If padding < 8 Then padding = padding + 64

  message = message + String(padding, Chr(0))   ' adjust length
  Dim As ULong l1 = Len(message)                ' new length

  l = l * 8    ' orignal length in bits
  ' create ubyte ptr to point to l ( = length in bits)
  Dim As UByte Ptr ub_ptr = Cast(UByte Ptr, @l)

  For i = 0 To 7  'copy length of message to the last 8 bytes
    message[l1 -8 + i] = ub_ptr[i]
  Next

  ' unsigned 32bit integers only
  Dim As UInteger<32> AA, A = &H67452301
  Dim As UInteger<32> BB, B = &Hefcdab89
  Dim As UInteger<32> CC, C = &H98badcfe
  Dim As UInteger<32> DD, D = &H10325476

  For i = 0 To (l1 -1) \ 64 ' split into 64 byte block

    AA = A : BB = B : CC = C : DD = D

    ' x point to 64 byte block inside the string message
    Dim As UInteger<32> Ptr x = Cast(UInteger<32> Ptr, @message[i*64])

    ' round 1
    A = A + F(B, C, D) + x[ 0] : ROtate_Left(A,  3)
    D = D + F(A, B, C) + x[ 1] : ROtate_Left(D,  7)
    C = C + F(D, A, B) + x[ 2] : ROtate_Left(C, 11)
    B = B + F(C, D, A) + x[ 3] : ROtate_Left(B, 19)
    A = A + F(B, C, D) + x[ 4] : ROtate_Left(A,  3)
    D = D + F(A, B, C) + x[ 5] : ROtate_Left(D,  7)
    C = C + F(D, A, B) + x[ 6] : ROtate_Left(C, 11)
    B = B + F(C, D, A) + x[ 7] : ROtate_Left(B, 19)
    A = A + F(B, C, D) + x[ 8] : ROtate_Left(A,  3)
    D = D + F(A, B, C) + x[ 9] : ROtate_Left(D,  7)
    C = C + F(D, A, B) + x[10] : ROtate_Left(C, 11)
    B = B + F(C, D, A) + x[11] : ROtate_Left(B, 19)
    A = A + F(B, C, D) + x[12] : ROtate_Left(A,  3)
    D = D + F(A, B, C) + x[13] : ROtate_Left(D,  7)
    C = C + F(D, A, B) + x[14] : ROtate_Left(C, 11)
    B = B + F(C, D, A) + x[15] : ROtate_Left(B, 19)

    ' round 2
    A = A + G(B, C, D) + x[ 0] + &H5A827999 : ROtate_Left(A,  3)
    D = D + G(A, B, C) + x[ 4] + &H5A827999 : ROtate_Left(D,  5)
    C = C + G(D, A, B) + x[ 8] + &H5A827999 : ROtate_Left(C,  9)
    B = B + G(C, D, A) + x[12] + &H5A827999 : ROtate_Left(B, 13)
    A = A + G(B, C, D) + x[ 1] + &H5A827999 : ROtate_Left(A,  3)
    D = D + G(A, B, C) + x[ 5] + &H5A827999 : ROtate_Left(D,  5)
    C = C + G(D, A, B) + x[ 9] + &H5A827999 : ROtate_Left(C,  9)
    B = B + G(C, D, A) + x[13] + &H5A827999 : ROtate_Left(B, 13)
    A = A + G(B, C, D) + x[ 2] + &H5A827999 : ROtate_Left(A,  3)
    D = D + G(A, B, C) + x[ 6] + &H5A827999 : ROtate_Left(D,  5)
    C = C + G(D, A, B) + x[10] + &H5A827999 : ROtate_Left(C,  9)
    B = B + G(C, D, A) + x[14] + &H5A827999 : ROtate_Left(B, 13)
    A = A + G(B, C, D) + x[ 3] + &H5A827999 : ROtate_Left(A,  3)
    D = D + G(A, B, C) + x[ 7] + &H5A827999 : ROtate_Left(D,  5)
    C = C + G(D, A, B) + x[11] + &H5A827999 : ROtate_Left(C,  9)
    B = B + G(C, D, A) + x[15] + &H5A827999 : ROtate_Left(B, 13)

    ' round 3
    A = A + H(B, C, D) + x[ 0] + &H6ED9EBA1 : ROtate_Left(A,  3)
    D = D + H(A, B, C) + x[ 8] + &H6ED9EBA1 : ROtate_Left(D,  9)
    C = C + H(D, A, B) + x[ 4] + &H6ED9EBA1 : ROtate_Left(C, 11)
    B = B + H(C, D, A) + x[12] + &H6ED9EBA1 : ROtate_Left(B, 15)
    A = A + H(B, C, D) + x[ 2] + &H6ED9EBA1 : ROtate_Left(A,  3)
    D = D + H(A, B, C) + x[10] + &H6ED9EBA1 : ROtate_Left(D,  9)
    C = C + H(D, A, B) + x[ 6] + &H6ED9EBA1 : ROtate_Left(C, 11)
    B = B + H(C, D, A) + x[14] + &H6ED9EBA1 : ROtate_Left(B, 15)
    A = A + H(B, C, D) + x[ 1] + &H6ED9EBA1 : ROtate_Left(A,  3)
    D = D + H(A, B, C) + x[ 9] + &H6ED9EBA1 : ROtate_Left(D,  9)
    C = C + H(D, A, B) + x[ 5] + &H6ED9EBA1 : ROtate_Left(C, 11)
    B = B + H(C, D, A) + x[13] + &H6ED9EBA1 : ROtate_Left(B, 15)
    A = A + H(B, C, D) + x[ 3] + &H6ED9EBA1 : ROtate_Left(A,  3)
    D = D + H(A, B, C) + x[11] + &H6ED9EBA1 : ROtate_Left(D,  9)
    C = C + H(D, A, B) + x[ 7] + &H6ED9EBA1 : ROtate_Left(C, 11)
    B = B + H(C, D, A) + x[15] + &H6ED9EBA1 : ROtate_Left(B, 15)

    A += AA : B += BB : C += CC : D += DD

  Next

  ' convert A, B, C and D in hex, then add low order first
  s1 = Hex(A, 8)
  For i = 7 To 1 Step -2 : answer +=Mid(s1, i, 2) : Next
  s1 = Hex(B, 8)
  For i = 7 To 1 Step -2 : answer +=Mid(s1, i, 2) : Next
  s1 = Hex(C, 8)
  For i = 7 To 1 Step -2 : answer +=Mid(s1, i, 2) : Next
  s1 = Hex(D, 8)
  For i = 7 To 1 Step -2 : answer +=Mid(s1, i, 2) : Next

Return LCase(answer)

End Function

' ------=< MAIN >=------

Dim As String test = "Rosetta Code"
Print
Print  test; " => "; MD4(test)

' empty keyboard buffer
While Inkey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End


package main

import (
    "golang.org/x/crypto/md4"
    "fmt"
)

func main() {
    h := md4.New()
    h.Write([]byte("Rosetta Code"))
    fmt.Printf("%x\n", h.Sum(nil))
}


#!/usr/bin/env runhaskell

import Data.ByteString.Char8 (pack)
import System.Environment (getArgs)
import Crypto.Hash

main :: IO ()
main = print . md4 . pack . unwords =<< getArgs
         where md4 x = hash x :: Digest MD4


   require 'ide/qt'
   gethash_jqtide_ 'MD4';'Rosetta Code'
a52bcfc6a0d0d300cdc5ddbfbefe478b


import org.bouncycastle.crypto.digests.MD4Digest;
import org.bouncycastle.util.encoders.Hex;

public class RosettaMD4
{
    public static void main (String[] argv) throws Exception
    {
        byte[] r = "Rosetta Code".getBytes("US-ASCII");
        MD4Digest d = new MD4Digest();
        d.update (r, 0, r.length);
        byte[] o = new byte[d.getDigestSize()];
        d.doFinal (o, 0);
        Hex.encode (o, System.out);
        System.out.println();
    }
}


const md4func = () => {

  const hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase    */
  const b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance  */
  const chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode   */

  const tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  const hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";

  /**
   * Add integers, wrapping at 2^32. This uses 16-bit operations internally
   * to work around bugs in some JS interpreters.
   */
  const safe_add = (x, y) => {
    const lsw = (x & 0xFFFF) + (y & 0xFFFF);
    const msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
  };

  /**
   * Bitwise rotate a 32-bit number to the left.
   */
  const rol = (num, cnt) => (num << cnt) | (num >>> (32 - cnt));

  /**
   * Convert a string to an array of little-endian words
   * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
   */
  const str2binl = str => {
    const bin = Array();
    const mask = (1 << chrsz) - 1;
    for (let i = 0; i < str.length * chrsz; i += chrsz)
      bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
    return bin;
  };

  /**
   * Convert an array of little-endian words to a string
   */
  const binl2str = bin => {
    let str = "";
    const mask = (1 << chrsz) - 1;
    for (let i = 0; i < bin.length * 32; i += chrsz)
      str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & mask);
    return str;
  };

  /**
   * Convert an array of little-endian words to a hex string.
   */
  const binl2hex = binarray => {
    let str = "";
    for (let i = 0; i < binarray.length * 4; i++) {
      str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +
          hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF);
    }
    return str;
  };

  /**
   * Convert an array of little-endian words to a base-64 string
   */
  const binl2b64 = binarray => {
    let str = "";
    for (let i = 0; i < binarray.length * 4; i += 3) {
      const triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 0xFF) << 16)
          | (((binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8)
          | ((binarray[i + 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF);
      for (let j = 0; j < 4; j++) {
        if (i * 8 + j * 6 > binarray.length * 32) str += b64pad;
        else str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
      }
    }
    return str;
  };

  /**
   * Calculate the MD4 of an array of little-endian words, and a bit length
   */
  const core_md4 = (x, len) => {

    x[len >> 5] |= 0x80 << (len % 32);
    x[(((len + 64) >>> 9) << 4) + 14] = len;
    let a = 1732584193;
    let b = -271733879;
    let c = -1732584194;
    let d = 271733878;

    for (let i = 0; i < x.length; i += 16) {

      const olda = a;
      const oldb = b;
      const oldc = c;
      const oldd = d;

      a = md4_ff(a, b, c, d, x[i], 3);
      d = md4_ff(d, a, b, c, x[i + 1], 7);
      c = md4_ff(c, d, a, b, x[i + 2], 11);
      b = md4_ff(b, c, d, a, x[i + 3], 19);
      a = md4_ff(a, b, c, d, x[i + 4], 3);
      d = md4_ff(d, a, b, c, x[i + 5], 7);
      c = md4_ff(c, d, a, b, x[i + 6], 11);
      b = md4_ff(b, c, d, a, x[i + 7], 19);
      a = md4_ff(a, b, c, d, x[i + 8], 3);
      d = md4_ff(d, a, b, c, x[i + 9], 7);
      c = md4_ff(c, d, a, b, x[i + 10], 11);
      b = md4_ff(b, c, d, a, x[i + 11], 19);
      a = md4_ff(a, b, c, d, x[i + 12], 3);
      d = md4_ff(d, a, b, c, x[i + 13], 7);
      c = md4_ff(c, d, a, b, x[i + 14], 11);
      b = md4_ff(b, c, d, a, x[i + 15], 19);

      a = md4_gg(a, b, c, d, x[i], 3);
      d = md4_gg(d, a, b, c, x[i + 4], 5);
      c = md4_gg(c, d, a, b, x[i + 8], 9);
      b = md4_gg(b, c, d, a, x[i + 12], 13);
      a = md4_gg(a, b, c, d, x[i + 1], 3);
      d = md4_gg(d, a, b, c, x[i + 5], 5);
      c = md4_gg(c, d, a, b, x[i + 9], 9);
      b = md4_gg(b, c, d, a, x[i + 13], 13);
      a = md4_gg(a, b, c, d, x[i + 2], 3);
      d = md4_gg(d, a, b, c, x[i + 6], 5);
      c = md4_gg(c, d, a, b, x[i + 10], 9);
      b = md4_gg(b, c, d, a, x[i + 14], 13);
      a = md4_gg(a, b, c, d, x[i + 3], 3);
      d = md4_gg(d, a, b, c, x[i + 7], 5);
      c = md4_gg(c, d, a, b, x[i + 11], 9);
      b = md4_gg(b, c, d, a, x[i + 15], 13);

      a = md4_hh(a, b, c, d, x[i], 3);
      d = md4_hh(d, a, b, c, x[i + 8], 9);
      c = md4_hh(c, d, a, b, x[i + 4], 11);
      b = md4_hh(b, c, d, a, x[i + 12], 15);
      a = md4_hh(a, b, c, d, x[i + 2], 3);
      d = md4_hh(d, a, b, c, x[i + 10], 9);
      c = md4_hh(c, d, a, b, x[i + 6], 11);
      b = md4_hh(b, c, d, a, x[i + 14], 15);
      a = md4_hh(a, b, c, d, x[i + 1], 3);
      d = md4_hh(d, a, b, c, x[i + 9], 9);
      c = md4_hh(c, d, a, b, x[i + 5], 11);
      b = md4_hh(b, c, d, a, x[i + 13], 15);
      a = md4_hh(a, b, c, d, x[i + 3], 3);
      d = md4_hh(d, a, b, c, x[i + 11], 9);
      c = md4_hh(c, d, a, b, x[i + 7], 11);
      b = md4_hh(b, c, d, a, x[i + 15], 15);

      a = safe_add(a, olda);
      b = safe_add(b, oldb);
      c = safe_add(c, oldc);
      d = safe_add(d, oldd);
    }

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

  };

  /**
   * These functions implement the basic operation for each round of the
   * algorithm.
   */
  const md4_cmn = (q, a, b, x, s, t) => safe_add(
      rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);

  const md4_ff = (a, b, c, d, x, s) => md4_cmn(
      (b & c) | ((~b) & d), a, 0, x, s, 0);

  const md4_gg = (a, b, c, d, x, s) => md4_cmn(
      (b & c) | (b & d) | (c & d), a, 0, x, s, 1518500249);

  const md4_hh = (a, b, c, d, x, s) => md4_cmn(
      b ^ c ^ d, a, 0, x, s, 1859775393);

  /**
   * Calculate the HMAC-MD4, of a key and some data
   */
  const core_hmac_md4 = (key, data) => {

    let bkey = str2binl(key);
    if (bkey.length > 16) {
      bkey = core_md4(bkey, key.length * chrsz)
    }

    const ipad = Array(16);
    const opad = Array(16);

    for (let i = 0; i < 16; i++) {
      ipad[i] = bkey[i] ^ 0x36363636;
      opad[i] = bkey[i] ^ 0x5C5C5C5C;
    }
    const hash = core_md4(
        ipad.concat(str2binl(data)), 512 + data.length * chrsz);

    return core_md4(opad.concat(hash), 512 + 128);
  };

  /**
   * These are the functions you'll usually want to call
   */
  return {
    hex_md4: s => binl2hex(core_md4(str2binl(s), s.length * chrsz)),
    b64_md4: s => binl2b64(core_md4(str2binl(s), s.length * chrsz)),
    str_md4: s => binl2str(core_md4(str2binl(s), s.length * chrsz)),
    hex_hmac_md4: (key, data) => binl2hex(core_hmac_md4(key, data)),
    b64_hmac_md4: (key, data) => binl2b64(core_hmac_md4(key, data)),
    str_hmac_md4: (key, data) => binl2str(core_hmac_md4(key, data)),
  };

};

const md4 = md4func();
console.log(md4.hex_md4('Rosetta Code'));


using Nettle

msg = "Rosetta Code"

h = HashState(MD4)
update!(h, msg)
h = hexdigest!(h)

println("\"", msg, "\" => ", h)


// version 1.0.6

import java.security.MessageDigest

class MD4() : MessageDigest("MD4"), Cloneable {
    private val blockLength = 64
    private var context = IntArray(4)
    private var count = 0L
    private var buffer = ByteArray(blockLength)
    private var x = IntArray(16)

    init {
        engineReset()
    }

    private constructor(md: MD4): this() {
        context = md.context.clone()
        buffer = md.buffer.clone()
        count = md.count
    }

    override fun clone(): Any = MD4(this)

    override fun engineReset() {
        context[0] = 0x67452301
        context[1] = 0xefcdab89.toInt()
        context[2] = 0x98badcfe.toInt()
        context[3] = 0x10325476
        count = 0L
        for (i in 0 until blockLength) buffer[i] = 0
    }

    override fun engineUpdate(b: Byte) {
        val i = (count % blockLength).toInt()
        count++
        buffer[i] = b
        if (i == blockLength - 1) transform(buffer, 0)
    }

    override fun engineUpdate(input: ByteArray, offset: Int, len: Int) {
        if (offset < 0 || len < 0 || offset.toLong() + len > input.size.toLong())
            throw ArrayIndexOutOfBoundsException()
        var bufferNdx = (count % blockLength).toInt()
        count += len
        val partLen = blockLength - bufferNdx
        var i = 0
        if (len >= partLen) {
            System.arraycopy(input, offset, buffer, bufferNdx, partLen)
            transform(buffer, 0)
            i = partLen
            while (i + blockLength - 1 < len) {
                transform(input, offset + i)
                i += blockLength
            }
            bufferNdx = 0
        }
        if (i < len) System.arraycopy(input, offset + i, buffer, bufferNdx, len - i)
    }

    override fun engineDigest(): ByteArray {
        val bufferNdx = (count % blockLength).toInt()
        val padLen = if (bufferNdx < 56) 56 - bufferNdx else 120 - bufferNdx
        val tail = ByteArray(padLen + 8)
        tail[0] = 0x80.toByte()
        for (i in 0..7) tail[padLen + i] = ((count * 8) ushr (8 * i)).toByte()
        engineUpdate(tail, 0, tail.size)
        val result = ByteArray(16)
        for (i in 0..3)
            for (j in 0..3)
                result[i * 4 + j] = (context[i] ushr (8 * j)).toByte()
        engineReset()
        return result
    }

    private fun transform (block: ByteArray, offset: Int) {
        var offset2 = offset
        for (i in 0..15)
            x[i] = ((block[offset2++].toInt() and 0xff)       ) or
                   ((block[offset2++].toInt() and 0xff) shl 8 ) or
                   ((block[offset2++].toInt() and 0xff) shl 16) or
                   ((block[offset2++].toInt() and 0xff) shl 24)

        var a = context[0]
        var b = context[1]
        var c = context[2]
        var d = context[3]

        a = ff(a, b, c, d, x[ 0],  3)
        d = ff(d, a, b, c, x[ 1],  7)
        c = ff(c, d, a, b, x[ 2], 11)
        b = ff(b, c, d, a, x[ 3], 19)
        a = ff(a, b, c, d, x[ 4],  3)
        d = ff(d, a, b, c, x[ 5],  7)
        c = ff(c, d, a, b, x[ 6], 11)
        b = ff(b, c, d, a, x[ 7], 19)
        a = ff(a, b, c, d, x[ 8],  3)
        d = ff(d, a, b, c, x[ 9],  7)
        c = ff(c, d, a, b, x[10], 11)
        b = ff(b, c, d, a, x[11], 19)
        a = ff(a, b, c, d, x[12],  3)
        d = ff(d, a, b, c, x[13],  7)
        c = ff(c, d, a, b, x[14], 11)
        b = ff(b, c, d, a, x[15], 19)

        a = gg(a, b, c, d, x[ 0],  3)
        d = gg(d, a, b, c, x[ 4],  5)
        c = gg(c, d, a, b, x[ 8],  9)
        b = gg(b, c, d, a, x[12], 13)
        a = gg(a, b, c, d, x[ 1],  3)
        d = gg(d, a, b, c, x[ 5],  5)
        c = gg(c, d, a, b, x[ 9],  9)
        b = gg(b, c, d, a, x[13], 13)
        a = gg(a, b, c, d, x[ 2],  3)
        d = gg(d, a, b, c, x[ 6],  5)
        c = gg(c, d, a, b, x[10],  9)
        b = gg(b, c, d, a, x[14], 13)
        a = gg(a, b, c, d, x[ 3],  3)
        d = gg(d, a, b, c, x[ 7],  5)
        c = gg(c, d, a, b, x[11],  9)
        b = gg(b, c, d, a, x[15], 13)

        a = hh(a, b, c, d, x[ 0],  3)
        d = hh(d, a, b, c, x[ 8],  9)
        c = hh(c, d, a, b, x[ 4], 11)
        b = hh(b, c, d, a, x[12], 15)
        a = hh(a, b, c, d, x[ 2],  3)
        d = hh(d, a, b, c, x[10],  9)
        c = hh(c, d, a, b, x[ 6], 11)
        b = hh(b, c, d, a, x[14], 15)
        a = hh(a, b, c, d, x[ 1],  3)
        d = hh(d, a, b, c, x[ 9],  9)
        c = hh(c, d, a, b, x[ 5], 11)
        b = hh(b, c, d, a, x[13], 15)
        a = hh(a, b, c, d, x[ 3],  3)
        d = hh(d, a, b, c, x[11],  9)
        c = hh(c, d, a, b, x[ 7], 11)
        b = hh(b, c, d, a, x[15], 15)

        context[0] += a
        context[1] += b
        context[2] += c
        context[3] += d
    }

    private fun ff(a: Int, b: Int, c: Int, d: Int, x: Int, s: Int): Int {
        val t = a + ((b and c) or (b.inv() and d)) + x
        return (t shl s) or (t ushr (32 - s))
    }

    private fun gg(a: Int, b: Int, c: Int, d: Int, x: Int, s: Int): Int {
        val t = a + ((b and (c or d)) or (c and d)) + x + 0x5a827999
        return (t shl s) or (t ushr (32 - s))
    }

    private fun hh(a: Int, b: Int, c: Int, d: Int, x: Int, s: Int): Int {
        val t = a + (b xor c xor d) + x + 0x6ed9eba1
        return (t shl s) or (t ushr (32 - s))
    }
}

fun main(args: Array<String>) {
    val text  = "Rosetta Code"
    val bytes = text.toByteArray(Charsets.US_ASCII)
    val md: MessageDigest = MD4()
    val digest = md.digest(bytes)
    for (byte in digest) print("%02x".format(byte))
    println()
}


#!/usr/bin/lua

require "crypto"

print(crypto.digest("MD4", "Rosetta Code"))


Hash["Rosetta Code", "MD4", "HexString"]


import strutils

const MD4Len = 16

proc MD4(d: cstring, n: culong, md: cstring = nil): cstring {.cdecl, dynlib: "libssl.so", importc.}

proc MD4(s: string): string =
  result = ""
  var s = MD4(s.cstring, s.len.culong)
  for i in 0 ..< MD4Len:
    result.add s[i].BiggestInt.toHex(2).toLower

echo MD4("Rosetta Code")


#include <pari/pari.h>
#include <openssl/md4.h>

#define HEX(x)  (((x) < 10)? (x)+'0': (x)-10+'a')

/*
 * PARI/GP func: MD4 hash
 *
 * gp code: install("plug_md4", "s", "MD4", "<library path>");
 */
GEN plug_md4(char *text)
{
  char md[MD4_DIGEST_LENGTH];
  char hash[sizeof(md) * 2 + 1];
  int i;

  MD4((unsigned char*)text, strlen(text), (unsigned char*)md);

  for (i = 0; i < sizeof(md); i++) {
    hash[i+i]   = HEX((md[i] >> 4) & 0x0f);
    hash[i+i+1] = HEX(md[i] & 0x0f);
  }

  hash[sizeof(md) * 2] = 0;

  return strtoGENstr(hash);
}


--
-- demo\rosetta\md4.exw
-- ====================
--
-- Non-optimised. If there is a genuine need for something faster, I can give #ilASM a bash.
-- MD4 is an obsolete hash function that computes a 128-bit message digest that sometimes appears in obsolete protocols.
-- Even the replacement, MD5 is now considered severly comprimised.
--
without js -- (allocate/poke/peek)
function r32(atom a)
    if a<0 then a+=#100000000 end if
    return remainder(a,#100000000)
end function

function rol(atom word, integer bits)
-- left rotate the bits of a 32-bit number by the specified number of bits
    word = r32(word)    -- trim to a 32-bit uint again
    return r32(word*power(2,bits))+floor(word/power(2,32-bits))
end function

function f(atom x,y,z)
    return or_bits(and_bits(x,y),and_bits(not_bits(x),z))
end function

function g(atom x,y,z)
    return or_all({r32(and_bits(x,y)),and_bits(x,z),and_bits(y,z)})
end function

function h(atom x,y,z)
    return xor_bits(r32(xor_bits(x,y)),z)
end function

function md4(sequence data)
    integer bytes_to_add = 64-remainder(length(data)+9,64)
    if bytes_to_add=64 then bytes_to_add = 0 end if
    data = data&#80&repeat(0,bytes_to_add)&
           int_to_bytes(length(data)*8,8)

    atom a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476

    atom m64 = allocate(64,true)
    integer i
    for x=1 to length(data)-1 by 64 do
        poke(m64,data[x..x+63])
        sequence z = peek4u({m64,16})
        atom a2 = a, b2 = b, c2 = c, d2 = d
        for i=0 to 12 by 4 do
            a = rol(a + f(b, c, d) + z[i+1],  3)
            d = rol(d + f(a, b, c) + z[i+2],  7)
            c = rol(c + f(d, a, b) + z[i+3], 11)
            b = rol(b + f(c, d, a) + z[i+4], 19)
        end for
        for i=1 to 4 do
            a = rol(a + g(b, c, d) + z[i+0]  + 0x5a827999,  3)
            d = rol(d + g(a, b, c) + z[i+4]  + 0x5a827999,  5)
            c = rol(c + g(d, a, b) + z[i+8]  + 0x5a827999,  9)
            b = rol(b + g(c, d, a) + z[i+12] + 0x5a827999, 13)
        end for
        for j=1 to 4 do
            i = {1, 3, 2, 4}[j]
            a = rol(a + h(b, c, d) + z[i+0]  + 0x6ed9eba1,  3)
            d = rol(d + h(a, b, c) + z[i+8]  + 0x6ed9eba1,  9)
            c = rol(c + h(d, a, b) + z[i+4]  + 0x6ed9eba1, 11)
            b = rol(b + h(c, d, a) + z[i+12] + 0x6ed9eba1, 15)
        end for
        a = r32(a+a2)
        b = r32(b+b2)
        c = r32(c+c2)
        d = r32(d+d2)
    end for
    poke4(m64,{a,b,c,d})
    return peek({m64,16})
end function

function hexify(sequence s)
    for i=1 to length(s) do
        s[i] = sprintf("%02X",s[i])
    end for
    return join(s,"")
end function

?hexify(md4("Rosetta Code"))

{} = wait_key()


import hashlib
print hashlib.new("md4",raw_input().encode('utf-16le')).hexdigest().upper()


#lang racket
(require (planet soegaard/digest:1:2/digest))
(md4 #"Rosetta Code")


require 'openssl'
puts OpenSSL::Digest::MD4.hexdigest('Rosetta Code')


// MD4, based on RFC 1186 and RFC 1320.
//
// https://www.ietf.org/rfc/rfc1186.txt
// https://tools.ietf.org/html/rfc1320
//

use std::fmt::Write;
use std::mem;

// Let not(X) denote the bit-wise complement of X.
// Let X v Y denote the bit-wise OR of X and Y.
// Let X xor Y denote the bit-wise XOR of X and Y.
// Let XY denote the bit-wise AND of X and Y.

// f(X,Y,Z)  =  XY v not(X)Z
fn f(x: u32, y: u32, z: u32) -> u32 {
    (x & y) | (!x & z)
}

// g(X,Y,Z)  =  XY v XZ v YZ
fn g(x: u32, y: u32, z: u32) -> u32 {
    (x & y) | (x & z) | (y & z)
}

// h(X,Y,Z)  =  X xor Y xor Z
fn h(x: u32, y: u32, z: u32) -> u32 {
    x ^ y ^ z
}

// Round 1 macro
// Let [A B C D i s] denote the operation
//   A = (A + f(B,C,D) + X[i]) <<< s
macro_rules! md4round1 {
    ( $a:expr, $b:expr, $c:expr, $d:expr, $i:expr, $s:expr, $x:expr) => {
        {
            // Rust defaults to non-overflowing arithmetic, so we need to specify wrapping add.
            $a = ($a.wrapping_add( f($b, $c, $d) ).wrapping_add( $x[$i] ) ).rotate_left($s);
        }
    };
}

// Round 2 macro
// Let [A B C D i s] denote the operation
//   A = (A + g(B,C,D) + X[i] + 5A827999) <<< s .
macro_rules! md4round2 {
    ( $a:expr, $b:expr, $c:expr, $d:expr, $i:expr, $s:expr, $x:expr) => {
        {
            $a = ($a.wrapping_add( g($b, $c, $d)).wrapping_add($x[$i]).wrapping_add(0x5a827999_u32)).rotate_left($s);
        }
    };
}

// Round 3 macro
// Let [A B C D i s] denote the operation
//   A = (A + h(B,C,D) + X[i] + 6ED9EBA1) <<< s .
macro_rules! md4round3 {
    ( $a:expr, $b:expr, $c:expr, $d:expr, $i:expr, $s:expr, $x:expr) => {
        {
            $a = ($a.wrapping_add(h($b, $c, $d)).wrapping_add($x[$i]).wrapping_add(0x6ed9eba1_u32)).rotate_left($s);
        }
    };
}

fn convert_byte_vec_to_u32(mut bytes: Vec<u8>) -> Vec<u32> {

    bytes.shrink_to_fit();
    let num_bytes = bytes.len();
    let num_words = num_bytes / 4;
    unsafe {
        let words = Vec::from_raw_parts(bytes.as_mut_ptr() as *mut u32, num_words, num_words);
        mem::forget(bytes);
        words
    }
}

// Returns a 128-bit MD4 hash as an array of four 32-bit words.
// Based on RFC 1186 from https://www.ietf.org/rfc/rfc1186.txt
fn md4<T: Into<Vec<u8>>>(input: T) -> [u32; 4] {

    let mut bytes = input.into().to_vec();
    let initial_bit_len = (bytes.len() << 3) as u64;

    // Step 1. Append padding bits
    // Append one '1' bit, then append 0 ≤ k < 512 bits '0', such that the resulting message
    // length in bis is congruent to 448 (mod 512).
    // Since our message is in bytes, we use one byte with a set high-order bit (0x80) plus
    // a variable number of zero bytes.

    // Append zeros
    // Number of padding bytes needed is 448 bits (56 bytes) modulo 512 bits (64 bytes)
    bytes.push(0x80_u8);
    while (bytes.len() % 64) != 56 {
        bytes.push(0_u8);
    }

    // Everything after this operates on 32-bit words, so reinterpret the buffer.
    let mut w = convert_byte_vec_to_u32(bytes);

    // Step 2. Append length
    // A 64-bit representation of b (the length of the message before the padding bits were added)
    // is appended to the result of the previous step, low-order bytes first.
    w.push(initial_bit_len as u32); // Push low-order bytes first
    w.push((initial_bit_len >> 32) as u32);

    // Step 3. Initialize MD buffer
    let mut a = 0x67452301_u32;
    let mut b = 0xefcdab89_u32;
    let mut c = 0x98badcfe_u32;
    let mut d = 0x10325476_u32;

    // Step 4. Process message in 16-word blocks
    let n = w.len();
    for i in 0..n / 16 {

        // Select the next 512-bit (16-word) block to process.
        let x = &w[i * 16..i * 16 + 16];

        let aa = a;
        let bb = b;
        let cc = c;
        let dd = d;

        // [Round 1]
        md4round1!(a, b, c, d, 0, 3, x);  // [A B C D 0 3]
        md4round1!(d, a, b, c, 1, 7, x);  // [D A B C 1 7]
        md4round1!(c, d, a, b, 2, 11, x); // [C D A B 2 11]
        md4round1!(b, c, d, a, 3, 19, x); // [B C D A 3 19]
        md4round1!(a, b, c, d, 4, 3, x);  // [A B C D 4 3]
        md4round1!(d, a, b, c, 5, 7, x);  // [D A B C 5 7]
        md4round1!(c, d, a, b, 6, 11, x); // [C D A B 6 11]
        md4round1!(b, c, d, a, 7, 19, x); // [B C D A 7 19]
        md4round1!(a, b, c, d, 8, 3, x);  // [A B C D 8 3]
        md4round1!(d, a, b, c, 9, 7, x);  // [D A B C 9 7]
        md4round1!(c, d, a, b, 10, 11, x);// [C D A B 10 11]
        md4round1!(b, c, d, a, 11, 19, x);// [B C D A 11 19]
        md4round1!(a, b, c, d, 12, 3, x); // [A B C D 12 3]
        md4round1!(d, a, b, c, 13, 7, x); // [D A B C 13 7]
        md4round1!(c, d, a, b, 14, 11, x);// [C D A B 14 11]
        md4round1!(b, c, d, a, 15, 19, x);// [B C D A 15 19]

        // [Round 2]
        md4round2!(a, b, c, d, 0, 3, x);  //[A B C D 0  3]
        md4round2!(d, a, b, c, 4, 5, x);  //[D A B C 4  5]
        md4round2!(c, d, a, b, 8, 9, x);  //[C D A B 8  9]
        md4round2!(b, c, d, a, 12, 13, x);//[B C D A 12 13]
        md4round2!(a, b, c, d, 1, 3, x);  //[A B C D 1  3]
        md4round2!(d, a, b, c, 5, 5, x);  //[D A B C 5  5]
        md4round2!(c, d, a, b, 9, 9, x);  //[C D A B 9  9]
        md4round2!(b, c, d, a, 13, 13, x);//[B C D A 13 13]
        md4round2!(a, b, c, d, 2, 3, x);  //[A B C D 2  3]
        md4round2!(d, a, b, c, 6, 5, x);  //[D A B C 6  5]
        md4round2!(c, d, a, b, 10, 9, x); //[C D A B 10 9]
        md4round2!(b, c, d, a, 14, 13, x);//[B C D A 14 13]
        md4round2!(a, b, c, d, 3, 3, x);  //[A B C D 3  3]
        md4round2!(d, a, b, c, 7, 5, x);  //[D A B C 7  5]
        md4round2!(c, d, a, b, 11, 9, x); //[C D A B 11 9]
        md4round2!(b, c, d, a, 15, 13, x);//[B C D A 15 13]

        // [Round 3]
        md4round3!(a, b, c, d, 0, 3, x);  //[A B C D 0  3]
        md4round3!(d, a, b, c, 8, 9, x);  //[D A B C 8  9]
        md4round3!(c, d, a, b, 4, 11, x); //[C D A B 4  11]
        md4round3!(b, c, d, a, 12, 15, x);//[B C D A 12 15]
        md4round3!(a, b, c, d, 2, 3, x);  //[A B C D 2  3]
        md4round3!(d, a, b, c, 10, 9, x); //[D A B C 10 9]
        md4round3!(c, d, a, b, 6, 11, x); //[C D A B 6  11]
        md4round3!(b, c, d, a, 14, 15, x);//[B C D A 14 15]
        md4round3!(a, b, c, d, 1, 3, x);  //[A B C D 1  3]
        md4round3!(d, a, b, c, 9, 9, x);  //[D A B C 9  9]
        md4round3!(c, d, a, b, 5, 11, x); //[C D A B 5  11]
        md4round3!(b, c, d, a, 13, 15, x);//[B C D A 13 15]
        md4round3!(a, b, c, d, 3, 3, x);  //[A B C D 3  3]
        md4round3!(d, a, b, c, 11, 9, x); //[D A B C 11 9]
        md4round3!(c, d, a, b, 7, 11, x); //[C D A B 7  11]
        md4round3!(b, c, d, a, 15, 15, x);//[B C D A 15 15]

        a = a.wrapping_add(aa);
        b = b.wrapping_add(bb);
        c = c.wrapping_add(cc);
        d = d.wrapping_add(dd);
    }

    // Step 5. Output
    // The message digest produced as output is A, B, C, D. That is, we begin with the low-order
    // byte of A, and end with the high-order byte of D.
    [u32::from_be(a), u32::from_be(b), u32::from_be(c), u32::from_be(d)]
}

fn digest_to_str(digest: &[u32]) -> String {
    let mut s = String::new();
    for &word in digest {
        write!(&mut s, "{:08x}", word).unwrap();
    }
    s
}

fn main() {
    let val = "Rosetta Code";
    println!("md4(\"{}\") = {}", val, digest_to_str(&md4(val)));
}


import org.bouncycastle.crypto.digests.MD4Digest

object RosettaRIPEMD160 extends App {
  val (raw, messageDigest) = ("Rosetta Code".getBytes("US-ASCII"), new MD4Digest())
  messageDigest.update(raw, 0, raw.length)
  val out = Array.fill[Byte](messageDigest.getDigestSize())(0)
  messageDigest.doFinal(out, 0)

  assert(out.map("%02x".format(_)).mkString == "a52bcfc6a0d0d300cdc5ddbfbefe478b")
  import scala.compat.Platform.currentTime
  println(s"Successfully completed without errors. [total ${currentTime - executionStart} ms]")
}


$ include "seed7_05.s7i";
  include "msgdigest.s7i";

const proc: main is func
  begin
    writeln(hex(md4("Rosetta Code")));
  end func;


var digest = frequire('Digest::MD4');
say digest.md4_hex('Rosetta Code');


package require md4

# Use -hex option for hexadecimal output instead of binary
puts [md4::md4 -hex "Rosetta Code"]


import "/fmt" for Fmt

var toBytes = Fn.new { |val|
    var bytes = List.filled(4, 0)
    bytes[0] = val         & 255
    bytes[1] = (val >> 8)  & 255
    bytes[2] = (val >> 16) & 255
    bytes[3] = (val >> 24) & 255
    return bytes
}

var toInt = Fn.new { |bytes| bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24 }

var md4 = Fn.new { |initMsg|
    var f = Fn.new { |x, y, z| (x & y) | (~x & z) }
    var g = Fn.new { |x, y, z| (x & y) | (x & z) | (y & z) }
    var h = Fn.new { |x, y, z| x ^ y ^ z }
    var r = Fn.new { |v, s| (v << s) | (v >> (32 - s)) }

    var a = 0x67452301
    var b = 0xefcdab89
    var c = 0x98badcfe
    var d = 0x10325476
    var initBytes = initMsg.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 = toBytes.call(initLen * 8)
    for (i in newLen...newLen+4) msg[i] = lenBits[i-newLen]
    var extraBits = toBytes.call(initLen >> 29)
    for (i in newLen+4...newLen+8) msg[i] = extraBits[i-newLen-4]
    var offset = 0
    var x = List.filled(16, 0)
    while (offset < newLen) {
        for (i in 0...16) x[i] = toInt.call(msg[offset+i*4...offset + i*4 + 4])
        var a2 = a
        var b2 = b
        var c2 = c
        var d2 = d
        for (i in [0, 4, 8, 12]) {
            a = r.call(a + f.call(b, c, d) + x[i+0],  3)
            d = r.call(d + f.call(a, b, c) + x[i+1],  7)
            c = r.call(c + f.call(d, a, b) + x[i+2], 11)
            b = r.call(b + f.call(c, d, a) + x[i+3], 19)
        }
        for (i in 0..3) {
            a = r.call(a + g.call(b, c, d) + x[i+0]  + 0x5a827999,  3)
            d = r.call(d + g.call(a, b, c) + x[i+4]  + 0x5a827999,  5)
            c = r.call(c + g.call(d, a, b) + x[i+8]  + 0x5a827999,  9)
            b = r.call(b + g.call(c, d, a) + x[i+12] + 0x5a827999, 13)
        }
        for (i in [0, 2, 1, 3]) {
            a = r.call(a + h.call(b, c, d) + x[i+0]  + 0x6ed9eba1,  3)
            d = r.call(d + h.call(a, b, c) + x[i+8]  + 0x6ed9eba1,  9)
            c = r.call(c + h.call(d, a, b) + x[i+4]  + 0x6ed9eba1, 11)
            b = r.call(b + h.call(c, d, a) + x[i+12] + 0x6ed9eba1, 15)
        }
        a = a + a2
        b = b + b2
        c = c + c2
        d = d + d2
        offset = offset + 64
    }
    var digest = List.filled(16, 0)
    var dBytes = toBytes.call(a)
    for (i in 0...4) digest[i] = dBytes[i]
    dBytes = toBytes.call(b)
    for (i in 0...4) digest[i+4] = dBytes[i]
    dBytes = toBytes.call(c)
    for (i in 0...4) digest[i+8] = dBytes[i]
    dBytes = toBytes.call(d)
    for (i in 0...4) digest[i+12] = dBytes[i]
    return digest
}

var strings = [
    "",
    "a",
    "abc",
    "message digest",
    "abcdefghijklmnopqrstuvwxyz",
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
    "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
    "Rosetta Code"
]

for (s in strings) {
    var digest = md4.call(s)
    Fmt.print("$s <== '$0s'", Fmt.v("xz", 2, digest, 0, "", ""), s)
}


      PROGRAM MAYA_DRIVER
      IMPLICIT NONE
!
! Local variables
!
      CHARACTER(80)  ::  haab_carry
      CHARACTER(80)  ::  long_carry
      CHARACTER(80)  ::  nightlord
      CHARACTER(80)  ::  tzolkin_carry
      INTEGER,DIMENSION(8) :: DAY, MONTH, YEAR
      INTEGER :: INDEX
      DATA YEAR /2071,2004,2012,2012,2019,2019,2020,2020/
      DATA MONTH /5,6,12,12,1,3,2,3/
      DATA DAY /16,19,18,21,19,27,29,01/
!  2071-05-16
!   2004-06-19
!   2012-12-18
!   2012-12-21
!   2019-01-19
!   2019-03-27
!   2020-02-29
!   2020-03-01
      DO INDEX = 1,8
!
          CALL MAYA_TIME(day(INDEX) , month(INDEX) , year(INDEX) , long_carry , haab_carry , tzolkin_carry ,       &
                       & nightlord)
          WRITE(6,20)day(INDEX),month(INDEX),year(INDEX),TRIM(tzolkin_carry),TRIM(haab_carry),TRIM(long_carry),TRIM(nightlord)
20    FORMAT(1X,I0,'-',I0,'-',I0,T12,A,T24,A,T38,A,T58,A)
      END DO
      STOP
      END PROGRAM MAYA_DRIVER
!
!   SUBROUTINE MAYA_TIME
    subroutine maya_time(day,month,year, long_carry,haab_carry, tzolkin_carry,nightlord)
    implicit none
    integer(kind=4), parameter :: startdate = 584283    ! Start of the Mayan Calendar in Julian days
    integer(kind=4), parameter :: kin = 1
    integer(kind=4), parameter :: winal = 20*kin
    integer(kind=4), parameter :: tun = winal*18
    integer(kind=4), parameter :: katun = tun*20
    integer(kind=4), parameter :: baktun = katun*20
    integer(kind=4), parameter :: piktun = baktun*20
    integer(kind=4), parameter :: longcount = baktun*20
!
    character(len=8), dimension(20) ,parameter :: tzolkin = &
                                             ["Imix'   ", "Ik´     ", "Ak´bal  ", "K´an    ", "Chikchan", "Kimi    ", &
                                              "Manik´  ", "Lamat   ", "Muluk   ", "Ok      ", "Chuwen  ", "Eb      ", &
                                              "Ben     ", "Hix     ", "Men     ", "K´ib´   ", "Kaban   ", "Etz´nab´", &
                                              "Kawak   ", "Ajaw    "]
    character(len=8), dimension(19) ,parameter :: haab = &
                                             ["Pop     ", "Wo´     ", "Sip     ", "Sotz´   ", "Sek     ", "Xul     ", &
                                              "Yaxk´in ", "Mol     ", "Ch´en   ", "Yax     ", "Sak´    ", "Keh     ", &
                                              "Mak     ", "K´ank´in", "Muwan   ", "Pax     ", "K´ayab  ", "Kumk´u  ", &
                                              "Wayeb´  "]
    character(len=20), dimension(9) ,parameter :: night_lords = &
                                             ["(G1) Xiuhtecuhtli   ", & ! ("Turquoise/Year/Fire Lord")
                                              "(G2) Tezcatlipoca   ", & ! ("Smoking Mirror")
                                              "(G3) Piltzintecuhtli", & ! ("Prince Lord")
                                              "(G4) Centeotl       ", & ! ("Maize God")
                                              "(G5) Mictlantecuhtli", & ! ("Underworld Lord")
                                              "(G6) Chalchiuhtlicue", & ! ("Jade Is Her Skirt")
                                              "(G7) Tlazolteotl    ", & ! ("Filth God[dess]")
                                              "(G8) Tepeyollotl    ", & ! ("Mountain Heart")
                                              "(G9) Tlaloc         "  ] ! (Rain God)
    integer(kind=4) :: day,month,year
    intent(in)      :: day,month,year
!
    integer(kind=4) :: j,l, numdays, keptdays
    integer(kind=4) :: kin_no, winal_no, tun_no, katun_no, baktun_no, longcount_no
    character(*) :: haab_carry, nightlord, tzolkin_carry, long_carry
    intent(inout) :: haab_carry, nightlord, tzolkin_carry, long_carry
    integer :: mo,da
!
    keptdays = julday(day,month,year)           ! Get the Julian date for selected date
    numdays = keptdays                          ! Keep for calcs later
!    Adjust from the beginning
    numdays = numdays-startdate                 ! Adjust the number of days from start of Mayan Calendar
    if (numdays .ge. longcount)then             ! We check if we have passed a longcount and need to adjust for a new start
        longcount_no = numdays/longcount
        print*, ' We have more than one longcount ',longcount_no
    endif
!
!   Calculate the longdate
    baktun_no = numdays/baktun
    numdays = numdays - (baktun_no*baktun)      ! Decrement days down by the number of baktuns
    katun_no = numdays/katun                    ! Get number of katuns
    numdays = numdays - (katun_no*katun)
    tun_no = numdays/tun
    numdays = numdays-(tun_no*tun)
    winal_no = numdays/winal
    numdays = numdays-(winal_no*winal)
    kin_no = numdays                                ! What is left is simply the days
    long_carry = ' '                                ! blank it out
    write(long_carry,'(4(i2.2,"."),I2.2)') baktun_no,katun_no,tun_no,winal_no,kin_no

!
!   OK. Now the longcount is done, let's calculate Tzolk´in, Haab´ & Nightlord (the calendar round)
!
    haab_carry = " "
    L = mod((keptdays+65),365)
    mo = (L/20)+1
    da = mod(l,20)
    if(da.ne.0)then
        write(haab_carry,'(i2,1x,a)') da,haab(mo)
    else
        write(haab_carry,'(a,1x,a)') 'Chum',haab(mo)
    endif
!
! Ok, Now let's calculate the Tzolk´in
! The calendar starts on the 4 Ahu
    tzolkin_carry = " "                     ! Total blank the carrier
    mo = mod((keptdays+16),20) + 1
    da = mod((keptdays+5),13) + 1
    write(tzolkin_carry,'(i2,1x,a)') da,tzolkin(mo)
!
!   Now let's have a look at the lords of the night
!   There are 9 lords of the night, let's assume that they start on the first day of the year
!
    numdays = keptdays -startdate           ! Elapsed Julian days since start of calendar
    J = mod(numdays,9)                      ! Number of days into this cycle
    if (j.eq.0) j = 9
    nightlord = night_lords(j)
    RETURN
    contains
!
    FUNCTION JULDAY( Id , Mm,  Iyyy)
      IMPLICIT NONE
!
! PARAMETER definitions
!
      INTEGER , PARAMETER  ::  IGREG = 15 + 31*(10 + 12*1582)
!
! Dummy arguments
!
      INTEGER  ::  Id , Iyyy , Mm
      INTEGER  ::  JULDAY
      INTENT (IN) Id , Iyyy , Mm
!
! Local variables
!
      INTEGER  ::  ja , jm , jy
!
      jy = Iyyy
      IF(jy == 0)STOP 'julday: there is no year zero'
      IF(jy < 0)jy = jy + 1
      IF(Mm > 2)THEN
         jm = Mm + 1
      ELSE
         jy = jy - 1
         jm = Mm + 13
      END IF
      JULDAY = 365*jy + INT(0.25D0*jy + 2000.D0) + INT(30.6001D0*jm) + Id + 1718995
      IF(Id + 31*(Mm + 12*Iyyy) >= IGREG)THEN
         ja = INT(0.01D0*jy)
         JULDAY = JULDAY + 2 - ja + INT(0.25D0*ja)
      END IF
      RETURN
          END FUNCTION JULDAY

    END SUBROUTINE maya_time


package main

import (
    "fmt"
    "strconv"
    "strings"
    "time"
)

var sacred = strings.Fields("Imix’ Ik’ Ak’bal K’an Chikchan Kimi Manik’ Lamat Muluk Ok Chuwen Eb Ben Hix Men K’ib’ Kaban Etz’nab’ Kawak Ajaw")

var civil = strings.Fields("Pop Wo’ Sip Sotz’ Sek Xul Yaxk’in Mol Ch’en Yax Sak’ Keh Mak K’ank’in Muwan’ Pax K’ayab Kumk’u Wayeb’")

var (
    date1 = time.Date(2012, time.December, 21, 0, 0, 0, 0, time.UTC)
    date2 = time.Date(2019, time.April, 2, 0, 0, 0, 0, time.UTC)
)

func tzolkin(date time.Time) (int, string) {
    diff := int(date.Sub(date1).Hours()) / 24
    rem := diff % 13
    if rem < 0 {
        rem = 13 + rem
    }
    var num int
    if rem <= 9 {
        num = rem + 4
    } else {
        num = rem - 9
    }
    rem = diff % 20
    if rem <= 0 {
        rem = 20 + rem
    }
    return num, sacred[rem-1]
}

func haab(date time.Time) (string, string) {
    diff := int(date.Sub(date2).Hours()) / 24
    rem := diff % 365
    if rem < 0 {
        rem = 365 + rem
    }
    month := civil[(rem+1)/20]
    last := 20
    if month == "Wayeb’" {
        last = 5
    }
    d := rem%20 + 1
    if d < last {
        return strconv.Itoa(d), month
    }
    return "Chum", month
}

func longCount(date time.Time) string {
    diff := int(date.Sub(date1).Hours()) / 24
    diff += 13 * 400 * 360
    baktun := diff / (400 * 360)
    diff %= 400 * 360
    katun := diff / (20 * 360)
    diff %= 20 * 360
    tun := diff / 360
    diff %= 360
    winal := diff / 20
    kin := diff % 20
    return fmt.Sprintf("%d.%d.%d.%d.%d", baktun, katun, tun, winal, kin)
}

func lord(date time.Time) string {
    diff := int(date.Sub(date1).Hours()) / 24
    rem := diff % 9
    if rem <= 0 {
        rem = 9 + rem
    }
    return fmt.Sprintf("G%d", rem)
}

func main() {
    const shortForm = "2006-01-02"
    dates := []string{
        "2004-06-19",
        "2012-12-18",
        "2012-12-21",
        "2019-01-19",
        "2019-03-27",
        "2020-02-29",
        "2020-03-01",
        "2071-05-16",
    }
    fmt.Println(" Gregorian   Tzolk’in        Haab’              Long           Lord of")
    fmt.Println("   Date       # Name       Day Month            Count         the Night")
    fmt.Println("----------   --------    -------------        --------------  ---------")
    for _, dt := range dates {
        date, _ := time.Parse(shortForm, dt)
        n, s := tzolkin(date)
        d, m := haab(date)
        lc := longCount(date)
        l := lord(date)
        fmt.Printf("%s   %2d %-8s %4s %-9s       %-14s     %s\n", dt, n, s, d, m, lc, l)
    }
}


require 'types/datetime'

NB. 1794214= (0 20 18 20 20#.13 0 0 0 0)-todayno 2012 12 21
longcount=: {{ rplc&' .'":0 20 18 20 20#:y+1794214 }}

tsolkin=: (cut {{)n
   Imix’   Ik’     Ak’bal    K’an    Chikchan
   Kimi    Manik’  Lamat     Muluk   Ok
   Chuwen  Eb      Ben       Hix     Men
   K’ib’   Kaban   Etz’nab’  Kawak   Ajaw
}}-.LF){{ (":1+13|y-4),' ',(20|y-7){::m }}

haab=:(cut {{)n
   Pop      Wo’       Sip     Sotz’   Sek      Xul
   Yaxk’in  Mol       Ch’en   Yax     Sak’     Keh
   Mak      K’ank’in  Muwan   Pax     K’ayab   Kumk’u
   Wayeb’
}}-.LF){{
  'M D'=.0 20#:365|y-143
  ({{ if.*y do.":y else.'Chum'end. }} D),' ',(M-0=D){::m
}}

round=: [:;:inv tsolkin;haab;'G',&":1+9|]

gmt=: >@(fmtDate;round;longcount)@todayno


using Dates

const Tzolk´in = [
"Imix´", "Ik´", "Ak´bal", "K´an", "Chikchan", "Kimi", "Manik´", "Lamat", "Muluk", "Ok",
"Chuwen", "Eb", "Ben", "Hix", "Men", "K´ib´", "Kaban", "Etz´nab´", "Kawak", "Ajaw"
]
const Haab´ = [
"Pop", "Wo´", "Sip", "Sotz´", "Sek", "Xul", "Yaxk´in", "Mol", "Ch´en", "Yax",
"Sak´", "Keh", "Mak", "K´ank´in", "Muwan", "Pax", "K´ayab", "Kumk´u", "Wayeb´"
]
const creationTzolk´in = Date(2012, 12, 21)
const zeroHaab´ = Date(2019, 4, 2)
daysperMayanmonth(month) = (month == "Wayeb´" ? 5 : 20)

function tzolkin(gregorian::Date)
    deltadays = (gregorian - creationTzolk´in).value
    rem = mod1(deltadays, 13)
    return string(rem <= 9 ? rem + 4 : rem - 9) * " " * Tzolk´in[mod1(deltadays, 20)]
end

function haab(gregorian::Date)
    rem = mod1((gregorian - zeroHaab´).value, 365)
    month = Haab´[(rem + 21) ÷ 20]
    dayofmonth = rem % 20 + 1
    return dayofmonth < daysperMayanmonth(month) ? "$dayofmonth $month" : "Chum $month"
end

function tolongdate(gregorian::Date)
    delta = (gregorian - creationTzolk´in).value + 13 * 360 * 400
    baktun = delta ÷ (360 * 400)
    delta %= (400 * 360)
    katun = delta ÷ (20 * 360)
    delta %= (20 * 360)
    tun = delta ÷ 360
    delta %= 360
    winal, kin = divrem(delta, 20)
    return mapreduce(x -> lpad(x, 3), *, [baktun, katun, tun, winal, kin])
end

nightlord(gregorian::Date) = "G$(mod1((gregorian - creationTzolk´in).value, 9))"

testdates = [
Date(1963, 11, 21), Date(2004, 06, 19), Date(2012, 12, 18), Date(2012, 12, 21),
Date(2019, 01, 19), Date(2019, 03, 27), Date(2020, 02, 29), Date(2020, 03, 01),
Date(2071, 5, 16), Date(2020, 2, 2)
]

println("Gregorian      Long Count       Tzolk´in  Haab´       Nightlord")
println("-----------------------------------------------------------------")
for date in testdates
    println(rpad(date,14), rpad(tolongdate(date), 18), rpad(tzolkin(date), 10),
        rpad(haab(date), 15), nightlord(date))
end


sacred = {"Imix\[CloseCurlyQuote]", "Ik\[CloseCurlyQuote]",
   "Ak\[CloseCurlyQuote]bal", "K\[CloseCurlyQuote]an", "Chikchan",
   "Kimi", "Manik\[CloseCurlyQuote]", "Lamat", "Muluk", "Ok",
   "Chuwen", "Eb", "Ben", "Hix", "Men",
   "K\[CloseCurlyQuote]ib\[CloseCurlyQuote]", "Kaban",
   "Etz\[CloseCurlyQuote]nab\[CloseCurlyQuote]", "Kawak", "Ajaw"};
civil = {"Pop", "Wo\[CloseCurlyQuote]", "Sip",
   "Sotz\[CloseCurlyQuote]", "Sek", "Xul", "Yaxk\[CloseCurlyQuote]in",
    "Mol", "Ch\[CloseCurlyQuote]en", "Yax", "Sak\[CloseCurlyQuote]",
   "Keh", "Mak", "K\[CloseCurlyQuote]ank\[CloseCurlyQuote]in",
   "Muwan\[CloseCurlyQuote]", "Pax", "K\[CloseCurlyQuote]ayab",
   "Kumk\[CloseCurlyQuote]u", "Wayeb\[CloseCurlyQuote]"};
date1 = {2012, 12, 21, 0, 0, 0};
date2 = {2019, 4, 2, 0, 0, 0};

ClearAll[Tzolkin]
Tzolkin[date_] := Module[{diff, rem, num},
  diff = QuantityMagnitude[DateDifference[date1, date], "Days"];
  rem = Mod[diff, 13];
  If[rem <= 9,
   num = rem + 4
   ,
   num = rem - 9
   ];
  rem = Mod[diff, 20, 1];
  ToString[num] <> " " <> sacred[[rem]]
  ]
ClearAll[Haab]
Haab[date_] := Module[{diff, rem, month, last, d},
  diff = QuantityMagnitude[DateDifference[date2, date], "Days"];
  rem = Mod[diff, 365];
  month = civil[[Floor[(rem + 1)/20] + 1]];
  last = 20;
  If[month == Last[civil],
   last = 5
   ];
  d = Mod[rem, 20] + 1;
  If[d < last,
   ToString[d] <> " " <> month
   ,
   "Chum " <> month
   ]
  ]
ClearAll[LongCount]
LongCount[date_] := Module[{diff, baktun, katun, tun, winal, kin},
  diff = QuantityMagnitude[DateDifference[date1, date], "Days"];
  diff += 13 400 360;
  {baktun, diff} = QuotientRemainder[diff, 400 360];
  {katun, diff} = QuotientRemainder[diff, 20 360];
  {tun, diff} = QuotientRemainder[diff, 360];
  {winal, kin} = QuotientRemainder[diff, 20];
  StringRiffle[ToString /@ {baktun, katun, tun, winal, kin}, "."]
  ]
ClearAll[LordOfTheNight]
LordOfTheNight[date_] := Module[{diff, rem},
  diff = QuantityMagnitude[DateDifference[date1, date], "Days"];
  rem = Mod[diff, 9, 1];
  "G" <> ToString[rem]
  ]
data = {{2004, 06, 19}, {2012, 12, 18}, {2012, 12, 21}, {2019, 01,
    19}, {2019, 03, 27}, {2020, 02, 29}, {2020, 03, 01}, {2071, 05,
    16}};
tzolkindata = Tzolkin /@ data;
haabdata = Haab /@ data;
longcountdata = LongCount /@ data;
lotndata = LordOfTheNight /@ data;
{DateObject /@ data, tzolkindata, haabdata, longcountdata, lotndata} // Transpose // Grid


import math, strformat, times

const

  Tzolk´in = ["Imix´", "Ik´", "Ak´bal", "K´an", "Chikchan", "Kimi", "Manik´", "Lamat", "Muluk", "Ok",
              "Chuwen", "Eb", "Ben", "Hix", "Men", "K´ib´", "Kaban", "Etz´nab´", "Kawak", "Ajaw"]

  Haab´ = ["Pop", "Wo´", "Sip", "Sotz´", "Sek", "Xul", "Yaxk´in", "Mol", "Ch´en", "Yax",
           "Sak´", "Keh", "Mak", "K´ank´in", "Muwan", "Pax", "K´ayab", "Kumk´u", "Wayeb´"]

let
  creationTzolk´in = initDateTime(21, mDec, 2012, 0, 0, 0, utc())
  zeroHaab´ = initDateTime(2, mApr, 2019, 0, 0, 0, utc())

func daysPerMayanMonth(month: string): int =
  if month == "Wayeb´": 5 else: 20

proc tzolkin(gregorian: DateTime): string =
  let deltaDays = (gregorian - creationTzolk´in).inDays
  let rem = floorMod(deltaDays, 13)
  result = $(if rem <= 9: rem + 4 else: rem - 9) & ' ' & Tzolk´in[floorMod(deltaDays - 1, 20)]

proc haab(gregorian: DateTime): string =
  let rem = floorMod((gregorian - zeroHaab´).inDays, 365)
  let month = Haab´[(rem + 1) div 20]
  let dayOfMonth = rem mod 20 + 1
  result = if dayOfMonth < daysPerMayanMonth(month): &"{dayOfMonth} {month}" else: &"Chum {month}"

proc toLongDate(gregorian: DateTime): string =
  var delta = (gregorian - creationTzolk´in).inDays + 13 * 360 * 400
  var baktun = delta div (360 * 400)
  delta = delta mod (400 * 360)
  let katun = delta div (20 * 360)
  delta = delta mod (20 * 360)
  let tun = delta div 360
  delta = delta mod 360
  let winal = delta div 20
  let kin = delta mod 20
  result = &"{baktun:2} {katun:2} {tun:2} {winal:2} {kin:2}"

proc nightLord(gregorian: DateTime): string =
  var rem = (gregorian - creationTzolk´in).inDays mod 9
  if rem <= 0: rem += 9
  result = 'G' & $rem

when isMainModule:

  let testDates = [initDateTime(21, mNov, 1963, 0, 0, 0, utc()),
                   initDateTime(19, mJun, 2004, 0, 0, 0, utc()),
                   initDateTime(18, mDec, 2012, 0, 0, 0, utc()),
                   initDateTime(21, mDec, 2012, 0, 0, 0, utc()),
                   initDateTime(19, mJan, 2019, 0, 0, 0, utc()),
                   initDateTime(27, mMar, 2019, 0, 0, 0, utc()),
                   initDateTime(29, mFeb, 2020, 0, 0, 0, utc()),
                   initDateTime(01, mMar, 2020, 0, 0, 0, utc()),
                   initDateTime(16, mMay, 2071, 0, 0, 0, utc()),
                   initDateTime(02, mfeb, 2020, 0, 0, 0, utc())]

echo "Gregorian      Long Count       Tzolk´in  Haab´       Nightlord"
echo "———————————————————————————————————————————————————————————————"
for date in testDates:
  let dateStr = date.format("YYYY-MM-dd")
  echo &"{dateStr:14} {date.toLongDate:16} {tzolkin(date):9} {haab(date):14} {nightLord(date)}"


use strict;
use warnings;
use utf8;
binmode STDOUT, ":utf8";
use Math::BaseArith;
use Date::Calc 'Delta_Days';

my @sacred = qw<Imix’ Ik’ Ak’bal K’an Chikchan Kimi Manik’ Lamat Muluk Ok
              Chuwen Eb Ben Hix Men K’ib’ Kaban Etz’nab’ Kawak Ajaw>;

my @civil = qw<Pop Wo’ Sip Sotz’ Sek Xul Yaxk’in Mol Ch’en Yax Sak’ Keh
             Mak K’ank’in Muwan’ Pax K’ayab Kumk’u Wayeb’>;

my %correlation = (
    'gregorian' => '2012-12-21',
    'round'     => [3,19,263,8],
    'long'      => 1872000,
);

sub mayan_calendar_round {
    my $date = shift;
    tzolkin($date), haab($date);
}

sub offset {
    my $date = shift;
    Delta_Days( split('-', $correlation{'gregorian'}), split('-', $date) );
}

sub haab {
    my $date  = shift;
    my $index = ($correlation{'round'}[2] + offset $date) % 365;
    my ($day, $month);
    if ($index > 360) {
        $day = $index - 360;
        $month = $civil[18];
        if ($day == 5) {
            $day = 'Chum';
            $month = $civil[0];
        }
    } else {
        $day = $index % 20;
        $month = $civil[int $index / 20];
        if ($day == 0) {
            $day = 'Chum';
            $month = $civil[int (1 + $index) / 20];
        }
    }
    $day, $month
}

sub tzolkin {
    my $date   = shift;
    my $offset = offset $date;
    1 + ($offset + $correlation{'round'}[0]) % 13,
    $sacred[($offset + $correlation{'round'}[1]) % 20]
}

sub lord {
    my $date = shift;
    1 + ($correlation{'round'}[3] + offset $date) % 9
}

sub mayan_long_count {
    my $date = shift;
    my $days = $correlation{'long'} + offset $date;
    encode($days, [20,20,20,18,20]);
}

print <<'EOH';
 Gregorian   Tzolk’in         Haab’             Long           Lord of
   Date       # Name       Day Month            Count         the Night
-----------------------------------------------------------------------
EOH

for my $date (<1961-10-06 2004-06-19 2012-12-18 2012-12-21 2019-01-19 2019-03-27 2020-02-29 2020-03-01 2071-05-16>) {
    printf "%10s   %2s %-9s %4s %-10s     %-14s     G%d\n",
      $date, mayan_calendar_round($date), join('.',mayan_long_count($date)), lord($date);
}


with javascript_semantics
include timedate.e

sequence sacred = split("Imix' Ik' Ak'bal K'an Chikchan Kimi Manik' Lamat Muluk Ok Chuwen Eb Ben Hix Men K'ib' Kaban Etz'nab' Kawak Ajaw"),
         civil = split("Pop Wo' Sip Sotz' Sek Xul Yaxk'in Mol Ch'en Yax Sak' Keh Mak K'ank'in Muwan' Pax K'ayab Kumk'u Wayeb'"),
         date1 = parse_date_string("21/12/2012",{"DD/MM/YYYY"}),
         date2 = parse_date_string("2/4/2019",{"DD/MM/YYYY"})

function tzolkin(integer diff)
    integer rem = mod(diff,13)
    if rem<0 then rem += 13 end if
    integer num = iff(rem<=9?rem+4:rem-9)
    rem = mod(diff,20)
    if rem<=0 then rem += 20 end if
    return {num, sacred[rem]}
end function

function haab(integer diff)
    integer rem = mod(diff,365)
    if rem<0 then rem += 365 end if
    string month = civil[floor((rem+1)/20)+1]
    integer last = iff(month="Wayeb'"?5:20),
            d = mod(rem,20) + 1
    return {iff(d<last?sprintf("%d",d):"Chum"), month}
end function

function longCount(integer diff)
    diff += 13 * 400 * 360
    integer baktun := floor(diff/(400*360))
    diff = mod(diff,400*360)
    integer katun := floor(diff/(20*360))
    diff = mod(diff,20*360)
    integer tun = floor(diff/360)
    diff = mod(diff,360)
    integer winal = floor(diff/20),
            kin = mod(diff,20)
    return sprintf("%d.%d.%d.%d.%d", {baktun, katun, tun, winal, kin})
end function

function lord(integer diff)
    integer rem = mod(diff,9)
    if rem<=0 then rem += 9 end if
    return sprintf("G%d", rem)
end function

constant dates = {"1961-10-06",
                  "1963-11-21",
                  "2004-06-19",
                  "2012-12-18",
                  "2012-12-21",
                  "2019-01-19",
                  "2019-03-27",
                  "2020-02-29",
                  "2020-03-01",
                  "2071-05-16",
                 },
         headers = """
 Gregorian   Tzolk'in        Haab'              Long           Lord of
   Date       # Name       Day Month            Count         the Night
----------   --------    -------------        --------------  ---------
"""

procedure main()
    printf(1,headers)
    for i=1 to length(dates) do
        string dt = dates[i]
        timedate td = parse_date_string(dt,{"YYYY-MM-DD"})
        integer diff1 = floor(timedate_diff(date1,td,DT_DAY) / (24*60*60)),
                diff2 = floor(timedate_diff(date2,td,DT_DAY) / (24*60*60))
        {integer n, string s} = tzolkin(diff1)
        string {d, m} = haab(diff2),
               lc := longCount(diff1),
               l := lord(diff1)
        printf(1,"%s   %2d %-8s %4s %-9s       %-14s     %s\n", {dt, n, s, d, m, lc, l})
    end for
end procedure
main()


import datetime

def g2m(date, gtm_correlation=True):
    """
    Translates Gregorian date into Mayan date, see
    https://rosettacode.org/wiki/Mayan_calendar

    Input arguments:

     date: string date in ISO-8601 format: YYYY-MM-DD
     gtm_correlation: GTM correlation to apply if True, Astronomical correlation otherwise (optional, True by default)

    Output arguments:

     long_date: Mayan date in Long Count system as string
     round_date: Mayan date in Calendar Round system as string
    """

    # define some parameters and names

    correlation = 584283 if gtm_correlation else 584285

    long_count_days = [144000, 7200, 360, 20, 1]

    tzolkin_months = ['Imix’', 'Ik’', 'Ak’bal', 'K’an', 'Chikchan', 'Kimi', 'Manik’', 'Lamat', 'Muluk', 'Ok', 'Chuwen',
                      'Eb', 'Ben', 'Hix', 'Men', 'K’ib’', 'Kaban', 'Etz’nab’', 'Kawak', 'Ajaw']  # tzolk'in

    haad_months = ['Pop', 'Wo’', 'Sip', 'Sotz’', 'Sek', 'Xul', 'Yaxk’in', 'Mol', 'Ch’en', 'Yax', 'Sak’', 'Keh', 'Mak',
                   'K’ank’in', 'Muwan', 'Pax', 'K’ayab', 'Kumk’u', 'Wayeb’']  # haab'

    gregorian_days = datetime.datetime.strptime(date, '%Y-%m-%d').toordinal()
    julian_days = gregorian_days + 1721425

    # 1. calculate long count date

    long_date = list()
    remainder = julian_days - correlation

    for days in long_count_days:

        result, remainder = divmod(remainder, days)
        long_date.append(int(result))

    long_date = '.'.join(['{:02d}'.format(d) for d in long_date])

    # 2. calculate round calendar date

    tzolkin_month = (julian_days + 16) % 20
    tzolkin_day = ((julian_days + 5) % 13) + 1

    haab_month = int(((julian_days + 65) % 365) / 20)
    haab_day = ((julian_days + 65) % 365) % 20
    haab_day = haab_day if haab_day else 'Chum'

    lord_number = (julian_days - correlation) % 9
    lord_number = lord_number if lord_number else 9

    round_date = f'{tzolkin_day} {tzolkin_months[tzolkin_month]} {haab_day} {haad_months[haab_month]} G{lord_number}'

    return long_date, round_date

if __name__ == '__main__':

    dates = ['2004-06-19', '2012-12-18', '2012-12-21', '2019-01-19', '2019-03-27', '2020-02-29', '2020-03-01']

    for date in dates:

        long, round = g2m(date)
        print(date, long, round)


my @sacred = <Imix’ Ik’ Ak’bal K’an Chikchan Kimi Manik’ Lamat Muluk Ok
              Chuwen Eb Ben Hix Men K’ib’ Kaban Etz’nab’ Kawak Ajaw>;

my @civil = <Pop Wo’ Sip Sotz’ Sek Xul Yaxk’in Mol Ch’en Yax Sak’ Keh
             Mak K’ank’in Muwan’ Pax K’ayab Kumk’u Wayeb’>;

my %correlation = :GMT({
    :gregorian(Date.new('2012-12-21')),
    :round([3,19,263,8]),
    :long(1872000)
});

sub mayan-calendar-round ($date) { .&tzolkin, .&haab given $date }

sub offset ($date, $factor = 'GMT') { Date.new($date) - %correlation{$factor}<gregorian> }

sub haab ($date, $factor = 'GMT') {
    my $index = (%correlation{$factor}<round>[2] + offset $date) % 365;
    my ($day, $month);
    if $index > 360 {
        $day = $index - 360;
        $month = @civil[18];
        if $day == 5 {
            $day = 'Chum';
            $month = @civil[0];
        }
    } else {
        $day = $index % 20;
        $month = @civil[$index div 20];
        if $day == 0 {
            $day = 'Chum';
            $month = @civil[(1 + $index) div 20];
        }
    }
    $day, $month
}

sub tzolkin ($date, $factor = 'GMT') {
    my $offset = offset $date;
    1 + ($offset + %correlation{$factor}<round>[0]) % 13,
    @sacred[($offset + %correlation{$factor}<round>[1]) % 20]
}

sub lord ($date, $factor = 'GMT') {
    'G' ~ 1 + (%correlation{$factor}<round>[3] + offset $date) % 9
}

sub mayan-long-count ($date, $factor = 'GMT') {
    my $days = %correlation{$factor}<long> + offset $date;
    reverse $days.polymod(20,18,20,20);
}

# HEADER
say ' Gregorian   Tzolk’in         Haab’             Long           Lord of ';
say '   Date       # Name       Day Month            Count         the Night';
say '-----------------------------------------------------------------------';

# DATES
<
1963-11-21
2004-06-19
2012-12-18
2012-12-21
2019-01-19
2019-03-27
2020-02-29
2020-03-01
2071-05-16
>.map: -> $date {
    printf "%10s   %2s %-9s %4s %-10s     %-14s %6s\n", Date.new($date),
      flat mayan-calendar-round($date), mayan-long-count($date).join('.'), lord($date);
}


import "/date" for Date
import "/fmt" for Fmt

var sacred = "Imix’ Ik’ Ak’bal K’an Chikchan Kimi Manik’ Lamat Muluk Ok Chuwen Eb Ben Hix Men K’ib’ Kaban Etz’nab’ Kawak Ajaw".split(" ")

var civil = "Pop Wo’ Sip Sotz’ Sek Xul Yaxk’in Mol Ch’en Yax Sak’ Keh Mak K’ank’in Muwan’ Pax K’ayab Kumk’u Wayeb’".split(" ")

var date1 = Date.new(2012, 12, 21)
var date2 = Date.new(2019, 4, 2)

var tzolkin = Fn.new { |date|
    var diff = (date - date1).days
    var rem = diff % 13
    if (rem < 0) rem = 13 + rem
    var num = (rem <= 9) ? rem + 4 : rem - 9
    rem = diff % 20
    if (rem <= 0) rem = 20 + rem
    return [num, sacred[rem-1]]
}

var haab = Fn.new { |date|
    var diff = (date - date2).days
    var rem = diff % 365
    if (rem < 0) rem = 365 + rem
    var month = civil[((rem+1)/20).floor]
    var last = (month == "Wayeb'") ? 5 : 20
    var d = rem%20 + 1
    if (d < last) return [d.toString, month]
    return ["Chum", month]
}

var longCount = Fn.new { |date|
    var diff = (date - date1).days
    diff = diff + 13*400*360
    var baktun = (diff/(400*360)).floor
    diff = diff % (400*360)
    var katun = (diff/(20 * 360)).floor
    diff = diff % (20*360)
    var tun = (diff/360).floor
    diff = diff % 360
    var winal = (diff/20).floor
    var kin = diff % 20
    return Fmt.swrite("$d.$d.$d.$d.$d", baktun, katun, tun, winal, kin)
}

var lord = Fn.new { |date|
    var diff = (date - date1).days
    var rem = diff % 9
    if (rem <= 0) rem = 9 + rem
    return Fmt.swrite("G$d", rem)
}

var dates = [
    "1961-10-06",
    "1963-11-21",
    "2004-06-19",
    "2012-12-18",
    "2012-12-21",
    "2019-01-19",
    "2019-03-27",
    "2020-02-29",
    "2020-03-01",
    "2071-05-16"
]
System.print(" Gregorian   Tzolk’in        Haab’              Long           Lord of")
System.print("   Date       # Name       Day Month            Count         the Night")
System.print("----------   --------    -------------        --------------  ---------")
Date.default = Date.isoDate
for (dt in dates) {
    var date = Date.parse(dt)
    var ns = tzolkin.call(date)
    var n = ns[0]
    var s = ns[1]
    var dm = haab.call(date)
    var d = dm[0]
    var m = dm[1]
    var lc = longCount.call(date)
    var l = lord.call(date)
    Fmt.lprint("$s   $2d $-8s $4s $-9s       $-14s     $s", [dt, n, s, d, m, lc, l])
}


var [const]
  sacred=T("Imix'","Ik'","Ak'bal","K'an","Chikchan","Kimi","Manik'","Lamat","Muluk","Ok",
           "Chuwen","Eb","Ben","Hix","Men","K'ib'","Kaban","Etz'nab'","Kawak","Ajaw"),
  civil=T("Pop","Wo'","Sip","Sotz'","Sek","Xul","Yaxk'in","Mol","Ch'en","Yax","Sak'","Keh",
          "Mak","K'ank'in","Muwan'","Pax","K'ayab","Kumk'u","Wayeb'"),
  Date=Time.Date,
  // correlation dates:
  Creation=T(2012, Date.December, 21),  // 13.0.0.0.0, Mayan day of creation
  OnePop=T(2019, Date.April, 2),	// 1 Pop in 2019
;

fcn haab(date){  // (y,m,d)-->("Chum"|Int,month name)
   diff:=Date.deltaDays(OnePop,date.xplode());	//--> signed int
   rem:=diff%365;
   if(rem<0) rem=365 + rem;
   month,last := civil[(rem+1)/20], 20;
   if(month==civil[-1]) last=5;
   d:=rem%20 + 1;
   if(d<last) return(d, month);
   return("Chum",month);
}

fcn tzolkin(date){ // (y,m,d)-->(Int,String)
   diff:=Date.deltaDays(Creation,date.xplode());	//--> signed int
   rem:=diff % 13;
   if(rem<0) rem=13 + rem;

   num:=( if(rem<=9) rem + 4 else rem - 9 );
   rem=diff % 20;
   if(rem<=0) rem=20 + rem;
   return(num, sacred[rem-1]);
}

fcn longCount(date){  // (y,m,d) --> (5 Ints)
   diff:=Date.deltaDays(Creation,date.xplode());	//--> signed int
   diff,baktun    := diff + 13*400*360, diff/(400*360);
   diff,katun     := diff % (400*360),  diff/(20*360);
   diff,tun       := diff % (20*360),   diff/360;
   diff,winal,kin := diff%360,          diff/20,       diff % 20;

   return(baktun, katun, tun, winal, kin)
}

fcn lord(date){  // (y,m,d) --> String
   diff:=Date.deltaDays(Creation,date.xplode());	//--> signed int
   rem:=diff % 9;
   if(rem<=0) rem=9 + rem;
   "G%d".fmt(rem)
}


"md5" cr:hash! "Some text" cr:hash cr:hash>s
. cr bye


/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program MD5_64.s   */

/*******************************************/
/* Constantes file                         */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"

.equ MD5_DIGEST_LENGTH, 16
.equ ZWORKSIZE,        1000

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessRosetta:         .asciz "Rosetta Code"
szMessTest1:           .asciz ""
szMessTest2:           .asciz "abc"
szMessTest3:           .asciz "abcdefghijklmnopqrstuvwxyz"
szMessTest4:           .asciz "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
szMessTest5:           .asciz "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
szMessFinPgm:          .asciz "Program End ok.\n"
szMessResult:          .asciz "Result for "
szMessResult1:         .asciz " => "
szMessSizeError:       .asciz "\033[31mWork area too small !! \033[0m \n"
szCarriageReturn:      .asciz "\n"

/* array constantes K */
tbConstK:  .int 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee
           .int 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501
           .int 0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be
           .int 0x6b901122,0xfd987193,0xa679438e,0x49b40821
           .int 0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa
           .int 0xd62f105d,0x2441453,0xd8a1e681,0xe7d3fbc8
           .int 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed
           .int 0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a
           .int 0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c
           .int 0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70
           .int 0x289b7ec6,0xeaa127fa,0xd4ef3085,0x4881d05
           .int 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665
           .int 0xf4292244,0x432aff97,0xab9423a7,0xfc93a039
           .int 0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1
           .int 0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1
           .int 0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391

/* array rotation coef R */
tbRotaR:   .int  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22
           .int  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20
           .int  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23
           .int  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21

tbConstH:            .int 0x67452301       // H0
                     .int 0xEFCDAB89       // H1
                     .int 0x98BADCFE       // H2
                     .int 0x10325476       // H3

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4
//iNbBlocs:                    .skip 8
sZoneConv:                   .skip 24
sZoneResult:                 .skip 24
tbH:                         .skip 4 * 4         // 4 variables H
sZoneTrav:                   .skip ZWORKSIZE
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                                      // entry of program

    ldr x0,qAdrszMessTest1
    bl computeExemple

    ldr x0,qAdrszMessTest2
    bl computeExemple

    ldr x0,qAdrszMessTest3
    bl computeExemple

    ldr x0,qAdrszMessTest4
    bl computeExemple

    ldr x0,qAdrszMessTest5
    bl computeExemple

    ldr x0,qAdrszMessFinPgm
    bl affichageMess                       // display message

100:                                       // standard end of the program
    mov x0,0                               // return code
    mov x8,EXIT                            // request to exit program
    svc 0                                  // perform the system call

qAdrszCarriageReturn:     .quad szCarriageReturn
qAdrszMessResult:         .quad szMessResult
qAdrszMessResult1:         .quad szMessResult1
qAdrszMessRosetta:        .quad szMessRosetta
qAdrszMessTest1:          .quad szMessTest1
qAdrszMessTest2:          .quad szMessTest2
qAdrszMessTest3:          .quad szMessTest3
qAdrszMessTest4:          .quad szMessTest4
qAdrszMessTest5:          .quad szMessTest5
qAdrsZoneTrav:            .quad sZoneTrav
qAdrsZoneConv:            .quad sZoneConv
qAdrszMessFinPgm:         .quad szMessFinPgm
/***********************************************/
/*     compute exemple                         */
/***********************************************/
/* x0 contains the address of the message */
computeExemple:
    stp x18,lr,[sp,-16]!      // save  registers
    mov x18,x0
    bl computeMD5             // call routine MD5

    ldr x0,qAdrszMessResult
    bl affichageMess
    mov x0,x18
    bl affichageMess
    ldr x0,qAdrszMessResult1
    bl affichageMess
    ldr x0, qAdrsZoneResult
    bl displayMD5

100:
    ldp x18,lr,[sp],16        // restaur  2 registers
    ret                       // return to address lr x30
/******************************************************************/
/*     compute MD5                         */
/******************************************************************/
/* x0 contains the address of the message */
computeMD5:
    stp x1,lr,[sp,-16]!       // save  registers
    ldr x1,qAdrsZoneTrav
    mov x2,#0                // counter length
1:                           // copy string in work area
    cmp x2,ZWORKSIZE
    bge 99f
    ldrb w3,[x0,x2]
    strb w3,[x1,x2]
    cmp x3,#0
    add x4,x2,1
    csel x2,x4,x2,ne
    bne 1b
                             // add bit et compute length
    lsl x6,x2,#3             // initial message length in bits
    mov x3,#0b10000000       // add bit 1 at end of string
    strb w3,[x1,x2]
    add x2,x2,#1             // length in bytes
    lsl x4,x2,#3             // length in bits
    mov x3,#0
2:
    lsr x5,x2,#6             // padding block 512 bytes
    lsl x5,x5,#6
    sub x5,x2,x5
    cmp x5,#56
    beq 3f                   // yes -> end add
    strb w3,[x1,x2]          // add zero at message end
    add x2,x2,#1             // increment length bytes
    add x4,x4,#8             // increment length in bits
    b 2b
3:
    str x6,[x1,x2]           // and store at end

    ldr x7,qAdrtbConstH      // constantes H address
    ldr x4,qAdrtbH           // start area H
    mov x5,#0
4:                           // init array H with start constantes
    ldr w6,[x7,x5,lsl #2]    // load constante
    str w6,[x4,x5,lsl #2]    // and store
    add x5,x5,#1
    cmp x5,#4                // constantes number
    blt 4b

                             // split into block of 64 bytes
    add x2,x2,#4             //  TODO : à revoir
    lsr x4,x2,#6             // blocks number
    mov x7,#0                // no de block et x1 contient l'adresse zone de travail
    ldr x3,qAdrtbConstK      // K constantes  address
    ldr x5,qAdrtbRotaR       // R rotation address

5:                           // begin loop of each block of 64 bytes
                             // init variable a b c d with H0 H1 H2 H3
    ldr x0,qAdrtbH
    ldr w8,[x0]              // a
    ldr w9,[x0,#4]           // b
    ldr w10,[x0,#8]          // c
    ldr w11,[x0,#12]         // d

    mov x6,#0                // indice t
                             /* x2  address begin each block */
    ldr x1,qAdrsZoneTrav
    add x2,x1,x7,lsl #6      //  compute block begin  indice * 4 * 16
6:                           // begin loop one
    cmp x6,15
    bgt 7f
                             // cas 1 f := (b et c) ou ((non b) et d)
                             //   g := i
    and w12,w9,w10
    mvn w13,w9
    and w13,w13,w11
    orr w12,w12,w13        // f
    mov x14,x6             // g
    b 10f
7:
    cmp x6,31
    bgt 8f
                           //  f := (d et b) ou ((non d) et c)
                           // g := (5×i + 1) mod 16
    and w12,w11,w9
    mvn w13,w11
    and w13,w13,w10
    orr w12,w12,w13        // f
    mov x13,5
    mul x13,x6,x13
    add x13,x13,1
    lsr x15,x13,4
    lsl x15,x15,4
    sub x14,x13,x15
    b 10f
8:
    cmp x6,47
    bgt 9f
                           // f := b xor c xor d
                           // g := (3×i + 5) mod 16
    eor w12,w9,w10
    eor w12,w12,w11
    mov x13,3
    mul x13,x6,x13
    add x13,x13,5
    lsr x15,x13,4
    lsl x15,x15,4
    sub x14,x13,x15

    b 10f
9:
                           // f := c xor (b ou (non d))
                           //  g := (7×i) mod 16
    mvn w13,w11
    orr w13,w13,w9
    eor w12,w13,w10        // f
    mov x13,7
    mul x13,x6,x13
    lsr x15,x13,4
    lsl x15,x15,4
    sub x14,x13,x15       // g

10:
    mov w15,w11
    mov w11,w10              // d = c
    mov w10,w9               // c = b
    add w16,w8,w12           // a + f
    ldr w17,[x2,x14,lsl #2]
    add w16,w16,w17          // + valeur bloc g
    ldr w13,[x3,x6,lsl #2]
    add w16,w16,w13          // + valeur constante K de i
    ldr w17,[x5,x6,lsl #2]   // rotate left value
    mov w13,32
    sub w17,w13,w17
    ror w13,w16,w17
    add w9,w9,w13            // new b
    mov w8, w15              // new a

    add x6,x6,1
    cmp x6,63
    ble 6b

    ldr x0,qAdrtbH
    ldr w1,[x0]                // H0
    add w1,w1,w8               // + a
    str w1,[x0]
    ldr w1,[x0,#4]             // H1
    add w1,w1,w9               // + b
    str w1,[x0,#4]
    ldr w1,[x0,#8]             // H2
    add w1,w1,w10              // + c
    str w1,[x0,#8]
    ldr w1,[x0,#12]            // H3
    add w1,w1,w11              // + d
    str w1,[x0,#12]
                               // other bloc
    add x7,x7,1                // increment block
    cmp x7,x4                  // maxi ?
    ble 5b

                               // compute final result
    ldr x0,qAdrtbH             // start area H
    ldr x2,qAdrsZoneResult
    ldr w1,[x0]
    str w1,[x2]
    ldr w1,[x0,#4]
    str w1,[x2,#4]
    ldr w1,[x0,#8]
    str w1,[x2,#8]
    ldr w1,[x0,#12]
    str w1,[x2,#12]

    mov x0,#0                    // routine OK
    b 100f
99:                              // size error
    ldr x0,qAdrszMessSizeError
    bl affichageMess
    mov x0,-1
100:
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
qAdrtbConstH:             .quad tbConstH
qAdrtbConstK:             .quad tbConstK
qAdrtbRotaR:              .quad tbRotaR
qAdrtbH:                  .quad tbH
qAdrsZoneResult:          .quad sZoneResult
qAdrszMessSizeError:      .quad szMessSizeError

/******************************************************************/
/*     display hash  MD5                         */
/******************************************************************/
/* x0 contains the address of hash  */
displayMD5:
    stp x1,lr,[sp,-16]!            // save  registers
    stp x2,x3,[sp,-16]!            // save  registers
    mov x3,x0
    mov x2,#0
1:
    ldr w0,[x3,x2,lsl #2]          // load 4 bytes
    rev w0,w0                      // reverse bytes
    ldr x1,qAdrsZoneConv
    bl conversion16_4W             // conversion hexa
    ldr x0,qAdrsZoneConv
    bl affichageMess
    add x2,x2,#1
    cmp x2,#MD5_DIGEST_LENGTH / 4
    blt 1b                         // and loop
    ldr x0,qAdrszCarriageReturn
    bl affichageMess               // display message
100:
    ldp x2,x3,[sp],16              // restaur  2 registers
    ldp x1,lr,[sp],16              // restaur  2 registers
    ret                            // return to address lr x30
/******************************************************************/
/*     conversion  hexadecimal register 32 bits                   */
/******************************************************************/
/* x0 contains value and x1 address zone receptrice   */
conversion16_4W:
    stp x0,lr,[sp,-48]!        // save  registres
    stp x1,x2,[sp,32]          // save  registres
    stp x3,x4,[sp,16]          // save  registres
    mov x2,#28                 // start bit position
    mov x4,#0xF0000000         // mask
    mov x3,x0                  // save entry value
1:                             // start loop
    and x0,x3,x4               // value register and mask
    lsr x0,x0,x2               // right shift
    cmp x0,#10                 // >= 10 ?
    bge 2f                     // yes
    add x0,x0,#48              // no is digit
    b 3f
2:
    add x0,x0,#55              // else is a letter A-F
3:
    strb w0,[x1],#1            // load result  and + 1 in address
    lsr x4,x4,#4               // shift mask 4 bits left
    subs x2,x2,#4              // decrement counter 4 bits <= zero  ?
    bge 1b                     // no -> loop

100:                           // fin standard de la fonction
    ldp x3,x4,[sp,16]          // restaur des  2 registres
    ldp x1,x2,[sp,32]          // restaur des  2 registres
    ldp x0,lr,[sp],48          // restaur des  2 registres
    ret
/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"


with Ada.Text_IO; use Ada.Text_IO;
with GNAT.MD5;

procedure MD5_Digest is
begin
   Put(GNAT.MD5.Digest("Foo bar baz"));
end MD5_Digest;


 md5←{
     ⍝ index origin zero
     ⎕IO←0
     ⍝ decoding UTF-8 & padding
     M←(⊢,(0⍴⍨512|448-512|≢))1,⍨l←,⍉(8⍴2)⊤'UTF-8'⎕UCS ⍵
     ⍝ add length
     M,←,⍉(8⍴2)⊤⌽(8⍴256)⊤≢l
     ⍝ init registers
     A←16⊥6 7 4 5 2 3 0 1
     B←16⊥14 15 12 13 10 11 8 9
     C←16⊥9 8 11 10 13 12 15 14
     D←16⊥1 0 3 2 5 4 7 6
     ⍝ T table
     T←⌊(2*32)×|1○1+⍳64
     ⍝ index table
     K←16|i,(1+5×i),(5+3×i),7×i←⍳16
     ⍝ rot table
     S←,1 0 2⍉4 4 4⍴7 12 17 22 5 9 14 20 4 11 16 23 6 10 15 21
     ⍝ truncate ⍵ to 32 bit & rot left ⍺
     rot←{2⊥⍺⌽(32⍴2)⊤⍵}
     proc←{
         ⍝ pack 512 bits into 32 bit words &
         ⍝ precompute X[k] + T[i]
         l←T+(⊂K)⌷256⊥⍉⌽16 4⍴2⊥⍉64 8⍴⍺
         fn←{
         ⍝ a b c d to binary
             a b c d←↓⍉(32⍴2)⊤⍵
         ⍝ a + F(b,c,d)
             ⍺<16:S[⍺]rot l[⍺]+2⊥a+d≠b∧c≠d
             ⍺<32:S[⍺]rot l[⍺]+2⊥a+(b∧d)∨(c∧~d)
             ⍺<48:S[⍺]rot l[⍺]+2⊥a+b≠c≠d
             S[⍺]rot l[⍺]+2⊥a+c≠b∨~d
         }
         (2*32)|⍵+⊃{¯1⌽((⍵[1]+⍺ fn ⍵)@0)⍵}/(⌽⍳64),⊂⍵
     }
     ⍝ process each 512 bits
     loop←{⍬≡⍺:⍵ ⋄ (512↓⍺)∇(512↑⍺)proc ⍵}
     ⍝ output registers
     (⎕D,⎕A)[,⍉(2⍴16)⊤,⍉⊖(4⍴256)⊤M loop A B C D]
 }


print digest "The quick brown fox jumped over the lazy dog's back"