MD4: Difference between revisions

9,776 bytes added ,  4 months ago
m
m (syntax highlighting fixup automation)
m (→‎{{header|Wren}}: Minor tidy)
 
(16 intermediate revisions by 4 users not shown)
Line 105:
<pre>String: Rosetta Code
MD4: A52BCFC6A0D0D300CDC5DDBFBEFE478B</pre>
 
=={{header|BASIC}}==
==={{header|FreeBASIC}}===
<syntaxhighlight lang="freebasic">' 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</syntaxhighlight>
{{out}}
<pre>Rosetta Code => a52bcfc6a0d0d300cdc5ddbfbefe478b</pre>
 
=={{header|C}}==
Line 414 ⟶ 571:
{{out}}
<pre>a52bcfc6a0d0d300cdc5ddbfbefe478b</pre>
 
=={{header|C++}}==
<syntaxhighlight lang="c++">
#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
 
class MD4 {
public:
MD4() {
engine_reset();
}
 
std::vector<int8_t> engine_digest(const std::string& text) {
engine_update(string_to_byte_vector(text), 0, text.length());
 
const int32_t buffer_index = static_cast<int32_t>(count % BLOCK_LENGTH);
const int32_t padding_length = ( buffer_index < 56 ) ? 56 - buffer_index : 120 - buffer_index;
 
std::vector<int8_t> tail(padding_length + 8, 0);
tail[0] = static_cast<int8_t>(0x80);
 
for ( int32_t i = 0; i < 8; ++i ) {
tail[padding_length + i] = static_cast<int8_t>(unsigned_right_shift(count * 8, 8 * i));
}
 
engine_update(tail, 0, tail.size());
 
std::vector<int8_t> result(16, 0);
for ( int32_t i = 0; i < 4; ++i ) {
for ( int32_t j = 0; j < 4; ++j ) {
result[i * 4 + j] = static_cast<int8_t>(unsigned_right_shift(context[i], 8 * j));
}
}
 
engine_reset();
return result;
}
 
private:
void engine_update(const std::vector<int8_t>& message_bytes,
const int32_t& offset, const int32_t& message_length) {
if ( offset < 0 || message_length < 0
|| (int64_t) offset + message_length > (int64_t) message_bytes.size() ) {
throw std::invalid_argument("Incorrect arguments for function engine_update");
}
 
int32_t buffer_index = static_cast<int32_t>(count % BLOCK_LENGTH);
count += message_length;
const int32_t partial_length = BLOCK_LENGTH - buffer_index;
int32_t i = 0;
 
if ( message_length >= partial_length ) {
for ( int32_t j = 0; j < partial_length; ++j ) {
buffer[buffer_index + j] = message_bytes[offset + j];
}
transform(buffer, 0);
i = partial_length;
while ( i + BLOCK_LENGTH - 1 < message_length ) {
transform(message_bytes, offset + i);
i += BLOCK_LENGTH;
}
buffer_index = 0;
}
 
if ( i < message_length ) {
for ( int32_t j = 0; j < message_length - i; ++j ) {
buffer[buffer_index + j] = message_bytes[offset + i + j];
}
}
}
 
void transform(const std::vector<int8_t>& buffer, int32_t offset) {
for ( int32_t i = 0; i < 16; ++i ) {
extra[i] = ( ( buffer[offset + 0] & 0xff ) ) |
( ( buffer[offset + 1] & 0xff ) << 8 ) |
( ( buffer[offset + 2] & 0xff ) << 16 ) |
( ( buffer[offset + 3] & 0xff ) << 24 );
offset += 4;
}
 
int32_t a = context[0];
int32_t b = context[1];
int32_t c = context[2];
int32_t d = context[3];
 
for ( const int32_t& i : { 0, 4, 8, 12 } ) {
a = ff(a, b, c, d, extra[i + 0], 3);
d = ff(d, a, b, c, extra[i + 1], 7);
c = ff(c, d, a, b, extra[i + 2], 11);
b = ff(b, c, d, a, extra[i + 3], 19);
}
 
for ( const int32_t& i : { 0, 1, 2, 3 } ) {
a = gg(a, b, c, d, extra[i + 0], 3);
d = gg(d, a, b, c, extra[i + 4], 5);
c = gg(c, d, a, b, extra[i + 8], 9);
b = gg(b, c, d, a, extra[i + 12], 13);
}
 
for ( const int32_t& i : { 0, 2, 1, 3 } ) {
a = hh(a, b, c, d, extra[i + 0], 3);
d = hh(d, a, b, c, extra[i + 8], 9);
c = hh(c, d, a, b, extra[i + 4], 11);
b = hh(b, c, d, a, extra[i + 12], 15);
}
 
context[0] += a;
context[1] += b;
context[2] += c;
context[3] += d;
}
 
void engine_reset() {
count = 0;
context.assign(4, 0);
context[0] = 0x67452301;
context[1] = 0xefcdab89;
context[2] = 0x98badcfe;
context[3] = 0x10325476;
extra.assign(16, 0);
buffer.assign(BLOCK_LENGTH, 0);
}
 
std::vector<int8_t> string_to_byte_vector(const std::string& text) {
std::vector<int8_t> bytes;
bytes.reserve(text.size());
 
std::transform(text.begin(), text.end(), std::back_inserter(bytes),
[](char ch){ return static_cast<int8_t>(ch); });
 
return bytes;
}
 
int32_t unsigned_right_shift(const int32_t& base, const int32_t& shift) {
if ( shift < 0 || shift >= 32 || base == 0 ) {
return 0;
}
return ( base > 0 ) ? base >> shift : static_cast<uint32_t>(base) >> shift;
}
 
int32_t rotate(const int32_t& t, const int32_t& s) {
return ( t << s ) | unsigned_right_shift(t, 32 - s);
}
 
int32_t ff(const int32_t& a, const int32_t& b, const int32_t& c,
const int32_t& d, const int32_t& x, const int32_t& s) {
return rotate(a + ( ( b & c ) | ( ~b & d ) ) + x, s);
}
 
int32_t gg(const int32_t& a, const int32_t& b, const int32_t& c,
const int32_t& d, const int32_t& x, const int32_t& s) {
return rotate(a + ( ( b & ( c | d ) ) | ( c & d ) ) + x + 0x5A827999, s);
}
 
int32_t hh(const int32_t& a, const int32_t& b, const int32_t& c,
const int32_t& d, const int32_t& x, const int32_t& s) {
return rotate(a + ( b ^ c ^ d ) + x + 0x6ED9EBA1, s);
}
 
uint64_t count;
std::vector<int32_t> context;
std::vector<int32_t> extra;
std::vector<int8_t> buffer;
 
const int32_t BLOCK_LENGTH = 64;
};
 
