hacks

(tidier examples of) random scripts from throughout the years
Log | Files | Refs | README

commit 189878e99676b316362ff8f3ad0b9b611c210770
parent 91cf00dc343e2ed3e870171f8199e8a1ce75689a
Author: quantumish <freifeld.david@gmail.com>
Date:   Wed, 29 Jul 2026 01:55:46 -0700

Add slightly parallel SHA256 and old zero knowledge proof thing

Diffstat:
Asha.cu | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Azk-poly.c | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 367 insertions(+), 0 deletions(-)

diff --git a/sha.cu b/sha.cu @@ -0,0 +1,172 @@ +/* Editor's note: a partially parallelized SHA256 implementation. + * Written around December 2021 for my high school computer security class. + * If I remember correctly the parallelization was done very poorly and there's room + * for a lot more optimization. + * + * The message schedules for the chunks processed by SHA256 are not sequentially + * dependent and so this program generates them in parallel and then process them + * sequentially when updating the hash. + */ + +#include <cstdint> +#include <cstring> +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <cuda_runtime_api.h> +#include <cuda.h> + +// 32-bit bit right rotation +#define rotr(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + +// 32-bit byte swap +#define bswap32(x) ((x>>24)&0xff) | \ + ((x<<8)&0xff0000) | \ + ((x>>8)&0xff00) | \ + ((x<<24)&0xff000000) \ + +uint64_t k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +}; + +struct sha_ctx { + uint32_t hash[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, + }; + uint64_t len; + + sha_ctx(uint64_t len); + void compress(uint32_t* w); + void dump_hash(); +}; + +sha_ctx::sha_ctx(uint64_t length) :len(length) {} + +/* + * GPU Kernel responsible for generating message schedules. + * Takes: + * - `bytes`, a pointer to a buffer containing the input from the file. + * - `w`, a pointer to the large buffer to write all the message schedules to. + * - `iters`, the number of message schedules to generate per thread. + * Does not return anything but instead modifies `w` + */ +__global__ void process(const uint8_t* bytes, uint32_t* w, uint32_t iters) { + const size_t start_chunk = (blockIdx.y*gridDim.x*blockDim.x)+(blockIdx.x*blockDim.x)+threadIdx.x; + for (int off = 0; off < iters; off++) { + uint32_t* w_adj = w+(((start_chunk*iters)+off)*64); + memcpy(w_adj, bytes+(((start_chunk*iters)+off)*64), 64); + for (int i = 0; i < 16; i++) w_adj[i] = bswap32(w_adj[i]); + for (int i = 16; i < 64; i++) { + uint32_t s0 = (rotr(w_adj[i-15], 7) ^ rotr(w_adj[i-15], 18) ^ (w_adj[i-15] >> 3)); + uint32_t s1 = (rotr(w_adj[i-2], 17) ^ rotr(w_adj[i-2], 19) ^ (w_adj[i-2] >> 10)); + w_adj[i] = w_adj[i-16] + s0 + w_adj[i-7] + s1; + } + } +} + +/* + * CPU-side function that updates the hash for a given message schedule. + * Takes: + * - `w`, a pointer to a single message schedule. + * Does not return anything but modifies `sha_ctx::hash` + */ +void sha_ctx::compress(uint32_t* w) { + uint32_t a[8] = {0}; + memcpy(a, hash, 8*sizeof(uint32_t)); + for (int i = 0; i < 64; i++) { + uint32_t s1 = (rotr(a[4], 6) ^ rotr(a[4], 11) ^ rotr(a[4], 25)); + uint32_t ch = (a[4] & a[5]) ^ ((~a[4]) & a[6]); + uint32_t temp1 = a[7] + s1 + ch + k[i] + w[i]; + uint32_t s0 = (rotr(a[0], 2) ^ rotr(a[0], 13) ^ rotr(a[0], 22)); + uint32_t maj = (a[0] & a[1]) ^ (a[0] & a[2]) ^ (a[1] & a[2]); + uint32_t temp2 = s0 + maj; + for (int i = 7; i > 0; i--) a[i] = a[i-1]; + a[4] += temp1; + a[0] = temp1 + temp2; + } + for (int i = 0; i < 8; i++) hash[i] += a[i]; +} + +/* + * CPU-side function that prints out the current hash. + * Returns nothing but writes to stdout. + */ +void sha_ctx::dump_hash() { + uint32_t temp_hash[8]; + memcpy(temp_hash, hash, 8*sizeof(uint32_t)); + for (int i = 0; i < 8; i++) temp_hash[i] = bswap32(temp_hash[i]); + auto u8_ptr = reinterpret_cast<uint8_t*>(temp_hash); + for (int i = 0; i < 32; i++) printf("%02x", u8_ptr[i]); +} + +int main(int argc, char** argv) { + // Open file and initialize sha_ctx + int fd = open(argv[1], O_RDONLY | O_NONBLOCK); + // Advise kernel we're reading sequentially + posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); + struct stat stat; + fstat(fd, &stat); // Get size of file + sha_ctx sha(stat.st_size); + + // Allocate input and message schedule buffers on the FPU + const size_t BUFFER_SIZE = 268435456; // 2 GiB + uint8_t* buf; + cudaMallocManaged(&buf, BUFFER_SIZE); + uint32_t* w; + cudaMallocManaged(&w, BUFFER_SIZE*4); + + bool padded = false; // Store if we've padded the input yet (for handling edge cases) + size_t bytes_read = read(fd, buf, BUFFER_SIZE); + + do { + // Maximum size_t (represented by underflow here) is read's return code for error + if (bytes_read == (size_t)-1) { + printf("Error reading file."); + exit(1); + } + if (!bytes_read) break; // If we're done reading, stop. + else if (bytes_read < BUFFER_SIZE) { + // Pad buffer in accordance with SHA256's standards + size_t buffer_len = 64 * (((bytes_read + 9) / 64) + 1); + for (size_t i = bytes_read; i < buffer_len; i++) buf[i] = 0; + buf[bytes_read] = 0b10000000; + for (int i = 1; i <= 8; i++) buf[buffer_len-i] = sha.len*8 >> (i-1)*8; + process<<<dim3{8,8,1}, 64>>>(buf, w, 1024); + cudaDeviceSynchronize(); + for (int i = 0; i < buffer_len/64; i++) sha.compress(w+(i*64)); + padded=true; + } else { + process<<<dim3{8,8,1}, 64>>>(buf, w, 1024); + cudaDeviceSynchronize(); + for (int i = 0; i < BUFFER_SIZE/64; i++) sha.compress(w+(i*64)); + } + } while ((bytes_read = read(fd, buf, BUFFER_SIZE))); + if (padded == false) { + // Pad buffer in accordance with SHA256 + for (size_t i = 0; i < 64; i++) buf[i] = 0; + buf[0] = 0b10000000; + for (int i = 1; i <= 8; i++) buf[64-i] = sha.len*8 >> (i-1)*8; + + // Run last chunk on CPU + memcpy(w, buf, 64); + for (int i = 0; i < 16; i++) w[i] = bswap32(w[i]); + for (int i = 16; i < 64; i++) { + uint32_t s0 = (rotr(w[i-15], 7) ^ rotr(w[i-15], 18) ^ (w[i-15] >> 3)); + uint32_t s1 = (rotr(w[i-2], 17) ^ rotr(w[i-2], 19) ^ (w[i-2] >> 10)); + w[i] = w[i-16] + s0 + w[i-7] + s1; + } + sha.compress(w); + } + sha.dump_hash(); + printf(" %s\n", argv[1]); +} diff --git a/zk-poly.c b/zk-poly.c @@ -0,0 +1,195 @@ +/* A hacky implementation of the "Non-Interactive Zero-Knowledge of a Polynomial" scheme + * described in https://doi.org/10.48550/arXiv.1906.07221 + * Written during late October 2020. + */ + +#include <pthread.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <string.h> +#include <math.h> +#include <time.h> +#include <gmp.h> + +#define PORT 5000 +#define BUFSIZE 1024 +#define EPSILON 0.000001 + +void* start_verifier(void* args) +{ + // Intialize socket with AF_INET IP family and SOCK_DGRAM datagram service, exit if failed + int s; + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + exit(1); + } + // Establish sockaddr_in struct to pass into bind function + struct sockaddr_in addr; + memset((char *)&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; // Specify address family. + addr.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY just 0.0.0.0, machine IP address + addr.sin_port = htons(PORT); // Specify port. + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + exit(1); + } + + // IP address of client + struct sockaddr_in remaddr; + socklen_t addrlen = sizeof(remaddr); + int recvlen; + unsigned char buf[BUFSIZE]; + + int connections = 0; + int clients[500]; + int unproven = 1; + int g = 6; + int degree = 3; + int n = 17; + int s_1; + int a; + mpz_t bigs; + mpz_init_set_ui(bigs, s_1); + mpz_t biga; + mpz_init_set_ui(biga, a); + mpz_t bigg; + mpz_init_set_ui(bigg, g); + mpz_t bign; + mpz_init_set_ui(bign, n); + mpz_t t; + while (unproven) { + recvlen = recvfrom(s, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen); + if (recvlen > BUFSIZE) { + sendto(s, "ERR: Too long.", 14, 0, (struct sockaddr *) &remaddr, addrlen); + } + else if (recvlen > 0) { + void* msg = 0x0; + buf[recvlen] = 0; + printf(" VERIFIER │ Received %d-byte message from %i: \"%s\"\n", + recvlen, remaddr.sin_port, buf); + if (recvlen==8) { + clients[connections] = remaddr.sin_port; + connections++; + srand(time(0)); + s_1 = rand() % 500; + a = rand() % 500; + mpz_init_set_ui(t, (s_1-((int*)buf)[0])*(s_1-((int*)buf)[1])); + printf(" VERIFIER │ Chose s = %d and a = %d\n", s_1, a); + mpz_t* enc_s = malloc(sizeof(mpz_t)*(degree+1)*2); + for (int i = 0; i <= degree; i++) { + mpz_init(enc_s[i]); + mpz_t temp1; + + mpz_init_set_ui(temp1, (int)pow(s_1, i)); + mpz_powm_sec(enc_s[i], bigg, temp1, bign); + mpz_init(enc_s[degree+1+i]); + mpz_t temp2; + mpz_init_set_ui(temp2, (int)a*pow(s_1, i)); + mpz_powm_sec(enc_s[i+1+degree], bigg, temp2, bign); + } + msg = enc_s; + } else if (recvlen == sizeof(mpz_t)*3) { + mpz_t tmp1; + mpz_init(tmp1); + mpz_t tmp2; + mpz_init(tmp2); + mpz_powm_sec(tmp1, ((mpz_t*)buf)[2], t, bign); + mpz_t tmp3; + mpz_init(tmp3); + mpz_div(tmp3, ((mpz_t*)buf)[0], tmp1); + mpz_abs(tmp3, tmp3); + mpz_ui_sub(tmp3, 1, tmp3); + //gmp_printf("%Fe %Fe (diff %Fe)\n", ((mpz_t*)buf)[0], tmp1, tmp3); + if (mpz_cmp_d(tmp3, EPSILON) == -1) printf(" VERIFIER │ Valid roots!\n"); + else printf(" VERIFIER │ ERR: Invalid roots!\n"); + mpz_powm_sec(tmp2, ((mpz_t*)buf)[0], biga, bign); + mpz_t tmp4; + mpz_init(tmp4); + mpz_div(tmp4, ((mpz_t*)buf)[1], tmp2); + mpz_abs(tmp4, tmp4); + mpz_ui_sub(tmp4, 1, tmp4); + //gmp_printf("%Fe %Fe (diff %Fe)\n", ((mpz_t*)buf)[1], tmp2, tmp4); + if (mpz_cmp_d(tmp4, EPSILON) == -1) printf(" VERIFIER │ Valid form!\n"); + else printf(" VERIFIER │ ERR: Invalid form!\n"); + } + if (msg != 0x0) { + sendto(s, msg, sizeof(mpz_t)*(degree+1)*2, 0, (struct sockaddr *) &remaddr, addrlen); + } + } + } + + return 0x0; +} + +void* start_prover(void* args) +{ + // Same socket is needed on client end so initialize all over again. + int s; + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("\n Error : Socket Failed \n"); + } + struct sockaddr_in addr; + memset((char *)&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; // Specify address family. + addr.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY just 0.0.0.0, machine IP address + addr.sin_port = htons(PORT); // Specify port. + // Connect to server + if(connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + printf("ERR: Connect failed.\n"); + return 0x0; + } + // NOTE This can and will not work if flag argument set to 1 + int roots[2] = {-1,-2}; + sendto(s, roots, 8, 0, (struct sockaddr*)NULL, sizeof(addr)); + printf(" Prover │ Informed server of existence.\n"); + char buf[BUFSIZE]; + int recvlen; + socklen_t len = sizeof(addr); + int phase = 0; + int constants[4] = {0, 2, 3, 1}; + int degree = 3; + int delta = rand() % 100; + while (1==1) { + recvlen = recvfrom(s, buf, BUFSIZE, 0, (struct sockaddr *) &addr, &len); + if (recvlen > 0) { + buf[recvlen] = 0; + printf(" Prover │ Received %d-byte message from server: \"%s\"\n", recvlen, buf); + mpz_t* enc_ph = malloc(sizeof(mpz_t)*3); + mpz_init_set_ui(enc_ph[0], 1); + mpz_init_set_ui(enc_ph[1], 1); + mpz_init(enc_ph[2]); + for (int i = 0; i < degree+1; i++) { + mpz_pow_ui(((mpz_t*)buf)[i], ((mpz_t*)buf)[i], abs(constants[i])); + mpz_mul(enc_ph[0], enc_ph[0], ((mpz_t*)buf)[i]); + mpz_mul(enc_ph[1], enc_ph[1], ((mpz_t*)buf)[i+1+degree]); + } + mpz_t tmp1; + mpz_init(tmp1); + mpz_pow_ui(tmp1, ((mpz_t*)buf)[0], -roots[0]); + mpz_mul(tmp1, tmp1, ((mpz_t*)buf)[1]); + mpz_t tmp2; + mpz_init(tmp2); + mpz_pow_ui(tmp1, ((mpz_t*)buf)[0], -roots[1]); + mpz_mul(tmp1, tmp1, ((mpz_t*)buf)[1]); + mpz_t denom; + mpz_init(denom); + mpz_mul(denom, tmp1, tmp2); + mpz_div(enc_ph[2], enc_ph[0], denom); + for (int i = 0; i < 3; i++) mpz_pow_ui(enc_ph[i], enc_ph[i], delta); + sendto(s, enc_ph, sizeof(mpz_t)*3, 0, (struct sockaddr*)NULL, sizeof(addr)); + } + } + return 0x0; +} + +int main() +{ + pthread_t verifier; + pthread_create(&verifier, NULL, start_verifier, 0x0); + pthread_t prover; + pthread_create(&prover, NULL, start_prover, 0x0); + pthread_join(verifier, NULL); +}