add fast_aggregate_verify
This commit is contained in:
parent
4be89d309f
commit
188f3e710c
|
@ -85,6 +85,7 @@ type
|
|||
cttBLS_PointNotInSubgroup
|
||||
cttBLS_ZeroSecretKey
|
||||
cttBLS_SecretKeyLargerThanCurveOrder
|
||||
cttBLS_ZeroLengthAggregation
|
||||
|
||||
# Comparisons
|
||||
# ------------------------------------------------------------------------------------------------
|
||||
|
@ -404,3 +405,39 @@ func verify*[T: byte|char](public_key: PublicKey, message: openarray[T], signatu
|
|||
if verified:
|
||||
return cttBLS_Success
|
||||
return cttBLS_VerificationFailure
|
||||
|
||||
func fast_aggregate_verify*[T: byte|char](public_keys: openArray[PublicKey], message: openarray[T], signature: Signature): CttBLSStatus =
|
||||
## Check that a signature is valid for a message
|
||||
## under the aggregate of provided public keys.
|
||||
## 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:
|
||||
## - Public keys 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 keys and signature are assumed to be on curve subgroup checked.
|
||||
|
||||
if public_keys.len == 0:
|
||||
# IETF spec precondition
|
||||
return cttBLS_ZeroLengthAggregation
|
||||
|
||||
# Deal with cases were pubkey or signature were mistakenly zero-init, due to a generic aggregation tentative for example
|
||||
if signature.raw.isInf().bool:
|
||||
return cttBLS_PointAtInfinity
|
||||
|
||||
for i in 0 ..< public_keys.len:
|
||||
if public_keys[i].raw.isInf().bool:
|
||||
return cttBLS_PointAtInfinity
|
||||
|
||||
let verified = fastAggregateVerify(
|
||||
toOpenArray(cast[ptr UncheckedArray[typeof public_keys[0].raw]](public_keys[0].raw.unsafeAddr), public_keys.low, public_keys.high),
|
||||
message, signature.raw,
|
||||
sha256, 128, augmentation = "", DST)
|
||||
if verified:
|
||||
return cttBLS_Success
|
||||
return cttBLS_VerificationFailure
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import
|
||||
../math/[ec_shortweierstrass, pairings],
|
||||
../math/elliptic/ec_shortweierstrass_batch_ops,
|
||||
../math/constants/zoo_generators,
|
||||
../hash_to_curve/hash_to_curve,
|
||||
../hashes
|
||||
|
@ -94,7 +95,7 @@ func coreSign*[B1, B2, B3: byte|char, Sig, SecKey](
|
|||
signature.affine(sig)
|
||||
|
||||
func coreVerify*[B1, B2, B3: byte|char, Pubkey, Sig](
|
||||
pubKey: Pubkey,
|
||||
pubkey: Pubkey,
|
||||
message: openarray[B1],
|
||||
signature: Sig,
|
||||
H: type CryptoHash,
|
||||
|
@ -119,8 +120,45 @@ func coreVerify*[B1, B2, B3: byte|char, Pubkey, Sig](
|
|||
|
||||
# e(PK, H(msg))*e(sig, -G) == 1
|
||||
when Sig.G == G2:
|
||||
pairing(gt, [pubKey, negG], [Q, signature])
|
||||
pairing(gt, [pubkey, negG], [Q, signature])
|
||||
else:
|
||||
pairing(gt, [Q, signature], [pubKey, negG])
|
||||
pairing(gt, [Q, signature], [pubkey, negG])
|
||||
|
||||
return gt.isOne().bool()
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Aggregate verification
|
||||
#
|
||||
# ############################################################
|
||||
#
|
||||
# Terminology:
|
||||
#
|
||||
# - fastAggregateVerify:
|
||||
# Verify the aggregate of multiple signatures by multiple pubkeys
|
||||
# on the same message.
|
||||
#
|
||||
# - aggregateVerify:
|
||||
# Verify the aggregate of multiple signatures by multiple (pubkey, message) pairs
|
||||
#
|
||||
# - batchVerify:
|
||||
# Verify that all (pubkey, message, signature) triplets are valid
|
||||
|
||||
func fastAggregateVerify*[B1, B2, B3: byte|char, Pubkey, Sig](
|
||||
pubkeys: openArray[Pubkey],
|
||||
message: openarray[B1],
|
||||
signature: Sig,
|
||||
H: type CryptoHash,
|
||||
k: static int,
|
||||
augmentation: openarray[B2],
|
||||
domainSepTag: openarray[B3]): bool =
|
||||
## Verify the aggregate of multiple signatures by multiple pubkeys
|
||||
## on the same message.
|
||||
|
||||
var accum {.noinit.}: ECP_ShortW_Jac[Pubkey.F, Pubkey.G]
|
||||
accum.sum_batch_vartime(pubkeys)
|
||||
|
||||
var aggPubkey {.noinit.}: Pubkey
|
||||
aggPubkey.affine(accum)
|
||||
|
||||
aggPubkey.coreVerify(message, signature, H, k, augmentation, domainSepTag)
|
|
@ -13,13 +13,16 @@ import
|
|||
../constantine/math/io/io_bigints
|
||||
|
||||
type
|
||||
# https://github.com/ethereum/bls12-381-tests/blob/master/formats/
|
||||
|
||||
PubkeyField = object
|
||||
pubkey: array[48, byte]
|
||||
SignatureField =object
|
||||
signature: array[96, byte]
|
||||
DeserG1_test = object
|
||||
input: PubkeyField
|
||||
output: bool
|
||||
|
||||
SignatureField =object
|
||||
signature: array[96, byte]
|
||||
DeserG2_test = object
|
||||
input: SignatureField
|
||||
output: bool
|
||||
|
@ -27,7 +30,6 @@ type
|
|||
InputSign = object
|
||||
privkey: array[32, byte]
|
||||
message: array[32, byte]
|
||||
|
||||
Sign_test = object
|
||||
input: InputSign
|
||||
output: array[96, byte]
|
||||
|
@ -36,11 +38,18 @@ type
|
|||
pubkey: array[48, byte]
|
||||
message: array[32, byte]
|
||||
signature: array[96, byte]
|
||||
|
||||
Verify_test = object
|
||||
input: InputVerify
|
||||
output: bool
|
||||
|
||||
InputFastAggregateVerify = object
|
||||
pubkeys: seq[array[48, byte]]
|
||||
message: array[32, byte]
|
||||
signature: array[96, byte]
|
||||
FastAggregateVerify_test = object
|
||||
input: InputFastAggregateVerify
|
||||
output: bool
|
||||
|
||||
proc parseHook*[N: static int](src: string, pos: var int, value: var array[N, byte]) =
|
||||
var str: string
|
||||
parseHook(src, pos, str)
|
||||
|
@ -73,7 +82,7 @@ template testGen*(name, testData, TestType, body: untyped): untyped =
|
|||
var count = 0 # Need to fail if walkDir doesn't return anything
|
||||
var skipped = 0
|
||||
for dir, file in walkTests(astToStr(name), skipped):
|
||||
stdout.write(" " & astToStr(name) & " test: " & alignLeft(file, 60))
|
||||
stdout.write(" " & astToStr(name) & " test: " & alignLeft(file, 70))
|
||||
let testFile = readFile(dir/file)
|
||||
let testData = testFile.fromJson(TestType)
|
||||
|
||||
|
@ -169,7 +178,7 @@ testGen(verify, testVector, Verify_test):
|
|||
var
|
||||
pubkey{.noInit.}: PublicKey
|
||||
signature{.noInit.}: Signature
|
||||
status = cttBLS_Success
|
||||
status = cttBLS_VerificationFailure
|
||||
|
||||
block testChecks:
|
||||
status = pubkey.deserialize_public_key_compressed(testVector.input.pubkey)
|
||||
|
@ -181,8 +190,8 @@ testGen(verify, testVector, Verify_test):
|
|||
# For point at infinity, we want to make sure that "verify" itself handles them.
|
||||
break testChecks
|
||||
|
||||
|
||||
status = pubkey.verify(testVector.input.message, signature)
|
||||
|
||||
let success = status == cttBLS_Success
|
||||
doAssert success == testVector.output, block:
|
||||
"\Verification differs from expected \n" &
|
||||
|
@ -202,6 +211,32 @@ testGen(verify, testVector, Verify_test):
|
|||
doAssert s == cttBLS_Success
|
||||
doAssert output == testVector.input.signature
|
||||
|
||||
testGen(fast_aggregate_verify, testVector, FastAggregateVerify_test):
|
||||
var
|
||||
pubkeys = newSeq[PublicKey](testVector.input.pubkeys.len)
|
||||
signature{.noInit.}: Signature
|
||||
status = cttBLS_VerificationFailure
|
||||
|
||||
block testChecks:
|
||||
for i in 0 ..< testVector.input.pubkeys.len:
|
||||
status = pubkeys[i].deserialize_public_key_compressed(testVector.input.pubkeys[i])
|
||||
if status notin {cttBLS_Success, cttBLS_PointAtInfinity}:
|
||||
# For point at infinity, we want to make sure that "verify" itself handles them.
|
||||
break testChecks
|
||||
|
||||
status = signature.deserialize_signature_compressed(testVector.input.signature)
|
||||
if status notin {cttBLS_Success, cttBLS_PointAtInfinity}:
|
||||
# For point at infinity, we want to make sure that "verify" itself handles them.
|
||||
break testChecks
|
||||
|
||||
status = pubkeys.fast_aggregate_verify(testVector.input.message, signature)
|
||||
|
||||
let success = status == cttBLS_Success
|
||||
doAssert success == testVector.output, block:
|
||||
"\Verification differs from expected \n" &
|
||||
" valid sig? " & $success & " (" & $status & ")\n" &
|
||||
" expected: " & $testVector.output
|
||||
|
||||
suite "BLS signature on BLS12381G3 - ETH 2.0 test vectors":
|
||||
test "Deserialization_G1(PublicKey) -> bool":
|
||||
test_deserialization_G1()
|
||||
|
@ -211,3 +246,5 @@ suite "BLS signature on BLS12381G3 - ETH 2.0 test vectors":
|
|||
test_sign()
|
||||
test "verify(PublicKey, message, Signature) -> bool":
|
||||
test_verify()
|
||||
test "fast_aggregate_verify(seq[PublicKey], message, Signature) -> bool":
|
||||
test_fast_aggregate_verify()
|
Loading…
Reference in New Issue