convert_authenticate — Group 10, Code 176
Authenticate CCv1 or CCv2 coins and credit their value to a conversion ledger kept on this RAIDA, then delete the legacy coins that pass. This command does not mint CCv3 — minting happens in convert_pickup (177). All coins in one request must be the same type, given by the CT byte; send CCv1 and CCv2 coins in separate requests.
Request Body
The body is encrypted per the standard encryption types. Total body size is 53 + 21×N bytes (N = coin count). Offsets below are from the start of the body.
CH CH CH CH CH CH CH CH CH CH CH CH CH CH CH CH // Challenge generated by the client
TD TD TD TD TD TD TD TD TD TD TD TD TD TD TD TD // Transaction ID: a random secret generated by the client,
// DIFFERENT on each of the 25 RAIDAs (see below)
CC CC // Coin Count to follow (big-endian). 0 = balance query
FU FU FU FU FU FU FU FU FU FU FU FU FU FU FU FU // Reserved for future use (zeros)
CT // Coin type: 0x01 = CCv1, 0x02 = CCv2. Applies to ALL coins in this request
Repeated Coin Count times (21 bytes per coin):
DN // Denomination byte (informational for legacy coins; value comes from the SN)
SN SN SN SN // Serial Number, big-endian. Legacy 3-byte SNs go in the low 3 bytes; top byte = 0
AN AN AN AN AN AN AN AN AN AN AN AN AN AN AN AN // Authenticity Number of the legacy coin
3E 3E // Terminating bytes, not encrypted
Packet Diagram — fixed header (bytes 0–50)
Packet Diagram — coin record (21 bytes, repeats Coin Count times, first record starts at byte 51)
Transaction ID — the pickup password
The transaction ID is a random 16-byte secret generated by the client, and it must be different on each of the 25 RAIDAs. It identifies the conversion session on this RAIDA and it is the password that spends the credits — 177 and 178 present the same transaction ID, and a COUNT=0 176 uses it to read the balance. The client must store all 25 transaction IDs safely before sending anything; losing them means losing access to the credits.
Why this is safe:- The server never stores the raw transaction ID. The ledger row is keyed by SHA-256(txid) (a NIST-approved hash). Anyone who reads the ledger database — a stolen backup or disk — gets only hashes, which cannot be sent in a request to spend the credits.
- One RAIDA learning a transaction ID gains nothing on the others. Because each RAIDA gets its own random txid, a rogue or compromised RAIDA that sees a decrypted request learns a secret that is only valid on itself — a node it already controls. It cannot touch the credits on the other 24.
- The challenge does a different job. The challenge authenticates the server (the server proves it decrypted the request by returning the challenge); it does not protect the credits. The transaction ID is what protects the credits.
Coin Count
These two big-endian bytes specify how many 21-byte coin records follow the fixed header (so 00 05 means five coins, 105 bytes of coin data).
If the coin count is greater than 0, the server authenticates that many coins, credits each pass to this transaction ID's balance, and deletes the legacy coin on this RAIDA. The server accepts up to 19,000 coin records per request; the often-quoted 1,411-coin maximum is a client-side transport guideline, not a server limit.
Balance query modeCOUNT = 0 (00 00) means no coins are being submitted — the client just wants to know how much credit this transaction ID already holds on this RAIDA. The client uses COUNT=0 after the first credit, and on recovery, to ask “how much is still on this ledger?” before calling 178/177 again. Same command, two modes, switched by that 16-bit count. In balance-query mode the CT byte is ignored.
Coin type, DN, and SN for legacy coins
CCv1 and CCv2 use the DN and SN fields differently than CCv3:
- Both CCv1 and CCv2 have 3-byte serial numbers. They are placed in the low 3 bytes of the 4-byte SN field, big-endian, with the top byte set to 0.
- CCv1 has five denominations, but the denomination is determined by the SN band (table below). The DN byte is informational and does not decide the credited value.
- CCv2 has a single denomination worth 85.125 CloudCoins each (8,512,500,000 microunits).
Credited value is computed by the server in microunits (1 CC = 1e8 microunits):
| Coin Version | Denomination (CC) | SN band | Microunits |
|---|---|---|---|
| CCv1 | 1 | 1–2,097,152 | 100,000,000 |
| CCv1 | 5 | 2,097,153–4,194,304 | 500,000,000 |
| CCv1 | 25 | 4,194,305–6,291,456 | 2,500,000,000 |
| CCv1 | 100 | 6,291,457–14,680,064 | 10,000,000,000 |
| CCv1 | 250 | 14,680,065–16,777,216 | 25,000,000,000 |
| CCv2 | 85.125 | all | 8,512,500,000 |
Response Body
AC AC // AUTHENTIC_NOTES: a COUNT of notes, not a value. How many of the
// submitted notes are now credited to this transaction ID (big-endian)
VA VA VA VA VA VA VA VA // VALUE_ADDED: microunits of credit added by this call (big-endian)
RB RB RB RB RB RB RB RB // RAIDA_BALANCE: total credit in microunits that this transaction ID
// now holds on this RAIDA (big-endian)
NB ... // NOTE_BITMAP: ceil(N/8) bytes, one bit per submitted note;
// bit i = 1 means note i is credited to this transaction ID
3E 3E // Terminating bytes
| Field | Bytes | Notes |
|---|---|---|
| AUTHENTIC_NOTES | 2 BE | A count, not a value — values are in VALUE_ADDED and RAIDA_BALANCE. Number of submitted notes now credited to this transaction ID; always equals the number of 1-bits in NOTE_BITMAP. Two bytes to mirror the 2-byte Coin Count (max 19,000). |
| VALUE_ADDED | 8 BE | Microunits of credit added by this call (1 CC = 100,000,000 microunits). 0 in COUNT=0 mode. A re-sent note that was already credited adds nothing here. |
| RAIDA_BALANCE | 8 BE | The total credit balance, in microunits, that this transaction ID now holds on this RAIDA. |
| NOTE_BITMAP | ceil(N/8) | One bit per submitted note, in request order: bit i = 1 means note i is credited to this transaction ID. Within each byte the least-significant bit is the lowest-numbered note. Absent in COUNT=0 mode. |
Per-coin behavior
- An unknown SN or a wrong AN fails that coin only: its bit is 0 and nothing is credited for it. A missing CCv1 database row is likewise a per-coin fail (bit 0), not a whole-call 54 — 54 is reserved for the legacy database being unreachable.
- No coin can ever be credited twice. The ledger keys credits by (transaction ID, coin type, SN), so a coin's value is added exactly once no matter how many times it is submitted.
- Retry recovery: after a coin is credited, 176 deletes the legacy coin, so if the client re-sends it (for example, the response was lost and the client does not know the coin passed), the coin can no longer authenticate. Instead of falsely reporting a fail, the server checks the ledger: if this (txid, type, SN) was already credited, the coin's bit is set to 1 and it counts in AUTHENTIC_NOTES, but it adds nothing to VALUE_ADDED or RAIDA_BALANCE.
- Operation order on the server: the credit is committed durably first, then the legacy coin is deleted. If the delete fails, the credit stands and the failure is logged.
Header Status Codes
| Code | Name | When |
|---|---|---|
| 250 | SUCCESS | All coins credited, or COUNT=0 balance query succeeded. |
| 243 | MIXED | Some coins credited; see bitmap. |
| 242 | ALL_FAIL | No coins credited. |
| 93 | UNKNOWN_OR_EXPIRED_TXN | COUNT=0 and no ledger row exists, or the row expired. |
| 198 | INVALID_PARAMETER | Bad body length, coin count, or CT byte. |
| 54 | LEGACY_DB_SELECT | Legacy coin database unavailable. Source coins untouched. |
| 252 | INTERNAL | Ledger failure. |
Every successful 176/177/178 call refreshes the ledger row's expiry to now + 30 days. Note that 241 is ALL_PASS in protocol.h — it is a success code, not a failure code.