diff --git a/README.md b/README.md index cd8104d..7ad3e96 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# Constantine - Constant time finite field primitives for Elliptic Curve Cryptography +# Constantine - Constant Time Elliptic Curve Cryptography [![License: Apache](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) ![Stability: experimental](https://img.shields.io/badge/stability-experimental-orange.svg) -This library provides constant time finite field primitives for implementation of elliptic curve cryptography. +This library provides constant-time implementation of elliptic curve cryptography. -Warning ⚠️: The library is in development state and cannot be used at the moment - except as a showcase or to start a discussion on modular big integers internals. +> Warning ⚠️: The library is in development state and cannot be used at the moment +> except as a showcase or to start a discussion on modular big integers internals. ## Installation @@ -16,6 +16,40 @@ You can install the developement version of the library through nimble with the nimble install https://github.com/mratsim/constantine@#master ``` +## Target audience + +The library aims to be a portable, compact and hardened library for elliptic curve cryptography needs, in particular for blockchain protocols and zero-knowledge proofs system. + +The library focuses on following properties: +- constant-time (not leaking secret data via side-channels) +- generated code size, datatype size and stack usage +- performance +in this order + +## Security + +Hardening an implementation against all existing and upcoming attack vectors is an extremely complex task. +The library is provided as is, without any guarantees at least until: +- it gets audited +- formal proofs of correctness are produced +- formal verification of constant-time implementation is possible + +Defense against common attack vectors are provided on a best effort basis +attackers may go to great lengths to retrieve secret data including: +- Timing the time taken to multiply on an elliptic curve +- Analysing the power usage of embedded devices +- Detecting cache misses when using lookup tables +- Memory attacks like page-faults, allocators, memory retention attacks + +This is would be incomplete without mentioning that the hardware, OS and compiler +actively hinder you by: +- Hardware: sometimes not implementing multiplication in constant-time. +- OS: not providing a way to prevent memory paging to disk, core dumps, a debugger attaching to your process or a context switch (coroutines) leaking register data. +- Compiler: optimizing away your carefully crafted branchless code and leaking server secrets or optimizing away your secure erasure routine which is "useless" because at the end of the function the data is not used anymore. + +A growing number of attack vectors is being collected for your viewing pleasure +at https://github.com/mratsim/constantine/wiki/Constant-time-arithmetics + ## License Licensed and distributed under either of diff --git a/constantine/bigints_public.nim b/constantine/bigints_public.nim deleted file mode 100644 index 3884945..0000000 --- a/constantine/bigints_public.nim +++ /dev/null @@ -1,54 +0,0 @@ -# Constantine -# Copyright (c) 2018-2019 Status Research & Development GmbH -# Copyright (c) 2020-Present Mamy André-Ratsimbazafy -# Licensed and distributed under either of -# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). -# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). -# at your option. This file may not be copied, modified, or distributed except according to those terms. - -import - ./bigints_raw, - ./primitives - -# ############################################################ -# -# BigInts Public API -# -# ############################################################ - -# The "public" API, exported for finite field computations -# enforced compile-time checking of BigInt bitsize -# -# The "raw" compute API, uses views to avoid code duplication due to generic/static monomorphization. - -# No exceptions allowed -{.push raises: [].} -{.push inline.} - -func isZero*(a: BigInt): CTBool[Word] = - ## Returns true if a big int is equal to zero - a.view.isZero - -func add*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] = - ## Constant-time big integer in-place optional addition - ## The addition is only performed if ctl is "true" - ## The result carry is always computed. - add(a.view, b.view, ctl) - -func sub*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] = - ## Constant-time big integer in-place optional addition - ## The addition is only performed if ctl is "true" - ## The result carry is always computed. - sub(a.view, b.view, ctl) - -func reduce*[aBits, mBits](r: var BigInt[mBits], a: BigInt[aBits], M: BigInt[mBits]) = - ## Reduce `a` modulo `M` and store the result in `r` - ## - ## The modulus `M` **must** use `mBits` bits (bits at position mBits-1 must be set) - ## - ## CT: Depends only on the length of the modulus `M` - - # Note: for all cryptographic intents and purposes the modulus is known at compile-time - # but we don't want to inline it as it would increase codesize, better have Nim - # pass a pointer+length to a fixed session of the BSS. - reduce(r.view, a.view, M.view) diff --git a/constantine/config/common.nim b/constantine/config/common.nim new file mode 100644 index 0000000..5d0945f --- /dev/null +++ b/constantine/config/common.nim @@ -0,0 +1,48 @@ +# Constantine +# Copyright (c) 2018-2019 Status Research & Development GmbH +# Copyright (c) 2020-Present Mamy André-Ratsimbazafy +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +# ############################################################ +# +# Common configuration +# +# ############################################################ + +import ../primitives/constant_time + +type Word* = Ct[uint32] + ## Logical BigInt word + ## A logical BigInt word is of size physical MachineWord-1 +type DoubleWord* = Ct[uint64] + +type BaseType* = uint32 + ## Physical BigInt for conversion in "normal integers" + +const + WordPhysBitSize* = sizeof(Word) * 8 + WordBitSize* = WordPhysBitSize - 1 + + CtTrue* = ctrue(Word) + CtFalse* = cfalse(Word) + + Zero* = Word(0) + One* = Word(1) + MaxWord* = (not Zero) shr 1 + ## This represents 0x7F_FF_FF_FF__FF_FF_FF_FF + ## also 0b0111...1111 + ## This biggest representable number in our limbs. + ## i.e. The most significant bit is never set at the end of each function + +# ############################################################ +# +# Instrumentation +# +# ############################################################ + +template debug*(body: untyped): untyped = + when defined(debugConstantine): + body diff --git a/constantine/curves_config.nim b/constantine/config/curves.nim similarity index 100% rename from constantine/curves_config.nim rename to constantine/config/curves.nim diff --git a/constantine/curves_config_parser.nim b/constantine/config/curves_parser.nim similarity index 100% rename from constantine/curves_config_parser.nim rename to constantine/config/curves_parser.nim diff --git a/constantine/elliptic/README.md b/constantine/elliptic/README.md new file mode 100644 index 0000000..93913b4 --- /dev/null +++ b/constantine/elliptic/README.md @@ -0,0 +1,7 @@ +# Elliptic Curves + +This folder will hold the implementation of elliptic curves. + +## References + +- Pairing-Friendly Curves https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-00#section-2.1 diff --git a/constantine/io/README.md b/constantine/io/README.md new file mode 100644 index 0000000..9c30eac --- /dev/null +++ b/constantine/io/README.md @@ -0,0 +1 @@ +# I/O and serialization diff --git a/constantine/io.nim b/constantine/io/io.nim similarity index 98% rename from constantine/io.nim rename to constantine/io/io.nim index c3bb291..9719275 100644 --- a/constantine/io.nim +++ b/constantine/io/io.nim @@ -12,7 +12,9 @@ import endians, - ./primitives, ./bigints_raw + ../primitives/constant_time, + ../math/bigints_checked, + ../config/common # ############################################################ # @@ -133,7 +135,7 @@ func dumpRawUintLE( var tail = dst.len while tail > 0: - let w = if src_idx < src.limbs.len: src.limbs[src_idx].BaseType + let w = if src_idx < src.limbs.len: BaseType(src.limbs[src_idx]) else: 0 inc src_idx diff --git a/constantine/math/README.md b/constantine/math/README.md new file mode 100644 index 0000000..b57874f --- /dev/null +++ b/constantine/math/README.md @@ -0,0 +1,5 @@ +# BigInt and Finite Field Arithmetic + +This folder contains the implementation of +- big integer +- finite field arithmetic (i.e. modular arithmetic) diff --git a/constantine/math/bigints_checked.nim b/constantine/math/bigints_checked.nim new file mode 100644 index 0000000..a783673 --- /dev/null +++ b/constantine/math/bigints_checked.nim @@ -0,0 +1,112 @@ +# Constantine +# Copyright (c) 2018-2019 Status Research & Development GmbH +# Copyright (c) 2020-Present Mamy André-Ratsimbazafy +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +import + ./bigints_raw, + ../primitives/constant_time, + ../config/common + +# ############################################################ +# +# BigInts type-checked API +# +# ############################################################ + +# The "checked" API is exported as a building blocks +# with enforced compile-time checking of BigInt bitsize +# and memory ownership. +# +# The "raw" compute API uses views to avoid code duplication +# due to generic/static monomorphization. +# +# The "checked" API is a thin wrapper above the "raw" API to get the best of both world: +# - small code footprint +# - compiler enforced checks: types, bitsizes (dependant types) +# - compiler enforced memory: stack allocation and buffer ownership + +func wordsRequired(bits: int): int {.compileTime.} = + ## Compute the number of limbs required + # from the **announced** bit length + (bits + WordBitSize - 1) div WordBitSize + +type + BigInt*[bits: static int] = object + ## Fixed-precision big integer + ## + ## - "bits" is the announced bit-length of the BigInt + ## This is public data, usually equal to the curve prime bitlength. + ## + ## - "bitLength" is the internal bitlength of the integer + ## This differs from the canonical bit-length as + ## Constantine word-size is smaller than a machine word. + ## This value should never be used as-is to prevent leaking secret data. + ## Computing this value requires constant-time operations. + ## Using this value requires converting it to the # of limbs in constant-time + ## + ## - "limbs" is an internal field that holds the internal representation + ## of the big integer. Least-significant limb first. Within limbs words are native-endian. + ## + ## This internal representation can be changed + ## without notice and should not be used by external applications or libraries. + bitLength: uint32 + limbs*: array[bits.wordsRequired, Word] + +template view*(a: BigInt): BigIntViewConst = + ## Returns a borrowed type-erased immutable view to a bigint + BigIntViewConst(cast[BigIntView](a.unsafeAddr)) + +template view*(a: var BigInt): BigIntViewMut = + ## Returns a borrowed type-erased mutable view to a mutable bigint + BigIntViewMut(cast[BigIntView](a.addr)) + +debug: + func `==`*(a, b: BigInt): CTBool[Word] = + ## Returns true if 2 big ints are equal + var accum: Word + for i in static(0 ..< a.limbs.len): + accum = accum or (a.limbs[i] xor b.limbs[i]) + result = accum.isZero + +# No exceptions allowed +{.push raises: [].} +{.push inline.} + +func setInternalBitLength*(a: var BigInt) {.inline.} = + ## Derive the actual bitsize used internally of a BigInt + ## from the announced BigInt bitsize + ## and set the bitLength field of that BigInt + ## to that computed value. + a.bitLength = static(a.bits + a.bits div WordBitSize) + +func isZero*(a: BigInt): CTBool[Word] = + ## Returns true if a big int is equal to zero + a.view.isZero + +func add*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] = + ## Constant-time big integer in-place optional addition + ## The addition is only performed if ctl is "true" + ## The result carry is always computed. + add(a.view, b.view, ctl) + +func sub*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] = + ## Constant-time big integer in-place optional addition + ## The addition is only performed if ctl is "true" + ## The result carry is always computed. + sub(a.view, b.view, ctl) + +func reduce*[aBits, mBits](r: var BigInt[mBits], a: BigInt[aBits], M: BigInt[mBits]) = + ## Reduce `a` modulo `M` and store the result in `r` + ## + ## The modulus `M` **must** use `mBits` bits (bits at position mBits-1 must be set) + ## + ## CT: Depends only on the length of the modulus `M` + + # Note: for all cryptographic intents and purposes the modulus is known at compile-time + # but we don't want to inline it as it would increase codesize, better have Nim + # pass a pointer+length to a fixed session of the BSS. + reduce(r.view, a.view, M.view) diff --git a/constantine/bigints_raw.nim b/constantine/math/bigints_raw.nim similarity index 81% rename from constantine/bigints_raw.nim rename to constantine/math/bigints_raw.nim index 901c6dc..abf8e7d 100644 --- a/constantine/bigints_raw.nim +++ b/constantine/math/bigints_raw.nim @@ -50,58 +50,30 @@ # actual computation is deferred to type-erased routines. import - ./primitives, ./common, - ./primitives_extprecision + ../primitives/constant_time, + ../primitives/extended_precision, + ../config/common from sugar import distinctBase -type Word* = Ct[uint32] - ## Logical BigInt word - ## A logical BigInt word is of size physical MachineWord-1 -type DoubleWord = Ct[uint64] +# ############################################################ +# +# BigInts type-erased API +# +# ############################################################ -type BaseType* = uint32 - ## Physical BigInt for conversion in "normal integers" - -const - WordPhysBitSize = sizeof(Word) * 8 - WordBitSize* = WordPhysBitSize - 1 - -const - Zero* = Word(0) - One* = Word(1) - MaxWord* = (not Zero) shr 1 - ## This represents 0x7F_FF_FF_FF__FF_FF_FF_FF - ## also 0b0111...1111 - ## This biggest representable number in our limbs. - ## i.e. The most significant bit is never set at the end of each function - -func wordsRequired(bits: int): int {.compileTime.} = - ## Compute the number of limbs required - # from the **announced** bit length - (bits + WordBitSize - 1) div WordBitSize +# The "checked" API is exported as a building blocks +# with enforced compile-time checking of BigInt bitsize +# and memory ownership. +# +# The "raw" compute API uses views to avoid code duplication +# due to generic/static monomorphization. +# +# The "checked" API is a thin wrapper above the "raw" API to get the best of both world: +# - small code footprint +# - compiler enforced checks: types, bitsizes +# - compiler enforced memory: stack allocation and buffer ownership type - BigInt*[bits: static int] = object - ## Fixed-precision big integer - ## - ## - "bits" is the announced bit-length of the BigInt - ## This is public data, usually equal to the curve prime bitlength. - ## - ## - "bitLength" is the internal bitlength of the integer - ## This differs from the canonical bit-length as - ## Constantine word-size is smaller than a machine word. - ## This value should never be used as-is to prevent leaking secret data. - ## Computing this value requires constant-time operations. - ## Using this value requires converting it to the # of limbs in constant-time - ## - ## - "limbs" is an internal field that holds the internal representation - ## of the big integer. Least-significant limb first. Within limbs words are native-endian. - ## - ## This internal representation can be changed - ## without notice and should not be used by external applications or libraries. - bitLength: uint32 - limbs*: array[bits.wordsRequired, Word] - BigIntView* = ptr object ## Type-erased fixed-precision big integer ## @@ -145,18 +117,10 @@ type # ############################################################ # -# Mutability safety +# Deep Mutability safety # # ############################################################ -template view*(a: BigInt): BigIntViewConst = - ## Returns a borrowed type-erased immutable view to a bigint - BigIntViewConst(cast[BigIntView](a.unsafeAddr)) - -template view*(a: var BigInt): BigIntViewMut = - ## Returns a borrowed type-erased mutable view to a mutable bigint - BigIntViewMut(cast[BigIntView](a.addr)) - template `[]`*(v: BigIntViewConst, limbIdx: int): Word = distinctBase(type v)(v).limbs[limbIdx] @@ -181,13 +145,13 @@ template setBitLength(v: BigIntViewMut, internalBitLength: uint32) = # TODO: Check if repeated v.numLimbs calls are optimized away template `[]`*(v: BigIntViewConst, limbIdxFromEnd: BackwardsIndex): Word = - distinctBase(type v)(v).limbs[v.numLimbs.int - int limbIdxFromEnd] + distinctBase(type v)(v).limbs[numLimbs(v).int - int limbIdxFromEnd] template `[]`*(v: BigIntViewMut, limbIdxFromEnd: BackwardsIndex): var Word = - distinctBase(type v)(v).limbs[v.numLimbs.int - int limbIdxFromEnd] + distinctBase(type v)(v).limbs[numLimbs(v).int - int limbIdxFromEnd] template `[]=`*(v: BigIntViewMut, limbIdxFromEnd: BackwardsIndex, val: Word) = - distinctBase(type v)(v).limbs[v.numLimbs.int - int limbIdxFromEnd] = val + distinctBase(type v)(v).limbs[numLimbs(v).int - int limbIdxFromEnd] = val # ############################################################ # @@ -214,13 +178,6 @@ template checkValidModulus(m: BigIntViewConst) = assert not m[^1].isZero.bool, "Internal Error: the modulus must use all declared bits" debug: - func `==`*(a, b: BigInt): CTBool[Word] = - ## Returns true if 2 big ints are equal - var accum: Word - for i in static(0 ..< a.limbs.len): - accum = accum or (a.limbs[i] xor b.limbs[i]) - result = accum.isZero - func `$`*(a: BigIntViewAny): string = let len = a.numLimbs() result = "[" @@ -238,13 +195,6 @@ debug: # # ############################################################ -func setInternalBitLength*(a: var BigInt) {.inline.} = - ## Derive the actual bitsize used internally of a BigInt - ## from the announced BigInt bitsize - ## and set the bitLength field of that BigInt - ## to that computed value. - a.bitLength = static(a.bits + a.bits div WordBitSize) - func isZero*(a: BigIntViewAny): CTBool[Word] = ## Returns true if a big int is equal to zero var accum: Word @@ -353,7 +303,7 @@ func shlAddMod(a: BigIntViewMut, c: Word, M: BigIntViewConst) = # Now substract a*2^63 - q*p var carry = Zero - var over_p = ctrue(Word) # Track if quotient greater than the modulus + var over_p = CtTrue # Track if quotient greater than the modulus for i in 0 ..< M.numLimbs(): var qp_lo: Word diff --git a/constantine/field_fp.nim b/constantine/math/finite_field.nim similarity index 88% rename from constantine/field_fp.nim rename to constantine/math/finite_field.nim index 30a59e5..103ad71 100644 --- a/constantine/field_fp.nim +++ b/constantine/math/finite_field.nim @@ -13,6 +13,7 @@ # ############################################################ # We assume that p is prime known at compile-time +# We assume that p is not even (requirement for Montgomery form) import ./primitives, ./bigints, ./curves_config @@ -22,22 +23,12 @@ type ## All operations on a field are modulo P value: BigInt[CurveBitSize[C]] - Montgomery*[C: static Curve] = object - ## P is the prime modulus of the Curve C - ## All operations in the Montgomery domain are modulo P - ## P **must** be odd - value: BigInt[CurveBitSize[C]] - # ############################################################ # # Aliases # # ############################################################ -const - CtTrue* = ctrue(Word) - CtFalse* = cfalse(Word) - template add(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] = add(a.value, b.value, ctl) diff --git a/constantine/montgomery_magic.nim b/constantine/math/montgomery_checked.nim similarity index 80% rename from constantine/montgomery_magic.nim rename to constantine/math/montgomery_checked.nim index a5f161a..4bcf90a 100644 --- a/constantine/montgomery_magic.nim +++ b/constantine/math/montgomery_checked.nim @@ -13,17 +13,13 @@ # ############################################################ import - ./primitives, ./bigints - -from bitops import fastLog2 - # This will only be used at compile-time - # so no constant-time worries (it is constant-time if using the De Bruijn multiplication) + ./primitives, ./bigints, ./primitives # No exceptions allowed {.push raises: [].} func montyMagic*(M: static BigInt): static Word {.inline.} = - ## Returns the Montgomery domain magic number for the input modulus: + ## Returns the Montgomery domain magic constant for the input modulus: ## -1/M[0] mod LimbSize ## M[0] is the least significant limb of M ## M must be odd and greater than 2. @@ -67,8 +63,27 @@ func montyMagic*(M: static BigInt): static Word {.inline.} = const M0 = M.limbs[0] - k = fastLog2(WordBitSize) + k = log2(WordBitSize) result = M0 # Start from an inverse of M0 modulo 2, M0 is odd and it's own inverse for _ in static(0 ..< k): result *= 2 + M * result # x' = x(2 + ax) (`+` to avoid negating at the end) + +# ############################################################ +# +# Montgomery domain primitives +# +# ############################################################ + +# No exceptions allowed +{.push raises: [].} + +func toMonty*[C: static Curve](a: Fp[C]): Montgomery[C] = + ## Convert a big integer over Fp to it's montgomery representation + ## over Fp. + ## i.e. Does "a * (2^LimbSize)^W (mod p), where W is the number + ## of words needed to represent p in base 2^LimbSize + + result = a + for i in static(countdown(C.Mod.limbs.high, 1)): + shiftAdd(result, 0) diff --git a/constantine/common.nim b/constantine/math/montgomery_raw.nim similarity index 81% rename from constantine/common.nim rename to constantine/math/montgomery_raw.nim index 38be505..1ce2a27 100644 --- a/constantine/common.nim +++ b/constantine/math/montgomery_raw.nim @@ -5,9 +5,3 @@ # * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). # * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). # at your option. This file may not be copied, modified, or distributed except according to those terms. - -# Common configuration - -template debug*(body: untyped): untyped = - when defined(debugConstantine): - body diff --git a/constantine/montgomery.nim b/constantine/montgomery.nim deleted file mode 100644 index a3451c7..0000000 --- a/constantine/montgomery.nim +++ /dev/null @@ -1,29 +0,0 @@ -# Constantine -# Copyright (c) 2018-2019 Status Research & Development GmbH -# Copyright (c) 2020-Present Mamy André-Ratsimbazafy -# Licensed and distributed under either of -# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). -# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). -# at your option. This file may not be copied, modified, or distributed except according to those terms. - -# ############################################################ -# -# Montgomery domain primitives -# -# ############################################################ - -import - ./primitives, ./bigints, ./field_fp, ./curves_config - -# No exceptions allowed -{.push raises: [].} - -func toMonty*[C: static Curve](a: Fp[C]): Montgomery[C] = - ## Convert a big integer over Fp to it's montgomery representation - ## over Fp. - ## i.e. Does "a * (2^LimbSize)^W (mod p), where W is the number - ## of words needed to represent p in base 2^LimbSize - - result = a - for i in static(countdown(C.Mod.limbs.high, 1)): - shiftAdd(result, 0) diff --git a/constantine/primitives/README.md b/constantine/primitives/README.md new file mode 100644 index 0000000..8d6d2b2 --- /dev/null +++ b/constantine/primitives/README.md @@ -0,0 +1,3 @@ +# Constant-time primitives + +This folder holds the constant-time primitives diff --git a/constantine/primitives.nim b/constantine/primitives/constant_time.nim similarity index 100% rename from constantine/primitives.nim rename to constantine/primitives/constant_time.nim diff --git a/constantine/primitives_extprecision.nim b/constantine/primitives/extended_precision.nim similarity index 96% rename from constantine/primitives_extprecision.nim rename to constantine/primitives/extended_precision.nim index 722b243..648999a 100644 --- a/constantine/primitives_extprecision.nim +++ b/constantine/primitives/extended_precision.nim @@ -12,7 +12,7 @@ # # ############################################################ -import ./primitives +import ./constant_time func asm_x86_64_extMul(hi, lo: var uint64, a, b: uint64) {.inline.}= ## Extended precision multiplication uint64 * uint64 --> uint128 @@ -115,6 +115,9 @@ func unsafeDiv2n1n*(q, r: var Ct[uint64], n_hi, n_lo, d: Ct[uint64]) {.inline.}= # with a fast path that may have branches. It might also # be the same at the hardware level. + # TODO !!! - Replace by constant-time, portable, non-assembly version + # -> use uint128? Compiler might add unwanted branches + type T = uint64 when not defined(amd64): @@ -131,6 +134,8 @@ func unsafeDiv2n1n*(q, r: var Ct[uint32], n_hi, n_lo, d: Ct[uint32]) {.inline.}= ## To avoid issues, n_hi, n_lo, d should be normalized. ## i.e. shifted (== multiplied by the same power of 2) ## so that the most significant bit in d is set. + # TODO !!! - Replace by constant-time, portable, non-assembly version + # -> use uint128? Compiler might add unwanted branches let dividend = (uint64(n_hi) shl 32) or uint64(n_lo) let divisor = uint64(d) q = (Ct[uint32])(dividend div divisor) diff --git a/constantine/signatures/README.md b/constantine/signatures/README.md new file mode 100644 index 0000000..e34e465 --- /dev/null +++ b/constantine/signatures/README.md @@ -0,0 +1,16 @@ +# Signature schemes + +This folder will hold the implementations of signature schemes. + +In particular: + - BLS (Boneh-Lynn-Shacham) + - ECDSA (Elliptic Curve Digital Signature Algorithm) + +Note: The BLS signature scheme should not be confused + with the BLS family of elliptic curve (Barreto-Lynn-Scott) + +## References + +### ECDSA + +- diff --git a/tests/test_bigints.nim b/tests/test_bigints.nim index c0ab575..f77b844 100644 --- a/tests/test_bigints.nim +++ b/tests/test_bigints.nim @@ -7,7 +7,10 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import unittest, random, strutils, - ../constantine/[io, bigints_public, bigints_raw, primitives] + ../constantine/io/io, + ../constantine/math/bigints_checked, + ../constantine/config/common, + ../constantine/primitives/constant_time suite "isZero": test "isZero for zero": diff --git a/tests/test_bigints_multimod.nim b/tests/test_bigints_multimod.nim index c3df390..e3d99d1 100644 --- a/tests/test_bigints_multimod.nim +++ b/tests/test_bigints_multimod.nim @@ -10,7 +10,9 @@ import # Standard library unittest, random, strutils, # Third-party - ../constantine/[io, bigints_raw, bigints_public, primitives] + ../constantine/io/io, + ../constantine/math/[bigints_raw, bigints_checked], + ../constantine/primitives/constant_time suite "Bigints - Multiprecision modulo": test "bitsize 237 mod bitsize 192": @@ -62,26 +64,26 @@ suite "Bigints - Multiprecision modulo": check: bool(r == expected) - # test "bitsize 1955 mod bitsize 459": - # let a = BigInt[1955].fromHex("0x4f688e286a7c6e2b64663d8925c2f686994f2b90d58e7a843087c676c2c614ebab3eef9c765a88fe597b23b0e1fb28c812627366020edeafeefd0bf67a95215b4335412e2bd623b4cf7b69e669e1a8e782ab9a3e5fd443f10f459eed4ec9bd61821d94da82e937989245d481612b83b75d6d393e5de2258ac92aec7cd6e4f12c6b035e1fac3ef22851a8e211232b57db7551c03a88e9272411eea86e15c989be9d2962d5ae32ca35b18060212aaf6599b5a5f2416e436f009728b4017f87f70f4e528c9a33042b6810040c1e64457d56695d03b701540a5537c8cf781ff2ea4be2aa6daf1a5f2f0874a1cf495485a01254c2e2f4a") - # let m = BigInt[459].fromHex("0x47304803a4a8c31e18287ad51c1ac7546c42e23206e9dc43e51eff5fa003f44bd08e542ec2659c405bfa4c9eb518ada943412767361029a902b") + test "bitsize 1955 mod bitsize 459": + let a = BigInt[1955].fromHex("0x4f688e286a7c6e2b64663d8925c2f686994f2b90d58e7a843087c676c2c614ebab3eef9c765a88fe597b23b0e1fb28c812627366020edeafeefd0bf67a95215b4335412e2bd623b4cf7b69e669e1a8e782ab9a3e5fd443f10f459eed4ec9bd61821d94da82e937989245d481612b83b75d6d393e5de2258ac92aec7cd6e4f12c6b035e1fac3ef22851a8e211232b57db7551c03a88e9272411eea86e15c989be9d2962d5ae32ca35b18060212aaf6599b5a5f2416e436f009728b4017f87f70f4e528c9a33042b6810040c1e64457d56695d03b701540a5537c8cf781ff2ea4be2aa6daf1a5f2f0874a1cf495485a01254c2e2f4a") + let m = BigInt[459].fromHex("0x47304803a4a8c31e18287ad51c1ac7546c42e23206e9dc43e51eff5fa003f44bd08e542ec2659c405bfa4c9eb518ada943412767361029a902b") - # let expected = BigInt[459].fromHex("0x1f039dfe7c9da071d578b3b852db3916f4d79f6169818085994cbc41610abb7abb96e10d1126313cc281a87c309c2dd43bed745a9603f3c606c") + let expected = BigInt[459].fromHex("0x1f039dfe7c9da071d578b3b852db3916f4d79f6169818085994cbc41610abb7abb96e10d1126313cc281a87c309c2dd43bed745a9603f3c606c") - # var r: BigInt[97] - # r.reduce(a, m) + var r: BigInt[459] + r.reduce(a, m) - # check: - # bool(r == expected) + check: + bool(r == expected) - # test "bitsize 2346 mod bitsize 97": - # let a = BigInt[2346].fromHex("0x1b5efa688e4124a71edd035f106c6ea81bafd78f610cd59d46fc6cda548fd970dde6b91c6fa10ab6d198026dea3c46c41495294082f2acc8210fd7ebfb25fdc6ce8131676ab0d749c5a4a83dd08172b3849df30304685192708ff0b510600cbf87be3179ce704adc43f2c9b22ba28c77f0a364fa1a96344d7f338227a8f346c0e721bc1312f53cebfc20fd0763ec039aa83a77ba489056ebee2a462058f1daffec9b5df29474f638185c6684729482a29764b46a5487e159fc4eedda5018d3d18ae1c0c6503ebbbd859b4dff3e09b6567b752d51c9733fc822b2758b69ffd65974a8fbf4ad25a40761bb9b9b6a1f886928fe08f9c1571fe3e3987b15e37208a22f64e2c3ff75a36815b7906fc2a52f7bd32d15e8b0441e8c39ae9127d80946e146db5cd2738") - # let m = BigInt[97].fromHex("0x1100d0717f9fff44c6cc7442e") + test "bitsize 2346 mod bitsize 97": + let a = BigInt[2346].fromHex("0x1b5efa688e4124a71edd035f106c6ea81bafd78f610cd59d46fc6cda548fd970dde6b91c6fa10ab6d198026dea3c46c41495294082f2acc8210fd7ebfb25fdc6ce8131676ab0d749c5a4a83dd08172b3849df30304685192708ff0b510600cbf87be3179ce704adc43f2c9b22ba28c77f0a364fa1a96344d7f338227a8f346c0e721bc1312f53cebfc20fd0763ec039aa83a77ba489056ebee2a462058f1daffec9b5df29474f638185c6684729482a29764b46a5487e159fc4eedda5018d3d18ae1c0c6503ebbbd859b4dff3e09b6567b752d51c9733fc822b2758b69ffd65974a8fbf4ad25a40761bb9b9b6a1f886928fe08f9c1571fe3e3987b15e37208a22f64e2c3ff75a36815b7906fc2a52f7bd32d15e8b0441e8c39ae9127d80946e146db5cd2738") + let m = BigInt[97].fromHex("0x1100d0717f9fff44c6cc7442e") - # let expected = BigInt[97].fromHex("0x0104ea05300eeb05cd374197b6") + let expected = BigInt[97].fromHex("0x0104ea05300eeb05cd374197b6") - # var r: BigInt[97] - # r.reduce(a, m) + var r: BigInt[97] + r.reduce(a, m) - # check: - # bool(r == expected) + check: + bool(r == expected) diff --git a/tests/test_bigints_vs_gmp.nim b/tests/test_bigints_vs_gmp.nim index 576c6f9..ff4d03c 100644 --- a/tests/test_bigints_vs_gmp.nim +++ b/tests/test_bigints_vs_gmp.nim @@ -12,7 +12,9 @@ import # Third-party gmp, stew/byteutils, # Internal - ../constantine/[io, bigints_raw, bigints_public, primitives] + ../constantine/io/io, + ../constantine/math/[bigints_raw, bigints_checked], + ../constantine/primitives/constant_time # We test up to 1024-bit, more is really slow diff --git a/tests/test_io.nim b/tests/test_io.nim index 14bdbb4..0933fef 100644 --- a/tests/test_io.nim +++ b/tests/test_io.nim @@ -7,7 +7,9 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import unittest, random, - ../constantine/[io, bigints_raw] + ../constantine/io/io, + ../constantine/config/common, + ../constantine/math/bigints_checked randomize(0xDEADBEEF) # Random seed for reproducibility type T = BaseType diff --git a/tests/test_primitives.nim b/tests/test_primitives.nim index 8606b03..f82425e 100644 --- a/tests/test_primitives.nim +++ b/tests/test_primitives.nim @@ -7,7 +7,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import unittest, random, math, - ../constantine/primitives + ../constantine/primitives/constant_time # Random seed for reproducibility randomize(0xDEADBEEF)