/** DrySponge Sebastien Riou, January 6th 2019 c99 little endian 32 bit implementation meant to fit in the supercop framework Note: although this is faster than the ref implementation we noticed that it is still several times slower compared to what can be done with assembly. */ #ifndef __DRYSPONGE_H__ #define __DRYSPONGE_H__ #include "drysponge_common.h" //assume 32bit alignement is enough to access uint64_t since we target 32 bit CPU #define ALIGN64 4 //#define ALIGN64 8 #ifndef DRYSPONGE_DBG_EN #define DRYSPONGE_DBG_EN 0 #endif typedef struct DRYSPONGE_struct_t { uint64_t c[DRYSPONGE_CAPACITYSIZE64]; uint64_t r[DRYSPONGE_BLOCKSIZE64]; uint64_t x[DRYSPONGE_XSIZE64]; uint8_t *obuf; uint64_t fcnt; #ifdef DRYSPONGE_EXT DRYSPONGE_EXT_t ext; #endif unsigned int rounds; } DRYSPONGE_t; #include "drysponge_dbg_support.h" static void DRYSPONGE_xor64( const uint64_t *const a,//exactly one block of input const uint64_t *const b, uint64_t *const y ){ for(unsigned int i=0;ic),ctx->rounds); } #else static void DRYSPONGE_g( DRYSPONGE_t *const ctx ){ #if DRYSPONGE_DBG_EN printf(" G entry %lu:\n",ctx->fcnt); DRYSPONGE_print_state(ctx); #endif ctx->fcnt++; DRYSPONGE_xor64(ctx->r,ctx->r,ctx->r);//r=0 for(unsigned int j = 0;jrounds;j++){ #if DRYSPONGE_DBG_EN >= DRYSPONGE_DBG_ROUND_IO printf(" CoreRound entry %d:\n",j); DRYSPONGE_print_state(ctx); #endif DRYSPONGE_CoreRound(ctx,j); uint32_t*r32 = (uint32_t*)ctx->r; for(unsigned int k=0;kc)+k*DRYSPONGE_BLOCKSIZE32; for(unsigned int i=0;ic),(uint32_t*)i,(uint32_t)ctx->ext,ctx->rounds); ctx->ext=0; } #else static void DRYSPONGE_f( DRYSPONGE_t *const ctx, const uint8_t *const i ){ #if DRYSPONGE_DBG_EN printf(" F entry %lu:\n",ctx->fcnt); DRYSPONGE_print_state(ctx); print_bytes_sep(" I = ",i,DRYSPONGE_BLOCKSIZE,"\n",""); #endif DRYSPONGE_MixPhase(ctx,i); #if DRYSPONGE_DBG_EN >= DRYSPONGE_DBG_ROUND_IO printf(" After mix phase:\n"); DRYSPONGE_print_state(ctx); #endif DRYSPONGE_g(ctx); } #endif static void DRYSPONGE_set_key( DRYSPONGE_t *const ctx, const uint8_t *const key, const unsigned int keylen ){ uint32_t *const c32 = (uint32_t *const)ctx->c; uint32_t *const x32 = (uint32_t *const)ctx->x; assert(DRYSPONGE_KEYSIZE<=keylen); const unsigned int midkeysize = DRYSPONGE_KEYSIZE+DRYSPONGE_XSIZE; const unsigned int fullkeysize = DRYSPONGE_CAPACITYSIZE+DRYSPONGE_XSIZE; if(DRYSPONGE_KEYSIZE!=keylen){//all words for x assumed to be different if((keylen%8) || (((uintptr_t)key)%ALIGN64)){ uint8_t*c = (uint8_t*)ctx->c; uint8_t*x = (uint8_t*)ctx->x; if(fullkeysize == keylen){ memcpy(ctx->c,key,DRYSPONGE_CAPACITYSIZE); memcpy(ctx->x,key+DRYSPONGE_CAPACITYSIZE,DRYSPONGE_XSIZE); } else { assert(midkeysize==keylen); for(unsigned int i=0;ic[i] = key64[i]; } for(unsigned int i=0;ix[i] = key64[i+DRYSPONGE_CAPACITYSIZE64]; } }else{ assert(midkeysize==keylen); for(unsigned int i=0;ic[i] = key64[i%DRYSPONGE_KEYSIZE64]; } for(unsigned int i=0;ix[i] = key64[i+DRYSPONGE_KEYSIZE64]; } } } }else{ uint8_t*c = (uint8_t*)ctx->c; for(unsigned int i=0;ix,ctx->c,DRYSPONGE_XSIZE); memcpy(ctx->c,key,DRYSPONGE_XSIZE); } //sanity check: all words in x shall be different for(unsigned int i=0;i DRYSPONGE_BLOCKSIZE ? DRYSPONGE_BLOCKSIZE : remaining; memcpy(out,ctx->r,len); out+=len; remaining-=len; if(remaining){ DRYSPONGE_g(ctx); } } } static void DRYSPONGE_init_ctx( DRYSPONGE_t *const ctx ){ #ifdef DRYSPONGE_EXT memset(DRYSPONGE_EXT_ARG,0,sizeof(DRYSPONGE_EXT_t)); #endif ctx->fcnt=0; memset(ctx->r,0x00,DRYSPONGE_BLOCKSIZE); } static void DRYSPONGE_hash( const uint8_t *const message, const size_t mlen, uint8_t *const digest ){ DRYSPONGE_t ctx_storage; DRYSPONGE_t *const ctx = &ctx_storage; DRYSPONGE_init_ctx(ctx); ctx->rounds=DRYSPONGE_ROUNDS; #if DRYSPONGE_DBG_EN printf("Hashing %lu bytes message: ",mlen); print_bytes_sep("",message,mlen,"\n",""); #endif const uint64_t CST_H[] = { 0xd308a385886a3f24, 0x447370032e8a1913, 0xd0319f29223809a4, 0x896c4eec98fa2e08, 0x7713d038e6212845, 0x6c0ce934cf6654be, 0xdd507cc9b729acc0, 0x170947b5b5d5843f, 0x1bfb7989d9d51692, 0xacb5df98a60b31d1, 0xb7df1ad0db72fd2f, 0x967e266aedafe1b8, 0x997f2cf145907cba, 0xf76c91b34799a124, 0x16fc8e85e2f20108, 0x694e5771d8206963, }; DRYSPONGE_set_key(ctx,(const uint8_t*)CST_H,DRYSPONGE_KEYSIZE+DRYSPONGE_XSIZE); DRYSPONGE_absorb_only(ctx,message,mlen,DRYSPONGE_DS,1); DRYSPONGE_squeez_only(ctx,digest,DRYSPONGE_DIGESTSIZE); #if DRYSPONGE_DBG_EN printf(" Final state:\n"); DRYSPONGE_print_state(ctx); print_bytes_sep(" Digest: ",digest,DRYSPONGE_DIGESTSIZE,"\n",""); #endif } static void DRYSPONGE_init( DRYSPONGE_t *const ctx, const uint8_t *const key, const unsigned int klen, const uint8_t *const nonce, uint8_t *out_buffer,//output buffer unsigned int finalize ){ DRYSPONGE_init_ctx(ctx); ctx->rounds=DRYSPONGE_ROUNDS; DRYSPONGE_set_key(ctx,key,klen); ctx->obuf = out_buffer; DRYSPONGE_DomainSeparator(DRYSPONGE_EXT_ARG,DRYSPONGE_DSINFO(0,DRYSPONGE_DD,finalize)); ctx->rounds=DRYSPONGE_INIT_ROUNDS; #if DRYSPONGE_NONCESIZE>DRYSPONGE_BLOCKSIZE assert(0==(DRYSPONGE_NONCESIZE%DRYSPONGE_BLOCKSIZE)); unsigned int nloops = DRYSPONGE_DIVUP(DRYSPONGE_NONCESIZE,DRYSPONGE_BLOCKSIZE); for(unsigned int i=0;irounds=DRYSPONGE_ROUNDS; } static void DRYSPONGE_enc_core( DRYSPONGE_t *const ctx, const uint64_t *const ib//exactly one block of input ){ DRYSPONGE_xor((uint8_t *)ctx->r,(uint8_t *)ib,ctx->obuf); DRYSPONGE_f(ctx,(uint8_t *)ib); ctx->obuf+=DRYSPONGE_BLOCKSIZE; } static void DRYSPONGE_enc_core_aligned( DRYSPONGE_t *const ctx, const uint64_t *const ib//exactly one block of input ){ assert((((uintptr_t)ctx->obuf)%8) == 0); DRYSPONGE_xor64(ctx->r,ib,(uint64_t*const)ctx->obuf); DRYSPONGE_f(ctx,(uint8_t *)ib); ctx->obuf+=DRYSPONGE_BLOCKSIZE; } static const uint8_t* DRYSPONGE_enc_blocks( DRYSPONGE_t *const ctx, const uint8_t *im,//whole message size_t m ){ (void)DRYSPONGE_load32; (void)DRYSPONGE_store32; (void)DRYSPONGE_load64; (void)DRYSPONGE_store64; uint64_t buf64[DRYSPONGE_BLOCKSIZE64]; const uint64_t *ib64; #if DRYSPONGE_BLOCKSIZE % ALIGN64 unsigned int input_aligned = 0; unsigned int output_aligned = 0; #else unsigned int input_aligned = 0==(((uintptr_t)im)%ALIGN64); unsigned int output_aligned = 0==(((uintptr_t)ctx->obuf)%ALIGN64); #endif if(input_aligned && output_aligned){ for(size_t i = 0; ir,ib,ctx->obuf); DRYSPONGE_f(ctx,ctx->obuf); ctx->obuf+=DRYSPONGE_BLOCKSIZE; } static void DRYSPONGE_dec_core_aligned( DRYSPONGE_t *const ctx, const uint64_t *const ib//exactly one block of input ){ DRYSPONGE_xor64(ctx->r,ib,(uint64_t*const)ctx->obuf); DRYSPONGE_f(ctx,ctx->obuf); ctx->obuf+=DRYSPONGE_BLOCKSIZE; } static const uint8_t* DRYSPONGE_dec_blocks( DRYSPONGE_t *const ctx, const uint8_t *im,//whole message size_t m ){ const uint64_t *ib64; #if DRYSPONGE_BLOCKSIZE % ALIGN64 unsigned int input_aligned = 0; unsigned int output_aligned = 0; #else unsigned int input_aligned = 0==(((uintptr_t)im)%ALIGN64); unsigned int output_aligned = 0==(((uintptr_t)ctx->obuf)%ALIGN64); #endif if(input_aligned && output_aligned){ for(size_t i = 0; iobuf = ciphertext + mlen;//fix the size } DRYSPONGE_squeez_only(ctx,ctx->obuf,DRYSPONGE_TAGSIZE); *clen = mlen+DRYSPONGE_TAGSIZE; #if DRYSPONGE_DBG_EN printf(" Final state:\n"); DRYSPONGE_print_state(ctx); print_bytes_sep(" CipherText: ",ciphertext,*clen,"\n",""); #endif } //WARNING the function writes plaintext into "message" before checking the tag. //It is the responsability of the caller to ensure that the "message" buffer is //not accessible by anything until this function has return. static int DRYSPONGE_dec( const uint8_t *const key, const unsigned int klen, const uint8_t *const nonce, const uint8_t *const ciphertext, const size_t clen, const uint8_t * const ad, const size_t alen, uint8_t *message ){ if(clenr,last_block64,last_block64); uint8_t mpad = DRYSPONGE_padding(last_block,remaining,last_block); im+=remaining; DRYSPONGE_DomainSeparator(DRYSPONGE_EXT_ARG,DRYSPONGE_DSINFO(mpad,DRYSPONGE_DM,1)); memcpy(ctx->obuf,last_block,remaining); DRYSPONGE_f(ctx,last_block); } uint64_t tag64[DRYSPONGE_TAGSIZE64]; uint8_t*tag = (uint8_t*)tag64; DRYSPONGE_squeez_only(ctx,tag,DRYSPONGE_TAGSIZE); DRYSPONGE_DBG(print_bytes_sep("expected tag=",im,DRYSPONGE_TAGSIZE,"\n","")); DRYSPONGE_DBG(print_bytes_sep("computed tag=",tag,DRYSPONGE_TAGSIZE,"\n","")); if(memcmp(tag,im,DRYSPONGE_TAGSIZE)){ memset(message,0,mlen);//erase all output return ~DRYSPONGE_PASS; } return DRYSPONGE_PASS; } #endif