Optimising SHA-1 for small input - c

I'm hoping to optimise an implementation of SHA-1 for an 8-bit MCU (8051-based). The input data is only 8-bytes, so I wonder if something could be done to improve this macro:
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
The issue I have is that when macro P calls S with S(b, 30), it takes around 60us to complete. Since there're 80 calls to P, it totals to around 4.8ms.
If I'm correct, S(x,n) expects x to be a uint32. Given the rather small input size, could the number of shifts be reduced by making x smaller, e.g., uint8?
If so, is this the only change needed? From:
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
To:
#define S(x,n) ((x << n) | ((x & 0xFF) >> (8 - n)))
From:
void sha1_process( sha1_context *ctx, uint8 data[64] )
{
uint32 temp, W[16], A, B, C, D, E;
// ...
To:
void sha1_process( sha1_context *ctx, uint8 data[64] )
{
uint8 temp, W[16], A, B, C, D, E;
// ...
Here's the complete code:
#include <string.h>
#include "sha1.h"
#define GET_UINT32(n,b,i) \
{ \
(n) = ( (uint32) (b)[(i) ] << 24 ) \
| ( (uint32) (b)[(i) + 1] << 16 ) \
| ( (uint32) (b)[(i) + 2] << 8 ) \
| ( (uint32) (b)[(i) + 3] ); \
}
#define PUT_UINT32(n,b,i) \
{ \
(b)[(i) ] = (uint8) ( (n) >> 24 ); \
(b)[(i) + 1] = (uint8) ( (n) >> 16 ); \
(b)[(i) + 2] = (uint8) ( (n) >> 8 ); \
(b)[(i) + 3] = (uint8) ( (n) ); \
}
void sha1_starts( sha1_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
}
void sha1_process( sha1_context *ctx, uint8 data[64] )
{
uint32 temp, W[16], A, B, C, D, E;
GET_UINT32( W[0], data, 0 );
GET_UINT32( W[1], data, 4 );
GET_UINT32( W[2], data, 8 );
GET_UINT32( W[3], data, 12 );
GET_UINT32( W[4], data, 16 );
GET_UINT32( W[5], data, 20 );
GET_UINT32( W[6], data, 24 );
GET_UINT32( W[7], data, 28 );
GET_UINT32( W[8], data, 32 );
GET_UINT32( W[9], data, 36 );
GET_UINT32( W[10], data, 40 );
GET_UINT32( W[11], data, 44 );
GET_UINT32( W[12], data, 48 );
GET_UINT32( W[13], data, 52 );
GET_UINT32( W[14], data, 56 );
GET_UINT32( W[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define R(t) \
( \
temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \
W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \
( W[t & 0x0F] = S(temp,1) ) \
)
#define P(a,b,c,d,e,x) \
{ \
e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
#define F(x,y,z) (z ^ (x & (y ^ z)))
#define K 0x5A827999
P( A, B, C, D, E, W[0] );
P( E, A, B, C, D, W[1] );
P( D, E, A, B, C, W[2] );
P( C, D, E, A, B, W[3] );
P( B, C, D, E, A, W[4] );
P( A, B, C, D, E, W[5] );
P( E, A, B, C, D, W[6] );
P( D, E, A, B, C, W[7] );
P( C, D, E, A, B, W[8] );
P( B, C, D, E, A, W[9] );
P( A, B, C, D, E, W[10] );
P( E, A, B, C, D, W[11] );
P( D, E, A, B, C, W[12] );
P( C, D, E, A, B, W[13] );
P( B, C, D, E, A, W[14] );
P( A, B, C, D, E, W[15] );
P( E, A, B, C, D, R(16) );
P( D, E, A, B, C, R(17) );
P( C, D, E, A, B, R(18) );
P( B, C, D, E, A, R(19) );
#undef K
#undef F
#define F(x,y,z) (x ^ y ^ z)
#define K 0x6ED9EBA1
P( A, B, C, D, E, R(20) );
P( E, A, B, C, D, R(21) );
P( D, E, A, B, C, R(22) );
P( C, D, E, A, B, R(23) );
P( B, C, D, E, A, R(24) );
P( A, B, C, D, E, R(25) );
P( E, A, B, C, D, R(26) );
P( D, E, A, B, C, R(27) );
P( C, D, E, A, B, R(28) );
P( B, C, D, E, A, R(29) );
P( A, B, C, D, E, R(30) );
P( E, A, B, C, D, R(31) );
P( D, E, A, B, C, R(32) );
P( C, D, E, A, B, R(33) );
P( B, C, D, E, A, R(34) );
P( A, B, C, D, E, R(35) );
P( E, A, B, C, D, R(36) );
P( D, E, A, B, C, R(37) );
P( C, D, E, A, B, R(38) );
P( B, C, D, E, A, R(39) );
#undef K
#undef F
#define F(x,y,z) ((x & y) | (z & (x | y)))
#define K 0x8F1BBCDC
P( A, B, C, D, E, R(40) );
P( E, A, B, C, D, R(41) );
P( D, E, A, B, C, R(42) );
P( C, D, E, A, B, R(43) );
P( B, C, D, E, A, R(44) );
P( A, B, C, D, E, R(45) );
P( E, A, B, C, D, R(46) );
P( D, E, A, B, C, R(47) );
P( C, D, E, A, B, R(48) );
P( B, C, D, E, A, R(49) );
P( A, B, C, D, E, R(50) );
P( E, A, B, C, D, R(51) );
P( D, E, A, B, C, R(52) );
P( C, D, E, A, B, R(53) );
P( B, C, D, E, A, R(54) );
P( A, B, C, D, E, R(55) );
P( E, A, B, C, D, R(56) );
P( D, E, A, B, C, R(57) );
P( C, D, E, A, B, R(58) );
P( B, C, D, E, A, R(59) );
#undef K
#undef F
#define F(x,y,z) (x ^ y ^ z)
#define K 0xCA62C1D6
P( A, B, C, D, E, R(60) );
P( E, A, B, C, D, R(61) );
P( D, E, A, B, C, R(62) );
P( C, D, E, A, B, R(63) );
P( B, C, D, E, A, R(64) );
P( A, B, C, D, E, R(65) );
P( E, A, B, C, D, R(66) );
P( D, E, A, B, C, R(67) );
P( C, D, E, A, B, R(68) );
P( B, C, D, E, A, R(69) );
P( A, B, C, D, E, R(70) );
P( E, A, B, C, D, R(71) );
P( D, E, A, B, C, R(72) );
P( C, D, E, A, B, R(73) );
P( B, C, D, E, A, R(74) );
P( A, B, C, D, E, R(75) );
P( E, A, B, C, D, R(76) );
P( D, E, A, B, C, R(77) );
P( C, D, E, A, B, R(78) );
P( B, C, D, E, A, R(79) );
#undef K
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
}
void sha1_update( sha1_context *ctx, uint8 *input, uint32 length )
{
uint32 left, fill;
if( ! length ) return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += length;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < length )
ctx->total[1]++;
if( left && length >= fill )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, fill );
sha1_process( ctx, ctx->buffer );
length -= fill;
input += fill;
left = 0;
}
while( length >= 64 )
{
sha1_process( ctx, input );
length -= 64;
input += 64;
}
if( length )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, length );
}
}
static uint8 sha1_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
void sha1_finish( sha1_context *ctx, uint8 digest[20] )
{
uint32 last, padn;
uint32 high, low;
uint8 msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32( high, msglen, 0 );
PUT_UINT32( low, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
sha1_update( ctx, sha1_padding, padn );
sha1_update( ctx, msglen, 8 );
PUT_UINT32( ctx->state[0], digest, 0 );
PUT_UINT32( ctx->state[1], digest, 4 );
PUT_UINT32( ctx->state[2], digest, 8 );
PUT_UINT32( ctx->state[3], digest, 12 );
PUT_UINT32( ctx->state[4], digest, 16 );
}
#ifdef TEST
#include <stdlib.h>
#include <stdio.h>
/*
* those are the standard FIPS-180-1 test vectors
*/
static char *msg[] =
{
"abc",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
NULL
};
static char *val[] =
{
"a9993e364706816aba3e25717850c26c9cd0d89d",
"84983e441c3bd26ebaae4aa1f95129e5e54670f1",
"34aa973cd4c4daa4f61eeb2bdbad27316534016f"
};
int main( int argc, char *argv[] )
{
FILE *f;
int i, j;
char output[41];
sha1_context ctx;
unsigned char buf[1000];
unsigned char sha1sum[20];
if( argc < 2 )
{
printf( "\n SHA-1 Validation Tests:\n\n" );
for( i = 0; i < 3; i++ )
{
printf( " Test %d ", i + 1 );
sha1_starts( &ctx );
if( i < 2 )
{
sha1_update( &ctx, (uint8 *) msg[i],
strlen( msg[i] ) );
}
else
{
memset( buf, 'a', 1000 );
for( j = 0; j < 1000; j++ )
{
sha1_update( &ctx, (uint8 *) buf, 1000 );
}
}
sha1_finish( &ctx, sha1sum );
for( j = 0; j < 20; j++ )
{
sprintf( output + j * 2, "%02x", sha1sum[j] );
}
if( memcmp( output, val[i], 40 ) )
{
printf( "failed!\n" );
return( 1 );
}
printf( "passed.\n" );
}
printf( "\n" );
}
else
{
if( ! ( f = fopen( argv[1], "rb" ) ) )
{
perror( "fopen" );
return( 1 );
}
sha1_starts( &ctx );
while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
{
sha1_update( &ctx, buf, i );
}
sha1_finish( &ctx, sha1sum );
for( j = 0; j < 20; j++ )
{
printf( "%02x", sha1sum[j] );
}
printf( " %s\n", argv[1] );
}
return( 0 );
}
#endif
Here's an example of the generated code for S(x,n) when called by P( E, A, B, C, D, W[1] ):
0031D0 85 18 82 MOV DPL,XSP(L)
0031D3 85 19 83 MOV DPH,XSP(H)
0031D6 78 08 MOV R0,#0x08
0031D8 12 17 85 LCALL ?L_MOV_X
0031DB 74 1E MOV A,#0x1E
0031DD 78 08 MOV R0,#0x08
0031DF 12 16 80 LCALL ?L_SHL
0031E2 85 18 82 MOV DPL,XSP(L)
0031E5 85 19 83 MOV DPH,XSP(H)
0031E8 78 10 MOV R0,#0x10
0031EA 12 17 85 LCALL ?L_MOV_X
0031ED 74 02 MOV A,#0x02
0031EF 78 10 MOV R0,#0x10
0031F1 12 16 67 LCALL ?UL_SHR
0031F4 78 08 MOV R0,#0x08
0031F6 79 10 MOV R1,#0x10
0031F8 12 17 39 LCALL ?L_IOR
0031FB 85 18 82 MOV DPL,XSP(L)
0031FE 85 19 83 MOV DPH,XSP(H)
003201 78 08 MOV R0,#0x08
003203 12 17 94 LCALL ?L_MOV_TO_X
Thanks

If I'm correct, S(x,n) expects x to be a uint32. Given the rather small input size, could the number of shifts be reduced by making x smaller, e.g., uint8?
No. The state of the SHA1 function consists of five 32-bit values which change every iteration, and those values are what S(x,n) is operating on. Changing those into 8-bit values would give you a completely different (and probably very broken!) hash function.
The MD5/SHA family of hash functions all rely heavily on 32-bit integer operations. Ease of implementation on 8-bit processors, like the 8051, was not a design goal for these functions, and implementations on these parts will not perform particularly well. Sorry. You'll need to either live with the slowness, use another microprocessor (or one with SHA1 hardware acceleration!), or use a different hash algorithm.

It sounds like your actual requirement is finding a MAC/PRF that's cheap to compute on your hardware for 8 byte inputs.
Since your data has fixed length, you can use a secure block cipher (with 128 bit blocks) as CBC-MAC. Since your data is shorter than one block, CBC-MAC simplifies to encrypting the data with the raw block cipher/ECB mode.
If your 128 bit block cipher has a similar cost-per-byte as SHA-1, this will result in an 8x speedup compared with HMAC-SHA-1 (SHA-1 has 512 bit blocks and you need to hash two blocks for HMAC). If you choose a cipher that's particularly suited for your CPU, the speedup might be even larger.
Since AES is so popular, finding implementations optimized for 8 bit CPUs shouldn't be too hard.

Related

Header file not found despite include path listed in makefile

I'm trying to compile some code that uses the BLIS framework, but it seems that the compiler is throwing errors at #include "blis.h" in my C Source File.
I've installed BLIS to C:\msys64\home\[USERPROFILE]\blis (where [userprofile] is my name, or $HOME/blis) and the test examples successfully compile. But running "make" with the following makefile (slightly edited from the BLIS-provided example) in a different directory from the examples (C:\Users\[USERPROFILE]\projects\blis_practice):
BLIS_PREFIX = $(HOME)/blis
BLIS_INC = $(BLIS_PREFIX)/include/haswell/blis
BLIS_LIB = $(BLIS_PREFIX)/lib/haswell/libblis.a
OTHER_LIBS = -lm -fopenmp
CC = clang
CFLAGS = -O2 -g -I$(BLIS_INC)
LINKER = $(CC)
OBJS = 00level1v.o
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
all: $(OBJS)
$(LINKER) $(OBJS) $(BLIS_LIB) $(OTHER_LIBS) -o 00level1v.x
Throws the following error:
clang -O2 -g -I/home/[USERPROFILE]/blis/include/haswell/blis -c 00level1v.c -o 00level1v.o
00level1v.c:36:10: fatal error: 'blis.h' file not found
#include "blis.h"
^~~~~~~~
1 error generated.
make: *** [Makefile:14: 00level1v.o] Error 1
I've confirmed that blis.h is located at C:\msys64\home\[USERPROFILE]\blis\include\haswell\ and libblis.a is located at C:\msys64\home\[USERPROFILE]\blis\lib\haswell\, while $HOME/blis links to C:\msys64\home\[USERPROFILE]\blis.
I installed BLIS using the following code in MSYS2 MINGW64
cd $HOME
git clone https://github.com/flame/blis.git
CC=clang CXX=clang++ AR=llvm-ar AS=llvm-as RANLIB=echo ./configure -t openmp --enable-static --disable-shared auto
make -j5
make install
The below is the full code from 00level1v.c:
#include <stdio.h>
#include "blis.h"
int main( int argc, char** argv )
{
double* x;
double* y;
double* z;
double* w;
double* a;
double alpha, beta, gamma;
dim_t m, n;
inc_t rs, cs;
// Initialize some basic constants.
double zero = 0.0;
double one = 1.0;
double minus_one = -1.0;
//
// This file demonstrates working with vectors and the level-1v
// operations.
//
//
// Example 1: Create vectors and then broadcast (copy) scalar
// values to all elements.
//
printf( "\n#\n# -- Example 1 --\n#\n\n" );
// Create a few vectors to work with. We make them all of the same length
// so that we can perform operations between them.
// NOTE: We've chosen to use row vectors here (1x4) instead of column
// vectors (4x1) to allow for easier reading of standard output (less
// scrolling).
m = 1; n = 4; rs = n; cs = 1;
x = malloc( m * n * sizeof( double ) );
y = malloc( m * n * sizeof( double ) );
z = malloc( m * n * sizeof( double ) );
w = malloc( m * n * sizeof( double ) );
a = malloc( m * n * sizeof( double ) );
// Let's initialize some scalars.
alpha = 2.0;
beta = 0.2;
gamma = 3.0;
printf( "alpha:\n%4.1f\n\n", alpha );
printf( "beta:\n%4.1f\n\n", beta );
printf( "gamma:\n%4.1f\n\n", gamma );
printf( "\n" );
bli_dsetv( BLIS_NO_CONJUGATE, n, &one, x, 1 );
bli_dsetv( BLIS_NO_CONJUGATE, n, &alpha, y, 1 );
bli_dsetv( BLIS_NO_CONJUGATE, n, &zero, z, 1 );
// Note that we can use printv or printm to print vectors since vectors
// are also matrices. We choose to use printm because it honors the
// orientation of the vector (row or column) when printing, whereas
// printv always prints vectors as column vectors regardless of their
// they are 1 x n or n x 1.
bli_dprintm( "x := 1.0", m, n, x, rs, cs, "%4.1f", "" );
bli_dprintm( "y := alpha", m, n, y, rs, cs, "%4.1f", "" );
bli_dprintm( "z := 0.0", m, n, z, rs, cs, "%4.1f", "" );
//
// Example 2: Randomize a vector.
//
printf( "\n#\n# -- Example 2 --\n#\n\n" );
// Set a vector to random values.
bli_drandv( n, w, 1 );
bli_dprintm( "x := randv()", m, n, w, rs, cs, "%4.1f", "" );
//
// Example 3: Perform various element-wise operations on vectors.
//
printf( "\n#\n# -- Example 3 --\n#\n\n" );
// Copy a vector.
bli_dcopyv( BLIS_NO_CONJUGATE, n, w, 1, a, 1 );
bli_dprintm( "a := w", m, n, a, rs, cs, "%4.1f", "" );
// Add and subtract vectors.
bli_daddv( BLIS_NO_CONJUGATE, n, y, 1, a, 1 );
bli_dprintm( "a := a + y", m, n, a, rs, cs, "%4.1f", "" );
bli_dsubv( BLIS_NO_CONJUGATE, n, w, 1, a, 1 );
bli_dprintm( "a := a + w", m, n, a, rs, cs, "%4.1f", "" );
// Scale a vector (destructive).
bli_dscalv( BLIS_NO_CONJUGATE, n, &beta, a, 1 );
bli_dprintm( "a := beta * a", m, n, a, rs, cs, "%4.1f", "" );
// Scale a vector (non-destructive).
bli_dscal2v( BLIS_NO_CONJUGATE, n, &gamma, a, 1, z, 1 );
bli_dprintm( "z := gamma * a", m, n, z, rs, cs, "%4.1f", "" );
// Scale and accumulate between vectors.
bli_daxpyv( BLIS_NO_CONJUGATE, n, &alpha, w, 1, x, 1 );
bli_dprintm( "x := x + alpha * w", m, n, x, rs, cs, "%4.1f", "" );
bli_dxpbyv( BLIS_NO_CONJUGATE, n, w, 1, &minus_one, x, 1 );
bli_dprintm( "x := -1.0 * x + w", m, n, x, rs, cs, "%4.1f", "" );
// Invert a vector element-wise.
bli_dinvertv( n, y, 1 );
bli_dprintm( "y := 1 / y", m, n, y, rs, cs, "%4.1f", "" );
// Swap two vectors.
bli_dswapv( n, x, 1, y, 1 );
bli_dprintm( "x (after swapping with y)", m, n, x, rs, cs, "%4.1f", "" );
bli_dprintm( "y (after swapping with x)", m, n, y, rs, cs, "%4.1f", "" );
//
// Example 4: Perform contraction-like operations on vectors.
//
printf( "\n#\n# -- Example 4 --\n#\n\n" );
// Perform a dot product.
bli_ddotv( BLIS_NO_CONJUGATE, BLIS_NO_CONJUGATE, n, a, 1, z, 1, &gamma );
printf( "gamma := a * z (dot product):\n%5.2f\n\n", gamma );
// Perform an extended dot product.
bli_ddotxv( BLIS_NO_CONJUGATE, BLIS_NO_CONJUGATE, n, &alpha, a, 1, z, 1, &one, &gamma );
printf( "gamma := 1.0 * gamma + alpha * a * z (accumulate scaled dot product):\n%5.2f\n\n", gamma );
// Free the memory obtained via malloc().
free( x );
free( y );
free( z );
free( w );
free( a );
return 0;
}
Just to wrap up the question, the issue was in how I wrote my include path. In the below:
BLIS_PREFIX = $(HOME)/blis
BLIS_INC = $(BLIS_PREFIX)/include/haswell/blis
BLIS_LIB = $(BLIS_PREFIX)/lib/haswell/libblis.a
BLIS_INC was directing to a folder in haswell called blis, rather than the header.
It should be changed to:
BLIS_PREFIX = $(HOME)/blis
BLIS_INC = $(BLIS_PREFIX)/include/haswell/
BLIS_LIB = $(BLIS_PREFIX)/lib/haswell/libblis.a
Upon doing so my code compiled properly.

I'm trying to recreate the Diffie-Hellman Key Exchange using addition but i get errors

#include<stdio.h>
#include<math.h>
long long int add(long long int a, long long int b,
long long int G)
{
if (b == 1)
return a;
else
return (((long long int)(a + b)) % G);
}
int main()
{
long long int G, x, a, y, b, ka, kb;
G = 43; //the agreed number
printf("The value of G : %lld\n\n", G);
a = 23; //private key for a
printf("The private key a for A : %lld\n", a);
x = add(G, a); //gets the generated key
b = 19; //private key for b
printf("The private key b for B : %lld\n\n", b);
y = add(G, b); // gets the generated key
ka = add(y, a, G); // Secret key for a
kb = add(x, b, G); // Secret key for b
printf("Secret key for the A is : %lld\n", ka);
printf("Secret Key for the B is : %lld\n", kb);
return 0;
}
this is the flow of the code
THIS IS THE EXPECTED OUTPUT/FLOW OF THE PROGRAM but my code has problems i attached an image to show the problem.
A and B will agree upon a number
G = 43 is the agreed number
A will generate a private number a = 23
B will generate a private number b = 19
A will calculate G=43 + a=23 mod G=43 OR 43 + 23 mod 43 = 66 (let's call it x) x = 66
B will calculate G=43 + b=19 mod G=43 OR 43+19mod43 = 62 (let's call it y) y = 62
for A we get x = 66
for B we get y = 62
They will then exchange x and y
x = 66 will go to B
y = 62 will go to A
A will now calculate y + a mod G OR 62+23 mod 43 = 85 (secret number is ka) ka = 85
B will now calculate x + b mod G OR 66+19 mod 43 = 85 (secret number is kb) kb = 85
This is the error that I get
Your 'add' function is declared as taking 3 arguments
long long int add(long long int a, long long int b, long long int G)
but twice you try to call it only passing 2, here
x = add(G, a); //gets the generated key
and here
y = add(G, b); // gets the generated key
reading the logic you posted those should be
x = add(G, a, G); //gets the generated key
and
y = add(G, b, G); // gets the generated key

How to stop recursion after some time in C

I need to stop recursion after, let's say, 30 seconds in C. One of my attempts was using a goto - despite recommendations of not using it, but i can't use it between different functions. The code is below:
void func_t(int n, int a, int b, int c, int d, int e, int f, int g, int height, Data *data, time_t start_time){
int cont;
data->level_recursions[height] = data->level_recursions[height] + 1;
if ( n<= 1) return;
for (cont = 1; cont <= a; cont++){
data->height = height + 1;
func_t( (n/b) - c, a, b, c, d, e, f, g, 1 + height, data );
}
for (cont = 1; cont <= d; cont++) {
data->height = height + 1;
func_t( (n/e) - f, a, b, c, d, e, f, g, 1 + height, data );
}
clock_t begin = clock();
for (cont = 1; cont <= fn(n, g); cont++);
clock_t end = clock();
data->level_work[height] = data->level_work[height] + ((double)(end - begin) / CLOCKS_PER_SEC);
}
Create a global const parameter(current time) that you init for the first running time.
If 30 sec + the value of the global < current time -> hit return or do what ever you want)
Maybe this is the if statement to enter to the recursion

Is it possible to hash using MD5 in BigQuery?

Does BigQuery have MD5() functionality? I know it has cityhash but I need MD5 specifically. thanks!
Since this shows up in Google searches for "BigQuery MD5", for instances, it's worth pointing out that BigQuery supports the following hashing functions natively in standard SQL:
MD5
SHA1
SHA256
SHA512
No, but bigquery does have some sha1-hash support. The SHA1() function returns bytes, but you can convert this to base64 by using TO_BASE64() which will give you a nice string or STRING() which will give you an ugly one:
SELECT TO_BASE64(SHA1(corpus)) from [publicdata:samples.shakespeare] limit 100;
Reviving an old thread here. It is now possible to implement md5 in BigQuery using user-defined functions: https://cloud.google.com/bigquery/user-defined-functions
Here is some example code:
function md5cycle(x, k) {
var a = x[0], b = x[1], c = x[2], d = x[3];
a = ff(a, b, c, d, k[0], 7, -680876936);
d = ff(d, a, b, c, k[1], 12, -389564586);
c = ff(c, d, a, b, k[2], 17, 606105819);
b = ff(b, c, d, a, k[3], 22, -1044525330);
a = ff(a, b, c, d, k[4], 7, -176418897);
d = ff(d, a, b, c, k[5], 12, 1200080426);
c = ff(c, d, a, b, k[6], 17, -1473231341);
b = ff(b, c, d, a, k[7], 22, -45705983);
a = ff(a, b, c, d, k[8], 7, 1770035416);
d = ff(d, a, b, c, k[9], 12, -1958414417);
c = ff(c, d, a, b, k[10], 17, -42063);
b = ff(b, c, d, a, k[11], 22, -1990404162);
a = ff(a, b, c, d, k[12], 7, 1804603682);
d = ff(d, a, b, c, k[13], 12, -40341101);
c = ff(c, d, a, b, k[14], 17, -1502002290);
b = ff(b, c, d, a, k[15], 22, 1236535329);
a = gg(a, b, c, d, k[1], 5, -165796510);
d = gg(d, a, b, c, k[6], 9, -1069501632);
c = gg(c, d, a, b, k[11], 14, 643717713);
b = gg(b, c, d, a, k[0], 20, -373897302);
a = gg(a, b, c, d, k[5], 5, -701558691);
d = gg(d, a, b, c, k[10], 9, 38016083);
c = gg(c, d, a, b, k[15], 14, -660478335);
b = gg(b, c, d, a, k[4], 20, -405537848);
a = gg(a, b, c, d, k[9], 5, 568446438);
d = gg(d, a, b, c, k[14], 9, -1019803690);
c = gg(c, d, a, b, k[3], 14, -187363961);
b = gg(b, c, d, a, k[8], 20, 1163531501);
a = gg(a, b, c, d, k[13], 5, -1444681467);
d = gg(d, a, b, c, k[2], 9, -51403784);
c = gg(c, d, a, b, k[7], 14, 1735328473);
b = gg(b, c, d, a, k[12], 20, -1926607734);
a = hh(a, b, c, d, k[5], 4, -378558);
d = hh(d, a, b, c, k[8], 11, -2022574463);
c = hh(c, d, a, b, k[11], 16, 1839030562);
b = hh(b, c, d, a, k[14], 23, -35309556);
a = hh(a, b, c, d, k[1], 4, -1530992060);
d = hh(d, a, b, c, k[4], 11, 1272893353);
c = hh(c, d, a, b, k[7], 16, -155497632);
b = hh(b, c, d, a, k[10], 23, -1094730640);
a = hh(a, b, c, d, k[13], 4, 681279174);
d = hh(d, a, b, c, k[0], 11, -358537222);
c = hh(c, d, a, b, k[3], 16, -722521979);
b = hh(b, c, d, a, k[6], 23, 76029189);
a = hh(a, b, c, d, k[9], 4, -640364487);
d = hh(d, a, b, c, k[12], 11, -421815835);
c = hh(c, d, a, b, k[15], 16, 530742520);
b = hh(b, c, d, a, k[2], 23, -995338651);
a = ii(a, b, c, d, k[0], 6, -198630844);
d = ii(d, a, b, c, k[7], 10, 1126891415);
c = ii(c, d, a, b, k[14], 15, -1416354905);
b = ii(b, c, d, a, k[5], 21, -57434055);
a = ii(a, b, c, d, k[12], 6, 1700485571);
d = ii(d, a, b, c, k[3], 10, -1894986606);
c = ii(c, d, a, b, k[10], 15, -1051523);
b = ii(b, c, d, a, k[1], 21, -2054922799);
a = ii(a, b, c, d, k[8], 6, 1873313359);
d = ii(d, a, b, c, k[15], 10, -30611744);
c = ii(c, d, a, b, k[6], 15, -1560198380);
b = ii(b, c, d, a, k[13], 21, 1309151649);
a = ii(a, b, c, d, k[4], 6, -145523070);
d = ii(d, a, b, c, k[11], 10, -1120210379);
c = ii(c, d, a, b, k[2], 15, 718787259);
b = ii(b, c, d, a, k[9], 21, -343485551);
x[0] = add32(a, x[0]);
x[1] = add32(b, x[1]);
x[2] = add32(c, x[2]);
x[3] = add32(d, x[3]);
}
function cmn(q, a, b, x, s, t) {
a = add32(add32(a, q), add32(x, t));
return add32((a << s) | (a >>> (32 - s)), b);
}
function ff(a, b, c, d, x, s, t) {
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function gg(a, b, c, d, x, s, t) {
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function hh(a, b, c, d, x, s, t) {
return cmn(b ^ c ^ d, a, b, x, s, t);
}
function ii(a, b, c, d, x, s, t) {
return cmn(c ^ (b | (~d)), a, b, x, s, t);
}
function md51(s) {
txt = '';
var n = s.length,
state = [1732584193, -271733879, -1732584194, 271733878], i;
for (i=64; i<=s.length; i+=64) {
md5cycle(state, md5blk(s.substring(i-64, i)));
}
s = s.substring(i-64);
var tail = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
for (i=0; i<s.length; i++)
tail[i>>2] |= s.charCodeAt(i) << ((i%4) << 3);
tail[i>>2] |= 0x80 << ((i%4) << 3);
if (i > 55) {
md5cycle(state, tail);
for (i=0; i<16; i++) tail[i] = 0;
}
tail[14] = n*8;
md5cycle(state, tail);
return state;
}
/* there needs to be support for Unicode here,
* unless we pretend that we can redefine the MD-5
* algorithm for multi-byte characters (perhaps
* by adding every four 16-bit characters and
* shortening the sum to 32 bits). Otherwise
* I suggest performing MD-5 as if every character
* was two bytes--e.g., 0040 0025 = #%--but then
* how will an ordinary MD-5 sum be matched?
* There is no way to standardize text to something
* like UTF-8 before transformation; speed cost is
* utterly prohibitive. The JavaScript standard
* itself needs to look at this: it should start
* providing access to strings as preformed UTF-8
* 8-bit unsigned value arrays.
*/
function md5blk(s) { /* I figured global was faster. */
var md5blks = [], i; /* Andy King said do it this way. */
for (i=0; i<64; i+=4) {
md5blks[i>>2] = s.charCodeAt(i)
+ (s.charCodeAt(i+1) << 8)
+ (s.charCodeAt(i+2) << 16)
+ (s.charCodeAt(i+3) << 24);
}
return md5blks;
}
var hex_chr = '0123456789abcdef'.split('');
function rhex(n)
{
var s='', j=0;
for(; j<4; j++)
s += hex_chr[(n >> (j * 8 + 4)) & 0x0F]
+ hex_chr[(n >> (j * 8)) & 0x0F];
return s;
}
function hex(x) {
for (var i=0; i<x.length; i++)
x[i] = rhex(x[i]);
return x.join('');
}
function md5(s) {
return hex(md51(s));
}
function add32(a, b) {
return (a + b) & 0xFFFFFFFF;
}
var input_columns = ['value'];
var output_schema = [{name: 'md5', type: 'string'}];
bigquery.create_tvf(
'md5', // The function name exposed to Dremel.
input_columns,
output_schema,
// This function will be invoked once for each input record.
function(record, emit) {
emit({md5: hex(md51(record.value))});
}
);

What does this recursive function do

i am doing some exam prep and one of the question is to describe what the following piece of C code does.
int g(int *a, int b ,int c){
if(b==c) return a[b];
return g(a,b,(b+c)/2) + g(a,(b+c)/2+1 ,c);}
Cant seem to figure out the recursion, from my understanding the sum of the left hand
is sum of the series b+2^n/2*c and sum of the series of right to be (2^n/2)*(b+c) where n starts at 0. But there is no value for n that will make the series to be equal b or c respectively. Does that mean if the first if condition isn't meet it will continue on for infinity?
Assuming b < c, g() returns the sum of the elements of the array a[] from index b to index c (both inclusive)
In other words,
g( a, b, c ) :=
int sum = 0;
for( int i = b; i <= c; ++i )
sum += a[ i ];
return sum;
EDIT Proof Sketch
Assume c - b = n
(b + c)/2
= (c - b + 2b)/2
= (c - b)/2 + b
= b + n/2
Thus, g( a, b, (b + c)/2 ) + g( a, (b + c)/2 + 1, c )
= g( a, b, b + n/2 ) + g( a, b + n/2 + 1, c )

Resources