nim-bncurve/bncurve/fq2.nim

162 lines
4.6 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 fp, arith
{.deadCodeElim: on.}
type
FQ2* = object
c0*: FQ
c1*: FQ
const
FQNonResidue = FQ([
0x68c3488912edefaa'u64, 0x8d087f6872aabf4f'u64,
0x51e1a24709081231'u64, 0x2259d6b14729c0fa'u64
])
FQ2NonResidue* = FQ2(
c0: FQ([
0xf60647ce410d7ff7'u64, 0x2f3d6f4dd31bd011'u64,
0x2943337e3940c6d1'u64, 0x1d9598e8a7e39857'u64
]),
c1: FQ([
0xd35d438dc58f0d9d'u64, 0x0a78eb28f5c70b3d'u64,
0x666ea36f7879462c'u64, 0x0e0a77c19a07df2f'u64
])
)
proc init*(c0, c1: FQ): FQ2 {.inline, noinit.} =
result.c0 = c0
result.c1 = c1
proc zero*(t: typedesc[FQ2]): FQ2 {.inline, noinit.} =
result.c0 = FQ.zero()
result.c1 = FQ.zero()
proc one*(t: typedesc[FQ2]): FQ2 {.inline, noinit.} =
result.c0 = FQ.one()
result.c1 = FQ.zero()
proc random*(t: typedesc[FQ2]): FQ2 {.inline, noinit.} =
result.c0 = FQ.random()
result.c1 = FQ.random()
proc isZero*(x: FQ2): bool {.inline, noinit.} =
result = (x.c0.isZero() and x.c1.isZero())
proc scale*(x: FQ2, by: FQ): FQ2 {.inline, noinit.} =
result.c0 = x.c0 * by
result.c1 = x.c1 * by
proc squared*(x: FQ2): FQ2 {.inline, noinit.} =
let ab = x.c0 * x.c1
result.c0 = (x.c1 * FQNonResidue + x.c0) * (x.c0 + x.c1) -
ab - ab * FQNonResidue
result.c1 = ab + ab
proc inverse*(x: FQ2): Option[FQ2] {.inline, noinit.} =
let opt = (x.c0.squared() - (x.c1.squared() * FQNonResidue)).inverse()
if isSome(opt):
let tmp = opt.get()
result = some[FQ2](FQ2(c0: x.c0 * tmp, c1: -(x.c1 * tmp)))
else:
result = none[FQ2]()
proc `+`*(x, y: FQ2): FQ2 {.noinit, inline.} =
## Return result of ``x + y``.
result.c0 = x.c0 + y.c0
result.c1 = x.c1 + y.c1
proc `+=`*(x: var FQ2, y: FQ2) {.noinit, inline.} =
## Perform inplace addition ``x = x + y``.
x.c0 += y.c0
x.c1 += y.c1
proc `-`*(x, y: FQ2): FQ2 {.noinit, inline.} =
## Return result of ``x - y``.
result.c0 = x.c0 - y.c0
result.c1 = x.c1 - y.c1
proc `-=`*(x: var FQ2, y: FQ2) {.noinit, inline.} =
## Perform inplace substraction ``x = x - y``.
x.c0 -= y.c0
x.c1 -= y.c1
proc `*`*(x, y: FQ2): FQ2 {.noinit, inline.} =
## Return result of ``x * y``.
let aa = x.c0 * y.c0
let bb = x.c1 * y.c1
result.c0 = bb * FQNonResidue + aa
result.c1 = (x.c0 + x.c1) * (y.c0 + y.c1) - aa - bb
proc `*=`*(x: var FQ2, y: FQ2) {.noinit, inline.} =
## Perform inplace multiplication ``x = x * y``.
let aa = x.c0 * y.c0
let bb = x.c1 * y.c1
let cc = x.c1 + x.c1
x.c0 = bb * FQNonResidue + aa
x.c1 = cc * (y.c0 + y.c1) - aa - bb
proc `-`*(x: FQ2): FQ2 {.noinit, inline.} =
## Negotiation of ``x``.
result.c0 = -x.c0
result.c1 = -x.c1
proc frobeniusMap*(x: FQ2, power: uint64): FQ2 =
if power mod 2 == 0:
result = x
else:
result.c0 = x.c0
result.c1 = x.c1 * FQNonResidue
proc `==`*(x: FQ2, y: FQ2): bool =
## Return ``true`` if ``a == b``.
result = (x.c0 == y.c0) and (x.c1 == y.c1)
proc mulByNonresidue*(x: FQ2): FQ2 =
result = x * FQ2NonResidue
proc fromBytes*(dst: var FQ2, src: openArray[byte]): bool {.noinit.} =
## Create 512bit integer FQ2 from big-endian bytes representation ``src``.
## Returns ``true`` if ``dst`` was successfully initialized, ``false``
## otherwise.
result = false
var value: BNU512
if fromBytes(value, src):
var b0: BNU256
var b1o = value.divrem(FQ.modulus(), b0)
if isSome(b1o):
var c0o = FQ.init(b0)
var c1o = FQ.init(b1o.get())
if isSome(c0o) and isSome(c1o):
dst = init(c0o.get(), c1o.get())
result = true
proc fromBytes2*(dst: var FQ2, src: openArray[byte]): bool {.noinit.} =
## Create integer FQ2 from big-endian bytes representation ``src`` in
## Ethereum way.
## Returns ``true`` if ``dst`` was successfully initialized, ``false``
## otherwise.
result = false
if dst.c1.fromBytes2(src.toOpenArray(0, 31)) and
dst.c0.fromBytes2(src.toOpenArray(32, 63)):
result = true
proc toBytes*(src: FQ2,
dst: var openArray[byte]): bool {.noinit, inline.} =
## Encode 512bit integer FQ2 to big-endian bytes representation ``dst``.
## Returns ``true`` if integer was successfully serialized, ``false``
## otherwise.
var c0, c1: BNU256
c0 = BNU256.into(src.c0)
c1 = BNU256.into(src.c1)
result = BNU512.into(c1, c0, FQ.modulus()).toBytes(dst)