现代密码学 第二章——流密码【下】

五、m序列

1、线性反馈移位寄存器的多项式表示

(1)在上一节中已经使用了递推公式描述LFSR,但这种形式不便于分析序列的周期、线性复杂度等性质,而多项式是数学里分析线性递推关系的"利器",它能把递推关系转化为多项式运算,直接关联到密码学关心的核心指标。

(2)延迟算子与LFSR一元多项式表示:

(3)生成函数的定义及定理:

①生成函数的定义:

②定理1:

③定理2:

④定理3:

2、m序列产生的条件

(1)不可约多项式与本原多项式:

①不可约多项式:

②本原多项式:

(2)m序列产生的必要条件:

(3)m序列产生的充要条件:

(4)m序列举例:

3、m序列的伪随机性

4、m序列的安全性

(1)已知m序列,推算相应的反馈多项式方法:

(2)解方程方法举例:

①例1:

②例2:

(3)线性反馈移位寄存器综合解:

①设计或求解LSFR时,主要考虑以下两个问题:

1\]如何利用级数尽可能短的LFSR产生周期大、随机性能良好的序列。这是从密钥生成角度考虑,用最小的代价产生尽可能好的、参与密码变换的序列。 \[2\]当已知一个长为N的序列时,如何构造一个级数尽可能小的LFSR来产生它。这是从密码分析角度来考虑,花费最小的代价,用线性方法重构密钥序列。 ②线性综合解: ![](https://i-blog.csdnimg.cn/direct/e24f9b8ede06481ba36409417c9d815f.png) ③LFSR综合问题: ![](https://i-blog.csdnimg.cn/direct/ef683ff66ef2413688d07293df662ac8.png) ④Berlekamp-Massey算法: ![](https://i-blog.csdnimg.cn/direct/906f5ed2d120443d82c22df47d2b6851.png) ![](https://i-blog.csdnimg.cn/direct/773e204b44b447cbb43002066f480e41.png) ![](https://i-blog.csdnimg.cn/direct/1a6e28fa479a46ddab164253155c3fe9.png) ![](https://i-blog.csdnimg.cn/direct/ad95461ecf79445bbb05a57e0f0e914f.png) ![](https://i-blog.csdnimg.cn/direct/2e7612e32e5f46fbbc2510ff6ae37297.png) ## 六、非线性序列 ### 1、Geffe序列生成器 (1)Geffe序列生成器的结构: Geffe序列生成器由3个LFSR组成,其中LFSR2作为控制生成器使用,如下图所示 当LFSR2输出1时,LFSR2与LFSR1相连接 当LFSR2输出0时,LFSR2与LFSR3相连接 ![](https://i-blog.csdnimg.cn/direct/7790b97e46b84ad58963c20cdcd0dd11.png) (2)Geffe序列生成器的工作逻辑: ![](https://i-blog.csdnimg.cn/direct/9729db396510487cac3bf9f2a3a09416.png) (3)Geffe序列生成器的C语言实现: ```cpp #include #include #include // 定义LFSR结构体 typedef struct { uint32_t state; // 寄存器状态(最高位为抽头位) uint32_t mask; // 抽头掩码(反馈多项式中抽头位对应1) uint32_t poly; // 反馈多项式(仅用于初始化掩码) int width; // 寄存器位宽 } LFSR; // 初始化LFSR:设置状态和抽头掩码(根据多项式) void lfsr_init(LFSR *lfsr, uint32_t seed, uint32_t polynomial, int width) { lfsr->state = seed & ((1ULL << width) - 1); // 限制在width位内 if (lfsr->state == 0) lfsr->state = 1; // 避免全0状态 lfsr->poly = polynomial; lfsr->width = width; // 构建掩码:多项式中所有非零项对应的位数(抽头位置) lfsr->mask = 0; for (int i = 0; i < width; i++) { if (polynomial & (1 << i)) { lfsr->mask |= (1 << i); } } } // 时钟一次:计算反馈位,移位,返回输出位(移出的最高位) uint8_t lfsr_clock(LFSR *lfsr) { // 计算反馈位:所有抽头位的异或(计算掩码内的位) uint32_t feedback = 0; uint32_t masked = lfsr->state & lfsr->mask; // 快速奇偶校验(计算所有位的异或) feedback = masked ^ (masked >> 16); feedback ^= feedback >> 8; feedback ^= feedback >> 4; feedback ^= feedback >> 2; feedback ^= feedback >> 1; feedback &= 1; // 输出位为移出的最高位(第width-1位) uint8_t output = (lfsr->state >> (lfsr->width - 1)) & 1; // 左移一位,将反馈位放入最低位 lfsr->state = ((lfsr->state << 1) & ((1ULL << lfsr->width) - 1)) | feedback; return output; } // 生成一个比特的Geffe输出 uint8_t geffe_bit(LFSR *lfsr1, LFSR *lfsr2, LFSR *lfsr3) { uint8_t b1 = lfsr_clock(lfsr1); uint8_t b2 = lfsr_clock(lfsr2); uint8_t b3 = lfsr_clock(lfsr3); // 若b3=1,输出b1;否则输出b2 return b3 ? b1 : b2; } // 生成一个密钥字节(8个连续比特) uint8_t geffe_byte(LFSR *lfsr1, LFSR *lfsr2, LFSR *lfsr3) { uint8_t byte = 0; for (int i = 0; i < 8; i++) { byte = (byte << 1) | geffe_bit(lfsr1, lfsr2, lfsr3); } return byte; } // 加密函数:数据与Geffe生成的密钥流异或(原地操作) void geffe_encrypt(uint8_t *data, size_t len, uint32_t seed1, uint32_t seed2, uint32_t seed3) { LFSR lfsr1, lfsr2, lfsr3; // 使用三个不同本原多项式(长度分别为 13, 15, 17) // 多项式以二进制表示:x^13 + x^4 + x^3 + x + 1 -> 0x201B (bit13=1, bit4=1, bit3=1, bit1=1) lfsr_init(&lfsr1, seed1, (1 << 13) | (1 << 4) | (1 << 3) | (1 << 1) | 1, 13); lfsr_init(&lfsr2, seed2, (1 << 15) | (1 << 1) | 1, 15); // x^15 + x + 1 lfsr_init(&lfsr3, seed3, (1 << 17) | (1 << 3) | 1, 17); // x^17 + x^3 + 1 for (size_t i = 0; i < len; i++) { uint8_t keystream = geffe_byte(&lfsr1, &lfsr2, &lfsr3); data[i] ^= keystream; } } // 解密函数(与加密相同,因为异或对称) void geffe_decrypt(uint8_t *data, size_t len, uint32_t seed1, uint32_t seed2, uint32_t seed3) { geffe_encrypt(data, len, seed1, seed2, seed3); } // 辅助函数:打印十六进制 void print_hex(const uint8_t *data, size_t len) { for (size_t i = 0; i < len; i++) { printf("%02X ", data[i]); } printf("\n"); } int main() { // 明文示例 uint8_t plaintext[] = "Geffe sequence generator example!"; size_t len = strlen((char*)plaintext); // 三个种子(密钥),不能为0,且应小于各自LFSR的最大周期 uint32_t seed1 = 0x1A2B; // 13位,小于8192 uint32_t seed2 = 0x3C4D; // 15位,小于32768 uint32_t seed3 = 0x5E6F; // 17位,小于131072 printf("原始明文: %s\n", plaintext); printf("明文(HEX): "); print_hex(plaintext, len); // 加密 geffe_encrypt(plaintext, len, seed1, seed2, seed3); printf("密文(HEX): "); print_hex(plaintext, len); // 解密(使用相同种子) geffe_decrypt(plaintext, len, seed1, seed2, seed3); printf("解密后明文: %s\n", plaintext); return 0; } ``` ### 2、J-K触发器与Pless生成器 (1)J-K触发器的结构: ![](https://i-blog.csdnimg.cn/direct/18ddd7d2f05944819f1d61f84d469eac.png) (2)利用1个J-K触发器构成的非线性序列生成器: ![](https://i-blog.csdnimg.cn/direct/49f39a764cfa41a582030ae4360ba006.png) (3)利用1个J-K触发器构成的非线性序列生成器的弱点: ![](https://i-blog.csdnimg.cn/direct/4813d069e46b4a5c83ebdca5e6303ed7.png) (4)Pless生成器的结构: Pless生成器由8个LFSR、4个J-K触发器和1个循环计数器构成,由循环计数器进行选通控制,如图所示 ![](https://i-blog.csdnimg.cn/direct/cfa2cb5cbf8d4a0a99875bac9d1e589c.png) (5)Pless生成器的C语言实现: ```cpp #include #include #include #include // ---------- 1. LFSR 结构体及实现 ---------- typedef struct { uint32_t state; uint32_t poly; uint8_t width; } LFSR; void lfsr_init(LFSR *lfsr, uint32_t seed, uint32_t poly, uint8_t width) { lfsr->state = seed & ((1UL << width) - 1); if (lfsr->state == 0 && width < 32) lfsr->state = 1; lfsr->poly = poly; lfsr->width = width; } uint8_t lfsr_clock(LFSR *lfsr) { uint8_t fb_bit = 0; for (uint8_t i = 0; i < lfsr->width; i++) { if ((lfsr->poly >> i) & 1) { fb_bit ^= (lfsr->state >> i) & 1; } } uint8_t output_bit = (lfsr->state >> (lfsr->width - 1)) & 1; lfsr->state = ((lfsr->state << 1) & ((1UL << lfsr->width) - 1)) | fb_bit; return output_bit; } // ---------- 2. JK 触发器结构体及实现 ---------- typedef struct { uint8_t q; // 当前输出状态 } JK_FlipFlop; void jk_init(JK_FlipFlop *jk, uint8_t init_q) { jk->q = init_q; // 初始化为 0 或 1 } uint8_t jk_clock(JK_FlipFlop *jk, uint8_t j, uint8_t k) { uint8_t next_q; if (j == 0 && k == 0) { next_q = jk->q; // 保持当前状态 } else if (j == 0 && k == 1) { next_q = 0; // 复位 (Reset) } else if (j == 1 && k == 0) { next_q = 1; // 置位 (Set) } else { // (j == 1 && k == 1) next_q = 1 ^ jk->q; // 翻转 (Toggle) } jk->q = next_q; return jk->q; } // ---------- 3. Pless 生成器 ---------- #define NUM_LFSR_PAIRS 4 typedef struct { LFSR lfsr_j; LFSR lfsr_k; JK_FlipFlop jk; } PlessUnit; typedef struct { PlessUnit units[NUM_LFSR_PAIRS]; uint8_t counter; // 循环计数器 (0 到 NUM_LFSR_PAIRS-1) } PlessGenerator; // 初始化Pless生成器 void pless_init(PlessGenerator *pg, const uint32_t seeds_J[4], const uint32_t seeds_K[4]) { // 8个LFSR的多项式和位宽(示例参数,可按需调整) const uint32_t polys_J[NUM_LFSR_PAIRS] = { 0x8003, 0x801B, 0x8021, 0x803D }; // x^15 + x + 1, 等等 const uint32_t polys_K[NUM_LFSR_PAIRS] = { 0x8049, 0x8065, 0x808F, 0x8020 }; // 不同多项式 const uint8_t width_J[NUM_LFSR_PAIRS] = { 15, 15, 15, 15 }; const uint8_t width_K[NUM_LFSR_PAIRS] = { 15, 15, 15, 15 }; for (int i = 0; i < NUM_LFSR_PAIRS; i++) { lfsr_init(&pg->units[i].lfsr_j, seeds_J[i], polys_J[i], width_J[i]); lfsr_init(&pg->units[i].lfsr_k, seeds_K[i], polys_K[i], width_K[i]); jk_init(&pg->units[i].jk, 0); } pg->counter = 0; } // 产生1位密钥流 -> Pless生成器的一个时钟 uint8_t pless_clock(PlessGenerator *pg) { // 1. 从循环计数器中选择当前的单元 uint8_t idx = pg->counter; PlessUnit *unit = &pg->units[idx]; // 2. 驱动选中的两个LFSR各前进1步,产生JK触发器的J和K输入 uint8_t j_in = lfsr_clock(&unit->lfsr_j); uint8_t k_in = lfsr_clock(&unit->lfsr_k); // 3. JK触发器产生输出 uint8_t out_bit = jk_clock(&unit->jk, j_in, k_in); // 4. 循环计数器前进到下一个单元 pg->counter = (pg->counter + 1) % NUM_LFSR_PAIRS; return out_bit; } // ---------- 4. 加密/解密接口 ---------- void pless_encrypt(uint8_t *data, size_t len, const uint32_t seeds_J[4], const uint32_t seeds_K[4]) { PlessGenerator pg; pless_init(&pg, seeds_J, seeds_K); for (size_t i = 0; i < len; i++) { uint8_t keystream_byte = 0; for (int bit = 0; bit < 8; bit++) { keystream_byte = (keystream_byte << 1) | pless_clock(&pg); } data[i] ^= keystream_byte; } } // 异或对称性,解密函数与加密相同 void pless_decrypt(uint8_t *data, size_t len, const uint32_t seeds_J[4], const uint32_t seeds_K[4]) { pless_encrypt(data, len, seeds_J, seeds_K); } // ---------- 5. 主函数演示 ---------- void print_hex(uint8_t *data, size_t len) { for (size_t i = 0; i < len; i++) printf("%02X ", data[i]); printf("\n"); } int main() { uint32_t seeds_J[4] = { 0x1234, 0x5678, 0x9ABC, 0xDEF0 }; uint32_t seeds_K[4] = { 0x1357, 0x2468, 0x9BDF, 0xACE0 }; char plaintext[] = "Pless generator example!"; size_t len = strlen(plaintext); uint8_t *data = (uint8_t*)malloc(len); memcpy(data, plaintext, len); printf("原始明文: %s\n", plaintext); printf("明文(HEX): "); print_hex(data, len); pless_encrypt(data, len, seeds_J, seeds_K); printf("密文(HEX): "); print_hex(data, len); pless_decrypt(data, len, seeds_J, seeds_K); printf("解密后明文: %s\n", data); free(data); return 0; } ``` ### 3、钟控序列生成器 (1)钟控序列生成器的结构: 钟控序列最基本的模型是用一个LFSR控制另外一个LFSR的移位时钟脉冲,如下图所示,这是一个最简单的钟控序列生成器(停走生成器),下面也以此结构对钟控序列生成器进行介绍 ![](https://i-blog.csdnimg.cn/direct/17277e19fe9e4171b2c9f6f739283391.png) ![](https://i-blog.csdnimg.cn/direct/22dbf8e4714a4d08ba9aceb103c88ea2.png) (2)钟控序列的周期: ![](https://i-blog.csdnimg.cn/direct/ff7ded18f4ab413781960c63724411fd.png) ![](https://i-blog.csdnimg.cn/direct/915011426f7f4363b703e77086ec250d.png) (3)钟控序列的线性复杂度: ![](https://i-blog.csdnimg.cn/direct/2b22acf1aa3346a894b6314e1b44b43b.png) (4)钟控序列生成器的C语言实现: ```cpp #include #include #include #include // ========== LFSR 结构体 ========== typedef struct { uint32_t state; // 当前状态(最高位为输出位) uint32_t mask; // 抽头掩码(反馈多项式对应的位) int width; // 寄存器宽度 } LFSR; // 初始化LFSR:根据种子和抽头掩码(种子不能为0) void lfsr_init(LFSR *lfsr, uint32_t seed, uint32_t tap_mask, int width) { lfsr->state = seed & ((1UL << width) - 1); if (lfsr->state == 0) lfsr->state = 1; // 避免全0死锁 lfsr->mask = tap_mask; lfsr->width = width; } // LFSR时钟一次,返回输出位(移出的最高位) uint8_t lfsr_clock(LFSR *lfsr) { // 计算反馈位:抽头位的异或 uint32_t fb = 0; uint32_t masked = lfsr->state & lfsr->mask; // 快速奇偶校验 fb = masked ^ (masked >> 16); fb ^= fb >> 8; fb ^= fb >> 4; fb ^= fb >> 2; fb ^= fb >> 1; fb &= 1; uint8_t out = (lfsr->state >> (lfsr->width - 1)) & 1; lfsr->state = ((lfsr->state << 1) & ((1UL << lfsr->width) - 1)) | fb; return out; } // ========== 停走生成器结构体 ========== typedef struct { LFSR control; // 控制LFSR(决定目标时钟) LFSR target; // 目标LFSR(输出序列) } StopGoGen; // 初始化停走生成器 void stopgo_init(StopGoGen *gen, uint32_t ctrl_seed, uint32_t ctrl_mask, int ctrl_width, uint32_t targ_seed, uint32_t targ_mask, int targ_width) { lfsr_init(&gen->control, ctrl_seed, ctrl_mask, ctrl_width); lfsr_init(&gen->target, targ_seed, targ_mask, targ_width); } // 产生一个输出比特(停走机制) uint8_t stopgo_bit(StopGoGen *gen) { // 控制LFSR始终时钟 uint8_t ctrl_out = lfsr_clock(&gen->control); // 如果控制输出为1,则目标LFSR时钟一次;否则目标不时钟 if (ctrl_out == 1) { lfsr_clock(&gen->target); // 注意:这里只时钟,丢弃其输出(也可以保存输出) } // 目标LFSR的当前输出作为最终输出(即每次调用都返回目标寄存器的当前最高位) // 注意:目标可能没时钟,所以输出与前一次相同。 return (gen->target.state >> (gen->target.width - 1)) & 1; } // 产生一个密钥字节(收集8个输出比特) uint8_t stopgo_byte(StopGoGen *gen) { uint8_t byte = 0; for (int i = 0; i < 8; i++) { byte = (byte << 1) | stopgo_bit(gen); } return byte; } // ========== 流密码加解密接口 ========== void stopgo_encrypt(uint8_t *data, size_t len, uint32_t ctrl_seed, uint32_t ctrl_mask, int ctrl_width, uint32_t targ_seed, uint32_t targ_mask, int targ_width) { StopGoGen gen; stopgo_init(&gen, ctrl_seed, ctrl_mask, ctrl_width, targ_seed, targ_mask, targ_width); for (size_t i = 0; i < len; i++) { uint8_t ks = stopgo_byte(&gen); data[i] ^= ks; } } void stopgo_decrypt(uint8_t *data, size_t len, uint32_t ctrl_seed, uint32_t ctrl_mask, int ctrl_width, uint32_t targ_seed, uint32_t targ_mask, int targ_width) { // 流密码加解密相同 stopgo_encrypt(data, len, ctrl_seed, ctrl_mask, ctrl_width, targ_seed, targ_mask, targ_width); } // ========== 辅助函数 ========== void print_hex(const uint8_t *data, size_t len) { for (size_t i = 0; i < len; i++) { printf("%02X ", data[i]); } printf("\n"); } // ========== 主函数演示 ========== int main() { // 选择两个LFSR的参数(可使用本原多项式对应的抽头掩码) // 控制LFSR: 宽度13,抽头掩码 x^13 + x^4 + x^3 + x + 1 对应位: 13,4,3,1,0 // 掩码 = (1<<12) | (1<<3) | (1<<2) | (1<<0) ? 注意:通常宽度13,最高位索引12 // 为简单,使用常见15级LFSR: x^15 + x + 1 掩码 = (1<<14) | (1<<0) 实际抽头位14和0 // 控制LFSR宽度15,掩码0x8001 (位14和位0) // 目标LFSR宽度17,掩码 x^17 + x^3 + 1 -> 位16和位2和位0 => 0x20005 uint32_t ctrl_mask = (1 << 14) | 1; // 15级,抽头14和0 int ctrl_width = 15; uint32_t targ_mask = (1 << 16) | (1 << 2) | 1; // 17级,抽头16,2,0 int targ_width = 17; // 种子不能全0 uint32_t ctrl_seed = 0x2A3F; // 15位内 uint32_t targ_seed = 0x1A5B7; // 17位内 // 测试明文 char text[] = "Stop-and-Go clock-controlled generator!"; size_t len = strlen(text); uint8_t *data = (uint8_t*)malloc(len); memcpy(data, text, len); printf("原始明文: %s\n", text); printf("明文(HEX): "); print_hex(data, len); // 加密 stopgo_encrypt(data, len, ctrl_seed, ctrl_mask, ctrl_width, targ_seed, targ_mask, targ_width); printf("密文(HEX): "); print_hex(data, len); // 解密 stopgo_decrypt(data, len, ctrl_seed, ctrl_mask, ctrl_width, targ_seed, targ_mask, targ_width); printf("解密后明文: %s\n", data); free(data); return 0; } ``` ## 七、A5流密码算法 ### 1、A5流密码算法介绍 (1)A5/1是GSM移动通信中用于语音通话加密的流密码,它的核心是用三个线性反馈移位寄存器(LFSR),通过钟控停走的方式生成密钥流,再和明文/密文做逐位异或完成加解密。 ![](https://i-blog.csdnimg.cn/direct/f534cf94cb33452d80004cd0152750b2.png) 需要说明的是,A5/1算法中,LFSR的移位方式是左移方式,各寄存器的编号从第0级编号到第n-1级 (2)基本密钥与会话密钥: ![](https://i-blog.csdnimg.cn/direct/36170c7a6ae143538c910ac139c2c1c3.png) (3)明文处理与加密方式: ①A5/1算法将通话的明文数据按每帧228bit分为若干帧,然后进行逐帧加密,每帧的处理方式相同且独立。 ![](https://i-blog.csdnimg.cn/direct/2a5fd313f9324024a93fb26ad2823bd8.png) ②加密方式: ![](https://i-blog.csdnimg.cn/direct/97a098efe4c84517b69d16364849d6b8.png) (4)算法初始化: 初始化就是利用一次通话的会话密钥k和帧序号设定三个线性移位寄存器的起点,也即初始状态 首先将三个LFSR的初始状态设置为全零,然后将64bit的会话密钥k从低位到高位依次移入三个寄存器,每一位密钥bit,同时与三个寄存器的反馈抽头输出异或,结果作为寄存器的输入,三个寄存器都移位64次,完成会话密钥的注入 然后将22bit的帧序号从低位到高位,依次移入三个寄存器,每一位帧序号bit,与三个寄存器的反馈抽头输出异或,作为输入,三个寄存器都移位22次,完成帧序号的注入(对不同的帧设置不同的帧序号,保证对每帧以不同的起点生成密钥流,尽可能地避免密钥重用) 此时,三个寄存器的状态已经混合了会话密钥和帧号,每帧的状态都不同 ### 2、A5流密码算法的基本原理 (1)密钥流生成与加解密: ![](https://i-blog.csdnimg.cn/direct/02c21dbbff144321a35e5ad6a77912b5.png) (2)加密过程: 三个LFSR以钟控方式连续动作100次,但不输出密钥流 然后三个LFSR以钟控方式连续动作114次,在每次动作后,三个LFSR都将最高位寄存器中的值输出,这三个bit的异或就是当前时刻输出的1bit密钥 然后连续动作114步,共输出114bit密钥流,用于对用户手机到基站传送的114bit数据的加密 (3)解密过程: 三个LFSR以钟控方式连续动作100次,但不输出密钥流 然后三个LFSR以钟控方式连续动作114次,在每次动作后,三个LFSR都将最高级寄存器中的值输出,这三个bit的模2和就是当前时刻输出的1bit密钥流 然后连续动作114步,共输出114bit密钥流,这114bit用于对基站到用户手机传送的114bit数据的解密 ### 3、A5流密码算法的弱点 (1)移位寄存器,太短容易遭受穷举攻击。 A5/1算法把主密钥作为算法中三个寄存器的初始值,长度为64bit,如果利用已知明文攻击,只需要知道其中两个寄存器的初始值,就可以计算出另一个寄存器的初始值,这只需要240步就可以得出寄存器LFSR-1和LFSR-2的结构 (2)事实上,A5/1加密算法中存在严重的安全问题。 利用GSM通信加密中的两个安全漏洞,可以通过离线迭代计算生成一个彩虹表,它包含有密钥和其相对应的输出密码,这个彩虹表的大小为984GB,得到了彩虹表之后,安全专家就可以在短短的九秒内确定用于加密通信数据的密钥

相关推荐
飞Link3 小时前
大模型长文本的“救命稻草”:深度解析 TurboQuant 与 KV Cache 压缩技术
算法
郝学胜-神的一滴4 小时前
深度学习优化核心:梯度下降与网络训练全解析
数据结构·人工智能·python·深度学习·算法·机器学习
Je1lyfish4 小时前
CMU15-445 (2025 Fall/2026 Spring) Project#3 - QueryExecution
linux·c语言·开发语言·数据结构·数据库·c++·算法
许彰午4 小时前
03-二叉树——从递归遍历到非递归实现
java·算法
Brilliantwxx5 小时前
【C++】 vector(代码实现+坑点讲解)
开发语言·c++·笔记·算法
NorburyL6 小时前
DPO笔记
深度学习·算法
老纪的技术唠嗑局7 小时前
深度解析 LLM Wiki / Obsidian-Wiki / GBrain:Agent 时代知识的“自组织”与“自进化”
大数据·数据库·人工智能·算法
YXXY3139 小时前
模拟算法的介绍
算法
happymaker062610 小时前
简单LRU的实现(基于LinkedHashMap)
算法·leetcode·lru