introduce unconditional add/sub and fused initialization+operation sum/diff
This commit is contained in:
parent
ddce056bb4
commit
2aec16d8d8
|
@ -113,24 +113,77 @@ func setOne*(a: var BigInt) =
|
|||
when a.limbs.len > 1:
|
||||
zeroMem(a.limbs[1].unsafeAddr, (a.limbs.len-1) * sizeof(Word))
|
||||
|
||||
func cadd*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||
func cadd*(a: var BigInt, b: BigInt, ctl: CTBool[Word]): CTBool[Word] =
|
||||
## Constant-time in-place conditional addition
|
||||
## The addition is only performed if ctl is "true"
|
||||
## The result carry is always computed.
|
||||
cadd(a.view, b.view, ctl)
|
||||
|
||||
func csub*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||
func csub*(a: var BigInt, b: BigInt, ctl: CTBool[Word]): CTBool[Word] =
|
||||
## Constant-time in-place conditional addition
|
||||
## The addition is only performed if ctl is "true"
|
||||
## The result carry is always computed.
|
||||
csub(a.view, b.view, ctl)
|
||||
|
||||
func cdouble*[bits](a: var BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||
func cdouble*(a: var BigInt, ctl: CTBool[Word]): CTBool[Word] =
|
||||
## Constant-time in-place conditional doubling
|
||||
## The doubling is only performed if ctl is "true"
|
||||
## The result carry is always computed.
|
||||
cadd(a.view, a.view, ctl)
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# BigInt Primitives Optimized for speed
|
||||
#
|
||||
# ############################################################
|
||||
#
|
||||
# TODO: fallback to cadd / csub with a "size" compile-option
|
||||
|
||||
func add*(a: var BigInt, b: BigInt): CTBool[Word] =
|
||||
## Constant-time in-place addition
|
||||
## Returns the carry
|
||||
add(a.view, b.view)
|
||||
|
||||
func sub*(a: var BigInt, b: BigInt): CTBool[Word] =
|
||||
## Constant-time in-place substraction
|
||||
## Returns the borrow
|
||||
sub(a.view, b.view)
|
||||
|
||||
func double*(a: var BigInt): CTBool[Word] =
|
||||
## Constant-time in-place doubling
|
||||
## Returns the carry
|
||||
add(a.view, a.view)
|
||||
|
||||
func sum*(r: var BigInt, a, b: BigInt): CTBool[Word] =
|
||||
## Sum `a` and `b` into `r`.
|
||||
## `r` is initialized/overwritten
|
||||
##
|
||||
## Returns the carry
|
||||
sum(r.view, a.view, b.view)
|
||||
|
||||
func diff*(r: var BigInt, a, b: BigInt): CTBool[Word] =
|
||||
## Substract `b` from `a` and store the result into `r`.
|
||||
## `r` is initialized/overwritten
|
||||
##
|
||||
## Returns the borrow
|
||||
diff(r.view, a.view, b.view)
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Comparisons
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
# Use "csub", which unfortunately requires the first operand to be mutable.
|
||||
# for example for a <= b, we now that if a-b borrows then b > a and so a<=b is false
|
||||
# This can be tested with "not csub(a, b, CtFalse)"
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Modular BigInt
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
func reduce*[aBits, mBits](r: var BigInt[mBits], a: BigInt[aBits], M: BigInt[mBits]) =
|
||||
## Reduce `a` modulo `M` and store the result in `r`
|
||||
##
|
||||
|
@ -143,7 +196,7 @@ func reduce*[aBits, mBits](r: var BigInt[mBits], a: BigInt[aBits], M: BigInt[mBi
|
|||
# pass a pointer+length to a fixed session of the BSS.
|
||||
reduce(r.view, a.view, M.view)
|
||||
|
||||
func montyResidue*[mBits](mres: var BigInt[mBits], a, N, r2modN: BigInt[mBits], negInvModWord: static BaseType) =
|
||||
func montyResidue*(mres: var BigInt, a, N, r2modN: BigInt, negInvModWord: static BaseType) =
|
||||
## Convert a BigInt from its natural representation
|
||||
## to the Montgomery n-residue form
|
||||
##
|
||||
|
@ -168,14 +221,20 @@ func redc*[mBits](r: var BigInt[mBits], a, N: BigInt[mBits], negInvModWord: stat
|
|||
one
|
||||
redc(r.view, a.view, one.view, N.view, Word(negInvModWord))
|
||||
|
||||
func montyMul*[mBits](r: var BigInt[mBits], a, b, M: BigInt[mBits], negInvModWord: static BaseType) =
|
||||
# ############################################################
|
||||
#
|
||||
# Montgomery Arithmetic
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
func montyMul*(r: var BigInt, a, b, M: BigInt, negInvModWord: static BaseType) =
|
||||
## Compute r <- a*b (mod M) in the Montgomery domain
|
||||
##
|
||||
## This resets r to zero before processing. Use {.noInit.}
|
||||
## to avoid duplicating with Nim zero-init policy
|
||||
montyMul(r.view, a.view, b.view, M.view, Word(negInvModWord))
|
||||
|
||||
func montySquare*[mBits](r: var BigInt[mBits], a, M: BigInt[mBits], negInvModWord: static BaseType) =
|
||||
func montySquare*(r: var BigInt, a, M: BigInt, negInvModWord: static BaseType) =
|
||||
## Compute r <- a^2 (mod M) in the Montgomery domain
|
||||
##
|
||||
## This resets r to zero before processing. Use {.noInit.}
|
||||
|
|
|
@ -299,6 +299,71 @@ func shiftRight*(a: BigIntViewMut, k: int) =
|
|||
a[i] = (a[i] shr k) or mask(a[i+1] shl (WordBitSize - k))
|
||||
a[len-1] = a[len-1] shr k
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# BigInt Primitives Optimized for speed
|
||||
#
|
||||
# ############################################################
|
||||
#
|
||||
# This section implements primitives that improve the speed
|
||||
# of common use-cases at the expense of a slight increase in code-size.
|
||||
# Where code size is a concern, the high-level API should use
|
||||
# copy and/or the conditional operations.
|
||||
|
||||
func add*(a: BigIntViewMut, b: BigIntViewAny): CTBool[Word] =
|
||||
## Constant-time in-place addition
|
||||
## Returns the carry
|
||||
##
|
||||
## a and b MAY be the same buffer
|
||||
## a and b MUST have the same announced bitlength (i.e. `bits` static parameters)
|
||||
checkMatchingBitlengths(a, b)
|
||||
|
||||
for i in 0 ..< a.numLimbs():
|
||||
a[i] = a[i] + b[i] + Word(result)
|
||||
result = a[i].isMsbSet()
|
||||
a[i] = a[i].mask()
|
||||
|
||||
func sub*(a: BigIntViewMut, b: BigIntViewAny): CTBool[Word] =
|
||||
## Constant-time in-place substraction
|
||||
## Returns the borrow
|
||||
##
|
||||
## a and b MAY be the same buffer
|
||||
## a and b MUST have the same announced bitlength (i.e. `bits` static parameters)
|
||||
checkMatchingBitlengths(a, b)
|
||||
|
||||
for i in 0 ..< a.numLimbs():
|
||||
a[i] = a[i] - b[i] - Word(result)
|
||||
result = a[i].isMsbSet()
|
||||
a[i] = a[i].mask()
|
||||
|
||||
func sum*(r: BigIntViewMut, a, b: BigIntViewAny): CTBool[Word] =
|
||||
## Sum `a` and `b` into `r`.
|
||||
## `r` is initialized/overwritten
|
||||
##
|
||||
## Returns the carry
|
||||
checkMatchingBitlengths(a, b)
|
||||
|
||||
r.setBitLength(bitSizeof(M))
|
||||
|
||||
for i in 0 ..< a.numLimbs():
|
||||
r[i] = a[i] + b[i] + Word(result)
|
||||
result = a[i].isMsbSet()
|
||||
r[i] = r[i].mask()
|
||||
|
||||
func diff*(r: BigIntViewMut, a, b: BigIntViewAny): CTBool[Word] =
|
||||
## Substract `b` from `a` and store the result into `r`.
|
||||
## `r` is initialized/overwritten
|
||||
##
|
||||
## Returns the borrow
|
||||
checkMatchingBitlengths(a, b)
|
||||
|
||||
r.setBitLength(bitSizeof(M))
|
||||
|
||||
for i in 0 ..< a.numLimbs():
|
||||
r[i] = a[i] - b[i] - Word(result)
|
||||
result = a[i].isMsbSet()
|
||||
r[i] = r[i].mask()
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Modular BigInt
|
||||
|
@ -550,7 +615,7 @@ func montyResidue*(
|
|||
|
||||
montyMul(r, a, r2ModN, N, negInvModWord)
|
||||
|
||||
func montySquare(
|
||||
func montySquare*(
|
||||
r: BigIntViewMut, a: BigIntViewAny,
|
||||
M: BigIntViewConst, negInvModWord: Word) {.inline.} =
|
||||
## Compute r <- a^2 (mod M) in the Montgomery domain
|
||||
|
@ -598,13 +663,6 @@ func montySquare(
|
|||
# of the exponent, leaking this to cache attacks
|
||||
# - in contrast BearSSL touches the whole table to
|
||||
# hide the actual selection
|
||||
#
|
||||
# Directly using the Hamming weight would probably
|
||||
# significantly improve pairing-friendly curves as
|
||||
# they are chosen for their low Hamming-Weight (see BLS12-381 x factor)
|
||||
# --> Expose an exponent-leaky powMod?
|
||||
# If so, create distinct type for leaked bits and BigInt
|
||||
# so that sensitive data use is compiler-checked
|
||||
|
||||
func getWindowLen(bufLen: int): uint =
|
||||
## Compute the maximum window size that fits in the scratchspace buffer
|
||||
|
|
|
@ -75,30 +75,6 @@ func toBig*(src: Fp): auto {.noInit.} =
|
|||
r.redc(src.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord())
|
||||
return r
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Aliases
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
template cadd(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] =
|
||||
## Constant-time in-place conditional addition
|
||||
## The addition is only performed if ctl is "true"
|
||||
## The result carry is always computed.
|
||||
##
|
||||
## a and b MAY be the same buffer
|
||||
## a and b MUST have the same announced bitlength (i.e. `bits` static parameters)
|
||||
cadd(a.mres, b.mres, ctl)
|
||||
|
||||
template csub(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] =
|
||||
## Constant-time in-place conditional substraction
|
||||
## The substraction is only performed if ctl is "true"
|
||||
## The result carry is always computed.
|
||||
##
|
||||
## a and b MAY be the same buffer
|
||||
## a and b MUST have the same announced bitlength (i.e. `bits` static parameters)
|
||||
csub(a.mres, b.mres, ctl)
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Field arithmetic primitives
|
||||
|
@ -124,20 +100,20 @@ func setOne*(a: var Fp) =
|
|||
|
||||
func `+=`*(a: var Fp, b: Fp) =
|
||||
## Addition modulo p
|
||||
var ctl = cadd(a, b, CtTrue)
|
||||
ctl = ctl or not csub(a, Fp.C.Mod, CtFalse)
|
||||
discard csub(a, Fp.C.Mod, ctl)
|
||||
var overflowed = add(a.mres, b.mres)
|
||||
overflowed = overflowed or not csub(a.mres, Fp.C.Mod.mres, CtFalse) # a >= P
|
||||
discard csub(a.mres, Fp.C.Mod.mres, overflowed)
|
||||
|
||||
func `-=`*(a: var Fp, b: Fp) =
|
||||
## Substraction modulo p
|
||||
let ctl = csub(a, b, CtTrue)
|
||||
discard cadd(a, Fp.C.Mod, ctl)
|
||||
let underflowed = sub(a.mres, b.mres)
|
||||
discard cadd(a.mres, Fp.C.Mod.mres, underflowed)
|
||||
|
||||
func double*(a: var Fp) =
|
||||
## Double ``a`` modulo p
|
||||
var ctl = cdouble(a, CtTrue)
|
||||
ctl = ctl or not csub(a, Fp.C.Mod, CtFalse)
|
||||
discard csub(a, Fp.C.Mod, ctl)
|
||||
var overflowed = double(a.mres)
|
||||
overflowed = overflowed or not csub(a.mres, Fp.C.Mod.mres, CtFalse) # a >= P
|
||||
discard csub(a.mres, Fp.C.Mod.mres, overflowed)
|
||||
|
||||
func `*`*(a, b: Fp): Fp {.noInit.} =
|
||||
## Multiplication modulo p
|
||||
|
|
|
@ -34,7 +34,7 @@ func isMsbSet(x: BaseType): bool =
|
|||
const msb_pos = BaseType.sizeof * 8 - 1
|
||||
bool(x shr msb_pos)
|
||||
|
||||
func double(a: var BigInt): bool =
|
||||
func dbl(a: var BigInt): bool =
|
||||
## In-place multiprecision double
|
||||
## a -> 2a
|
||||
for i in 0 ..< a.limbs.len:
|
||||
|
@ -61,7 +61,7 @@ func doubleMod(a: var BigInt, M: BigInt) =
|
|||
## It is NOT constant-time and is intended
|
||||
## only for compile-time precomputation
|
||||
## of non-secret data.
|
||||
var ctl = double(a)
|
||||
var ctl = dbl(a)
|
||||
ctl = ctl or not sub(a, M, false)
|
||||
discard sub(a, M, ctl)
|
||||
|
||||
|
|
Loading…
Reference in New Issue