NAC_Blockchain/nac-acc-1643/src/lib.rs

504 lines
14 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// NAC ACC-1643 协议实现
/// 基于GNACS的文档管理与法律披露协议
mod error;
mod types;
pub use error::{Acc1643Error, Result};
pub use types::*;
use sha3::{Digest, Sha3_384};
use std::collections::HashMap;
/// ACC-1643 文档管理协议
#[derive(Debug)]
pub struct Acc1643 {
/// 文档存储doc_id -> AssetDocument
documents: HashMap<String, AssetDocument>,
/// 文档类型索引doc_type -> vec<doc_id>
type_index: HashMap<String, Vec<String>>,
/// 文档Merkle根
documents_root: [u8; 16],
/// 角色权限(简化实现)
roles: HashMap<String, Vec<String>>,
/// 合法文档类型白名单
valid_doc_types: Vec<String>,
}
impl Acc1643 {
/// 创建新的ACC-1643实例
pub fn new() -> Self {
let mut valid_types = Vec::new();
valid_types.push("Prospectus".to_string());
valid_types.push("AuditReport".to_string());
valid_types.push("LegalOpinion".to_string());
valid_types.push("FinancialStatement".to_string());
valid_types.push("ComplianceReport".to_string());
Self {
documents: HashMap::new(),
type_index: HashMap::new(),
documents_root: [0u8; 16],
roles: HashMap::new(),
valid_doc_types: valid_types,
}
}
/// 设置文档(首次上传或更新)
pub fn set_document(
&mut self,
operator: &str,
doc_type: String,
uri: String,
content_hash: [u8; 48],
supersedes: [u8; 48],
receipt_hash: [u8; 32],
) -> Result<[u8; 48]> {
// 检查权限
if !self.has_role("ISSUER", operator) {
return Err(Acc1643Error::Unauthorized {
operator: operator.to_string(),
required_role: "ISSUER".to_string(),
});
}
// 验证文档类型
if !self.valid_doc_types.contains(&doc_type) {
return Err(Acc1643Error::InvalidDocumentType { doc_type });
}
// 验证宪法收据(简化实现)
if receipt_hash == [0u8; 32] {
return Err(Acc1643Error::InvalidConstitutionalReceipt {
receipt_hash: hex::encode(receipt_hash),
});
}
// 计算文档ID
let doc_id = self.calculate_doc_id(&uri, &content_hash, Self::current_timestamp());
let doc_id_hex = hex::encode(doc_id);
// 检查是否已存在
if self.documents.contains_key(&doc_id_hex) {
return Err(Acc1643Error::DocumentAlreadyExists { doc_id: doc_id_hex });
}
// 确定版本号
let version = if supersedes == [0u8; 48] {
1
} else {
let supersedes_hex = hex::encode(supersedes);
if let Some(old_doc) = self.documents.get(&supersedes_hex) {
old_doc.version + 1
} else {
return Err(Acc1643Error::DocumentNotFound {
doc_id: supersedes_hex,
});
}
};
// 创建文档
let document = AssetDocument {
doc_id,
doc_type: doc_type.clone(),
uri,
content_hash,
timestamp: Self::current_timestamp(),
version,
supersedes,
is_active: true,
};
// 存储文档
self.documents.insert(doc_id_hex.clone(), document);
// 更新类型索引
self.type_index
.entry(doc_type)
.or_insert_with(Vec::new)
.push(doc_id_hex);
// 更新Merkle根
self.update_documents_root();
Ok(doc_id)
}
/// 批量设置文档(原子操作)
pub fn set_documents(
&mut self,
operator: &str,
inputs: Vec<DocumentInput>,
receipt_hash: [u8; 32],
) -> Result<Vec<[u8; 48]>> {
let mut doc_ids = Vec::new();
for input in inputs {
let doc_id = self.set_document(
operator,
input.doc_type,
input.uri,
input.content_hash,
input.supersedes,
receipt_hash,
)?;
doc_ids.push(doc_id);
}
Ok(doc_ids)
}
/// 移除文档(标记为无效)
pub fn remove_document(
&mut self,
operator: &str,
doc_id: &[u8; 48],
receipt_hash: [u8; 32],
) -> Result<()> {
// 检查权限
if !self.has_role("ISSUER", operator) {
return Err(Acc1643Error::Unauthorized {
operator: operator.to_string(),
required_role: "ISSUER".to_string(),
});
}
// 验证宪法收据
if receipt_hash == [0u8; 32] {
return Err(Acc1643Error::InvalidConstitutionalReceipt {
receipt_hash: hex::encode(receipt_hash),
});
}
let doc_id_hex = hex::encode(doc_id);
// 查找文档
let document = self.documents.get_mut(&doc_id_hex).ok_or_else(|| {
Acc1643Error::DocumentNotFound {
doc_id: doc_id_hex.clone(),
}
})?;
// 标记为无效
document.is_active = false;
// 更新Merkle根
self.update_documents_root();
Ok(())
}
/// 获取文档详情
pub fn get_document(&self, doc_id: &[u8; 48]) -> Result<AssetDocument> {
let doc_id_hex = hex::encode(doc_id);
self.documents
.get(&doc_id_hex)
.cloned()
.ok_or_else(|| Acc1643Error::DocumentNotFound { doc_id: doc_id_hex })
}
/// 获取指定类型的最新文档
pub fn get_latest_document(&self, doc_type: &str) -> Result<AssetDocument> {
let doc_ids = self.type_index.get(doc_type).ok_or_else(|| {
Acc1643Error::InvalidDocumentType {
doc_type: doc_type.to_string(),
}
})?;
let mut latest: Option<AssetDocument> = None;
for doc_id_hex in doc_ids {
if let Some(doc) = self.documents.get(doc_id_hex) {
if doc.is_active {
if let Some(ref current_latest) = latest {
if doc.version > current_latest.version {
latest = Some(doc.clone());
}
} else {
latest = Some(doc.clone());
}
}
}
}
latest.ok_or_else(|| Acc1643Error::DocumentNotFound {
doc_id: format!("latest of type {}", doc_type),
})
}
/// 获取所有文档ID分页
pub fn get_all_documents(&self, offset: usize, limit: usize) -> Vec<[u8; 48]> {
self.documents
.values()
.skip(offset)
.take(limit)
.map(|doc| doc.doc_id)
.collect()
}
/// 验证文档是否属于资产且未被篡改
pub fn verify_document(
&self,
doc_id: &[u8; 48],
uri: &str,
content_hash: &[u8; 48],
) -> Result<bool> {
let document = self.get_document(doc_id)?;
// 验证URI和内容哈希
if document.uri != uri {
return Ok(false);
}
if &document.content_hash != content_hash {
return Ok(false);
}
// 验证文档ID
let expected_id = self.calculate_doc_id(uri, content_hash, document.timestamp);
if expected_id != *doc_id {
return Ok(false);
}
Ok(true)
}
/// 获取文档Merkle根
pub fn documents_root(&self) -> [u8; 16] {
self.documents_root
}
/// 计算文档IDSHA3-384(uri+contentHash+timestamp)
fn calculate_doc_id(&self, uri: &str, content_hash: &[u8; 48], timestamp: u64) -> [u8; 48] {
let mut hasher = Sha3_384::new();
hasher.update(uri.as_bytes());
hasher.update(content_hash);
hasher.update(&timestamp.to_be_bytes());
let result = hasher.finalize();
let mut doc_id = [0u8; 48];
doc_id.copy_from_slice(&result);
doc_id
}
/// 更新文档Merkle根
fn update_documents_root(&mut self) {
// 简化实现对所有文档ID进行哈希
let mut hasher = Sha3_384::new();
let mut doc_ids: Vec<_> = self.documents.keys().collect();
doc_ids.sort();
for doc_id in doc_ids {
hasher.update(doc_id.as_bytes());
}
let result = hasher.finalize();
self.documents_root[..16].copy_from_slice(&result[..16]);
}
/// 检查角色权限
fn has_role(&self, role: &str, account: &str) -> bool {
if let Some(accounts) = self.roles.get(role) {
accounts.contains(&account.to_string())
} else {
false
}
}
/// 授予角色
pub fn grant_role(&mut self, role: &str, account: &str) {
self.roles
.entry(role.to_string())
.or_insert_with(Vec::new)
.push(account.to_string());
}
/// 获取当前时间戳
fn current_timestamp() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
}
}
impl Default for Acc1643 {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_acc1643() -> Acc1643 {
let mut acc1643 = Acc1643::new();
acc1643.grant_role("ISSUER", "issuer1");
acc1643
}
#[test]
fn test_set_document() {
let mut acc1643 = create_test_acc1643();
let content_hash = [1u8; 48];
let doc_id = acc1643
.set_document(
"issuer1",
"Prospectus".to_string(),
"ipfs://QmTest".to_string(),
content_hash,
[0u8; 48],
[1u8; 32],
)
.unwrap();
let document = acc1643.get_document(&doc_id).unwrap();
assert_eq!(document.doc_type, "Prospectus");
assert_eq!(document.version, 1);
assert!(document.is_active);
}
#[test]
fn test_document_versioning() {
let mut acc1643 = create_test_acc1643();
// 创建第一个版本
let content_hash_v1 = [1u8; 48];
let doc_id_v1 = acc1643
.set_document(
"issuer1",
"Prospectus".to_string(),
"ipfs://QmTest1".to_string(),
content_hash_v1,
[0u8; 48],
[1u8; 32],
)
.unwrap();
// 创建第二个版本
let content_hash_v2 = [2u8; 48];
let doc_id_v2 = acc1643
.set_document(
"issuer1",
"Prospectus".to_string(),
"ipfs://QmTest2".to_string(),
content_hash_v2,
doc_id_v1,
[1u8; 32],
)
.unwrap();
let doc_v2 = acc1643.get_document(&doc_id_v2).unwrap();
assert_eq!(doc_v2.version, 2);
assert_eq!(doc_v2.supersedes, doc_id_v1);
}
#[test]
fn test_remove_document() {
let mut acc1643 = create_test_acc1643();
let content_hash = [1u8; 48];
let doc_id = acc1643
.set_document(
"issuer1",
"Prospectus".to_string(),
"ipfs://QmTest".to_string(),
content_hash,
[0u8; 48],
[1u8; 32],
)
.unwrap();
acc1643.remove_document("issuer1", &doc_id, [1u8; 32]).unwrap();
let document = acc1643.get_document(&doc_id).unwrap();
assert!(!document.is_active);
}
#[test]
fn test_get_latest_document() {
let mut acc1643 = create_test_acc1643();
// 创建多个版本
let doc_id_v1 = acc1643
.set_document(
"issuer1",
"Prospectus".to_string(),
"ipfs://QmTest1".to_string(),
[1u8; 48],
[0u8; 48],
[1u8; 32],
)
.unwrap();
let _doc_id_v2 = acc1643
.set_document(
"issuer1",
"Prospectus".to_string(),
"ipfs://QmTest2".to_string(),
[2u8; 48],
doc_id_v1,
[1u8; 32],
)
.unwrap();
let latest = acc1643.get_latest_document("Prospectus").unwrap();
assert_eq!(latest.version, 2);
}
#[test]
fn test_verify_document() {
let mut acc1643 = create_test_acc1643();
let content_hash = [1u8; 48];
let uri = "ipfs://QmTest".to_string();
let doc_id = acc1643
.set_document(
"issuer1",
"Prospectus".to_string(),
uri.clone(),
content_hash,
[0u8; 48],
[1u8; 32],
)
.unwrap();
let is_valid = acc1643.verify_document(&doc_id, &uri, &content_hash).unwrap();
assert!(is_valid);
// 验证错误的内容哈希
let wrong_hash = [2u8; 48];
let is_valid = acc1643.verify_document(&doc_id, &uri, &wrong_hash).unwrap();
assert!(!is_valid);
}
#[test]
fn test_documents_root_update() {
let mut acc1643 = create_test_acc1643();
let root_before = acc1643.documents_root();
acc1643
.set_document(
"issuer1",
"Prospectus".to_string(),
"ipfs://QmTest".to_string(),
[1u8; 48],
[0u8; 48],
[1u8; 32],
)
.unwrap();
let root_after = acc1643.documents_root();
assert_ne!(root_before, root_after);
}
}