Path: blob/main/crypto/libecc/src/examples/hash/gostr34_11_94.c
34889 views
/*1* Copyright (C) 2021 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[email protected]>6*7* This software is licensed under a dual BSD and GPL v2 license.8* See LICENSE file at the root folder of the project.9*/10#include "gostr34_11_94.h"1112/* The 8 4-bit GOST block cipher encryption SBOX */13static const u8 gostr34_11_94_sbox_norm[8][16] =14{15{ 4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3 },16{ 14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9 },17{ 5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11 },18{ 7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3 },19{ 6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2 },20{ 4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14 },21{ 13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12 },22{ 1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12 }23};2425static const u8 gostr34_11_94_sbox_rfc4357[8][16] =26{27{ 10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15},28{ 5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8},29{ 7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13},30{ 4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3},31{ 7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5},32{ 7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3},33{ 13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11},34{ 1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12}35};363738/* Endianness handling */39ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_arch_is_big_endian(void)40{41const u16 val = 0x0102;42const u8 *buf = (const u8 *)(&val);4344return (buf[0] == 0x01);45}4647/* A and P linear transformations */48static inline void gostr34_11_94_A(const u64 Y[GOSTR34_11_94_STATE_SIZE], u64 Y_[GOSTR34_11_94_STATE_SIZE])49{50u64 y1, y2, y3, y4;5152y1 = Y[3];53y2 = Y[2];54y3 = Y[1];55y4 = Y[0];5657Y_[0] = (y1 ^ y2);58Y_[1] = y4;59Y_[2] = y3;60Y_[3] = y2;6162return;63}6465static inline void gostr34_11_94_P(const u64 Y[GOSTR34_11_94_STATE_SIZE], u64 Y_[GOSTR34_11_94_STATE_SIZE])66{67unsigned int i, k;6869const u8 *y = (const u8*)Y;70u8 *y_ = (u8*)Y_;7172for(i = 0; i < 4; i++){73for(k = 1; k < 9; k++){74unsigned int phi_idx = (8 * GOSTR34_11_94_STATE_SIZE) - (i + (4 * (k - 1)));75unsigned int phi = ((8 * i) + k);76y_[phi_idx - 1] = y[phi - 1];77}78}79return;80}8182/* GOSTR34_11_94 key generation constants */83static const u64 gostr34_11_94_C[3][GOSTR34_11_94_STATE_SIZE] = {84{ 0, 0, 0, 0 },85{ 0xff000000ffff00ffULL, 0x00ffff00ff0000ffULL, 0xff00ff00ff00ff00ULL, 0x00ff00ff00ff00ffULL },86{ 0, 0, 0, 0 },87};8889/* GOSTR34_11_94 key generation */90ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_key_generation(const u64 H[GOSTR34_11_94_STATE_SIZE], const u64 M[GOSTR34_11_94_STATE_SIZE], u64 K[4][GOSTR34_11_94_STATE_SIZE])91{92/* U, V, W */93u64 U[GOSTR34_11_94_STATE_SIZE], V[GOSTR34_11_94_STATE_SIZE], W[GOSTR34_11_94_STATE_SIZE];94unsigned int i, j;95int ret;9697/* U = H */98ret = local_memcpy(U, H, sizeof(U)); EG(ret, err);99/* V = M */100ret = local_memcpy(V, M, sizeof(V)); EG(ret, err);101/* W = U ^ V */102for(j = 0; j < GOSTR34_11_94_STATE_SIZE; j++){103W[j] = (U[j] ^ V[j]);104}105/* K1 = P(W) */106gostr34_11_94_P(W, K[0]);107108for(i = 1; i < 4; i++){109/* U = A(U) ^ C */110gostr34_11_94_A(U, U);111for(j = 0; j < GOSTR34_11_94_STATE_SIZE; j++){112u64 C;113GET_UINT64_LE(C, (const u8*)&gostr34_11_94_C[i - 1][j], 0);114U[j] = (u64)(U[j] ^ C);115}116/* V = A(A(V)) */117gostr34_11_94_A(V, V);118gostr34_11_94_A(V, V);119/* W = U ^ V */120for(j = 0; j < GOSTR34_11_94_STATE_SIZE; j++){121W[j] = (u64)(U[j] ^ V[j]);122}123/* Ki = P(W) */124gostr34_11_94_P(W, K[i]);125}126127ret = 0;128129err:130return ret;131}132133/* GOSTR34_11_94 state encryption */134ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_block_encryption(const u64 K[GOSTR34_11_94_STATE_SIZE], const u64 P, u64 *E, const u8 sbox[8][16])135{136int ret;137unsigned int round, i;138u32 R_i, L_i, R_i1 = 0, L_i1 = 0;139const u8 *p = (const u8*)&P;140u8 *e = (u8*)E;141142MUST_HAVE((K != NULL) && (sbox != NULL) && (E != NULL), ret, err);143144/* The encryption is a Feistel network */145GET_UINT32_BE(L_i, p, 0);146GET_UINT32_BE(R_i, p, 4);147for(round = 0; round < 32; round++){148u32 sk;149const u8 *k = (const u8*)K;150u8 *r_i1 = (u8 *)&R_i1;151152/* Key schedule */153if(round < 24){154GET_UINT32_LE(sk, k, (4 * (round % 8)));155}156else{157GET_UINT32_LE(sk, k, (4 * (7 - (round % 8))));158}159/*** Feistel round ***/160R_i1 = (u32)(R_i + sk); /* add round key */161/* SBox layer */162for(i = 0; i < 4; i++){163unsigned int sb_idx;164if(gostr34_11_94_arch_is_big_endian()){165sb_idx = (2 * (3 - i));166}167else{168sb_idx = (2 * i);169}170r_i1[i] = (u8)((sbox[sb_idx + 1][(r_i1[i] & 0xf0) >> 4] << 4) | (sbox[sb_idx][(r_i1[i] & 0x0f)]));171}172/* Rotation by 11 and XOR with L */173R_i1 = (u32)(ROTL_GOSTR34_11_94(R_i1, 11) ^ L_i);174/* Feistel */175L_i1 = R_i;176/* Next round */177R_i = R_i1;178L_i = L_i1;179}180/* Output */181PUT_UINT32_LE(L_i1, e, 0);182PUT_UINT32_LE(R_i1, e, 4);183184ret = 0;185186err:187return ret;188}189190ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_state_encryption(const u64 K[4][GOSTR34_11_94_STATE_SIZE], const u64 H[GOSTR34_11_94_STATE_SIZE], u64 S[GOSTR34_11_94_STATE_SIZE], const u8 sbox[8][16])191{192int ret;193194195MUST_HAVE((GOSTR34_11_94_STATE_SIZE == 4), ret, err);196/* Return S = s4 s3 s2 s1 */197/* s1 = E(h1, K1) */198ret = gostr34_11_94_block_encryption(K[0], H[3], &S[0], sbox); EG(ret, err);199/* s2 = E(h2, K2) */200ret = gostr34_11_94_block_encryption(K[1], H[2], &S[1], sbox); EG(ret, err);201/* s3 = E(h3, K3) */202ret = gostr34_11_94_block_encryption(K[2], H[1], &S[2], sbox); EG(ret, err);203/* s4 = E(h4, K4) */204ret = gostr34_11_94_block_encryption(K[3], H[0], &S[3], sbox); EG(ret, err);205206ret = 0;207208err:209return ret;210}211212/*213* NOTE: we use a somehow "artificial" union here in order to deal with214* possible alignment issues in the gostr34_11_94_state_psi function215* (as we have to interpret an array of 4 u64 into an array of 16 u16216* in order to apply our Psi function).217*/218typedef union {219u64 A[GOSTR34_11_94_STATE_SIZE];220u16 B[16];221} gostr34_11_94_union;222223/* GOSTR34_11_94 output transformation */224ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_state_psi(const u64 G[GOSTR34_11_94_STATE_SIZE], u64 G_[GOSTR34_11_94_STATE_SIZE])225{226int ret;227unsigned int i;228/* Use our unions in order to deal with alignment issues229* (see the rationale above).230*/231gostr34_11_94_union G_copy;232gostr34_11_94_union *g = &G_copy;233gostr34_11_94_union *g_ = (gostr34_11_94_union*)G_;234235/* Better safe than sorry ... */236MUST_HAVE((sizeof(gostr34_11_94_union) == (sizeof(u64) * GOSTR34_11_94_STATE_SIZE)), ret, err);237238/* Copy input */239ret = local_memcpy(g, G, sizeof(gostr34_11_94_union)); EG(ret, err);240241/* ψ(Γ) = (γ0 ⊕ γ1 ⊕ γ2 ⊕ γ3 ⊕ γ12 ⊕ γ15) γ15 γ14 · · · γ1242* where Γ is split into sixteen 16-bit words, i.e. Γ = γ15 γ14 · · · γ0.243*/244for(i = 0; i < 15; i++){245g_->B[i] = g->B[i + 1];246}247g_->B[15] = (u16)((g->B[0]) ^ (g->B[1]) ^ (g->B[2]) ^ (g->B[3]) ^ (g->B[12]) ^ (g->B[15]));248249ret = 0;250251err:252return ret;253}254255ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_state_output_transform(const u64 H[GOSTR34_11_94_STATE_SIZE], const u64 S[GOSTR34_11_94_STATE_SIZE], const u64 M[GOSTR34_11_94_STATE_SIZE], u64 H_[GOSTR34_11_94_STATE_SIZE])256{257unsigned int i;258int ret;259260/* Compute psi^12 of S */261ret = local_memcpy(H_, S, GOSTR34_11_94_STATE_SIZE * sizeof(u64)); EG(ret, err);262for(i = 0; i < 12; i++){263ret = gostr34_11_94_state_psi(H_, H_); EG(ret, err);264}265/* Compute M xor psi^12 */266for(i = 0; i < GOSTR34_11_94_STATE_SIZE; i++){267u64 m;268if(gostr34_11_94_arch_is_big_endian()){269GET_UINT64_LE(m, (const u8*)&M[GOSTR34_11_94_STATE_SIZE - i - 1], 0);270}271else{272GET_UINT64_BE(m, (const u8*)&M[GOSTR34_11_94_STATE_SIZE - i - 1], 0);273}274H_[i] = (u64)(H_[i] ^ m);275}276ret = gostr34_11_94_state_psi(H_, H_); EG(ret, err);277/* Xor it with H */278for(i = 0; i < GOSTR34_11_94_STATE_SIZE; i++){279u64 h;280if(gostr34_11_94_arch_is_big_endian()){281GET_UINT64_LE(h, (const u8*)&H[GOSTR34_11_94_STATE_SIZE - i - 1], 0);282}283else{284GET_UINT64_BE(h, (const u8*)&H[GOSTR34_11_94_STATE_SIZE - i - 1], 0);285}286H_[i] = (u64)(H_[i] ^ h);287}288/* Now compute psi^61 */289for(i = 0; i < 61; i++){290ret = gostr34_11_94_state_psi(H_, H_); EG(ret, err);291}292293ret = 0;294295err:296return ret;297}298299/* GOSTR34_11_94 256-bit words summing (a simple adder with carry in constant time) */300static inline void gostr34_11_94_256bit_sum(const u64 A[GOSTR34_11_94_STATE_SIZE], const u64 B[GOSTR34_11_94_STATE_SIZE], u64 C[GOSTR34_11_94_STATE_SIZE])301{302unsigned int i;303u64 tmp, carry1, carry2, _carry;304305_carry = 0;306for(i = 0; i < GOSTR34_11_94_STATE_SIZE; i++){307u64 a, b, c;308unsigned int idx = (GOSTR34_11_94_STATE_SIZE - i - 1);309GET_UINT64_BE(a, (const u8*)(&A[idx]), 0);310GET_UINT64_BE(b, (const u8*)(&B[idx]), 0);311tmp = (u64)(a + b);312carry1 = (u64)(tmp < a);313c = (u64)(tmp + _carry);314carry2 = (u64)(c < tmp);315_carry = (u64)(carry1 | carry2);316PUT_UINT64_BE(c, (u8*)(&C[idx]), 0);317}318319return;320}321322/* GOSTR34_11_94 core processing. Returns 0 on success, -1 on error. */323ATTRIBUTE_WARN_UNUSED_RET static inline int gostr34_11_94_process(gostr34_11_94_context *ctx,324const u8 data[GOSTR34_11_94_BLOCK_SIZE])325{326int ret;327unsigned int i;328u64 K[4][GOSTR34_11_94_STATE_SIZE];329u64 H[GOSTR34_11_94_STATE_SIZE], S[GOSTR34_11_94_STATE_SIZE], M[GOSTR34_11_94_STATE_SIZE];330331MUST_HAVE((data != NULL), ret, err);332GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);333/* Get our local data in little endian format */334for(i = 0; i < GOSTR34_11_94_BLOCK_SIZE; i++){335((u8*)M)[i] = data[GOSTR34_11_94_BLOCK_SIZE - i - 1];336}337/* Get the saved state */338for(i = 0; i < GOSTR34_11_94_BLOCK_SIZE; i++){339((u8*)H)[i] = ((u8*)ctx->gostr34_11_94_state)[GOSTR34_11_94_BLOCK_SIZE - i - 1];340}341342/* Key generation */343ret = gostr34_11_94_key_generation(H, M, K); EG(ret, err);344/* State encryption */345switch(ctx->gostr34_11_94_t){346case GOST34_11_94_NORM:{347ret = gostr34_11_94_state_encryption((const u64 (*)[4])K, H, S, gostr34_11_94_sbox_norm); EG(ret, err);348break;349}350case GOST34_11_94_RFC4357:{351ret = gostr34_11_94_state_encryption((const u64 (*)[4])K, H, S, gostr34_11_94_sbox_rfc4357); EG(ret, err);352break;353}354default:{355ret = -1;356goto err;357}358}359/* Output transformation */360ret = gostr34_11_94_state_output_transform(H, S, M, ctx->gostr34_11_94_state); EG(ret, err);361/* Update the internal sum */362gostr34_11_94_256bit_sum(ctx->gostr34_11_94_sum, M, ctx->gostr34_11_94_sum);363364ret = 0;365366err:367return ret;368}369370/* Init hash function. Returns 0 on success, -1 on error. */371ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_init(gostr34_11_94_context *ctx)372{373int ret;374375MUST_HAVE((ctx != NULL), ret, err);376377/* Sanity check on size */378MUST_HAVE((GOSTR34_11_94_DIGEST_SIZE <= MAX_DIGEST_SIZE), ret, err);379380ctx->gostr34_11_94_total = 0;381ctx->gostr34_11_94_state[0] = 0;382ctx->gostr34_11_94_state[1] = 0;383ctx->gostr34_11_94_state[2] = 0;384ctx->gostr34_11_94_state[3] = 0;385386ret = local_memset(ctx->gostr34_11_94_sum, 0, sizeof(ctx->gostr34_11_94_sum)); EG(ret, err);387388/* Our default GOST34_11_94 type is GOST34_11_94_NORM */389ctx->gostr34_11_94_t = GOST34_11_94_NORM;390391/* Tell that we are initialized */392ctx->magic = GOSTR34_11_94_HASH_MAGIC;393394ret = 0;395396err:397return ret;398}399400/* Function to modify the initial IV as it is not imposed by the RFCs */401ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_set_iv(gostr34_11_94_context *ctx, const u64 iv[GOSTR34_11_94_STATE_SIZE])402{403int ret;404405MUST_HAVE((iv != NULL), ret, err);406GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);407408/* We cannot change the IV after the first update */409MUST_HAVE((ctx->gostr34_11_94_total == 0), ret, err);410411ctx->gostr34_11_94_state[0] = iv[0];412ctx->gostr34_11_94_state[1] = iv[1];413ctx->gostr34_11_94_state[2] = iv[2];414ctx->gostr34_11_94_state[3] = iv[3];415416ret = 0;417418err:419return ret;420}421422/* Function to modify the GOST type (that will dictate the underlying SBOX to use for block encryption) */423ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_set_type(gostr34_11_94_context *ctx, gostr34_11_94_type type)424{425int ret;426427GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);428429/* We cannot change the algorithm type after the first update */430MUST_HAVE((ctx->gostr34_11_94_total == 0), ret, err);431432if((type != GOST34_11_94_NORM) && (type != GOST34_11_94_RFC4357)){433ret = -1;434goto err;435}436437ctx->gostr34_11_94_t = type;438439ret = 0;440441err:442return ret;443}444445446ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_update(gostr34_11_94_context *ctx, const u8 *input, u32 ilen)447{448const u8 *data_ptr = input;449u32 remain_ilen = ilen;450u16 fill;451u8 left;452int ret;453454MUST_HAVE((input != NULL) || (ilen == 0), ret, err);455GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);456457/* Nothing to process, return */458if (ilen == 0) {459ret = 0;460goto err;461}462463/* Get what's left in our local buffer */464left = (ctx->gostr34_11_94_total & 0x3F);465fill = (u16)(GOSTR34_11_94_BLOCK_SIZE - left);466467ctx->gostr34_11_94_total += ilen;468469if ((left > 0) && (remain_ilen >= fill)) {470/* Copy data at the end of the buffer */471ret = local_memcpy(ctx->gostr34_11_94_buffer + left, data_ptr, fill); EG(ret, err);472ret = gostr34_11_94_process(ctx, ctx->gostr34_11_94_buffer); EG(ret, err);473data_ptr += fill;474remain_ilen -= fill;475left = 0;476}477478while (remain_ilen >= GOSTR34_11_94_BLOCK_SIZE) {479ret = gostr34_11_94_process(ctx, data_ptr); EG(ret, err);480data_ptr += GOSTR34_11_94_BLOCK_SIZE;481remain_ilen -= GOSTR34_11_94_BLOCK_SIZE;482}483484if (remain_ilen > 0) {485ret = local_memcpy(ctx->gostr34_11_94_buffer + left, data_ptr, remain_ilen); EG(ret, err);486}487488ret = 0;489490err:491return ret;492}493494/* Finalize. Returns 0 on success, -1 on error.*/495ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_final(gostr34_11_94_context *ctx, u8 output[GOSTR34_11_94_DIGEST_SIZE])496{497unsigned int block_present = 0;498u8 last_padded_block[2 * GOSTR34_11_94_BLOCK_SIZE];499int ret;500501MUST_HAVE((output != NULL), ret, err);502GOSTR34_11_94_HASH_CHECK_INITIALIZED(ctx, ret, err);503504/* This is our final step, so we proceed with the padding if necessary */505/* Fill in our last block with zeroes */506ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err);507508block_present = ctx->gostr34_11_94_total % GOSTR34_11_94_BLOCK_SIZE;509/* Copy what's left in our temporary context buffer */510ret = local_memcpy(last_padded_block, ctx->gostr34_11_94_buffer,511block_present); EG(ret, err);512513/* Put in the second block the size in bits of the message in bits in little endian */514PUT_UINT64_LE(8 * ctx->gostr34_11_94_total, last_padded_block, GOSTR34_11_94_BLOCK_SIZE);515516if(block_present != 0){517/* Process padding block if necessary */518ret = gostr34_11_94_process(ctx, last_padded_block); EG(ret, err);519}520/* Copy our sum in the beginning of the block */521if(gostr34_11_94_arch_is_big_endian()){522PUT_UINT64_LE(ctx->gostr34_11_94_sum[3], last_padded_block, 0);523PUT_UINT64_LE(ctx->gostr34_11_94_sum[2], last_padded_block, 8);524PUT_UINT64_LE(ctx->gostr34_11_94_sum[1], last_padded_block, 16);525PUT_UINT64_LE(ctx->gostr34_11_94_sum[0], last_padded_block, 24);526}527else{528PUT_UINT64_BE(ctx->gostr34_11_94_sum[3], last_padded_block, 0);529PUT_UINT64_BE(ctx->gostr34_11_94_sum[2], last_padded_block, 8);530PUT_UINT64_BE(ctx->gostr34_11_94_sum[1], last_padded_block, 16);531PUT_UINT64_BE(ctx->gostr34_11_94_sum[0], last_padded_block, 24);532}533534/* Process the "size" in bits block */535ret = gostr34_11_94_process(ctx, last_padded_block + GOSTR34_11_94_BLOCK_SIZE); EG(ret, err);536/* Process the message blocks sum */537ret = gostr34_11_94_process(ctx, last_padded_block); EG(ret, err);538539/* Output the hash result */540if(gostr34_11_94_arch_is_big_endian()){541PUT_UINT64_BE(ctx->gostr34_11_94_state[0], output, 0);542PUT_UINT64_BE(ctx->gostr34_11_94_state[1], output, 8);543PUT_UINT64_BE(ctx->gostr34_11_94_state[2], output, 16);544PUT_UINT64_BE(ctx->gostr34_11_94_state[3], output, 24);545}546else{547PUT_UINT64_LE(ctx->gostr34_11_94_state[0], output, 0);548PUT_UINT64_LE(ctx->gostr34_11_94_state[1], output, 8);549PUT_UINT64_LE(ctx->gostr34_11_94_state[2], output, 16);550PUT_UINT64_LE(ctx->gostr34_11_94_state[3], output, 24);551}552553/* Tell that we are uninitialized */554ctx->magic = WORD(0);555556ret = 0;557558err:559return ret;560}561562563/*564* Scattered version performing init/update/finalize on a vector of buffers565* 'inputs' with the length of each buffer passed via 'ilens'. The function566* loops on pointers in 'inputs' until it finds a NULL pointer. The function567* returns 0 on success, -1 on error.568*/569ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_scattered(const u8 **inputs, const u32 *ilens,570u8 output[GOSTR34_11_94_DIGEST_SIZE], gostr34_11_94_type type)571{572gostr34_11_94_context ctx;573int ret, pos = 0;574575MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);576577ret = gostr34_11_94_init(&ctx); EG(ret, err);578ret = gostr34_11_94_set_type(&ctx, type); EG(ret, err);579580while (inputs[pos] != NULL) {581ret = gostr34_11_94_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);582pos += 1;583}584585ret = gostr34_11_94_final(&ctx, output);586587err:588return ret;589}590591ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_scattered_norm(const u8 **inputs, const u32 *ilens,592u8 output[GOSTR34_11_94_DIGEST_SIZE])593{594return gostr34_11_94_scattered(inputs, ilens, output, GOST34_11_94_NORM);595}596597ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_scattered_rfc4357(const u8 **inputs, const u32 *ilens,598u8 output[GOSTR34_11_94_DIGEST_SIZE])599{600return gostr34_11_94_scattered(inputs, ilens, output, GOST34_11_94_RFC4357);601}602603604/*605* Single call version performing init/update/final on given input.606* Returns 0 on success, -1 on error.607*/608ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94(const u8 *input, u32 ilen, u8 output[GOSTR34_11_94_DIGEST_SIZE], gostr34_11_94_type type)609{610gostr34_11_94_context ctx;611int ret;612613ret = gostr34_11_94_init(&ctx); EG(ret, err);614ret = gostr34_11_94_set_type(&ctx, type); EG(ret, err);615ret = gostr34_11_94_update(&ctx, input, ilen); EG(ret, err);616ret = gostr34_11_94_final(&ctx, output);617618err:619return ret;620}621622ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_norm(const u8 *input, u32 ilen, u8 output[GOSTR34_11_94_DIGEST_SIZE])623{624return gostr34_11_94(input, ilen, output, GOST34_11_94_NORM);625}626627ATTRIBUTE_WARN_UNUSED_RET int gostr34_11_94_rfc4357(const u8 *input, u32 ilen, u8 output[GOSTR34_11_94_DIGEST_SIZE])628{629return gostr34_11_94(input, ilen, output, GOST34_11_94_RFC4357);630}631632633