ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
bignum.h File Reference

2048-bit big-integer arithmetic for DH-group14 and RSA-2048. More...

#include "protocore_config.h"
#include "server/mmgr/secure.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>

Go to the source code of this file.

Classes

struct  pc_bignum
 A 2048-bit unsigned integer stored as 64 little-endian 32-bit limbs. More...
 

Macros

#define PC_BN_LIMBS   64
 Number of 32-bit limbs in a 2048-bit integer.
 

Functions

void bn_from_bytes (pc_bignum *out, const uint8_t *bytes, size_t len)
 Read a big-endian byte array of len bytes into a pc_bignum.
 
void bn_to_bytes (uint8_t bytes[256], const pc_bignum *in)
 Write a pc_bignum as a 256-byte big-endian array.
 
int bn_cmp (const pc_bignum *a, const pc_bignum *b)
 Compare two pc_bignum values.
 
int bn_is_zero (const pc_bignum *a)
 Return non-zero if a is zero (all limbs zero).
 
int bn_cmp_raw (const uint32_t *a, const uint32_t *b, int n)
 Compute out = base^exp mod group14_p.
 
void bn_expmod_group14 (pc_bignum *out, const pc_bignum *base, const pc_bignum *exp)
 
int bn_dh_validate (const pc_bignum *v)
 Validate a received DH public value.
 

Variables

const pc_bignum group14_p
 The RFC 3526 MODP group-14 prime (2048-bit).
 
const pc_bignum group14_g
 Generator for group-14: g = 2.
 

Detailed Description

2048-bit big-integer arithmetic for DH-group14 and RSA-2048.

═══════════════════════════════════════════════════════════════════════════ DESIGN RATIONALE ═══════════════════════════════════════════════════════════════════════════

pc_bignum is a fixed-width 2048-bit integer stored as 64 little-endian 32-bit limbs (d[0] = least significant). Fixed width means:

  • Struct size is a compile-time constant: 256 bytes.
  • No dynamic allocation - both DH scalars and RSA key fragments fit in the same type and can live in BSS or on the stack.
  • Array indexing is bounds-safe; no VLA or pointer arithmetic hazards.

On Arduino (ESP32), DH uses mbedtls_mpi from ESP-IDF (heap-allocated, variable-length bignum), which has hardware-accelerated multiplication. On native builds, the software Montgomery path is used - correct but slower (~200 ms for a 2048-bit exponentiation on x86 at test time). Since DH happens once per connection and ESP32 uses the HW path in production, the native speed is acceptable for testing.

═══════════════════════════════════════════════════════════════════════════ MONTGOMERY MULTIPLICATION ═══════════════════════════════════════════════════════════════════════════

For DH-group14 the modulus p ends in ...FFFFFFFF FFFFFFFF (little-endian d[0]=0xFFFFFFFF). This gives Montgomery parameter:

p_inv = (-(p mod 2^32))^(-1) mod 2^32 = (-(0xFFFFFFFF))^(-1) mod 2^32 = (0x00000001)^(-1) mod 2^32 = 1

p_inv = 1 simplifies the inner reduction loop: m_i = t[i] * 1 = t[i].

Montgomery product: MonPro(a,b) = a·b·R^-1 mod p where R = 2^2048.

To compute a·b mod p normally:

  1. Convert a, b to Montgomery form: aR = a·R mod p (= MonPro(a, R²mod p))
  2. Compute MonPro(aR, bR) = a·b·R mod p
  3. Convert back: MonPro(a·b·R, 1) = a·b mod p

R² mod p is a precomputed 2048-bit constant (see pc_bignum.cpp).

═══════════════════════════════════════════════════════════════════════════ SCRATCH BUFFER ═══════════════════════════════════════════════════════════════════════════

The Montgomery SOS multiplication needs a 129-word (516-byte) temporary and the expmod three pc_bignum temporaries (768 bytes). bn_expmod_group14() borrows all of them as ONE working set from the secure pool (server/mmgr/secure.h), so the layout is the struct's own field order rather than byte offsets kept in step by hand here.

