The old way
Universities ask students for honest feedback through web portals tied to student logins. When low ratings can be linked to your student identity, students stay quiet or write polite praise.
Four weak spots, and how we close them
If feedback is not anonymous, nobody tells the truth.
Behind the panel
The student feedback dilemma
Universities need candid student evaluations to maintain course quality. Traditional survey systems face a trilemma: - Anonymity: Students need total confidence that teaching staff cannot trace critical comments back to their student registration number or login account. - Sybil resistance: The university must guarantee that only enrolled students can vote, and that each enrolled student submits at most one rating per course. - Integrity: Students and auditors need proof that submitted ratings were actually counted in the final summary, without relying on blind trust in database administrators.
Centralized web forms fail this trilemma. Even when a checkbox says "anonymous", the web server records login sessions, IP addresses, and timestamps. If student IDs are removed entirely, anyone with the link can spam fake reviews.
We solve all three requirements with elliptic-curve cryptography, without a central authority holding the power to deanonymize students.
Hidden in the crowd
You do not sign a review as yourself. A ring signature proves an enrolled student submitted the rating, without revealing which one.
One signature from five enrolled keys
- Enrolled key ring: The submission proves the author holds one of the registered SECP256k1 keys for this module.
- Signer ambiguity: Any student in the ring is equally likely to be the author. The mathematical probability for each member is identical.
- Unenrolled intruder: Anyone outside the official module ring cannot forge a valid signature, even with full network access.
The ring signature covers the ciphertext and module identifier, leaving zero identifying metadata.
Test the ring signature in the gameOne of us wrote it. You'll never know which.
Behind the panel
LSAG ring signatures
We use Linkable Spontaneous Anonymous Group (LSAG) ring signatures over the SECP256k1 elliptic curve (y^2 = x^3 + 7 mod p).
When a student enrolls in a course through Moodle, their browser generates a private scalar x and registers the public point P = x · G. When submitting feedback, the student fetches the public keys of all classmates enrolled in that module: R = [P_1, P_2, ..., P_k].
How the signature is formed
The student computes a ring signature sigma = (I, c_0, [s_1, s_2, ..., s_k]). The signature forms a cryptographic ring: each step hashes the previous point and scalar multiplier. The signer closes the ring using their private scalar x at their own secret position, while generating random decoy scalars for all classmates.
A verifier checks that the ring closes correctly using public points only. The verifier confirms that an enrolled student signed, but learns zero information about which classmate created it.
One student, one vote
Anonymous forms usually invite duplicate ratings. Each student generates an unlinkable cryptographic nullifier: rate once and it counts; rate twice and the duplicate is refused on the spot.
One student across two modules
- Module CS402: first review
- Nullifier tag 7f3a9c01 · Accepted
- Module CS402: duplicate attempt
- Nullifier tag 7f3a9c01 · Rejected (duplicate)
- Module CS403: different course
- Nullifier tag 2b8e4d19 · Accepted (fresh key)
- First submission in CS402 is accepted. The Feedback Server stores the nullifier tag.
- Second submission in CS402 carries the exact same nullifier tag and is rejected instantly.
- Submission in CS403 uses a fresh keypair generated at enrollment, so reviews cannot be linked across courses.
The nullifier is deterministic for the same module, but reveals nothing about student identity.
Try submitting twice in the gameAlready rated! Try again and the math catches you.
Behind the panel
Key image nullifiers
To prevent duplicate submissions without identifying students, each LSAG signature includes a key image (nullifier): I = x · H(R), where H(R) maps the public key ring to a valid point on SECP256k1, and x is the student's private scalar for that module.
Why duplicate voting fails
Because elliptic curve point multiplication is deterministic, the same student signing for the same module key ring will always produce the exact same key image I. The Feedback Server stores used key images in an indexed set. When a second submission arrives with an existing key image, the server rejects it as a double-vote.
Cross-module unlinkability
Students generate a distinct, independent SECP256k1 keypair for every enrolled module. Because the private scalar x and the ring R differ between modules, the key image I in CS402 shares no mathematical correlation with the key image in CS403. Even if a student submits reviews for five different courses, no entity can link those submissions together.
Decrypted only in Moodle
Your rating and comments are encrypted on your phone before leaving your browser. The Feedback Server and third-party auditors only ever store and see ciphertext: Moodle holds the module private key, and decrypts the reviews for the lecturer after grades close.
What leaves your browser
- Your review: rating and comment
- {"module":"CS402","rating":1,"comment":"Please stop reading the slides!"}
- What the Feedback Server & Auditor see: ciphertext only
- abe9e8f004a3bb4ad7d477acea826ddd819925e9501490b081d0a694fa047324f4309d918a37160a1289791aa91d316eafef543c89f9131ecca3b33796bb7e0c5d2632e59bda93f013bddc4b898ec9d12c6b7707fd5ddae08c
- Ephemeral symmetric key (encrypted with module public key)
- e017666b8ccc1934894259d9e4ec219a
The Feedback Server and Auditor never hold the decryption key. Moodle holds the module private key, fetches the ciphertexts, and decrypts them for the lecturer without knowing who submitted which review.
Seal your own review in the gameMoodle decrypts your review for me, but neither of us knows who wrote it.
Behind the panel
Hybrid ECIES encryption
Submissions use hybrid authenticated encryption: 1. The student browser generates an ephemeral 256-bit symmetric key K_sym. 2. The review payload (numeric rating and text comment) is sealed using AES-128-GCM under K_sym with a unique 96-bit nonce, producing the ciphertext and 16-byte authentication tag. 3. The symmetric key K_sym is encrypted under the module's public key K_pub = d · G using ECIES (Elliptic Curve Integrated Encryption Scheme).
Decoupled service architecture & key ownership
The system decouples identity, storage, and verification across three isolated services: - Moodle Server (:8001): Manages student enrollments and stores the module's private key d. Because Moodle generates and holds d, it has the cryptographic authority to decrypt course feedback for the teaching staff. - Feedback Server (:8002): Receives anonymous submissions, verifies LSAG ring signatures, checks key image nullifiers, and stores ciphertexts in the Merkle log. It never holds the private key d and cannot decrypt any review. - Verifier Server (:8003): Public audit engine that validates cryptographic proofs. Like the Feedback Server, it only ever sees ciphertext.
When the lecturer logs into Moodle to inspect feedback, Moodle fetches the ciphertexts from the Feedback Server over an authenticated machine-to-machine (M2M) API, decrypts them locally using the module private key d, and displays the reviews. Because submissions carry only ring signatures and zero student identifiers, neither Moodle nor the lecturer can tell which student wrote which review.
A receipt for your voice
Every accepted review is committed to an append-only Merkle tree, and your device receives an audit receipt. Change a single character or drop a review, and the tree breaks.
Someone edits one review in the log
- Entry 3, as logged
- feedback-04 · rating 1 · sealed
- Entry 3, edited
- feedback-04 · rating 5 · sealeD
LEAF_MISMATCH: changing 1 star to 5 stars alters every hash on the path up to the root, shown in red. The published root no longer matches, catching the edit immediately.
Change one star and everyone can see it. Admins included.
Behind the panel
RFC 9162 binary Merkle tree
Each module maintains an append-only binary Merkle tree following RFC 9162 (Certificate Transparency):
- Leaf hash:
SHA-256(module_id ‖ encrypted_feedback ‖ sig_hash)wheresig_hash = SHA-256(canonical_json(sigma)). - Interior node:
SHA-256(0x01 ‖ left_child ‖ right_child).
Inclusion receipts
Upon successful submission, the student receives a permanent receipt: { receipt_token, module_id, leaf_hash, leaf_index }.
Any student can independently verify that their review was incorporated into the published evaluation summary. The verifier requires only ceil(log2 N) sibling hashes to prove inclusion against the published merkle_root. For a class of 256 students, only 8 hashes prove complete integrity.
Don't trust us. Check.
Anyone can verify that all reviews were counted fairly. An independent verifier audits receipts and Merkle proofs without logging in, without learning student identities, and without reading comments.
Verifying a complete feedback round
- Each submission holds a valid LSAG ring signature over SECP256k1.
- Every signer belongs to the enrolled module public key ring.
- No key image nullifier is duplicated within the module.
- Ciphertexts remain unopened by the Feedback Server and auditors.
- Every accepted submission sits at its verified leaf in the Merkle log.
- The reconstructed Merkle root matches the published checkpoint.
Verified: 6 of 6 checks passed. Any altered review, forged signature, or dropped ballot triggers an immediate verification failure.
Don't trust the university. Check the math.
Behind the panel
Independent verifier engine
Our Verifier Server (:8003) is completely decoupled from both Moodle and the Feedback database: - It maintains its own isolated database (verifier_db.sqlite3). - It has zero direct database connections to Moodle or the Feedback Server. - It interacts strictly over public HTTP REST endpoints. - It operates solely on ciphertexts and cryptographic proofs, never seeing decrypted feedback.
# Audit a student receipt token against the live Merkle root:
curl -X POST https://erating-moodle.onrender.com/api/verify/audit/ \
-H "Content-Type: application/json" \
-d '{"receipt_token": "rcpt_7f3a9c..."}'
The audit verifies that: 1. The leaf hash correctly binds the ciphertext to the signature hash. 2. The Merkle sibling path hashes up to the active published root. 3. The LSAG signature satisfies the ring equation over SECP256k1. If any check fails, the verifier returns an explicit error code naming the exact point of failure.
What we don't claim
Every security design rests on assumptions and boundaries. These are ours, documented in our threat model along with what remains for future work.
Small cohort anonymity
In a module with 4 enrolled students, your ring signature provides 1-of-4 ambiguity. Larger cohorts provide proportionally stronger privacy.
Moodle holds module keys
Moodle generates and stores module private key d to decrypt reviews for lecturers. An administrator with direct root access to Moodle can read comments, though they still cannot identify who submitted which review.
Writing style and vocabulary
Cryptography protects your cryptographic keys, not your prose. A student who uses unique phrases or describes personal incidents can be identified by reading the comment.
Network IP privacy
Our current prototype does not include a built-in mixnet or Tor onion relay. In production, requests should pass through an anonymizing proxy to prevent IP logging.
Device security
Private keys are stored in browser local storage. If a student device is infected with malware or a keylogger, local secrecy is broken.
Single verifier instance
Our audit verifier currently runs as an independent third-party service. Anchoring Merkle roots to a public decentralized blockchain is planned next.
Behind the panel
- The LSAG ring signature scheme provides computational signer indistinguishability (CPA anonymity) under the Decisional Diffie-Hellman assumption on SECP256k1.
- Feedback should only be released to lecturers after all final course grades are submitted to the registrar, preventing retaliatory grading.
- If an enrolled student loses their device or private key before submitting feedback, re-enrollment requires issuing a new module key and updating the public ring.
- Text comments should ideally pass through an automated linguistic normalization filter (lowercasing, vocabulary sanitization) to reduce stylistic fingerprinting.
- Future work includes implementing zero-knowledge succinct non-interactive arguments of knowledge (zk-SNARKs) to reduce ring proof size from O(k) to O(1).