1
0

migration

This commit is contained in:
2025-04-29 22:08:00 +03:00
commit ad28507008
232 changed files with 12299 additions and 0 deletions

View File

@ -0,0 +1,2 @@
Викладач: Мельникова Р. В.
Оцінка: 96

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

View File

@ -0,0 +1,692 @@
// Academic aliases {{{1
/// subject abbreviations to full names
#let subjects = (
"БД": "Бази даних",
"ОПНJ": "Основи програмування на Java",
"ОС": "Операційні системи",
"ПП": "Проектний практикум",
"СПМ": "Скриптові мови програмування",
"Ф": "Філософія",
)
/// education program abbreviations to name & number
#let edu_programs = (
"ПЗПІ": (
name: "Інженерія програмного забезпечення",
number: 121, // TODO: ПЗПІ is "F2" now
),
)
// Template formatting functions {{{1
/// numberless heading
#let nheading(title) = heading(depth: 1, numbering: none, title)
/// fill horizontal space with a box and not an empty space
#let hfill(width) = box(width: width, repeat("")) // NOTE: This is a HAIR SPACE (U+200A), not a regular space
/// make underlined cell with filled value
#let uline(align: center, content) = underline[
#if align != left { hfill(1fr) }
#content
#if align != right { hfill(1fr) }
]
/// bold text
#let bold(content) = text(weight: "bold")[#content]
/// month name from its number
#let month_gen(month) = (
"січня",
"лютого",
"березня",
"квітня",
"травня",
"червня",
"липня",
"серпня",
"вересня",
"жовтня",
"листопада",
"грудня",
).at(month - 1)
// Helper functions {{{1
/// captioned image with label derived from path:
/// - "image.png" = @image
/// - "img/image.png" = @image
/// - "img/foo/image.png" = @foo_image
/// - "img/foo/foo_image.png" = @foo_image
/// the caption will be modified based on a conditional positional value:
/// - `none`: no change
/// - some value: "`caption` (за даними `value`)"
/// - no value: "`caption` (рисунок виконано самостійно)"
/// additional named arguments will be passed to original `image` function
#let img(path, caption, ..sink) = {
let parts = path.split(".").first().split("/")
let label_string = if parts.len() <= 2 or parts.at(-1).starts-with(parts.at(-2)) {
// ("image",), (_, "image") and (.., "img", "img_image")
parts.last()
} else {
// (.., "img", "image") = "img_image"
parts.at(-2) + "_" + parts.at(-1)
}.replace(" ", "_")
let caption = if sink.pos().len() == 0 {
caption + " (рисунок виконано самостійно)"
} else if sink.pos().first() == none {
caption
} else {
[#caption (за даними #sink.pos().first())]
}
[#figure(image(path, ..sink.named()), caption: caption) #label(label_string)]
}
// Styling {{{1
/// NOTE: may be wrong
#let ua_alpha_numbering = "абвгдежиклмнпрстуфхцшщюя".split("") // 0 = "", 1 = "а"
// general outlook {{{2
// spacing between lines
#let spacing = 0.95em
#let style(it) = {
set page(
paper: "a4",
margin: (top: 20mm, right: 10mm, bottom: 20mm, left: 25mm),
number-align: top + right,
numbering: (..numbers) => {
if numbers.pos().at(0) != 1 {
numbering("1", numbers.pos().at(0))
}
},
)
set text(font: ("Times New Roman", "Liberation Serif"), size: 14pt, hyphenate: false, lang: "uk")
set par(justify: true, first-line-indent: (amount: 1.25cm, all: true))
set underline(evade: false)
// set 1.5 line spacing
set block(spacing: spacing)
set par(spacing: spacing)
set par(leading: spacing)
// enums and lists {{{2
set enum(numbering: i => { ua_alpha_numbering.at(i) + ")" }, indent: 1.25cm, body-indent: 0.5cm)
show enum: it => {
set enum(indent: 0em, numbering: "1)")
it
}
set list(indent: 1.35cm, body-indent: 0.5cm, marker: [--])
// figures {{{2
show figure: it => {
v(spacing * 2, weak: true)
it
v(spacing * 2, weak: true)
}
set figure.caption(separator: [ -- ])
show figure.where(kind: table): set figure.caption(position: top)
show figure.caption.where(kind: table): set align(left)
// figure numbering
show heading.where(level: 1): it => {
counter(math.equation).update(0)
counter(figure.where(kind: image)).update(0)
counter(figure.where(kind: table)).update(0)
counter(figure.where(kind: raw)).update(0)
it
}
set math.equation(numbering: (..num) => numbering("(1.1)", counter(heading).get().at(0), num.pos().first()))
set figure(numbering: (..num) => numbering("1.1", counter(heading).get().at(0), num.pos().first()))
// appearance of references to images and tables {{{2
set ref(
supplement: it => {
if it == none or not it.has("kind") {
it
} else if it.kind == image {
"див. рис."
} else if it.kind == table {
"див. таблицю"
} else {
it
}
},
)
show ref: it => {
let el = it.element
if el == none or not el.has("kind") {
return it
}
if el.kind != image and el.kind != table {
return it
}
[(#it)]
}
// headings {{{2
set heading(numbering: "1.1")
show heading.where(level: 1): it => {
set align(center)
set text(size: 14pt, weight: "semibold")
pagebreak(weak: true)
upper(it)
v(spacing * 2, weak: true)
}
show heading.where(level: 2): it => {
set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[
#h(1.25cm)
#counter(heading).display(it.numbering)
#it.body
]
v(spacing * 2, weak: true)
}
show heading.where(level: 3): it => {
set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[
#h(1.25cm)
#counter(heading).display(it.numbering)
#it.body
]
v(spacing * 2, weak: true)
}
it
}
// Coursework template {{{1
/// DSTU 3008:2015 Template for NURE
/// -> content
/// - doc (content): Content to apply the template to.
/// - title (str): Title of the document.
/// - subject_shorthand (str): Subject short name.
/// - department_gen (str): Department name in genitive form.
/// - authors ((name: str, full_name_gen: str, variant: int, group: str, gender: str),): List of Authors dicts.
/// - mentors ((name: str, gender: str, degree: str),): List of mentors dicts.
/// - edu_program_shorthand (str): Education program shorthand.
/// - task_list (done_date: datetime, initial_date: datetime, source: (content | str), content: (content | str), graphics: (content | str)): Task list object.
/// - calendar_plan ( plan_table: (content | str), approval_date: datetime): Calendar plan object.
/// - abstract (keywords: (str, ), text: (content | str)): Abstract object.
/// - bib_path path: Path to the bibliography yaml file.
/// - appendices (content): Content with appendices.
#let cw-template(
doc,
title: "NONE",
subject_shorthand: "NONE",
department_gen: "Програмної інженерії",
author: (),
mentors: (),
edu_program_shorthand: "ПЗПІ",
task_list: (),
calendar_plan: (),
abstract: (),
bib_path: "bibl.yml",
appendices: (),
) = {
set document(title: title, author: author.name)
show: style
let bib-count = state("citation-counter", ())
show cite: it => {
it
bib-count.update(((..c)) => (..c, it.key))
}
show bibliography: it => {
set text(size: 0pt)
it
}
let head_mentor = mentors.at(0)
let edu_program = edu_programs.at(edu_program_shorthand)
// page 1 {{{2
[
#set align(center)
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ
\
Кафедра Програмної інженерії
\
ПОЯСНЮВАЛЬНА ЗАПИСКА
ДО КУРСОВОЇ РОБОТИ
з дисципліни: "#subjects.at(subject_shorthand, default: "NONE")"
Тема роботи: "#title"
\ \ \
#columns(2, gutter: 4cm)[
#set align(left)
#if author.gender == "m" { [Виконав\ ] } else { [Виконала\ ] } ст. гр. #author.group
\
Керівник:\
#head_mentor.degree
\
Робота захищена на оцінку
\
Комісія:\
#for mentor in mentors {
[#mentor.degree\
]
}
#colbreak()
#set align(left)
\
#author.name
\ \
#head_mentor.name
\
#underline(" " * 35)
\ \
#for mentor in mentors {
[#mentor.name\
]
}
]
#v(1fr)
Харків -- #task_list.done_date.display("[year]")
#pagebreak()
]
// page 2 {{{2
{
uline[Харківський національний університет радіоелектроніки]
linebreak()
linebreak()
grid(
columns: (100pt, 1fr),
bold[
Кафедра
Дисципліна
Спеціальність
],
{
uline(align: left, department_gen)
linebreak()
uline(align: left, subjects.at(subject_shorthand))
linebreak()
uline(align: left, [#edu_program.number #edu_program.name])
},
)
grid(
columns: (1fr, 1fr, 1fr),
gutter: 0.3fr,
[#bold[Курс] #uline(2)], [#bold[Група] #uline(author.group)], [#bold[Семестр] #uline(3)],
)
linebreak()
linebreak()
linebreak()
align(center, bold[ЗАВДАННЯ \ на курсову роботу студента])
linebreak()
uline(align: left)[_#author.full_name_gen _]
linebreak()
linebreak()
bold[\1. Тема роботи:]
uline[#title.]
linebreak()
{
bold[\2. Строк здачі закінченої роботи:]
uline(task_list.done_date.display("[day].[month].[year]"))
hfill(10fr)
}
linebreak()
bold[\3. Вихідні дані для роботи:]
uline(task_list.source)
linebreak()
bold[\4. Зміст розрахунково-пояснювальної записки:]
uline(task_list.content)
linebreak()
bold[\5. Перелік графічного матеріалу:]
uline(task_list.graphics)
linebreak()
{
bold[\6. Дата видачі завдання:]
uline(task_list.initial_date.display("[day].[month].[year]"))
hfill(10fr)
}
pagebreak()
}
// page 3 {{{2
{
align(center, bold[КАЛЕНДАРНИЙ ПЛАН])
set par(first-line-indent: 0pt)
linebreak()
calendar_plan.plan_table
linebreak()
grid(
columns: (5fr, 5fr),
grid(
columns: (1fr, 2fr, 1fr),
gutter: 0.2fr,
[
Студент \
Керівник \
#align(center)["#underline[#calendar_plan.approval_date.day()]"]
],
[
#uline(align: center, []) \
#uline(align: center, []) \
#uline(align: center, month_gen(calendar_plan.approval_date.month()))
],
[
\ \
#underline[#calendar_plan.approval_date.year()] р.
],
),
[
#author.name, \
#head_mentor.degree
#head_mentor.name.
],
)
pagebreak()
}
// page 4 {{{2
[
#align(center, bold[РЕФЕРАТ]) \
#context [
#let pages = counter(page).final().at(0)
#let images = query(figure.where(kind: image)).len()
#let tables = query(figure.where(kind: table)).len()
#let bibs = bib-count.final().dedup().len()
/* TODO: why this stopped working?
#let tables = counter(figure.where(kind: table)).final().at(0)
#let images = counter(figure.where(kind: image)).final().at(0)*/
#let counters = ()
#if pages != 0 { counters.push[#pages с.] }
#if tables != 0 { counters.push[#tables табл.] }
#if images != 0 { counters.push[#images рис.] }
#if bibs != 0 { counters.push[#bibs джерел] }
Пояснювальна записка до курсової роботи: #counters.join(", ").
]
\
#{
let keywords = abstract.keywords.map(upper)
let is_cyrillic = word => word.split("").any(char => ("А" <= char and char <= "я"))
let n = keywords.len()
for i in range(n) {
for j in range(0, n - i - 1) {
if (
(not is_cyrillic(keywords.at(j)) and is_cyrillic(keywords.at(j + 1)))
or (
is_cyrillic(keywords.at(j)) == is_cyrillic(keywords.at(j + 1)) and keywords.at(j) > keywords.at(j + 1)
)
) {
(keywords.at(j), keywords.at(j + 1)) = (keywords.at(j + 1), keywords.at(j))
}
}
}
keywords.join(", ")
}
\
#abstract.text
]
// page 5 {{{2
outline(
title: [
ЗМІСТ
#v(spacing * 2, weak: true)
],
depth: 2,
indent: auto,
)
doc
// bibliography {{{2
{
heading(depth: 1, numbering: none)[Перелік джерел посилання]
bibliography(
bib_path,
style: "ieee",
full: true,
title: none,
)
let bib_data = yaml(bib_path)
let format-entry(citation) = {
if (citation.type == "Web") {
let date_array = citation.url.date.split("-")
let date = datetime(
year: int(date_array.at(0)),
month: int(date_array.at(1)),
day: int(date_array.at(2)),
)
[
#citation.title.
#citation.author.
URL: #citation.url.value (дата звернення: #date.display("[day].[month].[year]")).
]
} else if citation.type == "Book" [
#citation.author
#citation.title.
#citation.publisher,
#citation.date.
#citation.page-total c.
] else [
UNSUPPORTED BIBLIOGRAPHY ENTRY TYPE, PLEASE OPEN AN ISSUE
]
}
show enum.item: it => {
set par(first-line-indent: 0pt)
box(width: 1.25cm)
box(width: 1em + 0.5cm)[#it.number.]
it.body
linebreak()
}
context {
for (i, citation) in query(ref.where(element: none)).map(r => str(r.target)).dedup().enumerate() {
enum.item(
i + 1,
format-entry(bib_data.at(citation)),
)
}
}
}
// appendices {{{2
{
counter(heading).update(0)
set heading(
numbering: (i, ..nums) => {
let char = upper(ua_alpha_numbering.at(i))
if nums.pos().len() == 0 { char } else {
char + "." + nums.pos().map(str).join(".")
}
},
)
show heading.where(level: 1): it => {
set align(center)
set text(size: 14pt, weight: "regular")
pagebreak(weak: true)
bold[ДОДАТОК #counter(heading).display(it.numbering)]
linebreak()
it.body
v(spacing * 2, weak: true)
}
show heading.where(level: 2): it => {
set text(size: 14pt, weight: "regular")
v(spacing * 2, weak: true)
block(width: 100%, spacing: 0em)[
#h(1.25cm)
#counter(heading).display(it.numbering)
#it.body
]
v(spacing * 2, weak: true)
}
appendices
}
}
// Laboratory work template {{{1
/// DSTU 3008:2015 Template for NURE
/// -> content
/// - doc (content): Content to apply the template to.
/// - doctype ("ЛБ" | "ПЗ"): Document type.
/// - title (str): Title of the document.
/// - subject_shorthand (str): Subject short name.
/// - department_gen (str): Department name in genitive form.
/// - worknumber (int): Number of the work, can be omitted.
/// - authors ((name: str, full_name_gen: str, variant: int, group: str, gender: str),): List of Authors dicts.
/// - mentor (name: str, gender: str, degree: str): Mentors objects.
#let lab-pz-template(
doc,
doctype: "NONE",
title: "NONE",
subject_shorthand: "NONE",
department_gen: "Програмної інженерії",
worknumber: 1,
authors: (),
mentor: (),
) = {
set document(title: title, author: authors.at(0).name)
show: style
context counter(heading).update(worknumber - 1)
// page 1 {{{2
align(center)[
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ \
ХАРКІВСЬКИЙ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ РАДІОЕЛЕКТРОНІКИ
\ \
Кафедра #department_gen
\ \ \
Звіт \
з
#if doctype == "ЛБ" [лабораторної роботи] else [практичної роботи]
#if worknumber != none [ #worknumber]
з дисципліни: "#subjects.at(subject_shorthand, default: "UNLNOWN SUBJECT, PLEASE OPEN AN ISSUE")"
з теми: "#title"
\ \ \ \
#columns(2)[
#set align(left)
#set par(first-line-indent: 0pt)
#if authors.len() == 1 {
let author = authors.at(0)
if author.gender == "m" [Виконав:\ ] else [Виконала:\ ]
[
ст. гр. #author.group\
#author.name\
]
if author.variant != none [Варіант: #author.variant]
} else [
Виконали:\
ст. гр. #authors.at(0).group\
#authors.map(a => [ #a.name\ ])
]
#colbreak()
#set align(right)
#if mentor.gender == "m" { [Перевірив:\ ] } else { [Перевірила:\ ] }
#mentor.degree #if mentor.degree.len() >= 15 [\ ]
#mentor.name\
]
#v(1fr)
Харків -- #datetime.today().display("[year]")
]
pagebreak(weak: true)
heading(title)
doc
}
// vim:sts=2:sw=2:fdl=0:fdm=marker:cms=/*%s*/

View File

@ -0,0 +1,24 @@
# CompileFlags:
# Add:
# - -I/usr/x86_64-w64-mingw32/include
# - -I/usr/x86_64-w64-mingw32/include/w32api
# - -DUNICODE
# - -D_UNICODE
CompileFlags:
Add: [-Wall, -Wextra, -std=c++17, -DBUILD_SHARED, --target=x86_64-w64-mingw32]
CompilationDatabase: build/
Diagnostics:
UnusedIncludes: Strict
InlayHints:
Enabled: Yes
ParameterNames: Yes
DeducedTypes: Yes
Index:
Background: Build
Hover:
ShowAKA: Yes

View File

@ -0,0 +1,28 @@
cc := "x86_64-w64-mingw32-clang++"
flags := "-Wall -Wextra -std=c++17"
@clean:
rm -rf build
@makedir-build: clean
mkdir -p build
@build-lib-shared: makedir-build
{{cc}} {{flags}} -D BUILD_SHARED --shared -Wl,--out-implib,build/rsa.lib library/rsa.cpp -o build/rsa.dll
@build-app-shared: build-lib-shared
{{cc}} {{flags}} application/main.cpp -L build -l rsa -o build/main.exe
@build-lib-static: makedir-build
{{cc}} {{flags}} -c -D BUILD_SHARED library/rsa.cpp -o build/rsa.o
ar rcs build/rsa.lib build/rsa.o
@build-app-static: build-lib-static
{{cc}} {{flags}} -D BUILD_STATIC application/main.cpp -L build -l rsa -o build/main.exe
@run:
wine cmd /c build/main.exe
run-shared: build-app-shared run
run-static: build-app-static run

View File

@ -0,0 +1,74 @@
#include <stdint.h>
#include <stdio.h>
#include "../library/rsa.h"
char *int128_to_str(__int128_t n) {
static char str[41] = {0};
char *s = str + sizeof(str) - 1;
bool neg = n < 0;
if (neg)
n = -n;
do {
*--s = "0123456789"[n % 10];
n /= 10;
} while (n);
if (neg)
*--s = '-';
return s;
}
int main() {
// uint64_t p0 = 8589934609, q0 = 2147483693, e0 = 65537;
// uint64_t p1 = 2147483659, q1 = 8589934621, e1 = 65537;
uint32_t p0 = 2147483659, q0 = 2147483693, e0 = 65537; // pair_0
uint32_t p1 = 2147483659, q1 = 2147483693, e1 = 65537; // pair_1
rsa_Pair pair_0 = rsa_gen_pair(p0, q0, e0);
rsa_Pair pair_1 = rsa_gen_pair(p1, q1, e1);
printf("pair_0:\n");
printf("- e:\t%s\n", int128_to_str(pair_0.e));
printf("- d:\t%s\n", int128_to_str(pair_0.d));
printf("- n:\t%s\n", int128_to_str(pair_0.n));
printf("pair_1:\n");
printf("- e:\t%s\n", int128_to_str(pair_1.e));
printf("- d:\t%s\n", int128_to_str(pair_1.d));
printf("- n:\t%s\n", int128_to_str(pair_1.n));
uint64_t t[] = {4096, 17, 8, 65500, 0x9fffffff};
for (size_t i = 0; i < 5; i++) {
printf("- - - - - - - - - - - - - - - - - -\n");
printf("t[%zu]:\t\t%lld\n", i, t[i]);
__int128_t e1t = rsa_encrypt(t[i], pair_0.e, pair_0.n);
printf("e1t:\t\t%s\n", int128_to_str(e1t));
__int128_t d1e1t = rsa_decrypt(e1t, pair_0.d, pair_0.n);
printf("d1e1t\t\t%s\n", int128_to_str(d1e1t));
if (d1e1t != t[i]) {
fprintf(stderr, "Error: decrypt[i]on failed - expected: %llu; got: %s\n",
t[i], int128_to_str(d1e1t));
return 1;
}
__int128_t e0d1e1t = rsa_encrypt(t[i], pair_1.e, pair_1.n);
printf("e0d1e1t:\t%s\n", int128_to_str(e0d1e1t));
__int128_t d0e0d1e1t = rsa_decrypt(e0d1e1t, pair_1.d, pair_1.n);
printf("d0e0d1e1t:\t%s\n", int128_to_str(d0e0d1e1t));
if (d0e0d1e1t != t[i]) {
fprintf(stderr, "Error: decrypt[i]on failed - expected: %llu; got: %s\n",
t[i], int128_to_str(d0e0d1e1t));
return 1;
}
}
return 0;
}

View File

@ -0,0 +1,78 @@
#include "rsa.h"
__int128_t mul_mod(__int128_t a, __int128_t b, __int128_t mod) {
__int128_t res = 0;
a %= mod;
while (b > 0) {
if (b & 1)
res = (res + a) % mod;
a = (a << 1) % mod;
b >>= 1;
}
return res;
}
__int128_t pow_mod(__int128_t base, __int128_t exp, __int128_t mod) {
__int128_t res = 1;
base %= mod;
while (exp > 0) {
if (exp & 1)
res = mul_mod(res, base, mod);
base = mul_mod(base, base, mod);
exp >>= 1;
}
return res;
}
__int128_t mod_inverse(__int128_t e, __int128_t phi) {
__int128_t a = e, b = phi;
__int128_t x = 1, y = 0;
__int128_t x1 = 0, y1 = 1;
__int128_t q, temp;
while (b != 0) {
q = a / b;
temp = a % b;
a = b;
b = temp;
temp = x - q * x1;
x = x1;
x1 = temp;
temp = y - q * y1;
y = y1;
y1 = temp;
}
if (x < 0)
x += phi;
return x;
}
rsa_Pair rsa_gen_pair(__int128_t p, __int128_t q, __int128_t e) {
rsa_Pair pair;
pair.e = e;
pair.n = p * q;
__int128_t phi = (p - 1) * (q - 1);
pair.d = mod_inverse(e, phi);
return pair;
}
__int128_t rsa_encrypt(__int128_t data, __int128_t e, __int128_t n) {
return pow_mod(data, e, n);
}
__int128_t rsa_decrypt(__int128_t data, __int128_t d, __int128_t n) {
return pow_mod(data, d, n);
}

View File

@ -0,0 +1,35 @@
#ifndef RSA_LIB
#define RSA_LIB
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#ifdef BUILD_SHARED
#define BUILD_SPEC __declspec(dllexport)
#elif BUILD_STATIC
#define BUILD_SPEC
#else
#define BUILD_SPEC __declspec(dllimport)
#endif
#else
#define BUILD_SPEC
#endif
typedef struct {
__int128_t d;
__int128_t e;
__int128_t n;
} rsa_Pair;
BUILD_SPEC rsa_Pair rsa_gen_pair(__int128_t p, __int128_t q, __int128_t e);
BUILD_SPEC __int128_t rsa_encrypt(__int128_t data, __int128_t e, __int128_t n);
BUILD_SPEC __int128_t rsa_decrypt(__int128_t data, __int128_t d, __int128_t n);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,378 @@
#import "@local/nure:0.0.0": *
#show: lab-pz-template.with(
doctype: "ЛБ",
title: "Створення та використання бібліотек. Частина 1",
subject_shorthand: "ОС",
department_gen: "Програмної інженерії",
authors: (
(
name: "Ситник Є. С.",
full_name_gen: "Ситника Єгора Сергійовича",
group: "ПЗПІ-23-2",
gender: "m",
variant: none,
),
),
mentor: (
name: "Мельнікова Р. В.",
gender: "f",
degree: "доц. каф. ПІ",
),
worknumber: 2,
)
#v(-spacing)
== Мета роботи
Вивчити прийоми та методи створення та використання динамічних бібліотек.
== Хід роботи
#v(-spacing)
=== Визначите необхідні функції для реалізації алгоритму RSA. Визначите серед цих функцій ті, які повинні використовуватись в зовнішніх програмах
RSA -- це криптографічний алгоритм, який використовує пару ключів: відкритий і закритий. Відкритий ключ використовується для шифрування повідомлень, а закритий -- для їх розшифрування.
Для реалізації алгоритму RSA знадобиться мінімум 3 функції:
+ функція генерації ключів;
+ функція шифрування даних;
+ функція розшифрування даних.
Також для зручності має сенс створити структуру, що буде зберігати пару ключів.
Ці функції та структура будуть доступні користувачу бібліотеки для зовнішнього використання.
=== Складіть файл заголовків таким чином, щоб цей файл заголовків можна було б використовувати для динамічної бібліотеки та програм, які використовують бібліотеку
Для операційної системи Windows створення динамічних бібліотек вимагає визначення певних розширених атрибутів класів зберігання (extended storage-class attributes), а саме -- "dllimport" та "dllexport".
Для універсальності бібліотеки необхідно створити макрос, який буде автоматично встановлювати потрібні атрибути в залежності від режиму компіляції.
Можна виділити такі особливі випадки компіляції:
+ компіляція статичної бібліотеки для операційної системи Windows;
+ компіляція динамічної бібліотеки для операційної системи Windows;
+ компіляція бібліотеки для інших операційних систем;
+ компіляція бібліотеки для використання із C;
+ компіляція бібліотеки для використання із C++.
Для визначення режиму компіляції використаємо макроси, які повинен вказати користувач, та стандартні макроси та вирази, що надає компілятор.
Також не варто забувати про можливість підключення користувачем файлу заголовків в кількох місцях. Існує кілька способів запобігання подібним ситуаціям, найкращим для цієї бібліотеки буде використання макросу, який запобігатиме повторному включенню файлу заголовків, адже цей спосіб не залежить від компілятора, що використовується.
Всі файли, що стосуються бібліотеки (файл заголовків "rsa.h" та файл реалізації "rsa.cpp") знаходитимуться в директорії "library".
#figure(image("img/header.png", width: 80%), caption: [Файл заголовків "rsa.h"])
Для запобігання повторному включенню файлу заголовків використано конструкцію із макросом "RSA_LIB". Файл буде включено тільки перший раз, всі наступні рази препроцесор не включить вміст файлу, через визначений макрос.
Для можливості використання бібліотеки як із C, так і з C++ використано конструкцію "extern C", що включається у файл тільки за умови визначення макросу "\_\_cplusplus", що додається компілятором під час компіляції в режимі C++.
Для сумісності бібліотеки із різними операційними системами використано конструкцію із макросом "\_WIN32", що визначає необхідні атрибути лише під час компіляції для цільової платформи Windows.
Для визначення атрибутів під час статичної та динамічної компіляції використано конструкцію із макросами "BUILD_SHARED" та "BUILD_STATIC".
В залежності від результату виконання вище вказаних конструкцій буде визначено макрос "BUILD_SPEC", який використовується під час оголошення функцій для додавання необхідних атрибутів.
Для всіх функцій в якості типу аргументів та результату було використано тип "\_\_int128_t", що є найбільшим із стандартних типів на момент написання. Варто зазначити, що для шифрування RSA зазвичай використовують значно більші типи, реалізовані в спеціалізованих бібліотеках, таких як "OpenSSL BN" або "GNU Multiple Precision Arithmetic Library".
Оскільки C, на відміну від C++, не має вбудованої можливості ізолювати функції та змінні в просторах імен, кожна функція та структура починаються із назви бібліотеки, а саме -- "rsa".
=== Реалізуйте функції бібліотек
Перш за все необхідно реалізувати функцію створення пари ключів на основі переданих користувачем простих чисел та відкритої експоненти @gen_pair.
#figure(image("img/gen_pair.png", width: 100%), caption: [Функція "rsa\_gen\_pair"]) <gen_pair>
Далі реалізуємо функції шифрування та розшифрування @crypt.
#figure(image("img/crypt.png", width: 100%), caption: [Функції "rsa\_encrypt" та "rsa\_decrypt"]) <crypt>
Оскільки стандартна бібліотека С не включає необхідні математичні функції їх також необхідно реалізувати @math. Ці функції розраховані на внутрішнє використання, тому їх нема в файлі заголовків.
#figure(
image("img/math.png", width: 80%),
caption: [Математичні функції "mul\_mod", "pow\_mod" та "mod\_inverse"],
) <math>
=== Створіть динамічну бібліотеку
Оскільки я використовую операційну систему Arch Linux, у мене нема доступу до компілятора Microsoft MSVC. Натомість мною було використано компілятор Clang із проєкту LLVM, та набір інструментів MinGW, що забезпечують кросс-компіляцію для Windows на POSIX-сумісних операційних системах (Linux, MacOS, BSD і подібних).
Під час компіляції динамічної бібліотеки необхідно:
+ визначити макрос "BUILD_SHARED";
+ вказати прапорець "shared" для компілятора;
+ встановити значення, що відповідає назві бібліотеки, для прапорця "out-implib" для компонувальника.
Компілятор автоматично викликає компонувальник, передати аргументи для нього можна за допомогою прапорця "Wl".
Динамічні бібліотеки для Windows складаються з 2 компонентів:
+ файл із розширенням ".dll" в якому знаходиться реалізація бібліотеки;
+ файл із розширенням ".lib" в якому знаходиться інформація, необхідна для зв'язування програми та бібліотеки.
Для зручнішого управління проєктом має сенс використовувати систему збірки, та визначати всі команди компіляції за її допомогою. Я використаю систему збірки "Just" @just. Всі скомпільовані файли будуть знаходитись в директорії "build".
#figure(
image("img/just.png", width: 100%),
caption: [Вміст "Justfile" з інструкціями для збірки],
) <just>
Скомпілюємо бібліотеку та перевіримо результат @dll_build.
#figure(
image("img/dll_build.png", width: 100%),
caption: [Результат збірки динамічної бібліотеки],
) <dll_build>
Можемо побачити, що компіляція пройшла без помилок та попереджень, та після компіляції, як і очікувалося, ми отримали 2 файли бібліотеки.
=== Реалізуйте головну програму для динамічної бібліотеки для першого способу її використання
Відповідно умові реалізуємо програму із використанням функцій бібліотеки. Для доступу до них необхідно підключити файл заголовків бібліотеки.
Оберемо пари простих чисел та відкриті експоненти для створення 2 пар ключів, створимо пари, почергово перевіримо роботу функцій шифрування та дешифрування із 2 парами ключів на різних даних друкуючу в консоль результат кожного етапу.
Оскільки бібліотека розрахована на роботу із даними типу "\_\_int128_t", а стандартні функції друку в консоль не підтримують цей тип, додатково реалізуємо функцію для перетворення чисел такого типу на строки.
Всі файли, що стосуються програми (файл реалізації "main.cpp") знаходитимуться в директорії "application".
#figure(
image("img/main.png", width: 70%),
caption: [Вміст файлу "main.cpp"],
) <main>
== Висновки
Під час виконання даної лабораторної роботи я вивчив прийоми та методи створення та використання динамічних бібліотек.
#counter(heading).update(0)
#set heading(
numbering: (i, ..nums) => {
let char = upper(ua_alpha_numbering.at(i))
if nums.pos().len() == 0 { char } else {
char + "." + nums.pos().map(str).join(".")
}
},
)
#show heading.where(level: 1): it => {
set align(center)
set text(size: 14pt, weight: "regular")
pagebreak(weak: true)
bold[ДОДАТОК #counter(heading).display(it.numbering)]
linebreak()
it.body
v(spacing * 2, weak: true)
}
= Вміст файлу "rsa.h"
```
#ifndef RSA_LIB
#define RSA_LIB
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#ifdef BUILD_SHARED
#define BUILD_SPEC __declspec(dllexport)
#elif BUILD_STATIC
#define BUILD_SPEC
#else
#define BUILD_SPEC __declspec(dllimport)
#endif
#else
#define BUILD_SPEC
#endif
typedef struct {
__int128_t d;
__int128_t e;
__int128_t n;
} rsa_Pair;
BUILD_SPEC rsa_Pair rsa_gen_pair(__int128_t p, __int128_t q, __int128_t e);
BUILD_SPEC __int128_t rsa_encrypt(__int128_t data, __int128_t e, __int128_t n);
BUILD_SPEC __int128_t rsa_decrypt(__int128_t data, __int128_t d, __int128_t n);
#ifdef __cplusplus
}
#endif
#endif
```
= Вміст файлу "rsa.cpp"
```
#include "rsa.h"
__int128_t mul_mod(__int128_t a, __int128_t b, __int128_t mod) {
__int128_t res = 0;
a %= mod;
while (b > 0) {
if (b & 1)
res = (res + a) % mod;
a = (a << 1) % mod;
b >>= 1;
}
return res;
}
__int128_t pow_mod(__int128_t base, __int128_t exp, __int128_t mod) {
__int128_t res = 1;
base %= mod;
while (exp > 0) {
if (exp & 1)
res = mul_mod(res, base, mod);
base = mul_mod(base, base, mod);
exp >>= 1;
}
return res;
}
__int128_t mod_inverse(__int128_t e, __int128_t phi) {
__int128_t a = e, b = phi;
__int128_t x = 1, y = 0;
__int128_t x1 = 0, y1 = 1;
__int128_t q, temp;
while (b != 0) {
q = a / b;
temp = a % b;
a = b;
b = temp;
temp = x - q * x1;
x = x1;
x1 = temp;
temp = y - q * y1;
y = y1;
y1 = temp;
}
if (x < 0)
x += phi;
return x;
}
rsa_Pair rsa_gen_pair(__int128_t p, __int128_t q, __int128_t e) {
rsa_Pair pair;
pair.e = e;
pair.n = p * q;
__int128_t phi = (p - 1) * (q - 1);
pair.d = mod_inverse(e, phi);
return pair;
}
__int128_t rsa_encrypt(__int128_t data, __int128_t e, __int128_t n) {
return pow_mod(data, e, n);
}
__int128_t rsa_decrypt(__int128_t data, __int128_t d, __int128_t n) {
return pow_mod(data, d, n);
}
```
= Вміст файлу "main.cpp"
```
#include <stdint.h>
#include <stdio.h>
#include "../library/rsa.h"
char *int128_to_str(__int128_t n) {
static char str[41] = {0};
char *s = str + sizeof(str) - 1;
bool neg = n < 0;
if (neg)
n = -n;
do {
*--s = "0123456789"[n % 10];
n /= 10;
} while (n);
if (neg)
*--s = '-';
return s;
}
int main() {
uint64_t p0 = 8589934609, q0 = 2147483693, e0 = 65537;
uint64_t p1 = 2147483659, q1 = 8589934621, e1 = 65537;
rsa_Pair pair_0 = rsa_gen_pair(p0, q0, e0);
rsa_Pair pair_1 = rsa_gen_pair(p1, q1, e1);
printf("pair_0:\n");
printf("- e:\t%s\n", int128_to_str(pair_0.e));
printf("- d:\t%s\n", int128_to_str(pair_0.d));
printf("- n:\t%s\n", int128_to_str(pair_0.n));
printf("pair_1:\n");
printf("- e:\t%s\n", int128_to_str(pair_1.e));
printf("- d:\t%s\n", int128_to_str(pair_1.d));
printf("- n:\t%s\n", int128_to_str(pair_1.n));
uint64_t t[] = {22, 17, 2, 65500, 100};
for (size_t i = 0; i < 5; i++) {
printf("- - - - - - - - - - - - - - - - - -\n");
printf("t[%zu]:\t\t%lld\n", i, t[i]);
__int128_t e1t = rsa_encrypt(t[i], pair_0.e, pair_0.n);
printf("e1t:\t\t%s\n", int128_to_str(e1t));
__int128_t d1e1t = rsa_decrypt(e1t, pair_0.d, pair_0.n);
printf("d1e1t:\t\t%s\n", int128_to_str(d1e1t));
if (d1e1t != t[i]) {
fprintf(stderr, "Error: decrypt[i]on failed - expected: %llu; got: %s\n",
t[i], int128_to_str(d1e1t));
return 1;
}
__int128_t e0d1e1t = rsa_encrypt(t[i], pair_1.e, pair_1.n);
printf("e0d1e1t:\t%s\n", int128_to_str(e0d1e1t));
__int128_t d0e0d1e1t = rsa_decrypt(e0d1e1t, pair_1.d, pair_1.n);
printf("d0e0d1e1t:\t%s\n", int128_to_str(d0e0d1e1t));
if (d0e0d1e1t != t[i]) {
fprintf(stderr, "Error: decrypt[i]on failed - expected: %llu; got: %s\n",
t[i], int128_to_str(d0e0d1e1t));
return 1;
}
}
return 0;
}
```
= Вміст файлу "Justfile"
```
cc := "x86_64-w64-mingw32-clang++"
flags := "-Wall -Wextra -std=c++17"
@clean:
rm -rf build
@makedir-build: clean
mkdir -p build
@build-lib-shared: makedir-build
{{cc}} {{flags}} -D BUILD_SHARED --shared -Wl,--out-implib,build/rsa.lib library/rsa.cpp -o build/rsa.dll
@build-app-shared: build-lib-shared
{{cc}} {{flags}} application/main.cpp -L build -l rsa -o build/main.exe
```