From 55258187ed330dbd4cbb8a0690e6a15f5be3df2f Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 15 Mar 2026 22:03:07 +0300 Subject: [PATCH 01/21] feature: add manually input bytes for generate numbers; connect driver with special GF library --- .gitignore | 8 +++ Makefile | 4 +- prandom.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 182 insertions(+), 22 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba5ce58 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.gfrandom.mod.cmd +compile_commands.json +gfrandom.mod +.cache +LICENSE +.clang-format +lib.c +lib.h \ No newline at end of file diff --git a/Makefile b/Makefile index 25861e7..a91cf40 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -obj-m += prandom.o +obj-m += gfrandom.o +gfrandom-objs := prandom.o lib.o KDIR := /lib/modules/$(shell uname -r)/build - PWD := $(shell pwd) all: diff --git a/prandom.c b/prandom.c index 7d3b415..e5a0a3a 100644 --- a/prandom.c +++ b/prandom.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later /* - * prandom – misc-драйвер, предоставляющий случайные данные, аналогично /dev/urandom + * prandom – misc-драйвер, предоставляющий случайные данные, аналогично + * /dev/urandom * * Copyright (C) 2025 Makar Lill * @@ -18,30 +19,171 @@ * along with this program. If not, see . */ -#include -#include #include +#include #include +#include +#include +#include #include -#define DEVICE_NAME "prandom" +#include "asm-generic/errno-base.h" +#include "lib.h" + +#define DEVICE_NAME "gfrandom" +#define POLY_DEGREE 256 +#define GF256_ONE (GF256_t)0x01 +#define GF256_DEGREES_AUTO {0, 2, 5, 10, 255} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Makar Lill"); +MODULE_DESCRIPTION("Analogue of /dev/urandom"); + +struct gf256_gprn +{ + GF256_t coeff[POLY_DEGREE]; + GF256_t t[POLY_DEGREE]; + int index; +}; -static ssize_t misc_read(struct file *filp, char __user *buf, size_t length, - loff_t *f_pos) +static struct gf256_gprn* global_gprn = NULL; + +static char* coeff_file = NULL; +static char* polynom_file = NULL; + +static int read_file_bytes(char* filename, GF256_t* row, size_t size) { - u8 kernel_buf[256]; - size_t bytes_to_read = length; - size_t chunk; + if (!filename || !row) + return !EINVAL; + + struct file* f = filp_open(filename, O_RDONLY, 0); + if (IS_ERR(f)) + return PTR_ERR(f); + + loff_t pos = 0; + int res = kernel_read(f, row, size, &pos); + filp_close(f, NULL); + + if (res != size) + return (res < 0) ? res : -EIO; + + return 0; +} + +static void gf256_gprn_init_t(struct gf256_gprn* gprn) +{ + int i; + + // read bytes from coeff file + if (coeff_file) + { + int res = read_file_bytes(coeff_file, gprn->coeff, sizeof(gprn->coeff)); + if (res != 0) + { + goto generate_coeffs; + } + } + else + { + generate_coeffs: + get_random_bytes(gprn->coeff, sizeof(gprn->coeff)); + + int all_zero = 1; + for (i = 0; i < POLY_DEGREE; i++) + { + if (gprn->coeff[i] != 0) + { + all_zero = 0; + break; + } + } + if (all_zero) + { + gprn->coeff[0] = GF256_ONE; + } + } + + // read bytes from polynom file + if (polynom_file) + { + int res = read_file_bytes(polynom_file, gprn->t, sizeof(gprn->t)); + if (res != 0) + { + goto default_polynom; + } + } + else + { + default_polynom: + for (i = 0; i < POLY_DEGREE; i++) + { + gprn->t[i] = 0; + } - while (bytes_to_read > 0) { + // we use polynom t^256 + t^10 + t^5 + t^2 + 1 + const int degrees[] = GF256_DEGREES_AUTO; + + for (int i = 0; i < ARRAY_SIZE(degrees); i++) + { + gprn->t[degrees[i]] = GF256_ONE; + } + } + + gprn->index = 0; +} + +static GF256_t gf256_gprn_next(struct gf256_gprn* gprn) +{ + GF256_t new_byte = 0; + int idx; + int i; + + for (i = 0; i < POLY_DEGREE; i++) + { + if (gprn->t[i] != 0) + { + idx = (gprn->index + i) % POLY_DEGREE; + new_byte = GF256_Add(new_byte, GF256_Mul(gprn->t[i], gprn->coeff[idx])); + } + } + + // "circular" array + gprn->coeff[gprn->index] = new_byte; + gprn->index = (gprn->index + 1) % POLY_DEGREE; + + return new_byte; +} + +static void gf256_gprn_generate(struct gf256_gprn* gprn, size_t count, GF256_t* output) +{ + size_t i; + for (i = 0; i < count; i++) + { + output[i] = gf256_gprn_next(gprn); + } +} + +static ssize_t misc_read(struct file* filp, char __user* buf, size_t length, loff_t* f_pos) +{ + GF256_t kernel_buf[256]; + size_t bytes_to_read = length; + size_t chunk; + + if (!global_gprn) + return -ENODEV; + + while (bytes_to_read > 0) + { chunk = min(bytes_to_read, sizeof(kernel_buf)); - get_random_bytes(kernel_buf, chunk); + + gf256_gprn_generate(global_gprn, chunk, kernel_buf); if (copy_to_user(buf, kernel_buf, chunk)) return -EFAULT; buf += chunk; bytes_to_read -= chunk; + *f_pos += chunk; } return length; @@ -49,19 +191,27 @@ static ssize_t misc_read(struct file *filp, char __user *buf, size_t length, static const struct file_operations fops = { .owner = THIS_MODULE, - .read = misc_read, + .read = misc_read, }; static struct miscdevice prandom_misc = { .minor = MISC_DYNAMIC_MINOR, - .name = DEVICE_NAME, - .fops = &fops, + .name = DEVICE_NAME, + .fops = &fops, }; static int __init misc_init(void) { + global_gprn = kmalloc(sizeof(struct gf256_gprn), GFP_KERNEL); + if (!global_gprn) + return -ENOMEM; + + gf256_gprn_init_t(global_gprn); + int err = misc_register(&prandom_misc); - if (err != 0) { + if (err != 0) + { + kfree(global_gprn); return err; } @@ -70,12 +220,14 @@ static int __init misc_init(void) static void __exit misc_exit(void) { + kfree(global_gprn); misc_deregister(&prandom_misc); } -module_init(misc_init); -module_exit(misc_exit); +module_param(coeff_file, charp, 0); +MODULE_PARM_DESC(coeff_file, "path to file with bytes for coefficients"); +module_param(polynom_file, charp, 0); +MODULE_PARM_DESC(polynom_file, "path to file with bytes for polynom"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Makar Lill"); -MODULE_DESCRIPTION("Analogue of /dev/urandom"); \ No newline at end of file +module_init(misc_init); +module_exit(misc_exit); \ No newline at end of file From c9b2278b07892a662d928870494b5c0d4fa26d94 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 15 Mar 2026 22:12:41 +0300 Subject: [PATCH 02/21] Add Galois Field library by Denis Potapov - Add GF(256) arithmetic library for prandom driver (lib.c / lib.h) - Original author: Denis Potapov - Added with GPL-3.0 compatibility headers - See ACKNOWLEDGMENTS for details Signed-off-by: Makar Lill --- lib.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib.h | 14 +++++++++ 2 files changed, 105 insertions(+) create mode 100644 lib.c create mode 100644 lib.h diff --git a/lib.c b/lib.c new file mode 100644 index 0000000..b2db982 --- /dev/null +++ b/lib.c @@ -0,0 +1,91 @@ + +#include "lib.h" + +#define ORDER 256 + +uint16_t Module = 0x11B; + +GF256_t alogs[ORDER]; +GF256_t logs[ORDER]; + +u8 ready_to_work = 0; + +void GF256_init(void) +{ + GF256_t g = 0x03; + GF256_t x = 1; + + for (int i = 0; i < ORDER - 1; i++) + { + alogs[i] = x; + logs[x] = i; + + u16 prod = x << 1; + if (prod & 0x100) + { + prod ^= Module; + } + prod ^= x; + x = (GF256_t)(prod & 0xFF); + } + alogs[ORDER - 1] = alogs[0]; + logs[0] = 0; + + ready_to_work = 1; +} + +GF256_t GF256_Add(GF256_t a, GF256_t b) +{ + return a ^ b; +} + +GF256_t GF256_Sub(GF256_t a, GF256_t b) +{ + return a ^ b; +} + +GF256_t GF256_Mul(GF256_t a, GF256_t b) +{ + if (!ready_to_work) + { + GF256_init(); + } + + if (a == 0 || b == 0) + { + return 0; + } + + u8 log_a = logs[a]; + u8 log_b = logs[b]; + + u8 sum = 0; + if ((u8)(ORDER - 1) - log_a < log_b) + { + sum = log_a - (ORDER - 1 - log_b); + } + else + { + sum = log_a + log_b; + } + + return alogs[sum]; +} + +static GF256_t inverse_mul_element(GF256_t a) +{ + if (!ready_to_work) + { + GF256_init(); + } + if (a == 0) + { + return 0; + } + return alogs[255 - logs[a]]; +} + +GF256_t GF256_Div(GF256_t a, GF256_t b) +{ + return GF256_Mul(a, inverse_mul_element(b)); +} diff --git a/lib.h b/lib.h new file mode 100644 index 0000000..a073329 --- /dev/null +++ b/lib.h @@ -0,0 +1,14 @@ +#ifndef LIB_H +#define LIB_H + +#include + +#define GF256_t u8 + +void GF256_init(void); +GF256_t GF256_Add(GF256_t a, GF256_t b); +GF256_t GF256_Sub(GF256_t a, GF256_t b); +GF256_t GF256_Mul(GF256_t a, GF256_t b); +GF256_t GF256_Div(GF256_t a, GF256_t b); + +#endif \ No newline at end of file From 9ef641d3f8c81c56aacb4ed8a3d56203be646593 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 15 Mar 2026 22:14:52 +0300 Subject: [PATCH 03/21] feature: add bin files with manually bytes input for tests --- test-files/coeff_file.bin | 2 ++ test-files/polynom_file.bin | Bin 0 -> 252 bytes 2 files changed, 2 insertions(+) create mode 100644 test-files/coeff_file.bin create mode 100644 test-files/polynom_file.bin diff --git a/test-files/coeff_file.bin b/test-files/coeff_file.bin new file mode 100644 index 0000000..3d73e6f --- /dev/null +++ b/test-files/coeff_file.bin @@ -0,0 +1,2 @@ +c}zzs/lbڠ~Ioq#7.[/> fcijS#a9 AJ$f6ˌa+l` ]$a{{o2 g~[ebQ0Y2heA}'S }yx2юm +LlFdՕ^d.7ubm@QBo"iR.D<"S \ No newline at end of file diff --git a/test-files/polynom_file.bin b/test-files/polynom_file.bin new file mode 100644 index 0000000000000000000000000000000000000000..e563af65e48f134cdb5fb7efca9cd6048fb16383 GIT binary patch literal 252 TcmZQ%U}OLxC;?)O6u<}o1l#}y literal 0 HcmV?d00001 From 8269c8e77be9504857036f47bc52347961739f4f Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Tue, 17 Mar 2026 16:10:51 +0300 Subject: [PATCH 04/21] feature-n-refactor: SMALL CHANGES DENIS POTAPOV LIBRARY (WITH PERMISSION, TEMPORARILY); separate algorithm of driver from misc-logic driver; add tests (build driver and 1 simple test); add CI --- .github/workflows/ci.yml | 20 +++ Makefile | 12 +- driver.c | 203 ++++++++++++++++++++++++++ lib.c | 23 +-- lib.h | 8 +- prandom.c | 284 +++++++----------------------------- prandom.h | 29 ++++ test-files/expected1.bin | 1 + test-files/polynom_file.bin | Bin 252 -> 256 bytes test.c | 80 ++++++++++ 10 files changed, 414 insertions(+), 246 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 driver.c create mode 100644 prandom.h create mode 100644 test-files/expected1.bin create mode 100644 test.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..dc9ad3e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,20 @@ +name: Simple driver tests + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: sudo apt-get update && sudo apt-get install -y gcc make + + - name: Build driver + run: make + + - name: Build test + run: make test_algo + + - name: Run test + run: make test \ No newline at end of file diff --git a/Makefile b/Makefile index a91cf40..0e5d096 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ obj-m += gfrandom.o -gfrandom-objs := prandom.o lib.o +gfrandom-objs := driver.o prandom.o lib.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) @@ -8,4 +8,12 @@ all: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: - $(MAKE) -C $(KDIR) M=$(PWD) clean \ No newline at end of file + $(MAKE) -C $(KDIR) M=$(PWD) clean + +test_algo: test.c lib.c prandom.c + gcc -o test test.c lib.c prandom.c -I. + +test: test_algo + ./test + +.PHONY: all clean test test \ No newline at end of file diff --git a/driver.c b/driver.c new file mode 100644 index 0000000..13bf073 --- /dev/null +++ b/driver.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + * prandom – misc-драйвер, предоставляющий случайные данные, аналогично + * /dev/urandom + * + * Copyright (C) 2026 Makar Lill + * + * This driver uses Galois Field arithmetic library written by Denis Potapov + * (lib.c / lib.h). Used with permission. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "asm-generic/errno-base.h" +#include "lib.h" +#include "prandom.h" + +#define DEVICE_NAME "gfrandom" + +MODULE_LICENSE("GPL-3.0"); +MODULE_AUTHOR("Makar Lill"); +MODULE_DESCRIPTION("Analogue of /dev/urandom"); + +struct gf256_gprn* global_gprn = NULL; + +static char* coeff_file = NULL; +static char* polynom_file = NULL; + +static int read_file_bytes(char* filename, GF256_t* row, size_t size) +{ + if (!filename || !row) + return !EINVAL; + + struct file* f = filp_open(filename, O_RDONLY, 0); + if (IS_ERR(f)) + return PTR_ERR(f); + + loff_t pos = 0; + int res = kernel_read(f, row, size, &pos); + filp_close(f, NULL); + + if (res != size) + return (res < 0) ? res : -EIO; + + return 0; +} + +static void gprn_init_t(struct gf256_gprn* gprn) +{ + GF256_t coeff_data[POLY_DEGREE]; + GF256_t polynom_data[POLY_DEGREE]; + GF256_t *coeff_ptr = NULL, *polynom_ptr = NULL; + + int i; + + // read bytes from coeff file + if (coeff_file) + { + int res = read_file_bytes(coeff_file, coeff_data, sizeof(coeff_data)); + coeff_ptr = coeff_data; + if (res != 0) + { + goto get_random_coeffs; + } + } + else + { + get_random_coeffs: + get_random_bytes(coeff_data, sizeof(coeff_ptr)); + + int all_zero = 1; + for (i = 0; i < POLY_DEGREE; i++) + { + if (coeff_data[i] != 0) + { + all_zero = 0; + break; + } + } + if (all_zero) + { + coeff_data[0] = GF256_ONE; + } + coeff_ptr = coeff_data; + } + + // read bytes from polynom file + if (polynom_file) + { + int res = read_file_bytes(polynom_file, polynom_data, sizeof(polynom_data)); + polynom_ptr = polynom_data; + if (res != 0) + { + goto get_auto_polynom; + } + } + else + { + get_auto_polynom: + for (i = 0; i < POLY_DEGREE; i++) + { + polynom_data[i] = 0; + } + + // we use polynom t^256 + t^10 + t^5 + t^2 + 1 + const int degrees[] = GF256_DEGREES_AUTO; + for (i = 0; i < ARRAY_SIZE(degrees); i++) + { + polynom_data[degrees[i]] = GF256_ONE; + } + polynom_ptr = polynom_data; + } + + gf256_gprn_init_t(gprn, coeff_ptr, polynom_ptr); +} + +static ssize_t misc_read(struct file* filp, char __user* buf, size_t length, loff_t* f_pos) +{ + GF256_t kernel_buf[256]; + size_t bytes_to_read = length; + size_t chunk; + + if (!global_gprn) + return -ENODEV; + + while (bytes_to_read > 0) + { + chunk = min(bytes_to_read, sizeof(kernel_buf)); + + gf256_gprn_generate(global_gprn, chunk, kernel_buf); + + if (copy_to_user(buf, kernel_buf, chunk)) + return -EFAULT; + + buf += chunk; + bytes_to_read -= chunk; + *f_pos += chunk; + } + + return length; +} + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .read = misc_read, +}; + +static struct miscdevice prandom_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = DEVICE_NAME, + .fops = &fops, +}; + +static int __init misc_init(void) +{ + global_gprn = kmalloc(sizeof(struct gf256_gprn), GFP_KERNEL); + if (!global_gprn) + return -ENOMEM; + + gprn_init_t(global_gprn); + + int err = misc_register(&prandom_misc); + if (err != 0) + { + kfree(global_gprn); + return err; + } + + return 0; +} + +static void __exit misc_exit(void) +{ + kfree(global_gprn); + misc_deregister(&prandom_misc); +} + +module_param(coeff_file, charp, 0); +MODULE_PARM_DESC(coeff_file, "path to file with bytes for coefficients"); +module_param(polynom_file, charp, 0); +MODULE_PARM_DESC(polynom_file, "path to file with bytes for polynom"); + +module_init(misc_init); +module_exit(misc_exit); \ No newline at end of file diff --git a/lib.c b/lib.c index b2db982..982622a 100644 --- a/lib.c +++ b/lib.c @@ -1,15 +1,20 @@ #include "lib.h" +#ifdef __KERNEL__ +#include +u16 Module = 0x11B; +u8 ready_to_work = 0; +#else +#include +uint16_t Module = 0x11B; +uint8_t ready_to_work = 0; +#endif #define ORDER 256 -uint16_t Module = 0x11B; - GF256_t alogs[ORDER]; GF256_t logs[ORDER]; -u8 ready_to_work = 0; - void GF256_init(void) { GF256_t g = 0x03; @@ -20,7 +25,7 @@ void GF256_init(void) alogs[i] = x; logs[x] = i; - u16 prod = x << 1; + uint16_t prod = x << 1; if (prod & 0x100) { prod ^= Module; @@ -56,11 +61,11 @@ GF256_t GF256_Mul(GF256_t a, GF256_t b) return 0; } - u8 log_a = logs[a]; - u8 log_b = logs[b]; + uint8_t log_a = logs[a]; + uint8_t log_b = logs[b]; - u8 sum = 0; - if ((u8)(ORDER - 1) - log_a < log_b) + uint8_t sum = 0; + if ((uint8_t)(ORDER - 1) - log_a < log_b) { sum = log_a - (ORDER - 1 - log_b); } diff --git a/lib.h b/lib.h index a073329..b51c074 100644 --- a/lib.h +++ b/lib.h @@ -1,9 +1,13 @@ #ifndef LIB_H #define LIB_H +#ifdef __KERNEL__ #include - -#define GF256_t u8 +typedef u8 GF256_t; +#else +#include +typedef uint8_t GF256_t; +#endif void GF256_init(void); GF256_t GF256_Add(GF256_t a, GF256_t b); diff --git a/prandom.c b/prandom.c index e5a0a3a..8456e7c 100644 --- a/prandom.c +++ b/prandom.c @@ -1,233 +1,51 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -/* - * prandom – misc-драйвер, предоставляющий случайные данные, аналогично - * /dev/urandom - * - * Copyright (C) 2025 Makar Lill - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "asm-generic/errno-base.h" -#include "lib.h" - -#define DEVICE_NAME "gfrandom" -#define POLY_DEGREE 256 -#define GF256_ONE (GF256_t)0x01 -#define GF256_DEGREES_AUTO {0, 2, 5, 10, 255} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Makar Lill"); -MODULE_DESCRIPTION("Analogue of /dev/urandom"); - -struct gf256_gprn -{ - GF256_t coeff[POLY_DEGREE]; - GF256_t t[POLY_DEGREE]; - int index; -}; - -static struct gf256_gprn* global_gprn = NULL; - -static char* coeff_file = NULL; -static char* polynom_file = NULL; - -static int read_file_bytes(char* filename, GF256_t* row, size_t size) -{ - if (!filename || !row) - return !EINVAL; - - struct file* f = filp_open(filename, O_RDONLY, 0); - if (IS_ERR(f)) - return PTR_ERR(f); - - loff_t pos = 0; - int res = kernel_read(f, row, size, &pos); - filp_close(f, NULL); - - if (res != size) - return (res < 0) ? res : -EIO; - - return 0; -} - -static void gf256_gprn_init_t(struct gf256_gprn* gprn) -{ - int i; - - // read bytes from coeff file - if (coeff_file) - { - int res = read_file_bytes(coeff_file, gprn->coeff, sizeof(gprn->coeff)); - if (res != 0) - { - goto generate_coeffs; - } - } - else - { - generate_coeffs: - get_random_bytes(gprn->coeff, sizeof(gprn->coeff)); - - int all_zero = 1; - for (i = 0; i < POLY_DEGREE; i++) - { - if (gprn->coeff[i] != 0) - { - all_zero = 0; - break; - } - } - if (all_zero) - { - gprn->coeff[0] = GF256_ONE; - } - } - - // read bytes from polynom file - if (polynom_file) - { - int res = read_file_bytes(polynom_file, gprn->t, sizeof(gprn->t)); - if (res != 0) - { - goto default_polynom; - } - } - else - { - default_polynom: - for (i = 0; i < POLY_DEGREE; i++) - { - gprn->t[i] = 0; - } - - // we use polynom t^256 + t^10 + t^5 + t^2 + 1 - const int degrees[] = GF256_DEGREES_AUTO; - - for (int i = 0; i < ARRAY_SIZE(degrees); i++) - { - gprn->t[degrees[i]] = GF256_ONE; - } - } - - gprn->index = 0; -} - -static GF256_t gf256_gprn_next(struct gf256_gprn* gprn) -{ - GF256_t new_byte = 0; - int idx; - int i; - - for (i = 0; i < POLY_DEGREE; i++) - { - if (gprn->t[i] != 0) - { - idx = (gprn->index + i) % POLY_DEGREE; - new_byte = GF256_Add(new_byte, GF256_Mul(gprn->t[i], gprn->coeff[idx])); - } - } - - // "circular" array - gprn->coeff[gprn->index] = new_byte; - gprn->index = (gprn->index + 1) % POLY_DEGREE; - - return new_byte; -} - -static void gf256_gprn_generate(struct gf256_gprn* gprn, size_t count, GF256_t* output) -{ - size_t i; - for (i = 0; i < count; i++) - { - output[i] = gf256_gprn_next(gprn); - } -} - -static ssize_t misc_read(struct file* filp, char __user* buf, size_t length, loff_t* f_pos) -{ - GF256_t kernel_buf[256]; - size_t bytes_to_read = length; - size_t chunk; - - if (!global_gprn) - return -ENODEV; - - while (bytes_to_read > 0) - { - chunk = min(bytes_to_read, sizeof(kernel_buf)); - - gf256_gprn_generate(global_gprn, chunk, kernel_buf); - - if (copy_to_user(buf, kernel_buf, chunk)) - return -EFAULT; - - buf += chunk; - bytes_to_read -= chunk; - *f_pos += chunk; - } - - return length; -} - -static const struct file_operations fops = { - .owner = THIS_MODULE, - .read = misc_read, -}; - -static struct miscdevice prandom_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = DEVICE_NAME, - .fops = &fops, -}; - -static int __init misc_init(void) -{ - global_gprn = kmalloc(sizeof(struct gf256_gprn), GFP_KERNEL); - if (!global_gprn) - return -ENOMEM; - - gf256_gprn_init_t(global_gprn); - - int err = misc_register(&prandom_misc); - if (err != 0) - { - kfree(global_gprn); - return err; - } - - return 0; -} - -static void __exit misc_exit(void) -{ - kfree(global_gprn); - misc_deregister(&prandom_misc); -} - -module_param(coeff_file, charp, 0); -MODULE_PARM_DESC(coeff_file, "path to file with bytes for coefficients"); -module_param(polynom_file, charp, 0); -MODULE_PARM_DESC(polynom_file, "path to file with bytes for polynom"); - -module_init(misc_init); -module_exit(misc_exit); \ No newline at end of file +#include "prandom.h" + +#include "lib.h" + +void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* polynom_data) +{ + int i; + + for (i = 0; i < POLY_DEGREE; i++) + { + gprn->coeff[i] = coeff_data[i]; + } + + for (i = 0; i < POLY_DEGREE; i++) + { + gprn->t[i] = polynom_data[i]; + } + + gprn->index = 0; +} + +GF256_t gf256_gprn_next(struct gf256_gprn* gprn) +{ + GF256_t new_byte = 0; + int idx; + int i; + + for (i = 0; i < POLY_DEGREE; i++) + { + if (gprn->t[i] != 0) + { + idx = (gprn->index + i) % POLY_DEGREE; + new_byte = GF256_Add(new_byte, GF256_Mul(gprn->t[i], gprn->coeff[idx])); + } + } + + // "circular" array + gprn->coeff[gprn->index] = new_byte; + gprn->index = (gprn->index + 1) % POLY_DEGREE; + + return new_byte; +} + +void gf256_gprn_generate(struct gf256_gprn* gprn, size_t count, GF256_t* output) +{ + size_t i; + for (i = 0; i < count; i++) + { + output[i] = gf256_gprn_next(gprn); + } +} \ No newline at end of file diff --git a/prandom.h b/prandom.h new file mode 100644 index 0000000..0b51880 --- /dev/null +++ b/prandom.h @@ -0,0 +1,29 @@ +#ifndef PRANDOM_H +#define PRANDOM_H + +#ifdef __KERNEL__ +#include +#else +#include // для size_t в userspace +#endif +#include "lib.h" + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif +#define POLY_DEGREE 256 +#define GF256_ONE (GF256_t)0x01 +#define GF256_DEGREES_AUTO {0, 2, 5, 10, 255} + +struct gf256_gprn +{ + GF256_t coeff[POLY_DEGREE]; + GF256_t t[POLY_DEGREE]; + int index; +}; + +void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* polynom_data); +GF256_t gf256_gprn_next(struct gf256_gprn* gprn); +void gf256_gprn_generate(struct gf256_gprn* gprn, size_t count, GF256_t* output); + +#endif \ No newline at end of file diff --git a/test-files/expected1.bin b/test-files/expected1.bin new file mode 100644 index 0000000..67407da --- /dev/null +++ b/test-files/expected1.bin @@ -0,0 +1 @@ +Gkwy`?ɲ \ No newline at end of file diff --git a/test-files/polynom_file.bin b/test-files/polynom_file.bin index e563af65e48f134cdb5fb7efca9cd6048fb16383..f459d91a31b9d7db0be2954102335bf734df6f62 100644 GIT binary patch delta 11 Scmeyv*uXU5_e2F2Mn(V}uLHsW delta 8 PcmZo*`olQkHzOke4>to1 diff --git a/test.c b/test.c new file mode 100644 index 0000000..f556570 --- /dev/null +++ b/test.c @@ -0,0 +1,80 @@ +#include +#include +#include + +#include "lib.h" +#include "prandom.h" + +#define NUM_BYTES 10 + +static int read_file(const char* path, unsigned char* buf, size_t size) +{ + FILE* f = fopen(path, "rb"); + if (!f) + return -1; + + size_t read = fread(buf, 1, size, f); + fclose(f); + return (read == size) ? 0 : -1; +} + +static int test1(void) +{ + const char* coeff_file = "test-files/coeff_file.bin"; + const char* poly_file = "test-files/polynom_file.bin"; + const char* expected_file = "test-files/expected1.bin"; + + unsigned char coeff[POLY_DEGREE]; + unsigned char poly[POLY_DEGREE]; + unsigned char generated[NUM_BYTES]; + unsigned char expected[NUM_BYTES]; + + if (read_file(coeff_file, coeff, POLY_DEGREE) != 0) + { + printf(" Failed to read %s\n", coeff_file); + return -1; + } + + if (read_file(poly_file, poly, POLY_DEGREE) != 0) + { + printf(" Failed to read %s\n", poly_file); + return -1; + } + + struct gf256_gprn gprn; + gf256_gprn_init_t(&gprn, (GF256_t*)coeff, (GF256_t*)poly); + gf256_gprn_generate(&gprn, NUM_BYTES, (GF256_t*)generated); + + if (read_file(expected_file, expected, NUM_BYTES) != 0) + { + printf(" Failed to read %s\n", expected_file); + return -1; + } + + for (int i = 0; i < NUM_BYTES; i++) + { + if (generated[i] != expected[i]) + { + printf(" ❌ Byte %d: 0x%02x != 0x%02x\n", i, generated[i], expected[i]); + return -1; + } + } + + printf(" ✅ Test 1 passed\n"); + return 0; +} + +int main(void) +{ + int result = 0; + + result = test1(); + if (result != 0) + { + printf("test1 failed\n"); + return 1; + } + + printf("All tests passed\n"); + return 0; +} \ No newline at end of file From 004df0c2cdbff13c7ac08751fdbb7d74bea81bbe Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Tue, 17 Mar 2026 17:13:39 +0300 Subject: [PATCH 05/21] refactor: SMALL CHANGES DENIS POTAPOV LIBRARY (WITH PERMISSION, TEMPORARILY); some changes (without change program logic) --- .gitignore | 3 ++- Makefile | 2 +- driver.c | 2 +- lib.h | 2 +- prandom.c | 2 +- prandom.h | 4 ++-- test.c | 12 ++++++------ 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index ba5ce58..6018f06 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ gfrandom.mod LICENSE .clang-format lib.c -lib.h \ No newline at end of file +lib.h +test \ No newline at end of file diff --git a/Makefile b/Makefile index 0e5d096..3f21afd 100644 --- a/Makefile +++ b/Makefile @@ -16,4 +16,4 @@ test_algo: test.c lib.c prandom.c test: test_algo ./test -.PHONY: all clean test test \ No newline at end of file +.PHONY: all clean test test diff --git a/driver.c b/driver.c index 13bf073..549608a 100644 --- a/driver.c +++ b/driver.c @@ -200,4 +200,4 @@ module_param(polynom_file, charp, 0); MODULE_PARM_DESC(polynom_file, "path to file with bytes for polynom"); module_init(misc_init); -module_exit(misc_exit); \ No newline at end of file +module_exit(misc_exit); diff --git a/lib.h b/lib.h index b51c074..22e07c1 100644 --- a/lib.h +++ b/lib.h @@ -15,4 +15,4 @@ GF256_t GF256_Sub(GF256_t a, GF256_t b); GF256_t GF256_Mul(GF256_t a, GF256_t b); GF256_t GF256_Div(GF256_t a, GF256_t b); -#endif \ No newline at end of file +#endif diff --git a/prandom.c b/prandom.c index 8456e7c..ebac38f 100644 --- a/prandom.c +++ b/prandom.c @@ -48,4 +48,4 @@ void gf256_gprn_generate(struct gf256_gprn* gprn, size_t count, GF256_t* output) { output[i] = gf256_gprn_next(gprn); } -} \ No newline at end of file +} diff --git a/prandom.h b/prandom.h index 0b51880..6b8aad3 100644 --- a/prandom.h +++ b/prandom.h @@ -4,7 +4,7 @@ #ifdef __KERNEL__ #include #else -#include // для size_t в userspace +#include #endif #include "lib.h" @@ -26,4 +26,4 @@ void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* GF256_t gf256_gprn_next(struct gf256_gprn* gprn); void gf256_gprn_generate(struct gf256_gprn* gprn, size_t count, GF256_t* output); -#endif \ No newline at end of file +#endif diff --git a/test.c b/test.c index f556570..6722de4 100644 --- a/test.c +++ b/test.c @@ -31,13 +31,13 @@ static int test1(void) if (read_file(coeff_file, coeff, POLY_DEGREE) != 0) { - printf(" Failed to read %s\n", coeff_file); + printf("failed to read %s\n", coeff_file); return -1; } if (read_file(poly_file, poly, POLY_DEGREE) != 0) { - printf(" Failed to read %s\n", poly_file); + printf("failed to read %s\n", poly_file); return -1; } @@ -47,7 +47,7 @@ static int test1(void) if (read_file(expected_file, expected, NUM_BYTES) != 0) { - printf(" Failed to read %s\n", expected_file); + printf("failed to read %s\n", expected_file); return -1; } @@ -55,12 +55,12 @@ static int test1(void) { if (generated[i] != expected[i]) { - printf(" ❌ Byte %d: 0x%02x != 0x%02x\n", i, generated[i], expected[i]); + printf("❌ Byte %d: 0x%02x != 0x%02x\n", i, generated[i], expected[i]); return -1; } } - printf(" ✅ Test 1 passed\n"); + printf("✅ Test 1 passed\n"); return 0; } @@ -77,4 +77,4 @@ int main(void) printf("All tests passed\n"); return 0; -} \ No newline at end of file +} From 2fe743e0911d94114d89a4d8a9f4460bd540a2b4 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Tue, 17 Mar 2026 17:58:04 +0300 Subject: [PATCH 06/21] formatting: change CRLF to LF in driver.c and Makefile --- Makefile | 38 +++--- driver.c | 406 +++++++++++++++++++++++++++---------------------------- 2 files changed, 222 insertions(+), 222 deletions(-) diff --git a/Makefile b/Makefile index 3f21afd..dec5144 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,19 @@ -obj-m += gfrandom.o -gfrandom-objs := driver.o prandom.o lib.o - -KDIR := /lib/modules/$(shell uname -r)/build -PWD := $(shell pwd) - -all: - $(MAKE) -C $(KDIR) M=$(PWD) modules - -clean: - $(MAKE) -C $(KDIR) M=$(PWD) clean - -test_algo: test.c lib.c prandom.c - gcc -o test test.c lib.c prandom.c -I. - -test: test_algo - ./test - -.PHONY: all clean test test +obj-m += gfrandom.o +gfrandom-objs := driver.o prandom.o lib.o + +KDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +all: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +clean: + $(MAKE) -C $(KDIR) M=$(PWD) clean + +test_algo: test.c lib.c prandom.c + gcc -o test test.c lib.c prandom.c -I. + +test: test_algo + ./test + +.PHONY: all clean test test diff --git a/driver.c b/driver.c index 549608a..d257df2 100644 --- a/driver.c +++ b/driver.c @@ -1,203 +1,203 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -/* - * prandom – misc-драйвер, предоставляющий случайные данные, аналогично - * /dev/urandom - * - * Copyright (C) 2026 Makar Lill - * - * This driver uses Galois Field arithmetic library written by Denis Potapov - * (lib.c / lib.h). Used with permission. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "asm-generic/errno-base.h" -#include "lib.h" -#include "prandom.h" - -#define DEVICE_NAME "gfrandom" - -MODULE_LICENSE("GPL-3.0"); -MODULE_AUTHOR("Makar Lill"); -MODULE_DESCRIPTION("Analogue of /dev/urandom"); - -struct gf256_gprn* global_gprn = NULL; - -static char* coeff_file = NULL; -static char* polynom_file = NULL; - -static int read_file_bytes(char* filename, GF256_t* row, size_t size) -{ - if (!filename || !row) - return !EINVAL; - - struct file* f = filp_open(filename, O_RDONLY, 0); - if (IS_ERR(f)) - return PTR_ERR(f); - - loff_t pos = 0; - int res = kernel_read(f, row, size, &pos); - filp_close(f, NULL); - - if (res != size) - return (res < 0) ? res : -EIO; - - return 0; -} - -static void gprn_init_t(struct gf256_gprn* gprn) -{ - GF256_t coeff_data[POLY_DEGREE]; - GF256_t polynom_data[POLY_DEGREE]; - GF256_t *coeff_ptr = NULL, *polynom_ptr = NULL; - - int i; - - // read bytes from coeff file - if (coeff_file) - { - int res = read_file_bytes(coeff_file, coeff_data, sizeof(coeff_data)); - coeff_ptr = coeff_data; - if (res != 0) - { - goto get_random_coeffs; - } - } - else - { - get_random_coeffs: - get_random_bytes(coeff_data, sizeof(coeff_ptr)); - - int all_zero = 1; - for (i = 0; i < POLY_DEGREE; i++) - { - if (coeff_data[i] != 0) - { - all_zero = 0; - break; - } - } - if (all_zero) - { - coeff_data[0] = GF256_ONE; - } - coeff_ptr = coeff_data; - } - - // read bytes from polynom file - if (polynom_file) - { - int res = read_file_bytes(polynom_file, polynom_data, sizeof(polynom_data)); - polynom_ptr = polynom_data; - if (res != 0) - { - goto get_auto_polynom; - } - } - else - { - get_auto_polynom: - for (i = 0; i < POLY_DEGREE; i++) - { - polynom_data[i] = 0; - } - - // we use polynom t^256 + t^10 + t^5 + t^2 + 1 - const int degrees[] = GF256_DEGREES_AUTO; - for (i = 0; i < ARRAY_SIZE(degrees); i++) - { - polynom_data[degrees[i]] = GF256_ONE; - } - polynom_ptr = polynom_data; - } - - gf256_gprn_init_t(gprn, coeff_ptr, polynom_ptr); -} - -static ssize_t misc_read(struct file* filp, char __user* buf, size_t length, loff_t* f_pos) -{ - GF256_t kernel_buf[256]; - size_t bytes_to_read = length; - size_t chunk; - - if (!global_gprn) - return -ENODEV; - - while (bytes_to_read > 0) - { - chunk = min(bytes_to_read, sizeof(kernel_buf)); - - gf256_gprn_generate(global_gprn, chunk, kernel_buf); - - if (copy_to_user(buf, kernel_buf, chunk)) - return -EFAULT; - - buf += chunk; - bytes_to_read -= chunk; - *f_pos += chunk; - } - - return length; -} - -static const struct file_operations fops = { - .owner = THIS_MODULE, - .read = misc_read, -}; - -static struct miscdevice prandom_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = DEVICE_NAME, - .fops = &fops, -}; - -static int __init misc_init(void) -{ - global_gprn = kmalloc(sizeof(struct gf256_gprn), GFP_KERNEL); - if (!global_gprn) - return -ENOMEM; - - gprn_init_t(global_gprn); - - int err = misc_register(&prandom_misc); - if (err != 0) - { - kfree(global_gprn); - return err; - } - - return 0; -} - -static void __exit misc_exit(void) -{ - kfree(global_gprn); - misc_deregister(&prandom_misc); -} - -module_param(coeff_file, charp, 0); -MODULE_PARM_DESC(coeff_file, "path to file with bytes for coefficients"); -module_param(polynom_file, charp, 0); -MODULE_PARM_DESC(polynom_file, "path to file with bytes for polynom"); - -module_init(misc_init); -module_exit(misc_exit); +// SPDX-License-Identifier: GPL-3.0-or-later +/* + * prandom – misc-драйвер, предоставляющий случайные данные, аналогично + * /dev/urandom + * + * Copyright (C) 2026 Makar Lill + * + * This driver uses Galois Field arithmetic library written by Denis Potapov + * (lib.c / lib.h). Used with permission. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "asm-generic/errno-base.h" +#include "lib.h" +#include "prandom.h" + +#define DEVICE_NAME "gfrandom" + +MODULE_LICENSE("GPL-3.0"); +MODULE_AUTHOR("Makar Lill"); +MODULE_DESCRIPTION("Analogue of /dev/urandom"); + +struct gf256_gprn* global_gprn = NULL; + +static char* coeff_file = NULL; +static char* polynom_file = NULL; + +static int read_file_bytes(char* filename, GF256_t* row, size_t size) +{ + if (!filename || !row) + return !EINVAL; + + struct file* f = filp_open(filename, O_RDONLY, 0); + if (IS_ERR(f)) + return PTR_ERR(f); + + loff_t pos = 0; + int res = kernel_read(f, row, size, &pos); + filp_close(f, NULL); + + if (res != size) + return (res < 0) ? res : -EIO; + + return 0; +} + +static void gprn_init_t(struct gf256_gprn* gprn) +{ + GF256_t coeff_data[POLY_DEGREE]; + GF256_t polynom_data[POLY_DEGREE]; + GF256_t *coeff_ptr = NULL, *polynom_ptr = NULL; + + int i; + + // read bytes from coeff file + if (coeff_file) + { + int res = read_file_bytes(coeff_file, coeff_data, sizeof(coeff_data)); + coeff_ptr = coeff_data; + if (res != 0) + { + goto get_random_coeffs; + } + } + else + { + get_random_coeffs: + get_random_bytes(coeff_data, sizeof(coeff_ptr)); + + int all_zero = 1; + for (i = 0; i < POLY_DEGREE; i++) + { + if (coeff_data[i] != 0) + { + all_zero = 0; + break; + } + } + if (all_zero) + { + coeff_data[0] = GF256_ONE; + } + coeff_ptr = coeff_data; + } + + // read bytes from polynom file + if (polynom_file) + { + int res = read_file_bytes(polynom_file, polynom_data, sizeof(polynom_data)); + polynom_ptr = polynom_data; + if (res != 0) + { + goto get_auto_polynom; + } + } + else + { + get_auto_polynom: + for (i = 0; i < POLY_DEGREE; i++) + { + polynom_data[i] = 0; + } + + // we use polynom t^256 + t^10 + t^5 + t^2 + 1 + const int degrees[] = GF256_DEGREES_AUTO; + for (i = 0; i < ARRAY_SIZE(degrees); i++) + { + polynom_data[degrees[i]] = GF256_ONE; + } + polynom_ptr = polynom_data; + } + + gf256_gprn_init_t(gprn, coeff_ptr, polynom_ptr); +} + +static ssize_t misc_read(struct file* filp, char __user* buf, size_t length, loff_t* f_pos) +{ + GF256_t kernel_buf[256]; + size_t bytes_to_read = length; + size_t chunk; + + if (!global_gprn) + return -ENODEV; + + while (bytes_to_read > 0) + { + chunk = min(bytes_to_read, sizeof(kernel_buf)); + + gf256_gprn_generate(global_gprn, chunk, kernel_buf); + + if (copy_to_user(buf, kernel_buf, chunk)) + return -EFAULT; + + buf += chunk; + bytes_to_read -= chunk; + *f_pos += chunk; + } + + return length; +} + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .read = misc_read, +}; + +static struct miscdevice prandom_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = DEVICE_NAME, + .fops = &fops, +}; + +static int __init misc_init(void) +{ + global_gprn = kmalloc(sizeof(struct gf256_gprn), GFP_KERNEL); + if (!global_gprn) + return -ENOMEM; + + gprn_init_t(global_gprn); + + int err = misc_register(&prandom_misc); + if (err != 0) + { + kfree(global_gprn); + return err; + } + + return 0; +} + +static void __exit misc_exit(void) +{ + kfree(global_gprn); + misc_deregister(&prandom_misc); +} + +module_param(coeff_file, charp, 0); +MODULE_PARM_DESC(coeff_file, "path to file with bytes for coefficients"); +module_param(polynom_file, charp, 0); +MODULE_PARM_DESC(polynom_file, "path to file with bytes for polynom"); + +module_init(misc_init); +module_exit(misc_exit); From 0e187d31271c37b4ce440e52652cac8fd912c1d5 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Tue, 17 Mar 2026 18:07:25 +0300 Subject: [PATCH 07/21] fix: critical bugs in driver.c has been fixed --- driver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/driver.c b/driver.c index d257df2..04e1adf 100644 --- a/driver.c +++ b/driver.c @@ -48,7 +48,7 @@ static char* polynom_file = NULL; static int read_file_bytes(char* filename, GF256_t* row, size_t size) { if (!filename || !row) - return !EINVAL; + return -EINVAL; struct file* f = filp_open(filename, O_RDONLY, 0); if (IS_ERR(f)) @@ -85,7 +85,7 @@ static void gprn_init_t(struct gf256_gprn* gprn) else { get_random_coeffs: - get_random_bytes(coeff_data, sizeof(coeff_ptr)); + get_random_bytes(coeff_data, sizeof(coeff_data)); int all_zero = 1; for (i = 0; i < POLY_DEGREE; i++) From 56b067bf9d2a7797a109d8c53f985552281c9745 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Tue, 17 Mar 2026 23:58:32 +0300 Subject: [PATCH 08/21] fix-n-refactor-n-feature: update README.md; some fixes and refactors; add second test; add auto generate polynom for userspace tests; update CI; other changes --- .clang-format | 28 +++++++ .github/workflows/ci.yml | 10 ++- .gitignore | 20 +++-- Makefile | 5 +- README.md | 94 ++++++++++++++++++++++++ {test-files => assets}/coeff_file.bin | 0 {test-files => assets}/expected1.bin | 0 {test-files => assets}/polynom_file.bin | Bin driver.c | 71 +++++++----------- prandom.c | 38 +++++++++- prandom.h | 8 +- test.c | 68 ++++++++++++++--- 12 files changed, 271 insertions(+), 71 deletions(-) create mode 100644 .clang-format create mode 100644 README.md rename {test-files => assets}/coeff_file.bin (100%) rename {test-files => assets}/expected1.bin (100%) rename {test-files => assets}/polynom_file.bin (100%) diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..108fa79 --- /dev/null +++ b/.clang-format @@ -0,0 +1,28 @@ +# Стиль форматирования +BasedOnStyle: Google + +# Настройки отступов +IndentWidth: 4 +TabWidth: 4 +UseTab: Never + +# Разрывы строк +ColumnLimit: 100 +BreakBeforeBraces: Allman + +# Пробелы +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false + +# Выравнивание +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true + +# Указатели и ссылки +PointerAlignment: Left + +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false + +# Сортировка +SortIncludes: true \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc9ad3e..19b7d97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install dependencies - run: sudo apt-get update && sudo apt-get install -y gcc make + run: sudo apt-get update && sudo apt-get install -y gcc make clang + + - name: Static analysis + run: clang-tidy prandom.c lib.c test.c -- -I. - name: Build driver run: make @@ -17,4 +20,7 @@ jobs: run: make test_algo - name: Run test - run: make test \ No newline at end of file + run: make test + + - name: Run with sanitizers + run: make test_sanitized && ./test \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6018f06..d98624f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,17 @@ +*.o +*.ko +*.mod.c +*.mod +*.order +*.symvers + Module.symvers .gfrandom.mod.cmd -compile_commands.json gfrandom.mod +compile_commands.json .cache -LICENSE -.clang-format -lib.c -lib.h -test \ No newline at end of file +*.swp +*.swo +*~ +test +test_gen +expected_gen diff --git a/Makefile b/Makefile index dec5144..202a979 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,10 @@ clean: $(MAKE) -C $(KDIR) M=$(PWD) clean test_algo: test.c lib.c prandom.c - gcc -o test test.c lib.c prandom.c -I. + gcc -o test test.c lib.c prandom.c + +test_sanitized: test.c lib.c prandom.c + gcc -o test test.c lib.c prandom.c -fsanitize=address,undefined -g test: test_algo ./test diff --git a/README.md b/README.md new file mode 100644 index 0000000..7de956e --- /dev/null +++ b/README.md @@ -0,0 +1,94 @@ +# gfrandom + +[![CI](https://github.com/estoniec/prandom/actions/workflows/ci.yml/badge.svg)](https://github.com/estoniec/prandom/actions/workflows/ci.yml) +[![Clang-Tidy](https://img.shields.io/badge/Clang--Tidy-passing-green)](https://clang.llvm.org/docs/ClangFormat.html) + +Linux kernel модуль, предоставляющий генератор псевдослучайных чисел на основе Galois Field (GF(2⁸)). + +## Описание + +Драйвер создаёт устройство `/dev/gfrandom`, которое возвращает псевдослучайные байты, сгенерированные с использованием арифметики Galois Field GF(2⁸). Является аналогом `/dev/urandom`. + +### Алгоритм + +Используется регистр сдвига с линейной обратной связью (LFSR) над полем GF(2⁸): +- Состояние: 256 байт (коэффициенты) +- Полином: t^256 + t^10 + t^5 + t^2 + 1 (или пользовательский) +- Генерируемое значение: сумма произведений ненулевых коэффициентов полинома на соответствующие коэффициенты состояния + +### Используемые компоненты + +- **gfrandom** — драйвер (GPL-3.0-or-later) +- **lib** — [библиотека арифметики Galois Field](https://github.com/DenisPotapov0/Galua-Field-library) (MIT License) + +## Требования + +- Linux kernel headers (для сборки модуля) +- GCC, make +- Для запуска тестов: linux-headers или root доступ для загрузки модуля + +## Сборка + +### Linux модуль + +```bash +make +``` + +### Userspace тесты + +```bash +make test_algo +./test +``` + +## Использование + +### Загрузка модуля + +```bash +sudo insmod gfrandom.ko +``` + +### Параметры модуля + +- `coeff_file` — путь к файлу с коэффициентами (256 байт) +- `polynom_file` — путь к файлу с полиномом (256 байт) + +Если параметры не указаны, используются автоматически сгенерированные значения. + +Пример использования собственных параметров: +```bash +sudo insmod gfrandom.ko coeff_file=/path/to/coeffs.bin polynom_file=/path/to/poly.bin +``` + +### Чтение случайных данных + +```bash +sudo cat /dev/gfrandom | head -c 1024 > /dev/null +``` + +### Выгрузка модуля + +```bash +sudo rmmod gfrandom +``` + +## Тестирование + +Тесты запускаются в CI и локально: + +```bash +make test +``` + +## Лицензия + +- **prandom**: GPL-3.0-or-later +- **lib** (Denis Potapov): MIT License + +Подробности см. в [LICENSE](LICENSE). + +## Автор + +Макар Лилль \ No newline at end of file diff --git a/test-files/coeff_file.bin b/assets/coeff_file.bin similarity index 100% rename from test-files/coeff_file.bin rename to assets/coeff_file.bin diff --git a/test-files/expected1.bin b/assets/expected1.bin similarity index 100% rename from test-files/expected1.bin rename to assets/expected1.bin diff --git a/test-files/polynom_file.bin b/assets/polynom_file.bin similarity index 100% rename from test-files/polynom_file.bin rename to assets/polynom_file.bin diff --git a/driver.c b/driver.c index 04e1adf..7c79997 100644 --- a/driver.c +++ b/driver.c @@ -22,6 +22,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -30,7 +31,6 @@ #include #include -#include "asm-generic/errno-base.h" #include "lib.h" #include "prandom.h" @@ -64,73 +64,48 @@ static int read_file_bytes(char* filename, GF256_t* row, size_t size) return 0; } -static void gprn_init_t(struct gf256_gprn* gprn) +static int gprn_init_t(struct gf256_gprn* gprn) { - GF256_t coeff_data[POLY_DEGREE]; - GF256_t polynom_data[POLY_DEGREE]; - GF256_t *coeff_ptr = NULL, *polynom_ptr = NULL; + GF256_t coeff_data[POLY_DEGREE]; + GF256_t polynom_data[POLY_DEGREE]; + int i; + int err; - int i; - - // read bytes from coeff file if (coeff_file) { - int res = read_file_bytes(coeff_file, coeff_data, sizeof(coeff_data)); - coeff_ptr = coeff_data; - if (res != 0) - { + err = read_file_bytes(coeff_file, coeff_data, sizeof(coeff_data)); + if (err != 0) goto get_random_coeffs; - } } else { get_random_coeffs: get_random_bytes(coeff_data, sizeof(coeff_data)); - - int all_zero = 1; for (i = 0; i < POLY_DEGREE; i++) { if (coeff_data[i] != 0) - { - all_zero = 0; break; - } } - if (all_zero) - { + if (i == POLY_DEGREE) coeff_data[0] = GF256_ONE; - } - coeff_ptr = coeff_data; } - // read bytes from polynom file if (polynom_file) { - int res = read_file_bytes(polynom_file, polynom_data, sizeof(polynom_data)); - polynom_ptr = polynom_data; - if (res != 0) - { - goto get_auto_polynom; - } + err = read_file_bytes(polynom_file, polynom_data, sizeof(polynom_data)); + if (err != 0) + goto use_auto_polynom; } else { - get_auto_polynom: - for (i = 0; i < POLY_DEGREE; i++) - { - polynom_data[i] = 0; - } - - // we use polynom t^256 + t^10 + t^5 + t^2 + 1 - const int degrees[] = GF256_DEGREES_AUTO; - for (i = 0; i < ARRAY_SIZE(degrees); i++) - { - polynom_data[degrees[i]] = GF256_ONE; - } - polynom_ptr = polynom_data; + use_auto_polynom: + memset(polynom_data, 0, sizeof(polynom_data)); + for (i = 0; i < ARRAY_SIZE(GF256_DEGREES_AUTO); i++) + polynom_data[GF256_DEGREES_AUTO[i]] = GF256_ONE; } - gf256_gprn_init_t(gprn, coeff_ptr, polynom_ptr); + gf256_gprn_init_t(gprn, coeff_data, polynom_data); + return 0; } static ssize_t misc_read(struct file* filp, char __user* buf, size_t length, loff_t* f_pos) @@ -156,7 +131,7 @@ static ssize_t misc_read(struct file* filp, char __user* buf, size_t length, lof *f_pos += chunk; } - return length; + return length - bytes_to_read; } static const struct file_operations fops = { @@ -172,11 +147,15 @@ static struct miscdevice prandom_misc = { static int __init misc_init(void) { - global_gprn = kmalloc(sizeof(struct gf256_gprn), GFP_KERNEL); + global_gprn = kzalloc(sizeof(struct gf256_gprn), GFP_KERNEL); if (!global_gprn) return -ENOMEM; - gprn_init_t(global_gprn); + if (gprn_init_t(global_gprn) != 0) + { + kfree(global_gprn); + return -EINVAL; + } int err = misc_register(&prandom_misc); if (err != 0) diff --git a/prandom.c b/prandom.c index ebac38f..372b945 100644 --- a/prandom.c +++ b/prandom.c @@ -4,16 +4,40 @@ void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* polynom_data) { + if (!gprn) + return; + int i; - for (i = 0; i < POLY_DEGREE; i++) + if (coeff_data) { - gprn->coeff[i] = coeff_data[i]; + for (i = 0; i < POLY_DEGREE; i++) + { + gprn->coeff[i] = coeff_data[i]; + } + } + else + { + for (i = 0; i < POLY_DEGREE; i++) + { + gprn->coeff[i] = (GF256_t)(i % 256); + } } - for (i = 0; i < POLY_DEGREE; i++) + if (polynom_data) { - gprn->t[i] = polynom_data[i]; + for (i = 0; i < POLY_DEGREE; i++) + { + gprn->t[i] = polynom_data[i]; + } + } + else + { + memset(gprn->t, 0, POLY_DEGREE); + for (i = 0; i < ARRAY_SIZE(GF256_DEGREES_AUTO); i++) + { + gprn->t[GF256_DEGREES_AUTO[i]] = GF256_ONE; + } } gprn->index = 0; @@ -21,6 +45,9 @@ void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* po GF256_t gf256_gprn_next(struct gf256_gprn* gprn) { + if (!gprn) + return 0; + GF256_t new_byte = 0; int idx; int i; @@ -43,6 +70,9 @@ GF256_t gf256_gprn_next(struct gf256_gprn* gprn) void gf256_gprn_generate(struct gf256_gprn* gprn, size_t count, GF256_t* output) { + if (!gprn || !output || count == 0) + return; + size_t i; for (i = 0; i < count; i++) { diff --git a/prandom.h b/prandom.h index 6b8aad3..007a3c3 100644 --- a/prandom.h +++ b/prandom.h @@ -1,6 +1,12 @@ #ifndef PRANDOM_H #define PRANDOM_H +#ifdef __KERNEL__ +#include +#else +#include +#endif + #ifdef __KERNEL__ #include #else @@ -13,7 +19,7 @@ #endif #define POLY_DEGREE 256 #define GF256_ONE (GF256_t)0x01 -#define GF256_DEGREES_AUTO {0, 2, 5, 10, 255} +static const int GF256_DEGREES_AUTO[] = {0, 2, 5, 10, 255}; struct gf256_gprn { diff --git a/test.c b/test.c index 6722de4..8407a15 100644 --- a/test.c +++ b/test.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -18,16 +19,16 @@ static int read_file(const char* path, unsigned char* buf, size_t size) return (read == size) ? 0 : -1; } -static int test1(void) +static int test1_simple(void) { - const char* coeff_file = "test-files/coeff_file.bin"; - const char* poly_file = "test-files/polynom_file.bin"; - const char* expected_file = "test-files/expected1.bin"; + const char* coeff_file = "assets/coeff_file.bin"; + const char* poly_file = "assets/polynom_file.bin"; + const char* expected_file = "assets/expected1.bin"; - unsigned char coeff[POLY_DEGREE]; - unsigned char poly[POLY_DEGREE]; - unsigned char generated[NUM_BYTES]; - unsigned char expected[NUM_BYTES]; + GF256_t coeff[POLY_DEGREE]; + GF256_t poly[POLY_DEGREE]; + GF256_t generated[NUM_BYTES]; + GF256_t expected[NUM_BYTES]; if (read_file(coeff_file, coeff, POLY_DEGREE) != 0) { @@ -42,8 +43,8 @@ static int test1(void) } struct gf256_gprn gprn; - gf256_gprn_init_t(&gprn, (GF256_t*)coeff, (GF256_t*)poly); - gf256_gprn_generate(&gprn, NUM_BYTES, (GF256_t*)generated); + gf256_gprn_init_t(&gprn, coeff, poly); + gf256_gprn_generate(&gprn, NUM_BYTES, generated); if (read_file(expected_file, expected, NUM_BYTES) != 0) { @@ -64,17 +65,62 @@ static int test1(void) return 0; } +static int test2_without_polynom(void) +{ + const char* coeff_file = "assets/coeff_file.bin"; + const char* expected_file = "assets/expected1.bin"; + + GF256_t coeff[POLY_DEGREE]; + GF256_t generated[NUM_BYTES]; + GF256_t expected[NUM_BYTES]; + + if (read_file(coeff_file, coeff, POLY_DEGREE) != 0) + { + printf("failed to read %s\n", coeff_file); + return -1; + } + + struct gf256_gprn gprn; + gf256_gprn_init_t(&gprn, coeff, NULL); + gf256_gprn_generate(&gprn, NUM_BYTES, generated); + + if (read_file(expected_file, expected, NUM_BYTES) != 0) + { + printf("failed to read %s\n", expected_file); + return -1; + } + + for (int i = 0; i < NUM_BYTES; i++) + { + if (generated[i] != expected[i]) + { + printf("❌ Byte %d: 0x%02x != 0x%02x\n", i, generated[i], expected[i]); + return -1; + } + } + + printf("✅ Test 2 passed\n"); + return 0; +} + int main(void) { int result = 0; - result = test1(); + result = test1_simple(); if (result != 0) { printf("test1 failed\n"); return 1; } + result = test2_without_polynom(); + if (result != 0) + { + printf("test2 failed\n"); + return 1; + } + printf("All tests passed\n"); return 0; } From d83eb91dec78ed3d5c368458307facc0bc73cbc9 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Wed, 18 Mar 2026 00:01:52 +0300 Subject: [PATCH 09/21] refactor: small change in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7de956e..ffeea78 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ make test ## Лицензия -- **prandom**: GPL-3.0-or-later +- **prandom**: GPL-3.0 - **lib** (Denis Potapov): MIT License Подробности см. в [LICENSE](LICENSE). From 21d11a08ffc1c2960c9768fbaf4e88abc6ec5f8b Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Wed, 18 Mar 2026 00:03:37 +0300 Subject: [PATCH 10/21] refactor: small change in README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ffeea78..2715569 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# gfrandom +# prandom [![CI](https://github.com/estoniec/prandom/actions/workflows/ci.yml/badge.svg)](https://github.com/estoniec/prandom/actions/workflows/ci.yml) [![Clang-Tidy](https://img.shields.io/badge/Clang--Tidy-passing-green)](https://clang.llvm.org/docs/ClangFormat.html) @@ -7,7 +7,7 @@ Linux kernel модуль, предоставляющий генератор п ## Описание -Драйвер создаёт устройство `/dev/gfrandom`, которое возвращает псевдослучайные байты, сгенерированные с использованием арифметики Galois Field GF(2⁸). Является аналогом `/dev/urandom`. +Драйвер создаёт misc-устройство `/dev/gfrandom`, которое возвращает псевдослучайные байты, сгенерированные с использованием арифметики Galois Field GF(2⁸). Является аналогом `/dev/urandom`. ### Алгоритм From 5df2c40d2574b507e1980767f398fe704ffba167 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Wed, 18 Mar 2026 00:08:13 +0300 Subject: [PATCH 11/21] refactor: small change in README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2715569..11cda3d 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ [![CI](https://github.com/estoniec/prandom/actions/workflows/ci.yml/badge.svg)](https://github.com/estoniec/prandom/actions/workflows/ci.yml) [![Clang-Tidy](https://img.shields.io/badge/Clang--Tidy-passing-green)](https://clang.llvm.org/docs/ClangFormat.html) -Linux kernel модуль, предоставляющий генератор псевдослучайных чисел на основе Galois Field (GF(2⁸)). +Linux kernel модуль, предоставляющий генератор псевдослучайных чисел на основе полей Галуа (GF(2⁸)). ## Описание -Драйвер создаёт misc-устройство `/dev/gfrandom`, которое возвращает псевдослучайные байты, сгенерированные с использованием арифметики Galois Field GF(2⁸). Является аналогом `/dev/urandom`. +Драйвер создаёт misc-устройство `/dev/gfrandom`, которое возвращает псевдослучайные байты, сгенерированные с использованием арифметики полей Галуа GF(2⁸). Является аналогом `/dev/urandom`. ### Алгоритм @@ -19,7 +19,7 @@ Linux kernel модуль, предоставляющий генератор п ### Используемые компоненты - **gfrandom** — драйвер (GPL-3.0-or-later) -- **lib** — [библиотека арифметики Galois Field](https://github.com/DenisPotapov0/Galua-Field-library) (MIT License) +- **lib** — [библиотека для работы с полями Галуа](https://github.com/DenisPotapov0/Galua-Field-library) (MIT License) ## Требования From 1a5654e2c7f7dc42255a778bf90b94a89ee57e8a Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 22 Mar 2026 20:35:39 +0300 Subject: [PATCH 12/21] update: update README.md; change polynom => seed --- README.md | 8 ++++++++ assets/seed_file.bin | Bin 0 -> 256 bytes driver.c | 20 ++++++++++---------- prandom.c | 6 +++--- prandom.h | 3 ++- test.c | 10 +++++----- 6 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 assets/seed_file.bin diff --git a/README.md b/README.md index 11cda3d..6635113 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,14 @@ Linux kernel модуль, предоставляющий генератор п - GCC, make - Для запуска тестов: linux-headers или root доступ для загрузки модуля +## Детерминированные тестовые данные + +Для удобства пользователей, желающих получить детерминированные предсказуемые числа, в папке `assets` представлены стандартные бинарные файлы по 256 байт каждый: +- `seed_file.bin` — начальное состояние (seed) +- `coeff_file.bin` — коэффициенты + +Эти же файлы используются в тестах №1 и №2. Первые 10 ожидаемых случайных байтов: `Gkwy\`..?..` (HEX: `47 6b 77 79 60 1c bd 3f c9 b2`) — см. `assets/expected1.bin`. + ## Сборка ### Linux модуль diff --git a/assets/seed_file.bin b/assets/seed_file.bin new file mode 100644 index 0000000000000000000000000000000000000000..f459d91a31b9d7db0be2954102335bf734df6f62 GIT binary patch literal 256 TcmZQ%U}OLxC;?)OB)|v&1n>X` literal 0 HcmV?d00001 diff --git a/driver.c b/driver.c index 7c79997..8a280d1 100644 --- a/driver.c +++ b/driver.c @@ -42,8 +42,8 @@ MODULE_DESCRIPTION("Analogue of /dev/urandom"); struct gf256_gprn* global_gprn = NULL; -static char* coeff_file = NULL; -static char* polynom_file = NULL; +static char* coeff_file = NULL; +static char* seed_file = NULL; static int read_file_bytes(char* filename, GF256_t* row, size_t size) { @@ -67,7 +67,7 @@ static int read_file_bytes(char* filename, GF256_t* row, size_t size) static int gprn_init_t(struct gf256_gprn* gprn) { GF256_t coeff_data[POLY_DEGREE]; - GF256_t polynom_data[POLY_DEGREE]; + GF256_t seed_data[POLY_DEGREE]; int i; int err; @@ -90,21 +90,21 @@ static int gprn_init_t(struct gf256_gprn* gprn) coeff_data[0] = GF256_ONE; } - if (polynom_file) + if (seed_file) { - err = read_file_bytes(polynom_file, polynom_data, sizeof(polynom_data)); + err = read_file_bytes(seed_file, seed_data, sizeof(seed_data)); if (err != 0) goto use_auto_polynom; } else { use_auto_polynom: - memset(polynom_data, 0, sizeof(polynom_data)); + memset(seed_data, 0, sizeof(seed_data)); for (i = 0; i < ARRAY_SIZE(GF256_DEGREES_AUTO); i++) - polynom_data[GF256_DEGREES_AUTO[i]] = GF256_ONE; + seed_data[GF256_DEGREES_AUTO[i]] = GF256_ONE; } - gf256_gprn_init_t(gprn, coeff_data, polynom_data); + gf256_gprn_init_t(gprn, coeff_data, seed_data); return 0; } @@ -175,8 +175,8 @@ static void __exit misc_exit(void) module_param(coeff_file, charp, 0); MODULE_PARM_DESC(coeff_file, "path to file with bytes for coefficients"); -module_param(polynom_file, charp, 0); -MODULE_PARM_DESC(polynom_file, "path to file with bytes for polynom"); +module_param(seed_file, charp, 0); +MODULE_PARM_DESC(seed_file, "path to file with bytes for polynom"); module_init(misc_init); module_exit(misc_exit); diff --git a/prandom.c b/prandom.c index 372b945..7d057cb 100644 --- a/prandom.c +++ b/prandom.c @@ -2,7 +2,7 @@ #include "lib.h" -void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* polynom_data) +void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* seed_data) { if (!gprn) return; @@ -24,11 +24,11 @@ void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* po } } - if (polynom_data) + if (seed_data) { for (i = 0; i < POLY_DEGREE; i++) { - gprn->t[i] = polynom_data[i]; + gprn->t[i] = seed_data[i]; } } else diff --git a/prandom.h b/prandom.h index 007a3c3..f434195 100644 --- a/prandom.h +++ b/prandom.h @@ -17,6 +17,7 @@ #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif + #define POLY_DEGREE 256 #define GF256_ONE (GF256_t)0x01 static const int GF256_DEGREES_AUTO[] = {0, 2, 5, 10, 255}; @@ -28,7 +29,7 @@ struct gf256_gprn int index; }; -void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* polynom_data); +void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* seed_data); GF256_t gf256_gprn_next(struct gf256_gprn* gprn); void gf256_gprn_generate(struct gf256_gprn* gprn, size_t count, GF256_t* output); diff --git a/test.c b/test.c index 8407a15..bf00000 100644 --- a/test.c +++ b/test.c @@ -22,11 +22,11 @@ static int read_file(const char* path, unsigned char* buf, size_t size) static int test1_simple(void) { const char* coeff_file = "assets/coeff_file.bin"; - const char* poly_file = "assets/polynom_file.bin"; + const char* seed_file = "assets/seed_file.bin"; const char* expected_file = "assets/expected1.bin"; GF256_t coeff[POLY_DEGREE]; - GF256_t poly[POLY_DEGREE]; + GF256_t seed[POLY_DEGREE]; GF256_t generated[NUM_BYTES]; GF256_t expected[NUM_BYTES]; @@ -36,14 +36,14 @@ static int test1_simple(void) return -1; } - if (read_file(poly_file, poly, POLY_DEGREE) != 0) + if (read_file(seed_file, seed, POLY_DEGREE) != 0) { - printf("failed to read %s\n", poly_file); + printf("failed to read %s\n", seed_file); return -1; } struct gf256_gprn gprn; - gf256_gprn_init_t(&gprn, coeff, poly); + gf256_gprn_init_t(&gprn, coeff, seed); gf256_gprn_generate(&gprn, NUM_BYTES, generated); if (read_file(expected_file, expected, NUM_BYTES) != 0) From 025c9fd10783f5fb880136971f4926af07431cc3 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 22 Mar 2026 20:44:02 +0300 Subject: [PATCH 13/21] update: update README.md; change polynom => seed --- README.md | 4 ++-- driver.c | 6 +++--- test.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6635113..6ae8250 100644 --- a/README.md +++ b/README.md @@ -61,13 +61,13 @@ sudo insmod gfrandom.ko ### Параметры модуля - `coeff_file` — путь к файлу с коэффициентами (256 байт) -- `polynom_file` — путь к файлу с полиномом (256 байт) +- `seed_file` — путь к файлу с seed (256 байт) Если параметры не указаны, используются автоматически сгенерированные значения. Пример использования собственных параметров: ```bash -sudo insmod gfrandom.ko coeff_file=/path/to/coeffs.bin polynom_file=/path/to/poly.bin +sudo insmod gfrandom.ko coeff_file=/path/to/coeffs.bin seed_file=/path/to/seed.bin ``` ### Чтение случайных данных diff --git a/driver.c b/driver.c index 8a280d1..7ddc642 100644 --- a/driver.c +++ b/driver.c @@ -94,11 +94,11 @@ static int gprn_init_t(struct gf256_gprn* gprn) { err = read_file_bytes(seed_file, seed_data, sizeof(seed_data)); if (err != 0) - goto use_auto_polynom; + goto use_auto_seed; } else { - use_auto_polynom: + use_auto_seed: memset(seed_data, 0, sizeof(seed_data)); for (i = 0; i < ARRAY_SIZE(GF256_DEGREES_AUTO); i++) seed_data[GF256_DEGREES_AUTO[i]] = GF256_ONE; @@ -176,7 +176,7 @@ static void __exit misc_exit(void) module_param(coeff_file, charp, 0); MODULE_PARM_DESC(coeff_file, "path to file with bytes for coefficients"); module_param(seed_file, charp, 0); -MODULE_PARM_DESC(seed_file, "path to file with bytes for polynom"); +MODULE_PARM_DESC(seed_file, "path to file with seed bytes"); module_init(misc_init); module_exit(misc_exit); diff --git a/test.c b/test.c index bf00000..3b14dc4 100644 --- a/test.c +++ b/test.c @@ -65,7 +65,7 @@ static int test1_simple(void) return 0; } -static int test2_without_polynom(void) +static int test2_without_seed(void) { const char* coeff_file = "assets/coeff_file.bin"; const char* expected_file = "assets/expected1.bin"; @@ -114,7 +114,7 @@ int main(void) return 1; } - result = test2_without_polynom(); + result = test2_without_seed(); if (result != 0) { printf("test2 failed\n"); From 55e1f7e0a0b378b52db7132d7e9bd6d8713046ce Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 22 Mar 2026 20:46:31 +0300 Subject: [PATCH 14/21] update: README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6ae8250..fe929cb 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Linux kernel модуль, предоставляющий генератор п ### Используемые компоненты -- **gfrandom** — драйвер (GPL-3.0-or-later) +- **gfrandom** — драйвер (GPL-3.0) - **lib** — [библиотека для работы с полями Галуа](https://github.com/DenisPotapov0/Galua-Field-library) (MIT License) ## Требования @@ -92,7 +92,7 @@ make test ## Лицензия -- **prandom**: GPL-3.0 +- **gfrandom**: GPL-3.0 - **lib** (Denis Potapov): MIT License Подробности см. в [LICENSE](LICENSE). From 9eafe2af63d4b271428ba7fe7b1855be2856470a Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 22 Mar 2026 20:47:30 +0300 Subject: [PATCH 15/21] update: README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe929cb..e413bd7 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Linux kernel модуль, предоставляющий генератор п - `seed_file.bin` — начальное состояние (seed) - `coeff_file.bin` — коэффициенты -Эти же файлы используются в тестах №1 и №2. Первые 10 ожидаемых случайных байтов: `Gkwy\`..?..` (HEX: `47 6b 77 79 60 1c bd 3f c9 b2`) — см. `assets/expected1.bin`. +Эти же файлы используются в тестах №1 и №2. Первые 10 ожидаемых случайных байтов: (HEX: `47 6b 77 79 60 1c bd 3f c9 b2`) — см. `assets/expected1.bin`. ## Сборка From 33eb302ceab46d45eeb2bdc288e160f27b2d9b7d Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 29 Mar 2026 00:35:35 +0300 Subject: [PATCH 16/21] sync: update changes from dependency lib --- Galois_Field_256.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++ Galois_Field_256.h | 24 ++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 Galois_Field_256.c create mode 100644 Galois_Field_256.h diff --git a/Galois_Field_256.c b/Galois_Field_256.c new file mode 100644 index 0000000..162c1a8 --- /dev/null +++ b/Galois_Field_256.c @@ -0,0 +1,82 @@ + +// SPDX-License-Identifier: MIT +// Copyright (c) 2026 Denis Potapov + +#include "Galois_Field_256.h" + +#ifdef __KERNEL__ +#include +u16 Module = 0x11B; +u8 ready_to_work = 0; +#else +#include +uint16_t Module = 0x11B; +uint8_t ready_to_work = 0; +#endif + +#define ORDER 256 + +GF256_t alogs[ORDER]; +GF256_t logs[ORDER]; + +void GF256_init(void) { + // порождающий элемент x + 1 + GF256_t elem = 1; // (x + 1)**0 + + for (int i = 0; i < ORDER - 1; i++) { + alogs[i] = elem; // <=> (x + 1)**i = elem + logs[elem] = i; + + uint16_t new_elem = (uint16_t)elem << 1; // <=> new_elem = elem * x + + new_elem ^= elem; // <=> new_elem = elem * x + elem <=> new_elem = elem * (x + 1) + + if (new_elem >= 0x100) { + new_elem ^= Module; + } + elem = (GF256_t)(new_elem); + } + alogs[ORDER - 1] = alogs[0]; + + logs[0] = 0; + + ready_to_work = 1; +} + +GF256_t GF256_Add(GF256_t a, GF256_t b) { + return a ^ b; +} + +GF256_t GF256_Sub(GF256_t a, GF256_t b) { + return a ^ b; +} + +GF256_t GF256_Mul(GF256_t a, GF256_t b) { + if (!ready_to_work) { + GF256_init(); + } + if (a == 0 || b == 0) { + return 0; + } + + uint8_t log_a = logs[a]; + uint8_t log_b = logs[b]; + + uint16_t sum = (log_a + log_b) % (ORDER - 1); + + return alogs[sum]; +} + +GF256_t inverse_mul_element(GF256_t a) { + if (a == 0) { + return 0; + } + if (!ready_to_work) { + GF256_init(); + } + return alogs[255 - logs[a]]; +} + +GF256_t GF256_Div(GF256_t a, GF256_t b) { + return GF256_Mul(a, inverse_mul_element(b)); +} \ No newline at end of file diff --git a/Galois_Field_256.h b/Galois_Field_256.h new file mode 100644 index 0000000..ab4b60a --- /dev/null +++ b/Galois_Field_256.h @@ -0,0 +1,24 @@ + +// SPDX-License-Identifier: MIT +// Copyright (c) 2026 Denis Potapov + +#ifndef Galois_Field_256 +#define Galois_Field_256 + +#ifdef __KERNEL__ +#include +typedef u8 GF256_t; +#else +#include +typedef uint8_t GF256_t; +#endif + +GF256_t GF256_Add(GF256_t a, GF256_t b); + +GF256_t GF256_Sub(GF256_t a, GF256_t b); + +GF256_t GF256_Mul(GF256_t a, GF256_t b); + +GF256_t GF256_Div(GF256_t a, GF256_t b); + +#endif \ No newline at end of file From 38f2fdf1e3a464417f9e95ecbabddb681003136f Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 29 Mar 2026 00:36:05 +0300 Subject: [PATCH 17/21] sync: update changes from dependency lib --- lib.c | 96 ----------------------------------------------------------- lib.h | 18 ----------- 2 files changed, 114 deletions(-) delete mode 100644 lib.c delete mode 100644 lib.h diff --git a/lib.c b/lib.c deleted file mode 100644 index 982622a..0000000 --- a/lib.c +++ /dev/null @@ -1,96 +0,0 @@ - -#include "lib.h" -#ifdef __KERNEL__ -#include -u16 Module = 0x11B; -u8 ready_to_work = 0; -#else -#include -uint16_t Module = 0x11B; -uint8_t ready_to_work = 0; -#endif - -#define ORDER 256 - -GF256_t alogs[ORDER]; -GF256_t logs[ORDER]; - -void GF256_init(void) -{ - GF256_t g = 0x03; - GF256_t x = 1; - - for (int i = 0; i < ORDER - 1; i++) - { - alogs[i] = x; - logs[x] = i; - - uint16_t prod = x << 1; - if (prod & 0x100) - { - prod ^= Module; - } - prod ^= x; - x = (GF256_t)(prod & 0xFF); - } - alogs[ORDER - 1] = alogs[0]; - logs[0] = 0; - - ready_to_work = 1; -} - -GF256_t GF256_Add(GF256_t a, GF256_t b) -{ - return a ^ b; -} - -GF256_t GF256_Sub(GF256_t a, GF256_t b) -{ - return a ^ b; -} - -GF256_t GF256_Mul(GF256_t a, GF256_t b) -{ - if (!ready_to_work) - { - GF256_init(); - } - - if (a == 0 || b == 0) - { - return 0; - } - - uint8_t log_a = logs[a]; - uint8_t log_b = logs[b]; - - uint8_t sum = 0; - if ((uint8_t)(ORDER - 1) - log_a < log_b) - { - sum = log_a - (ORDER - 1 - log_b); - } - else - { - sum = log_a + log_b; - } - - return alogs[sum]; -} - -static GF256_t inverse_mul_element(GF256_t a) -{ - if (!ready_to_work) - { - GF256_init(); - } - if (a == 0) - { - return 0; - } - return alogs[255 - logs[a]]; -} - -GF256_t GF256_Div(GF256_t a, GF256_t b) -{ - return GF256_Mul(a, inverse_mul_element(b)); -} diff --git a/lib.h b/lib.h deleted file mode 100644 index 22e07c1..0000000 --- a/lib.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef LIB_H -#define LIB_H - -#ifdef __KERNEL__ -#include -typedef u8 GF256_t; -#else -#include -typedef uint8_t GF256_t; -#endif - -void GF256_init(void); -GF256_t GF256_Add(GF256_t a, GF256_t b); -GF256_t GF256_Sub(GF256_t a, GF256_t b); -GF256_t GF256_Mul(GF256_t a, GF256_t b); -GF256_t GF256_Div(GF256_t a, GF256_t b); - -#endif From e3a5d8e0c3a9727daadddd4d07bf7572953655d0 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 29 Mar 2026 00:37:02 +0300 Subject: [PATCH 18/21] refactor: cosmetic changes --- Makefile | 10 +++++----- README.md | 8 ++++---- assets/polynom_file.bin | Bin 256 -> 0 bytes driver.c | 2 +- prandom.c | 2 +- prandom.h | 2 +- test.c | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) delete mode 100644 assets/polynom_file.bin diff --git a/Makefile b/Makefile index 202a979..ea6600a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ obj-m += gfrandom.o -gfrandom-objs := driver.o prandom.o lib.o +gfrandom-objs := driver.o prandom.o Galois_Field_256.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) @@ -10,11 +10,11 @@ all: clean: $(MAKE) -C $(KDIR) M=$(PWD) clean -test_algo: test.c lib.c prandom.c - gcc -o test test.c lib.c prandom.c +test_algo: test.c Galois_Field_256.c prandom.c + gcc -o test test.c Galois_Field_256.c prandom.c -test_sanitized: test.c lib.c prandom.c - gcc -o test test.c lib.c prandom.c -fsanitize=address,undefined -g +test_sanitized: test.c Galois_Field_256.c prandom.c + gcc -o test test.c Galois_Field_256.c prandom.c -fsanitize=address,undefined -g test: test_algo ./test diff --git a/README.md b/README.md index e413bd7..b714f3c 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,13 @@ Linux kernel модуль, предоставляющий генератор п Используется регистр сдвига с линейной обратной связью (LFSR) над полем GF(2⁸): - Состояние: 256 байт (коэффициенты) -- Полином: t^256 + t^10 + t^5 + t^2 + 1 (или пользовательский) -- Генерируемое значение: сумма произведений ненулевых коэффициентов полинома на соответствующие коэффициенты состояния +- Начальное состояние (seed): t^256 + t^10 + t^5 + t^2 + 1 (или пользовательский) +- Генерируемое значение: сумма произведений ненулевых коэффициентов состояния на соответствующие коэффициенты ### Используемые компоненты - **gfrandom** — драйвер (GPL-3.0) -- **lib** — [библиотека для работы с полями Галуа](https://github.com/DenisPotapov0/Galua-Field-library) (MIT License) +- **Galois_Field_256** — [библиотека для работы с полями Галуа](https://github.com/DenisPotapov0/Galua-Field-library) (MIT License) ## Требования @@ -93,7 +93,7 @@ make test ## Лицензия - **gfrandom**: GPL-3.0 -- **lib** (Denis Potapov): MIT License +- **Galois_Field_256** (Denis Potapov): MIT License Подробности см. в [LICENSE](LICENSE). diff --git a/assets/polynom_file.bin b/assets/polynom_file.bin deleted file mode 100644 index f459d91a31b9d7db0be2954102335bf734df6f62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 256 TcmZQ%U}OLxC;?)OB)|v&1n>X` diff --git a/driver.c b/driver.c index 7ddc642..e31dff4 100644 --- a/driver.c +++ b/driver.c @@ -31,7 +31,7 @@ #include #include -#include "lib.h" +#include "Galois_Field_256.h" #include "prandom.h" #define DEVICE_NAME "gfrandom" diff --git a/prandom.c b/prandom.c index 7d057cb..a5be38c 100644 --- a/prandom.c +++ b/prandom.c @@ -1,6 +1,6 @@ #include "prandom.h" -#include "lib.h" +#include "Galois_Field_256.h" void gf256_gprn_init_t(struct gf256_gprn* gprn, GF256_t* coeff_data, GF256_t* seed_data) { diff --git a/prandom.h b/prandom.h index f434195..79c86f1 100644 --- a/prandom.h +++ b/prandom.h @@ -12,7 +12,7 @@ #else #include #endif -#include "lib.h" +#include "Galois_Field_256.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) diff --git a/test.c b/test.c index 3b14dc4..22d906e 100644 --- a/test.c +++ b/test.c @@ -3,7 +3,7 @@ #include #include -#include "lib.h" +#include "Galois_Field_256.h" #include "prandom.h" #define NUM_BYTES 10 From 3736c3dd0cb79bf35196d141947f4f83e1a7647f Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 29 Mar 2026 18:25:41 +0300 Subject: [PATCH 19/21] optimization: up kernel_buf size from 256 to 1024 --- driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver.c b/driver.c index e31dff4..ea3a6cb 100644 --- a/driver.c +++ b/driver.c @@ -110,7 +110,7 @@ static int gprn_init_t(struct gf256_gprn* gprn) static ssize_t misc_read(struct file* filp, char __user* buf, size_t length, loff_t* f_pos) { - GF256_t kernel_buf[256]; + GF256_t kernel_buf[1024]; size_t bytes_to_read = length; size_t chunk; From 00be63a187dfa374ed025b1198771da75b931936 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 29 Mar 2026 18:26:05 +0300 Subject: [PATCH 20/21] feature: new test (#3) - chi-squared test --- test.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/test.c b/test.c index 22d906e..758d427 100644 --- a/test.c +++ b/test.c @@ -103,6 +103,53 @@ static int test2_without_seed(void) return 0; } +// тест на равномерность чисел +static int test3_chi_squared(void) +{ + int TEST_SIZE = 1024 * 1024; + GF256_t coeff[POLY_DEGREE]; + GF256_t* data = malloc(TEST_SIZE); + if (!data) + { + printf("failed to allocate memory\n"); + return -1; + } + if (read_file("assets/coeff_file.bin", coeff, POLY_DEGREE) != 0) + { + printf("failed to read coeff_file\n"); + free(data); + return -1; + } + struct gf256_gprn gprn; + gf256_gprn_init_t(&gprn, coeff, NULL); + gf256_gprn_generate(&gprn, TEST_SIZE, data); + int observed[256] = {0}; + for (size_t i = 0; i < TEST_SIZE; i++) + { + observed[data[i]]++; + } + + double expected = TEST_SIZE / 256.0; + double chi_sq = 0.0; + for (int i = 0; i < 256; i++) + { + double diff = observed[i] - expected; + chi_sq += (diff * diff) / expected; + } + free(data); + double chi_critical = 293.0; + if (chi_sq < chi_critical) + { + printf("✅ Chi-squared test passed (χ² = %.2f < %.2f)\n", chi_sq, chi_critical); + return 0; + } + else + { + printf("❌ Chi-squared test failed (χ² = %.2f >= %.2f)\n", chi_sq, chi_critical); + return -1; + } +} + int main(void) { int result = 0; @@ -121,6 +168,13 @@ int main(void) return 1; } + result = test3_chi_squared(); + if (result != 0) + { + printf("test3 failed\n"); + return 1; + } + printf("All tests passed\n"); return 0; } From 8cfdc196b418809d3e0e53cc491305212212a913 Mon Sep 17 00:00:00 2001 From: Makar Lill Date: Sun, 29 Mar 2026 21:39:20 +0300 Subject: [PATCH 21/21] fix: ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19b7d97..14dd333 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: run: sudo apt-get update && sudo apt-get install -y gcc make clang - name: Static analysis - run: clang-tidy prandom.c lib.c test.c -- -I. + run: clang-tidy prandom.c Galois_Field_256.c test.c -- -I. - name: Build driver run: make