eddsa-threshold 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. eddsa_threshold/__init__.py +1 -0
  2. eddsa_threshold/eddsa/__init__.py +1 -0
  3. eddsa_threshold/eddsa/algorithms/__init__.py +1 -0
  4. eddsa_threshold/eddsa/algorithms/ed25519.py +84 -0
  5. eddsa_threshold/eddsa/algorithms/ed25519ctx.py +23 -0
  6. eddsa_threshold/eddsa/algorithms/ed25519ph.py +23 -0
  7. eddsa_threshold/eddsa/algorithms/ed448.py +84 -0
  8. eddsa_threshold/eddsa/algorithms/ed448ph.py +23 -0
  9. eddsa_threshold/eddsa/curves/__init__.py +1 -0
  10. eddsa_threshold/eddsa/curves/base/__init__.py +1 -0
  11. eddsa_threshold/eddsa/curves/base/edwards_curve.py +91 -0
  12. eddsa_threshold/eddsa/curves/base/encoding.py +54 -0
  13. eddsa_threshold/eddsa/curves/base/field_ops.py +48 -0
  14. eddsa_threshold/eddsa/curves/base/scalar_ops.py +34 -0
  15. eddsa_threshold/eddsa/curves/ed25519/__init__.py +1 -0
  16. eddsa_threshold/eddsa/curves/ed25519/constants.py +37 -0
  17. eddsa_threshold/eddsa/curves/ed25519/ed25519_curve.py +79 -0
  18. eddsa_threshold/eddsa/curves/ed25519/encoding.py +80 -0
  19. eddsa_threshold/eddsa/curves/ed25519/field_ops.py +12 -0
  20. eddsa_threshold/eddsa/curves/ed25519/scalar_ops.py +12 -0
  21. eddsa_threshold/eddsa/curves/ed448/__init__.py +1 -0
  22. eddsa_threshold/eddsa/curves/ed448/constants.py +37 -0
  23. eddsa_threshold/eddsa/curves/ed448/ed448_curve.py +76 -0
  24. eddsa_threshold/eddsa/curves/ed448/encoding.py +77 -0
  25. eddsa_threshold/eddsa/curves/ed448/field_ops.py +12 -0
  26. eddsa_threshold/eddsa/curves/ed448/scalar_ops.py +12 -0
  27. eddsa_threshold/eddsa/keys/__init__.py +1 -0
  28. eddsa_threshold/eddsa/keys/ed25519_keypair.py +46 -0
  29. eddsa_threshold/eddsa/keys/ed448_keypair.py +45 -0
  30. eddsa_threshold/eddsa/keys/keypair.py +50 -0
  31. eddsa_threshold/eddsa/util/__init__.py +1 -0
  32. eddsa_threshold/eddsa/util/dom.py +17 -0
  33. eddsa_threshold/eddsa/util/hash_bindings.py +12 -0
  34. eddsa_threshold/frost/__init__.py +1 -0
  35. eddsa_threshold/frost/coordinator.py +185 -0
  36. eddsa_threshold/frost/core/__init__.py +1 -0
  37. eddsa_threshold/frost/core/base/__init__.py +1 -0
  38. eddsa_threshold/frost/core/base/frost_hashing.py +27 -0
  39. eddsa_threshold/frost/core/ed25519/__init__.py +1 -0
  40. eddsa_threshold/frost/core/ed25519/frost_hashing.py +26 -0
  41. eddsa_threshold/frost/core/ed448/__init__.py +1 -0
  42. eddsa_threshold/frost/core/ed448/frost_hashing.py +27 -0
  43. eddsa_threshold/frost/core/frost_types.py +53 -0
  44. eddsa_threshold/frost/core/polynomial.py +39 -0
  45. eddsa_threshold/frost/core/secrets/__init__.py +1 -0
  46. eddsa_threshold/frost/core/secrets/secret_sharing.py +26 -0
  47. eddsa_threshold/frost/core/secrets/shamir_secret_sharing.py +41 -0
  48. eddsa_threshold/frost/core/util.py +109 -0
  49. eddsa_threshold/frost/participant.py +140 -0
  50. eddsa_threshold/frost/trusted_dealer.py +72 -0
  51. eddsa_threshold-0.2.0.dist-info/METADATA +39 -0
  52. eddsa_threshold-0.2.0.dist-info/RECORD +55 -0
  53. eddsa_threshold-0.2.0.dist-info/WHEEL +5 -0
  54. eddsa_threshold-0.2.0.dist-info/licenses/LICENSE +14 -0
  55. eddsa_threshold-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,140 @@
