evidence-custody
evidence-custody records every exhibit seized in a case, every change of hands with the signatures of both sides, the forensic laboratory's examination and the sealed report. Its rules come from BNSS section 105 (recording search and seizure), section 329 (reports of Government scientific experts) and BSA section 63(4) (the certificate stating a recording's hash).
- Chaincode-level endorsement: the forensic laboratories and one state police organisation.
- Key-level policy of an exhibit and its sub-records: the forensic laboratories and the exhibit's state police, so neither side can rewrite the chain of custody alone.
- Private data:
stateA_private,stateB_private,stateA_lab,stateB_labandforensics_private.
The exhibit record
| Field | Meaning |
|---|---|
caseId, firNo, stateCode, station | The case, read from fir-registry at seizure |
exhibitNo | EV-<FIR number>-<NN>, unique across the country |
kind, category | DIGITAL (files), PHYSICAL (a sealed packet, with optional photos) or DOCUMENT; a category code |
seizedAt, placeGeohash5, sealNo | When and roughly where it was seized, and the packet's seal number |
files | Up to 20 files: plain and ciphertext SHA-256, size (up to 2 GiB for evidence media), type and key hash |
esakshyaSid | The e-Sakshya ID when the media were captured in e-Sakshya; the files then carry only e-Sakshya's hashes and nothing is uploaded again |
memoCommit | Commitment of the private seizure memo |
qr | The label code printed on the bag: digifir:ex:v1:<exhibit number>:<16 hex characters of its fingerprint> |
custody | The current holder, since when, and the hop count |
pending | An open custody offer, if any |
lab | The laboratory's state, number, stages, due day, refusals, the sealed report and any supplementary reports |
status | Derived: SEIZED, WITH_POLICE, IN_MALKHANA, IN_TRANSIT_TO_LAB, AT_LAB, REPORT_SEALED or IN_COURT_CUSTODY |
Chain of custody
A custody hop takes two transactions: the holder offers, and the receiver accepts. Both signatures are stored in the hop record, so the chain can be verified from world state and the key registry alone.
| Holder | Who may offer | Who may accept |
|---|---|---|
| A police officer | The holder, or the station's SHO when the holder's key is no longer active | The named officer of the same station |
| The malkhana | The station's malkhana in-charge | The named station's malkhana in-charge |
| A laboratory | Reception or an analyst of the laboratory division | lab.accept by the named laboratory and division |
| A court | Court staff or the magistrate | Court staff or the magistrate of the named court |
Purposes: DEPOSIT_MALKHANA, WITHDRAW_FROM_MALKHANA, ESCORT, FOR_EXAMINATION, RETURN_AFTER_EXAMINATION, PRODUCE_IN_COURT, RETURN_FROM_COURT, TRANSFER_INVESTIGATION. At acceptance the receiver records the seal's condition: SEAL_INTACT, SEAL_DAMAGED or NO_SEAL.
A pending offer never changes the holder until it is accepted. The holder, the time of the last hop and any pending offer are public, so the backend can flag an exhibit that has sat with one holder longer than the configured threshold.
Keeping police and laboratory data apart
Two kinds of data must not cross: the seizure memo and evidence keys must not reach the laboratory, and the laboratory's working notes must not reach the police before the report is sealed (an officer who sees a partial result could shape the investigation). Two transactions write only private data, so they need no peer from the other side:
| Action | Writes only to | Endorsed by |
|---|---|---|
evidence.memo | The state's private collection | The state police and the judiciary; the laboratory never sees the memo or the keys |
lab.notes | forensics_private | The forensic laboratories only; no police peer ever runs it |
A seizure is therefore two actions signed together on the IO's phone: evidence.seize (the public record) and then evidence.memo (the private memo and file keys). The memo is bound to the public record by memoCommit and each file's key hash, so it cannot be swapped later.
When the laboratory accepts a parcel, the officer's app sends the file keys again as transient data, and they are written into the state's laboratory collection (evidence.escrow_keys). Every endorser checks each key against the hash of the original.
Laboratory workflow
| Step | Action | Rules |
|---|---|---|
| Dispatch | lab.dispatch, by the IO or SHO | The laboratory serves the state and has the division. The forwarding letter, and optionally a photo of the station's specimen seal, go into the state's laboratory collection. |
| Accept | lab.accept, by reception or an analyst | Exactly four checks, all true: seal intact, seal matches the specimen, papers complete, contents match. If the label code is scanned, it must equal the exhibit's QR code (LABEL_MISMATCH otherwise). A laboratory number is assigned and the turnaround clock starts. |
| Refuse | lab.refuse | One or more reasons: seal broken, seal does not match, papers missing, contents differ, wrong laboratory. The parcel goes back unopened and the holder never changes. |
| Stages | lab.stage, by an analyst | Received, then screening, then confirmatory. Stages cannot be skipped. |
| Notes | lab.notes, by an analyst | Versioned working notes, private to the laboratories |
| Seal | lab.seal, by an analyst whose designation qualifies under s.329(4) | Only at the confirmatory stage, and within 10 minutes of signing, so it needs a live connection. The report hash goes on the shared ledger and the text into the state's laboratory collection. A sealed report is never replaced. |
| Supplement | lab.supplement | A supplementary report R2, R3 and so on, which leaves earlier reports as they were. If the exhibit must be examined again, it returns by a supplementary dispatch that names the report and the court's or IO's request. |
| Hand back | custody.offer with RETURN_AFTER_EXAMINATION, then custody.accept by the police or malkhana | Only after sealing |
The report object includes a random salt and the sealer's key ID, so a short finding such as "negative" cannot be guessed from its public hash. The IO can read the report only after sealing. The report PDF with its BSA s.63 certificate is an off-chain document whose hash is registered for public verification.
Cross-state handover
When a court transfers a case to another state, evidence.handover_keys (endorsed by the receiving state and the judiciary, never the laboratory) copies the evidence keys into the receiving state's collection. evidence.rehome then moves the exhibit's records and policies to that state.
Queries
| Query | Purpose |
|---|---|
GetExhibit, GetExhibitByNumber, ListExhibitsForCase | An exhibit by ID or number, and a case's exhibits |
GetCustodyChain | Every hop of an exhibit with both signatures |
ReadPrivate, ReadPrivateBatch | Signed reads of the memo, keys, letter, notes and report, by role |
VerifyReport | Public verification of a sealed report by its hash |
FileHashRefs | Tier-1 duplicate hints, used by fir-registry |
SearchExhibits | List screens only |
OnboardState prepares the chaincode for a new state.
Source: digifir-chaincode docs/SPEC.md section 4 and section 10.2; digifir-backend docs/architecture/DECISIONS.md ADR-12 and ADR-13.