Skip to content

Commit c068b17

Browse files
committed
feat: add HNSW and quantization kernels
1 parent c341ba0 commit c068b17

29 files changed

Lines changed: 6375 additions & 347 deletions

include/fp_blake3.h

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
#pragma once
2+
3+
/**
4+
* FP_BLAKE3 - BLAKE3 Cryptographic Hash using FP_ASM_LIB primitives
5+
*
6+
* BLAKE3 is a cryptographic hash function that is:
7+
* - Fast: ~3x faster than SHA-256 on modern CPUs
8+
* - Secure: Based on ChaCha permutation, resistant to length extension
9+
* - Parallelizable: Tree structure enables multi-threaded hashing
10+
* - Versatile: Supports hashing, keyed hashing, and key derivation
11+
*
12+
* This implementation uses FP_ASM_LIB's AVX2-optimized u32 primitives
13+
* for the core mixing operations.
14+
*
15+
* Output: 256-bit (32-byte) hash
16+
* Block size: 64 bytes
17+
*/
18+
19+
#include <stdint.h>
20+
#include <stddef.h>
21+
22+
#ifdef __cplusplus
23+
extern "C" {
24+
#endif
25+
26+
/* ============================================================================
27+
* Constants
28+
* ============================================================================ */
29+
30+
#define FP_BLAKE3_OUT_LEN 32 /* Default output length (256 bits) */
31+
#define FP_BLAKE3_KEY_LEN 32 /* Key length for keyed hashing */
32+
#define FP_BLAKE3_BLOCK_LEN 64 /* Block size in bytes */
33+
#define FP_BLAKE3_CHUNK_LEN 1024 /* Chunk size for tree hashing */
34+
35+
/* ============================================================================
36+
* Types
37+
* ============================================================================ */
38+
39+
/**
40+
* BLAKE3 hasher state
41+
*
42+
* Maintains incremental hashing state for streaming input.
43+
*/
44+
typedef struct {
45+
uint32_t cv[8]; /* Chaining value (current state) */
46+
uint64_t chunk_counter; /* Number of chunks processed */
47+
uint8_t buf[FP_BLAKE3_BLOCK_LEN]; /* Partial block buffer */
48+
uint8_t buf_len; /* Bytes in buffer */
49+
uint8_t blocks_compressed; /* Blocks compressed in current chunk */
50+
uint8_t flags; /* Domain separation flags */
51+
uint8_t key[FP_BLAKE3_KEY_LEN]; /* Key (for keyed mode) */
52+
} FpBlake3Hasher;
53+
54+
/**
55+
* BLAKE3 output structure
56+
*/
57+
typedef struct {
58+
uint8_t hash[FP_BLAKE3_OUT_LEN];
59+
} FpBlake3Hash;
60+
61+
/* ============================================================================
62+
* Simple API (One-shot hashing)
63+
* ============================================================================ */
64+
65+
/**
66+
* Hash data in one call
67+
*
68+
* @param input Input data to hash
69+
* @param len Length of input in bytes
70+
* @param output Output buffer (32 bytes)
71+
*/
72+
void fp_blake3_hash(const uint8_t* input, size_t len, uint8_t* output);
73+
74+
/**
75+
* Hash data with key (MAC)
76+
*
77+
* @param key 32-byte key
78+
* @param input Input data
79+
* @param len Length of input
80+
* @param output Output buffer (32 bytes)
81+
*/
82+
void fp_blake3_hash_keyed(const uint8_t* key, const uint8_t* input,
83+
size_t len, uint8_t* output);
84+
85+
/**
86+
* Derive a key from context and key material
87+
*
88+
* @param context Context string (domain separator)
89+
* @param context_len Length of context
90+
* @param key_material Input key material
91+
* @param km_len Length of key material
92+
* @param output Output buffer (32 bytes)
93+
*/
94+
void fp_blake3_derive_key(const char* context, size_t context_len,
95+
const uint8_t* key_material, size_t km_len,
96+
uint8_t* output);
97+
98+
/* ============================================================================
99+
* Incremental API (Streaming hashing)
100+
* ============================================================================ */
101+
102+
/**
103+
* Initialize hasher for incremental hashing
104+
*
105+
* @param hasher Hasher state to initialize
106+
*/
107+
void fp_blake3_hasher_init(FpBlake3Hasher* hasher);
108+
109+
/**
110+
* Initialize hasher for keyed hashing
111+
*
112+
* @param hasher Hasher state to initialize
113+
* @param key 32-byte key
114+
*/
115+
void fp_blake3_hasher_init_keyed(FpBlake3Hasher* hasher, const uint8_t* key);
116+
117+
/**
118+
* Add input data to hasher
119+
*
120+
* @param hasher Hasher state
121+
* @param input Input data
122+
* @param len Length of input
123+
*/
124+
void fp_blake3_hasher_update(FpBlake3Hasher* hasher, const uint8_t* input, size_t len);
125+
126+
/**
127+
* Finalize hash and produce output
128+
*
129+
* @param hasher Hasher state
130+
* @param output Output buffer (32 bytes)
131+
*/
132+
void fp_blake3_hasher_finalize(const FpBlake3Hasher* hasher, uint8_t* output);
133+
134+
/**
135+
* Finalize with extended output (XOF mode)
136+
*
137+
* @param hasher Hasher state
138+
* @param output Output buffer
139+
* @param output_len Desired output length (can be > 32 bytes)
140+
*/
141+
void fp_blake3_hasher_finalize_xof(const FpBlake3Hasher* hasher,
142+
uint8_t* output, size_t output_len);
143+
144+
/* ============================================================================
145+
* Low-level API (For advanced use)
146+
* ============================================================================ */
147+
148+
/**
149+
* BLAKE3 compression function (single block)
150+
*
151+
* This is the core primitive that transforms the state.
152+
* Uses AVX2-optimized operations from FP_ASM_LIB.
153+
*
154+
* @param state 8 x u32 state (modified in-place)
155+
* @param block 64-byte input block
156+
* @param block_len Actual length (for padding)
157+
* @param counter Block counter
158+
* @param flags Domain flags
159+
*/
160+
void fp_blake3_compress(uint32_t state[8], const uint8_t block[64],
161+
uint8_t block_len, uint64_t counter, uint8_t flags);
162+
163+
/**
164+
* BLAKE3 G mixing function (quarter-round)
165+
*
166+
* Core mixing operation, optimized with AVX2.
167+
* Operates on 4 words at positions a, b, c, d with messages mx, my.
168+
*
169+
* @param state 16 x u32 working state
170+
* @param a,b,c,d Indices into state
171+
* @param mx, my Message words
172+
*/
173+
void fp_blake3_g(uint32_t* state, int a, int b, int c, int d,
174+
uint32_t mx, uint32_t my);
175+
176+
/**
177+
* BLAKE3 round function
178+
*
179+
* Applies 8 G functions in specific pattern.
180+
*
181+
* @param state 16 x u32 working state
182+
* @param msg Message schedule (16 x u32)
183+
*/
184+
void fp_blake3_round(uint32_t* state, const uint32_t* msg);
185+
186+
/* ============================================================================
187+
* SIMD-Optimized Batch Operations
188+
* ============================================================================ */
189+
190+
/**
191+
* Hash multiple inputs in parallel (AVX2 optimized)
192+
*
193+
* Hashes up to 8 independent inputs simultaneously using SIMD.
194+
* Significant speedup for batch processing.
195+
*
196+
* @param inputs Array of input pointers
197+
* @param lengths Array of input lengths
198+
* @param outputs Array of output buffers (32 bytes each)
199+
* @param count Number of inputs (1-8)
200+
*/
201+
void fp_blake3_hash_batch(const uint8_t** inputs, const size_t* lengths,
202+
uint8_t** outputs, size_t count);
203+
204+
/* ============================================================================
205+
* AVX2-Accelerated Functions
206+
* ============================================================================ */
207+
208+
/**
209+
* AVX2-accelerated hash (3-5x faster than scalar)
210+
*/
211+
void fp_blake3_hash_avx2(const uint8_t* input, size_t len, uint8_t* output);
212+
213+
/**
214+
* Maximum performance hash - all operations in registers
215+
*/
216+
void fp_blake3_hash_fast(const uint8_t* input, size_t len, uint8_t* output);
217+
218+
/**
219+
* Official BLAKE3 implementation (3-5x faster than SHA-256)
220+
*/
221+
void fp_blake3_hash_official(const uint8_t* input, size_t len, uint8_t* output);
222+
void fp_blake3_hash_keyed_official(const uint8_t* key, const uint8_t* input,
223+
size_t len, uint8_t* output);
224+
void fp_blake3_derive_key_official(const char* context, size_t context_len,
225+
const uint8_t* key_material, size_t km_len,
226+
uint8_t* output);
227+
228+
/**
229+
* AVX2-accelerated keyed hash
230+
*/
231+
void fp_blake3_hash_keyed_avx2(const uint8_t* key, const uint8_t* input,
232+
size_t len, uint8_t* output);
233+
234+
/* ============================================================================
235+
* Utility Functions
236+
* ============================================================================ */
237+
238+
/**
239+
* Convert hash to hexadecimal string
240+
*
241+
* @param hash 32-byte hash
242+
* @param hex Output buffer (65 bytes: 64 hex chars + null)
243+
*/
244+
void fp_blake3_to_hex(const uint8_t* hash, char* hex);
245+
246+
/**
247+
* Compare two hashes in constant time
248+
*
249+
* @param a First hash (32 bytes)
250+
* @param b Second hash (32 bytes)
251+
* @return 0 if equal, non-zero otherwise
252+
*/
253+
int fp_blake3_compare(const uint8_t* a, const uint8_t* b);
254+
255+
#ifdef __cplusplus
256+
}
257+
#endif

include/fp_hnsw.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#ifndef FP_HNSW_H
2+
#define FP_HNSW_H
3+
4+
#include <stdint.h>
5+
#include <stddef.h>
6+
7+
/**
8+
* HNSW Node structure.
9+
* Each node represents a vector in the database.
10+
*/
11+
typedef struct {
12+
int32_t vector_idx; // Index into the database's columnar storage
13+
int32_t num_layers; // Number of layers this node belongs to
14+
int32_t** neighbors; // Array of neighbor indices per layer
15+
int32_t* neighbor_counts; // Number of neighbors per layer
16+
} fp_hnsw_node;
17+
18+
/**
19+
* HNSW Index structure.
20+
*/
21+
typedef struct {
22+
int32_t dim; // Vector dimension
23+
int32_t M; // Max number of neighbors per node
24+
int32_t ef_construction; // Search depth during construction
25+
int32_t max_layers; // Max layers allowed
26+
int32_t entry_point; // Node index of the entry point
27+
int32_t current_max_layer;
28+
29+
fp_hnsw_node* nodes; // Array of nodes
30+
size_t count; // Number of nodes currently in index
31+
size_t capacity; // Max nodes
32+
} fp_hnsw_index;
33+
34+
/**
35+
* Initialize a new HNSW index.
36+
*/
37+
fp_hnsw_index* fp_hnsw_create(int32_t dim, int32_t M, int32_t ef_construction, size_t capacity);
38+
39+
/**
40+
* Free HNSW index.
41+
*/
42+
void fp_hnsw_free(fp_hnsw_index* index);
43+
44+
/**
45+
* Insert a vector into the HNSW index.
46+
* Note: Caller must provide the vector data since HNSW only stores indices.
47+
*/
48+
void fp_hnsw_insert(fp_hnsw_index* index, int32_t vector_idx, const double* vector, const double** db_columns, size_t db_count);
49+
50+
/**
51+
* Search the HNSW index.
52+
*/
53+
size_t fp_hnsw_search(
54+
const fp_hnsw_index* index,
55+
const double* query_vec,
56+
int32_t k,
57+
int32_t ef_search,
58+
const double** db_columns,
59+
size_t db_count,
60+
int32_t* results_indices,
61+
double* results_scores
62+
);
63+
64+
#endif /* FP_HNSW_H */

