constantine/tests/t_hash_to_curve.nim

217 lines
6.0 KiB
Nim

# 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
std/[unittest, times, os, strutils],
# 3rd party
pkg/jsony,
# Internals
../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
# 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* =
currentSourcePath.rsplit(DirSep, 1)[0] / "protocol_hash_to_curve"
proc parseHook*(src: string, pos: var int, value: var ECP_ShortW_Aff) =
# Note when nim-serialization was used:
# When ECP_ShortW_Aff[Fp[Foo], G1]
# and ECP_ShortW_Aff[Fp[Foo], G2]
# 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
) =
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"
suite testSuiteDesc & " [" & $WordBitWidth & "-bit mode]":
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
P_ref.fromAffine(vec.vectors[i].P)
doAssert: bool(P == P_ref)
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"
suite testSuiteDesc & " [" & $WordBitWidth & "-bit mode]":
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)
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
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"
)
run_hash_to_curve_test(
ECP_ShortW_Prj[Fp2[BLS12_381], G2],
"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
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"
)
run_hash_to_curve_test(
ECP_ShortW_Prj[Fp2[BLS12_381], G2],
"v7",
"tv_h2c_v7_BLS12_381_hash_to_G2_SHA256_SSWU_RO.json"
)
# 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"
)