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

Fix: Prevent underconstraint in xor(), and(), and not() functions #1745

Merged
merged 5 commits into from
Jul 19, 2024

Conversation

MartinMinkov
Copy link
Contributor

@MartinMinkov MartinMinkov commented Jul 11, 2024

Overview

This PR addresses a potential overflow vulnerability in the bitwise operations (xor, and, not) as identified in a recent audit. The changes reduce the maximum allowed bit length from 254 to 240 bits and refactor the bit length validation logic to prevent underconstraining of circuits.

Changes

  1. Reduced maximum bit length from 254 to 240 for xor, and, and not operations.
  2. Extracted bit length validation logic into a separate function validateBitLength() to reduce code duplication and ensure consistent checks across all bitwise operations.
  3. Updated error messages to provide more context and clarity.
  4. Adjusted test cases to reflect the new 240-bit limit.

Motivation

The audit revealed that for input lengths between 240 and 254 bits, the padLength calculation could result in a 256-bit value, potentially causing an overflow when constraining the weighted sum of 16-bit limbs. This could lead to underconstrained circuits, posing a security risk.

Technical Details

  • xor(), and(), and not() functions now use a maximum length of 240 bits.
  • A new validateBitLength() function handles input validation for all bitwise operations.
  • The padLength calculation remains unchanged, but with the new 240-bit limit, it will never exceed 240 bits (next multiple of 16).

Testing

Updated existing test cases in bitwise.unit-test.ts to use 240 bits instead of 254.
Added new test cases to verify behavior at the new maximum length.

@MartinMinkov MartinMinkov force-pushed the audit/bound-check-pad-length branch from 2430572 to ab43852 Compare July 11, 2024 22:49
length < Field.sizeInBits,
`Length ${length} exceeds maximum of ${Field.sizeInBits} bits.`
);
validateBitLength(length, Field.sizeInBits, 'not');
Copy link
Collaborator

Choose a reason for hiding this comment

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

not() also pads the length so let's do 240 here as well

length <= Field.sizeInBits,
`Length ${length} exceeds maximum of ${Field.sizeInBits} bits.`
);
validateBitLength(length, Field.sizeInBits, 'and');
Copy link
Collaborator

Choose a reason for hiding this comment

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

and() also pads the length so let's do 240 here as well

@mitschabaude
Copy link
Collaborator

Should probably be targetting v2

not necessary IMO

@MartinMinkov MartinMinkov force-pushed the audit/bound-check-pad-length branch from 5d34ad4 to 8fe7149 Compare July 16, 2024 18:48
@MartinMinkov MartinMinkov force-pushed the audit/bound-check-pad-length branch from 8fe7149 to aeedff1 Compare July 18, 2024 17:21
Copy link
Member

@Trivo25 Trivo25 left a comment

Choose a reason for hiding this comment

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

let's add a small note to the doc comments as well

@@ -343,3 +326,17 @@ function leftShift32(field: Field, bits: number) {
let { remainder: shifted } = divMod32(field.mul(1n << BigInt(bits)));
return shifted;
}

function validateBitLength(
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice abstraction!

…e function to reduce code duplication

refactor(bitwise): reduce maximum bit length for xor operation from 254 to 240 bits to improve performance and simplify implementation
docs(bitwise): improve error messages for bit length validation to provide more context and clarity on the cause of the error
…40 in validateBitLength calls

The hardcoded value of 240 is now used instead of Field.sizeInBits when calling the validateBitLength function in the not and and functions. This change was made to avoid relying on the Field.sizeInBits property and instead use a fixed value for the maximum bit length validation. Using a hardcoded value provides more explicit control over the allowed bit length and reduces the dependency on the Field class.
…r, notUnchecked, notChecked methods and error message

The bit size was reduced from 254 to 240 in multiple places within the Bitwise ZkProgram and the corresponding test case. This change was likely made to optimize performance or to align with some specific requirements of the application. By using a smaller bit size, the computations and proofs involving bitwise operations will be more efficient in terms of time and space complexity.
…nd operations from 254 to 240 bits to improve performance and simplify implementation
@MartinMinkov MartinMinkov force-pushed the audit/bound-check-pad-length branch from aeedff1 to d840bd9 Compare July 19, 2024 18:19
…bit length at 240 bits in not(), xor(), and and() functions to prevent potential underconstraint issues in the circuit

docs(bitwise): add JSDoc comments for validateBitLength() function to describe its purpose, parameters, and thrown error
@MartinMinkov MartinMinkov merged commit 5b08adb into main Jul 19, 2024
22 of 24 checks passed
@MartinMinkov MartinMinkov deleted the audit/bound-check-pad-length branch July 19, 2024 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants