3 # ====================================================================
4 # Written by Andy Polyakov, @dot-asm, initially for use with OpenSSL.
5 # ====================================================================
7 # ChaCha20 for Itanium.
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.
19 open STDOUT, ">$output" if $output;
21 my @k = map("r$_",(16..31));
22 my @x = map("r$_",(38..53));
23 my @y = map("r$_",(8..11));
24 my @z = map("r$_",(15,35..37));
25 my ($out,$inp,$len,$key,$counter) = map("r$_",(32..36));
28 #if defined(_HPUX_SOURCE)
40 .global ChaCha20_ctr32#
46 { .mmi; alloc r2=ar.pfs,5,17,0,0
50 { .mmi; ADDP $key=0,$key
51 ADDP $counter=0,$counter
56 { .mlx; ld4 @k[4]=[$key],8
57 movl @k[0]=0x61707865 }
58 { .mlx; ld4 @k[5]=[@k[11]],8
59 movl @k[1]=0x3320646e };;
60 { .mlx; ld4 @k[6]=[$key],8
61 movl @k[2]=0x79622d32 }
62 { .mlx; ld4 @k[7]=[@k[11]],8
63 movl @k[3]=0x6b206574 };;
64 { .mmi; ld4 @k[8]=[$key],8
66 add @k[15]=4,$counter };;
67 { .mmi; ld4 @k[10]=[$key]
70 { .mmi; ld4 @k[12]=[$counter],8
73 { .mmi; ld4 @k[14]=[$counter]
76 { .mmi; mov @x[3]=@k[3]
79 { .mmi; mov @x[6]=@k[6]
82 { .mmi; mov @x[9]=@k[9]
85 { .mmi; mov @x[12]=@k[12]
90 { .mii; mov @x[15]=@k[15]
93 { .mmb; cmp.geu p6,p0=64,$len
95 brp.loop.imp .Loop_top,.Loop_end-16 };;
100 my ($a0,$b0,$c0,$d0)=@_;
101 my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
102 my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
103 my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
106 { .mmi; add @x[$a0]=@x[$a0],@x[$b0]
107 add @x[$a1]=@x[$a1],@x[$b1]
108 add @x[$a2]=@x[$a2],@x[$b2] };;
109 { .mmi; add @x[$a3]=@x[$a3],@x[$b3]
110 xor @x[$d0]=@x[$d0],@x[$a0]
111 xor @x[$d1]=@x[$d1],@x[$a1] };;
112 { .mmi; xor @x[$d2]=@x[$d2],@x[$a2]
113 xor @x[$d3]=@x[$d3],@x[$a3]
114 extr.u @y[0]=@x[$d0],16,16 };;
115 { .mii; extr.u @y[1]=@x[$d1],16,16
116 dep @x[$d0]=@x[$d0],@y[0],16,16 };;
117 { .mii; add @x[$c0]=@x[$c0],@x[$d0]
118 extr.u @y[2]=@x[$d2],16,16
119 dep @x[$d1]=@x[$d1],@y[1],16,16 };;
120 { .mii; add @x[$c1]=@x[$c1],@x[$d1]
121 xor @x[$b0]=@x[$b0],@x[$c0]
122 extr.u @y[3]=@x[$d3],16,16 };;
123 { .mii; xor @x[$b1]=@x[$b1],@x[$c1]
124 dep @x[$d2]=@x[$d2],@y[2],16,16
125 dep @x[$d3]=@x[$d3],@y[3],16,16 };;
126 { .mmi; add @x[$c2]=@x[$c2],@x[$d2]
127 add @x[$c3]=@x[$c3],@x[$d3]
128 extr.u @y[0]=@x[$b0],20,12 };;
129 { .mmi; xor @x[$b2]=@x[$b2],@x[$c2]
130 xor @x[$b3]=@x[$b3],@x[$c3]
131 dep.z @x[$b0]=@x[$b0],12,20 };;
132 { .mii; or @x[$b0]=@x[$b0],@y[0]
133 extr.u @y[1]=@x[$b1],20,12
134 dep.z @x[$b1]=@x[$b1],12,20 };;
135 { .mii; add @x[$a0]=@x[$a0],@x[$b0]
136 extr.u @y[2]=@x[$b2],20,12
137 extr.u @y[3]=@x[$b3],20,12 }
138 { .mii; or @x[$b1]=@x[$b1],@y[1]
139 dep.z @x[$b2]=@x[$b2],12,20
140 dep.z @x[$b3]=@x[$b3],12,20 };;
141 { .mmi; or @x[$b2]=@x[$b2],@y[2]
142 or @x[$b3]=@x[$b3],@y[3]
143 add @x[$a1]=@x[$a1],@x[$b1] };;
144 { .mmi; add @x[$a2]=@x[$a2],@x[$b2]
145 add @x[$a3]=@x[$a3],@x[$b3]
146 xor @x[$d0]=@x[$d0],@x[$a0] };;
147 { .mii; xor @x[$d1]=@x[$d1],@x[$a1]
148 extr.u @y[0]=@x[$d0],24,8
149 dep.z @x[$d0]=@x[$d0],8,24 };;
150 { .mii; or @x[$d0]=@x[$d0],@y[0]
151 extr.u @y[1]=@x[$d1],24,8
152 dep.z @x[$d1]=@x[$d1],8,24 };;
153 { .mmi; or @x[$d1]=@x[$d1],@y[1]
154 xor @x[$d2]=@x[$d2],@x[$a2]
155 xor @x[$d3]=@x[$d3],@x[$a3] };;
156 { .mii; add @x[$c0]=@x[$c0],@x[$d0]
157 extr.u @y[2]=@x[$d2],24,8
158 dep.z @x[$d2]=@x[$d2],8,24 };;
159 { .mii; xor @x[$b0]=@x[$b0],@x[$c0]
160 extr.u @y[3]=@x[$d3],24,8
161 dep.z @x[$d3]=@x[$d3],8,24 };;
162 { .mmi; or @x[$d2]=@x[$d2],@y[2]
163 or @x[$d3]=@x[$d3],@y[3]
164 extr.u @y[0]=@x[$b0],25,7 };;
165 { .mmi; add @x[$c1]=@x[$c1],@x[$d1]
166 add @x[$c2]=@x[$c2],@x[$d2]
167 dep.z @x[$b0]=@x[$b0],7,25 };;
168 { .mmi; xor @x[$b1]=@x[$b1],@x[$c1]
169 xor @x[$b2]=@x[$b2],@x[$c2]
170 add @x[$c3]=@x[$c3],@x[$d3] };;
171 { .mii; xor @x[$b3]=@x[$b3],@x[$c3]
172 extr.u @y[1]=@x[$b1],25,7
173 dep.z @x[$b1]=@x[$b1],7,25 };;
174 { .mii; or @x[$b0]=@x[$b0],@y[0]
175 extr.u @y[2]=@x[$b2],25,7
176 dep.z @x[$b2]=@x[$b2],7,25 };;
177 { .mii; or @x[$b1]=@x[$b1],@y[1]
178 extr.u @y[3]=@x[$b3],25,7
179 dep.z @x[$b3]=@x[$b3],7,25 };;
181 $code.=<<___ if ($d0 == 12);
182 { .mmi; or @x[$b2]=@x[$b2],@y[2]
183 or @x[$b3]=@x[$b3],@y[3]
186 $code.=<<___ if ($d0 == 15);
187 { .mmb; or @x[$b2]=@x[$b2],@y[2]
188 or @x[$b3]=@x[$b3],@y[3]
189 br.ctop.sptk .Loop_top };;
193 &ROUND(0, 5, 10, 15);
197 { .mmi; add @x[0]=@x[0],@k[0]
198 add @x[1]=@x[1],@k[1]
199 (p6) shr.u @z[0]=@z[0],@z[1] }
200 { .mmb; add @x[2]=@x[2],@k[2]
201 add @x[3]=@x[3],@k[3]
203 { .mmi; add @x[4]=@x[4],@k[4]
204 add @x[5]=@x[5],@k[5]
205 add @x[6]=@x[6],@k[6] }
206 { .mmi; add @x[7]=@x[7],@k[7]
207 add @x[8]=@x[8],@k[8]
208 add @x[9]=@x[9],@k[9] }
209 { .mmi; add @x[10]=@x[10],@k[10]
210 add @x[11]=@x[11],@k[11]
211 add @x[12]=@x[12],@k[12] }
212 { .mmi; add @x[13]=@x[13],@k[13]
213 add @x[14]=@x[14],@k[14]
214 add @x[15]=@x[15],@k[15] }
215 { .mmi; add @k[12]=1,@k[12] // next counter
216 mov pr=@z[0],0x1ffff };;
218 //////////////////////////////////////////////////////////////////
219 // Each predicate bit corresponds to byte to be processed. Note
220 // that p0 is wired to 1, but it works out, because there always
221 // is at least one byte to process...
222 { .mmi; (p0) ld1 @z[0]=[$inp],1
223 shr.u @y[1]=@x[0],8 };;
224 { .mmi; (p1) ld1 @z[1]=[$inp],1
225 (p2) shr.u @y[2]=@x[0],16 };;
226 { .mmi; (p2) ld1 @z[2]=[$inp],1
227 (p0) xor @z[0]=@z[0],@x[0]
228 (p3) shr.u @y[3]=@x[0],24 };;
230 for(my $i0=0; $i0<60; $i0+=4) {
231 my ($i1, $i2, $i3, $i4, $i5, $i6, $i7) = map($i0+$_,(1..7));
235 { .mmi; (p$i3) ld1 @z[3]=[$inp],1
236 (p$i0) st1 [$out]=@z[0],1
237 (p$i1) xor @z[1]=@z[1],@y[1] };;
238 { .mmi; (p$i4) ld1 @z[0]=[$inp],1
239 (p$i5) shr.u @y[1]=@x[$k],8 }
240 { .mmi; (p$i1) st1 [$out]=@z[1],1
241 (p$i2) xor @z[2]=@z[2],@y[2]
242 (p1) mov @x[$k-1]=@k[$k-1] };;
243 { .mfi; (p$i5) ld1 @z[1]=[$inp],1
244 (p$i6) shr.u @y[2]=@x[$k],16 }
245 { .mfi; (p$i2) st1 [$out]=@z[2],1
246 (p$i3) xor @z[3]=@z[3],@y[3] };;
247 { .mfi; (p$i6) ld1 @z[2]=[$inp],1
248 (p$i7) shr.u @y[3]=@x[$k],24 }
250 $code.=<<___ if ($i0==0); # p1,p2 are available for reuse in first round
251 { .mmi; (p$i3) st1 [$out]=@z[3],1
252 (p$i4) xor @z[0]=@z[0],@x[$k]
253 cmp.ltu p1,p2=64,$len };;
255 $code.=<<___ if ($i0>0);
256 { .mfi; (p$i3) st1 [$out]=@z[3],1
257 (p$i4) xor @z[0]=@z[0],@x[$k] };;
261 { .mmi; (p63) ld1 @z[3]=[$inp],1
262 (p60) st1 [$out]=@z[0],1
263 (p61) xor @z[1]=@z[1],@y[1] };;
264 { .mmi; (p61) st1 [$out]=@z[1],1
265 (p62) xor @z[2]=@z[2],@y[2] };;
266 { .mmi; (p62) st1 [$out]=@z[2],1
267 (p63) xor @z[3]=@z[3],@y[3]
268 (p2) mov ar.lc=r3 };;
269 { .mib; (p63) st1 [$out]=@z[3],1
270 (p1) add $len=-64,$len
271 (p1) br.dptk.many .Loop_outer };;
273 { .mmi; mov @k[4]=0 // wipe key material
285 { .mib; mov pr=r14,0x1ffff
286 br.ret.sptk.many b0 };;
287 .endp ChaCha20_ctr32#
288 stringz "ChaCha20 for IA64, CRYPTOGAMS by \@dot-asm"