mirror of
https://github.com/logos-storage/constantine.git
synced 2026-01-08 16:13:14 +00:00
conditional arithmetic prefixed with c: cadd, csub. Also use ccopy instead of cmov to avoid potential confusion like in https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/issues/210
This commit is contained in:
parent
5b53ad9cf3
commit
bb8dc579ea
@ -113,23 +113,23 @@ func setOne*(a: var BigInt) =
|
|||||||
when a.limbs.len > 1:
|
when a.limbs.len > 1:
|
||||||
zeroMem(a.limbs[1].unsafeAddr, (a.limbs.len-1) * sizeof(Word))
|
zeroMem(a.limbs[1].unsafeAddr, (a.limbs.len-1) * sizeof(Word))
|
||||||
|
|
||||||
func add*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
func cadd*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place optional addition
|
## Constant-time in-place conditional addition
|
||||||
## The addition is only performed if ctl is "true"
|
## The addition is only performed if ctl is "true"
|
||||||
## The result carry is always computed.
|
## The result carry is always computed.
|
||||||
add(a.view, b.view, ctl)
|
cadd(a.view, b.view, ctl)
|
||||||
|
|
||||||
func sub*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
func csub*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place optional addition
|
## Constant-time in-place conditional addition
|
||||||
## The addition is only performed if ctl is "true"
|
## The addition is only performed if ctl is "true"
|
||||||
## The result carry is always computed.
|
## The result carry is always computed.
|
||||||
sub(a.view, b.view, ctl)
|
csub(a.view, b.view, ctl)
|
||||||
|
|
||||||
func double*[bits](a: var BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
func cdouble*[bits](a: var BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place optional doubling
|
## Constant-time in-place conditional doubling
|
||||||
## The doubling is only performed if ctl is "true"
|
## The doubling is only performed if ctl is "true"
|
||||||
## The result carry is always computed.
|
## The result carry is always computed.
|
||||||
add(a.view, a.view, ctl)
|
cadd(a.view, a.view, ctl)
|
||||||
|
|
||||||
func reduce*[aBits, mBits](r: var BigInt[mBits], a: BigInt[aBits], M: BigInt[mBits]) =
|
func reduce*[aBits, mBits](r: var BigInt[mBits], a: BigInt[aBits], M: BigInt[mBits]) =
|
||||||
## Reduce `a` modulo `M` and store the result in `r`
|
## Reduce `a` modulo `M` and store the result in `r`
|
||||||
|
|||||||
@ -228,7 +228,7 @@ func setZero(a: BigIntViewMut) =
|
|||||||
## It's bit size is unchanged
|
## It's bit size is unchanged
|
||||||
zeroMem(a[0].unsafeAddr, a.numLimbs() * sizeof(Word))
|
zeroMem(a[0].unsafeAddr, a.numLimbs() * sizeof(Word))
|
||||||
|
|
||||||
func cmov*(a: BigIntViewMut, b: BigIntViewAny, ctl: CTBool[Word]) =
|
func ccopy*(a: BigIntViewMut, b: BigIntViewAny, ctl: CTBool[Word]) =
|
||||||
## Constant-time conditional copy
|
## Constant-time conditional copy
|
||||||
## If ctl is true: b is copied into a
|
## If ctl is true: b is copied into a
|
||||||
## if ctl is false: b is not copied and a is untouched
|
## if ctl is false: b is not copied and a is untouched
|
||||||
@ -241,8 +241,8 @@ func cmov*(a: BigIntViewMut, b: BigIntViewAny, ctl: CTBool[Word]) =
|
|||||||
# if it is a placebo operation. It stills performs the
|
# if it is a placebo operation. It stills performs the
|
||||||
# same memory accesses to be side-channel attack resistant.
|
# same memory accesses to be side-channel attack resistant.
|
||||||
|
|
||||||
func add*(a: BigIntViewMut, b: BigIntViewAny, ctl: CTBool[Word]): CTBool[Word] =
|
func cadd*(a: BigIntViewMut, b: BigIntViewAny, ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place optional addition
|
## Constant-time in-place conditional addition
|
||||||
## The addition is only performed if ctl is "true"
|
## The addition is only performed if ctl is "true"
|
||||||
## The result carry is always computed.
|
## The result carry is always computed.
|
||||||
##
|
##
|
||||||
@ -255,8 +255,8 @@ func add*(a: BigIntViewMut, b: BigIntViewAny, ctl: CTBool[Word]): CTBool[Word] =
|
|||||||
result = new_a.isMsbSet()
|
result = new_a.isMsbSet()
|
||||||
a[i] = ctl.mux(new_a.mask(), a[i])
|
a[i] = ctl.mux(new_a.mask(), a[i])
|
||||||
|
|
||||||
func sub*(a: BigIntViewMut, b: BigIntViewAny, ctl: CTBool[Word]): CTBool[Word] =
|
func csub*(a: BigIntViewMut, b: BigIntViewAny, ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place optional substraction
|
## Constant-time in-place conditional substraction
|
||||||
## The substraction is only performed if ctl is "true"
|
## The substraction is only performed if ctl is "true"
|
||||||
## The result carry is always computed.
|
## The result carry is always computed.
|
||||||
##
|
##
|
||||||
@ -395,8 +395,8 @@ func shlAddMod(a: BigIntViewMut, c: Word, M: BigIntViewConst) =
|
|||||||
let neg = carry > hi
|
let neg = carry > hi
|
||||||
let tooBig = not neg and (over_p or (carry < hi))
|
let tooBig = not neg and (over_p or (carry < hi))
|
||||||
|
|
||||||
discard a.add(M, ctl = neg)
|
discard a.cadd(M, ctl = neg)
|
||||||
discard a.sub(M, ctl = tooBig)
|
discard a.csub(M, ctl = tooBig)
|
||||||
return
|
return
|
||||||
|
|
||||||
func reduce*(r: BigIntViewMut, a: BigIntViewAny, M: BigIntViewConst) =
|
func reduce*(r: BigIntViewMut, a: BigIntViewAny, M: BigIntViewConst) =
|
||||||
@ -496,7 +496,7 @@ func montyMul*(
|
|||||||
|
|
||||||
# If the extra word is not zero or if r-M does not borrow (i.e. r > M)
|
# If the extra word is not zero or if r-M does not borrow (i.e. r > M)
|
||||||
# Then substract M
|
# Then substract M
|
||||||
discard r.sub(M, r_hi.isNonZero() or not r.sub(M, CtFalse))
|
discard r.csub(M, r_hi.isNonZero() or not r.csub(M, CtFalse))
|
||||||
|
|
||||||
func redc*(r: BigIntViewMut, a: BigIntViewAny, one, N: BigIntViewConst, negInvModWord: Word) {.inline.} =
|
func redc*(r: BigIntViewMut, a: BigIntViewAny, one, N: BigIntViewConst, negInvModWord: Word) {.inline.} =
|
||||||
## Transform a bigint ``a`` from it's Montgomery N-residue representation (mod N)
|
## Transform a bigint ``a`` from it's Montgomery N-residue representation (mod N)
|
||||||
@ -573,7 +573,7 @@ func montySquare(
|
|||||||
# and k the window-size
|
# and k the window-size
|
||||||
# - we always multiply even for unused multiplications
|
# - we always multiply even for unused multiplications
|
||||||
# - conditional copy only save a small fraction of time
|
# - conditional copy only save a small fraction of time
|
||||||
# (multiplication O(n²), cmov O(n), doing nothing i.e. non constant-time O(n))
|
# (multiplication O(n²), ccopy O(n), doing nothing i.e. non constant-time O(n))
|
||||||
# - Table lookup is O(kn) copy time since we need to access the whole table to
|
# - Table lookup is O(kn) copy time since we need to access the whole table to
|
||||||
# defeat cache attacks. Without windows, we don't have table lookups at all.
|
# defeat cache attacks. Without windows, we don't have table lookups at all.
|
||||||
#
|
#
|
||||||
@ -738,12 +738,12 @@ func montyPow*(
|
|||||||
# just index the openarray with the bits to avoid cache attacks.
|
# just index the openarray with the bits to avoid cache attacks.
|
||||||
for i in 1 ..< 1 shl k:
|
for i in 1 ..< 1 shl k:
|
||||||
let ctl = Word(i) == Word(bits)
|
let ctl = Word(i) == Word(bits)
|
||||||
scratchspace[1].cmov(scratchspace[1+i], ctl)
|
scratchspace[1].ccopy(scratchspace[1+i], ctl)
|
||||||
|
|
||||||
# Multiply with the looked-up value
|
# Multiply with the looked-up value
|
||||||
# we keep the product only if the exponent bits are not all zero
|
# we keep the product only if the exponent bits are not all zero
|
||||||
scratchspace[0].montyMul(a, scratchspace[1], M, negInvModWord)
|
scratchspace[0].montyMul(a, scratchspace[1], M, negInvModWord)
|
||||||
a.cmov(scratchspace[0], Word(bits) != Zero)
|
a.ccopy(scratchspace[0], Word(bits) != Zero)
|
||||||
|
|
||||||
func montyPowUnsafeExponent*(
|
func montyPowUnsafeExponent*(
|
||||||
a: BigIntViewMut,
|
a: BigIntViewMut,
|
||||||
|
|||||||
@ -81,23 +81,23 @@ func toBig*(src: Fp): auto {.noInit.} =
|
|||||||
#
|
#
|
||||||
# ############################################################
|
# ############################################################
|
||||||
|
|
||||||
template add(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] =
|
template cadd(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place optional addition
|
## Constant-time in-place conditional addition
|
||||||
## The addition is only performed if ctl is "true"
|
## The addition is only performed if ctl is "true"
|
||||||
## The result carry is always computed.
|
## The result carry is always computed.
|
||||||
##
|
##
|
||||||
## a and b MAY be the same buffer
|
## a and b MAY be the same buffer
|
||||||
## a and b MUST have the same announced bitlength (i.e. `bits` static parameters)
|
## a and b MUST have the same announced bitlength (i.e. `bits` static parameters)
|
||||||
add(a.mres, b.mres, ctl)
|
cadd(a.mres, b.mres, ctl)
|
||||||
|
|
||||||
template sub(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] =
|
template csub(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place optional substraction
|
## Constant-time in-place conditional substraction
|
||||||
## The substraction is only performed if ctl is "true"
|
## The substraction is only performed if ctl is "true"
|
||||||
## The result carry is always computed.
|
## The result carry is always computed.
|
||||||
##
|
##
|
||||||
## a and b MAY be the same buffer
|
## a and b MAY be the same buffer
|
||||||
## a and b MUST have the same announced bitlength (i.e. `bits` static parameters)
|
## a and b MUST have the same announced bitlength (i.e. `bits` static parameters)
|
||||||
sub(a.mres, b.mres, ctl)
|
csub(a.mres, b.mres, ctl)
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
#
|
#
|
||||||
@ -124,20 +124,20 @@ func setOne*(a: var Fp) =
|
|||||||
|
|
||||||
func `+=`*(a: var Fp, b: Fp) =
|
func `+=`*(a: var Fp, b: Fp) =
|
||||||
## Addition modulo p
|
## Addition modulo p
|
||||||
var ctl = add(a, b, CtTrue)
|
var ctl = cadd(a, b, CtTrue)
|
||||||
ctl = ctl or not sub(a, Fp.C.Mod, CtFalse)
|
ctl = ctl or not csub(a, Fp.C.Mod, CtFalse)
|
||||||
discard sub(a, Fp.C.Mod, ctl)
|
discard csub(a, Fp.C.Mod, ctl)
|
||||||
|
|
||||||
func `-=`*(a: var Fp, b: Fp) =
|
func `-=`*(a: var Fp, b: Fp) =
|
||||||
## Substraction modulo p
|
## Substraction modulo p
|
||||||
let ctl = sub(a, b, CtTrue)
|
let ctl = csub(a, b, CtTrue)
|
||||||
discard add(a, Fp.C.Mod, ctl)
|
discard cadd(a, Fp.C.Mod, ctl)
|
||||||
|
|
||||||
func double*(a: var Fp) =
|
func double*(a: var Fp) =
|
||||||
## Double ``a`` modulo p
|
## Double ``a`` modulo p
|
||||||
var ctl = double(a, CtTrue)
|
var ctl = cdouble(a, CtTrue)
|
||||||
ctl = ctl or not sub(a, Fp.C.Mod, CtFalse)
|
ctl = ctl or not csub(a, Fp.C.Mod, CtFalse)
|
||||||
discard sub(a, Fp.C.Mod, ctl)
|
discard csub(a, Fp.C.Mod, ctl)
|
||||||
|
|
||||||
func `*`*(a, b: Fp): Fp {.noInit.} =
|
func `*`*(a, b: Fp): Fp {.noInit.} =
|
||||||
## Multiplication modulo p
|
## Multiplication modulo p
|
||||||
|
|||||||
@ -32,14 +32,14 @@ proc main() =
|
|||||||
test "Adding 2 zeros":
|
test "Adding 2 zeros":
|
||||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||||
let carry = a.add(b, ctrue(Word))
|
let carry = a.cadd(b, ctrue(Word))
|
||||||
check: a.isZero().bool
|
check: a.isZero().bool
|
||||||
|
|
||||||
test "Adding 1 zero - real addition":
|
test "Adding 1 zero - real addition":
|
||||||
block:
|
block:
|
||||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
let carry = a.add(b, ctrue(Word))
|
let carry = a.cadd(b, ctrue(Word))
|
||||||
|
|
||||||
let c = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
let c = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
check:
|
check:
|
||||||
@ -47,7 +47,7 @@ proc main() =
|
|||||||
block:
|
block:
|
||||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||||
let carry = a.add(b, ctrue(Word))
|
let carry = a.cadd(b, ctrue(Word))
|
||||||
|
|
||||||
let c = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
let c = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
check:
|
check:
|
||||||
@ -57,7 +57,7 @@ proc main() =
|
|||||||
block:
|
block:
|
||||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
let carry = a.add(b, cfalse(Word))
|
let carry = a.cadd(b, cfalse(Word))
|
||||||
|
|
||||||
let c = a
|
let c = a
|
||||||
check:
|
check:
|
||||||
@ -65,7 +65,7 @@ proc main() =
|
|||||||
block:
|
block:
|
||||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||||
let carry = a.add(b, cfalse(Word))
|
let carry = a.cadd(b, cfalse(Word))
|
||||||
|
|
||||||
let c = a
|
let c = a
|
||||||
check:
|
check:
|
||||||
@ -75,7 +75,7 @@ proc main() =
|
|||||||
block:
|
block:
|
||||||
var a = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
var a = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
let carry = a.add(b, ctrue(Word))
|
let carry = a.cadd(b, ctrue(Word))
|
||||||
|
|
||||||
let c = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000001")
|
let c = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000001")
|
||||||
check:
|
check:
|
||||||
@ -83,7 +83,7 @@ proc main() =
|
|||||||
block:
|
block:
|
||||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
let b = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
||||||
let carry = a.add(b, ctrue(Word))
|
let carry = a.cadd(b, ctrue(Word))
|
||||||
|
|
||||||
let c = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000001")
|
let c = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000001")
|
||||||
check:
|
check:
|
||||||
@ -93,7 +93,7 @@ proc main() =
|
|||||||
block:
|
block:
|
||||||
var a = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
var a = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
let carry = a.add(b, cfalse(Word))
|
let carry = a.cadd(b, cfalse(Word))
|
||||||
|
|
||||||
let c = a
|
let c = a
|
||||||
check:
|
check:
|
||||||
@ -101,7 +101,7 @@ proc main() =
|
|||||||
block:
|
block:
|
||||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
let b = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
||||||
let carry = a.add(b, cfalse(Word))
|
let carry = a.cadd(b, cfalse(Word))
|
||||||
|
|
||||||
let c = a
|
let c = a
|
||||||
check:
|
check:
|
||||||
@ -111,7 +111,7 @@ proc main() =
|
|||||||
block:
|
block:
|
||||||
var a = fromHex(BigInt[128], "0x00000000_FFFFFFFF_FFFFFFFF_FFFFFFFE")
|
var a = fromHex(BigInt[128], "0x00000000_FFFFFFFF_FFFFFFFF_FFFFFFFE")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
let carry = a.add(b, ctrue(Word))
|
let carry = a.cadd(b, ctrue(Word))
|
||||||
|
|
||||||
let c = fromHex(BigInt[128], "0x00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF")
|
let c = fromHex(BigInt[128], "0x00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF")
|
||||||
check:
|
check:
|
||||||
@ -121,7 +121,7 @@ proc main() =
|
|||||||
block:
|
block:
|
||||||
var a = fromHex(BigInt[128], "0x00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF")
|
var a = fromHex(BigInt[128], "0x00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF")
|
||||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||||
let carry = a.add(b, ctrue(Word))
|
let carry = a.cadd(b, ctrue(Word))
|
||||||
|
|
||||||
let c = fromHex(BigInt[128], "0x00000001_00000000_00000000_00000000")
|
let c = fromHex(BigInt[128], "0x00000001_00000000_00000000_00000000")
|
||||||
check:
|
check:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user