Exemple #1
0
    def generate_ca(valid_attributes):
        """Initializes the credential system. Runs exactly once in the
        beginning. Decides on schemes public parameters and choses a secret key
        for the server.

        Args:
            valid_attributes (string): a list of all valid attributes. Users cannot
            get a credential with a attribute which is not included here.

            Note: You can use JSON to encode valid_attributes in the string.

        Returns:
            (tuple): tuple containing:
                byte[] : server's pubic information
                byte[] : server's secret key
            You are free to design this as you see fit, but all commuincations
            needs to be encoded as byte arrays.
        """

        # Code to generate the secret key
        private_key_array = []
        public_key_array = []
        ys_in_G1 = []
        g = G2.generator()
        for i in range(L + 1):
            c = G1.order().random()
            private_key_array.append(c)
            public_key_array.append(g**c)
            ys_in_G1.append(G1.generator()**c)
        x = private_key_array[0]
        X = public_key_array[0]
        X_G1 = G1.generator()**x
        y_s = private_key_array[1:]
        Y_s = public_key_array[1:]
        ys_in_G1 = ys_in_G1[1:]

        # Some sanity checks on the key
        for i in range(len(y_s)):
            if not (G1.generator().pair(Y_s[i]) == ys_in_G1[i].pair(
                    G2.generator())):
                raise Exception("Key generation failed !")

        public_information = {
            "Ys": Y_s,
            "X_G1": X_G1,
            "X": X,
            "Ys_G1": ys_in_G1,
            "validAttributes": valid_attributes.split(",")
        }
        pk = jsonpickle.encode(public_information).encode()
        private_key = {
            "Ys": Y_s,
            "X_G1": X_G1,
            "X": X,
            "Ys_G1": ys_in_G1,
            "validAttributes": valid_attributes.split(","),
            "x": x,
            "ys": y_s
        }
        return pk, jsonpickle.encode(private_key).encode()
 def sign(cls, sk, messages):
     m = Bn.from_binary(hashlib.sha256(messages).digest())
     h = G1.generator() ** G1.order().random()   
     while h == G1.neutral_element():
         h = G1.generator() ** G1.order().random()
     sig = [h, h ** (sk[0] + sk[1] * m)]
     return sig
    def create_issue_request(server_pk, attributes):
        """Gets all known attributes (subscription) of a user and creates an issuance request.
        You are allowed to add extra attributes to the issuance.

        You should design the issue_request as you see fit.
        """
        attributes = [Bn.from_binary(hashlib.sha256(attr.encode()).digest()) for attr in attributes]
        gen_g1 = server_pk[0]
        t = G1.order().random()

        #Gen C
        C = gen_g1 ** t
        for e in zip(server_pk[1:], attributes):
            C = C * e[0] ** e[1]
        
        #Gen commitment
        comm_values = [G1.order().random() for _ in range(len(attributes) + 1)]
        comm = gen_g1 ** comm_values[0]
        for e in zip(server_pk[1:], comm_values[1:]):
            comm  = comm * e[0] ** e[1]
        
        #Gen challenge
        challenge = hashlib.sha256(jsonpickle.encode(C).encode())
        challenge.update(jsonpickle.encode(comm).encode())
        challenge.update(jsonpickle.encode(server_pk).encode())
        challenge = Bn.from_binary(challenge.digest())

        #Generate response
        response = [e[0].mod_sub(challenge * e[1],G1.order()) for e in zip(comm_values, [t] + attributes)]


        return IssuanceRequest(C, comm, challenge, response),t
    def generate_ca(valid_attributes):
        """Initializes the credential system. Runs exactly once in the
        beginning. Decides on schemes public parameters and choses a secret key
        for the server.

        Args:
            valid_attributes (string): a list of all valid attributes. Users cannot
            get a credential with a attribute which is not included here.

            Note: You can use JSON to encode valid_attributes in the string.

        Returns:
            (tuple): tuple containing:
                byte[] : server's pubic information
                byte[] : server's secret key
            You are free to design this as you see fit, but all commuincations
            needs to be encoded as byte arrays.
        """
        attr_list = valid_attributes.split(',')
        nb_attributes = len(attr_list)

        gen_g1 = G1.generator()
        gen_g2 = G2.generator()
        exp = [G1.order().random() for _ in range(nb_attributes + 1)]

        pk = [gen_g1] + [gen_g1**i for i in exp[1:]
                         ] + [gen_g2] + [gen_g2**i for i in exp]
        sk = gen_g1**exp[0]

        sk = [sk, pk, attr_list]
        pk = [pk, attr_list]

        return (jsonpickle.encode(pk).encode(), jsonpickle.encode(sk).encode())
    def sign(self, message, revealed_attr):
        """Signs the message.

        Args:
            message (byte []): message
            revealed_attr (string []): a list of revealed attributes

        Return:
            Signature: signature
        """
        #public_key separation
        nb_attr_public_key = (len(self.server_pk) - 3) // 2
        gen_g1_pk = self.server_pk[0]
        public_key1 = self.server_pk[1:nb_attr_public_key + 1]
        gen_g2_pk = self.server_pk[nb_attr_public_key + 1]
        x_g2_pk = self.server_pk[nb_attr_public_key + 2]
        public_key2 = self.server_pk[nb_attr_public_key + 3:]

        #Gen signature
        r = G1.order().random()
        t = G1.order().random()
        signature = (self.credential[0] ** r, (self.credential[1] * self.credential[0]**t)**r)

        #attributes work
        revealed_attributes_idx = [self.attributes.index(attr) for attr in self.attributes if attr in revealed_attr]
        revealed_attributes_bn = [Bn.from_binary(hashlib.sha256(attr.encode()).digest()) for attr in revealed_attr]
        hidden_attributes_idx = [self.attributes.index(attr) for attr in self.attributes if attr not in revealed_attr]
        hidden_attributes_bn = [Bn.from_binary(hashlib.sha256(attr.encode()).digest()) for attr in self.attributes if attr not in revealed_attr]


        #Gen C (left-hand side)
        C = signature[1].pair(gen_g2_pk) / signature[0].pair(x_g2_pk)
        for i in range(len(revealed_attr)):
            C = C * signature[0].pair(public_key2[revealed_attributes_idx[i]]) ** (-revealed_attributes_bn[i] % G1.order())
        

        #Gen commitment (to prove right-hand side)
        comm_values = [G1.order().random() for _ in range(len(hidden_attributes_idx) + 1)]
        comm = signature[0].pair(gen_g2_pk) ** comm_values[0]
        for e in zip(hidden_attributes_idx, comm_values[1:]):
            comm = comm * signature[0].pair(public_key2[e[0]])**e[1]


        #Gen Challenge
        challenge = hashlib.sha256(jsonpickle.encode(C).encode())
        challenge.update(jsonpickle.encode(comm).encode())
        challenge.update(jsonpickle.encode(self.server_pk).encode())
        challenge.update(message)
        challenge = Bn.from_binary(challenge.digest())

        #Gen Responses
        response = [e[0].mod_sub(challenge * e[1],G1.order()) for e in zip(comm_values, [t] + hidden_attributes_bn)]


        return Signature(signature, comm, challenge, response, revealed_attributes_idx)
