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

Add a Math.inv function that inverse a number in Z/nZ #4839

Merged
merged 28 commits into from
Jan 24, 2024

Conversation

Amxx
Copy link
Collaborator

@Amxx Amxx commented Jan 17, 2024

This is a very common function use in finite fields such as the ones that power ECDSA curves.

PR Checklist

  • Tests
  • Documentation
  • Changeset entry (run npx changeset add)

@Amxx Amxx added this to the 5.1 milestone Jan 17, 2024
Copy link

changeset-bot bot commented Jan 17, 2024

🦋 Changeset detected

Latest commit: f683c96

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
openzeppelin-solidity Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@Amxx Amxx requested a review from ernestognw January 17, 2024 14:57
@Amxx Amxx added feature New contracts, functions, or helpers. Cryptography labels Jan 17, 2024
@Amxx
Copy link
Collaborator Author

Amxx commented Jan 17, 2024

Some ressources:

  • A solidity implementation that uses signed numbers instead of addmod and mulmod. Its solidity 0.5.0, and porting it nativelly in 0.8.0 causes overflows that showed up when doing fuzzing.
  • Noble's implementation in typescript: they use bigint so they don't have to do the modulo at every step. The gcd = 1 check comes from there.

All these are based on the Euclidean algorithm, and Bezout's identity. To find r such that a * r + p * k = 1 which is equivalent to saying a * r = 1 (mod p). This works when a and p are relative primes, which is always the case if p is prime, and which is verified by checking that the gcd of a and p is 1.

@ernestognw
Copy link
Member

ernestognw commented Jan 19, 2024

This is my current understanding:

  • Z is the set of natural numbers (i.e. {… , ⁻2, ⁻1, 0, 1, 2, …})
  • Z/nZ is the set of natural numbers numbers mod n (i.e. {0, 1, . . . , n − 1})

What we're providing with this function is the modular multiplicative inverse of an uint256 a in a field defined by n (it's uint256 p in the function implementation currently).

The multiplicative inverse of a is an integer x such that the product ax is congruent. This is that ax ≡ 1 (mod n), and the way to calculate such thing is using the Euclidean algorithm (runs in O(log2(n))) to find the greatest common divisor (gcd for short), and, (if gcd == 1), then the inverse x can be found from the Bezout's identity that states:

ax + ny = gcd = 1

ax + ny = 1

ax = 1 + (-y)n

ax ≡ 1 (mod n) # We've found `x`

If the gcd of a, n (i.e. gcd(a,n)) is 1, it means they're relative primes. So, for a field n to have multiplicative inverses for every value in the field, then n should be prime. This is because if n is prime, then the amount of relative primes < n is n - 1 (it excludes only the 0).

contracts/utils/math/Math.sol Outdated Show resolved Hide resolved
contracts/utils/math/Math.sol Outdated Show resolved Hide resolved
contracts/utils/math/Math.sol Outdated Show resolved Hide resolved
contracts/utils/math/Math.sol Outdated Show resolved Hide resolved
}

function testInvModP256(uint256 seed) public {
uint256 p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff; // prime
Copy link
Member

Choose a reason for hiding this comment

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

Wow now I get why the rumors of a backdoor in secp256r1, this is a weird number

ernestognw
ernestognw previously approved these changes Jan 23, 2024
Copy link
Member

@ernestognw ernestognw left a comment

Choose a reason for hiding this comment

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

LGTM

contracts/utils/math/Math.sol Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Cryptography feature New contracts, functions, or helpers.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants