nim-bncurve/bncurve/fq6.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