From 9dc5b41fbcb4d155659f6937a62e814bba4220b0 Mon Sep 17 00:00:00 2001 From: MITSUNARI Shigeo Date: Tue, 19 Mar 2019 17:47:47 +0900 Subject: [PATCH] add binding of she for python --- Makefile | 13 +- ffi/python/she.py | 297 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 309 insertions(+), 1 deletion(-) create mode 100644 ffi/python/she.py diff --git a/Makefile b/Makefile index a35e6f2..7df1dd3 100644 --- a/Makefile +++ b/Makefile @@ -45,9 +45,10 @@ BN384_256_SLIB=$(LIB_DIR)/lib$(BN384_256_SNAME).$(LIB_SUF) BN512_LIB=$(LIB_DIR)/libmclbn512.a BN512_SLIB=$(LIB_DIR)/lib$(BN512_SNAME).$(LIB_SUF) SHE256_LIB=$(LIB_DIR)/libmclshe256.a +SHE256_SLIB=$(LIB_DIR)/lib$(SHE256_SNAME).$(LIB_SUF) SHE384_LIB=$(LIB_DIR)/libmclshe384.a ECDSA_LIB=$(LIB_DIR)/libmclecdsa.a -all: $(MCL_LIB) $(MCL_SLIB) $(BN256_LIB) $(BN256_SLIB) $(BN384_LIB) $(BN384_SLIB) $(BN384_256_LIB) $(BN384_256_SLIB) $(BN512_LIB) $(BN512_SLIB) $(SHE256_LIB) $(SHE384_lib) $(ECDSA_LIB) +all: $(MCL_LIB) $(MCL_SLIB) $(BN256_LIB) $(BN256_SLIB) $(BN384_LIB) $(BN384_SLIB) $(BN384_256_LIB) $(BN384_256_SLIB) $(BN512_LIB) $(BN512_SLIB) $(SHE256_LIB) $(SHE256_SLIB) $(SHE384_lib) $(ECDSA_LIB) #LLVM_VER=-3.8 LLVM_LLC=llc$(LLVM_VER) @@ -121,6 +122,7 @@ ifneq ($(findstring $(OS),mac/mingw64),) BN384_SLIB_LDFLAGS+=-l$(MCL_SNAME) -L./lib BN384_256_SLIB_LDFLAGS+=-l$(MCL_SNAME) -L./lib BN512_SLIB_LDFLAGS+=-l$(MCL_SNAME) -L./lib + SHE256_SLIB_LDFLAGS+=-l$(MCL_SNAME) -L./lib endif ifeq ($(OS),mingw64) MCL_SLIB_LDFLAGS+=-Wl,--out-implib,$(LIB_DIR)/lib$(MCL_SNAME).a @@ -128,6 +130,7 @@ ifeq ($(OS),mingw64) BN384_SLIB_LDFLAGS+=-Wl,--out-implib,$(LIB_DIR)/lib$(BN384_SNAME).a BN384_256_SLIB_LDFLAGS+=-Wl,--out-implib,$(LIB_DIR)/lib$(BN384_256_SNAME).a BN512_SLIB_LDFLAGS+=-Wl,--out-implib,$(LIB_DIR)/lib$(BN512_SNAME).a + SHE256_SLIB_LDFLAGS+=-Wl,--out-implib,$(LIB_DIR)/lib$(SHE256_SNAME).a endif $(MCL_LIB): $(LIB_OBJ) @@ -142,6 +145,9 @@ $(BN256_LIB): $(BN256_OBJ) $(SHE256_LIB): $(SHE256_OBJ) $(AR) $@ $(SHE256_OBJ) +$(SHE256_SLIB): $(SHE256_OBJ) $(MCL_LIB) + $(PRE)$(CXX) -o $@ $(SHE256_OBJ) $(MCL_LIB) -shared $(LDFLAGS) $(SHE256_SLIB_LDFLAGS) + $(SHE384_LIB): $(SHE384_OBJ) $(AR) $@ $(SHE384_OBJ) @@ -224,6 +230,11 @@ test_go: $(MAKE) test_go384 $(MAKE) test_go384_256 +test_python_she: $(SHE256_SLIB) + cd ffi/python && env LD_LIBRARY_PATH="../../lib" DYLD_LIBRARY_PATH="../../lib" PATH=$$PATH:"../../lib" python3 she.py +test_python: + $(MAKE) test_python_she + test_java: $(MAKE) -C ffi/java test diff --git a/ffi/python/she.py b/ffi/python/she.py new file mode 100644 index 0000000..e509f65 --- /dev/null +++ b/ffi/python/she.py @@ -0,0 +1,297 @@ +import os +import platform +from ctypes import * + +MCL_BN254 = 0 +MCLBN_FR_UNIT_SIZE = 4 +MCLBN_FP_UNIT_SIZE = 4 + +FR_SIZE = MCLBN_FR_UNIT_SIZE +G1_SIZE = MCLBN_FP_UNIT_SIZE * 3 +G2_SIZE = MCLBN_FP_UNIT_SIZE * 6 +GT_SIZE = MCLBN_FP_UNIT_SIZE * 12 + +SEC_SIZE = FR_SIZE * 2 +PUB_SIZE = G1_SIZE + G2_SIZE +G1_CIPHER_SIZE = G1_SIZE * 2 +G2_CIPHER_SIZE = G2_SIZE * 2 +GT_CIPHER_SIZE = GT_SIZE * 4 + +MCLBN_COMPILED_TIME_VAR = (MCLBN_FR_UNIT_SIZE * 10) + MCLBN_FP_UNIT_SIZE + +Buffer = c_ubyte * 1536 +lib = None + +def init(curveType=MCL_BN254): + global lib + name = platform.system() + if name == 'Linux': + suf = 'so' + elif name == 'Darwin': + suf = 'dylib' + else: + raise RuntimeError("not support yet", name) + libname = "libmclshe256." + suf + lib = cdll.LoadLibrary(libname) + ret = lib.sheInit(MCL_BN254, MCLBN_COMPILED_TIME_VAR) + if ret != 0: + raise RuntimeError("sheInit", ret) + # custom setup for a function which returns pointer + lib.shePrecomputedPublicKeyCreate.restype = c_void_p + +def setRangeForDLP(hashSize): + ret = lib.sheSetRangeForDLP(hashSize) + if ret != 0: + raise RuntimeError("setRangeForDLP", ret) + +def setTryNum(tryNum): + ret = lib.sheSetTryNum(tryNum) + if ret != 0: + raise RuntimeError("setTryNum", ret) + +def hexStr(v): + s = "" + for x in v: + s += format(x, '02x') + return s + +class CipherTextG1(Structure): + _fields_ = [("v", c_ulonglong * G1_CIPHER_SIZE)] + def serialize(self): + buf = Buffer() + ret = lib.sheCipherTextG1Serialize(byref(buf), len(buf), byref(self.v)) + if ret == 0: + raise RuntimeError("serialize") + return buf[0:ret] + def serializeToHexStr(self): + return hexStr(self.serialize()) + +class CipherTextG2(Structure): + _fields_ = [("v", c_ulonglong * G2_CIPHER_SIZE)] + def serialize(self): + buf = Buffer() + ret = lib.sheCipherTextG2Serialize(byref(buf), len(buf), byref(self.v)) + if ret == 0: + raise RuntimeError("serialize") + return buf[0:ret] + def serializeToHexStr(self): + return hexStr(self.serialize()) + +class CipherTextGT(Structure): + _fields_ = [("v", c_ulonglong * GT_CIPHER_SIZE)] + def serialize(self): + buf = Buffer() + ret = lib.sheCipherTextGTSerialize(byref(buf), len(buf), byref(self.v)) + if ret == 0: + raise RuntimeError("serialize") + return buf[0:ret] + def serializeToHexStr(self): + return hexStr(self.serialize()) + +class PrecomputedPublicKey(Structure): + def __init__(self): + self.p = 0 + def create(self): + if not self.p: + self.p = c_void_p(lib.shePrecomputedPublicKeyCreate()) + if self.p == 0: + raise RuntimeError("PrecomputedPublicKey::create") + def destroy(self): + lib.shePrecomputedPublicKeyDestroy(self.p) + def encG1(self, m): + c = CipherTextG1() + ret = lib.shePrecomputedPublicKeyEncG1(byref(c.v), self.p, m) + if ret != 0: + raise RuntimeError("encG1", m) + return c + def encG2(self, m): + c = CipherTextG2() + ret = lib.shePrecomputedPublicKeyEncG2(byref(c.v), self.p, m) + if ret != 0: + raise RuntimeError("encG2", m) + return c + def encGT(self, m): + c = CipherTextGT() + ret = lib.shePrecomputedPublicKeyEncGT(byref(c.v), self.p, m) + if ret != 0: + raise RuntimeError("encGT", m) + return c + +class PublicKey(Structure): + _fields_ = [("v", c_ulonglong * PUB_SIZE)] + def serialize(self): + buf = Buffer() + ret = lib.shePublicKeySerialize(byref(buf), len(buf), byref(self.v)) + if ret == 0: + raise RuntimeError("serialize") + return buf[0:ret] + def serializeToHexStr(self): + return hexStr(self.serialize()) + def encG1(self, m): + c = CipherTextG1() + ret = lib.sheEncG1(byref(c.v), byref(self.v), m) + if ret != 0: + raise RuntimeError("encG1", m) + return c + def encG2(self, m): + c = CipherTextG2() + ret = lib.sheEncG2(byref(c.v), byref(self.v), m) + if ret != 0: + raise RuntimeError("encG2", m) + return c + def encGT(self, m): + c = CipherTextGT() + ret = lib.sheEncGT(byref(c.v), byref(self.v), m) + if ret != 0: + raise RuntimeError("encGT", m) + return c + def createPrecomputedPublicKey(self): + ppub = PrecomputedPublicKey() + ppub.create() + ret = lib.shePrecomputedPublicKeyInit(ppub.p, byref(self.v)) + if ret != 0: + raise RuntimeError("createPrecomputedPublicKey") + return ppub + +class SecretKey(Structure): + _fields_ = [("v", c_ulonglong * SEC_SIZE)] + def setByCSPRNG(self): + ret = lib.sheSecretKeySetByCSPRNG(byref(self.v)) + if ret != 0: + raise RuntimeError("setByCSPRNG", ret) + def serialize(self): + buf = Buffer() + ret = lib.sheSecretKeySerialize(byref(buf), len(buf), byref(self.v)) + if ret == 0: + raise RuntimeError("serialize") + return buf[0:ret] + def serializeToHexStr(self): + return hexStr(self.serialize()) + def getPulicKey(self): + pub = PublicKey() + lib.sheGetPublicKey(byref(pub.v), byref(self.v)) + return pub + def dec(self, c): + m = c_longlong() + if isinstance(c, CipherTextG1): + ret = lib.sheDecG1(byref(m), byref(self.v), byref(c.v)) + elif isinstance(c, CipherTextG2): + ret = lib.sheDecG2(byref(m), byref(self.v), byref(c.v)) + elif isinstance(c, CipherTextGT): + ret = lib.sheDecGT(byref(m), byref(self.v), byref(c.v)) + if ret != 0: + raise RuntimeError("dec") + return m.value + +def neg(c): + ret = -1 + if isinstance(c, CipherTextG1): + out = CipherTextG1() + ret = lib.sheNegG1(byref(out.v), byref(c.v)) + elif isinstance(c, CipherTextG2): + out = CipherTextG2() + ret = lib.sheNegG2(byref(out.v), byref(c.v)) + elif isinstance(c, CipherTextGT): + out = CipherTextGT() + ret = lib.sheNegGT(byref(out.v), byref(c.v)) + if ret != 0: + raise RuntimeError("neg") + return out + +def add(cx, cy): + ret = -1 + if isinstance(cx, CipherTextG1) and isinstance(cy, CipherTextG1): + out = CipherTextG1() + ret = lib.sheAddG1(byref(out.v), byref(cx.v), byref(cy.v)) + elif isinstance(cx, CipherTextG2) and isinstance(cy, CipherTextG2): + out = CipherTextG2() + ret = lib.sheAddG2(byref(out.v), byref(cx.v), byref(cy.v)) + elif isinstance(cx, CipherTextGT) and isinstance(cy, CipherTextGT): + out = CipherTextGT() + ret = lib.sheAddGT(byref(out.v), byref(cx.v), byref(cy.v)) + if ret != 0: + raise RuntimeError("add") + return out + +def sub(cx, cy): + ret = -1 + if isinstance(cx, CipherTextG1) and isinstance(cy, CipherTextG1): + out = CipherTextG1() + ret = lib.sheSubG1(byref(out.v), byref(cx.v), byref(cy.v)) + elif isinstance(cx, CipherTextG2) and isinstance(cy, CipherTextG2): + out = CipherTextG2() + ret = lib.sheSubG2(byref(out.v), byref(cx.v), byref(cy.v)) + elif isinstance(cx, CipherTextGT) and isinstance(cy, CipherTextGT): + out = CipherTextGT() + ret = lib.sheSubGT(byref(out.v), byref(cx.v), byref(cy.v)) + if ret != 0: + raise RuntimeError("sub") + return out + +def mul(cx, cy): + ret = -1 + if isinstance(cx, CipherTextG1) and isinstance(cy, CipherTextG2): + out = CipherTextGT() + ret = lib.sheMul(byref(out.v), byref(cx.v), byref(cy.v)) + elif isinstance(cx, CipherTextG1) and isinstance(cy, int): + out = CipherTextG1() + ret = lib.sheMulG1(byref(out.v), byref(cx.v), cy) + elif isinstance(cx, CipherTextG2) and isinstance(cy, int): + out = CipherTextG2() + ret = lib.sheMulG2(byref(out.v), byref(cx.v), cy) + elif isinstance(cx, CipherTextGT) and isinstance(cy, int): + out = CipherTextGT() + ret = lib.sheMulGT(byref(out.v), byref(cx.v), cy) + if ret != 0: + raise RuntimeError("mul") + return out + +if __name__ == '__main__': + init() + sec = SecretKey() + sec.setByCSPRNG() + print("sec=", sec.serializeToHexStr()) + pub = sec.getPulicKey() + print("pub=", pub.serializeToHexStr()) + + m11 = 1 + m12 = 5 + m21 = 3 + m22 = -4 + c11 = pub.encG1(m11) + c12 = pub.encG1(m12) + # dec(enc) for G1 + if sec.dec(c11) != m11: print("err1") + + # add/sub for G1 + if sec.dec(add(c11, c12)) != m11 + m12: print("err2") + if sec.dec(sub(c11, c12)) != m11 - m12: print("err3") + + # add/sub for G2 + c21 = pub.encG2(m21) + c22 = pub.encG2(m22) + if sec.dec(c21) != m21: print("err4") + if sec.dec(add(c21, c22)) != m21 + m22: print("err5") + if sec.dec(sub(c21, c22)) != m21 - m22: print("err6") + + mt = -56 + ct = pub.encGT(mt) + if sec.dec(ct) != mt: print("err7") + + # mul G1 and G2 + if sec.dec(mul(c11, c21)) != m11 * m21: print("err8") + + # use precomputedPublicKey for performance + ppub = pub.createPrecomputedPublicKey() + c1 = ppub.encG1(m11) + if sec.dec(c1) != m11: print("err9") + + import sys + if sys.version_info.major >= 3: + import timeit + N = 100000 + print(str(timeit.timeit("pub.encG1(12)", number=N, globals=globals()) / float(N) * 1e3) + "msec") + print(str(timeit.timeit("ppub.encG1(12)", number=N, globals=globals()) / float(N) * 1e3) + "msec") + + ppub.destroy() # necessary to avoid memory leak +