NOVA SDK for Rust
A Rust SDK for interacting with NOVA secure file-sharing on NEAR blockchain. Provides encrypted, decentralized file storage using IPFS and NEAR smart contracts with group-based access control.
Features
🔐 AES-256-CBC Encryption - Client-side encryption for data privacy
🌐 IPFS Storage - Decentralized file storage via Pinata
⛓️ NEAR Blockchain - Immutable transaction records and access control
👥 Group Management - Fine-grained access control with member authorization
🔑 Key Rotation - Automatic key rotation on member revocation
🚀 Composite Operations - Simplified high-level workflows
Installation
Add to your Cargo.toml
:
[dependencies]
nova-sdk-rs = "0.1.0"
tokio = { version = "1", features = ["full"] }
Quick Start
use nova_sdk_rs::{NovaSdk, CompositeUploadResult};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize SDK
let sdk = NovaSdk::new(
"https://rpc.testnet.near.org",
"nova-contract.testnet",
"your_pinata_api_key",
"your_pinata_secret_key"
).with_signer(
"ed25519:your_private_key",
"your-account.testnet"
)?;
// Upload encrypted file
let result = sdk.composite_upload(
"project_alpha", // group_id
"alice.testnet", // user_id
"Confidential data", // data
"report.txt" // filename
).await?;
println!("✅ Uploaded to IPFS: {}", result.cid);
println!("📝 Transaction ID: {}", result.trans_id);
println!("🔒 File Hash: {}", result.file_hash);
// Retrieve and decrypt file
let retrieved = sdk.composite_retrieve(
"project_alpha",
&result.cid
).await?;
let decrypted = base64::engine::general_purpose::STANDARD
.decode(&retrieved.decrypted_b64)?;
let content = String::from_utf8(decrypted)?;
println!("📄 Content: {}", content);
Ok(())
}
Core Concepts
Groups
Groups provide isolated access control domains. Each group has:
A unique identifier (
group_id
)An owner who manages membership
A shared encryption key
A list of authorized members
Access Control
// Register new group (owner only)
sdk.register_group("secure_vault").await?;
// Add members
sdk.add_group_member("secure_vault", "bob.testnet").await?;
// Check authorization
let authorized = sdk.is_authorized("secure_vault", "bob.testnet").await?;
// Revoke member (automatically rotates key)
sdk.revoke_group_member("secure_vault", "bob.testnet").await?;
Encryption
All data is encrypted client-side using AES-256-CBC:
256-bit symmetric keys
Random IV per encryption
PKCS7 padding
Keys stored encrypted on blockchain
Transaction Recording
Every file operation creates an immutable blockchain record:
let trans_id = sdk.record_transaction(
"my_group",
"alice.testnet",
"file_hash_sha256",
"QmIPFSHash"
).await?;
// Query group transactions
let txs = sdk.get_transactions_for_group("my_group", "alice.testnet").await?;
API Overview
Initialization
NovaSdk::new()
- Create SDK instancewith_signer()
- Attach NEAR account credentials
Group Management
register_group()
- Create new groupadd_group_member()
- Grant access to userrevoke_group_member()
- Revoke access and rotate keyis_authorized()
- Check user authorization
Key Management
store_group_key()
- Store encryption keyget_group_key()
- Retrieve key (authorized users only)
File Operations
composite_upload()
- Encrypt, upload to IPFS, record transactioncomposite_retrieve()
- Fetch from IPFS, decryptrecord_transaction()
- Record file metadata on blockchainget_transactions_for_group()
- Query transaction history
Utilities
get_balance()
- Check NEAR account balancetransfer_tokens()
- Transfer NEAR tokens
Environment Setup
For testing and development, set these environment variables:
# Required for integration tests
TEST_NEAR_ACCOUNT_ID=your-account.testnet
TEST_NEAR_PRIVATE_KEY=ed25519:your_private_key
PINATA_API_KEY=your_pinata_key
PINATA_SECRET_KEY=your_pinata_secret
Create a .env
file:
TEST_NEAR_ACCOUNT_ID=alice.testnet
TEST_NEAR_PRIVATE_KEY=ed25519:...
PINATA_API_KEY=...
PINATA_SECRET_KEY=...
Testing
# Run unit tests
cargo test
# Run with integration tests (requires .env setup)
cargo test -- --include-ignored
# Run specific test
cargo test test_composite_upload
Error Handling
The SDK uses a custom NovaError
enum:
use nova_sdk_rs::NovaError;
match sdk.get_group_key("my_group", "user.testnet").await {
Ok(key) => println!("Key: {}", key),
Err(NovaError::Near(msg)) => eprintln!("RPC error: {}", msg),
Err(NovaError::InvalidKey) => eprintln!("Invalid encryption key"),
Err(NovaError::ParseAccount) => eprintln!("Invalid account ID"),
Err(NovaError::Signing(msg)) => eprintln!("Signing failed: {}", msg),
}
Security Considerations
⚠️ Important Security Notes:
Private Keys - Never commit private keys to version control
Key Storage - Store encryption keys securely
IPFS Privacy - IPFS content is public; encryption is essential
Access Control - Verify user authorization before operations
Key Rotation - Revoked members cannot decrypt new content
Examples
See the examples directory for complete working examples:
simple_upload.rs
- Basic file upload/downloadgroup_management.rs
- Managing groups and memberskey_rotation.rs
- Handling member revocation
Contributing
Contributions are welcome! Please:
Fork the repository
Create a feature branch
Add tests for new functionality
Ensure all tests pass (
cargo test
)Submit a pull request
License
This project is licensed under the MIT License - see LICENSE file for details.
Resources
Support
Issues: GitHub Issues
Discussions: GitHub Discussions
Last updated