Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Montgomery representation of integer modulo rings gives weird results when cross-compiled with mingw-w64 #31

Open
TransparentLC opened this issue Aug 7, 2023 · 0 comments

Comments

@TransparentLC
Copy link

I use mingw-w64 on Ubuntu 22.04 to cross-compile pbc to get 64-bit Windows binaries since only 32-bit binaries are provided on the homepage.

Build script
set -e

PBC_BUILD_DIR=$(pwd)
GMP_VERSION=6.3.0
PBC_VERSION=0.5.14

apt install mingw-w64 m4 flex bison

wget https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.zst
tar --zstd -xvf gmp-${GMP_VERSION}.tar.zst
rm gmp-${GMP_VERSION}.tar.zst

cd gmp-${GMP_VERSION}
./configure \
    CC="x86_64-w64-mingw32-gcc" \
    CC_FOR_BUILD="x86_64-linux-gnu-gcc" \
    CPPFLAGS="-I${PBC_BUILD_DIR}/include -D__USE_MINGW_ANSI_STDIO=0" \
    LDFLAGS="-L${PBC_BUILD_DIR}/lib" \
    --host=x86_64-w64-mingw32 \
    --prefix=${PBC_BUILD_DIR} \
    --enable-static \
    --disable-shared
make -j$(nproc)
make check -j$(nproc)
make install
cd ..

wget https://crypto.stanford.edu/pbc/files/pbc-${PBC_VERSION}.tar.gz
tar zxvf pbc-${PBC_VERSION}.tar.gz
rm pbc-${PBC_VERSION}.tar.gz

cd pbc-${PBC_VERSION}
./configure \
    CC="x86_64-w64-mingw32-gcc" \
    CPPFLAGS="-I${PBC_BUILD_DIR}/include -D__USE_MINGW_ANSI_STDIO=0" \
    LDFLAGS="-L${PBC_BUILD_DIR}/lib" \
    LIBS="-lgmp" \
    --host=x86_64-w64-mingw32 \
    --prefix=${PBC_BUILD_DIR} \
    --enable-static \
    --disable-shared
make -j$(nproc)
make install
cd ..

# ├── build.sh
# ├── main.c
# ├── gmp-x.x.x
# │   └── ...
# ├── include
# │   ├── gmp.h
# │   └── pbc
# │       ├── pbc.h
# │       └── ...
# ├── lib
# │   ├── libgmp.a
# │   ├── libgmp.la
# │   ├── libpbc.a
# │   ├── libpbc.la
# │   └── pkgconfig
# │       └── gmp.pc
# ├── pbc-x.x.x
# │   └── ...
# └── share
#     └── ...
# x86_64-w64-mingw32-gcc -Wall -Iinclude -o main main.c -Llib -lpbc -lgmp

Then I found that these binaries always gives weird results. For example, for the following code:

#include "pbc/pbc.h"

// param/a.param
#define CURVE_PARAM ("" \
    "type a\n" \
    "q 8780710799663312522437781984754049815806883199414208211028653399266475630880222957078625179422662221423155858769582317459277713367317481324925129998224791\n" \
    "h 12016012264891146079388821366740534204802954401251311822919615131047207289359704531102844802183906537786776\n" \
    "r 730750818665451621361119245571504901405976559617\n" \
    "exp2 159\n" \
    "exp1 107\n" \
    "sign1 1\n" \
    "sign0 1\n" \
"")

int main(int argc, char const *argv[]) {
    pbc_random_set_deterministic(0x114514);

    pairing_t e;
    pairing_init_set_str(e, CURVE_PARAM);

    element_t x; element_init_Zr(x, e);
    element_set0(x);
    element_printf("x (set0) = %B\n", x);
    element_set1(x);
    element_printf("x (set1) = %B\n", x);
    element_add(x, x, x);
    element_printf("x (add(set1, set1)) = %B\n", x);
    element_set_si(x, 0x2);
    element_printf("x (set_si 0x2) = %B\n", x);
    element_random(x);
    element_printf("x (random seed=0x114514) = %B\n", x);
    element_from_hash(x, "Test data", 9);
    element_printf("x (from_hash \"Test data\") = %B\n", x);

    element_clear(x);
    pairing_clear(e);
    return 0;
}

The output when running on Ubuntu without cross-compiling:

x (set0) = 0
x (set1) = 1
x (add(set1, set1)) = 2
x (set_si 0x2) = 2
x (random seed=0x114514) = 627055856547974011506813785332492935521893207354
x (from_hash "Test data") = 481817657442947330395294957845829757162661110017

Running on Windows with cross-compiled binaries:

x (set0) = 0
x (set1) = 365375757781869456591985165927106086913303379970
x (add(set1, set1)) = 365375757781869456591985165927106086913303379971
x (set_si 0x2) = 365375757781869456591985165927106086913303379971
x (random seed=0x114514) = 704059715193577092360776882805714726779267438415
x (from_hash "Test data") = 269047460191534710553423228971153386492057830638

All of the assignment functions result in errors. The calculator and signature algorithms in the example also don't work. Someone on Stack Overflow seems to have encountered a similar problem.

This problem does not occur if the implementation of integer modulo ring used by pbc is changed to another implementation instead of the default Montgomery representation.

I don't know how to fix the implementation for now. A temporary fix is to add these lines to the code that uses pbc:

#ifdef __MINGW32__
#include "pbc/pbc_fp.h"
#endif

// ...

#ifdef __MINGW32__
pbc_tweak_use_fp("faster");
#endif

... or apply the patch before cross-compiling pbc:

--- arith/fp.c 2013-06-15 11:43:00.000000000 +0800
+++ arith/fp.c 2023-08-07 23:17:39.271450800 +0800
@@ -17,7 +17,11 @@
 // By default, use the montfp.c implementation of F_p. After
 // pbc_tweak_use_fp(), future field_init_fp calls will use the specified
 // implementation. This is useful for benchmarking and testing.
+#ifdef __MINGW32__
+static void (*option_fpinit) (field_ptr f, mpz_t prime) = field_init_faster_fp;
+#else
 static void (*option_fpinit) (field_ptr f, mpz_t prime) = field_init_mont_fp;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant