diff --git a/constantine/arithmetic/finite_fields_inversion.nim b/constantine/arithmetic/finite_fields_inversion.nim index 51c8725..246454a 100644 --- a/constantine/arithmetic/finite_fields_inversion.nim +++ b/constantine/arithmetic/finite_fields_inversion.nim @@ -7,454 +7,15 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - ../config/[common, curves], + ../config/[common, curves, type_fp], ./bigints, - ./finite_fields + ../curves/addchain_inversions + +export addchain_inversions # ############################################################ # -# Specialized inversions -# -# ############################################################ - -# Field-specific inversion routines -func square_repeated(r: var Fp, num: int) = - ## Repeated squarings - for _ in 0 ..< num: - r.square() - -# Secp256k1 -# ------------------------------------------------------------ -func inv_addchain(r: var Fp[Secp256k1], a: Fp[Secp256k1]) {.used.}= - ## We invert via Little Fermat's theorem - ## a^(-1) ≡ a^(p-2) (mod p) - ## with p = "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F" - ## We take advantage of the prime special form to hardcode - ## the sequence of squarings and multiplications for the modular exponentiation - ## - ## See libsecp256k1 - ## - ## The binary representation of (p - 2) has 5 blocks of 1s, with lengths in - ## { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: - ## [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] - - var - x2{.noInit.}: Fp[Secp256k1] - x3{.noInit.}: Fp[Secp256k1] - x6{.noInit.}: Fp[Secp256k1] - x9{.noInit.}: Fp[Secp256k1] - x11{.noInit.}: Fp[Secp256k1] - x22{.noInit.}: Fp[Secp256k1] - x44{.noInit.}: Fp[Secp256k1] - x88{.noInit.}: Fp[Secp256k1] - x176{.noInit.}: Fp[Secp256k1] - x220{.noInit.}: Fp[Secp256k1] - x223{.noInit.}: Fp[Secp256k1] - - x2.square(a) - x2 *= a - - x3.square(x2) - x3 *= a - - x6 = x3 - x6.square_repeated(3) - x6 *= x3 - - x9 = x6 - x9.square_repeated(3) - x9 *= x3 - - x11 = x9 - x11.square_repeated(2) - x11 *= x2 - - x22 = x11 - x22.square_repeated(11) - x22 *= x11 - - x44 = x22 - x44.square_repeated(22) - x44 *= x22 - - x88 = x44 - x88.square_repeated(44) - x88 *= x44 - - x176 = x88 - x88.square_repeated(88) - x176 *= x88 - - x220 = x176 - x220.square_repeated(44) - x220 *= x44 - - x223 = x220 - x223.square_repeated(3) - x223 *= x3 - - # The final result is then assembled using a sliding window over the blocks - r = x223 - r.square_repeated(23) - r *= x22 - r.square_repeated(5) - r *= a - r.square_repeated(3) - r *= x2 - r.square_repeated(2) - r *= a - -# BLS12-381 -# ------------------------------------------------------------ -func inv_addchain*(r: var Fp[BLS12_381], a: Fp[BLS12_381]) = - var - x10 {.noinit.}: Fp[BLS12_381] - x100 {.noinit.}: Fp[BLS12_381] - x1000 {.noinit.}: Fp[BLS12_381] - x1001 {.noinit.}: Fp[BLS12_381] - x1011 {.noinit.}: Fp[BLS12_381] - x1101 {.noinit.}: Fp[BLS12_381] - x10001 {.noinit.}: Fp[BLS12_381] - x10100 {.noinit.}: Fp[BLS12_381] - x11001 {.noinit.}: Fp[BLS12_381] - x11010 {.noinit.}: Fp[BLS12_381] - x110100 {.noinit.}: Fp[BLS12_381] - x110110 {.noinit.}: Fp[BLS12_381] - x110111 {.noinit.}: Fp[BLS12_381] - x1001101 {.noinit.}: Fp[BLS12_381] - x1001111 {.noinit.}: Fp[BLS12_381] - x1010101 {.noinit.}: Fp[BLS12_381] - x1011101 {.noinit.}: Fp[BLS12_381] - x1100111 {.noinit.}: Fp[BLS12_381] - x1101001 {.noinit.}: Fp[BLS12_381] - x1110111 {.noinit.}: Fp[BLS12_381] - x1111011 {.noinit.}: Fp[BLS12_381] - x10001001 {.noinit.}: Fp[BLS12_381] - x10010101 {.noinit.}: Fp[BLS12_381] - x10010111 {.noinit.}: Fp[BLS12_381] - x10101001 {.noinit.}: Fp[BLS12_381] - x10110001 {.noinit.}: Fp[BLS12_381] - x10111111 {.noinit.}: Fp[BLS12_381] - x11000011 {.noinit.}: Fp[BLS12_381] - x11010000 {.noinit.}: Fp[BLS12_381] - x11010111 {.noinit.}: Fp[BLS12_381] - x11100001 {.noinit.}: Fp[BLS12_381] - x11100101 {.noinit.}: Fp[BLS12_381] - x11101011 {.noinit.}: Fp[BLS12_381] - x11110101 {.noinit.}: Fp[BLS12_381] - x11111111 {.noinit.}: Fp[BLS12_381] - - x10 .square(a) - x100 .square(x10) - x1000 .square(x100) - x1001 .prod(a, x1000) - x1011 .prod(x10, x1001) - x1101 .prod(x10, x1011) - x10001 .prod(x100, x1101) - x10100 .prod(x1001, x1011) - x11001 .prod(x1000, x10001) - x11010 .prod(a, x11001) - x110100 .square(x11010) - x110110 .prod(x10, x110100) - x110111 .prod(a, x110110) - x1001101 .prod(x11001, x110100) - x1001111 .prod(x10, x1001101) - x1010101 .prod(x1000, x1001101) - x1011101 .prod(x1000, x1010101) - x1100111 .prod(x11010, x1001101) - x1101001 .prod(x10, x1100111) - x1110111 .prod(x11010, x1011101) - x1111011 .prod(x100, x1110111) - x10001001 .prod(x110100, x1010101) - x10010101 .prod(x11010, x1111011) - x10010111 .prod(x10, x10010101) - x10101001 .prod(x10100, x10010101) - x10110001 .prod(x1000, x10101001) - x10111111 .prod(x110110, x10001001) - x11000011 .prod(x100, x10111111) - x11010000 .prod(x1101, x11000011) - x11010111 .prod(x10100, x11000011) - x11100001 .prod(x10001, x11010000) - x11100101 .prod(x100, x11100001) - x11101011 .prod(x10100, x11010111) - x11110101 .prod(x10100, x11100001) - x11111111 .prod(x10100, x11101011) # 35 operations - - # TODO: we can accumulate in a partially reduced - # doubled-size `r` to avoid the final substractions. - # and only reduce at the end. - # This requires the number of op to be less than log2(p) == 381 - - # 35 + 22 = 57 operations - r.prod(x10111111, x11100001) - r.square_repeated(8) - r *= x10001 - r.square_repeated(11) - r *= x11110101 - - # 57 + 28 = 85 operations - r.square_repeated(11) - r *= x11100101 - r.square_repeated(8) - r *= x11111111 - r.square_repeated(7) - - # 88 + 22 = 107 operations - r *= x1001101 - r.square_repeated(9) - r *= x1101001 - r.square_repeated(10) - r *= x10110001 - - # 107+24 = 131 operations - r.square_repeated(7) - r *= x1011101 - r.square_repeated(9) - r *= x1111011 - r.square_repeated(6) - - # 131+23 = 154 operations - r *= x11001 - r.square_repeated(11) - r *= x1101001 - r.square_repeated(9) - r *= x11101011 - - # 154+28 = 182 operations - r.square_repeated(10) - r *= x11010111 - r.square_repeated(6) - r *= x11001 - r.square_repeated(10) - - # 182+23 = 205 operations - r *= x1110111 - r.square_repeated(9) - r *= x10010111 - r.square_repeated(11) - r *= x1001111 - - # 205+30 = 235 operations - r.square_repeated(10) - r *= x11100001 - r.square_repeated(9) - r *= x10001001 - r.square_repeated(9) - - # 235+21 = 256 operations - r *= x10111111 - r.square_repeated(8) - r *= x1100111 - r.square_repeated(10) - r *= x11000011 - - # 256+28 = 284 operations - r.square_repeated(9) - r *= x10010101 - r.square_repeated(12) - r *= x1111011 - r.square_repeated(5) - - # 284 + 21 = 305 operations - r *= x1011 - r.square_repeated(11) - r *= x1111011 - r.square_repeated(7) - r *= x1001 - - # 305+32 = 337 operations - r.square_repeated(13) - r *= x11110101 - r.square_repeated(9) - r *= x10111111 - r.square_repeated(8) - - # 337+22 = 359 operations - r *= x11111111 - r.square_repeated(8) - r *= x11101011 - r.square_repeated(11) - r *= x10101001 - - # 359+24 = 383 operations - r.square_repeated(8) - r *= x11111111 - r.square_repeated(8) - r *= x11111111 - r.square_repeated(6) - - # 383+22 = 405 operations - r *= x110111 - r.square_repeated(10) - r *= x11111111 - r.square_repeated(9) - r *= x11111111 - - # 405+26 = 431 operations - r.square_repeated(8) - r *= x11111111 - r.square_repeated(8) - r *= x11111111 - r.square_repeated(8) - - # 431+19 = 450 operations - r *= x11111111 - r.square_repeated(7) - r *= x1010101 - r.square_repeated(9) - r *= x10101001 - - # Total 450 operations: - # - 74 multiplications - # - 376 squarings - -# BN Curves -# ------------------------------------------------------------ - -func inv_addchain*(r: var Fp[BN254_Snarks], a: Fp[BN254_Snarks]) = - var - x10 {.noInit.}: Fp[BN254_Snarks] - x11 {.noInit.}: Fp[BN254_Snarks] - x101 {.noInit.}: Fp[BN254_Snarks] - x110 {.noInit.}: Fp[BN254_Snarks] - x1000 {.noInit.}: Fp[BN254_Snarks] - x1101 {.noInit.}: Fp[BN254_Snarks] - x10010 {.noInit.}: Fp[BN254_Snarks] - x10011 {.noInit.}: Fp[BN254_Snarks] - x10100 {.noInit.}: Fp[BN254_Snarks] - x10111 {.noInit.}: Fp[BN254_Snarks] - x11100 {.noInit.}: Fp[BN254_Snarks] - x100000 {.noInit.}: Fp[BN254_Snarks] - x100011 {.noInit.}: Fp[BN254_Snarks] - x101011 {.noInit.}: Fp[BN254_Snarks] - x101111 {.noInit.}: Fp[BN254_Snarks] - x1000001 {.noInit.}: Fp[BN254_Snarks] - x1010011 {.noInit.}: Fp[BN254_Snarks] - x1011011 {.noInit.}: Fp[BN254_Snarks] - x1100001 {.noInit.}: Fp[BN254_Snarks] - x1110101 {.noInit.}: Fp[BN254_Snarks] - x10010001 {.noInit.}: Fp[BN254_Snarks] - x10010101 {.noInit.}: Fp[BN254_Snarks] - x10110101 {.noInit.}: Fp[BN254_Snarks] - x10111011 {.noInit.}: Fp[BN254_Snarks] - x11000001 {.noInit.}: Fp[BN254_Snarks] - x11000011 {.noInit.}: Fp[BN254_Snarks] - x11010011 {.noInit.}: Fp[BN254_Snarks] - x11100001 {.noInit.}: Fp[BN254_Snarks] - x11100011 {.noInit.}: Fp[BN254_Snarks] - x11100111 {.noInit.}: Fp[BN254_Snarks] - - x10 .square(a) - x11 .prod(x10, a) - x101 .prod(x10, x11) - x110 .prod(x101, a) - x1000 .prod(x10, x110) - x1101 .prod(x101, x1000) - x10010 .prod(x101, x1101) - x10011 .prod(x10010, a) - x10100 .prod(x10011, a) - x10111 .prod(x11, x10100) - x11100 .prod(x101, x10111) - x100000 .prod(x1101, x10011) - x100011 .prod(x11, x100000) - x101011 .prod(x1000, x100011) - x101111 .prod(x10011, x11100) - x1000001 .prod(x10010, x101111) - x1010011 .prod(x10010, x1000001) - x1011011 .prod(x1000, x1010011) - x1100001 .prod(x110, x1011011) - x1110101 .prod(x10100, x1100001) - x10010001 .prod(x11100, x1110101) - x10010101 .prod(x100000, x1110101) - x10110101 .prod(x100000, x10010101) - x10111011 .prod(x110, x10110101) - x11000001 .prod(x110, x10111011) - x11000011 .prod(x10, x11000001) - x11010011 .prod(x10010, x11000001) - x11100001 .prod(x100000, x11000001) - x11100011 .prod(x10, x11100001) - x11100111 .prod(x110, x11100001) # 30 operations - - # 30 + 27 = 57 operations - r.square(x11000001) - r.square_repeated(7) - r *= x10010001 - r.square_repeated(10) - r *= x11100111 - r.square_repeated(7) - - # 57 + 19 = 76 operations - r *= x10111 - r.square_repeated(9) - r *= x10011 - r.square_repeated(7) - r *= x1101 - - # 76 + 33 = 109 operations - r.square_repeated(14) - r *= x1010011 - r.square_repeated(9) - r *= x11100001 - r.square_repeated(8) - - # 109 + 18 = 127 operations - r *= x1000001 - r.square_repeated(10) - r *= x1011011 - r.square_repeated(5) - r *= x1101 - - # 127 + 34 = 161 operations - r.square_repeated(8) - r *= x11 - r.square_repeated(12) - r *= x101011 - r.square_repeated(12) - - # 161 + 25 = 186 operations - r *= x10111011 - r.square_repeated(8) - r *= x101111 - r.square_repeated(14) - r *= x10110101 - - # 186 + 28 = 214 - r.square_repeated(9) - r *= x10010001 - r.square_repeated(5) - r *= x1101 - r.square_repeated(12) - - # 214 + 22 = 236 - r *= x11100011 - r.square_repeated(8) - r *= x10010101 - r.square_repeated(11) - r *= x11010011 - - # 236 + 32 = 268 - r.square_repeated(7) - r *= x1100001 - r.square_repeated(11) - r *= x100011 - r.square_repeated(12) - - # 268 + 20 = 288 - r *= x1011011 - r.square_repeated(9) - r *= x11000011 - r.square_repeated(8) - r *= x11100111 - - # 288 + 15 = 303 - r.square_repeated(7) - r *= x1110101 - r.square_repeated(6) - r *= x101 - -# ############################################################ -# -# Dispatch +# Finite field inversion # # ############################################################ diff --git a/constantine/curves/addchain_inversions.nim b/constantine/curves/addchain_inversions.nim new file mode 100644 index 0000000..b9e20d8 --- /dev/null +++ b/constantine/curves/addchain_inversions.nim @@ -0,0 +1,17 @@ +# 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 + ./bls12_381_inversion, + ./bn254_snarks_inversion, + ./secp256k1_inversion + +export + bls12_381_inversion, + bn254_snarks_inversion, + secp256k1_inversion diff --git a/constantine/curves/bls12_381_inversion.nim b/constantine/curves/bls12_381_inversion.nim new file mode 100644 index 0000000..b95e9f3 --- /dev/null +++ b/constantine/curves/bls12_381_inversion.nim @@ -0,0 +1,225 @@ +# 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 + ../config/curves, + ../arithmetic/finite_fields + +# ############################################################ +# +# Specialized inversion for BLS12-381 +# +# ############################################################ + +# Field-specific inversion routines +func square_repeated(r: var Fp, num: int) = + ## Repeated squarings + for _ in 0 ..< num: + r.square() + +func inv_addchain*(r: var Fp[BLS12_381], a: Fp[BLS12_381]) = + var + x10 {.noinit.}: Fp[BLS12_381] + x100 {.noinit.}: Fp[BLS12_381] + x1000 {.noinit.}: Fp[BLS12_381] + x1001 {.noinit.}: Fp[BLS12_381] + x1011 {.noinit.}: Fp[BLS12_381] + x1101 {.noinit.}: Fp[BLS12_381] + x10001 {.noinit.}: Fp[BLS12_381] + x10100 {.noinit.}: Fp[BLS12_381] + x11001 {.noinit.}: Fp[BLS12_381] + x11010 {.noinit.}: Fp[BLS12_381] + x110100 {.noinit.}: Fp[BLS12_381] + x110110 {.noinit.}: Fp[BLS12_381] + x110111 {.noinit.}: Fp[BLS12_381] + x1001101 {.noinit.}: Fp[BLS12_381] + x1001111 {.noinit.}: Fp[BLS12_381] + x1010101 {.noinit.}: Fp[BLS12_381] + x1011101 {.noinit.}: Fp[BLS12_381] + x1100111 {.noinit.}: Fp[BLS12_381] + x1101001 {.noinit.}: Fp[BLS12_381] + x1110111 {.noinit.}: Fp[BLS12_381] + x1111011 {.noinit.}: Fp[BLS12_381] + x10001001 {.noinit.}: Fp[BLS12_381] + x10010101 {.noinit.}: Fp[BLS12_381] + x10010111 {.noinit.}: Fp[BLS12_381] + x10101001 {.noinit.}: Fp[BLS12_381] + x10110001 {.noinit.}: Fp[BLS12_381] + x10111111 {.noinit.}: Fp[BLS12_381] + x11000011 {.noinit.}: Fp[BLS12_381] + x11010000 {.noinit.}: Fp[BLS12_381] + x11010111 {.noinit.}: Fp[BLS12_381] + x11100001 {.noinit.}: Fp[BLS12_381] + x11100101 {.noinit.}: Fp[BLS12_381] + x11101011 {.noinit.}: Fp[BLS12_381] + x11110101 {.noinit.}: Fp[BLS12_381] + x11111111 {.noinit.}: Fp[BLS12_381] + + x10 .square(a) + x100 .square(x10) + x1000 .square(x100) + x1001 .prod(a, x1000) + x1011 .prod(x10, x1001) + x1101 .prod(x10, x1011) + x10001 .prod(x100, x1101) + x10100 .prod(x1001, x1011) + x11001 .prod(x1000, x10001) + x11010 .prod(a, x11001) + x110100 .square(x11010) + x110110 .prod(x10, x110100) + x110111 .prod(a, x110110) + x1001101 .prod(x11001, x110100) + x1001111 .prod(x10, x1001101) + x1010101 .prod(x1000, x1001101) + x1011101 .prod(x1000, x1010101) + x1100111 .prod(x11010, x1001101) + x1101001 .prod(x10, x1100111) + x1110111 .prod(x11010, x1011101) + x1111011 .prod(x100, x1110111) + x10001001 .prod(x110100, x1010101) + x10010101 .prod(x11010, x1111011) + x10010111 .prod(x10, x10010101) + x10101001 .prod(x10100, x10010101) + x10110001 .prod(x1000, x10101001) + x10111111 .prod(x110110, x10001001) + x11000011 .prod(x100, x10111111) + x11010000 .prod(x1101, x11000011) + x11010111 .prod(x10100, x11000011) + x11100001 .prod(x10001, x11010000) + x11100101 .prod(x100, x11100001) + x11101011 .prod(x10100, x11010111) + x11110101 .prod(x10100, x11100001) + x11111111 .prod(x10100, x11101011) # 35 operations + + # TODO: we can accumulate in a partially reduced + # doubled-size `r` to avoid the final substractions. + # and only reduce at the end. + # This requires the number of op to be less than log2(p) == 381 + + # 35 + 22 = 57 operations + r.prod(x10111111, x11100001) + r.square_repeated(8) + r *= x10001 + r.square_repeated(11) + r *= x11110101 + + # 57 + 28 = 85 operations + r.square_repeated(11) + r *= x11100101 + r.square_repeated(8) + r *= x11111111 + r.square_repeated(7) + + # 88 + 22 = 107 operations + r *= x1001101 + r.square_repeated(9) + r *= x1101001 + r.square_repeated(10) + r *= x10110001 + + # 107+24 = 131 operations + r.square_repeated(7) + r *= x1011101 + r.square_repeated(9) + r *= x1111011 + r.square_repeated(6) + + # 131+23 = 154 operations + r *= x11001 + r.square_repeated(11) + r *= x1101001 + r.square_repeated(9) + r *= x11101011 + + # 154+28 = 182 operations + r.square_repeated(10) + r *= x11010111 + r.square_repeated(6) + r *= x11001 + r.square_repeated(10) + + # 182+23 = 205 operations + r *= x1110111 + r.square_repeated(9) + r *= x10010111 + r.square_repeated(11) + r *= x1001111 + + # 205+30 = 235 operations + r.square_repeated(10) + r *= x11100001 + r.square_repeated(9) + r *= x10001001 + r.square_repeated(9) + + # 235+21 = 256 operations + r *= x10111111 + r.square_repeated(8) + r *= x1100111 + r.square_repeated(10) + r *= x11000011 + + # 256+28 = 284 operations + r.square_repeated(9) + r *= x10010101 + r.square_repeated(12) + r *= x1111011 + r.square_repeated(5) + + # 284 + 21 = 305 operations + r *= x1011 + r.square_repeated(11) + r *= x1111011 + r.square_repeated(7) + r *= x1001 + + # 305+32 = 337 operations + r.square_repeated(13) + r *= x11110101 + r.square_repeated(9) + r *= x10111111 + r.square_repeated(8) + + # 337+22 = 359 operations + r *= x11111111 + r.square_repeated(8) + r *= x11101011 + r.square_repeated(11) + r *= x10101001 + + # 359+24 = 383 operations + r.square_repeated(8) + r *= x11111111 + r.square_repeated(8) + r *= x11111111 + r.square_repeated(6) + + # 383+22 = 405 operations + r *= x110111 + r.square_repeated(10) + r *= x11111111 + r.square_repeated(9) + r *= x11111111 + + # 405+26 = 431 operations + r.square_repeated(8) + r *= x11111111 + r.square_repeated(8) + r *= x11111111 + r.square_repeated(8) + + # 431+19 = 450 operations + r *= x11111111 + r.square_repeated(7) + r *= x1010101 + r.square_repeated(9) + r *= x10101001 + + # Total 450 operations: + # - 74 multiplications + # - 376 squarings diff --git a/constantine/curves/bn254_snarks_inversion.nim b/constantine/curves/bn254_snarks_inversion.nim new file mode 100644 index 0000000..b869f3a --- /dev/null +++ b/constantine/curves/bn254_snarks_inversion.nim @@ -0,0 +1,164 @@ +# 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 + ../config/curves, + ../arithmetic/finite_fields + +# ############################################################ +# +# Specialized inversion for BN254-Snarks +# +# ############################################################ + +# Field-specific inversion routines +func square_repeated(r: var Fp, num: int) = + ## Repeated squarings + for _ in 0 ..< num: + r.square() + +func inv_addchain*(r: var Fp[BN254_Snarks], a: Fp[BN254_Snarks]) = + var + x10 {.noInit.}: Fp[BN254_Snarks] + x11 {.noInit.}: Fp[BN254_Snarks] + x101 {.noInit.}: Fp[BN254_Snarks] + x110 {.noInit.}: Fp[BN254_Snarks] + x1000 {.noInit.}: Fp[BN254_Snarks] + x1101 {.noInit.}: Fp[BN254_Snarks] + x10010 {.noInit.}: Fp[BN254_Snarks] + x10011 {.noInit.}: Fp[BN254_Snarks] + x10100 {.noInit.}: Fp[BN254_Snarks] + x10111 {.noInit.}: Fp[BN254_Snarks] + x11100 {.noInit.}: Fp[BN254_Snarks] + x100000 {.noInit.}: Fp[BN254_Snarks] + x100011 {.noInit.}: Fp[BN254_Snarks] + x101011 {.noInit.}: Fp[BN254_Snarks] + x101111 {.noInit.}: Fp[BN254_Snarks] + x1000001 {.noInit.}: Fp[BN254_Snarks] + x1010011 {.noInit.}: Fp[BN254_Snarks] + x1011011 {.noInit.}: Fp[BN254_Snarks] + x1100001 {.noInit.}: Fp[BN254_Snarks] + x1110101 {.noInit.}: Fp[BN254_Snarks] + x10010001 {.noInit.}: Fp[BN254_Snarks] + x10010101 {.noInit.}: Fp[BN254_Snarks] + x10110101 {.noInit.}: Fp[BN254_Snarks] + x10111011 {.noInit.}: Fp[BN254_Snarks] + x11000001 {.noInit.}: Fp[BN254_Snarks] + x11000011 {.noInit.}: Fp[BN254_Snarks] + x11010011 {.noInit.}: Fp[BN254_Snarks] + x11100001 {.noInit.}: Fp[BN254_Snarks] + x11100011 {.noInit.}: Fp[BN254_Snarks] + x11100111 {.noInit.}: Fp[BN254_Snarks] + + x10 .square(a) + x11 .prod(x10, a) + x101 .prod(x10, x11) + x110 .prod(x101, a) + x1000 .prod(x10, x110) + x1101 .prod(x101, x1000) + x10010 .prod(x101, x1101) + x10011 .prod(x10010, a) + x10100 .prod(x10011, a) + x10111 .prod(x11, x10100) + x11100 .prod(x101, x10111) + x100000 .prod(x1101, x10011) + x100011 .prod(x11, x100000) + x101011 .prod(x1000, x100011) + x101111 .prod(x10011, x11100) + x1000001 .prod(x10010, x101111) + x1010011 .prod(x10010, x1000001) + x1011011 .prod(x1000, x1010011) + x1100001 .prod(x110, x1011011) + x1110101 .prod(x10100, x1100001) + x10010001 .prod(x11100, x1110101) + x10010101 .prod(x100000, x1110101) + x10110101 .prod(x100000, x10010101) + x10111011 .prod(x110, x10110101) + x11000001 .prod(x110, x10111011) + x11000011 .prod(x10, x11000001) + x11010011 .prod(x10010, x11000001) + x11100001 .prod(x100000, x11000001) + x11100011 .prod(x10, x11100001) + x11100111 .prod(x110, x11100001) # 30 operations + + # 30 + 27 = 57 operations + r.square(x11000001) + r.square_repeated(7) + r *= x10010001 + r.square_repeated(10) + r *= x11100111 + r.square_repeated(7) + + # 57 + 19 = 76 operations + r *= x10111 + r.square_repeated(9) + r *= x10011 + r.square_repeated(7) + r *= x1101 + + # 76 + 33 = 109 operations + r.square_repeated(14) + r *= x1010011 + r.square_repeated(9) + r *= x11100001 + r.square_repeated(8) + + # 109 + 18 = 127 operations + r *= x1000001 + r.square_repeated(10) + r *= x1011011 + r.square_repeated(5) + r *= x1101 + + # 127 + 34 = 161 operations + r.square_repeated(8) + r *= x11 + r.square_repeated(12) + r *= x101011 + r.square_repeated(12) + + # 161 + 25 = 186 operations + r *= x10111011 + r.square_repeated(8) + r *= x101111 + r.square_repeated(14) + r *= x10110101 + + # 186 + 28 = 214 + r.square_repeated(9) + r *= x10010001 + r.square_repeated(5) + r *= x1101 + r.square_repeated(12) + + # 214 + 22 = 236 + r *= x11100011 + r.square_repeated(8) + r *= x10010101 + r.square_repeated(11) + r *= x11010011 + + # 236 + 32 = 268 + r.square_repeated(7) + r *= x1100001 + r.square_repeated(11) + r *= x100011 + r.square_repeated(12) + + # 268 + 20 = 288 + r *= x1011011 + r.square_repeated(9) + r *= x11000011 + r.square_repeated(8) + r *= x11100111 + + # 288 + 15 = 303 + r.square_repeated(7) + r *= x1110101 + r.square_repeated(6) + r *= x101 diff --git a/constantine/curves/secp256k1_inversion.nim b/constantine/curves/secp256k1_inversion.nim new file mode 100644 index 0000000..b95ee77 --- /dev/null +++ b/constantine/curves/secp256k1_inversion.nim @@ -0,0 +1,102 @@ +# 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 + ../config/curves, + ../arithmetic/finite_fields + +# ############################################################ +# +# Specialized inversion for Secp256k1 +# +# ############################################################ + +# Field-specific inversion routines +func square_repeated(r: var Fp, num: int) = + ## Repeated squarings + for _ in 0 ..< num: + r.square() + +func inv_addchain*(r: var Fp[Secp256k1], a: Fp[Secp256k1]) {.used.}= + ## We invert via Little Fermat's theorem + ## a^(-1) ≡ a^(p-2) (mod p) + ## with p = "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F" + ## We take advantage of the prime special form to hardcode + ## the sequence of squarings and multiplications for the modular exponentiation + ## + ## See libsecp256k1 + ## + ## The binary representation of (p - 2) has 5 blocks of 1s, with lengths in + ## { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: + ## [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + + var + x2{.noInit.}: Fp[Secp256k1] + x3{.noInit.}: Fp[Secp256k1] + x6{.noInit.}: Fp[Secp256k1] + x9{.noInit.}: Fp[Secp256k1] + x11{.noInit.}: Fp[Secp256k1] + x22{.noInit.}: Fp[Secp256k1] + x44{.noInit.}: Fp[Secp256k1] + x88{.noInit.}: Fp[Secp256k1] + x176{.noInit.}: Fp[Secp256k1] + x220{.noInit.}: Fp[Secp256k1] + x223{.noInit.}: Fp[Secp256k1] + + x2.square(a) + x2 *= a + + x3.square(x2) + x3 *= a + + x6 = x3 + x6.square_repeated(3) + x6 *= x3 + + x9 = x6 + x9.square_repeated(3) + x9 *= x3 + + x11 = x9 + x11.square_repeated(2) + x11 *= x2 + + x22 = x11 + x22.square_repeated(11) + x22 *= x11 + + x44 = x22 + x44.square_repeated(22) + x44 *= x22 + + x88 = x44 + x88.square_repeated(44) + x88 *= x44 + + x176 = x88 + x88.square_repeated(88) + x176 *= x88 + + x220 = x176 + x220.square_repeated(44) + x220 *= x44 + + x223 = x220 + x223.square_repeated(3) + x223 *= x3 + + # The final result is then assembled using a sliding window over the blocks + r = x223 + r.square_repeated(23) + r *= x22 + r.square_repeated(5) + r *= a + r.square_repeated(3) + r *= x2 + r.square_repeated(2) + r *= a