Initial commit.
This commit is contained in:
parent
7b55d96b2f
commit
4b8f6db181
|
@ -0,0 +1,86 @@
|
|||
version: '{build}'
|
||||
|
||||
cache:
|
||||
- x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z -> .appveyor.yml
|
||||
- i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z -> .appveyor.yml
|
||||
- Nim -> .appveyor.yml
|
||||
|
||||
matrix:
|
||||
# We always want 32 and 64-bit compilation
|
||||
fast_finish: false
|
||||
|
||||
platform:
|
||||
- x86
|
||||
- x64
|
||||
|
||||
install:
|
||||
- setlocal EnableExtensions EnableDelayedExpansion
|
||||
|
||||
- IF "%PLATFORM%" == "x86" (
|
||||
SET "MINGW_ARCHIVE=i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z" &
|
||||
SET "MINGW_URL=https://sourceforge.net/projects/mingw-w64/files/Toolchains%%20targetting%%20Win32/Personal%%20Builds/mingw-builds/4.9.2/threads-win32/dwarf/i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z" &
|
||||
SET "MINGW_DIR=mingw32"
|
||||
) ELSE (
|
||||
IF "%PLATFORM%" == "x64" (
|
||||
SET "MINGW_ARCHIVE=x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z" &
|
||||
SET "MINGW_URL=https://sourceforge.net/projects/mingw-w64/files/Toolchains%%20targetting%%20Win64/Personal%%20Builds/mingw-builds/4.9.2/threads-win32/seh/x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z" &
|
||||
SET "MINGW_DIR=mingw64"
|
||||
) else (
|
||||
echo "Unknown platform"
|
||||
)
|
||||
)
|
||||
|
||||
- SET PATH=%CD%\%MINGW_DIR%\bin;%CD%\Nim\bin;%PATH%
|
||||
|
||||
# Unpack mingw
|
||||
- IF NOT EXIST "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%"
|
||||
- 7z x -y "%MINGW_ARCHIVE%" > nul
|
||||
|
||||
# build nim from our own branch - this to avoid the day-to-day churn and
|
||||
# regressions of the fast-paced Nim development while maintaining the
|
||||
# flexibility to apply patches
|
||||
- SET "NEED_REBUILD="
|
||||
|
||||
- IF NOT EXIST "Nim\\.git\\" (
|
||||
git clone https://github.com/status-im/Nim.git
|
||||
) ELSE (
|
||||
( cd Nim ) &
|
||||
( git pull ) &
|
||||
( cd .. )
|
||||
)
|
||||
|
||||
# Rebuild Nim if HEAD has moved or if we don't yet have a cached version
|
||||
- IF NOT EXIST "Nim\\ver.txt" (
|
||||
SET NEED_REBUILD=1
|
||||
) ELSE (
|
||||
( CD Nim ) &
|
||||
( git rev-parse HEAD > ..\\cur_ver.txt ) &
|
||||
( fc ver.txt ..\\cur_ver.txt || SET NEED_REBUILD=1 ) &
|
||||
( cd .. )
|
||||
)
|
||||
|
||||
- IF NOT EXIST "Nim\\bin\\nim.exe" SET NEED_REBUILD=1
|
||||
- IF NOT EXIST "Nim\\bin\\nimble.exe" SET NEED_REBUILD=1
|
||||
|
||||
# after building nim, wipe csources to save on cache space
|
||||
- IF DEFINED NEED_REBUILD (
|
||||
cd Nim &
|
||||
( IF EXIST "csources" rmdir /s /q csources ) &
|
||||
git clone --depth 1 https://github.com/nim-lang/csources &
|
||||
cd csources &
|
||||
( IF "%PLATFORM%" == "x64" ( build64.bat ) else ( build.bat ) ) &
|
||||
cd .. &
|
||||
bin\nim c koch &
|
||||
koch boot -d:release &
|
||||
koch nimble &
|
||||
git rev-parse HEAD > ver.txt &
|
||||
rmdir /s /q csources
|
||||
)
|
||||
|
||||
build_script:
|
||||
- cd C:\projects\%APPVEYOR_PROJECT_SLUG%
|
||||
- nimble install -y
|
||||
test_script:
|
||||
- nimble test
|
||||
|
||||
deploy: off
|
|
@ -0,0 +1,39 @@
|
|||
language: c # or other C/C++ variants
|
||||
|
||||
sudo: false
|
||||
|
||||
# https://docs.travis-ci.com/user/caching/
|
||||
#
|
||||
# Caching the whole nim folder is better than relying on ccache - this way, we
|
||||
# skip the expensive bootstrap process and linking
|
||||
cache:
|
||||
directories:
|
||||
- nim
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
install:
|
||||
# build nim from our own branch - this to avoid the day-to-day churn and
|
||||
# regressions of the fast-paced Nim development while maintaining the
|
||||
# flexibility to apply patches
|
||||
#
|
||||
# check version of remote branch
|
||||
- "export NIMVER=$(git ls-remote https://github.com/status-im/nim.git HEAD | cut -f 1)"
|
||||
|
||||
# after building nim, wipe csources to save on cache space
|
||||
- "{ [ -f nim/$NIMVER/bin/nim ] && [ -f nim/$NIMVER/bin/nimble ] ; } ||
|
||||
{ rm -rf nim ;
|
||||
mkdir -p nim ;
|
||||
git clone --depth=1 https://github.com/status-im/nim.git nim/$NIMVER ;
|
||||
cd nim/$NIMVER ;
|
||||
sh build_all.sh ;
|
||||
rm -rf csources ;
|
||||
cd ../.. ;
|
||||
}"
|
||||
- "export PATH=$PWD/nim/$NIMVER/bin:$PATH"
|
||||
|
||||
script:
|
||||
- nimble install -y
|
||||
- nimble test
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2018 Status Research & Development GmbH
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Status
|
||||
Copyright (c) 2018 Status Research & Development GmbH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
|
@ -0,0 +1,47 @@
|
|||
## BNCurve
|
||||
[![Build Status](https://travis-ci.org/status-im/nim-bncurve.svg?branch=master)](https://travis-ci.org/status-im/nim-bncurve)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/hvv14l9v31mksam6/branch/master?svg=true)](https://ci.appveyor.com/project/nimbus/nim-bncurve/branch/master)
|
||||
[![License: Apache](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
|
||||
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
|
||||
![Stability: experimental](https://img.shields.io/badge/stability-experimental-orange.svg)
|
||||
|
||||
## Introduction
|
||||
This pure Nim implementation of Barreto-Naehrig pairing-friendly elliptic curve.
|
||||
|
||||
This is a [pairing cryptography](https://en.wikipedia.org/wiki/Pairing-based_cryptography) library written in pure Nim. It makes use of the Barreto-Naehrig (BN) curve construction from [[BCTV2015]](https://eprint.iacr.org/2013/879.pdf) to provide two cyclic groups **G<sub>1</sub>** and **G<sub>2</sub>**, with an efficient bilinear pairing:
|
||||
|
||||
*e: G<sub>1</sub> × G<sub>2</sub> → G<sub>T</sub>*
|
||||
|
||||
This code is adaptation of (bn)[https://github.com/zcash-hackworks/bn.git] library.
|
||||
|
||||
## Security warnings
|
||||
|
||||
This library, like other pairing cryptography libraries implementing this construction, is not resistant to side-channel attacks.
|
||||
|
||||
## Installation
|
||||
|
||||
Add to your `.nimble` file:
|
||||
```
|
||||
requires "https://github.com/status-im/nim-bncurve"
|
||||
```
|
||||
|
||||
or install it via
|
||||
```
|
||||
nimble install https://github.com/status-im/nim-bncurve
|
||||
```
|
||||
|
||||
## Build and test
|
||||
|
||||
```
|
||||
nimble install https://github.com/status-im/nim-bncurve
|
||||
nimble test
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed and distributed under either of
|
||||
|
||||
* MIT license: [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 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.
|
|
@ -0,0 +1,10 @@
|
|||
# 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 bncurve/[fields, groups]
|
||||
export fields, groups
|
|
@ -0,0 +1,26 @@
|
|||
packageName = "bncurve"
|
||||
version = "1.0.0"
|
||||
author = "Status Research & Development GmbH"
|
||||
description = "Barreto-Naehrig pairing-friendly elliptic curve implementation"
|
||||
license = "Apache License 2.0 or MIT"
|
||||
skipDirs = @["tests", "Nim", "nim"]
|
||||
|
||||
### Dependencies
|
||||
|
||||
requires "nim > 0.18.0"
|
||||
|
||||
task test, "Run all tests":
|
||||
exec "nim c -r tests/tarith"
|
||||
exec "nim c -r -d:release tests/tarith"
|
||||
|
||||
exec "nim c -r tests/tfields"
|
||||
exec "nim c -r -d:release tests/tfields"
|
||||
|
||||
exec "nim c -r tests/tgroups"
|
||||
exec "nim c -r -d:release tests/tgroups"
|
||||
|
||||
exec "nim c -r tests/tpairing"
|
||||
exec "nim c -r -d:release tests/tpairing"
|
||||
|
||||
exec "nim c -r tests/tvectors"
|
||||
exec "nim c -r -d:release tests/tvectors"
|
|
@ -0,0 +1,423 @@
|
|||
# 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, endians
|
||||
import nimcrypto/[utils, sysrand]
|
||||
|
||||
export options
|
||||
|
||||
type
|
||||
BNU256* = array[4, uint64]
|
||||
BNU512* = array[8, uint64]
|
||||
|
||||
proc setRandom*(a: var BNU512) {.inline, noinit.} =
|
||||
## Set value of integer ``a`` to random value.
|
||||
let ret = randomBytes(a)
|
||||
doAssert(ret == 8)
|
||||
|
||||
proc random*(t: typedesc[BNU512]): BNU512 {.inline, noinit.} =
|
||||
## Return random 512bit integer.
|
||||
setRandom(result)
|
||||
|
||||
proc setZero*(a: var BNU256) {.inline, noinit.} =
|
||||
## Set value of integer ``a`` to zero.
|
||||
a[0] = 0'u64
|
||||
a[1] = 0'u64
|
||||
a[2] = 0'u64
|
||||
a[3] = 0'u64
|
||||
|
||||
proc setOne*(a: var BNU256) {.inline, noinit.} =
|
||||
## Set value of integer ``a`` to one.
|
||||
a[0] = 1'u64
|
||||
a[1] = 0'u64
|
||||
a[2] = 0'u64
|
||||
a[3] = 0'u64
|
||||
|
||||
proc zero*(t: typedesc[BNU256]): BNU256 {.inline, noinit.} =
|
||||
## Return zero 256bit integer.
|
||||
setZero(result)
|
||||
|
||||
proc one*(t: typedesc[BNU256]): BNU256 {.inline, noinit.} =
|
||||
## Return one 256bit integer.
|
||||
setOne(result)
|
||||
|
||||
proc isZero*(a: BNU256): bool {.inline, noinit.} =
|
||||
## Check if integer ``a`` is zero.
|
||||
(a[0] == 0'u64) and (a[1] == 0'u64) and (a[2] == 0'u64) and (a[3] == 0'u64)
|
||||
|
||||
proc setBit*(a: var openarray[uint64], n: int,
|
||||
to: bool): bool {.inline, noinit.} =
|
||||
## Set bit of integer ``a`` at position ``n`` to value ``to``.
|
||||
if n >= 256:
|
||||
return
|
||||
let part = n shr 6
|
||||
let bit = n - (part shl 6)
|
||||
if to:
|
||||
a[part] = a[part] or (1'u64 shl bit)
|
||||
else:
|
||||
a[part] = a[part] and not(1'u64 shl bit)
|
||||
result = true
|
||||
|
||||
proc getBit*(a: openarray[uint64], n: int): bool {.inline, noinit.} =
|
||||
## Get value of bit at position ``n`` in integer ``a``.
|
||||
let part = n shr 6
|
||||
let bit = n - (part shl 6)
|
||||
result = ((a[part] and (1'u64 shl bit)) != 0)
|
||||
|
||||
template splitU64(n: uint64, hi, lo: untyped) =
|
||||
## Split 64bit unsigned integer to 32bit parts
|
||||
hi = n shr 32
|
||||
lo = n and 0xFFFF_FFFF'u64
|
||||
|
||||
template combineU64(hi, lo: untyped): uint64 =
|
||||
## Combine 64bit unsigned integer from 32bit parts
|
||||
(hi shl 32) or lo
|
||||
|
||||
proc div2*(a: var BNU256) {.inline, noinit.} =
|
||||
## Divide integer ``a`` in place by ``2``.
|
||||
var t = a[3] shl 63
|
||||
a[3] = a[3] shr 1
|
||||
let b = a[2] shl 63
|
||||
a[2] = a[2] shr 1
|
||||
a[2] = a[2] or t
|
||||
t = a[1] shl 63
|
||||
a[1] = a[1] shr 1
|
||||
a[1] = a[1] or b
|
||||
a[0] = a[0] shr 1
|
||||
a[0] = a[0] or t
|
||||
|
||||
proc mul2*(a: var BNU256) {.inline, noinit.} =
|
||||
## Multiply integer ``a`` in place by ``2``.
|
||||
var last = 0'u64
|
||||
for i in a.mitems():
|
||||
let tmp = i shr 63
|
||||
i = i shl 1
|
||||
i = i or last
|
||||
last = tmp
|
||||
|
||||
proc adc(a, b: uint64, carry: var uint64): uint64 {.inline, noinit.} =
|
||||
## Calculate ``a + b`` and return result, set ``carry`` to addition
|
||||
## operation carry.
|
||||
var a0, a1, b0, b1, c, r0, r1: uint64
|
||||
splitU64(a, a1, a0)
|
||||
splitU64(b, b1, b0)
|
||||
let tmp0 = a0 + b0 + carry
|
||||
splitU64(tmp0, c, r0)
|
||||
let tmp1 = a1 + b1 + c
|
||||
splitU64(tmp1, c, r1)
|
||||
carry = c
|
||||
result = combineU64(r1, r0)
|
||||
|
||||
proc addNoCarry*(a: var BNU256, b: BNU256) {.inline, noinit.} =
|
||||
## Calculate integer addition ``a = a + b``.
|
||||
var carry = 0'u64
|
||||
a[0] = adc(a[0], b[0], carry)
|
||||
a[1] = adc(a[1], b[1], carry)
|
||||
a[2] = adc(a[2], b[2], carry)
|
||||
a[3] = adc(a[3], b[3], carry)
|
||||
assert(carry == 0)
|
||||
|
||||
proc subNoBorrow*(a: var BNU256, b: BNU256) {.inline, noinit.} =
|
||||
## Calculate integer substraction ``a = a - b``.
|
||||
proc sbb(a: uint64, b: uint64,
|
||||
borrow: var uint64): uint64 {.inline, noinit.}=
|
||||
var a0, a1, b0, b1, t0, r0, r1: uint64
|
||||
splitU64(a, a1, a0)
|
||||
splitU64(b, b1, b0)
|
||||
let tmp0 = (1'u64 shl 32) + a0 - b0 - borrow
|
||||
splitU64(tmp0, t0, r0)
|
||||
let tmp1 = (1'u64 shl 32) + a1 - b1 - uint64(t0 == 0'u64)
|
||||
splitU64(tmp1, t0, r1)
|
||||
borrow = uint64(t0 == 0)
|
||||
result = combineU64(r1, r0)
|
||||
var borrow = 0'u64
|
||||
a[0] = sbb(a[0], b[0], borrow)
|
||||
a[1] = sbb(a[1], b[1], borrow)
|
||||
a[2] = sbb(a[2], b[2], borrow)
|
||||
a[3] = sbb(a[3], b[3], borrow)
|
||||
assert(borrow == 0)
|
||||
|
||||
proc macDigit(acc: var openarray[uint64], pos: int, b: openarray[uint64],
|
||||
c: uint64) {.noinit.} =
|
||||
proc macWithCarry(a, b, c: uint64, carry: var uint64): uint64 {.noinit.} =
|
||||
var
|
||||
bhi, blo, chi, clo, ahi, alo, carryhi, carrylo: uint64
|
||||
xhi, xlo, yhi, ylo, zhi, zlo, rhi, rlo: uint64
|
||||
splitU64(b, bhi, blo)
|
||||
splitU64(c, chi, clo)
|
||||
splitU64(a, ahi, alo)
|
||||
splitU64(carry, carryhi, carrylo)
|
||||
splitU64(blo * clo + alo + carrylo, xhi, xlo)
|
||||
splitU64(blo * chi, yhi, ylo)
|
||||
splitU64(bhi * clo, zhi, zlo)
|
||||
splitU64(x_hi + y_lo + z_lo + a_hi + carry_hi, rhi, rlo)
|
||||
carry = (bhi * chi) + rhi + yhi + zhi
|
||||
result = combineU64(rlo, xlo)
|
||||
|
||||
if c == 0'u64:
|
||||
return
|
||||
var carry = 0'u64
|
||||
for i in pos..<len(acc):
|
||||
if (i - pos) < len(b):
|
||||
acc[i] = macWithCarry(acc[i], b[i - pos], c, carry)
|
||||
elif carry != 0:
|
||||
acc[i] = macWithCarry(acc[i], 0'u64, c, carry)
|
||||
else:
|
||||
break
|
||||
assert(carry == 0)
|
||||
|
||||
proc mulReduce(a: var BNU256, by: BNU256, modulus: BNU256,
|
||||
inv: uint64) {.noinit.} =
|
||||
var res: array[4 * 2, uint64]
|
||||
var k: uint64
|
||||
for i in 0..<8:
|
||||
res[i] = 0'u64
|
||||
macDigit(res, 0, by, a[0])
|
||||
macDigit(res, 1, by, a[1])
|
||||
macDigit(res, 2, by, a[2])
|
||||
macDigit(res, 3, by, a[3])
|
||||
for i in 0..<4:
|
||||
k = inv * res[i]
|
||||
macDigit(res, i, modulus, k)
|
||||
a[0] = res[4]
|
||||
a[1] = res[5]
|
||||
a[2] = res[6]
|
||||
a[3] = res[7]
|
||||
|
||||
proc compare*(a: BNU256, b: BNU256): int {.noinit, inline.}=
|
||||
## Compare integers ``a`` and ``b``.
|
||||
## Returns ``-1`` if ``a < b``, ``1`` if ``a > b``, ``0`` if ``a == b``.
|
||||
for i in countdown(3, 0):
|
||||
if a[i] < b[i]:
|
||||
return -1
|
||||
elif a[i] > b[i]:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
proc `<`*(a: BNU256, b: BNU256): bool {.noinit, inline.} =
|
||||
## Return true if `a < b`.
|
||||
result = (compare(a, b) == -1)
|
||||
|
||||
proc `<=`*(a: BNU256, b: BNU256): bool {.noinit, inline.} =
|
||||
## Return true if `a <= b`.
|
||||
result = (compare(a, b) <= 0)
|
||||
|
||||
proc `==`*(a: BNU256, b: BNU256): bool {.noinit, inline.} =
|
||||
## Return true if `a == b`.
|
||||
result = (compare(a, b) == 0)
|
||||
|
||||
proc mul*(a: var BNU256, b: BNU256, modulo: BNU256,
|
||||
inv: uint64) {.inline, noinit.} =
|
||||
## Multiply integer ``a`` by ``b`` (mod ``modulo``) via the Montgomery
|
||||
## multiplication method.
|
||||
mulReduce(a, b, modulo, inv)
|
||||
if a >= modulo:
|
||||
subNoBorrow(a, modulo)
|
||||
|
||||
proc add*(a: var BNU256, b: BNU256, modulo: BNU256) {.inline, noinit.} =
|
||||
## Add integer ``b`` from integer ``a`` (mod ``modulo``).
|
||||
addNoCarry(a, b)
|
||||
if a >= modulo:
|
||||
subNoBorrow(a, modulo)
|
||||
|
||||
proc sub*(a: var BNU256, b: BNU256, modulo: BNU256) {.inline, noinit.} =
|
||||
## Subtract integer ``b`` from integer ``a`` (mod ``modulo``).
|
||||
if a < b:
|
||||
addNoCarry(a, modulo)
|
||||
subNoBorrow(a, b)
|
||||
|
||||
proc neg*(a: var BNU256, modulo: BNU256) {.inline.} =
|
||||
## Turn integer ``a`` into its additive inverse (mod ``modulo``).
|
||||
if a > BNU256.zero():
|
||||
var tmp = modulo
|
||||
subNoBorrow(tmp, a)
|
||||
a = tmp
|
||||
|
||||
proc isEven*(a: BNU256): bool {.inline, noinit.} =
|
||||
## Check if ``a`` is even.
|
||||
((a[0] and 1'u64) == 0'u64)
|
||||
|
||||
proc divrem*(a: BNU512, modulo: BNU256, reminder: var BNU256): Option[BNU256] =
|
||||
## Divides integer ``a`` by ``modulo``, set ``remainder`` to reminder and, if
|
||||
## possible, return quotient smaller than the modulus.
|
||||
var q: BNU256
|
||||
reminder.setZero()
|
||||
result = some[BNU256](q)
|
||||
for i in countdown(511, 0):
|
||||
mul2(reminder)
|
||||
let ret = reminder.setBit(0, a.getBit(i))
|
||||
assert ret
|
||||
if reminder >= modulo:
|
||||
subNoBorrow(reminder, modulo)
|
||||
if result.isSome():
|
||||
if not q.setBit(i, true):
|
||||
result = none[BNU256]()
|
||||
else:
|
||||
result = some[BNU256](q)
|
||||
|
||||
if result.isSome() and result.get() >= modulo:
|
||||
result = none[BNU256]()
|
||||
|
||||
proc into*(t: typedesc[BNU512], c1: BNU256,
|
||||
c0: BNU256, modulo: BNU256): BNU512 =
|
||||
## Return 512bit integer of value ``c1 * modulo + c0``.
|
||||
macDigit(result, 0, modulo, c1[0])
|
||||
macDigit(result, 1, modulo, c1[1])
|
||||
macDigit(result, 2, modulo, c1[2])
|
||||
macDigit(result, 3, modulo, c1[3])
|
||||
var carry = 0'u64
|
||||
for i in 0..<len(result):
|
||||
if len(c0) > i:
|
||||
result[i] = adc(result[i], c0[i], carry)
|
||||
elif carry != 0'u64:
|
||||
result[i] = adc(result[i], 0'u64, carry)
|
||||
else:
|
||||
break
|
||||
assert(carry == 0'u64)
|
||||
|
||||
proc fromBytes*(dst: var BNU256, src: openarray[byte]): bool =
|
||||
## Create 256bit integer from big-endian bytes representation ``src``.
|
||||
## Returns ``true`` if ``dst`` was successfully initialized, ``false``
|
||||
## otherwise.
|
||||
var buffer: array[32, byte]
|
||||
if len(src) == 0:
|
||||
return false
|
||||
let length = if len(src) > 32: 32 else: len(src)
|
||||
copyMem(addr buffer[0], unsafeAddr src[0], length)
|
||||
bigEndian64(addr dst[0], addr buffer[3 * sizeof(uint64)])
|
||||
bigEndian64(addr dst[1], addr buffer[2 * sizeof(uint64)])
|
||||
bigEndian64(addr dst[2], addr buffer[1 * sizeof(uint64)])
|
||||
bigEndian64(addr dst[3], addr buffer[0 * sizeof(uint64)])
|
||||
result = true
|
||||
|
||||
proc fromBytes*(dst: var BNU512, src: openarray[byte]): bool {.noinit.} =
|
||||
## Create 512bit integer form big-endian bytes representation ``src``.
|
||||
## Returns ``true`` if ``dst`` was successfully initialized, ``false``
|
||||
## otherwise.
|
||||
var buffer: array[64, byte]
|
||||
if len(src) == 0:
|
||||
return false
|
||||
let length = if len(src) > 64: 64 else: len(src)
|
||||
copyMem(addr buffer[0], unsafeAddr src[0], length)
|
||||
bigEndian64(addr dst[0], addr buffer[7 * sizeof(uint64)])
|
||||
bigEndian64(addr dst[1], addr buffer[6 * sizeof(uint64)])
|
||||
bigEndian64(addr dst[2], addr buffer[5 * sizeof(uint64)])
|
||||
bigEndian64(addr dst[3], addr buffer[4 * sizeof(uint64)])
|
||||
bigEndian64(addr dst[4], addr buffer[3 * sizeof(uint64)])
|
||||
bigEndian64(addr dst[5], addr buffer[2 * sizeof(uint64)])
|
||||
bigEndian64(addr dst[6], addr buffer[1 * sizeof(uint64)])
|
||||
bigEndian64(addr dst[7], addr buffer[0 * sizeof(uint64)])
|
||||
result = true
|
||||
|
||||
proc fromHexString*(dst: var BNU256, src: string): bool {.inline, noinit.} =
|
||||
## Create 256bit integer from big-endian hexadecimal string
|
||||
## representation ``src``.
|
||||
## Returns ``true`` if ``dst`` was successfully initialized, ``false``
|
||||
## otherwise.
|
||||
result = dst.fromBytes(fromHex(src))
|
||||
|
||||
proc toBytes*(src: BNU256, dst: var openarray[byte]): bool {.noinit.} =
|
||||
## Convert 256bit integer ``src`` to big-endian bytes representation.
|
||||
## Return ``true`` if ``dst`` was successfully set, ``false`` otherwise.
|
||||
if len(dst) < 4 * sizeof(uint64):
|
||||
return false
|
||||
bigEndian64(addr dst[0 * sizeof(uint64)], unsafeAddr src[3])
|
||||
bigEndian64(addr dst[1 * sizeof(uint64)], unsafeAddr src[2])
|
||||
bigEndian64(addr dst[2 * sizeof(uint64)], unsafeAddr src[1])
|
||||
bigEndian64(addr dst[3 * sizeof(uint64)], unsafeAddr src[0])
|
||||
result = true
|
||||
|
||||
proc toBytes*(src: BNU512, dst: var openarray[byte]): bool {.noinit.} =
|
||||
## Convert 512bit integer ``src`` to big-endian bytes representation.
|
||||
## Return ``true`` if ``dst`` was successfully set, ``false`` otherwise.
|
||||
if len(dst) < 8 * sizeof(uint64):
|
||||
return false
|
||||
bigEndian64(addr dst[0 * sizeof(uint64)], unsafeAddr src[7])
|
||||
bigEndian64(addr dst[1 * sizeof(uint64)], unsafeAddr src[6])
|
||||
bigEndian64(addr dst[2 * sizeof(uint64)], unsafeAddr src[5])
|
||||
bigEndian64(addr dst[3 * sizeof(uint64)], unsafeAddr src[4])
|
||||
bigEndian64(addr dst[4 * sizeof(uint64)], unsafeAddr src[3])
|
||||
bigEndian64(addr dst[5 * sizeof(uint64)], unsafeAddr src[2])
|
||||
bigEndian64(addr dst[6 * sizeof(uint64)], unsafeAddr src[1])
|
||||
bigEndian64(addr dst[7 * sizeof(uint64)], unsafeAddr src[0])
|
||||
result = true
|
||||
|
||||
proc toString*(src: BNU256, lowercase = true): string =
|
||||
## Convert 256bit integer ``src`` to big-endian hexadecimal representation.
|
||||
var a: array[4 * sizeof(uint64), byte]
|
||||
discard src.toBytes(a)
|
||||
result = a.toHex(lowercase)
|
||||
|
||||
proc toString*(src: BNU512, lowercase = true): string =
|
||||
## Convert 512bit integer ``src`` to big-endian hexadecimal representation.
|
||||
var a: array[8 * sizeof(uint64), byte]
|
||||
discard src.toBytes(a)
|
||||
result = a.toHex(lowercase)
|
||||
|
||||
proc `$`*(src: BNU256): string =
|
||||
## Return hexadecimal string representation of integer ``src``.
|
||||
result = toString(src, false)
|
||||
|
||||
proc `$`*(src: BNU512): string =
|
||||
## Return hexadecimal string representation of integer ``src``.
|
||||
result = toString(src, false)
|
||||
|
||||
proc setRandom*(a: var BNU256, modulo: BNU256) {.noinit, inline.} =
|
||||
## Set value of integer ``a`` to random value (mod ``modulo``).
|
||||
var r = BNU512.random()
|
||||
discard divrem(r, modulo, a)
|
||||
|
||||
proc random*(t: typedesc[BNU256], modulo: BNU256): BNU256 {.noinit, inline.} =
|
||||
## Return random 256bit integer (mod ``modulo``).
|
||||
result.setRandom(modulo)
|
||||
|
||||
proc invert*(a: var BNU256, modulo: BNU256) =
|
||||
## Turn integer ``a`` into its multiplicative inverse (mod ``modulo``).
|
||||
var u = a
|
||||
var v = modulo
|
||||
var b = BNU256.one()
|
||||
var c = BNU256.zero()
|
||||
|
||||
while u != BNU256.one() and v != BNU256.one():
|
||||
while u.isEven():
|
||||
u.div2()
|
||||
if b.isEven():
|
||||
b.div2()
|
||||
else:
|
||||
b.addNoCarry(modulo)
|
||||
b.div2()
|
||||
while v.isEven():
|
||||
v.div2()
|
||||
if c.isEven():
|
||||
c.div2()
|
||||
else:
|
||||
c.addNoCarry(modulo)
|
||||
c.div2()
|
||||
if u >= v:
|
||||
u.subNoBorrow(v)
|
||||
b.sub(c, modulo)
|
||||
else:
|
||||
v.subNoBorrow(u)
|
||||
c.sub(b, modulo)
|
||||
|
||||
if u == BNU256.one():
|
||||
a = b
|
||||
else:
|
||||
a = c
|
||||
|
||||
iterator bits*(a: BNU256): bool =
|
||||
## Iterate over bits of integer ``a``.
|
||||
for i in countdown(255, 0):
|
||||
yield a.getBit(i)
|
||||
|
||||
iterator pairs*(a: BNU256): tuple[key: int, value: bool] =
|
||||
## Iterate over index and bit value of integer ``a``.
|
||||
var k = 0
|
||||
for i in countdown(255, 0):
|
||||
yield (k, a.getBit(i))
|
||||
inc(k)
|
|
@ -0,0 +1,10 @@
|
|||
# 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, arith, fp, fq2, fq6, fq12
|
||||
export options, arith, fp, fq2, fq6, fq12
|
|
@ -0,0 +1,193 @@
|
|||
# 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 arith, options
|
||||
|
||||
template fieldImplementation(finame, fimodulus, firsquared, fircubed,
|
||||
fionep, fiinv: untyped): untyped {.dirty.} =
|
||||
type finame* = distinct BNU256
|
||||
|
||||
proc setZero*(dst: var finame) {.noinit, inline.} =
|
||||
## Set ``zero`` representation in Fp to ``dst``.
|
||||
dst = finame([0'u64, 0'u64, 0'u64, 0'u64])
|
||||
|
||||
proc isZero*(src: finame): bool {.noinit, inline.} =
|
||||
## Check if ``src`` is ``zero``.
|
||||
result = BNU256(src).isZero()
|
||||
|
||||
proc setOne*(dst: var finame) {.noinit, inline.}=
|
||||
## Set ``one`` representation in Fp to ``dst``.
|
||||
dst = finame(fionep)
|
||||
|
||||
proc zero*(t: typedesc[finame]): finame {.noinit, inline.} =
|
||||
## Return ``zero`` representation in Fp.
|
||||
result.setZero()
|
||||
|
||||
proc one*(t: typedesc[finame]): finame {.noinit, inline.} =
|
||||
## Return ``one`` representation in Fp.
|
||||
result.setOne()
|
||||
|
||||
proc modulus*(t: typedesc[finame]): BNU256 {.noinit, inline} =
|
||||
## Return ``Fp`` modulus.
|
||||
result = fimodulus
|
||||
|
||||
proc setRandom*(dst: var finame) {.noinit, inline.} =
|
||||
## Set ``dst`` to random value
|
||||
var a = BNU256.random(fimodulus)
|
||||
dst = finame(a)
|
||||
|
||||
proc random*(t: typedesc[finame]): finame {.noinit, inline.} =
|
||||
## Return random ``Fp``.
|
||||
result.setRandom()
|
||||
|
||||
proc `+`*(x, y: finame): finame {.noinit, inline.} =
|
||||
## Return result of ``x + y``.
|
||||
result = x
|
||||
add(BNU256(result), BNU256(y), fimodulus)
|
||||
|
||||
proc `+=`*(x: var finame, y: finame) {.noinit, inline.} =
|
||||
## Perform inplace addition ``x = x + y``.
|
||||
add(BNU256(x), BNU256(y), fimodulus)
|
||||
|
||||
proc `-`*(x, y: finame): finame {.noinit, inline.} =
|
||||
## Return result of ``x - y``.
|
||||
result = x
|
||||
sub(BNU256(result), BNU256(y), fimodulus)
|
||||
|
||||
proc `-=`*(x: var finame, y: finame) {.noinit, inline.} =
|
||||
## Perform inplace substraction ``x = x - y``.
|
||||
sub(BNU256(x), BNU256(y), fimodulus)
|
||||
|
||||
proc `*`*(x, y: finame): finame {.noinit, inline.} =
|
||||
## Return result of ``x * y``.
|
||||
result = x
|
||||
mul(BNU256(result), BNU256(y), fimodulus, fiinv)
|
||||
|
||||
proc `*=`*(x: var finame, y: finame) {.noinit, inline.} =
|
||||
## Perform inplace multiplication ``x = x * y``.
|
||||
mul(BNU256(x), BNU256(y), fimodulus, fiinv)
|
||||
|
||||
proc `-`*(x: finame): finame {.noinit, inline.} =
|
||||
## Negotiation of ``x``.
|
||||
result = x
|
||||
neg(BNU256(result), fimodulus)
|
||||
|
||||
proc fromString*(t: typedesc[finame],
|
||||
number: string): finame {.noinit, inline.} =
|
||||
## Convert decimal string representation to ``Fp``.
|
||||
var numis = newSeq[finame](11)
|
||||
var acc = finame.zero()
|
||||
for number in numis.mitems():
|
||||
number = acc
|
||||
acc += finame.one()
|
||||
result.setZero()
|
||||
for ch in number:
|
||||
assert(ch in {'0'..'9'})
|
||||
let idx = ord(ch) - ord('0')
|
||||
result *= numis[10]
|
||||
result += numis[idx]
|
||||
|
||||
proc into*(t: typedesc[BNU256], num: finame): BNU256 =
|
||||
## Convert Fp ``num`` to 256bit integer.
|
||||
result = BNU256(num)
|
||||
mul(result, BNU256.one(), BNU256(fimodulus), fiinv)
|
||||
|
||||
proc init*(t: typedesc[finame], num: BNU256): Option[finame] =
|
||||
## Initialize Fp from 256bit integer ``num``.
|
||||
if num >= BNU256(fimodulus):
|
||||
result = none[finame]()
|
||||
else:
|
||||
var res: finame
|
||||
res = finame(num)
|
||||
mul(BNU256(res), BNU256(firsquared), BNU256(fimodulus), fiinv)
|
||||
result = some[finame](res)
|
||||
|
||||
proc fromBytes*(dst: var finame, src: openarray[byte]): bool {.noinit.} =
|
||||
## Create integer FP/FQ from big-endian bytes representation ``src``.
|
||||
## Returns ``true`` if ``dst`` was successfully initialized, ``false``
|
||||
## otherwise.
|
||||
result = false
|
||||
var bn: BNU256
|
||||
if bn.fromBytes(src):
|
||||
var optr = finame.init(bn)
|
||||
if isSome(optr):
|
||||
dst = optr.get()
|
||||
result = true
|
||||
|
||||
proc toBytes*(src: finame,
|
||||
dst: var openarray[byte]): bool {.noinit, inline.} =
|
||||
## Encode integer FP/FQ to big-endian bytes representation ``dst``.
|
||||
## Returns ``true`` if integer was successfully serialized, ``false``
|
||||
## otherwise.
|
||||
result = BNU256.into(src).toBytes(dst)
|
||||
|
||||
proc fromHexString*(dst: var finame,
|
||||
src: string): bool {.noinit, inline.} =
|
||||
## Create integer FP/FQ from hexadecimal string representation ``src``.
|
||||
## Returns ``true`` if ``dst`` was successfully initialized, ``false``
|
||||
## otherwise.
|
||||
result = false
|
||||
var bn: BNU256
|
||||
if bn.fromHexString(src):
|
||||
var optr = finame.init(bn)
|
||||
if isSome(optr):
|
||||
dst = optr.get()
|
||||
result = true
|
||||
|
||||
proc inverse*(num: finame): Option[finame] =
|
||||
## Perform inversion of ``Fp``.
|
||||
if num.isZero():
|
||||
result = none[finame]()
|
||||
else:
|
||||
var res: BNU256
|
||||
res = BNU256(num)
|
||||
invert(res, BNU256(fimodulus))
|
||||
mul(res, BNU256(fircubed), BNU256(fimodulus), fiinv)
|
||||
result = some[finame](finame(res))
|
||||
|
||||
proc `==`*(a: finame, b: finame): bool {.inline, noinit.} =
|
||||
## Return ``true`` if ``a == b``.
|
||||
result = (BNU256(a) == BNU256(b))
|
||||
|
||||
proc squared*(a: finame): finame {.inline, noinit.} =
|
||||
## Return ``a * a``.
|
||||
result = a * a
|
||||
|
||||
proc pow*(a: finame, by: BNU256): finame {.inline, noinit.} =
|
||||
## Return ``a^by``.
|
||||
result = finame.one()
|
||||
for i in by.bits():
|
||||
result = result.squared()
|
||||
if i:
|
||||
result *= a
|
||||
|
||||
fieldImplementation(
|
||||
FR,
|
||||
[0x43e1f593f0000001'u64, 0x2833e84879b97091'u64,
|
||||
0xb85045b68181585d'u64, 0x30644e72e131a029'u64],
|
||||
[0x1bb8e645ae216da7'u64, 0x53fe3ab1e35c59e3'u64,
|
||||
0x8c49833d53bb8085'u64, 0x0216d0b17f4e44a5'u64],
|
||||
[0x5e94d8e1b4bf0040'u64, 0x2a489cbe1cfbb6b8'u64,
|
||||
0x893cc664a19fcfed'u64, 0x0cf8594b7fcc657c'u64],
|
||||
[0xac96341c4ffffffb'u64, 0x36fc76959f60cd29'u64,
|
||||
0x666ea36f7879462e'u64, 0xe0a77c19a07df2f'u64],
|
||||
0xc2e1f593efffffff'u64
|
||||
)
|
||||
|
||||
fieldImplementation(
|
||||
FQ,
|
||||
[0x3c208c16d87cfd47'u64, 0x97816a916871ca8d'u64,
|
||||
0xb85045b68181585d'u64, 0x30644e72e131a029'u64],
|
||||
[0xf32cfc5b538afa89'u64, 0xb5e71911d44501fb'u64,
|
||||
0x47ab1eff0a417ff6'u64, 0x06d89f71cab8351f'u64],
|
||||
[0xb1cd6dafda1530df'u64, 0x62f210e6a7283db6'u64,
|
||||
0xef7f0b0c0ada0afb'u64, 0x20fd6e902d592544'u64],
|
||||
[0xd35d438dc58f0d9d'u64, 0xa78eb28f5c70b3d'u64,
|
||||
0x666ea36f7879462c'u64, 0xe0a77c19a07df2f'u64],
|
||||
0x87d20782e4866389'u64
|
||||
)
|
|
@ -0,0 +1,309 @@
|
|||
# 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 fq6, fq2, fp, arith
|
||||
|
||||
const frobeniusCoeffsC1: array[4, FQ2] = [
|
||||
FQ2.one(),
|
||||
FQ2(
|
||||
c0: Fq([12653890742059813127'u64, 14585784200204367754'u64,
|
||||
1278438861261381767'u64, 212598772761311868'u64]),
|
||||
c1: Fq([11683091849979440498'u64, 14992204589386555739'u64,
|
||||
15866167890766973222'u64, 1200023580730561873'u64])
|
||||
),
|
||||
FQ2(
|
||||
c0: Fq([14595462726357228530'u64, 17349508522658994025'u64,
|
||||
1017833795229664280'u64, 299787779797702374'u64]),
|
||||
c1: Fq.zero()
|
||||
),
|
||||
FQ2(
|
||||
c0: Fq([3914496794763385213'u64, 790120733010914719'u64,
|
||||
7322192392869644725'u64, 581366264293887267'u64]),
|
||||
c1: Fq([12817045492518885689'u64, 4440270538777280383'u64,
|
||||
11178533038884588256'u64, 2767537931541304486'u64])
|
||||
)
|
||||
]
|
||||
|
||||
type
|
||||
FQ12* = object
|
||||
c0*: FQ6
|
||||
c1*: FQ6
|
||||
|
||||
proc init*(c0, c1: FQ6): FQ12 {.inline, noinit.} =
|
||||
result.c0 = c0
|
||||
result.c1 = c1
|
||||
|
||||
proc zero*(t: typedesc[FQ12]): FQ12 {.inline, noinit.} =
|
||||
result.c0 = FQ6.zero()
|
||||
result.c1 = FQ6.zero()
|
||||
|
||||
proc one*(t: typedesc[FQ12]): FQ12 {.inline, noinit.} =
|
||||
result.c0 = FQ6.one()
|
||||
result.c1 = FQ6.zero()
|
||||
|
||||
proc random*(t: typedesc[FQ12]): FQ12 {.inline, noinit.} =
|
||||
result.c0 = FQ6.random()
|
||||
result.c1 = FQ6.random()
|
||||
|
||||
proc isZero*(x: FQ12): bool {.inline, noinit.} =
|
||||
result = (x.c0.isZero() and x.c1.isZero())
|
||||
|
||||
proc squared*(x: FQ12): FQ12 {.inline, noinit.} =
|
||||
let ab = x.c0 * x.c1
|
||||
result.c0 = (x.c1.mulByNonresidue() + x.c0) * (x.c0 + x.c1) - ab -
|
||||
ab.mulByNonresidue()
|
||||
result.c1 = ab + ab
|
||||
|
||||
proc inverse*(x: FQ12): Option[FQ12] {.inline, noinit.} =
|
||||
let opt = (x.c0.squared() - (x.c1.squared().mulByNonresidue())).inverse()
|
||||
if isSome(opt):
|
||||
let tmp = opt.get()
|
||||
result = some[FQ12](FQ12(c0: x.c0 * tmp, c1: -(x.c1 * tmp)))
|
||||
else:
|
||||
result = none[FQ12]()
|
||||
|
||||
proc `+`*(x, y: FQ12): FQ12 {.noinit, inline.} =
|
||||
## Return result of ``x + y``.
|
||||
result.c0 = x.c0 + y.c0
|
||||
result.c1 = x.c1 + y.c1
|
||||
|
||||
proc `+=`*(x: var FQ12, y: FQ12) {.noinit, inline.} =
|
||||
## Perform inplace addition ``x = x + y``.
|
||||
x.c0 += y.c0
|
||||
x.c1 += y.c1
|
||||
|
||||
proc `-`*(x, y: FQ12): FQ12 {.noinit, inline.} =
|
||||
## Return result of ``x - y``.
|
||||
result.c0 = x.c0 - y.c0
|
||||
result.c1 = x.c1 - y.c1
|
||||
|
||||
proc `-=`*(x: var FQ12, y: FQ12) {.noinit, inline.} =
|
||||
## Perform inplace substraction ``x = x - y``.
|
||||
x.c0 -= y.c0
|
||||
x.c1 -= y.c1
|
||||
|
||||
proc `*`*(x, y: FQ12): FQ12 {.noinit, inline.} =
|
||||
## Return result of ``x * y``.
|
||||
let aa = x.c0 * y.c0
|
||||
let bb = x.c1 * y.c1
|
||||
result.c0 = bb.mulByNonresidue() + aa
|
||||
result.c1 = (x.c0 + x.c1) * (y.c0 + y.c1) - aa - bb
|
||||
|
||||
proc `*=`*(x: var FQ12, y: FQ12) {.noinit, inline.} =
|
||||
## Perform inplace multiplication ``x = x * y``.
|
||||
let aa = x.c0 * y.c0
|
||||
let bb = x.c1 * y.c1
|
||||
let cc = x.c0 + x.c1
|
||||
x.c0 = bb.mulByNonresidue() + aa
|
||||
x.c1 = cc * (y.c0 + y.c1) - aa - bb
|
||||
|
||||
proc `-`*(x: FQ12): FQ12 {.noinit, inline.} =
|
||||
## Negotiation of ``x``.
|
||||
result.c0 = -x.c0
|
||||
result.c1 = -x.c1
|
||||
|
||||
proc pow*(x: FQ12, by: BNU256): FQ12 {.noinit.} =
|
||||
result = FQ12.one()
|
||||
for i in by.bits():
|
||||
result = result.squared()
|
||||
if i:
|
||||
result *= x
|
||||
|
||||
proc pow*(x: FQ12, by: FR): FQ12 {.inline, noinit.} =
|
||||
result = pow(x, BNU256.into(by))
|
||||
|
||||
proc frobeniusMap*(x: FQ12, power: uint64): FQ12 =
|
||||
result.c0 = x.c0.frobeniusMap(power)
|
||||
result.c1 = x.c1.frobeniusMap(power).scale(frobeniusCoeffsC1[power mod 12])
|
||||
|
||||
proc unitaryInverse*(x: FQ12): FQ12 =
|
||||
result.c0 = x.c0
|
||||
result.c1 = -x.c1
|
||||
|
||||
proc cyclotomicSquared*(x: FQ12): FQ12 =
|
||||
var z0 = x.c0.c0
|
||||
var z4 = x.c0.c1
|
||||
var z3 = x.c0.c2
|
||||
var z2 = x.c1.c0
|
||||
var z1 = x.c1.c1
|
||||
var z5 = x.c1.c2
|
||||
|
||||
var tmp = z0 * z1
|
||||
let t0 = (z0 + z1) * (z1.mulByNonresidue() + z0) - tmp - tmp.mulByNonresidue()
|
||||
let t1 = tmp + tmp
|
||||
|
||||
tmp = z2 * z3;
|
||||
let t2 = (z2 + z3) * (z3.mulByNonresidue() + z2) - tmp - tmp.mulByNonresidue()
|
||||
let t3 = tmp + tmp
|
||||
|
||||
tmp = z4 * z5;
|
||||
let t4 = (z4 + z5) * (z5.mulByNonresidue() + z4) - tmp - tmp.mulByNonresidue()
|
||||
let t5 = tmp + tmp
|
||||
|
||||
z0 = t0 - z0
|
||||
z0 = z0 + z0
|
||||
z0 = z0 + t0
|
||||
|
||||
z1 = t1 + z1
|
||||
z1 = z1 + z1
|
||||
z1 = z1 + t1
|
||||
|
||||
tmp = t5.mulByNonresidue()
|
||||
z2 = tmp + z2
|
||||
z2 = z2 + z2
|
||||
z2 = z2 + tmp
|
||||
|
||||
z3 = t4 - z3
|
||||
z3 = z3 + z3
|
||||
z3 = z3 + t4
|
||||
|
||||
z4 = t2 - z4
|
||||
z4 = z4 + z4
|
||||
z4 = z4 + t2
|
||||
|
||||
z5 = t3 + z5
|
||||
z5 = z5 + z5
|
||||
z5 = z5 + t3
|
||||
|
||||
result.c0 = init(z0, z4, z3)
|
||||
result.c1 = init(z2, z1, z5)
|
||||
|
||||
proc cyclotomicPow*(x: FQ12, by: BNU256): FQ12 =
|
||||
result = FQ12.one()
|
||||
var foundOne = false
|
||||
|
||||
for i in by.bits():
|
||||
if foundOne:
|
||||
result = result.cyclotomicSquared()
|
||||
if i:
|
||||
foundOne = true
|
||||
result = x * result
|
||||
|
||||
proc expByNegZ*(x: FQ12): FQ12 =
|
||||
let uconst = BNU256([4965661367192848881'u64, 0'u64, 0'u64, 0'u64])
|
||||
result = x.cyclotomicPow(uconst).unitaryInverse()
|
||||
|
||||
proc finalExpFirstChunk*(x: FQ12): Option[FQ12] =
|
||||
let opt = x.inverse()
|
||||
if isSome(opt):
|
||||
let b = opt.get()
|
||||
let a = x.unitaryInverse()
|
||||
let c = a * b
|
||||
let d = c.frobeniusMap(2)
|
||||
result = some[FQ12](d * c)
|
||||
else:
|
||||
result = none[FQ12]()
|
||||
|
||||
proc finalExpLastChunk*(x: FQ12): FQ12 =
|
||||
let a = x.expByNegZ()
|
||||
let b = a.cyclotomicSquared()
|
||||
let c = b.cyclotomicSquared()
|
||||
let d = c * b
|
||||
|
||||
let e = d.expByNegZ()
|
||||
let f = e.cyclotomicSquared()
|
||||
let g = f.expByNegZ()
|
||||
let h = d.unitaryInverse()
|
||||
let i = g.unitaryInverse()
|
||||
|
||||
let j = i * e
|
||||
let k = j * h
|
||||
let ll = k * b
|
||||
let m = k * e
|
||||
let n = x * m
|
||||
|
||||
let o = ll.frobeniusMap(1)
|
||||
let p = o * n
|
||||
|
||||
let q = k.frobeniusMap(2)
|
||||
let r = q * p
|
||||
|
||||
let s = x.unitaryInverse()
|
||||
let t = s * ll
|
||||
let u = t.frobeniusMap(3)
|
||||
let v = u * r
|
||||
|
||||
result = v
|
||||
|
||||
proc finalExponentiation*(x: FQ12): Option[FQ12] =
|
||||
let opt = x.finalExpFirstChunk()
|
||||
if opt.isSome():
|
||||
result = some[FQ12](opt.get().finalExpLastChunk())
|
||||
else:
|
||||
result = none[FQ12]()
|
||||
|
||||
proc mulBy024*(x: FQ12, ell0, ellvw, ellvv: FQ2): FQ12 =
|
||||
var
|
||||
z0, z1, z2, z3, z4, z5: FQ2
|
||||
x0, x2, x4, d0, d2, d4: FQ2
|
||||
s0, s1, t0, t1, t2, t3, t4: FQ2
|
||||
|
||||
z0 = x.c0.c0
|
||||
z1 = x.c0.c1
|
||||
z2 = x.c0.c2
|
||||
z3 = x.c1.c0
|
||||
z4 = x.c1.c1
|
||||
z5 = x.c1.c2
|
||||
|
||||
x0 = ell0
|
||||
x2 = ellvv
|
||||
x4 = ellvw
|
||||
|
||||
d0 = z0 * x0
|
||||
d2 = z2 * x2
|
||||
d4 = z4 * x4
|
||||
t2 = z0 + z4
|
||||
t1 = z0 + z2
|
||||
s0 = z1 + z3 + z5
|
||||
|
||||
s1 = z1 * x2
|
||||
t3 = s1 + d4
|
||||
t4 = t3.mulByNonresidue() + d0
|
||||
z0 = t4
|
||||
|
||||
t3 = z5 * x4
|
||||
s1 = s1 + t3
|
||||
t3 = t3 + d2
|
||||
t4 = t3.mulByNonresidue()
|
||||
t3 = z1 * x0
|
||||
s1 = s1 + t3
|
||||
t4 = t4 + t3
|
||||
z1 = t4
|
||||
|
||||
t0 = x0 + x2
|
||||
t3 = t1 * t0 - d0 - d2
|
||||
t4 = z3 * x4
|
||||
s1 = s1 + t4
|
||||
t3 = t3 + t4
|
||||
|
||||
t0 = z2 + z4
|
||||
z2 = t3
|
||||
|
||||
t1 = x2 + x4
|
||||
t3 = t0 * t1 - d2 - d4
|
||||
t4 = t3.mulByNonresidue()
|
||||
t3 = z3 * x0
|
||||
s1 = s1 + t3
|
||||
t4 = t4 + t3
|
||||
z3 = t4
|
||||
|
||||
t3 = z5 * x2
|
||||
s1 = s1 + t3
|
||||
t4 = t3.mulByNonresidue()
|
||||
t0 = x0 + x4
|
||||
t3 = t2 * t0 - d0 - d4
|
||||
t4 = t4 + t3
|
||||
z4 = t4
|
||||
|
||||
t0 = x0 + x2 + x4
|
||||
t3 = s0 * t0 - s1
|
||||
z5 = t3
|
||||
|
||||
result.c0 = init(z0, z1, z2)
|
||||
result.c1 = init(z3, z4, z5)
|
|
@ -0,0 +1,149 @@
|
|||
# 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
|
||||
|
||||
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 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)
|
|
@ -0,0 +1,178 @@
|
|||
# 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
|
||||
|
||||
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
|
|
@ -0,0 +1,515 @@
|
|||
# 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 fields, arith, options
|
||||
export fields, arith, options
|
||||
import nimcrypto/utils
|
||||
|
||||
type
|
||||
G1* = object
|
||||
G2* = object
|
||||
|
||||
Point*[T: G1|G2] = object
|
||||
when T is G1:
|
||||
x*, y*, z*: FQ
|
||||
else:
|
||||
x*, y*, z*: FQ2
|
||||
|
||||
AffinePoint*[T: G1|G2] = object
|
||||
when T is G1:
|
||||
x*, y*: FQ
|
||||
else:
|
||||
x*, y*: FQ2
|
||||
|
||||
Coeff*[T: G1|G2] = object
|
||||
when T is G1:
|
||||
b*: FQ
|
||||
else:
|
||||
b*: FQ2
|
||||
|
||||
EllCoeffs* = object
|
||||
ell_0*: FQ2
|
||||
ell_vw*: FQ2
|
||||
ell_vv*: FQ2
|
||||
|
||||
G2Precomp* = object
|
||||
q*: AffinePoint[G2]
|
||||
coeffs*: seq[EllCoeffs]
|
||||
|
||||
const
|
||||
G1One = Point[G1](
|
||||
x: FQ.one(),
|
||||
y: FQ([0xa6ba871b8b1e1b3a'u64, 0x14f1d651eb8e167b'u64,
|
||||
0xccdd46def0f28c58'u64, 0x1c14ef83340fbe5e'u64]),
|
||||
z: FQ.one()
|
||||
)
|
||||
|
||||
G1B = FQ([0x7a17caa950ad28d7'u64, 0x1f6ac17ae15521b9'u64,
|
||||
0x334bea4e696bd284'u64, 0x2a1f6744ce179d8e'u64])
|
||||
|
||||
G2One = Point[G2](
|
||||
x: FQ2(
|
||||
c0: FQ([0x8e83b5d102bc2026'u64, 0xdceb1935497b0172'u64,
|
||||
0xfbb8264797811adf'u64, 0x19573841af96503b'u64]),
|
||||
c1: FQ([0xafb4737da84c6140'u64, 0x6043dd5a5802d8c4'u64,
|
||||
0x09e950fc52a02f86'u64, 0x14fef0833aea7b6b'u64])
|
||||
),
|
||||
y: FQ2(
|
||||
c0: FQ([0x619dfa9d886be9f6'u64, 0xfe7fd297f59e9b78'u64,
|
||||
0xff9e1a62231b7dfe'u64, 0x28fd7eebae9e4206'u64]),
|
||||
c1: FQ([0x64095b56c71856ee'u64, 0xdc57f922327d3cbb'u64,
|
||||
0x55f935be33351076'u64, 0x0da4a0e693fd6482'u64])
|
||||
),
|
||||
z: FQ2.one()
|
||||
)
|
||||
|
||||
G2B = FQ2(
|
||||
c0: FQ([0x3bf938e377b802a8'u64, 0x020b1b273633535d'u64,
|
||||
0x26b7edf049755260'u64, 0x2514c6324384a86d'u64]),
|
||||
c1: FQ([0x38e7ecccd1dcff67'u64, 0x65f0b37d93ce0d3e'u64,
|
||||
0xd749d0dd22ac00aa'u64, 0x0141b9ce4a688d4d'u64])
|
||||
)
|
||||
|
||||
AteLoopCount = BNU256([
|
||||
0x9d797039be763ba8'u64, 0x0000000000000001'u64,
|
||||
0x0000000000000000'u64, 0x0000000000000000'u64
|
||||
])
|
||||
|
||||
TwoInv = FQ([
|
||||
9781510331150239090'u64, 15059239858463337189'u64,
|
||||
10331104244869713732'u64, 2249375503248834476'u64
|
||||
])
|
||||
|
||||
Twist = FQ2NonResidue
|
||||
|
||||
TwistMulByQx = FQ2(
|
||||
c0: FQ([
|
||||
13075984984163199792'u64, 3782902503040509012'u64,
|
||||
8791150885551868305'u64, 1825854335138010348'u64
|
||||
]),
|
||||
c1: FQ([
|
||||
7963664994991228759'u64, 12257807996192067905'u64,
|
||||
13179524609921305146'u64, 2767831111890561987'u64
|
||||
])
|
||||
)
|
||||
|
||||
TwistMulByQy = FQ2(
|
||||
c0: FQ([
|
||||
16482010305593259561'u64, 13488546290961988299'u64,
|
||||
3578621962720924518'u64, 2681173117283399901'u64
|
||||
]),
|
||||
c1: FQ([
|
||||
11661927080404088775'u64, 553939530661941723'u64,
|
||||
7860678177968807019'u64, 3208568454732775116'u64
|
||||
])
|
||||
)
|
||||
|
||||
proc one*[T: G1|G2](t: typedesc[T]): Point[T] {.inline, noinit.} =
|
||||
when T is G1:
|
||||
result = G1One
|
||||
else:
|
||||
result = G2One
|
||||
|
||||
# proc one*(t: typedesc[Gt]): Gt {.inline, noinit.} =
|
||||
# result = FQ12.one()
|
||||
|
||||
proc name*[T: G1|G2](t: typedesc[T]): string {.inline, noinit.} =
|
||||
when T is G1:
|
||||
result = "G1"
|
||||
else:
|
||||
result = "G2"
|
||||
|
||||
proc coeff*[T: G1|G2](t: typedesc[T]): Coeff[T] {.inline, noinit.} =
|
||||
when T is G1:
|
||||
result = G1B
|
||||
else:
|
||||
result = G2B
|
||||
|
||||
proc zero*[T: G1|G2](t: typedesc[T]): Point[T] {.inline, noinit.} =
|
||||
when T is G1:
|
||||
result.x = FQ.zero()
|
||||
result.y = FQ.one()
|
||||
result.z = FQ.zero()
|
||||
else:
|
||||
result.x = FQ2.zero()
|
||||
result.y = FQ2.one()
|
||||
result.z = FQ2.zero()
|
||||
|
||||
proc isZero*[T: G1|G2](p: Point[T]): bool {.inline, noinit.} =
|
||||
result = p.z.isZero()
|
||||
|
||||
proc double*[T: G1|G2](p: Point[T]): Point[T] {.noinit.} =
|
||||
let a = p.x.squared()
|
||||
let b = p.y.squared()
|
||||
let c = b.squared()
|
||||
var d = (p.x + b).squared() - a - c
|
||||
d = d + d
|
||||
let e = a + a + a
|
||||
let f = e.squared()
|
||||
let x3 = f - (d + d)
|
||||
var eightc = c + c
|
||||
eightc = eightc + eightc
|
||||
eightc = eightc + eightc
|
||||
let y1z1 = p.y * p.z
|
||||
result.x = x3
|
||||
result.y = e * (d - x3) - eightc
|
||||
result.z = y1z1 + y1z1
|
||||
|
||||
proc `*`*[T: G1|G2](p: Point[T], by: FR): Point[T] =
|
||||
result = T.zero()
|
||||
var foundOne = false
|
||||
for i in BNU256.into(by).bits():
|
||||
if foundOne:
|
||||
result = result.double()
|
||||
if i:
|
||||
foundOne = true
|
||||
result = result + p
|
||||
|
||||
proc random*[T: G1|G2](t: typedesc[T]): Point[T] {.inline, noinit.} =
|
||||
result = t.one() * FR.random()
|
||||
|
||||
proc `+`*[T: G1|G2](p1, p2: Point[T]): Point[T] {.noinit.} =
|
||||
if p1.isZero():
|
||||
return p2
|
||||
if p2.isZero():
|
||||
return p1
|
||||
|
||||
let z1squared = p1.z.squared()
|
||||
let z2squared = p2.z.squared()
|
||||
let u1 = p1.x * z2squared
|
||||
let u2 = p2.x * z1squared
|
||||
let z1cubed = p1.z * z1squared
|
||||
let z2cubed = p2.z * z2squared
|
||||
let s1 = p1.y * z2cubed
|
||||
let s2 = p2.y * z1cubed
|
||||
|
||||
if u1 == u2 and s1 == s2:
|
||||
result = p1.double()
|
||||
else:
|
||||
let h = u2 - u1
|
||||
let s2minuss1 = s2 - s1
|
||||
let i = (h + h).squared()
|
||||
let j = h * i
|
||||
let r = s2minuss1 + s2minuss1
|
||||
let v = u1 * i
|
||||
let s1j = s1 * j
|
||||
let x3 = r.squared() - j - (v + v)
|
||||
result.x = x3
|
||||
result.y = r * (v - x3) - (s1j + s1j)
|
||||
result.z = ((p1.z + p2.z).squared() - z1squared - z2squared) * h
|
||||
|
||||
proc `-`*[T: G1|G2](p: Point[T]): Point[T] {.inline, noinit.} =
|
||||
if p.isZero():
|
||||
return p
|
||||
else:
|
||||
result.x = p.x
|
||||
result.y = -p.y
|
||||
result.z = p.z
|
||||
|
||||
proc `-`*[T: G1|G2](p: AffinePoint[T]): AffinePoint[T] {.inline, noinit.} =
|
||||
result.x = p.x
|
||||
result.y = -p.y
|
||||
|
||||
proc `-`*[T: G1|G2](p1, p2: Point[T]): Point[T] {.inline, noinit.} =
|
||||
result = p1 + (-p2)
|
||||
|
||||
proc `==`*[T: G1|G2](p1, p2: Point[T]): bool =
|
||||
if p1.isZero():
|
||||
return p2.isZero()
|
||||
if p2.isZero():
|
||||
return false
|
||||
let z1squared = p1.z.squared()
|
||||
let z2squared = p2.z.squared()
|
||||
if (p1.x * z2squared) != (p2.x * z1squared):
|
||||
return false
|
||||
let z1cubed = p1.z * z1squared
|
||||
let z2cubed = p2.z * z2squared
|
||||
if (p1.y * z2cubed) != (p2.y * z1cubed):
|
||||
return false
|
||||
return true
|
||||
|
||||
proc toJacobian*[T: G1|G2](p: AffinePoint[T]): Point[T] {.inline, noinit.} =
|
||||
## Convert affine coordinates' point ``p`` to point.
|
||||
result.x = p.x
|
||||
result.y = p.y
|
||||
when T is G1:
|
||||
result.z = FQ.one()
|
||||
else:
|
||||
result.z = FQ2.one()
|
||||
|
||||
proc toAffine*[T: G1|G2](p: Point[T]): Option[AffinePoint[T]] =
|
||||
## Attempt to convert point ``p`` to affine coordinates.
|
||||
when T is G1:
|
||||
var fone = FQ.one()
|
||||
else:
|
||||
var fone = FQ2.one()
|
||||
|
||||
if p.z.isZero():
|
||||
result = none[AffinePoint[T]]()
|
||||
elif p.z == fone:
|
||||
result = some[AffinePoint[T]](AffinePoint[T](x: p.x, y: p.y))
|
||||
else:
|
||||
let ozinv = p.z.inverse()
|
||||
if isSome(ozinv):
|
||||
let zinv = ozinv.get()
|
||||
var zinvsquared = zinv.squared()
|
||||
result = some[AffinePoint[T]](
|
||||
AffinePoint[T](
|
||||
x: p.x * zinvsquared,
|
||||
y: p.y * (zinvsquared * zinv)
|
||||
)
|
||||
)
|
||||
else:
|
||||
result = none[AffinePoint[T]]()
|
||||
|
||||
proc normalize*(p: var Point[G2]) {.inline, noinit.} =
|
||||
let aopt = p.toAffine()
|
||||
if isSome(aopt):
|
||||
p = aopt.get().toJacobian()
|
||||
else:
|
||||
return
|
||||
|
||||
proc isOnCurve*[T: G1|G2](p: AffinePoint[T]): bool =
|
||||
when T is G1:
|
||||
result = (p.y.squared() == (p.x.squared() * p.x) + G1B)
|
||||
else:
|
||||
result = (p.y.squared() == (p.x.squared() * p.x) + G2B)
|
||||
|
||||
proc mulByQ(p: AffinePoint[G2]): AffinePoint[G2] =
|
||||
result.x = TwistMulByQx * p.x.frobeniusMap(1)
|
||||
result.y = TwistMulByQy * p.y.frobeniusMap(1)
|
||||
|
||||
proc mixedAdditionStepForFlippedML(p: var Point[G2],
|
||||
base: AffinePoint[G2]): EllCoeffs =
|
||||
let d = p.x - p.z * base.x
|
||||
let e = p.y - p.z * base.y
|
||||
let f = d.squared()
|
||||
let g = e.squared()
|
||||
let h = d * f
|
||||
let i = p.x * f
|
||||
let j = p.z * g + h - (i + i)
|
||||
|
||||
p.x = d * j
|
||||
p.y = e * (i - j) - h * p.y
|
||||
p.z = p.z * h
|
||||
|
||||
result.ell_0 = Twist * (e * base.x - d * base.y)
|
||||
result.ell_vv = -e
|
||||
result.ell_vw = d
|
||||
|
||||
proc doublingStepForFlippedML(p: var Point[G2]): EllCoeffs =
|
||||
let a = (p.x * p.y).scale(TwoInv)
|
||||
let b = p.y.squared()
|
||||
let c = p.z.squared()
|
||||
let d = c + c + c
|
||||
let e = G2B * d
|
||||
let f = e + e + e
|
||||
let g = (b + f).scale(TwoInv)
|
||||
let h = (p.y + p.z).squared() - (b + c)
|
||||
let i = e - b
|
||||
let j = p.x.squared()
|
||||
let e_sq = e.squared()
|
||||
|
||||
p.x = a * (b - f)
|
||||
p.y = g.squared() - (e_sq + e_sq + e_sq)
|
||||
p.z = b * h
|
||||
|
||||
result.ell_0 = Twist * i
|
||||
result.ell_vw = -h
|
||||
result.ell_vv = j + j + j
|
||||
|
||||
proc precompute*(p: AffinePoint[G2]): G2Precomp =
|
||||
var r = p.toJacobian()
|
||||
result.coeffs = newSeqOfCap[EllCoeffs](102)
|
||||
var foundOne = false
|
||||
|
||||
for i in AteLoopCount.bits():
|
||||
if not foundOne:
|
||||
foundOne = i
|
||||
continue
|
||||
result.coeffs.add(r.doublingStepForFlippedML())
|
||||
if i:
|
||||
result.coeffs.add(r.mixedAdditionStepForFlippedML(p))
|
||||
|
||||
let q1 = p.mulByQ()
|
||||
let q2 = -(q1.mulByQ())
|
||||
|
||||
result.coeffs.add(r.mixedAdditionStepForFlippedML(q1))
|
||||
result.coeffs.add(r.mixedAdditionStepForFlippedML(q2))
|
||||
result.q = p
|
||||
|
||||
proc millerLoop*(pc: G2Precomp, g1: AffinePoint[G1]): FQ12 =
|
||||
result = FQ12.one()
|
||||
var idx = 0
|
||||
var foundOne = false
|
||||
var c: EllCoeffs
|
||||
for i in AteLoopCount.bits():
|
||||
if not foundOne:
|
||||
foundOne = i
|
||||
continue
|
||||
c = pc.coeffs[idx]
|
||||
inc(idx)
|
||||
result = result.squared().mulBy024(c.ell_0, c.ell_vw.scale(g1.y),
|
||||
c.ell_vv.scale(g1.x))
|
||||
if i:
|
||||
c = pc.coeffs[idx]
|
||||
idx += 1
|
||||
result = result.mulBy024(c.ell_0, c.ell_vw.scale(g1.y),
|
||||
c.ell_vv.scale(g1.x))
|
||||
c = pc.coeffs[idx]
|
||||
idx += 1
|
||||
result = result.mulBy024(c.ell_0, c.ell_vw.scale(g1.y), c.ell_vv.scale(g1.x))
|
||||
c = pc.coeffs[idx]
|
||||
result = result.mulBy024(c.ell_0, c.ell_vw.scale(g1.y), c.ell_vv.scale(g1.x))
|
||||
|
||||
proc pairing*(p: Point[G1], q: Point[G2]): FQ12 {.noinit, inline.} =
|
||||
result = FQ12.one()
|
||||
var optp = p.toAffine()
|
||||
var optq = q.toAffine()
|
||||
if optp.isSome() and optq.isSome():
|
||||
let pc = optq.get().precompute()
|
||||
let ores = finalExponentiation(pc.millerLoop(optp.get()))
|
||||
if ores.isSome():
|
||||
result = ores.get()
|
||||
|
||||
proc toBytes*[T: G1|G2](p: AffinePoint[T], dst: var openarray[byte]): bool =
|
||||
## Encode affine point coordinates (x, y) to big-endian bytes representation
|
||||
## ``dst``.
|
||||
## Returns ``true`` if coordinates was successfully serialized, ``false``
|
||||
## otherwise.
|
||||
when T is G1:
|
||||
if len(dst) >= 64:
|
||||
if p.x.toBytes(toOpenArray(dst, 0, 31)):
|
||||
if p.y.toBytes(toOpenArray(dst, 32, 63)):
|
||||
result = true
|
||||
else:
|
||||
if len(dst) >= 128:
|
||||
if p.x.toBytes(toOpenArray(dst, 0, 63)):
|
||||
if p.y.toBytes(toOpenArray(dst, 64, 127)):
|
||||
result = true
|
||||
|
||||
proc fromBytes*[T: G1|G2](p: var AffinePoint[T], src: openarray[byte]): bool =
|
||||
## Decode affine point coordinates (x, y) from big endian bytes representation
|
||||
## ``src``.
|
||||
## Returns ``true`` if coordinates was successfully serialized, ``false``
|
||||
## otherwise.
|
||||
when T is G1:
|
||||
const
|
||||
nextOffset = 32
|
||||
coeff = G1B
|
||||
var
|
||||
x, y: FQ
|
||||
point: Point[G1]
|
||||
else:
|
||||
const
|
||||
nextOffset = 64
|
||||
coeff = G2B
|
||||
var
|
||||
x, y: FQ2
|
||||
point: Point[G2]
|
||||
|
||||
if len(src) >= nextOffset * 2:
|
||||
if x.fromBytes(src):
|
||||
if y.fromBytes(toOpenArray(src, nextOffset, len(src) - 1)):
|
||||
if y.squared() == (x.squared() * x) + coeff:
|
||||
## Check if point on curve.
|
||||
point.x = x
|
||||
point.y = y
|
||||
when T is G1:
|
||||
point.z = FQ.one()
|
||||
else:
|
||||
point.z = FQ2.one()
|
||||
if (point * (-FR.one())) + point == T.zero():
|
||||
p.x = x
|
||||
p.y = y
|
||||
result = true
|
||||
else:
|
||||
## Point is not in the subgroup
|
||||
discard
|
||||
|
||||
proc fromHexString*[T: G1|G2](p: var AffinePoint[T],
|
||||
src: string): bool {.inline.} =
|
||||
## Decode affine point coordinates (x, y) from hexadecimal string
|
||||
## representation ``src``.
|
||||
## Returns ``true`` if coordinates was successfully serialized, ``false``
|
||||
## otherwise.
|
||||
## ``Note:`` Can raise exception on malformed hexadecimal string.
|
||||
result = fromBytes(p, fromHex(src))
|
||||
|
||||
proc toHexString*[T: G1|G2](p: AffinePoint[T],
|
||||
lowercase = false): string {.inline.} =
|
||||
## Encode affine point coordinates (x, y) and return hexadecimal string
|
||||
## representation.
|
||||
when T is G1:
|
||||
var buffer: array[64, byte]
|
||||
else:
|
||||
var buffer: array[128, byte]
|
||||
if toBytes(p, buffer):
|
||||
result = toHex(buffer, lowercase)
|
||||
|
||||
proc toBytes*[T: G1|G2](p: Point[T],
|
||||
dst: var openarray[byte]): bool {.inline.} =
|
||||
## Encode point coordinates (x, y, z) to big-endian bytes representation
|
||||
## ``dst``.
|
||||
## Returns ``true`` if coordinates was successfully serialized, ``false``
|
||||
## otherwise.
|
||||
when T is G1:
|
||||
const outputSize = 64
|
||||
else:
|
||||
const outputSize = 128
|
||||
if p.isZero():
|
||||
if len(dst) >= 1:
|
||||
dst[0] = 0x00'u8
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
else:
|
||||
if len(dst) >= 1 + outputSize:
|
||||
var apo = p.toAffine()
|
||||
if isSome(apo):
|
||||
dst[0] = 0x04'u8
|
||||
result = apo.get().toBytes(toOpenArray(dst, 1, outputSize))
|
||||
|
||||
proc fromBytes*[T: G1|G2](p: var Point[T],
|
||||
src: openarray[byte]): bool {.inline.} =
|
||||
## Decode affine point coordinates (x, y, z) from big endian bytes
|
||||
## representation ``src``.
|
||||
## Returns ``true`` if coordinates was successfully serialized, ``false``
|
||||
## otherwise.
|
||||
when T is G1:
|
||||
const inputSize = 64
|
||||
else:
|
||||
const inputSize = 128
|
||||
if len(src) > 0:
|
||||
if src[0] == 0x00'u8:
|
||||
p = T.zero()
|
||||
result = true
|
||||
elif src[0] == 0x04'u8:
|
||||
if len(src) >= inputSize + 1:
|
||||
var ap: AffinePoint[T]
|
||||
if ap.fromBytes(toOpenArray(src, 1, inputSize)):
|
||||
p = toJacobian(ap)
|
||||
result = true
|
||||
|
||||
proc fromHexString*[T: G1|G2](p: var Point[T], src: string): bool {.inline.} =
|
||||
## Decode point coordinates (x, y, z) from hexadecimal string
|
||||
## representation ``src``.
|
||||
## Returns ``true`` if coordinates was successfully serialized, ``false``
|
||||
## otherwise.
|
||||
## ``Note:`` Can raise exception on malformed hexadecimal string.
|
||||
result = fromBytes(p, fromHex(src))
|
||||
|
||||
proc toHexString*[T: G1|G2](p: Point[T], lowercase = false): string {.inline.} =
|
||||
## Encode affine point coordinates (x, y, z) and return hexadecimal string
|
||||
## representation.
|
||||
when T is G1:
|
||||
var buffer: array[64 + 1, byte]
|
||||
else:
|
||||
var buffer: array[128 + 1, byte]
|
||||
if toBytes(p, buffer):
|
||||
result = toHex(buffer, lowercase)
|
|
@ -0,0 +1,186 @@
|
|||
import unittest
|
||||
import ../bncurve/arith
|
||||
|
||||
when isMainModule:
|
||||
let modulo = [
|
||||
0x3c208c16d87cfd47'u64, 0x97816a916871ca8d'u64,
|
||||
0xb85045b68181585d'u64, 0x30644e72e131a029'u64
|
||||
]
|
||||
|
||||
suite "Modular arithmetic test suite":
|
||||
test "[256] Serialize/Deserialize tests":
|
||||
for i in 0..<100:
|
||||
var c0, c1, c2: BNU256
|
||||
var c0b: array[4 * sizeof(uint64), byte]
|
||||
c0 = BNU256.random(modulo)
|
||||
var c0s = c0.toString()
|
||||
check:
|
||||
c0.toBytes(c0b) == true
|
||||
c1.fromBytes(c0b) == true
|
||||
c2.fromHexString(c0s) == true
|
||||
c0 == c1
|
||||
c0 == c2
|
||||
|
||||
test "[512] Serialize/Deserialize tests":
|
||||
for i in 0..<100:
|
||||
var cb: BNU512
|
||||
var cbs: array[8 * sizeof(uint64), byte]
|
||||
var e0 = BNU256.random(modulo)
|
||||
var e1 = BNU256.random(modulo)
|
||||
var bb12 = BNU512.into(e1, e0, modulo)
|
||||
check:
|
||||
bb12.toBytes(cbs) == true
|
||||
cb.fromBytes(cbs) == true
|
||||
var c0: BNU256
|
||||
var c1opt = cb.divrem(modulo, c0)
|
||||
check:
|
||||
isSome(c1opt) == true
|
||||
c1opt.get() == e1
|
||||
c0 == e0
|
||||
|
||||
test "Setting bits":
|
||||
var moduloS = [
|
||||
0xfffffffffffffffff'u64, 0xfffffffffffffffff'u64,
|
||||
0xfffffffffffffffff'u64, 0xfffffffffffffffff'u64
|
||||
]
|
||||
var a = BNU256.random(moduloS)
|
||||
var e = BNU256.zero()
|
||||
for i, b in a.pairs():
|
||||
let ret = e.setBit(255 - i, b)
|
||||
doAssert ret
|
||||
check e == a
|
||||
|
||||
test "fromValue & divrem on random numbers":
|
||||
for i in 0..<100:
|
||||
var nc0: BNU256
|
||||
var nc1: Option[BNU256]
|
||||
var c0 = BNU256.random(modulo)
|
||||
var c1 = BNU256.random(modulo)
|
||||
var c1q = BNU512.into(c1, c0, modulo)
|
||||
nc1 = c1q.divrem(modulo, nc0)
|
||||
check:
|
||||
nc1.get() == c1
|
||||
nc0 == c0
|
||||
|
||||
test "Modulus should become 1*q + 0":
|
||||
var a = [
|
||||
0x3c208c16d87cfd47'u64, 0x97816a916871ca8d'u64,
|
||||
0xb85045b68181585d'u64, 0x30644e72e131a029'u64,
|
||||
0'u64, 0'u64, 0'u64, 0'u64
|
||||
]
|
||||
|
||||
var c0, c2: BNU256
|
||||
var c1: Option[BNU256]
|
||||
c1 = a.divrem(modulo, c0)
|
||||
c2 = c1.get()
|
||||
check:
|
||||
c2 == BNU256.one()
|
||||
c0 == BNU256.zero()
|
||||
c2 == BNU256.one()
|
||||
c0 == BNU256.zero()
|
||||
|
||||
test "Modulus squared minus 1 should be (q-1) q + q-1":
|
||||
let a = [
|
||||
0x3b5458a2275d69b0'u64, 0xa602072d09eac101'u64,
|
||||
0x4a50189c6d96cadc'u64, 0x04689e957a1242c8'u64,
|
||||
0x26edfa5c34c6b38d'u64, 0xb00b855116375606'u64,
|
||||
0x599a6f7c0348d21c'u64, 0x0925c4b8763cbf9c'u64
|
||||
]
|
||||
let expect = [
|
||||
0x3c208c16d87cfd46'u64, 0x97816a916871ca8d'u64,
|
||||
0xb85045b68181585d'u64, 0x30644e72e131a029'u64
|
||||
]
|
||||
var c0, c2: BNU256
|
||||
var c1: Option[BNU256]
|
||||
c1 = a.divrem(modulo, c0)
|
||||
c2 = c1.get()
|
||||
check:
|
||||
c0 == expect
|
||||
c2 == expect
|
||||
|
||||
test "Modulus squared minus 2 should be (q-1) q + q-2":
|
||||
let a = [
|
||||
0x3b5458a2275d69af'u64, 0xa602072d09eac101'u64,
|
||||
0x4a50189c6d96cadc'u64, 0x04689e957a1242c8'u64,
|
||||
0x26edfa5c34c6b38d'u64, 0xb00b855116375606'u64,
|
||||
0x599a6f7c0348d21c'u64, 0x0925c4b8763cbf9c'u64
|
||||
]
|
||||
let expectc1 = [
|
||||
0x3c208c16d87cfd46'u64, 0x97816a916871ca8d'u64,
|
||||
0xb85045b68181585d'u64, 0x30644e72e131a029'u64
|
||||
]
|
||||
let expectc0 = [
|
||||
0x3c208c16d87cfd45'u64, 0x97816a916871ca8d'u64,
|
||||
0xb85045b68181585d'u64, 0x30644e72e131a029'u64
|
||||
]
|
||||
var c0, c2: BNU256
|
||||
var c1: Option[BNU256]
|
||||
c1 = a.divrem(modulo, c0)
|
||||
c2 = c1.get()
|
||||
check:
|
||||
c0 == expectc0
|
||||
c2 == expectc1
|
||||
|
||||
test "Ridiculously large number should fail":
|
||||
let a = [
|
||||
0xfffffffffffffffff'u64, 0xfffffffffffffffff'u64,
|
||||
0xfffffffffffffffff'u64, 0xfffffffffffffffff'u64,
|
||||
0xfffffffffffffffff'u64, 0xfffffffffffffffff'u64,
|
||||
0xfffffffffffffffff'u64, 0xfffffffffffffffff'u64
|
||||
]
|
||||
let expectc0 = [
|
||||
0xf32cfc5b538afa88'u64, 0xb5e71911d44501fb'u64,
|
||||
0x47ab1eff0a417ff6'u64, 0x06d89f71cab8351f'u64
|
||||
]
|
||||
var c0: BNU256
|
||||
var c1: Option[BNU256]
|
||||
c1 = a.divrem(modulo, c0)
|
||||
check:
|
||||
c1.isNone() == true
|
||||
c0 == expectc0
|
||||
|
||||
test "Modulus squared should fail":
|
||||
let a = [
|
||||
0x3b5458a2275d69b1'u64, 0xa602072d09eac101'u64,
|
||||
0x4a50189c6d96cadc'u64, 0x04689e957a1242c8'u64,
|
||||
0x26edfa5c34c6b38d'u64, 0xb00b855116375606'u64,
|
||||
0x599a6f7c0348d21c'u64, 0x0925c4b8763cbf9c'u64
|
||||
]
|
||||
var c0: BNU256
|
||||
var c1: Option[BNU256]
|
||||
c1 = a.divrem(modulo, c0)
|
||||
check:
|
||||
c1.isNone() == true
|
||||
c0.isZero() == true
|
||||
|
||||
test "Modulus squared plus one should fail":
|
||||
let a = [
|
||||
0x3b5458a2275d69b2'u64, 0xa602072d09eac101'u64,
|
||||
0x4a50189c6d96cadc'u64, 0x04689e957a1242c8'u64,
|
||||
0x26edfa5c34c6b38d'u64, 0xb00b855116375606'u64,
|
||||
0x599a6f7c0348d21c'u64, 0x0925c4b8763cbf9c'u64
|
||||
]
|
||||
var c0: BNU256
|
||||
var c1: Option[BNU256]
|
||||
c1 = a.divrem(modulo, c0)
|
||||
check:
|
||||
c1.isNone() == true
|
||||
c0 == BNU256.one()
|
||||
|
||||
test "Fr modulus masked off is valid":
|
||||
let a = [
|
||||
0xffffffffffffffff'u64, 0xffffffffffffffff'u64,
|
||||
0xffffffffffffffff'u64, 0xffffffffffffffff'u64,
|
||||
0xffffffffffffffff'u64, 0xffffffffffffffff'u64,
|
||||
0xffffffffffffffff'u64, 0x07ffffffffffffff'u64
|
||||
]
|
||||
let moduloFr = [
|
||||
0x43e1f593f0000001'u64, 0x2833e84879b97091'u64,
|
||||
0xb85045b68181585d'u64, 0x30644e72e131a029'u64
|
||||
]
|
||||
var c0, c2: BNU256
|
||||
var c1: Option[BNU256]
|
||||
c1 = a.divrem(moduloFr, c0)
|
||||
check:
|
||||
c1.get() < moduloFr
|
||||
c0 < moduloFr
|
|
@ -0,0 +1,562 @@
|
|||
import unittest
|
||||
import nimcrypto/utils
|
||||
import ../bncurve/fields
|
||||
|
||||
proc randomSquaring*[T](): bool =
|
||||
for i in 0..100:
|
||||
var a = T.random()
|
||||
if a * a != a.squared():
|
||||
return false
|
||||
|
||||
var cur = T.zero()
|
||||
for i in 0..100:
|
||||
if cur.squared() != cur * cur:
|
||||
return false
|
||||
cur = cur + T.one()
|
||||
|
||||
return true
|
||||
|
||||
proc zeroTest*[T](): bool =
|
||||
if -T.zero() != T.zero():
|
||||
return false
|
||||
if (-T.one() + T.one()) != T.zero():
|
||||
return false
|
||||
if (T.zero() - T.zero()) != T.zero():
|
||||
return false
|
||||
return true
|
||||
|
||||
proc canInvert*[T](): bool =
|
||||
var a = T.one()
|
||||
for i in 0..100:
|
||||
if (a * a.inverse().get()) != T.one():
|
||||
return false
|
||||
a = a + T.one()
|
||||
a = -T.one()
|
||||
for i in 0..100:
|
||||
if (a * a.inverse().get()) != T.one():
|
||||
return false
|
||||
a = a - T.one()
|
||||
return true
|
||||
|
||||
proc randomElementInverse*[T](): bool =
|
||||
for i in 0..100:
|
||||
var a = T.random()
|
||||
if a.inverse().get() * a != T.one():
|
||||
return false
|
||||
var b = T.random()
|
||||
if a * b * a.inverse().get() != b:
|
||||
return false
|
||||
return true
|
||||
|
||||
proc randomElementMultiplication*[T](): bool =
|
||||
for i in 0..250:
|
||||
var a = T.random()
|
||||
var b = T.random()
|
||||
var c = T.random()
|
||||
result = ((a * b) * c == a * (b * c))
|
||||
|
||||
proc randomElementEval*[T](): bool =
|
||||
for i in 0..100:
|
||||
var a = T.random()
|
||||
var b = T.random()
|
||||
var c = T.random()
|
||||
var d = T.random()
|
||||
|
||||
var lhs = (a + b) * (c + d)
|
||||
var rhs = (a * c) + (b * c) + (a * d) + (b * d)
|
||||
if lhs != rhs:
|
||||
return false
|
||||
return true
|
||||
|
||||
proc randomElementASN*[T](): bool =
|
||||
for i in 0..100:
|
||||
var a = T.random()
|
||||
if a + (-a) != T.zero():
|
||||
return false
|
||||
|
||||
for i in 0..10:
|
||||
var a = T.random()
|
||||
var r = T.random()
|
||||
var b = a + r
|
||||
var c = T.random()
|
||||
var d = c + r
|
||||
|
||||
for m in 0..10:
|
||||
let r0 = T.random()
|
||||
a += r0
|
||||
b += r0
|
||||
c = c + r0
|
||||
d = d + r0
|
||||
let r1 = T.random()
|
||||
a -= r1
|
||||
b -= r1
|
||||
c = c - r1
|
||||
d = d - r1
|
||||
let r2 = T.random()
|
||||
a += (-(-r2))
|
||||
b += (-(-r2))
|
||||
c = c + (-(-r2))
|
||||
d = d + (-(-r2))
|
||||
let r3 = T.random()
|
||||
a -= r3
|
||||
b += -r3
|
||||
c = c - r3
|
||||
d = d + (-r3)
|
||||
let r4 = T.random()
|
||||
a += -r4
|
||||
b -= r4
|
||||
c = c + (-r4)
|
||||
d = d - r4
|
||||
b -= r
|
||||
d = d - r
|
||||
|
||||
if a != b or c != d:
|
||||
return false
|
||||
return true
|
||||
|
||||
proc testCyclotomicExp(): bool =
|
||||
var orig = FQ12(
|
||||
c0: FQ6(
|
||||
c0: FQ2(
|
||||
c0: FQ.fromString("2259924035228092997691937637688451143058635253053054071159756458902878894295"),
|
||||
c1: FQ.fromString("13145690032701362144460254305183927872683620413225364127064863863535255135244")
|
||||
),
|
||||
c1: FQ2(
|
||||
c0: FQ.fromString("9910063591662383599552477067956819406417086889312288278252482503717089428441"),
|
||||
c1: FQ.fromString("537414042055419261990282459138081732565514913399498746664966841152381183961")
|
||||
),
|
||||
c2: FQ2(
|
||||
c0: FQ.fromString("15311812409497308894370893420777496684951030254049554818293571309705780605004"),
|
||||
c1: FQ.fromString("13657107176064455789881282546557276003626320193974643644160350907227082365810")
|
||||
)
|
||||
),
|
||||
c1: FQ6(
|
||||
c0: FQ2(
|
||||
c0: FQ.fromString("4913017949003742946864670837361832856526234260447029873580022776602534856819"),
|
||||
c1: FQ.fromString("7834351480852267338070670220119081676575418514182895774094743209915633114041")
|
||||
),
|
||||
c1: FQ2(
|
||||
c0: FQ.fromString("12837298223308203788092748646758194441270207338661891973231184407371206766993"),
|
||||
c1: FQ.fromString("12756474445699147370503225379431475413909971718057034061593007812727141391799")
|
||||
),
|
||||
c2: FQ2(
|
||||
c0: FQ.fromString("9473802207170192255373153510655867502408045964296373712891954747252332944018"),
|
||||
c1: FQ.fromString("4583089109360519374075173304035813179013579459429335467869926761027310749713")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
var expected = FQ12(
|
||||
c0: FQ6(
|
||||
c0: FQ2(
|
||||
c0: FQ.fromString("14722956046055152398903846391223329501345567382234608299399030576415080188350"),
|
||||
c1: FQ.fromString("14280703280777926697010730619606819467080027543707671882210769811674790473417")
|
||||
),
|
||||
c1: FQ2(
|
||||
c0: FQ.fromString("19969875076083990244184003223190771301761436396530543002586073549972410735411"),
|
||||
c1: FQ.fromString("10717335566913889643303549252432531178405520196706173198634734518494041323243")
|
||||
),
|
||||
c2: FQ2(
|
||||
c0: FQ.fromString("6063612626166484870786832843320782567259894784043383626084549455432890717937"),
|
||||
c1: FQ.fromString("17089783040131779205038789608891431427943860868115199598200376195935079808729")
|
||||
)
|
||||
),
|
||||
c1: FQ6(
|
||||
c0: FQ2(
|
||||
c0: FQ.fromString("10029863438921507421569931792104023129735006154272482043027653425575205672906"),
|
||||
c1: FQ.fromString("6406252222753462799887280578845937185621081001436094637606245493619821542775")
|
||||
),
|
||||
c1: FQ2(
|
||||
c0: FQ.fromString("1048245462913506652602966692378792381004227332967846949234978073448561848050"),
|
||||
c1: FQ.fromString("1444281375189053827455518242624554285012408033699861764136810522738182087554")
|
||||
),
|
||||
c2: FQ2(
|
||||
c0: FQ.fromString("8839610992666735109106629514135300820412539620261852250193684883379364789120"),
|
||||
c1: FQ.fromString("11347360242067273846784836674906058940820632082713814508736182487171407730718")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
let e = orig.expByNegZ()
|
||||
result = (e == expected)
|
||||
|
||||
proc fq12TestVector(): bool =
|
||||
let start = FQ12(
|
||||
c0: FQ6(
|
||||
c0: FQ2(
|
||||
c0: FQ.fromString("19797905000333868150253315089095386158892526856493194078073564469188852136946"),
|
||||
c1: FQ.fromString("10509658143212501778222314067134547632307419253211327938344904628569123178733")
|
||||
),
|
||||
c1: FQ2(
|
||||
c0: FQ.fromString("208316612133170645758860571704540129781090973693601051684061348604461399206"),
|
||||
c1: FQ.fromString("12617661120538088237397060591907161689901553895660355849494983891299803248390")
|
||||
),
|
||||
c2: FQ2(
|
||||
c0: FQ.fromString("2897490589776053688661991433341220818937967872052418196321943489809183508515"),
|
||||
c1: FQ.fromString("2730506433347642574983433139433778984782882168213690554721050571242082865799")
|
||||
)
|
||||
),
|
||||
c1: FQ6(
|
||||
c0: FQ2(
|
||||
c0: FQ.fromString("17870056122431653936196746815433147921488990391314067765563891966783088591110"),
|
||||
c1: FQ.fromString("14314041658607615069703576372547568077123863812415914883625850585470406221594")
|
||||
),
|
||||
c1: FQ2(
|
||||
c0: FQ.fromString("10123533891707846623287020000407963680629966110211808794181173248765209982878"),
|
||||
c1: FQ.fromString("5062091880848845693514855272640141851746424235009114332841857306926659567101")
|
||||
),
|
||||
c2: FQ2(
|
||||
c0: FQ.fromString("9839781502639936537333620974973645053542086898304697594692219798017709586567"),
|
||||
c1: FQ.fromString("1583892292110602864638265389721494775152090720173641072176370350017825640703")
|
||||
)
|
||||
)
|
||||
)
|
||||
let expect = FQ12(
|
||||
c0: FQ6(
|
||||
c0: FQ2(
|
||||
c0: FQ.fromString("18388750939593263065521177085001223024106699964957029146547831509155008229833"),
|
||||
c1: FQ.fromString("18370529854582635460997127698388761779167953912610241447912705473964014492243")
|
||||
),
|
||||
c1: FQ2(
|
||||
c0: FQ.fromString("3691824277096717481466579496401243638295254271265821828017111951446539785268"),
|
||||
c1: FQ.fromString("20513494218085713799072115076991457239411567892860153903443302793553884247235")
|
||||
),
|
||||
c2: FQ2(
|
||||
c0: FQ.fromString("12214155472433286415803224222551966441740960297013786627326456052558698216399"),
|
||||
c1: FQ.fromString("10987494248070743195602580056085773610850106455323751205990078881956262496575")
|
||||
)
|
||||
),
|
||||
c1: FQ6(
|
||||
c0: FQ2(
|
||||
c0: FQ.fromString("5134522153456102954632718911439874984161223687865160221119284322136466794876"),
|
||||
c1: FQ.fromString("20119236909927036376726859192821071338930785378711977469360149362002019539920")
|
||||
),
|
||||
c1: FQ2(
|
||||
c0: FQ.fromString("8839766648621210419302228913265679710586991805716981851373026244791934012854"),
|
||||
c1: FQ.fromString("9103032146464138788288547957401673544458789595252696070370942789051858719203")
|
||||
),
|
||||
c2: FQ2(
|
||||
c0: FQ.fromString("10378379548636866240502412547812481928323945124508039853766409196375806029865"),
|
||||
c1: FQ.fromString("9021627154807648093720460686924074684389554332435186899318369174351765754041")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
var next = start
|
||||
for i in 0..<100:
|
||||
next = next * start
|
||||
|
||||
var cpy = next
|
||||
for i in 0..<10:
|
||||
next = next.squared()
|
||||
|
||||
for i in 0..<10:
|
||||
next = next + start
|
||||
next = next - cpy
|
||||
next = -next
|
||||
|
||||
next = next.squared()
|
||||
result = (expect == next)
|
||||
|
||||
proc fpSerializeTests[T](): bool =
|
||||
when (T is FQ) or (T is FR):
|
||||
var buffer: array[32, byte]
|
||||
elif (T is FQ2):
|
||||
var buffer: array[64, byte]
|
||||
else:
|
||||
{.fatal.}
|
||||
|
||||
for i in 0..<1000:
|
||||
var e = T.random()
|
||||
zeroMem(addr buffer[0], sizeof(buffer))
|
||||
if not e.toBytes(buffer):
|
||||
return false
|
||||
var a: T
|
||||
if not a.fromBytes(buffer):
|
||||
return false
|
||||
if a != e:
|
||||
return false
|
||||
return true
|
||||
|
||||
proc fq2SerializeTestVectors(): bool =
|
||||
const vectors = [
|
||||
FQ2(
|
||||
c0: FQ([12685471316754074400'u64, 5151117139186389981'u64,
|
||||
1811926512010801501'u64, 2926027770199945729'u64]),
|
||||
c1: FQ([13288357145490715372'u64, 8465179270531902744'u64,
|
||||
2331932027798174928'u64, 1169568334929779847'u64])
|
||||
),
|
||||
FQ2(
|
||||
c0: FQ([6571363706651148129'u64, 12259671536166748744'u64,
|
||||
13297153216522874336'u64, 3368736813872212066'u64]),
|
||||
c1: FQ([7356918428694088001'u64, 13325610168162790738'u64,
|
||||
11761401944674591087'u64, 2142266911265180485'u64])
|
||||
),
|
||||
FQ2(
|
||||
c0: FQ([12770271250542491457'u64, 5841829129088508933'u64,
|
||||
5021659154182959822'u64, 765728708107386899'u64]),
|
||||
c1: FQ([9814770014224857768'u64, 169926129335489937'u64,
|
||||
4476430648250845846'u64, 575721800450622933'u64])
|
||||
),
|
||||
FQ2(
|
||||
c0: FQ([10535443743532733005'u64, 18354663162560926093'u64,
|
||||
3005889269269496788'u64, 892863378917010121'u64]),
|
||||
c1: FQ([9912639056721134596'u64, 6115953886839683024'u64,
|
||||
4097812286267812943'u64, 1337629367136352970'u64])
|
||||
),
|
||||
FQ2(
|
||||
c0: FQ([7658679475413450244'u64, 11440992707440007515'u64,
|
||||
16146061400040738154'u64, 991671862947387812'u64]),
|
||||
c1: FQ([2385857951922426638'u64, 6278331068203224119'u64,
|
||||
8247542493832618243'u64, 2945883060694238627'u64])
|
||||
)
|
||||
]
|
||||
|
||||
const expects = [
|
||||
"06b812bee59693d4f9f18dc46c55afe42fc5c18965669316117850ca22f55ffa44dda4f58baf6cdf629ecacae4a810098fc7d68a6bfcd200ca59322e37a4be3c",
|
||||
"00a41dd99c355e6984dedfc9c6752cd22b6d4d70283a128e4399734fbaa715724e0494d2d0cc7b0c71bda29d304a60cf6b3a69e366a3d50d80bfe441192d778d",
|
||||
"08f943db03ed61e8f2633740bdc071b76c27547891fe90d56776f9ef2a16de98dfd7d0a481fd5efb55374ea3762d879d226ac9bf7c0b347bae142e27f97d03ed",
|
||||
"068744cde0af982bff29d66a0e5799e78b350216ce53da6d828ca64d94bcd482af8816b7cad0dea041604d5b3ee5ddf2c5b65fc394e1752f6fa52133547a44bc",
|
||||
"09042d4acda2f2ff75073700783010461c5250f10724a0c27ecd295b2bda961245c9a740d3d8de3dbf6ed4fe142ee5480bd96a70d9a4442385718c4995b04b8b"
|
||||
]
|
||||
|
||||
var buffer: array[64, byte]
|
||||
for i in 0..<len(vectors):
|
||||
zeroMem(addr buffer[0], sizeof(buffer))
|
||||
if not vectors[i].toBytes(buffer):
|
||||
return false
|
||||
var expect = fromHex(expects[i])
|
||||
if not equalMem(addr expect[0], addr buffer[0], sizeof(buffer)):
|
||||
return false
|
||||
var c: FQ2
|
||||
if c.fromBytes(buffer) != true:
|
||||
return false
|
||||
if c != vectors[i]:
|
||||
return false
|
||||
return true
|
||||
|
||||
proc frSerializeTestVectors(): bool =
|
||||
const vectors = [
|
||||
FR([17421400499845239983'u64, 6997355861326767820'u64,
|
||||
8120099025258387513'u64, 3183707257070674626'u64]),
|
||||
FR([2146638237245267213'u64, 5090456461755122866'u64,
|
||||
6235019329087538353'u64, 387017393791451532'u64]),
|
||||
FR([6344330946110213979'u64, 4581536139297704744'u64,
|
||||
16303670869942326496'u64, 2666106878953846273'u64]),
|
||||
FR([8748641423870480081'u64, 5579982342510408473'u64,
|
||||
8096786847344710301'u64, 194588591521887053'u64]),
|
||||
FR([13962585249620634127'u64, 12179982421793366287'u64,
|
||||
16590787540748934681'u64, 1292188281347940190'u64])
|
||||
]
|
||||
|
||||
const expects = [
|
||||
"11177bed2bc11734f04d9c5ef4724e062835e514dc7142d7ea9c41758d16f8a0",
|
||||
"2619ea8400189f81213d2f1c29c4372ab5a91be78df5b1f2649827138a1d8401",
|
||||
"24f582ad30f718ecccbe241b94d826adb75f3aa9103deed3c7e183b06979bf1f",
|
||||
"22efbafeb86bd66aa38389b5ff513384bae6de53269fafd42a8a614b3d275e56",
|
||||
"03a880d889b5b4cf45376207b13d6c007c6efe0338f9490ab83938f20bd444b2"
|
||||
]
|
||||
var buffer: array[32, byte]
|
||||
for i in 0..<len(vectors):
|
||||
zeroMem(addr buffer[0], sizeof(buffer))
|
||||
if not vectors[i].toBytes(buffer):
|
||||
return false
|
||||
var expect = fromHex(expects[i])
|
||||
if not equalMem(addr expect[0], addr buffer[0], sizeof(buffer)):
|
||||
return false
|
||||
var c: FR
|
||||
if c.fromBytes(buffer) != true:
|
||||
return false
|
||||
if c != vectors[i]:
|
||||
return false
|
||||
return true
|
||||
|
||||
proc fqSerializeTestVectors(): bool =
|
||||
const vectors = [
|
||||
FQ([12123287589963276695'u64, 17077283578393155025'u64,
|
||||
18124373372772101378'u64, 846421381194958693'u64]),
|
||||
FQ([17853748202411400943'u64, 2656002062984499858'u64,
|
||||
10048626202887305070'u64, 694231139270692630'u64]),
|
||||
FQ([14471564705950005567'u64, 18111991644968140513'u64,
|
||||
17814103556911721998'u64, 92110366780417983'u64]),
|
||||
FQ([2989648722487476748'u64, 6723225646291704123'u64,
|
||||
11622908385009293013'u64, 2374314218300473764'u64]),
|
||||
FQ([4494471629382615894'u64, 1770606299211341443'u64,
|
||||
11311559966274242210'u64, 3399355515865771034'u64])
|
||||
]
|
||||
|
||||
const expects = [
|
||||
"0b812cdf8aafd6cbe1d6959968066172ebf606339547f18d735cf8364ebb6008",
|
||||
"23094811623a66136c3a3f86dcf8ac67bf7a2654e1e880a42243cf0f2b652847",
|
||||
"25b9bf5f353b1d29c62b954257ac188330e1335d557a11c04fcd10fc6ef07834",
|
||||
"111341c47c8c55345493a0ee73fa91d5e9f853451a11c982ff6ae824d42d8017",
|
||||
"15e851e5eb9e990b33d9e2056749dbb8ca6f0726c750b6665052090ff6249a63"
|
||||
]
|
||||
var buffer: array[32, byte]
|
||||
for i in 0..<len(vectors):
|
||||
zeroMem(addr buffer[0], sizeof(buffer))
|
||||
if not vectors[i].toBytes(buffer):
|
||||
return false
|
||||
var expect = fromHex(expects[i])
|
||||
if not equalMem(addr expect[0], addr buffer[0], sizeof(buffer)):
|
||||
return false
|
||||
var c: FQ
|
||||
if c.fromBytes(buffer) != true:
|
||||
return false
|
||||
if c != vectors[i]:
|
||||
return false
|
||||
return true
|
||||
|
||||
when isMainModule:
|
||||
|
||||
suite "Field elements test suite":
|
||||
test "[FR] rsquared() test":
|
||||
for i in 0..<1000:
|
||||
var a = FR.random()
|
||||
var b = BNU256.into(a)
|
||||
var c = FR.init(b)
|
||||
check a == c.get()
|
||||
|
||||
test "[FR] String conversion test":
|
||||
var a = FR.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495616")
|
||||
check a == -FR.one()
|
||||
|
||||
test "[FR] Random multiplication test":
|
||||
check randomElementMultiplication[FR]() == true
|
||||
|
||||
test "[FR] Random addition/substraction/negation test":
|
||||
check randomElementASN[FR]() == true
|
||||
|
||||
test "[FR] Inversion test":
|
||||
check canInvert[FR]() == true
|
||||
|
||||
test "[FR] Zero test":
|
||||
check zeroTest[FR]() == true
|
||||
|
||||
test "[FR] Random element squaring test":
|
||||
check randomSquaring[FR]() == true
|
||||
|
||||
test "[FR] Random element inversion test":
|
||||
check randomElementInverse[FR]() == true
|
||||
|
||||
test "[FR] Random element evaluation test":
|
||||
check randomElementEval[FR]() == true
|
||||
|
||||
test "[FR] Serialize/Deserialize tests":
|
||||
check fpSerializeTests[FR]() == true
|
||||
|
||||
test "[FR] Serialize test vectors":
|
||||
check frSerializeTestVectors() == true
|
||||
|
||||
test "[FQ] rsquared() tests":
|
||||
for i in 0..1000:
|
||||
var a = FQ.random()
|
||||
var b = BNU256.into(a)
|
||||
var c = FQ.init(b)
|
||||
check a == c.get()
|
||||
|
||||
test "[FQ] String conversion test":
|
||||
var b = FQ.fromString("21888242871839275222246405745257275088696311157297823662689037894645226208582")
|
||||
check b == -FQ.one()
|
||||
|
||||
test "[FQ] Random multiplication test":
|
||||
check randomElementMultiplication[FQ]() == true
|
||||
|
||||
test "[FQ] Random addition/substraction/negation test":
|
||||
check randomElementASN[FQ]() == true
|
||||
|
||||
test "[FQ] Inversion test":
|
||||
check canInvert[FQ]() == true
|
||||
|
||||
test "[FQ] Zero test":
|
||||
check zeroTest[FQ]() == true
|
||||
|
||||
test "[FQ] Random element squaring test":
|
||||
check randomSquaring[FQ]() == true
|
||||
|
||||
test "[FQ] Random element inversion test":
|
||||
check randomElementInverse[FQ]() == true
|
||||
|
||||
test "[FQ] Random element evaluation test":
|
||||
check randomElementEval[FQ]() == true
|
||||
|
||||
test "[FQ] Serialize/Deserialize tests":
|
||||
check fpSerializeTests[FQ]() == true
|
||||
|
||||
test "[FQ] Serialize test vectors":
|
||||
check fqSerializeTestVectors() == true
|
||||
|
||||
test "[FQ2] Random multiplication test":
|
||||
check randomElementMultiplication[FQ2]() == true
|
||||
|
||||
test "[FQ2] Random addition/substraction/negation test":
|
||||
check randomElementASN[FQ2]() == true
|
||||
|
||||
test "[FQ2] Inversion test":
|
||||
check canInvert[FQ2]() == true
|
||||
|
||||
test "[FQ2] Zero test":
|
||||
check zeroTest[FQ2]() == true
|
||||
|
||||
test "[FQ2] Random element squaring test":
|
||||
check randomSquaring[FQ2]() == true
|
||||
|
||||
test "[FQ2] Random element inversion test":
|
||||
check randomElementInverse[FQ2]() == true
|
||||
|
||||
test "[FQ2] Random element evaluation test":
|
||||
check randomElementEval[FQ2]() == true
|
||||
|
||||
test "[FQ2] Serialize/Deserialize tests":
|
||||
check fpSerializeTests[FQ2]() == true
|
||||
|
||||
test "[FQ2] Serialize test vectors":
|
||||
check fq2SerializeTestVectors() == true
|
||||
|
||||
test "[FQ6] Random multiplication test":
|
||||
check randomElementMultiplication[FQ6]() == true
|
||||
|
||||
test "[FQ6] Random addition/substraction/negation test":
|
||||
check randomElementASN[FQ6]() == true
|
||||
|
||||
test "[FQ6] Inversion test":
|
||||
check canInvert[FQ6]() == true
|
||||
|
||||
test "[FQ6] Zero test":
|
||||
check zeroTest[FQ6]() == true
|
||||
|
||||
test "[FQ6] Random element squaring test":
|
||||
check randomSquaring[FQ6]() == true
|
||||
|
||||
test "[FQ6] Random element inversion test":
|
||||
check randomElementInverse[FQ6]() == true
|
||||
|
||||
test "[FQ6] Random element evaluation test":
|
||||
check randomElementEval[FQ6]() == true
|
||||
|
||||
test "[FQ12] Random multiplication test":
|
||||
check randomElementMultiplication[FQ12]() == true
|
||||
|
||||
test "[FQ12] Random addition/substraction/negation test":
|
||||
check randomElementASN[FQ12]() == true
|
||||
|
||||
test "[FQ12] Inversion test":
|
||||
check canInvert[FQ12]() == true
|
||||
|
||||
test "[FQ12] Zero test":
|
||||
check zeroTest[FQ12]() == true
|
||||
|
||||
test "[FQ12] Random element squaring test":
|
||||
check randomSquaring[FQ12]() == true
|
||||
|
||||
test "[FQ12] Random element inversion test":
|
||||
check randomElementInverse[FQ12]() == true
|
||||
|
||||
test "[FQ12] Random element evaluation test":
|
||||
check randomElementEval[FQ12]() == true
|
||||
|
||||
test "[FQ12] Cyclotomic exponent test":
|
||||
check testCyclotomicExp() == true
|
||||
|
||||
test "[FQ12] Test vector test":
|
||||
check fq12TestVector() == true
|
|
@ -0,0 +1,138 @@
|
|||
import unittest
|
||||
import ../bncurve/groups
|
||||
|
||||
proc randomAdd*(G: typedesc): bool =
|
||||
for i in 0..<10:
|
||||
let r1 = G.random()
|
||||
let r2 = G.random()
|
||||
let r3 = G.random()
|
||||
|
||||
if ((r1 + r2) + r3) != (r1 + (r2 + r3)):
|
||||
return false
|
||||
let rc = (r1 + r2 + r3) - r2 - r3 - r1
|
||||
if not rc.isZero():
|
||||
return false
|
||||
return true
|
||||
|
||||
proc randomMul*(G: typedesc): bool =
|
||||
for i in 0..<10:
|
||||
let r1 = G.random()
|
||||
let r2 = G.random()
|
||||
let ti = FR.fromString("2").inverse().get()
|
||||
|
||||
if (r1 + r2) + r1 != (r1.double() + r2):
|
||||
return false
|
||||
if r1 != r1.double() * ti:
|
||||
return false
|
||||
return true
|
||||
|
||||
proc zeroTest*(G: typedesc): bool =
|
||||
if not G.zero().isZero():
|
||||
return false
|
||||
if not (G.zero() - G.zero()).isZero():
|
||||
return false
|
||||
if not (G.one() - G.one()).isZero():
|
||||
return false
|
||||
if (G.one() + G.one()) != (G.one() * FR.fromString("2")):
|
||||
return false
|
||||
if not G.zero().double().isZero():
|
||||
return false
|
||||
if not ((G.one() * (-FR.one())) + G.one()).isZero():
|
||||
return false
|
||||
return true
|
||||
|
||||
proc randomDH*(G: typedesc): bool =
|
||||
for i in 0..<10:
|
||||
let alice_sk = FR.random()
|
||||
let bob_sk = FR.random()
|
||||
let alice_pk = G.one() * alice_sk
|
||||
let bob_pk = G.one() * bob_sk
|
||||
let alice_shared = bob_pk * alice_sk
|
||||
let bob_shared = alice_pk * bob_sk
|
||||
if alice_shared != bob_shared:
|
||||
return false
|
||||
result = true
|
||||
|
||||
proc randomEquality*(G: typedesc): bool =
|
||||
let ti = FR.fromString("2").inverse().get()
|
||||
for i in 0..<10:
|
||||
let begin = G.random()
|
||||
var acc = begin
|
||||
|
||||
let a = FR.random()
|
||||
let b = G.random()
|
||||
let c = FR.random()
|
||||
let d = G.random()
|
||||
|
||||
for k in 0..<10:
|
||||
acc = acc * a
|
||||
acc = -acc
|
||||
acc = acc + b
|
||||
acc = acc * c
|
||||
acc = -acc
|
||||
acc = acc - d
|
||||
acc = acc.double()
|
||||
|
||||
let ai = a.inverse().get()
|
||||
let ci = c.inverse().get()
|
||||
|
||||
for k in 0..<10:
|
||||
acc = acc * ti
|
||||
acc = acc + d
|
||||
acc = -acc
|
||||
acc = acc * ci
|
||||
acc = acc - b
|
||||
acc = -acc
|
||||
acc = acc * ai
|
||||
|
||||
if begin != acc:
|
||||
return false
|
||||
result = true
|
||||
|
||||
proc affineJacobianConversion(G: typedesc): bool =
|
||||
if not G.zero().toAffine().isNone():
|
||||
return false
|
||||
if not G.zero().toAffine().isNone():
|
||||
return false
|
||||
for i in 0..<100:
|
||||
var a = G.one() * FR.random()
|
||||
let b = a.toAffine().get()
|
||||
let c = b.toJacobian()
|
||||
if a != c:
|
||||
return false
|
||||
return true
|
||||
|
||||
when isMainModule:
|
||||
suite "Group elements test suite:":
|
||||
test "[G1] Zero/One test":
|
||||
check G1.zeroTest() == true
|
||||
test "[G1] Random addition test":
|
||||
check G1.randomAdd() == true
|
||||
test "[G1] Random doubling test":
|
||||
check G1.randomMul() == true
|
||||
test "[G1] Random Diffie-Hellman test":
|
||||
check G1.randomDH() == true
|
||||
test "[G1] Random equality test":
|
||||
check G1.randomEquality() == true
|
||||
test "[G1] Random Affine to Jacobian conversion test":
|
||||
check G1.affineJacobianConversion() == true
|
||||
test "[G1] Y at point at Infinity test":
|
||||
check:
|
||||
(G1.zero()).y == FQ.one()
|
||||
(-G1.zero()).y == FQ.one()
|
||||
test "[G2] Zero/One test":
|
||||
check G2.zeroTest() == true
|
||||
test "[G2] Random addition test":
|
||||
check G1.randomAdd() == true
|
||||
test "[G2] Random doubling test":
|
||||
check G2.randomMul() == true
|
||||
test "[G2] Random Diffie-Hellman test":
|
||||
check G2.randomDH() == true
|
||||
test "[G2] Random equality test":
|
||||
check G2.randomEquality() == true
|
||||
test "[G2] Random Affine to Jacobian conversion test":
|
||||
check G2.affineJacobianConversion() == true
|
||||
test "[G2] Y at point at Infinity test":
|
||||
check:
|
||||
(G2.zero()).y == FQ2.one()
|
||||
(-G2.zero()).y == FQ2.one()
|
|
@ -0,0 +1,240 @@
|
|||
import unittest
|
||||
import ../bncurve/groups
|
||||
|
||||
proc testPreparedG2(): bool =
|
||||
var expect = G2Precomp(
|
||||
q: AffinePoint[G2](x: FQ2(c0: FQ.fromString("13936578204263895229092967414825041569724079982537616431212348844388899776640"), c1: FQ.fromString("6372636725635053773371996212293600406870925440022386078671828127711809436031")), y: FQ2(c0: FQ.fromString("19293035970010898452454381709939058714495082898872914526540420247178075881697"), c1: FQ.fromString("13822349107533275437553410197128434338071760794202849712402800746887549494974"))),
|
||||
coeffs: @[
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("2627043964130257285960335798481049684473505235282434252362906013168360965985"), c1: FQ.fromString("14787221188041042838526170263203159226721816513593198738527261794343476005673")), ell_vw: FQ2(c0: FQ.fromString("5190413803656753539584048070636432748402456516849818272297235294934300653772"), c1: FQ.fromString("16131787528611999569385991096257681501249100726189947900572474295515353427218")), ell_vv: FQ2(c0: FQ.fromString("11284217811624345285836951206193951701052480344824103057273798441033858118424"), c1: FQ.fromString("6392116536365389562188363539617434898082427085812013656312597845585909267447"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("827617134098165717451808940080463277390770457691666780560712143809003953598"), c1: FQ.fromString("6776229088211374446530917353066321938640163548858035832637439231634790575465")), ell_vw: FQ2(c0: FQ.fromString("987776078024262725561041258416387561158070255475504730561661362421251696401"), c1: FQ.fromString("15312963471998242334683179861466148222641884112991952428739813077336923189144")), ell_vv: FQ2(c0: FQ.fromString("2813988028633040066320201189843971639620433430176492766961373503539074898364"), c1: FQ.fromString("17055167212030988864288747645634552775658830115224987200613220012554982651578"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("17093477194591041266397380404112224367919571835678040889250664706433487493043"), c1: FQ.fromString("8643160753646550179100165428401120938543691942215161396502118430923535820500")), ell_vw: FQ2(c0: FQ.fromString("10933962898922943120024964690690003920835888964592980369975615298196656183772"), c1: FQ.fromString("10054435552662455933652209211749007190981947542684285471884164039871580864235")), ell_vv: FQ2(c0: FQ.fromString("1475406195060586931258578851599932495282912871465827155842007043242102046659"), c1: FQ.fromString("5049830924161187876168845800328902567850325970867534538120475909389784841990"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("10434276065336457961840942984114655645641355797054067910262735814196303889171"), c1: FQ.fromString("13878009844584745291193244072670264656592436467816383615606044714978763054890")), ell_vw: FQ2(c0: FQ.fromString("20993505060568459085534388708128029516059470166174503494622391683433030357130"), c1: FQ.fromString("10192769806017258272908841309051731389378033999625803563624881649401237928876")), ell_vv: FQ2(c0: FQ.fromString("17377091829483421118284926147077357677507183290871250621761583281560333718550"), c1: FQ.fromString("18297780639039540893260206902113850213293978821982237672423968999898103045256"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("5064242330961655837810472366173802140673816516016739528934082190598759216129"), c1: FQ.fromString("20172028727708469864987113767379594545870343866584998839699240724281670882460")), ell_vw: FQ2(c0: FQ.fromString("2996734698689069564052128450078797792056313730363946953355442668966438200951"), c1: FQ.fromString("9910941594900797404370917094355311738210439203708671856236954583027355115302")), ell_vv: FQ2(c0: FQ.fromString("6899792008443933570863502403567742315007264221354931185809349393350618040985"), c1: FQ.fromString("18692424201235977456836009406318755884773471215777102117879530727096807383696"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("9406196439119227017197200697795682187217614676635965071601916278141238949664"), c1: FQ.fromString("1156397052245190909533108891675012415349316096091404012699655652677336827483")), ell_vw: FQ2(c0: FQ.fromString("9249275523859165912800910211783530541095037634552893633043938333737241478198"), c1: FQ.fromString("13674086724537885208439774394455021050268654286498757861381516198880504360984")), ell_vv: FQ2(c0: FQ.fromString("5760486636714317173624828119078349011897522431614835257025421978626292083787"), c1: FQ.fromString("19195594701877562770296730558597966521343920474874926443609709880727520577918"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("12166638768862632131967787101186130559865354321458713212316891357299196109517"), c1: FQ.fromString("1517854601414954363921968422436855204960697222979994177630673862982254831193")), ell_vw: FQ2(c0: FQ.fromString("13366104107979832799705928625277388583673352228059815944738106504080223007902"), c1: FQ.fromString("21648874073566751720910466086303831459661520354253552089758049591613143727506")), ell_vv: FQ2(c0: FQ.fromString("3488776451414334656597670851583995239177248056342375163461521452312663358741"), c1: FQ.fromString("20333414955874213710027365371143864644434939642550352414403887754960702108637"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("20468104499950674906991599591024893438007901046236752159815194628487603192867"), c1: FQ.fromString("19069685413250623899891139234721987960230148622397590130148098858949057649761")), ell_vw: FQ2(c0: FQ.fromString("2458162095258922865086779772179745380154704066745856173311580123496018896409"), c1: FQ.fromString("14594824564551859025266692529845827840804005950672166057231487026855067744741")), ell_vv: FQ2(c0: FQ.fromString("9689655654286496198845571066967567466951511863880400774464590553022163229348"), c1: FQ.fromString("10870127206120874488753221889350215535903993427218589071224774335669836789433"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("15334990572515495832170458963151379997993357347608954164027751164770129172212"), c1: FQ.fromString("13576640273125978757652414940234881692674718901710647917847939367156260249620")), ell_vw: FQ2(c0: FQ.fromString("17441399177222030197667035179458353890777336233312342937564354849059149975908"), c1: FQ.fromString("17007488955907409465543686050546106251553784366237996525801373957978511005278")), ell_vv: FQ2(c0: FQ.fromString("11907792503811346855438657769533223907267837220830333730410940125854558637383"), c1: FQ.fromString("19490060942462197243379937108210110931787757078893580540054690416131017931738"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("17315779415820661602591970083599829709759601467527578787441772726289774228451"), c1: FQ.fromString("12080802446892182171725856453369856169039939341293608060423916935382017714476")), ell_vw: FQ2(c0: FQ.fromString("12912774602739952889552025090054804346758888115608888766725054474682313950190"), c1: FQ.fromString("18204955971588024842905918028829132053489100674596042021111813303048407250440")), ell_vv: FQ2(c0: FQ.fromString("15721987682182104464109212111163313043868345920774975073102123159159010623181"), c1: FQ.fromString("12041652399509652544977783565303273845883245418094457529808044120827920548972"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("19999070717670362479390656255660288732744476951677182489244240784338456791622"), c1: FQ.fromString("3906002755238658676658974095984902840159437088441472633765497396881255783772")), ell_vw: FQ2(c0: FQ.fromString("4998301920940599524538129746790252820575786197710804708434384224972978627969"), c1: FQ.fromString("13740819604543965458992763357705315276969968429480411530007322182403523242226")), ell_vv: FQ2(c0: FQ.fromString("12357083524385039711813704948190809675818592911528835736620903716727226601953"), c1: FQ.fromString("13949012942996636079549854439740332990496218971788334041233648192605019948979"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("19805154539184543843735550309592886829271314363908537964547876413114433734624"), c1: FQ.fromString("16481416862400234230001935040590314552205484054708993091993487440981092053599")), ell_vw: FQ2(c0: FQ.fromString("2850933690997557614680452825756662353227291804228932023648526608593113870536"), c1: FQ.fromString("4786423507519240726599235257249783193682886531662683554713943115802063984530")), ell_vv: FQ2(c0: FQ.fromString("1023533030117941985730558522296044345509721849960856436490999820443312747347"), c1: FQ.fromString("16431548648882316869128893343209930754508425074299553782883149795599907406302"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("17203075478724975791441470425150871365957382183648220405350599958349478966969"), c1: FQ.fromString("19566853320706390536799238411444563555185156853468371794865496424286288424312")), ell_vw: FQ2(c0: FQ.fromString("15310908404682220539815850064952575682898427316407655213706791187971849703724"), c1: FQ.fromString("16518878079785062271298378680376701241016697782308466806532677867880353948389")), ell_vv: FQ2(c0: FQ.fromString("14461573034674366293217641735721285869692106578982161360427147953320122006893"), c1: FQ.fromString("6682535969691272372531048932989583075363217464304983455197465867679730319705"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("20895553497690200905762157235991552162755238828234592755315911339400881373107"), c1: FQ.fromString("11947919061415103173593352950044808416347417810515010536678086292686107222044")), ell_vw: FQ2(c0: FQ.fromString("6277981470671734560229149673222400771590408919719217743512900463425397921908"), c1: FQ.fromString("857212248193599195410711267373529614085739023676782457331058533755337294689")), ell_vv: FQ2(c0: FQ.fromString("13885916052404740835214284721162700704805447448922857617672445286139626987191"), c1: FQ.fromString("19585389042100086858633036225209396447924441966778662250950999864988284098182"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("12748401205319976481200663793287165427761341490879316890008250070038707706903"), c1: FQ.fromString("9347025175062646190962067344106887221752685406563421042329129538495481178145")), ell_vw: FQ2(c0: FQ.fromString("12819473645128401077507234830331609583133696659610406468927174080626676619197"), c1: FQ.fromString("9039389340404634934394726812078086316924048399159604642340339967187032834011")), ell_vv: FQ2(c0: FQ.fromString("3576972655652865483567741810151575278761470911419381093571973994483543095285"), c1: FQ.fromString("15017468236028111406921228193688973260631093975412858847563400987354453569177"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("15407570760857043664675198351546637734249070940748070513828892036078049928562"), c1: FQ.fromString("16864837887933576789187120028615006826049916557295792205508706545038103706967")), ell_vw: FQ2(c0: FQ.fromString("10721360465919602144653520112889689786555051462198759164582568961994647563952"), c1: FQ.fromString("15294101887395462362997873520785213441488786364828649600395509678143054744021")), ell_vv: FQ2(c0: FQ.fromString("338877711237691732068166553384070140091720428235937017002925264628733553275"), c1: FQ.fromString("8565770517833678396194963042166078986348581926120249815567974171840711179000"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("17302401852599488824262121640328139426135883695023154134865582322858078206108"), c1: FQ.fromString("17762524466294762819341377108361075499043287383142581974755577861093917129883")), ell_vw: FQ2(c0: FQ.fromString("13015933066581331586057031655765394156438563571733887223640331819027233831808"), c1: FQ.fromString("758435331870656231667722761984400968773108978847112431665229252181053186864")), ell_vv: FQ2(c0: FQ.fromString("1969703955244816291771524536928710541897907643982046151796341732075930805350"), c1: FQ.fromString("7031491051442716548063495812915693048061021502544985435130728834982309403017"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("3256431897334799395000264533777543923057110731812322608781781329228902421476"), c1: FQ.fromString("12181683857561584905762347955319259913388176042023651776593530168946356566719")), ell_vw: FQ2(c0: FQ.fromString("796109596241493969908761241268545233387446802589790513588935996990189190052"), c1: FQ.fromString("1881011435205668659920588004752042238985141500261993259857887774967416952583")), ell_vv: FQ2(c0: FQ.fromString("8939978626202472531630769965940628317376245215184468794030552730424109408120"), c1: FQ.fromString("6876296539554825957959953448623382464100292373640362636397165101276891176372"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("9977776755404508431321449793657366203354342168643747704006143818738023991417"), c1: FQ.fromString("17287266532802977377832339048078093713694407321084566908200498605546793435820")), ell_vw: FQ2(c0: FQ.fromString("13828304001931491210449888619926027655755205497065268858009259221646932328015"), c1: FQ.fromString("15160507616608365341639459841002920786281000303114113782821091199951204875277")), ell_vv: FQ2(c0: FQ.fromString("11161349646944933007552237093278324942110971730799870343491465916610232191523"), c1: FQ.fromString("1406353163795290818414111649956135144227974028417320470897284179379367096127"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("7051926909684750402992796647032741235565177570654429988875094870973533133596"), c1: FQ.fromString("20900584116079647608136401104271956963096697793208792824067775068966626057321")), ell_vw: FQ2(c0: FQ.fromString("16845876804097000415961425779514720605919619149076212452284059758659650969766"), c1: FQ.fromString("20806461795944565303534619813753388058736049320841472653130287521152836019826")), ell_vv: FQ2(c0: FQ.fromString("14700937697004489523945953560825193972493636932341330040072362595384517591325"), c1: FQ.fromString("17137955424118909932502168320776219042080643724609838664247554484115994974522"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("11997142079850902731018491830701934107296522353910410046841604519639199995406"), c1: FQ.fromString("7846127392296015970710836702134527490160588060582987110380879354952036676012")), ell_vw: FQ2(c0: FQ.fromString("17663414534578185845724108244425572237371794484114570058559740097895281553299"), c1: FQ.fromString("5029140669755495687983399191536061323171057684732073778423303267496666431971")), ell_vv: FQ2(c0: FQ.fromString("18428442704115060890708987869503078260482829714024061977805185634781850796860"), c1: FQ.fromString("10997089106320530533400287751108615584976629751702164406696900094998369084403"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("13049677819639682137107272322562642308503411465986079606334189062279441432203"), c1: FQ.fromString("8874624972677935217588093490885486721673594121072678233714072789659128555367")), ell_vw: FQ2(c0: FQ.fromString("17057994029556488440657870420250293132874472170733557198308184169150330844407"), c1: FQ.fromString("21633949388482190843211557537195287403106536528012825991981214057356654097223")), ell_vv: FQ2(c0: FQ.fromString("6897044784874980042628318562068623805084522888972873438474139199226581764756"), c1: FQ.fromString("2692625602037608101594849144393949134766066123857076012132350588113519149572"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("9195356099870032305655798667367006686897880523242566329014149856866611060003"), c1: FQ.fromString("8052880750949660720559492348565167987253311417692073778040482170195175946428")), ell_vw: FQ2(c0: FQ.fromString("14126308928695836758114496610102001680995565158909643521688860213965125059872"), c1: FQ.fromString("671075569038912473223544948981506373517307914345286644404839238190008163502")), ell_vv: FQ2(c0: FQ.fromString("16828103633974871724641544770525140436938333764966095252502003672344759889143"), c1: FQ.fromString("11294529501746593948507624028584472676389760897716457892342249916318954501723"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("21124500310722447577044753724306337899524073055454053171030128408285122310058"), c1: FQ.fromString("6266274689105996173186441194758121417834460925587732781640173398761521329055")), ell_vw: FQ2(c0: FQ.fromString("21576331134605070996263178912402854747994495442070419140713471256922277734125"), c1: FQ.fromString("10074747339717657657921727946300324710951646905879034242434327125816600264379")), ell_vv: FQ2(c0: FQ.fromString("21765519811276677250031796638148457542841530645055777846258335421409598000534"), c1: FQ.fromString("21113224637771003677145667454854210585751245642107143223999187554888833454243"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("3972300323627467772646468544189830113523911494046612234673787196935654523692"), c1: FQ.fromString("4678843490808368914310764558657240771944434980659329233409943752329617161210")), ell_vw: FQ2(c0: FQ.fromString("17273599953138772488805612764323870175561796764345770950040891840763740358904"), c1: FQ.fromString("20415406312940209525918367703821373463952436739154646433333601347381723237136")), ell_vv: FQ2(c0: FQ.fromString("9160987523541118769404859219229455872777126347530590315596894278463599930633"), c1: FQ.fromString("9054614112960826755739076858442558227570393423663838494067070216861352843202"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("9994954547022379603539679290217274617475455164007187108524364097751858323148"), c1: FQ.fromString("20207771379440433457553782484784849880846158790602128386495229840158065235194")), ell_vw: FQ2(c0: FQ.fromString("4256518944443059194982602310083745017699415852751800911480635583088649250060"), c1: FQ.fromString("15878038811235111024146051545935959211923223574364333740058604258589674044428")), ell_vv: FQ2(c0: FQ.fromString("15953919860849853924955813198899405295748673040941543212644580663271517228860"), c1: FQ.fromString("19594437991878043589671466710739298733201896072505590020656735731744884281871"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("1333543700232406379832215757617068657339748039338978081735192495239856176346"), c1: FQ.fromString("13583045269132775344737980756385257860562307101313068058661941588822340692712")), ell_vw: FQ2(c0: FQ.fromString("11316045827391404343818336116749364562466461792138476673985290066961360847098"), c1: FQ.fromString("6683447190424452097068562814518005185732181765401062334661636064120276671717")), ell_vv: FQ2(c0: FQ.fromString("21483741541431414142042872578822487244163622589552506298253453995156009765340"), c1: FQ.fromString("16502358172728062550923345759488126380665850742066670591562640787191536290296"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("4727679401549029925466046980042210063407620223804057104870816459356196798234"), c1: FQ.fromString("4245208253099058296636688301996648265313738760450861302514451065904449375848")), ell_vw: FQ2(c0: FQ.fromString("19589426516750929424306774984752060788246605243046082989256140076730177865962"), c1: FQ.fromString("19202599366770569221216501935740579180019961851730854119509268985533547631061")), ell_vv: FQ2(c0: FQ.fromString("18329650333197074546830734977650617140322812110454751288122555715911145072440"), c1: FQ.fromString("18685828888894718887886440900247948352873037333999376257561751598045361934940"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("15348453159719894937627693446890053385899104841918429189733580400902437025934"), c1: FQ.fromString("7501190780205720975723852235835733848687299193764526538831345783610137314719")), ell_vw: FQ2(c0: FQ.fromString("12341649147852680664345690534373468938440543264264387581538764313149640739302"), c1: FQ.fromString("140543540021318882234026314588789476198722270107997413913717074968501481488")), ell_vv: FQ2(c0: FQ.fromString("5960374673747504135132782820167542238733653290730217772559545641742563125282"), c1: FQ.fromString("14507139191276441762644240084427079430815677404266073216544260783868466836469"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("1463974716527100203803811366059855506152810619047460592789012516365557382809"), c1: FQ.fromString("12894560712946121716686238503640546420854178898471895472462918225441749701869")), ell_vw: FQ2(c0: FQ.fromString("10508120321944855490271402587060090544503473558782513226881398929302598320386"), c1: FQ.fromString("20659878091446285231719184399846880718538938504006216923931157918871132219202")), ell_vv: FQ2(c0: FQ.fromString("9314687360620406591930278900314522432964075856747694070384017245464130048974"), c1: FQ.fromString("17694675150016443475335083504221747995503842086249559620223686305992007745569"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("14196539467892272085884829545587228956041818801561947743113049357924737022135"), c1: FQ.fromString("11319357657686312684765696405805456576475636756706867678717962076341276658626")), ell_vw: FQ2(c0: FQ.fromString("2758949814978246411081695103954624266457693267107844100147125044169545866221"), c1: FQ.fromString("9492100316900274072027501035053797502489796059345864111677781413985743864383")), ell_vv: FQ2(c0: FQ.fromString("4704107896591496617393915690357581449785399000813194972371050438639491862314"), c1: FQ.fromString("11531365345870313813093010071065540963321572589131340821665512078366854738990"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("18802465664727774773666122120775907428094487475952383150269507875840089541246"), c1: FQ.fromString("1731637922302665944958348222164323910730404298281499149800917211427254836819")), ell_vw: FQ2(c0: FQ.fromString("9297609456558817283944780415839637083190742770917810313181849518385379162642"), c1: FQ.fromString("16377246183633200781091121197835476043913744319877154056563766308564474143489")), ell_vv: FQ2(c0: FQ.fromString("9542461764772800142773586971354345045722377861760780709590923740133551871717"), c1: FQ.fromString("21640615613954317564353959148225302612886621120325752435425437529806262143694"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("19906049876176293236988182778475214525096978055900789654464603831282713330781"), c1: FQ.fromString("20362580925091945825523087376754169675844247448742703441518744743887060798158")), ell_vw: FQ2(c0: FQ.fromString("12267599301269062964822189844562856172284191535014283588478875529832316401461"), c1: FQ.fromString("16669825137620567269982790548542800570592942517936126877686519256685036586668")), ell_vv: FQ2(c0: FQ.fromString("8883573260261802165780406246211290131940260376316892224137508921505842308805"), c1: FQ.fromString("19231108274886583687672953546761020040720197580241947146286750565108059707992"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("634182853515641884871095612114627494589971356340786857463490962898713112220"), c1: FQ.fromString("11430884471074068345749191262196070058384500365559620896062382995797164195815")), ell_vw: FQ2(c0: FQ.fromString("10550902705393315932525976596381459439846414130661652807183357995272197708172"), c1: FQ.fromString("3961587743443277010160905820636488892023891053433292002931434257476626412826")), ell_vv: FQ2(c0: FQ.fromString("12451440882697904111698352784988882971851697245540249016187908252126835129000"), c1: FQ.fromString("11782592623486603129029758483031965320434451423371375539247662743178943477576"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("1404156345033137762434737426689373534725204733157905834242027185649572912742"), c1: FQ.fromString("19570890322851668915358612375948367153948206621537633922343603465980161569078")), ell_vw: FQ2(c0: FQ.fromString("8686503710040621382075118769097735385052600877432244428197116763766844918162"), c1: FQ.fromString("17223447941612107204326938316335236704702567123017447936901253775530936851086")), ell_vv: FQ2(c0: FQ.fromString("18767158861904777443587157807982315566545548385817262926280782765269843879565"), c1: FQ.fromString("21334543677892438295079840326280352051766440588072368601899791201007143326750"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("20453014818098756686381445228623803935714316636974320420742351477862354368007"), c1: FQ.fromString("11004429848286161246832723709453157691786114066215975460914111961981461575367")), ell_vw: FQ2(c0: FQ.fromString("14444837779919119651023367195508370508399423510380962187645910198528103345317"), c1: FQ.fromString("4021193867366929691652413553892868612329317391162172266658368471326882495507")), ell_vv: FQ2(c0: FQ.fromString("21098047915839588616030399663527845846589272989005835932893550785408588982098"), c1: FQ.fromString("16796487305049888740077005894512139332211008298712590271618863352993144873711"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("8799932768264091269394526725962837485495458036153083882004277055769655900574"), c1: FQ.fromString("18596145973176446599121174893654309094121045316907408604913712044917019537350")), ell_vw: FQ2(c0: FQ.fromString("5727901458562943136998396728651681550262281371313580881804977990767435431080"), c1: FQ.fromString("16665276274186006945492338822028666786935953718794303569570538737692828117635")), ell_vv: FQ2(c0: FQ.fromString("10910280368195212990489805322100030141483989387720003214110076576431959738476"), c1: FQ.fromString("9606982070265587786427675480691869167035030735018706315315080889814741903522"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("14453637744147393731588213406970287317078500183808667567110703622821377404467"), c1: FQ.fromString("2399421543794348043991999124897133983828094348779941685913680103324762089779")), ell_vw: FQ2(c0: FQ.fromString("9949473626857777965864312230577133154733097780222892008806269288857107115742"), c1: FQ.fromString("3174442934451895428948522429276679446276043250911620596846605340399481680631")), ell_vv: FQ2(c0: FQ.fromString("10773554875563236900680111254025179423521083612506388720894431016952344645908"), c1: FQ.fromString("1791500946161395076321848651097476041018873800532919907790655022966446958329"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("13228018442560564090007964181563674306630092611719086476342149061864561185280"), c1: FQ.fromString("12610285327624889222715450538150491139050620893563766277510163987972586901233")), ell_vw: FQ2(c0: FQ.fromString("17479662858773093405375538474745376030990506794065246603293683266124925174043"), c1: FQ.fromString("2084404960859519365733972471606438409123459865402210971655148862692485946826")), ell_vv: FQ2(c0: FQ.fromString("9675635536108496330861750800277390856149950003475979013330722219857375990089"), c1: FQ.fromString("17889926389980731198337394126857435112726851886206769936779651682292365620935"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("19205463777127243508919644186723680978776945615422050305472500178064412123473"), c1: FQ.fromString("10530028762478985738084339660443655112791893212694172883230610760959423970096")), ell_vw: FQ2(c0: FQ.fromString("16515559472874148379011472911124765449097459867226728232468301906190158644000"), c1: FQ.fromString("17379548905015313648731271429222704537289418711815257252434537403381161039222")), ell_vv: FQ2(c0: FQ.fromString("13018298656134311744614296809909600459918460239498208291306800551968894517759"), c1: FQ.fromString("16285303269049929546880902543736204779249639088136468614535789316688521663976"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("9506592875949693201584225006409064359870098448027454395748349563972724759341"), c1: FQ.fromString("1756212124305090096775291444252901778765176938185769777272403090820692916832")), ell_vw: FQ2(c0: FQ.fromString("8608069305722185875126845710591577689851258364137915830961192516727536204958"), c1: FQ.fromString("7879742654857051185278955345176850926952262018841407228150061698899939295057")), ell_vv: FQ2(c0: FQ.fromString("2311752966405194522531977544398652994349075269275918521122768201037004674541"), c1: FQ.fromString("8056192790171072186146581305753657840809572079825584316343698126369167589177"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("16894171323623324294071017663897158494527746239981369238071300334653959886935"), c1: FQ.fromString("21839557351524624846710837291698003965911117746801809883425361529677608757736")), ell_vw: FQ2(c0: FQ.fromString("7921995242367245298209685641602469741817826911044923939882608549077724733892"), c1: FQ.fromString("16195366803093832645900011617380218833645406154510352140817411408898365560241")), ell_vv: FQ2(c0: FQ.fromString("12718951609280728995721445896408716663776093135974310357265585518411722037823"), c1: FQ.fromString("14775730569800772809191320148533632897226925930462946258120395650683306784222"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("18324740767049924394294219212760164185884801967765967078427354810675386933254"), c1: FQ.fromString("18510525798971302215942990229348890627301667188256739950256532108744423958467")), ell_vw: FQ2(c0: FQ.fromString("392130232730851920199052091589353916248087256056205523658797958171832234380"), c1: FQ.fromString("21095230708713942590602820178155041621291598326436725983218983799781802054278")), ell_vv: FQ2(c0: FQ.fromString("3496296009938486548567151348321691013571513425434397040346440937975425900960"), c1: FQ.fromString("5982055369526470853931810147684497423036063399292908540001447206525852512531"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("19247021831371751344058078378442480867649167715937305884736113857856820190448"), c1: FQ.fromString("3844115161163747856814522390569661892955450798273343821401275758096863392646")), ell_vw: FQ2(c0: FQ.fromString("6827864046826742026186179073427918229064686953470940699125130948982461542396"), c1: FQ.fromString("17615043663229174389408922909891358248158892597678816385681324344031892930590")), ell_vv: FQ2(c0: FQ.fromString("17143020152984715373298117189870583206488981021188881359521310100992509008220"), c1: FQ.fromString("2174519777022093979454116656397980458948553322768446892932246705483799164016"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("7787149350876246869417695770873628344850130125888658086308716316049428077539"), c1: FQ.fromString("3645376584593179034263104864050174094110419584940335745722492256564582048708")), ell_vw: FQ2(c0: FQ.fromString("11834206166934740935662681278907472701573638397628522018255718023777042308993"), c1: FQ.fromString("11564024956967266505944728035150285591786947709753433733529805379472238406883")), ell_vv: FQ2(c0: FQ.fromString("15009525058621581543328262019401183048318643177731888421709672368574056014500"), c1: FQ.fromString("13573139489477783981960389988307434036015536834494019264597795654229345703051"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("16059660214342726778635842789601639915164060169646706775268999439826160969051"), c1: FQ.fromString("3592864998692836817549974752747753891215991801035643051485066473571282986623")), ell_vw: FQ2(c0: FQ.fromString("16014086539360826224382965134738311010906671679277894939278016943520015391650"), c1: FQ.fromString("8080101227643664909861133876167034094240488311720250596061359317310944652491")), ell_vv: FQ2(c0: FQ.fromString("3252331663236937425057834000082561720577180169369353108561319513563871033743"), c1: FQ.fromString("11096433584385810520286571872297862049422429286608206525566845219548956753724"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("19106172305007554707393707438702629275907204152148571359255256006833275609105"), c1: FQ.fromString("19930525972818199875851038877132322547334829658949554806801108404941414101103")), ell_vw: FQ2(c0: FQ.fromString("6679449617056144648556013688092503718528081567224358397706944806960707450866"), c1: FQ.fromString("11834339054115289581728384446510154030614495257639549098914576992681792644317")), ell_vv: FQ2(c0: FQ.fromString("1103971970080878735020200145931068396548255816344141900100578642050167835756"), c1: FQ.fromString("17442014287618549059909689032626628911431121434337187918457502534017974292771"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("13076805492928497748141329405065621544173515733010216253264862326898999186011"), c1: FQ.fromString("19346998537378535293491878821381642632408077348855336790184043880601230192418")), ell_vw: FQ2(c0: FQ.fromString("2545953185107430710067715026283426197979102699516436299879612082830465064387"), c1: FQ.fromString("658480144944520773976742499043453183928200527625254756411898212059863027220")), ell_vv: FQ2(c0: FQ.fromString("10599092041977168661053673645861514974472253862403262653806335823439984547520"), c1: FQ.fromString("17162893574285047796735108280435654463748265136801600105571927738662909784323"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("7085319511141515608176313666085289847826695130590757892136226409211984372940"), c1: FQ.fromString("4640142023499829801003091193578633557246618475866500623404375352964089302137")), ell_vw: FQ2(c0: FQ.fromString("1378711095367589966539356394028311641404402942969200900226036867512926984525"), c1: FQ.fromString("20227188036459114276006891788262806649925222994898646338447622388573680807347")), ell_vv: FQ2(c0: FQ.fromString("10909351851886459521617902618958119972478357132140936115187854789408351897716"), c1: FQ.fromString("4270359828288113001419972416654771076387260764523167288282363565700959902034"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("10664974041382313497332907041293813168318012018754207087217051246266695094381"), c1: FQ.fromString("7224602128989495563505314962160716046811485526332201590284671097356858321790")), ell_vw: FQ2(c0: FQ.fromString("3934655983500232748821065857705540333423053242147172231346384664554964864345"), c1: FQ.fromString("11454752219285395886386371667205283572988335397450041936477253847740701967591")), ell_vv: FQ2(c0: FQ.fromString("8613140983903038954690786727135433848146709090100659195246608245554768285578"), c1: FQ.fromString("11683437859485859733100235618517710813205908191940301821880216475492534630964"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("9260311336006363265451970156091146121161647548618044834929651955256342089015"), c1: FQ.fromString("13937163080647677520680042908210664749449075029135461146729576039103333691760")), ell_vw: FQ2(c0: FQ.fromString("17902331142943185999552054453100857674678810044830315483268693319046882556841"), c1: FQ.fromString("1544882902322119030227919062381439448920928851067359863906156836436873153173")), ell_vv: FQ2(c0: FQ.fromString("16995331248700240765237826468302734126993772776070338276810983166039248498016"), c1: FQ.fromString("14969634758504522458179971123440531767135906355134596040598769037804654587702"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("9691457346326988270440356562380914538881384898220972529069554878570918299675"), c1: FQ.fromString("4212749851190062070411861546581519573149862920541429109749681953529770836138")), ell_vw: FQ2(c0: FQ.fromString("10890917529063563080488636605724946896609903254351684402546841801646043334166"), c1: FQ.fromString("17064796604657821037034221187126605208939910043822292844975397354283757360178")), ell_vv: FQ2(c0: FQ.fromString("10053764157025690527213061522668163518874554311426109722786780729745637570153"), c1: FQ.fromString("12784239716790558610229592219566905741360808124013978959238298462172061891010"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("18178610037180803777372696468852749823139836169202607246443680867419301660001"), c1: FQ.fromString("2203553150397509140176760042861998991151797164185565920046676990283238338489")), ell_vw: FQ2(c0: FQ.fromString("20994248737185978263276750124680792452522185817020429107744966692073225126536"), c1: FQ.fromString("6349838002511478763817816496894821255234760390494115897123421446389963162622")), ell_vv: FQ2(c0: FQ.fromString("1263928993764270656816573911502202456032289420152723320064785370753332332564"), c1: FQ.fromString("3046827108505433561924898780283267608115953987844810798949064271834105292424"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("8956928906602747002792065663685826131559810003765184492377190892700326559543"), c1: FQ.fromString("9256558483224710959389211180674778886236784676421453067453985103303008910100")), ell_vw: FQ2(c0: FQ.fromString("19258483215045500292709619645410473292886118206783068420253408398264757067719"), c1: FQ.fromString("4451865829956913287893327659699467549695832858717473490066802599791690802339")), ell_vv: FQ2(c0: FQ.fromString("2764660330371796211645912465865514165647712230266940655139955982219479135487"), c1: FQ.fromString("13240152986607724183470740198192310673584785226612774164092563912390438227662"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("681767682327814473892054649470454096768283412403007527891528077929769397010"), c1: FQ.fromString("7668193584311505399758378551993462119934308304509766677185196010163712481402")), ell_vw: FQ2(c0: FQ.fromString("5655243760535315520783349710797795360471266639432050916814563868068635911845"), c1: FQ.fromString("6563255051651012450772847952915771842363624186837705815170827122750163703821")), ell_vv: FQ2(c0: FQ.fromString("649940975249127008407571724305690292046357719924151085455652491670338045916"), c1: FQ.fromString("21579311737676937819033214124612551530127167774002946532496743344036322675381"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("21175778737847401044104466077056088822729568143966863788586142950892805137666"), c1: FQ.fromString("5595589116740977138584720715075423123216685509908153451278598090500673116809")), ell_vw: FQ2(c0: FQ.fromString("10584200644032922607821101570277578933623023426596682657073390742969073652895"), c1: FQ.fromString("12837953697025504547863231066503572653998301486985427806275987315834659812986")), ell_vv: FQ2(c0: FQ.fromString("8117107548208718171682922744254403704391859020172151233388364110731129041045"), c1: FQ.fromString("13049999463955485268550904857465746325902043660001708636685369259450564610454"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("8364961604780202742303921161081604160922838515374423608219736048018999860853"), c1: FQ.fromString("2351019119583633406807532653396626109486234484023597064733508979159842183382")), ell_vw: FQ2(c0: FQ.fromString("21028432880575926523752559333294402827459370060933557257525967464997077946986"), c1: FQ.fromString("8046872296156140750811104526560806223677002170113323621491280498583760192616")), ell_vv: FQ2(c0: FQ.fromString("12898024833491487058567514428449740829256150305937499595589780150928565842102"), c1: FQ.fromString("4285065448422006185829060466560686578745712460867295748911655362509144300948"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("8072232359889306936722303478835558056241116613774315547062190240728474923834"), c1: FQ.fromString("11177008054227634237663439894104913366867843529726469624208391026893438331544")), ell_vw: FQ2(c0: FQ.fromString("6809080759521318546573252139200749353665236974149238674422052122591837770337"), c1: FQ.fromString("17038522274461048605370004543286094433565235245947661777349160189041706387246")), ell_vv: FQ2(c0: FQ.fromString("14024834693814357899802394991122512208020612837103453479716792821268632856005"), c1: FQ.fromString("12162253519201182595066522680875457472054933146636012038079782236991342232964"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("7517621744472550238729147112582763290619696603888340562320661653468259785459"), c1: FQ.fromString("5775958628431902009928696648706206677051589697801230225207961079701351805991")), ell_vw: FQ2(c0: FQ.fromString("17101537508347637393046612945060881733341630882242907674489426818282232192765"), c1: FQ.fromString("11439924192045730134857855444951867487673481853061712676505751821713592417848")), ell_vv: FQ2(c0: FQ.fromString("16524831954193049226680237913906512849861747525312574297009556588583016003485"), c1: FQ.fromString("17961833510100001957206410577764797351002903290115563676683242640020206248673"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("16912575460065719860154998920476780598787708817030774617128864437198545819929"), c1: FQ.fromString("18523390726102623209642393197047309169880798198922216024709291880134883505164")), ell_vw: FQ2(c0: FQ.fromString("8711744315121016096444521009902336544777137803294883395587631628756743226403"), c1: FQ.fromString("384665796631718061484470820770858149414181395445222225443039170963661807931")), ell_vv: FQ2(c0: FQ.fromString("15774538322747462731385931838340979144243491164741595437453112329195248618714"), c1: FQ.fromString("11632275451601229685994821619837954138410931366643826111939350416539675376582"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("4193777370819241345875098285464776579390947200963349948619027946434227330979"), c1: FQ.fromString("509866391215626792725431227507051906680902316754753085884521978793646270092")), ell_vw: FQ2(c0: FQ.fromString("6037175194865804429042789680410737585033925490367655507316663717551980954540"), c1: FQ.fromString("18041663784750649636833746105782119188697038394822653258671508993118228507622")), ell_vv: FQ2(c0: FQ.fromString("5823434994217288412340362524966578492063846889148854293277163714066988854109"), c1: FQ.fromString("5672396008289604057966364197930061596003079754530820851713923211431895221182"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("4038166397773785982077422827894979131906966567246129821324959462204170431412"), c1: FQ.fromString("18437550501813119699199412531646289403507307693226141098858673836744295275291")), ell_vw: FQ2(c0: FQ.fromString("14284923653983275338299458156785711701885868498245540450770121796221847779083"), c1: FQ.fromString("12602897944901625024952695280664364105484904418233840369524699062991946110320")), ell_vv: FQ2(c0: FQ.fromString("5486498814295375008109094800710678785628460899485721363575459728835468025031"), c1: FQ.fromString("16200691130190012476008796365701719097160136918178762563260333528187553865070"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("12314546787967340174315157919495563500551846522430770700093005979883034971431"), c1: FQ.fromString("3526449836226747514409509674529965207620312182683788709671366453353950282439")), ell_vw: FQ2(c0: FQ.fromString("5093273668274685698542824313074411944254604209522407110762874543698544425100"), c1: FQ.fromString("14413934995969972893982204347979972725062293812449032149868616703831967954701")), ell_vv: FQ2(c0: FQ.fromString("5926816361020227072352913556957354039762675747717706660663155084741002986207"), c1: FQ.fromString("11598493987133778453993847174276604684683441101397418085992950965674684594056"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("14605016886275487293555440005295724730930746064070181829857167303747503806723"), c1: FQ.fromString("125488028578519699988648864181559879827394253209756997049515479109363959656")), ell_vw: FQ2(c0: FQ.fromString("13618798589781916917754240943924749450694915714095829562214241999969133303075"), c1: FQ.fromString("7919521676249934186275057369006254600339974917319129664598969307290994883444")), ell_vv: FQ2(c0: FQ.fromString("13618646464444173552701873510284352084626546810748938598145778229202447557390"), c1: FQ.fromString("9476574581262975213029808591741428214940842553330900266594833123385626035464"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("20330569420634759863618802200434379756882301920599312733161738334139846403423"), c1: FQ.fromString("16941424680188140264426604507849243567044731815188670894126312258606055646954")), ell_vw: FQ2(c0: FQ.fromString("4276245652046353558826181153633997046897244969830610112857888938076187872093"), c1: FQ.fromString("5218134511825218024578456539758678791071455837562669069391138178014247652283")), ell_vv: FQ2(c0: FQ.fromString("5074559277335429630740829563679793620243538875458585401599810469948320707914"), c1: FQ.fromString("8399181532479234777915440768158248538072911084393374644710065479068982458679"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("228456190514225889641604150077307010131630607092226273786181288134202785827"), c1: FQ.fromString("6829691501727142726895142554058769478742020003540473851444113314854839779896")), ell_vw: FQ2(c0: FQ.fromString("7239124420778199901449006013253700083679198792863456824897986348225520969318"), c1: FQ.fromString("9612815502366829000381428453387330590336692138445456863004983078118510731327")), ell_vv: FQ2(c0: FQ.fromString("3032095333965417803301146592958869325973325547652138997619203744855910423626"), c1: FQ.fromString("9140900126707960555227810341717821370276432039323462635381934661102939064717"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("15183121839690585327918066578070528787848569635478652970262274682157344344126"), c1: FQ.fromString("17032257654469593612895387885450704824985120918227803531218149228038247116993")), ell_vw: FQ2(c0: FQ.fromString("4449946720064992614521464039848704811573349967863291193814384877976473528180"), c1: FQ.fromString("16213473115750238158840972181958630393893069174331658126086552358850995045944")), ell_vv: FQ2(c0: FQ.fromString("14820364816206160787218030695278797219740217739100995460398841348849807343630"), c1: FQ.fromString("13391831978082769659226335015618034703517552702532093599836056107584855920091"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("19376350172596821938106071755601309991977917109030961898807003698880067029751"), c1: FQ.fromString("8432677549750770318577385075581043130355856390772751886981628666318547719067")), ell_vw: FQ2(c0: FQ.fromString("19907801542387995008974808935818119635245812040205527769417146511798917761987"), c1: FQ.fromString("5161102563798536355551540455475021097419898845343559944869423371507274303876")), ell_vv: FQ2(c0: FQ.fromString("8934093116311670296805867189709376457342708648536176030347455800639124491789"), c1: FQ.fromString("2703243001408501823489300103176986467031566088207792046257025791153593204110"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("14246576411085900561418149065736187542613160942023368670593924207716148262147"), c1: FQ.fromString("3894319734417282749436553474309402307762162253367446669496582090013706055610")), ell_vw: FQ2(c0: FQ.fromString("8375748526029577467798965722696242475050467009610481042928314348040697238273"), c1: FQ.fromString("5150547143250446746041060583106242553976637956855972603954741388536316657102")), ell_vv: FQ2(c0: FQ.fromString("15907790590424017252473639606980913201030067954178224590289142061847439584806"), c1: FQ.fromString("11159987404206640511954116561264499629862056981304725791275082386203982274572"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("8534750176510034607784585561677263909151653570221826711790070724427621935471"), c1: FQ.fromString("7817152482056867378682253092041139659293041868731996264204246731388352069129")), ell_vw: FQ2(c0: FQ.fromString("16961113237531514134058762308816541864350643273034658785830240248900850618232"), c1: FQ.fromString("1179078000730113993104369721112852911420394064162245727296751799866128074554")), ell_vv: FQ2(c0: FQ.fromString("20457374714339105220680185601375259716132143552962630535477097129353077443649"), c1: FQ.fromString("4422525926709336878773825319073188719230418589270084994878618648788354576429"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("7627847586963893527076371866753343482026765205726665650559945926181618692545"), c1: FQ.fromString("11854660093187915385325641424610609952992715573834872602540776698350931163771")), ell_vw: FQ2(c0: FQ.fromString("12061802008303461437760636908585485318885385024493098952040511326354153801540"), c1: FQ.fromString("2483328707802038203960641185873859652602098605879879702928670691083351376828")), ell_vv: FQ2(c0: FQ.fromString("3179938981834043637934998748622377818001614400201120097155888429286598162788"), c1: FQ.fromString("3387712903817602592588061982323804658595985412237324988504760476608661908669"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("18935668687475417752670528265758371887227072908926123795139093572891409166177"), c1: FQ.fromString("7137948322161355685471108734802366001522057971184080351365620151904917529667")), ell_vw: FQ2(c0: FQ.fromString("4339156032094542567838794153972725732752104151129467898887880650450609600794"), c1: FQ.fromString("12048671216064877807276853910375839173096391682288251978695349073893797560105")), ell_vv: FQ2(c0: FQ.fromString("1950772803812480571427275248471639178971170644950730072787717123474197730954"), c1: FQ.fromString("9181624035531055165333621510604231877029437698520448252367489746796255738472"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("11063654615400954717295218153285806614049542407631184476400061600226642090639"), c1: FQ.fromString("10322234663627758865726091502227262577963762851829427143908452375568424940506")), ell_vw: FQ2(c0: FQ.fromString("5088512375045637070831200431021199523774202712519349524231646029565850243137"), c1: FQ.fromString("13830164350727008423053294968318643994288249825064419288902919319598527803018")), ell_vv: FQ2(c0: FQ.fromString("5664114633031170805308124108402506179037402200165762737765348606356467981435"), c1: FQ.fromString("6420500289322096738785425211380588437700105870048213919996474830908364662080"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("12089017351045163205876906516764262596252750496306969979802152087250767442655"), c1: FQ.fromString("10210558808216547366164047615754858102665922901025755697993978799086515582216")), ell_vw: FQ2(c0: FQ.fromString("5805411494371431706302702029555168082350433630263841912576207114214821637903"), c1: FQ.fromString("13417649473832328299363309530328161775713579734460687495589323668315481789186")), ell_vv: FQ2(c0: FQ.fromString("7100161023424716303226449735068569399024504614273633218656928626719841360262"), c1: FQ.fromString("4608780226874321006375565633722017610093139802788639970961143211665122970425"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("7402656885283645637844399867437832414708002274719716809314550750025200002816"), c1: FQ.fromString("3359755418859898733774484791668766343777859472186478368952701397946858170923")), ell_vw: FQ2(c0: FQ.fromString("13972633490402551449646647488711159435500678729477306484155919447807727623768"), c1: FQ.fromString("7493072689132118410451346570771015894599566093753023472904593233187191189290")), ell_vv: FQ2(c0: FQ.fromString("10553632499535499938294059057022861371325444554911689769145218759723376859522"), c1: FQ.fromString("15031724096959569889887883166930429112400023614133986918505200177949730145621"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("19614666780105423133718014776333000423285968913902974939878172716992608453809"), c1: FQ.fromString("11603995082765755677014543451017101337084691386341657702599446172204728703168")), ell_vw: FQ2(c0: FQ.fromString("3640285626277218751703647194759635465446306209869384174139659856814138047153"), c1: FQ.fromString("19852827152161121673942769427296662914445783006570890136096053338872958018957")), ell_vv: FQ2(c0: FQ.fromString("15133277841235179795557173122463348349264603847086033764926472096701308210280"), c1: FQ.fromString("11477545358800195084620539652687203979589770655971679975137907269158992047904"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("14110112013826130627308137057440352762673176006101512326319632538666268095190"), c1: FQ.fromString("11939502323738533476551128890683182628994629048369580067812328846012456410750")), ell_vw: FQ2(c0: FQ.fromString("4903570904021379863440412383519324112841733022665060696302943089410552325193"), c1: FQ.fromString("14266803156893138980425811506240396635009593456307449490727186191181005152878")), ell_vv: FQ2(c0: FQ.fromString("14881072700587137091207448172180518390500891251946414292329369965686915854422"), c1: FQ.fromString("15926908436628594399583920130944357569706863129497064862365363758969852348774"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("12558706151877569296451844961986237406953575964353502214928234165049347203902"), c1: FQ.fromString("20986351119648698768747274174278231882270962658108929786748672594878002377020")), ell_vw: FQ2(c0: FQ.fromString("19049669232824485247328064933680299726722169816787419902393190195363675139966"), c1: FQ.fromString("9038064204016446065702766858179381867420605337773795708435102200352238225734")), ell_vv: FQ2(c0: FQ.fromString("20935836360010341957040867041308346409399314465762274744792154001186771274330"), c1: FQ.fromString("10203406114258970224185400536984459120400171034941205452745624846762632193745"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("5273485321155899320017031787320374433252287213043632779466667239152835002841"), c1: FQ.fromString("3053056741460414900892697870729818263336633719763669407853703091660209931803")), ell_vw: FQ2(c0: FQ.fromString("14340825980720147789753139378133767339849529468405152905403690972933175947523"), c1: FQ.fromString("10774533501875920615470512566140848784460524907884011188458749902565676606519")), ell_vv: FQ2(c0: FQ.fromString("3964278893337662256819152335242286127722672026565541866237058714197501521533"), c1: FQ.fromString("18022244127367262334687067361628890804799640514175862613915842388966614841200"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("16332502873726000727943290608233946425803707374189230473690022986938005644703"), c1: FQ.fromString("1567962947294031055122165158764344785171646063465144808831306664719326769256")), ell_vw: FQ2(c0: FQ.fromString("20252166217271346908492216031557669988560255907738941815783926955730505937199"), c1: FQ.fromString("17117796187826532609679851805915085724672631310980423533710032156677468384570")), ell_vv: FQ2(c0: FQ.fromString("17447467886258986370787137061379217598255780655216428459333948972673151012677"), c1: FQ.fromString("5126879980313476901131854669269919146638602687291477011061931179530480305128"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("6088970897125028663727223015788851329277811231049906821835210021445230531470"), c1: FQ.fromString("8269042454443245208032034843063473106607747629991910601236499943382389383909")), ell_vw: FQ2(c0: FQ.fromString("9390988514296458582044517134794855627538985266829573142624063333360969055582"), c1: FQ.fromString("14809192622791971819542419564616657251564340618078775692251491022692953050806")), ell_vv: FQ2(c0: FQ.fromString("12392403118986217155446218801253632414719473065843423820454574775060624572223"), c1: FQ.fromString("17315648550786131512187415565477299679361071890287921321719420341945848525344"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("8509704393616883918389461491307625357351608849562781376448108143686881397874"), c1: FQ.fromString("20273788844812669168701278525056990767412251703786041383351127813548056060175")), ell_vw: FQ2(c0: FQ.fromString("13587733380957601917144020513037833512715927912961534242274129611676082179670"), c1: FQ.fromString("18219007782547538891755131684432302965729501555658190323551992733355994409648")), ell_vv: FQ2(c0: FQ.fromString("15212235563035911012497734239429958536448576200220918241945992532007455729638"), c1: FQ.fromString("15868967159924843704138451124239001351258676891119605450618238262537266256000"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("566642944339341838872659990670775497018813579200118662738575067585620262683"), c1: FQ.fromString("80633561422247315402489148783136836267866433112423246780090434639448081501")), ell_vw: FQ2(c0: FQ.fromString("16776314135335488452712466347201660236874408701359052824185479604688604443386"), c1: FQ.fromString("9397286871750513195379912820117368990110423949006393550333044521067916303673")), ell_vv: FQ2(c0: FQ.fromString("11213241389292792759942014406027965770431479614859139543821417488303149467800"), c1: FQ.fromString("13968940593285273772185768016764839518710968380183853737025067101492115101555"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("6582524148524166281651049223972241418275829952930531957133089376081226599310"), c1: FQ.fromString("12912796945237135113112612780707994091197804899944634993937602107108817617069")), ell_vw: FQ2(c0: FQ.fromString("5915143763477343907746278070838860419057837978194254349309930636588762054019"), c1: FQ.fromString("16829580672314341143130263740133292836202318062773617917928807522786048686905")), ell_vv: FQ2(c0: FQ.fromString("6048262046277135430490078693604752857941808479983722633615831914037376701617"), c1: FQ.fromString("11339265196645696685132629437938382050130007247287625382019491127986659567508"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("16221040390720130701106818492787718054167551387591190581820867019772199748452"), c1: FQ.fromString("13816650124538024294513769170531808824213976236314395631188393480750356347832")), ell_vw: FQ2(c0: FQ.fromString("17884725815671017389514271919761437310258619463085199936932965564030171526767"), c1: FQ.fromString("18248973796984942533601080062907385035195180110558182226420098600644022965345")), ell_vv: FQ2(c0: FQ.fromString("3137416660392142651716799414483848222789075294982695366740419822188364577896"), c1: FQ.fromString("9694367271685190541749430052152010428005565838702388077250686840743397580564"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("6357610272973630149840225505274539351850867930627803566656124705077309138236"), c1: FQ.fromString("6532064867969562545750502093085673423036025281166230602025667552530979558092")), ell_vw: FQ2(c0: FQ.fromString("16786670094068652274677750111730144379312178408732829954083928254919389983983"), c1: FQ.fromString("6341529030893580474995202784328098673009525246309131907462803539077246776781")), ell_vv: FQ2(c0: FQ.fromString("1974498926273096258802796702119259182018579009158122203612017565775578915815"), c1: FQ.fromString("16202371700345289299248140495735793174324620209466889736695203996551421837181"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("7645596703863049949671625140189098533219782764649960681401839437305310089346"), c1: FQ.fromString("19662686877039093771787921401379726144714150453645437909640334762978238819386")), ell_vw: FQ2(c0: FQ.fromString("19675517233991845002128733409028273554556593365253876728982552859262257722391"), c1: FQ.fromString("17810553502824017140555114404262914434390762266054795883352268646885364159410")), ell_vv: FQ2(c0: FQ.fromString("18665072545928024509881282829034535118797458683193169885406548536617293330990"), c1: FQ.fromString("19411595053923298782146703680748498557982136082135126508584153240357549362078"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("14470514611309746071605255274946119202484366658141275541087020842175954067559"), c1: FQ.fromString("2594897518684998941907190849745518961756699273476562463311001408776339658780")), ell_vw: FQ2(c0: FQ.fromString("935873152179726234311073616163680460286310013909076125956427156452613025181"), c1: FQ.fromString("1833293684395168387765260233178732135932817355166697645828433012629591012612")), ell_vv: FQ2(c0: FQ.fromString("15506344864201849985196152671178663605696906693236430756412539843011256851197"), c1: FQ.fromString("21249626787247514663459670711353542343321937134901366527096486234949436840608"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("14844298589371811580114643149994926627935566419885127313767249060440840193460"), c1: FQ.fromString("21865492910219121705480174226763323783866193080747061232287801827306146286946")), ell_vw: FQ2(c0: FQ.fromString("17151100973274235243640792655189642956800303990602164052684336481398298289411"), c1: FQ.fromString("14392190221562986523826107157981466944764379735735544220135185056395768909930")), ell_vv: FQ2(c0: FQ.fromString("4350255565215767538405433120041486620343663937357318680211203103336875636557"), c1: FQ.fromString("9926081950735179732148156026738993553156731124330466866635273595752973758855"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("13218761129163938072615510267349114476398845757988353548581904005855607494827"), c1: FQ.fromString("5599121822325202341068442750237639791575579072233857524815548719976323285948")), ell_vw: FQ2(c0: FQ.fromString("15971120376538832228790474763995956330325241100841265267806125625593561200292"), c1: FQ.fromString("12523288625433720594713119420870235433458343202664663107083051275205911332632")), ell_vv: FQ2(c0: FQ.fromString("16334648365696506264242655102949242813244449705193389318653840069223698505218"), c1: FQ.fromString("5656148484258838154513173637616383061988381726003070282394323376702835298685"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("17813738829828434290335491956960173922453516626523775773406434062574864455163"), c1: FQ.fromString("20602369742562270094694203910247000789225384961205618501257582838246099644397")), ell_vw: FQ2(c0: FQ.fromString("19878549521928480892919729627745688905048802531306612605469432942519616386562"), c1: FQ.fromString("5017457857497268504225948371697060380418757800650743056471872023476645133890")), ell_vv: FQ2(c0: FQ.fromString("11253669115821132651967277438747600032147012598164512191026558281212405907059"), c1: FQ.fromString("17527101633359473938082679669763197242520773041737623688955597341205608093817"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("4215545173967763533303120784928042872427929334572670490629936371429427871071"), c1: FQ.fromString("12294795716682648009432653500746413304750644076589949908249345884220200424705")), ell_vw: FQ2(c0: FQ.fromString("18825720171660950734491494575282684507875213824417353005009465489701558195915"), c1: FQ.fromString("16705960611772713893529695679517111622754789317070946155202186944060021844706")), ell_vv: FQ2(c0: FQ.fromString("727717707174551758531261221179545916153780087179478433501944451338651779512"), c1: FQ.fromString("8112271980906996458859937804680221894935591766524365848766530295751121904748"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("10233024162783159141952008177866660607852287510058437429941412641351833243474"), c1: FQ.fromString("9594838646894429694778293318641489517645344438331800828882574864439372872574")), ell_vw: FQ2(c0: FQ.fromString("16645682756797429615195184700295338945089747965333104334845226609564841400023"), c1: FQ.fromString("4162352035394629024812623559649906911351409190415492302470361657064711946691")), ell_vv: FQ2(c0: FQ.fromString("6032119528092518381867266123093895943802103316999621961287699634448441322294"), c1: FQ.fromString("16978590002913514123461500015923670605519520926487110857783653291799516315656"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("8218196524386055233961282665657821183883422738571989211183480610420112668380"), c1: FQ.fromString("10415506866745570162620028320970394286106067432626512901854031549920339603997")), ell_vw: FQ2(c0: FQ.fromString("5210044150482547744429104832217210823770891140961861953610847155896342519957"), c1: FQ.fromString("7249576834325689075837879557249227252903732278842727723303356548006299693332")), ell_vv: FQ2(c0: FQ.fromString("10566250213397026997176223676662431109660830193211672199901829008963029461821"), c1: FQ.fromString("10109726446308488117042758961222375921166426648339199001670753736584698407831"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("14958658301977599538003236672511296104101995894564376511283101560012949683335"), c1: FQ.fromString("3048608469033125363311089547916169290720115268350540694596412955569118898494")), ell_vw: FQ2(c0: FQ.fromString("574489666015527527356241753990038643397861257676315289742492198353125347063"), c1: FQ.fromString("20135743140323312729475654806927894483883158119600963784497647679670289292384")), ell_vv: FQ2(c0: FQ.fromString("429037282750459454100296565403648201904295120071497517313998879109362521423"), c1: FQ.fromString("15853233349247701874380259741343021520320591334343875702627292292088300425145"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("18700030680590279184945769912899822403041358764323477965514340815228877402331"), c1: FQ.fromString("10683998632701796443517414309938660369292269662497518738662465524924019738910")), ell_vw: FQ2(c0: FQ.fromString("1310694906110452150099267122613851606459600617516350757492763828252192371857"), c1: FQ.fromString("4783076385012654125132398886450190041207227400254467276271580769333335151361")), ell_vv: FQ2(c0: FQ.fromString("19588709046778297839342456362815786766378666302331732601204786295010565114246"), c1: FQ.fromString("15768094978512846661820502043664035262466161785979259300748269497441797675546"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("13060364876687824737412369705619641318084803694180161837383771909738942399322"), c1: FQ.fromString("18217552047682533290011237332328856250732338018560605204821714348687071938690")), ell_vw: FQ2(c0: FQ.fromString("12869661643727171099080271622741099816758098286424339832028838960253051261267"), c1: FQ.fromString("9771005613420764951919925720405408601257471427085946188171574196917272408972")), ell_vv: FQ2(c0: FQ.fromString("50909581144623642750375885935872654509592339539711209410079054797052409354"), c1: FQ.fromString("18926528403466649263993967111065644144239906211315737390219036362821972145669"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("20549804669307980165961565026567668900175984309510667407934326603524068980568"), c1: FQ.fromString("2860891967505015044048360806986650576604923893849408592665407858213623973073")), ell_vw: FQ2(c0: FQ.fromString("15425380359872501526721873883293811604657689327716748473720120299487795555723"), c1: FQ.fromString("19476618728903347368164774764554105623361814261939990815870207909384053172994")), ell_vv: FQ2(c0: FQ.fromString("1391900673866549134877070137078952075347059393013450066057338968238992587955"), c1: FQ.fromString("4196316861965319041187484774757427170509633759722370813890904092023663955821"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("17275387403896977778123657295201685204905269368879700703438840824610915049467"), c1: FQ.fromString("19208898840130004899976179132541534722147305748950927170013798354273078356439")), ell_vw: FQ2(c0: FQ.fromString("2806476769978795611970161315323438770892084130100332531802098991493644141407"), c1: FQ.fromString("12027685137795878129532114449809592645364590672303716160923491816560315933093")), ell_vv: FQ2(c0: FQ.fromString("8236588507133996535585623995380369531792969451558421380293164596516832310024"), c1: FQ.fromString("7194816002224802847462171990762514812770222507636791853795854276216118633532"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("8988630595018387496849477785798469553390006328427704582362113137927154840355"), c1: FQ.fromString("2295777524525303845671711839319946449143831320846022233249545363172788331149")), ell_vw: FQ2(c0: FQ.fromString("19856063720990800344827304970869772811632532243020577718537161398914360273978"), c1: FQ.fromString("19822454791015240925652351664190735476954892251509376470361602440577337517739")), ell_vv: FQ2(c0: FQ.fromString("16437024240432855113321845721989731630224984534156413407578941758236945886728"), c1: FQ.fromString("10915573623321985107029933965796058231484519510670830600808943167010577314334"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("21286975582879196598650077668567283554136994229408922053641846042051746388886"), c1: FQ.fromString("5421529658065143080970166226046014500038127295988164061860891929414040927615")), ell_vw: FQ2(c0: FQ.fromString("5555485154537896512520569992616892769357525491868135294451583184259218193278"), c1: FQ.fromString("4831809465565304340310880868620257258305484211486308136368207144444325564275")), ell_vv: FQ2(c0: FQ.fromString("2583089702666220608189326901976548985583885001543445628170288810575076369034"), c1: FQ.fromString("7097788099664798415333498763272677734135137637990913349021964143797057593727"))),
|
||||
EllCoeffs(ell_0: FQ2(c0: FQ.fromString("21356455346146359274071336488740257199607341582407258426849457339859865454145"), c1: FQ.fromString("19512280220246743343068375192508909480135195681362473260894831078332945004959")), ell_vw: FQ2(c0: FQ.fromString("15435677241338788169971902812985017500898533325271813422525238374746874853456"), c1: FQ.fromString("6382067580057986766020919077216175344977116334133202456947134195629074647989")), ell_vv: FQ2(c0: FQ.fromString("1150360546643207487285835972411275438312694180812115547021545502055712764110"), c1: FQ.fromString("2194960903427600986795419731825236689333014397679688012527722471213485607323")))
|
||||
]
|
||||
)
|
||||
var g2 = G2.one() * FR.fromString("20390255904278144451778773028944684152769293537511418234311120800877067946")
|
||||
var g2p = g2.toAffine().get().precompute()
|
||||
if g2p.q != expect.q:
|
||||
return false
|
||||
if g2p.coeffs != expect.coeffs:
|
||||
return false
|
||||
return true
|
||||
|
||||
proc testMillerLoop(): bool =
|
||||
var expect = FQ12(
|
||||
c0: FQ6(
|
||||
c0: FQ2(c0: FQ.fromString("14551901853310307118181117653102171756020286507151693083446930124375536995872"), c1: FQ.fromString("9312135802322424742640599513015426415694425842442244572104764725304978020017")),
|
||||
c1: FQ2(c0: FQ.fromString("2008578374540014049115224515107136454624926345291695498760935593377832328658"), c1: FQ.fromString("19401931167387470703307774451905975977586101231060812348184567722817888018105")),
|
||||
c2: FQ2(c0: FQ.fromString("15835061253582829097893482726334173316772697321004871665993836763948321578465"), c1: FQ.fromString("2434436628082562384254182545550914004674636606111293955202388712261962820365"))
|
||||
),
|
||||
c1: FQ6(
|
||||
c0: FQ2(c0: FQ.fromString("2874440054453559166574356420729655370224872280550180463983603224123901706537"), c1: FQ.fromString("21199736323249863378180814900160978651989782296293186487853700340281870105680")),
|
||||
c1: FQ2(c0: FQ.fromString("19165582755854282767090326095669835261356341739532443976394958023142879015770"), c1: FQ.fromString("1381947898997178910398427566832118260186305708991760706544743699683050330259")),
|
||||
c2: FQ2(c0: FQ.fromString("282285618133171001983721596014922591835675934808772882476123488581876545578"), c1: FQ.fromString("9533292755262567365755835323107174518472361243562718718917822947506880920117"))
|
||||
)
|
||||
)
|
||||
let g1 = G1.one() * FR.fromString("18097487326282793650237947474982649264364522469319914492172746413872781676")
|
||||
let g2 = G2.one() * FR.fromString("20390255904278144451778773028944684152769293537511418234311120800877067946")
|
||||
|
||||
let g1pre = g1.toAffine().get()
|
||||
let g2pre = g2.toAffine().get().precompute()
|
||||
let gt = g2pre.millerLoop(g1pre)
|
||||
|
||||
if gt == expect:
|
||||
return true
|
||||
|
||||
proc testReducedPairing(): bool =
|
||||
let g1 = G1.one() * FR.fromString("18097487326282793650237947474982649264364522469319914492172746413872781676")
|
||||
let g2 = G2.one() * FR.fromString("20390255904278144451778773028944684152769293537511418234311120800877067946")
|
||||
|
||||
let gt = pairing(g1, g2)
|
||||
|
||||
let expected = FQ12(
|
||||
c0: FQ6(
|
||||
c0: FQ2(c0: FQ.fromString("7520311483001723614143802378045727372643587653754534704390832890681688842501"), c1: FQ.fromString("20265650864814324826731498061022229653175757397078253377158157137251452249882")),
|
||||
c1: FQ2(c0: FQ.fromString("11942254371042183455193243679791334797733902728447312943687767053513298221130"), c1: FQ.fromString("759657045325139626991751731924144629256296901790485373000297868065176843620")),
|
||||
c2: FQ2(c0: FQ.fromString("16045761475400271697821392803010234478356356448940805056528536884493606035236"), c1: FQ.fromString("4715626119252431692316067698189337228571577552724976915822652894333558784086"))
|
||||
),
|
||||
c1: FQ6(
|
||||
c0: FQ2(c0: FQ.fromString("14901948363362882981706797068611719724999331551064314004234728272909570402962"), c1: FQ.fromString("11093203747077241090565767003969726435272313921345853819385060670210834379103")),
|
||||
c1: FQ2(c0: FQ.fromString("17897835398184801202802503586172351707502775171934235751219763553166796820753"), c1: FQ.fromString("1344517825169318161285758374052722008806261739116142912817807653057880346554")),
|
||||
c2: FQ2(c0: FQ.fromString("11123896897251094532909582772961906225000817992624500900708432321664085800838"), c1: FQ.fromString("17453370448280081813275586256976217762629631160552329276585874071364454854650"))
|
||||
)
|
||||
)
|
||||
result = (gt == expected)
|
||||
|
||||
proc testBinlinearity(): bool =
|
||||
for i in 0..<10:
|
||||
let p = G1.random()
|
||||
let q = G2.random()
|
||||
let s = FR.random()
|
||||
let sp = p * s
|
||||
let sq = q * s
|
||||
|
||||
let a = pairing(p, q).pow(s)
|
||||
let b = pairing(sp, q)
|
||||
let c = pairing(p, sq)
|
||||
|
||||
if a != b:
|
||||
return false
|
||||
if b != c:
|
||||
return false
|
||||
|
||||
let t = -(FR.one())
|
||||
|
||||
if a == FQ12.one():
|
||||
return false
|
||||
if a.pow(t) * a != FQ12.one():
|
||||
return false
|
||||
return true
|
||||
|
||||
proc testDH(): bool =
|
||||
# Generate private keys
|
||||
var alice_sk = FR.random()
|
||||
var bob_sk = FR.random()
|
||||
var carol_sk = FR.random()
|
||||
# Construct public keys
|
||||
let alice_pk = G1.one() * alice_sk
|
||||
let bob_pk = G1.one() * bob_sk
|
||||
let carol_pk = G1.one() * carol_sk
|
||||
# Round one
|
||||
let alice_dh_1 = bob_pk * carol_sk
|
||||
let bob_dh_1 = carol_pk * alice_sk
|
||||
let carol_dh_1 = alice_pk * bob_sk
|
||||
# Round two
|
||||
let alice_dh_2 = alice_dh_1 * alice_sk
|
||||
let bob_dh_2 = bob_dh_1 * bob_sk
|
||||
let carol_dh_2 = carol_dh_1 * carol_sk
|
||||
|
||||
result = (alice_dh_2 == bob_dh_2 and bob_dh_2 == carol_dh_2)
|
||||
|
||||
proc testJoux(): bool =
|
||||
# Generate private keys
|
||||
var alice_sk = FR.random()
|
||||
var bob_sk = FR.random()
|
||||
var carol_sk = FR.random()
|
||||
# Generate public keys in G1 and G2
|
||||
let alice_pk1 = G1.one() * alice_sk
|
||||
let alice_pk2 = G2.one() * alice_sk
|
||||
let bob_pk1 = G1.one() * bob_sk
|
||||
let bob_pk2 = G2.one() * bob_sk
|
||||
let carol_pk1 = G1.one() * carol_sk
|
||||
let carol_pk2 = G2.one() * carol_sk
|
||||
# Each party computes the shared secret
|
||||
let alice_ss = pairing(bob_pk1, carol_pk2).pow(alice_sk)
|
||||
let bob_ss = pairing(carol_pk1, alice_pk2).pow(bob_sk)
|
||||
let carol_ss = pairing(alice_pk1, bob_pk2).pow(carol_sk)
|
||||
|
||||
result = (alice_ss == bob_ss and bob_ss == carol_ss)
|
||||
|
||||
when isMainModule:
|
||||
suite "Pairing test suite":
|
||||
test "Prepared G2 test":
|
||||
check testPreparedG2() == true
|
||||
test "Miller loop test":
|
||||
check testMillerLoop() == true
|
||||
test "Reduced pairing test":
|
||||
check testReducedPairing() == true
|
||||
test "Binlinearity test":
|
||||
check testBinlinearity() == true
|
||||
test "Diffie-Hellman test":
|
||||
check testDH() == true
|
||||
test "Joux test":
|
||||
check testJoux() == true
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue