Π‘ ΡΠ°Π·Π²ΠΈΡΠΈΠ΅ΠΌ ΠΊΠ²Π°Π½ΡΠΎΠ²ΡΡ ΠΊΠΎΠΌΠΏΡΡΡΠ΅ΡΠΎΠ² ΡΡΡΠ΅ΡΡΠ²ΡΡΡΠΈΠ΅ Π°Π»Π³ΠΎΡΠΈΡΠΌΡ ΡΠΈΡΡΠΎΠ²Π°Π½ΠΈΡ (RSA, ECC) ΡΡΠ°Π½ΡΡ ΡΡΠ·Π²ΠΈΠΌΡ. ΠΡ ΡΠ΅Π°Π»ΠΈΠ·ΡΠ΅ΠΌ ΠΊΠ²Π°Π½ΡΠΎΠ²ΠΎ-ΡΡΡΠΎΠΉΡΠΈΠ²ΡΠΉ Π°Π»Π³ΠΎΡΠΈΡΠΌ CRYSTALS-Kyber (Π½Π° ΠΎΡΠ½ΠΎΠ²Π΅ ΡΠ΅ΡΠ΅ΡΠΎΠΊ) Π½Π° ATmega328P!
Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ Kyber-512 (ΡΠΏΡΠΎΡΠ΅Π½Π½Π°Ρ Π²Π΅ΡΡΠΈΡ):
cpp
#include <avr/random.h>
#include <avr/pgmspace.h>
#define KYBER_N 256 // Π Π°Π·ΠΌΠ΅ΡΠ½ΠΎΡΡΡ ΡΠ΅ΡΠ΅ΡΠΊΠΈ
#define KYBER_Q 3329 // ΠΠΎΠ΄ΡΠ»Ρ
#define KYBER_K 2 // ΠΠ°ΡΠ°ΠΌΠ΅ΡΡ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡΠΈ
// ΠΠΎΠ»ΠΈΠ½ΠΎΠΌ (ΠΊΠΎΡΡΡΠΈΡΠΈΠ΅Π½ΡΡ ΠΏΠΎ ΠΌΠΎΠ΄ΡΠ»Ρ Q)
struct Poly {
int16_t coeffs[KYBER_N];
};
// ΠΠ°ΡΡΠΈΡΠ° ΠΏΠΎΠ»ΠΈΠ½ΠΎΠΌΠΎΠ²
struct PolyMatrix {
Poly rows[KYBER_K];
Poly cols[KYBER_K];
};
// ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ ΡΠ»ΡΡΠ°ΠΉΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΠΈΠ½ΠΎΠΌΠ°
void randomPoly(Poly* p) {
for (uint8_t i = 0; i < KYBER_N; i++) {
p->coeffs[i] = random(KYBER_Q);
}
}
// Π£ΠΌΠ½ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ»ΠΈΠ½ΠΎΠΌΠΎΠ² (Π±ΡΡΡΡΠΎΠ΅ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΠ’Π’)
void polyMul(Poly* a, Poly* b, Poly* result) {
// Π£ΠΏΡΠΎΡΠ΅Π½Π½Π°Ρ Π²Π΅ΡΡΠΈΡ (Π±Π΅Π· NTT Π΄Π»Ρ ΡΠΊΠΎΠ½ΠΎΠΌΠΈΠΈ RAM)
for (uint8_t i = 0; i < KYBER_N; i++) {
int32_t sum = 0;
for (uint8_t j = 0; j < KYBER_N; j++) {
sum += (int32_t)a->coeffs[j] * b->coeffs[(i - j + KYBER_N) % KYBER_N];
}
result->coeffs[i] = sum % KYBER_Q;
}
}
// ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ ΠΊΠ»ΡΡΠ΅Π²ΠΎΠΉ ΠΏΠ°ΡΡ Kyber
struct KyberKeyPair {
PolyMatrix publicKey;
PolyMatrix privateKey;
};
void kyberKeyGen(KyberKeyPair* keys) {
// Π¨Π°Π³ 1: ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ ΠΌΠ°ΡΡΠΈΡΡ A (ΠΏΡΠ±Π»ΠΈΡΠ½Π°Ρ)
PolyMatrix A;
for (uint8_t i = 0; i < KYBER_K; i++) {
for (uint8_t j = 0; j < KYBER_K; j++) {
randomPoly(&A.rows[i]);
}
}
// Π¨Π°Π³ 2: ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ ΡΠ΅ΠΊΡΠ΅ΡΠ½ΠΎΠΉ ΠΌΠ°ΡΡΠΈΡΡ S
PolyMatrix S;
for (uint8_t i = 0; i < KYBER_K; i++) {
for (uint8_t j = 0; j < KYBER_K; j++) {
// Π‘Π΅ΠΊΡΠ΅ΡΠ½ΡΠ΅ ΠΊΠΎΡΡΡΠΈΡΠΈΠ΅Π½ΡΡ: -1, 0, 1
S.rows[i].coeffs[j] = random(-1, 2);
}
}
// Π¨Π°Π³ 3: ΠΡΡΠΈΡΠ»Π΅Π½ΠΈΠ΅ ΠΏΡΠ±Π»ΠΈΡΠ½ΠΎΠΉ ΠΌΠ°ΡΡΠΈΡΡ B = A * S + E
PolyMatrix B;
for (uint8_t i = 0; i < KYBER_K; i++) {
for (uint8_t j = 0; j < KYBER_K; j++) {
// B = A * S (ΡΠΏΡΠΎΡΠ΅Π½Π½ΠΎ)
Poly temp;
polyMul(&A.rows[i], &S.rows[j], &temp);
B.rows[i].coeffs[j] = (temp.coeffs[0] + random(-2, 3)) % KYBER_Q;
}
}
// Π‘ΠΎΡ
ΡΠ°Π½ΡΠ΅ΠΌ ΠΊΠ»ΡΡΠΈ
keys->publicKey = B;
keys->privateKey = S;
}
// Π¨ΠΈΡΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ (Π±Π°ΠΉΡ Π² ΠΏΠΎΠ»ΠΈΠ½ΠΎΠΌ)
void kyberEncrypt(uint8_t* message, uint8_t len, PolyMatrix* publicKey, PolyMatrix* ciphertext) {
// ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ ΡΠ»ΡΡΠ°ΠΉΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΠΈΠ½ΠΎΠΌΠ° r (Π΄Π»Ρ ΠΌΠ°ΡΠΊΠΈΡΠΎΠ²ΠΊΠΈ)
Poly r;
randomPoly(&r);
// Π¨ΠΈΡΡΡΠ΅ΠΌ ΠΊΠ°ΠΆΠ΄ΡΠΉ Π±Π°ΠΉΡ
for (uint8_t i = 0; i < len; i++) {
Poly m;
for (uint8_t j = 0; j < KYBER_N; j++) {
m.coeffs[j] = (message[i] >> (j % 8)) & 1;
}
// c = publicKey * r + m
Poly temp;
polyMul(&publicKey->rows[0], &r, &temp);
for (uint8_t j = 0; j < KYBER_N; j++) {
ciphertext->rows[i].coeffs[j] = (temp.coeffs[j] + m.coeffs[j]) % KYBER_Q;
}
}
}
// ΠΠ΅ΡΠΈΡΡΠΎΠ²Π°Π½ΠΈΠ΅
void kyberDecrypt(PolyMatrix* ciphertext, PolyMatrix* privateKey, uint8_t* message, uint8_t len) {
for (uint8_t i = 0; i < len; i++) {
// m = ciphertext - privateKey * r
Poly temp;
polyMul(&privateKey->rows[0], &ciphertext->rows[i], &temp);
uint8_t byte = 0;
for (uint8_t j = 0; j < KYBER_N; j++) {
int16_t bit = (temp.coeffs[j] - ciphertext->rows[i].coeffs[j]) % KYBER_Q;
if (abs(bit) > KYBER_Q / 2) {
byte |= (1 << (j % 8));
}
}
message[i] = byte;
}
}
void setup() {
Serial.begin(115200);
randomSeed(analogRead(A0));
// ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ ΠΊΠ»ΡΡΠ΅ΠΉ
KyberKeyPair keys;
kyberKeyGen(&keys);
// Π‘ΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅
uint8_t message[] = "ARDUINOHACKS QUANTUM SECURE!";
uint8_t encrypted[32];
uint8_t decrypted[32];
// Π¨ΠΈΡΡΠΎΠ²Π°Π½ΠΈΠ΅
PolyMatrix ciphertext;
kyberEncrypt(message, sizeof(message), &keys.publicKey, &ciphertext);
// ΠΠ΅ΡΠΈΡΡΠΎΠ²Π°Π½ΠΈΠ΅
kyberDecrypt(&ciphertext, &keys.privateKey, decrypted, sizeof(message));
Serial.print("ΠΡΠΈΠ³ΠΈΠ½Π°Π»: ");
Serial.println((char*)message);
Serial.print("ΠΠ΅ΡΠΈΡΡΠΎΠ²Π°Π½ΠΎ: ");
Serial.println((char*)decrypted);
}
void loop() {}