apache / incubator-milagro-crypto-c

Apache milagro (Incubating)
Other
36 stars 15 forks source link

Python wrappers #38

Open GuillaumeCisco opened 5 years ago

GuillaumeCisco commented 5 years ago

Hello there.

I'm trying to implement some idemix support for the fabric hyperledger tool. Main thread here: https://lists.hyperledger.org/g/fabric/message/6625

I wonder if all the python wrappers are available for the milagro crypto c libreary. For exemple. I need to translate this: go implementation:

// RandModOrder returns a random element in 0, ..., GroupOrder-1
func RandModOrder(rng *amcl.RAND) *FP256BN.BIG {
   // curve order q
   q := FP256BN.NewBIGints(FP256BN.CURVE_Order)

   // Take random element in Zq
   return FP256BN.Randomnum(q, rng)
}

or java implementation

public static BIG randModOrder(RAND rng) {
    BIG q = new BIG(ROM.CURVE_Order);

    // Takes random element in this Zq.
    return BIG.randomnum(q, rng);
}

to python code. Is this achievable right now?

Thanks,

kealan commented 5 years ago

Hi There is only Python support for high level functions. It would be straightforward to extend the wrappers to level code.

GuillaumeCisco commented 5 years ago

Thank you very much @kealan for this confirmation. Could you help me begin in this translation. I'm not familiar with ffi and need a little help. I'll try a to make a Pull Request for supporting the rom.c file, if you can help me on this, it would be great!

kealan commented 5 years ago

Hi My advice would be just to copy the bls example.

GuillaumeCisco commented 5 years ago

Quick question, is bls_ZZZ.py.in a generated file? What .py.in stands for? could we generate a rom_ZZZ.py.in file?

kealan commented 5 years ago

Try and build the library and you will see what is happening. The bls_ZZZ.py.in is the template file that gets overwritten. In the rom files there are only constants so I don't see that you would need a wrapper for them.

GuillaumeCisco commented 5 years ago

Thanks for the precision, using make with a python virtual env set on python 2.7 built the target folder successfully. I now have files like bls_BLS381.py... If I understand it correctly, .py.in are only template files for a building over a specific curve. Here BLS381. In my particular case, I should build these files against FP256BN. I also tried the ./scripts/buildMulti.sh and saw no new files :/ I also looked at the config.mk file. I can see: AMCL_CURVE:=ED25519,NIST256,GOLDILOCKS,BLS381 Replacing it by AMCL_CURVE:=FP256BN and then running make, produced files like bls_FP256BN.py files which is what I'm looking for :)

Thanks! I'm still discovering this project and your help is greatly appreciated. I also see a folder target/default/lib with *.so files (I'm on linux). libamcl_bls_FP256BN.so libamcl_core_FP256BN.so libamcl_curve_FP256BN.so libamcl_mpin_FP256BN.so libamcl_pariing_FP256BN.so libamcl_rsa_FP256BN.so libamcl_wcc_FP256BN.so libamcl_x509.so

We have three templates: bls_ZZZ.py.in mpin_ZZZ.py.in wcc_ZZZ.py.in Should we create these others templates too? core_ZZZ.py.in curve_ZZZ.py.in pairing_ZZZ.py.in rsa_ZZZ.py.in

Now I need an extra help about handling the constants from rom_curve_FP256BN.c for example. How from python could I load the CURVE_Order_FP256BN. I guess this will be translated to a python tuple... but can't figure out how to import it.

kealan commented 5 years ago

For the constants you may have to write a c function which you wrap with CFFI. Something like this in C.

include

include

include

include

include <amcl/pair_BLS381.h>

int main() { BIG_384_58 q2; BIG_384_58 r2;

printf("BLS381\n");
BIG_384_58_rcopy(q2,Modulus_BLS381); printf("q (381) = 0x"); BIG_384_58_output(q2);
printf("\n");
BIG_384_58_rcopy(r2,CURVE_Order_BLS381); printf("r (257) = 0x"); }

GuillaumeCisco commented 5 years ago

Thanks. I need a little help on this one. If I create rom.c like:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <amcl/pair_FP256BN.h>

int main()
{
BIG_256_56 q2;
BIG_256_28 r2;

printf("BLS381\n");
BIG_256_56_rcopy(q2, Modulus_FP256BN);
printf("q (381) = 0x");
BIG_256_56_output(q2);
printf("\n");
BIG_256_28_rcopy(r2 ,CURVE_Order_FP256BN);
printf("r (257) = 0x");
}

Then how do I wrap it with cffi? If I write something like:

import cffi
import platform

ffi = cffi.FFI()
ffi.cdef("""
   int main();
""")

if (platform.system() == 'Windows'):
    libamcl_wcc_FP256BN = ffi.dlopen("libamcl_wcc_FP256BN.dll")
    libamcl_core = ffi.dlopen("libamcl_core.dll")
elif (platform.system() == 'Darwin'):
    libamcl_wcc_FP256BN = ffi.dlopen("libamcl_wcc_FP256BN.dylib")
    libamcl_core = ffi.dlopen("libamcl_core.dylib")
else:
    libamcl_wcc_FP256BN = ffi.dlopen("libamcl_wcc_FP256BN.so")
    libamcl_core = ffi.dlopen("libamcl_core.so")

libamcl_core.main()

It won't work, as there is no link between rom.c and libamcl_core. I should create a .so file from the rom.c, right? I have no knowledge in cffi and will learn how to use it. But a little help would be great ;) Also is it possible to simply export constant from a C code for importing it after from python?

Thanks

GuillaumeCisco commented 5 years ago

What I tried: Using the file test_pair_FP256BN.c which use CURVE_Order_FP256BN. Creating the .so (from python wrapper generated directory) using: gcc -g -I../../include -I../../../../include -fPIC -Wall -Wextra ../../test/test_pair_FP256BN.c -shared -o ./test_pair_FP256BN.so With a file named test_pair_FP256BN.py:

import cffi

ffi = cffi.FFI()
ffi.cdef("""
   int main();
""")

lib = ffi.dlopen("./test_pair_FP256BN.so")
lib.main()

Then:

$> python
Python 2.7.15+ (default, Nov 27 2018, 23:36:35) 
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test_pair_FP256BN
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: ./test_pair_FP256BN.so: undefined symbol: CURVE_Order_FP256BN

There is something I'm not doing correctly...

kealan commented 5 years ago

It could be that you need to link the dependent components;

See if you can build and run one of the examples after installation;

  1. use BLS381 in config.mk
  2. make; cd target/default; make install
  3. cp target/default/examples/example_bls_BLS381.c /tmp
  4. cd tmp
  5. edit /tmp/example_bls_BLS381.c

include

include

include

include <amcl/config_curve_BLS381.h>

include <amcl/randapi.h>

if CURVE_SECURITY_BLS381 == 128

include <amcl/bls_BLS381.h>

elif CURVE_SECURITY_BLS381 == 192

include <amcl/bls192_BLS381.h>

elif CURVE_SECURITY_BLS381 == 256

include <amcl/bls256_BLS381.h>

endif

  1. Build

gcc -O0 -g ./example_bls_BLS381.c $(pkg-config --libs --cflags amcl) -o example_bls_BLS381

For a new library that you want a CFFI interface you need to do the linking - that seems to be the only step you are missing.

GuillaumeCisco commented 5 years ago

Ok I succeeded runing this example, on a fresh environment, using these steps:

sudo apt-get install -y git cmake build-essential python python-dev python-pip libffi-dev doxygen doxygen-latex parallel pip install cffi (in a virtual env) Do not modify config.mk make cd target/default sudo make install (sudo is important for installing in /usr/... folders) cp ./example_bls_BLS381.c /tmp cd /tmp Edit example_bls_BLS381.c for replacing imports"

#include "config_curve_BLS381.h"
#include "randapi.h"

