def test_dleq_parallel(): α = [Scalar.random() for _ in range(10)] g = [G * Scalar.random() for _ in range(10)] x = [g[i] * α[i] for i in range(10)] h = [H * Scalar.random() for _ in range(10)] y = [h[i] * α[i] for i in range(10)] e, z = _DLEQ_prove(g, x, h, y, α) assert _DLEQ_verify(g, x, h, y, e, z)
def random(degree: int, secret: Optional[Scalar] = None) -> "Polynomial": """ Return a polynomial with random coefficients from Zq. p(x) = c_0 + c_1*x + ... c_{degree} * x^{degree} """ if secret is None: coeffs = [Scalar.random() for i in range(degree + 1)] else: coeffs = [secret] + [Scalar.random() for i in range(degree)] return Polynomial(coeffs)
def share_random_secret( receiver_public_keys: List[Point], recovery_threshold: int, secret_scalar: Optional[Scalar] = None ) -> Tuple[Scalar, List[Point], ShareCorrectnessProof]: """ generate a fresh random base secret s (or uses the provided one) computes share (s_1, ..., s_n) for S = h^s encrypts them with the public keys to obtain ŝ_1, ..., ŝ_n compute the verification information returns - the secret s (which can is used to reveal and verify S) - the encrypted shares ŝ_1, ..., ŝ_n - the share verification information, i.e. PROOF_D, which consists of - the commitments v_1, ..., v_n (v_i = g^{s_i}) - the (common) challenge e - the responses z_1, ..., z_n """ num_receivers = len(receiver_public_keys) secret = secret_scalar or Scalar.random() poly = Polynomial.random(recovery_threshold - 1, secret) shares = [poly(i) for i in range(1, num_receivers + 1)] encrypted_shares = [ pk * share for pk, share in zip(receiver_public_keys, shares) ] proof = prove_share_correctness(shares, encrypted_shares, receiver_public_keys) return secret, encrypted_shares, proof
def _DLEQ_prove(g, x, h, y, α): """ Performs a the DLEQ NIZK protocol for the given values g, x, h, y and the exponent α. I.e. the prover shows that he knows α such that x = g^α and y = h^α holds. To perform the proving prodedure in parallel (but with a common challenge) g, x, h, y and α might be lists. """ g, x, h, y, α = _listify(g, x, h, y, α) assert len(g) == len(x) == len(h) == len(y) == len(α) n = len(g) w = [Scalar.random() for _ in range(n)] # w random element from Zq a1 = [g[i] * w[i] for i in range(n)] # a1 = g^w a2 = [h[i] * w[i] for i in range(n)] # a2 = h^w e = _DLEQ_derive_challenge(x, y, a1, a2) # the challenge e z = [w[i] - (α[i] * e) for i in range(n)] # the response(s) z return e, z[0] if n == 1 else z
def test_dleq_non_equal(): a = Scalar.random() b = Scalar.random() e, z = _DLEQ_prove(G, G * a, H, H * b, a) assert not _DLEQ_verify(G, G * a, H, H * b, e, z)
def test_dleq_invalid_challenge(): α = Scalar.random() e, z = _DLEQ_prove(G, G * α, H, H * α, α) e += Scalar(1) assert not _DLEQ_verify(G, G * α, H, H * α, e, z)
def test_dleq(): α = Scalar.random() e, z = _DLEQ_prove(G, G * α, H, H * α, α) assert _DLEQ_verify(G, G * α, H, H * α, e, z)
def keygen(): """ generates a fresh ed25519 keypair (sk, pk = h^sk) for a participant in the PVSS """ secret_key = Scalar.random() public_key = H * secret_key return secret_key, public_key
assert N == 128, "set i.e. N=128 before running this file in config.py" keypairs = [KeyPair.random() for i in range(N - 1)] public_keys = [k.public_key for k in keypairs] shared_secret, encrypted_shares, proofs = pvss.share_random_secret( public_keys, T) decrypted_shares = [ pvss.decrypt_share(share, keypair.secret_scalar) for share, keypair in zip(encrypted_shares, keypairs) ] dataset_header = DatasetHeader( round_idx=4711, prev_round_idx=4710, revealed_secret=Scalar.random(), beacon=Hash(utils.deterministic_random_bytes(32, "some beacon")), recovered_beacons=[], merkle_root=merkle.compute_root( [Hash(bytes(es)) for es in encrypted_shares])) decryption_proofs = [ pvss.prove_share_decryption(decrypted_share, encrypted_share, keypair.secret_scalar, keypair.public_key) for decrypted_share, encrypted_share, keypair in zip( decrypted_shares, encrypted_shares, keypairs) ] merkle_branches = [ merkle.compute_branch([Hash(bytes(s.value)) for s in encrypted_shares], share_idx) for share_idx, _ in enumerate(encrypted_shares)
def get(obj_type, num_elements=None, **kwargs): mapping = { Scalar: lambda: Scalar.random(), Point: lambda: Point.base_times(Scalar.random()), Hash: lambda: Hash(secrets.token_bytes(32)), Signature: lambda: Signature(secrets.token_bytes(64)), RecoveryCertificate: lambda: RecoveryCertificate( signers=random.sample(list(range(N)), F + 1), signatures=get(Signature, F + 1), ), ConfirmationCertificate: lambda: ConfirmationCertificate( dataset_header_digest=get(Hash), signers=random.sample(list(range(N)), F + 1), signatures=get(Signature, F + 1), ), ShareCorrectnessProof: lambda: ShareCorrectnessProof( commitments=get(Point, N - 1), challenge=get(Scalar), responses=get(Scalar, N - 1), ), ShareDecryptionProof: lambda: ShareDecryptionProof( challenge=get(Scalar), response=get(Scalar), ), RecoveredShare: lambda: RecoveredShare( share=get(Point), proof=get(ShareDecryptionProof), merkle_branch=get(Hash, merkle.branch_length(N - 1)), ), DatasetHeader: lambda **kws: DatasetHeader( round_idx=kws['round_idx'], prev_round_idx=kws['prev_round_idx'], revealed_secret=get(Scalar), beacon=get(Hash), recovered_beacons=get(Hash, kws['round_idx'] - kws['prev_round_idx'] - 1), merkle_root=get(Hash), ), Dataset: lambda **kws: Dataset( round_idx=kws['round_idx'], prev_round_idx=kws['prev_round_idx'], revealed_secret=get(Scalar), beacon=get(Hash), recovered_beacons=get(Hash, kws['round_idx'] - kws['prev_round_idx'] - 1), merkle_root=get(Hash), encrypted_shares=get(Point, N - 1), proof=get(ShareCorrectnessProof), confirmation_certificate=None if kws['prev_round_idx'] == 0 else get(ConfirmationCertificate), recovery_certificates=get(RecoveryCertificate, kws['round_idx'] - kws['prev_round_idx'] - 1), ), ProposeMessage: lambda **kws: ProposeMessage( sender=random.randint(0, N - 1), dataset=get(Dataset, **kws), dataset_header_signature=get(Signature), confirmation_certificate_signature=get(Signature), ), AcknowledgeMessage: lambda **kws: AcknowledgeMessage( sender=random.randint(0, N - 1), dataset_header=get(DatasetHeader, **kws), dataset_header_signature=get(Signature), ), ConfirmMessage: lambda **kws: ConfirmMessage( sender=random.randint(0, N - 1), round_idx=kws.get('round_idx', random.randint(0, 1000_000)), dataset_header_digest=get(Hash), ), RecoverMessage: lambda **kws: RecoverMessage( sender=random.randint(0, N - 1), round_idx=kws.get('round_idx', random.randint(0, 1000_000)), recovery_certificate_signature=get(Signature), recovered_share=get(RecoveredShare) if kws.get('add_recovered_share', True) else None ), SignedMessage: lambda **kws: SignedMessage( message=get(kws['msg_type'], **kws), signature=get(Signature), ) } if num_elements is None: return mapping[obj_type](**kwargs) return [mapping[obj_type](**kwargs) for _ in range(num_elements)]