BYOiD/PROTOCOL

CVK Session Activation

Specification of the secondary authentication ceremony that promotes a CMK-authenticated user to full session control over their personal Consumer Vendor Key for user-sovereign signing.

18 min read

Overview

The CVK Session Activation ceremony grants a CMK-authenticated user session-level control over their Consumer Vendor Key (CVK) - a per-user, per-vendor key that acts as the user's personal cryptographic authority within that vendor's context. The CVK enables user-sovereign operations: identity wallet signing, cryptocurrency wallet transactions, SSH certificate issuance, or any use case requiring individual (rather than organizational) authority.
The ceremony is substantially simpler than CMK authentication (Protocol: CMK Authentication):
  • No PRISM. The user has already proven password knowledge via the CMK ceremony. CVK ORKs accept the CMK blind signature as the authentication gate.
  • No blinding. CVK ORKs already know the user's VUID and gCVK - there is no cross-vendor unlinkability requirement at this layer. CVK signing uses standard threshold Ed25519, not the double-blind BEd255475 construction.
  • No identity recovery. The VUID was derived during CMK authentication and is provided directly.
The ceremony completes in two round-trips between the Secure Web Enclave (SWE) and the CVK ORK swarm. The CMK blind signature serves as a non-interactive proof of authentication - CVK ORKs verify it independently before signing.
Loading diagram...

Preconditions

CMK Authentication Must Complete

The CVK session protocol is a secondary ceremony that builds on top of the primary CMK authentication ceremony but is performed in parallel with it.
To start the CVK session protocol, the SWE must hold the output of a successful CMK round-trip 1 Authentication Ceremony (Protocol: CMK Authentication):
  • gCMKAuth\mathit{gCMKAuth} - the user's vendor-specific authentication public key
  • mauthm_{\text{auth}} - the authentication token message (containing VUID\mathit{VUID}, expiry, vendor session public key KK, session identifier)
  • (k,K)(k, K) - the non-extractable vendor session key pair
By the time the CVK round-trip 1 protocol completes, the SWE will also hold the output of CMK round-trip 2 Authentication, which is a pre-requisite for the CVK signing step (round-trip 2):
  • (R,S)(R, S) - the CMK blind signature on the specialized twisted Edwards curve BEd255475
The double-blind signature serves as a non-interactive proof: any party holding gCMKAuth\mathit{gCMKAuth} can verify it via the standard Schnorr equation on the specialized BEd255475 curve.

Per-CVK-ORK Stored State