Exemple #6
0
    def register(self, server_sk, issuance_request, username, attributes):
        """ Registers a new account on the server.

        Args:
            server_sk (byte []): the server's secret key (serialized)
            issuance_request (bytes[]): The issuance request (serialized)
            username (string): username
            attributes (string): attributes

            Note: You can use JSON to encode attributes in the string.

        Return:
            response (bytes[]): the client should be able to build a credential
            with this response.
        """

        #Reconstructing the secret key
        sk = jsonpickle.decode(server_sk)
        #Decoding the request
        decoded_request = jsonpickle.decode(issuance_request)
        C = decoded_request["C"]

        #Verifying the value for C
        s_sk = decoded_request["s_sk"]
        s_t = decoded_request["s_t"]
        R = decoded_request["R"]
        c = int.from_bytes(
            sha256((username + attributes).encode()).digest(),
            "big") % G1.order()  # hashing

        if (sk["Ys_G1"][0]**s_sk) * (G1.generator()**s_t) * C**c != R:
            raise Exception("Invalid register !")

        #Generating a random u
        u = G1.order().random()
        g_pow_u = G1.generator()**u
        X = sk[
            "X_G1"]  #Note : I decided to have X in the secret key, rather than recompute it everytime

        #Building the Ys
        Ys = sk["Ys_G1"]

        sigma_2 = X * C
        #The subscription attributes
        for att in attributes.split(","):
            if att not in sk["validAttributes"]:
                raise ValueError("Non-recognized attribute")
            else:
                index_of_att = sk["validAttributes"].index(att)
                y_i = Ys[index_of_att + 1]  #+1 because of the hidden attribute
                sigma_2 = sigma_2 * y_i
        json_res = {"sigma1": g_pow_u, "sigma2": sigma_2**u}
        return jsonpickle.encode(json_res).encode()
Exemple #7
0
    def check_request_signature(self, server_pk, message, revealed_attributes,
                                signature):
        """

        Args:
            server_pk (byte[]): the server's public key (serialized)
            message (byte[]): The message to sign
            revealed_attributes (string): revealed attributes
            signature (bytes[]): user's autorization (serialized)

            Note: You can use JSON to encode revealed_attributes in the string.

        Returns:
            valid (boolean): is signature valid
        """
        sig = jsonpickle.decode(signature)
        att = revealed_attributes.split(",")
        pk = jsonpickle.decode(server_pk)
        valid_attributes = pk["validAttributes"]

        R = sig["R"]
        c = sig["c"]
        s_is = sig["s_is"]
        sigma1 = sig["sigma"][0]
        sigma2 = sig["sigma"][1]
        if sigma1 == G1.generator()**G1.order():  #Checking that sigma1 != 1
            return False

        # Verifying the hash was legit
        c_us = int.from_bytes(sha256(message).digest(), "big") % G1.order()
        if (c_us != c):
            return False

        # Need to recreate the value the proof of knowledge is showing
        acc = sigma2.pair(G2.generator()) / sigma1.pair(pk["X"])
        for i in range(len(att)):
            acc = acc / (sigma1).pair(
                pk["Ys"][valid_attributes.index(att[i]) + 1])

        values_to_prove = [
        ]  # Storing the values used in the proof of knowledge
        values_to_prove.append((sigma1).pair(G2.generator()))
        values_to_prove.append(sigma1.pair(pk["Ys"][0]))
        for att in valid_attributes:
            if att not in revealed_attributes.split(","):
                values_to_prove.append(
                    sigma1.pair(pk["Ys"][valid_attributes.index(att) + 1]))
        thing_to_add_to_r = acc**c_us
        for v, exp in zip(values_to_prove, s_is):
            thing_to_add_to_r = thing_to_add_to_r * (v**exp)
        return R == thing_to_add_to_r
Exemple #8
0
def test_random_sigma():
    """
        This test aims at verifying that if the sigmas aren't conform they will be refused
    """
    server = Server()
    client = Client()

    #Generating the keys
    pk_serialized, sk_serialized = server.generate_ca("a,b,c")
    
    #Registering the user on the server

    m = b"some message for test"
    c = int.from_bytes(sha256(m).digest(), "big") % G1.order()

    credential = jsonpickle.encode({"R":3, "c":c, "sigma": (G1.generator() ** G1.order().random(), G1.generator() ** G1.order().random()), "random_sk": 1})
    #Trying to sign a message
    sig = client.sign_request(pk_serialized, credential, m,"a,b")
    
    #Verifying the signature
    assert server.check_request_signature(pk_serialized, m, "a,b", sig) == False
