• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#include "arm_arch.h"
2
3.text
4#if defined(__thumb2__)
5.syntax	unified
6.thumb
7#else
8.code	32
9#endif
10
11.globl	poly1305_emit
12.globl	poly1305_blocks
13.globl	poly1305_init
14.type	poly1305_init,%function
15.align	5
16poly1305_init:
17.Lpoly1305_init:
18	stmdb	sp!,{r4-r11}
19
20	eor	r3,r3,r3
21	cmp	r1,#0
22	str	r3,[r0,#0]		@ zero hash value
23	str	r3,[r0,#4]
24	str	r3,[r0,#8]
25	str	r3,[r0,#12]
26	str	r3,[r0,#16]
27	str	r3,[r0,#36]		@ is_base2_26
28	add	r0,r0,#20
29
30#ifdef	__thumb2__
31	it	eq
32#endif
33	moveq	r0,#0
34	beq	.Lno_key
35
36#if	__ARM_MAX_ARCH__>=7
37	adr	r11,.Lpoly1305_init
38	ldr	r12,.LOPENSSL_armcap
39#endif
40	ldrb	r4,[r1,#0]
41	mov	r10,#0x0fffffff
42	ldrb	r5,[r1,#1]
43	and	r3,r10,#-4		@ 0x0ffffffc
44	ldrb	r6,[r1,#2]
45	ldrb	r7,[r1,#3]
46	orr	r4,r4,r5,lsl#8
47	ldrb	r5,[r1,#4]
48	orr	r4,r4,r6,lsl#16
49	ldrb	r6,[r1,#5]
50	orr	r4,r4,r7,lsl#24
51	ldrb	r7,[r1,#6]
52	and	r4,r4,r10
53
54#if	__ARM_MAX_ARCH__>=7
55	ldr	r12,[r11,r12]		@ OPENSSL_armcap_P
56# ifdef	__APPLE__
57	ldr	r12,[r12]
58# endif
59#endif
60	ldrb	r8,[r1,#7]
61	orr	r5,r5,r6,lsl#8
62	ldrb	r6,[r1,#8]
63	orr	r5,r5,r7,lsl#16
64	ldrb	r7,[r1,#9]
65	orr	r5,r5,r8,lsl#24
66	ldrb	r8,[r1,#10]
67	and	r5,r5,r3
68
69#if	__ARM_MAX_ARCH__>=7
70	tst	r12,#ARMV7_NEON		@ check for NEON
71# ifdef	__APPLE__
72	adr	r9,poly1305_blocks_neon
73	adr	r11,poly1305_blocks
74#  ifdef __thumb2__
75	it	ne
76#  endif
77	movne	r11,r9
78	adr	r12,poly1305_emit
79	adr	r10,poly1305_emit_neon
80#  ifdef __thumb2__
81	it	ne
82#  endif
83	movne	r12,r10
84# else
85#  ifdef __thumb2__
86	itete	eq
87#  endif
88	addeq	r12,r11,#(.Lpoly1305_emit-.Lpoly1305_init)
89	addne	r12,r11,#(.Lpoly1305_emit_neon-.Lpoly1305_init)
90	addeq	r11,r11,#(.Lpoly1305_blocks-.Lpoly1305_init)
91	addne	r11,r11,#(.Lpoly1305_blocks_neon-.Lpoly1305_init)
92# endif
93# ifdef	__thumb2__
94	orr	r12,r12,#1	@ thumb-ify address
95	orr	r11,r11,#1
96# endif
97#endif
98	ldrb	r9,[r1,#11]
99	orr	r6,r6,r7,lsl#8
100	ldrb	r7,[r1,#12]
101	orr	r6,r6,r8,lsl#16
102	ldrb	r8,[r1,#13]
103	orr	r6,r6,r9,lsl#24
104	ldrb	r9,[r1,#14]
105	and	r6,r6,r3
106
107	ldrb	r10,[r1,#15]
108	orr	r7,r7,r8,lsl#8
109	str	r4,[r0,#0]
110	orr	r7,r7,r9,lsl#16
111	str	r5,[r0,#4]
112	orr	r7,r7,r10,lsl#24
113	str	r6,[r0,#8]
114	and	r7,r7,r3
115	str	r7,[r0,#12]
116#if	__ARM_MAX_ARCH__>=7
117	stmia	r2,{r11,r12}		@ fill functions table
118	mov	r0,#1
119#else
120	mov	r0,#0
121#endif
122.Lno_key:
123	ldmia	sp!,{r4-r11}
124#if	__ARM_ARCH__>=5
125	bx	lr				@ bx	lr
126#else
127	tst	lr,#1
128	moveq	pc,lr			@ be binary compatible with V4, yet
129	.word	0xe12fff1e			@ interoperable with Thumb ISA:-)
130#endif
131.size	poly1305_init,.-poly1305_init
132.type	poly1305_blocks,%function
133.align	5
134poly1305_blocks:
135.Lpoly1305_blocks:
136	stmdb	sp!,{r3-r11,lr}
137
138	ands	r2,r2,#-16
139	beq	.Lno_data
140
141	cmp	r3,#0
142	add	r2,r2,r1		@ end pointer
143	sub	sp,sp,#32
144
145	ldmia	r0,{r4-r12}		@ load context
146
147	str	r0,[sp,#12]		@ offload stuff
148	mov	lr,r1
149	str	r2,[sp,#16]
150	str	r10,[sp,#20]
151	str	r11,[sp,#24]
152	str	r12,[sp,#28]
153	b	.Loop
154
155.Loop:
156#if __ARM_ARCH__<7
157	ldrb	r0,[lr],#16		@ load input
158# ifdef	__thumb2__
159	it	hi
160# endif
161	addhi	r8,r8,#1		@ 1<<128
162	ldrb	r1,[lr,#-15]
163	ldrb	r2,[lr,#-14]
164	ldrb	r3,[lr,#-13]
165	orr	r1,r0,r1,lsl#8
166	ldrb	r0,[lr,#-12]
167	orr	r2,r1,r2,lsl#16
168	ldrb	r1,[lr,#-11]
169	orr	r3,r2,r3,lsl#24
170	ldrb	r2,[lr,#-10]
171	adds	r4,r4,r3		@ accumulate input
172
173	ldrb	r3,[lr,#-9]
174	orr	r1,r0,r1,lsl#8
175	ldrb	r0,[lr,#-8]
176	orr	r2,r1,r2,lsl#16
177	ldrb	r1,[lr,#-7]
178	orr	r3,r2,r3,lsl#24
179	ldrb	r2,[lr,#-6]
180	adcs	r5,r5,r3
181
182	ldrb	r3,[lr,#-5]
183	orr	r1,r0,r1,lsl#8
184	ldrb	r0,[lr,#-4]
185	orr	r2,r1,r2,lsl#16
186	ldrb	r1,[lr,#-3]
187	orr	r3,r2,r3,lsl#24
188	ldrb	r2,[lr,#-2]
189	adcs	r6,r6,r3
190
191	ldrb	r3,[lr,#-1]
192	orr	r1,r0,r1,lsl#8
193	str	lr,[sp,#8]		@ offload input pointer
194	orr	r2,r1,r2,lsl#16
195	add	r10,r10,r10,lsr#2
196	orr	r3,r2,r3,lsl#24
197#else
198	ldr	r0,[lr],#16		@ load input
199# ifdef	__thumb2__
200	it	hi
201# endif
202	addhi	r8,r8,#1		@ padbit
203	ldr	r1,[lr,#-12]
204	ldr	r2,[lr,#-8]
205	ldr	r3,[lr,#-4]
206# ifdef	__ARMEB__
207	rev	r0,r0
208	rev	r1,r1
209	rev	r2,r2
210	rev	r3,r3
211# endif
212	adds	r4,r4,r0		@ accumulate input
213	str	lr,[sp,#8]		@ offload input pointer
214	adcs	r5,r5,r1
215	add	r10,r10,r10,lsr#2
216	adcs	r6,r6,r2
217#endif
218	add	r11,r11,r11,lsr#2
219	adcs	r7,r7,r3
220	add	r12,r12,r12,lsr#2
221
222	umull	r2,r3,r5,r9
223	 adc	r8,r8,#0
224	umull	r0,r1,r4,r9
225	umlal	r2,r3,r8,r10
226	umlal	r0,r1,r7,r10
227	ldr	r10,[sp,#20]		@ reload r10
228	umlal	r2,r3,r6,r12
229	umlal	r0,r1,r5,r12
230	umlal	r2,r3,r7,r11
231	umlal	r0,r1,r6,r11
232	umlal	r2,r3,r4,r10
233	str	r0,[sp,#0]		@ future r4
234	 mul	r0,r11,r8
235	ldr	r11,[sp,#24]		@ reload r11
236	adds	r2,r2,r1		@ d1+=d0>>32
237	 eor	r1,r1,r1
238	adc	lr,r3,#0		@ future r6
239	str	r2,[sp,#4]		@ future r5
240
241	mul	r2,r12,r8
242	eor	r3,r3,r3
243	umlal	r0,r1,r7,r12
244	ldr	r12,[sp,#28]		@ reload r12
245	umlal	r2,r3,r7,r9
246	umlal	r0,r1,r6,r9
247	umlal	r2,r3,r6,r10
248	umlal	r0,r1,r5,r10
249	umlal	r2,r3,r5,r11
250	umlal	r0,r1,r4,r11
251	umlal	r2,r3,r4,r12
252	ldr	r4,[sp,#0]
253	mul	r8,r9,r8
254	ldr	r5,[sp,#4]
255
256	adds	r6,lr,r0		@ d2+=d1>>32
257	ldr	lr,[sp,#8]		@ reload input pointer
258	adc	r1,r1,#0
259	adds	r7,r2,r1		@ d3+=d2>>32
260	ldr	r0,[sp,#16]		@ reload end pointer
261	adc	r3,r3,#0
262	add	r8,r8,r3		@ h4+=d3>>32
263
264	and	r1,r8,#-4
265	and	r8,r8,#3
266	add	r1,r1,r1,lsr#2		@ *=5
267	adds	r4,r4,r1
268	adcs	r5,r5,#0
269	adcs	r6,r6,#0
270	adcs	r7,r7,#0
271	adc	r8,r8,#0
272
273	cmp	r0,lr			@ done yet?
274	bhi	.Loop
275
276	ldr	r0,[sp,#12]
277	add	sp,sp,#32
278	stmia	r0,{r4-r8}		@ store the result
279
280.Lno_data:
281#if	__ARM_ARCH__>=5
282	ldmia	sp!,{r3-r11,pc}
283#else
284	ldmia	sp!,{r3-r11,lr}
285	tst	lr,#1
286	moveq	pc,lr			@ be binary compatible with V4, yet
287	.word	0xe12fff1e			@ interoperable with Thumb ISA:-)
288#endif
289.size	poly1305_blocks,.-poly1305_blocks
290.type	poly1305_emit,%function
291.align	5
292poly1305_emit:
293.Lpoly1305_emit:
294	stmdb	sp!,{r4-r11}
295.Lpoly1305_emit_enter:
296
297	ldmia	r0,{r3-r7}
298	adds	r8,r3,#5		@ compare to modulus
299	adcs	r9,r4,#0
300	adcs	r10,r5,#0
301	adcs	r11,r6,#0
302	adc	r7,r7,#0
303	tst	r7,#4			@ did it carry/borrow?
304
305#ifdef	__thumb2__
306	it	ne
307#endif
308	movne	r3,r8
309	ldr	r8,[r2,#0]
310#ifdef	__thumb2__
311	it	ne
312#endif
313	movne	r4,r9
314	ldr	r9,[r2,#4]
315#ifdef	__thumb2__
316	it	ne
317#endif
318	movne	r5,r10
319	ldr	r10,[r2,#8]
320#ifdef	__thumb2__
321	it	ne
322#endif
323	movne	r6,r11
324	ldr	r11,[r2,#12]
325
326	adds	r3,r3,r8
327	adcs	r4,r4,r9
328	adcs	r5,r5,r10
329	adc	r6,r6,r11
330
331#if __ARM_ARCH__>=7
332# ifdef __ARMEB__
333	rev	r3,r3
334	rev	r4,r4
335	rev	r5,r5
336	rev	r6,r6
337# endif
338	str	r3,[r1,#0]
339	str	r4,[r1,#4]
340	str	r5,[r1,#8]
341	str	r6,[r1,#12]
342#else
343	strb	r3,[r1,#0]
344	mov	r3,r3,lsr#8
345	strb	r4,[r1,#4]
346	mov	r4,r4,lsr#8
347	strb	r5,[r1,#8]
348	mov	r5,r5,lsr#8
349	strb	r6,[r1,#12]
350	mov	r6,r6,lsr#8
351
352	strb	r3,[r1,#1]
353	mov	r3,r3,lsr#8
354	strb	r4,[r1,#5]
355	mov	r4,r4,lsr#8
356	strb	r5,[r1,#9]
357	mov	r5,r5,lsr#8
358	strb	r6,[r1,#13]
359	mov	r6,r6,lsr#8
360
361	strb	r3,[r1,#2]
362	mov	r3,r3,lsr#8
363	strb	r4,[r1,#6]
364	mov	r4,r4,lsr#8
365	strb	r5,[r1,#10]
366	mov	r5,r5,lsr#8
367	strb	r6,[r1,#14]
368	mov	r6,r6,lsr#8
369
370	strb	r3,[r1,#3]
371	strb	r4,[r1,#7]
372	strb	r5,[r1,#11]
373	strb	r6,[r1,#15]
374#endif
375	ldmia	sp!,{r4-r11}
376#if	__ARM_ARCH__>=5
377	bx	lr				@ bx	lr
378#else
379	tst	lr,#1
380	moveq	pc,lr			@ be binary compatible with V4, yet
381	.word	0xe12fff1e			@ interoperable with Thumb ISA:-)
382#endif
383.size	poly1305_emit,.-poly1305_emit
384#if	__ARM_MAX_ARCH__>=7
385.fpu	neon
386
387.type	poly1305_init_neon,%function
388.align	5
389poly1305_init_neon:
390	ldr	r4,[r0,#20]		@ load key base 2^32
391	ldr	r5,[r0,#24]
392	ldr	r6,[r0,#28]
393	ldr	r7,[r0,#32]
394
395	and	r2,r4,#0x03ffffff	@ base 2^32 -> base 2^26
396	mov	r3,r4,lsr#26
397	mov	r4,r5,lsr#20
398	orr	r3,r3,r5,lsl#6
399	mov	r5,r6,lsr#14
400	orr	r4,r4,r6,lsl#12
401	mov	r6,r7,lsr#8
402	orr	r5,r5,r7,lsl#18
403	and	r3,r3,#0x03ffffff
404	and	r4,r4,#0x03ffffff
405	and	r5,r5,#0x03ffffff
406
407	vdup.32	d0,r2			@ r^1 in both lanes
408	add	r2,r3,r3,lsl#2		@ *5
409	vdup.32	d1,r3
410	add	r3,r4,r4,lsl#2
411	vdup.32	d2,r2
412	vdup.32	d3,r4
413	add	r4,r5,r5,lsl#2
414	vdup.32	d4,r3
415	vdup.32	d5,r5
416	add	r5,r6,r6,lsl#2
417	vdup.32	d6,r4
418	vdup.32	d7,r6
419	vdup.32	d8,r5
420
421	mov	r5,#2		@ counter
422
423.Lsquare_neon:
424	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
425	@ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
426	@ d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
427	@ d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
428	@ d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
429	@ d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
430
431	vmull.u32	q5,d0,d0[1]
432	vmull.u32	q6,d1,d0[1]
433	vmull.u32	q7,d3,d0[1]
434	vmull.u32	q8,d5,d0[1]
435	vmull.u32	q9,d7,d0[1]
436
437	vmlal.u32	q5,d7,d2[1]
438	vmlal.u32	q6,d0,d1[1]
439	vmlal.u32	q7,d1,d1[1]
440	vmlal.u32	q8,d3,d1[1]
441	vmlal.u32	q9,d5,d1[1]
442
443	vmlal.u32	q5,d5,d4[1]
444	vmlal.u32	q6,d7,d4[1]
445	vmlal.u32	q8,d1,d3[1]
446	vmlal.u32	q7,d0,d3[1]
447	vmlal.u32	q9,d3,d3[1]
448
449	vmlal.u32	q5,d3,d6[1]
450	vmlal.u32	q8,d0,d5[1]
451	vmlal.u32	q6,d5,d6[1]
452	vmlal.u32	q7,d7,d6[1]
453	vmlal.u32	q9,d1,d5[1]
454
455	vmlal.u32	q8,d7,d8[1]
456	vmlal.u32	q5,d1,d8[1]
457	vmlal.u32	q6,d3,d8[1]
458	vmlal.u32	q7,d5,d8[1]
459	vmlal.u32	q9,d0,d7[1]
460
461	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
462	@ lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
463	@ and P. Schwabe
464	@
465	@ H0>>+H1>>+H2>>+H3>>+H4
466	@ H3>>+H4>>*5+H0>>+H1
467	@
468	@ Trivia.
469	@
470	@ Result of multiplication of n-bit number by m-bit number is
471	@ n+m bits wide. However! Even though 2^n is a n+1-bit number,
472	@ m-bit number multiplied by 2^n is still n+m bits wide.
473	@
474	@ Sum of two n-bit numbers is n+1 bits wide, sum of three - n+2,
475	@ and so is sum of four. Sum of 2^m n-m-bit numbers and n-bit
476	@ one is n+1 bits wide.
477	@
478	@ >>+ denotes Hnext += Hn>>26, Hn &= 0x3ffffff. This means that
479	@ H0, H2, H3 are guaranteed to be 26 bits wide, while H1 and H4
480	@ can be 27. However! In cases when their width exceeds 26 bits
481	@ they are limited by 2^26+2^6. This in turn means that *sum*
482	@ of the products with these values can still be viewed as sum
483	@ of 52-bit numbers as long as the amount of addends is not a
484	@ power of 2. For example,
485	@
486	@ H4 = H4*R0 + H3*R1 + H2*R2 + H1*R3 + H0 * R4,
487	@
488	@ which can't be larger than 5 * (2^26 + 2^6) * (2^26 + 2^6), or
489	@ 5 * (2^52 + 2*2^32 + 2^12), which in turn is smaller than
490	@ 8 * (2^52) or 2^55. However, the value is then multiplied by
491	@ by 5, so we should be looking at 5 * 5 * (2^52 + 2^33 + 2^12),
492	@ which is less than 32 * (2^52) or 2^57. And when processing
493	@ data we are looking at triple as many addends...
494	@
495	@ In key setup procedure pre-reduced H0 is limited by 5*4+1 and
496	@ 5*H4 - by 5*5 52-bit addends, or 57 bits. But when hashing the
497	@ input H0 is limited by (5*4+1)*3 addends, or 58 bits, while
498	@ 5*H4 by 5*5*3, or 59[!] bits. How is this relevant? vmlal.u32
499	@ instruction accepts 2x32-bit input and writes 2x64-bit result.
500	@ This means that result of reduction have to be compressed upon
501	@ loop wrap-around. This can be done in the process of reduction
502	@ to minimize amount of instructions [as well as amount of
503	@ 128-bit instructions, which benefits low-end processors], but
504	@ one has to watch for H2 (which is narrower than H0) and 5*H4
505	@ not being wider than 58 bits, so that result of right shift
506	@ by 26 bits fits in 32 bits. This is also useful on x86,
507	@ because it allows to use paddd in place for paddq, which
508	@ benefits Atom, where paddq is ridiculously slow.
509
510	vshr.u64	q15,q8,#26
511	vmovn.i64	d16,q8
512	 vshr.u64	q4,q5,#26
513	 vmovn.i64	d10,q5
514	vadd.i64	q9,q9,q15		@ h3 -> h4
515	vbic.i32	d16,#0xfc000000	@ &=0x03ffffff
516	 vadd.i64	q6,q6,q4		@ h0 -> h1
517	 vbic.i32	d10,#0xfc000000
518
519	vshrn.u64	d30,q9,#26
520	vmovn.i64	d18,q9
521	 vshr.u64	q4,q6,#26
522	 vmovn.i64	d12,q6
523	 vadd.i64	q7,q7,q4		@ h1 -> h2
524	vbic.i32	d18,#0xfc000000
525	 vbic.i32	d12,#0xfc000000
526
527	vadd.i32	d10,d10,d30
528	vshl.u32	d30,d30,#2
529	 vshrn.u64	d8,q7,#26
530	 vmovn.i64	d14,q7
531	vadd.i32	d10,d10,d30	@ h4 -> h0
532	 vadd.i32	d16,d16,d8	@ h2 -> h3
533	 vbic.i32	d14,#0xfc000000
534
535	vshr.u32	d30,d10,#26
536	vbic.i32	d10,#0xfc000000
537	 vshr.u32	d8,d16,#26
538	 vbic.i32	d16,#0xfc000000
539	vadd.i32	d12,d12,d30	@ h0 -> h1
540	 vadd.i32	d18,d18,d8	@ h3 -> h4
541
542	subs		r5,r5,#1
543	beq		.Lsquare_break_neon
544
545	add		r6,r0,#(48+0*9*4)
546	add		r7,r0,#(48+1*9*4)
547
548	vtrn.32		d0,d10		@ r^2:r^1
549	vtrn.32		d3,d14
550	vtrn.32		d5,d16
551	vtrn.32		d1,d12
552	vtrn.32		d7,d18
553
554	vshl.u32	d4,d3,#2		@ *5
555	vshl.u32	d6,d5,#2
556	vshl.u32	d2,d1,#2
557	vshl.u32	d8,d7,#2
558	vadd.i32	d4,d4,d3
559	vadd.i32	d2,d2,d1
560	vadd.i32	d6,d6,d5
561	vadd.i32	d8,d8,d7
562
563	vst4.32		{d0[0],d1[0],d2[0],d3[0]},[r6]!
564	vst4.32		{d0[1],d1[1],d2[1],d3[1]},[r7]!
565	vst4.32		{d4[0],d5[0],d6[0],d7[0]},[r6]!
566	vst4.32		{d4[1],d5[1],d6[1],d7[1]},[r7]!
567	vst1.32		{d8[0]},[r6,:32]
568	vst1.32		{d8[1]},[r7,:32]
569
570	b		.Lsquare_neon
571
572.align	4
573.Lsquare_break_neon:
574	add		r6,r0,#(48+2*4*9)
575	add		r7,r0,#(48+3*4*9)
576
577	vmov		d0,d10		@ r^4:r^3
578	vshl.u32	d2,d12,#2		@ *5
579	vmov		d1,d12
580	vshl.u32	d4,d14,#2
581	vmov		d3,d14
582	vshl.u32	d6,d16,#2
583	vmov		d5,d16
584	vshl.u32	d8,d18,#2
585	vmov		d7,d18
586	vadd.i32	d2,d2,d12
587	vadd.i32	d4,d4,d14
588	vadd.i32	d6,d6,d16
589	vadd.i32	d8,d8,d18
590
591	vst4.32		{d0[0],d1[0],d2[0],d3[0]},[r6]!
592	vst4.32		{d0[1],d1[1],d2[1],d3[1]},[r7]!
593	vst4.32		{d4[0],d5[0],d6[0],d7[0]},[r6]!
594	vst4.32		{d4[1],d5[1],d6[1],d7[1]},[r7]!
595	vst1.32		{d8[0]},[r6]
596	vst1.32		{d8[1]},[r7]
597
598	bx	lr				@ bx	lr
599.size	poly1305_init_neon,.-poly1305_init_neon
600
601.type	poly1305_blocks_neon,%function
602.align	5
603poly1305_blocks_neon:
604.Lpoly1305_blocks_neon:
605	ldr	ip,[r0,#36]		@ is_base2_26
606	ands	r2,r2,#-16
607	beq	.Lno_data_neon
608
609	cmp	r2,#64
610	bhs	.Lenter_neon
611	tst	ip,ip			@ is_base2_26?
612	beq	.Lpoly1305_blocks
613
614.Lenter_neon:
615	stmdb	sp!,{r4-r7}
616	vstmdb	sp!,{d8-d15}		@ ABI specification says so
617
618	tst	ip,ip			@ is_base2_26?
619	bne	.Lbase2_26_neon
620
621	stmdb	sp!,{r1-r3,lr}
622	bl	poly1305_init_neon
623
624	ldr	r4,[r0,#0]		@ load hash value base 2^32
625	ldr	r5,[r0,#4]
626	ldr	r6,[r0,#8]
627	ldr	r7,[r0,#12]
628	ldr	ip,[r0,#16]
629
630	and	r2,r4,#0x03ffffff	@ base 2^32 -> base 2^26
631	mov	r3,r4,lsr#26
632	 veor	d10,d10,d10
633	mov	r4,r5,lsr#20
634	orr	r3,r3,r5,lsl#6
635	 veor	d12,d12,d12
636	mov	r5,r6,lsr#14
637	orr	r4,r4,r6,lsl#12
638	 veor	d14,d14,d14
639	mov	r6,r7,lsr#8
640	orr	r5,r5,r7,lsl#18
641	 veor	d16,d16,d16
642	and	r3,r3,#0x03ffffff
643	orr	r6,r6,ip,lsl#24
644	 veor	d18,d18,d18
645	and	r4,r4,#0x03ffffff
646	mov	r1,#1
647	and	r5,r5,#0x03ffffff
648	str	r1,[r0,#36]		@ is_base2_26
649
650	vmov.32	d10[0],r2
651	vmov.32	d12[0],r3
652	vmov.32	d14[0],r4
653	vmov.32	d16[0],r5
654	vmov.32	d18[0],r6
655	adr	r5,.Lzeros
656
657	ldmia	sp!,{r1-r3,lr}
658	b	.Lbase2_32_neon
659
660.align	4
661.Lbase2_26_neon:
662	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
663	@ load hash value
664
665	veor		d10,d10,d10
666	veor		d12,d12,d12
667	veor		d14,d14,d14
668	veor		d16,d16,d16
669	veor		d18,d18,d18
670	vld4.32		{d10[0],d12[0],d14[0],d16[0]},[r0]!
671	adr		r5,.Lzeros
672	vld1.32		{d18[0]},[r0]
673	sub		r0,r0,#16		@ rewind
674
675.Lbase2_32_neon:
676	add		r4,r1,#32
677	mov		r3,r3,lsl#24
678	tst		r2,#31
679	beq		.Leven
680
681	vld4.32		{d20[0],d22[0],d24[0],d26[0]},[r1]!
682	vmov.32		d28[0],r3
683	sub		r2,r2,#16
684	add		r4,r1,#32
685
686# ifdef	__ARMEB__
687	vrev32.8	q10,q10
688	vrev32.8	q13,q13
689	vrev32.8	q11,q11
690	vrev32.8	q12,q12
691# endif
692	vsri.u32	d28,d26,#8	@ base 2^32 -> base 2^26
693	vshl.u32	d26,d26,#18
694
695	vsri.u32	d26,d24,#14
696	vshl.u32	d24,d24,#12
697	vadd.i32	d29,d28,d18	@ add hash value and move to #hi
698
699	vbic.i32	d26,#0xfc000000
700	vsri.u32	d24,d22,#20
701	vshl.u32	d22,d22,#6
702
703	vbic.i32	d24,#0xfc000000
704	vsri.u32	d22,d20,#26
705	vadd.i32	d27,d26,d16
706
707	vbic.i32	d20,#0xfc000000
708	vbic.i32	d22,#0xfc000000
709	vadd.i32	d25,d24,d14
710
711	vadd.i32	d21,d20,d10
712	vadd.i32	d23,d22,d12
713
714	mov		r7,r5
715	add		r6,r0,#48
716
717	cmp		r2,r2
718	b		.Long_tail
719
720.align	4
721.Leven:
722	subs		r2,r2,#64
723	it		lo
724	movlo		r4,r5
725
726	vmov.i32	q14,#1<<24		@ padbit, yes, always
727	vld4.32		{d20,d22,d24,d26},[r1]	@ inp[0:1]
728	add		r1,r1,#64
729	vld4.32		{d21,d23,d25,d27},[r4]	@ inp[2:3] (or 0)
730	add		r4,r4,#64
731	itt		hi
732	addhi		r7,r0,#(48+1*9*4)
733	addhi		r6,r0,#(48+3*9*4)
734
735# ifdef	__ARMEB__
736	vrev32.8	q10,q10
737	vrev32.8	q13,q13
738	vrev32.8	q11,q11
739	vrev32.8	q12,q12
740# endif
741	vsri.u32	q14,q13,#8		@ base 2^32 -> base 2^26
742	vshl.u32	q13,q13,#18
743
744	vsri.u32	q13,q12,#14
745	vshl.u32	q12,q12,#12
746
747	vbic.i32	q13,#0xfc000000
748	vsri.u32	q12,q11,#20
749	vshl.u32	q11,q11,#6
750
751	vbic.i32	q12,#0xfc000000
752	vsri.u32	q11,q10,#26
753
754	vbic.i32	q10,#0xfc000000
755	vbic.i32	q11,#0xfc000000
756
757	bls		.Lskip_loop
758
759	vld4.32		{d0[1],d1[1],d2[1],d3[1]},[r7]!	@ load r^2
760	vld4.32		{d0[0],d1[0],d2[0],d3[0]},[r6]!	@ load r^4
761	vld4.32		{d4[1],d5[1],d6[1],d7[1]},[r7]!
762	vld4.32		{d4[0],d5[0],d6[0],d7[0]},[r6]!
763	b		.Loop_neon
764
765.align	5
766.Loop_neon:
767	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
768	@ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
769	@ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
770	@   ___________________/
771	@ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
772	@ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
773	@   ___________________/ ____________________/
774	@
775	@ Note that we start with inp[2:3]*r^2. This is because it
776	@ doesn't depend on reduction in previous iteration.
777	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
778	@ d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
779	@ d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
780	@ d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
781	@ d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
782	@ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
783
784	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
785	@ inp[2:3]*r^2
786
787	vadd.i32	d24,d24,d14	@ accumulate inp[0:1]
788	vmull.u32	q7,d25,d0[1]
789	vadd.i32	d20,d20,d10
790	vmull.u32	q5,d21,d0[1]
791	vadd.i32	d26,d26,d16
792	vmull.u32	q8,d27,d0[1]
793	vmlal.u32	q7,d23,d1[1]
794	vadd.i32	d22,d22,d12
795	vmull.u32	q6,d23,d0[1]
796
797	vadd.i32	d28,d28,d18
798	vmull.u32	q9,d29,d0[1]
799	subs		r2,r2,#64
800	vmlal.u32	q5,d29,d2[1]
801	it		lo
802	movlo		r4,r5
803	vmlal.u32	q8,d25,d1[1]
804	vld1.32		d8[1],[r7,:32]
805	vmlal.u32	q6,d21,d1[1]
806	vmlal.u32	q9,d27,d1[1]
807
808	vmlal.u32	q5,d27,d4[1]
809	vmlal.u32	q8,d23,d3[1]
810	vmlal.u32	q9,d25,d3[1]
811	vmlal.u32	q6,d29,d4[1]
812	vmlal.u32	q7,d21,d3[1]
813
814	vmlal.u32	q8,d21,d5[1]
815	vmlal.u32	q5,d25,d6[1]
816	vmlal.u32	q9,d23,d5[1]
817	vmlal.u32	q6,d27,d6[1]
818	vmlal.u32	q7,d29,d6[1]
819
820	vmlal.u32	q8,d29,d8[1]
821	vmlal.u32	q5,d23,d8[1]
822	vmlal.u32	q9,d21,d7[1]
823	vmlal.u32	q6,d25,d8[1]
824	vmlal.u32	q7,d27,d8[1]
825
826	vld4.32		{d21,d23,d25,d27},[r4]	@ inp[2:3] (or 0)
827	add		r4,r4,#64
828
829	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
830	@ (hash+inp[0:1])*r^4 and accumulate
831
832	vmlal.u32	q8,d26,d0[0]
833	vmlal.u32	q5,d20,d0[0]
834	vmlal.u32	q9,d28,d0[0]
835	vmlal.u32	q6,d22,d0[0]
836	vmlal.u32	q7,d24,d0[0]
837	vld1.32		d8[0],[r6,:32]
838
839	vmlal.u32	q8,d24,d1[0]
840	vmlal.u32	q5,d28,d2[0]
841	vmlal.u32	q9,d26,d1[0]
842	vmlal.u32	q6,d20,d1[0]
843	vmlal.u32	q7,d22,d1[0]
844
845	vmlal.u32	q8,d22,d3[0]
846	vmlal.u32	q5,d26,d4[0]
847	vmlal.u32	q9,d24,d3[0]
848	vmlal.u32	q6,d28,d4[0]
849	vmlal.u32	q7,d20,d3[0]
850
851	vmlal.u32	q8,d20,d5[0]
852	vmlal.u32	q5,d24,d6[0]
853	vmlal.u32	q9,d22,d5[0]
854	vmlal.u32	q6,d26,d6[0]
855	vmlal.u32	q8,d28,d8[0]
856
857	vmlal.u32	q7,d28,d6[0]
858	vmlal.u32	q5,d22,d8[0]
859	vmlal.u32	q9,d20,d7[0]
860	vmov.i32	q14,#1<<24		@ padbit, yes, always
861	vmlal.u32	q6,d24,d8[0]
862	vmlal.u32	q7,d26,d8[0]
863
864	vld4.32		{d20,d22,d24,d26},[r1]	@ inp[0:1]
865	add		r1,r1,#64
866# ifdef	__ARMEB__
867	vrev32.8	q10,q10
868	vrev32.8	q11,q11
869	vrev32.8	q12,q12
870	vrev32.8	q13,q13
871# endif
872
873	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
874	@ lazy reduction interleaved with base 2^32 -> base 2^26 of
875	@ inp[0:3] previously loaded to q10-q13 and smashed to q10-q14.
876
877	vshr.u64	q15,q8,#26
878	vmovn.i64	d16,q8
879	 vshr.u64	q4,q5,#26
880	 vmovn.i64	d10,q5
881	vadd.i64	q9,q9,q15		@ h3 -> h4
882	vbic.i32	d16,#0xfc000000
883	  vsri.u32	q14,q13,#8		@ base 2^32 -> base 2^26
884	 vadd.i64	q6,q6,q4		@ h0 -> h1
885	  vshl.u32	q13,q13,#18
886	 vbic.i32	d10,#0xfc000000
887
888	vshrn.u64	d30,q9,#26
889	vmovn.i64	d18,q9
890	 vshr.u64	q4,q6,#26
891	 vmovn.i64	d12,q6
892	 vadd.i64	q7,q7,q4		@ h1 -> h2
893	  vsri.u32	q13,q12,#14
894	vbic.i32	d18,#0xfc000000
895	  vshl.u32	q12,q12,#12
896	 vbic.i32	d12,#0xfc000000
897
898	vadd.i32	d10,d10,d30
899	vshl.u32	d30,d30,#2
900	  vbic.i32	q13,#0xfc000000
901	 vshrn.u64	d8,q7,#26
902	 vmovn.i64	d14,q7
903	vaddl.u32	q5,d10,d30	@ h4 -> h0 [widen for a sec]
904	  vsri.u32	q12,q11,#20
905	 vadd.i32	d16,d16,d8	@ h2 -> h3
906	  vshl.u32	q11,q11,#6
907	 vbic.i32	d14,#0xfc000000
908	  vbic.i32	q12,#0xfc000000
909
910	vshrn.u64	d30,q5,#26		@ re-narrow
911	vmovn.i64	d10,q5
912	  vsri.u32	q11,q10,#26
913	  vbic.i32	q10,#0xfc000000
914	 vshr.u32	d8,d16,#26
915	 vbic.i32	d16,#0xfc000000
916	vbic.i32	d10,#0xfc000000
917	vadd.i32	d12,d12,d30	@ h0 -> h1
918	 vadd.i32	d18,d18,d8	@ h3 -> h4
919	  vbic.i32	q11,#0xfc000000
920
921	bhi		.Loop_neon
922
923.Lskip_loop:
924	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
925	@ multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
926
927	add		r7,r0,#(48+0*9*4)
928	add		r6,r0,#(48+1*9*4)
929	adds		r2,r2,#32
930	it		ne
931	movne		r2,#0
932	bne		.Long_tail
933
934	vadd.i32	d25,d24,d14	@ add hash value and move to #hi
935	vadd.i32	d21,d20,d10
936	vadd.i32	d27,d26,d16
937	vadd.i32	d23,d22,d12
938	vadd.i32	d29,d28,d18
939
940.Long_tail:
941	vld4.32		{d0[1],d1[1],d2[1],d3[1]},[r7]!	@ load r^1
942	vld4.32		{d0[0],d1[0],d2[0],d3[0]},[r6]!	@ load r^2
943
944	vadd.i32	d24,d24,d14	@ can be redundant
945	vmull.u32	q7,d25,d0
946	vadd.i32	d20,d20,d10
947	vmull.u32	q5,d21,d0
948	vadd.i32	d26,d26,d16
949	vmull.u32	q8,d27,d0
950	vadd.i32	d22,d22,d12
951	vmull.u32	q6,d23,d0
952	vadd.i32	d28,d28,d18
953	vmull.u32	q9,d29,d0
954
955	vmlal.u32	q5,d29,d2
956	vld4.32		{d4[1],d5[1],d6[1],d7[1]},[r7]!
957	vmlal.u32	q8,d25,d1
958	vld4.32		{d4[0],d5[0],d6[0],d7[0]},[r6]!
959	vmlal.u32	q6,d21,d1
960	vmlal.u32	q9,d27,d1
961	vmlal.u32	q7,d23,d1
962
963	vmlal.u32	q8,d23,d3
964	vld1.32		d8[1],[r7,:32]
965	vmlal.u32	q5,d27,d4
966	vld1.32		d8[0],[r6,:32]
967	vmlal.u32	q9,d25,d3
968	vmlal.u32	q6,d29,d4
969	vmlal.u32	q7,d21,d3
970
971	vmlal.u32	q8,d21,d5
972	 it		ne
973	 addne		r7,r0,#(48+2*9*4)
974	vmlal.u32	q5,d25,d6
975	 it		ne
976	 addne		r6,r0,#(48+3*9*4)
977	vmlal.u32	q9,d23,d5
978	vmlal.u32	q6,d27,d6
979	vmlal.u32	q7,d29,d6
980
981	vmlal.u32	q8,d29,d8
982	 vorn		q0,q0,q0	@ all-ones, can be redundant
983	vmlal.u32	q5,d23,d8
984	 vshr.u64	q0,q0,#38
985	vmlal.u32	q9,d21,d7
986	vmlal.u32	q6,d25,d8
987	vmlal.u32	q7,d27,d8
988
989	beq		.Lshort_tail
990
991	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
992	@ (hash+inp[0:1])*r^4:r^3 and accumulate
993
994	vld4.32		{d0[1],d1[1],d2[1],d3[1]},[r7]!	@ load r^3
995	vld4.32		{d0[0],d1[0],d2[0],d3[0]},[r6]!	@ load r^4
996
997	vmlal.u32	q7,d24,d0
998	vmlal.u32	q5,d20,d0
999	vmlal.u32	q8,d26,d0
1000	vmlal.u32	q6,d22,d0
1001	vmlal.u32	q9,d28,d0
1002
1003	vmlal.u32	q5,d28,d2
1004	vld4.32		{d4[1],d5[1],d6[1],d7[1]},[r7]!
1005	vmlal.u32	q8,d24,d1
1006	vld4.32		{d4[0],d5[0],d6[0],d7[0]},[r6]!
1007	vmlal.u32	q6,d20,d1
1008	vmlal.u32	q9,d26,d1
1009	vmlal.u32	q7,d22,d1
1010
1011	vmlal.u32	q8,d22,d3
1012	vld1.32		d8[1],[r7,:32]
1013	vmlal.u32	q5,d26,d4
1014	vld1.32		d8[0],[r6,:32]
1015	vmlal.u32	q9,d24,d3
1016	vmlal.u32	q6,d28,d4
1017	vmlal.u32	q7,d20,d3
1018
1019	vmlal.u32	q8,d20,d5
1020	vmlal.u32	q5,d24,d6
1021	vmlal.u32	q9,d22,d5
1022	vmlal.u32	q6,d26,d6
1023	vmlal.u32	q7,d28,d6
1024
1025	vmlal.u32	q8,d28,d8
1026	 vorn		q0,q0,q0	@ all-ones
1027	vmlal.u32	q5,d22,d8
1028	 vshr.u64	q0,q0,#38
1029	vmlal.u32	q9,d20,d7
1030	vmlal.u32	q6,d24,d8
1031	vmlal.u32	q7,d26,d8
1032
1033.Lshort_tail:
1034	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1035	@ horizontal addition
1036
1037	vadd.i64	d16,d16,d17
1038	vadd.i64	d10,d10,d11
1039	vadd.i64	d18,d18,d19
1040	vadd.i64	d12,d12,d13
1041	vadd.i64	d14,d14,d15
1042
1043	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1044	@ lazy reduction, but without narrowing
1045
1046	vshr.u64	q15,q8,#26
1047	vand.i64	q8,q8,q0
1048	 vshr.u64	q4,q5,#26
1049	 vand.i64	q5,q5,q0
1050	vadd.i64	q9,q9,q15		@ h3 -> h4
1051	 vadd.i64	q6,q6,q4		@ h0 -> h1
1052
1053	vshr.u64	q15,q9,#26
1054	vand.i64	q9,q9,q0
1055	 vshr.u64	q4,q6,#26
1056	 vand.i64	q6,q6,q0
1057	 vadd.i64	q7,q7,q4		@ h1 -> h2
1058
1059	vadd.i64	q5,q5,q15
1060	vshl.u64	q15,q15,#2
1061	 vshr.u64	q4,q7,#26
1062	 vand.i64	q7,q7,q0
1063	vadd.i64	q5,q5,q15		@ h4 -> h0
1064	 vadd.i64	q8,q8,q4		@ h2 -> h3
1065
1066	vshr.u64	q15,q5,#26
1067	vand.i64	q5,q5,q0
1068	 vshr.u64	q4,q8,#26
1069	 vand.i64	q8,q8,q0
1070	vadd.i64	q6,q6,q15		@ h0 -> h1
1071	 vadd.i64	q9,q9,q4		@ h3 -> h4
1072
1073	cmp		r2,#0
1074	bne		.Leven
1075
1076	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1077	@ store hash value
1078
1079	vst4.32		{d10[0],d12[0],d14[0],d16[0]},[r0]!
1080	vst1.32		{d18[0]},[r0]
1081
1082	vldmia	sp!,{d8-d15}			@ epilogue
1083	ldmia	sp!,{r4-r7}
1084.Lno_data_neon:
1085	bx	lr					@ bx	lr
1086.size	poly1305_blocks_neon,.-poly1305_blocks_neon
1087
1088.type	poly1305_emit_neon,%function
1089.align	5
1090poly1305_emit_neon:
1091.Lpoly1305_emit_neon:
1092	ldr	ip,[r0,#36]		@ is_base2_26
1093
1094	stmdb	sp!,{r4-r11}
1095
1096	tst	ip,ip
1097	beq	.Lpoly1305_emit_enter
1098
1099	ldmia	r0,{r3-r7}
1100	eor	r8,r8,r8
1101
1102	adds	r3,r3,r4,lsl#26	@ base 2^26 -> base 2^32
1103	mov	r4,r4,lsr#6
1104	adcs	r4,r4,r5,lsl#20
1105	mov	r5,r5,lsr#12
1106	adcs	r5,r5,r6,lsl#14
1107	mov	r6,r6,lsr#18
1108	adcs	r6,r6,r7,lsl#8
1109	adc	r7,r8,r7,lsr#24	@ can be partially reduced ...
1110
1111	and	r8,r7,#-4		@ ... so reduce
1112	and	r7,r6,#3
1113	add	r8,r8,r8,lsr#2	@ *= 5
1114	adds	r3,r3,r8
1115	adcs	r4,r4,#0
1116	adcs	r5,r5,#0
1117	adcs	r6,r6,#0
1118	adc	r7,r7,#0
1119
1120	adds	r8,r3,#5		@ compare to modulus
1121	adcs	r9,r4,#0
1122	adcs	r10,r5,#0
1123	adcs	r11,r6,#0
1124	adc	r7,r7,#0
1125	tst	r7,#4			@ did it carry/borrow?
1126
1127	it	ne
1128	movne	r3,r8
1129	ldr	r8,[r2,#0]
1130	it	ne
1131	movne	r4,r9
1132	ldr	r9,[r2,#4]
1133	it	ne
1134	movne	r5,r10
1135	ldr	r10,[r2,#8]
1136	it	ne
1137	movne	r6,r11
1138	ldr	r11,[r2,#12]
1139
1140	adds	r3,r3,r8		@ accumulate nonce
1141	adcs	r4,r4,r9
1142	adcs	r5,r5,r10
1143	adc	r6,r6,r11
1144
1145# ifdef __ARMEB__
1146	rev	r3,r3
1147	rev	r4,r4
1148	rev	r5,r5
1149	rev	r6,r6
1150# endif
1151	str	r3,[r1,#0]		@ store the result
1152	str	r4,[r1,#4]
1153	str	r5,[r1,#8]
1154	str	r6,[r1,#12]
1155
1156	ldmia	sp!,{r4-r11}
1157	bx	lr				@ bx	lr
1158.size	poly1305_emit_neon,.-poly1305_emit_neon
1159
1160.align	5
1161.Lzeros:
1162.long	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
1163.LOPENSSL_armcap:
1164.word	OPENSSL_armcap_P-.Lpoly1305_init
1165#endif
1166.asciz	"Poly1305 for ARMv4/NEON, CRYPTOGAMS by <appro@openssl.org>"
1167.align	2
1168#if	__ARM_MAX_ARCH__>=7
1169.comm   OPENSSL_armcap_P,4,4
1170#endif
1171