Highlight that bools and words are "Secret" in the codebase
This commit is contained in:
parent
75557d88d8
commit
8a9cb9287c
|
@ -72,12 +72,12 @@ type
|
|||
##
|
||||
## This internal representation can be changed
|
||||
## without notice and should not be used by external applications or libraries.
|
||||
limbs*: array[bits.wordsRequired, Word]
|
||||
limbs*: array[bits.wordsRequired, SecretWord]
|
||||
|
||||
# For unknown reason, `bits` doesn't semcheck if
|
||||
# `limbs: Limbs[bits.wordsRequired]`
|
||||
# with
|
||||
# `Limbs[N: static int] = distinct array[N, Word]`
|
||||
# `Limbs[N: static int] = distinct array[N, SecretWord]`
|
||||
# so we don't set Limbs as a distinct type
|
||||
|
||||
debug:
|
||||
|
@ -108,7 +108,7 @@ func setOne*(a: var BigInt) =
|
|||
# Copy
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func ccopy*(a: var BigInt, b: BigInt, ctl: CTBool[Word]) =
|
||||
func ccopy*(a: var BigInt, b: BigInt, ctl: SecretBool) =
|
||||
## Constant-time conditional copy
|
||||
## If ctl is true: b is copied into a
|
||||
## if ctl is false: b is not copied and a is untouched
|
||||
|
@ -126,92 +126,92 @@ func cswap*(a, b: var BigInt, ctl: CTBool) =
|
|||
# Comparison
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func `==`*(a, b: BigInt): CTBool[Word] =
|
||||
func `==`*(a, b: BigInt): SecretBool =
|
||||
## Returns true if 2 big ints are equal
|
||||
## Comparison is constant-time
|
||||
a.limbs == b.limbs
|
||||
|
||||
func `<`*(a, b: BigInt): CTBool[Word] =
|
||||
func `<`*(a, b: BigInt): SecretBool =
|
||||
## Returns true if a < b
|
||||
a.limbs < b.limbs
|
||||
|
||||
func `<=`*(a, b: BigInt): CTBool[Word] =
|
||||
func `<=`*(a, b: BigInt): SecretBool =
|
||||
## Returns true if a <= b
|
||||
a.limbs <= b.limbs
|
||||
|
||||
func isZero*(a: BigInt): CTBool[Word] =
|
||||
func isZero*(a: BigInt): SecretBool =
|
||||
## Returns true if a big int is equal to zero
|
||||
a.limbs.isZero
|
||||
|
||||
func isOne*(a: BigInt): CTBool[Word] =
|
||||
func isOne*(a: BigInt): SecretBool =
|
||||
## Returns true if a big int is equal to one
|
||||
a.limbs.isOne
|
||||
|
||||
func isOdd*(a: BigInt): CTBool[Word] =
|
||||
func isOdd*(a: BigInt): SecretBool =
|
||||
## Returns true if a is odd
|
||||
a.limbs.isOdd
|
||||
|
||||
# Arithmetic
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func cadd*(a: var BigInt, b: BigInt, ctl: CTBool[Word]): CTBool[Word] =
|
||||
func cadd*(a: var BigInt, b: BigInt, ctl: SecretBool): SecretBool =
|
||||
## Constant-time in-place conditional addition
|
||||
## The addition is only performed if ctl is "true"
|
||||
## The result carry is always computed.
|
||||
(CTBool[Word]) cadd(a.limbs, b.limbs, ctl)
|
||||
(SecretBool) cadd(a.limbs, b.limbs, ctl)
|
||||
|
||||
func csub*(a: var BigInt, b: BigInt, ctl: CTBool[Word]): CTBool[Word] =
|
||||
func csub*(a: var BigInt, b: BigInt, ctl: SecretBool): SecretBool =
|
||||
## Constant-time in-place conditional addition
|
||||
## The addition is only performed if ctl is "true"
|
||||
## The result carry is always computed.
|
||||
(CTBool[Word]) csub(a.limbs, b.limbs, ctl)
|
||||
(SecretBool) csub(a.limbs, b.limbs, ctl)
|
||||
|
||||
func cdouble*(a: var BigInt, ctl: CTBool[Word]): CTBool[Word] =
|
||||
func cdouble*(a: var BigInt, ctl: SecretBool): SecretBool =
|
||||
## Constant-time in-place conditional doubling
|
||||
## The doubling is only performed if ctl is "true"
|
||||
## The result carry is always computed.
|
||||
(CTBool[Word]) cadd(a.limbs, a.limbs, ctl)
|
||||
(SecretBool) cadd(a.limbs, a.limbs, ctl)
|
||||
|
||||
func add*(a: var BigInt, b: BigInt): CTBool[Word] =
|
||||
func add*(a: var BigInt, b: BigInt): SecretBool =
|
||||
## Constant-time in-place addition
|
||||
## Returns the carry
|
||||
(CTBool[Word]) add(a.limbs, b.limbs)
|
||||
(SecretBool) add(a.limbs, b.limbs)
|
||||
|
||||
func add*(a: var BigInt, b: Word): CTBool[Word] =
|
||||
func add*(a: var BigInt, b: SecretWord): SecretBool =
|
||||
## Constant-time in-place addition
|
||||
## Returns the carry
|
||||
(CTBool[Word]) add(a.limbs, b)
|
||||
(SecretBool) add(a.limbs, b)
|
||||
|
||||
func sub*(a: var BigInt, b: BigInt): CTBool[Word] =
|
||||
func sub*(a: var BigInt, b: BigInt): SecretBool =
|
||||
## Constant-time in-place substraction
|
||||
## Returns the borrow
|
||||
(CTBool[Word]) sub(a.limbs, b.limbs)
|
||||
(SecretBool) sub(a.limbs, b.limbs)
|
||||
|
||||
func double*(a: var BigInt): CTBool[Word] =
|
||||
func double*(a: var BigInt): SecretBool =
|
||||
## Constant-time in-place doubling
|
||||
## Returns the carry
|
||||
(CTBool[Word]) add(a.limbs, a.limbs)
|
||||
(SecretBool) add(a.limbs, a.limbs)
|
||||
|
||||
func sum*(r: var BigInt, a, b: BigInt): CTBool[Word] =
|
||||
func sum*(r: var BigInt, a, b: BigInt): SecretBool =
|
||||
## Sum `a` and `b` into `r`.
|
||||
## `r` is initialized/overwritten
|
||||
##
|
||||
## Returns the carry
|
||||
(CTBool[Word]) sum(r.limbs, a.limbs, b.limbs)
|
||||
(SecretBool) sum(r.limbs, a.limbs, b.limbs)
|
||||
|
||||
func diff*(r: var BigInt, a, b: BigInt): CTBool[Word] =
|
||||
func diff*(r: var BigInt, a, b: BigInt): SecretBool =
|
||||
## Substract `b` from `a` and store the result into `r`.
|
||||
## `r` is initialized/overwritten
|
||||
##
|
||||
## Returns the borrow
|
||||
(CTBool[Word]) diff(r.limbs, a.limbs, b.limbs)
|
||||
(SecretBool) diff(r.limbs, a.limbs, b.limbs)
|
||||
|
||||
func double*(r: var BigInt, a: BigInt): CTBool[Word] =
|
||||
func double*(r: var BigInt, a: BigInt): SecretBool =
|
||||
## Double `a` into `r`.
|
||||
## `r` is initialized/overwritten
|
||||
##
|
||||
## Returns the carry
|
||||
(CTBool[Word]) sum(r.limbs, a.limbs, a.limbs)
|
||||
(SecretBool) sum(r.limbs, a.limbs, a.limbs)
|
||||
|
||||
func div2*(a: var BigInt) =
|
||||
## In-place divide ``a`` by 2
|
||||
|
|
|
@ -71,7 +71,7 @@ func toBig*(src: Fp): auto {.noInit.} =
|
|||
# Copy
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func ccopy*(a: var Fp, b: Fp, ctl: CTBool[Word]) =
|
||||
func ccopy*(a: var Fp, b: Fp, ctl: SecretBool) =
|
||||
## Constant-time conditional copy
|
||||
## If ctl is true: b is copied into a
|
||||
## if ctl is false: b is not copied and a is untouched
|
||||
|
@ -106,15 +106,15 @@ func cswap*(a, b: var Fp, ctl: CTBool) =
|
|||
# In practice I'm not aware of such prime being using in elliptic curves.
|
||||
# 2^127 - 1 and 2^521 - 1 are used but 127 and 521 are not multiple of 32/64
|
||||
|
||||
func `==`*(a, b: Fp): CTBool[Word] =
|
||||
func `==`*(a, b: Fp): SecretBool =
|
||||
## Constant-time equality check
|
||||
a.mres == b.mres
|
||||
|
||||
func isZero*(a: Fp): CTBool[Word] =
|
||||
func isZero*(a: Fp): SecretBool =
|
||||
## Constant-time check if zero
|
||||
a.mres.isZero()
|
||||
|
||||
func isOne*(a: Fp): CTBool[Word] =
|
||||
func isOne*(a: Fp): SecretBool =
|
||||
## Constant-time check if one
|
||||
a.mres == Fp.C.getMontyOne()
|
||||
|
||||
|
@ -246,7 +246,7 @@ func powUnsafeExponent*(a: var Fp, exponent: openarray[byte]) =
|
|||
#
|
||||
# ############################################################
|
||||
|
||||
func isSquare*[C](a: Fp[C]): CTBool[Word] =
|
||||
func isSquare*[C](a: Fp[C]): SecretBool =
|
||||
## Returns true if ``a`` is a square (quadratic residue) in 𝔽p
|
||||
##
|
||||
## Assumes that the prime modulus ``p`` is public.
|
||||
|
@ -274,7 +274,7 @@ func sqrt_p3mod4*[C](a: var Fp[C]) =
|
|||
static: doAssert C.Mod.limbs[0].BaseType mod 4 == 3
|
||||
a.powUnsafeExponent(C.getPrimePlus1div4_BE())
|
||||
|
||||
func sqrt_if_square_p3mod4*[C](a: var Fp[C]): CTBool[Word] =
|
||||
func sqrt_if_square_p3mod4*[C](a: var Fp[C]): SecretBool =
|
||||
## If ``a`` is a square, compute the square root of ``a``
|
||||
## if not, ``a`` is unmodified.
|
||||
##
|
||||
|
|
|
@ -36,7 +36,7 @@ import
|
|||
# The limb-endianess is little-endian, less significant limb is at index 0.
|
||||
# The word-endianness is native-endian.
|
||||
|
||||
type Limbs*[N: static int] = array[N, Word]
|
||||
type Limbs*[N: static int] = array[N, SecretWord]
|
||||
## Limbs-type
|
||||
## Should be distinct type to avoid builtins to use non-constant time
|
||||
## implementation, for example for comparison.
|
||||
|
@ -69,14 +69,14 @@ debug:
|
|||
#
|
||||
# Commented out since we don't use a distinct type
|
||||
|
||||
# template `[]`[N](v: Limbs[N], idx: int): Word =
|
||||
# (array[N, Word])(v)[idx]
|
||||
# template `[]`[N](v: Limbs[N], idx: int): SecretWord =
|
||||
# (array[N, SecretWord])(v)[idx]
|
||||
#
|
||||
# template `[]`[N](v: var Limbs[N], idx: int): var Word =
|
||||
# (array[N, Word])(v)[idx]
|
||||
# template `[]`[N](v: var Limbs[N], idx: int): var SecretWord =
|
||||
# (array[N, SecretWord])(v)[idx]
|
||||
#
|
||||
# template `[]=`[N](v: Limbs[N], idx: int, val: Word) =
|
||||
# (array[N, Word])(v)[idx] = val
|
||||
# template `[]=`[N](v: Limbs[N], idx: int, val: SecretWord) =
|
||||
# (array[N, SecretWord])(v)[idx] = val
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
|
@ -106,14 +106,14 @@ func setZero*(a: var Limbs) =
|
|||
|
||||
func setOne*(a: var Limbs) =
|
||||
## Set ``a`` to 1
|
||||
a[0] = Word(1)
|
||||
a[0] = SecretWord(1)
|
||||
when a.len > 1:
|
||||
zeroMem(a[1].addr, (a.len - 1) * sizeof(Word))
|
||||
zeroMem(a[1].addr, (a.len - 1) * sizeof(SecretWord))
|
||||
|
||||
# Copy
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func ccopy*(a: var Limbs, b: Limbs, ctl: CTBool[Word]) =
|
||||
func ccopy*(a: var Limbs, b: Limbs, ctl: SecretBool) =
|
||||
## Constant-time conditional copy
|
||||
## If ctl is true: b is copied into a
|
||||
## if ctl is false: b is not copied and a is untouched
|
||||
|
@ -131,7 +131,7 @@ func cswap*(a, b: var Limbs, ctl: CTBool) =
|
|||
## Whether ``ctl`` is true or not, the same
|
||||
## memory accesses are done (unless the compiler tries to be clever)
|
||||
|
||||
var mask = -(Word ctl)
|
||||
var mask = -(SecretWord ctl)
|
||||
for i in 0 ..< a.len:
|
||||
let t = mask and (a[i] xor b[i])
|
||||
a[i] = a[i] xor t
|
||||
|
@ -140,7 +140,7 @@ func cswap*(a, b: var Limbs, ctl: CTBool) =
|
|||
# Comparison
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func `==`*(a, b: Limbs): CTBool[Word] =
|
||||
func `==`*(a, b: Limbs): SecretBool =
|
||||
## Returns true if 2 limbs are equal
|
||||
## Comparison is constant-time
|
||||
var accum = Zero
|
||||
|
@ -148,37 +148,37 @@ func `==`*(a, b: Limbs): CTBool[Word] =
|
|||
accum = accum or (a[i] xor b[i])
|
||||
result = accum.isZero()
|
||||
|
||||
func `<`*(a, b: Limbs): CTBool[Word] =
|
||||
func `<`*(a, b: Limbs): SecretBool =
|
||||
## Returns true if a < b
|
||||
## Comparison is constant-time
|
||||
var diff: Word
|
||||
var diff: SecretWord
|
||||
var borrow: Borrow
|
||||
for i in 0 ..< a.len:
|
||||
subB(borrow, diff, a[i], b[i], borrow)
|
||||
|
||||
result = (CTBool[Word])(borrow)
|
||||
result = (SecretBool)(borrow)
|
||||
|
||||
func `<=`*(a, b: Limbs): CTBool[Word] =
|
||||
func `<=`*(a, b: Limbs): SecretBool =
|
||||
## Returns true if a <= b
|
||||
## Comparison is constant-time
|
||||
not(b < a)
|
||||
|
||||
func isZero*(a: Limbs): CTBool[Word] =
|
||||
func isZero*(a: Limbs): SecretBool =
|
||||
## Returns true if ``a`` is equal to zero
|
||||
var accum = Zero
|
||||
for i in 0 ..< a.len:
|
||||
accum = accum or a[i]
|
||||
result = accum.isZero()
|
||||
|
||||
func isOne*(a: Limbs): CTBool[Word] =
|
||||
func isOne*(a: Limbs): SecretBool =
|
||||
## Returns true if ``a`` is equal to one
|
||||
result = a[0] == Word(1)
|
||||
result = a[0] == SecretWord(1)
|
||||
for i in 1 ..< a.len:
|
||||
result = result and a[i].isZero()
|
||||
|
||||
func isOdd*(a: Limbs): CTBool[Word] =
|
||||
func isOdd*(a: Limbs): SecretBool =
|
||||
## Returns true if a is odd
|
||||
CTBool[Word](a[0] and Word(1))
|
||||
SecretBool(a[0] and SecretWord(1))
|
||||
|
||||
# Arithmetic
|
||||
# ------------------------------------------------------------
|
||||
|
@ -190,7 +190,7 @@ func add*(a: var Limbs, b: Limbs): Carry =
|
|||
for i in 0 ..< a.len:
|
||||
addC(result, a[i], a[i], b[i], result)
|
||||
|
||||
func add*(a: var Limbs, w: Word): Carry =
|
||||
func add*(a: var Limbs, w: SecretWord): Carry =
|
||||
## Limbs addition, add a number that fits in a word
|
||||
## Returns the carry
|
||||
result = Carry(0)
|
||||
|
@ -198,7 +198,7 @@ func add*(a: var Limbs, w: Word): Carry =
|
|||
for i in 1 ..< a.len:
|
||||
addC(result, a[i], a[i], Zero, result)
|
||||
|
||||
func cadd*(a: var Limbs, b: Limbs, ctl: CTBool[Word]): Carry =
|
||||
func cadd*(a: var Limbs, b: Limbs, ctl: SecretBool): Carry =
|
||||
## Limbs conditional addition
|
||||
## Returns the carry
|
||||
##
|
||||
|
@ -208,7 +208,7 @@ func cadd*(a: var Limbs, b: Limbs, ctl: CTBool[Word]): Carry =
|
|||
##
|
||||
## Time and memory accesses are the same whether a copy occurs or not
|
||||
result = Carry(0)
|
||||
var sum: Word
|
||||
var sum: SecretWord
|
||||
for i in 0 ..< a.len:
|
||||
addC(result, sum, a[i], b[i], result)
|
||||
ctl.ccopy(a[i], sum)
|
||||
|
@ -229,7 +229,7 @@ func sub*(a: var Limbs, b: Limbs): Borrow =
|
|||
for i in 0 ..< a.len:
|
||||
subB(result, a[i], a[i], b[i], result)
|
||||
|
||||
func csub*(a: var Limbs, b: Limbs, ctl: CTBool[Word]): Borrow =
|
||||
func csub*(a: var Limbs, b: Limbs, ctl: SecretBool): Borrow =
|
||||
## Limbs conditional substraction
|
||||
## Returns the borrow
|
||||
##
|
||||
|
@ -239,7 +239,7 @@ func csub*(a: var Limbs, b: Limbs, ctl: CTBool[Word]): Borrow =
|
|||
##
|
||||
## Time and memory accesses are the same whether a copy occurs or not
|
||||
result = Borrow(0)
|
||||
var diff: Word
|
||||
var diff: SecretWord
|
||||
for i in 0 ..< a.len:
|
||||
subB(result, diff, a[i], b[i], result)
|
||||
ctl.ccopy(a[i], diff)
|
||||
|
@ -266,11 +266,11 @@ func cneg*(a: var Limbs, ctl: CTBool) =
|
|||
# So we need to xor all words and then add 1
|
||||
# The "+1" might carry
|
||||
# So we fuse the 2 steps
|
||||
let mask = -Word(ctl) # Obtain a 0xFF... or 0x00... mask
|
||||
var carry = Word(ctl)
|
||||
let mask = -SecretWord(ctl) # Obtain a 0xFF... or 0x00... mask
|
||||
var carry = SecretWord(ctl)
|
||||
for i in 0 ..< a.len:
|
||||
let t = (a[i] xor mask) + carry # XOR with mask and add 0x01 or 0x00 respectively
|
||||
carry = Word(t < carry) # Carry on
|
||||
carry = SecretWord(t < carry) # Carry on
|
||||
a[i] = t
|
||||
|
||||
# Bit manipulation
|
||||
|
|
|
@ -92,7 +92,7 @@ func steinsGCD*(v: var Limbs, a: Limbs, F, M: Limbs, bits: int, mp1div2: Limbs)
|
|||
let isOddA = a.isOdd()
|
||||
|
||||
# if isOddA: a -= b
|
||||
let aLessThanB = isOddA and (CTBool[Word]) a.csub(b, isOddA)
|
||||
let aLessThanB = isOddA and (SecretBool) a.csub(b, isOddA)
|
||||
# if a < b and the sub was processed
|
||||
# in that case, b <- a = a - b + b
|
||||
discard b.cadd(a, aLessThanB)
|
||||
|
@ -104,7 +104,7 @@ func steinsGCD*(v: var Limbs, a: Limbs, F, M: Limbs, bits: int, mp1div2: Limbs)
|
|||
# Swap u and v is a < b
|
||||
u.cswap(v, aLessThanB)
|
||||
# if isOddA: u -= v (mod M)
|
||||
let neg = isOddA and (CTBool[Word]) u.csub(v, isOddA)
|
||||
let neg = isOddA and (SecretBool) u.csub(v, isOddA)
|
||||
let corrected = u.cadd(M, neg)
|
||||
|
||||
let isOddU = u.isOdd()
|
||||
|
@ -141,7 +141,7 @@ func steinsGCD*(v: var Limbs, a: Limbs, F, M: Limbs, bits: int, mp1div2: Limbs)
|
|||
# ------------------------------------------------------------
|
||||
|
||||
type
|
||||
LimbsView = ptr UncheckedArray[Word]
|
||||
LimbsView = ptr UncheckedArray[SecretWord]
|
||||
## Type-erased fixed-precision limbs
|
||||
##
|
||||
## This type mirrors the Limb type and is used
|
||||
|
@ -172,19 +172,19 @@ template view(a: var Limbs): LimbsViewMut =
|
|||
## Returns a borrowed type-erased mutable view to a mutable bigint
|
||||
LimbsViewMut(cast[LimbsView](a.addr))
|
||||
|
||||
template `[]`*(v: LimbsViewConst, limbIdx: int): Word =
|
||||
template `[]`*(v: LimbsViewConst, limbIdx: int): SecretWord =
|
||||
LimbsView(v)[limbIdx]
|
||||
|
||||
template `[]`*(v: LimbsViewMut, limbIdx: int): var Word =
|
||||
template `[]`*(v: LimbsViewMut, limbIdx: int): var SecretWord =
|
||||
LimbsView(v)[limbIdx]
|
||||
|
||||
template `[]=`*(v: LimbsViewMut, limbIdx: int, val: Word) =
|
||||
template `[]=`*(v: LimbsViewMut, limbIdx: int, val: SecretWord) =
|
||||
LimbsView(v)[limbIdx] = val
|
||||
|
||||
# Type-erased add-sub
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func cadd(a: LimbsViewMut, b: LimbsViewAny, ctl: CTBool[Word], len: int): Carry =
|
||||
func cadd(a: LimbsViewMut, b: LimbsViewAny, ctl: SecretBool, len: int): Carry =
|
||||
## Type-erased conditional addition
|
||||
## Returns the carry
|
||||
##
|
||||
|
@ -194,12 +194,12 @@ func cadd(a: LimbsViewMut, b: LimbsViewAny, ctl: CTBool[Word], len: int): Carry
|
|||
##
|
||||
## Time and memory accesses are the same whether a copy occurs or not
|
||||
result = Carry(0)
|
||||
var sum: Word
|
||||
var sum: SecretWord
|
||||
for i in 0 ..< len:
|
||||
addC(result, sum, a[i], b[i], result)
|
||||
ctl.ccopy(a[i], sum)
|
||||
|
||||
func csub(a: LimbsViewMut, b: LimbsViewAny, ctl: CTBool[Word], len: int): Borrow =
|
||||
func csub(a: LimbsViewMut, b: LimbsViewAny, ctl: SecretBool, len: int): Borrow =
|
||||
## Type-erased conditional addition
|
||||
## Returns the borrow
|
||||
##
|
||||
|
@ -209,7 +209,7 @@ func csub(a: LimbsViewMut, b: LimbsViewAny, ctl: CTBool[Word], len: int): Borrow
|
|||
##
|
||||
## Time and memory accesses are the same whether a copy occurs or not
|
||||
result = Borrow(0)
|
||||
var diff: Word
|
||||
var diff: SecretWord
|
||||
for i in 0 ..< len:
|
||||
subB(result, diff, a[i], b[i], result)
|
||||
ctl.ccopy(a[i], diff)
|
||||
|
@ -222,8 +222,8 @@ func numWordsFromBits(bits: int): int {.inline.} =
|
|||
result = (bits + WordBitWidth - 1) shr divShiftor
|
||||
|
||||
func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
|
||||
c: Word, M: LimbsViewConst, mBits: int
|
||||
): tuple[neg, tooBig: CTBool[Word]] =
|
||||
c: SecretWord, M: LimbsViewConst, mBits: int
|
||||
): tuple[neg, tooBig: SecretBool] =
|
||||
## Estimate a <- a shl 2^w + c (mod M)
|
||||
##
|
||||
## with w the base word width, usually 32 on 32-bit platforms and 64 on 64-bit platforms
|
||||
|
@ -237,7 +237,7 @@ func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
|
|||
let MLen = numWordsFromBits(mBits)
|
||||
|
||||
# Captures aLen and MLen
|
||||
template `[]`(v: untyped, limbIdxFromEnd: BackwardsIndex): Word {.dirty.}=
|
||||
template `[]`(v: untyped, limbIdxFromEnd: BackwardsIndex): SecretWord {.dirty.}=
|
||||
v[`v Len` - limbIdxFromEnd.int]
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
@ -245,16 +245,16 @@ func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
|
|||
let hi = a[^1] # Save the high word to detect carries
|
||||
let R = mBits and (WordBitWidth - 1) # R = mBits mod 64
|
||||
|
||||
var a0, a1, m0: Word
|
||||
var a0, a1, m0: SecretWord
|
||||
if R == 0: # If the number of mBits is a multiple of 64
|
||||
a0 = a[^1] #
|
||||
moveMem(a[1].addr, a[0].addr, (aLen-1) * Word.sizeof) # we can just shift words
|
||||
moveMem(a[1].addr, a[0].addr, (aLen-1) * SecretWord.sizeof) # we can just shift words
|
||||
a[0] = c # and replace the first one by c
|
||||
a1 = a[^1]
|
||||
m0 = M[^1]
|
||||
else: # Else: need to deal with partial word shifts at the edge.
|
||||
a0 = (a[^1] shl (WordBitWidth-R)) or (a[^2] shr R)
|
||||
moveMem(a[1].addr, a[0].addr, (aLen-1) * Word.sizeof)
|
||||
moveMem(a[1].addr, a[0].addr, (aLen-1) * SecretWord.sizeof)
|
||||
a[0] = c
|
||||
a1 = (a[^1] shl (WordBitWidth-R)) or (a[^2] shr R)
|
||||
m0 = (M[^1] shl (WordBitWidth-R)) or (M[^2] shr R)
|
||||
|
@ -262,7 +262,7 @@ func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
|
|||
# m0 has its high bit set. (a0, a1)/p0 fits in a limb.
|
||||
# Get a quotient q, at most we will be 2 iterations off
|
||||
# from the true quotient
|
||||
var q, r: Word
|
||||
var q, r: SecretWord
|
||||
unsafeDiv2n1n(q, r, a0, a1, m0) # Estimate quotient
|
||||
q = mux( # If n_hi == divisor
|
||||
a0 == m0, MaxWord, # Quotient == MaxWord (0b1111...1111)
|
||||
|
@ -277,7 +277,7 @@ func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
|
|||
var over_p = CtTrue # Track if quotient greater than the modulus
|
||||
|
||||
for i in 0 ..< MLen:
|
||||
var qp_lo: Word
|
||||
var qp_lo: SecretWord
|
||||
|
||||
block: # q*p
|
||||
# q * p + carry (doubleword) carry from previous limb
|
||||
|
@ -286,7 +286,7 @@ func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
|
|||
block: # a*2^64 - q*p
|
||||
var borrow: Borrow
|
||||
subB(borrow, a[i], a[i], qp_lo, Borrow(0))
|
||||
carry += Word(borrow) # Adjust if borrow
|
||||
carry += SecretWord(borrow) # Adjust if borrow
|
||||
|
||||
over_p = mux(
|
||||
a[i] == M[i], over_p,
|
||||
|
@ -302,7 +302,7 @@ func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
|
|||
result.tooBig = not(result.neg) and (over_p or (carry < hi))
|
||||
|
||||
func shlAddMod(a: LimbsViewMut, aLen: int,
|
||||
c: Word, M: LimbsViewConst, mBits: int) =
|
||||
c: SecretWord, M: LimbsViewConst, mBits: int) =
|
||||
## Fused modular left-shift + add
|
||||
## Shift input `a` by a word and add `c` modulo `M`
|
||||
##
|
||||
|
@ -323,7 +323,7 @@ func shlAddMod(a: LimbsViewMut, aLen: int,
|
|||
let lo = c shl (WordBitWidth-R)
|
||||
let m0 = M[0] shl (WordBitWidth-R)
|
||||
|
||||
var q, r: Word
|
||||
var q, r: SecretWord
|
||||
unsafeDiv2n1n(q, r, hi, lo, m0) # (hi, lo) mod M
|
||||
|
||||
a[0] = r shr (WordBitWidth-R)
|
||||
|
@ -346,7 +346,7 @@ func reduce(r: LimbsViewMut,
|
|||
# if a uses less bits than the modulus,
|
||||
# it is guaranteed < modulus.
|
||||
# This relies on the precondition that the modulus uses all declared bits
|
||||
copyMem(r[0].addr, a[0].unsafeAddr, aLen * sizeof(Word))
|
||||
copyMem(r[0].addr, a[0].unsafeAddr, aLen * sizeof(SecretWord))
|
||||
for i in aLen ..< mLen:
|
||||
r[i] = Zero
|
||||
else:
|
||||
|
@ -354,7 +354,7 @@ func reduce(r: LimbsViewMut,
|
|||
# we can copy modulus.limbs-1 words
|
||||
# and modular shift-left-add the rest
|
||||
let aOffset = aLen - mLen
|
||||
copyMem(r[0].addr, a[aOffset+1].unsafeAddr, (mLen-1) * sizeof(Word))
|
||||
copyMem(r[0].addr, a[aOffset+1].unsafeAddr, (mLen-1) * sizeof(SecretWord))
|
||||
r[rLen - 1] = Zero
|
||||
# Now shift-left the copied words while adding the new word modulo M
|
||||
for i in countdown(aOffset, 0):
|
||||
|
|
|
@ -90,7 +90,7 @@ func montyMul_CIOS_nocarry(r: var Limbs, a, b, M: Limbs, m0ninv: BaseType) =
|
|||
## Montgomery Multiplication using Coarse Grained Operand Scanning (CIOS)
|
||||
## and no-carry optimization.
|
||||
## This requires the most significant word of the Modulus
|
||||
## M[^1] < high(Word) shr 1 (i.e. less than 0b01111...1111)
|
||||
## M[^1] < high(SecretWord) shr 1 (i.e. less than 0b01111...1111)
|
||||
## https://hackmd.io/@zkteam/modular_multiplication
|
||||
|
||||
# We want all the computation to be kept in registers
|
||||
|
@ -101,10 +101,10 @@ func montyMul_CIOS_nocarry(r: var Limbs, a, b, M: Limbs, m0ninv: BaseType) =
|
|||
# (A, t[0]) <- a[0] * b[i] + t[0]
|
||||
# m <- (t[0] * m0ninv) mod 2^w
|
||||
# (C, _) <- m * M[0] + t[0]
|
||||
var A: Word
|
||||
var A: SecretWord
|
||||
muladd1(A, t[0], a[0], b[i], t[0])
|
||||
let m = t[0] * Word(m0ninv)
|
||||
var C, lo: Word
|
||||
let m = t[0] * SecretWord(m0ninv)
|
||||
var C, lo: SecretWord
|
||||
muladd1(C, lo, m, M[0], t[0])
|
||||
|
||||
staticFor j, 1, N:
|
||||
|
@ -133,7 +133,7 @@ func montyMul_CIOS(r: var Limbs, a, b, M: Limbs, m0ninv: BaseType) =
|
|||
var t: typeof(M) # zero-init
|
||||
const N = t.len
|
||||
# Extra words to handle up to 2 carries t[N] and t[N+1]
|
||||
var tN: Word
|
||||
var tN: SecretWord
|
||||
var tNp1: Carry
|
||||
|
||||
staticFor i, 0, N:
|
||||
|
@ -148,7 +148,7 @@ func montyMul_CIOS(r: var Limbs, a, b, M: Limbs, m0ninv: BaseType) =
|
|||
# m <- (t[0] * m0ninv) mod 2^w
|
||||
# (C, _) <- m * M[0] + t[0]
|
||||
var C, lo = Zero
|
||||
let m = t[0] * Word(m0ninv)
|
||||
let m = t[0] * SecretWord(m0ninv)
|
||||
muladd1(C, lo, m, M[0], t[0])
|
||||
staticFor j, 1, N:
|
||||
# (C, t[j-1]) <- m*M[j] + t[j] + C
|
||||
|
@ -158,7 +158,7 @@ func montyMul_CIOS(r: var Limbs, a, b, M: Limbs, m0ninv: BaseType) =
|
|||
# (_, t[N]) <- t[N+1] + C
|
||||
var carry: Carry
|
||||
addC(carry, t[N-1], tN, C, Carry(0))
|
||||
addC(carry, tN, Word(tNp1), Zero, carry)
|
||||
addC(carry, tN, SecretWord(tNp1), Zero, carry)
|
||||
|
||||
# t[N+1] can only be non-zero in the intermediate computation
|
||||
# since it is immediately reduce to t[N] at the end of each "i" iteration
|
||||
|
@ -170,7 +170,7 @@ func montySquare_CIOS_nocarry(r: var Limbs, a, M: Limbs, m0ninv: BaseType) =
|
|||
## Montgomery Multiplication using Coarse Grained Operand Scanning (CIOS)
|
||||
## and no-carry optimization.
|
||||
## This requires the most significant word of the Modulus
|
||||
## M[^1] < high(Word) shr 2 (i.e. less than 0b00111...1111)
|
||||
## M[^1] < high(SecretWord) shr 2 (i.e. less than 0b00111...1111)
|
||||
## https://hackmd.io/@zkteam/modular_multiplication
|
||||
|
||||
# We want all the computation to be kept in registers
|
||||
|
@ -181,7 +181,7 @@ func montySquare_CIOS_nocarry(r: var Limbs, a, M: Limbs, m0ninv: BaseType) =
|
|||
# Squaring
|
||||
var
|
||||
A1: Carry
|
||||
A0: Word
|
||||
A0: SecretWord
|
||||
# (A0, t[i]) <- a[i] * a[i] + t[i]
|
||||
muladd1(A0, t[i], a[i], a[i], t[i])
|
||||
staticFor j, i+1, N:
|
||||
|
@ -192,8 +192,8 @@ func montySquare_CIOS_nocarry(r: var Limbs, a, M: Limbs, m0ninv: BaseType) =
|
|||
# Reduction
|
||||
# m <- (t[0] * m0ninv) mod 2^w
|
||||
# (C, _) <- m * M[0] + t[0]
|
||||
let m = t[0] * Word(m0ninv)
|
||||
var C, lo: Word
|
||||
let m = t[0] * SecretWord(m0ninv)
|
||||
var C, lo: SecretWord
|
||||
muladd1(C, lo, m, M[0], t[0])
|
||||
staticFor j, 1, N:
|
||||
# (C, t[j-1]) <- m*M[j] + t[j] + C
|
||||
|
@ -220,14 +220,14 @@ func montySquare_CIOS(r: var Limbs, a, M: Limbs, m0ninv: BaseType) =
|
|||
var t: typeof(M) # zero-init
|
||||
const N = t.len
|
||||
# Extra words to handle up to 2 carries t[N] and t[N+1]
|
||||
var tNp1: Word
|
||||
var tN: Word
|
||||
var tNp1: SecretWord
|
||||
var tN: SecretWord
|
||||
|
||||
staticFor i, 0, N:
|
||||
# Squaring
|
||||
var
|
||||
A1: Carry
|
||||
A0: Word
|
||||
A0: SecretWord
|
||||
# (A0, t[i]) <- a[i] * a[i] + t[i]
|
||||
muladd1(A0, t[i], a[i], a[i], t[i])
|
||||
staticFor j, i+1, N:
|
||||
|
@ -237,13 +237,13 @@ func montySquare_CIOS(r: var Limbs, a, M: Limbs, m0ninv: BaseType) =
|
|||
|
||||
var carryS: Carry
|
||||
addC(carryS, tN, tN, A0, Carry(0))
|
||||
addC(carryS, tNp1, Word(A1), Zero, carryS)
|
||||
addC(carryS, tNp1, SecretWord(A1), Zero, carryS)
|
||||
|
||||
# Reduction
|
||||
# m <- (t[0] * m0ninv) mod 2^w
|
||||
# (C, _) <- m * M[0] + t[0]
|
||||
var C, lo: Word
|
||||
let m = t[0] * Word(m0ninv)
|
||||
var C, lo: SecretWord
|
||||
let m = t[0] * SecretWord(m0ninv)
|
||||
muladd1(C, lo, m, M[0], t[0])
|
||||
staticFor j, 1, N:
|
||||
# (C, t[j-1]) <- m*M[j] + t[j] + C
|
||||
|
@ -253,7 +253,7 @@ func montySquare_CIOS(r: var Limbs, a, M: Limbs, m0ninv: BaseType) =
|
|||
# (_, t[N]) <- t[N+1] + C
|
||||
var carryR: Carry
|
||||
addC(carryR, t[N-1], tN, C, Carry(0))
|
||||
addC(carryR, tN, Word(tNp1), Zero, carryR)
|
||||
addC(carryR, tN, SecretWord(tNp1), Zero, carryR)
|
||||
|
||||
discard t.csub(M, tN.isNonZero() or not(t < M)) # TODO: (t >= M) is unnecessary for prime in the form (2^64)^w
|
||||
r = t
|
||||
|
@ -265,7 +265,7 @@ func montyMul*(
|
|||
r: var Limbs, a, b, M: Limbs,
|
||||
m0ninv: static BaseType, canUseNoCarryMontyMul: static bool) =
|
||||
## Compute r <- a*b (mod M) in the Montgomery domain
|
||||
## `m0ninv` = -1/M (mod Word). Our words are 2^32 or 2^64
|
||||
## `m0ninv` = -1/M (mod SecretWord). Our words are 2^32 or 2^64
|
||||
##
|
||||
## This resets r to zero before processing. Use {.noInit.}
|
||||
## to avoid duplicating with Nim zero-init policy
|
||||
|
@ -298,7 +298,7 @@ func montyMul*(
|
|||
func montySquare*(r: var Limbs, a, M: Limbs,
|
||||
m0ninv: static BaseType, canUseNoCarryMontySquare: static bool) =
|
||||
## Compute r <- a^2 (mod M) in the Montgomery domain
|
||||
## `m0ninv` = -1/M (mod Word). Our words are 2^31 or 2^63
|
||||
## `m0ninv` = -1/M (mod SecretWord). Our words are 2^31 or 2^63
|
||||
|
||||
when canUseNoCarryMontySquare:
|
||||
montySquare_CIOS_nocarry(r, a, M, m0ninv)
|
||||
|
@ -512,13 +512,13 @@ func montyPow*(
|
|||
# in particular we need the same memory accesses, we can't
|
||||
# just index the openarray with the bits to avoid cache attacks.
|
||||
for i in 1 ..< 1 shl k:
|
||||
let ctl = Word(i) == Word(bits)
|
||||
let ctl = SecretWord(i) == SecretWord(bits)
|
||||
scratchspace[1].ccopy(scratchspace[1+i], ctl)
|
||||
|
||||
# Multiply with the looked-up value
|
||||
# we keep the product only if the exponent bits are not all zero
|
||||
scratchspace[0].montyMul(a, scratchspace[1], M, m0ninv, canUseNoCarryMontyMul)
|
||||
a.ccopy(scratchspace[0], Word(bits).isNonZero())
|
||||
a.ccopy(scratchspace[0], SecretWord(bits).isNonZero())
|
||||
|
||||
func montyPowUnsafeExponent*(
|
||||
a: var Limbs,
|
||||
|
|
|
@ -72,11 +72,11 @@ func add(a: var BigInt, w: BaseType): bool =
|
|||
## Returns the carry
|
||||
var carry, sum: BaseType
|
||||
addC(carry, sum, BaseType(a.limbs[0]), w, carry)
|
||||
a.limbs[0] = Word(sum)
|
||||
a.limbs[0] = SecretWord(sum)
|
||||
for i in 1 ..< a.limbs.len:
|
||||
let ai = BaseType(a.limbs[i])
|
||||
addC(carry, sum, ai, 0, carry)
|
||||
a.limbs[i] = Word(sum)
|
||||
a.limbs[i] = SecretWord(sum)
|
||||
|
||||
result = bool(carry)
|
||||
|
||||
|
@ -87,7 +87,7 @@ func dbl(a: var BigInt): bool =
|
|||
for i in 0 ..< a.limbs.len:
|
||||
let ai = BaseType(a.limbs[i])
|
||||
addC(carry, sum, ai, ai, carry)
|
||||
a.limbs[i] = Word(sum)
|
||||
a.limbs[i] = SecretWord(sum)
|
||||
|
||||
result = bool(carry)
|
||||
|
||||
|
@ -96,11 +96,11 @@ func sub(a: var BigInt, w: BaseType): bool =
|
|||
## Returns the carry
|
||||
var borrow, diff: BaseType
|
||||
subB(borrow, diff, BaseType(a.limbs[0]), w, borrow)
|
||||
a.limbs[0] = Word(diff)
|
||||
a.limbs[0] = SecretWord(diff)
|
||||
for i in 1 ..< a.limbs.len:
|
||||
let ai = BaseType(a.limbs[i])
|
||||
subB(borrow, diff, ai, 0, borrow)
|
||||
a.limbs[i] = Word(diff)
|
||||
a.limbs[i] = SecretWord(diff)
|
||||
|
||||
result = bool(borrow)
|
||||
|
||||
|
@ -116,7 +116,7 @@ func cadd(a: var BigInt, b: BigInt, ctl: bool): bool =
|
|||
let bi = BaseType(b.limbs[i])
|
||||
addC(carry, sum, ai, bi, carry)
|
||||
if ctl:
|
||||
a.limbs[i] = Word(sum)
|
||||
a.limbs[i] = SecretWord(sum)
|
||||
|
||||
result = bool(carry)
|
||||
|
||||
|
@ -132,7 +132,7 @@ func csub(a: var BigInt, b: BigInt, ctl: bool): bool =
|
|||
let bi = BaseType(b.limbs[i])
|
||||
subB(borrow, diff, ai, bi, borrow)
|
||||
if ctl:
|
||||
a.limbs[i] = Word(diff)
|
||||
a.limbs[i] = SecretWord(diff)
|
||||
|
||||
result = bool(borrow)
|
||||
|
||||
|
@ -181,7 +181,7 @@ func useNoCarryMontySquare*(M: BigInt): bool =
|
|||
func negInvModWord*(M: BigInt): BaseType =
|
||||
## Returns the Montgomery domain magic constant for the input modulus:
|
||||
##
|
||||
## µ ≡ -1/M[0] (mod Word)
|
||||
## µ ≡ -1/M[0] (mod SecretWord)
|
||||
##
|
||||
## M[0] is the least significant limb of M
|
||||
## M must be odd and greater than 2.
|
||||
|
@ -265,7 +265,7 @@ func r_powmod(n: static int, M: BigInt): BigInt =
|
|||
start = (w-1)*WordBitWidth + msb
|
||||
stop = n*WordBitWidth*w
|
||||
|
||||
result.limbs[^1] = Word(BaseType(1) shl msb) # C0 = 2^(wn-1), the power of 2 immediatly less than the modulus
|
||||
result.limbs[^1] = SecretWord(BaseType(1) shl msb) # C0 = 2^(wn-1), the power of 2 immediatly less than the modulus
|
||||
for _ in start ..< stop:
|
||||
result.doubleMod(M)
|
||||
|
||||
|
|
|
@ -24,20 +24,22 @@ else:
|
|||
## Physical BigInt for conversion in "normal integers"
|
||||
|
||||
type
|
||||
Word* = Ct[BaseType]
|
||||
SecretWord* = Ct[BaseType]
|
||||
## Logical BigInt word
|
||||
## A logical BigInt word is of size physical MachineWord-1
|
||||
|
||||
SecretBool* = CTBool[SecretWord]
|
||||
|
||||
const
|
||||
WordBitWidth* = sizeof(Word) * 8
|
||||
WordBitWidth* = sizeof(SecretWord) * 8
|
||||
## Logical word size
|
||||
|
||||
CtTrue* = ctrue(Word)
|
||||
CtFalse* = cfalse(Word)
|
||||
CtTrue* = ctrue(SecretWord)
|
||||
CtFalse* = cfalse(SecretWord)
|
||||
|
||||
Zero* = Word(0)
|
||||
One* = Word(1)
|
||||
MaxWord* = Word(high(BaseType))
|
||||
Zero* = SecretWord(0)
|
||||
One* = SecretWord(1)
|
||||
MaxWord* = SecretWord(high(BaseType))
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
|
|
|
@ -42,7 +42,7 @@ func curve_eq_rhs*[F](y2: var F, x: F) =
|
|||
t *= F.C.getCoefA()
|
||||
y2 += t
|
||||
|
||||
func isOnCurve*[F](x, y: F): CTBool[Word] =
|
||||
func isOnCurve*[F](x, y: F): SecretBool =
|
||||
## Returns true if the (x, y) coordinates
|
||||
## represents a point of the elliptic curve
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ type ECP_SWei_Proj*[F] = object
|
|||
## Note that projective coordinates are not unique
|
||||
x, y, z: F
|
||||
|
||||
func `==`*[F](P, Q: ECP_SWei_Proj[F]): CTBool[Word] =
|
||||
func `==`*[F](P, Q: ECP_SWei_Proj[F]): SecretBool =
|
||||
## Constant-time equality check
|
||||
# Reminder: the representation is not unique
|
||||
|
||||
|
@ -46,7 +46,7 @@ func `==`*[F](P, Q: ECP_SWei_Proj[F]): CTBool[Word] =
|
|||
b.prod(Q.y, P.z)
|
||||
result = result and a == b
|
||||
|
||||
func isInf*(P: ECP_SWei_Proj): CTBool[Word] =
|
||||
func isInf*(P: ECP_SWei_Proj): SecretBool =
|
||||
## Returns true if P is an infinity point
|
||||
## and false otherwise
|
||||
##
|
||||
|
@ -62,7 +62,7 @@ func setInf*(P: var ECP_SWei_Proj) =
|
|||
P.y.setOne()
|
||||
P.z.setZero()
|
||||
|
||||
func trySetFromCoordsXandZ*[F](P: var ECP_SWei_Proj[F], x, z: F): CTBool[Word] =
|
||||
func trySetFromCoordsXandZ*[F](P: var ECP_SWei_Proj[F], x, z: F): SecretBool =
|
||||
## Try to create a point the elliptic curve
|
||||
## Y²Z = X³ + aXZ² + bZ³ (projective coordinates)
|
||||
## y² = x³ + a x + b (affine coordinate)
|
||||
|
@ -79,7 +79,7 @@ func trySetFromCoordsXandZ*[F](P: var ECP_SWei_Proj[F], x, z: F): CTBool[Word] =
|
|||
P.y *= z
|
||||
P.z = z
|
||||
|
||||
func trySetFromCoordX*[F](P: var ECP_SWei_Proj[F], x: F): CTBool[Word] =
|
||||
func trySetFromCoordX*[F](P: var ECP_SWei_Proj[F], x: F): SecretBool =
|
||||
## Try to create a point the elliptic curve
|
||||
## y² = x³ + a x + b (affine coordinate)
|
||||
##
|
||||
|
|
|
@ -46,7 +46,7 @@ func fromRawUintLE(
|
|||
acc_len = 0
|
||||
|
||||
for src_idx in 0 ..< src.len:
|
||||
let src_byte = Word(src[src_idx])
|
||||
let src_byte = SecretWord(src[src_idx])
|
||||
|
||||
# buffer reads
|
||||
acc = acc or (src_byte shl acc_len)
|
||||
|
@ -83,7 +83,7 @@ func fromRawUintBE(
|
|||
acc_len = 0
|
||||
|
||||
for src_idx in countdown(src.len-1, 0):
|
||||
let src_byte = Word(src[src_idx])
|
||||
let src_byte = SecretWord(src[src_idx])
|
||||
|
||||
# buffer reads
|
||||
acc = acc or (src_byte shl acc_len)
|
||||
|
@ -194,7 +194,7 @@ func exportRawUintLE(
|
|||
acc = w
|
||||
acc_len = WordBitWidth
|
||||
else:
|
||||
when WordBitWidth == sizeof(Word) * 8:
|
||||
when WordBitWidth == sizeof(SecretWord) * 8:
|
||||
let lo = acc
|
||||
acc = w
|
||||
else: # If using 63-bit (or less) out of uint64
|
||||
|
@ -202,11 +202,11 @@ func exportRawUintLE(
|
|||
dec acc_len
|
||||
acc = w shr (WordBitWidth - acc_len)
|
||||
|
||||
if tail >= sizeof(Word):
|
||||
if tail >= sizeof(SecretWord):
|
||||
# Unrolled copy
|
||||
dst.blobFrom(src = lo, dst_idx, littleEndian)
|
||||
dst_idx += sizeof(Word)
|
||||
tail -= sizeof(Word)
|
||||
dst_idx += sizeof(SecretWord)
|
||||
tail -= sizeof(SecretWord)
|
||||
else:
|
||||
# Process the tail and exit
|
||||
when cpuEndian == littleEndian:
|
||||
|
@ -247,7 +247,7 @@ func exportRawUintBE(
|
|||
acc = w
|
||||
acc_len = WordBitWidth
|
||||
else:
|
||||
when WordBitWidth == sizeof(Word) * 8:
|
||||
when WordBitWidth == sizeof(SecretWord) * 8:
|
||||
let lo = acc
|
||||
acc = w
|
||||
else: # If using 63-bit (or less) out of uint64
|
||||
|
@ -255,9 +255,9 @@ func exportRawUintBE(
|
|||
dec acc_len
|
||||
acc = w shr (WordBitWidth - acc_len)
|
||||
|
||||
if tail >= sizeof(Word):
|
||||
if tail >= sizeof(SecretWord):
|
||||
# Unrolled copy
|
||||
tail -= sizeof(Word)
|
||||
tail -= sizeof(SecretWord)
|
||||
dst.blobFrom(src = lo, tail, bigEndian)
|
||||
else:
|
||||
# Process the tail and exit
|
||||
|
|
|
@ -16,7 +16,7 @@ import ./constant_time_types
|
|||
|
||||
# No exceptions allowed
|
||||
{.push raises: [].}
|
||||
# Word primitives are inlined
|
||||
# SecretWord primitives are inlined
|
||||
{.push inline.}
|
||||
|
||||
# ############################################################
|
||||
|
|
|
@ -16,9 +16,9 @@ import ./constant_time_types
|
|||
|
||||
# For efficiency, those are implemented in inline assembly if possible
|
||||
# API:
|
||||
# - mux(CTBool, Word, Word)
|
||||
# - mux(CTBool, SecretWord, SecretWord)
|
||||
# - mux(CTBool, CTBool, CTBool)
|
||||
# - ccopy(CTBool, var Word, Word)
|
||||
# - ccopy(CTBool, var SecretWord, SecretWord)
|
||||
#
|
||||
# Those prevents the compiler from introducing branches and leaking secret data:
|
||||
# - https://www.cl.cam.ac.uk/~rja14/Papers/whatyouc.pdf
|
||||
|
|
|
@ -59,19 +59,19 @@ func setOne*(a: var ExtensionField) =
|
|||
# Comparison
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
func `==`*(a, b: ExtensionField): CTBool[Word] =
|
||||
func `==`*(a, b: ExtensionField): SecretBool =
|
||||
## Constant-time equality check
|
||||
result = CtTrue
|
||||
for fA, fB in fields(a, b):
|
||||
result = result and (fA == fB)
|
||||
|
||||
func isZero*(a: ExtensionField): CTBool[Word] =
|
||||
func isZero*(a: ExtensionField): SecretBool =
|
||||
## Constant-time check if zero
|
||||
result = CtTrue
|
||||
for fA in fields(a):
|
||||
result = result and fA.isZero()
|
||||
|
||||
func isOne*(a: ExtensionField): CTBool[Word] =
|
||||
func isOne*(a: ExtensionField): SecretBool =
|
||||
## Constant-time check if one
|
||||
result = CtTrue
|
||||
for fieldName, fA in fieldPairs(a):
|
||||
|
|
|
@ -89,7 +89,7 @@ func random_unsafe[T](rng: var RngState, a: var T, C: static Curve) {.noInit.}=
|
|||
var reduced, unreduced{.noInit.}: T
|
||||
|
||||
for i in 0 ..< unreduced.limbs.len:
|
||||
unreduced.limbs[i] = Word(rng.next())
|
||||
unreduced.limbs[i] = SecretWord(rng.next())
|
||||
|
||||
# Note: a simple modulo will be biaised but it's simple and "fast"
|
||||
reduced.reduce(unreduced, C.Mod)
|
||||
|
|
|
@ -32,14 +32,14 @@ proc mainArith() =
|
|||
test "Adding 2 zeros":
|
||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||
let carry = a.cadd(b, ctrue(Word))
|
||||
let carry = a.cadd(b, CtTrue)
|
||||
check: a.isZero().bool
|
||||
|
||||
test "Adding 1 zero - real addition":
|
||||
block:
|
||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let carry = a.cadd(b, ctrue(Word))
|
||||
let carry = a.cadd(b, CtTrue)
|
||||
|
||||
let c = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
check:
|
||||
|
@ -47,7 +47,7 @@ proc mainArith() =
|
|||
block:
|
||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||
let carry = a.cadd(b, ctrue(Word))
|
||||
let carry = a.cadd(b, CtTrue)
|
||||
|
||||
let c = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
check:
|
||||
|
@ -57,7 +57,7 @@ proc mainArith() =
|
|||
block:
|
||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let carry = a.cadd(b, cfalse(Word))
|
||||
let carry = a.cadd(b, CtFalse)
|
||||
|
||||
let c = a
|
||||
check:
|
||||
|
@ -65,7 +65,7 @@ proc mainArith() =
|
|||
block:
|
||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||
let carry = a.cadd(b, cfalse(Word))
|
||||
let carry = a.cadd(b, CtFalse)
|
||||
|
||||
let c = a
|
||||
check:
|
||||
|
@ -75,7 +75,7 @@ proc mainArith() =
|
|||
block:
|
||||
var a = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let carry = a.cadd(b, ctrue(Word))
|
||||
let carry = a.cadd(b, CtTrue)
|
||||
|
||||
let c = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000001")
|
||||
check:
|
||||
|
@ -83,7 +83,7 @@ proc mainArith() =
|
|||
block:
|
||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
||||
let carry = a.cadd(b, ctrue(Word))
|
||||
let carry = a.cadd(b, CtTrue)
|
||||
|
||||
let c = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000001")
|
||||
check:
|
||||
|
@ -93,7 +93,7 @@ proc mainArith() =
|
|||
block:
|
||||
var a = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let carry = a.cadd(b, cfalse(Word))
|
||||
let carry = a.cadd(b, CtFalse)
|
||||
|
||||
let c = a
|
||||
check:
|
||||
|
@ -101,7 +101,7 @@ proc mainArith() =
|
|||
block:
|
||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000001_00000000_00000000")
|
||||
let carry = a.cadd(b, cfalse(Word))
|
||||
let carry = a.cadd(b, CtFalse)
|
||||
|
||||
let c = a
|
||||
check:
|
||||
|
@ -111,7 +111,7 @@ proc mainArith() =
|
|||
block:
|
||||
var a = fromHex(BigInt[128], "0x00000000_FFFFFFFF_FFFFFFFF_FFFFFFFE")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let carry = a.cadd(b, ctrue(Word))
|
||||
let carry = a.cadd(b, CtTrue)
|
||||
|
||||
let c = fromHex(BigInt[128], "0x00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF")
|
||||
check:
|
||||
|
@ -121,21 +121,21 @@ proc mainArith() =
|
|||
block:
|
||||
var a = fromHex(BigInt[128], "0x00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let carry = a.cadd(b, ctrue(Word))
|
||||
let carry = a.cadd(b, CtTrue)
|
||||
|
||||
let c = fromHex(BigInt[128], "0x00000001_00000000_00000000_00000000")
|
||||
check:
|
||||
bool(a == c)
|
||||
not bool(carry)
|
||||
|
||||
suite "BigInt + Word":
|
||||
suite "BigInt + SecretWord":
|
||||
test "Addition limbs carry":
|
||||
block: # P256 / 2
|
||||
var a = BigInt[256].fromhex"0x7fffffff800000008000000000000000000000007fffffffffffffffffffffff"
|
||||
|
||||
let expected = BigInt[256].fromHex"7fffffff80000000800000000000000000000000800000000000000000000000"
|
||||
|
||||
discard a.add(Word 1)
|
||||
discard a.add(SecretWord 1)
|
||||
check: bool(a == expected)
|
||||
|
||||
suite "Modular operations - small modulus":
|
||||
|
@ -370,7 +370,7 @@ proc mainModularInverse() =
|
|||
let M = BigInt[16].fromUint(2017'u16)
|
||||
|
||||
var mp1div2 = M
|
||||
discard mp1div2.add(Word 1)
|
||||
discard mp1div2.add(SecretWord 1)
|
||||
mp1div2.shiftRight(1)
|
||||
|
||||
let expected = BigInt[16].fromUint(1969'u16)
|
||||
|
@ -385,7 +385,7 @@ proc mainModularInverse() =
|
|||
let M = BigInt[381].fromUint(2017'u16)
|
||||
|
||||
var mp1div2 = M
|
||||
discard mp1div2.add(Word 1)
|
||||
discard mp1div2.add(SecretWord 1)
|
||||
mp1div2.shiftRight(1)
|
||||
|
||||
let expected = BigInt[381].fromUint(1969'u16)
|
||||
|
@ -401,7 +401,7 @@ proc mainModularInverse() =
|
|||
let M = BigInt[16].fromUint(383'u16)
|
||||
|
||||
var mp1div2 = M
|
||||
discard mp1div2.add(Word 1)
|
||||
discard mp1div2.add(SecretWord 1)
|
||||
mp1div2.shiftRight(1)
|
||||
|
||||
let expected = BigInt[16].fromUint(106'u16)
|
||||
|
@ -416,7 +416,7 @@ proc mainModularInverse() =
|
|||
let M = BigInt[381].fromUint(383'u16)
|
||||
|
||||
var mp1div2 = M
|
||||
discard mp1div2.add(Word 1)
|
||||
discard mp1div2.add(SecretWord 1)
|
||||
mp1div2.shiftRight(1)
|
||||
|
||||
let expected = BigInt[381].fromUint(106'u16)
|
||||
|
@ -431,7 +431,7 @@ proc mainModularInverse() =
|
|||
let M = BigInt[381].fromHex("0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab")
|
||||
|
||||
var mp1div2 = M
|
||||
discard mp1div2.add(Word 1)
|
||||
discard mp1div2.add(SecretWord 1)
|
||||
mp1div2.shiftRight(1)
|
||||
|
||||
let expected = BigInt[381].fromHex("0x0636759a0f3034fa47174b2c0334902f11e9915b7bd89c6a2b3082b109abbc9837da17201f6d8286fe6203caa1b9d4c8")
|
||||
|
@ -448,7 +448,7 @@ proc mainModularInverse() =
|
|||
|
||||
var mp1div2 = M
|
||||
mp1div2.shiftRight(1)
|
||||
discard mp1div2.add(Word 1)
|
||||
discard mp1div2.add(SecretWord 1)
|
||||
|
||||
let expected = BigInt[16].fromUint(0'u16)
|
||||
var r {.noInit.}: BigInt[16]
|
||||
|
@ -463,7 +463,7 @@ proc mainModularInverse() =
|
|||
|
||||
var mp1div2 = M
|
||||
mp1div2.shiftRight(1)
|
||||
discard mp1div2.add(Word 1)
|
||||
discard mp1div2.add(SecretWord 1)
|
||||
|
||||
let expected = BigInt[381].fromUint(0'u16)
|
||||
var r {.noInit.}: BigInt[381]
|
||||
|
|
Loading…
Reference in New Issue