Skip to content

Commit

Permalink
Attach field properties to an instantiated field instead of the curve…
Browse files Browse the repository at this point in the history
… enum
  • Loading branch information
mratsim committed Jan 20, 2021
1 parent dc7a8a9 commit 4bb786a
Show file tree
Hide file tree
Showing 48 changed files with 257 additions and 228 deletions.
2 changes: 1 addition & 1 deletion benchmarks/bench_fields_template.nim
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ proc invEuclidBench*(T: typedesc, iters: int) =

proc invPowFermatBench*(T: typedesc, iters: int) =
let x = rng.random_unsafe(T)
const exponent = T.C.getInvModExponent()
const exponent = T.getInvModExponent()
bench("Inversion via exponentiation p-2 (Little Fermat)", T, iters):
var r = x
r.powUnsafeExponent(exponent)
Expand Down
58 changes: 29 additions & 29 deletions constantine/arithmetic/finite_fields.nim
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import
../primitives,
../config/[common, type_fp, type_fr, curves],
../config/[common, type_ff, curves],
./bigints, ./limbs_montgomery

when UseASM_X86_64:
Expand All @@ -37,7 +37,7 @@ when nimvm:
else:
discard

export Fp, Fr
export Fp, Fr, FF

# No exceptions allowed
{.push raises: [].}
Expand All @@ -48,12 +48,12 @@ export Fp, Fr
#
# ############################################################

