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