Exemple #9
0
def test_pair_type():
    g1 = G1.generator()
    g2 = G2.generator()
    a = g1**3
    b = g2**5
    c = a.pair(b)

    assert isinstance(c, GTElement)

    d = g1**7
    with pytest.raises(Exception):
        a.pair(c)

    with pytest.raises(Exception):
        a.pair(d)

    with pytest.raises(Exception):
        a.pair(11)
    def issue(sk, request, username, attributes):
        """Issues a credential for a new user. 

        This function should receive a issuance request from the user
        (AnonCredential.create_issue_request), and a list of known attributes of the
        user (e.g. the server received bank notes for subscriptions x, y, and z).

        You should design the issue_request as you see fit.
        """
        #extract public and secret key
        secret_key = sk[0]
        public_key = sk[1]

        #Derive challenge
        challenge = hashlib.sha256(jsonpickle.encode(request.C).encode())
        challenge.update(jsonpickle.encode(request.commitment).encode())
        challenge.update(jsonpickle.encode(public_key).encode())
        challenge = Bn.from_binary(challenge.digest())

        #Compare the derived challenge to the received challenge
        challenge_valid = challenge == request.challenge

        #Compute the zkp
        candidate = request.C ** challenge
        for e in zip(public_key, request.response):
            candidate = candidate * e[0] ** e[1]
        

        proof_valid = request.commitment == candidate

        #If the proof and the derived challenge is valid, sig the credential
        if proof_valid and challenge_valid:
            u = G1.order().random()
            sig = (public_key[0] ** u,(secret_key * request.C) ** u)
            return sig
        else :
            raise ValueError
 def verify(cls, pk, messages, signature):
     m = Bn.from_binary(hashlib.sha256(messages).digest())
     is_gen = signature[0] == G1.neutral_element()
     is_valid = signature[0].pair(pk[1] * pk[2] ** m) == signature[1].pair(pk[0])
     return is_valid and not is_gen
 def generate_key(cls):
     gen = G2.generator()
     sk = [G1.order().random(),G1.order().random()]
     pk = [gen] + [gen ** i for i in sk]
     return sk, pk
    def verify(self, issuer_public_info, public_attrs, message):
        """Verifies a signature.

        Args:
            issuer_public_info (): output of issuer's 'get_serialized_public_key' method
            public_attrs (dict): public attributes
            message (byte []): list of messages

        returns:
            valid (boolean): is signature valid
        """
        #public_key separation
        nb_attr_public_key = (len(issuer_public_info) - 3) // 2
        gen_g1_pk = issuer_public_info[0]
        public_key1 = issuer_public_info[1:nb_attr_public_key + 1]
        gen_g2_pk = issuer_public_info[nb_attr_public_key + 1]
        x_g2_pk = issuer_public_info[nb_attr_public_key + 2]
        public_key2 = issuer_public_info[nb_attr_public_key + 3:]

        #attributes work
        nb_attr = len(self.response) - 1 + len(public_attrs)
        public_attributes_idx = self.attributes_idx
        public_attributes_bn = [Bn.from_binary(hashlib.sha256(attr.encode()).digest()) for attr in public_attrs]
        hidden_attributes_idx = [i for i in range(nb_attr) if i not in public_attributes_idx]


        #Gen C (left-hand side)
        C = self.signature[1].pair(gen_g2_pk) / self.signature[0].pair(x_g2_pk)
        for i in range(len(public_attrs)):
            C = C * self.signature[0].pair(public_key2[public_attributes_idx[i]]) ** (-public_attributes_bn[i] % G1.order())

        #Gen Challenge
        challenge = hashlib.sha256(jsonpickle.encode(C).encode())
        challenge.update(jsonpickle.encode(self.commitment).encode())
        challenge.update(jsonpickle.encode(issuer_public_info).encode())
        challenge.update(message)
        challenge = Bn.from_binary(challenge.digest())

        #check challenge
        challenge_valid = challenge == self.challenge

        #Compute zkp
        candidate = C ** challenge * self.signature[0].pair(gen_g2_pk) ** self.response[0]
        for e in zip(hidden_attributes_idx, self.response[1:]):
            candidate = candidate * self.signature[0].pair(public_key2[e[0]]) ** e[1]

        proof_valid = candidate == self.commitment


        return challenge_valid and proof_valid 
Exemple #14
0
    def sign_request(self, server_pk, credential, message, revealed_info):
        """Signs the request with the clients credential.

        Arg:
            server_pk (byte[]): a server's public key (serialized)
            credential (byte[]): client's credential (serialized)
            message (byte[]): message to sign
            revealed_info (string): attributes which need to be authorized

            Note: You can use JSON to encode revealed_info.

        Returns:
            byte []: message's signature (serialized)
        """
        # Generating r,t
        r = G1.order().random()
        t = G1.order().random()

        #Decoding the public key
        pk = jsonpickle.decode(server_pk)
        valid_attributes = pk["validAttributes"]

        decoded_credential = jsonpickle.decode(credential)
        sigma = decoded_credential["sigma"]
        random_sk = decoded_credential["random_sk"]

        sigma_bis = (sigma[0]**r, ((sigma[0]**t) * sigma[1])**r)

        values_to_prove = [
        ]  # Storing the values used in the proof of knowledge

        com = (sigma_bis[0]).pair(G2.generator())**t
        values_to_prove.append((sigma_bis[0]).pair(G2.generator()))
        # The secret part of the multiplication
        com = com * sigma_bis[0].pair(pk["Ys"][0]**random_sk)
        values_to_prove.append(sigma_bis[0].pair(pk["Ys"][0]))
        # Attributes
        for att in valid_attributes:
            if att not in revealed_info.split(","):
                #raise ValueError("Attribute not in the possible ones !")
                com = com * sigma_bis[0].pair(
                    pk["Ys"][valid_attributes.index(att) + 1])
                values_to_prove.append(sigma_bis[0].pair(
                    pk["Ys"][valid_attributes.index(att) + 1]))
        c = int.from_bytes(sha256(message).digest(),
                           "big") % G1.order()  # hashing

        #Adding the signature
        r_is = []
        R = GT.generator()**GT.order()  # The neutral element of the group
        for value in values_to_prove:
            r_i = G1.order().random()
            r_is.append(r_i)
            R = R * (value**r_i)  # creating the R part of the protocol

        s_is = []
        for (i, r_i) in zip(range(len(r_is)), r_is):
            tmp = r_i - c % G1.order()
            if i == 0:
                tmp = (r_i - c * t) % G1.order()
            if i == 1:
                tmp = (r_i - c * random_sk) % G1.order()

            if tmp < 0:
                tmp += G1.order()
            s_is.append(tmp)

        proof = {"c": c, "R": R, "s_is": s_is, "sigma": sigma_bis}
        return jsonpickle.encode(proof).encode()
Exemple #15
0
    def prepare_registration(self, server_pk, username, attributes):
        """Prepare a request to register a new account on the server.

        Args:
            server_pk (byte[]): a server's public key (serialized)
            username (string): username
            attributes (string): user's attributes

            Note: You can use JSON to encode attributes in the string.

        Return:
            tuple:
                byte[]: an issuance request
                (private_state): You can use state to store and transfer information
                from prepare_registration to proceed_registration_response.
                You need to design the state yourself.
        """

        t = G1.order().random()
        pk = jsonpickle.decode(server_pk)
        Ys_in_G1 = pk["Ys_G1"]

        random_sk = G1.order().random()  # Some secret key as asked
        C = (G1.generator()**t) * (Ys_in_G1[0]**random_sk)
        for att in attributes.split(","):
            if att not in pk["validAttributes"]:
                raise ValueError(
                    "Attribute not in list of accepted attribute by the server"
                )

        issuance_request = {}
        issuance_request["C"] = C
        r_sk = G1.order().random()
        r_t = G1.order().random()
        c = int.from_bytes(
            sha256((username + attributes).encode()).digest(),
            "big") % G1.order()  # hashing

        s_sk = ((r_sk - random_sk * c) + G1.order()) % G1.order()
        s_t = ((r_t - t * c) + G1.order()) % G1.order()

        R = (Ys_in_G1[0]**r_sk) * (G1.generator()**r_t)
        if (Ys_in_G1[0]**s_sk) * (G1.generator()**s_t) * C**c != R:
            raise Exception("Invalid signature !")

        issuance_request["s_t"] = s_t
        issuance_request["s_sk"] = s_sk
        issuance_request["R"] = R

        return jsonpickle.encode(issuance_request).encode(), (
            random_sk, t
        )  #t is the inner state, we only need to remember that (since the key as secret attribute is completely useless)