1
+ import os
2
+ from typing import Final, Tuple
3
+
4
+ from eddsa_threshold.eddsa.curves.base.edwards_curve import EdwardsCurve
5
+ from eddsa_threshold.frost.core.base.frost_hashing import FrostHashing
6
+ from eddsa_threshold.frost.core.frost_types import GroupInfo, NonceCommitment, ParticipantId, SecretShare, SecretValue, SessionId, SigningPackage, VSSCommitment
7
+ from eddsa_threshold.frost.core.polynomial import derive_interpolating_value
8
+ from eddsa_threshold.frost.core.util import binding_factor_for_participant, compute_binding_factors, compute_group_commitment, derive_group_info
9
+
10
+
11
+ class FrostParticipant:
12
+ """
13
+ Participant-side implementation for a 2-round FROST signing flow.
14
+
15
+ The participant owns one long-term secret key share and ephemeral nonces.
16
+ """
17
+
18
+ # EdwardsCurve for now, because this project only implements FROST for EdDSA, but this can be made more generic if needed.
19
+ def __init__(self, participant_id: ParticipantId, threshold: int, max_participants: int, hashing: FrostHashing, curve: EdwardsCurve):
20
+ self.PARTICIPANT_ID: Final[ParticipantId] = participant_id
21
+ self.THRESHOLD: Final[int] = threshold
22
+ self.MAX_PARTICIPANTS: Final[int] = max_participants
23
+
24
+ self._HASHING: Final[FrostHashing] = hashing
25
+ self._CURVE: Final[EdwardsCurve] = curve
26
+
27
+ self._dealer_info_set: bool = False
28
+
29
+ self._nonce_pair: dict[SessionId, Tuple[int, int]] = dict() # store nonce pairs for active signing sessions, cleared after signing is complete
30
+
31
+ def set_and_verify_dealer_info(self, secret_share: SecretShare, vss_commitment: list[VSSCommitment]) -> None:
32
+ """
33
+ Set the participant's secret share and group info after receiving and verifying them from the trusted dealer.
34
+ """
35
+
36
+ if not self._vss_verify(secret_share, vss_commitment):
37
+ raise ValueError(f"VSS verification failed for the received secret share and VSS commitment for participant {self.PARTICIPANT_ID}")
38
+
39
+ if self._dealer_info_set:
40
+ raise ValueError(f"Participant {self.PARTICIPANT_ID} has already set their dealer info")
41
+
42
+ self._SECRET_SHARE = secret_share
43
+ self._GROUP_INFO = derive_group_info(self.THRESHOLD, self.MAX_PARTICIPANTS, vss_commitment, self._CURVE)
44
+ self._dealer_info_set = True
45
+
46
+ def round_one_commit(self, session_id: SessionId) -> NonceCommitment:
47
+ """
48
+ Round 1 of FROST signing: generates a nonce pair and returns the corresponding commitment.
49
+ """
50
+
51
+ if not self._dealer_info_set:
52
+ raise ValueError(f"Participant {self.PARTICIPANT_ID} has not set their dealer info")
53
+
54
+ if session_id in self._nonce_pair:
55
+ raise ValueError(f"participant {self.PARTICIPANT_ID} has already committed to this signing session")
56
+
57
+ nonce_pair, commitment = self._commit()
58
+ self._nonce_pair[session_id] = nonce_pair
59
+
60
+ return commitment
61
+
62
+ def round_two_sign(self, signing_package: SigningPackage) -> SecretValue:
63
+ """
64
+ Round 2 of FROST signing: takes the signing package from the coordinator and returns the signature share.
65
+ """
66
+
67
+ if signing_package.session_id not in self._nonce_pair:
68
+ raise ValueError(f"participant {self.PARTICIPANT_ID} must commit to this signing session before signing")
69
+
70
+ nonce_pair = self._nonce_pair[signing_package.session_id]
71
+ signature_share = self._sign(signing_package.session_id, signing_package.message, list(signing_package.commitments.values()))
72
+
73
+ self._nonce_pair.pop(signing_package.session_id) # clear nonce pair for this session since signing is complete
74
+
75
+ return signature_share
76
+
77
+ def _commit(self) -> Tuple[Tuple[int, int], NonceCommitment]:
78
+ """
79
+ Generates a nonce pair and the corresponding commitment for round 1 of FROST signing.
80
+ """
81
+
82
+ encoded_secret_share = self._CURVE.encoding.encode_scalar(self._SECRET_SHARE.value)
83
+ hiding_nonce = self._generate_nonce(encoded_secret_share)
84
+ binding_nonce = self._generate_nonce(encoded_secret_share)
85
+
86
+ hiding_nonce_commitment = self._CURVE.extended_to_affine(self._CURVE.scalar_mult(hiding_nonce, None)) # None means base point
87
+ binding_nonce_commitment = self._CURVE.extended_to_affine(self._CURVE.scalar_mult(binding_nonce, None))
88
+
89
+ return (hiding_nonce, binding_nonce), NonceCommitment(self._SECRET_SHARE.index, hiding_nonce_commitment, binding_nonce_commitment)
90
+
91
+ def _sign(self, session_id: SessionId, message: bytes, commitments: list[NonceCommitment]) -> SecretValue:
92
+ """
93
+ Generates a signature share for round 2 of FROST signing given the signing package from the coordinator.
94
+ """
95
+
96
+ nonce_pair = self._nonce_pair[session_id]
97
+
98
+ binding_factors = compute_binding_factors(self._GROUP_INFO.group_public_key, commitments, message, self._HASHING, self._CURVE.encoding)
99
+ binding_factor = binding_factor_for_participant(self._SECRET_SHARE.index, binding_factors)
100
+
101
+ group_commitment = compute_group_commitment(commitments, binding_factors, self._CURVE)
102
+
103
+ participants = list(commitment.participant_id for commitment in commitments)
104
+ # Potentially implemenet reuse logic
105
+ lambda_i = derive_interpolating_value(participants, self._SECRET_SHARE.index, 0, self._CURVE.scalar_ops)
106
+
107
+ challenge = self._compute_challenge(group_commitment, message)
108
+
109
+ hiding_nonce, binding_nonce = nonce_pair
110
+ signature_share = hiding_nonce + (binding_nonce * binding_factor) + (lambda_i * self._SECRET_SHARE.value * challenge)
111
+
112
+ return self._CURVE.scalar_ops.reduce(signature_share)
113
+
114
+ def _vss_verify(self, secret_share: SecretShare, vss_commitment: list[VSSCommitment]) -> bool:
115
+ """
116
+ Verify a participant's secret share against the VSS commitment.
117
+ """
118
+
119
+ S = self._CURVE.scalar_mult(secret_share.value, None)
120
+ S_ = (0, 1, 1, 0) # identity point in extended coordinates
121
+ for i in range(0, self.THRESHOLD):
122
+ S_ = self._CURVE.add(S_, self._CURVE.scalar_mult(pow(secret_share.index, i), vss_commitment[i]))
123
+
124
+ return self._CURVE.extended_to_affine(S) == self._CURVE.extended_to_affine(S_)
125
+
126
+ def _generate_nonce(self, secret: bytes) -> int:
127
+ """
128
+ Generates a nonce using the participant's secret share and a random value.
129
+ """
130
+
131
+ random = os.urandom(32)
132
+ return self._HASHING.h3(random + secret)
133
+
134
+ def _compute_challenge(self, group_commitment: Tuple, message: bytes) -> int:
135
+ """
136
+ Computes the signing challenge c = H(R || A || m) where R is the group commitment, A is the group public key, and m is the message.
137
+ """
138
+
139
+ challenge_input = self._CURVE.encoding.encode_point(group_commitment) + self._GROUP_INFO.group_public_key + message
140
+ return self._HASHING.h2(challenge_input)
@@ -0,0 +1,72 @@
1
+ from typing import Callable, Final
2
+
3
+ from eddsa_threshold.eddsa.curves.base.edwards_curve import EdwardsCurve
4
+ from eddsa_threshold.frost.core.base.frost_hashing import FrostHashing
5
+ from eddsa_threshold.frost.core.secrets.shamir_secret_sharing import ShamirSecretSharing
6
+ from eddsa_threshold.frost.core.frost_types import ParticipantId, SecretShare, VSSCommitment
7
+ from eddsa_threshold.frost.core.util import check_participant_bounds
8
+
9
+
10
+ class FrostTrustedDealer:
11
+
12
+ def __init__(self, seed: int, threshold: int, participant_ids: list[ParticipantId], participant_connections: dict[ParticipantId, Callable[[SecretShare, list[VSSCommitment]], None]], coordinator_connection: Callable[[list[VSSCommitment]], None], curve: EdwardsCurve) -> None:
13
+ if seed < 0 or seed >= curve.scalar_ops.order:
14
+ raise ValueError("seed must be a valid scalar value for the curve")
15
+
16
+ check_participant_bounds(threshold, participant_ids, curve.scalar_ops)
17
+
18
+ self._seed = seed
19
+ self.PARTICIPANT_IDS: Final[list[ParticipantId]] = participant_ids
20
+ self._PARTICIPANT_CONNECTIONS: Final[dict[ParticipantId, Callable[[SecretShare, list[VSSCommitment]], None]]] = participant_connections
21
+ self._COORDINATOR_CONNECTION: Final[Callable[[list[VSSCommitment]], None]] = coordinator_connection
22
+ self._CURVE: Final[EdwardsCurve] = curve
23
+
24
+ # In the future, we may want to support other secret sharing schemes
25
+ self._SECRET_SHARING: Final[ShamirSecretSharing] = ShamirSecretSharing(threshold, len(self.PARTICIPANT_IDS), self._CURVE.scalar_ops)
26
+
27
+ def keygen(self):
28
+ """
29
+ Trusted dealer key generation.
30
+ """
31
+
32
+ shares, coeffs = self._SECRET_SHARING.split(self._seed)
33
+
34
+ vss_commitment = self._vss_commit(coeffs)
35
+
36
+ for participant_id, share in zip(self.PARTICIPANT_IDS, shares):
37
+ if participant_id in self._PARTICIPANT_CONNECTIONS:
38
+ self._PARTICIPANT_CONNECTIONS[participant_id](share, vss_commitment)
39
+ else:
40
+ raise ValueError(f"No connection provided for participant {participant_id}")
41
+
42
+ if self._COORDINATOR_CONNECTION:
43
+ self._COORDINATOR_CONNECTION(vss_commitment)
44
+
45
+ # clear seed, shares, coeffs from memory after key generation, MUST not be reused for another keygen session
46
+ self._seed = -1
47
+ shares.clear()
48
+ coeffs.clear()
49
+
50
+ @classmethod
51
+ def from_private_bytes(cls, seed: int, threshold: int, participant_ids: list[ParticipantId], participant_connections: dict[ParticipantId, Callable[[SecretShare, list[VSSCommitment]], None]], coordinator_connection: Callable[[list[VSSCommitment]], None], curve: EdwardsCurve) -> FrostTrustedDealer:
52
+ """Create a dealer instance from the given private seed bytes."""
53
+ return cls(seed, threshold, participant_ids, participant_connections, coordinator_connection, curve)
54
+
55
+ @classmethod
56
+ def generate(cls, threshold: int, participant_ids: list[ParticipantId], participant_connections: dict[ParticipantId, Callable[[SecretShare, list[VSSCommitment]], None]], coordinator_connection: Callable[[list[VSSCommitment]], None], curve: EdwardsCurve) -> FrostTrustedDealer:
57
+ """Generate a new dealer instance with a fresh secret."""
58
+ seed = curve.scalar_ops.random_scalar()
59
+ return cls(seed, threshold, participant_ids, participant_connections, coordinator_connection, curve)
60
+
61
+ def _vss_commit(self, coeffs: list[int]) -> list[VSSCommitment]:
62
+ """
63
+ Generates a VSS commitment from the given polynomial coefficients.
64
+ """
65
+
66
+ vss_commitment = []
67
+
68
+ for coeff in coeffs:
69
+ vss_i = self._CURVE.scalar_mult(coeff, None)
70
+ vss_commitment.append(vss_i)
71
+
72
+ return vss_commitment
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.4
2
+ Name: eddsa-threshold
3
+ Version: 0.2.0
4
+ Summary: Educational EdDSA and FROST implementations
5
+ Author-email: Maximilian <23641084+xfallme@users.noreply.github.com>
6
+ License-Expression: 0BSD
7
+ Project-URL: Homepage, https://github.com/xfallme/EdDSA-Threshold
8
+ Project-URL: Repository, https://github.com/xfallme/EdDSA-Threshold
9
+ Project-URL: Issues, https://github.com/xfallme/EdDSA-Threshold/issues
10
+ Keywords: cryptography,threshold,eddsa,frost
11
+ Requires-Python: >=3.14
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Provides-Extra: dev
15
+ Requires-Dist: black>=26.5; extra == "dev"
16
+ Requires-Dist: mypy>=2.1; extra == "dev"
17
+ Requires-Dist: pytest==9.0.3; extra == "dev"
18
+ Requires-Dist: pytest-cases==3.10.1; extra == "dev"
19
+ Requires-Dist: pytest-mock==3.15.1; extra == "dev"
20
+ Requires-Dist: ruff>=0.15; extra == "dev"
21
+ Requires-Dist: pynacl>=1.6.2; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ # EdDSA (Threshold)
25
+
26
+ > [!CAUTION]
27
+ > This project is a strictly educational implementation of the EdDSA standard and FROST algorithm. This means it is NOT PRODUCTION READY at the moment.
28
+ > And will likely never be.
29
+
30
+ This repository contains two different but linked implementations. The first is a "normal" single- party DSA, in this case EdDSA. The second is a multi-party threshold signature scheme, namely FROST.
31
+
32
+ ## EdDSA
33
+
34
+ Although this implementation is strictly educational, it follows the standard for EdDSA as specified in [RFC 8032](https://datatracker.ietf.org/doc/html/rfc8032).
35
+
36
+ ## FROST
37
+
38
+ FROST is a bit different, there is no standard (yet) and the [RFC 9591](https://datatracker.ietf.org/doc/html/rfc9591) is strictly informational.
39
+ Also, the RFC defines multiple instantiations for FROST, however this package only implements the version compatible with [Ed25519](https://datatracker.ietf.org/doc/html/rfc9591#name-frosted25519-sha-512) and [Ed448](https://datatracker.ietf.org/doc/html/rfc9591#name-frosted448-shake256) since the focus of the corresponding Master Thesis is on backwards compatibility in regards to the verification.
@@ -0,0 +1,55 @@
1
+ eddsa_threshold/__init__.py,sha256=lfKASrNz00_628laptQbdv7sb118Ltk-7n9xu3xsVHk,30
2
+ eddsa_threshold/eddsa/__init__.py,sha256=8n4W6uj_mIwQyz4TXVbvDVtuOEE07EP_Xu6hWaJeYsk,23
3
+ eddsa_threshold/eddsa/algorithms/__init__.py,sha256=OgSLr3-cQJ1findSBT_K0XjwQp7vc448RZwEGtQKqeA,31
4
+ eddsa_threshold/eddsa/algorithms/ed25519.py,sha256=FjG6ADGPlRD_VO51F9k5uAJcHRhcLPwHsqgaWqnODmI,3179
5
+ eddsa_threshold/eddsa/algorithms/ed25519ctx.py,sha256=psIu67FKXCuyLMt4Ww58UIQTn9-gJgTKwyBDwp5vjUs,1034
6
+ eddsa_threshold/eddsa/algorithms/ed25519ph.py,sha256=kB8dnedMRvn2AZP7cPDyFrHsi9Kp6ORf-Gjx8lUfpdk,1065
7
+ eddsa_threshold/eddsa/algorithms/ed448.py,sha256=eussmwjgoGWYRbJdIABOJNQHJBgNA28FSRsqhUQkG-E,3232
8
+ eddsa_threshold/eddsa/algorithms/ed448ph.py,sha256=0VgopcxQ3af98I1tzPZHwO6cRWgnnPfOmgsZccwm8-c,957
9
+ eddsa_threshold/eddsa/curves/__init__.py,sha256=IK7ljKkfDzfkCDEP4EFJtMT1-gInReCqjUG01pPgFRk,28
10
+ eddsa_threshold/eddsa/curves/base/__init__.py,sha256=n9Lvy8LC7DEFjp1fMlF6GkJRKx-TNR0sa7Hqz2vfvw8,30
11
+ eddsa_threshold/eddsa/curves/base/edwards_curve.py,sha256=RUqMF7Vc5Qriovq733FqIMoswwzFj0zw0FpT92zCrgw,2927
12
+ eddsa_threshold/eddsa/curves/base/encoding.py,sha256=TXogRKFEGHItftu-H2Wx3UyyvF7L23osTWzBY2ZpxS8,1635
13
+ eddsa_threshold/eddsa/curves/base/field_ops.py,sha256=EJAA6iY7rw0ZUjh2-_--5fqWIY8qz3_jiDUB3uAHLvo,1350
14
+ eddsa_threshold/eddsa/curves/base/scalar_ops.py,sha256=4tgrqPs4zDSyyIkZXabNJ1bvBWBspXCxE5XewKi8m2c,956
15
+ eddsa_threshold/eddsa/curves/ed25519/__init__.py,sha256=EMBoAt4lBb-KykLhy1UZ8zXCEO5O8iCVQbMwW26loTc,35
16
+ eddsa_threshold/eddsa/curves/ed25519/constants.py,sha256=LvXshRDSA3FE4O4qbw8yQap8WnEkUHxxBlUrSxgeapU,923
17
+ eddsa_threshold/eddsa/curves/ed25519/ed25519_curve.py,sha256=UrvAF85zumOiBFr7JJCEPr7iIWylUA6zK2SUd5G3TOg,2029
18
+ eddsa_threshold/eddsa/curves/ed25519/encoding.py,sha256=TLJJVi7C7-aqyd-JJFJ1r0ty7q6l61d4e8mTz9WiOeQ,2484
19
+ eddsa_threshold/eddsa/curves/ed25519/field_ops.py,sha256=LcQQEHPutCP6xGf95_u005Nj8F70BgxA20Ins56Q9i4,270
20
+ eddsa_threshold/eddsa/curves/ed25519/scalar_ops.py,sha256=9Ormd6XeCDuEMoluz6XZBtnr5Ff-RC_hAVa8UDiWbBI,268
21
+ eddsa_threshold/eddsa/curves/ed448/__init__.py,sha256=9FnwT1eOBgcskwR0H9GES_wNofjt2YTlm6qTxcw00dI,33
22
+ eddsa_threshold/eddsa/curves/ed448/constants.py,sha256=KuG2fwz4Vo6l_lrZ8CpS243H5KyXXIrVdJ5IyLMb-zU,1006
23
+ eddsa_threshold/eddsa/curves/ed448/ed448_curve.py,sha256=vE_UmOnK7nt0yTKaGKXWBq-zaNtZAJrFcXyWDJ73xks,1912
24
+ eddsa_threshold/eddsa/curves/ed448/encoding.py,sha256=oaTE56rgxQr96AJTlhY0dEwvsqbpqBKu935FW6aEs7s,2325
25
+ eddsa_threshold/eddsa/curves/ed448/field_ops.py,sha256=8MhjocTHJifeMJaTqRgYIRXeu6AyxTh29nWJOv80_Tg,273
26
+ eddsa_threshold/eddsa/curves/ed448/scalar_ops.py,sha256=AH2vUnaeyt1v22Ui18sG_ty327p0oTVJx2FOgB8Na0M,261
27
+ eddsa_threshold/eddsa/keys/__init__.py,sha256=OVoWR2WgDoEkOW2IpRRTWemWd4d3CVyrQVv4adGefSg,22
28
+ eddsa_threshold/eddsa/keys/ed25519_keypair.py,sha256=fTbCB1t6wcQ4gonFNiLQVXPpSTAuP8UwwfSCW4Rq8p4,1561
29
+ eddsa_threshold/eddsa/keys/ed448_keypair.py,sha256=gJm6CWhOA7ShqSm-PrJgYFN63mQHzv-wSctxr10VGmg,1554
30
+ eddsa_threshold/eddsa/keys/keypair.py,sha256=myvBx7qNMFVVhi30EVwtejhZwA83swvN4U2Rrqg0nEQ,1623
31
+ eddsa_threshold/eddsa/util/__init__.py,sha256=wFHlAEsRLfuekGImWHqi-_1OzvPYfDcbiRbSANgDuIM,22
32
+ eddsa_threshold/eddsa/util/dom.py,sha256=kqU7e0axroO2AZ2deh0qcuUPgltMfDJ6VqZdsloQ688,663
33
+ eddsa_threshold/eddsa/util/hash_bindings.py,sha256=KcKkMENtCLSMx118BBsFuMvZgPefOLEnic0wKivrZ60,349
34
+ eddsa_threshold/frost/__init__.py,sha256=iK_XjyEK_4ApFFNN6MRTYpH0Cpxqyy7axinGj3Q_aWs,36
35
+ eddsa_threshold/frost/coordinator.py,sha256=74JLPw7MntKmvjpiOGAcLEM-ceqsJJ_FC5fjKZOv0dI,7744
36
+ eddsa_threshold/frost/participant.py,sha256=jiS_XeVWV3to6UQsqKnzQgt-68OFO1JTyjxOh4RBgI4,6943
37
+ eddsa_threshold/frost/trusted_dealer.py,sha256=ndfwPyAiHE1D33z_4GUqwPEB0xagLNlUGTkFsWFJQfI,3878
38
+ eddsa_threshold/frost/core/__init__.py,sha256=1KX1Z_tlMEkLpDH6skCl_tb3rGjvhJ6VQOLBI8Oq5qo,28
39
+ eddsa_threshold/frost/core/frost_types.py,sha256=LYiowaolZn6yw-T3VJ-ho35vvuXvlkhkxWqBHah06yg,1253
40
+ eddsa_threshold/frost/core/polynomial.py,sha256=Hi4D7p4VBIYNcZe7nos-fgKy3eCQeKf6IZLKikweqZM,1132
41
+ eddsa_threshold/frost/core/util.py,sha256=o4O1x0lLGlgqprH52i_EdO1pRVKg_uV0haW-Fd9hQ5w,4924
42
+ eddsa_threshold/frost/core/base/__init__.py,sha256=0eFoCkRPKQ-l6UhQbp1y9w57QlemTj6XKfDXcDDdbtg,28
43
+ eddsa_threshold/frost/core/base/frost_hashing.py,sha256=qboXjQr36J0BVUg2SGpkLFzAl7Th2Dsw2peX0zRXgog,658
44
+ eddsa_threshold/frost/core/ed25519/__init__.py,sha256=A6MxasKrHxcl-dv1pu-YH8FhrjZI2Pvs7FgOm6cVJlU,37
45
+ eddsa_threshold/frost/core/ed25519/frost_hashing.py,sha256=zvvdrhyvAxQipkvOs5dUJcz3cNwE7iH2HmCCI8hQxbw,919
46
+ eddsa_threshold/frost/core/ed448/__init__.py,sha256=LePiRkQccNcBfHY8vve7jwZHNSyUbh65H7QJOhc2jDk,35
47
+ eddsa_threshold/frost/core/ed448/frost_hashing.py,sha256=sQpan2t6RI70lfkhT2NK8CZMY4O5M2cbj2J3lP07E6I,1078
48
+ eddsa_threshold/frost/core/secrets/__init__.py,sha256=QI-UHdD9Pyhhbd6mRwa2UX-8qBPlBtRTQ42seqc8wWw,29
49
+ eddsa_threshold/frost/core/secrets/secret_sharing.py,sha256=8YbTWSbO76DaBHymRvT8Ej3CVIVrTvxC8vtndF91BfE,854
50
+ eddsa_threshold/frost/core/secrets/shamir_secret_sharing.py,sha256=ntx1iPjPamTE_bWvWfEc2juVYHsTc4o9zrAgPdYgTJI,1767
51
+ eddsa_threshold-0.2.0.dist-info/licenses/LICENSE,sha256=GnTcxvPvk1nKBdI6c2txhYiKrz6d12VBluN9qN59_1w,660
52
+ eddsa_threshold-0.2.0.dist-info/METADATA,sha256=UrqBi1bH36ZGF1cl1nNnqcHNGRM8D9fqRmrqKiXFJJo,2054
53
+ eddsa_threshold-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
54
+ eddsa_threshold-0.2.0.dist-info/top_level.txt,sha256=iLKoOwo1o3ZOWfN1iZSY_M-Gr8kzE_Yc4v8K6wB9j0w,16
55
+ eddsa_threshold-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,14 @@
1
+ BSD Zero Clause License
2
+
3
+ Copyright (c) 2026 xfallme
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14
+ PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1 @@
1
+ eddsa_threshold