1#!/usr/bin/perl -w 2# 3# MD5 optimized for AMD64. 4# 5# Author: Marc Bevand <bevand_m (at) epita.fr> 6# Licence: I hereby disclaim the copyright on this code and place it 7# in the public domain. 8# 9 10# 11# The following is Marc Bevand's MD5 implementation optimized for 12# AMD64. It has been lifted intact, except for changing the comment 13# character and adding comments. 14# 15# typedef struct { 16# uint32_t state[4]; /* state (ABCD) */ 17# uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ 18# union { 19# uint8_t buf8[64]; /* undigested input */ 20# uint32_t buf32[16]; /* realigned input */ 21# } buf_un; 22# } MD5_CTX; 23# 24# void md5_block_asm_host_order(MD5_CTX *ctx, const void *inpp, 25# unsigned int input_length_in_blocks); 26# 27# Registers used: 28# rax A r8 old A 29# rbx B r9 old B 30# rcx C r10 tmp 31# rdx D r11 tmp 32# rsi ptr r12 tmp 33# rdi end r13 - 34# rbp - r14 old C 35# rsp stack r15 old D 36# 37 38use strict; 39my $code; 40 41 42# round1_step() does: 43# dst = x + ((dst + F(x,y,z) + X[k] + T_i) <<< s) 44# %r10d = X[k_next] 45# %r11d = z' (copy of z for the next step) 46# Each round1_step() takes about 5.3 clocks (9 instructions, 1.7 IPC) 47sub round1_step 48{ 49 my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_; 50 $code .= " mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */\n" if ($pos == -1); 51 $code .= " mov %edx, %r11d /* (NEXT STEP) z' = %edx */\n" if ($pos == -1); 52 53 $code .= <<EOF; 54 xor $y, %r11d /* y ^ ... */ 55 lea $T_i($dst,%r10d),$dst /* Const + dst + ... */ 56 and $x, %r11d /* x & ... */ 57 xor $z, %r11d /* z ^ ... */ 58 mov $k_next*4(%rsi),%r10d /* (NEXT STEP) X[$k_next] */ 59 add %r11d, $dst /* dst += ... */ 60 rol \$$s, $dst /* dst <<< s */ 61 mov $y, %r11d /* (NEXT STEP) z' = $y */ 62 add $x, $dst /* dst += x */ 63EOF 64} 65 66# round2_step() does: 67# dst = x + ((dst + G(x,y,z) + X[k] + T_i) <<< s) 68# %r10d = X[k_next] 69# %r11d = z' (copy of z for the next step) 70# %r12d = z' (copy of z for the next step) 71# Each round2_step() takes about 5.4 clocks (11 instructions, 2.0 IPC) 72sub round2_step 73{ 74 my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_; 75 $code .= " mov 1*4(%rsi), %r10d /* (NEXT STEP) X[1] */\n" if ($pos == -1); 76 $code .= " mov %edx, %r11d /* (NEXT STEP) z' = %edx */\n" if ($pos == -1); 77 $code .= " mov %edx, %r12d /* (NEXT STEP) z' = %edx */\n" if ($pos == -1); 78 79 $code .= <<EOF; 80 not %r11d /* not z */ 81 lea $T_i($dst,%r10d),$dst /* Const + dst + ... */ 82 and $x, %r12d /* x & z */ 83 and $y, %r11d /* y & (not z) */ 84 mov $k_next*4(%rsi),%r10d /* (NEXT STEP) X[$k_next] */ 85 or %r11d, %r12d /* (y & (not z)) | (x & z) */ 86 mov $y, %r11d /* (NEXT STEP) z' = $y */ 87 add %r12d, $dst /* dst += ... */ 88 mov $y, %r12d /* (NEXT STEP) z' = $y */ 89 rol \$$s, $dst /* dst <<< s */ 90 add $x, $dst /* dst += x */ 91EOF 92} 93 94# round3_step() does: 95# dst = x + ((dst + H(x,y,z) + X[k] + T_i) <<< s) 96# %r10d = X[k_next] 97# %r11d = y' (copy of y for the next step) 98# Each round3_step() takes about 4.2 clocks (8 instructions, 1.9 IPC) 99sub round3_step 100{ 101 my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_; 102 $code .= " mov 5*4(%rsi), %r10d /* (NEXT STEP) X[5] */\n" if ($pos == -1); 103 $code .= " mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */\n" if ($pos == -1); 104 105 $code .= <<EOF; 106 lea $T_i($dst,%r10d),$dst /* Const + dst + ... */ 107 mov $k_next*4(%rsi),%r10d /* (NEXT STEP) X[$k_next] */ 108 xor $z, %r11d /* z ^ ... */ 109 xor $x, %r11d /* x ^ ... */ 110 add %r11d, $dst /* dst += ... */ 111 rol \$$s, $dst /* dst <<< s */ 112 mov $x, %r11d /* (NEXT STEP) y' = $x */ 113 add $x, $dst /* dst += x */ 114EOF 115} 116 117# round4_step() does: 118# dst = x + ((dst + I(x,y,z) + X[k] + T_i) <<< s) 119# %r10d = X[k_next] 120# %r11d = not z' (copy of not z for the next step) 121# Each round4_step() takes about 5.2 clocks (9 instructions, 1.7 IPC) 122sub round4_step 123{ 124 my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_; 125 $code .= " mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */\n" if ($pos == -1); 126 $code .= " mov \$0xffffffff, %r11d\n" if ($pos == -1); 127 $code .= " xor %edx, %r11d /* (NEXT STEP) not z' = not %edx*/\n" 128 if ($pos == -1); 129 130 $code .= <<EOF; 131 lea $T_i($dst,%r10d),$dst /* Const + dst + ... */ 132 or $x, %r11d /* x | ... */ 133 xor $y, %r11d /* y ^ ... */ 134 add %r11d, $dst /* dst += ... */ 135 mov $k_next*4(%rsi),%r10d /* (NEXT STEP) X[$k_next] */ 136 mov \$0xffffffff, %r11d 137 rol \$$s, $dst /* dst <<< s */ 138 xor $y, %r11d /* (NEXT STEP) not z' = not $y */ 139 add $x, $dst /* dst += x */ 140EOF 141} 142 143 144# 145# Execution begins here. 146# 147 148my $output = shift; 149open STDOUT,">$output" or die "can't open $output: $!"; 150 151$code .= <<EOF; 152#if defined(lint) || defined(__lint) 153#include <sys/md5.h> 154 155/* ARGSUSED */ 156void md5_block_asm_host_order(MD5_CTX *ctx, const void *inpp, 157 unsigned int input_length_in_blocks) 158{ 159} 160 161#else 162#include <sys/asm_linkage.h> 163 164 ENTRY_NP(md5_block_asm_host_order) 165 push %rbp 166 push %rbx 167 push %r12 168 push %r13 169 push %r14 170 push %r15 171 172 / rdi = arg #1 (ctx, MD5_CTX pointer) 173 / rsi = arg #2 (ptr, data pointer) 174 / rdx = arg #3 (nbr, number of 64-byte blocks to process) 175 mov %rdi, %rbp / rbp = ctx 176 shl \$6, %rdx / rdx = nbr in bytes 177 lea (%rsi,%rdx), %rdi / rdi = end 178 mov 0*4(%rbp), %eax / eax = ctx->A 179 mov 1*4(%rbp), %ebx / ebx = ctx->B 180 mov 2*4(%rbp), %ecx / ecx = ctx->C 181 mov 3*4(%rbp), %edx / edx = ctx->D 182 push %rbp / save ctx 183 / end is 'rdi' 184 / ptr is 'rsi' 185 / A is 'eax' 186 / B is 'ebx' 187 / C is 'ecx' 188 / D is 'edx' 189 190 cmp %rdi, %rsi / cmp end with ptr 191 je 1f / jmp if ptr == end 192 193 / BEGIN of loop over 64-byte blocks 1942: / save old values of A, B, C, D 195 mov %eax, %r8d 196 mov %ebx, %r9d 197 mov %ecx, %r14d 198 mov %edx, %r15d 199EOF 200round1_step(-1,'%eax','%ebx','%ecx','%edx', '1','0xd76aa478', '7'); 201round1_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xe8c7b756','12'); 202round1_step( 0,'%ecx','%edx','%eax','%ebx', '3','0x242070db','17'); 203round1_step( 0,'%ebx','%ecx','%edx','%eax', '4','0xc1bdceee','22'); 204round1_step( 0,'%eax','%ebx','%ecx','%edx', '5','0xf57c0faf', '7'); 205round1_step( 0,'%edx','%eax','%ebx','%ecx', '6','0x4787c62a','12'); 206round1_step( 0,'%ecx','%edx','%eax','%ebx', '7','0xa8304613','17'); 207round1_step( 0,'%ebx','%ecx','%edx','%eax', '8','0xfd469501','22'); 208round1_step( 0,'%eax','%ebx','%ecx','%edx', '9','0x698098d8', '7'); 209round1_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8b44f7af','12'); 210round1_step( 0,'%ecx','%edx','%eax','%ebx','11','0xffff5bb1','17'); 211round1_step( 0,'%ebx','%ecx','%edx','%eax','12','0x895cd7be','22'); 212round1_step( 0,'%eax','%ebx','%ecx','%edx','13','0x6b901122', '7'); 213round1_step( 0,'%edx','%eax','%ebx','%ecx','14','0xfd987193','12'); 214round1_step( 0,'%ecx','%edx','%eax','%ebx','15','0xa679438e','17'); 215round1_step( 1,'%ebx','%ecx','%edx','%eax', '0','0x49b40821','22'); 216 217round2_step(-1,'%eax','%ebx','%ecx','%edx', '6','0xf61e2562', '5'); 218round2_step( 0,'%edx','%eax','%ebx','%ecx','11','0xc040b340', '9'); 219round2_step( 0,'%ecx','%edx','%eax','%ebx', '0','0x265e5a51','14'); 220round2_step( 0,'%ebx','%ecx','%edx','%eax', '5','0xe9b6c7aa','20'); 221round2_step( 0,'%eax','%ebx','%ecx','%edx','10','0xd62f105d', '5'); 222round2_step( 0,'%edx','%eax','%ebx','%ecx','15', '0x2441453', '9'); 223round2_step( 0,'%ecx','%edx','%eax','%ebx', '4','0xd8a1e681','14'); 224round2_step( 0,'%ebx','%ecx','%edx','%eax', '9','0xe7d3fbc8','20'); 225round2_step( 0,'%eax','%ebx','%ecx','%edx','14','0x21e1cde6', '5'); 226round2_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xc33707d6', '9'); 227round2_step( 0,'%ecx','%edx','%eax','%ebx', '8','0xf4d50d87','14'); 228round2_step( 0,'%ebx','%ecx','%edx','%eax','13','0x455a14ed','20'); 229round2_step( 0,'%eax','%ebx','%ecx','%edx', '2','0xa9e3e905', '5'); 230round2_step( 0,'%edx','%eax','%ebx','%ecx', '7','0xfcefa3f8', '9'); 231round2_step( 0,'%ecx','%edx','%eax','%ebx','12','0x676f02d9','14'); 232round2_step( 1,'%ebx','%ecx','%edx','%eax', '0','0x8d2a4c8a','20'); 233 234round3_step(-1,'%eax','%ebx','%ecx','%edx', '8','0xfffa3942', '4'); 235round3_step( 0,'%edx','%eax','%ebx','%ecx','11','0x8771f681','11'); 236round3_step( 0,'%ecx','%edx','%eax','%ebx','14','0x6d9d6122','16'); 237round3_step( 0,'%ebx','%ecx','%edx','%eax', '1','0xfde5380c','23'); 238round3_step( 0,'%eax','%ebx','%ecx','%edx', '4','0xa4beea44', '4'); 239round3_step( 0,'%edx','%eax','%ebx','%ecx', '7','0x4bdecfa9','11'); 240round3_step( 0,'%ecx','%edx','%eax','%ebx','10','0xf6bb4b60','16'); 241round3_step( 0,'%ebx','%ecx','%edx','%eax','13','0xbebfbc70','23'); 242round3_step( 0,'%eax','%ebx','%ecx','%edx', '0','0x289b7ec6', '4'); 243round3_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xeaa127fa','11'); 244round3_step( 0,'%ecx','%edx','%eax','%ebx', '6','0xd4ef3085','16'); 245round3_step( 0,'%ebx','%ecx','%edx','%eax', '9', '0x4881d05','23'); 246round3_step( 0,'%eax','%ebx','%ecx','%edx','12','0xd9d4d039', '4'); 247round3_step( 0,'%edx','%eax','%ebx','%ecx','15','0xe6db99e5','11'); 248round3_step( 0,'%ecx','%edx','%eax','%ebx', '2','0x1fa27cf8','16'); 249round3_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xc4ac5665','23'); 250 251round4_step(-1,'%eax','%ebx','%ecx','%edx', '7','0xf4292244', '6'); 252round4_step( 0,'%edx','%eax','%ebx','%ecx','14','0x432aff97','10'); 253round4_step( 0,'%ecx','%edx','%eax','%ebx', '5','0xab9423a7','15'); 254round4_step( 0,'%ebx','%ecx','%edx','%eax','12','0xfc93a039','21'); 255round4_step( 0,'%eax','%ebx','%ecx','%edx', '3','0x655b59c3', '6'); 256round4_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8f0ccc92','10'); 257round4_step( 0,'%ecx','%edx','%eax','%ebx', '1','0xffeff47d','15'); 258round4_step( 0,'%ebx','%ecx','%edx','%eax', '8','0x85845dd1','21'); 259round4_step( 0,'%eax','%ebx','%ecx','%edx','15','0x6fa87e4f', '6'); 260round4_step( 0,'%edx','%eax','%ebx','%ecx', '6','0xfe2ce6e0','10'); 261round4_step( 0,'%ecx','%edx','%eax','%ebx','13','0xa3014314','15'); 262round4_step( 0,'%ebx','%ecx','%edx','%eax', '4','0x4e0811a1','21'); 263round4_step( 0,'%eax','%ebx','%ecx','%edx','11','0xf7537e82', '6'); 264round4_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xbd3af235','10'); 265round4_step( 0,'%ecx','%edx','%eax','%ebx', '9','0x2ad7d2bb','15'); 266round4_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xeb86d391','21'); 267$code .= <<EOF; 268 / add old values of A, B, C, D 269 add %r8d, %eax 270 add %r9d, %ebx 271 add %r14d, %ecx 272 add %r15d, %edx 273 274 / loop control 275 add \$64, %rsi / ptr += 64 276 cmp %rdi, %rsi / cmp end with ptr 277 jb 2b / jmp if ptr < end 278 / END of loop over 64-byte blocks 279 2801: pop %rbp / restore ctx 281 mov %eax, 0*4(%rbp) / ctx->A = A 282 mov %ebx, 1*4(%rbp) / ctx->B = B 283 mov %ecx, 2*4(%rbp) / ctx->C = C 284 mov %edx, 3*4(%rbp) / ctx->D = D 285 286 pop %r15 287 pop %r14 288 pop %r13 289 pop %r12 290 pop %rbx 291 pop %rbp 292 ret 293 SET_SIZE(md5_block_asm_host_order) 294 295#endif /* lint || __lint */ 296EOF 297 298print $code; 299