Skip to content

Commit

Permalink
BLS signature v4 (#91)
Browse files Browse the repository at this point in the history
* Update vectors to BLSv4 v1.0.0-rc0 [skip ci]

* Workaround ethereum/consensus-spec-tests#22, ethereum/consensus-specs#2099

* Rework BLSv4 API ethereum/consensus-specs#2080 and address #76 #77

* Upgade Milagro vectors

* Upgrade BLST backend with new API

* BLST forgot to return true for publicFromSecret
  • Loading branch information
mratsim committed Oct 26, 2020
1 parent 70cbdd1 commit 3878b9b
Show file tree
Hide file tree
Showing 71 changed files with 281 additions and 148 deletions.
3 changes: 1 addition & 2 deletions blscurve.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
# This file may not be copied, modified, or distributed except according to
# those terms.

const BLS_ETH2_SPEC* = "v0.12.x (deprecated)"

const BLS_ETH2_SPEC* = "v1.0.0-rc0"
import
blscurve/bls_backend,
blscurve/keygen_eip2333
Expand Down
4 changes: 2 additions & 2 deletions blscurve/bls_backend.nim
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ else:
SecretKey, PublicKey, Signature, ProofOfPossession,
AggregateSignature,
`==`,
init, aggregate, finish,
init, aggregate, finish, aggregateAll,
sign, verify, aggregateVerify, fastAggregateVerify,
privToPub,
publicFromSecret, isZero,
fromHex, fromBytes, toHex, serialize, exportRaw
55 changes: 31 additions & 24 deletions blscurve/blst/bls_sig_min_pubkey_size_pop.nim
Original file line number Diff line number Diff line change
Expand Up @@ -148,24 +148,27 @@ func fromBytes*(
return false
let pa = cast[ptr array[L, byte]](raw[0].unsafeAddr)
result = obj.point.blst_p1_uncompress(pa[]) == BLST_SUCCESS
if obj.vec_is_zero():
return false

func fromBytes*(
obj: var SecretKey,
raw: openarray[byte] or array[32, byte]
): bool {.inline.} =
## Initialize a BLS signature scheme object from
## Initialize a BLS secret key from
## its raw bytes representation.
## Returns true on success and false otherwise
const L = 32
when raw is array:
obj.scalar.blst_scalar_from_bendian(raw)
return true
else:
if raw.len != 32:
return false
let pa = cast[ptr array[L, byte]](raw[0].unsafeAddr)
obj.scalar.blst_scalar_from_bendian(pa[])
return true
if obj.vec_is_zero():
return false
return true

func fromHex*(
obj: var (SecretKey|PublicKey|Signature|ProofOfPossession),
Expand Down Expand Up @@ -229,15 +232,18 @@ func exportRaw*(signature: Signature): array[96, byte] {.inline.}=
# Primitives
# ----------------------------------------------------------------------

func privToPub*(secretKey: SecretKey): PublicKey {.inline.} =
func publicFromSecret*(pubkey: var PublicKey, seckey: SecretKey): bool =
## Generates a public key from a secret key
## Generates a public key from a secret key
## This requires some -O3 compiler optimizations to be off
## as such {.passC: "-fno-peel-loops -fno-tree-loop-vectorize".}
## is automatically added to the compiler flags
## as such {.passC: "-fno-tree-vectorize".}
## is automatically added to the compiler flags in blst_lowlevel
if seckey.vec_is_zero():
return false
var pk {.noInit.}: blst_p1
pk.blst_sk_to_pk_in_g1(secretKey.scalar)
result.point.blst_p1_to_affine(pk)
pk.blst_sk_to_pk_in_g1(seckey.scalar)
pubkey.point.blst_p1_to_affine(pk)
return true

# Aggregate
# ----------------------------------------------------------------------
Expand All @@ -248,13 +254,15 @@ func init*(agg: var AggregateSignature, sig: Signature) {.inline.} =

func aggregate*(agg: var AggregateSignature, sig: Signature) {.inline.} =
## Aggregates signature ``sig`` into ``agg``
# Precondition n >= 1 is respected
agg.point.blst_p2_add_or_double_affine(
agg.point,
sig.point
)

proc aggregate*(agg: var AggregateSignature, sigs: openarray[Signature]) =
## Aggregates an array of signatures `sigs` into a signature `sig`
# Precondition n >= 1 is respected even if sigs.len == 0
for s in sigs:
agg.point.blst_p2_add_or_double_affine(
agg.point,
Expand All @@ -265,18 +273,22 @@ proc finish*(sig: var Signature, agg: AggregateSignature) {.inline.} =
## Canonicalize the AggregateSignature into a Signature
sig.point.blst_p2_to_affine(agg.point)

proc aggregate*(sigs: openarray[Signature]): Signature =
## Aggregates array of signatures ``sigs``
## and return aggregated signature.
##
proc aggregateAll*(dst: var Signature, sigs: openarray[Signature]): bool =
## Returns the aggregate signature of ``sigs[0..<sigs.len]``.
## Important:
## `dst` is overwritten
## if `dst` contains a signature, it WILL NOT be aggregated with `sigs`
## Array ``sigs`` must not be empty!
# TODO: what is the correct empty signature to return?
# for now we assume that empty aggregation is handled at the client level
doAssert(len(sigs) > 0)
##
## Returns false if `sigs` is the empty array
## and true otherwise
if len(sigs) == 0:
return false
var agg{.noInit.}: AggregateSignature
agg.init(sigs[0])
agg.aggregate(sigs.toOpenArray(1, sigs.high))
result.finish(agg)
dst.finish(agg)
return true

# Core operations
# ----------------------------------------------------------------------
Expand Down Expand Up @@ -322,13 +334,6 @@ func coreVerify[T: byte|char](
domainSepTag: static string): bool {.inline.} =
## Check that a signature (or proof-of-possession) is valid
## for a message (or serialized publickey) under the provided public key

# TODO
# ETH2~BLST difference https://github.com/supranational/blst/issues/11
if publicKey.point.vec_is_zero() and
sig_or_proof.point.vec_is_zero():
return true

result = BLST_SUCCESS == blst_core_verify_pk_in_g1(
publicKey.point,
sig_or_proof.point,
Expand Down Expand Up @@ -470,7 +475,9 @@ func popProve*(secretKey: SecretKey): ProofOfPossession =
# 4. R = SK * Q
# 5. proof = point_to_signature(R)
# 6. return proof
let pubkey = privToPub(secretKey)
var pubkey {.noInit.}: PublicKey
let ok {.used.} = pubkey.publicFromSecret(secretKey)
assert ok, "The secret key is INVALID, it should be initialized non-zero with keyGen or derive_child_secretKey"
result = popProve(secretKey, pubkey)

func popVerify*(publicKey: PublicKey, proof: ProofOfPossession): bool =
Expand Down
3 changes: 1 addition & 2 deletions blscurve/eth2_keygen/hkdf_mod_r_blst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -184,5 +184,4 @@ func keyGen*(ikm: openarray[byte], publicKey: var PublicKey, secretKey: var Secr

# The cast is a workaround for private field access
cast[ptr blst_scalar](secretKey.addr)[].blst_keygen(ikm, info = "")
publicKey = privToPub(secretKey)
return true
result = publicKey.publicFromSecret(secretKey)
8 changes: 5 additions & 3 deletions blscurve/eth2_keygen/hkdf_mod_r_miracl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func hkdf_mod_r*(secretKey: var SecretKey, ikm: openArray[byte], key_info: strin
# The cast is a workaround for private field access
BIG_384_dmod(cast[ptr BIG_384](secretKey.addr)[], dseckey, CURVE_Order)

if bool cast[ptr BIG_384](secretKey.addr)[].BIG_384_iszilch():
if secretKey.isZero():
salt = sha256.digest(salt0)
else:
return true
Expand Down Expand Up @@ -120,11 +120,13 @@ func keyGen*(ikm: openarray[byte], publicKey: var PublicKey, secretKey: var Secr
if ikm.len < 32:
return false

let ok = secretKey.hkdf_mod_r(ikm, key_info)
var ok = secretKey.hkdf_mod_r(ikm, key_info)
if not ok:
return false

# 4. xP = x * P
# 6. PK = point_to_pubkey(xP)
publicKey = privToPub(secretKey)
ok = publicKey.publicFromSecret(secretKey)
if not ok:
return false
return true
16 changes: 16 additions & 0 deletions blscurve/miracl/bls_sig_io.nim
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,18 @@ func fromHex*[T: SecretKey|PublicKey|Signature|ProofOfPossession](
## Initialize a BLS signature scheme object from
## its hex raw bytes representation.
## Returns true on a success and false otherwise
## For secret key deserialization
## A zero key is invalid
when obj is SecretKey:
result = obj.intVal.fromHex(hexStr)
if obj.intVal.isZilch():
return false
else:
result = obj.point.fromHex(hexStr)
when obj is PublicKey:
# KeyValidate
if obj.point.isInf():
result = false

func fromBytes*[T: SecretKey|PublicKey|Signature|ProofOfPossession](
obj: var T,
Expand All @@ -34,10 +42,18 @@ func fromBytes*[T: SecretKey|PublicKey|Signature|ProofOfPossession](
## Initialize a BLS signature scheme object from
## its raw bytes representation.
## Returns true on success and false otherwise
## For secret key deserialization
## A zero key is invalid
when obj is SecretKey:
result = obj.intVal.fromBytes(raw)
if obj.intVal.isZilch():
return false
else:
result = obj.point.fromBytes(raw)
when obj is PublicKey:
# KeyValidate
if obj.point.isInf():
result = false

func toHex*(obj: SecretKey|PublicKey|Signature|ProofOfPossession): string {.inline.} =
## Return the hex representation of a BLS signature scheme object
Expand Down
Loading

0 comments on commit 3878b9b

Please sign in to comment.