#if CURVE_SECURITY_BLS381 == 128
#include "bls_BLS381.h"
#elif CURVE_SECURITY_BLS381 == 192
#include "bls192_BLS381.h"
#elif CURVE_SECURITY_BLS381 == 256
#include "bls256_BLS381.h"
#endif

to

#include <amcl/config_curve_BLS381.h>
#include <amcl/randapi.h>

#if CURVE_SECURITY_BLS381 == 128
#include <amcl/bls_BLS381.h>
#elif CURVE_SECURITY_BLS381 == 192
#include <amcl/bls192_BLS381.h>
#elif CURVE_SECURITY_BLS381 == 256
#include <amcl/bls256_BLS381.h>
#endif

Then compile it" gcc -O0 -g ./example_bls_BLS381.c $(pkg-config --libs --cflags amcl) -o example_bls_BLS381 Try it:

$> ./example_bls_BLS381 
./example_bls_BLS381: error while loading shared libraries: libamcl_core.so.1: cannot open shared object file: No such file or directory

Find where is libamcl_core.so.

 $> sudo find / -name libamcl_core.so
/usr/local/lib/libamcl_core.so

exporting library export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/ Try again:

./example_bls_BLS381 
SEED: 78d0fb6705ce77dee47d03eb5b9c5d30

Testing BLS signature for curve BLS381
Private key SK1: 000000000000000000000000000000001ab4d90898292c30524488630453308cd2fa1f9d76c15f98b1025138f81bf1da
Public key PKTMP: 0f0bcdc9de4968355e30302ef97e8ec0dd344f87aeb35f6c556dc810a0a506a7aa5e8a4ae3063ad7de241511445e708006796e2ba3b366fda588937fa5cead3a9b6e0e6c29eb328339cd1afb3e0c838f39d2a5f438122c35529658cccd789c700f33fd318079ec077f7c17b89d5c94feffff1d3fab02cde565854a93458dce002241281a7e2d9f58d8a88952fc7fe0260991bc6c2971004a78c9724a18f5fa4c4995b2a2697b9cb0d0adddfae6f500b0732173f092971cbaaaba13c8ffb4ec09
Public key PK1: 0f0bcdc9de4968355e30302ef97e8ec0dd344f87aeb35f6c556dc810a0a506a7aa5e8a4ae3063ad7de241511445e708006796e2ba3b366fda588937fa5cead3a9b6e0e6c29eb328339cd1afb3e0c838f39d2a5f438122c35529658cccd789c700f33fd318079ec077f7c17b89d5c94feffff1d3fab02cde565854a93458dce002241281a7e2d9f58d8a88952fc7fe0260991bc6c2971004a78c9724a18f5fa4c4995b2a2697b9cb0d0adddfae6f500b0732173f092971cbaaaba13c8ffb4ec09
Private key SK2: 000000000000000000000000000000002c78985d1620cf5f585fb95fa12643f35874f8ac3e27b1a72793244734eadb2b
Public key PK2: 00e083bfbf91ccb04e332758ae84aecd23948b349a36d271e9444c04d2cd9263e4cd2b7df79187a71f2d2a2059524938169b09f3ce0e8be623ede589bb5b8d999d023222a20827089897217667b11d8d659bb42b1b55127659b5d2dda50af5eb0e7b36d785d1db7ffcfbbee023c6330ad39440bf8ed287657ea7a3b4b30445de1eb512f8764d3ce7b2a1aa6505e267d81155e430e7248c20ee62d7dc7836d1835f9c0cbf0d551f469ff2e2a7ffcaab46be00162e30e09a382f02396828bbabf9
Private key SK3: 000000000000000000000000000000002c78985d1620cf5f585fb95fa12643f35874f8ac3e27b1a72793244734eadb2b
Public key PK3: 00e083bfbf91ccb04e332758ae84aecd23948b349a36d271e9444c04d2cd9263e4cd2b7df79187a71f2d2a2059524938169b09f3ce0e8be623ede589bb5b8d999d023222a20827089897217667b11d8d659bb42b1b55127659b5d2dda50af5eb0e7b36d785d1db7ffcfbbee023c6330ad39440bf8ed287657ea7a3b4b30445de1eb512f8764d3ce7b2a1aa6505e267d81155e430e7248c20ee62d7dc7836d1835f9c0cbf0d551f469ff2e2a7ffcaab46be00162e30e09a382f02396828bbabf9

