diff --git a/constantine/math/arithmetic/finite_fields_square_root.nim b/constantine/math/arithmetic/finite_fields_square_root.nim index 7e5c1b362..a57b2fe19 100644 --- a/constantine/math/arithmetic/finite_fields_square_root.nim +++ b/constantine/math/arithmetic/finite_fields_square_root.nim @@ -10,7 +10,7 @@ import ../../platforms/abstractions, ../config/curves, ../constants/zoo_square_roots, - ./finite_fields_precomp_square_root, + ./finite_fields_square_root_precomp, ./bigints, ./finite_fields, ./limbs_exgcd # ############################################################ @@ -212,10 +212,13 @@ func invsqrt*[C](r: var Fp[C], a: Fp[C]) = elif C.has_P_5mod8_primeModulus(): r.invsqrt_p5mod8(a) elif C == Bandersnatch or C == Banderwagon: - r.inv_sqrt_precomp(a) + r.inv_sqrt_precomp_vartime(a) # should be changed else: r.invsqrt_tonelli_shanks(a) +func invsqrt_vartime*[C](r: var Fp[C], a: Fp[C]) = + r.inv_sqrt_precomp_vartime(a) + func sqrt*[C](a: var Fp[C]) = ## Compute the square root of ``a`` ## @@ -231,6 +234,14 @@ func sqrt*[C](a: var Fp[C]) = t.invsqrt(a) a *= t +func sqrt_vartime*[C](a: var Fp[C]) = + ## This is a vartime version of sqrt + ## It is not constant-time + ## This has the precomp optimisation + var t {.noInit.}: Fp[C] + t.invsqrt_vartime(a) + a *= t + func sqrt_invsqrt*[C](sqrt, invsqrt: var Fp[C], a: Fp[C]) = ## Compute the square root and inverse square root of ``a`` ## @@ -244,6 +255,12 @@ func sqrt_invsqrt*[C](sqrt, invsqrt: var Fp[C], a: Fp[C]) = invsqrt.invsqrt(a) sqrt.prod(invsqrt, a) +func sqrt_invsqrt_vartime*[C](sqrt, invsqrt: var Fp[C], a: Fp[C]) = + ## It is not constant-time + ## This has the precomp optimisation + invsqrt.invsqrt_vartime(a) + sqrt.prod(invsqrt, a) + func sqrt_invsqrt_if_square*[C](sqrt, invsqrt: var Fp[C], a: Fp[C]): SecretBool = ## Compute the square root and ivnerse square root of ``a`` ## @@ -259,6 +276,14 @@ func sqrt_invsqrt_if_square*[C](sqrt, invsqrt: var Fp[C], a: Fp[C]): SecretBool test.square(sqrt) result = test == a +func sqrt_invsqrt_if_square_vartime*[C](sqrt, invsqrt: var Fp[C], a: Fp[C]): SecretBool = + ## It is not constant-time + ## This has the precomp optimisation + sqrt_invsqrt_vartime(sqrt, invsqrt, a) + var test {.noInit.}: Fp[C] + test.square(sqrt) + result = test == a + func sqrt_if_square*[C](a: var Fp[C]): SecretBool = ## If ``a`` is a square, compute the square root of ``a`` ## if not, ``a`` is undefined. @@ -282,6 +307,12 @@ func invsqrt_if_square*[C](r: var Fp[C], a: Fp[C]): SecretBool = var sqrt{.noInit.}: Fp[C] result = sqrt_invsqrt_if_square(sqrt, r, a) +func invsqrt_if_square_vartime*[C](r: var Fp[C], a: Fp[C]): SecretBool = + ## It is not constant-time + ## This has the precomp optimisation + var sqrt{.noInit.}: Fp[C] + result = sqrt_invsqrt_if_square_vartime(sqrt, r, a) + # Legendre symbol / Euler's Criterion / Kronecker's symbol # ------------------------------------------------------------ @@ -318,4 +349,12 @@ func sqrt_ratio_if_square*(r: var Fp, u, v: Fp): SecretBool {.inline.} = result = r.invsqrt_if_square(uv) # 1/√uv r *= u # √u/√v +func sqrt_ratio_if_square_vartime*(r: var Fp, u, v: Fp): SecretBool {.inline.} = + ## It is not constant-time + ## This has the precomp optimisation + var uv{.noInit.}: Fp + uv.prod(u, v) # uv + result = r.invsqrt_if_square_vartime(uv) # 1/√uv + r *= u # √u/√v + {.pop.} # raises no exceptions diff --git a/constantine/math/arithmetic/finite_fields_precomp_square_root.nim b/constantine/math/arithmetic/finite_fields_square_root_precomp.nim similarity index 90% rename from constantine/math/arithmetic/finite_fields_precomp_square_root.nim rename to constantine/math/arithmetic/finite_fields_square_root_precomp.nim index 784c83934..a6c0c0b54 100644 --- a/constantine/math/arithmetic/finite_fields_precomp_square_root.nim +++ b/constantine/math/arithmetic/finite_fields_square_root_precomp.nim @@ -24,7 +24,7 @@ import # The returned value is only meaningful modulo 1<= 0: + P.y.fromUint uint F.C.getCoefD() + else: + P.y.fromUint uint -F.C.getCoefD() + P.y.neg() + else: + P.y = F.C.getCoefD() + P.y *= t + P.y.neg() + P.y += one + + # (1 - ax²) + when F.C.getCoefA() is int: + when F.C.getCoefA() >= 0: + P.x.fromUint uint F.C.getCoefA() + else: + P.x.fromUint uint -F.C.getCoefA() + P.x.neg() + else: + P.x = F.C.getCoefA() + P.x *= t + P.x.neg() + P.x += one + + # √((1 - ax²)/(1 - dx²)) + result = sqrt_ratio_if_square_vartime(t, P.x, P.y) + P.y = t + P.x = x func trySetFromCoordY*[F](P: var ECP_TwEdwards_Aff[F], y: F): SecretBool = ## Try to create a point the elliptic curve diff --git a/constantine/math/elliptic/ec_twistededwards_projective.nim b/constantine/math/elliptic/ec_twistededwards_projective.nim index 764c442b4..c0603318c 100644 --- a/constantine/math/elliptic/ec_twistededwards_projective.nim +++ b/constantine/math/elliptic/ec_twistededwards_projective.nim @@ -84,6 +84,25 @@ func trySetFromCoordX*[F]( P.y = Q.y P.z.setOne() +func trySetFromCoordX_vartime*[F]( + P: var ECP_TwEdwards_Prj[F], + x: F): SecretBool = + ## this is not in constant time + ## Try to create a point on the elliptic curve from X co-ordinate + ## ax²+y²=1+dx²y² (affine coordinate) + ## + ## The `Z` coordinates is set to 1 + ## + ## return true and update `P` if `y` leads to a valid point + ## return false otherwise, in that case `P` is undefined. + + var Q{.noInit.}: ECP_TwEdwards_Aff[F] + result = Q.trySetFromCoordX_vartime(x) + + P.x = Q.x + P.y = Q.y + P.z.setOne() + func trySetFromCoordY*[F]( P: var ECP_TwEdwards_Prj[F], diff --git a/constantine/serialization/codecs_banderwagon.nim b/constantine/serialization/codecs_banderwagon.nim index 8c5445dae..a4e71f180 100644 --- a/constantine/serialization/codecs_banderwagon.nim +++ b/constantine/serialization/codecs_banderwagon.nim @@ -123,7 +123,7 @@ func deserialize_unchecked*(dst: var EC_Prj, src: array[32, byte]): CttCodecEccS var x{.noInit.}: Fp[Banderwagon] x.fromBig(t) - let onCurve = dst.trySetFromCoordX(x) + let onCurve = dst.trySetFromCoordX_vartime(x) # later to be shifted to a constant time version if not(bool onCurve): return cttCodecEcc_PointNotOnCurve