nova-sdk-rs 1.0.2

Lightweight Rust SDK for NOVA: Secure group-based file sharing on NEAR Protocol with Shade/TEE + fees model.
Documentation

NOVA SDK for Rust

Version: 1.0.1 (Mainnet)
License: MIT
Network: NEAR Protocol Mainnet Crates: nova-sdk-rs

A Rust SDK for NOVA's secure, decentralized file-sharing primitive on NEAR. NOVA hybridizes on-chain access control with off-chain TEE-secured keys via Shade Agents, using nonce-based ed25519-signed tokens for ephemeral, verifiable access. This ensures privacy-first data sharing for AI datasets, healthcare/financial records, and sensitive documents.

Features

  • šŸ” Zero-Knowledge Architecture - Keys managed in TEE; never exposed to SDK
  • 🌐 IPFS Storage - Decentralized file storage via Pinata
  • ā›“ļø NEAR Blockchain - Immutable access control & transaction logs
  • šŸ›”ļø Session-Based Auth - OAuth flow (no private key handling)
  • šŸ”‘ Automated Signing - MCP server signs transactions using keys from Shade TEE
  • šŸ‘„ Group Management - Fine-grained membership with automatic key rotation on revocation
  • šŸš€ Composite Operations - Simplified workflows for upload/retrieve

Installation

Add to Cargo.toml:

[dependencies]
nova-sdk-rs = "1.0.1"
tokio = { version = "1", features = ["full"] }

āš ļø Mainnet Notice

NOVA v1.0.0 operates on NEAR mainnet by default. All operations consume real NEAR tokens.

Typical costs:

  • Register group: 0.05 NEAR ($0.15 USD)
  • Upload file: ~0.01 NEAR + IPFS storage
  • Retrieve file: ~0.001 NEAR

For development, use testnet configuration.

Quick Start

1. Prerequisites

  1. Create a NOVA account at nova-sdk.com
  2. Fund your account with NEAR tokens for transaction fees

2. Basic Usage

use nova_sdk_rs::NovaSdk;
use std::fs;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize SDK - automatic token management!
    // Just provide your account ID, SDK handles authentication
    let sdk = NovaSdk::new("alice.nova-sdk.near")?;

    // For testnet development:
    // let sdk = NovaSdk::testnet("alice.nova-sdk-5.testnet")?;

    // Verify connection
    println!("Network: {} | Contract: {}", sdk.network_id(), sdk.contract_id());

    // Register group
    sdk.register_group("my-secure-files").await?;

    // Upload file (client-side encryption)
    let file_data = fs::read("./confidential.pdf")?;
    let result = sdk.upload(
        "my-secure-files",
        &file_data,
        "confidential.pdf"
    ).await?;

    println!("āœ… Uploaded: {}", result.cid);
    println!("šŸ“ Transaction: {}", result.trans_id);

    // Retrieve file (client-side decryption)
    let retrieved = sdk.retrieve(
        "my-secure-files",
        &result.cid
    ).await?;

    fs::write("./decrypted.pdf", &retrieved.data)?;
    println!("āœ… Decrypted!");

    Ok(())
}

Core Concepts

Groups

Groups manage shared access to encrypted files. Each group has:

  • A unique identifier (group_id)
  • An owner who manages membership
  • A shared encryption key stored off-chain in Shade Agent/TEE (never stored publicly).
  • A list of authorized members

Access Control (Ephemeral Tokens)

NOVA uses signed tokens for key access:

  • Generate payload (group_id/user_id/nonce/timestamp/signing_pk_b58).
  • Sign with ed25519 (from account keypair).
  • Claim on-chain (claim_token): Verifies sig/membership/nonce (5min window), returns token.
  • Present to Shade: TEE decrypts key, verifies checksum, responds transiently.

Encryption

All data is encrypted client-side using AES-256-GCM:

  • 256-bit symmetric keys (retrieved from Shade TEE)
  • 12-byte random IV per encryption
  • Authenticated encryption with integrity verification
  • SHA256 hashing for file integrity
  • Keys never leave the client unencrypted

Transaction Recording

File metadata (CID/hash) is recorded on-chain automatically during composite_upload.

// Query group transactions
let txs = sdk.get_transactions_for_group("my_group", None).await?;
for tx in txs {
    println!("File: {} | IPFS: {}", tx.file_hash, tx.ipfs_hash);
}

Authentication

The SDK handles session tokens automatically:

  1. Automatic fetching - On first API call, SDK fetches a token from nova-sdk.com
  2. Automatic refresh - Tokens are cached and refreshed before expiry (24h validity)
  3. Manual refresh - Call sdk.refresh_token().await? if you encounter auth errors
// SDK fetches token automatically on first use
let sdk = NovaSdk::new("alice.nova-sdk.near")?;

// Or provide a pre-fetched token
let config = NovaSdkConfig::default().with_token("your-token-here");
let sdk = NovaSdk::with_config("alice.nova-sdk.near", config)?;

// Force refresh if needed
sdk.refresh_token().await?;

API Reference

Initialization

// Simplest - automatic token management (mainnet)
let sdk = NovaSdk::new("alice.nova-sdk.near")?;

// Testnet
let sdk = NovaSdk::testnet("alice.nova-sdk-5.testnet")?;

// Custom config
use nova_sdk_rs::NovaSdkConfig;

let config = NovaSdkConfig::default()
    .with_token("pre-fetched-token");  // Optional: provide your own token
let sdk = NovaSdk::with_config("alice.nova-sdk.near", config)?;

// Force token refresh if needed
sdk.refresh_token().await?;

Group Management

// Check authorization
sdk.auth_status(Some("my-group")).await?;

// Register group
sdk.register_group("my-group").await?;

// Add member
sdk.add_group_member("my-group", "bob.near").await?;

// Revoke member
sdk.revoke_group_member("my-group", "bob.near").await?;

File Operations

// Upload (encrypts locally, uploads to IPFS, records on NEAR)
let result = sdk.upload(group_id, &data, filename).await?;
// Returns: UploadResult { cid, trans_id, file_hash }

// Retrieve (fetches from IPFS, decrypts locally)
let retrieved = sdk.retrieve(group_id, ipfs_hash).await?;
// Returns: RetrieveResult { data, ipfs_hash, group_id }

Deprecated methods (still work, but emit warnings):

// Use upload() instead
sdk.composite_upload(group_id, &data, filename).await?;

// Use retrieve() instead  
sdk.composite_retrieve(group_id, ipfs_hash).await?;

Error Handling

The SDK uses a custom NovaError enum:

use nova_sdk_rs::NovaError;

match sdk.upload("my_group", b"data", "file.txt").await {
    Ok(result) => println!("CID: {}", result.cid),
    Err(NovaError::Near(msg)) => eprintln!("RPC error: {}", msg),
    Err(NovaError::Mcp(msg)) => eprintln!("MCP server error: {}", msg),
    Err(NovaError::Auth(msg)) => eprintln!("Authentication error: {}", msg),
    Err(NovaError::Token(msg)) => eprintln!("Token error: {}", msg),
    Err(NovaError::InvalidCid(cid)) => eprintln!("Invalid CID: {}", cid),
    Err(NovaError::ParseAccount) => eprintln!("Invalid account ID"),
    Err(NovaError::Http(msg)) => eprintln!("HTTP error: {}", msg),
    Err(NovaError::Encryption(msg)) => eprintln!("Encryption error: {}", msg),
    Err(NovaError::Decryption(msg)) => eprintln!("Decryption error: {}", msg),

šŸ” Security Considerations

  1. Never commit session tokens - Use environment variables
  2. Verify network - Check sdk.network_id() before operations
  3. Validate file hashes - Compare after retrieval
  4. Use TLS - Always connect over secure connections
  5. Rotate tokens - Refresh JWT tokens regularly
  6. Client-side encryption - Keys are fetched from TEE and used locally; encrypted data travels separately from keys

Examples

See the examples directory for complete working examples:

  • simple_upload.rs - Basic file upload
  • group_management.rs - Managing groups and members

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass (cargo test)
  5. Submit a pull request

License

MIT LICENSE - Copyright (c) 2026 CivicTech OÜ

Resources

Support