#include "crypto_asm_hidden.h"
// linker define fe25519_nsquare
// linker use mask63

/* Assembly for feedback field squaring. */

#define mask63 CRYPTO_SHARED_NAMESPACE(mask63)

	.p2align 5
	ASM_HIDDEN _CRYPTO_SHARED_NAMESPACE(fe25519_nsquare)
	.globl _CRYPTO_SHARED_NAMESPACE(fe25519_nsquare)
	ASM_HIDDEN CRYPTO_SHARED_NAMESPACE(fe25519_nsquare)
	.globl CRYPTO_SHARED_NAMESPACE(fe25519_nsquare)

_CRYPTO_SHARED_NAMESPACE(fe25519_nsquare):
CRYPTO_SHARED_NAMESPACE(fe25519_nsquare):

	movq    %rsp,%r11
	andq 	$-32,%rsp
	subq    $64,%rsp

	movq    %r11,0(%rsp)
	movq    %r12,8(%rsp)
	movq    %r13,16(%rsp)
	movq    %r14,24(%rsp)
	movq    %r15,32(%rsp)
	movq    %rbx,40(%rsp)
	movq    %rbp,48(%rsp)
	movq    %rdi,56(%rsp)

	movq    0(%rsi),%rbx  
	movq    8(%rsi),%rbp  
	movq    16(%rsi),%rax
	movq    24(%rsi),%rsi

	movq    %rdx,%rdi

.L:
	xorq    %r13,%r13
	movq    %rbx,%rdx
	    
	mulx    %rbp,%r9,%r10

	mulx    %rax,%rcx,%r11
	adcx    %rcx,%r10
	    
	mulx    %rsi,%rcx,%r12
	adcx    %rcx,%r11
	adcx    %r13,%r12

	movq    %rbp,%rdx
	xorq    %r14,%r14
	    
	mulx    %rax,%rcx,%rdx
	adcx    %rcx,%r11
	adox    %rdx,%r12
	    
	movq    %rbp,%rdx
	mulx    %rsi,%rcx,%rdx
	adcx    %rcx,%r12
	adox    %rdx,%r13
	adcx    %r14,%r13

	xorq    %r15,%r15
	movq    %rax,%rdx
	    
	mulx    %rsi,%rcx,%r14
	adcx    %rcx,%r13
	adcx    %r15,%r14

	shld    $1,%r14,%r15
	shld    $1,%r13,%r14
	shld    $1,%r12,%r13
	shld    $1,%r11,%r12
	shld    $1,%r10,%r11
	shld    $1,%r9,%r10
	shlq    $1,%r9
	     
	xorq    %rdx,%rdx
	movq    %rbx,%rdx
	mulx    %rdx,%r8,%rdx
	adcx    %rdx,%r9

	movq    %rbp,%rdx
	mulx    %rdx,%rcx,%rdx
	adcx    %rcx,%r10
	adcx    %rdx,%r11

	movq    %rax,%rdx
	mulx    %rdx,%rcx,%rdx
	adcx    %rcx,%r12
	adcx    %rdx,%r13

	movq    %rsi,%rdx
	mulx    %rdx,%rcx,%rdx
	adcx    %rcx,%r14
	adcx    %rdx,%r15

	xorq    %rbx,%rbx
	movq    $38,%rdx    		

	mulx    %r12,%r12,%rbp
	adcx    %r8,%r12
	adox    %r9,%rbp

	mulx    %r13,%rcx,%rax
	adcx    %rcx,%rbp
	adox    %r10,%rax

	mulx    %r14,%rcx,%rsi
	adcx    %rcx,%rax
	adox    %r11,%rsi

	mulx    %r15,%rcx,%r15
	adcx    %rcx,%rsi
	adox    %rbx,%r15
	adcx    %rbx,%r15

	shld    $1,%rsi,%r15
	andq	mask63(%rip),%rsi

	imul   $19,%r15,%rbx
	addq   %r12,%rbx
	adcq   $0,%rbp
	adcq   $0,%rax
	adcq   $0,%rsi

	subq    $1,%rdi
	cmpq    $0,%rdi

	jne     .L

	movq    56(%rsp),%rdi

	movq    %rbx,0(%rdi)
	movq    %rbp,8(%rdi)
	movq    %rax,16(%rdi)
	movq    %rsi,24(%rdi)

	movq    0(%rsp),%r11
	movq    8(%rsp),%r12
	movq    16(%rsp),%r13
	movq    24(%rsp),%r14
	movq    32(%rsp),%r15
	movq    40(%rsp),%rbx
	movq    48(%rsp),%rbp

	movq    %r11,%rsp

	ret
.section	.note.GNU-stack,"",@progbits