include/fp_kmeans.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include <stdint.h>
3131
#include "fp_monads.h"
32+
#include "fp_progress.h"
3233

3334
/* ============================================================================
3435
* K-MEANS RESULT STRUCTURE
@@ -72,6 +73,25 @@ KMeansResult fp_kmeans_f64(
7273
uint64_t seed
7374
);
7475

76+
/**
77+
* fp_kmeans_f64_progress - Run K-Means with progress callbacks per iteration
78+
*
79+
* @param progress Progress callback + user pointer (can be {NULL, NULL})
80+
*
81+
* The callback receives (current_iter, max_iter, phase) and should return:
82+
* 1 to continue, 0 to stop early (cancellation).
83+
*/
84+
KMeansResult fp_kmeans_f64_progress(
85+
const double* data,
86+
int n,
87+
int d,
88+
int k,
89+
int max_iter,
90+
double tol,
91+
uint64_t seed,
92+
fp_progress_t progress
93+
);
94+
7595
/**
7696
* fp_kmeans_free - Free internal arrays of KMeansResult
7797
*

include/fp_math.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@
44
#include "fp_graphics_engine.h"
55
#include <math.h>
66

7-
static inline Vec3f vec3f_add(Vec3f a, Vec3f b) { return (Vec3f){a.x + b.x, a.y + b.y, a.z + b.z}; }
8-
static inline Vec3f vec3f_sub(Vec3f a, Vec3f b) { return (Vec3f){a.x - b.x, a.y - b.y, a.z - b.z}; }
9-
static inline Vec3f vec3f_scale(Vec3f v, float s) { return (Vec3f){v.x * s, v.y * s, v.z * s}; }
7+
static inline Vec3f vec3f_add(Vec3f a, Vec3f b) { return (Vec3f){a.x + b.x, a.y + b.y, a.z + b.z, 0.0f}; }
8+
static inline Vec3f vec3f_sub(Vec3f a, Vec3f b) { return (Vec3f){a.x - b.x, a.y - b.y, a.z - b.z, 0.0f}; }
9+
static inline Vec3f vec3f_scale(Vec3f v, float s) { return (Vec3f){v.x * s, v.y * s, v.z * s, 0.0f}; }
1010
static inline float vec3f_length(Vec3f v) { return sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); }
1111
static inline Vec3f vec3f_normalize(Vec3f v) { float l = vec3f_length(v); return l > 0 ? vec3f_scale(v, 1.0f / l) : v; }
1212
static inline Vec3f vec3f_cross(Vec3f a, Vec3f b) {
1313
return (Vec3f){
1414
a.y * b.z - a.z * b.y,
1515
a.z * b.x - a.x * b.z,
16-
a.x * b.y - a.y * b.x
16+
a.x * b.y - a.y * b.x,
17+
0.0f
1718
};
1819
}
1920

include/fp_progress.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef FP_PROGRESS_H
2+
#define FP_PROGRESS_H
3+
4+
#include <stdint.h>
5+
6+
typedef int (*fp_progress_callback)(void* user, uint64_t current, uint64_t total, const char* phase);
7+
8+
typedef struct {
9+
fp_progress_callback callback;
10+
void* user;
11+
} fp_progress_t;
12+
13+
static inline int fp_progress_emit(fp_progress_t progress, uint64_t current, uint64_t total, const char* phase) {
14+
if (progress.callback) {
15+
return progress.callback(progress.user, current, total, phase);
16+
}
17+
return 1;
18+
}
19+
20+
#endif /* FP_PROGRESS_H */

0 commit comments

Comments
 (0)