#ifndef SALSA
#define SALSA 1


#if (CLSIZE == 64)
uint16 halfsalsa(uint16 w){
	for(uint i=0; i<4; ++i){
		w.s0123 ^= rotl(w.scdef + w.s89ab, 7U);
		w.s4567 ^= rotl(w.s0123 + w.scdef, 9U);
		w.s89ab ^= rotl(w.s4567 + w.s0123, 13U);
		w.scdef ^= rotl(w.s89ab + w.s4567, 18U);
		w.s89ab ^= rotl(w.sfcde + w.s2301, 7U);
		w.s4567 ^= rotl(w.sb89a + w.sefcd, 9U);
		w.s0123 ^= rotl(w.s7456 + w.sab89, 13U);
		w.scdef ^= rotl(w.s3012 + w.s6745, 18U);
	}
	return w;
}
#endif


#if (CLSIZE == 64)

# if (LOOKUP_GAP == 2)
void salsa(uint16 *B, bool db){

	B[0] ^= B[1];
	B[0] += halfsalsa(B[0]);
	B[1] ^= B[0];
	B[1] += halfsalsa(B[1]);

	if(db){
		B[0] ^= B[1];
		B[0] += halfsalsa(B[0]);
		B[1] ^= B[0];
		B[1] += halfsalsa(B[1]);
	}
}
# elif (LOOKUP_GAP == 3)
/*
void salsa(uint16 *B, ushort times){
	B[0] ^= B[1];
	B[0] += halfsalsa(B[0]);
	B[1] ^= B[0];
	B[1] += halfsalsa(B[1]);

	if(times){
		B[0] ^= B[1];
		B[0] += halfsalsa(B[0]);
		B[1] ^= B[0];
		B[1] += halfsalsa(B[1]);
	}

	if(times==2){
		B[0] ^= B[1];
		B[0] += halfsalsa(B[0]);
		B[1] ^= B[0];
		B[1] += halfsalsa(B[1]);
	}
}
*/
void salsa(uint16 *B, ushort times){
    for(uint i=0; i<times+1; i++){
        B[0] ^= B[1];
        B[0] += halfsalsa(B[0]);
        B[1] ^= B[0];
        B[1] += halfsalsa(B[1]);
    }
}

# elif (LOOKUP_GAP != 1)
void salsa(uint16 *B, ushort times){
	for(uint i=0; i<times+1; i++){
		B[0] ^= B[1];
		B[0] += halfsalsa(B[0]);
		B[1] ^= B[0];
		B[1] += halfsalsa(B[1]);
	}
}
# else
void salsa(uint16 *B){
	B[0] ^= B[1];
	B[0] += halfsalsa(B[0]);
	B[1] ^= B[0];
	B[1] += halfsalsa(B[1]);
}
# endif

#else

void halfsalsa(uint8 *w){
	for(uint i=0; i<4; ++i){
		w[0].s0123 ^= rotl(w[1].s4567 + w[1].s0123, 7U);
		w[0].s4567 ^= rotl(w[0].s0123 + w[1].s4567, 9U);
		w[1].s0123 ^= rotl(w[0].s4567 + w[0].s0123, 13U);
		w[1].s4567 ^= rotl(w[1].s0123 + w[0].s4567, 18U);
		w[1].s0123 ^= rotl(w[1].s7456 + w[0].s2301, 7U);
		w[0].s4567 ^= rotl(w[1].s3012 + w[1].s6745, 9U);
		w[0].s0123 ^= rotl(w[0].s7456 + w[1].s2301, 13U);
		w[1].s4567 ^= rotl(w[0].s3012 + w[0].s6745, 18U);
	}
}

# if (LOOKUP_GAP == 2)
void salsa(uint8 *B, bool db){
# elif (LOOKUP_GAP != 1)
void salsa(uint8 *B, ushort times){
# else
void salsa(uint8 *B){
# endif
	uint8 w[2];
	w[0] = (B[0]^=B[2]);
	w[1] = (B[1]^=B[3]);
	halfsalsa(w);
	w[0] = (B[2]^=(B[0]+=w[0]));
	w[1] = (B[3]^=(B[1]+=w[1]));
	halfsalsa(w);

# if (LOOKUP_GAP == 2)
    if(db){
		w[0] = (B[0]^=(B[2]+=w[0]));
		w[1] = (B[1]^=(B[3]+=w[1]));
		halfsalsa(w);
		w[0] = (B[2]^=(B[0]+=w[0]));
		w[1] = (B[3]^=(B[1]+=w[1]));
		halfsalsa(w);
    }
# elif (LOOKUP_GAP != 1)
	for(uint i=0; i<times; i++){
		w[0] = (B[0]^=(B[2]+=w[0]));
		w[1] = (B[1]^=(B[3]+=w[1]));
		halfsalsa(w);
		w[0] = (B[2]^=(B[0]+=w[0]));
		w[1] = (B[3]^=(B[1]+=w[1]));
		halfsalsa(w);
	}
# endif
	B[2] += w[0];
	B[3] += w[1];
}

#endif

#endif