BLS signatures for Ethereum (BLS sig on BLS12-381 G2 with SHA256) (#183)

* Finally add the (Ethereum) bls signatures (on BLS12-381 G2)

* fix test path and remove old low-level signature test
This commit is contained in:
Mamy Ratsimbazafy 2022-02-26 21:22:34 +01:00 committed by GitHub
parent fe500a6a79
commit 5bc6d1d426
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
126 changed files with 1255 additions and 257 deletions

View File

@ -45,7 +45,7 @@ After [installation](#installation), the available high-level protocols are:
- [x] Ethereum EVM precompiles on BN254_Snarks (also called alt_bn128 or bn256 in Ethereum)
`import constantine/ethereum_evm_precompiles`
- [ ] BLS signature on BLS12-381 G2 as used in Ethereum 2.
- [x] BLS signature on BLS12-381 G2 as used in Ethereum 2.
Cryptographic suite: `BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_`
This scheme is also used in the following blockchains:

View File

@ -0,0 +1,187 @@
# 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
# Internals
../constantine/blssig_pop_on_bls12381_g2,
# Helpers
../helpers/prng_unsafe,
./bench_blueprint
proc separator*() = separator(132)
proc report(op, curve: string, startTime, stopTime: MonoTime, startClk, stopClk: int64, iters: int) =
let ns = inNanoseconds((stopTime-startTime) div iters)
let throughput = 1e9 / float64(ns)
when SupportsGetTicks:
echo &"{op:<40} {curve:<15} {throughput:>15.3f} ops/s {ns:>9} ns/op {(stopClk - startClk) div iters:>9} CPU cycles (approx)"
else:
echo &"{op:<40} {curve:<15} {throughput:>15.3f} ops/s {ns:>9} ns/op"
template bench(op: string, curve: string, iters: int, body: untyped): untyped =
measure(iters, startTime, stopTime, startClk, stopClk, body)
report(op, curve, startTime, stopTime, startClk, stopClk, iters)
proc benchDeserPubkey*(iters: int) =
var seckey: array[32, byte]
for i in 1 ..< 32:
seckey[i] = byte 42
var
sk{.noInit.}: SecretKey
pk{.noInit.}: PublicKey
pk_comp{.noInit.}: array[48, byte]
let ok = sk.deserialize_secret_key(seckey)
doAssert ok == cttBLS_Success
let ok2 = pk.derive_public_key(sk)
doAssert ok2 == cttBLS_Success
# Serialize compressed
let ok3 = pk_comp.serialize_public_key_compressed(pk)
doAssert ok3 == cttBLS_Success
var pk2{.noInit.}: PublicKey
bench("Pubkey deserialization (full checks)", "BLS12_381 G1", iters):
let status = pk2.deserialize_public_key_compressed(pk_comp)
proc benchDeserPubkeyUnchecked*(iters: int) =
var seckey: array[32, byte]
for i in 1 ..< 32:
seckey[i] = byte 42
var
sk{.noInit.}: SecretKey
pk{.noInit.}: PublicKey
pk_comp{.noInit.}: array[48, byte]
let ok = sk.deserialize_secret_key(seckey)
doAssert ok == cttBLS_Success
let ok2 = pk.derive_public_key(sk)
doAssert ok2 == cttBLS_Success
# Serialize compressed
let ok3 = pk_comp.serialize_public_key_compressed(pk)
doAssert ok3 == cttBLS_Success
var pk2{.noInit.}: PublicKey
bench("Pubkey deserialization (skip checks)", "BLS12_381 G1", iters):
let status = pk2.deserialize_public_key_compressed_unchecked(pk_comp)
proc benchDeserSig*(iters: int) =
var seckey: array[32, byte]
for i in 1 ..< 32:
seckey[i] = byte 42
const msg = "abcdef0123456789"
var
sk{.noInit.}: SecretKey
pk{.noInit.}: PublicKey
sig_comp{.noInit.}: array[96, byte]
sig {.noInit.}: Signature
let ok = sk.deserialize_secret_key(seckey)
doAssert ok == cttBLS_Success
let ok2 = pk.derive_public_key(sk)
doAssert ok2 == cttBLS_Success
let status = sig.sign(sk, msg)
doAssert status == cttBLS_Success
# Serialize compressed
let ok3 = sig_comp.serialize_signature_compressed(sig)
doAssert ok3 == cttBLS_Success
var sig2{.noInit.}: Signature
bench("Signature deserialization (full checks)", "BLS12_381 G2", iters):
let status = sig2.deserialize_signature_compressed(sig_comp)
proc benchDeserSigUnchecked*(iters: int) =
var seckey: array[32, byte]
for i in 1 ..< 32:
seckey[i] = byte 42
const msg = "abcdef0123456789"
var
sk{.noInit.}: SecretKey
pk{.noInit.}: PublicKey
sig_comp{.noInit.}: array[96, byte]
sig {.noInit.}: Signature
let ok = sk.deserialize_secret_key(seckey)
doAssert ok == cttBLS_Success
let ok2 = pk.derive_public_key(sk)
doAssert ok2 == cttBLS_Success
let status = sig.sign(sk, msg)
doAssert status == cttBLS_Success
# Serialize compressed
let ok3 = sig_comp.serialize_signature_compressed(sig)
doAssert ok3 == cttBLS_Success
var sig2{.noInit.}: Signature
bench("Signature deserialization (skip checks)", "BLS12_381 G2", iters):
let status = sig2.deserialize_signature_compressed_unchecked(sig_comp)
proc benchSign*(iters: int) =
var seckey: array[32, byte]
for i in 1 ..< 32:
seckey[i] = byte 42
let msg = "Mr F was here"
var pk: PublicKey
var sk: SecretKey
var sig: Signature
let ok = sk.deserialize_secret_key(seckey)
doAssert ok == cttBLS_Success
bench("BLS signature", "BLS12_381 G2", iters):
let status = sig.sign(sk, msg)
doAssert status == cttBLS_Success
proc benchVerify*(iters: int) =
var seckey: array[32, byte]
for i in 1 ..< 32:
seckey[i] = byte 42
let msg = "Mr F was here"
var pk: PublicKey
var sk: SecretKey
var sig: Signature
let ok = sk.deserialize_secret_key(seckey)
doAssert ok == cttBLS_Success
let ok2 = sig.sign(sk, msg)
let ok3 = pk.derive_public_key(sk)
doAssert ok3 == cttBLS_Success
bench("BLS verification", "BLS12_381", iters):
let valid = pk.verify(msg, sig)
const Iters = 1000
proc main() =
separator()
benchDeserPubkey(Iters)
benchDeserPubkeyUnchecked(Iters)
benchDeserSig(Iters)
benchDeserSigUnchecked(Iters)
separator()
benchSign(Iters)
benchVerify(Iters)
separator()
main()
notes()

View File

@ -38,7 +38,7 @@ macro fixFieldDisplay(T: typedesc): untyped =
# At compile-time, enums are integers and their display is buggy
# we get the Curve ID instead of the curve name.
let instantiated = T.getTypeInst()
var name = $instantiated[1][0] # Fp
var name = $instantiated[1][0] # 𝔽p
name.add "[" & $Curve(instantiated[1][1].intVal) & "]"
result = newLit name

View File

@ -190,8 +190,8 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
# Protocols
# ----------------------------------------------------------
("tests/t_sig_bls_lowlevel.nim", false),
("tests/t_ethereum_evm_precompiles.nim", false),
("tests/t_blssig_pop_on_bls12381_g2.nim", false),
]
# For temporary (hopefully) investigation that can only be reproduced in CI
@ -209,9 +209,7 @@ const skipSanitizers = [
"tests/backend/t_ec_sage_bls12_377.nim",
"tests/backend/t_ec_sage_bls12_381.nim",
"tests/backend/t_hash_to_field.nim",
"tests/backend/t_hash_to_curve.nim",
"tests/backend/t_sig_bls_lowlevel.nim",
"tests/protocols/t_ethereum_evm_precompiles.nim"
"tests/backend/t_hash_to_curve.nim"
]
when defined(windows):
@ -746,3 +744,20 @@ task bench_hash_to_curve_gcc_noasm, "Run Hash-to-Curve benchmarks":
task bench_hash_to_curve_clang_noasm, "Run Hash-to-Curve benchmarks":
runBench("bench_hash_to_curve", "clang", useAsm = false)
# BLS signatures
# ------------------------------------------
task bench_blssig_on_bls12_381_g2, "Run Hash-to-Curve benchmarks":
runBench("bench_blssig_on_bls12_381_g2")
task bench_blssig_on_bls12_381_g2_gcc, "Run Hash-to-Curve benchmarks":
runBench("bench_blssig_on_bls12_381_g2", "gcc")
task bench_blssig_on_bls12_381_g2_clang, "Run Hash-to-Curve benchmarks":
runBench("bench_blssig_on_bls12_381_g2", "clang")
task bench_blssig_on_bls12_381_g2_gcc_noasm, "Run Hash-to-Curve benchmarks":
runBench("bench_blssig_on_bls12_381_g2", "gcc", useAsm = false)
task bench_blssig_on_bls12_381_g2_clang_noasm, "Run Hash-to-Curve benchmarks":
runBench("bench_blssig_on_bls12_381_g2", "clang", useAsm = false)

View File

@ -36,7 +36,7 @@ export CurveFamily, SexticTwist
# - type Curve* = enum
# - proc Mod*(curve: static Curve): auto
# which returns the field modulus of the curve
# - proc Family*(curve: static Curve): CurveFamily
# - proc family*(curve: static Curve): CurveFamily
# which returns the curve family
declareCurves:

View File

@ -0,0 +1,32 @@
# 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
../config/[curves, type_ff],
../elliptic/ec_shortweierstrass_affine,
../io/[io_fields, io_towers]
# Generators
# -----------------------------------------------------------------
# https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-10#section-4.2.1
const BLS12_381_generator_G1* = ECP_ShortW_Aff[Fp[BLS12_381], G1](
x: Fp[BLS12_381].fromHex"0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb",
y: Fp[BLS12_381].fromHex"0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1"
)
const BLS12_381_generator_G2* = ECP_ShortW_Aff[Fp2[BLS12_381], G2](
x: Fp2[BLS12_381].fromHex(
"0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8",
"0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e"
),
y: Fp2[BLS12_381].fromHex(
"0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801",
"0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be"
)
)

View File

@ -82,11 +82,11 @@ const Cofactor_Eff_BLS12_381_G2 = BigInt[636].fromHex"0xbc69f08f2ee75b3584c6a0ea
## P -> (x^2 - x - 1) P + (x - 1) ψ(P) + ψ(ψ(2P))
func clearCofactorReference*(P: var ECP_ShortW_Prj[Fp[BLS12_381], G1]) {.inline.} =
## Clear the cofactor of BLS12_381 G1
## Clear the cofactor of BLS12_381 𝔾1
P.scalarMulGeneric(Cofactor_Eff_BLS12_381_G1)
func clearCofactorReference*(P: var ECP_ShortW_Prj[Fp2[BLS12_381], G2]) {.inline.} =
## Clear the cofactor of BLS12_381 G2
## Clear the cofactor of BLS12_381 𝔾2
# Endomorphism acceleration cannot be used if cofactor is not cleared
P.scalarMulGeneric(Cofactor_Eff_BLS12_381_G2)
@ -96,11 +96,11 @@ func clearCofactorReference*(P: var ECP_ShortW_Prj[Fp2[BLS12_381], G2]) {.inline
#
# ############################################################
# BLS12 G1
# BLS12 𝔾1
# ------------------------------------------------------------
func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp[BLS12_381], G1]) =
## Clear the cofactor of BLS12_381 G1
func clearCofactorFast*(P: var ECP_ShortW[Fp[BLS12_381], G1]) =
## Clear the cofactor of BLS12_381 𝔾1
##
## Wahby et al "Fast and simple constant-time hashing to the BLS12-381 elliptic curve", https://eprint.iacr.org/2019/403
## Optimized using endomorphisms
@ -109,19 +109,19 @@ func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp[BLS12_381], G1]) =
t.pow_bls12_381_minus_x(P) # [-x]P
P += t # [1-x]P
# BLS12 G2
# BLS12 𝔾2
# ------------------------------------------------------------
# From any point on the elliptic curve E2 of a BLS12 curve
# Obtain a point in the G2 prime-order subgroup
# Obtain a point in the 𝔾2 prime-order subgroup
#
# Described in https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-G.4
#
# Implementations, multiple implementations are possible in increasing order of speed:
#
# - The default, canonical, implementation is h_eff * P
# - Scott et al, "Fast Hashing to G2 on Pairing-Friendly Curves", https://doi.org/10.1007/978-3-642-03298-1_8
# - Fuentes-Castaneda et al, "Fast Hashing to G2 on Pairing-Friendly Curves", https://doi.org/10.1007/978-3-642-28496-0_25
# - Budroni et al, "Hashing to G2 on BLS pairing-friendly curves", https://doi.org/10.1145/3313880.3313884
# - Scott et al, "Fast Hashing to 𝔾2 on Pairing-Friendly Curves", https://doi.org/10.1007/978-3-642-03298-1_8
# - Fuentes-Castaneda et al, "Fast Hashing to 𝔾2 on Pairing-Friendly Curves", https://doi.org/10.1007/978-3-642-28496-0_25
# - Budroni et al, "Hashing to 𝔾2 on BLS pairing-friendly curves", https://doi.org/10.1145/3313880.3313884
# - Wahby et al "Fast and simple constant-time hashing to the BLS12-381 elliptic curve", https://eprint.iacr.org/2019/403
# - IETF "Hashing to Elliptic Curves", https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-G.4
#
@ -138,8 +138,8 @@ func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp[BLS12_381], G1]) =
# with Psi (ψ) - untwist-Frobenius-Twist function
# and x the curve BLS parameter
func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp2[BLS12_381], G2]) =
## Clear the cofactor of BLS12_381 G2
func clearCofactorFast*(P: var ECP_ShortW[Fp2[BLS12_381], G2]) =
## Clear the cofactor of BLS12_381 𝔾2
## Optimized using endomorphisms
## P -> [x²-x-1]P + [x-1] ψ(P) + ψ²([2]P)
@ -166,18 +166,18 @@ func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp2[BLS12_381], G2]) =
#
# ############################################################
func isInSubgroup*(P: ECP_ShortW_Prj[Fp[BLS12_381], G1]): SecretBool =
## Returns true if P is in G1 subgroup, i.e. P is a point of order r.
func isInSubgroup*(P: ECP_ShortW_Jac[Fp[BLS12_381], G1] or ECP_ShortW_Prj[Fp[BLS12_381], G1]): SecretBool =
## Returns true if P is in 𝔾1 subgroup, i.e. P is a point of order r.
## A point may be on a curve but not on the prime order r subgroup.
## Not checking subgroup exposes a protocol to small subgroup attacks.
##
## Warning ⚠: Assumes that P is on curve
# Implementation: Scott, https://eprint.iacr.org/2021/1130.pdf
# A note on group membership tests for G1, G2 and GT
# A note on group membership tests for 𝔾1, 𝔾2 and 𝔾T
# on BLS pairing-friendly curves
# P is in the G1 subgroup iff ϕ(P) == [-u²](P)
var t0{.noInit.}, t1{.noInit.}: ECP_ShortW_Prj[Fp[BLS12_381], G1]
# P is in the 𝔾1 subgroup iff ϕ(P) == [-u²](P)
var t0{.noInit.}, t1{.noInit.}: typeof(P)
# [-u²]P
t0.pow_bls12_381_x(P)
t1.pow_bls12_381_minus_x(t0)
@ -189,18 +189,39 @@ func isInSubgroup*(P: ECP_ShortW_Prj[Fp[BLS12_381], G1]): SecretBool =
return t0 == t1
func isInSubgroup*(P: ECP_ShortW_Prj[Fp2[BLS12_381], G2]): SecretBool =
## Returns true if P is in G2 subgroup, i.e. P is a point of order r.
func isInSubgroup*(P: ECP_ShortW_Jac[Fp2[BLS12_381], G2] or ECP_ShortW_Prj[Fp2[BLS12_381], G2]): SecretBool =
## Returns true if P is in 𝔾2 subgroup, i.e. P is a point of order r.
## A point may be on a curve but not on the prime order r subgroup.
## Not checking subgroup exposes a protocol to small subgroup attacks.
##
## Warning ⚠: Assumes that P is on curve
# Implementation: Scott, https://eprint.iacr.org/2021/1130.pdf
# A note on group membership tests for G1, G2 and GT
# A note on group membership tests for 𝔾1, 𝔾2 and 𝔾T
# on BLS pairing-friendly curves
# P is in the G1 subgroup iff ψ(P) == [u](P)
var t0{.noInit.}, t1{.noInit.}: ECP_ShortW_Prj[Fp2[BLS12_381], G2]
# P is in the 𝔾1 subgroup iff ψ(P) == [u](P)
var t0{.noInit.}, t1{.noInit.}: typeof(P)
t0.pow_bls12_381_x(P) # [u]P
t1.frobenius_psi(P) # ψ(P)
return t0 == t1
return t0 == t1
func isInSubgroup*(P: ECP_ShortW_Aff[Fp[BLS12_381], G1]): SecretBool =
## Returns true if P is in 𝔾1 subgroup, i.e. P is a point of order r.
## A point may be on a curve but not on the prime order r subgroup.
## Not checking subgroup exposes a protocol to small subgroup attacks.
##
## Warning ⚠: Assumes that P is on curve
var t{.noInit.}: ECP_ShortW_Prj[Fp[BLS12_381], G1]
t.fromAffine(P)
return t.isInSubgroup()
func isInSubgroup*(P: ECP_ShortW_Aff[Fp2[BLS12_381], G2]): SecretBool =
## Returns true if P is in 𝔾2 subgroup, i.e. P is a point of order r.
## A point may be on a curve but not on the prime order r subgroup.
## Not checking subgroup exposes a protocol to small subgroup attacks.
##
## Warning ⚠: Assumes that P is on curve
var t{.noInit.}: ECP_ShortW_Jac[Fp2[BLS12_381], G2]
t.fromAffine(P)
return t.isInSubgroup()

View File

@ -9,11 +9,11 @@
import
std/macros,
../config/curves,
./bls12_377_g2_params,
./bls12_381_g2_params,
./bn254_nogami_g2_params,
./bn254_snarks_g2_params,
./bw6_761_g2_params
./bls12_377_constants,
./bls12_381_constants,
./bn254_nogami_constants,
./bn254_snarks_constants,
./bw6_761_constants
{.experimental: "dynamicBindSym".}

View File

@ -0,0 +1,23 @@
# 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
std/macros,
../config/curves,
./bls12_381_generators
{.experimental: "dynamicbindsym".}
macro getGenerator*(C: static Curve, subgroup: static string = ""): untyped =
## Returns the curve subgroup generator.
## Pairing-friendly curves expect G1 or G2
if subgroup == "":
return bindSym($C & "_generator")
else:
return bindSym($C & "_generator_" & subgroup)

View File

@ -25,7 +25,7 @@ export
func clearCofactor*[ECP](P: var ECP) {.inline.} =
## Clear the cofactor of a point on the curve
## From a point on the curve, returns a point on the subgroup of order r
when ECP.F.C in {BLS12_381}:
when ECP.F.C in {BN254_Nogami, BN254_SNarks, BLS12_377, BLS12_381}:
P.clearCofactorFast()
else:
P.clearCofactorReference()

View File

@ -29,7 +29,6 @@ import
# using:
# - GLV endomorphism on G1 (Gallant-Lambert-Vanstone)
# - GLV and GLS endomorphisms on G2 (Galbraith-Lin-Scott)
# - NAF recoding (windowed Non-Adjacent-Form)
# Decomposition into scalars -> miniscalars
# ----------------------------------------------------------------------------------------

View File

@ -12,7 +12,7 @@ import
../arithmetic,
../towers,
../io/[io_fields, io_towers],
../curves/zoo_g2_params
../curves/zoo_constants
# ############################################################
#
@ -45,6 +45,11 @@ func isInf*(P: ECP_ShortW_Aff): SecretBool =
## and false otherwise
result = P.x.isZero() and P.y.isZero()
func setInf*(P: var ECP_ShortW_Aff) =
## Set P to the infinity point
P.x.setZero()
P.y.setZero()
func ccopy*(P: var ECP_ShortW_Aff, Q: ECP_ShortW_Aff, ctl: SecretBool) {.inline.} =
## Constant-time conditional copy
## If ctl is true: Q is copied into P
@ -71,7 +76,7 @@ func curve_eq_rhs*[F](y2: var F, x: F, G: static Subgroup) =
y2.fromUint uint -F.C.getCoefB()
y2.diff(t, y2)
else:
y2.sum(F.C.getCoefB_G2, t)
y2.sum(F.C.getCoefB_G2(), t)
when F.C.getCoefA() != 0:
t = x

View File

@ -41,14 +41,14 @@ template strxor(b_i: var array, b0: array): untyped =
b_i[i] = b_i[i] xor b0[i]
# ----------------------------------------------------------------
func shortDomainSepTag[DigestSize: static int, B: byte|char](
func shortDomainSepTag*[DigestSize: static int, B: byte|char](
H: type CryptoHash,
output: var array[DigestSize, byte],
oversizedDST: openarray[B]) =
## Compute a short Domain Separation Tag
## from a domain separation tag larger than 255 bits
## from a domain separation tag larger than 255 bytes
##
## https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-09#section-5.4.3
## https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-14#section-5.4.3
static: doAssert DigestSize == H.type.digestSize
var ctx {.noInit.}: H
ctx.init()
@ -86,11 +86,10 @@ func expandMessageXMD*[B1, B2, B3: byte|char, len_in_bytes: static int](
## and `CoreVerify(PK, PK || message, signature)`
## - `message` is the message to hash
## - `domainSepTag` is the protocol domain separation tag (DST).
## If a domainSepTag larger than 255-bit is required,
## it is recommended to cache the reduced DST
# TODO oversized DST support
## `domainSepTag` MUST be at most 255 bytes.
## The function `shortDomainSepTag` MUST be used to compute an adequate DST
## for an oversized source DST.
## That DST can be cached.
# Steps:
# 1. ell = ceil(len_in_bytes / b_in_bytes)
# 2. ABORT if ell > 255
@ -210,7 +209,7 @@ func hashToField*[Field; B1, B2, B3: byte|char, count: static int](
len_in_bytes = count * m * L
var uniform_bytes{.noInit.}: array[len_in_bytes, byte]
sha256.expandMessageXMD(
H.expandMessageXMD(
uniform_bytes,
augmentation = augmentation,
message = message,

View File

@ -54,7 +54,7 @@ func sgn0(x: Fp): SecretBool =
# Another angle is that if M is odd,
# a+M and a have different parity even though they are
# the same modulo M.
let canonical = x.toBig()
let canonical {.noInit.} = x.toBig()
result = canonical.isOdd()
func sgn0(x: Fp2): SecretBool =

View File

@ -125,7 +125,7 @@ func hashToCurve*[
B1, B2, B3: byte|char](
H: type CryptoHash,
k: static int,
output: var ECP_ShortW_Prj[F, G],
output: var ECP_ShortW_Jac[F, G],
augmentation: openarray[B1],
message: openarray[B2],
domainSepTag: openarray[B3]
@ -149,20 +149,52 @@ func hashToCurve*[
## and `CoreVerify(PK, PK || message, signature)`
## - `message` is the message to hash
## - `domainSepTag` is the protocol domain separation tag (DST).
## If a domainSepTag larger than 255-bit is required,
## it is recommended to cache the reduced DST.
var u{.noInit.}: array[2, F]
H.hashToField(k, u, augmentation, message, domainSepTag)
when false:
var P{.noInit.}: array[2, ECP_ShortW_Prj[F, G]]
P[0].mapToCurve(u[0])
P[1].mapToCurve(u[1])
output.sum(P[0], P[1])
if domainSepTag.len <= 255:
H.hashToField(k, u, augmentation, message, domainSepTag)
else:
var Pjac{.noInit.}: ECP_ShortW_Jac[F, G]
Pjac.mapToCurve_fusedAdd(u[0], u[1])
output.projectiveFromJacobian(Pjac)
const N = H.type.digestSize()
var dst {.noInit.}: array[N, byte]
H.shortDomainSepTag(dst, domainSepTag)
H.hashToField(k, u, augmentation, message, dst)
output.mapToCurve_fusedAdd(u[0], u[1])
output.clearCofactor()
func hashToCurve*[
F; G: static Subgroup;
B1, B2, B3: byte|char](
H: type CryptoHash,
k: static int,
output: var (ECP_ShortW_Prj[F, G] or ECP_ShortW_Aff[F, G]),
augmentation: openarray[B1],
message: openarray[B2],
domainSepTag: openarray[B3]
) =
## Hash a message to an elliptic curve
##
## Arguments:
## - `Hash` a cryptographic hash function.
## - `Hash` MAY be a Merkle-Damgaard hash function like SHA-2
## - `Hash` MAY be a sponge-based hash function like SHA-3 or BLAKE2
## - Otherwise, H MUST be a hash function that has been proved
## indifferentiable from a random oracle [MRH04] under a reasonable
## cryptographic assumption.
## - k the security parameter of the suite in bits (for example 128)
## - `output`, an elliptic curve point that will be overwritten.
## - `augmentation`, an optional augmentation to the message. This will be prepended,
## prior to hashing.
## This is used for building the "message augmentation" variant of BLS signatures
## https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04#section-3.2
## which requires `CoreSign(SK, PK || message)`
## and `CoreVerify(PK, PK || message, signature)`
## - `message` is the message to hash
## - `domainSepTag` is the protocol domain separation tag (DST).
var Pjac{.noInit.}: ECP_ShortW_Jac[F, G]
H.hashToCurve(k, Pjac, augmentation, message, domainSepTag)
when output is ECP_ShortW_Prj:
output.projectiveFromJacobian(Pjac)
else:
output.affine(Pjac)

View File

@ -25,8 +25,8 @@ type
## - SHA3-512 block size is 72 bits
# should we avoid int to avoid exception? But they are compile-time
H.digestSize is int
H.internalBlockSize is int
H.digestSize is static int
H.internalBlockSize is static int
# Context
# -------------------------------------------

View File

@ -293,7 +293,8 @@ func exportRawUint*(
## or zero-padded right for little-endian.
## I.e least significant bit is aligned to buffer boundary
assert dst.len >= (BigInt.bits + 7) div 8, "BigInt -> Raw int conversion: destination buffer is too small"
debug:
doAssert dst.len >= (BigInt.bits + 7) div 8, "BigInt -> Raw int conversion: destination buffer is too small"
when BigInt.bits == 0:
zeroMem(dst, dst.len)

View File

@ -15,6 +15,7 @@ import
],
../isogeny/frobenius,
../curves/zoo_pairings,
../arithmetic,
./cyclotomic_subgroup,
./lines_eval,
./miller_loops
@ -118,7 +119,7 @@ func finalExpHard_BLS12*[C](f: var Fp12[C]) {.meter.} =
v2.cyclotomic_square(f) # v2 = f²
# (x1)²
when C.pairing(ate_param).isEven.bool:
when C.pairing(ate_param).isEven().bool:
v0.cycl_exp_by_curve_param_div2(v2) # v0 = (f²)^(x/2) = f^x
else:
v0.cycl_exp_by_curve_param(f)

View File

@ -0,0 +1,20 @@
# 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
./config/curves,
./pairing/[pairing_bn, pairing_bls12],
./towers
template pairing*[C](gt: var Fp12[C], P, Q: typed) =
when family(C) == BarretoNaehrig:
pairing_bn(gt, P, Q)
elif family(C) == BarretoLynnScott:
pairing_bls12(gt, P, Q)
else:
{.error: "Pairing not implemented for " & $C.}

View File

@ -0,0 +1,6 @@
# Signatures schemes
## BLS signatures (Boneh-Lynn-Schacham)
- https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04
- https://github.com/cfrg/draft-irtf-cfrg-bls-signature

View File

@ -0,0 +1,126 @@
# 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
../ec_shortweierstrass,
../hash_to_curve/hash_to_curve,
../hashes, ../pairings,
../curves/zoo_generators
# ############################################################
#
# BLS Signatures
#
# ############################################################
# This module implements generic BLS signatures
# https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04
# https://github.com/cfrg/draft-irtf-cfrg-bls-signature
#
# We use generic shortnames SecKey, PubKey, Sig
# so tat the algorithms fit whether Pubkey and Sig are on G1 or G2
# Actual protocols should expose publicly the full names SecretKey, PublicKey and Signature
{.push inline.} # inline in the main public procs
{.push raises: [].} # No exceptions allowed in core cryptographic operations
func derivePubkey*[Pubkey, SecKey](pubkey: var Pubkey, seckey: SecKey): bool =
## Generates the public key associated with the input secret key.
##
## Returns:
## - false is secret key is invalid (SK == 0 or >= BLS12-381 curve order),
## true otherwise
## By construction no public API should ever instantiate
## an invalid secretkey in the first place.
const Group = Pubkey.G
type Field = Pubkey.F
const EC = Field.C
if seckey.isZero().bool:
return false
if bool(seckey >= EC.getCurveOrder()):
return false
var pk {.noInit.}: ECP_ShortW_Jac[Field, Group]
pk.fromAffine(EC.getGenerator($Group))
pk.scalarMul(seckey)
pubkey.affine(pk)
return true
func coreSign*[B1, B2, B3: byte|char, Sig, SecKey](
signature: var Sig,
secretKey: SecKey,
message: openarray[B1],
H: type CryptoHash,
k: static int,
augmentation: openarray[B2],
domainSepTag: openarray[B3]) =
## Computes a signature for the message from the specified secret key.
##
## Output:
## - `signature` is overwritten with `message` signed with `secretKey`
##
## Inputs:
## - `Hash` a cryptographic hash function.
## - `Hash` MAY be a Merkle-Damgaard hash function like SHA-2
## - `Hash` MAY be a sponge-based hash function like SHA-3 or BLAKE2
## - Otherwise, H MUST be a hash function that has been proved
## indifferentiable from a random oracle [MRH04] under a reasonable
## cryptographic assumption.
## - k the security parameter of the suite in bits (for example 128)
## - `output`, an elliptic curve point that will be overwritten.
## - `augmentation`, an optional augmentation to the message. This will be prepended,
## prior to hashing.
## This is used for building the "message augmentation" variant of BLS signatures
## https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04#section-3.2
## which requires `CoreSign(SK, PK || message)`
## and `CoreVerify(PK, PK || message, signature)`
## - `message` is the message to hash
## - `domainSepTag` is the protocol domain separation tag (DST).
type ECP_Jac = ECP_ShortW_Jac[Sig.F, Sig.G]
var sig {.noInit.}: ECP_Jac
H.hashToCurve(k, sig, augmentation, message, domainSepTag)
sig.scalarMul(secretKey)
signature.affine(sig)
func coreVerify*[B1, B2, B3: byte|char, Pubkey, Sig](
pubKey: Pubkey,
message: openarray[B1],
signature: Sig,
H: type CryptoHash,
k: static int,
augmentation: openarray[B2],
domainSepTag: openarray[B3]): bool =
## Check that a signature is valid
## for a message under the provided public key
## This assumes that the PublicKey and Signatures
## have been pre-checked for non-infinity and being in the correct subgroup
## (likely on deserialization)
var Q {.noInit.}: ECP_ShortW_Aff[Sig.F, Sig.G]
var negG {.noInit.}: ECP_ShortW_Aff[Pubkey.F, Pubkey.G]
negG.neg(Pubkey.F.C.getGenerator($Pubkey.G))
H.hashToCurve(k, Q, augmentation, message, domainSepTag)
when Sig.F.C.getEmbeddingDegree() == 12:
var gt {.noInit.}: Fp12[Sig.F.C]
else:
{.error: "Not implemented: signature on k=" & $Sig.F.C.getEmbeddingDegree() & " for curve " & $$Sig.F.C.}
# e(PK, H(msg))*e(sig, -G) == 1
when Sig.G == G2:
pairing(gt, [pubKey, negG], [Q, signature])
else:
pairing(gt, [Q, signature], [pubKey, negG])
return gt.isOne().bool()

View File

@ -0,0 +1,408 @@
# 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
./backend/config/[
common, curves, type_bigint, type_ff
],
./backend/[
ec_shortweierstrass,
hash_to_curve/hash_to_curve,
hashes,
towers,
arithmetic,
signatures/bls_signatures,
curves/zoo_subgroups,
primitives
],
./backend/io/[io_bigints, io_fields]
export
curves, # generic sandwich on matchingBigInt
towers, # generic sandwich on extension field access
hashes, # generic sandwich on sha256
ec_shortweierstrass # generic sandwich on affine
## ############################################################
##
## BLS Signatures on BLS12-381 G2
##
## ############################################################
##
## This module implements BLS Signatures (Boneh-Lynn-Schacham)
## on top of the BLS12-381 curve (Barreto-Lynn-Scott).
##
## Ciphersuite:
##
## - Secret keys on Fr (32 bytes)
## - Public keys on G1 (48 bytes compressed, 96 bytes uncompressed)
## - Signatures on G2 (96 bytes compressed, 192 bytes uncompressed)
##
## Hash-to curve:
## - Domain separation tag: "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"
## - Hash function: SHA256
##
## Currently Constantine does not provide popProve and popVerify
## which are thin wrapper over sign/verify with
## - the message to sign or verify being the compressed or uncompressed public key
## or another application-specific "hash_pubkey_to_point" scheme
## - domain-separation-tag: "BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"
##
## Constantine currently assumes that proof-of-possessions are handled at the application-level
##
## In proof-of-stake blockchains, being part of the staker/validator sets
## already serve as proof-of-possession.
const DST = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"
const ffi_prefix = "ctt_blssig_pop_on_bls12381_g2_"
{.push raises: [].} # No exceptions allowed in core cryptographic operations
# {.push cdecl, dynlib, exportc:ffi_prefix & "$1".} # TODO, C API
type
SecretKey* {.byref.} = object
## A BLS12_381 secret key
raw: matchingOrderBigInt(BLS12_381)
PublicKey* {.byref.} = object
## A BLS12_381 public key for BLS signature schemes with public keys on G1 and signatures on G2
raw: ECP_ShortW_Aff[Fp[BLS12_381], G1]
Signature* {.byref.} = object
## A BLS12_381 signature for BLS signature schemes with public keys on G1 and signatures on G2
raw: ECP_ShortW_Aff[Fp2[BLS12_381], G2]
CttBLSStatus* = enum
cttBLS_Success
cttBLS_VerificationFailure
cttBLS_InvalidEncoding
cttBLS_CoordinateGreaterOrEqualThanModulus
cttBLS_PointAtInfinity
cttBLS_PointNotOnCurve
cttBLS_PointNotInSubgroup
cttBLS_ZeroSecretKey
cttBLS_SecretKeyLargerThanCurveOrder
# Comparisons
# ------------------------------------------------------------------------------------------------
func isZero*(elem: PublicKey or Signature): bool =
## Returns true if input is 0
bool(elem.raw.isInf())
func `==`*(a, b: PublicKey or Signature): bool =
## Returns true if inputs are equal
bool(a.raw == b.raw)
# Input validation
# ------------------------------------------------------------------------------------------------
func validate_seckey*(secret_key: SecretKey): CttBLSStatus =
## Validate the secret key.
## Regarding timing attacks, this will leak timing information only if the key is invalid.
## Namely, the secret key is 0 or the secret key is too large.
if secret_key.raw.isZero().bool():
return cttBLS_ZeroSecretKey
if bool(secret_key.raw >= BLS12_381.getCurveOrder()):
return cttBLS_SecretKeyLargerThanCurveOrder
return cttBLS_Success
func validate_pubkey*(public_key: PublicKey): CttBLSStatus =
## Validate the public key.
## This is an expensive operation that can be cached
if public_key.raw.isInf().bool():
return cttBLS_PointAtInfinity
if not isOnCurve(public_key.raw.x, public_key.raw.y, G1).bool():
return cttBLS_PointNotOnCurve
if not public_key.raw.isInSubgroup().bool():
return cttBLS_PointNotInSubgroup
func validate_sig*(signature: Signature): CttBLSStatus =
## Validate the signature.
## This is an expensive operation that can be cached
if signature.raw.isInf().bool():
return cttBLS_PointAtInfinity
if not isOnCurve(signature.raw.x, signature.raw.y, G2).bool():
return cttBLS_PointNotOnCurve
if not signature.raw.isInSubgroup().bool():
return cttBLS_PointNotInSubgroup
# Codecs
# ------------------------------------------------------------------------------------------------
## BLS12-381 serialization
##
## 𝔽p elements are encoded in big-endian form. They occupy 48 bytes in this form.
## 𝔽p2 elements are encoded in big-endian form, meaning that the 𝔽p2 element c0+c1u
## is represented by the 𝔽p element c1 followed by the 𝔽p element c0.
## This means 𝔽p2 elements occupy 96 bytes in this form.
## The group 𝔾1 uses 𝔽p elements for coordinates. The group 𝔾2 uses 𝔽p2 elements for coordinates.
## 𝔾1 and 𝔾2 elements can be encoded in uncompressed form (the x-coordinate followed by the y-coordinate) or in compressed form (just the x-coordinate).
## 𝔾1 elements occupy 96 bytes in uncompressed form, and 48 bytes in compressed form.
## 𝔾2 elements occupy 192 bytes in uncompressed form, and 96 bytes in compressed form.
##
## The most-significant three bits of a 𝔾1 or 𝔾2 encoding should be masked away before the coordinate(s) are interpreted. These bits are used to unambiguously represent the underlying element:
##
## The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form.
## The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group elements encoding should be set to zero.
## The third-most significant bit is set if (and only if) this point is in compressed form
## and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate.
##
## - https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#appendix-A
## - https://docs.rs/bls12_381/latest/bls12_381/notes/serialization/index.html
## - https://github.com/zkcrypto/bls12_381/blob/0.6.0/src/notes/serialization.rs
func serialize_secret_key*(dst: var array[32, byte], secret_key: SecretKey): CttBLSStatus =
## Serialize a secret key
## Returns cttBLS_Success if successful
dst.exportRawUint(secret_key.raw, bigEndian)
return cttBLS_Success
func serialize_public_key_compressed*(dst: var array[48, byte], public_key: PublicKey): CttBLSStatus =
## Serialize a public key in compressed (Zcash) format
##
## Returns cttBLS_Success if successful
if public_key.raw.isInf().bool():
for i in 0 ..< dst.len:
dst[i] = byte 0
dst[0] = byte 0b11000000 # Compressed + Infinity
return cttBLS_Success
dst.exportRawUint(public_key.raw.x, bigEndian)
# The curve equation has 2 solutions for y² = x³ + 4 with y unknown and x known
# The lexicographically largest will have bit 381 set to 1
# (and bit 383 for the compressed representation)
# The solutions are {y, p-y} hence the lexicographyically largest is greater than p/2
# so with exact integers, as p is odd, greater or equal (p+1)/2
let lexicographicallyLargest = byte(public_key.raw.y.toBig() >= Fp[BLS12_381].getPrimePlus1div2())
dst[0] = dst[0] or (0b10000000 or (lexicographicallyLargest shl 5))
return cttBLS_Success
func serialize_signature_compressed*(dst: var array[96, byte], signature: Signature): CttBLSStatus =
## Serialize a signature in compressed (Zcash) format
##
## Returns cttBLS_Success if successful
if signature.raw.isInf().bool():
for i in 0 ..< dst.len:
dst[i] = byte 0
dst[0] = byte 0b11000000 # Compressed + Infinity
return cttBLS_Success
dst.toOpenArray(0, 48-1).exportRawUint(signature.raw.x.c1, bigEndian)
dst.toOpenArray(48, 96-1).exportRawUint(signature.raw.x.c0, bigEndian)
let isLexicographicallyLargest =
if signature.raw.y.c1.isZero().bool():
byte(signature.raw.y.c0.toBig() >= Fp[BLS12_381].getPrimePlus1div2())
else:
byte(signature.raw.y.c1.toBig() >= Fp[BLS12_381].getPrimePlus1div2())
dst[0] = dst[0] or (byte 0b10000000 or (isLexicographicallyLargest shl 5))
return cttBLS_Success
func deserialize_secret_key*(dst: var SecretKey, src: array[32, byte]): CttBLSStatus =
## deserialize a secret key
##
## This is protected against side-channel unless your key is invalid.
## In that case it will like whether it's all zeros or larger than the curve order.
dst.raw.fromRawUint(src, bigEndian)
let status = validate_seckey(dst)
if status != cttBLS_Success:
dst.raw.setZero()
return status
return cttBLS_Success
func deserialize_public_key_compressed_unchecked*(dst: var PublicKey, src: array[48, byte]): CttBLSStatus =
## Deserialize a public_key in compressed (Zcash) format.
##
## Warning ⚠:
## This procedure skips the very expensive subgroup checks.
## Not checking subgroup exposes a protocol to small subgroup attacks.
##
## Returns cttBLS_Success if successful
# src must have the compressed flag
if (src[0] and byte 0b10000000) == byte 0:
return cttBLS_InvalidEncoding
# if infinity, src must be all zeros
if (src[0] and byte 0b01000000) != 0:
if (src[0] and byte 0b00111111) != 0: # Check all the remaining bytes in MSB
return cttBLS_InvalidEncoding
for i in 1 ..< src.len:
if src[i] != byte 0:
return cttBLS_InvalidEncoding
dst.raw.setInf()
return cttBLS_PointAtInfinity
# General case
var t{.noInit.}: matchingBigInt(BLS12_381)
t.fromRawUint(src, bigEndian)
t.limbs[^1] = t.limbs[^1] and (MaxWord shr 3) # The first 3 bytes contain metadata to mask out
if bool(t >= BLS12_381.Mod()):
return cttBLS_CoordinateGreaterOrEqualThanModulus
var x{.noInit.}: Fp[BLS12_381]
x.fromBig(t)
let onCurve = dst.raw.trySetFromCoordX(x)
if not(bool onCurve):
return cttBLS_PointNotOnCurve
let isLexicographicallyLargest = dst.raw.y.toBig() >= Fp[BLS12_381].getPrimePlus1div2()
let srcIsLargest = SecretBool((src[0] shr 5) and byte 1)
dst.raw.y.cneg(isLexicographicallyLargest xor srcIsLargest)
func deserialize_public_key_compressed*(dst: var PublicKey, src: array[48, byte]): CttBLSStatus =
## Deserialize a public_key in compressed (Zcash) format
##
## Returns cttBLS_Success if successful
result = deserialize_public_key_compressed_unchecked(dst, src)
if result != cttBLS_Success:
return result
if not(bool dst.raw.isInSubgroup):
return cttBLS_PointNotInSubgroup
func deserialize_signature_compressed_unchecked*(dst: var Signature, src: array[96, byte]): CttBLSStatus =
## Deserialize a signature in compressed (Zcash) format.
##
## Warning ⚠:
## This procedure skips the very expensive subgroup checks.
## Not checking subgroup exposes a protocol to small subgroup attacks.
##
## Returns cttBLS_Success if successful
# src must have the compressed flag
if (src[0] and byte 0b10000000) == byte 0:
return cttBLS_InvalidEncoding
# if infinity, src must be all zeros
if (src[0] and byte 0b01000000) != 0:
if (src[0] and byte 0b00111111) != 0: # Check all the remaining bytes in MSB
return cttBLS_InvalidEncoding
for i in 1 ..< src.len:
if src[i] != byte 0:
return cttBLS_InvalidEncoding
dst.raw.setInf()
return cttBLS_PointAtInfinity
# General case
var t{.noInit.}: matchingBigInt(BLS12_381)
t.fromRawUint(src.toOpenArray(0, 48-1), bigEndian)
t.limbs[^1] = t.limbs[^1] and (MaxWord shr 3) # The first 3 bytes contain metadata to mask out
if bool(t >= BLS12_381.Mod()):
return cttBLS_CoordinateGreaterOrEqualThanModulus
var x{.noInit.}: Fp2[BLS12_381]
x.c1.fromBig(t)
t.fromRawUint(src.toOpenArray(48, 96-1), bigEndian)
if bool(t >= BLS12_381.Mod()):
return cttBLS_CoordinateGreaterOrEqualThanModulus
x.c0.fromBig(t)
let onCurve = dst.raw.trySetFromCoordX(x)
if not(bool onCurve):
return cttBLS_PointNotOnCurve
let isLexicographicallyLargest =
if dst.raw.y.c1.isZero().bool():
dst.raw.y.c0.toBig() >= Fp[BLS12_381].getPrimePlus1div2()
else:
dst.raw.y.c1.toBig() >= Fp[BLS12_381].getPrimePlus1div2()
let srcIsLargest = SecretBool((src[0] shr 5) and byte 1)
dst.raw.y.cneg(isLexicographicallyLargest xor srcIsLargest)
func deserialize_signature_compressed*(dst: var Signature, src: array[96, byte]): CttBLSStatus =
## Deserialize a public_key in compressed (Zcash) format
##
## Returns cttBLS_Success if successful
result = deserialize_signature_compressed_unchecked(dst, src)
if result != cttBLS_Success:
return result
if not(bool dst.raw.isInSubgroup):
return cttBLS_PointNotInSubgroup
# Signatures
# ------------------------------------------------------------------------------------------------
func derive_public_key*(public_key: var PublicKey, secret_key: SecretKey): CttBLSStatus =
## Derive the public key matching with a secret key
##
## Secret protection:
## - A valid secret key will only leak that it is valid.
## - An invalid secret key will leak whether it's all zero or larger than the curve order.
let status = validate_seckey(secret_key)
if status != cttBLS_Success:
return status
let ok = public_key.raw.derivePubkey(secret_key.raw)
if not ok:
# This is unreachable since validate_seckey would have caught those
return cttBLS_InvalidEncoding
return cttBLS_Success
func sign*[T: byte|char](signature: var Signature, secret_key: SecretKey, message: openArray[T]): CttBLSStatus =
## Produce a signature for the message under the specified secret key
## Signature is on BLS12-381 G2 (and public key on G1)
##
## For message domain separation purpose, the tag is `BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_`
##
## Input:
## - A secret key
## - A message
##
## Output:
## - `signature` is overwritten with `message` signed with `secretKey`
## with the scheme
## - A status code indicating success or if the secret key is invalid.
##
## Secret protection:
## - A valid secret key will only leak that it is valid.
## - An invalid secret key will leak whether it's all zero or larger than the curve order.
let status = validate_seckey(secret_key)
if status != cttBLS_Success:
signature.raw.setInf()
return status
coreSign(signature.raw, secretKey.raw, message, sha256, 128, augmentation = "", DST)
return cttBLS_Success
func verify*[T: byte|char](public_key: PublicKey, message: openarray[T], signature: Signature): CttBLSStatus =
## Check that a signature is valid for a message
## under the provided public key.
## returns `true` if the signature is valid, `false` otherwise.
##
## For message domain separation purpose, the tag is `BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_`
##
## Input:
## - A public key initialized by one of the key derivation or deserialization procedure.
## Or validated via validate_pubkey
## - A message
## - A signature initialized by one of the key derivation or deserialization procedure.
## Or validated via validate_pubkey
##
## In particular, the public key and signature are assumed to be on curve subgroup checked.
# Deal with cases were pubkey or signature were mistakenly zero-init, due to a generic aggregation tentative for example
if bool(public_key.raw.isInf() or signature.raw.isInf()):
return cttBLS_PointAtInfinity
let verified = coreVerify(public_key.raw, message, signature.raw, sha256, 128, augmentation = "", DST)
if verified:
return cttBLS_Success
return cttBLS_VerificationFailure

View File

@ -0,0 +1,4 @@
# BLS signature on BLS12-381 G2 tests
Source: https://github.com/ethereum/bls12-381-tests
version 0.1.1 at https://github.com/ethereum/bls12-381-tests/releases/tag/v0.1.1

View File

@ -0,0 +1 @@
{"input": ["0xb6ed936746e01f8ecf281f020953fbf1f01debd5657c4a383940b020b26507f6076334f91e2366c96e9ab279fb5158090352ea1c5b0c9274504f4f0e7053af24802e51e4568d164fe986834f41e55c8e850ce1f98458c0cfc9ab380b55285a55", "0xb23c46be3a001c63ca711f87a005c200cc550b9429d5f4eb38d74322144f1b63926da3388979e5321012fb1a0526bcd100b5ef5fe72628ce4cd5e904aeaa3279527843fae5ca9ca675f4f51ed8f83bbf7155da9ecc9663100a885d5dc6df96d9", "0x948a7cb99f76d616c2c564ce9bf4a519f1bea6b0a624a02276443c245854219fabb8d4ce061d255af5330b078d5380681751aa7053da2c98bae898edc218c75f07e24d8802a17cd1f6833b71e58f5eb5b94208b4d0bb3848cecb075ea21be115"], "output": "0x9683b3e6701f9a4b706709577963110043af78a5b41991b998475a3d3fd62abf35ce03b33908418efc95a058494a8ae504354b9f626231f6b3f3c849dfdeaf5017c4780e2aee1850ceaf4b4d9ce70971a3d2cfcd97b7e5ecf6759f8da5f76d31"}

View File

@ -0,0 +1 @@
{"input": ["0x882730e5d03f6b42c3abc26d3372625034e1d871b65a8a6b900a56dae22da98abbe1b68f85e49fe7652a55ec3d0591c20767677e33e5cbb1207315c41a9ac03be39c2e7668edc043d6cb1d9fd93033caa8a1c5b0e84bedaeb6c64972503a43eb", "0xaf1390c3c47acdb37131a51216da683c509fce0e954328a59f93aebda7e4ff974ba208d9a4a2a2389f892a9d418d618418dd7f7a6bc7aa0da999a9d3a5b815bc085e14fd001f6a1948768a3f4afefc8b8240dda329f984cb345c6363272ba4fe", "0xa4efa926610b8bd1c8330c918b7a5e9bf374e53435ef8b7ec186abf62e1b1f65aeaaeb365677ac1d1172a1f5b44b4e6d022c252c58486c0a759fbdc7de15a756acc4d343064035667a594b4c2a6f0b0b421975977f297dba63ee2f63ffe47bb6"], "output": "0xad38fc73846583b08d110d16ab1d026c6ea77ac2071e8ae832f56ac0cbcdeb9f5678ba5ce42bd8dce334cc47b5abcba40a58f7f1f80ab304193eb98836cc14d8183ec14cc77de0f80c4ffd49e168927a968b5cdaa4cf46b9805be84ad7efa77b"}

View File

@ -0,0 +1 @@
{"input": ["0x91347bccf740d859038fcdcaf233eeceb2a436bcaaee9b2aa3bfb70efe29dfb2677562ccbea1c8e061fb9971b0753c240622fab78489ce96768259fc01360346da5b9f579e5da0d941e4c6ba18a0e64906082375394f337fa1af2b7127b0d121", "0x9674e2228034527f4c083206032b020310face156d4a4685e2fcaec2f6f3665aa635d90347b6ce124eb879266b1e801d185de36a0a289b85e9039662634f2eea1e02e670bc7ab849d006a70b2f93b84597558a05b879c8d445f387a5d5b653df", "0xae82747ddeefe4fd64cf9cedb9b04ae3e8a43420cd255e3c7cd06a8d88b7c7f8638543719981c5d16fa3527c468c25f0026704a6951bde891360c7e8d12ddee0559004ccdbe6046b55bae1b257ee97f7cdb955773d7cf29adf3ccbb9975e4eb9"], "output": "0x9712c3edd73a209c742b8250759db12549b3eaf43b5ca61376d9f30e2747dbcf842d8b2ac0901d2a093713e20284a7670fcf6954e9ab93de991bb9b313e664785a075fc285806fa5224c82bde146561b446ccfc706a64b8579513cfc4ff1d930"}

View File

@ -0,0 +1 @@
{"input": ["0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"], "output": "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

View File

@ -0,0 +1 @@
{"input": [], "output": null}

View File

@ -0,0 +1 @@
{"input": ["0xb6ed936746e01f8ecf281f020953fbf1f01debd5657c4a383940b020b26507f6076334f91e2366c96e9ab279fb5158090352ea1c5b0c9274504f4f0e7053af24802e51e4568d164fe986834f41e55c8e850ce1f98458c0cfc9ab380b55285a55"], "output": "0xb6ed936746e01f8ecf281f020953fbf1f01debd5657c4a383940b020b26507f6076334f91e2366c96e9ab279fb5158090352ea1c5b0c9274504f4f0e7053af24802e51e4568d164fe986834f41e55c8e850ce1f98458c0cfc9ab380b55285a55"}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f", "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"], "messages": ["0x0000000000000000000000000000000000000000000000000000000000000000", "0x5656565656565656565656565656565656565656565656565656565656565656", "0xabababababababababababababababababababababababababababababababab", "0x1212121212121212121212121212121212121212121212121212121212121212"], "signature": "0x9104e74b9dfd3ad502f25d6a5ef57db0ed7d9a0e00f3500586d8ce44231212542fcfaf87840539b398bf07626705cf1105d246ca1062c6c2e1a53029a0f790ed5e3cb1f52f8234dc5144c45fc847c0cd37a92d68e7c5ba7c648a8a339f171244"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": [], "messages": [], "signature": "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": [], "messages": [], "signature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f"], "messages": ["0x0000000000000000000000000000000000000000000000000000000000000000", "0x5656565656565656565656565656565656565656565656565656565656565656", "0xabababababababababababababababababababababababababababababababab"], "signature": "0x9104e74bffffffff"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f"], "messages": ["0x0000000000000000000000000000000000000000000000000000000000000000", "0x5656565656565656565656565656565656565656565656565656565656565656", "0xabababababababababababababababababababababababababababababababab"], "signature": "0x9104e74b9dfd3ad502f25d6a5ef57db0ed7d9a0e00f3500586d8ce44231212542fcfaf87840539b398bf07626705cf1105d246ca1062c6c2e1a53029a0f790ed5e3cb1f52f8234dc5144c45fc847c0cd37a92d68e7c5ba7c648a8a339f171244"}, "output": true}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81"], "messages": ["0x0000000000000000000000000000000000000000000000000000000000000000", "0x5656565656565656565656565656565656565656565656565656565656565656"], "signatures": ["0xa70f1f1b4bd97d182ebb55d08be3f90b1dc232bb50b44e259381a642ef0bad3629ad3542f3e8ff6a84e451fc0b595e090fc4f0e860cfc5584715ef1b6cd717b9994378f7a51b815bbf5a0d95bc3402583ad2e95a229731e539906249a5e4355c", "0xb758eb7e15c101f53be2214d2a6b65e8fe7053146dbe3c73c9fe9b5efecdf63ca06a4d5d938dbf18fe6600529c0011a7013f45ae012b02904d5c7c33316e935a0e084abead4f43f84383c52cd3b3f14024437e251a2a7c0d5147954022873a58"]}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f"], "messages": ["0x0000000000000000000000000000000000000000000000000000000000000000", "0x5656565656565656565656565656565656565656565656565656565656565656", "0xabababababababababababababababababababababababababababababababab"], "signatures": ["0xb6ed936746e01f8ecf281f020953fbf1f01debd5657c4a383940b020b26507f6076334f91e2366c96e9ab279fb5158090352ea1c5b0c9274504f4f0e7053af24802e51e4568d164fe986834f41e55c8e850ce1f98458c0cfc9ab380b55285a55", "0xaf1390c3c47acdb37131a51216da683c509fce0e954328a59f93aebda7e4ff974ba208d9a4a2a2389f892a9d418d618418dd7f7a6bc7aa0da999a9d3a5b815bc085e14fd001f6a1948768a3f4afefc8b8240dda329f984cb345c6363272ba4fe", "0xae82747ddeefe4fd64cf9cedb9b04ae3e8a43420cd255e3c7cd06a8d88b7c7f8638543719981c5d16fa3527c468c25f0026704a6951bde891360c7e8d12ddee0559004ccdbe6046b55bae1b257ee97f7cdb955773d7cf29adf3ccbb9975e4eb9"]}, "output": true}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "c01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde0"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaa900"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "c123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "a491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a"}, "output": true}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": true}

View File

@ -0,0 +1 @@
{"input": {"signature": "800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "c01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde0"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefff"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "c123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "9a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"signature": "b2cc74bc9f089ed9764bbceac5edba416bef5e73701288977b9cac1ccb6964269d4ebf78b4e8aa7792ba09d3e49c8e6a1351bdf582971f796bbaf6320e81251c9d28f674d720cca07ed14596b96697cf18238e0e03ebd7fc1353d885a39407e0"}, "output": true}

View File

@ -0,0 +1 @@
{"input": {"signature": "c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": true}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f"], "message": "0x5656565656565656565656565656565656565656565656565656565656565656", "signature": "0x912c3615f69575407db9392eb21fee18fff797eeb2fbe1816366ca2a08ae574d8824dbfafb4c9eaa1cf61b63c6f9b69911f269b664c42947dd1b53ef1081926c1e82bb2a465f927124b08391a5249036146d6f3f1e17ff5f162f779746d830d1"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f"], "message": "0xabababababababababababababababababababababababababababababababab", "signature": "0x9712c3edd73a209c742b8250759db12549b3eaf43b5ca61376d9f30e2747dbcf842d8b2ac0901d2a093713e20284a7670fcf6954e9ab93de991bb9b313e664785a075fc285806fa5224c82bde146561b446ccfc706a64b8579513cfc4ff1d930"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f"], "message": "0x0000000000000000000000000000000000000000000000000000000000000000", "signature": "0xb6ed936746e01f8ecf281f020953fbf1f01debd5657c4a383940b020b26507f6076334f91e2366c96e9ab279fb5158090352ea1c5b0c9274504f4f0e7053af24802e51e4568d164fe986834f41e55c8e850ce1f98458c0cfc9ab380b55285a55"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f", "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"], "message": "0x1212121212121212121212121212121212121212121212121212121212121212", "signature": "0xafcb4d980f079265caa61aee3e26bf48bebc5dc3e7f2d7346834d76cbc812f636c937b6b44a9323d8bc4b1cdf71d6811035ddc2634017faab2845308f568f2b9a0356140727356eae9eded8b87fd8cb8024b440c57aee06076128bb32921f584"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": [], "message": "0xabababababababababababababababababababababababababababababababab", "signature": "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": [], "message": "0xabababababababababababababababababababababababababababababababab", "signature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f"], "message": "0xabababababababababababababababababababababababababababababababab", "signature": "0x9712c3edd73a209c742b8250759db12549b3eaf43b5ca61376d9f30e2747dbcf842d8b2ac0901d2a093713e20284a7670fcf6954e9ab93de991bb9b313e664785a075fc285806fa5224c82bde146561b446ccfc706a64b8579513cfcffffffff"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a"], "message": "0x0000000000000000000000000000000000000000000000000000000000000000", "signature": "0xb6ed936746e01f8ecf281f020953fbf1f01debd5657c4a383940b020b26507f6076334f91e2366c96e9ab279fb5158090352ea1c5b0c9274504f4f0e7053af24802e51e4568d164fe986834f41e55c8e850ce1f98458c0cfc9ab380bffffffff"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81"], "message": "0x5656565656565656565656565656565656565656565656565656565656565656", "signature": "0x912c3615f69575407db9392eb21fee18fff797eeb2fbe1816366ca2a08ae574d8824dbfafb4c9eaa1cf61b63c6f9b69911f269b664c42947dd1b53ef1081926c1e82bb2a465f927124b08391a5249036146d6f3f1e17ff5f162f7797ffffffff"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f"], "message": "0xabababababababababababababababababababababababababababababababab", "signature": "0x9712c3edd73a209c742b8250759db12549b3eaf43b5ca61376d9f30e2747dbcf842d8b2ac0901d2a093713e20284a7670fcf6954e9ab93de991bb9b313e664785a075fc285806fa5224c82bde146561b446ccfc706a64b8579513cfc4ff1d930"}, "output": true}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a"], "message": "0x0000000000000000000000000000000000000000000000000000000000000000", "signature": "0xb6ed936746e01f8ecf281f020953fbf1f01debd5657c4a383940b020b26507f6076334f91e2366c96e9ab279fb5158090352ea1c5b0c9274504f4f0e7053af24802e51e4568d164fe986834f41e55c8e850ce1f98458c0cfc9ab380b55285a55"}, "output": true}

