Skip to content
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

feat: Cycle Group Fuzzer #12154

Merged
merged 5 commits into from
Feb 27, 2025
Merged

feat: Cycle Group Fuzzer #12154

merged 5 commits into from
Feb 27, 2025

Conversation

Sarkoxed
Copy link
Contributor

This pr introduces a fuzzer for stdlib::primitives::cycle_group

@Sarkoxed Sarkoxed self-assigned this Feb 20, 2025
@Sarkoxed Sarkoxed added the product-security PRs extending our security mechanisms label Feb 20, 2025
@Sarkoxed Sarkoxed marked this pull request as ready for review February 20, 2025 17:03
@Sarkoxed Sarkoxed requested a review from Rumata888 February 24, 2025 16:37
@Sarkoxed Sarkoxed marked this pull request as draft February 24, 2025 17:54
@Sarkoxed Sarkoxed marked this pull request as ready for review February 24, 2025 17:55
Element(ScalarField s = ScalarField::one(), GroupElement g = GroupElement::one())
: scalar(s)
, value(g){};
// Element(GroupElement& el)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need this?

uint256_t temp;
// Generate a random mask_size-bit value
// We want to sample from log distribution instead of uniform
uint16_t* p = (uint16_t*)&temp;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FastRandom generates 32-bit values, you can generate faster

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, not really. It generates 31-bit values + a little bit more. I can change the parameters to p1, a, b=(4294967291, 38978, 1337) so that it would generate 32 bit values better though.

It's not a strong prime, unlike the current one. But I don't see how a strong one could benefit the generator

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just too scared to look at these 13%...

In [1]: p = 3758096939
In [2]: p / 2**32
Out[2]: 0.8750001292210072

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ok, no problem then

// Instruction arguments
ArgumentContents arguments;

template <typename T> static inline uint256_t fast_uint256_log(T& rng)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name doesn't really explain well what's happening here. Either comments or a rename would help

e.scalar = ScalarField::one().sqrt().second.invert();
break;
case 5:
e.scalar = ScalarField::get_root_of_unity(13);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 13?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a small prime factor of the multiplicative group order. Could be 9 or 6.

// this->scalar = 0;
// }
ScalarField scalar;
GroupElement value;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you using group elements?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the AffineElement's operations first cast to GroupElement and then are cast back. Just cut out the middle man

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's ok, but I don't think changing the projective coordinates affects the cycle group representation at all, so you have a mutation that only affect the native implementation. Since we're fuzzing the circuit one, it's probably wasted effort

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, thought of that too

PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.mulArgs.in);
PUT_RANDOM_BYTE_IF_LUCKY(instruction.arguments.mulArgs.out);
if (rng.next() & 1) {
instruction.arguments.mulArgs.scalar = ScalarField(Instruction::fast_uint256_log(rng));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not change it in other ways, too? You are just substituting with a random value, but you could alternatively mutate it in the same way we usually mutate fields

size_t ind =
rng.next() % static_cast<size_t>(instruction.arguments.batchMulArgs.add_elements_count);
instruction.arguments.batchMulArgs.scalars[ind] =
ScalarField(Instruction::fast_uint256_log(rng));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here


cycle_group_t cg() const
{
const bool reconstruct = static_cast<bool>(VarianceRNG.next() % 2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your randomseed weight is zero, so rng might not change unless the call order is different

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by that? Why rng might not change?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right, I mixed up mutation weights and construction weights. No, it should work, sorry

*/
class InstructionWeights {
public:
static constexpr size_t SET = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do these instructions have a zero weight?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed SET_INF weight to 2. The other two ops cost nothing, so I thought we can use them as much as possible. Like in bigfield fuzzer

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, yes, you're right

Copy link
Contributor

@Rumata888 Rumata888 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do the rename and update the scalar field mutations and then merge

@Sarkoxed Sarkoxed merged commit 061189d into master Feb 27, 2025
9 checks passed
@Sarkoxed Sarkoxed deleted the as/fuzzing-cycle-group branch February 27, 2025 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
product-security PRs extending our security mechanisms
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants