mirror of
https://github.com/codex-storage/constantine.git
synced 2025-01-18 15:00:55 +00:00
MSB-to-LSB minimum Hamming Weight Recoding (#219)
* signed recoding * use recoding
This commit is contained in:
parent
7c5421ffdc
commit
082cd1deb9
@ -57,6 +57,9 @@ proc main() =
|
|||||||
scalarMulUnsafeDoubleAddBench(ECP_ShortW_Prj[Fp[curve], G1], MulIters)
|
scalarMulUnsafeDoubleAddBench(ECP_ShortW_Prj[Fp[curve], G1], MulIters)
|
||||||
scalarMulUnsafeDoubleAddBench(ECP_ShortW_Jac[Fp[curve], G1], MulIters)
|
scalarMulUnsafeDoubleAddBench(ECP_ShortW_Jac[Fp[curve], G1], MulIters)
|
||||||
separator()
|
separator()
|
||||||
|
scalarMulUnsafeMinHammingWeightRecodingBench(ECP_ShortW_Prj[Fp[curve], G1], MulIters)
|
||||||
|
scalarMulUnsafeMinHammingWeightRecodingBench(ECP_ShortW_Jac[Fp[curve], G1], MulIters)
|
||||||
|
separator()
|
||||||
scalarMulGenericBench(ECP_ShortW_Prj[Fp[curve], G1], window = 2, MulIters)
|
scalarMulGenericBench(ECP_ShortW_Prj[Fp[curve], G1], window = 2, MulIters)
|
||||||
scalarMulGenericBench(ECP_ShortW_Prj[Fp[curve], G1], window = 3, MulIters)
|
scalarMulGenericBench(ECP_ShortW_Prj[Fp[curve], G1], window = 3, MulIters)
|
||||||
scalarMulGenericBench(ECP_ShortW_Prj[Fp[curve], G1], window = 4, MulIters)
|
scalarMulGenericBench(ECP_ShortW_Prj[Fp[curve], G1], window = 4, MulIters)
|
||||||
|
@ -58,6 +58,9 @@ proc main() =
|
|||||||
scalarMulUnsafeDoubleAddBench(ECP_ShortW_Prj[Fp2[curve], G2], MulIters)
|
scalarMulUnsafeDoubleAddBench(ECP_ShortW_Prj[Fp2[curve], G2], MulIters)
|
||||||
scalarMulUnsafeDoubleAddBench(ECP_ShortW_Jac[Fp2[curve], G2], MulIters)
|
scalarMulUnsafeDoubleAddBench(ECP_ShortW_Jac[Fp2[curve], G2], MulIters)
|
||||||
separator()
|
separator()
|
||||||
|
scalarMulUnsafeMinHammingWeightRecodingBench(ECP_ShortW_Prj[Fp2[curve], G2], MulIters)
|
||||||
|
scalarMulUnsafeMinHammingWeightRecodingBench(ECP_ShortW_Jac[Fp2[curve], G2], MulIters)
|
||||||
|
separator()
|
||||||
scalarMulGenericBench(ECP_ShortW_Prj[Fp2[curve], G2], window = 2, MulIters)
|
scalarMulGenericBench(ECP_ShortW_Prj[Fp2[curve], G2], window = 2, MulIters)
|
||||||
scalarMulGenericBench(ECP_ShortW_Prj[Fp2[curve], G2], window = 3, MulIters)
|
scalarMulGenericBench(ECP_ShortW_Prj[Fp2[curve], G2], window = 3, MulIters)
|
||||||
scalarMulGenericBench(ECP_ShortW_Prj[Fp2[curve], G2], window = 4, MulIters)
|
scalarMulGenericBench(ECP_ShortW_Prj[Fp2[curve], G2], window = 4, MulIters)
|
||||||
|
@ -143,6 +143,18 @@ proc scalarMulUnsafeDoubleAddBench*(EC: typedesc, iters: int) =
|
|||||||
r = P
|
r = P
|
||||||
r.unsafe_ECmul_double_add(exponent)
|
r.unsafe_ECmul_double_add(exponent)
|
||||||
|
|
||||||
|
proc scalarMulUnsafeMinHammingWeightRecodingBench*(EC: typedesc, iters: int) =
|
||||||
|
const bits = EC.F.C.getCurveOrderBitwidth()
|
||||||
|
|
||||||
|
var r {.noInit.}: EC
|
||||||
|
var P = rng.random_unsafe(EC) # TODO: clear cofactor
|
||||||
|
|
||||||
|
let exponent = rng.random_unsafe(BigInt[bits])
|
||||||
|
|
||||||
|
bench("EC ScalarMul " & $bits & "-bit " & $EC.G & " (unsafe min Hamming Weight recoding)", EC, iters):
|
||||||
|
r = P
|
||||||
|
r.unsafe_ECmul_minHammingWeight(exponent)
|
||||||
|
|
||||||
proc multiAddBench*(EC: typedesc, numPoints: int, useBatching: bool, iters: int) =
|
proc multiAddBench*(EC: typedesc, numPoints: int, useBatching: bool, iters: int) =
|
||||||
var points = newSeq[ECP_ShortW_Aff[EC.F, EC.G]](numPoints)
|
var points = newSeq[ECP_ShortW_Aff[EC.F, EC.G]](numPoints)
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
|
|||||||
# ("tests/math/t_pairing_bls12_377_line_functions.nim", false),
|
# ("tests/math/t_pairing_bls12_377_line_functions.nim", false),
|
||||||
# ("tests/math/t_pairing_bls12_381_line_functions.nim", false),
|
# ("tests/math/t_pairing_bls12_381_line_functions.nim", false),
|
||||||
# ("tests/math/t_pairing_mul_fp12_by_lines.nim", false),
|
# ("tests/math/t_pairing_mul_fp12_by_lines.nim", false),
|
||||||
# ("tests/math/t_pairing_cyclotomic_subgroup.nim", false),
|
("tests/math/t_pairing_cyclotomic_subgroup.nim", false),
|
||||||
("tests/math/t_pairing_bn254_nogami_optate.nim", false),
|
("tests/math/t_pairing_bn254_nogami_optate.nim", false),
|
||||||
("tests/math/t_pairing_bn254_snarks_optate.nim", false),
|
("tests/math/t_pairing_bn254_snarks_optate.nim", false),
|
||||||
("tests/math/t_pairing_bls12_377_optate.nim", false),
|
("tests/math/t_pairing_bls12_377_optate.nim", false),
|
||||||
|
@ -491,5 +491,52 @@ func invmod*[bits](r: var BigInt[bits], a, M: BigInt[bits]) =
|
|||||||
one.setOne()
|
one.setOne()
|
||||||
r.invmod(a, one, M)
|
r.invmod(a, one, M)
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
#
|
||||||
|
# Recoding
|
||||||
|
#
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
iterator recoding_l2r_vartime*(a: BigInt): int8 =
|
||||||
|
## This is a minimum-Hamming-Weight left-to-right recoding.
|
||||||
|
## It outputs signed {-1, 0, 1} bits from MSB to LSB
|
||||||
|
## with minimal Hamming Weight to minimize operations
|
||||||
|
## in Miller Loop and vartime scalar multiplications
|
||||||
|
##
|
||||||
|
## Tagged vartime as it returns an int8
|
||||||
|
## - Optimal Left-to-Right Binary Signed-Digit Recoding
|
||||||
|
## Joye, Yen, 2000
|
||||||
|
## https://marcjoye.github.io/papers/JY00sd2r.pdf
|
||||||
|
|
||||||
|
# As the caller is copy-pasted at each yield
|
||||||
|
# we rework the algorithm so that we have a single yield point
|
||||||
|
# We rely on the compiler for loop hoisting and/or loop peeling
|
||||||
|
|
||||||
|
var bi, bi1, ri, ri1, ri2: int8
|
||||||
|
|
||||||
|
var i = a.bits
|
||||||
|
while true:
|
||||||
|
if i == a.bits: # We rely on compiler to hoist this branch out of the loop.
|
||||||
|
ri = 0
|
||||||
|
ri1 = int8 a.bit(a.bits-1)
|
||||||
|
ri2 = int8 a.bit(a.bits-2)
|
||||||
|
bi = 0
|
||||||
|
else:
|
||||||
|
bi = bi1
|
||||||
|
ri = ri1
|
||||||
|
ri1 = ri2
|
||||||
|
if i < 2:
|
||||||
|
ri2 = 0
|
||||||
|
else:
|
||||||
|
ri2 = int8 a.bit(i-2)
|
||||||
|
|
||||||
|
bi1 = (bi + ri1 + ri2) shr 1
|
||||||
|
yield -2*bi + ri + bi1
|
||||||
|
|
||||||
|
if i > 0:
|
||||||
|
i -= 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
{.pop.} # inline
|
{.pop.} # inline
|
||||||
{.pop.} # raises no exceptions
|
{.pop.} # raises no exceptions
|
||||||
|
@ -630,14 +630,18 @@ func double*(P: var ECP_ShortW_Jac) {.inline.} =
|
|||||||
## In-place point doubling
|
## In-place point doubling
|
||||||
P.double(P)
|
P.double(P)
|
||||||
|
|
||||||
func diff*(r: var ECP_ShortW_Jac,
|
func diff*(r: var ECP_ShortW_Jac, P, Q: ECP_ShortW_Jac) {.inline.} =
|
||||||
P, Q: ECP_ShortW_Jac
|
|
||||||
) {.inline.} =
|
|
||||||
## r = P - Q
|
## r = P - Q
|
||||||
var nQ {.noInit.}: typeof(Q)
|
var nQ {.noInit.}: typeof(Q)
|
||||||
nQ.neg(Q)
|
nQ.neg(Q)
|
||||||
r.sum(P, nQ)
|
r.sum(P, nQ)
|
||||||
|
|
||||||
|
func `-=`*(P: var ECP_ShortW_Jac, Q: ECP_ShortW_Jac) {.inline.} =
|
||||||
|
## In-place point substraction
|
||||||
|
var nQ {.noInit.}: typeof(Q)
|
||||||
|
nQ.neg(Q)
|
||||||
|
P.sum(P, nQ)
|
||||||
|
|
||||||
func affine*[F; G](
|
func affine*[F; G](
|
||||||
aff: var ECP_ShortW_Aff[F, G],
|
aff: var ECP_ShortW_Aff[F, G],
|
||||||
jac: ECP_ShortW_Jac[F, G]) =
|
jac: ECP_ShortW_Jac[F, G]) =
|
||||||
|
@ -417,15 +417,19 @@ func double*(P: var ECP_ShortW_Prj) {.inline.} =
|
|||||||
## In-place EC doubling
|
## In-place EC doubling
|
||||||
P.double(P)
|
P.double(P)
|
||||||
|
|
||||||
func diff*(r: var ECP_ShortW_Prj,
|
func diff*(r: var ECP_ShortW_Prj, P, Q: ECP_ShortW_Prj) {.inline.} =
|
||||||
P, Q: ECP_ShortW_Prj
|
|
||||||
) {.inline.} =
|
|
||||||
## r = P - Q
|
## r = P - Q
|
||||||
## Can handle r and Q aliasing
|
## Can handle r and Q aliasing
|
||||||
var nQ {.noInit.}: typeof(Q)
|
var nQ {.noInit.}: typeof(Q)
|
||||||
nQ.neg(Q)
|
nQ.neg(Q)
|
||||||
r.sum(P, nQ)
|
r.sum(P, nQ)
|
||||||
|
|
||||||
|
func `-=`*(P: var ECP_ShortW_Prj, Q: ECP_ShortW_Prj) {.inline.} =
|
||||||
|
## In-place point substraction
|
||||||
|
var nQ {.noInit.}: typeof(Q)
|
||||||
|
nQ.neg(Q)
|
||||||
|
P.sum(P, nQ)
|
||||||
|
|
||||||
func affine*[F, G](
|
func affine*[F, G](
|
||||||
aff: var ECP_ShortW_Aff[F, G],
|
aff: var ECP_ShortW_Aff[F, G],
|
||||||
proj: ECP_ShortW_Prj[F, G]) =
|
proj: ECP_ShortW_Prj[F, G]) =
|
||||||
|
@ -385,26 +385,29 @@ func cycl_sqr_repeated*[FT](r: var FT, a: FT, num: int) {.inline, meter.} =
|
|||||||
for _ in 1 ..< num:
|
for _ in 1 ..< num:
|
||||||
r.cyclotomic_square()
|
r.cyclotomic_square()
|
||||||
|
|
||||||
iterator unpack(scalarByte: byte): bool =
|
func cyclotomic_exp*[FT](r: var FT, a: FT, exponent: static BigInt, invert: bool) {.meter.} =
|
||||||
yield bool((scalarByte and 0b10000000) shr 7)
|
## Assumes public exponent
|
||||||
yield bool((scalarByte and 0b01000000) shr 6)
|
var na {.noInit.}: FT
|
||||||
yield bool((scalarByte and 0b00100000) shr 5)
|
na.cyclotomic_inv(a)
|
||||||
yield bool((scalarByte and 0b00010000) shr 4)
|
|
||||||
yield bool((scalarByte and 0b00001000) shr 3)
|
|
||||||
yield bool((scalarByte and 0b00000100) shr 2)
|
|
||||||
yield bool((scalarByte and 0b00000010) shr 1)
|
|
||||||
yield bool( scalarByte and 0b00000001)
|
|
||||||
|
|
||||||
func cyclotomic_exp*[FT](r: var FT, a: FT, exponent: BigInt, invert: bool) {.meter.} =
|
|
||||||
var eBytes: array[(exponent.bits+7) div 8, byte]
|
|
||||||
eBytes.marshal(exponent, bigEndian)
|
|
||||||
|
|
||||||
r.setOne()
|
r.setOne()
|
||||||
for b in eBytes:
|
var init = false
|
||||||
for bit in unpack(b):
|
for bit in recoding_l2r_vartime(exponent):
|
||||||
|
if init:
|
||||||
r.cyclotomic_square()
|
r.cyclotomic_square()
|
||||||
if bit:
|
if bit == 1:
|
||||||
|
if not init:
|
||||||
|
r = a
|
||||||
|
init = true
|
||||||
|
else:
|
||||||
r *= a
|
r *= a
|
||||||
|
elif bit == -1:
|
||||||
|
if not init:
|
||||||
|
r = na
|
||||||
|
init = true
|
||||||
|
else:
|
||||||
|
r *= na
|
||||||
|
|
||||||
if invert:
|
if invert:
|
||||||
r.cyclotomic_inv()
|
r.cyclotomic_inv()
|
||||||
|
|
||||||
|
@ -1397,3 +1397,5 @@ func mul_by_2_lines*[Fpk, Fpkdiv6](f: var Fpk, line0, line1: Line[Fpkdiv6]) {.in
|
|||||||
var t{.noInit.}: Fpk
|
var t{.noInit.}: Fpk
|
||||||
t.prod_from_2_lines(line0, line1)
|
t.prod_from_2_lines(line0, line1)
|
||||||
f.mul_by_prod_of_2_lines(t)
|
f.mul_by_prod_of_2_lines(t)
|
||||||
|
|
||||||
|
# func asFpk
|
@ -45,6 +45,7 @@ func basicMillerLoop*[FT, F1, F2](
|
|||||||
var u3 = ate_param
|
var u3 = ate_param
|
||||||
u3 *= 3
|
u3 *= 3
|
||||||
for i in countdown(u3.bits - 2, 1):
|
for i in countdown(u3.bits - 2, 1):
|
||||||
|
if i != u3.bits - 2:
|
||||||
f.square()
|
f.square()
|
||||||
line.line_double(T, P)
|
line.line_double(T, P)
|
||||||
f.mul_by_line(line)
|
f.mul_by_line(line)
|
||||||
@ -320,6 +321,7 @@ func basicMillerLoop*[FT, F1, F2](
|
|||||||
var u3 = ate_param
|
var u3 = ate_param
|
||||||
u3 *= 3
|
u3 *= 3
|
||||||
for i in countdown(u3.bits - 2, 1):
|
for i in countdown(u3.bits - 2, 1):
|
||||||
|
if i != u3.bits - 2:
|
||||||
f.square()
|
f.square()
|
||||||
f.double_jToN(j=0, line0, line1, Ts, Ps, N)
|
f.double_jToN(j=0, line0, line1, Ts, Ps, N)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import
|
import
|
||||||
../math/[ec_shortweierstrass, extension_fields],
|
../math/[ec_shortweierstrass, extension_fields],
|
||||||
|
../math/io/io_bigints,
|
||||||
../math/elliptic/ec_shortweierstrass_batch_ops,
|
../math/elliptic/ec_shortweierstrass_batch_ops,
|
||||||
../math/pairings/[pairings_generic, miller_accumulators],
|
../math/pairings/[pairings_generic, miller_accumulators],
|
||||||
../math/constants/zoo_generators,
|
../math/constants/zoo_generators,
|
||||||
@ -365,41 +366,30 @@ func init*[T0, T1: char|byte](
|
|||||||
|
|
||||||
H.hash(ctx.secureBlinding, secureRandomBytes, accumSepTag)
|
H.hash(ctx.secureBlinding, secureRandomBytes, accumSepTag)
|
||||||
|
|
||||||
iterator unpack(scalarByte: byte): bool =
|
func scalarMul_minHammingWeight_vartime[EC](
|
||||||
yield bool((scalarByte and 0b10000000) shr 7)
|
|
||||||
yield bool((scalarByte and 0b01000000) shr 6)
|
|
||||||
yield bool((scalarByte and 0b00100000) shr 5)
|
|
||||||
yield bool((scalarByte and 0b00010000) shr 4)
|
|
||||||
yield bool((scalarByte and 0b00001000) shr 3)
|
|
||||||
yield bool((scalarByte and 0b00000100) shr 2)
|
|
||||||
yield bool((scalarByte and 0b00000010) shr 1)
|
|
||||||
yield bool( scalarByte and 0b00000001)
|
|
||||||
|
|
||||||
func scalarMul_doubleAdd_vartime[EC](
|
|
||||||
P: var EC,
|
P: var EC,
|
||||||
scalarCanonical: openArray[byte],
|
scalar: BigInt,
|
||||||
) =
|
) =
|
||||||
## **Variable-time** Elliptic Curve Scalar Multiplication
|
## **Variable-time** Elliptic Curve Scalar Multiplication
|
||||||
##
|
##
|
||||||
## P <- [k] P
|
## P <- [k] P
|
||||||
##
|
##
|
||||||
## This uses the double-and-add algorithm
|
## This uses an online recoding with minimum Hamming Weight
|
||||||
## This is UNSAFE to use with secret data and is only intended for signature verification
|
## (which is not NAF, NAF is least-significant bit to most)
|
||||||
## to multiply by random blinding scalars.
|
|
||||||
## Due to those scalars being 64-bit, window-method or endomorphism acceleration are slower
|
## Due to those scalars being 64-bit, window-method or endomorphism acceleration are slower
|
||||||
## than double-and-add.
|
## than double-and-add.
|
||||||
##
|
##
|
||||||
## This is highly VULNERABLE to timing attacks and power analysis attacks.
|
## This is highly VULNERABLE to timing attacks and power analysis attacks.
|
||||||
var t0{.noInit.}, t1{.noInit.}: typeof(P)
|
## For our usecase, scaling with a random number not in attacker control,
|
||||||
|
## leaking the scalar bits is not an issue.
|
||||||
|
var t0{.noInit.}: typeof(P)
|
||||||
t0.setInf()
|
t0.setInf()
|
||||||
t1.setInf()
|
for bit in recoding_l2r_vartime(scalar):
|
||||||
for scalarByte in scalarCanonical:
|
t0.double()
|
||||||
for bit in unpack(scalarByte):
|
if bit == 1:
|
||||||
t1.double(t0)
|
t0 += P
|
||||||
if bit:
|
elif bit == -1:
|
||||||
t0.sum(t1, P)
|
t0 -= P
|
||||||
else:
|
|
||||||
t0 = t1
|
|
||||||
P = t0
|
P = t0
|
||||||
|
|
||||||
func update*[T: char|byte, Pubkey, Sig: ECP_ShortW_Aff](
|
func update*[T: char|byte, Pubkey, Sig: ECP_ShortW_Aff](
|
||||||
@ -434,7 +424,12 @@ func update*[T: char|byte, Pubkey, Sig: ECP_ShortW_Aff](
|
|||||||
# we only use a 1..<2^64 random blinding factor.
|
# we only use a 1..<2^64 random blinding factor.
|
||||||
# We assume that the attacker cannot resubmit 2^64 times
|
# We assume that the attacker cannot resubmit 2^64 times
|
||||||
# forged public keys and signatures.
|
# forged public keys and signatures.
|
||||||
|
#
|
||||||
# Discussion https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
|
# Discussion https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
|
||||||
|
# See also
|
||||||
|
# - Faster batch forgery identification
|
||||||
|
# Daniel J. Bernstein, Jeroen Doumen, Tanja Lange, and Jan-Jaap Oosterwijk, 2012
|
||||||
|
# https://eprint.iacr.org/2012/549
|
||||||
|
|
||||||
# We only use the first 8 bytes for blinding
|
# We only use the first 8 bytes for blinding
|
||||||
# but use the full 32 bytes to derive new random scalar
|
# but use the full 32 bytes to derive new random scalar
|
||||||
@ -459,8 +454,10 @@ func update*[T: char|byte, Pubkey, Sig: ECP_ShortW_Aff](
|
|||||||
pkG1_jac.fromAffine(pubkey)
|
pkG1_jac.fromAffine(pubkey)
|
||||||
sigG2_jac.fromAffine(signature)
|
sigG2_jac.fromAffine(signature)
|
||||||
|
|
||||||
pkG1_jac.scalarMul_doubleAdd_vartime(ctx.secureBlinding.toOpenArray(0, 7))
|
var randFactor{.noInit.}: BigInt[64]
|
||||||
sigG2_jac.scalarMul_doubleAdd_vartime(ctx.secureBlinding.toOpenArray(0, 7))
|
randFactor.unmarshal(ctx.secureBlinding.toOpenArray(0, 7), bigEndian)
|
||||||
|
pkG1_jac.scalarMul_minHammingWeight_vartime(randFactor)
|
||||||
|
sigG2_jac.scalarMul_minHammingWeight_vartime(randFactor)
|
||||||
|
|
||||||
if ctx.aggSigOnce == false:
|
if ctx.aggSigOnce == false:
|
||||||
ctx.aggSig = sigG2_jac
|
ctx.aggSig = sigG2_jac
|
||||||
@ -493,8 +490,10 @@ func update*[T: char|byte, Pubkey, Sig: ECP_ShortW_Aff](
|
|||||||
|
|
||||||
sigG1_jac.fromAffine(signature)
|
sigG1_jac.fromAffine(signature)
|
||||||
|
|
||||||
hmsgG1_jac.scalarMul_doubleAdd_vartime(ctx.secureBlinding.toOpenArray(0, 7))
|
var randFactor{.noInit.}: BigInt[64]
|
||||||
sigG1_jac.scalarMul_doubleAdd_vartime(ctx.secureBlinding.toOpenArray(0, 7))
|
randFactor.unmarshal(ctx.secureBlinding.toOpenArray(0, 7), bigEndian)
|
||||||
|
hmsgG1_jac.scalarMul_minHammingWeight_vartime(randFactor)
|
||||||
|
sigG1_jac.scalarMul_minHammingWeight_vartime(randFactor)
|
||||||
|
|
||||||
if ctx.aggSigOnce == false:
|
if ctx.aggSigOnce == false:
|
||||||
ctx.aggSig = sigG1_jac
|
ctx.aggSig = sigG1_jac
|
||||||
|
@ -39,14 +39,33 @@ func unsafe_ECmul_double_add*[EC](
|
|||||||
var scalarCanonical: array[(scalar.bits+7) div 8, byte]
|
var scalarCanonical: array[(scalar.bits+7) div 8, byte]
|
||||||
scalarCanonical.marshal(scalar, bigEndian)
|
scalarCanonical.marshal(scalar, bigEndian)
|
||||||
|
|
||||||
var t0{.noInit.}, t1{.noInit.}: typeof(P)
|
var t0: typeof(P)
|
||||||
t0.setInf()
|
t0.setInf()
|
||||||
t1.setInf()
|
|
||||||
for scalarByte in scalarCanonical:
|
for scalarByte in scalarCanonical:
|
||||||
for bit in unpack(scalarByte):
|
for bit in unpack(scalarByte):
|
||||||
t1.double(t0)
|
t0.double()
|
||||||
if bit:
|
if bit:
|
||||||
t0.sum(t1, P)
|
t0 += P
|
||||||
else:
|
P = t0
|
||||||
t0 = t1
|
|
||||||
|
func unsafe_ECmul_minHammingWeight*[EC](
|
||||||
|
P: var EC,
|
||||||
|
scalar: BigInt) =
|
||||||
|
## **Unsafe** Elliptic Curve Scalar Multiplication
|
||||||
|
##
|
||||||
|
## P <- [k] P
|
||||||
|
##
|
||||||
|
## This uses an online recoding with minimum Hamming Weight
|
||||||
|
## (which is not NAF, NAF is least-significant bit to most)
|
||||||
|
## This is UNSAFE to use in production and only intended for testing purposes.
|
||||||
|
##
|
||||||
|
## This is highly VULNERABLE to timing attacks and power analysis attacks
|
||||||
|
var t0{.noInit.}: typeof(P)
|
||||||
|
t0.setInf()
|
||||||
|
for bit in recoding_l2r_vartime(scalar):
|
||||||
|
t0.double()
|
||||||
|
if bit == 1:
|
||||||
|
t0 += P
|
||||||
|
elif bit == -1:
|
||||||
|
t0 -= P
|
||||||
P = t0
|
P = t0
|
@ -421,11 +421,15 @@ proc run_EC_mul_vs_ref_impl*(
|
|||||||
var
|
var
|
||||||
impl = a
|
impl = a
|
||||||
reference = a
|
reference = a
|
||||||
|
refMinWeight = a
|
||||||
|
|
||||||
impl.scalarMulGeneric(exponent)
|
impl.scalarMulGeneric(exponent)
|
||||||
reference.unsafe_ECmul_double_add(exponent)
|
reference.unsafe_ECmul_double_add(exponent)
|
||||||
|
refMinWeight.unsafe_ECmul_minHammingWeight(exponent)
|
||||||
|
|
||||||
check: bool(impl == reference)
|
check:
|
||||||
|
bool(impl == reference)
|
||||||
|
bool(impl == refMinWeight)
|
||||||
|
|
||||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Uniform)
|
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Uniform)
|
||||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Uniform)
|
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Uniform)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user