diff --git a/benchmarks/bench_gt.nim b/benchmarks/bench_gt.nim index aee22e1a..cc10108e 100644 --- a/benchmarks/bench_gt.nim +++ b/benchmarks/bench_gt.nim @@ -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() diff --git a/benchmarks/bench_gt_template.nim b/benchmarks/bench_gt_template.nim index 78d3b13c..4e41b5f1 100644 --- a/benchmarks/bench_gt_template.nim +++ b/benchmarks/bench_gt_template.nim @@ -20,6 +20,7 @@ import constantine/math/pairings/[ pairings_generic, cyclotomic_subgroups, + gt_exponentiations, gt_exponentiations_vartime ], # Helpers @@ -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) diff --git a/constantine/math/elliptic/ec_scalar_mul.nim b/constantine/math/elliptic/ec_scalar_mul.nim index 5619a532..10b0094b 100644 --- a/constantine/math/elliptic/ec_scalar_mul.nim +++ b/constantine/math/elliptic/ec_scalar_mul.nim @@ -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 # @@ -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 @@ -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] @@ -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 diff --git a/constantine/math/elliptic/ec_scalar_mul_vartime.nim b/constantine/math/elliptic/ec_scalar_mul_vartime.nim index 84e94cbf..4f4c719b 100644 --- a/constantine/math/elliptic/ec_scalar_mul_vartime.nim +++ b/constantine/math/elliptic/ec_scalar_mul_vartime.nim @@ -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) @@ -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], diff --git a/constantine/math/endomorphisms/split_scalars.nim b/constantine/math/endomorphisms/split_scalars.nim index 1394da7a..db88af06 100644 --- a/constantine/math/endomorphisms/split_scalars.nim +++ b/constantine/math/endomorphisms/split_scalars.nim @@ -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 # # ############################################################ # @@ -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 diff --git a/constantine/math/pairings/gt_exponentiations.nim b/constantine/math/pairings/gt_exponentiations.nim new file mode 100644 index 00000000..901bf14a --- /dev/null +++ b/constantine/math/pairings/gt_exponentiations.nim @@ -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) diff --git a/constantine/math/pairings/gt_exponentiations_vartime.nim b/constantine/math/pairings/gt_exponentiations_vartime.nim index 3775b797..a307bd6e 100644 --- a/constantine/math/pairings/gt_exponentiations_vartime.nim +++ b/constantine/math/pairings/gt_exponentiations_vartime.nim @@ -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) @@ -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], @@ -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 ๐”พโ‚‚ diff --git a/tests/math_pairings/t_pairing_template.nim b/tests/math_pairings/t_pairing_template.nim index 3490f2da..0c738247 100644 --- a/tests/math_pairings/t_pairing_template.nim +++ b/tests/math_pairings/t_pairing_template.nim @@ -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 @@ -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 @@ -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'