Commit 00f2b4a2 authored by jan.koester's avatar jan.koester
Browse files

rwar

parent 211888a2
Loading
Loading
Loading
Loading

test/ecc.cpp

0 → 100644
+344 −0
Original line number Diff line number Diff line
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cstdint>

#include "crypto/ecc_p256.h"
#include "crypto/ecc_u256.h"

using namespace netplus;

// ------------------------------------------------------------
// Dump helpers
// ------------------------------------------------------------
static void dump_hex(const char* name, const uint8_t* p, size_t n) {
    std::cout << name << " (" << std::dec << n << " bytes): ";
    for (size_t i = 0; i < n; i++)
        std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)p[i];
    std::cout << std::dec << "\n";
}

static void dump_u256_be(const char* name, const u256& a) {
    uint8_t b[32];
    u256_to_be(b, a);
    dump_hex(name, b, 32);
}

static void dump_u256_words(const char* name, const u256& a) {
    std::cout << name << " (LE words w0..w7): ";
    for(int i=0;i<8;i++){
        std::cout << std::hex << std::setw(8) << std::setfill('0') << a.w[i];
        if(i!=7) std::cout << " ";
    }
    std::cout << std::dec << "\n";
}

static void dump_u512_words(const char* name, const u512& x) {
    std::cout << name << " (w15..w0): ";
    for(int i=15;i>=0;--i){
        std::cout << std::hex << std::setw(8) << std::setfill('0') << x.w[i];
        if(i!=0) std::cout << " ";
    }
    std::cout << std::dec << "\n";
}

// ------------------------------------------------------------
// Correct: 64 bytes Big Endian -> u512 with w[0]=LSW
// ------------------------------------------------------------
static u512 u512_from_be64(const uint8_t be[64]) {
    u512 r;
    for(int i=0;i<16;i++){
        int o = 4*i;
        uint32_t w =
            ((uint32_t)be[o+0] << 24) |
            ((uint32_t)be[o+1] << 16) |
            ((uint32_t)be[o+2] <<  8) |
            ((uint32_t)be[o+3] <<  0);

        r.w[15 - i] = w; // store LE
    }
    return r;
}

// ------------------------------------------------------------
// Pattern sanity: 00..3F must map to w15..w0 = 00010203 ... 3C3D3E3F
// ------------------------------------------------------------
static bool test_u512_loader() {
    std::cout << "\n=== u512_from_be64() sanity test (00..3F pattern) ===\n";

    uint8_t pat[64];
    for(int i=0;i<64;i++) pat[i]=(uint8_t)i;

    u512 x = u512_from_be64(pat);
    dump_u512_words("PATTERN", x);

    uint32_t exp_w15_to_w0[16] = {
        0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f,
        0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f,
        0x20212223, 0x24252627, 0x28292a2b, 0x2c2d2e2f,
        0x30313233, 0x34353637, 0x38393a3b, 0x3c3d3e3f
    };

    bool ok=true;
    for(int i=0;i<16;i++){
        uint32_t want = exp_w15_to_w0[i];
        uint32_t got  = x.w[15 - i];
        if(got != want) ok=false;
    }

    std::cout << (ok ? "✅ PASS\n" : "❌ FAIL\n");
    return ok;
}

// ------------------------------------------------------------
// Prime check
// ------------------------------------------------------------
static void verify_prime_constant() {
    std::cout << "\n--- Prime Constant Check ---\n";
    dump_u256_be("P256_P", P256_P);
}