Each CVK ORK ii stores (established during the user's CVK registration):
  • VUID\mathit{VUID} - the user's vendor-specific identifier (index key)
  • gCMKAuth\mathit{gCMKAuth} - the user's vendor authentication public key (used to verify CMK proof)
  • CVKi\mathit{CVK}_i - Shamir share of the user's CVK private key
  • gCVK=GCVK\mathit{gCVK} = G \cdot \mathit{CVK} - the CVK public key (public value, same across all ORKs)
  • vSecORKi\mathit{vSecORK}_i, vgORKi\mathit{vgORK}_i - the ORK's own long-term key pair

Vendor State

The vendor holds VUID\mathit{VUID}, gCVK\mathit{gCVK}, gVVK\mathit{gVVK}, and the ephemeral gVRK\mathit{gVRK} + its VVK-signed delegation proof.

Protocol Flow

Step 0 - CVK Swarm Discovery

The SWE queries the home ORK for the CVK swarm roster associated with this VUID\mathit{VUID}:
SWEHome ORK:GetKeyORKs(VUID)\text{SWE} \rightarrow \text{Home ORK}: \textsf{GetKeyORKs}(\mathit{VUID})
Returns: gCVK\mathit{gCVK}, CVK ORK URLs, identifiers vIdi\mathit{vId}_i, and public keys vgORKi\mathit{vgORK}_i.
If no CVK record exists for this VUID, the SWE initiates a CVK registration flow (separate protocol, not specified here).

Round-Trip 1: PreSign

Loading diagram...
The ECDH channel between the SWE and each CVK ORK uses the vendor session key KK - the same non-extractable key generated during the CMK ceremony. This binds the CVK session to the same browser context.
Convergence wait: The SWE waits up to 1 second for all nn responses or 5 seconds for the first tt (14), records participants in ORKsBitwise\mathit{ORKsBitwise} with count II.

SWE Processing: Nonce Aggregation and Message Construction

The SWE decrypts each ORK's response using the ECDH shared secret:
ECDHiDH(vgORKi,k)\mathit{ECDH}_i \leftarrow \textsf{DH}(\mathit{vgORK}_i, k) {gCVKRi[j]}AES_DECECDHi(ECDHi,enci)\{\mathit{gCVKR}_i[j]\} \leftarrow \textsf{AES\_DEC}_{\mathit{ECDH}_i}(\mathit{ECDH}_i, \mathit{enc}_i)
It aggregates nonces per signature slot:
gCVKR[j]iSgCVKRi[j]j[1..m]\mathit{gCVKR}[j] \leftarrow \sum_{i \in S} \mathit{gCVKR}_i[j] \quad \forall\, j \in [1..m]
It then constructs the message(s) to be signed, depending on the model. The primary slot (j=1j = 1) is always a CVK session JWT:
jwtcreateJWT(id:VUID,  spk:K,  exp:timestamp+30min,  iss:“Tide.org”,  aud:gVVK)\mathit{jwt} \leftarrow \textsf{createJWT}(\mathit{id}: \mathit{VUID},\; \mathit{spk}: K,\; \mathit{exp}: \text{timestamp} + 30\text{min},\; \mathit{iss}: \text{``Tide.org''},\; \mathit{aud}: \mathit{gVVK})
Additional slots carry model-specific payloads (e.g., an SSH certificate signing request, a blockchain transaction). The model determines how many slots and what validation rules each CVK ORK applies.

Round-Trip 2: Sign

Loading diagram...
The critical point: the CVK ORK independently verifies the CMK blind signature before producing any CVK partial signature. This is a non-interactive verification - the CVK ORK needs only gCMKAuth\mathit{gCMKAuth} (which it stores from registration) and the signature (R,S,mauth)(R, S, m_{\text{auth}}) from the SWE. No communication with CMK ORKs is required.

SWE Processing: Signature Aggregation and Verification

Algebraic correctness:
CVKsi[j]=(cvkRi[j]+h[j]CVKiLi)\sum \mathit{CVKs}_i[j] = \sum (\mathit{cvkR}_i[j] + h[j] \cdot \mathit{CVK}_i \cdot L_i) =cvkRi[j]=cvkR[j]+h[j]CVKiLi=CVK= \underbrace{\sum \mathit{cvkR}_i[j]}_{= \mathit{cvkR}[j]} + h[j] \cdot \underbrace{\sum \mathit{CVK}_i \cdot L_i}_{= \mathit{CVK}}
By Shamir reconstruction, the partial nonces sum to the joint nonce and the partial key contributions sum to the joint key - producing a standard Ed25519 signature verifiable against gCVK\mathit{gCVK}.

Delivery to Vendor

The SWE encrypts the results under the vendor's ephemeral public key:
VendorEncryptedDataENCgVRK(VUID,gCVK,{(gCVKR[j],CVKS[j])}j=1m)\mathit{VendorEncryptedData} \leftarrow \textsf{ENC}_{\mathit{gVRK}}(\mathit{VUID}, \mathit{gCVK}, \{(\mathit{gCVKR}[j], \mathit{CVKS}[j])\}_{j=1}^{m})
The vendor decrypts, aggregates the per-slot signatures if needed, and establishes a session granting the user CVK-level authority. The primary JWT signature (j=1j = 1) authorizes the session; additional slots provide model-specific signed artifacts (SSH certificates, signed transactions, etc.).

The Model System

The CVK ceremony supports model-based multi-signature: a single authentication can produce multiple purpose-specific signatures in parallel, each covering a different payload and subject to different validation rules.
ModelSlotsPrimary SignatureAdditional SignaturesValidation Rules
Default1CVK session JWT-Standard claims validation
OpenSSH2CVK session JWTSSH user auth request (SSH wire format)Parse SSH request, validate against SSH policy rules
CustommmCVK session JWTApplication-defined payloadsApplication-defined rules enforced by CVK ORKs
Each CVK ORK independently validates model rules before signing. The model name is committed during PreSign (cached server-side); it cannot be changed between rounds.
The number of nonces generated in Round-Trip 1 matches the number of signatures the model requires. Each slot jj has its own independent nonce cvkRi[j]\mathit{cvkR}_i[j], aggregate gCVKR[j]\mathit{gCVKR}[j], message msg[j]\mathit{msg}[j], and partial signature CVKsi[j]\mathit{CVKs}_i[j].

Failure Recovery

ORK drops between PreSign and Sign. If a CVK ORK that committed nonces in PreSign fails to respond to Sign, the nonce set is inconsistent. The SWE must restart with a new PreSign. The CMK blind signature remains valid (its expiry is typically 30-90 seconds) and does not need to be recomputed.
CMK blind signature expired. If the CMK authentication token's expiry has elapsed before the Sign call reaches CVK ORKs, verification fails. The SWE must re-authenticate via the CMK ceremony (or the stored authentication variant if within the remember-me window).
CVK record not found. If no CVK record exists for this VUID, the SWE initiates a CVK registration flow - a separate protocol that creates CVK shares via DKG and distributes them across the CVK ORK swarm.

Notation Reference

Notation inherited from the CMK sub-protocols (Protocol: PRISM, Protocol: Double-Blind TSS) is not restated. CVK-specific notation:
SymbolDescription
CVK\mathit{CVK}, CVKi\mathit{CVK}_iUser's Consumer Vendor Key (joint private key) / ORK ii's Shamir share
gCVK\mathit{gCVK}CVK public key: GCVKG \cdot \mathit{CVK}
VUID\mathit{VUID}Vendor User ID (derived during CMK authentication)
gCMKAuth\mathit{gCMKAuth}User's vendor-specific authentication public key (from CMK ceremony)
(R,S)(R, S)CMK blind signature (proof of authentication)
mauthm_{\text{auth}}CMK authentication token message (contains VUID, expiry, session key KK)
(k,K)(k, K)Vendor session key pair (non-extractable via WebCrypto, generated during CMK ceremony)
vSecORKi\mathit{vSecORK}_i, vgORKi\mathit{vgORK}_iCVK ORK ii's long-term private/public key
cvkRi[j]\mathit{cvkR}_i[j], gCVKRi[j]\mathit{gCVKR}_i[j]Per-ORK nonce scalar/point for signature slot jj
gCVKR[j]\mathit{gCVKR}[j]Aggregate nonce for slot jj: gCVKRi[j]\sum \mathit{gCVKR}_i[j]
mmNumber of signature slots required by the model
gVRK\mathit{gVRK}TideCloak's ephemeral public key (for encrypting payloads to TideCloak)
LiL_iLagrange coefficient for CVK ORK ii
ENCA(B)\textsf{ENC}_{A}(B)X25519-based El-Gamal encryption of message BB with public key AA
AES_ENCa(B)\textsf{AES\_ENC}_{a}(B)AES256 encryption of message BB with key aa
AES_DECa(B)\textsf{AES\_DEC}_{a}(B)AES256 decryption of message BB with key aa

Actors & Trust Assumptions

ActorRoleTrust Assumption
Secure Web EnclaveOrchestrates the CVK ceremony after CMK authentication. Aggregates CVK partial signatures.Potentially adversarial. A malicious SWE that has completed CMK auth can only produce CVK signatures for its own VUID - it cannot sign on behalf of other users or other vendors.
Home ORKReturns CVK swarm roster for the given VUID.No elevated trust. Compromised home ORK can return stale roster.
CVK ORK Swarm (20 nodes)Independently operated nodes holding CVK shares for this user-vendor pair. Verify CMK proof before signing.Up to 13 may be malicious. Separate swarm from CMK ORKs - different nodes, different operators, different key material.
VendorReceives CVK-signed payloads. Aggregates partial signatures. Establishes user session with CVK authority.Holds gCVK\mathit{gCVK} (public), VUID\mathit{VUID}, gVRK\mathit{gVRK} (ephemeral). Never possesses CVK private key.
Settlement LayerFunds CVK ORK operations via one-time voucher.Binds operation to paying vendor.

Layer Traversal

LayerHow CVK Activation Engages It
LegitimacyVoucher validates each CVK ORK call. ECDH between KK and vgORKi\mathit{vgORK}_i qualifies the channel.
AuthorityEach CVK ORK retrieves its CVK share CVKi\mathit{CVK}_i - undifferentiated key material.
AgencyThe standard threshold Ed25519 partial signature is the purpose-specific operation. The CMK blind signature verification is the authentication gate.
SettlementVoucher funds participation, binds operation to vendor, ensures the CVK operation was authorized by the correct payer.

Security Properties

PropertyMechanismAssumption
CMK authentication requiredCVK ORKs independently verify CMK blind signature (R,S)(R, S) against stored gCMKAuth\mathit{gCMKAuth} before signingSpecialized BEd255475 curve hardness
No CVK private key materializationCVK Shamir-shared across 20 independent ORKs; joint key reconstructed only as implicit sum within partial signaturesThreshold assumption (<t< t compromised)
Session bindingECDH channel uses vendor session key KK (non-extractable); CVK session JWT embeds KK as session proofWebCrypto API integrity
CMK proof non-transferableAuthentication token mauthm_{\text{auth}} contains vendor session key KK, VUID, and expiry; CVK ORKs verify VUID and gCMKAuth\mathit{gCMKAuth} match stored valuesToken construction integrity
Model commitmentModel name committed during PreSign, cached server-side; Sign call cannot alter the model or request additional signature slotsCache integrity
Model rule enforcementEach CVK ORK independently validates model-specific rules before signing; a malicious SWE cannot bypass policyThreshold: majority of ORKs enforce rules honestly
Cross-vendor isolationCVK shares are per-vendor (distinct from CMK shares); CVK ORKs store only data for their vendor's usersStructural property
Separate trust domainCVK ORK swarm is operationally independent from CMK ORK swarm - different nodes, different operators, different key materialSwarm assignment protocol
Replay resistanceNonce cache entries destroyed on use; CMK proof has bounded expiryORK cache discipline
14-of-20 fault/security toleranceSame threshold properties as CMK: 6 may be offline, 13 may be maliciousThreshold assumption

Comparison: CVK vs VVK

Both CVK and VVK produce threshold Schnorr signatures via ORK swarms. The distinction is in authority scope:
PropertyVVK (Organization)CVK (User)
Key scopeOne key per vendor/organizationOne key per user-vendor pair
Authority modelShared organizational authority, differentiated by RBACIndividual user authority
Authentication gateTideCloak presents authorization proofCMK blind signature
Typical usesJWT signing, RBAC enforcement, org-managed E2EEIdentity wallets, crypto wallets, SSH certs, personal signatures
Who initiatesTideCloak IAM (server-side)User SWE (client-side)
Signing styleStandard threshold SchnorrStandard threshold Schnorr
Some platforms use both: VVK for organizational access control and CVK for personal wallet capabilities, authenticated through the same CMK ceremony.

Call Summary

CallDirectionPayloadState Change
PreSignCVKSWE → all nn CVK ORKsSend: VUID\mathit{VUID}, KK, modelName\mathit{modelName}, gVRK\mathit{gVRK}+sig, gVVK\mathit{gVVK}, voucher. Receive: encrypted nonces gCVKRi[1..m]\mathit{gCVKR}_i[1..m]ORK creates cache entry (VUID,K)(\mathit{VUID}, K)
SignCVKSWE → II participating ORKsSend: VUID\mathit{VUID}, CMK proof (R,S,gCMKAuth,mauth)(R, S, \mathit{gCMKAuth}, m_{\text{auth}}), {gCVKR[j]}\{\mathit{gCVKR}[j]\}, ORKsBitwise\mathit{ORKsBitwise}, modelData\mathit{modelData}. Receive: encrypted partial signatures {CVKsi[j]}\{\mathit{CVKs}_i[j]\}ORK destroys cache entry
Between calls, the SWE decrypts nonces, aggregates per slot, and constructs message(s). No network communication occurs.

References

  • Komlo, C. & Goldberg, I. (2020). FROST: Flexible Round-Optimized Schnorr Threshold Signatures. SAC 2020.
  • Hall, J. L., Hertzog, Y., et al. (2023). Manifesting Unobtainable Secrets: Threshold Elliptic Curve Key Generation using Nested Shamir Secret Sharing. arXiv:2309.00915. Presented at AustMS 2021.
  • RFC 9449 - OAuth 2.0 Demonstrating Proof of Possession (DPoP). IETF, 2023.
  • Tide Developer Documentation: docs.tidecloak.com
Related Protocol Articles: