1#! /usr/bin/env perl
2# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
3#
4# Licensed under the Apache License 2.0 (the "License").  You may not use
5# this file except in compliance with the License.  You can obtain a copy
6# in the file LICENSE in the source distribution or at
7# https://www.openssl.org/source/license.html
8
9#
10# ====================================================================
11# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
12# project. The module is, however, dual licensed under OpenSSL and
13# CRYPTOGAMS licenses depending on where you obtain it. For further
14# details see http://www.openssl.org/~appro/cryptogams/.
15# ====================================================================
16#
17# Poly1305 hash for C64x+.
18#
19# October 2015
20#
21# Performance is [incredible for a 32-bit processor] 1.82 cycles per
22# processed byte. Comparison to compiler-generated code is problematic,
23# because results were observed to vary from 2.1 to 7.6 cpb depending
24# on compiler's ability to inline small functions. Compiler also
25# disables interrupts for some reason, thus making interrupt response
26# time dependent on input length. This module on the other hand is free
27# from such limitation.
28
29$output=pop and open STDOUT,">$output";
30
31($CTXA,$INPB,$LEN,$PADBIT)=("A4","B4","A6","B6");
32($H0,$H1,$H2,$H3,$H4,$H4a)=("A8","B8","A10","B10","B2",$LEN);
33($D0,$D1,$D2,$D3)=         ("A9","B9","A11","B11");
34($R0,$R1,$R2,$R3,$S1,$S2,$S3,$S3b)=("A0","B0","A1","B1","A12","B12","A13","B13");
35($THREE,$R0b,$S2a)=("B7","B5","A5");
36
37$code.=<<___;
38	.text
39
40	.if	.ASSEMBLER_VERSION<7000000
41	.asg	0,__TI_EABI__
42	.endif
43	.if	__TI_EABI__
44	.asg	poly1305_init,_poly1305_init
45	.asg	poly1305_blocks,_poly1305_blocks
46	.asg	poly1305_emit,_poly1305_emit
47	.endif
48
49	.asg	B3,RA
50	.asg	A15,FP
51	.asg	B15,SP
52
53	.if	.LITTLE_ENDIAN
54	.asg	MV,SWAP2
55	.asg	MV.L,SWAP4
56	.endif
57
58	.global	_poly1305_init
59_poly1305_init:
60	.asmfunc
61	LDNDW	*${INPB}[0],B17:B16	; load key material
62	LDNDW	*${INPB}[1],A17:A16
63
64||	ZERO	B9:B8
65||	MVK	-1,B0
66	STDW	B9:B8,*${CTXA}[0]	; initialize h1:h0
67||	SHRU	B0,4,B0			; 0x0fffffff
68||	MVK	-4,B1
69	STDW	B9:B8,*${CTXA}[1]	; initialize h3:h2
70||	AND	B0,B1,B1		; 0x0ffffffc
71	STW	B8,*${CTXA}[4]		; initialize h4
72
73	.if	.BIG_ENDIAN
74	SWAP2	B16,B17
75||	SWAP2	B17,B16
76	SWAP2	A16,A17
77||	SWAP2	A17,A16
78	SWAP4	B16,B16
79||	SWAP4	A16,A16
80	SWAP4	B17,B17
81||	SWAP4	A17,A17
82	.endif
83
84	AND	B16,B0,B20		; r0 = key[0] & 0x0fffffff
85||	AND	B17,B1,B22		; r1 = key[1] & 0x0ffffffc
86||	EXTU	B17,4,6,B16		; r1>>2
87	AND	A16,B1,B21		; r2 = key[2] & 0x0ffffffc
88||	AND	A17,B1,A23		; r3 = key[3] & 0x0ffffffc
89||	BNOP	RA
90	SHRU	B21,2,B18
91||	ADD	B22,B16,B16		; s1 = r1 + r1>>2
92
93	STDW	B21:B20,*${CTXA}[3]	; save r2:r0
94||	ADD	B21,B18,B18		; s2 = r2 + r2>>2
95||	SHRU	A23,2,B17
96||	MV	A23,B23
97	STDW	B23:B22,*${CTXA}[4]	; save r3:r1
98||	ADD	B23,B17,B19		; s3 = r3 + r3>>2
99||	ADD	B23,B17,B17		; s3 = r3 + r3>>2
100	STDW	B17:B16,*${CTXA}[5]	; save s3:s1
101	STDW	B19:B18,*${CTXA}[6]	; save s3:s2
102||	ZERO	A4			; return 0
103	.endasmfunc
104
105	.global	_poly1305_blocks
106	.align	32
107_poly1305_blocks:
108	.asmfunc	stack_usage(40)
109	SHRU	$LEN,4,A2		; A2 is loop counter, number of blocks
110  [!A2]	BNOP	RA			; no data
111|| [A2]	STW	FP,*SP--(40)		; save frame pointer and alloca(40)
112|| [A2]	MV	SP,FP
113   [A2]	STDW	B13:B12,*SP[4]		; ABI says so
114|| [A2]	MV	$CTXA,$S3b		; borrow $S3b
115   [A2]	STDW	B11:B10,*SP[3]
116|| [A2]	STDW	A13:A12,*FP[-3]
117   [A2]	STDW	A11:A10,*FP[-4]
118
119|| [A2]	LDDW	*${S3b}[0],B25:B24	; load h1:h0
120   [A2]	LDNW	*${INPB}++[4],$D0	; load inp[0]
121   [A2]	LDNW	*${INPB}[-3],$D1	; load inp[1]
122
123	LDDW	*${CTXA}[1],B29:B28	; load h3:h2, B28 is h2
124	LDNW	*${INPB}[-2],$D2	; load inp[2]
125	LDNW	*${INPB}[-1],$D3	; load inp[3]
126
127	LDDW	*${CTXA}[3],$R2:$R0	; load r2:r0
128||	LDDW	*${S3b}[4],$R3:$R1	; load r3:r1
129||	SWAP2	$D0,$D0
130
131	LDDW	*${CTXA}[5],$S3:$S1	; load s3:s1
132||	LDDW	*${S3b}[6],$S3b:$S2	; load s3:s2
133||	SWAP4	$D0,$D0
134||	SWAP2	$D1,$D1
135
136	ADDU	$D0,B24,$D0:$H0		; h0+=inp[0]
137||	ADD	$D0,B24,B27		; B-copy of h0+inp[0]
138||	SWAP4	$D1,$D1
139	ADDU	$D1,B25,$D1:$H1		; h1+=inp[1]
140||	MVK	3,$THREE
141||	SWAP2	$D2,$D2
142	LDW	*${CTXA}[4],$H4		; load h4
143||	SWAP4	$D2,$D2
144||	MV	B29,B30			; B30 is h3
145	MV	$R0,$R0b
146
147loop?:
148	MPY32U	$H0,$R0,A17:A16
149||	MPY32U	B27,$R1,B17:B16		; MPY32U	$H0,$R1,B17:B16
150||	ADDU	$D0,$D1:$H1,B25:B24	; ADDU		$D0,$D1:$H1,$D1:$H1
151||	ADDU	$D2,B28,$D2:$H2		; h2+=inp[2]
152||	SWAP2	$D3,$D3
153	MPY32U	$H0,$R2,A19:A18
154||	MPY32U	B27,$R3,B19:B18		; MPY32U	$H0,$R3,B19:B18
155||	ADD	$D0,$H1,A24		; A-copy of B24
156||	SWAP4	$D3,$D3
157|| [A2]	SUB	A2,1,A2			; decrement loop counter
158
159	MPY32U	A24,$S3,A21:A20		; MPY32U	$H1,$S3,A21:A20
160||	MPY32U	B24,$R0b,B21:B20	; MPY32U	$H1,$R0,B21:B20
161||	ADDU	B25,$D2:$H2,$D2:$H2	; ADDU		$D1,$D2:$H2,$D2:$H2
162||	ADDU	$D3,B30,$D3:$H3		; h3+=inp[3]
163||	ADD	B25,$H2,B25		; B-copy of $H2
164	MPY32U	A24,$R1,A23:A22		; MPY32U	$H1,$R1,A23:A22
165||	MPY32U	B24,$R2,B23:B22		; MPY32U	$H1,$R2,B23:B22
166
167	MPY32U	$H2,$S2,A25:A24
168||	MPY32U	B25,$S3b,B25:B24	; MPY32U	$H2,$S3,B25:B24
169||	ADDU	$D2,$D3:$H3,$D3:$H3
170||	ADD	$PADBIT,$H4,$H4		; h4+=padbit
171	MPY32U	$H2,$R0,A27:A26
172||	MPY32U	$H2,$R1,B27:B26
173||	ADD	$D3,$H4,$H4
174||	MV	$S2,$S2a
175
176	MPY32U	$H3,$S1,A29:A28
177||	MPY32U	$H3,$S2,B29:B28
178||	ADD	A21,A17,A21		; start accumulating "d3:d0"
179||	ADD	B21,B17,B21
180||	ADDU	A20,A16,A17:A16
181||	ADDU	B20,B16,B17:B16
182|| [A2]	LDNW	*${INPB}++[4],$D0	; load inp[0]
183	MPY32U	$H3,$S3,A31:A30
184||	MPY32U	$H3,$R0b,B31:B30
185||	ADD	A23,A19,A23
186||	ADD	B23,B19,B23
187||	ADDU	A22,A18,A19:A18
188||	ADDU	B22,B18,B19:B18
189|| [A2]	LDNW	*${INPB}[-3],$D1	; load inp[1]
190
191	MPY32	$H4,$S1,B20
192||	MPY32	$H4,$S2a,A20
193||	ADD	A25,A21,A21
194||	ADD	B25,B21,B21
195||	ADDU	A24,A17:A16,A17:A16
196||	ADDU	B24,B17:B16,B17:B16
197|| [A2]	LDNW	*${INPB}[-2],$D2	; load inp[2]
198	MPY32	$H4,$S3b,B22
199||	ADD	A27,A23,A23
200||	ADD	B27,B23,B23
201||	ADDU	A26,A19:A18,A19:A18
202||	ADDU	B26,B19:B18,B19:B18
203|| [A2]	LDNW	*${INPB}[-1],$D3	; load inp[3]
204
205	MPY32	$H4,$R0b,$H4
206||	ADD	A29,A21,A21		; final hi("d0")
207||	ADD	B29,B21,B21		; final hi("d1")
208||	ADDU	A28,A17:A16,A17:A16	; final lo("d0")
209||	ADDU	B28,B17:B16,B17:B16
210	ADD	A31,A23,A23		; final hi("d2")
211||	ADD	B31,B23,B23		; final hi("d3")
212||	ADDU	A30,A19:A18,A19:A18
213||	ADDU	B30,B19:B18,B19:B18
214	ADDU	B20,B17:B16,B17:B16	; final lo("d1")
215||	ADDU	A20,A19:A18,A19:A18	; final lo("d2")
216	ADDU	B22,B19:B18,B19:B18	; final lo("d3")
217
218||	ADD	A17,A21,A21		; "flatten" "d3:d0"
219	MV	A19,B29			; move to avoid cross-path stalls
220	ADDU	A21,B17:B16,B27:B26	; B26 is h1
221	ADD	B21,B27,B27
222||	DMV	B29,A18,B29:B28		; move to avoid cross-path stalls
223	ADDU	B27,B29:B28,B29:B28	; B28 is h2
224|| [A2]	SWAP2	$D0,$D0
225	ADD	A23,B29,B29
226|| [A2]	SWAP4	$D0,$D0
227	ADDU	B29,B19:B18,B31:B30	; B30 is h3
228	ADD	B23,B31,B31
229||	MV	A16,B24			; B24 is h0
230|| [A2]	SWAP2	$D1,$D1
231	ADD	B31,$H4,$H4
232|| [A2]	SWAP4	$D1,$D1
233
234	SHRU	$H4,2,B16		; last reduction step
235||	AND	$H4,$THREE,$H4
236	ADDAW	B16,B16,B16		; 5*(h4>>2)
237|| [A2]	BNOP	loop?
238
239	ADDU	B24,B16,B25:B24		; B24 is h0
240|| [A2]	SWAP2	$D2,$D2
241	ADDU	B26,B25,B27:B26		; B26 is h1
242|| [A2]	SWAP4	$D2,$D2
243	ADDU	B28,B27,B29:B28		; B28 is h2
244|| [A2]	ADDU	$D0,B24,$D0:$H0		; h0+=inp[0]
245|| [A2]	ADD	$D0,B24,B27		; B-copy of h0+inp[0]
246	ADDU	B30,B29,B31:B30		; B30 is h3
247	ADD	B31,$H4,$H4
248|| [A2]	ADDU	$D1,B26,$D1:$H1		; h1+=inp[1]
249;;===== branch to loop? is taken here
250
251	LDDW	*FP[-4],A11:A10		; ABI says so
252	LDDW	*FP[-3],A13:A12
253||	LDDW	*SP[3],B11:B10
254	LDDW	*SP[4],B13:B12
255||	MV	B26,B25
256||	BNOP	RA
257	LDW	*++SP(40),FP		; restore frame pointer
258||	MV	B30,B29
259	STDW	B25:B24,*${CTXA}[0]	; save h1:h0
260	STDW	B29:B28,*${CTXA}[1]	; save h3:h2
261	STW	$H4,*${CTXA}[4]		; save h4
262	NOP	1
263	.endasmfunc
264___
265{
266my ($MAC,$NONCEA,$NONCEB)=($INPB,$LEN,$PADBIT);
267
268$code.=<<___;
269	.global	_poly1305_emit
270	.align	32
271_poly1305_emit:
272	.asmfunc
273	LDDW	*${CTXA}[0],A17:A16	; load h1:h0
274	LDDW	*${CTXA}[1],A19:A18	; load h3:h2
275	LDW	*${CTXA}[4],A20		; load h4
276	MV	$NONCEA,$NONCEB
277
278	MVK	5,A22			; compare to modulus
279	ADDU	A16,A22,A23:A22
280||	LDW	*${NONCEA}[0],A8
281||	LDW	*${NONCEB}[1],B8
282	ADDU	A17,A23,A25:A24
283||	LDW	*${NONCEA}[2],A9
284||	LDW	*${NONCEB}[3],B9
285	ADDU	A19,A25,A27:A26
286	ADDU	A19,A27,A29:A28
287	ADD	A20,A29,A29
288
289	SHRU	A29,2,A2		; check for overflow in 130-th bit
290
291   [A2]	MV	A22,A16			; select
292|| [A2]	MV	A24,A17
293   [A2]	MV	A26,A18
294|| [A2]	MV	A28,A19
295
296||	ADDU	A8,A16,A23:A22		; accumulate nonce
297	ADDU	B8,A17,A25:A24
298||	SWAP2	A22,A22
299	ADDU	A23,A25:A24,A25:A24
300	ADDU	A9,A18,A27:A26
301||	SWAP2	A24,A24
302	ADDU	A25,A27:A26,A27:A26
303||	ADD	B9,A19,A28
304	ADD	A27,A28,A28
305||	SWAP2	A26,A26
306
307	.if	.BIG_ENDIAN
308	SWAP2	A28,A28
309||	SWAP4	A22,A22
310||	SWAP4	A24,B24
311	SWAP4	A26,A26
312	SWAP4	A28,A28
313||	MV	B24,A24
314	.endif
315
316	BNOP	RA,1
317	STNW	A22,*${MAC}[0]		; write the result
318	STNW	A24,*${MAC}[1]
319	STNW	A26,*${MAC}[2]
320	STNW	A28,*${MAC}[3]
321	.endasmfunc
322___
323}
324$code.=<<___;
325	.sect	.const
326	.cstring "Poly1305 for C64x+, CRYPTOGAMS by <appro\@openssl.org>"
327	.align	4
328___
329
330print $code;
331