mirror of
https://github.com/logos-storage/constantine.git
synced 2026-01-02 13:13:07 +00:00
134 lines
3.7 KiB
Nim
134 lines
3.7 KiB
Nim
# 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/[common, curves],
|
||
./finite_fields
|
||
|
||
# ############################################################
|
||
#
|
||
# Specialized inversions
|
||
#
|
||
# ############################################################
|
||
|
||
# Field-specific inversion routines
|
||
template repeat(num: int, body: untyped) =
|
||
for _ in 0 ..< num:
|
||
body
|
||
|
||
# Secp256k1
|
||
# ------------------------------------------------------------
|
||
func invmod_addchain(r: var Fp[Secp256k1], a: Fp[Secp256k1]) =
|
||
## 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
|
||
repeat 3: x6.square()
|
||
x6 *= x3
|
||
|
||
x9 = x6
|
||
repeat 3: x9.square()
|
||
x9 *= x3
|
||
|
||
x11 = x9
|
||
repeat 2: x11.square()
|
||
x11 *= x2
|
||
|
||
x22 = x11
|
||
repeat 11: x22.square()
|
||
x22 *= x11
|
||
|
||
x44 = x22
|
||
repeat 22: x44.square()
|
||
x44 *= x22
|
||
|
||
x88 = x44
|
||
repeat 44: x88.square()
|
||
x88 *= x44
|
||
|
||
x176 = x88
|
||
repeat 88: x88.square()
|
||
x176 *= x88
|
||
|
||
x220 = x176
|
||
repeat 44: x220.square()
|
||
x220 *= x44
|
||
|
||
x223 = x220
|
||
repeat 3: x223.square()
|
||
x223 *= x3
|
||
|
||
# The final result is then assembled using a sliding window over the blocks
|
||
r = x223
|
||
repeat 23: r.square()
|
||
r *= x22
|
||
repeat 5: r.square()
|
||
r *= a
|
||
repeat 3: r.square()
|
||
r *= x2
|
||
repeat 2: r.square()
|
||
r *= a
|
||
|
||
# BN Curves
|
||
# ------------------------------------------------------------
|
||
# Efficient Pairings and ECC for Embedded Systems
|
||
# Thomas Unterluggauer and Erich Wenger
|
||
# https://eprint.iacr.org/2014/800.pdf
|
||
#
|
||
# BN curve field modulus are of the form:
|
||
# p = 36u^4 + 36u^3 + 24u^2 + 6u + 1
|
||
#
|
||
# We construct the following multiplication-squaring chain
|
||
# a^-1 mod p = a^(p-2) mod p (Little Fermat Theorem)
|
||
# = a^(36 u^4 + 36 u^3 + 24 u^2 + 6u + 1 - 2) mod p
|
||
# = a^(36 u^4) . a^(36 u^3) . a^(24 u^2) . a^(6u-1) mod p
|
||
#
|
||
# Note: it only works for u positive, in particular BN254 doesn't work :/
|
||
# Is there a way to only use a^-u or even powers?
|
||
|
||
# ############################################################
|
||
#
|
||
# Dispatch
|
||
#
|
||
# ############################################################
|
||
|
||
func inv*(r: var Fp, a: Fp) =
|
||
## Inversion modulo p
|
||
# For now we don't activate the addition chain.
|
||
# Performance is equal to GCD and it does not pass test on 𝔽p2
|
||
# We need faster squaring/multiplications
|
||
r.mres.steinsGCD(a.mres, Fp.C.getR2modP(), Fp.C.Mod.mres, Fp.C.getPrimePlus1div2())
|