Loading src/CMakeLists.txt +2 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ list(APPEND netplussrc crypto/ecc_p256.cpp crypto/hkdf.cpp crypto/rsa_pss_sha256.cpp crypto/curve25519.cpp exception.cpp connection.cpp ssl.cpp Loading Loading @@ -63,6 +64,7 @@ set(headers crypto/hkdf.h crypto/rsa_pss_sha256.h crypto/sha.h crypto/curve25519.h ) add_library(netplus SHARED ${netplussrc} ${headers}) Loading src/crypto/aes.cpp +37 −22 Original line number Diff line number Diff line Loading @@ -273,7 +273,10 @@ block128 aes::encrypt(const block128& plaintext) { if (plaintext.size() != 16) throw std::invalid_argument("aes::encrypt: block must be 16 bytes"); uint8_t state[16]; uint8_t state[16]={0}; if (plaintext.size() != 16) throw; std::memcpy(state, plaintext.data(), 16); // round 0 Loading @@ -299,7 +302,8 @@ block128 aes::decrypt(const block128& ciphertext) { if (ciphertext.size() != 16) throw std::invalid_argument("aes::decrypt: block must be 16 bytes"); uint8_t state[16]; uint8_t state[16]={0}; std::memcpy(state, ciphertext.data(), 16); // round 10 Loading Loading @@ -387,8 +391,8 @@ static inline void xor_block_inplace(uint8_t out[16], const uint8_t b[16]) { for (int i=0;i<16;i++) out[i] ^= b[i]; } static inline void store_be64(uint8_t out[8], uint64_t x) { for (int i=0;i<8;i++) out[i] = (uint8_t)(x >> (56 - 8*i)); static inline void store_be64(uint8_t* out, uint64_t v) { for (int i=7;i>=0;i--) { out[i] = v & 0xFF; v >>= 8; } } // multiply in GF(2^128) with poly 0xE1 Loading Loading @@ -437,7 +441,7 @@ static void ghash(uint8_t out[16], const uint8_t H[16], ghash_update(Y, H, aad, aad_len); ghash_update(Y, H, ct, ct_len); uint8_t lenblk[16]; uint8_t lenblk[16] ={0}; store_be64(lenblk, (uint64_t)aad_len * 8); store_be64(lenblk + 8, (uint64_t)ct_len * 8); Loading Loading @@ -487,29 +491,35 @@ bool aes::aes_gcm_encrypt( std::memcpy(J0, iv12, 12); J0[15] = 1; // CTR keystream uint8_t ctr[16]; // CTR = J0 uint8_t ctr[16] = {0}; std::memcpy(ctr, J0, 16); // CTR encrypt size_t off = 0; while (off < pt_len) { inc32(ctr); uint8_t S[16]; uint8_t S[16] = {0}; // ✅ MUST init aes_encrypt_block(*this, ctr, S); size_t take = (pt_len - off < 16) ? (pt_len - off) : 16; for (size_t i=0;i<take;i++) ct[off+i] = pt[off+i] ^ S[i]; for (size_t i=0;i<take;i++) ct[off+i] = pt[off+i] ^ S[i]; off += take; } // GHASH uint8_t Sgh[16]; uint8_t Sgh[16] = {0}; // ✅ MUST init ghash(Sgh, H, aad, aad_len, ct, pt_len); // Tag = AES_k(J0) XOR GHASH uint8_t EJ0[16]; uint8_t EJ0[16] = {0}; // ✅ MUST init aes_encrypt_block(*this, J0, EJ0); for (int i=0;i<16;i++) tag16[i] = EJ0[i] ^ Sgh[i]; for (int i=0;i<16;i++) tag16[i] = EJ0[i] ^ Sgh[i]; return true; } Loading @@ -529,33 +539,38 @@ bool aes::aes_gcm_decrypt( J0[15] = 1; // expected tag uint8_t Sgh[16]; uint8_t Sgh[16] = {0}; // ✅ MUST init ghash(Sgh, H, aad, aad_len, ct, ct_len); uint8_t EJ0[16]; uint8_t EJ0[16] = {0}; // ✅ MUST init aes_encrypt_block(*this, J0, EJ0); uint8_t expTag[16]; for (int i=0;i<16;i++) expTag[i] = EJ0[i] ^ Sgh[i]; uint8_t expTag[16] = {0}; // ✅ MUST init for (int i=0;i<16;i++) expTag[i] = EJ0[i] ^ Sgh[i]; if (ct_memeq_mask(expTag, tag16, 16) != 0) return false; // IMPORTANT: If ct_memeq_mask returns 0 when equal: if (ct_memeq_mask(expTag, tag16, 16) != 0) return false; // CTR decrypt uint8_t ctr[16]; uint8_t ctr[16] = {0}; // ✅ MUST init std::memcpy(ctr, J0, 16); size_t off = 0; while (off < ct_len) { inc32(ctr); uint8_t S[16]; uint8_t S[16] = {0}; // ✅ MUST init aes_encrypt_block(*this, ctr, S); size_t take = (ct_len - off < 16) ? (ct_len - off) : 16; for (size_t i=0;i<take;i++) pt[off+i] = ct[off+i] ^ S[i]; for (size_t i=0;i<take;i++) pt[off+i] = ct[off+i] ^ S[i]; off += take; } return true; } }; src/crypto/aes.h +2 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,8 @@ private: public: explicit aes(const key128& key); virtual ~aes() = default; // NOTE: Keeping your vector-based API, but avoids realloc/extra copies. block128 encrypt(const block128& plaintext); block128 decrypt(const block128& ciphertext); Loading src/crypto/curve25519.cpp 0 → 100644 +275 −0 Original line number Diff line number Diff line #include "curve25519.h" #include <string.h> namespace netplus { static inline uint32_t load32(const uint8_t *p) { return ((uint32_t)p[0]) | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); } static inline void store32(uint8_t *p, uint32_t v) { p[0] = (uint8_t)(v); p[1] = (uint8_t)(v >> 8); p[2] = (uint8_t)(v >> 16); p[3] = (uint8_t)(v >> 24); } // Field element radix 2^25.5 typedef int32_t fe[10]; static void fe_0(fe h) { memset(h, 0, sizeof(fe)); } static void fe_1(fe h) { fe_0(h); h[0] = 1; } static void fe_copy(fe h, const fe f) { memcpy(h, f, sizeof(fe)); } static void fe_add(fe h, const fe f, const fe g) { for (int i=0;i<10;i++) h[i] = f[i] + g[i]; } static void fe_sub(fe h, const fe f, const fe g) { for (int i=0;i<10;i++) h[i] = f[i] - g[i]; } static void fe_cswap(fe f, fe g, uint32_t b) { b = -b; for (int i=0;i<10;i++) { int32_t x = b & (f[i] ^ g[i]); f[i] ^= x; g[i] ^= x; } } static void fe_carry(fe h) { int64_t c; c = (h[0] + ((int64_t)1<<25)) >> 26; h[1] += c; h[0] -= c<<26; c = (h[1] + ((int64_t)1<<24)) >> 25; h[2] += c; h[1] -= c<<25; c = (h[2] + ((int64_t)1<<25)) >> 26; h[3] += c; h[2] -= c<<26; c = (h[3] + ((int64_t)1<<24)) >> 25; h[4] += c; h[3] -= c<<25; c = (h[4] + ((int64_t)1<<25)) >> 26; h[5] += c; h[4] -= c<<26; c = (h[5] + ((int64_t)1<<24)) >> 25; h[6] += c; h[5] -= c<<25; c = (h[6] + ((int64_t)1<<25)) >> 26; h[7] += c; h[6] -= c<<26; c = (h[7] + ((int64_t)1<<24)) >> 25; h[8] += c; h[7] -= c<<25; c = (h[8] + ((int64_t)1<<25)) >> 26; h[9] += c; h[8] -= c<<26; c = (h[9] + ((int64_t)1<<24)) >> 25; h[0] += c*19; h[9] -= c<<25; c = (h[0] + ((int64_t)1<<25)) >> 26; h[1] += c; h[0] -= c<<26; } static void fe_mul(fe h, const fe f, const fe g) { int64_t f0=f[0], f1=f[1], f2=f[2], f3=f[3], f4=f[4], f5=f[5], f6=f[6], f7=f[7], f8=f[8], f9=f[9]; int64_t g0=g[0], g1=g[1], g2=g[2], g3=g[3], g4=g[4], g5=g[5], g6=g[6], g7=g[7], g8=g[8], g9=g[9]; int64_t g1_19 = 19*g1; int64_t g2_19 = 19*g2; int64_t g3_19 = 19*g3; int64_t g4_19 = 19*g4; int64_t g5_19 = 19*g5; int64_t g6_19 = 19*g6; int64_t g7_19 = 19*g7; int64_t g8_19 = 19*g8; int64_t g9_19 = 19*g9; int64_t h0 = f0*g0 + f1*g9_19 + f2*g8_19 + f3*g7_19 + f4*g6_19 + f5*g5_19 + f6*g4_19 + f7*g3_19 + f8*g2_19 + f9*g1_19; int64_t h1 = f0*g1 + f1*g0 + f2*g9_19 + f3*g8_19 + f4*g7_19 + f5*g6_19 + f6*g5_19 + f7*g4_19 + f8*g3_19 + f9*g2_19; int64_t h2 = f0*g2 + f1*g1 + f2*g0 + f3*g9_19 + f4*g8_19 + f5*g7_19 + f6*g6_19 + f7*g5_19 + f8*g4_19 + f9*g3_19; int64_t h3 = f0*g3 + f1*g2 + f2*g1 + f3*g0 + f4*g9_19 + f5*g8_19 + f6*g7_19 + f7*g6_19 + f8*g5_19 + f9*g4_19; int64_t h4 = f0*g4 + f1*g3 + f2*g2 + f3*g1 + f4*g0 + f5*g9_19 + f6*g8_19 + f7*g7_19 + f8*g6_19 + f9*g5_19; int64_t h5 = f0*g5 + f1*g4 + f2*g3 + f3*g2 + f4*g1 + f5*g0 + f6*g9_19 + f7*g8_19 + f8*g7_19 + f9*g6_19; int64_t h6 = f0*g6 + f1*g5 + f2*g4 + f3*g3 + f4*g2 + f5*g1 + f6*g0 + f7*g9_19 + f8*g8_19 + f9*g7_19; int64_t h7 = f0*g7 + f1*g6 + f2*g5 + f3*g4 + f4*g3 + f5*g2 + f6*g1 + f7*g0 + f8*g9_19 + f9*g8_19; int64_t h8 = f0*g8 + f1*g7 + f2*g6 + f3*g5 + f4*g4 + f5*g3 + f6*g2 + f7*g1 + f8*g0 + f9*g9_19; int64_t h9 = f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0; h[0]=(int32_t)h0; h[1]=(int32_t)h1; h[2]=(int32_t)h2; h[3]=(int32_t)h3; h[4]=(int32_t)h4; h[5]=(int32_t)h5; h[6]=(int32_t)h6; h[7]=(int32_t)h7; h[8]=(int32_t)h8; h[9]=(int32_t)h9; fe_carry(h); } static void fe_sq(fe h, const fe f) { fe_mul(h,f,f); } static void fe_pow22523(fe out, const fe z) { fe t0,t1,t2; fe_sq(t0,z); fe_sq(t1,t0); fe_sq(t1,t1); fe_mul(t1,z,t1); fe_mul(t0,t0,t1); fe_sq(t0,t0); fe_mul(t0,t1,t0); fe_sq(t1,t0); for(int i=1;i<5;i++) fe_sq(t1,t1); fe_mul(t0,t1,t0); fe_sq(t1,t0); for(int i=1;i<10;i++) fe_sq(t1,t1); fe_mul(t1,t1,t0); fe_sq(t2,t1); for(int i=1;i<20;i++) fe_sq(t2,t2); fe_mul(t1,t2,t1); fe_sq(t1,t1); for(int i=1;i<10;i++) fe_sq(t1,t1); fe_mul(t0,t1,t0); fe_sq(t1,t0); for(int i=1;i<50;i++) fe_sq(t1,t1); fe_mul(t1,t1,t0); fe_sq(t2,t1); for(int i=1;i<100;i++) fe_sq(t2,t2); fe_mul(t1,t2,t1); fe_sq(t1,t1); for(int i=1;i<50;i++) fe_sq(t1,t1); fe_mul(t0,t1,t0); fe_sq(t0,t0); fe_sq(t0,t0); fe_mul(out,t0,z); } static void fe_frombytes(fe h, const uint8_t s[32]) { int64_t t0 = load32(s); int64_t t1 = load32(s+4); int64_t t2 = load32(s+8); int64_t t3 = load32(s+12); int64_t t4 = load32(s+16); int64_t t5 = load32(s+20); int64_t t6 = load32(s+24); int64_t t7 = load32(s+28); h[0] = (int32_t)( t0 & 0x3ffffff); h[1] = (int32_t)(((t0>>26) | (t1<<6)) & 0x1ffffff); h[2] = (int32_t)(((t1>>19) | (t2<<13)) & 0x3ffffff); h[3] = (int32_t)(((t2>>13) | (t3<<19)) & 0x1ffffff); h[4] = (int32_t)(( t3>>6) & 0x3ffffff); h[5] = (int32_t)( t4 & 0x1ffffff); h[6] = (int32_t)(((t4>>25) | (t5<<7)) & 0x3ffffff); h[7] = (int32_t)(((t5>>18) | (t6<<14)) & 0x1ffffff); h[8] = (int32_t)(((t6>>12) | (t7<<20)) & 0x3ffffff); h[9] = (int32_t)(( t7>>6) & 0x1ffffff); } static void fe_tobytes(uint8_t s[32], fe h) { fe_carry(h); int32_t q = (19*h[9] + (1<<24)) >> 25; q = (h[0] + q) >> 26; q = (h[1] + q) >> 25; q = (h[2] + q) >> 26; q = (h[3] + q) >> 25; q = (h[4] + q) >> 26; q = (h[5] + q) >> 25; q = (h[6] + q) >> 26; q = (h[7] + q) >> 25; q = (h[8] + q) >> 26; q = (h[9] + q) >> 25; h[0] += 19*q; fe_carry(h); int64_t t0 = ((int64_t)h[0]) | ((int64_t)h[1]<<26); int64_t t1 = ((int64_t)h[1]>>6) | ((int64_t)h[2]<<19); int64_t t2 = ((int64_t)h[2]>>13) | ((int64_t)h[3]<<13); int64_t t3 = ((int64_t)h[3]>>19) | ((int64_t)h[4]<<6); store32(s, (uint32_t)t0); store32(s+4, (uint32_t)(t0>>32)); store32(s+8, (uint32_t)t1); store32(s+12,(uint32_t)(t1>>32)); store32(s+16,(uint32_t)t2); store32(s+20,(uint32_t)(t2>>32)); store32(s+24,(uint32_t)t3); store32(s+28,(uint32_t)(t3>>32)); } static void x25519_scalarmult(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32]) { uint8_t e[32]; memcpy(e, scalar, 32); // Clamp e[0] &= 248; e[31] &= 127; e[31] |= 64; fe x1, x2, z2, x3, z3, tmp0, tmp1; fe_frombytes(x1, point); fe_1(x2); fe_0(z2); fe_copy(x3, x1); fe_1(z3); uint32_t swap = 0; for (int pos = 254; pos >= 0; --pos) { uint32_t b = (e[pos/8] >> (pos & 7)) & 1; swap ^= b; fe_cswap(x2, x3, swap); fe_cswap(z2, z3, swap); swap = b; fe_add(tmp0, x2, z2); fe_sub(tmp1, x2, z2); fe_sq(tmp0, tmp0); fe_sq(tmp1, tmp1); fe_sub(z2, tmp0, tmp1); fe_add(x3, x3, z3); fe_sub(z3, x3, z3); fe_mul(z3, z3, tmp0); fe_mul(x3, x3, tmp1); fe_add(tmp0, z3, x3); fe_sub(tmp1, z3, x3); fe_sq(x3, tmp0); fe_sq(tmp0, tmp1); fe_mul(z3, tmp0, x1); fe_mul(x2, tmp0, tmp1); // z2 = E*(AA + 121665*E) fe_mul(tmp1, z2, (fe){121665,0,0,0,0,0,0,0,0,0}); fe_add(tmp1, tmp1, tmp0); fe_mul(z2, z2, tmp1); } fe_cswap(x2, x3, swap); fe_cswap(z2, z3, swap); fe_pow22523(z2, z2); fe_mul(x2, x2, z2); fe_tobytes(out, x2); } static void x25519_scalarmult_base(uint8_t out[32], const uint8_t scalar[32]) { static const uint8_t base[32] = { 9 }; x25519_scalarmult(out, scalar, base); } bool scalarmult_curve25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t point_u[32]) { x25519_scalarmult(out, scalar, point_u); // reject all-zero result uint8_t acc = 0; for (int i=0;i<32;i++) acc |= out[i]; return acc != 0; } bool scalarmult_curve25519_base(uint8_t out[32], const uint8_t scalar[32]) { x25519_scalarmult_base(out, scalar); uint8_t acc = 0; for (int i=0;i<32;i++) acc |= out[i]; return acc != 0; } } // namespace netplus src/crypto/curve25519.h 0 → 100644 +16 −0 Original line number Diff line number Diff line #pragma once #include <stdint.h> namespace netplus { // out = scalar * basepoint(9) bool scalarmult_curve25519_base(uint8_t out[32], const uint8_t scalar[32]); // out = scalar * point_u (point_u = 32-byte u-coordinate) bool scalarmult_curve25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t point_u[32]); } // namespace netplus Loading
src/CMakeLists.txt +2 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ list(APPEND netplussrc crypto/ecc_p256.cpp crypto/hkdf.cpp crypto/rsa_pss_sha256.cpp crypto/curve25519.cpp exception.cpp connection.cpp ssl.cpp Loading Loading @@ -63,6 +64,7 @@ set(headers crypto/hkdf.h crypto/rsa_pss_sha256.h crypto/sha.h crypto/curve25519.h ) add_library(netplus SHARED ${netplussrc} ${headers}) Loading
src/crypto/aes.cpp +37 −22 Original line number Diff line number Diff line Loading @@ -273,7 +273,10 @@ block128 aes::encrypt(const block128& plaintext) { if (plaintext.size() != 16) throw std::invalid_argument("aes::encrypt: block must be 16 bytes"); uint8_t state[16]; uint8_t state[16]={0}; if (plaintext.size() != 16) throw; std::memcpy(state, plaintext.data(), 16); // round 0 Loading @@ -299,7 +302,8 @@ block128 aes::decrypt(const block128& ciphertext) { if (ciphertext.size() != 16) throw std::invalid_argument("aes::decrypt: block must be 16 bytes"); uint8_t state[16]; uint8_t state[16]={0}; std::memcpy(state, ciphertext.data(), 16); // round 10 Loading Loading @@ -387,8 +391,8 @@ static inline void xor_block_inplace(uint8_t out[16], const uint8_t b[16]) { for (int i=0;i<16;i++) out[i] ^= b[i]; } static inline void store_be64(uint8_t out[8], uint64_t x) { for (int i=0;i<8;i++) out[i] = (uint8_t)(x >> (56 - 8*i)); static inline void store_be64(uint8_t* out, uint64_t v) { for (int i=7;i>=0;i--) { out[i] = v & 0xFF; v >>= 8; } } // multiply in GF(2^128) with poly 0xE1 Loading Loading @@ -437,7 +441,7 @@ static void ghash(uint8_t out[16], const uint8_t H[16], ghash_update(Y, H, aad, aad_len); ghash_update(Y, H, ct, ct_len); uint8_t lenblk[16]; uint8_t lenblk[16] ={0}; store_be64(lenblk, (uint64_t)aad_len * 8); store_be64(lenblk + 8, (uint64_t)ct_len * 8); Loading Loading @@ -487,29 +491,35 @@ bool aes::aes_gcm_encrypt( std::memcpy(J0, iv12, 12); J0[15] = 1; // CTR keystream uint8_t ctr[16]; // CTR = J0 uint8_t ctr[16] = {0}; std::memcpy(ctr, J0, 16); // CTR encrypt size_t off = 0; while (off < pt_len) { inc32(ctr); uint8_t S[16]; uint8_t S[16] = {0}; // ✅ MUST init aes_encrypt_block(*this, ctr, S); size_t take = (pt_len - off < 16) ? (pt_len - off) : 16; for (size_t i=0;i<take;i++) ct[off+i] = pt[off+i] ^ S[i]; for (size_t i=0;i<take;i++) ct[off+i] = pt[off+i] ^ S[i]; off += take; } // GHASH uint8_t Sgh[16]; uint8_t Sgh[16] = {0}; // ✅ MUST init ghash(Sgh, H, aad, aad_len, ct, pt_len); // Tag = AES_k(J0) XOR GHASH uint8_t EJ0[16]; uint8_t EJ0[16] = {0}; // ✅ MUST init aes_encrypt_block(*this, J0, EJ0); for (int i=0;i<16;i++) tag16[i] = EJ0[i] ^ Sgh[i]; for (int i=0;i<16;i++) tag16[i] = EJ0[i] ^ Sgh[i]; return true; } Loading @@ -529,33 +539,38 @@ bool aes::aes_gcm_decrypt( J0[15] = 1; // expected tag uint8_t Sgh[16]; uint8_t Sgh[16] = {0}; // ✅ MUST init ghash(Sgh, H, aad, aad_len, ct, ct_len); uint8_t EJ0[16]; uint8_t EJ0[16] = {0}; // ✅ MUST init aes_encrypt_block(*this, J0, EJ0); uint8_t expTag[16]; for (int i=0;i<16;i++) expTag[i] = EJ0[i] ^ Sgh[i]; uint8_t expTag[16] = {0}; // ✅ MUST init for (int i=0;i<16;i++) expTag[i] = EJ0[i] ^ Sgh[i]; if (ct_memeq_mask(expTag, tag16, 16) != 0) return false; // IMPORTANT: If ct_memeq_mask returns 0 when equal: if (ct_memeq_mask(expTag, tag16, 16) != 0) return false; // CTR decrypt uint8_t ctr[16]; uint8_t ctr[16] = {0}; // ✅ MUST init std::memcpy(ctr, J0, 16); size_t off = 0; while (off < ct_len) { inc32(ctr); uint8_t S[16]; uint8_t S[16] = {0}; // ✅ MUST init aes_encrypt_block(*this, ctr, S); size_t take = (ct_len - off < 16) ? (ct_len - off) : 16; for (size_t i=0;i<take;i++) pt[off+i] = ct[off+i] ^ S[i]; for (size_t i=0;i<take;i++) pt[off+i] = ct[off+i] ^ S[i]; off += take; } return true; } };
src/crypto/aes.h +2 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,8 @@ private: public: explicit aes(const key128& key); virtual ~aes() = default; // NOTE: Keeping your vector-based API, but avoids realloc/extra copies. block128 encrypt(const block128& plaintext); block128 decrypt(const block128& ciphertext); Loading
src/crypto/curve25519.cpp 0 → 100644 +275 −0 Original line number Diff line number Diff line #include "curve25519.h" #include <string.h> namespace netplus { static inline uint32_t load32(const uint8_t *p) { return ((uint32_t)p[0]) | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); } static inline void store32(uint8_t *p, uint32_t v) { p[0] = (uint8_t)(v); p[1] = (uint8_t)(v >> 8); p[2] = (uint8_t)(v >> 16); p[3] = (uint8_t)(v >> 24); } // Field element radix 2^25.5 typedef int32_t fe[10]; static void fe_0(fe h) { memset(h, 0, sizeof(fe)); } static void fe_1(fe h) { fe_0(h); h[0] = 1; } static void fe_copy(fe h, const fe f) { memcpy(h, f, sizeof(fe)); } static void fe_add(fe h, const fe f, const fe g) { for (int i=0;i<10;i++) h[i] = f[i] + g[i]; } static void fe_sub(fe h, const fe f, const fe g) { for (int i=0;i<10;i++) h[i] = f[i] - g[i]; } static void fe_cswap(fe f, fe g, uint32_t b) { b = -b; for (int i=0;i<10;i++) { int32_t x = b & (f[i] ^ g[i]); f[i] ^= x; g[i] ^= x; } } static void fe_carry(fe h) { int64_t c; c = (h[0] + ((int64_t)1<<25)) >> 26; h[1] += c; h[0] -= c<<26; c = (h[1] + ((int64_t)1<<24)) >> 25; h[2] += c; h[1] -= c<<25; c = (h[2] + ((int64_t)1<<25)) >> 26; h[3] += c; h[2] -= c<<26; c = (h[3] + ((int64_t)1<<24)) >> 25; h[4] += c; h[3] -= c<<25; c = (h[4] + ((int64_t)1<<25)) >> 26; h[5] += c; h[4] -= c<<26; c = (h[5] + ((int64_t)1<<24)) >> 25; h[6] += c; h[5] -= c<<25; c = (h[6] + ((int64_t)1<<25)) >> 26; h[7] += c; h[6] -= c<<26; c = (h[7] + ((int64_t)1<<24)) >> 25; h[8] += c; h[7] -= c<<25; c = (h[8] + ((int64_t)1<<25)) >> 26; h[9] += c; h[8] -= c<<26; c = (h[9] + ((int64_t)1<<24)) >> 25; h[0] += c*19; h[9] -= c<<25; c = (h[0] + ((int64_t)1<<25)) >> 26; h[1] += c; h[0] -= c<<26; } static void fe_mul(fe h, const fe f, const fe g) { int64_t f0=f[0], f1=f[1], f2=f[2], f3=f[3], f4=f[4], f5=f[5], f6=f[6], f7=f[7], f8=f[8], f9=f[9]; int64_t g0=g[0], g1=g[1], g2=g[2], g3=g[3], g4=g[4], g5=g[5], g6=g[6], g7=g[7], g8=g[8], g9=g[9]; int64_t g1_19 = 19*g1; int64_t g2_19 = 19*g2; int64_t g3_19 = 19*g3; int64_t g4_19 = 19*g4; int64_t g5_19 = 19*g5; int64_t g6_19 = 19*g6; int64_t g7_19 = 19*g7; int64_t g8_19 = 19*g8; int64_t g9_19 = 19*g9; int64_t h0 = f0*g0 + f1*g9_19 + f2*g8_19 + f3*g7_19 + f4*g6_19 + f5*g5_19 + f6*g4_19 + f7*g3_19 + f8*g2_19 + f9*g1_19; int64_t h1 = f0*g1 + f1*g0 + f2*g9_19 + f3*g8_19 + f4*g7_19 + f5*g6_19 + f6*g5_19 + f7*g4_19 + f8*g3_19 + f9*g2_19; int64_t h2 = f0*g2 + f1*g1 + f2*g0 + f3*g9_19 + f4*g8_19 + f5*g7_19 + f6*g6_19 + f7*g5_19 + f8*g4_19 + f9*g3_19; int64_t h3 = f0*g3 + f1*g2 + f2*g1 + f3*g0 + f4*g9_19 + f5*g8_19 + f6*g7_19 + f7*g6_19 + f8*g5_19 + f9*g4_19; int64_t h4 = f0*g4 + f1*g3 + f2*g2 + f3*g1 + f4*g0 + f5*g9_19 + f6*g8_19 + f7*g7_19 + f8*g6_19 + f9*g5_19; int64_t h5 = f0*g5 + f1*g4 + f2*g3 + f3*g2 + f4*g1 + f5*g0 + f6*g9_19 + f7*g8_19 + f8*g7_19 + f9*g6_19; int64_t h6 = f0*g6 + f1*g5 + f2*g4 + f3*g3 + f4*g2 + f5*g1 + f6*g0 + f7*g9_19 + f8*g8_19 + f9*g7_19; int64_t h7 = f0*g7 + f1*g6 + f2*g5 + f3*g4 + f4*g3 + f5*g2 + f6*g1 + f7*g0 + f8*g9_19 + f9*g8_19; int64_t h8 = f0*g8 + f1*g7 + f2*g6 + f3*g5 + f4*g4 + f5*g3 + f6*g2 + f7*g1 + f8*g0 + f9*g9_19; int64_t h9 = f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0; h[0]=(int32_t)h0; h[1]=(int32_t)h1; h[2]=(int32_t)h2; h[3]=(int32_t)h3; h[4]=(int32_t)h4; h[5]=(int32_t)h5; h[6]=(int32_t)h6; h[7]=(int32_t)h7; h[8]=(int32_t)h8; h[9]=(int32_t)h9; fe_carry(h); } static void fe_sq(fe h, const fe f) { fe_mul(h,f,f); } static void fe_pow22523(fe out, const fe z) { fe t0,t1,t2; fe_sq(t0,z); fe_sq(t1,t0); fe_sq(t1,t1); fe_mul(t1,z,t1); fe_mul(t0,t0,t1); fe_sq(t0,t0); fe_mul(t0,t1,t0); fe_sq(t1,t0); for(int i=1;i<5;i++) fe_sq(t1,t1); fe_mul(t0,t1,t0); fe_sq(t1,t0); for(int i=1;i<10;i++) fe_sq(t1,t1); fe_mul(t1,t1,t0); fe_sq(t2,t1); for(int i=1;i<20;i++) fe_sq(t2,t2); fe_mul(t1,t2,t1); fe_sq(t1,t1); for(int i=1;i<10;i++) fe_sq(t1,t1); fe_mul(t0,t1,t0); fe_sq(t1,t0); for(int i=1;i<50;i++) fe_sq(t1,t1); fe_mul(t1,t1,t0); fe_sq(t2,t1); for(int i=1;i<100;i++) fe_sq(t2,t2); fe_mul(t1,t2,t1); fe_sq(t1,t1); for(int i=1;i<50;i++) fe_sq(t1,t1); fe_mul(t0,t1,t0); fe_sq(t0,t0); fe_sq(t0,t0); fe_mul(out,t0,z); } static void fe_frombytes(fe h, const uint8_t s[32]) { int64_t t0 = load32(s); int64_t t1 = load32(s+4); int64_t t2 = load32(s+8); int64_t t3 = load32(s+12); int64_t t4 = load32(s+16); int64_t t5 = load32(s+20); int64_t t6 = load32(s+24); int64_t t7 = load32(s+28); h[0] = (int32_t)( t0 & 0x3ffffff); h[1] = (int32_t)(((t0>>26) | (t1<<6)) & 0x1ffffff); h[2] = (int32_t)(((t1>>19) | (t2<<13)) & 0x3ffffff); h[3] = (int32_t)(((t2>>13) | (t3<<19)) & 0x1ffffff); h[4] = (int32_t)(( t3>>6) & 0x3ffffff); h[5] = (int32_t)( t4 & 0x1ffffff); h[6] = (int32_t)(((t4>>25) | (t5<<7)) & 0x3ffffff); h[7] = (int32_t)(((t5>>18) | (t6<<14)) & 0x1ffffff); h[8] = (int32_t)(((t6>>12) | (t7<<20)) & 0x3ffffff); h[9] = (int32_t)(( t7>>6) & 0x1ffffff); } static void fe_tobytes(uint8_t s[32], fe h) { fe_carry(h); int32_t q = (19*h[9] + (1<<24)) >> 25; q = (h[0] + q) >> 26; q = (h[1] + q) >> 25; q = (h[2] + q) >> 26; q = (h[3] + q) >> 25; q = (h[4] + q) >> 26; q = (h[5] + q) >> 25; q = (h[6] + q) >> 26; q = (h[7] + q) >> 25; q = (h[8] + q) >> 26; q = (h[9] + q) >> 25; h[0] += 19*q; fe_carry(h); int64_t t0 = ((int64_t)h[0]) | ((int64_t)h[1]<<26); int64_t t1 = ((int64_t)h[1]>>6) | ((int64_t)h[2]<<19); int64_t t2 = ((int64_t)h[2]>>13) | ((int64_t)h[3]<<13); int64_t t3 = ((int64_t)h[3]>>19) | ((int64_t)h[4]<<6); store32(s, (uint32_t)t0); store32(s+4, (uint32_t)(t0>>32)); store32(s+8, (uint32_t)t1); store32(s+12,(uint32_t)(t1>>32)); store32(s+16,(uint32_t)t2); store32(s+20,(uint32_t)(t2>>32)); store32(s+24,(uint32_t)t3); store32(s+28,(uint32_t)(t3>>32)); } static void x25519_scalarmult(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32]) { uint8_t e[32]; memcpy(e, scalar, 32); // Clamp e[0] &= 248; e[31] &= 127; e[31] |= 64; fe x1, x2, z2, x3, z3, tmp0, tmp1; fe_frombytes(x1, point); fe_1(x2); fe_0(z2); fe_copy(x3, x1); fe_1(z3); uint32_t swap = 0; for (int pos = 254; pos >= 0; --pos) { uint32_t b = (e[pos/8] >> (pos & 7)) & 1; swap ^= b; fe_cswap(x2, x3, swap); fe_cswap(z2, z3, swap); swap = b; fe_add(tmp0, x2, z2); fe_sub(tmp1, x2, z2); fe_sq(tmp0, tmp0); fe_sq(tmp1, tmp1); fe_sub(z2, tmp0, tmp1); fe_add(x3, x3, z3); fe_sub(z3, x3, z3); fe_mul(z3, z3, tmp0); fe_mul(x3, x3, tmp1); fe_add(tmp0, z3, x3); fe_sub(tmp1, z3, x3); fe_sq(x3, tmp0); fe_sq(tmp0, tmp1); fe_mul(z3, tmp0, x1); fe_mul(x2, tmp0, tmp1); // z2 = E*(AA + 121665*E) fe_mul(tmp1, z2, (fe){121665,0,0,0,0,0,0,0,0,0}); fe_add(tmp1, tmp1, tmp0); fe_mul(z2, z2, tmp1); } fe_cswap(x2, x3, swap); fe_cswap(z2, z3, swap); fe_pow22523(z2, z2); fe_mul(x2, x2, z2); fe_tobytes(out, x2); } static void x25519_scalarmult_base(uint8_t out[32], const uint8_t scalar[32]) { static const uint8_t base[32] = { 9 }; x25519_scalarmult(out, scalar, base); } bool scalarmult_curve25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t point_u[32]) { x25519_scalarmult(out, scalar, point_u); // reject all-zero result uint8_t acc = 0; for (int i=0;i<32;i++) acc |= out[i]; return acc != 0; } bool scalarmult_curve25519_base(uint8_t out[32], const uint8_t scalar[32]) { x25519_scalarmult_base(out, scalar); uint8_t acc = 0; for (int i=0;i<32;i++) acc |= out[i]; return acc != 0; } } // namespace netplus
src/crypto/curve25519.h 0 → 100644 +16 −0 Original line number Diff line number Diff line #pragma once #include <stdint.h> namespace netplus { // out = scalar * basepoint(9) bool scalarmult_curve25519_base(uint8_t out[32], const uint8_t scalar[32]); // out = scalar * point_u (point_u = 32-byte u-coordinate) bool scalarmult_curve25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t point_u[32]); } // namespace netplus