SIG1: 0308be9a543a978c9a5b143fc8aed6482bdbe5f9dd969693b65c9b2bfdea25e1a611bcbf96f8899bfea06ef71c30bf70ad
SIG2: 0216d5cbfd2e29445a42bfa7075a28fdf139d4d9c48f31c7233c8b9822929148bdf0fadf315f082c2377ed08cf5dd57f5b
SIG3: 02082ab439b2c6d366199ae44fcdf72f15529a3af88f413a471196a69aaf65ccddf9ace8a9975426c6080148ca2d30ac9b

Success: Signature is valid
Success: Signature is valid
Success: Signature is valid
Public key PK: 08c2ead7baac23a8b648d6572fd2b3cfe06a0a3d31dafdde14f901fdc582be72647fcc088d33b923ddcc63eba62723e81403ce9283381ab0b56d398da01b7886064eb5679d164cd1fb2efcac21f56d19247d40b7a52a4e6463c792bfb41909f40b1024ffdf0a7fdfc4f92c437f00dde3ac8bbff6c6bbe65a8393aa488d6b5af7f7919acee8262eb240915619b95a65f4017785c554211282bd3d2478fcb236d4fa7c459a6a7b2067785d1a50ae00c9ea5a4921d80a41b8b26b7ce6f34d3a8b2a

Error: Aggregated signature is invalid (expected result) 
SIG: 030b5620207d709e2991413830ba052fc15199731442f8b868217de7cceaa5406c27261c76eb942b426d0c031e8a349836

Success: Aggregated signature is valid
message Zest message
Error: Invalid Signature (expected result) 
message test message
Signature SIG1: 0508be9a543a978c9a5b143fc8aed6482bdbe5f9dd969693b65c9b2bfdea25e1a611bcbf96f8899bfea06ef71c30bf70ad
Error: Invalid Signature  (expected result) 

It works as expected!

Now we can finally work on the part I'm looking at, the linking between C and python.

Creating a shared library instead of an executable" gcc -O0 -g ./example_bls_BLS381.c $(pkg-config --libs --cflags amcl) --shared -o example_bls_BLS381.so Creating the python file example_bls_BLS381.py:

import cffi

ffi = cffi.FFI()
ffi.cdef("""
   int main();
""")

lib = ffi.dlopen("/tmp/example_bls_BLS381.so")
lib.main()

Testing:

python example_bls_BLS381.py 
SEED: 78d0fb6705ce77dee47d03eb5b9c5d30

