'01 Big Raffle  ·  Engagement brief

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.

The question this page answers

“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.

1–3Ordinary workBank to payments, payments to tickets, tickets to the published list.
4The new oneConfirm the list the draw used is the list published that morning.
YoursThe count checkYour own ticket total, set against ours. It can stop the draw.

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.

How this engagement is described

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.

Start here

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

  1. 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.
  2. 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.
  3. The seed becomes a byte stream. SHA-256 of the seed with a counter appended, incrementing, for as many bytes as the shuffle needs.
  4. 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.
  5. 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 one idea worth a minute

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.

Draw day

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.

Scope

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
Your control

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.

Why this one matters

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.

Link 4, demonstrated

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.

The check

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.

Press a button.

Link 4 is that check, start to finish. If it ever reads mismatch, the draw is void and we say so publicly.

Volume

What the season looks like

ItemCountNotes
Weekly draws13Fridays, September to November. Each awards several prizes
Grand draw1Homecoming, 5 December
Redraw sessions~4For unclaimed prizes. One session covers several at once
Time per draw~1 hrWeekly draws remote or in person, to be confirmed with you. The grand draw is expected in person, per section 16 of your proposal
ReconciliationweeklyAround 15 weeks
Prizes per weekly draw~10Varies by week, frozen each draw morning
Prize awards to reconcile~130Across the season, plus claims and forfeits
Tickets issued to date329Target 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.

Before you assess our code

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 randomnessdrand · League of Entropy
Run since 2019 by 17 independent organisations, among them Cloudflare, the Ethereum Foundation, Kudelski Security, Protocol Labs, EPFL, University College London and the University of Chile. The signing key is split across them, so no member can produce a round alone or predict one early. We consume it. We have no relationship with it and no influence over it.
The fingerprintingSHA-256 · FIPS 180-4
A US federal standard published by NIST, and the same function behind the padlock in your browser, the integrity check on software downloads, and every commit identifier in Git. No collision has ever been found, and it has been under public attack since 2001.
The shuffleFisher-Yates
Described in 1938 and in every algorithms textbook since. It is the standard method precisely because it is provably even-handed when fed an even-handed stream, which is why we take the extra step of discarding out-of-range values rather than folding them back.
Oursabout 370 lines
The glue: read the two files, refuse them if they fail any check, combine the inputs in a fixed order, and print the result. That is the only part you are being asked to form a view on, it is published, and it is written twice in two languages so the two can be set against each other.

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.

Raised 3 September, after the walkthrough

Your questions, answered

One change since we last spoke removes a whole group of these rather than answering them, so it comes first.

Question 1Superseded

How will the three parties generate and record their secret numbers, in what format, where stored, and how are the commitments produced?

Short answer

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.

The detail

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.

Question 2Answered

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?

Short answer

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.

The detail

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.

FileWhat it holds
01-ticket-registerEvery 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-reversedEvery 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-ticketsTickets issued without payment, flagged at the order. Covers (e).
04-weekly-winners-excludedEvery recorded weekly winner, which is what the engine excludes from later weekly draws. Covers (f).
05-draw-indexOne row per draw: cut-off, draw time, list fingerprint, row count, prize fingerprint, beacon round. Covers (c).
06-ticket-number-gapsAny missing ticket number, with a pointer to the reversal that caused it. Covers (g).
07-control-totalsOrdered 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.

Question 3Answered

Is the prize list fixed in a predetermined order? When is it finalised, and where is it published?

Short answer

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.

The detail

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.

The internal freeze page: a dropdown reading Draw 1, entries-close and draw times filled in automatically from the published schedule, a prize box with three prizes one per line, and two buttons reading Check first and Freeze and publish.
Where the prize order is set. Typing the prizes closes nothing on its own — Freeze and publish is what fixes them, and it fixes the ticket list in the same action, so the two fingerprints are written together and before the random value exists.
Question 4Reframed

Can you demonstrate again how the revealed secret numbers and the drand value are retrieved, verified and combined into the final seed?

Short answer

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 detail

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:

1version tag01BIGFIGHT-DRAW-v2
2list fingerprintcc6a5a29e2cb0748122d11ddd041d970a9bbf6baf92f24d6ebae4a32368a366f
3draw number00
4attempt0
5beacondrand:quicknet:31815412:af5a5a0392c312b0a4f6e95eb5c99e6d510086f5518f85b09bc712d3152c92df
SHA-256 of those five, newline-separated → final seed
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.

Question 5Answered

Can we request the complete randomised ticket sequence for each draw, and the fallback sequence where applicable?

Short answer

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.

The detail

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.

Question 6Answered

How are failed, mismatched or invalid draws handled: ticket-count differences, hash mismatches, drand problems, system failure?

Short answer

If anything does not add up, the draw stops. There is no proceed-anyway button.

The detail

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.

Question 7Answered

How would we independently reproduce a result from the frozen population and the published inputs?

Short answer

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 ↗
The detail

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.

The result of pressing Check first: a heading reading Nothing has been frozen yet, then draw 1 weekly, 532 tickets, 0 excluded prior winners, 3 prizes, round 31,901,812, and the list fingerprint.
Check first against live data, run while writing this. It reports the count you would be reconciling against, the round that will be used, and the fingerprint — and the heading says what it did to the record, which is nothing. Run it as often as you like before committing.
Question 8Answered

What will the draw minutes contain, and may we review the template?

Short answer

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.

The detail

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.

Question 9Answered

We will require a continuing register from the first draw through the grand draw, showing issued, added, cancelled, excluded and adjusted tickets.

Short answer

One running list from draw one to the grand draw. Tickets added, tickets voided, winners taken out. Every change stays on the record.

The detail

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.

Question 10Answered

When is a redraw or replacement session conducted, and when is the predetermined fallback sequence used?

Short answer

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.

The detail

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.

Questions we expect

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.

Deliverables

What we are asking for in return

  1. A signed reconciliation per drawCovering the four links, for the draw pack published after each draw.
  2. Your countersignature on the minutesAlongside the College '86 observer and two committee members.
  3. A season-end reportTotal raised, total tickets, total prizes awarded, and any exceptions raised during the season.
  4. 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.

Where things stand today

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.