func fromBig*[C: static Curve](dst: var Fp[C], src: BigInt) {.inline.}=
func fromBig*(dst: var Fp, src: BigInt) {.inline.}=
## Convert a BigInt to its Montgomery form
when nimvm:
dst.mres.montyResidue_precompute(src, C.Mod, C.getR2modP(), C.getNegInvModWord())
dst.mres.montyResidue_precompute(src, Fp.C.Mod, Fp.getR2modP(), Fp.getNegInvModWord())
else:
dst.mres.montyResidue(src, C.Mod, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
dst.mres.montyResidue(src, Fp.C.Mod, Fp.getR2modP(), Fp.getNegInvModWord(), Fp.canUseNoCarryMontyMul())

func fromBig*[C: static Curve](T: type Fp[C], src: BigInt): Fp[C] {.noInit, inline.} =
## Convert a BigInt to its Montgomery form
Expand All @@ -62,7 +62,7 @@ func fromBig*[C: static Curve](T: type Fp[C], src: BigInt): Fp[C] {.noInit, inli
func toBig*(src: Fp): auto {.noInit, inline.} =
## Convert a finite-field element to a BigInt in natural representation
var r {.noInit.}: typeof(src.mres)
r.redc(src.mres, Fp.C.Mod, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontyMul())
r.redc(src.mres, Fp.C.Mod, Fp.getNegInvModWord(), Fp.canUseNoCarryMontyMul())
return r

# Copy
Expand Down Expand Up @@ -113,11 +113,11 @@ func isZero*(a: Fp): SecretBool {.inline.} =

func isOne*(a: Fp): SecretBool {.inline.} =
## Constant-time check if one
a.mres == Fp.C.getMontyOne()
a.mres == Fp.getMontyOne()

func isMinusOne*(a: Fp): SecretBool {.inline.} =
## Constant-time check if -1 (mod p)
a.mres == Fp.C.getMontyPrimeMinus1()
a.mres == Fp.getMontyPrimeMinus1()

func setZero*(a: var Fp) {.inline.} =
## Set ``a`` to zero
Expand All @@ -128,7 +128,7 @@ func setOne*(a: var Fp) {.inline.} =
# Note: we need 1 in Montgomery residue form
# TODO: Nim codegen is not optimal it uses a temporary
# Check if the compiler optimizes it away
a.mres = Fp.C.getMontyOne()
a.mres = Fp.getMontyOne()

func `+=`*(a: var Fp, b: Fp) {.inline.} =
## In-place addition modulo p
Expand Down Expand Up @@ -213,11 +213,11 @@ func double*(r: var Fp, a: Fp) {.inline.} =
func prod*(r: var Fp, a, b: Fp) {.inline.} =
## Store the product of ``a`` by ``b`` modulo p into ``r``
## ``r`` is initialized / overwritten
r.mres.montyMul(a.mres, b.mres, Fp.C.Mod, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontyMul())
r.mres.montyMul(a.mres, b.mres, Fp.C.Mod, Fp.getNegInvModWord(), Fp.canUseNoCarryMontyMul())

func square*(r: var Fp, a: Fp) {.inline.} =
## Squaring modulo p
r.mres.montySquare(a.mres, Fp.C.Mod, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontySquare())
r.mres.montySquare(a.mres, Fp.C.Mod, Fp.getNegInvModWord(), Fp.canUseNoCarryMontySquare())

func neg*(r: var Fp, a: Fp) {.inline.} =
## Negate modulo p
Expand All @@ -235,7 +235,7 @@ func neg*(a: var Fp) {.inline.} =

func div2*(a: var Fp) {.inline.} =
## Modular division by 2
a.mres.div2_modular(Fp.C.getPrimePlus1div2())
a.mres.div2_modular(Fp.getPrimePlus1div2())

# ############################################################
#
Expand Down Expand Up @@ -284,10 +284,10 @@ func pow*(a: var Fp, exponent: BigInt) {.inline.} =
const windowSize = 5 # TODO: find best window size for each curves
a.mres.montyPow(
exponent,
Fp.C.Mod, Fp.C.getMontyOne(),
Fp.C.getNegInvModWord(), windowSize,
Fp.C.canUseNoCarryMontyMul(),
Fp.C.canUseNoCarryMontySquare()
Fp.C.Mod, Fp.getMontyOne(),
Fp.getNegInvModWord(), windowSize,
Fp.canUseNoCarryMontyMul(),
Fp.canUseNoCarryMontySquare()
)

func pow*(a: var Fp, exponent: openarray[byte]) {.inline.} =
Expand All @@ -297,10 +297,10 @@ func pow*(a: var Fp, exponent: openarray[byte]) {.inline.} =
const windowSize = 5 # TODO: find best window size for each curves
a.mres.montyPow(
exponent,
Fp.C.Mod, Fp.C.getMontyOne(),
Fp.C.getNegInvModWord(), windowSize,
Fp.C.canUseNoCarryMontyMul(),
Fp.C.canUseNoCarryMontySquare()
Fp.C.Mod, Fp.getMontyOne(),
Fp.getNegInvModWord(), windowSize,
Fp.canUseNoCarryMontyMul(),
Fp.canUseNoCarryMontySquare()
)

func powUnsafeExponent*(a: var Fp, exponent: BigInt) {.inline.} =
Expand All @@ -317,10 +317,10 @@ func powUnsafeExponent*(a: var Fp, exponent: BigInt) {.inline.} =
const windowSize = 5 # TODO: find best window size for each curves
a.mres.montyPowUnsafeExponent(
exponent,
Fp.C.Mod, Fp.C.getMontyOne(),
Fp.C.getNegInvModWord(), windowSize,
Fp.C.canUseNoCarryMontyMul(),
Fp.C.canUseNoCarryMontySquare()
Fp.C.Mod, Fp.getMontyOne(),
Fp.getNegInvModWord(), windowSize,
Fp.canUseNoCarryMontyMul(),
Fp.canUseNoCarryMontySquare()
)

func powUnsafeExponent*(a: var Fp, exponent: openarray[byte]) {.inline.} =
Expand All @@ -337,10 +337,10 @@ func powUnsafeExponent*(a: var Fp, exponent: openarray[byte]) {.inline.} =
const windowSize = 5 # TODO: find best window size for each curves
a.mres.montyPowUnsafeExponent(
exponent,
Fp.C.Mod, Fp.C.getMontyOne(),
Fp.C.getNegInvModWord(), windowSize,
Fp.C.canUseNoCarryMontyMul(),
Fp.C.canUseNoCarryMontySquare()
Fp.C.Mod, Fp.getMontyOne(),
Fp.getNegInvModWord(), windowSize,
Fp.canUseNoCarryMontyMul(),
Fp.canUseNoCarryMontySquare()
)

# ############################################################
Expand Down Expand Up @@ -377,7 +377,7 @@ func `*=`*(a: var Fp, b: Fp) {.inline.} =

func square*(a: var Fp) {.inline.} =
## Squaring modulo p
a.mres.montySquare(a.mres, Fp.C.Mod, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontySquare())
a.mres.montySquare(a.mres, Fp.C.Mod, Fp.getNegInvModWord(), Fp.canUseNoCarryMontySquare())

func square_repeated*(r: var Fp, num: int) {.inline.} =
## Repeated squarings
Expand Down
6 changes: 3 additions & 3 deletions constantine/arithmetic/finite_fields_double_width.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.

import
../config/[common, curves, type_fp],
../config/[common, curves, type_ff],
../primitives,
./bigints,
./finite_fields,
Expand Down Expand Up @@ -38,8 +38,8 @@ func reduce*(r: var Fp, a: FpDbl) {.inline.} =
r.mres.limbs,
a.limbs2x,
Fp.C.Mod.limbs,
Fp.C.getNegInvModWord(),
Fp.C.canUseNoCarryMontyMul()
Fp.getNegInvModWord(),
Fp.canUseNoCarryMontyMul()
)

func diffNoInline(r: var FpDbl, a, b: FpDbl): Borrow =
Expand Down
4 changes: 2 additions & 2 deletions constantine/arithmetic/finite_fields_inversion.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.

import
../config/[curves, type_fp],
../config/[curves, type_ff],
./bigints,
../curves/zoo_inversions

Expand All @@ -23,7 +23,7 @@ func inv_euclid*(r: var Fp, a: Fp) {.inline.} =
## Inversion modulo p via
## Niels Moller constant-time version of
## Stein's GCD derived from extended binary Euclid algorithm
r.mres.steinsGCD(a.mres, Fp.C.getR2modP(), Fp.C.Mod, Fp.C.getPrimePlus1div2())
r.mres.steinsGCD(a.mres, Fp.getR2modP(), Fp.C.Mod, Fp.getPrimePlus1div2())

func inv*(r: var Fp, a: Fp) {.inline.} =
## Inversion modulo p
Expand Down
56 changes: 28 additions & 28 deletions constantine/arithmetic/finite_fields_square_root.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import
../primitives,
../config/[common, type_fp, curves],
../config/[common, type_ff, curves],
../curves/zoo_square_roots,
./bigints, ./finite_fields

Expand All @@ -21,7 +21,7 @@ import
# Legendre symbol / Euler's Criterion / Kronecker's symbol
# ------------------------------------------------------------

func isSquare*[C](a: Fp[C]): SecretBool {.inline.} =
func isSquare*(a: Fp): SecretBool {.inline.} =
## Returns true if ``a`` is a square (quadratic residue) in 𝔽p
##
## Assumes that the prime modulus ``p`` is public.
Expand All @@ -30,7 +30,7 @@ func isSquare*[C](a: Fp[C]): SecretBool {.inline.} =
# Note that we don't care about leaking the bits of p
# as we assume that
var xi {.noInit.} = a # TODO: is noInit necessary? see https://github.com/mratsim/constantine/issues/21
xi.powUnsafeExponent(C.getPrimeMinus1div2_BE())
xi.powUnsafeExponent(Fp.getPrimeMinus1div2_BE())
result = not(xi.isMinusOne())
# xi can be:
# - 1 if a square
Expand All @@ -46,7 +46,7 @@ func isSquare*[C](a: Fp[C]): SecretBool {.inline.} =
# Specialized routine for p ≡ 3 (mod 4)
# ------------------------------------------------------------

func sqrt_p3mod4[C](a: var Fp[C]) {.inline.} =
func sqrt_p3mod4(a: var Fp) {.inline.} =
## Compute the square root of ``a``
##
## This requires ``a`` to be a square
Expand All @@ -57,10 +57,10 @@ func sqrt_p3mod4[C](a: var Fp[C]) {.inline.} =
## The square root, if it exist is multivalued,
## i.e. both x² == (-x)²
## This procedure returns a deterministic result
static: doAssert BaseType(C.Mod.limbs[0]) mod 4 == 3
a.powUnsafeExponent(C.getPrimePlus1div4_BE())
static: doAssert BaseType(Fp.C.Mod.limbs[0]) mod 4 == 3
a.powUnsafeExponent(Fp.getPrimePlus1div4_BE())

func sqrt_invsqrt_p3mod4[C](sqrt, invsqrt: var Fp[C], a: Fp[C]) {.inline.} =
func sqrt_invsqrt_p3mod4(sqrt, invsqrt: var Fp, a: Fp) {.inline.} =
## If ``a`` is a square, compute the square root of ``a`` in sqrt
## and the inverse square root of a in invsqrt
##
Expand All @@ -74,26 +74,26 @@ func sqrt_invsqrt_p3mod4[C](sqrt, invsqrt: var Fp[C], a: Fp[C]) {.inline.} =
# a^((p-1)/2)) * a^-1 ≡ 1/a (mod p)
# a^((p-3)/2)) ≡ 1/a (mod p)
# a^((p-3)/4)) ≡ 1/√a (mod p) # Requires p ≡ 3 (mod 4)
static: doAssert BaseType(C.Mod.limbs[0]) mod 4 == 3
static: doAssert BaseType(Fp.C.Mod.limbs[0]) mod 4 == 3

invsqrt = a
invsqrt.powUnsafeExponent(C.getPrimeMinus3div4_BE())
invsqrt.powUnsafeExponent(Fp.getPrimeMinus3div4_BE())
# √a ≡ a * 1/√a ≡ a^((p+1)/4) (mod p)
sqrt.prod(invsqrt, a)

func sqrt_invsqrt_if_square_p3mod4[C](sqrt, invsqrt: var Fp[C], a: Fp[C]): SecretBool {.inline.} =
func sqrt_invsqrt_if_square_p3mod4(sqrt, invsqrt: var Fp, a: Fp): SecretBool {.inline.} =
## If ``a`` is a square, compute the square root of ``a`` in sqrt
## and the inverse square root of a in invsqrt
##
## If a is not square, sqrt and invsqrt are undefined
##
## This assumes that the prime field modulus ``p``: p ≡ 3 (mod 4)
sqrt_invsqrt_p3mod4(sqrt, invsqrt, a)
var test {.noInit.}: Fp[C]
var test {.noInit.}: Fp
test.square(sqrt)
result = test == a

func sqrt_if_square_p3mod4[C](a: var Fp[C]): SecretBool {.inline.} =
func sqrt_if_square_p3mod4(a: var Fp): SecretBool {.inline.} =
## If ``a`` is a square, compute the square root of ``a``
## if not, ``a`` is unmodified.
##
Expand All @@ -104,28 +104,28 @@ func sqrt_if_square_p3mod4[C](a: var Fp[C]): SecretBool {.inline.} =
## The square root, if it exist is multivalued,
## i.e. both x² == (-x)²
## This procedure returns a deterministic result
var sqrt {.noInit.}, invsqrt {.noInit.}: Fp[C]
var sqrt {.noInit.}, invsqrt {.noInit.}: Fp
result = sqrt_invsqrt_if_square_p3mod4(sqrt, invsqrt, a)
a.ccopy(sqrt, result)

# Tonelli Shanks for any prime
# ------------------------------------------------------------

func precompute_tonelli_shanks[C](
a_pre_exp: var Fp[C],
a: Fp[C]) =
func precompute_tonelli_shanks(
a_pre_exp: var Fp,
a: Fp) =
a_pre_exp = a
a_pre_exp.powUnsafeExponent(C.tonelliShanks(exponent))
a_pre_exp.powUnsafeExponent(Fp.C.tonelliShanks(exponent))

func isSquare_tonelli_shanks[C](
a, a_pre_exp: Fp[C]): SecretBool =
func isSquare_tonelli_shanks(
a, a_pre_exp: Fp): SecretBool =
## Returns if `a` is a quadratic residue
## This uses common precomputation for
## Tonelli-Shanks based square root and inverse square root
##
## a^((p-1-2^e)/(2*2^e))
const e = C.tonelliShanks(twoAdicity)
var r {.noInit.}: Fp[C]
const e = Fp.C.tonelliShanks(twoAdicity)
var r {.noInit.}: Fp
r.square(a_pre_exp) # a^(2(q-1-2^e)/(2*2^e)) = a^((q-1)/2^e - 1)
r *= a # a^((q-1)/2^e)
for _ in 0 ..< e-1:
Expand All @@ -143,26 +143,26 @@ func isSquare_tonelli_shanks[C](
r.isMinusOne()
)

func sqrt_invsqrt_tonelli_shanks[C](
sqrt, invsqrt: var Fp[C],
a, a_pre_exp: Fp[C]) =
func sqrt_invsqrt_tonelli_shanks(
sqrt, invsqrt: var Fp,
a, a_pre_exp: Fp) =
## Compute the square_root and inverse_square_root
## of `a` via constant-time Tonelli-Shanks
##
## a_pre_exp is a precomputation a^((p-1-2^e)/(2*2^e))
## ThItat is shared with the simultaneous isSquare routine
template z: untyped = a_pre_exp
template r: untyped = invsqrt
var t {.noInit.}: Fp[C]
const e = C.tonelliShanks(twoAdicity)
var t {.noInit.}: Fp
const e = Fp.C.tonelliShanks(twoAdicity)

t.square(z)
t *= a
r = z
var b = t
var root = C.tonelliShanks(root_of_unity)
var root = Fp.C.tonelliShanks(root_of_unity)

var buf {.noInit.}: Fp[C]
var buf {.noInit.}: Fp

for i in countdown(e, 2, 1):
for j in 1 .. i-2:
Expand Down
Loading

0 comments on commit 4bb786a

Please sign in to comment.