-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pseudo-random generator statistical tests #4
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can only review the go code, and that looks good. But i don't know if this is the proper structure for this sort of project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to create new test suites, it would probably be better to use the cadence testing framework or overflow so we don't have to continue to rely on the poorly organized test suites from the other repos any more. Are either of those possible?
@joshuahannan Agreed, I'll build out tests for the other contracts & their scripts using the Cadence testing framework. The PRG test needs to be done a non-Cadence framework since we need to run an analysis on the statistical distribution of random numbers returned from the PRG. Go is preferable here given the supporting |
Are we able to use overflow though? that is much better design framework than my tests |
I'd imagine so. I'm not familiar with it, but can look into it for the test setup & execution. Better for me to familiarize myself with it since it's been mentioned as a powerful tool. |
Quick update: the PRG stat tests now use overflow as suggested by @joshuahannan. Since overflow pulls the contract config from local flow.json, I've moved the test & its helper to the root dir where the project's flow.json is located. And since we're using overflow, we no longer need the contract bindata or templates, so the Once this PR is done and merged, I can move on to building out Cadence unit tests. |
Looking at this PR shortly, apologies for the delay |
prg_test.go
Outdated
classWidth := (math.MaxUint64 / uint64(n)) + 1 | ||
|
||
// using the same seed, the salt varies in getNextUInt64() | ||
seed := GetRandomSeed(t) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The uniformity checked in this test is different from the uniformity that we expect to test when assessing a PRG quality : this test looks at the the uniformity of the first generated output across multiple PRG instances (diversified per salt), the quality of a PRG is evaluated using successive outputs of the same PRG instance (same seed and salt).
A PRG that succeeds the first criteria may fail the second (the main quality one).
I suggest two things:
- update the current test to use the same PRG instance and evaluate the uniformity of it successive outputs.
- add another test, to make sure both the seed and salt are taken into account in the implementation. This doesn't need to be a statistical test. It's enough to check that two instances with different seeds but same salt output different randoms (the first output is enough to check), and then the same for 2 instances with the same seed but different salts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really helpful, thank you! I'll make these changes shortly.
go.mod
Outdated
require ( | ||
github.com/bjartek/overflow v1.14.1 | ||
github.com/onflow/cadence v0.42.2 | ||
github.com/onflow/flow-go/crypto v0.24.9 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a recent PR to improve the statistical tests (onflow/flow-go#4844). It can help reduce flakiness in the test. Maybe I can merge that PR and tag a new version to be used here first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I'll bump the version once it's ready to go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just merged the PR and tagged a new version v0.24.10
that you can use
Co-authored-by: Tarak Ben Youssef <[email protected]>
Co-authored-by: Tarak Ben Youssef <[email protected]>
Update PRG interface and implementation
Quick update - PR should be ready for another round of reviews. Some notes on changes:
Note that the sample size assignment in the result distribution test had to be hardcoded due to its calculation in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice and clean work in such a short time 👌🏼 Thank you!
I didn't think of the complexity of having to batch the queries (and the txs and scripts that had to be implemented). I suggest to merge the PR in its current state, and that we continue to think of a way to simplify the tests. We can add/modify the tools in crypto/random
if that helps.
In particular I'm thinking if there is a way to make a transaction return a value somehow (maybe through the transaction results?).
Suggestions on simplifying the tests are welcome!
let receipt <- signer.load<@CoinToss.Receipt>(from: CoinToss.ReceiptStoragePath) | ||
?? panic("No Receipt found!") | ||
|
||
// Reveal by redeeming my receipt | ||
// Reveal by redeeming my receipt - fingers crossed! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤞🏼
// calls a script which creates a new PRG struct from the given seed and | ||
// random salt, gets the next uint64 and destroys the prg resource before | ||
// returning the next uint64 | ||
func GetNextUInt64NewPRGRandSalt( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this function isn't used and can be deleted
|
||
// get the results in batches again due to query computational limit | ||
results := make([]uint64, sampleSize) | ||
ProcessBatches(sampleSize, maxBatchSize, func(startIdx, batchSize int) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apologies, my suggestion on how to structure the test wasn't simple to implement! I missed the computation limit on both the transaction (generating the randoms) and script (reading the randoms), and didn't think we may need to perform that in batches.
Nice and clean implementation 👌🏼
var sampleSize int | ||
|
||
// taken from BasicDistributionTest constants - hardcoding here is | ||
/// fragile, but it's determined within flow-go/crypto/rand_utils |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this part to get the sampleSize
isn't ideal, I also missed that this should have been exported by the tools in flow-go/crypto/random
just like BasicDistributionTest
.
My last comment is about the repo structure and whether developers can be confused about what’s a test, example and production code. For instance /contracts contains 2 production contracts (history + xorshift) and 1 example (cointoss). Same for /transaction where there are also test transactions. I’m wondering if it’s better to have a /test subfolder and /example subfolder under /contracts , /transactions and /scripts , or another way to clear the possible confusion. |
Co-authored-by: Tarak Ben Youssef <[email protected]>
Thank you @tarakby!
Good point. Just to make sure main is updated ASAP, I'll merge PR as-is and create a fast-follow PR with a directory restructure. |
Closes: #3
Introduces statistical tests for the xorshift128+ implementation in
PseudoRandomGenerator
contract, asserting a uniform distribution across a sample of UInt64 random results.