Skip to main content

qrcode_rust_shared/
qr_math.rs

1//! QR Code Math utilities - Galois Field operations
2
3/// Galois Field 数学运算
4pub struct QRMath;
5
6static mut EXP_TABLE: [i32; 256] = [0; 256];
7static mut LOG_TABLE: [i32; 256] = [0; 256];
8static INIT: std::sync::Once = std::sync::Once::new();
9
10fn init_tables() {
11    INIT.call_once(|| {
12        unsafe {
13            // Galois Field 指数表初始化
14            // 生成多项式: x^8 + x^4 + x^3 + x^2 + 1 (0x11d)
15            EXP_TABLE[0] = 1;
16            for i in 1..256 {
17                let mut v = EXP_TABLE[i - 1] << 1;
18                if v > 255 {
19                    v ^= 0x11d; // 异或生成多项式
20                }
21                EXP_TABLE[i] = v;
22            }
23
24            // 构建对数表
25            for i in 0..255 {
26                LOG_TABLE[EXP_TABLE[i] as usize] = i as i32;
27            }
28            LOG_TABLE[0] = 0; // log(0) 未定义,设为 0
29        }
30    });
31}
32
33impl QRMath {
34    /// Galois Field 对数
35    pub fn glog(n: i32) -> i32 {
36        init_tables();
37        if n < 1 {
38            panic!("glog({})", n);
39        }
40        unsafe { LOG_TABLE[n as usize] }
41    }
42
43    /// Galois Field 指数
44    pub fn gexp(n: i32) -> i32 {
45        init_tables();
46        let mut n = n;
47        while n < 0 {
48            n += 255;
49        }
50        while n >= 256 {
51            n -= 255;
52        }
53        unsafe { EXP_TABLE[n as usize] }
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn test_gexp_basic() {
63        assert_eq!(QRMath::gexp(0), 1);
64        assert_eq!(QRMath::gexp(1), 2);
65        assert_eq!(QRMath::gexp(2), 4);
66    }
67
68    #[test]
69    fn test_gexp_overflow() {
70        assert_eq!(QRMath::gexp(255), 1);
71        assert_eq!(QRMath::gexp(256), 2);
72    }
73
74    #[test]
75    fn test_gexp_negative() {
76        assert_eq!(QRMath::gexp(-1), QRMath::gexp(254));
77    }
78
79    #[test]
80    fn test_glog_basic() {
81        assert_eq!(QRMath::glog(1), 0);
82        assert_eq!(QRMath::glog(2), 1);
83        assert_eq!(QRMath::glog(4), 2);
84    }
85
86    #[test]
87    fn test_glog_gexp_inverse() {
88        for i in 0..255 {
89            let exp = QRMath::gexp(i);
90            let log = QRMath::glog(exp);
91            assert_eq!(log, i, "glog(gexp({})) failed", i);
92        }
93    }
94
95    #[test]
96    fn test_gexp_glog_inverse() {
97        for i in 1..256 {
98            let log = QRMath::glog(i);
99            let exp = QRMath::gexp(log);
100            assert_eq!(exp, i, "gexp(glog({})) failed", i);
101        }
102    }
103
104    #[test]
105    #[should_panic(expected = "glog(0)")]
106    fn test_glog_zero_panics() {
107        QRMath::glog(0);
108    }
109}