1 // SPDX-License-Identifier: MIT
2
3 //! This is a simple QR encoder for DRM panic.
4 //!
5 //! It is called from a panic handler, so it should't allocate memory and
6 //! does all the work on the stack or on the provided buffers. For
7 //! simplification, it only supports low error correction, and applies the
8 //! first mask (checkerboard). It will draw the smallest QRcode that can
9 //! contain the string passed as parameter. To get the most compact
10 //! QR code, the start of the URL is encoded as binary, and the
11 //! compressed kmsg is encoded as numeric.
12 //!
13 //! The binary data must be a valid URL parameter, so the easiest way is
14 //! to use base64 encoding. But this wastes 25% of data space, so the
15 //! whole stack trace won't fit in the QR code. So instead it encodes
16 //! every 7 bytes of input into 17 decimal digits, and then uses the
17 //! efficient numeric encoding, that encode 3 decimal digits into
18 //! 10bits. This makes 168bits of compressed data into 51 decimal digits,
19 //! into 170bits in the QR code, so wasting only 1.17%. And the numbers are
20 //! valid URL parameter, so the website can do the reverse, to get the
21 //! binary data. This is the same algorithm used by Fido v2.2 QR-initiated
22 //! authentication specification.
23 //!
24 //! Inspired by these 3 projects, all under MIT license:
25 //!
26 //! * <https://github.com/kennytm/qrcode-rust>
27 //! * <https://github.com/erwanvivien/fast_qr>
28 //! * <https://github.com/bjguillot/qr>
29
30 use kernel::{prelude::*, str::CStr};
31
32 #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
33 struct Version(usize);
34
35 // Generator polynomials for ECC, only those that are needed for low quality.
36 const P7: [u8; 7] = [87, 229, 146, 149, 238, 102, 21];
37 const P10: [u8; 10] = [251, 67, 46, 61, 118, 70, 64, 94, 32, 45];
38 const P15: [u8; 15] = [
39 8, 183, 61, 91, 202, 37, 51, 58, 58, 237, 140, 124, 5, 99, 105,
40 ];
41 const P18: [u8; 18] = [
42 215, 234, 158, 94, 184, 97, 118, 170, 79, 187, 152, 148, 252, 179, 5, 98, 96, 153,
43 ];
44 const P20: [u8; 20] = [
45 17, 60, 79, 50, 61, 163, 26, 187, 202, 180, 221, 225, 83, 239, 156, 164, 212, 212, 188, 190,
46 ];
47 const P22: [u8; 22] = [
48 210, 171, 247, 242, 93, 230, 14, 109, 221, 53, 200, 74, 8, 172, 98, 80, 219, 134, 160, 105,
49 165, 231,
50 ];
51 const P24: [u8; 24] = [
52 229, 121, 135, 48, 211, 117, 251, 126, 159, 180, 169, 152, 192, 226, 228, 218, 111, 0, 117,
53 232, 87, 96, 227, 21,
54 ];
55 const P26: [u8; 26] = [
56 173, 125, 158, 2, 103, 182, 118, 17, 145, 201, 111, 28, 165, 53, 161, 21, 245, 142, 13, 102,
57 48, 227, 153, 145, 218, 70,
58 ];
59 const P28: [u8; 28] = [
60 168, 223, 200, 104, 224, 234, 108, 180, 110, 190, 195, 147, 205, 27, 232, 201, 21, 43, 245, 87,
61 42, 195, 212, 119, 242, 37, 9, 123,
62 ];
63 const P30: [u8; 30] = [
64 41, 173, 145, 152, 216, 31, 179, 182, 50, 48, 110, 86, 239, 96, 222, 125, 42, 173, 226, 193,
65 224, 130, 156, 37, 251, 216, 238, 40, 192, 180,
66 ];
67
68 /// QR Code parameters for Low quality ECC:
69 /// - Error Correction polynomial.
70 /// - Number of blocks in group 1.
71 /// - Number of blocks in group 2.
72 /// - Block size in group 1.
73 ///
74 /// (Block size in group 2 is one more than group 1).
75 struct VersionParameter(&'static [u8], u8, u8, u8);
76 const VPARAM: [VersionParameter; 40] = [
77 VersionParameter(&P7, 1, 0, 19), // V1
78 VersionParameter(&P10, 1, 0, 34), // V2
79 VersionParameter(&P15, 1, 0, 55), // V3
80 VersionParameter(&P20, 1, 0, 80), // V4
81 VersionParameter(&P26, 1, 0, 108), // V5
82 VersionParameter(&P18, 2, 0, 68), // V6
83 VersionParameter(&P20, 2, 0, 78), // V7
84 VersionParameter(&P24, 2, 0, 97), // V8
85 VersionParameter(&P30, 2, 0, 116), // V9
86 VersionParameter(&P18, 2, 2, 68), // V10
87 VersionParameter(&P20, 4, 0, 81), // V11
88 VersionParameter(&P24, 2, 2, 92), // V12
89 VersionParameter(&P26, 4, 0, 107), // V13
90 VersionParameter(&P30, 3, 1, 115), // V14
91 VersionParameter(&P22, 5, 1, 87), // V15
92 VersionParameter(&P24, 5, 1, 98), // V16
93 VersionParameter(&P28, 1, 5, 107), // V17
94 VersionParameter(&P30, 5, 1, 120), // V18
95 VersionParameter(&P28, 3, 4, 113), // V19
96 VersionParameter(&P28, 3, 5, 107), // V20
97 VersionParameter(&P28, 4, 4, 116), // V21
98 VersionParameter(&P28, 2, 7, 111), // V22
99 VersionParameter(&P30, 4, 5, 121), // V23
100 VersionParameter(&P30, 6, 4, 117), // V24
101 VersionParameter(&P26, 8, 4, 106), // V25
102 VersionParameter(&P28, 10, 2, 114), // V26
103 VersionParameter(&P30, 8, 4, 122), // V27
104 VersionParameter(&P30, 3, 10, 117), // V28
105 VersionParameter(&P30, 7, 7, 116), // V29
106 VersionParameter(&P30, 5, 10, 115), // V30
107 VersionParameter(&P30, 13, 3, 115), // V31
108 VersionParameter(&P30, 17, 0, 115), // V32
109 VersionParameter(&P30, 17, 1, 115), // V33
110 VersionParameter(&P30, 13, 6, 115), // V34
111 VersionParameter(&P30, 12, 7, 121), // V35
112 VersionParameter(&P30, 6, 14, 121), // V36
113 VersionParameter(&P30, 17, 4, 122), // V37
114 VersionParameter(&P30, 4, 18, 122), // V38
115 VersionParameter(&P30, 20, 4, 117), // V39
116 VersionParameter(&P30, 19, 6, 118), // V40
117 ];
118
119 const MAX_EC_SIZE: usize = 30;
120 const MAX_BLK_SIZE: usize = 123;
121
122 /// Position of the alignment pattern grid.
123 const ALIGNMENT_PATTERNS: [&[u8]; 40] = [
124 &[],
125 &[6, 18],
126 &[6, 22],
127 &[6, 26],
128 &[6, 30],
129 &[6, 34],
130 &[6, 22, 38],
131 &[6, 24, 42],
132 &[6, 26, 46],
133 &[6, 28, 50],
134 &[6, 30, 54],
135 &[6, 32, 58],
136 &[6, 34, 62],
137 &[6, 26, 46, 66],
138 &[6, 26, 48, 70],
139 &[6, 26, 50, 74],
140 &[6, 30, 54, 78],
141 &[6, 30, 56, 82],
142 &[6, 30, 58, 86],
143 &[6, 34, 62, 90],
144 &[6, 28, 50, 72, 94],
145 &[6, 26, 50, 74, 98],
146 &[6, 30, 54, 78, 102],
147 &[6, 28, 54, 80, 106],
148 &[6, 32, 58, 84, 110],
149 &[6, 30, 58, 86, 114],
150 &[6, 34, 62, 90, 118],
151 &[6, 26, 50, 74, 98, 122],
152 &[6, 30, 54, 78, 102, 126],
153 &[6, 26, 52, 78, 104, 130],
154 &[6, 30, 56, 82, 108, 134],
155 &[6, 34, 60, 86, 112, 138],
156 &[6, 30, 58, 86, 114, 142],
157 &[6, 34, 62, 90, 118, 146],
158 &[6, 30, 54, 78, 102, 126, 150],
159 &[6, 24, 50, 76, 102, 128, 154],
160 &[6, 28, 54, 80, 106, 132, 158],
161 &[6, 32, 58, 84, 110, 136, 162],
162 &[6, 26, 54, 82, 110, 138, 166],
163 &[6, 30, 58, 86, 114, 142, 170],
164 ];
165
166 /// Version information for format V7-V40.
167 const VERSION_INFORMATION: [u32; 34] = [
168 0b00_0111_1100_1001_0100,
169 0b00_1000_0101_1011_1100,
170 0b00_1001_1010_1001_1001,
171 0b00_1010_0100_1101_0011,
172 0b00_1011_1011_1111_0110,
173 0b00_1100_0111_0110_0010,
174 0b00_1101_1000_0100_0111,
175 0b00_1110_0110_0000_1101,
176 0b00_1111_1001_0010_1000,
177 0b01_0000_1011_0111_1000,
178 0b01_0001_0100_0101_1101,
179 0b01_0010_1010_0001_0111,
180 0b01_0011_0101_0011_0010,
181 0b01_0100_1001_1010_0110,
182 0b01_0101_0110_1000_0011,
183 0b01_0110_1000_1100_1001,
184 0b01_0111_0111_1110_1100,
185 0b01_1000_1110_1100_0100,
186 0b01_1001_0001_1110_0001,
187 0b01_1010_1111_1010_1011,
188 0b01_1011_0000_1000_1110,
189 0b01_1100_1100_0001_1010,
190 0b01_1101_0011_0011_1111,
191 0b01_1110_1101_0111_0101,
192 0b01_1111_0010_0101_0000,
193 0b10_0000_1001_1101_0101,
194 0b10_0001_0110_1111_0000,
195 0b10_0010_1000_1011_1010,
196 0b10_0011_0111_1001_1111,
197 0b10_0100_1011_0000_1011,
198 0b10_0101_0100_0010_1110,
199 0b10_0110_1010_0110_0100,
200 0b10_0111_0101_0100_0001,
201 0b10_1000_1100_0110_1001,
202 ];
203
204 /// Format info for low quality ECC.
205 const FORMAT_INFOS_QR_L: [u16; 8] = [
206 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976,
207 ];
208
209 impl Version {
210 /// Returns the smallest QR version than can hold these segments.
from_segments(segments: &[&Segment<'_>]) -> Option<Version>211 fn from_segments(segments: &[&Segment<'_>]) -> Option<Version> {
212 (1..=40)
213 .map(Version)
214 .find(|&v| v.max_data() * 8 >= segments.iter().map(|s| s.total_size_bits(v)).sum())
215 }
216
width(&self) -> u8217 fn width(&self) -> u8 {
218 (self.0 as u8) * 4 + 17
219 }
220
max_data(&self) -> usize221 fn max_data(&self) -> usize {
222 self.g1_blk_size() * self.g1_blocks() + (self.g1_blk_size() + 1) * self.g2_blocks()
223 }
224
ec_size(&self) -> usize225 fn ec_size(&self) -> usize {
226 VPARAM[self.0 - 1].0.len()
227 }
228
g1_blocks(&self) -> usize229 fn g1_blocks(&self) -> usize {
230 VPARAM[self.0 - 1].1 as usize
231 }
232
g2_blocks(&self) -> usize233 fn g2_blocks(&self) -> usize {
234 VPARAM[self.0 - 1].2 as usize
235 }
236
g1_blk_size(&self) -> usize237 fn g1_blk_size(&self) -> usize {
238 VPARAM[self.0 - 1].3 as usize
239 }
240
alignment_pattern(&self) -> &'static [u8]241 fn alignment_pattern(&self) -> &'static [u8] {
242 ALIGNMENT_PATTERNS[self.0 - 1]
243 }
244
poly(&self) -> &'static [u8]245 fn poly(&self) -> &'static [u8] {
246 VPARAM[self.0 - 1].0
247 }
248
version_info(&self) -> u32249 fn version_info(&self) -> u32 {
250 if *self >= Version(7) {
251 VERSION_INFORMATION[self.0 - 7]
252 } else {
253 0
254 }
255 }
256 }
257
258 /// Exponential table for Galois Field GF(256).
259 const EXP_TABLE: [u8; 256] = [
260 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117,
261 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181,
262 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161,
263 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187,
264 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136,
265 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197,
266 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168,
267 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198,
268 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149,
269 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167,
270 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72,
271 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207,
272 131, 27, 54, 108, 216, 173, 71, 142, 1,
273 ];
274
275 /// Reverse exponential table for Galois Field GF(256).
276 const LOG_TABLE: [u8; 256] = [
277 175, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141,
278 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142,
279 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114,
280 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148,
281 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126,
282 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172,
283 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24,
284 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149,
285 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132,
286 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12,
287 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95,
288 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173,
289 232, 116, 214, 244, 234, 168, 80, 88, 175,
290 ];
291
292 // 4 bits segment header.
293 const MODE_STOP: u16 = 0;
294 const MODE_NUMERIC: u16 = 1;
295 const MODE_BINARY: u16 = 4;
296 /// Padding bytes.
297 const PADDING: [u8; 2] = [236, 17];
298
299 /// Number of bits to encode characters in numeric mode.
300 const NUM_CHARS_BITS: [usize; 4] = [0, 4, 7, 10];
301 /// Number of decimal digits required to encode n bytes of binary data.
302 /// eg: you need 15 decimal digits to fit 6 bytes of binary data.
303 const BYTES_TO_DIGITS: [usize; 8] = [0, 3, 5, 8, 10, 13, 15, 17];
304
305 enum Segment<'a> {
306 Numeric(&'a [u8]),
307 Binary(&'a [u8]),
308 }
309
310 impl Segment<'_> {
get_header(&self) -> (u16, usize)311 fn get_header(&self) -> (u16, usize) {
312 match self {
313 Segment::Binary(_) => (MODE_BINARY, 4),
314 Segment::Numeric(_) => (MODE_NUMERIC, 4),
315 }
316 }
317
318 // Returns the size of the length field in bits, depending on QR Version.
length_bits_count(&self, version: Version) -> usize319 fn length_bits_count(&self, version: Version) -> usize {
320 let Version(v) = version;
321 match self {
322 Segment::Binary(_) => match v {
323 1..=9 => 8,
324 _ => 16,
325 },
326 Segment::Numeric(_) => match v {
327 1..=9 => 10,
328 10..=26 => 12,
329 _ => 14,
330 },
331 }
332 }
333
334 // Number of characters in the segment.
character_count(&self) -> usize335 fn character_count(&self) -> usize {
336 match self {
337 Segment::Binary(data) => data.len(),
338 Segment::Numeric(data) => {
339 let last_chars = BYTES_TO_DIGITS[data.len() % 7];
340 // 17 decimal numbers per 7bytes + remainder.
341 17 * (data.len() / 7) + last_chars
342 }
343 }
344 }
345
get_length_field(&self, version: Version) -> (u16, usize)346 fn get_length_field(&self, version: Version) -> (u16, usize) {
347 (
348 self.character_count() as u16,
349 self.length_bits_count(version),
350 )
351 }
352
total_size_bits(&self, version: Version) -> usize353 fn total_size_bits(&self, version: Version) -> usize {
354 let data_size = match self {
355 Segment::Binary(data) => data.len() * 8,
356 Segment::Numeric(_) => {
357 let digits = self.character_count();
358 10 * (digits / 3) + NUM_CHARS_BITS[digits % 3]
359 }
360 };
361 // header + length + data.
362 4 + self.length_bits_count(version) + data_size
363 }
364
iter(&self) -> SegmentIterator<'_>365 fn iter(&self) -> SegmentIterator<'_> {
366 SegmentIterator {
367 segment: self,
368 offset: 0,
369 carry: 0,
370 carry_len: 0,
371 }
372 }
373 }
374
375 struct SegmentIterator<'a> {
376 segment: &'a Segment<'a>,
377 offset: usize,
378 carry: u64,
379 carry_len: usize,
380 }
381
382 impl Iterator for SegmentIterator<'_> {
383 type Item = (u16, usize);
384
next(&mut self) -> Option<Self::Item>385 fn next(&mut self) -> Option<Self::Item> {
386 match self.segment {
387 Segment::Binary(data) => {
388 if self.offset < data.len() {
389 let byte = data[self.offset] as u16;
390 self.offset += 1;
391 Some((byte, 8))
392 } else {
393 None
394 }
395 }
396 Segment::Numeric(data) => {
397 if self.carry_len < 3 && self.offset < data.len() {
398 // If there are less than 3 decimal digits in the carry,
399 // take the next 7 bytes of input, and add them to the carry.
400 let mut buf = [0u8; 8];
401 let len = 7.min(data.len() - self.offset);
402 buf[..len].copy_from_slice(&data[self.offset..self.offset + len]);
403 let chunk = u64::from_le_bytes(buf);
404 let pow = u64::pow(10, BYTES_TO_DIGITS[len] as u32);
405 self.carry = chunk + self.carry * pow;
406 self.offset += len;
407 self.carry_len += BYTES_TO_DIGITS[len];
408 }
409 match self.carry_len {
410 0 => None,
411 len => {
412 // take the next 3 decimal digits of the carry
413 // and return 10bits of numeric data.
414 let out_len = 3.min(len);
415 self.carry_len -= out_len;
416 let pow = u64::pow(10, self.carry_len as u32);
417 let out = (self.carry / pow) as u16;
418 self.carry = self.carry % pow;
419 Some((out, NUM_CHARS_BITS[out_len]))
420 }
421 }
422 }
423 }
424 }
425 }
426
427 struct EncodedMsg<'a> {
428 data: &'a mut [u8],
429 ec_size: usize,
430 g1_blocks: usize,
431 g2_blocks: usize,
432 g1_blk_size: usize,
433 g2_blk_size: usize,
434 poly: &'static [u8],
435 version: Version,
436 }
437
438 /// Data to be put in the QR code, with correct segment encoding, padding, and
439 /// Error Code Correction.
440 impl EncodedMsg<'_> {
new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>>441 fn new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> {
442 let version = Version::from_segments(segments)?;
443 let ec_size = version.ec_size();
444 let g1_blocks = version.g1_blocks();
445 let g2_blocks = version.g2_blocks();
446 let g1_blk_size = version.g1_blk_size();
447 let g2_blk_size = g1_blk_size + 1;
448 let poly = version.poly();
449
450 // clear the output.
451 data.fill(0);
452
453 let mut em = EncodedMsg {
454 data,
455 ec_size,
456 g1_blocks,
457 g2_blocks,
458 g1_blk_size,
459 g2_blk_size,
460 poly,
461 version,
462 };
463 em.encode(segments);
464 Some(em)
465 }
466
467 /// Push bits of data at an offset (in bits).
push(&mut self, offset: &mut usize, bits: (u16, usize))468 fn push(&mut self, offset: &mut usize, bits: (u16, usize)) {
469 let (number, len_bits) = bits;
470 let byte_off = *offset / 8;
471 let bit_off = *offset % 8;
472 let b = bit_off + len_bits;
473
474 match (bit_off, b) {
475 (0, 0..=8) => {
476 self.data[byte_off] = (number << (8 - b)) as u8;
477 }
478 (0, _) => {
479 self.data[byte_off] = (number >> (b - 8)) as u8;
480 self.data[byte_off + 1] = (number << (16 - b)) as u8;
481 }
482 (_, 0..=8) => {
483 self.data[byte_off] |= (number << (8 - b)) as u8;
484 }
485 (_, 9..=16) => {
486 self.data[byte_off] |= (number >> (b - 8)) as u8;
487 self.data[byte_off + 1] = (number << (16 - b)) as u8;
488 }
489 _ => {
490 self.data[byte_off] |= (number >> (b - 8)) as u8;
491 self.data[byte_off + 1] = (number >> (b - 16)) as u8;
492 self.data[byte_off + 2] = (number << (24 - b)) as u8;
493 }
494 }
495 *offset += len_bits;
496 }
497
add_segments(&mut self, segments: &[&Segment<'_>])498 fn add_segments(&mut self, segments: &[&Segment<'_>]) {
499 let mut offset: usize = 0;
500
501 for s in segments.iter() {
502 self.push(&mut offset, s.get_header());
503 self.push(&mut offset, s.get_length_field(self.version));
504 for bits in s.iter() {
505 self.push(&mut offset, bits);
506 }
507 }
508 self.push(&mut offset, (MODE_STOP, 4));
509
510 let pad_offset = offset.div_ceil(8);
511 for i in pad_offset..self.version.max_data() {
512 self.data[i] = PADDING[(i & 1) ^ (pad_offset & 1)];
513 }
514 }
515
error_code_for_blocks(&mut self, offset: usize, size: usize, ec_offset: usize)516 fn error_code_for_blocks(&mut self, offset: usize, size: usize, ec_offset: usize) {
517 let mut tmp: [u8; MAX_BLK_SIZE + MAX_EC_SIZE] = [0; MAX_BLK_SIZE + MAX_EC_SIZE];
518
519 tmp[0..size].copy_from_slice(&self.data[offset..offset + size]);
520 for i in 0..size {
521 let lead_coeff = tmp[i] as usize;
522 if lead_coeff == 0 {
523 continue;
524 }
525 let log_lead_coeff = usize::from(LOG_TABLE[lead_coeff]);
526 for (u, &v) in tmp[i + 1..].iter_mut().zip(self.poly.iter()) {
527 *u ^= EXP_TABLE[(usize::from(v) + log_lead_coeff) % 255];
528 }
529 }
530 self.data[ec_offset..ec_offset + self.ec_size]
531 .copy_from_slice(&tmp[size..size + self.ec_size]);
532 }
533
compute_error_code(&mut self)534 fn compute_error_code(&mut self) {
535 let mut offset = 0;
536 let mut ec_offset = self.g1_blocks * self.g1_blk_size + self.g2_blocks * self.g2_blk_size;
537
538 for _ in 0..self.g1_blocks {
539 self.error_code_for_blocks(offset, self.g1_blk_size, ec_offset);
540 offset += self.g1_blk_size;
541 ec_offset += self.ec_size;
542 }
543 for _ in 0..self.g2_blocks {
544 self.error_code_for_blocks(offset, self.g2_blk_size, ec_offset);
545 offset += self.g2_blk_size;
546 ec_offset += self.ec_size;
547 }
548 }
549
encode(&mut self, segments: &[&Segment<'_>])550 fn encode(&mut self, segments: &[&Segment<'_>]) {
551 self.add_segments(segments);
552 self.compute_error_code();
553 }
554
iter(&self) -> EncodedMsgIterator<'_>555 fn iter(&self) -> EncodedMsgIterator<'_> {
556 EncodedMsgIterator {
557 em: self,
558 offset: 0,
559 }
560 }
561 }
562
563 /// Iterator, to retrieve the data in the interleaved order needed by QR code.
564 struct EncodedMsgIterator<'a> {
565 em: &'a EncodedMsg<'a>,
566 offset: usize,
567 }
568
569 impl Iterator for EncodedMsgIterator<'_> {
570 type Item = u8;
571
572 // Send the bytes in interleaved mode, first byte of first block of group1,
573 // then first byte of second block of group1, ...
next(&mut self) -> Option<Self::Item>574 fn next(&mut self) -> Option<Self::Item> {
575 let em = self.em;
576 let blocks = em.g1_blocks + em.g2_blocks;
577 let g1_end = em.g1_blocks * em.g1_blk_size;
578 let g2_end = g1_end + em.g2_blocks * em.g2_blk_size;
579 let ec_end = g2_end + em.ec_size * blocks;
580
581 if self.offset >= ec_end {
582 return None;
583 }
584
585 let offset = if self.offset < em.g1_blk_size * blocks {
586 // group1 and group2 interleaved
587 let blk = self.offset % blocks;
588 let blk_off = self.offset / blocks;
589 if blk < em.g1_blocks {
590 blk * em.g1_blk_size + blk_off
591 } else {
592 g1_end + em.g2_blk_size * (blk - em.g1_blocks) + blk_off
593 }
594 } else if self.offset < g2_end {
595 // last byte of group2 blocks
596 let blk2 = self.offset - blocks * em.g1_blk_size;
597 em.g1_blk_size * em.g1_blocks + blk2 * em.g2_blk_size + em.g2_blk_size - 1
598 } else {
599 // EC blocks
600 let ec_offset = self.offset - g2_end;
601 let blk = ec_offset % blocks;
602 let blk_off = ec_offset / blocks;
603
604 g2_end + blk * em.ec_size + blk_off
605 };
606 self.offset += 1;
607 Some(em.data[offset])
608 }
609 }
610
611 /// A QR code image, encoded as a linear binary framebuffer.
612 /// 1 bit per module (pixel), each new line start at next byte boundary.
613 /// Max width is 177 for V40 QR code, so `u8` is enough for coordinate.
614 struct QrImage<'a> {
615 data: &'a mut [u8],
616 width: u8,
617 stride: u8,
618 version: Version,
619 }
620
621 impl QrImage<'_> {
new<'a, 'b>(em: &'b EncodedMsg<'b>, qrdata: &'a mut [u8]) -> QrImage<'a>622 fn new<'a, 'b>(em: &'b EncodedMsg<'b>, qrdata: &'a mut [u8]) -> QrImage<'a> {
623 let width = em.version.width();
624 let stride = width.div_ceil(8);
625 let data = qrdata;
626
627 let mut qr_image = QrImage {
628 data,
629 width,
630 stride,
631 version: em.version,
632 };
633 qr_image.draw_all(em.iter());
634 qr_image
635 }
636
clear(&mut self)637 fn clear(&mut self) {
638 self.data.fill(0);
639 }
640
641 // Set pixel to light color.
set(&mut self, x: u8, y: u8)642 fn set(&mut self, x: u8, y: u8) {
643 let off = y as usize * self.stride as usize + x as usize / 8;
644 let mut v = self.data[off];
645 v |= 0x80 >> (x % 8);
646 self.data[off] = v;
647 }
648
649 // Invert a module color.
xor(&mut self, x: u8, y: u8)650 fn xor(&mut self, x: u8, y: u8) {
651 let off = y as usize * self.stride as usize + x as usize / 8;
652 self.data[off] ^= 0x80 >> (x % 8);
653 }
654
655 // Draw a light square at (x, y) top left corner.
draw_square(&mut self, x: u8, y: u8, size: u8)656 fn draw_square(&mut self, x: u8, y: u8, size: u8) {
657 for k in 0..size {
658 self.set(x + k, y);
659 self.set(x, y + k + 1);
660 self.set(x + size, y + k);
661 self.set(x + k + 1, y + size);
662 }
663 }
664
665 // Finder pattern: 3 8x8 square at the corners.
draw_finders(&mut self)666 fn draw_finders(&mut self) {
667 self.draw_square(1, 1, 4);
668 self.draw_square(self.width - 6, 1, 4);
669 self.draw_square(1, self.width - 6, 4);
670 for k in 0..8 {
671 self.set(k, 7);
672 self.set(self.width - k - 1, 7);
673 self.set(k, self.width - 8);
674 }
675 for k in 0..7 {
676 self.set(7, k);
677 self.set(self.width - 8, k);
678 self.set(7, self.width - 1 - k);
679 }
680 }
681
is_finder(&self, x: u8, y: u8) -> bool682 fn is_finder(&self, x: u8, y: u8) -> bool {
683 let end = self.width - 8;
684 #[expect(clippy::nonminimal_bool)]
685 {
686 (x < 8 && y < 8) || (x < 8 && y >= end) || (x >= end && y < 8)
687 }
688 }
689
690 // Alignment pattern: 5x5 squares in a grid.
draw_alignments(&mut self)691 fn draw_alignments(&mut self) {
692 let positions = self.version.alignment_pattern();
693 for &x in positions.iter() {
694 for &y in positions.iter() {
695 if !self.is_finder(x, y) {
696 self.draw_square(x - 1, y - 1, 2);
697 }
698 }
699 }
700 }
701
is_alignment(&self, x: u8, y: u8) -> bool702 fn is_alignment(&self, x: u8, y: u8) -> bool {
703 let positions = self.version.alignment_pattern();
704 for &ax in positions.iter() {
705 for &ay in positions.iter() {
706 if self.is_finder(ax, ay) {
707 continue;
708 }
709 if x >= ax - 2 && x <= ax + 2 && y >= ay - 2 && y <= ay + 2 {
710 return true;
711 }
712 }
713 }
714 false
715 }
716
717 // Timing pattern: 2 dotted line between the finder patterns.
draw_timing_patterns(&mut self)718 fn draw_timing_patterns(&mut self) {
719 let end = self.width - 8;
720
721 for x in (9..end).step_by(2) {
722 self.set(x, 6);
723 self.set(6, x);
724 }
725 }
726
is_timing(&self, x: u8, y: u8) -> bool727 fn is_timing(&self, x: u8, y: u8) -> bool {
728 x == 6 || y == 6
729 }
730
731 // Mask info: 15 bits around the finders, written twice for redundancy.
draw_maskinfo(&mut self)732 fn draw_maskinfo(&mut self) {
733 let info: u16 = FORMAT_INFOS_QR_L[0];
734 let mut skip = 0;
735
736 for k in 0..7 {
737 if k == 6 {
738 skip = 1;
739 }
740 if info & (1 << (14 - k)) == 0 {
741 self.set(k + skip, 8);
742 self.set(8, self.width - 1 - k);
743 }
744 }
745 skip = 0;
746 for k in 0..8 {
747 if k == 2 {
748 skip = 1;
749 }
750 if info & (1 << (7 - k)) == 0 {
751 self.set(8, 8 - skip - k);
752 self.set(self.width - 8 + k, 8);
753 }
754 }
755 }
756
is_maskinfo(&self, x: u8, y: u8) -> bool757 fn is_maskinfo(&self, x: u8, y: u8) -> bool {
758 let end = self.width - 8;
759 // Count the dark module as mask info.
760 (x <= 8 && y == 8) || (y <= 8 && x == 8) || (x == 8 && y >= end) || (x >= end && y == 8)
761 }
762
763 // Version info: 18bits written twice, close to the finders.
draw_version_info(&mut self)764 fn draw_version_info(&mut self) {
765 let vinfo = self.version.version_info();
766 let pos = self.width - 11;
767
768 if vinfo != 0 {
769 for x in 0..3 {
770 for y in 0..6 {
771 if vinfo & (1 << (x + y * 3)) == 0 {
772 self.set(x + pos, y);
773 self.set(y, x + pos);
774 }
775 }
776 }
777 }
778 }
779
is_version_info(&self, x: u8, y: u8) -> bool780 fn is_version_info(&self, x: u8, y: u8) -> bool {
781 let vinfo = self.version.version_info();
782 let pos = self.width - 11;
783
784 vinfo != 0 && ((x >= pos && x < pos + 3 && y < 6) || (y >= pos && y < pos + 3 && x < 6))
785 }
786
787 // Returns true if the module is reserved (Not usable for data and EC).
is_reserved(&self, x: u8, y: u8) -> bool788 fn is_reserved(&self, x: u8, y: u8) -> bool {
789 self.is_alignment(x, y)
790 || self.is_finder(x, y)
791 || self.is_timing(x, y)
792 || self.is_maskinfo(x, y)
793 || self.is_version_info(x, y)
794 }
795
796 // Last module to draw, at bottom left corner.
is_last(&self, x: u8, y: u8) -> bool797 fn is_last(&self, x: u8, y: u8) -> bool {
798 x == 0 && y == self.width - 1
799 }
800
801 // Move to the next module according to QR code order.
802 // From bottom right corner, to bottom left corner.
next(&self, x: u8, y: u8) -> (u8, u8)803 fn next(&self, x: u8, y: u8) -> (u8, u8) {
804 let x_adj = if x <= 6 { x + 1 } else { x };
805 let column_type = (self.width - x_adj) % 4;
806
807 match column_type {
808 2 if y > 0 => (x + 1, y - 1),
809 0 if y < self.width - 1 => (x + 1, y + 1),
810 0 | 2 if x == 7 => (x - 2, y),
811 _ => (x - 1, y),
812 }
813 }
814
815 // Find next module that can hold data.
next_available(&self, x: u8, y: u8) -> (u8, u8)816 fn next_available(&self, x: u8, y: u8) -> (u8, u8) {
817 let (mut x, mut y) = self.next(x, y);
818 while self.is_reserved(x, y) && !self.is_last(x, y) {
819 (x, y) = self.next(x, y);
820 }
821 (x, y)
822 }
823
draw_data(&mut self, data: impl Iterator<Item = u8>)824 fn draw_data(&mut self, data: impl Iterator<Item = u8>) {
825 let (mut x, mut y) = (self.width - 1, self.width - 1);
826 for byte in data {
827 for s in 0..8 {
828 if byte & (0x80 >> s) == 0 {
829 self.set(x, y);
830 }
831 (x, y) = self.next_available(x, y);
832 }
833 }
834 // Set the remaining modules (0, 3 or 7 depending on version).
835 // because 0 correspond to a light module.
836 while !self.is_last(x, y) {
837 if !self.is_reserved(x, y) {
838 self.set(x, y);
839 }
840 (x, y) = self.next(x, y);
841 }
842 }
843
844 // Apply checkerboard mask to all non-reserved modules.
apply_mask(&mut self)845 fn apply_mask(&mut self) {
846 for x in 0..self.width {
847 for y in 0..self.width {
848 if (x ^ y) % 2 == 0 && !self.is_reserved(x, y) {
849 self.xor(x, y);
850 }
851 }
852 }
853 }
854
855 // Draw the QR code with the provided data iterator.
draw_all(&mut self, data: impl Iterator<Item = u8>)856 fn draw_all(&mut self, data: impl Iterator<Item = u8>) {
857 // First clear the table, as it may have already some data.
858 self.clear();
859 self.draw_finders();
860 self.draw_alignments();
861 self.draw_timing_patterns();
862 self.draw_version_info();
863 self.draw_data(data);
864 self.draw_maskinfo();
865 self.apply_mask();
866 }
867 }
868
869 /// C entry point for the rust QR Code generator.
870 ///
871 /// Write the QR code image in the data buffer, and return the QR code width,
872 /// or 0, if the data doesn't fit in a QR code.
873 ///
874 /// * `url`: The base URL of the QR code. It will be encoded as Binary segment.
875 /// * `data`: A pointer to the binary data, to be encoded. if URL is NULL, it
876 /// will be encoded as binary segment, otherwise it will be encoded
877 /// efficiently as a numeric segment, and appended to the URL.
878 /// * `data_len`: Length of the data, that needs to be encoded, must be less
879 /// than data_size.
880 /// * `data_size`: Size of data buffer, it should be at least 4071 bytes to hold
881 /// a V40 QR code. It will then be overwritten with the QR code image.
882 /// * `tmp`: A temporary buffer that the QR code encoder will use, to write the
883 /// segments and ECC.
884 /// * `tmp_size`: Size of the temporary buffer, it must be at least 3706 bytes
885 /// long for V40.
886 ///
887 /// # Safety
888 ///
889 /// * `url` must be null or point at a nul-terminated string.
890 /// * `data` must be valid for reading and writing for `data_size` bytes.
891 /// * `tmp` must be valid for reading and writing for `tmp_size` bytes.
892 ///
893 /// They must remain valid for the duration of the function call.
894 #[export]
drm_panic_qr_generate( url: *const kernel::ffi::c_char, data: *mut u8, data_len: usize, data_size: usize, tmp: *mut u8, tmp_size: usize, ) -> u8895 pub unsafe extern "C" fn drm_panic_qr_generate(
896 url: *const kernel::ffi::c_char,
897 data: *mut u8,
898 data_len: usize,
899 data_size: usize,
900 tmp: *mut u8,
901 tmp_size: usize,
902 ) -> u8 {
903 if data_size < 4071 || tmp_size < 3706 || data_len > data_size {
904 return 0;
905 }
906 // SAFETY: The caller ensures that `data` is a valid pointer for reading and
907 // writing `data_size` bytes.
908 let data_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(data, data_size) };
909 // SAFETY: The caller ensures that `tmp` is a valid pointer for reading and
910 // writing `tmp_size` bytes.
911 let tmp_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(tmp, tmp_size) };
912 if url.is_null() {
913 match EncodedMsg::new(&[&Segment::Binary(&data_slice[0..data_len])], tmp_slice) {
914 None => 0,
915 Some(em) => {
916 let qr_image = QrImage::new(&em, data_slice);
917 qr_image.width
918 }
919 }
920 } else {
921 // SAFETY: The caller ensures that `url` is a valid pointer to a
922 // nul-terminated string.
923 let url_cstr: &CStr = unsafe { CStr::from_char_ptr(url) };
924 let segments = &[
925 &Segment::Binary(url_cstr.as_bytes()),
926 &Segment::Numeric(&data_slice[0..data_len]),
927 ];
928 match EncodedMsg::new(segments, tmp_slice) {
929 None => 0,
930 Some(em) => {
931 let qr_image = QrImage::new(&em, data_slice);
932 qr_image.width
933 }
934 }
935 }
936 }
937
938 /// Returns the maximum data size that can fit in a QR code of this version.
939 /// * `version`: QR code version, between 1-40.
940 /// * `url_len`: Length of the URL.
941 ///
942 /// * If `url_len` > 0, remove the 2 segments header/length and also count the
943 /// conversion to numeric segments.
944 /// * If `url_len` = 0, only removes 3 bytes for 1 binary segment.
945 ///
946 /// # Safety
947 ///
948 /// Always safe to call.
949 // Required to be unsafe due to the `#[export]` annotation.
950 #[export]
drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize951 pub unsafe extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize {
952 #[expect(clippy::manual_range_contains)]
953 if version < 1 || version > 40 {
954 return 0;
955 }
956 let max_data = Version(version as usize).max_data();
957
958 if url_len > 0 {
959 // Binary segment (URL) 4 + 16 bits, numeric segment (kmsg) 4 + 12 bits => 5 bytes.
960 if url_len + 5 >= max_data {
961 0
962 } else {
963 let max = max_data - url_len - 5;
964 (max * 39) / 40
965 }
966 } else {
967 // Remove 3 bytes for the binary segment (header 4 bits, length 16 bits, stop 4bits).
968 max_data - 3
969 }
970 }
971