Testing BLS signature for curve BLS381
Private key SK1: 000000000000000000000000000000001ab4d90898292c30524488630453308cd2fa1f9d76c15f98b1025138f81bf1da
Public key PKTMP: 0f0bcdc9de4968355e30302ef97e8ec0dd344f87aeb35f6c556dc810a0a506a7aa5e8a4ae3063ad7de241511445e708006796e2ba3b366fda588937fa5cead3a9b6e0e6c29eb328339cd1afb3e0c838f39d2a5f438122c35529658cccd789c700f33fd318079ec077f7c17b89d5c94feffff1d3fab02cde565854a93458dce002241281a7e2d9f58d8a88952fc7fe0260991bc6c2971004a78c9724a18f5fa4c4995b2a2697b9cb0d0adddfae6f500b0732173f092971cbaaaba13c8ffb4ec09
Public key PK1: 0f0bcdc9de4968355e30302ef97e8ec0dd344f87aeb35f6c556dc810a0a506a7aa5e8a4ae3063ad7de241511445e708006796e2ba3b366fda588937fa5cead3a9b6e0e6c29eb328339cd1afb3e0c838f39d2a5f438122c35529658cccd789c700f33fd318079ec077f7c17b89d5c94feffff1d3fab02cde565854a93458dce002241281a7e2d9f58d8a88952fc7fe0260991bc6c2971004a78c9724a18f5fa4c4995b2a2697b9cb0d0adddfae6f500b0732173f092971cbaaaba13c8ffb4ec09
Private key SK2: 000000000000000000000000000000002c78985d1620cf5f585fb95fa12643f35874f8ac3e27b1a72793244734eadb2b
Public key PK2: 00e083bfbf91ccb04e332758ae84aecd23948b349a36d271e9444c04d2cd9263e4cd2b7df79187a71f2d2a2059524938169b09f3ce0e8be623ede589bb5b8d999d023222a20827089897217667b11d8d659bb42b1b55127659b5d2dda50af5eb0e7b36d785d1db7ffcfbbee023c6330ad39440bf8ed287657ea7a3b4b30445de1eb512f8764d3ce7b2a1aa6505e267d81155e430e7248c20ee62d7dc7836d1835f9c0cbf0d551f469ff2e2a7ffcaab46be00162e30e09a382f02396828bbabf9
Private key SK3: 000000000000000000000000000000002c78985d1620cf5f585fb95fa12643f35874f8ac3e27b1a72793244734eadb2b
Public key PK3: 00e083bfbf91ccb04e332758ae84aecd23948b349a36d271e9444c04d2cd9263e4cd2b7df79187a71f2d2a2059524938169b09f3ce0e8be623ede589bb5b8d999d023222a20827089897217667b11d8d659bb42b1b55127659b5d2dda50af5eb0e7b36d785d1db7ffcfbbee023c6330ad39440bf8ed287657ea7a3b4b30445de1eb512f8764d3ce7b2a1aa6505e267d81155e430e7248c20ee62d7dc7836d1835f9c0cbf0d551f469ff2e2a7ffcaab46be00162e30e09a382f02396828bbabf9

SIG1: 0308be9a543a978c9a5b143fc8aed6482bdbe5f9dd969693b65c9b2bfdea25e1a611bcbf96f8899bfea06ef71c30bf70ad
SIG2: 0216d5cbfd2e29445a42bfa7075a28fdf139d4d9c48f31c7233c8b9822929148bdf0fadf315f082c2377ed08cf5dd57f5b
SIG3: 02082ab439b2c6d366199ae44fcdf72f15529a3af88f413a471196a69aaf65ccddf9ace8a9975426c6080148ca2d30ac9b

Success: Signature is valid
Success: Signature is valid
Success: Signature is valid
Public key PK: 08c2ead7baac23a8b648d6572fd2b3cfe06a0a3d31dafdde14f901fdc582be72647fcc088d33b923ddcc63eba62723e81403ce9283381ab0b56d398da01b7886064eb5679d164cd1fb2efcac21f56d19247d40b7a52a4e6463c792bfb41909f40b1024ffdf0a7fdfc4f92c437f00dde3ac8bbff6c6bbe65a8393aa488d6b5af7f7919acee8262eb240915619b95a65f4017785c554211282bd3d2478fcb236d4fa7c459a6a7b2067785d1a50ae00c9ea5a4921d80a41b8b26b7ce6f34d3a8b2a

Error: Aggregated signature is invalid (expected result) 
SIG: 030b5620207d709e2991413830ba052fc15199731442f8b868217de7cceaa5406c27261c76eb942b426d0c031e8a349836

Success: Aggregated signature is valid
message Zest message
Error: Invalid Signature (expected result) 
message test message
Signature SIG1: 0508be9a543a978c9a5b143fc8aed6482bdbe5f9dd969693b65c9b2bfdea25e1a611bcbf96f8899bfea06ef71c30bf70ad
Error: Invalid Signature  (expected result)

It works as expected. I now need to tweak this example for being able to play with CURVE_Order_FP256BN I'm close :) Thanks again for these pieces of informations.

kealan commented 5 years ago

You are welcome. You have the idea now - just build the library for the curve you are interested in.

giorgiozoppi commented 1 year ago

@GuillaumeCisco can we close this?