-
-
Notifications
You must be signed in to change notification settings - Fork 63
tests: koala and babybear field ops #580
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
base: master
Are you sure you want to change the base?
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.
Summary of Changes
Hello @agnxsh, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request significantly enhances the test coverage for the BabyBear and KoalaBear finite fields. It introduces new tests for core arithmetic operations (addition, subtraction, multiplication), validates field I/O, and ensures the consistency of modular squaring. These additions improve the robustness and reliability of these critical cryptographic components.
Highlights
- New Field Operation Tests: Comprehensive unit tests have been added for addition, subtraction, and multiplication operations for both BabyBear and KoalaBear finite fields.
- Field I/O Operation Tests: Tests for field input/output (marshalling) operations have been introduced for BabyBear and KoalaBear.
- Modular Squaring Consistency: Sanity checks have been extended to include BabyBear and KoalaBear, ensuring modular squaring consistency with multiplication.
- Curve Configuration Update: The testingCurve flag has been set to true for both BabyBear and KoalaBear curves to enable their use in testing environments.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
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.
Code Review
This pull request adds a comprehensive set of tests for the KoalaBear and BabyBear fields, covering basic arithmetic operations, I/O, and sanity checks for modular squaring. The changes are well-structured and the test cases, including edge cases, are relevant. My feedback focuses on improving the maintainability of the test code by reducing duplication through helper functions and removing hardcoded magic numbers.
| test "Addition mod 2^31 - 2^27 + 1": | ||
| block: | ||
| var x, y, z: Fp[BabyBear] | ||
|
|
||
| x.fromUint(80'u32) | ||
| y.fromUint(10'u32) | ||
| z.fromUint(90'u32) | ||
|
|
||
| x += y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 90'u32 | ||
|
|
||
| block: | ||
| var x, y, z: Fp[BabyBear] | ||
|
|
||
| x.fromUint(0x78000000'u32) # p-1 | ||
| y.fromUint(1'u32) | ||
| z.fromUint(0'u32) | ||
|
|
||
| x += y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 0'u32 | ||
|
|
||
| test "Substraction mod 2^31 - 2^27 + 1": | ||
| block: | ||
| var x, y, z: Fp[BabyBear] | ||
|
|
||
| x.fromUint(80'u32) | ||
| y.fromUint(10'u32) | ||
| z.fromUint(70'u32) | ||
|
|
||
| x -= y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 70'u32 | ||
|
|
||
| block: | ||
| var x, y, z: Fp[BabyBear] | ||
|
|
||
| x.fromUint(0'u32) | ||
| y.fromUint(1'u32) | ||
| z.fromUint(0x78000000'u32) # p-1 | ||
|
|
||
| x -= y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 0x78000000'u32 | ||
|
|
||
| test "Multiplication mod 2^31 - 2^27 + 1": | ||
| block: | ||
| var x, y, z, r: Fp[BabyBear] | ||
|
|
||
| x.fromUint(10'u32) | ||
| y.fromUint(10'u32) | ||
| z.fromUint(100'u32) | ||
|
|
||
| r.prod(x, y) | ||
|
|
||
| var r_bytes: array[4, byte] | ||
| r_bytes.marshal(r, cpuEndian) | ||
| let new_r = cast[uint32](r_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == r) | ||
| # Check equality when converting back to natural domain | ||
| new_r == 100'u32 | ||
|
|
||
| block: | ||
| var x, y, z, r: Fp[BabyBear] | ||
|
|
||
| x.fromUint(0x10000'u32) | ||
| y.fromUint(0x10000'u32) | ||
| z.fromUint(uint32((0x10000'u64 * 0x10000'u64) mod 0x78000001'u64)) | ||
|
|
||
| r.prod(x, y) | ||
|
|
||
| var r_bytes: array[4, byte] | ||
| r_bytes.marshal(r, cpuEndian) | ||
| let new_r = cast[uint32](r_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == r) | ||
| # Check equality when converting back to natural domain | ||
| new_r == uint32((0x10000'u64 * 0x10000'u64) mod 0x78000001'u64) | ||
|
|
||
| test "Addition mod 2^31 - 2^24 + 1": | ||
| block: | ||
| var x, y, z: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(50'u32) | ||
| y.fromUint(20'u32) | ||
| z.fromUint(70'u32) | ||
|
|
||
| x += y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 70'u32 | ||
|
|
||
| block: | ||
| var x, y, z: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(0x7f000000'u32) # p-1 | ||
| y.fromUint(1'u32) | ||
| z.fromUint(0'u32) | ||
|
|
||
| x += y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 0'u32 | ||
|
|
||
| test "Substraction mod 2^31 - 2^24 + 1": | ||
| block: | ||
| var x, y, z: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(70'u32) | ||
| y.fromUint(20'u32) | ||
| z.fromUint(50'u32) | ||
|
|
||
| x -= y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 50'u32 | ||
|
|
||
| block: | ||
| var x, y, z: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(0'u32) | ||
| y.fromUint(1'u32) | ||
| z.fromUint(0x7f000000'u32) # p-1 | ||
|
|
||
| x -= y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 0x7f000000'u32 | ||
|
|
||
| test "Multiplication mod 2^31 - 2^24 + 1": | ||
| block: | ||
| var x, y, z, r: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(12'u32) | ||
| y.fromUint(12'u32) | ||
| z.fromUint(144'u32) | ||
|
|
||
| r.prod(x, y) | ||
|
|
||
| var r_bytes: array[4, byte] | ||
| r_bytes.marshal(r, cpuEndian) | ||
| let new_r = cast[uint32](r_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == r) | ||
| # Check equality when converting back to natural domain | ||
| new_r == 144'u32 | ||
|
|
||
| block: | ||
| var x, y, z, r: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(0x10000'u32) | ||
| y.fromUint(0x20000'u32) | ||
| z.fromUint(uint32((0x10000'u64 * 0x20000'u64) mod 0x7f000001'u64)) | ||
|
|
||
| r.prod(x, y) | ||
|
|
||
| var r_bytes: array[4, byte] | ||
| r_bytes.marshal(r, cpuEndian) | ||
| let new_r = cast[uint32](r_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == r) | ||
| # Check equality when converting back to natural domain | ||
| new_r == uint32((0x10000'u64 * 0x20000'u64) mod 0x7f000001'u64) | ||
|
|
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 tests for BabyBear and KoalaBear contain a lot of duplicated code for addition, subtraction, and multiplication. This can be refactored using helper procedures to make the tests more concise and maintainable.
Here are some example helper procedures you could add:
proc testAdd[F: static Algebra](x_val, y_val, z_val: uint32) =
var x, y, z: Fp[F]
x.fromUint(x_val)
y.fromUint(y_val)
z.fromUint(z_val)
x += y
var x_bytes: array[4, byte]
x_bytes.marshal(x, cpuEndian)
let new_x = cast[uint32](x_bytes)
check:
bool(z == x)
new_x == z_val
proc testSub[F: static Algebra](x_val, y_val, z_val: uint32) =
var x, y, z: Fp[F]
x.fromUint(x_val)
y.fromUint(y_val)
z.fromUint(z_val)
x -= y
var x_bytes: array[4, byte]
x_bytes.marshal(x, cpuEndian)
let new_x = cast[uint32](x_bytes)
check:
bool(z == x)
new_x == z_val
proc testMul[F: static Algebra](x_val, y_val, z_val: uint32) =
var x, y, z, r: Fp[F]
x.fromUint(x_val)
y.fromUint(y_val)
z.fromUint(z_val)
r.prod(x, y)
var r_bytes: array[4, byte]
r_bytes.marshal(r, cpuEndian)
let new_r = cast[uint32](r_bytes)
check:
bool(z == r)
new_r == z_valWith these helpers, the tests become much simpler, for example:
test "Addition mod 2^31 - 2^27 + 1":
testAdd[BabyBear](80'u32, 10'u32, 90'u32)
testAdd[BabyBear](0x78000000'u32, 1'u32, 0'u32)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 a valid suggestion by Gemini
| # BabyBear --------------------------------- | ||
| block: | ||
| # "Little-endian" - 0 | ||
| let x = 0'u64 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[BabyBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - 1 | ||
| let x = 1'u64 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[BabyBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - 2^15 | ||
| let x = 1'u64 shl 15 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[BabyBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - p-1 | ||
| let x = 2013265921'u64 - 1 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[BabyBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| # KoalaBear --------------------------------- | ||
| block: | ||
| # "Little-endian" - 0 | ||
| let x = 0'u64 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[KoalaBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - 1 | ||
| let x = 1'u64 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[KoalaBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - 2^15 | ||
| let x = 1'u64 shl 15 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[KoalaBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - p-1 | ||
| let x = 2130706433'u64 - 1 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[KoalaBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
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.
There's a lot of repeated code in the IO tests for BabyBear and KoalaBear. You could reduce this duplication by creating a helper procedure. This would make the tests more concise and easier to maintain.
Here's an example of a helper procedure:
proc checkFieldIO[F: static Algebra](value: uint64) =
let x_bytes = cast[array[8, byte]](value)
var f: Fp[F]
f.fromUint(value)
var r_bytes: array[8, byte]
marshal(r_bytes, f, littleEndian)
check: x_bytes == r_bytesThen you could refactor the test blocks like this:
# BabyBear ---------------------------------
block:
# "Little-endian" - 0
checkFieldIO[BabyBear](0'u64)
block:
# "Little-endian" - 1
checkFieldIO[BabyBear](1'u64)
# ... and so on for other test cases and KoalaBear.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 a valid suggestion by gemini
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.
just first pass
| # ----------------------------------------------------------------------------- | ||
|
|
||
| curve BabyBear: # BabyBear field used in SNARKs and zkVMs | ||
| testingCurve: true |
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.
Testing curves is for fields/curves that aren't used in end-user applications like mod 101, it's unnecessary here
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.
fixing
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.
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 most important test files is t_finite_fields_vs_gmp.nim which enables comprehensive differential fuzzing vs GMP.
The other files are light sanity checks.
| test "Addition mod 2^31 - 2^27 + 1": | ||
| block: | ||
| var x, y, z: Fp[BabyBear] | ||
|
|
||
| x.fromUint(80'u32) | ||
| y.fromUint(10'u32) | ||
| z.fromUint(90'u32) | ||
|
|
||
| x += y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 90'u32 | ||
|
|
||
| block: | ||
| var x, y, z: Fp[BabyBear] | ||
|
|
||
| x.fromUint(0x78000000'u32) # p-1 | ||
| y.fromUint(1'u32) | ||
| z.fromUint(0'u32) | ||
|
|
||
| x += y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 0'u32 | ||
|
|
||
| test "Substraction mod 2^31 - 2^27 + 1": | ||
| block: | ||
| var x, y, z: Fp[BabyBear] | ||
|
|
||
| x.fromUint(80'u32) | ||
| y.fromUint(10'u32) | ||
| z.fromUint(70'u32) | ||
|
|
||
| x -= y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 70'u32 | ||
|
|
||
| block: | ||
| var x, y, z: Fp[BabyBear] | ||
|
|
||
| x.fromUint(0'u32) | ||
| y.fromUint(1'u32) | ||
| z.fromUint(0x78000000'u32) # p-1 | ||
|
|
||
| x -= y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 0x78000000'u32 | ||
|
|
||
| test "Multiplication mod 2^31 - 2^27 + 1": | ||
| block: | ||
| var x, y, z, r: Fp[BabyBear] | ||
|
|
||
| x.fromUint(10'u32) | ||
| y.fromUint(10'u32) | ||
| z.fromUint(100'u32) | ||
|
|
||
| r.prod(x, y) | ||
|
|
||
| var r_bytes: array[4, byte] | ||
| r_bytes.marshal(r, cpuEndian) | ||
| let new_r = cast[uint32](r_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == r) | ||
| # Check equality when converting back to natural domain | ||
| new_r == 100'u32 | ||
|
|
||
| block: | ||
| var x, y, z, r: Fp[BabyBear] | ||
|
|
||
| x.fromUint(0x10000'u32) | ||
| y.fromUint(0x10000'u32) | ||
| z.fromUint(uint32((0x10000'u64 * 0x10000'u64) mod 0x78000001'u64)) | ||
|
|
||
| r.prod(x, y) | ||
|
|
||
| var r_bytes: array[4, byte] | ||
| r_bytes.marshal(r, cpuEndian) | ||
| let new_r = cast[uint32](r_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == r) | ||
| # Check equality when converting back to natural domain | ||
| new_r == uint32((0x10000'u64 * 0x10000'u64) mod 0x78000001'u64) | ||
|
|
||
| test "Addition mod 2^31 - 2^24 + 1": | ||
| block: | ||
| var x, y, z: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(50'u32) | ||
| y.fromUint(20'u32) | ||
| z.fromUint(70'u32) | ||
|
|
||
| x += y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 70'u32 | ||
|
|
||
| block: | ||
| var x, y, z: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(0x7f000000'u32) # p-1 | ||
| y.fromUint(1'u32) | ||
| z.fromUint(0'u32) | ||
|
|
||
| x += y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 0'u32 | ||
|
|
||
| test "Substraction mod 2^31 - 2^24 + 1": | ||
| block: | ||
| var x, y, z: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(70'u32) | ||
| y.fromUint(20'u32) | ||
| z.fromUint(50'u32) | ||
|
|
||
| x -= y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 50'u32 | ||
|
|
||
| block: | ||
| var x, y, z: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(0'u32) | ||
| y.fromUint(1'u32) | ||
| z.fromUint(0x7f000000'u32) # p-1 | ||
|
|
||
| x -= y | ||
|
|
||
| var x_bytes: array[4, byte] | ||
| x_bytes.marshal(x, cpuEndian) | ||
| let new_x = cast[uint32](x_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == x) | ||
| # Check equality when converting back to natural domain | ||
| new_x == 0x7f000000'u32 | ||
|
|
||
| test "Multiplication mod 2^31 - 2^24 + 1": | ||
| block: | ||
| var x, y, z, r: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(12'u32) | ||
| y.fromUint(12'u32) | ||
| z.fromUint(144'u32) | ||
|
|
||
| r.prod(x, y) | ||
|
|
||
| var r_bytes: array[4, byte] | ||
| r_bytes.marshal(r, cpuEndian) | ||
| let new_r = cast[uint32](r_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == r) | ||
| # Check equality when converting back to natural domain | ||
| new_r == 144'u32 | ||
|
|
||
| block: | ||
| var x, y, z, r: Fp[KoalaBear] | ||
|
|
||
| x.fromUint(0x10000'u32) | ||
| y.fromUint(0x20000'u32) | ||
| z.fromUint(uint32((0x10000'u64 * 0x20000'u64) mod 0x7f000001'u64)) | ||
|
|
||
| r.prod(x, y) | ||
|
|
||
| var r_bytes: array[4, byte] | ||
| r_bytes.marshal(r, cpuEndian) | ||
| let new_r = cast[uint32](r_bytes) | ||
|
|
||
| check: | ||
| # Check equality in the Montgomery domain | ||
| bool(z == r) | ||
| # Check equality when converting back to natural domain | ||
| new_r == uint32((0x10000'u64 * 0x20000'u64) mod 0x7f000001'u64) | ||
|
|
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 a valid suggestion by Gemini
| # BabyBear --------------------------------- | ||
| block: | ||
| # "Little-endian" - 0 | ||
| let x = 0'u64 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[BabyBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - 1 | ||
| let x = 1'u64 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[BabyBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - 2^15 | ||
| let x = 1'u64 shl 15 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[BabyBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - p-1 | ||
| let x = 2013265921'u64 - 1 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[BabyBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| # KoalaBear --------------------------------- | ||
| block: | ||
| # "Little-endian" - 0 | ||
| let x = 0'u64 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[KoalaBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - 1 | ||
| let x = 1'u64 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[KoalaBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - 2^15 | ||
| let x = 1'u64 shl 15 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[KoalaBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
||
| block: | ||
| # "Little-endian" - p-1 | ||
| let x = 2130706433'u64 - 1 | ||
| let x_bytes = cast[array[8, byte]](x) | ||
| var f: Fp[KoalaBear] | ||
| f.fromUint(x) | ||
|
|
||
| var r_bytes: array[8, byte] | ||
| marshal(r_bytes, f, littleEndian) | ||
| check: x_bytes == r_bytes | ||
|
|
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 a valid suggestion by gemini
Addressing #573
Consists tests for :