2021-08-13 20:07:26 +00:00
|
|
|
# Constantine
|
|
|
|
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
|
|
|
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
|
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
|
|
|
import
|
|
|
|
# Standard library
|
2023-01-12 19:25:57 +00:00
|
|
|
std/[unittest, times, os, strutils],
|
2021-08-13 20:07:26 +00:00
|
|
|
# 3rd party
|
2022-02-27 00:49:08 +00:00
|
|
|
pkg/jsony,
|
2021-08-13 20:07:26 +00:00
|
|
|
# Internals
|
2022-04-26 19:24:07 +00:00
|
|
|
../constantine/platforms/abstractions,
|
|
|
|
../constantine/math/config/curves,
|
|
|
|
../constantine/math/extension_fields,
|
|
|
|
../constantine/math/io/[io_bigints, io_ec],
|
|
|
|
../constantine/math/ec_shortweierstrass,
|
|
|
|
../constantine/hash_to_curve/hash_to_curve,
|
|
|
|
../constantine/hashes
|
2021-08-13 20:07:26 +00:00
|
|
|
|
|
|
|
# Serialization
|
|
|
|
# --------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type
|
|
|
|
FieldDesc = object
|
|
|
|
m: string
|
|
|
|
p: string
|
|
|
|
|
|
|
|
MapDesc = object
|
|
|
|
name: string
|
|
|
|
|
|
|
|
HashToCurveTest[EC: ECP_ShortW_Aff] = object
|
|
|
|
L: string
|
|
|
|
Z: string
|
|
|
|
ciphersuite: string
|
|
|
|
curve: string
|
|
|
|
dst: string
|
|
|
|
expand: string
|
|
|
|
field: FieldDesc
|
|
|
|
hash: string
|
|
|
|
k: string
|
|
|
|
map: MapDesc
|
|
|
|
randomOracle: bool
|
|
|
|
vectors: seq[TestVector[EC]]
|
|
|
|
|
|
|
|
TestVector*[EC: ECP_ShortW_Aff] = object
|
|
|
|
P: EC
|
|
|
|
Q0, Q1: EC
|
|
|
|
msg: string
|
|
|
|
u: seq[string]
|
|
|
|
|
|
|
|
EC_G1_hex = object
|
|
|
|
x: string
|
|
|
|
y: string
|
|
|
|
|
|
|
|
Fp2_hex = string
|
|
|
|
|
|
|
|
EC_G2_hex = object
|
|
|
|
x: Fp2_hex
|
|
|
|
y: Fp2_hex
|
|
|
|
|
|
|
|
const
|
|
|
|
TestVectorsDir* =
|
2022-04-26 19:24:07 +00:00
|
|
|
currentSourcePath.rsplit(DirSep, 1)[0] / "protocol_hash_to_curve"
|
2021-08-13 20:07:26 +00:00
|
|
|
|
|
|
|
proc parseHook*(src: string, pos: var int, value: var ECP_ShortW_Aff) =
|
|
|
|
# Note when nim-serialization was used:
|
2022-01-01 18:17:04 +00:00
|
|
|
# When ECP_ShortW_Aff[Fp[Foo], G1]
|
|
|
|
# and ECP_ShortW_Aff[Fp[Foo], G2]
|
2021-08-13 20:07:26 +00:00
|
|
|
# are generated in the same file (i.e. twists and base curve are both on Fp)
|
|
|
|
# this creates bad codegen, in the C code, the `value`parameter gets the wrong type
|
|
|
|
# TODO: upstream
|
|
|
|
when ECP_ShortW_Aff.F is Fp:
|
|
|
|
var P: EC_G1_hex
|
|
|
|
parseHook(src, pos, P)
|
|
|
|
let ok = value.fromHex(P.x, P.y)
|
|
|
|
doAssert ok, "\nDeserialization error on G1 for\n" &
|
|
|
|
" P.x: " & P.x & "\n" &
|
|
|
|
" P.y: " & P.x & "\n"
|
|
|
|
elif ECP_ShortW_Aff.F is Fp2:
|
|
|
|
var P: EC_G2_hex
|
|
|
|
parseHook(src, pos, P)
|
|
|
|
let Px = P.x.split(',')
|
|
|
|
let Py = P.y.split(',')
|
|
|
|
|
|
|
|
let ok = value.fromHex(Px[0], Px[1], Py[0], Py[1])
|
|
|
|
doAssert ok, "\nDeserialization error on G2 for\n" &
|
|
|
|
" P.x0: " & Px[0] & "\n" &
|
|
|
|
" P.x1: " & Px[1] & "\n" &
|
|
|
|
" P.y0: " & Py[0] & "\n" &
|
|
|
|
" P.y1: " & Py[1] & "\n"
|
|
|
|
else:
|
|
|
|
{.error: "Not Implemented".}
|
|
|
|
|
|
|
|
proc loadVectors(TestType: typedesc, filename: string): TestType =
|
|
|
|
let content = readFile(TestVectorsDir/filename)
|
|
|
|
result = content.fromJson(TestType)
|
|
|
|
|
|
|
|
# Testing
|
|
|
|
# ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
proc run_hash_to_curve_test(
|
|
|
|
EC: typedesc,
|
|
|
|
spec_version: string,
|
|
|
|
filename: string
|
|
|
|
) =
|
|
|
|
|
2022-01-01 18:17:04 +00:00
|
|
|
when EC.G == G1:
|
2021-08-13 20:07:26 +00:00
|
|
|
const G1_or_G2 = "G1"
|
|
|
|
else:
|
|
|
|
const G1_or_G2 = "G2"
|
2022-01-01 18:17:04 +00:00
|
|
|
let vec = loadVectors(HashToCurveTest[ECP_ShortW_Aff[EC.F, EC.G]], filename)
|
2021-08-13 20:07:26 +00:00
|
|
|
|
|
|
|
let testSuiteDesc = "Hash to Curve " & $EC.F.C & " " & G1_or_G2 & " - official specs " & spec_version & " test vectors"
|
|
|
|
|
2023-02-16 11:45:05 +00:00
|
|
|
suite testSuiteDesc & " [" & $WordBitWidth & "-bit words]":
|
2021-08-13 20:07:26 +00:00
|
|
|
|
|
|
|
doAssert vec.hash == "sha256"
|
|
|
|
doAssert vec.k == "0x80" # 128
|
|
|
|
|
|
|
|
for i in 0 ..< vec.vectors.len:
|
|
|
|
test "test " & $i & " - msg: \'" & vec.vectors[i].msg & "\'":
|
|
|
|
var P{.noInit.}: EC
|
|
|
|
sha256.hashToCurve(
|
|
|
|
k = 128,
|
|
|
|
output = P,
|
|
|
|
augmentation = "",
|
|
|
|
message = vec.vectors[i].msg,
|
|
|
|
domainSepTag = vec.dst
|
|
|
|
)
|
|
|
|
|
|
|
|
var P_ref: EC
|
2022-02-10 13:05:07 +00:00
|
|
|
P_ref.fromAffine(vec.vectors[i].P)
|
2021-08-13 20:07:26 +00:00
|
|
|
|
|
|
|
doAssert: bool(P == P_ref)
|
|
|
|
|
2022-04-26 19:24:07 +00:00
|
|
|
proc run_hash_to_curve_svdw_test(
|
|
|
|
EC: typedesc,
|
|
|
|
spec_version: string,
|
|
|
|
filename: string
|
|
|
|
) =
|
|
|
|
|
|
|
|
when EC.G == G1:
|
|
|
|
const G1_or_G2 = "G1"
|
|
|
|
else:
|
|
|
|
const G1_or_G2 = "G2"
|
|
|
|
let vec = loadVectors(HashToCurveTest[ECP_ShortW_Aff[EC.F, EC.G]], filename)
|
|
|
|
|
|
|
|
let testSuiteDesc = "Hash to Curve " & $EC.F.C & " " & G1_or_G2 & " - official specs " & spec_version & " test vectors"
|
|
|
|
|
2023-02-16 11:45:05 +00:00
|
|
|
suite testSuiteDesc & " [" & $WordBitWidth & "-bit words]":
|
2022-04-26 19:24:07 +00:00
|
|
|
|
|
|
|
doAssert vec.hash == "sha256"
|
|
|
|
doAssert vec.k == "0x80" # 128
|
|
|
|
|
|
|
|
for i in 0 ..< vec.vectors.len:
|
|
|
|
test "test " & $i & " - msg: \'" & vec.vectors[i].msg & "\'":
|
|
|
|
var P{.noInit.}: EC
|
|
|
|
sha256.hashToCurve_svdw(
|
|
|
|
k = 128,
|
|
|
|
output = P,
|
|
|
|
augmentation = "",
|
|
|
|
message = vec.vectors[i].msg,
|
|
|
|
domainSepTag = vec.dst
|
|
|
|
)
|
|
|
|
|
|
|
|
var P_ref: EC
|
|
|
|
P_ref.fromAffine(vec.vectors[i].P)
|
|
|
|
|
|
|
|
doAssert: bool(P == P_ref)
|
|
|
|
|
2021-08-13 20:07:26 +00:00
|
|
|
echo "\n------------------------------------------------------\n"
|
|
|
|
echo "Hash-to-curve" & '\n'
|
|
|
|
|
|
|
|
# Hash-to-curve v8 to latest
|
|
|
|
# https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/blob/draft-irtf-cfrg-hash-to-curve-10/poc/vectors/BLS12381G2_XMD:SHA-256_SSWU_RO_.json
|
2022-04-10 22:57:16 +00:00
|
|
|
run_hash_to_curve_test(
|
|
|
|
ECP_ShortW_Prj[Fp[BLS12_381], G1],
|
|
|
|
"v8",
|
|
|
|
"tv_h2c_v8_BLS12_381_hash_to_G1_SHA256_SSWU_RO.json"
|
|
|
|
)
|
|
|
|
|
2021-08-13 20:07:26 +00:00
|
|
|
run_hash_to_curve_test(
|
2022-01-01 18:17:04 +00:00
|
|
|
ECP_ShortW_Prj[Fp2[BLS12_381], G2],
|
2021-08-13 20:07:26 +00:00
|
|
|
"v8",
|
|
|
|
"tv_h2c_v8_BLS12_381_hash_to_G2_SHA256_SSWU_RO.json"
|
|
|
|
)
|
|
|
|
|
|
|
|
# Hash-to-curve v7 (different domain separation tag)
|
|
|
|
# https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/blob/draft-irtf-cfrg-hash-to-curve-07/poc/vectors/BLS12381G2_XMD:SHA-256_SSWU_RO_.json
|
2022-04-10 22:57:16 +00:00
|
|
|
run_hash_to_curve_test(
|
|
|
|
ECP_ShortW_Prj[Fp[BLS12_381], G1],
|
|
|
|
"v7",
|
|
|
|
"tv_h2c_v7_BLS12_381_hash_to_G1_SHA256_SSWU_RO.json"
|
|
|
|
)
|
|
|
|
|
2021-08-13 20:07:26 +00:00
|
|
|
run_hash_to_curve_test(
|
2022-01-01 18:17:04 +00:00
|
|
|
ECP_ShortW_Prj[Fp2[BLS12_381], G2],
|
2021-08-13 20:07:26 +00:00
|
|
|
"v7",
|
|
|
|
"tv_h2c_v7_BLS12_381_hash_to_G2_SHA256_SSWU_RO.json"
|
|
|
|
)
|
2022-04-26 19:24:07 +00:00
|
|
|
|
|
|
|
# With the slower universal SVDW mapping instead of SSWU
|
|
|
|
run_hash_to_curve_svdw_test(
|
|
|
|
ECP_ShortW_Jac[Fp[BLS12_381], G1],
|
|
|
|
"v7 (SVDW)",
|
|
|
|
"tv_h2c_v7_BLS12_381_hash_to_G1_SHA256_SVDW_RO.json"
|
|
|
|
)
|
|
|
|
|
|
|
|
run_hash_to_curve_svdw_test(
|
|
|
|
ECP_ShortW_Jac[Fp2[BLS12_381], G2],
|
|
|
|
"v7 (SVDW)",
|
|
|
|
"tv_h2c_v7_BLS12_381_hash_to_G2_SHA256_SVDW_RO.json"
|
|
|
|
)
|