From bd2b10817e6b252d343f0812fecd758106a7b32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mamy=20Andr=C3=A9-Ratsimbazafy?= Date: Sat, 8 Feb 2020 14:55:49 +0100 Subject: [PATCH] Add curve configuration + BN254 config (zkSnarks, ZCash, Ethereum 1 precompile) --- constantine/curves_config.nim | 37 +++++ constantine/private/curves_config_parser.nim | 150 +++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 constantine/curves_config.nim create mode 100644 constantine/private/curves_config_parser.nim diff --git a/constantine/curves_config.nim b/constantine/curves_config.nim new file mode 100644 index 0000000..a2db25a --- /dev/null +++ b/constantine/curves_config.nim @@ -0,0 +1,37 @@ +# 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 + # Internal + ./private/curves_config_parser + +# ############################################################ +# +# Configuration of finite fields +# +# ############################################################ + +# Finite fields are preconfigured in this file +# To workaround the following limitation https://github.com/nim-lang/Nim/issues/11142 +# i.e. an object can be parametrized by a compiletime bigint +# we instead have the fields, curve points and Montgomery objects +# be parametrized over an enum. + +# Note, in the past the convention was to name a curve by its conjectured security level. +# as this might change with advances in research, the new convention is +# to name curves according to the length of the prime bit length. +# i.e. the BN254 was previously named BN128. + +declareCurves: + # Barreto-Naehrig curve, Prime 254 bit, 128-bit security, https://eprint.iacr.org/2013/879.pdf + # Usage: Zero-Knowledge Proofs / zkSNARKs in ZCash and Ethereum 1 + # https://eips.ethereum.org/EIPS/eip-196 + curve BN254: + bitsize: 254 + modulus: "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47" + # Equation: Y^2 = X^3 + 3 diff --git a/constantine/private/curves_config_parser.nim b/constantine/private/curves_config_parser.nim new file mode 100644 index 0000000..83b1a95 --- /dev/null +++ b/constantine/private/curves_config_parser.nim @@ -0,0 +1,150 @@ +# 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 + # Standard library + macros, + # Internal + ../io, ../bigints + +# Macro to parse declarative curves configuration. + +macro declareCurves*(curves: untyped): untyped = + ## Parse curve configuration and generates + ## + ## type Curve = enum + ## BN254 + ## ... + ## + ## const CurveBitSize* = array[ + ## BN254: 254, + ## ... + ## ] + ## + ## TODO: Ensure that the modulus is not inlined at runtime + ## to avoid codesize explosion. + ## const BN254_Modulus = fromHex(BigInt[254], "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47") + ## + ## func fieldModulus*(curve: static Curve): auto = + ## when curve == BN254_Modulus: BN254_Modulus + ## ... + curves.expectKind(nnkStmtList) + + # curve BN254: + # bitsize: 254 + # modulus: "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47" + # + # is parsed into + # + # StmtList + # Command + # Ident "curve" + # Ident "BN254" + # StmtList + # Call + # Ident "bitsize" + # StmtList + # IntLit 254 + # Call + # Ident "modulus" + # StmtList + # StrLit "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47" + + var Curves: seq[NimNode] + var CurveBitSize = nnKBracket.newTree() + var curveModStmts = newStmtList() + var curveModWhenStmt = nnkWhenStmt.newTree() + + for curveDesc in curves: + curveDesc.expectKind(nnkCommand) + doAssert curveDesc[0].eqIdent"curve" + curveDesc[1].expectKind(nnkIdent) # Curve name + curveDesc[2].expectKind(nnkStmtList) + curveDesc[2][0].expectKind(nnkCall) + curveDesc[2][1].expectKind(nnkCall) + + let curve = curveDesc[1] + + let sizeSection = curveDesc[2][0] + doAssert sizeSection[0].eqIdent"bitsize" + sizeSection[1].expectKind(nnkStmtList) + let bitSize = sizeSection[1][0] + + let modSection = curveDesc[2][1] + doAssert modSection[0].eqIdent"modulus" + modSection[1].expectKind(nnkStmtList) + let modulus = modSection[1][0] + + Curves.add curve + # "BN254: 254" for array construction + CurveBitSize.add nnkExprColonExpr.newTree( + curve, bitSize + ) + + # const BN254_Modulus = fromHex(BigInt[254], "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47") + let modulusID = ident($curve & "_Modulus") + curveModStmts.add newConstStmt( + modulusID, + newCall( + bindSym"fromHex", + nnkBracketExpr.newTree( + bindSym"BigInt", + bitSize + ), + modulus + ) + ) + + # when curve == BN254: BN254_Modulus + curveModWhenStmt.add nnkElifBranch.newTree( + nnkInfix.newTree( + ident"==", + ident"curve", + curve + ), + modulusID + ) + + result = newStmtList() + + result.add newEnum( + name = ident"Curve", + fields = Curves, + public = true, + pure = false + ) + + result.add quote do: + const CurveBitSize: array[Curve, int] = `CurveBitSize` + + result.add curveModStmts + + # Add 'else: {.error: "Unreachable".}' to the when statements + curveModWhenStmt.add nnkElse.newTree( + nnkPragma.newTree( + nnkExprColonExpr.newTree( + ident"error", + newLit"Unreachable: the curve does not exist." + ) + ) + ) + result.add newProc( + name = nnkPostfix.newTree(ident"*", ident"fieldModulus"), + params = [ + ident"auto", + newIdentDefs( + name = ident"curve", + kind = nnkStaticTy.newTree(ident"Curve") + ) + ], + body = curveModWhenStmt, + procType = nnkFuncDef, + pragmas = nnkPragma.newTree(ident"compileTime") + ) + + # echo result.toStrLit