aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMITSUNARI Shigeo <herumi@nifty.com>2019-03-19 16:47:47 +0800
committerMITSUNARI Shigeo <herumi@nifty.com>2019-03-21 21:31:25 +0800
commit9dc5b41fbcb4d155659f6937a62e814bba4220b0 (patch)
tree284738d28293c0ccf9b4d6e3b3d1e0dfec2fdd1e
parentace9d509eabe37fdde55d9ae363003c334821f53 (diff)
downloadtangerine-mcl-9dc5b41fbcb4d155659f6937a62e814bba4220b0.tar.gz
tangerine-mcl-9dc5b41fbcb4d155659f6937a62e814bba4220b0.tar.zst
tangerine-mcl-9dc5b41fbcb4d155659f6937a62e814bba4220b0.zip
add binding of she for python
-rw-r--r--Makefile13
-rw-r--r--ffi/python/she.py297
2 files changed, 309 insertions, 1 deletions
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
+