agentcert 0.1.0__tar.gz
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.
- agentcert-0.1.0/LICENSE +21 -0
- agentcert-0.1.0/PKG-INFO +334 -0
- agentcert-0.1.0/README.md +303 -0
- agentcert-0.1.0/pyproject.toml +53 -0
- agentcert-0.1.0/setup.cfg +4 -0
- agentcert-0.1.0/src/agentcert/__init__.py +130 -0
- agentcert-0.1.0/src/agentcert/anchor.py +499 -0
- agentcert-0.1.0/src/agentcert/certificate.py +162 -0
- agentcert-0.1.0/src/agentcert/chain.py +309 -0
- agentcert-0.1.0/src/agentcert/cli.py +323 -0
- agentcert-0.1.0/src/agentcert/exceptions.py +37 -0
- agentcert-0.1.0/src/agentcert/keys.py +96 -0
- agentcert-0.1.0/src/agentcert/types.py +276 -0
- agentcert-0.1.0/src/agentcert/verify.py +173 -0
- agentcert-0.1.0/src/agentcert.egg-info/PKG-INFO +334 -0
- agentcert-0.1.0/src/agentcert.egg-info/SOURCES.txt +24 -0
- agentcert-0.1.0/src/agentcert.egg-info/dependency_links.txt +1 -0
- agentcert-0.1.0/src/agentcert.egg-info/entry_points.txt +2 -0
- agentcert-0.1.0/src/agentcert.egg-info/requires.txt +8 -0
- agentcert-0.1.0/src/agentcert.egg-info/top_level.txt +1 -0
- agentcert-0.1.0/tests/test_anchor.py +296 -0
- agentcert-0.1.0/tests/test_certificate.py +184 -0
- agentcert-0.1.0/tests/test_chain.py +185 -0
- agentcert-0.1.0/tests/test_integration.py +272 -0
- agentcert-0.1.0/tests/test_keys.py +82 -0
- agentcert-0.1.0/tests/test_verify.py +227 -0
agentcert-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Shaleen Chauhan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
agentcert-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentcert
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bitcoin-anchored identity certificates for AI agents
|
|
5
|
+
Author: Shaleen Chauhan
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/shaleenchauhan/agentcert
|
|
8
|
+
Project-URL: Documentation, https://github.com/shaleenchauhan/agentcert#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/shaleenchauhan/agentcert
|
|
10
|
+
Project-URL: Issues, https://github.com/shaleenchauhan/agentcert/issues
|
|
11
|
+
Keywords: bitcoin,ai,identity,certificates,agents
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Security :: Cryptography
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: cryptography>=42.0
|
|
24
|
+
Requires-Dist: requests>=2.31
|
|
25
|
+
Requires-Dist: click>=8.1
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-cov>=4.1; extra == "dev"
|
|
29
|
+
Requires-Dist: responses>=0.24; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# AgentCert
|
|
33
|
+
|
|
34
|
+
Bitcoin-anchored identity certificates for AI agents.
|
|
35
|
+
|
|
36
|
+
AgentCert is the open-source Python implementation of **AIT-1** (Agent Identity Certificates) from the Agent Internet Trust protocol. It lets developers create cryptographically signed, Bitcoin-anchored identity certificates that bind a **creator** (human or company) to an **agent** (autonomous software) — with verifiable metadata, capabilities, constraints, and a risk tier.
|
|
37
|
+
|
|
38
|
+
Every certificate is signed with ECDSA/secp256k1, hashed with SHA-256, and optionally anchored to Bitcoin via OP_RETURN. Any third party can verify the certificate using only math and the blockchain.
|
|
39
|
+
|
|
40
|
+
**Proven on Bitcoin testnet:** [`6b3b8cd6...`](https://blockstream.info/testnet/tx/6b3b8cd6624d833e98add57823a7a8ba72134a9de4aae6b7eb7617ebd7cb771c)
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install agentcert
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or from source:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
git clone https://github.com/shaleenchauhan/agentcert.git
|
|
52
|
+
cd agentcert
|
|
53
|
+
pip install -e ".[dev]"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Requires Python 3.11+. Dependencies: `cryptography`, `requests`, `click`.
|
|
57
|
+
|
|
58
|
+
## Quickstart
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import agentcert
|
|
62
|
+
|
|
63
|
+
# Generate key pairs
|
|
64
|
+
creator_keys = agentcert.generate_keys()
|
|
65
|
+
agent_keys = agentcert.generate_keys()
|
|
66
|
+
|
|
67
|
+
# Create a signed certificate
|
|
68
|
+
cert = agentcert.create_certificate(
|
|
69
|
+
creator_keys=creator_keys,
|
|
70
|
+
agent_keys=agent_keys,
|
|
71
|
+
name="procurement-agent-v1",
|
|
72
|
+
platform="langchain",
|
|
73
|
+
model_hash="sha256:a1b2c3d4e5f6",
|
|
74
|
+
capabilities=["procurement", "negotiation"],
|
|
75
|
+
constraints=["max-transaction-50000-usd"],
|
|
76
|
+
risk_tier=3,
|
|
77
|
+
expires_days=90,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Verify it
|
|
81
|
+
result = agentcert.verify(cert)
|
|
82
|
+
assert result.valid
|
|
83
|
+
print(result.status) # "VALID"
|
|
84
|
+
|
|
85
|
+
# Save to disk
|
|
86
|
+
agentcert.save_certificate(cert, "agent.cert.json")
|
|
87
|
+
agentcert.save_keys(creator_keys, "creator.keys.json")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## CLI
|
|
91
|
+
|
|
92
|
+
AgentCert ships a full command-line interface:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Generate keys
|
|
96
|
+
agentcert keygen -o creator.keys.json
|
|
97
|
+
agentcert keygen -o agent.keys.json
|
|
98
|
+
|
|
99
|
+
# Create a certificate
|
|
100
|
+
agentcert create \
|
|
101
|
+
--creator-keys creator.keys.json \
|
|
102
|
+
--agent-keys agent.keys.json \
|
|
103
|
+
--name "my-agent" \
|
|
104
|
+
--platform "langchain" \
|
|
105
|
+
--capabilities "procurement,negotiation" \
|
|
106
|
+
--constraints "max-50k-usd" \
|
|
107
|
+
--risk-tier 3 \
|
|
108
|
+
--expires 90d \
|
|
109
|
+
-o cert.json
|
|
110
|
+
|
|
111
|
+
# Inspect it
|
|
112
|
+
agentcert inspect cert.json
|
|
113
|
+
|
|
114
|
+
# Verify it
|
|
115
|
+
agentcert verify cert.json
|
|
116
|
+
|
|
117
|
+
# Update (add capabilities, new version in the chain)
|
|
118
|
+
agentcert update cert.json \
|
|
119
|
+
--creator-keys creator.keys.json \
|
|
120
|
+
--add-capability "invoicing" \
|
|
121
|
+
-o cert-v2.json
|
|
122
|
+
|
|
123
|
+
# Revoke
|
|
124
|
+
agentcert revoke cert-v2.json \
|
|
125
|
+
--creator-keys creator.keys.json \
|
|
126
|
+
--reason "Decommissioned" \
|
|
127
|
+
-o revoke.json
|
|
128
|
+
|
|
129
|
+
# Verify the full chain
|
|
130
|
+
agentcert verify-chain cert.json cert-v2.json revoke.json
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## SDK API
|
|
134
|
+
|
|
135
|
+
All functions are available at the top level — no submodule imports needed.
|
|
136
|
+
|
|
137
|
+
### Keys
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
creator_keys = agentcert.generate_keys()
|
|
141
|
+
agentcert.save_keys(creator_keys, "creator.keys.json")
|
|
142
|
+
creator_keys = agentcert.load_keys("creator.keys.json")
|
|
143
|
+
|
|
144
|
+
# Derive Bitcoin address (for funding anchor transactions)
|
|
145
|
+
address = agentcert.derive_bitcoin_address(creator_keys, network="testnet")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Certificates
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
cert = agentcert.create_certificate(
|
|
152
|
+
creator_keys=creator_keys,
|
|
153
|
+
agent_keys=agent_keys,
|
|
154
|
+
name="my-agent",
|
|
155
|
+
platform="langchain",
|
|
156
|
+
model_hash="sha256:...",
|
|
157
|
+
capabilities=["task-a", "task-b"],
|
|
158
|
+
constraints=["spending-limit-1000"],
|
|
159
|
+
risk_tier=2,
|
|
160
|
+
expires_days=90,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
agentcert.save_certificate(cert, "agent.cert.json")
|
|
164
|
+
cert = agentcert.load_certificate("agent.cert.json")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Verification
|
|
168
|
+
|
|
169
|
+
The verifier runs 6 checks (all must pass for `VALID`):
|
|
170
|
+
|
|
171
|
+
1. **cert_id integrity** — SHA-256(body) matches cert_id
|
|
172
|
+
2. **creator_id derivation** — SHA-256(creator_public_key) matches creator_id
|
|
173
|
+
3. **agent_id derivation** — SHA-256(agent_public_key) matches agent_id
|
|
174
|
+
4. **Creator signature** — ECDSA verification against creator_public_key
|
|
175
|
+
5. **Anchor integrity** — certificate hash matches the anchored hash (if receipt provided)
|
|
176
|
+
6. **Expiration** — current time < expires
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
result = agentcert.verify(cert) # without anchor
|
|
180
|
+
result = agentcert.verify(cert, receipt) # with anchor receipt
|
|
181
|
+
|
|
182
|
+
print(result.status) # "VALID" or "INVALID"
|
|
183
|
+
print(result.valid) # True / False
|
|
184
|
+
|
|
185
|
+
for check in result.checks:
|
|
186
|
+
print(f"[{'PASS' if check.passed else 'FAIL'}] {check.name}: {check.detail}")
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Chain Operations
|
|
190
|
+
|
|
191
|
+
Certificates form a linked chain: create → update → ... → revoke.
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
# Update (carries over unchanged fields)
|
|
195
|
+
updated = agentcert.update_certificate(
|
|
196
|
+
previous_cert=cert,
|
|
197
|
+
creator_keys=creator_keys,
|
|
198
|
+
capabilities=["procurement", "negotiation", "invoicing"],
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# Revoke (terminates the chain)
|
|
202
|
+
revocation = agentcert.revoke_certificate(
|
|
203
|
+
previous_cert=updated,
|
|
204
|
+
creator_keys=creator_keys,
|
|
205
|
+
reason="Decommissioned",
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Verify the full chain
|
|
209
|
+
chain_result = agentcert.verify_chain([cert, updated, revocation])
|
|
210
|
+
print(chain_result.status) # "REVOKED"
|
|
211
|
+
print(chain_result.valid) # True (REVOKED is a valid terminal state)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Bitcoin Anchoring
|
|
215
|
+
|
|
216
|
+
Anchor a certificate to Bitcoin via an OP_RETURN transaction:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
# The creator's Bitcoin address must be funded first
|
|
220
|
+
address = agentcert.derive_bitcoin_address(creator_keys, network="testnet")
|
|
221
|
+
print(f"Fund this address: {address}")
|
|
222
|
+
|
|
223
|
+
# Anchor (builds, signs, and broadcasts a Bitcoin transaction)
|
|
224
|
+
receipt = agentcert.anchor(cert, creator_keys=creator_keys, network="testnet")
|
|
225
|
+
print(receipt.txid)
|
|
226
|
+
|
|
227
|
+
# Save the receipt for later verification
|
|
228
|
+
agentcert.save_receipt(receipt, "receipt.json")
|
|
229
|
+
receipt = agentcert.load_receipt("receipt.json")
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The OP_RETURN payload is 38 bytes:
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
[AIT\0] protocol tag (4 bytes)
|
|
236
|
+
[0x01] version (1 byte)
|
|
237
|
+
[0x02] IDENTITY_CERT (1 byte)
|
|
238
|
+
[...] SHA-256 hash (32 bytes)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Certificate Structure
|
|
242
|
+
|
|
243
|
+
```json
|
|
244
|
+
{
|
|
245
|
+
"ait_version": 1,
|
|
246
|
+
"cert_type": 1,
|
|
247
|
+
"cert_id": "<SHA-256 of body>",
|
|
248
|
+
"timestamp": 1739750000,
|
|
249
|
+
"expires": 1747526000,
|
|
250
|
+
"agent_public_key": "<33-byte compressed public key, hex>",
|
|
251
|
+
"agent_id": "<SHA-256 of agent_public_key>",
|
|
252
|
+
"creator_public_key": "<33-byte compressed public key, hex>",
|
|
253
|
+
"creator_id": "<SHA-256 of creator_public_key>",
|
|
254
|
+
"agent_metadata": {
|
|
255
|
+
"name": "my-agent",
|
|
256
|
+
"model_hash": "sha256:...",
|
|
257
|
+
"platform": "langchain",
|
|
258
|
+
"capabilities": ["procurement", "negotiation"],
|
|
259
|
+
"constraints": ["max-transaction-50000-usd"],
|
|
260
|
+
"risk_tier": 3
|
|
261
|
+
},
|
|
262
|
+
"previous_cert_id": null,
|
|
263
|
+
"creator_signature": "<ECDSA DER signature, hex>"
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
| Field | Description |
|
|
268
|
+
|-------|-------------|
|
|
269
|
+
| `cert_type` | 1 = CREATION, 2 = UPDATE, 3 = REVOCATION |
|
|
270
|
+
| `cert_id` | SHA-256 of the certificate body (all fields except `cert_id` and `creator_signature`) |
|
|
271
|
+
| `creator_signature` | ECDSA/secp256k1 signature over the same body |
|
|
272
|
+
| `previous_cert_id` | Links to the prior certificate in the chain (null for the first) |
|
|
273
|
+
|
|
274
|
+
## How It Works
|
|
275
|
+
|
|
276
|
+
**Signing:** The cert_id and creator_signature are computed over the same canonical JSON body. The cert_id verifies integrity (any tampering changes the hash). The signature verifies authenticity (only the creator's private key can produce it). Both are independently checkable by any third party.
|
|
277
|
+
|
|
278
|
+
**Anchoring:** The anchor hash is SHA-256 of the *complete* certificate (including cert_id and signature). This goes into a Bitcoin OP_RETURN output. If anything is modified after anchoring, the anchor check fails.
|
|
279
|
+
|
|
280
|
+
**Chain verification** checks: each cert's `previous_cert_id` links to the prior cert's `cert_id`, the same creator throughout, valid signatures on every cert, and the final cert's type determines the chain status (ACTIVE or REVOKED).
|
|
281
|
+
|
|
282
|
+
## Development
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
git clone https://github.com/shaleenchauhan/agentcert.git
|
|
286
|
+
cd agentcert
|
|
287
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
288
|
+
pip install -e ".[dev]"
|
|
289
|
+
|
|
290
|
+
# Run tests
|
|
291
|
+
pytest
|
|
292
|
+
|
|
293
|
+
# Run tests with coverage
|
|
294
|
+
pytest --cov=agentcert --cov-report=term-missing
|
|
295
|
+
|
|
296
|
+
# Run examples
|
|
297
|
+
python examples/quickstart.py
|
|
298
|
+
python examples/full_lifecycle.py
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Project Structure
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
agentcert/
|
|
305
|
+
src/agentcert/
|
|
306
|
+
__init__.py # Public API (33 exports, no submodule imports needed)
|
|
307
|
+
keys.py # Key generation, save, load (secp256k1)
|
|
308
|
+
certificate.py # Certificate creation, signing, serialization
|
|
309
|
+
chain.py # Update, revoke, chain verification
|
|
310
|
+
anchor.py # Bitcoin OP_RETURN + Blockstream API
|
|
311
|
+
verify.py # 6-check verification with structured results
|
|
312
|
+
types.py # KeyPair, Certificate, AgentMetadata, etc.
|
|
313
|
+
exceptions.py # Custom exception hierarchy
|
|
314
|
+
cli.py # Click-based CLI (8 commands)
|
|
315
|
+
tests/ # 118 tests, 93% coverage
|
|
316
|
+
examples/ # quickstart.py, full_lifecycle.py
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Technical Decisions
|
|
320
|
+
|
|
321
|
+
| Component | Choice | Rationale |
|
|
322
|
+
|-----------|--------|-----------|
|
|
323
|
+
| Language | Python 3.11+ | AI/ML ecosystem standard |
|
|
324
|
+
| Curve | secp256k1 | Bitcoin-native, same keys for signing and anchoring |
|
|
325
|
+
| Signatures | ECDSA | Proven; Schnorr migration path later |
|
|
326
|
+
| Hashing | SHA-256 | Bitcoin-native |
|
|
327
|
+
| Serialization | JSON (deterministic) | `sort_keys=True, separators=(',',':')` |
|
|
328
|
+
| CLI | Click | Mature, clean subcommand support |
|
|
329
|
+
| Bitcoin API | Blockstream | No auth, free, reliable |
|
|
330
|
+
| Dependencies | 3 runtime | `cryptography`, `requests`, `click` |
|
|
331
|
+
|
|
332
|
+
## License
|
|
333
|
+
|
|
334
|
+
MIT
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# AgentCert
|
|
2
|
+
|
|
3
|
+
Bitcoin-anchored identity certificates for AI agents.
|
|
4
|
+
|
|
5
|
+
AgentCert is the open-source Python implementation of **AIT-1** (Agent Identity Certificates) from the Agent Internet Trust protocol. It lets developers create cryptographically signed, Bitcoin-anchored identity certificates that bind a **creator** (human or company) to an **agent** (autonomous software) — with verifiable metadata, capabilities, constraints, and a risk tier.
|
|
6
|
+
|
|
7
|
+
Every certificate is signed with ECDSA/secp256k1, hashed with SHA-256, and optionally anchored to Bitcoin via OP_RETURN. Any third party can verify the certificate using only math and the blockchain.
|
|
8
|
+
|
|
9
|
+
**Proven on Bitcoin testnet:** [`6b3b8cd6...`](https://blockstream.info/testnet/tx/6b3b8cd6624d833e98add57823a7a8ba72134a9de4aae6b7eb7617ebd7cb771c)
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install agentcert
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or from source:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git clone https://github.com/shaleenchauhan/agentcert.git
|
|
21
|
+
cd agentcert
|
|
22
|
+
pip install -e ".[dev]"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Requires Python 3.11+. Dependencies: `cryptography`, `requests`, `click`.
|
|
26
|
+
|
|
27
|
+
## Quickstart
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import agentcert
|
|
31
|
+
|
|
32
|
+
# Generate key pairs
|
|
33
|
+
creator_keys = agentcert.generate_keys()
|
|
34
|
+
agent_keys = agentcert.generate_keys()
|
|
35
|
+
|
|
36
|
+
# Create a signed certificate
|
|
37
|
+
cert = agentcert.create_certificate(
|
|
38
|
+
creator_keys=creator_keys,
|
|
39
|
+
agent_keys=agent_keys,
|
|
40
|
+
name="procurement-agent-v1",
|
|
41
|
+
platform="langchain",
|
|
42
|
+
model_hash="sha256:a1b2c3d4e5f6",
|
|
43
|
+
capabilities=["procurement", "negotiation"],
|
|
44
|
+
constraints=["max-transaction-50000-usd"],
|
|
45
|
+
risk_tier=3,
|
|
46
|
+
expires_days=90,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Verify it
|
|
50
|
+
result = agentcert.verify(cert)
|
|
51
|
+
assert result.valid
|
|
52
|
+
print(result.status) # "VALID"
|
|
53
|
+
|
|
54
|
+
# Save to disk
|
|
55
|
+
agentcert.save_certificate(cert, "agent.cert.json")
|
|
56
|
+
agentcert.save_keys(creator_keys, "creator.keys.json")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## CLI
|
|
60
|
+
|
|
61
|
+
AgentCert ships a full command-line interface:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Generate keys
|
|
65
|
+
agentcert keygen -o creator.keys.json
|
|
66
|
+
agentcert keygen -o agent.keys.json
|
|
67
|
+
|
|
68
|
+
# Create a certificate
|
|
69
|
+
agentcert create \
|
|
70
|
+
--creator-keys creator.keys.json \
|
|
71
|
+
--agent-keys agent.keys.json \
|
|
72
|
+
--name "my-agent" \
|
|
73
|
+
--platform "langchain" \
|
|
74
|
+
--capabilities "procurement,negotiation" \
|
|
75
|
+
--constraints "max-50k-usd" \
|
|
76
|
+
--risk-tier 3 \
|
|
77
|
+
--expires 90d \
|
|
78
|
+
-o cert.json
|
|
79
|
+
|
|
80
|
+
# Inspect it
|
|
81
|
+
agentcert inspect cert.json
|
|
82
|
+
|
|
83
|
+
# Verify it
|
|
84
|
+
agentcert verify cert.json
|
|
85
|
+
|
|
86
|
+
# Update (add capabilities, new version in the chain)
|
|
87
|
+
agentcert update cert.json \
|
|
88
|
+
--creator-keys creator.keys.json \
|
|
89
|
+
--add-capability "invoicing" \
|
|
90
|
+
-o cert-v2.json
|
|
91
|
+
|
|
92
|
+
# Revoke
|
|
93
|
+
agentcert revoke cert-v2.json \
|
|
94
|
+
--creator-keys creator.keys.json \
|
|
95
|
+
--reason "Decommissioned" \
|
|
96
|
+
-o revoke.json
|
|
97
|
+
|
|
98
|
+
# Verify the full chain
|
|
99
|
+
agentcert verify-chain cert.json cert-v2.json revoke.json
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## SDK API
|
|
103
|
+
|
|
104
|
+
All functions are available at the top level — no submodule imports needed.
|
|
105
|
+
|
|
106
|
+
### Keys
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
creator_keys = agentcert.generate_keys()
|
|
110
|
+
agentcert.save_keys(creator_keys, "creator.keys.json")
|
|
111
|
+
creator_keys = agentcert.load_keys("creator.keys.json")
|
|
112
|
+
|
|
113
|
+
# Derive Bitcoin address (for funding anchor transactions)
|
|
114
|
+
address = agentcert.derive_bitcoin_address(creator_keys, network="testnet")
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Certificates
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
cert = agentcert.create_certificate(
|
|
121
|
+
creator_keys=creator_keys,
|
|
122
|
+
agent_keys=agent_keys,
|
|
123
|
+
name="my-agent",
|
|
124
|
+
platform="langchain",
|
|
125
|
+
model_hash="sha256:...",
|
|
126
|
+
capabilities=["task-a", "task-b"],
|
|
127
|
+
constraints=["spending-limit-1000"],
|
|
128
|
+
risk_tier=2,
|
|
129
|
+
expires_days=90,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
agentcert.save_certificate(cert, "agent.cert.json")
|
|
133
|
+
cert = agentcert.load_certificate("agent.cert.json")
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Verification
|
|
137
|
+
|
|
138
|
+
The verifier runs 6 checks (all must pass for `VALID`):
|
|
139
|
+
|
|
140
|
+
1. **cert_id integrity** — SHA-256(body) matches cert_id
|
|
141
|
+
2. **creator_id derivation** — SHA-256(creator_public_key) matches creator_id
|
|
142
|
+
3. **agent_id derivation** — SHA-256(agent_public_key) matches agent_id
|
|
143
|
+
4. **Creator signature** — ECDSA verification against creator_public_key
|
|
144
|
+
5. **Anchor integrity** — certificate hash matches the anchored hash (if receipt provided)
|
|
145
|
+
6. **Expiration** — current time < expires
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
result = agentcert.verify(cert) # without anchor
|
|
149
|
+
result = agentcert.verify(cert, receipt) # with anchor receipt
|
|
150
|
+
|
|
151
|
+
print(result.status) # "VALID" or "INVALID"
|
|
152
|
+
print(result.valid) # True / False
|
|
153
|
+
|
|
154
|
+
for check in result.checks:
|
|
155
|
+
print(f"[{'PASS' if check.passed else 'FAIL'}] {check.name}: {check.detail}")
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Chain Operations
|
|
159
|
+
|
|
160
|
+
Certificates form a linked chain: create → update → ... → revoke.
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# Update (carries over unchanged fields)
|
|
164
|
+
updated = agentcert.update_certificate(
|
|
165
|
+
previous_cert=cert,
|
|
166
|
+
creator_keys=creator_keys,
|
|
167
|
+
capabilities=["procurement", "negotiation", "invoicing"],
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Revoke (terminates the chain)
|
|
171
|
+
revocation = agentcert.revoke_certificate(
|
|
172
|
+
previous_cert=updated,
|
|
173
|
+
creator_keys=creator_keys,
|
|
174
|
+
reason="Decommissioned",
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Verify the full chain
|
|
178
|
+
chain_result = agentcert.verify_chain([cert, updated, revocation])
|
|
179
|
+
print(chain_result.status) # "REVOKED"
|
|
180
|
+
print(chain_result.valid) # True (REVOKED is a valid terminal state)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Bitcoin Anchoring
|
|
184
|
+
|
|
185
|
+
Anchor a certificate to Bitcoin via an OP_RETURN transaction:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# The creator's Bitcoin address must be funded first
|
|
189
|
+
address = agentcert.derive_bitcoin_address(creator_keys, network="testnet")
|
|
190
|
+
print(f"Fund this address: {address}")
|
|
191
|
+
|
|
192
|
+
# Anchor (builds, signs, and broadcasts a Bitcoin transaction)
|
|
193
|
+
receipt = agentcert.anchor(cert, creator_keys=creator_keys, network="testnet")
|
|
194
|
+
print(receipt.txid)
|
|
195
|
+
|
|
196
|
+
# Save the receipt for later verification
|
|
197
|
+
agentcert.save_receipt(receipt, "receipt.json")
|
|
198
|
+
receipt = agentcert.load_receipt("receipt.json")
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The OP_RETURN payload is 38 bytes:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
[AIT\0] protocol tag (4 bytes)
|
|
205
|
+
[0x01] version (1 byte)
|
|
206
|
+
[0x02] IDENTITY_CERT (1 byte)
|
|
207
|
+
[...] SHA-256 hash (32 bytes)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Certificate Structure
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"ait_version": 1,
|
|
215
|
+
"cert_type": 1,
|
|
216
|
+
"cert_id": "<SHA-256 of body>",
|
|
217
|
+
"timestamp": 1739750000,
|
|
218
|
+
"expires": 1747526000,
|
|
219
|
+
"agent_public_key": "<33-byte compressed public key, hex>",
|
|
220
|
+
"agent_id": "<SHA-256 of agent_public_key>",
|
|
221
|
+
"creator_public_key": "<33-byte compressed public key, hex>",
|
|
222
|
+
"creator_id": "<SHA-256 of creator_public_key>",
|
|
223
|
+
"agent_metadata": {
|
|
224
|
+
"name": "my-agent",
|
|
225
|
+
"model_hash": "sha256:...",
|
|
226
|
+
"platform": "langchain",
|
|
227
|
+
"capabilities": ["procurement", "negotiation"],
|
|
228
|
+
"constraints": ["max-transaction-50000-usd"],
|
|
229
|
+
"risk_tier": 3
|
|
230
|
+
},
|
|
231
|
+
"previous_cert_id": null,
|
|
232
|
+
"creator_signature": "<ECDSA DER signature, hex>"
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
| Field | Description |
|
|
237
|
+
|-------|-------------|
|
|
238
|
+
| `cert_type` | 1 = CREATION, 2 = UPDATE, 3 = REVOCATION |
|
|
239
|
+
| `cert_id` | SHA-256 of the certificate body (all fields except `cert_id` and `creator_signature`) |
|
|
240
|
+
| `creator_signature` | ECDSA/secp256k1 signature over the same body |
|
|
241
|
+
| `previous_cert_id` | Links to the prior certificate in the chain (null for the first) |
|
|
242
|
+
|
|
243
|
+
## How It Works
|
|
244
|
+
|
|
245
|
+
**Signing:** The cert_id and creator_signature are computed over the same canonical JSON body. The cert_id verifies integrity (any tampering changes the hash). The signature verifies authenticity (only the creator's private key can produce it). Both are independently checkable by any third party.
|
|
246
|
+
|
|
247
|
+
**Anchoring:** The anchor hash is SHA-256 of the *complete* certificate (including cert_id and signature). This goes into a Bitcoin OP_RETURN output. If anything is modified after anchoring, the anchor check fails.
|
|
248
|
+
|
|
249
|
+
**Chain verification** checks: each cert's `previous_cert_id` links to the prior cert's `cert_id`, the same creator throughout, valid signatures on every cert, and the final cert's type determines the chain status (ACTIVE or REVOKED).
|
|
250
|
+
|
|
251
|
+
## Development
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
git clone https://github.com/shaleenchauhan/agentcert.git
|
|
255
|
+
cd agentcert
|
|
256
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
257
|
+
pip install -e ".[dev]"
|
|
258
|
+
|
|
259
|
+
# Run tests
|
|
260
|
+
pytest
|
|
261
|
+
|
|
262
|
+
# Run tests with coverage
|
|
263
|
+
pytest --cov=agentcert --cov-report=term-missing
|
|
264
|
+
|
|
265
|
+
# Run examples
|
|
266
|
+
python examples/quickstart.py
|
|
267
|
+
python examples/full_lifecycle.py
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Project Structure
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
agentcert/
|
|
274
|
+
src/agentcert/
|
|
275
|
+
__init__.py # Public API (33 exports, no submodule imports needed)
|
|
276
|
+
keys.py # Key generation, save, load (secp256k1)
|
|
277
|
+
certificate.py # Certificate creation, signing, serialization
|
|
278
|
+
chain.py # Update, revoke, chain verification
|
|
279
|
+
anchor.py # Bitcoin OP_RETURN + Blockstream API
|
|
280
|
+
verify.py # 6-check verification with structured results
|
|
281
|
+
types.py # KeyPair, Certificate, AgentMetadata, etc.
|
|
282
|
+
exceptions.py # Custom exception hierarchy
|
|
283
|
+
cli.py # Click-based CLI (8 commands)
|
|
284
|
+
tests/ # 118 tests, 93% coverage
|
|
285
|
+
examples/ # quickstart.py, full_lifecycle.py
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Technical Decisions
|
|
289
|
+
|
|
290
|
+
| Component | Choice | Rationale |
|
|
291
|
+
|-----------|--------|-----------|
|
|
292
|
+
| Language | Python 3.11+ | AI/ML ecosystem standard |
|
|
293
|
+
| Curve | secp256k1 | Bitcoin-native, same keys for signing and anchoring |
|
|
294
|
+
| Signatures | ECDSA | Proven; Schnorr migration path later |
|
|
295
|
+
| Hashing | SHA-256 | Bitcoin-native |
|
|
296
|
+
| Serialization | JSON (deterministic) | `sort_keys=True, separators=(',',':')` |
|
|
297
|
+
| CLI | Click | Mature, clean subcommand support |
|
|
298
|
+
| Bitcoin API | Blockstream | No auth, free, reliable |
|
|
299
|
+
| Dependencies | 3 runtime | `cryptography`, `requests`, `click` |
|
|
300
|
+
|
|
301
|
+
## License
|
|
302
|
+
|
|
303
|
+
MIT
|