proofnest 0.2.0__py3-none-any.whl → 0.2.1__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.
tests/test_proof.py DELETED
@@ -1,279 +0,0 @@
1
- """
2
- Tests for PROOF primitive.
3
- """
4
-
5
- import pytest
6
- import sys
7
- import os
8
-
9
- # Add parent to path
10
- sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
11
-
12
- from proof import (
13
- Proof, ProofType, Identity, Evidence, Signature,
14
- Timestamp, Anchor, AnchorType, Consensus, ConsensusState,
15
- SignatureAlgorithm
16
- )
17
-
18
-
19
- class TestIdentity:
20
- """Test Identity generation and verification"""
21
-
22
- def test_generate_agent_identity(self):
23
- """Test generating an agent identity"""
24
- identity, private_key = Identity.generate("agent")
25
-
26
- assert identity.did.startswith("did:pn:agent:")
27
- assert len(identity.public_key) > 0
28
- assert identity.algorithm == SignatureAlgorithm.DILITHIUM3
29
- assert len(private_key) > 0
30
-
31
- def test_generate_validator_identity(self):
32
- """Test generating a validator identity"""
33
- identity, private_key = Identity.generate("validator")
34
-
35
- assert identity.did.startswith("did:pn:validator:")
36
- assert len(identity.public_key) > 0
37
-
38
- def test_identity_uniqueness(self):
39
- """Test that each identity is unique"""
40
- id1, _ = Identity.generate("agent")
41
- id2, _ = Identity.generate("agent")
42
-
43
- assert id1.did != id2.did
44
- assert id1.public_key != id2.public_key
45
-
46
- def test_generate_hybrid_identity(self):
47
- """Test generating a hybrid ML-DSA + Ed25519 identity (GPT-5.2 audit recommendation)"""
48
- identity, private_key = Identity.generate("agent", SignatureAlgorithm.HYBRID_ML_DSA_ED25519)
49
-
50
- assert identity.did.startswith("did:pn:agent:")
51
- assert identity.algorithm == SignatureAlgorithm.HYBRID_ML_DSA_ED25519
52
- # Hybrid public key = Dilithium (1952) + Ed25519 (32)
53
- assert len(identity.public_key) == 1984
54
- # Hybrid private key = Dilithium (~4000) + Ed25519 (32)
55
- assert len(private_key) == 4032
56
-
57
- def test_generate_ed25519_identity(self):
58
- """Test generating an Ed25519 identity (transitional)"""
59
- identity, private_key = Identity.generate("agent", SignatureAlgorithm.ED25519)
60
-
61
- assert identity.did.startswith("did:pn:agent:")
62
- assert identity.algorithm == SignatureAlgorithm.ED25519
63
- assert len(identity.public_key) == 32 # Ed25519 public key size
64
- assert len(private_key) == 32 # Ed25519 private key size
65
-
66
-
67
- class TestEvidence:
68
- """Test Evidence creation"""
69
-
70
- def test_create_from_data(self):
71
- """Test creating evidence from raw data"""
72
- data = b"Test evidence data"
73
- evidence = Evidence.from_data(data)
74
-
75
- assert evidence.content_hash is not None
76
- assert "shake256:" in evidence.content_hash # Uses SHAKE256 prefix
77
- assert evidence.content_size == len(data)
78
-
79
- def test_embedded_data(self):
80
- """Test evidence with embedded data"""
81
- data = b"Embedded content"
82
- evidence = Evidence.from_data(data)
83
-
84
- assert evidence.embedded == data
85
- assert evidence.content_type == "application/octet-stream"
86
-
87
-
88
- class TestProof:
89
- """Test PROOF creation and verification"""
90
-
91
- def test_create_claim_proof(self):
92
- """Test creating a basic CLAIM proof"""
93
- issuer, private_key = Identity.generate("agent")
94
-
95
- proof = Proof.create(
96
- proof_type=ProofType.CLAIM,
97
- claim="Test claim",
98
- issuer=issuer,
99
- private_key=private_key,
100
- )
101
-
102
- assert proof.proof_id.startswith("proof:")
103
- assert proof.claim == "Test claim"
104
- assert proof.issuer.did == issuer.did
105
- assert proof.signature is not None
106
- assert proof.verify() is True
107
-
108
- def test_create_work_proof(self):
109
- """Test creating a WORK proof"""
110
- issuer, private_key = Identity.generate("agent")
111
-
112
- proof = Proof.work(
113
- issuer=issuer,
114
- private_key=private_key,
115
- description="Completed task",
116
- result=b"Task output",
117
- )
118
-
119
- assert proof.proof_type == ProofType.WORK
120
- assert proof.evidence is not None
121
- assert proof.verify() is True
122
-
123
- def test_create_identity_proof(self):
124
- """Test creating an IDENTITY proof"""
125
- issuer, private_key = Identity.generate("agent")
126
-
127
- proof = Proof.identity(
128
- issuer=issuer,
129
- private_key=private_key,
130
- name="Test Agent",
131
- role="tester",
132
- )
133
-
134
- assert proof.proof_type == ProofType.IDENTITY
135
- assert proof.subject is not None # Subject is issuer for identity proof
136
- assert proof.verify() is True
137
-
138
- def test_proof_hash_stability(self):
139
- """Test that proof hash is stable"""
140
- issuer, private_key = Identity.generate("agent")
141
-
142
- proof = Proof.create(
143
- proof_type=ProofType.CLAIM,
144
- claim="Stable claim",
145
- issuer=issuer,
146
- private_key=private_key,
147
- )
148
-
149
- hash1 = proof.compute_hash()
150
- hash2 = proof.compute_hash()
151
-
152
- assert hash1 == hash2
153
- assert hash1 == proof.proof_id
154
-
155
- def test_proof_chain(self):
156
- """Test proof chaining"""
157
- issuer, private_key = Identity.generate("agent")
158
-
159
- proof1 = Proof.create(
160
- proof_type=ProofType.CLAIM,
161
- claim="First claim",
162
- issuer=issuer,
163
- private_key=private_key,
164
- )
165
-
166
- proof2 = Proof.create(
167
- proof_type=ProofType.CLAIM,
168
- claim="Second claim",
169
- issuer=issuer,
170
- private_key=private_key,
171
- previous_proof=proof1.proof_id,
172
- )
173
-
174
- assert proof2.previous_proof == proof1.proof_id
175
-
176
- def test_proof_to_dict(self):
177
- """Test proof serialization to dict"""
178
- issuer, private_key = Identity.generate("agent")
179
-
180
- proof = Proof.create(
181
- proof_type=ProofType.CLAIM,
182
- claim="Serialization test",
183
- issuer=issuer,
184
- private_key=private_key,
185
- )
186
-
187
- d = proof.to_dict()
188
-
189
- assert "proof_id" in d
190
- assert "claim" in d
191
- assert "proof_type" in d
192
- assert "issuer" in d
193
- assert "timestamp" in d
194
-
195
- def test_hybrid_signature_proof(self):
196
- """Test PROOF with hybrid ML-DSA + Ed25519 signature (GPT-5.2 audit recommendation)"""
197
- issuer, private_key = Identity.generate("agent", SignatureAlgorithm.HYBRID_ML_DSA_ED25519)
198
-
199
- proof = Proof.create(
200
- proof_type=ProofType.CLAIM,
201
- claim="Hybrid signature test",
202
- issuer=issuer,
203
- private_key=private_key,
204
- )
205
-
206
- assert proof.signature.algorithm == SignatureAlgorithm.HYBRID_ML_DSA_ED25519
207
- # Verify MÕLEMAD allkirjad töötavad
208
- assert proof.verify() is True
209
- # Hybrid signature = Dilithium (~3293) + Ed25519 (64)
210
- assert len(proof.signature.value) > 3000
211
-
212
- def test_hybrid_signature_tamper_resistance(self):
213
- """Test that tampering with hybrid-signed PROOF is detected"""
214
- issuer, private_key = Identity.generate("agent", SignatureAlgorithm.HYBRID_ML_DSA_ED25519)
215
-
216
- proof = Proof.create(
217
- proof_type=ProofType.CLAIM,
218
- claim="Original claim",
219
- issuer=issuer,
220
- private_key=private_key,
221
- )
222
-
223
- # Create tampered proof with different claim
224
- tampered = Proof(
225
- proof_id=proof.proof_id,
226
- proof_type=proof.proof_type,
227
- claim="TAMPERED claim", # Modified!
228
- issuer=proof.issuer,
229
- signature=proof.signature,
230
- timestamp=proof.timestamp,
231
- )
232
-
233
- # Original should verify
234
- assert proof.verify() is True
235
- # Tampered should fail (hash won't match)
236
- assert tampered.verify() is False
237
-
238
-
239
- class TestTimestamp:
240
- """Test Timestamp with nonce (replay protection)"""
241
-
242
- def test_timestamp_has_nonce(self):
243
- """Test that timestamp includes nonce for replay protection"""
244
- ts = Timestamp.now()
245
-
246
- assert ts.unix_time > 0
247
- assert ts.nonce is not None
248
- assert len(ts.nonce) > 0
249
-
250
- def test_timestamp_uniqueness(self):
251
- """Test that timestamps are unique even at same time"""
252
- ts1 = Timestamp.now()
253
- ts2 = Timestamp.now()
254
-
255
- # Nonces should be different
256
- assert ts1.nonce != ts2.nonce
257
-
258
-
259
- class TestConsensus:
260
- """Test Consensus state"""
261
-
262
- def test_consensus_state(self):
263
- """Test consensus state creation"""
264
- consensus = Consensus(
265
- state=ConsensusState.PENDING,
266
- quorum_threshold=0.67
267
- )
268
-
269
- assert consensus.state == ConsensusState.PENDING
270
- assert consensus.quorum_threshold == 0.67
271
-
272
- def test_consensus_accepted_state(self):
273
- """Test accepted consensus state"""
274
- consensus = Consensus(state=ConsensusState.ACCEPTED)
275
- assert consensus.state == ConsensusState.ACCEPTED
276
-
277
-
278
- if __name__ == "__main__":
279
- pytest.main([__file__, "-v"])
tests/test_staking.py DELETED
@@ -1,174 +0,0 @@
1
- """
2
- Tests for Staking & Sybil Resistance (GPT-5.2 audit)
3
- """
4
-
5
- import pytest
6
- import sys
7
- import os
8
- from decimal import Decimal
9
-
10
- sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
11
-
12
- from staking import (
13
- StakingRegistry,
14
- ValidatorStake,
15
- StakeRecord,
16
- StakeType,
17
- SlashReason,
18
- )
19
-
20
-
21
- class TestValidatorStake:
22
- """Test validator stake operations"""
23
-
24
- def test_create_validator(self):
25
- """Test creating a validator with initial stake"""
26
- validator = ValidatorStake(validator_did="did:pn:validator:test")
27
- validator.add_reputation(100)
28
-
29
- assert validator.validator_did == "did:pn:validator:test"
30
- assert validator.reputation_score == 100
31
- assert validator.total_stake == Decimal("100")
32
-
33
- def test_voting_power_calculation(self):
34
- """Test that voting power uses diminishing returns"""
35
- v1 = ValidatorStake(validator_did="did:pn:validator:small")
36
- v1.add_reputation(100)
37
-
38
- v2 = ValidatorStake(validator_did="did:pn:validator:large")
39
- v2.add_reputation(100)
40
- # Add large economic stake
41
- v2.stakes.append(StakeRecord(
42
- stake_id="stake:1",
43
- validator_did="did:pn:validator:large",
44
- stake_type=StakeType.ESCROW,
45
- amount=Decimal("10000"),
46
- currency="USD",
47
- ))
48
-
49
- # Large validator should have more power, but not 100x more
50
- ratio = float(v2.voting_power) / float(v1.voting_power)
51
- assert ratio > 1.5 # Larger should have more power
52
- assert ratio < 100 # But not proportionally more (diminishing returns)
53
-
54
- def test_slash_reduces_stake(self):
55
- """Test that slashing reduces effective stake"""
56
- validator = ValidatorStake(validator_did="did:pn:validator:slashme")
57
- validator.stakes.append(StakeRecord(
58
- stake_id="stake:1",
59
- validator_did="did:pn:validator:slashme",
60
- stake_type=StakeType.ESCROW,
61
- amount=Decimal("1000"),
62
- currency="USD",
63
- ))
64
-
65
- initial_stake = validator.total_stake
66
- validator.slash(SlashReason.DOUBLE_SIGN, Decimal("0.5"))
67
-
68
- assert validator.total_stake < initial_stake
69
- assert validator.total_stake == Decimal("500")
70
-
71
- def test_jail_prevents_validation(self):
72
- """Test that jailed validators cannot participate"""
73
- validator = ValidatorStake(validator_did="did:pn:validator:jailed")
74
- validator.add_reputation(500)
75
-
76
- # Not jailed initially
77
- assert validator.is_jailed is False
78
-
79
- # Jail for 1 hour
80
- validator.jail(3600)
81
- assert validator.is_jailed is True
82
-
83
- # Cannot unjail yet (time hasn't passed)
84
- assert validator.unjail() is False
85
-
86
-
87
- class TestStakingRegistry:
88
- """Test staking registry operations"""
89
-
90
- def test_register_validator(self):
91
- """Test registering a new validator"""
92
- registry = StakingRegistry()
93
- validator = registry.register_validator("did:pn:validator:new")
94
-
95
- assert validator is not None
96
- assert validator.validator_did == "did:pn:validator:new"
97
-
98
- def test_minimum_stake_requirement(self):
99
- """Test that minimum stake is required to validate"""
100
- registry = StakingRegistry()
101
-
102
- # Validator with no stake
103
- registry.register_validator("did:pn:validator:poor")
104
- assert registry.can_validate("did:pn:validator:poor") is False
105
-
106
- # Validator with enough stake
107
- v = registry.register_validator("did:pn:validator:rich")
108
- v.add_reputation(200)
109
- assert registry.can_validate("did:pn:validator:rich") is True
110
-
111
- def test_reward_increases_reputation(self):
112
- """Test that validation rewards increase reputation"""
113
- registry = StakingRegistry()
114
- v = registry.register_validator("did:pn:validator:worker")
115
- v.add_reputation(100) # Initial stake
116
-
117
- initial_rep = v.reputation_score
118
- registry.reward_validation("did:pn:validator:worker", "proof:123", True)
119
-
120
- assert v.reputation_score > initial_rep
121
-
122
- def test_slash_for_misbehavior(self):
123
- """Test slashing for various violations"""
124
- registry = StakingRegistry()
125
- v = registry.register_validator("did:pn:validator:bad")
126
- v.stakes.append(StakeRecord(
127
- stake_id="stake:1",
128
- validator_did="did:pn:validator:bad",
129
- stake_type=StakeType.ESCROW,
130
- amount=Decimal("1000"),
131
- currency="USD",
132
- ))
133
-
134
- event = registry.slash_validator("did:pn:validator:bad", SlashReason.DOUBLE_SIGN)
135
-
136
- assert event is not None
137
- assert event.reason == SlashReason.DOUBLE_SIGN
138
- assert v.is_jailed is True
139
-
140
- def test_get_active_validators(self):
141
- """Test getting only active validators"""
142
- registry = StakingRegistry()
143
-
144
- # Active validator
145
- v1 = registry.register_validator("did:pn:validator:active")
146
- v1.add_reputation(200)
147
-
148
- # Jailed validator
149
- v2 = registry.register_validator("did:pn:validator:jailed")
150
- v2.add_reputation(200)
151
- v2.jail(3600)
152
-
153
- active = registry.get_active_validators()
154
- assert len(active) == 1
155
- assert active[0].validator_did == "did:pn:validator:active"
156
-
157
- def test_voting_power_distribution(self):
158
- """Test getting voting power for all active validators"""
159
- registry = StakingRegistry()
160
-
161
- v1 = registry.register_validator("did:pn:validator:a")
162
- v1.add_reputation(300)
163
-
164
- v2 = registry.register_validator("did:pn:validator:b")
165
- v2.add_reputation(150)
166
-
167
- powers = registry.get_voting_power_distribution()
168
-
169
- assert len(powers) == 2
170
- assert powers["did:pn:validator:a"] > powers["did:pn:validator:b"]
171
-
172
-
173
- if __name__ == "__main__":
174
- pytest.main([__file__, "-v"])