Skip to content

Commit

Permalink
feat(𝔾ₜ constant-time exponentiation): implement constant-time 𝔾ₜ exp…
Browse files Browse the repository at this point in the history
…onentiation
  • Loading branch information
mratsim committed Jul 15, 2024
1 parent 776e906 commit 4f3eb84
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 10 deletions.
3 changes: 3 additions & 0 deletions benchmarks/bench_gt.nim
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ proc main() =
gtExp_endo_wNAF_vartimeBench(Fp12[curve], window = 3, ExpIters)
gtExp_endo_wNAF_vartimeBench(Fp12[curve], window = 4, ExpIters)
separator()
gtExpEndo_constanttimeBench(Fp12[curve], ExpIters)
separator()


main()
notes()
8 changes: 8 additions & 0 deletions benchmarks/bench_gt_template.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import
constantine/math/pairings/[
pairings_generic,
cyclotomic_subgroups,
gt_exponentiations,
gt_exponentiations_vartime
],
# Helpers
Expand Down Expand Up @@ -165,3 +166,10 @@ proc gtExp_endo_wNAF_vartimeBench*(T: typedesc, window: static int, iters: int)
var r {.noInit.}: T
bench("𝔾ₜ Exponentiation " & $exponent.bits & "-bit (endomorphism, wNAF-" & $window & ", vartime)", T, iters):
r.gtExpEndo_wNAF_vartime(x, exponent, window)

proc gtExpEndo_constanttimeBench*(T: typedesc, iters: int) =
let x = rng.random_gt(T)
let exponent = rng.random_unsafe(BigInt[Fr[T.Name].bits()])
var r {.noInit.}: T
bench("𝔾ₜ Exponentiation " & $exponent.bits & "-bit (endomorphism, constant-time)", T, iters):
r.gtExpEndo(x, exponent)
7 changes: 4 additions & 3 deletions constantine/math/elliptic/ec_scalar_mul.nim
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import
./ec_shortweierstrass_batch_ops,
./ec_twistededwards_batch_ops

{.push raises: [].} # No exceptions allowed in core cryptographic operations
{.push checks: off.} # No defects due to array bound checking or signed integer overflow allowed

# ############################################################
# #
# Scalar Multiplication #
Expand Down Expand Up @@ -275,7 +278,6 @@ func scalarMulEndo*[scalBits; EC](
## Requires:
## - Cofactor to be cleared
## - 0 <= scalar < curve order
const C = P.F.Name # curve
static: doAssert scalBits <= EC.getScalarField().bits(), "Do not use endomorphism to multiply beyond the curve order"

# 1. Compute endomorphisms
Expand Down Expand Up @@ -339,7 +341,7 @@ func scalarMulEndo*[scalBits; EC](
func buildEndoLookupTable_m2w2[EC, ECaff](
lut: var array[8, ECaff],
P0, P1: EC) =
## Build a lookup lutle for GLV with 2-dimensional decomposition
## Build a lookup table for GLV with 2-dimensional decomposition
## and window of size 2
# Step 1. Create the lookup-table in alternative coordinates
var tab {.noInit.}: array[8, EC]
Expand All @@ -366,7 +368,6 @@ func scalarMulGLV_m2w2*[scalBits; EC](P0: var EC, scalar: BigInt[scalBits]) {.me
## Requires:
## - Cofactor to be cleared
## - 0 <= scalar < curve order
const C = P0.F.Name # curve
static: doAssert: scalBits <= EC.getScalarField().bits()
const G = when EC isnot EC_ShortW_Aff|EC_ShortW_Jac|EC_ShortW_Prj: G1
else: EC.G
Expand Down
10 changes: 10 additions & 0 deletions constantine/math/elliptic/ec_scalar_mul_vartime.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ import
{.push raises: [].} # No exceptions allowed in core cryptographic operations
{.push checks: off.} # No defects due to array bound checking or signed integer overflow allowed

# ############################################################
# #
# Scalar Multiplication #
# variable-time #
# #
# ############################################################

iterator unpackBE(scalarByte: byte): bool =
for i in countdown(7, 0):
yield bool((scalarByte shr i) and 1)
Expand Down Expand Up @@ -172,6 +179,9 @@ func scalarMul_jy00_vartime*[EC](P: var EC, scalar: BigInt) {.tags:[VarTime].}
elif bit == -1:
P ~-= Paff

# Non-Adjacent Form (NAF) recoding
# ------------------------------------------------------------

func initNAF[precompSize, NafMax: static int, EC, ECaff](
P: var EC,
tab: array[precompSize, ECaff],
Expand Down
10 changes: 6 additions & 4 deletions constantine/math/endomorphisms/split_scalars.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ import
constantine/named/zoo_endomorphisms,
constantine/math/arithmetic/bigints

{.push raises: [].} # No exceptions allowed in core cryptographic operations
{.push checks: off.} # No defects due to array bound checking or signed integer overflow allowed

# ############################################################
#
# Endomorphism acceleration for
# Scalar Multiplication
# Splitting scalars for endomorphism acceleration
#
# ############################################################
#
Expand Down Expand Up @@ -351,10 +353,10 @@ template buildEndoLookupTable_m2w2*[Group](
lut: var array[8, Group],
P0, P1: Group,
groupLawAdd, groupLawSub, groupLawDouble: untyped) =
## Build a lookup lutle for GLV with 2-dimensional decomposition
## Build a lookup table for GLV with 2-dimensional decomposition
## and window of size 2

# Create the lookup-lutle in alternative coordinates
# Create the lookup-table in alternative coordinates
# with [k0, k1] the mini-scalars with digits of size 2-bit
#
# 4 = 0b100 - encodes [0b01, 0b00] ≡ P0
Expand Down
110 changes: 110 additions & 0 deletions constantine/math/pairings/gt_exponentiations.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Constantine
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.

import
# Internals
constantine/math/arithmetic,
constantine/math/extension_fields,
constantine/math/endomorphisms/split_scalars,
constantine/math/io/io_bigints,
constantine/platforms/abstractions,
constantine/math_arbitrary_precision/arithmetic/limbs_views,
constantine/named/zoo_endomorphisms,
constantine/named/algebras,
./cyclotomic_subgroups

from constantine/math/elliptic/ec_shortweierstrass_affine import G2

{.push raises: [].} # No exceptions allowed in core cryptographic operations
{.push checks: off.} # No defects due to array bound checking or signed integer overflow allowed

# ############################################################
# #
# Exponentiation in 𝔾ₜ #
# #
# ############################################################

func cinv[Gt](r{.noalias.}: var Gt, a{.noalias.}: Gt, ctl: SecretBool) {.inline.} =
r.cyclotomic_inv(a)
r.ccopy(a, not ctl)

func cinv[Gt](a: var Gt, ctl: SecretBool) {.inline.} =
var t{.noInit.}: Gt
t.cyclotomic_inv(a)
a.ccopy(t, ctl)

func quot[Gt](r: var Gt, a{.noalias.}, b: Gt) {.inline.} =
r.cyclotomic_inv(b)
r *= a

func gtExpEndo*[Gt: ExtensionField, scalBits: static int](
r: var Gt,
a: Gt,
scalar: BigInt[scalBits]) {.meter.} =
## Endomorphism accelerated **Variable-time** Exponentiation in 𝔾ₜ
##
## r <- aᵏ
##
## Requires:
## - Cofactor to be cleared
## - 0 <= scalar < curve order
static: doAssert scalBits <= Fr[Gt.Name].bits(), "Do not use endomorphism to multiply beyond the curve order"

# 1. Compute endomorphisms
const M = when Gt is Fp6: 2
elif Gt is Fp12: 4
else: {.error: "Unconfigured".}

var endos {.noInit.}: array[M-1, Gt]
endos.computeEndomorphisms(a)

# 2. Decompose scalar into mini-scalars
const L = Fr[Gt.Name].bits().computeEndoRecodedLength(M)
var miniScalars {.noInit.}: array[M, BigInt[L]]
var negateElems {.noInit.}: array[M, SecretBool]
miniScalars.decomposeEndo(negateElems, scalar, Fr[Gt.Name].bits(), Gt.Name, G2) # 𝔾ₜ has same decomposition as 𝔾₂

# 3. Handle negative mini-scalars
# A scalar decomposition might lead to negative miniscalar.
# For proper handling it requires either:
# 1. Negating it and then negating the corresponding curve point P
# 2. Adding an extra bit to L for the recoding, which will do the right thing™
block:
r.cinv(a, negateElems[0])
staticFor i, 1, M:
endos[i-1].cinv(negateElems[i])

# 4. Precompute lookup table
var lut {.noInit.}: array[1 shl (M-1), Gt]
buildEndoLookupTable(
r, endos, lut,
groupLawAdd = prod, # 𝔾ₜ is a multiplicative subgroup
)

# 5. Recode the miniscalars
# we need the base miniscalar (that encodes the sign)
# to be odd, and this in constant-time to protect the secret least-significant bit.
let k0isOdd = miniScalars[0].isOdd()
discard miniScalars[0].cadd(One, not k0isOdd)

var recoded: GLV_SAC[M, L] # zero-init required
recoded.nDimMultiScalarRecoding(miniScalars)

# 6. Proceed to GLV accelerated scalar multiplication
var Q {.noInit.}, t {.noInit.}: Gt
Q.secretLookup(lut, recoded.getRecodedIndex(L-1))

for i in countdown(L-2, 0):
Q.cyclotomic_square()
t.secretLookup(lut, recoded.getRecodedIndex(i))
t.cinv(SecretBool recoded.getRecodedNegate(i))
Q *= t

# Now we need to correct if the sign miniscalar was not odd
r.quot(Q, r)
r.ccopy(Q, k0isOdd)
12 changes: 11 additions & 1 deletion constantine/math/pairings/gt_exponentiations_vartime.nim
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ from constantine/math/elliptic/ec_shortweierstrass_affine import G2
{.push raises: [].} # No exceptions allowed in core cryptographic operations
{.push checks: off.} # No defects due to array bound checking or signed integer overflow allowed

# ############################################################
# #
# Exponentiation in 𝔾ₜ #
# variable-time #
# #
# ############################################################

iterator unpackBE(scalarByte: byte): bool =
for i in countdown(7, 0):
yield bool((scalarByte shr i) and 1)
Expand Down Expand Up @@ -171,6 +178,9 @@ func gtExp_jy00_vartime*[Gt: ExtensionField](r: var Gt, a: Gt, scalar: BigInt) {
elif bit == -1:
r *= na

# Non-Adjacent Form (NAF) recoding
# ------------------------------------------------------------

func initNAF[precompSize, NafMax: static int, Gt: ExtensionField](
acc: var Gt,
tab: array[precompSize, Gt],
Expand Down Expand Up @@ -261,7 +271,7 @@ func gtExpEndo_wNAF_vartime*[Gt: ExtensionField, scalBits: static int](
endos.computeEndomorphisms(a)

# 2. Decompose scalar into mini-scalars
const L = Fr[Gt.Name].bits().ceilDiv_vartime(M) + 1
const L = Fr[Gt.Name].bits().computeEndoRecodedLength(M)
var miniScalars {.noInit.}: array[M, BigInt[L]]
var negateElems {.noInit.}: array[M, SecretBool]
miniScalars.decomposeEndo(negateElems, scalar, Fr[Gt.Name].bits(), Gt.Name, G2) # 𝔾ₜ has same decomposition as 𝔾₂
Expand Down
14 changes: 12 additions & 2 deletions tests/math_pairings/t_pairing_template.nim
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import
constantine/named/algebras,
constantine/named/zoo_subgroups,
constantine/math/elliptic/[ec_shortweierstrass_affine, ec_shortweierstrass_projective],
constantine/math/pairings/[cyclotomic_subgroups, gt_exponentiations_vartime, pairings_generic],
constantine/math/pairings/[
cyclotomic_subgroups,
gt_exponentiations,
gt_exponentiations_vartime,
pairings_generic],
constantine/math/io/io_extfields,

# Test utilities
Expand All @@ -27,7 +31,8 @@ export
ec_shortweierstrass_affine, ec_shortweierstrass_projective,
arithmetic, extension_fields,
io_extfields,
cyclotomic_subgroups, gt_exponentiations_vartime,
cyclotomic_subgroups,
gt_exponentiations, gt_exponentiations_vartime,
abstractions, algebras

type
Expand Down Expand Up @@ -202,6 +207,11 @@ template runGTexponentiationTests*(Iters: static int, GT: typedesc): untyped {.d
r_endoWNAF.gtExpEndo_wNAF_vartime(a, k, window = 4)
doAssert bool(r_ref == r_endoWNAF)

# Constant-time 𝔾ₜ exponentiation with endomorphism
var r_ctEndo {.noInit.}: GT
r_ctEndo.gtExpEndo(a, k)
doAssert bool(r_ref == r_ctEndo)

stdout.write '.'

stdout.write '\n'
Expand Down

0 comments on commit 4f3eb84

Please sign in to comment.