// ------------------------------------------------------------
// Montgomery field ops test
// ------------------------------------------------------------
static bool test_field_ops_mont() {
    std::cout << "\n=== Field Operations Test (Montgomery) ===\n";
    bool ok = true;

    u256 two_std   = {{2,0,0,0,0,0,0,0}};
    u256 three_std = {{3,0,0,0,0,0,0,0}};
    u256 one_std   = {{1,0,0,0,0,0,0,0}};

    u256 prod_std = from_mont(fp_mul(to_mont(two_std), to_mont(three_std)));
    if(prod_std.w[0] != 6) {
        ok=false;
        std::cout << "FAIL: 2*3 != 6\n";
        dump_u256_be("Got", prod_std);
    } else std::cout << "PASS: 2*3 == 6\n";

    uint32_t br=0;
    u256 pm1_std = u256_sub_raw(P256_P, one_std, br);

    u256 sum_std = from_mont(fp_add(to_mont(pm1_std), to_mont(one_std)));
    if(!u256_is_zero(sum_std)) {
        ok=false;
        std::cout << "FAIL: (P-1)+1 != 0\n";
        dump_u256_be("Got", sum_std);
    } else std::cout << "PASS: (P-1)+1 == 0\n";

    u256 sq_std = from_mont(fp_mul(to_mont(pm1_std), to_mont(pm1_std)));
    if(u256_cmp(sq_std, one_std)!=0) {
        ok=false;
        std::cout << "FAIL: (P-1)^2 != 1\n";
        dump_u256_be("sq", sq_std);
        dump_u256_words("sq", sq_std);
    } else std::cout << "PASS: (P-1)^2 == 1\n";

    return ok;
}

// ------------------------------------------------------------
// FIPS-ish test vector: input = P||payload  => result = payload
// ------------------------------------------------------------
static bool test_fips_vector() {
    std::cout << "\n=== NIST P-256 Reduction Test (P||payload) ===\n";

    uint8_t be[64] = {
        // MS 256 bits = P
        0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x01,
        0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,
        0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,
        // LS 256 bits = payload
        0x11,0x22,0x33,0x44, 0x55,0x66,0x77,0x88,
        0x99,0xaa,0xbb,0xcc, 0xdd,0xee,0xff,0x00,
        0x01,0x02,0x03,0x04, 0x05,0x06,0x07,0x08,
        0x09,0x0a,0x0b,0x0c, 0x0d,0x0e,0x0f,0x10
    };

    u512 input = u512_from_be64(be);
    dump_u512_words("Input", input);

    // since input = P*2^256 + payload, input mod P = payload
    u256 expected = {{
        0x0d0e0f10, 0x090a0b0c, 0x05060708, 0x01020304,
        0xddeeff00, 0x99aabbcc, 0x55667788, 0x11223344
    }};

    u256 got = mod_p256(input);

    if(u256_cmp(got, expected) != 0) {
        std::cout << "❌ FAIL\n";
        dump_u256_be("Got", got);
        dump_u256_be("Expected", expected);
        dump_u256_words("Got", got);
        dump_u256_words("Expected", expected);
        return false;
    }

    std::cout << "✅ PASS\n";
    return true;
}

// ------------------------------------------------------------
// NIST vector: x = 2^512-1
// ------------------------------------------------------------
// ------------------------------------------------------------
// NIST vector: x = 2^512-1
// ------------------------------------------------------------
static bool test_nist_vector() {
    std::cout << "\n=== NIST P-256 Reduction Vector Test (All F's) ===\n";

    u512 input;
    for(int i = 0; i < 16; i++) input.w[i] = 0xFFFFFFFFu;

    // ✅ Correct expected:
    // (2^512 - 1) mod p =
    // 00000004fffffffdfffffffffffffffefffffffbffffffff0000000000000002
    u256 expected = {{
        0x00000002,  // ✅ FIXED (LSW)
        0x00000000,
        0xFFFFFFFF,
        0xFFFFFFFB,
        0xFFFFFFFE,
        0xFFFFFFFF,
        0xFFFFFFFD,
        0x00000004   // MSW
    }};

    u256 got = mod_p256(input);

    if(u256_cmp(got, expected) != 0) {
        std::cout << "❌ FAIL\n";
        dump_u256_be("Got", got);
        dump_u256_be("Expected", expected);
        dump_u256_words("Got", got);
        dump_u256_words("Expected", expected);
        return false;
    }

    std::cout << "✅ PASS\n";
    return true;
}