These temporaries hold DH private-exponent and shared-secret fragments. They are wiped when the borrow is released - by the pool, on every exit path. This module does not perform the wipe and does not need to know that one happens.

═══════════════════════════════════════════════════════════════════════════

Author
Douglas Quigg (dstroy0)
Date
2026

Definition in file bignum.h.

Macro Definition Documentation

◆ PC_BN_LIMBS

#define PC_BN_LIMBS   64

Number of 32-bit limbs in a 2048-bit integer.

Definition at line 83 of file bignum.h.

Function Documentation

◆ bn_from_bytes()

void bn_from_bytes ( pc_bignum out,
const uint8_t *  bytes,
size_t  len 
)

Read a big-endian byte array of len bytes into a pc_bignum.

If len < 256 the most-significant limbs are zeroed. If len > 256 only the least-significant 256 bytes are read.

Parameters
outDestination bignum.
bytesBig-endian source bytes.
lenNumber of source bytes (typically 256 for 2048-bit).

Definition at line 84 of file bignum.cpp.

References pc_bignum::d.

Referenced by ssh_kexdh_handle().

◆ bn_to_bytes()

void bn_to_bytes ( uint8_t  bytes[256],
const pc_bignum in 
)

Write a pc_bignum as a 256-byte big-endian array.

Parameters
bytesDestination buffer (exactly 256 bytes).
inSource bignum.

Definition at line 96 of file bignum.cpp.

References pc_bignum::d, and PC_BN_LIMBS.

Referenced by ssh_kexdh_handle().

◆ bn_cmp()

int bn_cmp ( const pc_bignum a,
const pc_bignum b 
)

Compare two pc_bignum values.

Returns
-1 if a < b, 0 if a == b, 1 if a > b.

Definition at line 108 of file bignum.cpp.

References bn_cmp_raw(), pc_bignum::d, and PC_BN_LIMBS.

Referenced by bn_dh_validate().

◆ bn_is_zero()

int bn_is_zero ( const pc_bignum a)

Return non-zero if a is zero (all limbs zero).

Definition at line 113 of file bignum.cpp.

References pc_bignum::d, and PC_BN_LIMBS.

◆ bn_cmp_raw()

int bn_cmp_raw ( const uint32_t *  a,
const uint32_t *  b,
int  n 
)

Compute out = base^exp mod group14_p.

Uses Montgomery modular exponentiation with left-to-right binary scan. Borrows one working set for all temporaries; it is wiped when released.

On Arduino the computation is delegated to mbedtls_mpi_exp_mod() which uses hardware multiplication and blinding.

Parameters
outResult (base^exp mod p, 2048-bit).
baseBase value; must satisfy 1 < base < p-1.
expExponent (e.g. the 2048-bit private DH scalar y).

Compare two n-limb magnitudes: -1, 0 or 1. Shared with the backends.

Definition at line 64 of file bignum.cpp.

Referenced by bn_cmp().

◆ bn_expmod_group14()

void bn_expmod_group14 ( pc_bignum out,
const pc_bignum base,
const pc_bignum exp 
)

◆ bn_dh_validate()

int bn_dh_validate ( const pc_bignum v)

Validate a received DH public value.

RFC 4253 §8: the received value e (or f) must satisfy 1 < e < p-1. Returns 0 if the value is valid, -1 otherwise.

Parameters
vReceived public DH value.

Definition at line 125 of file bignum.cpp.

References bn_cmp(), pc_bignum::d, group14_p, and PC_BN_LIMBS.

Referenced by ssh_kexdh_handle().

Variable Documentation

◆ group14_p

const pc_bignum group14_p
extern

The RFC 3526 MODP group-14 prime (2048-bit).

Definition at line 42 of file bignum.cpp.

Referenced by bn_dh_validate().

◆ group14_g

const pc_bignum group14_g
extern

Generator for group-14: g = 2.

Definition at line 54 of file bignum.cpp.

Referenced by ssh_dh_generate().