Skip to content

Conversation

mratsim
Copy link
Owner

@mratsim mratsim commented Jul 16, 2024

Constantine implements a fused inversion+multiply (FIM) that does FIM(a, F, p) = F.a⁻¹ (mod p)

This allows inversion in the Montgomery domain without converting back-and-forth in the canonical representation.

As a reminder, in the Montgomery domain we map a to a' with a' = aR (mod p) with R a magic constant, for example for Fr[BLS12_381] which is 255 bits, R = 2⁶⁴*⁴ (mod p) i.e. the next multiple of the word size that can fully store the modulus p.

Hence a'⁻¹ = a⁻¹R (mod p) = (aR)⁻¹.R² (mod p) = FIM(a', R², p)

Unfortunately the code was shortcutting when a' == 1 to 1 instead of F.

func invmod_vartime*(
r: var Limbs, a: Limbs,
F, M: Limbs, bits: static int) {.tags:[VarTime].} =
## Compute the scaled modular inverse of ``a`` modulo M
## r ≡ F.a⁻¹ (mod M)
##
## M MUST be odd, M does not need to be prime.
## ``a`` MUST be less than M.
if a.isZero().bool:
r.setZero()
return
if a.isOne().bool:
r.setOne()
return

Impact

Fortunately at the protocol-level Constantine only uses vartime inversion in MSM and KZG:

  • MSM are used together with transcript/randomness so that an attacker does not control the inputs
  • KZG SRS are spec-level
  • It's also used for a random evaluation point (from transcript) minus roots of unity

In particular BLS signatures do not use inv_vartime in finalExpEasy

image

cc @guidovranken

@mratsim mratsim added the bug 🪲 Something isn't working label Jul 16, 2024
@mratsim mratsim merged commit 4f31dcb into master Jul 16, 2024
@mratsim mratsim deleted the fuzz-bug-inv-vartime branch July 16, 2024 08:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🪲 Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant