NERO
Security & Recovery

Security Model

Cryptographic primitives, share exchange encryption, threat model, and security guarantees of the NERO MPC SDK

Security Model

Trust Assumptions

The NERO MPC SDK operates under a cooperative threshold security model:

  • Client + Server cooperation required: Both parties must participate in signing. A compromised server alone cannot steal funds.
  • Client-side encryption: Key shares are encrypted with a device-specific key using AES-256-GCM. Physical device access alone is insufficient without the encrypted share.
  • Backend integrity: The backend must correctly execute MPC protocol rounds. The cryptographic protocol provides verification of correct execution through proofs of knowledge and VSSS commitments.
  • Key isolation: The full private key is never reconstructed during normal signing operations in either protocol.

Threat Mitigation

ThreatMitigation
Server compromiseServer holds only one share — insufficient to sign alone
Client device theftKey shares encrypted with AES-256-GCM device key
Network interceptionAll communication over HTTPS/WSS; share exchange uses ECIES encryption
Session hijackingTokens encrypted at rest, auto-refresh with device binding
Key reconstructionPrivate key is never assembled on any single device
Share tamperingAES-GCM 128-bit authentication tags prevent modification
Protocol manipulationSchnorr proofs (DKLS) and VSSS commitments (Pedersen) verify correct execution

Cryptographic Primitives

The SDK implements foundational cryptographic operations for browser environments, leveraging the @noble/hashes library and Web Crypto API. All primitives are exported from src/core/crypto-primitives.ts.

Encryption Functions

FunctionPurposeAlgorithmOutput
encryptWithPasswordEncrypt using user passwordPBKDF2 + AES-GCMEncryptionResult
decryptWithPasswordDecrypt password-encrypted dataPBKDF2 + AES-GCMstring (UTF-8)
encryptWithKeyEncrypt using existing CryptoKeyAES-GCM{ ciphertext, iv }
decryptWithKeyDecrypt using existing CryptoKeyAES-GCMstring (UTF-8)

Key Derivation Functions

deriveKeyFromPassword — Derives a CryptoKey from a password using PBKDF2-HMAC-SHA256:

ParameterValue
Iterations100,000
Salt length16 bytes
AlgorithmPBKDF2 with SHA-256
TargetAES-GCM 256-bit key

deriveKeyFromDeviceInfo — Creates deterministic keys from a combination of deviceId and userId, binding keys to specific user sessions on particular devices:

  1. Concatenate deviceId and userId with a colon delimiter
  2. Compute SHA-256 hash of the combined string
  3. Import the resulting hash as a raw AES-GCM 256-bit key

Hashing and Commitment Functions

hashSha256 — Computes SHA-256 hash returning a hexadecimal string. Handles both UTF-8 strings and Uint8Array inputs.

computeCommitment — Commitment scheme for MPC protocols (including Pedersen DKG) to commit to values before revelation. Logic: hashSha256("${value}:${blinding}").

Address Derivation

deriveEOAAddress — Derives standard Ethereum (EOA) addresses from uncompressed secp256k1 public keys:

  1. Accepts public keys with or without 0x or 04 prefixes
  2. Validates public key length
  3. Returns a 42-character hex string starting with 0x

checksumAddress — Implements EIP-55 mixed-case checksumming to prevent transcription errors.

Share Exchange Encryption

During Distributed Key Generation (DKG), parties exchange secret polynomial shares using an ECIES-based encryption scheme combining ECDH key agreement with AES-256-GCM authenticated encryption.

EncryptedShare Structure

FieldTypeDescription
fromPartyIdnumberIdentifier of the creating party
toPartyIdnumberIdentifier of the intended recipient
ephemeralPublicKeystringHex-encoded compressed secp256k1 public key for ECDH
ciphertextstringHex-encoded AES-GCM encrypted share data
noncestringHex-encoded 12-byte random nonce for AES-GCM
tagstringHex-encoded 16-byte authentication tag from AES-GCM

ECDH Key Agreement

The deriveSharedSecret function performs three steps:

  1. ECDH point multiplication: Multiply the recipient's public key point by the sender's private scalar
  2. Extract x-coordinate: Extract the x-coordinate from the resulting elliptic curve point
  3. HKDF key derivation: Derive a 32-byte encryption key using HKDF-SHA256 with context string "nero-mpc:ecdh:share-exchange"

The context string ensures that keys derived for share exchange cannot be reused elsewhere, even if the same ECDH point appears in different contexts.

Ephemeral Key Pairs

Each party generates a fresh ephemeral secp256k1 key pair for every DKG session using crypto.getRandomValues(). The function ensures the resulting scalar is non-zero and within the secp256k1 curve order. The public key is encoded in compressed format (33 bytes). Ephemeral keys are discarded after the DKG completes.

Encryption Process (encryptShare)

  1. Generate a new ephemeral private key using generateSecureScalar()
  2. Compute the ephemeral public key by multiplying the secp256k1 base point
  3. Derive a shared secret using ECDH with the ephemeral private key and recipient's public key
  4. Generate a random 12-byte nonce
  5. Serialize the bigint share to hex string, then to UTF-8 bytes
  6. Encrypt using aesGcmEncrypt with the shared secret as key
  7. Package all components in the EncryptedShare structure

Decryption Process (decryptShare)

  1. Derive the shared secret using ECDH with the recipient's private key and sender's ephemeral public key
  2. Extract ciphertext, nonce, and tag from hex strings
  3. Decrypt and verify authenticity using aesGcmDecrypt (Web Crypto API automatically verifies the authentication tag)
  4. Convert UTF-8 plaintext to hex string, then parse to bigint via hexToScalar

AES-GCM Operations

aesGcmEncrypt:

  1. Import the 32-byte shared secret as an AES-GCM key using Web Crypto API
  2. Generate a random 12-byte nonce
  3. Encrypt the plaintext with AES-GCM
  4. Extract the ciphertext and 16-byte authentication tag

aesGcmDecrypt:

  1. Import the shared secret as an AES-GCM key
  2. Concatenate the ciphertext and authentication tag
  3. Decrypt using AES-GCM with the provided nonce
  4. Web Crypto API automatically verifies the authentication tag

Serialization Utilities

  • serializeEncryptedShare: Converts an EncryptedShare object to a JSON string for storage or transmission
  • deserializeEncryptedShare: Parses a JSON string back into an EncryptedShare object

Security Properties Summary

Confidentiality

PropertyMechanism
Share secrecyAES-256-GCM encryption with 256-bit keys
Key derivationHKDF-SHA256 with domain separation
Random nonces12-byte nonces from crypto.getRandomValues()
At-rest encryptionDevice-key-encrypted storage via SecureKeyStorage

Authenticity and Integrity

PropertyMechanism
Authentication tagAES-GCM 128-bit tag prevents tampering
Party identificationfromPartyId and toPartyId in encrypted structure
Proof of possessionSchnorr proofs during DKLS keygen
VSSS verificationShare verification against coefficient commitments (Pedersen)

Protocol-Level Guarantees

  • DKLS: State sanitization clears all intermediate values in finally blocks after each operation
  • Pedersen: cleanup() method resets state to null, wipes polynomial coefficients, clears ephemeral key pairs, and removes commitment and share maps
  • Both protocols: Sensitive user identifiers are SHA-256 hashed before use as storage keys

Integration Points

These cryptographic primitives underpin:

  • Client Key Manager: Secure storage of key shares
  • Self-custody recovery: Offline key reconstruction via password-encrypted backups
  • Protocol messages: Encrypted share exchange during DKG and signing
  • Address management: Wallet address derivation from MPC-generated keys

Session Security

  • Auth tokens are encrypted before storage using the device key
  • Automatic token refresh before expiry
  • Device fingerprinting for session binding
  • Session state events ("login", "logout", "connected", "disconnected") for monitoring lifecycle

On this page