Trying to use GMP on esp8266?

fair warning im a novice most of this stuff(software wise anyway).

i have a project that im working on that i want to be able to handle BIG numbers (2048 bits). i want them big beacuse i am trying to “build” long messages for the usbpd protocol and an unsigned long long is still too small. i did some reasartch and GMP seems to suit my needs. however the only available version of gmp in the librarys provided by platformio is mini-gmp witch doesn’t have the features i need. i have attempted to build GMP from source but i believe that i built if for x86 instead of esp8266(idk if i eaven built if for a specific architecture at all)

TBH im kinda lost

when i attempt to build my project i get the following error

c:/users/[my username]/.platformio/packages/toolchain-xtensa/bin/../lib/gcc/xtensa-lx106-elf/10.3.0/../../../../xtensa-lx106-elf/bin/ld.exe: lib\lib\libgmp.a: error adding symbols: file format not recognized
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\esp12e\firmware.elf] Error 1

you can take a look at my project at (i know im probably not using github right)
and shod be able to find my compiled version of GMP in the /lib directory

any help with getting GMP to work or suggesting other librays would be greatly appreciated

The linking error is definitely from you compiling it for x86 / x64.

I have personally tried to compile GMP for ESP8266 (xtensa-lx106) some time ago and have not succeeded. While it possible to get the libgmp.a compiled properly (after a tiny but of Makefile hacking, config.h massaging and a very long ./configure command that has all the esp8266-specific build flags), it immediately overflowed the available IRAM in the ESP8266. I have not looked further at it since then. I can publish my current state when I can.

This seems like a big red flag. There should be no 2048 bit long continuous numbers in the… USB PD protocol. Perhaps you need to construct a 2048 bit long message, made out of individual bytes or some individual integers in them. In that case you want a struct definition if the layout of which field is where is known beforehand.

// define datastructure
typedef struct {
  uint32_t some_field_1;
  int16_t power;
  uint8_t byte_coded[64];
  float what_even_is_this;
} weird_usb_pd_message;

// create message and fill data
weird_usb_pd_message my_msg;
my_msg.some_field_1 = 12345;
my_msg.power = 999;
const uint8_t x[64] = { 0xab, 0xcd, 0xef};
memcpy(&my_msg.byte_coded, x, sizeof(x));
// send off..

If the structure is not known beforehand or very dynamic, a simple byte buffer (uint8_t usb_msg[256];) can be used in which you can push elements into (e.g., a byte, a 16-bit short, a 32-bit int, a float, another byte array / structure, etc.), that at the end of all operations may have 2048 bits in it. In that case you can write the logic yourself (essentially memcpy()s and boundary checks) or even use a premade library like

ubyte_t main_arr[64] ;
byte_buffer b( main_arr, 64 ) ;
// push some data into it
b.putr< int   >( 42 ) ;
b.putr< char  >( 'a' ) ;
b.putr< float >( 42.42 ) ;
// main_arr now has b.position() bytes written to it

In the case that you are absolutely sure you need to do arithmetic (plus, minus, multiply, divide, modulus, exponentiation, inverted-modulo, GCD, …) on a 2048 bit number, and gmp-mini doesn’t cut in, the next best is to use the mbedTLS library. The library features a general “big int” sublibrary that you can freely use, mbedtls_mpi and all. It compiles for all platforms with very minimal configuration / integration for the target, only if you want it.

For example:

platform = espressif8266
board = nodemcuv2
framework = arduino
monitor_speed = 115200
; activate Bignum support in mbedTLS
build_flags =
; slightly older mbedTLS version
; but has integration with ESP8266's RNG and network interface
lib_deps =
#include <Arduino.h>
#include <mbedtls/bignum.h>

void setup() {

void print_mpi(mbedtls_mpi* num, const char* name) {
  size_t resultStrLen = 0;
  static char resultStr[512];
  mbedtls_mpi_write_string(num, 10, resultStr, sizeof(resultStr), &resultStrLen);
  Serial.print(": ");
  Serial.print((const char*)resultStr);

void loop() {
  mbedtls_mpi a, b, result;
  // read big decimal number from string
  mbedtls_mpi_read_string(&a, 10, "12345678999999999999999");
  // read big hexadecimal number from string
  mbedtls_mpi_read_string(&b, 16, "ABCDEF123456789ABCDEF123");
  // multiply them
  mbedtls_mpi_mul_mpi(&result, &a, &b);
  // print all out
  print_mpi(&a, "A");
  print_mpi(&b, "B");
  print_mpi(&result, "A * B");
  // free memory
  Serial.println("============ CALCULATION DONE  ====================");
A: 12345678999999999999999
B: 53170895453873139248688722211
A * B: 656430807416077083886558964441722395860751311277789
============ CALCULATION DONE  ====================

the reason why i need the big “number” is to store a built pd message to make it easier to hand to other functions. however as i am having issues with using GMP and the bignum lib’s big numbers aren’t big enough for my use case. moving forward i think im going to take a different approach and load the the message components broke down to individual bytes directly to an array so i dont have a need for a big number in the first place.

but thanks for the reply anyway :slight_smile: