2021-08-15 09:41:46 +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
|
|
|
|
std/[os, times],
|
|
|
|
# Internals
|
|
|
|
../constantine/config/common,
|
|
|
|
../constantine/[
|
|
|
|
arithmetic, primitives,
|
|
|
|
towers, ec_shortweierstrass,
|
|
|
|
hashes
|
|
|
|
],
|
|
|
|
../constantine/elliptic/ec_scalar_mul,
|
|
|
|
../constantine/io/[io_fields, io_towers, io_ec],
|
|
|
|
../constantine/config/curves,
|
|
|
|
../constantine/hash_to_curve/[hash_to_curve, cofactors],
|
|
|
|
../constantine/pairing/pairing_bls12,
|
|
|
|
# Test utilities
|
|
|
|
../helpers/prng_unsafe
|
|
|
|
|
|
|
|
# Testing implementation of BLS signature scheme
|
|
|
|
# with low-level primitives
|
|
|
|
# ----------------------------------------------
|
|
|
|
|
|
|
|
var rng: RngState
|
|
|
|
let timeseed = uint32(toUnix(getTime()) and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
|
|
|
seed(rng, timeseed)
|
|
|
|
echo "\n------------------------------------------------------\n"
|
|
|
|
echo "test_sig_bls xoshiro512** seed: ", timeseed
|
|
|
|
|
|
|
|
# Generators
|
|
|
|
# -------------------------------------------------------------
|
|
|
|
# https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-10#section-4.2.1
|
|
|
|
#
|
|
|
|
const BLS12_381_G1_generator_x = Fp[BLS12_381].fromHex(
|
|
|
|
"0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac58" &
|
|
|
|
"6c55e83ff97a1aeffb3af00adb22c6bb"
|
|
|
|
)
|
|
|
|
|
|
|
|
const BLS12_381_G1_generator_y = Fp[BLS12_381].fromHex(
|
|
|
|
"0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3ed" &
|
|
|
|
"d03cc744a2888ae40caa232946c5e7e1"
|
|
|
|
)
|
|
|
|
|
|
|
|
const BLS12_381_G2_generator_x = Fp2[BLS12_381].fromHex(
|
|
|
|
"0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d177" &
|
|
|
|
"0bac0326a805bbefd48056c8c121bdb8",
|
|
|
|
"0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049" &
|
|
|
|
"334cf11213945d57e5ac7d055d042b7e"
|
|
|
|
)
|
|
|
|
|
|
|
|
const BLS12_381_G2_generator_y = Fp2[BLS12_381].fromHex(
|
|
|
|
"0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c" &
|
|
|
|
"923ac9cc3baca289e193548608b82801",
|
|
|
|
"0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab" &
|
|
|
|
"3f370d275cec1da1aaa9075ff05f79be"
|
|
|
|
)
|
|
|
|
|
|
|
|
const BLS12_381_G1_generator = ECP_ShortW_Aff[Fp[BLS12_381], NotOnTwist](
|
|
|
|
x: BLS12_381_G1_generator_x, y: BLS12_381_G1_generator_y
|
|
|
|
)
|
|
|
|
const BLS12_381_G2_generator = ECP_ShortW_Aff[Fp2[BLS12_381], OnTwist](
|
|
|
|
x: BLS12_381_G2_generator_x, y: BLS12_381_G2_generator_y
|
|
|
|
)
|
|
|
|
|
|
|
|
# We test using the pubkey on G1, signature on G2 scheme.
|
|
|
|
# with SHA256 hash and proof-of-possession. (Ethereum 2 config).
|
|
|
|
const DomainSepTag = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"
|
|
|
|
|
|
|
|
func genSecretKey(rng: var RngState, seckey: var Fr[BLS12_381]) =
|
|
|
|
# Don't do this at home!
|
|
|
|
seckey = rng.random_unsafe(Fr[BLS12_381])
|
|
|
|
while seckey.isZero().bool:
|
|
|
|
seckey = rng.random_unsafe(Fr[BLS12_381])
|
|
|
|
|
|
|
|
func publicKeyG1(
|
|
|
|
pubkey: var ECP_ShortW_Aff[Fp[BLS12_381], NotOnTwist],
|
|
|
|
seckey: Fr[BLS12_381]
|
|
|
|
) =
|
|
|
|
var t: ECP_ShortW_Prj[Fp[BLS12_381], NotOnTwist]
|
|
|
|
t.projectiveFromAffine(BLS12_381_G1_generator)
|
|
|
|
t.scalarMul(seckey.toBig())
|
|
|
|
pubkey.affineFromprojective(t)
|
|
|
|
doAssert not bool pubkey.isInf()
|
|
|
|
|
|
|
|
func signG2[T: byte|char](
|
|
|
|
signature: var ECP_ShortW_Aff[Fp2[BLS12_381], OnTwist],
|
|
|
|
message: openarray[T],
|
|
|
|
secretKey: Fr[BLS12_381]
|
|
|
|
) =
|
|
|
|
doAssert not bool secretKey.isZero()
|
|
|
|
var t: ECP_ShortW_Prj[Fp2[BLS12_381], OnTwist]
|
|
|
|
hashToCurve(
|
|
|
|
H = sha256, k = 128,
|
|
|
|
output = t,
|
|
|
|
augmentation = "",
|
|
|
|
message = message,
|
|
|
|
domainSepTag = DomainSepTag
|
|
|
|
)
|
|
|
|
t.scalarMul(secretKey.toBig())
|
|
|
|
signature.affineFromprojective(t)
|
|
|
|
doAssert not bool signature.isInf()
|
|
|
|
|
|
|
|
func verifyG2[T: byte|char](
|
|
|
|
pubkey: ECP_ShortW_Aff[Fp[BLS12_381], NotOnTwist],
|
|
|
|
message: openarray[T],
|
|
|
|
signature: ECP_ShortW_Aff[Fp2[BLS12_381], OnTwist]
|
|
|
|
): SecretBool =
|
|
|
|
doAssert not pubkey.isInf.bool
|
|
|
|
doAssert not signature.isInf.bool
|
|
|
|
|
|
|
|
var Q {.noinit.}: typeof(signature)
|
|
|
|
var Qprj {.noInit.}: ECP_ShortW_Prj[Fp2[BLS12_381], OnTwist]
|
|
|
|
hashToCurve(
|
|
|
|
H = sha256, k = 128,
|
|
|
|
output = Qprj,
|
|
|
|
augmentation = "",
|
|
|
|
message = message,
|
|
|
|
domainSepTag = DomainSepTag
|
|
|
|
)
|
|
|
|
Q.affineFromprojective(Qprj)
|
|
|
|
|
|
|
|
var e0{.noInit.}, e1{.noInit.}: Fp12[BLS12_381]
|
|
|
|
e0.pairing_bls12(pubkey, Q)
|
|
|
|
e1.pairing_bls12(BLS12_381_G1_generator, signature)
|
|
|
|
|
|
|
|
return e0 == e1
|
|
|
|
|
2021-08-16 20:22:51 +00:00
|
|
|
func verifyG2_multi[T: byte|char](
|
|
|
|
pubkey: ECP_ShortW_Aff[Fp[BLS12_381], NotOnTwist],
|
|
|
|
message: openarray[T],
|
|
|
|
signature: ECP_ShortW_Aff[Fp2[BLS12_381], OnTwist]
|
|
|
|
): SecretBool =
|
|
|
|
doAssert not pubkey.isInf.bool
|
|
|
|
doAssert not signature.isInf.bool
|
|
|
|
|
|
|
|
var Qprj {.noInit.}: ECP_ShortW_Prj[Fp2[BLS12_381], OnTwist]
|
|
|
|
hashToCurve(
|
|
|
|
H = sha256, k = 128,
|
|
|
|
output = Qprj,
|
|
|
|
augmentation = "",
|
|
|
|
message = message,
|
|
|
|
domainSepTag = DomainSepTag
|
|
|
|
)
|
|
|
|
|
|
|
|
var G2s: array[2, ECP_ShortW_Aff[Fp2[BLS12_381], OnTwist]]
|
|
|
|
var G1s: array[2, ECP_ShortW_Aff[Fp[BLS12_381], NotOnTwist]]
|
|
|
|
|
|
|
|
G1s[0] = pubkey
|
|
|
|
G2s[0].affineFromprojective(Qprj)
|
|
|
|
|
|
|
|
G1s[1].neg(BLS12_381_G1_generator)
|
|
|
|
G2s[1] = signature
|
|
|
|
|
|
|
|
var e: Fp12[BLS12_381]
|
|
|
|
e.pairing_bls12(G1s, G2s)
|
|
|
|
|
|
|
|
return e.isOne()
|
|
|
|
|
2021-08-15 09:41:46 +00:00
|
|
|
proc bls_signature_test(rng: var RngState, i: int) =
|
|
|
|
var
|
|
|
|
seckey: Fr[BLS12_381]
|
|
|
|
pubkey: ECP_ShortW_Aff[Fp[BLS12_381], NotOnTwist]
|
|
|
|
message = rng.random_byte_seq(length = i)
|
|
|
|
signature: ECP_ShortW_Aff[Fp2[BLS12_381], OnTwist]
|
|
|
|
|
|
|
|
rng.genSecretKey(seckey)
|
|
|
|
pubkey.publicKeyG1(seckey)
|
|
|
|
signature.signG2(message, seckey)
|
|
|
|
|
2021-08-16 20:22:51 +00:00
|
|
|
let okSingle = pubkey.verifyG2(message, signature)
|
|
|
|
doAssert bool okSingle
|
|
|
|
|
|
|
|
let okMulti = pubkey.verifyG2_multi(message, signature)
|
|
|
|
doAssert bool okMulti
|
2021-08-15 09:41:46 +00:00
|
|
|
|
|
|
|
for i in 0 ..< 500:
|
|
|
|
rng.bls_signature_test(i)
|
|
|
|
stdout.write('.')
|
|
|
|
stdout.flushFile()
|
|
|
|
stdout.write('\n')
|
|
|
|
|
|
|
|
echo "SUCCESS - BLS Signature scheme on BLS12_381, pubkey on G1, signatures on G2"
|