./research / verifiable-audit-layer
Một lớp kiểm toán có thể xác minh cho AI.
Một lớp kiểm toán để lộ dấu vết can thiệp cho suy luận mô hình và thực thi tác nhân: tuần tự hóa chuẩn tắc, băm tách miền, chữ ký DSSE, một Merkle DAG cho mỗi lần chạy, và một Merkle Mountain Range xuyên các lần chạy chứng minh không lần chạy nào bị xóa. Mỗi nguyên thủy được chọn từ một phép đo điểm chuẩn đối đầu với các phương án thật, với dữ liệu thô được commit. Ghi chú này chính là thiết kế và các thí nghiệm đằng sau nó.
Mô hình mối đe dọa
Chúng tôi giả định một đối thủ kiểm soát bộ nhớ lưu trữ và có thể viết lại các bản ghi sau khi việc đã rồi, kể cả người vận hành đã tạo ra chúng. Mục tiêu là mọi chỉnh sửa lên một lần chạy đã niêm phong đều phát hiện được, bản ghi vẫn xác minh được suốt một kỳ lưu giữ đo bằng năm, và việc xác minh không để lộ bất kỳ đầu vào riêng tư nào. Hai tính chất được giữ tách biệt xuyên suốt: tính toàn vẹn của một lần chạy đơn lẻ, và tính đầy đủ của tập các lần chạy. Một biên nhận cho mỗi lần chạy cho cái đầu và chẳng nói gì về cái sau, nên cả hai được thiết kế riêng.
Mỗi lựa chọn dưới đây được đưa ra theo cùng một cách. Chúng tôi không khẳng định một nguyên thủy là tốt nhất; chúng tôi đo nó với các phương án đáng tin trên cùng một máy và commit dữ liệu thô, để bất kỳ con số nào ở đây đều tái lập bằng một lệnh. Thời gian là nhanh nhất trong nhiều lần chạy sau khi loại bỏ giai đoạn khởi động, giữ lại trung bình và độ lệch chuẩn để một phép đo bất ổn được đánh dấu thay vì bị giấu. Các con số đến từ một máy chủ AMD64 duy nhất trên CPython 3.14 và có ý nghĩa như tỉ lệ, không phải giá trị tuyệt đối.
Thí nghiệm và kết quả
Mỗi cột mốc là một phép thử đối đầu với các phương án thật, không phải một phép đo đơn lẻ. Tổng quan ở dưới; kết quả chi tiết của từng cái nằm ở các mục tiếp theo.
| Cột mốc | Đo với | Kết quả |
|---|---|---|
| Dạng chuẩn tắc | JSON ngây thơ, CBOR | JCS, giống nhau từng byte, ~3x chi phí |
| Băm | SHA-256, BLAKE3, keccak-256 | keccak bản địa 17x, cùng byte |
| Lõi bản địa | backend pip vs Rust | niêm phong 6x, gốc giống nhau từng byte |
| Chữ ký | ECDSA, BLS, ML-DSA | Ed25519, 64 B, tất định |
| Hậu lượng tử | ML-DSA 44 / 65 / 87 | theo giai đoạn, xác minh ngang bằng, 38x kích thước |
| Vết mỗi lần chạy | 8 kiểu tấn công giả mạo, chi phí phụ | tất cả bị bắt, ~121 us / sự kiện |
| Nhật ký xuyên lần chạy | dựng lại Merkle thường | MMR, thêm phẳng, 483x |
Tuần tự hóa chuẩn tắc
Một viên nang phải băm ra cùng những byte trong lõi Python của chúng tôi, trong client TypeScript của chúng tôi, và trong công cụ riêng của một kiểm toán viên, nếu không một bản ghi hợp lệ sẽ xác minh thất bại. Chúng tôi dùng RFC 8785 (JSON Canonicalization Scheme), vốn cố định định dạng số, thứ tự khóa theo đơn vị mã UTF-16, và việc từ chối các giá trị không hữu hạn. Chúng tôi thử nó với JSON sắp khóa ngây thơ và với CBOR.
| Cách tiếp cận | Python vs Node | Chi phí |
|---|---|---|
| JSON sắp xếp ngây thơ | phân kỳ ở Unicode và số | mốc gốc |
| RFC 8785 JCS | giống nhau từng byte | khoảng 3x khi tuần tự hóa |
| CBOR | nhị phân, cần bộ giải mã để đọc | gọn |
JSON ngây thơ phân kỳ giữa các runtime ở thứ tự Unicode và định dạng số, nên âm thầm phá vỡ xác minh xuyên ngôn ngữ. JCS giống nhau từng byte ở cả hai, ở khoảng 3x thời gian tuần tự hóa, trả một lần mỗi lần băm và không đáng kể so với việc băm và công việc mạng xung quanh. Chúng tôi giữ đúng một bản hiện thực của nó. Khi module bản địa của chúng tôi mang theo bộ tuần tự hóa JSON riêng, chúng tôi gỡ nó đi, bởi một bộ chuẩn tắc hóa thứ hai đồng thuận trên đầu vào thường và phân kỳ trên các ca biên mà đối thủ có thể chọn thì tệ hơn là không có.
Băm và lõi bản địa
Lá được băm bằng BLAKE3 và nút Merkle bằng keccak-256, cả hai với tách miền RFC 6962 (tiền tố khác nhau cho lá và nút trong) để đóng lớp tiền ảnh thứ hai, nơi một nút trong được trình ra như một lá. keccak-256 không phải SHA3-256; hai cái chia sẻ một hoán vị nhưng khác nhau ở một byte đệm, và bộ xác minh on-chain nói keccak, nên một sự thay thế âm thầm sẽ khiến mọi gốc thất bại on-chain. Vì vậy lớp băm tính toán thuật toán được yêu cầu hoặc ném lỗi, không bao giờ là kẻ giống hệt, và ghi thuật toán trong mỗi viên nang để một bộ xác minh tái lập đúng hàm thay vì suy ra nó từ thứ được cài đặt cục bộ.
| Nguyên thủy, đầu vào 64 B | Thông lượng | Ghi chú |
|---|---|---|
| SHA-256 (stdlib) | 1,50M ops/s | mốc gốc, luôn có |
| BLAKE3 (pip) | 1,44M ops/s | ngang với SHA-256 |
| keccak-256 (pip) | 99k ops/s | chậm 15x, nút thắt cổ chai |
| keccak-256 (lõi Rust) | 1,69M ops/s | nhanh hơn pip 17x |
keccak không có bản hiện thực trong thư viện chuẩn, và chính điều đó khiến module bản địa đáng để dựng. Khoảng cách rộng nhất ở đầu vào cỡ một sự kiện vì chi phí của pycryptodome ở đó là cấp phát đối tượng mỗi lần gọi chứ không phải băm, đúng cỡ mà một vết kiểm toán băm nhiều nhất; từ đầu đến cuối, lõi bản địa nâng việc niêm phong một lần chạy 1000 sự kiện từ 78 lên 491 niêm phong mỗi giây, khoảng 6x. Điều then chốt: bật bộ tăng tốc không thể thay đổi kết quả: niêm phong cùng một lần chạy có và không có crate cho ra một gốc giống nhau từng bit, một bộ kiểm thử tuân thủ đối chiếu cả hai đường với các vector do tác giả thuật toán công bố, và CI dựng một wheel ABI ổn định (abi3) duy nhất và xác minh một hiện vật đó trên mọi Python từ 3.10 đến 3.14. Cài nó thay đổi tốc độ và không gì khác.
Chữ ký cho một bản ghi kéo dài một thập kỷ
Một chữ ký trên bản ghi kiểm toán phải giữ được chừng nào bản ghi còn có thể bị tranh chấp, và nghĩa vụ ghi nhật ký AI nay đang tiến tới một thập kỷ. Nếu sơ đồ vỡ khi một bản ghi còn trong cửa sổ lưu giữ, một đối thủ có thể giả mạo và ghi lùi ngày nó, nên toàn bộ kho lưu trữ hỏng cùng lúc. Chúng tôi đo Ed25519 với ECDSA, BLS, và họ hậu lượng tử NIST ML-DSA, trên thông lượng và kích thước.
| Sơ đồ | Xác minh (ops/s) | Kích thước chữ ký |
|---|---|---|
| ECDSA P-256 | 16 887 | ~72 B |
| ML-DSA-44 (hậu lượng tử) | 10 725 | 2420 B |
| Ed25519 | 10 375 | 64 B |
| BLS12-381 | chỉ bản hiện thực tham chiếu | 96 B, gộp được |
Hai kết quả lật đổ các giả định chúng tôi mang theo, và chúng tôi giữ cả hai trong hồ sơ. Ed25519 không phải nhanh nhất để xác minh: ECDSA P-256 đo nhanh hơn khoảng 1,6x, trên assembly thư viện đã tối ưu. Ed25519 vẫn là mặc định về kích thước chữ ký và về tính tất định (RFC 8032), vốn loại bỏ lỗi tái dùng nonce của ECDSA làm rò khóa riêng trong khi chữ ký vẫn xác minh được. Và chữ ký hậu lượng tử không chậm khi xác minh: ML-DSA-44 nhỉnh hơn Ed25519, chi phí của nó nằm ở ký (chậm khoảng 13x) và kích thước (khoảng 38x byte). Vì một vết được ký một lần và xác minh trong nhiều năm, phía đắt đỏ là phía chúng tôi làm ít nhất. BLS bị loại vì một yêu cầu, không phải vì một con số: việc gộp co nhiều chữ ký thành 96 byte, nhưng một gộp xác minh theo kiểu tất-cả-hoặc-không và cần mọi khóa và thông điệp, điều này không tương thích với việc tiết lộ một nhánh của một quyết định mà không để lộ phần còn lại.
Cách đóng khung lại quan trọng: chữ ký không bí mật, nên "thu hoạch bây giờ, giải mã sau" không áp dụng, và mối đe dọa thật là giả mạo hồi tố trong cửa sổ lưu giữ. Neo một gốc vào một sổ cái công khai chứng minh khi nào một bản ghi tồn tại, độc lập với sơ đồ chữ ký, nên một khóa vỡ làm mất khả năng chứng minh ai đã niêm phong một bản ghi nhưng không mất khi nào hay cái gì. Vì thế việc neo nằm trên đường tới hạn và ML-DSA được xếp theo giai đoạn phía sau nó, với phong bì DSSE giữ linh hoạt về thuật toán và thuật toán được ghi theo từng viên nang.
Vết kiểm toán mỗi lần chạy
Mỗi lần chạy là một chuỗi sự kiện chỉ-thêm và móc-xích-bằng-băm (gọi LLM, gọi công cụ, truy hồi, sinh tác nhân con, phê duyệt của con người, quyết định của lan can bảo vệ), với một gốc Merkle trên toàn bộ và một chữ ký DSSE trên gốc. Chỉ các băm của đầu vào và đầu ra được lưu, không bao giờ là tải trọng, nên vết bảo toàn quyền riêng tư theo mặc định. Bộ xác minh không chỉ trả về hợp lệ hay không hợp lệ; nó gọi tên đảm bảo đã vỡ.
| Thao tác (lần chạy 102 sự kiện) | Chi phí | Mở rộng theo quy mô |
|---|---|---|
| Ghi một sự kiện | ~121 us | phẳng, dưới 0,01% một bước |
| Niêm phong, dựng gốc | 0,15 ms | tuyến tính theo sự kiện |
| Xác minh, tính lại mọi lá | 9,2 ms | tuyến tính, khoảng 60x niêm phong |
Ghi là chưa tới một phần trăm của một phần trăm một bước tác nhân điển hình, vốn bị chi phối bởi vòng khứ hồi tới mô hình, nên chi phí phụ không phải lý do để lấy mẫu và vết vẫn đầy đủ thay vì thống kê. Xác minh nặng hơn niêm phong nhiều vì nó tính lại mỗi lá từ nội dung trong khi niêm phong chỉ dựng cây trên các băm đã có sẵn. Sự bất đối xứng đó là đúng cho một vết kiểm toán, nơi ghi là hằng số và xác minh thì hiếm, và nó đánh dấu tái xác minh hàng loạt là nơi lõi bản địa và song song sinh lợi kế tiếp. Để làm các đảm bảo trở nên cụ thể, một demo tấn công một lần chạy đã niêm phong bằng tám cách, mỗi cách bị từ chối với một lý do cụ thể:
| Tấn công | Bị từ chối như |
|---|---|
| Viết lại một đầu ra mô hình | lệch băm lá |
| Xóa hoặc chèn một sự kiện | lệch số đếm sự kiện |
| Sắp lại thứ tự sự kiện | đứt xích |
| Cắt cụt lần chạy | lệch đầu xích |
| Hạ cấp thuật toán băm | lệch băm lá |
| Trình dưới khóa sai | chữ ký không xác minh được |
Nhật ký minh bạch xuyên lần chạy
Một viên nang mỗi lần chạy hợp lệ không thể chứng minh tập các lần chạy là đầy đủ. Một người vận hành bỏ đi một lần chạy bất tiện nắm trong tay một bộ sưu tập những viên nang từng cái hoàn hảo và một lịch sử có lỗ hổng. Chúng tôi bịt điều đó bằng một nhật ký chỉ-thêm duy nhất chứa các gốc viên nang, hỗ trợ chứng minh bao hàm (một lần chạy có trong nhật ký) và chứng minh nhất quán (nhật ký ở một kích thước sớm hơn là tiền tố chính xác của nhật ký hiện tại). Tính nhất quán bắt được kiểm duyệt: một nhật ký được dựng lại với một lần chạy bị gỡ thì bên trong vẫn đúng dạng và mỗi viên nang sống sót vẫn xác minh được, nhưng nó trượt một phép kiểm nhất quán đối với gốc đã công bố trước đó, và cùng phép kiểm đó từ chối một chèn ghi lùi ngày. Điều này chỉ hiệu quả đối với một gốc được commit trước khi can thiệp, nên gốc đó phải sống ở nơi mà người vận hành không thể sửa lại, chẳng hạn một điểm neo công khai.
Chúng tôi dùng một Merkle Mountain Range thay vì một cây Merkle thường vì một lần thêm chỉ bổ sung nút và không bao giờ viết lại nút nào, điều này để nhật ký sống trên bộ lưu ghi-một-lần hoặc lưu đối tượng và giữ các chứng minh bao hàm cũ vẫn hợp lệ khi nhật ký lớn lên. Tính chất đó gần tối ưu, không chỉ tiện: ePrint 2025/234 chứng minh rằng mọi cam kết chỉ-thêm cô đọng đều buộc phải gây ra số cập nhật nhân chứng siêu tuyến tính, và một biến thể MMR gần đó về cơ bản đạt tới cận.
| Kích thước nhật ký | Dựng MMR | Dựng lại thường |
|---|---|---|
| 500 | 1,3 ms | 158 ms (120x) |
| 1000 | 2,6 ms | 618 ms (237x) |
| 2000 | 5,2 ms | 2491 ms (483x) |
Việc thêm giữ phẳng khi nhật ký lớn lên (khoảng 390k lần thêm mỗi giây ở cả 100 lẫn 10 000 mục) trong khi dựng lại một cây thường tụt từ 8176 xuống 84 gốc mỗi giây trên cùng khoảng, chữ ký bậc-hai-đối-đầu-tuyến-tính-loga. Lưu trữ ổn định ở 2,00 băm được lưu mỗi mục và chứng minh bao hàm chỉ tăng từ 7 lên 17 bước giữa 100 và 100 000 mục. Chỗ chúng tôi thua: chứng minh nhất quán của chúng tôi là O(log^2 n), mang một đường cho mỗi đỉnh của nhật ký cũ thay vì O(log n) đạt được, vài kilobyte ở 100 000 mục và một đánh đổi có chủ ý để lấy một cấu trúc mà người rà soát có thể kiểm bằng cách đọc.
Những giới hạn chúng tôi không vượt qua
Băm cho bằng chứng can thiệp, không phải khả năng chống can thiệp. Một đối thủ dựng lại một lần chạy và tính lại gốc của nó tạo ra một bản ghi tự nhất quán, vì một gốc Merkle chứng minh các sự kiện khớp với gốc, chứ không phải gốc đó là gốc đã được công bố. Chữ ký bắt được điều đó, và điểm neo công khai chứng minh thời điểm. Nhật ký minh bạch, ở tầm lớn, dựa trên cùng một giả định: nó chỉ phát hiện một lần chạy bị xóa tương đối với một gốc được commit trước khi xóa. Chúng tôi nêu các ranh giới này trong sản phẩm và các demo của nó, và một bài kiểm khẳng định rằng demo giả mạo vẫn tiếp tục cho thấy cuộc tấn công mà chúng tôi không chặn, để trường hợp trung thực không thể lặng lẽ biến mất.
Khả năng tái lập
Mỗi con số ở đây đến từ một phép đo điểm chuẩn được commit, chạy lại trong một lệnh, bên cạnh các bài kiểm, các bộ tuân thủ xuyên ngôn ngữ và xuyên hiện thực, và ma trận CI vận hành Python 3.10 đến 3.14 có và không có lõi bản địa. Phương pháp luận, JSON thô, và các ghi chú quyết định (kể cả các chiều mà mỗi lựa chọn thua) đều ở trong kho, bởi một lớp làm cho AI có thể kiểm toán thì tự nó cũng phải kiểm toán được.