static const uint8_t VEC_A_IN[64] = {
  0x11,0x22,0x33,0x44,0x38,0x47,0x56,0x21,
  0x19,0x28,0x37,0x46,0x48,0x29,0x30,0x21,
  0x39,0x53,0x79,0x01,0x18,0x73,0x13,0x2e,
  0x45,0x25,0x38,0x11,0x1f,0x49,0x67,0x3b,
  0x93,0x30,0x10,0xad,0x48,0x11,0xa2,0xf9,
  0xad,0x52,0x07,0x7e,0x7c,0x26,0x37,0x99,
  0x22,0x80,0x2d,0x3f,0x11,0x1c,0x0a,0xd1,
  0x36,0x7f,0x8a,0x7a,0x4b,0xc4,0x21,0xc4
};

static const uint8_t VEC_A_OUT[32] = {
  0x32,0xc8,0x1e,0x1e,0xc7,0xe5,0xa3,0xdf,
  0x0f,0x8c,0xc9,0x62,0x19,0x78,0x11,0x49,
  0xc9,0x10,0xe4,0x39,0x00,0x50,0xd6,0x54,
  0xe9,0x5c,0xe4,0xec,0xdd,0x46,0x8a,0x87
};

static const uint8_t VEC_B_IN[64] = {
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
};

static const uint8_t VEC_B_OUT[32] = {
  0x00,0x00,0x00,0x04,0xff,0xff,0xff,0xfd,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,
  0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02
};

static const uint8_t VEC_C_OUT[32] = {
  0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,
  0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00,
  0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
  0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10
};




static bool run_vec(const char* name, const uint8_t in64[64], const uint8_t out32[32]) {
    u512 x = u512_from_be64(in64);
    u256 got = mod_p256(x);

    uint8_t got_be[32];
    u256_to_be(got_be, got);

    if (std::memcmp(got_be, out32, 32) != 0) {
        std::cout << "❌ FAIL " << name << "\n";
        dump_hex("Got", got_be, 32);
        dump_hex("Expected", out32, 32);
        return false;
    }

    std::cout << "✅ PASS " << name << "\n";
    return true;
}

static bool selftest_modp() {
    int fails = 0;

    fails += !run_vec("VEC_A_FIPS", VEC_A_IN, VEC_A_OUT);
    fails += !run_vec("VEC_B_ALLF", VEC_B_IN, VEC_B_OUT);

    if (fails != 0){
        std::cout << "❌ MODP FAILS: " << fails << "\n";
        return false;
    }
    std::cout << "✅ ALL MODP TESTS PASSED\n";
    return true;
}

static bool test_kp_plus_x()
{
    u256 x = {{0xdeadbeef,0x11111111,0x22222222,0x33333333,
              0x44444444,0x55555555,0x66666666,0x77777777}};

    // build u512 input = p*2^256 + x  (k=2^256)
    u512 in;
    for(int i=0;i<8;i++) in.w[i] = x.w[i];
    for(int i=0;i<8;i++) in.w[i+8] = P256_P.w[i];

    u256 got = mod_p256(in);
    bool test = u256_cmp(got, x) == 0 ? true : false;

    if(!test)
        std::cout << "❌ test_kp_plus_x FAILED"<< "\n";

    return test;
}



int main() {
    int fails = 0;

    if(!test_kp_plus_x()) fails++;
    if(!selftest_modp()) fails++;
    if(!test_u512_loader()) fails++;
    verify_prime_constant();
    if(!test_field_ops_mont()) fails++;
    if(!test_fips_vector()) fails++;
    if(!test_nist_vector()) fails++;

    std::cout << "\n==============================\n";
    std::cout << "TEST SUMMARY\n";
    std::cout << "==============================\n";

    if(fails==0) {
        std::cout << "✅ ALL TESTS PASSED\n";
        return 0;
    }
    std::cout << "❌ FAILURES: " << fails << "\n";
    return 1;
}