aad-assignment-1/aad_vault.h

146 lines
4.5 KiB
C

//
// Tomás Oliveira e Silva, September 2025
//
// Arquiteturas de Alto Desempenho 2025/2026
//
// implements a vault for all found DETI coins
//
#ifndef AAD_VAULT
#define AAD_VAULT
static void save_coin(u32_t coin[14])
{
# define VAULT_FILE_NAME "deti_coins_v2_vault.txt"
# define MAX_SAVED_COINS 65536u
static u08_t saved_coins[MAX_SAVED_COINS][4 + 55];
static u32_t n_saved_coins = 0u;
static u08_t deti_coin_v2_template[56u] =
{ // non-zero entries are mandatory, the others are arbitrary
[ 0u] = (u08_t)'D',
[ 1u] = (u08_t)'E',
[ 2u] = (u08_t)'T',
[ 3u] = (u08_t)'I',
[ 4u] = (u08_t)' ',
[ 5u] = (u08_t)'c',
[ 6u] = (u08_t)'o',
[ 7u] = (u08_t)'i',
[ 8u] = (u08_t)'n',
[ 9u] = (u08_t)' ',
[10u] = (u08_t)'2',
[11u] = (u08_t)' ',
[54u] = (u08_t)'\n',
[55u] = (u08_t)0x80
};
static int error_tolerance_count = 4; // number of errors to tolerate before bailing out
u32_t idx,n,hash[5];
char *reason;
u08_t *s;
//
// handle a NULL argument (meaning: save all stored DETI coins) or an already full buffer
//
if(coin == NULL || n_saved_coins == MAX_SAVED_COINS)
{
if(n_saved_coins > 0u)
{
FILE *fp = fopen(VAULT_FILE_NAME,"a");
if(fp == NULL ||
fwrite((void *)&saved_coins[0][0],(size_t)(4 + 55),(size_t)n_saved_coins,fp) != (size_t)n_saved_coins ||
fflush(fp) != 0 ||
fclose(fp) != 0)
{
fprintf(stderr,"save_coin(): error while updating file \"" VAULT_FILE_NAME "\"\n");
exit(1);
}
}
n_saved_coins = 0u;
}
if(coin == NULL)
return;
//
// compute the SHA1 secure hash
//
sha1(coin,hash);
//
// make sure that the coin has the appropriate format
//
for(idx = 0u;idx < 56u;idx++)
if((deti_coin_v2_template[idx] != (u08_t)0 && deti_coin_v2_template[idx] != ((u08_t *)coin)[idx ^ 3]) || (idx >= 12u && idx <= 53u && ((char *)coin)[idx ^ 3] == '\n'))
{
reason = "coin does not match the template";
error:
fprintf(stderr,"save_coin(): bad DETI coin v2 format (%s)\n",reason);
fprintf(stderr," coin contents\n");
fprintf(stderr," idx template coin\n");
fprintf(stderr," --- --------- ---------\n");
for(idx = 0u;idx < 56u;idx++)
{
u08_t t = deti_coin_v2_template[idx];
u08_t c = ((u08_t *)coin)[idx ^ 3];
fprintf(stderr," %3u",idx);
if(t == (u08_t)0)
fprintf(stderr," arbitrary");
else if(t == '\n')
fprintf(stderr," 0x%02X '\\n'",(int)t);
else if(t >= 32 && t <= 126)
fprintf(stderr," 0x%02X '%c'",(int)t,t);
else
fprintf(stderr," 0x%02X ",(int)t);
fprintf(stderr," 0x%02X",(int)c);
if(c == '\n')
fprintf(stderr," '\\n'");
else if(c == '\b')
fprintf(stderr," '\\b'");
else if(c >= 32 && c <= 126)
fprintf(stderr," '%c'",c);
else
fprintf(stderr," ");
if((t != (u08_t)0 && t != c) || (idx >= 12u && idx <= 53u && c == '\n'))
fprintf(stderr," error");
fprintf(stderr,"\n");
}
fprintf(stderr," --- --------- ---------\n");
fprintf(stderr," SHA1 secure hash\n");
fprintf(stderr," idx value\n");
fprintf(stderr," --- ----------\n");
for(idx = 0u;idx < 5u;idx++)
fprintf(stderr," %u 0x%08X%s\n",idx,hash[idx],(idx == 0u && hash[idx] != 0xAAD20250u) ? " error" : "");
fprintf(stderr," --- ----------\n\n");
if(--error_tolerance_count < 0)
exit(1); // too many errors, exit
return; // ignore this coin
}
//
// chech the DETI coin v2 signature
//
if(hash[0] != 0xAAD20250u)
{
reason = "bad coin signature";
goto error;
}
//
// count the number of leading zeros bits of the last 4 32-bit words of the SHA1 secure hash
//
for(n = 0u;n < 128u;n++)
if((hash[1u + n / 32u] >> (31u - n % 32u)) % 2u != 0u)
break;
//
// save the coin in the buffer
// format of each line: "Vuv:" "coin_data" where u and v are ascii digits that encode, in base 10, the reported power of the coin
//
if(n > 99u)
n = 99u;
s = &saved_coins[n_saved_coins++][0];
*s++ = (u08_t)'V';
*s++ = (u08_t)('0' + n / 10u);
*s++ = (u08_t)('0' + n % 10u);
*s++ = (u08_t)':';
for(idx = 0u;idx < 55u;idx++)
*s++ = ((u08_t *)coin)[idx ^ 3];
# undef VAULT_FILE_NAME
# undef MAX_SAVED_COINS
}
#endif