python/bls_ZZZ.py.in (345 lines of code) (raw):

#!/usr/bin/env python3 """ Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ """ bls This module use cffi to access the c functions in the BLS library. There is also an example usage program in this file. """ import cffi import platform import os ffi = cffi.FFI() ffi.cdef(""" typedef struct { unsigned int ira[21]; /* random number... */ int rndptr; /* ...array & pointer */ unsigned int borrow; int pool_ptr; char pool[32]; /* random pool */ } csprng; typedef struct { int len; int max; char *val; } octet; extern void CREATE_CSPRNG(csprng *R,octet *S); extern void KILL_CSPRNG(csprng *R); extern void OCT_clear(octet *O); extern int BLS_ZZZ_KEY_PAIR_GENERATE(csprng *RNG,octet* S,octet *W); extern int BLS_ZZZ_SIGN(octet *SIG,octet *m,octet *S); extern int BLS_ZZZ_VERIFY(octet *SIG,octet *m,octet *W); extern int BLS_ZZZ_ADD_G1(octet *R1,octet *R2,octet *R); extern int BLS_ZZZ_ADD_G2(octet *W1,octet *W2,octet *W); """) if (platform.system() == 'Windows'): libamcl_bls_ZZZ = ffi.dlopen("libamcl_bls_ZZZ.dll") libamcl_core = ffi.dlopen("libamcl_core.dll") elif (platform.system() == 'Darwin'): libamcl_bls_ZZZ = ffi.dlopen("libamcl_bls_ZZZ.dylib") libamcl_core = ffi.dlopen("libamcl_core.dylib") else: libamcl_bls_ZZZ = ffi.dlopen("libamcl_bls_ZZZ.so") libamcl_core = ffi.dlopen("libamcl_core.so") # Group Size BGS = @NB@ # Field Size BFS = @NB@ CURVE_SECURITY = @CS@ G1LEN = BFS + 1 if CURVE_SECURITY == 128: G2LEN = 4 * BFS if CURVE_SECURITY == 192: G2LEN = 8 * BFS if CURVE_SECURITY == 256: G2LEN = 16 * BFS def to_str(octet_value): """Converts an octet type into a string Add all the values in an octet into an array. Args:: octet_value. An octet pointer type Returns:: String Raises: Exception """ i = 0 val = [] while i < octet_value.len: val.append(octet_value.val[i]) i = i + 1 out = b'' for x in val: out = out + x return out def make_octet(length, value=None): """Generates an octet pointer Generates an empty octet or one filled with the input value Args:: length: Length of empty octet value: Data to assign to octet Returns:: oct_ptr: octet pointer val: data associated with octet to prevent garbage collection Raises: """ oct_ptr = ffi.new("octet*") if value: val = ffi.new("char [%s]" % len(value), value) oct_ptr.val = val oct_ptr.max = len(value) oct_ptr.len = len(value) else: val = ffi.new("char []", length) oct_ptr.val = val oct_ptr.max = length oct_ptr.len = length return oct_ptr, val def create_csprng(seed): """Make a Cryptographically secure pseudo-random number generator instance Make a Cryptographically secure pseudo-random number generator instance Args:: seed: random seed value Returns:: rng: Pointer to cryptographically secure pseudo-random number generator instance Raises: """ seed_oct, seed_val = make_octet(None, seed) # random number generator rng = ffi.new('csprng*') libamcl_core.CREATE_CSPRNG(rng, seed_oct) libamcl_core.OCT_clear(seed_oct) return rng def kill_csprng(rng): """Kill a random number generator Deletes all internal state Args:: rng: Pointer to cryptographically secure pseudo-random number generator instance Returns:: Raises: """ libamcl_core.KILL_CSPRNG(rng) return 0 def key_pair_generate(rng, sk=None): """Generate key pair Generate key pair Args:: rng: Pointer to cryptographically secure pseudo-random number generator instance sk: secret key. Externally generated Returns:: error_code: error from the C function sk: secret key pk: public key Raises: """ if sk: sk1, sk1_val = make_octet(None, sk) rng = ffi.NULL else: sk1, sk1val = make_octet(BGS) pk1, pk1val = make_octet(G2LEN) error_code = libamcl_bls_ZZZ.BLS_ZZZ_KEY_PAIR_GENERATE(rng, sk1, pk1) sk = to_str(sk1) pk = to_str(pk1) # clear memory libamcl_core.OCT_clear(sk1) libamcl_core.OCT_clear(pk1) return error_code, sk, pk def sign(message, sk): """Calculate a signature Generate key pair Args:: message: Message to sign sk: BLS secret key Returns:: error_code: Zero for success or else an error code signature: BLS signature Raises: """ m, m_val = make_octet(None, message) sk1, sk1_val = make_octet(None, sk) signature1, signature1_val = make_octet(G1LEN) error_code = libamcl_bls_ZZZ.BLS_ZZZ_SIGN(signature1, m, sk1) signature = to_str(signature1) # clear memory libamcl_core.OCT_clear(sk1) libamcl_core.OCT_clear(signature1) return error_code, signature def verify(signature, message, pk): """Verify a signature Verify a signature Args:: message: Message to verify signature: BLS signature pk: BLS public key Returns:: error_code: Zero for success or else an error code Raises: """ m, m_val = make_octet(None, message) pk1, pk1_val = make_octet(None, pk) signature1, signature1_val = make_octet(None, signature) error_code = libamcl_bls_ZZZ.BLS_ZZZ_VERIFY(signature1, m, pk1) # clear memory libamcl_core.OCT_clear(pk1) libamcl_core.OCT_clear(signature1) return error_code def add_G1(R1, R2): """Add two members from the group G1 Add two members from the group G1 Args:: R1: member of G1 R2: member of G1 Returns:: R: member of G1. R = R1+R2 error_code: Zero for success or else an error code Raises: """ R11, R11_val = make_octet(None, R1) R21, R21_val = make_octet(None, R2) R1, R1_val = make_octet(G1LEN) error_code = libamcl_bls_ZZZ.BLS_ZZZ_ADD_G1(R11, R21, R1) R = to_str(R1) # clear memory libamcl_core.OCT_clear(R11) libamcl_core.OCT_clear(R21) libamcl_core.OCT_clear(R1) return error_code, R def add_G2(R1, R2): """Add two members from the group G2 Add two members from the group G2 Args:: R1: member of G2 R2: member of G2 Returns:: R: member of G2. R = R1+R2 error_code: Zero for success or else an error code Raises: """ R11, R11_val = make_octet(None, R1) R21, R21_val = make_octet(None, R2) R1, R1_val = make_octet(G2LEN) error_code = libamcl_bls_ZZZ.BLS_ZZZ_ADD_G2(R11, R21, R1) R = to_str(R1) # clear memory libamcl_core.OCT_clear(R11) libamcl_core.OCT_clear(R21) libamcl_core.OCT_clear(R1) return error_code, R if __name__ == "__main__": # Print hex values DEBUG = False # Seed seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30" seed = bytes.fromhex(seed_hex) # Message message = b"test message" # random number generator rng = create_csprng(seed) # Generate key pairs rtn, sk1, pktmp = key_pair_generate(rng) if rtn != 0: print("Error: key_pair_generate {}".format(rtn)) raise SystemExit(0) print("sk1: {}".format(sk1.hex())) print("pktmp: {}".format(pktmp.hex())) rtn, sk1, pk1 = key_pair_generate(rng, sk1) if rtn != 0: print("Error: key_pair_generate {}".format(rtn)) raise SystemExit(0) print("sk1: {}".format(sk1.hex())) print("pk1: {}".format(pk1.hex())) rtn, sk2, pk2 = key_pair_generate(rng) if rtn != 0: print("Error: key_pair_generate {}".format(rtn)) raise SystemExit(0) print("sk2: {}".format(sk2.hex())) print("pk2: {}".format(pk2.hex())) rtn, sk3, pk3 = key_pair_generate(rng) if rtn != 0: print("Error: key_pair_generate {}".format(rtn)) raise SystemExit(0) print("sk3: {}".format(sk3.hex())) print("pk3: {}".format(pk3.hex())) # Sign and verify rtn, sig1 = sign(message, sk1) if rtn != 0: print("Error: sign {}".format(rtn)) raise SystemExit(0) print("sig1: {}".format(sig1.hex())) rtn = verify(sig1, message, pk1) if rtn != 0: print("Error: Invalid signature {}".format(rtn)) raise SystemExit(0) print("Success: Signature is valid") rtn, sig2 = sign(message, sk2) if rtn != 0: print("Error: sign {}".format(rtn)) raise SystemExit(0) print("sig2: {}".format(sig2.hex())) rtn = verify(sig2, message, pk2) if rtn != 0: print("Error: Invalid signature {}".format(rtn)) raise SystemExit(0) print("Success: Signature is valid") rtn, sig3 = sign(message, sk3) if rtn != 0: print("Error: sign {}".format(rtn)) raise SystemExit(0) print("sig3: {}".format(sig3.hex())) rtn = verify(sig3, message, pk3) if rtn != 0: print("Error: Invalid signature {}".format(rtn)) raise SystemExit(0) print("Success: Signature is valid") # Add Signatures rtn, sig12 = add_G1(sig1, sig2) if rtn != 0: print("Error: add_G1 {}".format(rtn)) raise SystemExit(0) print("sig12: {}".format(sig12.hex())) rtn, sig123 = add_G1(sig12, sig3) if rtn != 0: print("Error: add_G1 {}".format(rtn)) raise SystemExit(0) print("sig123: {}".format(sig123.hex())) # Add Public keys rtn, pk12 = add_G2(pk1, pk2) if rtn != 0: print("Error: add_G2 {}".format(rtn)) raise SystemExit(0) print("pk12: {}".format(pk12.hex())) rtn, pk123 = add_G2(pk12, pk3) if rtn != 0: print("Error: add_G2 {}".format(rtn)) raise SystemExit(0) print("pk123: {}".format(pk123.hex())) # Verify aggretated values rtn = verify(sig123, message, pk123) if rtn != 0: print("Error: Invalid aggregated signature {}".format(rtn)) raise SystemExit(0) print("Success: Aggregated signature is valid") # Clear memory kill_csprng(rng) del sk1 del pk1 del sk2 del pk2 del sk3 del pk3