Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BLS signature v4 #91

Merged
merged 6 commits into from
Oct 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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