What we are asking an independent accountant to do.
A fundraising raffle by Ateneo High School Batch 2001 with College Batch 1986. Thirteen weekly draws from September to November, each awarding around ten prizes, then a grand draw at the homecoming on 5 December.
“What are we actually being asked to check?”
Four reconciliations. Three are ordinary bookkeeping. The fourth is loading two files onto a web page and reading one line.
You are the only outside party in this engagement. This page sets out the scope, the volume, and the one control that sits with you.
Coria & Co. act as the Independent Accountant under an agreed-upon procedures engagement per PSRS 4400 (Revised). They perform the specific procedures agreed in writing and report the factual findings. That report is not an audit opinion, a certification, or assurance of any kind, and they are not our auditor.
Their scope excludes the technical design of the draw: the source code, the hashing, the external randomness beacon, the seed-generation and shuffle methods, security, and resistance to manipulation. A countersignature on draw minutes evidences their attendance and the procedures they performed. It is not a statement that the system is sound, unbiased or fair, and we are not asking them for one.
Responsibility for the conduct of the raffle, its records, its legal and regulatory compliance, and the resolution of any discrepancy sits with AHS 2001 Batch Organization Corp.
Each draw produces two files
Everything else on this page refers back to these. Both are small plain-text files you can open in a text editor.
pool-01.csv — the hat
One line per ticket, two columns: a ticket number and a ticket code. That is the entire format. 517 lines means 517 tickets in that draw.
It is a photograph of every stub in the hat: you can count them and read each one. Tracing a stub back to a person takes our order records, which sit outside this file and stay with us.
draw-01.json — the instructions
The rules of that one draw, written down and published before it runs: which draw, when entries closed, a fingerprint of the hat, the prize list, which future random number will be used, and one that had already been published when the file was written.
Afterwards the same file also carries the random value that came out and the winners. It is the instruction sheet, signed before anybody knows the answer.
How the two files produce a winner
- Both files go in. The list supplies the tickets in the order they were issued; the instructions supply the random value for the named round.
- They are reduced to one value. A single SHA-256 over a fixed sequence: a version tag, the list’s fingerprint, the draw number, the attempt number, and the drand value. The same inputs always give the same 64-character seed.
- The seed becomes a byte stream. SHA-256 of the seed with a counter appended, incrementing, for as many bytes as the shuffle needs.
- The stream shuffles the list. Fisher-Yates: walk from the last ticket to the first, swapping each with one drawn at random from those not yet placed. Indices are chosen by rejection sampling rather than % n — bytes falling outside a clean range are discarded and redrawn. Every position is then exactly equally likely, which plain % n cannot promise.
- Position one takes prize one, position two takes prize two, and so on for as many prizes as the frozen list names.
On issue order: the list is ordered by ticket number, so it reflects the sequence in which tickets were issued. That ordering is an input — shuffling a differently ordered list yields a different result — but it is frozen, published and fingerprinted before the random value exists, and the shuffle is uniform, so every position is worth the same.
The instructions carry a fingerprint of the hat rather than the hat itself: a 64-character value derived from the file. Change one character in the list, add a ticket or remove one, and that fingerprint changes completely, and it cannot be worked backwards. So if the value published in the morning still matches the file you download in the afternoon, you have established the list is the same one. That check takes about two seconds: one command if you use a terminal, or none at all — the list page below does it in your browser.
The current ticket list is published in full here ↗ counted and fingerprinted by your own browser.
What happens, and when
Six fixed steps, the same every week: buying deadline at 9:00 PM, entries close at 11:59 PM, the list frozen and published at midnight, payment checking paused until 5:00 PM, the draw at 4:00, the record published after.
Each step, with who does it and why it sits where it does, is set out on its own page.
Four links, and only the last one is unfamiliar
The first three are ordinary reconciliation. The fourth ties the list we drew from to the list we published beforehand.
Link 4 exists because the draw is arithmetic. The same published inputs put through the same published method always produce the same winner, so anybody can repeat it and compare. Your part is loading two files and reading the answer.
What sits with you, and what does not
✓ In scope
- ·Weekly reconciliation of the four links above
- ·Attend each draw as observer, remotely or in person as we agree in the draw schedule
- ·Confirm the verified ticket count from your own records at each draw
- ·Receive and retain the published files for each draw
- ·Sign the minutes for each draw
- ·A season-end report
✕ Not asked of you
- ·Running software or using a command line
- ·Reading or reviewing source code
- ·Any knowledge of cryptography
- ·Custody of any key, password or secret
- ·Handling participants' personal data. The published files carry ticket numbers and ticket codes only, never names
- ·Deciding winners, or any part of the draw itself
The count check
At each draw you compare the ticket total you determined from your own records against the count we published that morning. If the two disagree, the draw stops until it is resolved.
The figure has to come from your side. When a file reports its own count, the same hand produced both, so the count merely repeats itself. Your independently kept total is what gives it weight: an observer watching the number typed in can confirm the typing, while your records can contradict the number.
Our published count appears in three places, all fetched from the same frozen list: the pool_row_count field of draw-NN.json, the number of rows in pool-NN.csv, and the figure shown at 01bigfight.com/raffle/list, which counts the file in the browser rather than reading a stored number. Comparing takes a moment. The independently kept total behind it is what you are pricing.
What the file check looks like
On the day you receive two published files. You load them onto the draw page and it answers in one line. Press either button below to see both outcomes, calculated in your browser as you click.
Both are real files you can download. Forty invented tickets, so the check works end to end before draw one exists. Load them on the draw page to run the full verification yourself, or read the whole ticket list on the list page right in the browser.
Link 4 is that check, start to finish. If it ever reads mismatch, the draw is void and we say so publicly.
What the season looks like
| Item | Count | Notes |
|---|---|---|
| Weekly draws | 13 | Fridays, September to November. Each awards several prizes |
| Grand draw | 1 | Homecoming, 5 December |
| Redraw sessions | ~4 | For unclaimed prizes. One session covers several at once |
| Time per draw | ~1 hr | Weekly draws remote or in person, to be confirmed with you. The grand draw is expected in person, per section 16 of your proposal |
| Reconciliation | weekly | Around 15 weeks |
| Prizes per weekly draw | ~10 | Varies by week, frozen each draw morning |
| Prize awards to reconcile | ~130 | Across the season, plus claims and forfeits |
| Tickets issued to date | 329 | Target in the low thousands |
Cut-off and draw timing
Payment verification closes at midnight. The list is frozen and published the following morning, and the draw runs that afternoon. That leaves one working morning, and it is when we need your count.
Almost none of this is ours
A home-built draw is a fair thing to be sceptical of. So it is worth being precise about which parts we wrote and which parts we borrowed from infrastructure that already carries its own standing.
The engagement excludes the technical design of the draw, and we are not asking you to revisit that. This is here so that the scope exclusion is a considered one rather than a leap.
Your questions, answered
One change since we last spoke removes a whole group of these rather than answering them, so it comes first.
How will the three parties generate and record their secret numbers, in what format, where stored, and how are the commitments produced?
We scrapped the three secret numbers. They made draw night fragile and proved nothing extra, because the whole ticket list is already public hours before the winning number exists.
This no longer applies. We removed the three secret numbers. Asking three parties to generate, hold and reveal a secret added custody risk and a coordination failure on every draw night, and it bought no assurance we did not already have: the ticket list and its fingerprint are published sixteen hours before the draw, and the random value comes from a public service on a round named in advance that none of us can influence.
What replaced them. Each frozen file now carries an anchor: a value from that same public service that had already been published at the moment we froze. Naming a future round proves the file was written before that round existed. Carrying an already-published value proves it was written after that one appeared. Together they bracket the moment of freezing without anyone relying on our clock. The anchor takes no part in the draw itself.
In your framework, section 5 in full and sections 7.2 and 7.3 can be struck.
Will you provide bank statements, the ticket issuance register, the frozen file per draw, cancelled and voided tickets, complimentary tickets, excluded previous winners, and records of adjustments?
Yes, and it is already built. One file per thing you asked for: every ticket and what was paid for it, everything cancelled or reversed and why, the freebies, and a totals sheet that checks itself. No names, emails or phone numbers in any of it.
Yes to (b) through (g). The export is built and can be sent now and reissued before each draw. It carries order references, payment references, amounts and verification timestamps, and deliberately carries no names, emails or phone numbers, consistent with your engagement excluding participants’ personal data.
| File | What it holds |
|---|---|
| 01-ticket-register | Every ticket issued, with its order reference, payment method, payment reference, amount, quantity and the time a verifier approved it. Ties (b) to the bank statement. |
| 02-cancelled-voided-reversed | Every rejected or reversed order, the reason in the verifier’s own words, and whether any ticket is still issued against it. Covers (d). |
| 03-complimentary-tickets | Tickets issued without payment, flagged at the order. Covers (e). |
| 04-weekly-winners-excluded | Every recorded weekly winner, which is what the engine excludes from later weekly draws. Covers (f). |
| 05-draw-index | One row per draw: cut-off, draw time, list fingerprint, row count, prize fingerprint, beacon round. Covers (c). |
| 06-ticket-number-gaps | Any missing ticket number, with a pointer to the reversal that caused it. Covers (g). |
| 07-control-totals | Ordered quantity against tickets issued, duplicate-code count, tickets sitting on unapproved orders, and the numbering range. The pack proves its own consistency. |
For (a) bank statements, those come from our two treasurers, who are the only people with account access. Neither of them can reach the database, and the person who runs the draw cannot reach the bank account.
One thing you will notice. The published ticket numbers contain a gap. Two tickets were issued and then voided when their order was reversed, because it and another order were backed by the same payment reference and one payment cannot support two orders. Gaps of that kind stay visible in the published list rather than being renumbered away, and file 06 names the reversal behind each one.
Is the prize list fixed in a predetermined order? When is it finalised, and where is it published?
First prize, second, third: written down and locked at midnight, before anyone knows anything. If that list is edited afterwards, the draw refuses to run at all.
Fixed and ranked one to n, finalised when the list is frozen at midnight, hashed, and published inside the instructions file for that draw.
The engine refuses to draw if the prize list has changed since freezing. That check exists because a list that could change after the order is known would let the number of winners be decided late, once someone could see who sat where.
Can you demonstrate again how the revealed secret numbers and the drand value are retrieved, verified and combined into the final seed?
Two things go in. The locked ticket list, and one public number that nobody can predict. They get blended into a single 64-character code, and that code decides the order the tickets come out of the hat. Put the same two things in and you always get the same order out. Every input is public, and the order falls out of the arithmetic.
The same thing with pictures, written for our batchmates ↗The seed is built from public inputs only, so there is no reveal step. It is a single SHA-256 over five fields joined by newlines, with a trailing newline. Worked through on our published sample:
87ae2a6260a7b7ef6e039327d31c1006250038dcc272c14387441782a0430028
That seed drives a byte stream, the stream drives a Fisher-Yates shuffle using
rejection sampling rather than % n, and position one takes prize one. The
same five fields always give the same order.
The beacon value is read from two independent hosts and compared before it is used. Happy to walk through this live whenever suits you.
Can we request the complete randomised ticket sequence for each draw, and the fallback sequence where applicable?
The draw settles the whole running order, top to bottom, and you can rebuild it yourself from the published files. And if a winner never claims, nobody slides up into their place. We hold a fresh draw for that prize.
You do not need us to supply it. The ordering is deterministic, so you can regenerate the complete sequence yourself from the two published files, which is a stronger position than receiving a list from us.
We currently publish the winners plus the next twenty in order. We will publish the complete ordering with each draw if you would rather have it in the pack.
One correction in fairness. That field is currently named
fallbacks, which is a misnomer we are fixing. It is published so the ordering
can be checked. It is never used to promote a runner-up, because we do not operate a
fallback sequence at all — see question 10.
How are failed, mismatched or invalid draws handled: ticket-count differences, hash mismatches, drand problems, system failure?
If anything does not add up, the draw stops. There is no proceed-anyway button.
The engine refuses rather than degrades. It stops and produces no winner if:
- the list supplied does not match the fingerprint published that morning
- the row count disagrees with the frozen count
- the prize list changed after freezing
- any ticket code fails its check digit
- ticket numbers are not strictly ascending, or a number or code repeats
- a previous weekly winner is still present in a weekly pool
- a grand draw attempts to exclude anyone
- the named beacon round has not been published yet
Operationally: if a step cannot happen when it should, we stop and reschedule rather than improvise. And if your independent count disagrees with the published count, the draw does not run until the difference is explained. That is your control, and it is the one that can stop the day.
How would we independently reproduce a result from the frozen population and the published inputs?
Open our check page, drop in the two files, and it answers in one line. Or run our published program yourself and compare. Either way you never have to take our word for the result.
Try it now on the sample files ↗Two ways, neither of which requires trusting us.
- In a browser. Load the two published files onto the check page and it recomputes the draw in front of you and answers in one line.
- From the published method. Two independent implementations, one in Node and one in Python, published with checksums, so you can confirm the two agree with each other as well as with us.
You can try either right now on the sample files further down this page, before draw one has run.
What will the draw minutes contain, and may we review the template?
A one-page form: who was in the room, what the list was, what the number was, who won, and a tick-list of what was checked. Draft is attached, please mark it up.
Template written and ready for your review. It records attendance, the frozen list and its fingerprint, your independent count beside ours, the prize order, both readings of the beacon value, the result, and a checklist of what was verified in the room.
The signature block states that your countersignature evidences attendance and the agreed-upon procedures performed, and is not an audit opinion, a certification or assurance of any kind, and does not extend to the technical design of the draw. Please mark it up freely.
We will require a continuing register from the first draw through the grand draw, showing issued, added, cancelled, excluded and adjusted tickets.
One running list from draw one to the grand draw. Tickets added, tickets voided, winners taken out. Every change stays on the record.
Understood, and the export is built for exactly that. It is cumulative by construction: it reads the full history each time rather than keeping a running file, so the register you receive before draw seven contains everything from draw one, and the gaps and reversals stay visible in it permanently.
When is a redraw or replacement session conducted, and when is the predetermined fallback sequence used?
Nobody gets bumped up into first place. If a prize goes unclaimed or is forfeited, we run a brand new draw for that prize, over the same original list, using a fresh public number.
There is no fallback sequence. An unclaimed or forfeited prize is re-raffled in a later session, never passed down a list. Framework section 8.4 does not apply to us.
A redraw runs over the same frozen pool the prize was originally drawn from, because someone who bought after that week’s cut-off was never eligible for that prize and does not become eligible later. The engine enforces three things:
- the original list, byte for byte — the forfeiting winner is skipped at selection rather than edited out, so the published fingerprint still holds
- a later beacon round than the draw it replaces, since reusing the original round would reproduce the original winner
- an explicit list of who is no longer eligible: the forfeiting winner and everyone who already won in that draw
Re-deriving from the same round with a different attempt number is refused, because by redraw time the inputs are public and whoever ran it could try attempt one, two, three and stop at a flattering one.
On your framework document. It is a better skeleton than ours and we will write the Mechanics against it. Section 5 in full, and sections 7.2 and 7.3, fall away with the secret numbers. Section 8.4 does not apply. Everything else stands, and where our answer differs from the heading we have said so above.
Before you quote
What kind of engine are you using?
We built the draw ourselves and published the method: about 370 lines, whose only outside part is a standard hashing function.
The design is a common one. Before the draw we publish the ticket list, its fingerprint, and the number of a future round of a public randomness service nobody here controls. On the day that round publishes its value. The fingerprint and the value are hashed together into one seed, and the seed shuffles the frozen list. Same inputs, same shuffle, every time.
We wrote it. It runs on our site, and in the browser of anybody checking it.
Is it a certified or licensed system?
No. It holds no certification, and the code stands unreviewed by any outside party.
Its standing rests on publication: every input and the method itself go out before each draw, so anyone can recompute the result and check it.
Are we being asked to vouch for the randomness?
No. Your signature covers the reconciliation: money to tickets, tickets to the frozen list, and that the file used on the day is the file published that morning.
Whether the method is cryptographically sound sits outside that signature. Say the word and we will put the distinction in the engagement letter.
What software do we need?
A web browser, and that is the whole list. The check on this page is the same one you would run on the day.
Do we handle any personal data?
No. The published files carry two columns, ticket number and ticket code. Names, initials, sections, email addresses and phone numbers all stay in our own records.
The committee verifies winner identities against ID after a draw, and those identities stay out of everything you receive.
What happens if our count disagrees with the file?
The draw stops until someone explains the difference. That explanation is the only route forward — carrying on and footnoting it in the report is not one we take.
The same applies to the file check: a mismatch voids the draw and we say so publicly.
Can we use our own tools instead of your page?
Yes. The method is published, so you or anyone you appoint can reimplement it and compare. Our page is there for convenience.
What if a draw is challenged after the fact?
Every draw leaves a pack: the frozen list, the instructions, the beacon value, the result and the signed minutes. Anyone challenging a draw re-runs the published method against that pack and compares.
Any liability question beyond that belongs in your engagement letter. Raise it before you sign.
What we are asking for in return
- A signed reconciliation per drawCovering the four links, for the draw pack published after each draw.
- Your countersignature on the minutesAlongside the College '86 observer and two committee members.
- A season-end reportTotal raised, total tickets, total prizes awarded, and any exceptions raised during the season.
- Your view on the engagement typeWhether this reads as agreed-upon procedures or something lighter. That shapes the fee more than the hours do, and it is your call to make.
Ask us anything before quoting. The mechanics, the draw page and the published method are open to you now, ahead of any signature.
The draw method is built and tested. The draw pack for a given draw only exists once that draw is frozen, so the file names on the draw page are examples until each draw runs. If you click through and find them missing, that is why.
To quote, reply to the email this reached you on. Ask us anything first. It is easier to answer before you price the work.
