Loading .kdev4/libnetplus.kdev4 +3 −3 Original line number Diff line number Diff line Loading @@ -2,8 +2,8 @@ BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x14\x00l\x00i\x00b\x00n\x00e\x00t\x00p\x00l\x00u\x00s) [CMake] Build Directory Count=2 Current Build Directory Index-Host System=0 Build Directory Count=3 Current Build Directory Index-Host System=2 Current Build Directory Index-Host-System=1 Temporary Build Directory Index=1 Loading @@ -25,7 +25,7 @@ CMake Executable=/usr/bin/cmake Environment Profile= Extra Arguments= Install Directory=/usr/local Runtime=Host-System Runtime=Host System [MakeBuilder] Make Binary=ninja Loading src/crypto/curve25519.cpp +128 −235 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ FieldElement::FieldElement(int v) { FieldElement::FieldElement(const std::vector<int32_t>& v) { limbs.fill(0); for (size_t i = 0; i < 10 && i < v.size(); ++i) for (size_t i = 0; i < 16 && i < v.size(); ++i) limbs[i] = v[i]; } Loading @@ -26,110 +26,60 @@ FieldElement::FieldElement(const FieldElement& src) : limbs(src.limbs) {} FieldElement& FieldElement::operator=(const std::vector<int32_t>& v) { limbs.fill(0); for (size_t i = 0; i < 10 && i < v.size(); ++i) for (size_t i = 0; i < 16 && i < v.size(); ++i) limbs[i] = v[i]; return *this; } FieldElement FieldElement::operator+(const FieldElement& other) const { FieldElement r; for (int i = 0; i < 10; ++i) for (int i = 0; i < 16; ++i) r.limbs[i] = limbs[i] + other.limbs[i]; return r; } FieldElement FieldElement::operator-(const FieldElement& other) const { FieldElement r; for (int i = 0; i < 10; ++i) for (int i = 0; i < 16; ++i) r.limbs[i] = limbs[i] - other.limbs[i]; return r; } FieldElement FieldElement::operator*(const FieldElement& g) const { const int64_t* f = limbs.data(); const int64_t* h = g.limbs.data(); int64_t f0 = f[0]; int64_t f1 = f[1]; int64_t f2 = f[2]; int64_t f3 = f[3]; int64_t f4 = f[4]; int64_t f5 = f[5]; int64_t f6 = f[6]; int64_t f7 = f[7]; int64_t f8 = f[8]; int64_t f9 = f[9]; int64_t g0 = h[0]; int64_t g1 = h[1]; int64_t g2 = h[2]; int64_t g3 = h[3]; int64_t g4 = h[4]; int64_t g5 = h[5]; int64_t g6 = h[6]; int64_t g7 = h[7]; int64_t g8 = h[8]; int64_t g9 = h[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 f1_2 = 2 * f1; int64_t f3_2 = 2 * f3; int64_t f5_2 = 2 * f5; int64_t f7_2 = 2 * f7; int64_t f9_2 = 2 * f9; int64_t h0 = f0*g0 + f1_2*g9_19 + f2*g8_19 + f3_2*g7_19 + f4*g6_19 + f5_2*g5_19 + f6*g4_19 + f7_2*g3_19 + f8*g2_19 + f9_2*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_2*g1 + f2*g0 + f3_2*g9_19 + f4*g8_19 + f5_2*g7_19 + f6*g6_19 + f7_2*g5_19 + f8*g4_19 + f9_2*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_2*g3 + f2*g2 + f3_2*g1 + f4*g0 + f5_2*g9_19 + f6*g8_19 + f7_2*g7_19 + f8*g6_19 + f9_2*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_2*g5 + f2*g4 + f3_2*g3 + f4*g2 + f5_2*g1 + f6*g0 + f7_2*g9_19 + f8*g8_19 + f9_2*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_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*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; // carry propagation int64_t carry0 = (h0 + (1LL<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; int64_t carry1 = (h1 + (1LL<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; int64_t carry2 = (h2 + (1LL<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; int64_t carry3 = (h3 + (1LL<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; int64_t carry4 = (h4 + (1LL<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; int64_t carry5 = (h5 + (1LL<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; int64_t carry6 = (h6 + (1LL<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; int64_t carry7 = (h7 + (1LL<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; int64_t carry8 = (h8 + (1LL<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; int64_t carry9 = (h9 + (1LL<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; void FieldElement::carry25519(){ int64_t cry; for(size_t i=0; i<16; ++i){ cry =limbs[i] >> 16; limbs[i]-=cry << 16; i < 15 ? limbs[i+1]+=cry : limbs[0] += 38 * cry; } return; }; carry0 = (h0 + (1LL<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; FieldElement FieldElement::operator*(const FieldElement& g) const { std::array<int64_t,31> prod; std::fill(prod.begin(),prod.end(),0); FieldElement out; FieldElement r; r.limbs[0] = h0; r.limbs[1] = h1; r.limbs[2] = h2; r.limbs[3] = h3; r.limbs[4] = h4; r.limbs[5] = h5; r.limbs[6] = h6; r.limbs[7] = h7; r.limbs[8] = h8; r.limbs[9] = h9; return r; for(size_t i=0; i< 16; ++i){ for(size_t j=0; j<16; ++j){ prod[i+j]+=this->limbs[i] * g.limbs[j]; } } for(size_t i=0; i< 15; ++i){ prod[i] += 38 * prod[i+16]; } for(size_t i=0; i <16; ++i){ out.limbs[i]=prod[i]; } out.carry25519(); out.carry25519(); return out; } FieldElement FieldElement::operator*(int32_t scalar) const { FieldElement r; int64_t sc = scalar; for (int i = 0; i < 10; ++i) for (int i = 0; i < 16; ++i) r.limbs[i] = limbs[i] * sc; return r; } Loading @@ -148,73 +98,29 @@ void FieldElement::one() { zero(); limbs[0] = 1; } // Add to FieldElement class: FieldElement FieldElement::invert() const { FieldElement z2; // z^2 FieldElement z9; // z^9 FieldElement z11; // z^11 FieldElement z2_5_0; FieldElement z2_10_0; FieldElement z2_20_0; FieldElement z2_50_0; FieldElement z2_100_0; FieldElement t; // 2 z2 = (*this) * (*this); // 4 t = z2 * z2; // 8 t = t * t; // 9 z9 = t * (*this); // 11 z11 = z9 * z2; // 2^5 - 2^0 = 31 z2_5_0 = z11; for (int i = 0; i < 5; ++i) z2_5_0 = z2_5_0 * z2_5_0; z2_5_0 = z2_5_0 * z11; // 2^10 - 2^0 z2_10_0 = z2_5_0; for (int i = 0; i < 10; ++i) z2_10_0 = z2_10_0 * z2_10_0; z2_10_0 = z2_10_0 * z2_5_0; // 2^20 - 2^0 z2_20_0 = z2_10_0; for (int i = 0; i < 20; ++i) z2_20_0 = z2_20_0 * z2_20_0; z2_20_0 = z2_20_0 * z2_10_0; // 2^50 - 2^0 z2_50_0 = z2_20_0; for (int i = 0; i < 50; ++i) z2_50_0 = z2_50_0 * z2_50_0; z2_50_0 = z2_50_0 * z2_20_0; // 2^100 - 2^0 z2_100_0 = z2_50_0; for (int i = 0; i < 100; ++i) z2_100_0 = z2_100_0 * z2_100_0; z2_100_0 = z2_100_0 * z2_50_0; // 2^200 - 2^0 t = z2_100_0; for (int i = 0; i < 100; ++i) t = t * t; t = t * z2_100_0; // 2^250 - 2^0 for (int i = 0; i < 50; ++i) t = t * t; t = t * z2_50_0; FieldElement out; for(size_t i =0; i< limbs.size(); ++i){ out.limbs[i]=limbs[i]; } for(size_t i = 253; i!=std::string::npos; i--){ out=out * out; if(i!=2 && i!=4){ out=out*(*this); } } return out; } // 2^255 - 21 for (int i = 0; i < 5; ++i) t = t * t; return t * z11; void FieldElement::from_bytes(std::vector<uint8_t> in){ for(size_t i=0; i< 16; ++i){ limbs[i]=in[2*i]+static_cast<int64_t>(in[2*i+1] << 8); } limbs[15] &=0x7FFF; } std::vector<uint8_t> FieldElement::to_bytes() const { int64_t h[10]; for (int i = 0; i < 10; ++i) h[i] = limbs[i]; for (int i = 0; i < 16; ++i) h[i] = limbs[i]; // --------------------------------------------------------------------- // Canonical reduction: ensure 0 <= h < p Loading Loading @@ -291,112 +197,99 @@ std::vector<uint8_t> FieldElement::to_bytes() const { s[31] = (uint8_t)(h[9] >> 18); return s; } bool scalarmult_curve25519(std::vector<uint8_t> &out, const std::vector<uint8_t> &scalar, const std::vector<uint8_t> &point_u) { auto cswap = [&](FieldElement& a, FieldElement& b, int swap) { uint64_t mask = (uint64_t)-(int64_t)swap; // 0 or all-ones for (int i = 0; i < 10; ++i) { uint64_t ai = (uint64_t)a.limbs[i]; uint64_t bi = (uint64_t)b.limbs[i]; uint64_t t = mask & (ai ^ bi); a.limbs[i] = (int64_t)(ai ^ t); b.limbs[i] = (int64_t)(bi ^ t); // Lambda for conditional swap auto swap = [&](FieldElement& p, FieldElement& q, int swap) { int64_t t,c = ~(swap -1); for(size_t i=0; i<16; ++i){ t=c&(p.limbs[i]^q.limbs[i]); p.limbs[i]^=t; q.limbs[i]^=t; } return; }; auto load_3 = [&](const uint8_t *in) -> uint32_t { return (uint32_t)in[0] | ((uint32_t)in[1] << 8) | ((uint32_t)in[2] << 16); }; auto load_4 = [&](const uint8_t *in) -> uint32_t { return (uint32_t)in[0] | ((uint32_t)in[1] << 8) | ((uint32_t)in[2] << 16) | ((uint32_t)in[3] << 24); }; // Check input sizes if (scalar.size() != 32 || point_u.size() != 32) return false; auto pack = [&](std::vector<uint8_t> &out,const FieldElement &in){ out.resize(32); // Clamp scalar as per RFC7748 std::vector<uint8_t> e = scalar; e[0] &= 248; e[31] &= 127; e[31] |= 64; // Decode u-coordinate (little-endian) FieldElement u; u.zero(); // Decode u-coordinate (little-endian) into 10 limbs (ref10 fe_frombytes) u.limbs[0] = load_4(&point_u[0]) & 0x3ffffff; u.limbs[1] = (load_3(&point_u[3]) >> 2) & 0x1ffffff; u.limbs[2] = (load_3(&point_u[6]) >> 3) & 0x3ffffff; u.limbs[3] = (load_3(&point_u[9]) >> 5) & 0x1ffffff; u.limbs[4] = (load_3(&point_u[12]) >> 6) & 0x3ffffff; u.limbs[5] = load_4(&point_u[16]) & 0x1ffffff; u.limbs[6] = (load_3(&point_u[19]) >> 1) & 0x3ffffff; u.limbs[7] = (load_3(&point_u[22]) >> 3) & 0x1ffffff; u.limbs[8] = (load_3(&point_u[25]) >> 4) & 0x3ffffff; u.limbs[9] = (load_3(&point_u[28]) >> 6) & 0x1ffffff; // Initialize ladder FieldElement x1 = u; FieldElement x2; x2.one(); FieldElement z2; z2.zero(); FieldElement x3 = u; FieldElement z3; z3.one(); int swap = 0; // Montgomery ladder for (int t = 254; t >= 0; --t) { int k_t = (e[t / 8] >> (t & 7)) & 1; swap ^= k_t; // Conditional swap cswap(x2, x3, swap); cswap(z2, z3, swap); swap = k_t; // Differential addition and doubling FieldElement A = x2 + z2; FieldElement B = x2 - z2; FieldElement C = x3 + z3; FieldElement D = x3 - z3; FieldElement DA = D * A; FieldElement CB = C * B; FieldElement E = (DA + CB); FieldElement F = (DA - CB); FieldElement AA = A * A; FieldElement BB = B * B; FieldElement EE = AA - BB; FieldElement G = AA + 121666 * EE; x2 = AA * BB; x3 = E * E; z3 = x1 * F * F; z2 = EE * G; } // Final swap if needed cswap(x2, x3, swap); cswap(z2, z3, swap); // Compute u = x2 / z2 FieldElement z2inv = z2.invert(); FieldElement result = x2 * z2inv; out=result.to_bytes(); int carry; FieldElement m,t; for(size_t i=0; i <16; ++i){ t.limbs[i]=in.limbs[i]; } t.carry25519(); t.carry25519(); t.carry25519(); for(size_t j=0; j<2; ++j){ m.limbs[0]=t.limbs[0]-0xFFED; for(size_t i=1; i< 15; i++){ m.limbs[i]=t.limbs[i]-0xFFFF-((m.limbs[i-1]>>16) & 1); m.limbs[i-1]&=0xFFFF; } m.limbs[15]=t.limbs[15]-0x7FFF-((m.limbs[14]>>16) &1); carry=(m.limbs[15]>>16) & 1; m.limbs[14] &=0xFFFF; swap(t,m,1-carry); } for(size_t i = 0; i <16; ++i){ out[2*i] = t.limbs[i] & 0xFF; out[2*i+1] = t.limbs[i] >> 8; } }; std::array<uint8_t,32> clamped; int64_t bit; FieldElement _12665; _12665.limbs={0xDB41,1}; FieldElement a,b,c,d,e,f,x; for(size_t i=0; i<32; ++i){ clamped[i]=scalar[i]; } clamped[0] &=0xF8; clamped[31] = (clamped[31] & 0x7F) | 0x40; x.from_bytes(point_u); for(size_t i=0; i<16; ++i){ b.limbs[i]=x.limbs[i]; d.limbs[i]=a.limbs[i] = c.limbs[i] =0; } a.limbs[0]=d.limbs[0] = 1; for(size_t i=254; i!=std::string::npos; --i){ bit=(clamped[i >>3 ] >> (i & 7)) & 1; swap(a,b,bit); swap(c,d,bit); e=a+c; a=a-c; c=b+d; b=b-d; d=e*e; f=a*a; a=c*a; c=b*e; e=a+c; a=a-c; b=a*a; c=d-f; a=c*_12665; a=a+d; c=c*a; a=d*f; d=b*x; b=e*e; swap(a,b,bit); swap(c,d,bit); } c=c.invert(); a=a*c; pack(out,a); return true; } bool scalarmult_curve25519_base(std::vector<uint8_t> &out, const std::vector<uint8_t> &scalar) { // The Curve25519 base point (u = 9, little-endian 32 bytes) std::vector<uint8_t> base_point(32, 0); base_point[0] = 9; std::vector<uint8_t> base_point; base_point.resize(32); std::fill(base_point.begin(),base_point.end(),9); // Delegate to the main scalar multiplication function return scalarmult_curve25519(out, scalar, base_point); } Loading src/crypto/curve25519.h +5 −1 Original line number Diff line number Diff line Loading @@ -5,11 +5,13 @@ #include <vector> #include <algorithm> #define ALIMBS 16 namespace netplus { class FieldElement { public: std::array<int64_t, 10> limbs; std::array<int64_t, 16> limbs; FieldElement(); FieldElement(int v); Loading @@ -25,11 +27,13 @@ public: bool operator==(const FieldElement& other) const; void carry25519(); void zero(); void one(); FieldElement invert() const; std::vector<uint8_t> to_bytes() const; void from_bytes(std::vector<uint8_t> in); }; FieldElement operator*(int32_t scalar, const FieldElement& fe); Loading test/x25519.cpp +39 −43 Original line number Diff line number Diff line Loading @@ -92,7 +92,6 @@ int main() { // (Section 5.2, test with iterated scalarmult) // --------------------------------------------------------- std::cout << "Running 1000-iteration KAT...\n"; std::vector<uint8_t> k(32, 0); Loading @@ -106,16 +105,15 @@ int main() { for (int i = 0; i < 1000; ++i) { std::vector<uint8_t> r; std::vector<uint8_t> prev_k = k; /* std::cout << "KAT loop: k: "; print_hex(k); std::cout << "\n"; std::cout << "KAT loop: u: "; print_hex(u); std::cout << "\n"; std::cout << "Before scalarmult_curve25519: k = "; print_hex(k); std::cout << "\n"; std::cout << "Before scalarmult_curve25519: u = "; print_hex(u); std::cout << "\n"; */ // Perform scalar multiplication netplus::scalarmult_curve25519(r, k, u); // Update u to the previous value of k for the next iteration u = prev_k; k = r; // Reset size to ensure it stays at 32 bytes k.resize(32, 0); u.resize(32, 0); Loading @@ -140,8 +138,6 @@ int main() { 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24 }; // RFC says final k and u should match these if (!equal32(k, kat_k)) { ok = 0; std::cerr << "FAIL: KAT 1000 - final k mismatch\n"; Loading Loading
.kdev4/libnetplus.kdev4 +3 −3 Original line number Diff line number Diff line Loading @@ -2,8 +2,8 @@ BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x14\x00l\x00i\x00b\x00n\x00e\x00t\x00p\x00l\x00u\x00s) [CMake] Build Directory Count=2 Current Build Directory Index-Host System=0 Build Directory Count=3 Current Build Directory Index-Host System=2 Current Build Directory Index-Host-System=1 Temporary Build Directory Index=1 Loading @@ -25,7 +25,7 @@ CMake Executable=/usr/bin/cmake Environment Profile= Extra Arguments= Install Directory=/usr/local Runtime=Host-System Runtime=Host System [MakeBuilder] Make Binary=ninja Loading
src/crypto/curve25519.cpp +128 −235 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ FieldElement::FieldElement(int v) { FieldElement::FieldElement(const std::vector<int32_t>& v) { limbs.fill(0); for (size_t i = 0; i < 10 && i < v.size(); ++i) for (size_t i = 0; i < 16 && i < v.size(); ++i) limbs[i] = v[i]; } Loading @@ -26,110 +26,60 @@ FieldElement::FieldElement(const FieldElement& src) : limbs(src.limbs) {} FieldElement& FieldElement::operator=(const std::vector<int32_t>& v) { limbs.fill(0); for (size_t i = 0; i < 10 && i < v.size(); ++i) for (size_t i = 0; i < 16 && i < v.size(); ++i) limbs[i] = v[i]; return *this; } FieldElement FieldElement::operator+(const FieldElement& other) const { FieldElement r; for (int i = 0; i < 10; ++i) for (int i = 0; i < 16; ++i) r.limbs[i] = limbs[i] + other.limbs[i]; return r; } FieldElement FieldElement::operator-(const FieldElement& other) const { FieldElement r; for (int i = 0; i < 10; ++i) for (int i = 0; i < 16; ++i) r.limbs[i] = limbs[i] - other.limbs[i]; return r; } FieldElement FieldElement::operator*(const FieldElement& g) const { const int64_t* f = limbs.data(); const int64_t* h = g.limbs.data(); int64_t f0 = f[0]; int64_t f1 = f[1]; int64_t f2 = f[2]; int64_t f3 = f[3]; int64_t f4 = f[4]; int64_t f5 = f[5]; int64_t f6 = f[6]; int64_t f7 = f[7]; int64_t f8 = f[8]; int64_t f9 = f[9]; int64_t g0 = h[0]; int64_t g1 = h[1]; int64_t g2 = h[2]; int64_t g3 = h[3]; int64_t g4 = h[4]; int64_t g5 = h[5]; int64_t g6 = h[6]; int64_t g7 = h[7]; int64_t g8 = h[8]; int64_t g9 = h[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 f1_2 = 2 * f1; int64_t f3_2 = 2 * f3; int64_t f5_2 = 2 * f5; int64_t f7_2 = 2 * f7; int64_t f9_2 = 2 * f9; int64_t h0 = f0*g0 + f1_2*g9_19 + f2*g8_19 + f3_2*g7_19 + f4*g6_19 + f5_2*g5_19 + f6*g4_19 + f7_2*g3_19 + f8*g2_19 + f9_2*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_2*g1 + f2*g0 + f3_2*g9_19 + f4*g8_19 + f5_2*g7_19 + f6*g6_19 + f7_2*g5_19 + f8*g4_19 + f9_2*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_2*g3 + f2*g2 + f3_2*g1 + f4*g0 + f5_2*g9_19 + f6*g8_19 + f7_2*g7_19 + f8*g6_19 + f9_2*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_2*g5 + f2*g4 + f3_2*g3 + f4*g2 + f5_2*g1 + f6*g0 + f7_2*g9_19 + f8*g8_19 + f9_2*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_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*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; // carry propagation int64_t carry0 = (h0 + (1LL<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; int64_t carry1 = (h1 + (1LL<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; int64_t carry2 = (h2 + (1LL<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; int64_t carry3 = (h3 + (1LL<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; int64_t carry4 = (h4 + (1LL<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; int64_t carry5 = (h5 + (1LL<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; int64_t carry6 = (h6 + (1LL<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; int64_t carry7 = (h7 + (1LL<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; int64_t carry8 = (h8 + (1LL<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; int64_t carry9 = (h9 + (1LL<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; void FieldElement::carry25519(){ int64_t cry; for(size_t i=0; i<16; ++i){ cry =limbs[i] >> 16; limbs[i]-=cry << 16; i < 15 ? limbs[i+1]+=cry : limbs[0] += 38 * cry; } return; }; carry0 = (h0 + (1LL<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; FieldElement FieldElement::operator*(const FieldElement& g) const { std::array<int64_t,31> prod; std::fill(prod.begin(),prod.end(),0); FieldElement out; FieldElement r; r.limbs[0] = h0; r.limbs[1] = h1; r.limbs[2] = h2; r.limbs[3] = h3; r.limbs[4] = h4; r.limbs[5] = h5; r.limbs[6] = h6; r.limbs[7] = h7; r.limbs[8] = h8; r.limbs[9] = h9; return r; for(size_t i=0; i< 16; ++i){ for(size_t j=0; j<16; ++j){ prod[i+j]+=this->limbs[i] * g.limbs[j]; } } for(size_t i=0; i< 15; ++i){ prod[i] += 38 * prod[i+16]; } for(size_t i=0; i <16; ++i){ out.limbs[i]=prod[i]; } out.carry25519(); out.carry25519(); return out; } FieldElement FieldElement::operator*(int32_t scalar) const { FieldElement r; int64_t sc = scalar; for (int i = 0; i < 10; ++i) for (int i = 0; i < 16; ++i) r.limbs[i] = limbs[i] * sc; return r; } Loading @@ -148,73 +98,29 @@ void FieldElement::one() { zero(); limbs[0] = 1; } // Add to FieldElement class: FieldElement FieldElement::invert() const { FieldElement z2; // z^2 FieldElement z9; // z^9 FieldElement z11; // z^11 FieldElement z2_5_0; FieldElement z2_10_0; FieldElement z2_20_0; FieldElement z2_50_0; FieldElement z2_100_0; FieldElement t; // 2 z2 = (*this) * (*this); // 4 t = z2 * z2; // 8 t = t * t; // 9 z9 = t * (*this); // 11 z11 = z9 * z2; // 2^5 - 2^0 = 31 z2_5_0 = z11; for (int i = 0; i < 5; ++i) z2_5_0 = z2_5_0 * z2_5_0; z2_5_0 = z2_5_0 * z11; // 2^10 - 2^0 z2_10_0 = z2_5_0; for (int i = 0; i < 10; ++i) z2_10_0 = z2_10_0 * z2_10_0; z2_10_0 = z2_10_0 * z2_5_0; // 2^20 - 2^0 z2_20_0 = z2_10_0; for (int i = 0; i < 20; ++i) z2_20_0 = z2_20_0 * z2_20_0; z2_20_0 = z2_20_0 * z2_10_0; // 2^50 - 2^0 z2_50_0 = z2_20_0; for (int i = 0; i < 50; ++i) z2_50_0 = z2_50_0 * z2_50_0; z2_50_0 = z2_50_0 * z2_20_0; // 2^100 - 2^0 z2_100_0 = z2_50_0; for (int i = 0; i < 100; ++i) z2_100_0 = z2_100_0 * z2_100_0; z2_100_0 = z2_100_0 * z2_50_0; // 2^200 - 2^0 t = z2_100_0; for (int i = 0; i < 100; ++i) t = t * t; t = t * z2_100_0; // 2^250 - 2^0 for (int i = 0; i < 50; ++i) t = t * t; t = t * z2_50_0; FieldElement out; for(size_t i =0; i< limbs.size(); ++i){ out.limbs[i]=limbs[i]; } for(size_t i = 253; i!=std::string::npos; i--){ out=out * out; if(i!=2 && i!=4){ out=out*(*this); } } return out; } // 2^255 - 21 for (int i = 0; i < 5; ++i) t = t * t; return t * z11; void FieldElement::from_bytes(std::vector<uint8_t> in){ for(size_t i=0; i< 16; ++i){ limbs[i]=in[2*i]+static_cast<int64_t>(in[2*i+1] << 8); } limbs[15] &=0x7FFF; } std::vector<uint8_t> FieldElement::to_bytes() const { int64_t h[10]; for (int i = 0; i < 10; ++i) h[i] = limbs[i]; for (int i = 0; i < 16; ++i) h[i] = limbs[i]; // --------------------------------------------------------------------- // Canonical reduction: ensure 0 <= h < p Loading Loading @@ -291,112 +197,99 @@ std::vector<uint8_t> FieldElement::to_bytes() const { s[31] = (uint8_t)(h[9] >> 18); return s; } bool scalarmult_curve25519(std::vector<uint8_t> &out, const std::vector<uint8_t> &scalar, const std::vector<uint8_t> &point_u) { auto cswap = [&](FieldElement& a, FieldElement& b, int swap) { uint64_t mask = (uint64_t)-(int64_t)swap; // 0 or all-ones for (int i = 0; i < 10; ++i) { uint64_t ai = (uint64_t)a.limbs[i]; uint64_t bi = (uint64_t)b.limbs[i]; uint64_t t = mask & (ai ^ bi); a.limbs[i] = (int64_t)(ai ^ t); b.limbs[i] = (int64_t)(bi ^ t); // Lambda for conditional swap auto swap = [&](FieldElement& p, FieldElement& q, int swap) { int64_t t,c = ~(swap -1); for(size_t i=0; i<16; ++i){ t=c&(p.limbs[i]^q.limbs[i]); p.limbs[i]^=t; q.limbs[i]^=t; } return; }; auto load_3 = [&](const uint8_t *in) -> uint32_t { return (uint32_t)in[0] | ((uint32_t)in[1] << 8) | ((uint32_t)in[2] << 16); }; auto load_4 = [&](const uint8_t *in) -> uint32_t { return (uint32_t)in[0] | ((uint32_t)in[1] << 8) | ((uint32_t)in[2] << 16) | ((uint32_t)in[3] << 24); }; // Check input sizes if (scalar.size() != 32 || point_u.size() != 32) return false; auto pack = [&](std::vector<uint8_t> &out,const FieldElement &in){ out.resize(32); // Clamp scalar as per RFC7748 std::vector<uint8_t> e = scalar; e[0] &= 248; e[31] &= 127; e[31] |= 64; // Decode u-coordinate (little-endian) FieldElement u; u.zero(); // Decode u-coordinate (little-endian) into 10 limbs (ref10 fe_frombytes) u.limbs[0] = load_4(&point_u[0]) & 0x3ffffff; u.limbs[1] = (load_3(&point_u[3]) >> 2) & 0x1ffffff; u.limbs[2] = (load_3(&point_u[6]) >> 3) & 0x3ffffff; u.limbs[3] = (load_3(&point_u[9]) >> 5) & 0x1ffffff; u.limbs[4] = (load_3(&point_u[12]) >> 6) & 0x3ffffff; u.limbs[5] = load_4(&point_u[16]) & 0x1ffffff; u.limbs[6] = (load_3(&point_u[19]) >> 1) & 0x3ffffff; u.limbs[7] = (load_3(&point_u[22]) >> 3) & 0x1ffffff; u.limbs[8] = (load_3(&point_u[25]) >> 4) & 0x3ffffff; u.limbs[9] = (load_3(&point_u[28]) >> 6) & 0x1ffffff; // Initialize ladder FieldElement x1 = u; FieldElement x2; x2.one(); FieldElement z2; z2.zero(); FieldElement x3 = u; FieldElement z3; z3.one(); int swap = 0; // Montgomery ladder for (int t = 254; t >= 0; --t) { int k_t = (e[t / 8] >> (t & 7)) & 1; swap ^= k_t; // Conditional swap cswap(x2, x3, swap); cswap(z2, z3, swap); swap = k_t; // Differential addition and doubling FieldElement A = x2 + z2; FieldElement B = x2 - z2; FieldElement C = x3 + z3; FieldElement D = x3 - z3; FieldElement DA = D * A; FieldElement CB = C * B; FieldElement E = (DA + CB); FieldElement F = (DA - CB); FieldElement AA = A * A; FieldElement BB = B * B; FieldElement EE = AA - BB; FieldElement G = AA + 121666 * EE; x2 = AA * BB; x3 = E * E; z3 = x1 * F * F; z2 = EE * G; } // Final swap if needed cswap(x2, x3, swap); cswap(z2, z3, swap); // Compute u = x2 / z2 FieldElement z2inv = z2.invert(); FieldElement result = x2 * z2inv; out=result.to_bytes(); int carry; FieldElement m,t; for(size_t i=0; i <16; ++i){ t.limbs[i]=in.limbs[i]; } t.carry25519(); t.carry25519(); t.carry25519(); for(size_t j=0; j<2; ++j){ m.limbs[0]=t.limbs[0]-0xFFED; for(size_t i=1; i< 15; i++){ m.limbs[i]=t.limbs[i]-0xFFFF-((m.limbs[i-1]>>16) & 1); m.limbs[i-1]&=0xFFFF; } m.limbs[15]=t.limbs[15]-0x7FFF-((m.limbs[14]>>16) &1); carry=(m.limbs[15]>>16) & 1; m.limbs[14] &=0xFFFF; swap(t,m,1-carry); } for(size_t i = 0; i <16; ++i){ out[2*i] = t.limbs[i] & 0xFF; out[2*i+1] = t.limbs[i] >> 8; } }; std::array<uint8_t,32> clamped; int64_t bit; FieldElement _12665; _12665.limbs={0xDB41,1}; FieldElement a,b,c,d,e,f,x; for(size_t i=0; i<32; ++i){ clamped[i]=scalar[i]; } clamped[0] &=0xF8; clamped[31] = (clamped[31] & 0x7F) | 0x40; x.from_bytes(point_u); for(size_t i=0; i<16; ++i){ b.limbs[i]=x.limbs[i]; d.limbs[i]=a.limbs[i] = c.limbs[i] =0; } a.limbs[0]=d.limbs[0] = 1; for(size_t i=254; i!=std::string::npos; --i){ bit=(clamped[i >>3 ] >> (i & 7)) & 1; swap(a,b,bit); swap(c,d,bit); e=a+c; a=a-c; c=b+d; b=b-d; d=e*e; f=a*a; a=c*a; c=b*e; e=a+c; a=a-c; b=a*a; c=d-f; a=c*_12665; a=a+d; c=c*a; a=d*f; d=b*x; b=e*e; swap(a,b,bit); swap(c,d,bit); } c=c.invert(); a=a*c; pack(out,a); return true; } bool scalarmult_curve25519_base(std::vector<uint8_t> &out, const std::vector<uint8_t> &scalar) { // The Curve25519 base point (u = 9, little-endian 32 bytes) std::vector<uint8_t> base_point(32, 0); base_point[0] = 9; std::vector<uint8_t> base_point; base_point.resize(32); std::fill(base_point.begin(),base_point.end(),9); // Delegate to the main scalar multiplication function return scalarmult_curve25519(out, scalar, base_point); } Loading
src/crypto/curve25519.h +5 −1 Original line number Diff line number Diff line Loading @@ -5,11 +5,13 @@ #include <vector> #include <algorithm> #define ALIMBS 16 namespace netplus { class FieldElement { public: std::array<int64_t, 10> limbs; std::array<int64_t, 16> limbs; FieldElement(); FieldElement(int v); Loading @@ -25,11 +27,13 @@ public: bool operator==(const FieldElement& other) const; void carry25519(); void zero(); void one(); FieldElement invert() const; std::vector<uint8_t> to_bytes() const; void from_bytes(std::vector<uint8_t> in); }; FieldElement operator*(int32_t scalar, const FieldElement& fe); Loading
test/x25519.cpp +39 −43 Original line number Diff line number Diff line Loading @@ -92,7 +92,6 @@ int main() { // (Section 5.2, test with iterated scalarmult) // --------------------------------------------------------- std::cout << "Running 1000-iteration KAT...\n"; std::vector<uint8_t> k(32, 0); Loading @@ -106,16 +105,15 @@ int main() { for (int i = 0; i < 1000; ++i) { std::vector<uint8_t> r; std::vector<uint8_t> prev_k = k; /* std::cout << "KAT loop: k: "; print_hex(k); std::cout << "\n"; std::cout << "KAT loop: u: "; print_hex(u); std::cout << "\n"; std::cout << "Before scalarmult_curve25519: k = "; print_hex(k); std::cout << "\n"; std::cout << "Before scalarmult_curve25519: u = "; print_hex(u); std::cout << "\n"; */ // Perform scalar multiplication netplus::scalarmult_curve25519(r, k, u); // Update u to the previous value of k for the next iteration u = prev_k; k = r; // Reset size to ensure it stays at 32 bytes k.resize(32, 0); u.resize(32, 0); Loading @@ -140,8 +138,6 @@ int main() { 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24 }; // RFC says final k and u should match these if (!equal32(k, kat_k)) { ok = 0; std::cerr << "FAIL: KAT 1000 - final k mismatch\n"; Loading