1#!/usr/bin/env perl 2# 3# ==================================================================== 4# Written by Andy Polyakov, @dot-asm, initially for use with OpenSSL. 5# ==================================================================== 6# 7# ChaCha20 for Itanium. 8# 9# March 2019 10# 11# Itanium 9xxx, which has pair of shifters, manages to process one byte 12# in 9.3 cycles. This aligns perfectly with theoretical estimate. 13# On the other hand, pre-9000 CPU has single shifter and each extr/dep 14# pairs below takes additional cycle. Then final input->xor->output 15# pass runs slower than expected... Overall result is 15.6 cpb, two 16# cycles more than theoretical estimate. 17 18$output = pop and open STDOUT, ">$output"; 19 20my @k = map("r$_",(16..31)); 21my @x = map("r$_",(38..53)); 22my @y = map("r$_",(8..11)); 23my @z = map("r$_",(15,35..37)); 24my ($out,$inp,$len,$key,$counter) = map("r$_",(32..36)); 25 26$code.=<<___; 27#if defined(_HPUX_SOURCE) 28# if !defined(_LP64) 29# define ADDP addp4 30# else 31# define ADDP add 32# endif 33#else 34# define ADDP add 35#endif 36 37.text 38 39.global ChaCha20_ctr32# 40.proc ChaCha20_ctr32# 41.align 32 42ChaCha20_ctr32: 43 .prologue 44 .save ar.pfs,r2 45{ .mmi; alloc r2=ar.pfs,5,17,0,0 46 ADDP @k[11]=4,$key 47 .save ar.lc,r3 48 mov r3=ar.lc } 49{ .mmi; ADDP $out=0,$out 50 ADDP $inp=0,$inp } 51{ .mmi; ADDP $key=0,$key 52 ADDP $counter=0,$counter 53 .save pr,r14 54 mov r14=pr };; 55 56 .body 57{ .mlx; ld4 @k[4]=[$key],8 58 movl @k[0]=0x61707865 } 59{ .mlx; ld4 @k[5]=[@k[11]],8 60 movl @k[1]=0x3320646e };; 61{ .mlx; ld4 @k[6]=[$key],8 62 movl @k[2]=0x79622d32 } 63{ .mlx; ld4 @k[7]=[@k[11]],8 64 movl @k[3]=0x6b206574 };; 65{ .mmi; ld4 @k[8]=[$key],8 66 ld4 @k[9]=[@k[11]],8 67 add @k[15]=4,$counter };; 68{ .mmi; ld4 @k[10]=[$key] 69 ld4 @k[11]=[@k[11]] 70 mov @x[0]=@k[0] };; 71{ .mmi; ld4 @k[12]=[$counter],8 72 ld4 @k[13]=[@k[15]],8 73 mov @x[1]=@k[1] };; 74{ .mmi; ld4 @k[14]=[$counter] 75 ld4 @k[15]=[@k[15]] 76 mov @x[2]=@k[2] } 77{ .mmi; mov @x[3]=@k[3] 78 mov @x[4]=@k[4] 79 mov @x[5]=@k[5] };; 80{ .mmi; mov @x[6]=@k[6] 81 mov @x[7]=@k[7] 82 mov @x[8]=@k[8] } 83{ .mmi; mov @x[9]=@k[9] 84 mov @x[10]=@k[10] 85 mov @x[11]=@k[11] } 86{ .mmi; mov @x[12]=@k[12] 87 mov @x[13]=@k[13] 88 mov @x[14]=@k[14] };; 89 90.Loop_outer: 91{ .mii; mov @x[15]=@k[15] 92 mov ar.lc=9 93 mov ar.ec=1 } 94{ .mmb; cmp.geu p6,p0=64,$len 95 sub @z[1]=64,$len 96 brp.loop.imp .Loop_top,.Loop_end-16 };; 97 98.Loop_top: 99___ 100sub ROUND { 101my ($a0,$b0,$c0,$d0)=@_; 102my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0)); 103my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1)); 104my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2)); 105 106$code.=<<___; 107{ .mmi; add @x[$a0]=@x[$a0],@x[$b0] 108 add @x[$a1]=@x[$a1],@x[$b1] 109 add @x[$a2]=@x[$a2],@x[$b2] };; 110{ .mmi; add @x[$a3]=@x[$a3],@x[$b3] 111 xor @x[$d0]=@x[$d0],@x[$a0] 112 xor @x[$d1]=@x[$d1],@x[$a1] };; 113{ .mmi; xor @x[$d2]=@x[$d2],@x[$a2] 114 xor @x[$d3]=@x[$d3],@x[$a3] 115 extr.u @y[0]=@x[$d0],16,16 };; 116{ .mii; extr.u @y[1]=@x[$d1],16,16 117 dep @x[$d0]=@x[$d0],@y[0],16,16 };; 118{ .mii; add @x[$c0]=@x[$c0],@x[$d0] 119 extr.u @y[2]=@x[$d2],16,16 120 dep @x[$d1]=@x[$d1],@y[1],16,16 };; 121{ .mii; add @x[$c1]=@x[$c1],@x[$d1] 122 xor @x[$b0]=@x[$b0],@x[$c0] 123 extr.u @y[3]=@x[$d3],16,16 };; 124{ .mii; xor @x[$b1]=@x[$b1],@x[$c1] 125 dep @x[$d2]=@x[$d2],@y[2],16,16 126 dep @x[$d3]=@x[$d3],@y[3],16,16 };; 127{ .mmi; add @x[$c2]=@x[$c2],@x[$d2] 128 add @x[$c3]=@x[$c3],@x[$d3] 129 extr.u @y[0]=@x[$b0],20,12 };; 130{ .mmi; xor @x[$b2]=@x[$b2],@x[$c2] 131 xor @x[$b3]=@x[$b3],@x[$c3] 132 dep.z @x[$b0]=@x[$b0],12,20 };; 133{ .mii; or @x[$b0]=@x[$b0],@y[0] 134 extr.u @y[1]=@x[$b1],20,12 135 dep.z @x[$b1]=@x[$b1],12,20 };; 136{ .mii; add @x[$a0]=@x[$a0],@x[$b0] 137 extr.u @y[2]=@x[$b2],20,12 138 extr.u @y[3]=@x[$b3],20,12 } 139{ .mii; or @x[$b1]=@x[$b1],@y[1] 140 dep.z @x[$b2]=@x[$b2],12,20 141 dep.z @x[$b3]=@x[$b3],12,20 };; 142{ .mmi; or @x[$b2]=@x[$b2],@y[2] 143 or @x[$b3]=@x[$b3],@y[3] 144 add @x[$a1]=@x[$a1],@x[$b1] };; 145{ .mmi; add @x[$a2]=@x[$a2],@x[$b2] 146 add @x[$a3]=@x[$a3],@x[$b3] 147 xor @x[$d0]=@x[$d0],@x[$a0] };; 148{ .mii; xor @x[$d1]=@x[$d1],@x[$a1] 149 extr.u @y[0]=@x[$d0],24,8 150 dep.z @x[$d0]=@x[$d0],8,24 };; 151{ .mii; or @x[$d0]=@x[$d0],@y[0] 152 extr.u @y[1]=@x[$d1],24,8 153 dep.z @x[$d1]=@x[$d1],8,24 };; 154{ .mmi; or @x[$d1]=@x[$d1],@y[1] 155 xor @x[$d2]=@x[$d2],@x[$a2] 156 xor @x[$d3]=@x[$d3],@x[$a3] };; 157{ .mii; add @x[$c0]=@x[$c0],@x[$d0] 158 extr.u @y[2]=@x[$d2],24,8 159 dep.z @x[$d2]=@x[$d2],8,24 };; 160{ .mii; xor @x[$b0]=@x[$b0],@x[$c0] 161 extr.u @y[3]=@x[$d3],24,8 162 dep.z @x[$d3]=@x[$d3],8,24 };; 163{ .mmi; or @x[$d2]=@x[$d2],@y[2] 164 or @x[$d3]=@x[$d3],@y[3] 165 extr.u @y[0]=@x[$b0],25,7 };; 166{ .mmi; add @x[$c1]=@x[$c1],@x[$d1] 167 add @x[$c2]=@x[$c2],@x[$d2] 168 dep.z @x[$b0]=@x[$b0],7,25 };; 169{ .mmi; xor @x[$b1]=@x[$b1],@x[$c1] 170 xor @x[$b2]=@x[$b2],@x[$c2] 171 add @x[$c3]=@x[$c3],@x[$d3] };; 172{ .mii; xor @x[$b3]=@x[$b3],@x[$c3] 173 extr.u @y[1]=@x[$b1],25,7 174 dep.z @x[$b1]=@x[$b1],7,25 };; 175{ .mii; or @x[$b0]=@x[$b0],@y[0] 176 extr.u @y[2]=@x[$b2],25,7 177 dep.z @x[$b2]=@x[$b2],7,25 };; 178{ .mii; or @x[$b1]=@x[$b1],@y[1] 179 extr.u @y[3]=@x[$b3],25,7 180 dep.z @x[$b3]=@x[$b3],7,25 };; 181___ 182$code.=<<___ if ($d0 == 12); 183{ .mmi; or @x[$b2]=@x[$b2],@y[2] 184 or @x[$b3]=@x[$b3],@y[3] 185 mov @z[0]=-1 };; 186___ 187$code.=<<___ if ($d0 == 15); 188{ .mmb; or @x[$b2]=@x[$b2],@y[2] 189 or @x[$b3]=@x[$b3],@y[3] 190 br.ctop.sptk .Loop_top };; 191___ 192} 193 &ROUND(0, 4, 8, 12); 194 &ROUND(0, 5, 10, 15); 195$code.=<<___; 196.Loop_end: 197 198{ .mmi; add @x[0]=@x[0],@k[0] 199 add @x[1]=@x[1],@k[1] 200(p6) shr.u @z[0]=@z[0],@z[1] } 201{ .mmb; add @x[2]=@x[2],@k[2] 202 add @x[3]=@x[3],@k[3] 203 clrrrb.pr };; 204{ .mmi; add @x[4]=@x[4],@k[4] 205 add @x[5]=@x[5],@k[5] 206 add @x[6]=@x[6],@k[6] } 207{ .mmi; add @x[7]=@x[7],@k[7] 208 add @x[8]=@x[8],@k[8] 209 add @x[9]=@x[9],@k[9] } 210{ .mmi; add @x[10]=@x[10],@k[10] 211 add @x[11]=@x[11],@k[11] 212 add @x[12]=@x[12],@k[12] } 213{ .mmi; add @x[13]=@x[13],@k[13] 214 add @x[14]=@x[14],@k[14] 215 add @x[15]=@x[15],@k[15] } 216{ .mmi; add @k[12]=1,@k[12] // next counter 217 mov pr=@z[0],0x1ffff };; 218 219////////////////////////////////////////////////////////////////// 220// Each predicate bit corresponds to byte to be processed. Note 221// that p0 is wired to 1, but it works out, because there always 222// is at least one byte to process... 223{ .mmi; (p0) ld1 @z[0]=[$inp],1 224 shr.u @y[1]=@x[0],8 };; 225{ .mmi; (p1) ld1 @z[1]=[$inp],1 226 (p2) shr.u @y[2]=@x[0],16 };; 227{ .mmi; (p2) ld1 @z[2]=[$inp],1 228 (p0) xor @z[0]=@z[0],@x[0] 229 (p3) shr.u @y[3]=@x[0],24 };; 230___ 231for(my $i0=0; $i0<60; $i0+=4) { 232my ($i1, $i2, $i3, $i4, $i5, $i6, $i7) = map($i0+$_,(1..7)); 233my $k = $i0/4+1; 234 235$code.=<<___; 236{ .mmi; (p$i3) ld1 @z[3]=[$inp],1 237 (p$i0) st1 [$out]=@z[0],1 238 (p$i1) xor @z[1]=@z[1],@y[1] };; 239{ .mmi; (p$i4) ld1 @z[0]=[$inp],1 240 (p$i5) shr.u @y[1]=@x[$k],8 } 241{ .mmi; (p$i1) st1 [$out]=@z[1],1 242 (p$i2) xor @z[2]=@z[2],@y[2] 243 (p1) mov @x[$k-1]=@k[$k-1] };; 244{ .mfi; (p$i5) ld1 @z[1]=[$inp],1 245 (p$i6) shr.u @y[2]=@x[$k],16 } 246{ .mfi; (p$i2) st1 [$out]=@z[2],1 247 (p$i3) xor @z[3]=@z[3],@y[3] };; 248{ .mfi; (p$i6) ld1 @z[2]=[$inp],1 249 (p$i7) shr.u @y[3]=@x[$k],24 } 250___ 251$code.=<<___ if ($i0==0); # p1,p2 are available for reuse in first round 252{ .mmi; (p$i3) st1 [$out]=@z[3],1 253 (p$i4) xor @z[0]=@z[0],@x[$k] 254 cmp.ltu p1,p2=64,$len };; 255___ 256$code.=<<___ if ($i0>0); 257{ .mfi; (p$i3) st1 [$out]=@z[3],1 258 (p$i4) xor @z[0]=@z[0],@x[$k] };; 259___ 260} 261$code.=<<___; 262{ .mmi; (p63) ld1 @z[3]=[$inp],1 263 (p60) st1 [$out]=@z[0],1 264 (p61) xor @z[1]=@z[1],@y[1] };; 265{ .mmi; (p61) st1 [$out]=@z[1],1 266 (p62) xor @z[2]=@z[2],@y[2] };; 267{ .mmi; (p62) st1 [$out]=@z[2],1 268 (p63) xor @z[3]=@z[3],@y[3] 269 (p2) mov ar.lc=r3 };; 270{ .mib; (p63) st1 [$out]=@z[3],1 271 (p1) add $len=-64,$len 272(p1) br.dptk.many .Loop_outer };; 273 274{ .mmi; mov @k[4]=0 // wipe key material 275 mov @k[5]=0 276 mov @k[6]=0 } 277{ .mmi; mov @k[7]=0 278 mov @k[8]=0 279 mov @k[9]=0 } 280{ .mmi; mov @k[10]=0 281 mov @k[11]=0 282 mov @k[12]=0 } 283{ .mmi; mov @k[13]=0 284 mov @k[14]=0 285 mov @k[15]=0 } 286{ .mib; mov pr=r14,0x1ffff 287 br.ret.sptk.many b0 };; 288.endp ChaCha20_ctr32# 289stringz "ChaCha20 for IA64, CRYPTOGAMS by \@dot-asm" 290___ 291 292print $code; 293close STDOUT or die "error closing STDOUT: $!"; 294