View File

@ -0,0 +1 @@
{"input": {"pubkeys": ["0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81"], "message": "0x5656565656565656565656565656565656565656565656565656565656565656", "signature": "0x912c3615f69575407db9392eb21fee18fff797eeb2fbe1816366ca2a08ae574d8824dbfafb4c9eaa1cf61b63c6f9b69911f269b664c42947dd1b53ef1081926c1e82bb2a465f927124b08391a5249036146d6f3f1e17ff5f162f779746d830d1"}, "output": true}

View File

@ -0,0 +1 @@
{"input": {"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "output": {"x": "0x01a6ba2f9a11fa5598b2d8ace0fbe0a0eacb65deceb476fbbcb64fd24557c2f4b18ecfc5663e54ae16a84f5ab7f62534,0x11fca2ff525572795a801eed17eb12785887c7b63fb77a42be46ce4a34131d71f7a73e95fee3f812aea3de78b4d01569", "y": "0x0b6798718c8aed24bc19cb27f866f1c9effcdbf92397ad6448b5c9db90d2b9da6cbabf48adc1adf59a1a28344e79d57e,0x03a47f8e6d1763ba0cad63d6114c0accbef65707825a511b251a660a9b3994249ae4e63fac38b23da0c398689ee2ab52"}}

View File

@ -0,0 +1 @@
{"input": {"msg": "abc"}, "output": {"x": "0x02c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e6,0x139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd8", "y": "0x1787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48,0x00aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd16"}}

View File

@ -0,0 +1 @@
{"input": {"msg": ""}, "output": {"x": "0x0141ebfbdca40eb85b87142e130ab689c673cf60f1a3e98d69335266f30d9b8d4ac44c1038e9dcdd5393faf5c41fb78a,0x05cb8437535e20ecffaef7752baddf98034139c38452458baeefab379ba13dff5bf5dd71b72418717047f5b0f37da03d", "y": "0x0503921d7f6a12805e72940b963c0cf3471c7b2a524950ca195d11062ee75ec076daf2d4bc358c4b190c0c98064fdd92,0x12424ac32561493f3fe3c260708a12b7c620e7be00099a974e259ddc7d1f6395c3c811cdd19f1e8dbf3e9ecfdcbab8d6"}}

View File

@ -0,0 +1 @@
{"input": {"msg": "abcdef0123456789"}, "output": {"x": "0x121982811d2491fde9ba7ed31ef9ca474f0e1501297f68c298e9f4c0028add35aea8bb83d53c08cfc007c1e005723cd0,0x190d119345b94fbd15497bcba94ecf7db2cbfd1e1fe7da034d26cbba169fb3968288b3fafb265f9ebd380512a71c3f2c", "y": "0x05571a0f8d3c08d094576981f4a3b8eda0a8e771fcdcc8ecceaf1356a6acf17574518acb506e435b639353c2e14827c8,0x0bb5e7572275c567462d91807de765611490205a941a5a6af3b1691bfe596c31225d3aabdf15faff860cb4ef17c7c3be"}}

View File

@ -0,0 +1 @@
{"input": {"privkey": "0x47b8192d77bf871b62e87859d653922725724a5c031afeabc60bcef5ff665138", "message": "0x0000000000000000000000000000000000000000000000000000000000000000"}, "output": "0xb23c46be3a001c63ca711f87a005c200cc550b9429d5f4eb38d74322144f1b63926da3388979e5321012fb1a0526bcd100b5ef5fe72628ce4cd5e904aeaa3279527843fae5ca9ca675f4f51ed8f83bbf7155da9ecc9663100a885d5dc6df96d9"}

View File

@ -0,0 +1 @@
{"input": {"privkey": "0x47b8192d77bf871b62e87859d653922725724a5c031afeabc60bcef5ff665138", "message": "0x5656565656565656565656565656565656565656565656565656565656565656"}, "output": "0xaf1390c3c47acdb37131a51216da683c509fce0e954328a59f93aebda7e4ff974ba208d9a4a2a2389f892a9d418d618418dd7f7a6bc7aa0da999a9d3a5b815bc085e14fd001f6a1948768a3f4afefc8b8240dda329f984cb345c6363272ba4fe"}

View File

@ -0,0 +1 @@
{"input": {"privkey": "0x47b8192d77bf871b62e87859d653922725724a5c031afeabc60bcef5ff665138", "message": "0xabababababababababababababababababababababababababababababababab"}, "output": "0x9674e2228034527f4c083206032b020310face156d4a4685e2fcaec2f6f3665aa635d90347b6ce124eb879266b1e801d185de36a0a289b85e9039662634f2eea1e02e670bc7ab849d006a70b2f93b84597558a05b879c8d445f387a5d5b653df"}

View File

@ -0,0 +1 @@
{"input": {"privkey": "0x328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d216", "message": "0x0000000000000000000000000000000000000000000000000000000000000000"}, "output": "0x948a7cb99f76d616c2c564ce9bf4a519f1bea6b0a624a02276443c245854219fabb8d4ce061d255af5330b078d5380681751aa7053da2c98bae898edc218c75f07e24d8802a17cd1f6833b71e58f5eb5b94208b4d0bb3848cecb075ea21be115"}

View File

@ -0,0 +1 @@
{"input": {"privkey": "0x328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d216", "message": "0xabababababababababababababababababababababababababababababababab"}, "output": "0xae82747ddeefe4fd64cf9cedb9b04ae3e8a43420cd255e3c7cd06a8d88b7c7f8638543719981c5d16fa3527c468c25f0026704a6951bde891360c7e8d12ddee0559004ccdbe6046b55bae1b257ee97f7cdb955773d7cf29adf3ccbb9975e4eb9"}

View File

@ -0,0 +1 @@
{"input": {"privkey": "0x328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d216", "message": "0x5656565656565656565656565656565656565656565656565656565656565656"}, "output": "0xa4efa926610b8bd1c8330c918b7a5e9bf374e53435ef8b7ec186abf62e1b1f65aeaaeb365677ac1d1172a1f5b44b4e6d022c252c58486c0a759fbdc7de15a756acc4d343064035667a594b4c2a6f0b0b421975977f297dba63ee2f63ffe47bb6"}

View File

@ -0,0 +1 @@
{"input": {"privkey": "0x263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3", "message": "0x0000000000000000000000000000000000000000000000000000000000000000"}, "output": "0xb6ed936746e01f8ecf281f020953fbf1f01debd5657c4a383940b020b26507f6076334f91e2366c96e9ab279fb5158090352ea1c5b0c9274504f4f0e7053af24802e51e4568d164fe986834f41e55c8e850ce1f98458c0cfc9ab380b55285a55"}

View File

@ -0,0 +1 @@
{"input": {"privkey": "0x263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3", "message": "0x5656565656565656565656565656565656565656565656565656565656565656"}, "output": "0x882730e5d03f6b42c3abc26d3372625034e1d871b65a8a6b900a56dae22da98abbe1b68f85e49fe7652a55ec3d0591c20767677e33e5cbb1207315c41a9ac03be39c2e7668edc043d6cb1d9fd93033caa8a1c5b0e84bedaeb6c64972503a43eb"}

View File

@ -0,0 +1 @@
{"input": {"privkey": "0x263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3", "message": "0xabababababababababababababababababababababababababababababababab"}, "output": "0x91347bccf740d859038fcdcaf233eeceb2a436bcaaee9b2aa3bfb70efe29dfb2677562ccbea1c8e061fb9971b0753c240622fab78489ce96768259fc01360346da5b9f579e5da0d941e4c6ba18a0e64906082375394f337fa1af2b7127b0d121"}

View File

@ -0,0 +1 @@
{"input": {"privkey": "0x0000000000000000000000000000000000000000000000000000000000000000", "message": "0xabababababababababababababababababababababababababababababababab"}, "output": null}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "message": "0x1212121212121212121212121212121212121212121212121212121212121212", "signature": "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "0xb53d21a4cfd562c469cc81514d4ce5a6b577d8403d32a394dc265dd190b47fa9f829fdd7963afdf972e5e77854051f6f", "message": "0xabababababababababababababababababababababababababababababababab", "signature": "0xae82747ddeefe4fd64cf9cedb9b04ae3e8a43420cd255e3c7cd06a8d88b7c7f8638543719981c5d16fa3527c468c25f0026704a6951bde891360c7e8d12ddee0559004ccdbe6046b55bae1b257ee97f7cdb955773d7cf29adf3ccbb9ffffffff"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a", "message": "0x5656565656565656565656565656565656565656565656565656565656565656", "signature": "0x882730e5d03f6b42c3abc26d3372625034e1d871b65a8a6b900a56dae22da98abbe1b68f85e49fe7652a55ec3d0591c20767677e33e5cbb1207315c41a9ac03be39c2e7668edc043d6cb1d9fd93033caa8a1c5b0e84bedaeb6c64972ffffffff"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "message": "0x0000000000000000000000000000000000000000000000000000000000000000", "signature": "0xb23c46be3a001c63ca711f87a005c200cc550b9429d5f4eb38d74322144f1b63926da3388979e5321012fb1a0526bcd100b5ef5fe72628ce4cd5e904aeaa3279527843fae5ca9ca675f4f51ed8f83bbf7155da9ecc9663100a885d5dffffffff"}, "output": false}

View File

@ -0,0 +1 @@
{"input": {"pubkey": "0xb301803f8b5ac4a1133581fc676dfedc60d891dd5fa99028805e5ea5b08d3491af75d0707adab3b70c6a6a580217bf81", "message": "0x5656565656565656565656565656565656565656565656565656565656565656", "signature": "0xaf1390c3c47acdb37131a51216da683c509fce0e954328a59f93aebda7e4ff974ba208d9a4a2a2389f892a9d418d618418dd7f7a6bc7aa0da999a9d3a5b815bc085e14fd001f6a1948768a3f4afefc8b8240dda329f984cb345c6363ffffffff"}, "output": false}

Some files were not shown because too many files have changed in this diff Show More