Primitives API

zksk.primitives.dlrep – Discrete Logarithm Representations

ZK proof for linear representations of discrete logarithms, our basic building block.

An example of such proof is \(PK\{ (x_0, x_1): y = x_0 G_0 + x_1 G_1 \}\), where \(x_0\) and \(x_1\) are secret integers from a finite field, \(G_0\) and \(G_1\) are points on a same elliptic curve, and \(y\) is the actual value of the expression \(x_0 G_0 + x_1 G_1\).

See “Proof Systems for General Statements about Discrete Logarithms” by Camenisch and Stadler, 1997 for the details.

class zksk.primitives.dlrep.DLRep(lhs, expr, simulated=False)

Proof statement for a discrete-logarithm representation proof.

Supports statements of the following form:

\[PK\{ (x_0, x_1, ..., x_n): Y = x_0 G_0 + x_1 G_1 + ... + x_n G_n \}\]

Example usage for \(PK\{x: Y = x G \}\):

>>> from petlib.ec import EcGroup
>>> x = Secret(name="x")
>>> g = EcGroup().generator()
>>> y = 42 * g
>>> stmt = DLRep(y, x * g)
>>> nizk = stmt.prove({x: 42})
>>> stmt.verify(nizk)
True
Parameters
  • expr (zksk.base.Expression) – Proof statement. For example: Secret("x") * g represents \(PK\{ x: Y = x G \}\).

  • lhs – “Left-hand side.” Value of \(Y\).

get_proof_id(secret_id_map=None)

Identifier for the proof statement

Returns

Objects that can be used for hashing.

Return type

list

get_prover(secrets_dict=None)

Get a prover for the current proof statement.

Parameters

secrets_dict – Optional mapping from secrets or secret names to their values.

Returns

Prover object if all secret values are known.

Return type

DLRepProver or None

get_randomizers()

Initialize randomizers for each secret.

Each randomizer is drawn at random from the associated group.

By using a dictionary, we enforce that if secret are repeated in \(x_0 G_0 + x_1 G_1 + ... + x_n G_n\), that is, if \(x_i\) and \(x_j\) have the same name, they will get the same random value. Identical secret values and identical randomizers will yield identical responses, and this identity will be checked by the verifier.

Returns

Mapping from secrets to the random values that are needed to compute the responses

of the proof.

Return type

dict

recompute_commitment(challenge, responses)

Compute a pseudo-commitment.

A pseudo-commitment is the commitment a verifier should have received if the proof was correct. It should be compared to the actual commitment.

Re-occuring secrets yield identical responses.

Parameters
  • challenge – the challenge used in the proof

  • response – a list of responses, ordered as the list of secret names, i.e., with as many elements as there are secrets in the proof claim.

simulate_proof(responses_dict=None, challenge=None)

Returns a transcript of a proof simulation. Responses and challenge can be enforced. The function will misbehave if passed a non-empty but incomplete responses_dict.

Parameters
  • responses_dict – Optinal mapping from secrets or secret names to responses.

  • challenge – Optional challenge to use in the simulation

verifier_cls

alias of DLRepVerifier

class zksk.primitives.dlrep.DLRepProver(stmt, secret_values)

The prover in a discrete logarithm proof.

compute_response(challenge)

Constructs an (ordered) list of response for each secret.

For each secret \(x\) and a random value \(k\) (associated to \(x\)), the response is equal to \(k + c x\), where \(c\) is the challenge value.

Parameters

challenge – Challenge value

Returns

A list of responses

internal_commit(randomizers_dict=None)

Compute the commitment using the randomizers.

Parameters

randomizers_dict – Optional mapping from secrets or secret names to random values. Every random value not given here will be generated at random.

Returns

A single commitment—sum of bases, weighted by the corresponding randomizers

class zksk.primitives.dlrep.DLRepVerifier(stmt)
check_responses_consistency(responses, responses_dict=None)

Check if reoccuring secrets yield the same responses.

To do so, go through the names of the secrets in the current DLRep, and construct a mapping between secrets and responses.

Parameters
  • response – List of responses

  • responses_dict – Mapping from secrets to responses

Returns

True if responses are consistent, False otherwise.

Return type

bool

zksk.primitives.dl_notequal – Inequality of Discrete Logarithms

ZK proof of inequality of two discrete logarithms.

\[PK\{ (x): H_0 = x h_0 \land H_1 \neq x h_1 \}\]

See Protocol 1 in “Thinking Inside the BLAC Box: Smarter Protocols for Faster Anonymous Blacklisting” by Henry and Goldberg, 2013:

class zksk.primitives.dl_notequal.DLNotEqual(valid_pair, invalid_pair, x, bind=False, simulated=False)

ZK proof statement of inequality of two discrete logarithms.

\[PK\{ (x): H_0 = x h_0 \land H_1 \neq x h_1 \}\]

The statement is constructed from two pairs: \((H_0, h_0)\), \((H_1, h_1)\), and a expr.Secret object representing a secret \(x\).

The proof can be made binding: bind the \(x\) to another proof. If the proof is not binding, it is not possible to assert that the same \(x\) was used in any other proof (even in, say, an AND conjunction).

Parameters
  • valid_pair (tuple) – Pair of two Elliptic curve points \((H_0, h_0)\) such that \(H_0 = x h_0\)

  • invalid_pair (tuple) – Pair of two Elliptic curve points \((H_1, h_1)\) such that \(H_1 \neq x h_1\)

  • x (expr.Secret) – Secret.

  • bind (bool) – Whether the proof is binding.

  • simulated (bool) – If this proof is a part of an or-proof: whether it should be simulated.

construct_stmt(precommitment)

Build the internal proof statement.

See the formula in Protocol 1 of the Thinking Inside the BLAC Box: Smarter Protocols for Faster Anonymous Blacklisting paper.

precommit()

Build the left-hand side of the internal proof statement.

simulate_precommit()

Draw a base at random (not unity) from the bases’ group.

validate(precommitment)

Verify the the proof statement is indeed proving the inequality of discret logs.

zksk.primitives.bbsplus – Knowledge of BBS+ Signature

ZK proof of knowledge of a BBS+ signature.

This proof can be used to build blacklistable anonymous credential schemes.

See “Constant-Size Dynamic k-TAA” by Au et al., 2008 for the details.

class zksk.primitives.bbsplus.BBSPlusKeypair(generators, h0, sk, pk)

A public-private key pair, along with a list of canonical bases to use in proofs.

static generate(bilinear_pair, num_generators)

Generate a keypair.

Parameters
  • bilinear_pair (pairings.BilinearGroupPair) – Bilinear group pair.

  • num_generators – Upper bound on the number of generators needed to compute the proof. Should be at least 2 + the number of messages.

Returns

Keypair.

Return type

BBSPlusKeypair

class zksk.primitives.bbsplus.BBSPlusPublicKey(w, h0, generators)

BBS+ public key.

Automatically pre-computes the generator pairings \(e(g_i, h_0)\).

__attrs_post_init__()

Pre-compute the group pairings.

class zksk.primitives.bbsplus.BBSPlusSecretKey(h0, gamma, generators)

BBS+ private key.

sign(lhs)

Sign a committed message (typically a product, blinded or not),

A signature is \((A, e, s_2)\) such that \(A = (g_0 + s_2 g_1 + C_m) \cdot \frac{1}{e+\gamma}\).

If the product was blinded by the user’s \(s_1\) secret value, user has to update the signature.

class zksk.primitives.bbsplus.BBSPlusSignature(A, e, s)

BBS+ signature.

verify_signature(pk, messages)

Verify the validity of the signature w.r.t the given public key and set of messages.

class zksk.primitives.bbsplus.BBSPlusSignatureCreator(pk)

Pre-signed product along with a NIZK proof of correct construction.

Parameters

pk (PublicKey) – Public key.

commit(messages, zkp=True)

Construct the product of messages and optionaly a Pedersen commitment and its proof.

Parameters
  • messages – Messages (attributes) to commit to

  • zkp (bool) – Whether to construct a Pedersen commitment and proof the knowledge of the messages for this commitment.

Returns

user’s packed commitment.

Return type

UserCommitmentMessage

obtain_signature(presignature)

Make a complete signature from the received pre-signature.

Parameters

presignature (BBSPlusSignature) – presignature

Returns

Signature.

Return type

BBSPlusSignature

class zksk.primitives.bbsplus.BBSPlusSignatureStmt(secret_vars, pk, signature=None, binding=True, simulated=False)

Proof of knowledge of a BBS+ signature over a set of (hidden) messages.

The proof can be made binding: bind the secrets to another proof. If the proof is not binding, it is not possible to assert that the same secrets were used in any other proof.

Parameters
  • secret_vars – Secret variables. If binding, the two first elements of secret_vars as the Secret variables for the e and s attributes of the signature.

  • pk (BBSPlusPublicKey) – Public key.

  • signature (BBSPlusSignature) – Signature. Required if used for proving.

  • binding (bool) – Whether the signature is binding.

  • simulated (bool) – If this proof is a part of an or-proof: whether it should be simulated.

construct_stmt(precommitment)

Proof of knowledge of a signature.

This is an implementation of a proof \(\Pi_5\) detailed on page 7 of the Constant-Size Dynamick-TAA paper.

precommit()

Generate the lacking information to construct a complete proof.

The precommitment comprises the A1 and A2 commitments that depend on the secret signature and the Prover’s randomness.

simulate_precommit()

Draw \(A_1\), \(A_2\) at random.

class zksk.primitives.bbsplus.UserCommitmentMessage(com_message, com_nizk_proof=None)

Embed the product to be pre-signed by the issuer.

If blinded by a user’s Pedersen commitment, a NI proof is also specified.

verify_blinding(pk)

Verify the NIZK proof for Pedersen commitment.

zksk.primitives.rangeproof – Range proofs

Range proof: ZK proof that a committed value lies within a range.

\[PK \{ (r, x): \underbrace{C = x G + r H}_{Commitment} \land \underbrace{l \leq x < u}_{Range} \}\]

This module implements a Schoenmakers’ range proof, a conjuction of or-proofs for each bit of the value.

class zksk.primitives.rangeproof.GenericRangeOnlyStmtMaker

Auxiliary builder class for generic range proofs.

\[PK \{ (x): a \leq x < b \}\]

See “Efficient Protocols for Set Membership and Range Proofs” by Camenisch et al., 2008.

In practice, use the zksk.primitives.rangeproof.RangeStmt object directly:

>>> x = Secret(value=3)
>>> lo = 0
>>> hi = 5
>>> stmt = RangeOnlyStmt(lo, hi, x)
>>> nizk = stmt.prove()
>>> stmt.verify(nizk)
True

See GenericRangeStmtMaker.__call__() for the construction signature.

__call__(a, b, x=None)

Get a conjunction of two range-power-of-two proofs. :param a: Lower limit \(a\) :param b: Upper limit \(b\) :param x: Value for which we construct a range proof

class zksk.primitives.rangeproof.GenericRangeStmtMaker

Auxiliary builder class for generic range proofs.

\[PK \{ (r, x): x G + r H \land a \leq x < b \}\]

See “Efficient Protocols for Set Membership and Range Proofs” by Camenisch et al., 2008.

In practice, use the zksk.primitives.rangeproof.RangeStmt object directly:

>>> group = EcGroup()
>>> x = Secret(value=3)
>>> randomizer = Secret(value=group.order().random())
>>> g = group.hash_to_point(b"1")
>>> h = group.hash_to_point(b"2")
>>> lo = 0
>>> hi = 5
>>> com = x * g + randomizer * h
>>> stmt = RangeStmt(com.eval(), g, h, lo, hi, x, randomizer)
>>> nizk = stmt.prove()
>>> stmt.verify(nizk)
True

See GenericRangeStmtMaker.__call__() for the construction signature.

__call__(com, g, h, a, b, x, r)

Get a conjunction of two range-power-of-two proofs.

Parameters
  • com – Value of the Pedersen commitment, \(C = x G + r H\)

  • g – First commitment base point \(G\)

  • h – Second commitment base point \(H\)

  • a – Lower limit \(a\)

  • b – Upper limit \(b\)

  • x – Value for which we construct a range proof

  • r – Randomizer of the commitment \(r\)

class zksk.primitives.rangeproof.PowerTwoRangeStmt(com, g, h, num_bits, x=None, randomizer=None)

A power-two range proof statement.

\[PK \{ (r, x): C = x G + r H \land 0 \leq x < 2^n \}\]
Parameters
  • com – Value of the Pedersen commitment, \(C = x G + r H\)

  • g – First commitment base point \(G\)

  • h – Second commitment base point \(H\)

  • num_bits – The number of bits of the committed value \(n\)

  • x – Value for which we construct a range proof (prover only)

  • randomizer – Randomizer of the commitment \(r\) (prover only)

construct_stmt(precommitment)

Construct the internal proof statement.

precommit()

Commit to the bit-decomposition of the value.

simulate_precommit()

Simulate a precommitment. Override if needed.

Override this method to enable using this proof in or-proofs.

It should compute the same output as generated by precommit, but without relying on any secrets.

validate(precommitment)

Check the commitment to the bit-decomposition is correct.

zksk.primitives.rangeproof.decompose_into_n_bits(value, n)

Array of bits, least significant bit first