int main() {
MD4 md4;
std::vector<int8_t> result = md4.engine_digest("Rosetta Code");
 
for ( const int8_t& bb : result ) {
std::cout << std::hex << std::setfill('0') << std::setw(2) << ( bb & 0xff );
}
std::cout << std::endl;
}
</syntaxhighlight>
{{ out }}
<pre>
a52bcfc6a0d0d300cdc5ddbfbefe478b
</pre>
 
=={{header|Clojure}}==
Line 550 ⟶ 892:
Rosetta Code => A52BCFC6A0D0D300CDC5DDBFBEFE478B
</pre>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">' 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</syntaxhighlight>
{{out}}
<pre>Rosetta Code => a52bcfc6a0d0d300cdc5ddbfbefe478b</pre>
 
=={{header|Go}}==
Line 767 ⟶ 953:
}</syntaxhighlight>
{{out}}
<pre>
a52bcfc6a0d0d300cdc5ddbfbefe478b
</pre>
 
===Without external libraries===
<syntaxhighlight lang="java">
import java.util.Arrays;
import java.util.List;
 
public final class MD4Task {
public static void main(String[] aArgs) {
String text = "Rosetta Code";
MD4 md4 = new MD4();
byte[] result = md4.engineDigest(text);
StringBuilder stringBuilder = new StringBuilder();
for ( byte bb : result ) {
stringBuilder.append(String.format("%02x", bb));
}
System.out.println(stringBuilder.toString());
}
}
final class MD4 {
public MD4() {
engineReset();
}
 
public byte[] engineDigest(String aText) {
engineUpdate(aText.getBytes(), 0, aText.length());
final int bufferIndex = (int) ( count % BLOCK_LENGTH );
final int paddingLength = ( bufferIndex < 56 ) ? 56 - bufferIndex : 120 - bufferIndex;
 
byte[] tail = new byte[paddingLength + 8];
tail[0] = (byte) 0x80;
for ( int i = 0; i < 8; i++ ) {
tail[paddingLength + i] = (byte) ( ( count * 8 ) >>> ( 8 * i ) );
}
engineUpdate(tail, 0, tail.length);
 
byte[] result = new byte[16];
for ( int i = 0; i < 4; i++ ) {
for ( int j = 0; j < 4; j++ ) {
result[i * 4 + j] = (byte) ( context[i] >>> ( 8 * j ) );
}
}
 
engineReset();
return result;
}
private void engineUpdate(byte[] aMessageBytes, int aOffset, int aMessageLength) {
if ( aOffset < 0 || aMessageLength < 0 || (long) aOffset + aMessageLength > (long) aMessageBytes.length ) {
throw new ArrayIndexOutOfBoundsException("Incorrect arguments for method engineUpdate");
}
int bufferIndex = (int) ( count % BLOCK_LENGTH );
count += aMessageLength;
final int partialLength = BLOCK_LENGTH - bufferIndex;
int i = 0;
if ( aMessageLength >= partialLength ) {
System.arraycopy(aMessageBytes, aOffset, buffer, bufferIndex, partialLength);
transform(buffer, 0);
i = partialLength;
while ( i + BLOCK_LENGTH - 1 < aMessageLength ) {
transform(aMessageBytes, aOffset + i);
i += BLOCK_LENGTH;
}
bufferIndex = 0;
}
if ( i < aMessageLength ) {
System.arraycopy(aMessageBytes, aOffset + i, buffer, bufferIndex, aMessageLength - i);
}
}
private void transform (byte[] aBuffer, int aOffset) {
for ( int i = 0; i < 16; i++ ) {
extra[i] = ( ( aBuffer[aOffset++] & 0xff ) ) |
( ( aBuffer[aOffset++] & 0xff ) << 8 ) |
( ( aBuffer[aOffset++] & 0xff ) << 16 ) |
( ( aBuffer[aOffset++] & 0xff ) << 24 );
}
int a = context[0];
int b = context[1];
int c = context[2];
int d = context[3];
for ( int i : List.of( 0, 4, 8, 12 ) ) {
a = ff(a, b, c, d, extra[i + 0], 3);
d = ff(d, a, b, c, extra[i + 1], 7);
c = ff(c, d, a, b, extra[i + 2], 11);
b = ff(b, c, d, a, extra[i + 3], 19);
}
for ( int i : List.of( 0, 1, 2, 3 ) ) {
a = gg(a, b, c, d, extra[i + 0], 3);
d = gg(d, a, b, c, extra[i + 4], 5);
c = gg(c, d, a, b, extra[i + 8], 9);
b = gg(b, c, d, a, extra[i + 12], 13);
}
for ( int i : List.of( 0, 2, 1, 3 ) ) {
a = hh(a, b, c, d, extra[i + 0], 3);
d = hh(d, a, b, c, extra[i + 8], 9);
c = hh(c, d, a, b, extra[i + 4], 11);
b = hh(b, c, d, a, extra[i + 12], 15);
}
 
context[0] += a;
context[1] += b;
context[2] += c;
context[3] += d;
}
private void engineReset() {
count = 0;
context[0] = 0x67452301;
context[1] = 0xefcdab89;
context[2] = 0x98badcfe;
context[3] = 0x10325476;
Arrays.fill(extra, 0);
Arrays.fill(buffer, (byte) 0);
}
private static int rotate(int t, int s) {
return t << s | t >>> ( 32 - s );
}
private static int ff(int a, int b, int c, int d, int x, int s) {
return rotate(a + ( ( b & c ) | ( ~b & d ) ) + x, s);
}
private static int gg(int a, int b, int c, int d, int x, int s) {
return rotate(a + ( ( b & ( c | d ) ) | ( c & d ) ) + x + 0x5A827999, s);
}
private static int hh(int a, int b, int c, int d, int x, int s) {
return rotate(a + ( b ^ c ^ d ) + x + 0x6ED9EBA1, s);
}
private static final int BLOCK_LENGTH = 64;
private long count;
private int[] context = new int[4];
private int[] extra = new int[16];
private byte[] buffer = new byte[BLOCK_LENGTH];
 
}
</syntaxhighlight>
{{ out }}
<pre>
a52bcfc6a0d0d300cdc5ddbfbefe478b
Line 1,267 ⟶ 1,613:
=={{header|Perl}}==
In-lining code from module [https://metacpan.org/pod/Digest::Perl::MD4 Digest::Perl::MD4], lightly edited for clarity.
<syntaxhighlight lang="perl">sub md4 :prototype(@) {
my @input = grep { defined && length > 0 } split /(.{64})/s, join '', @_;
push @input, '' if !@input || length($input[$#input]) >= 56;
Line 1,328 ⟶ 1,674:
}
 
sub md4_hex :prototype(@) { # convert to hexadecimal
unpack 'H*', &md4;
}
Line 1,636 ⟶ 1,982:
(formerly Perl 6)
<syntaxhighlight lang="raku" line>sub md4($str) {
my @buf8 $buf .= new: $str.ordsencode;
my $buflenbuf-length = @$buf.elems;
$buf.push: 0x80;
$buf.push: 0 until ($buf - (448 div 8)) %% (512 div 8);
# raku serializes in little endian by default
$buf.write-uint64: $buf.elems, $buf-length*8;
 
my \mask(&f, =&g, (1&h, +< 32&r) -= 1;
my &f = -> $x, $y, $z { ($^x +& $^y) +| (+^$x +^ mask) +& $^z },
my &g = -> $x, $y, $z { ($^x +& $^y) +| ($x +& $^z) +| ($y +& $z) },
my &h = -> $x, $y, $z { $^x +^ $^y +^ $^z },
# for some reason we have to type v here
my &r = -> $v, $s { (($v +< $s) +& mask) +| (($v +& mask) +> (32 - $s)) }
-> uint32 $v, $s { $v +< $s +| $v +> (32 - $s) }
 
my uint32 ($a, $b, $c, $d) = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476;
sub pack-le (@a) {
gather for @a -> $a,$b,$c,$d { take $d +< 24 + $c +< 16 + $b +< 8 + $a }
}
loop (my $pos = 0; $pos < $buf.elems; $pos+=64) {
my ($a, $b, $c, $d) = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476;
my ($aa, $bb, $cc, $dd) = $a, $b, $c, $d;
for 0, 4, 8, 12 -> $i {
my $term = False;
$a = r($a + f($b, $c, $d) + $buf.read-uint32($pos+($i+0)*4), 3);
my $last = False;
$d = r($d + f($a, $b, $c) + $buf.read-uint32($pos+($i+1)*4), 7);
my $off = 0;
$c = r($c + f($d, $a, $b) + $buf.read-uint32($pos+($i+2)*4), 11);
repeat until $last {
my @block $b = @buf[r($off..$offb +63]:v; f($offc, $d, $a) += 64$buf.read-uint32($pos+($i+3)*4), 19);
}
myfor @x;0, 1, 2, 3 -> $i {
$a = r($a + g($b, $c, $d) + $buf.read-uint32($pos+($i+0 )*4) + 0x5a827999, 3);
given +@block {
$d = r($d + g($a, $b, $c) + $buf.read-uint32($pos+($i+4 )*4) + 0x5a827999, 5);
when 64 {
$c = r($c + g($d, $a, $b) + $buf.read-uint32($pos+($i+8 )*4) + 0x5a827999, 9);
@x = pack-le @block;
$b = r($b + g($c, $d, $a) + $buf.read-uint32($pos+($i+12)*4) + 0x5a827999, 13);
}
when 56..63 { }
$termfor =0, 2, 1, 3 -> $i True;{
$a = r($a + h($b, $c, $d) + $buf.read-uint32($pos+($i+0 )*4) + 0x6ed9eba1, 3);
@block.push(0x80);
$d = r($d + h($a, $b, $c) + $buf.read-uint32($pos+($i+4 )*4) + 0x6ed9eba1, 9);
@block.push(slip 0 xx 63 - $_);
$c = r($c + h($d, $a, $b) + $buf.read-uint32($pos+($i+8 )*4) + 0x6ed9eba1, 11);
@x = pack-le @block;
$b = r($b + h($c, $d, $a) + $buf.read-uint32($pos+($i+12)*4) + 0x6ed9eba1, 15);
}
when 0..55 { }
@block.push($terma,$b,$c,$d) ??Z[+=] 0 !! 0x80($aa,$bb,$cc,$dd);
@block.push(slip 0 xx 55 - $_);
@x = pack-le @block;
my $bit_len = $buflen +< 3;
@x.push: $bit_len +& mask, $bit_len +> 32;
$last = True;
}
default {
die "oops";
}
}
my ($aa, $bb, $cc, $dd) = $a, $b, $c, $d;
for 0, 4, 8, 12 -> \i {
$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);
}
for 0, 1, 2, 3 -> \i {
$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);
}
for 0, 2, 1, 3 -> \i {
$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 = ($a + $aa) +& mask;
$b = ($b + $bb) +& mask;
$c = ($c + $cc) +& mask;
$d = ($d + $dd) +& mask;
}
reduce { $^buf.write-uint32: $buf.elems, $^x; $buf }, buf8.new, $a, $b, $c, $d;
sub b2l($n is copy) {
my $x = 0;
for ^4 {
$x +<= 8;
$x += $n +& 0xff;
$n +>= 8;
}
$x;
}
 
b2l($a) +< 96 +
b2l($b) +< 64 +
b2l($c) +< 32 +
b2l($d);
}
CHECK {
sub MAIN {
use Test;
my $str = 'Rosetta Code';
plan 1;
say md4($str).base(16).lc;
is md4('Rosetta Code').list.fmt('%02X'), 'A5 2B CF C6 A0 D0 D3 00 CD C5 DD BF BE FE 47 8B';
}</syntaxhighlight>
{{out}}
<pre>1..1
<pre>a52bcfc6a0d0d300cdc5ddbfbefe478b</pre>
ok 1 -
</pre>
 
=={{header|Ruby}}==
Line 2,065 ⟶ 2,369:
{{trans|D}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="ecmascriptwren">import "./fmt" for Fmt
 
var toBytes = Fn.new { |val|
9,482

edits