181 lines
5.4 KiB
Nim
181 lines
5.4 KiB
Nim
# Nim Barreto-Naehrig pairing-friendly elliptic curve implementation
|
|
# Copyright (c) 2018 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
# at your option.
|
|
# This file may not be copied, modified, or distributed except according to
|
|
# those terms.
|
|
import options
|
|
import fq2, fp, arith
|
|
|
|
{.deadCodeElim: on.}
|
|
|
|
const frobeniusCoeffsC1: array[4, FQ2] = [
|
|
FQ2.one(),
|
|
FQ2(
|
|
c0: Fq([13075984984163199792'u64, 3782902503040509012'u64,
|
|
8791150885551868305'u64, 1825854335138010348'u64]),
|
|
c1: Fq([7963664994991228759'u64, 12257807996192067905'u64,
|
|
13179524609921305146'u64, 2767831111890561987'u64])
|
|
),
|
|
FQ2(
|
|
c0: Fq([3697675806616062876'u64, 9065277094688085689'u64,
|
|
6918009208039626314'u64, 2775033306905974752'u64]),
|
|
c1: Fq.zero()
|
|
),
|
|
FQ2(
|
|
c0: Fq([14532872967180610477'u64, 12903226530429559474'u64,
|
|
1868623743233345524'u64, 2316889217940299650'u64]),
|
|
c1: Fq([12447993766991532972'u64, 4121872836076202828'u64,
|
|
7630813605053367399'u64, 740282956577754197'u64])
|
|
)
|
|
]
|
|
|
|
const frobeniusCoeffsC2: array[4, FQ2] = [
|
|
FQ2.one(),
|
|
FQ2(
|
|
c0: Fq([8314163329781907090'u64, 11942187022798819835'u64,
|
|
11282677263046157209'u64, 1576150870752482284'u64]),
|
|
c1: Fq([6763840483288992073'u64, 7118829427391486816'u64,
|
|
4016233444936635065'u64, 2630958277570195709'u64])
|
|
),
|
|
FQ2(
|
|
c0: Fq([8183898218631979349'u64, 12014359695528440611'u64,
|
|
12263358156045030468'u64, 3187210487005268291'u64]),
|
|
c1: Fq.zero()
|
|
),
|
|
FQ2(
|
|
c0: Fq([4938922280314430175'u64, 13823286637238282975'u64,
|
|
15589480384090068090'u64, 481952561930628184'u64]),
|
|
c1: Fq([3105754162722846417'u64, 11647802298615474591'u64,
|
|
13057042392041828081'u64, 1660844386505564338'u64])
|
|
)
|
|
]
|
|
|
|
type
|
|
FQ6* = object
|
|
c0*: FQ2
|
|
c1*: FQ2
|
|
c2*: FQ2
|
|
|
|
proc init*(c0, c1, c2: FQ2): FQ6 {.inline, noinit.} =
|
|
result.c0 = c0
|
|
result.c1 = c1
|
|
result.c2 = c2
|
|
|
|
proc zero*(t: typedesc[FQ6]): FQ6 {.inline, noinit.} =
|
|
result.c0 = FQ2.zero()
|
|
result.c1 = FQ2.zero()
|
|
result.c2 = FQ2.zero()
|
|
|
|
proc one*(t: typedesc[FQ6]): FQ6 {.inline, noinit.} =
|
|
result.c0 = FQ2.one()
|
|
result.c1 = FQ2.zero()
|
|
result.c2 = FQ2.zero()
|
|
|
|
proc random*(t: typedesc[FQ6]): FQ6 {.inline, noinit.} =
|
|
result.c0 = FQ2.random()
|
|
result.c1 = FQ2.random()
|
|
result.c2 = FQ2.random()
|
|
|
|
proc isZero*(x: FQ6): bool {.inline, noinit.} =
|
|
result = (x.c0.isZero() and x.c1.isZero() and x.c2.isZero())
|
|
|
|
proc scale*(x: FQ6, by: FQ2): FQ6 {.inline, noinit.} =
|
|
result.c0 = x.c0 * by
|
|
result.c1 = x.c1 * by
|
|
result.c2 = x.c2 * by
|
|
|
|
proc squared*(x: FQ6): FQ6 {.inline, noinit.} =
|
|
let s0 = x.c0.squared()
|
|
let ab = x.c0 * x.c1
|
|
let s1 = ab + ab
|
|
let s2 = (x.c0 - x.c1 + x.c2).squared()
|
|
let bc = x.c1 * x.c2
|
|
let s3 = bc + bc
|
|
let s4 = x.c2.squared()
|
|
|
|
result.c0 = s0 + s3.mulByNonresidue()
|
|
result.c1 = s1 + s4.mulByNonresidue()
|
|
result.c2 = s1 + s2 + s3 - s0 - s4
|
|
|
|
proc inverse*(x: FQ6): Option[FQ6] {.inline, noinit.} =
|
|
let c0 = x.c0.squared() - (x.c1 * x.c2.mulByNonresidue())
|
|
let c1 = x.c2.squared().mulByNonresidue() - (x.c0 * x.c1)
|
|
let c2 = x.c1.squared() - (x.c0 * x.c2)
|
|
let opt = ((x.c2 * c1 + x.c1 * c2).mulByNonresidue() +
|
|
x.c0 * c0).inverse()
|
|
if isSome(opt):
|
|
let tmp = opt.get()
|
|
result = some[FQ6](FQ6(c0: tmp * c0, c1: tmp * c1, c2: tmp * c2))
|
|
else:
|
|
result = none[FQ6]()
|
|
|
|
proc `+`*(x, y: FQ6): FQ6 {.noinit, inline.} =
|
|
## Return result of ``x + y``.
|
|
result.c0 = x.c0 + y.c0
|
|
result.c1 = x.c1 + y.c1
|
|
result.c2 = x.c2 + y.c2
|
|
|
|
proc `+=`*(x: var FQ6, y: FQ6) {.noinit, inline.} =
|
|
## Perform inplace addition ``x = x + y``.
|
|
x.c0 += y.c0
|
|
x.c1 += y.c1
|
|
x.c2 += y.c2
|
|
|
|
proc `-`*(x, y: FQ6): FQ6 {.noinit, inline.} =
|
|
## Return result of ``x - y``.
|
|
result.c0 = x.c0 - y.c0
|
|
result.c1 = x.c1 - y.c1
|
|
result.c2 = x.c2 - y.c2
|
|
|
|
proc `-=`*(x: var FQ6, y: FQ6) {.noinit, inline.} =
|
|
## Perform inplace substraction ``x = x - y``.
|
|
x.c0 -= y.c0
|
|
x.c1 -= y.c1
|
|
x.c2 -= y.c2
|
|
|
|
proc `*`*(x, y: FQ6): FQ6 {.noinit, inline.} =
|
|
## Return result of ``x * y``.
|
|
let aa = x.c0 * y.c0
|
|
let bb = x.c1 * y.c1
|
|
let cc = x.c2 * y.c2
|
|
result.c0 = ((x.c1 + x.c2) * (y.c1 + y.c2) - bb - cc).mulByNonresidue() +
|
|
aa
|
|
result.c1 = (x.c0 + x.c1) * (y.c0 + y.c1) - aa - bb + cc.mulByNonresidue()
|
|
result.c2 = (x.c0 + x.c2) * (y.c0 + y.c2) - aa + bb - cc
|
|
|
|
proc `*=`*(x: var FQ6, y: FQ6) {.noinit, inline.} =
|
|
## Perform inplace multiplication ``x = x * y``.
|
|
let aa = x.c0 * y.c0
|
|
let bb = x.c1 * y.c1
|
|
let cc = x.c2 * y.c2
|
|
let dd = x.c1 + x.c2
|
|
let ee = x.c0 + x.c1
|
|
let ff = x.c0 + x.c2
|
|
|
|
x.c0 = (dd * (y.c1 + y.c2) - bb - cc).mulByNonresidue() + aa
|
|
x.c1 = ee * (y.c0 + y.c1) - aa - bb + cc.mulByNonresidue()
|
|
x.c2 = ff * (y.c0 + y.c2) - aa - bb - cc
|
|
|
|
proc `-`*(x: FQ6): FQ6 {.noinit, inline.} =
|
|
## Negotiation of ``x``.
|
|
result.c0 = -x.c0
|
|
result.c1 = -x.c1
|
|
result.c2 = -x.c2
|
|
|
|
proc frobeniusMap*(x: FQ6, power: uint64): FQ6 =
|
|
result.c0 = x.c0.frobeniusMap(power)
|
|
result.c1 = x.c1.frobeniusMap(power) * frobeniusCoeffsC1[power mod 6]
|
|
result.c2 = x.c2.frobeniusMap(power) * frobeniusCoeffsC2[power mod 6]
|
|
|
|
proc `==`*(x: FQ6, y: FQ6): bool =
|
|
## Return ``true`` if ``a == b``.
|
|
result = (x.c0 == y.c0) and (x.c1 == y.c1) and (x.c2 == y.c2)
|
|
|
|
proc mulByNonresidue*(x: FQ6): FQ6 =
|
|
result.c0 = x.c2.mulByNonresidue()
|
|
result.c1 = x.c0
|
|
result.c2 = x.c1
|