herumi / mcl

a portable and fast pairing-based cryptography library
BSD 3-Clause "New" or "Revised" License
450 stars 152 forks source link

[QUESTION] adding complement operator to mclBnFr that can handle full 32-byte serialized array #147

Closed exfinen closed 1 year ago

exfinen commented 2 years ago

Hi Mitsunari-san,

Based on your comments in #144, I'm trying to write a complement operator that works on top of mclBnFr in the following way:

  1. Serialize mclBnFr instance to a 32-byte buffer by mclBnFr_serialize
  2. Apply the C++ complement operator (~) to each byte in the buffer
  3. Deserialize the buffer to mclBnFr by mclBnFr_deserialize

This works for a small number such as INT64_MAX. Below code outputs:

        int64_t n = INT64_MAX;
        std::cout << n << std::endl;
        mclBnFr fr;
        mclBnFr_setInt(&fr, n);

        char nbuf[100];
        size_t size = mclBnFr_serialize(nbuf, 100, &fr);

        mclBnFr fr2;
        mclBnFr_deserialize(&fr2, nbuf, size);

        char sbuf[1024];
        mclBnFr_getStr(sbuf, 1024, &fr2, 10);
        std::cout << sbuf << std::endl;
9223372036854775807
9223372036854775807

But when I try a big number such as ~1, I get an unexpected result. Below code outputs:

        std::vector<uint8_t> nbuf = {
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            255,
            254
        };
        mclBnFr fr;
        mclBnFr_deserialize(&fr, &nbuf[0], 32);

        char sbuf[1024];
        mclBnFr_getStr(sbuf, 1024, &fr, 16);
        std::cout << sbuf << std::endl;
3c709a2cc99c42994f31c8f36ab38b2ffcde0ee4ec457b40d811492b03147f82

which differs from nbuf mod curve order or nbuf's hex representation that is:

fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe   // nbuf in hex
1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffc   // nbuf mod curve order in hex

While trying other bn.h functions, I found that setting curve order to mclBnFr with mclBnFr_setStr results in an error while curve order - 1 is accepted.

Is it the case that mclBnFr_deserialize expects its input to be below curve order like mclBnFr_setStr does? Or could you suggest if I and missing something?

herumi commented 1 year ago

You should have to check whether the return value of mclBnFr_deserialize is not zero. It returns zero if the value is bigger than or equal to the r.

The following codes shows

ret=32
3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
#include <mcl/bn_c384_256.h>
#include <stdint.h>
#include <vector>
#include <iostream>

int main()
    try
{
    mclBn_init(MCL_BLS12_381, MCLBN_COMPILED_TIME_VAR);
    std::vector<uint8_t> nbuf = {
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        255,
        63,
    };
    mclBnFr fr;
    int ret = mclBnFr_deserialize(&fr, &nbuf[0], 32);
    printf("ret=%d\n", ret);
    if (ret == 0) {
      fprintf(stderr, "bad value\n");
      return 1;
    }

    char sbuf[1024];
    mclBnFr_getStr(sbuf, 1024, &fr, 16);
    std::cout << sbuf << std::endl;
} catch (std::exception& e) {
    printf("err %s\n", e.what());
}
exfinen commented 1 year ago

Thank you. I understood. So mclBnFr doesn't accept a value outside Fr range from outside.