| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- # Distributed Key Generation scheme
- t = 4 # Threshold
- n = 10 # Participants
- assert t <= n
- # Pallas
- p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
- q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
- Fp = GF(p)
- Fq = GF(q)
- Ep = EllipticCurve(Fp, (0, 5))
- Ep.set_order(q)
- # NullifierK Generator: G
- G = Ep([0x25e7aa169ca8198d2e375571faf4c9cf5e7eb192ccb5db9bd36f6aa7e447ca75,
- 0x155c1f851b1a3384880473442008ff755fe0a49ec1c1b4332db8dce21ae001cc])
- # =================================
- # Step 1: Secret Share Distribution
- # =================================
- polynomials = []
- shares = {}
- public_values = []
- broadcast_values = {}
- # The participants create their random polynomials and broadcast shares.
- for i in range(n):
- # Pick a random secret
- coeffs = [Fq.random_element()]
- # Generate random polynomial of degree t
- for _ in range(t):
- coeffs.append(Fq.random_element())
- polynomials.append(coeffs)
- # Compute and send secret shares
- shares[i+1] = [sum([coeffs[j] * (k**j) for j in range(t+1)]) for k in range(1, n+1)]
- # Compute public value
- public_values.append(coeffs[0] * G)
- # Broadcast evaluations of the polynomial at public points
- broadcast_values[i+1] = [sum([coeffs[j] * (k**j) for j in range(t+1)]) * G for k in range(1, n+1)]
- # ====================
- # Step 2: Verification
- # ====================
- # In real-world, it is important to ensure that malicious participants
- # cannot raise false complaints to disqualify honest participants.
- # Having a robust mechanism to protect against Sybil attacks or malicious
- # complaint flodding is essential.
- complaints = {}
- # Initial check against broadcasted values
- for i in range(1, n+1):
- for j in range(1, n+1):
- if shares[i][j-1] * G != broadcast_values[i][j-1]:
- if j not in complaints:
- complaints[j] = []
- complaints[j].append(i)
- # Handle complaints
- for complainant, offenders in complaints.items():
- for offender in list(offenders): # Using list() to avoid runtime modification issues
- # The offender proves they sent a correct share to the complainant
- revealed_share = sum([polynomials[offender-1][k] * complainant**k for k in range(t+1)])
- if revealed_share * G == broadcast_values[offender][complainant-1]:
- complaints[complainant].remove(offender)
- # Disqualification step
- disqualified = {i for i, comp in complaints.items() if len(comp) > 0}
- # ===================================
- # Step 3: Secret Share Reconstruction
- # ===================================
- # Sum the secrets of qualified participants to get the group's secret share
- # In a real-world application, this isn't safe and measures should be in
- # place to prevent this scenario.
- qualified_shares = [polynomials[i][0] for i in range(n) if i+1 not in disqualified]
- if len(qualified_shares) < t+1:
- raise ValueError("Too many disqualifications. DKG failed.")
- group_secret = sum(qualified_shares)
- group_public_0 = group_secret * G
- # However we can also do this without ever giving a single party enough
- # shares to reconstruct the secret:
- participant_pubkeys = [polynomials[i][0] * G for i in range(n) if i+1 not in disqualified]
- if len(participant_pubkeys) < t+1:
- raise ValueError("Too many disqualifications. DKG failed.")
- group_public_1 = sum(participant_pubkeys)
- assert group_public_0 == group_public_1
|