diff --git a/.gitmodules b/.gitmodules index 1da07b1b..a50a3489 100644 --- a/.gitmodules +++ b/.gitmodules @@ -183,3 +183,6 @@ url = https://github.com/status-im/nim-libp2p-dht.git ignore = untracked branch = master +[submodule "vendor/constantine"] + path = vendor/constantine + url = https://github.com/mratsim/constantine diff --git a/dagger/por/README.md b/dagger/por/README.md index 1ee54b5e..258606b2 100644 --- a/dagger/por/README.md +++ b/dagger/por/README.md @@ -1 +1,9 @@ Nim implementation of Proof of Storage related schemes + +Implementation of the BLS-based public PoS scheme from +Shacham H., Waters B., "Compact Proofs of Retrievability" +using pairing over BLS12-381 ECC. + +For a detailed description of the implementation, see `bls.nim` + +For a usage example, see `testbls.nim` diff --git a/dagger/por/backends/backend_blst.nim b/dagger/por/backends/backend_blst.nim new file mode 100644 index 00000000..1c27109a --- /dev/null +++ b/dagger/por/backends/backend_blst.nim @@ -0,0 +1,111 @@ +## Nim-POS +## Copyright (c) 2022 Status Research & Development GmbH +## Licensed under either of +## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) +## * MIT license ([LICENSE-MIT](LICENSE-MIT)) +## at your option. +## This file may not be copied, modified, or distributed except according to +## those terms. + +# Implementation of the BLS-based public PoS scheme from +# Shacham H., Waters B., "Compact Proofs of Retrievability" +# using pairing over BLS12-381 ECC + +import blscurve +import blscurve/blst/blst_abi + +type + ec_SecretKey* = blscurve.SecretKey + ec_PublicKey* = blscurve.PublicKey + ec_p1* = blst_p1 + ec_p2* = blst_p2 + ec_scalar* = blst_scalar + ec_fr* = blst_fr + ec_signature* = Signature + +# these need to be template as a workaround for const +template EC_G1* : blst_p1_affine = BLS12_381_G1 +template EC_G2* : blst_p2_affine = BLS12_381_G2 + +let + ec_p1_from_affine* = blst_p1_from_affine + ec_scalar_from_bendian* = blst_scalar_from_bendian + ec_scalar_fr_check* = blst_scalar_fr_check + ec_p2_from_affine* = blst_p2_from_affine + ec_p2_mult* = blst_p2_mult + ec_p1_mult* = blst_p1_mult + ec_p1_add_or_double* = blst_p1_add_or_double + ec_fr_from_scalar* = blst_fr_from_scalar + ec_fr_mul* = blst_fr_mul + ec_scalar_from_fr* = blst_scalar_from_fr + ec_fr_add* = blst_fr_add + ec_p1_on_curve* = blst_p1_on_curve + ec_keygen* = blscurve.keyGen + +func ec_export_raw*(signature: Signature): array[96, byte] {.inline, noinit.} = + blscurve.exportRaw(signature) + +proc ec_sign*[T: byte|char](secretKey: SecretKey, message: openarray[T]): Signature = + blscurve.sign(secretKey, message) + +proc ec_hash_to_g1*[T,U,V: byte|char](dst: var blst_p1; + msg: openArray[T]; + domainSepTag: openArray[U]; + aug: openArray[V]) = + blst_hash_to_g1(dst, msg, domainSepTag, aug) + +proc pairing(a: ec_p1, b: ec_p2): blst_fp12 = + ## Calculate pairing G_1,G_2 -> G_T + var aa: blst_p1_affine + var bb: blst_p2_affine + blst_p1_to_affine(aa, a) + blst_p2_to_affine(bb, b) + var l: blst_fp12 + blst_miller_loop(l, bb, aa) + blst_final_exp(result, l) + +proc verifyPairingsNaive(a1: blst_p1, a2: blst_p2, b1: blst_p1, b2: blst_p2) : bool = + let e1 = pairing(a1, a2) + let e2 = pairing(b1, b2) + return e1 == e2 + +proc verifyPairingsNeg(a1: ec_p1, a2: ec_p2, b1: ec_p1, b2: ec_p2) : bool = + ## Faster pairing verification using 2 miller loops but ony one final exponentiation + ## based on https://github.com/benjaminion/c-kzg/blob/main/src/bls12_381.c + var + loop0, loop1, gt_point: blst_fp12 + aa1, bb1: blst_p1_affine + aa2, bb2: blst_p2_affine + + var a1neg = a1 + blst_p1_cneg(a1neg, 1) + + blst_p1_to_affine(aa1, a1neg) + blst_p1_to_affine(bb1, b1) + blst_p2_to_affine(aa2, a2) + blst_p2_to_affine(bb2, b2) + + blst_miller_loop(loop0, aa2, aa1) + blst_miller_loop(loop1, bb2, bb1) + + blst_fp12_mul(gt_point, loop0, loop1) + blst_final_exp(gt_point, gt_point) + + return blst_fp12_is_one(gt_point).bool + +proc verifyPairings*(a1: ec_p1, a2: ec_p2, b1: ec_p1, b2: ec_p2) : bool = + ## Wrapper to select verify pairings implementation + verifyPairingsNaive(a1, a2, b1, b2) + #verifyPairingsNeg(a1, a2, b1, b2) + +func ec_from_bytes*( + obj: var (Signature|ProofOfPossession), + raw: array[96, byte] or array[192, byte] + ): bool {.inline.} = + fromBytes(obj, raw) + +func ec_verify*[T: byte|char]( + publicKey: PublicKey, + message: openarray[T], + signature: Signature) : bool = + verify(publicKey, message, signature) \ No newline at end of file diff --git a/dagger/por/backends/backend_constantine.nim b/dagger/por/backends/backend_constantine.nim new file mode 100644 index 00000000..2218c79a --- /dev/null +++ b/dagger/por/backends/backend_constantine.nim @@ -0,0 +1,189 @@ +## Nim-POS +## Copyright (c) 2022 Status Research & Development GmbH +## Licensed under either of +## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) +## * MIT license ([LICENSE-MIT](LICENSE-MIT)) +## at your option. +## This file may not be copied, modified, or distributed except according to +## those terms. + +# Implementation of the BLS-based public PoS scheme from +# Shacham H., Waters B., "Compact Proofs of Retrievability" +# using pairing over BLS12-381 ECC + +import + constantine, + # constantine/platforms/abstractions, + constantine/math/arithmetic, + # constantine/math/extension_fields, + # constantine/math/config/curves, + constantine/math/elliptic/[ec_shortweierstrass_affine, ec_shortweierstrass_projective], + constantine/math/curves/[zoo_subgroups, zoo_pairings, zoo_generators], + # constantine/math/pairing/cyclotomic_subgroup, + # constantine/math/io/io_extfields, + constantine/math/io/io_bigints, + # constantine/math/config/[curves_declaration, type_ff], + constantine/math/config/type_ff, + constantine/blssig_pop_on_bls12381_g2, + constantine/hash_to_curve/hash_to_curve, + constantine/hashes, + constantine/math/pairings + +export hashes +export matchingBigInt +export getNonResidueFp + +when defined(debugConstantine): + import constantine/math/config/type_bigint + export `$` + +#set up curve and G1/G2 +#const C = BN254_Snarks +const C = BLS12_381 + +type + ec_SecretKey* = SecretKey + ec_PublicKey* = PublicKey + ec_p1* = ECP_ShortW_Jac[Fp[C], G1] + ec_p1_affine = ECP_ShortW_Aff[Fp[C], G1] + ec_p2* = ECP_ShortW_Jac[Fp2[C], G2] + ec_p2_affine = ECP_ShortW_Aff[Fp2[C], G2] + ec_scalar* = matchingOrderBigInt(C) + ec_fr* = Fr[C] + ec_signature* = Signature + +let + EC_G1* = C.getGenerator($G1) + EC_G2* = C.getGenerator($G2) + +func ec_p1_from_affine*(dst: var ec_p1, a: ec_p1_affine) = + dst.fromAffine(a) + +#let ec_scalar_from_bendian* = unmarshalBE # not exposed +func ec_scalar_from_bendian*( + s: var ec_scalar, + b: openArray[byte]) = + s.unmarshal(b, bigEndian) + +#let ec_scalar_fr_check* = blst_scalar_fr_check +func ec_scalar_fr_check*( + s: ec_scalar) : bool = + bool(s < C.getCurveOrder()) + +func ec_p2_from_affine*(dst: var ec_p2, a: ec_p2_affine) = + dst.fromAffine(a) + +func ec_p2_mult*( + dst: var ec_p2, + p: ec_p2, + scalar: ec_scalar, + nbits: uint) = + dst = p + dst.scalarMul(scalar) + +func ec_p1_mult*( + dst: var ec_p1, + p: ec_p1, + scalar: ec_scalar, + nbits: uint) = + dst = p + dst.scalarMul(scalar) + +func ec_p1_add_or_double*(dst: var ec_p1, a: ec_p1, b: ec_p1) = + dst.sum(a,b) + +# Workaround: using ec_fr makes bindConstant fail, hence Fr[C] type below +func ec_fr_from_scalar*(res: var Fr[C], scalar: ec_scalar) = + res.fromBig(scalar) + +# Workaround: using ec_fr makes bindConstant fail, hence Fr[C] type below +func ec_scalar_from_fr*(res: var ec_scalar, fr: Fr[C]) = + res = toBig(fr) + +func ec_fr_add*(res: var Fr[C], a, b: Fr[C]) = + sum(res, a, b) + +func ec_fr_mul*(res: var Fr[C], a, b: Fr[C]) = + prod(res, a, b) + +func ec_p1_on_curve*(p: ec_p1) : bool = + var aff : ec_p1_affine + aff.affine(p) + (bool) isOnCurve(aff.x, aff.y, G1) + +func ec_keygen*(ikm: array[32, byte], pk: var PublicKey, sk: var SecretKey) : bool = + # TODO: HKDF key generation as in spec (https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature#section-2.3) + var ikm2 = ikm + ikm2[0] = 0 # TODO: this is a hack, not secure + let ok = sk.deserialize_secret_key(ikm2) + doAssert ok == cttBLS_Success + let ok2 = pk.derive_public_key(sk) + doAssert ok2 == cttBLS_Success + (ok == cttBLS_Success) and (ok2 == cttBLS_Success) + +func ec_export_raw*(signature: Signature): array[96, byte] {.inline, noinit.} = + let ok = result.serialize_signature_compressed(signature) + doAssert ok == cttBLS_Success + +proc ec_sign*(secretKey: SecretKey, message: openarray[char]): Signature = + let ok = result.sign(secretKey, message) + doAssert ok == cttBLS_Success + +proc ec_hash_to_g1*(dst: var ec_p1, + msg: openArray[byte], + domainSepTag: openArray[char], + aug: openArray[char]) = + sha256.hashToCurve(128, dst, aug, msg, domainSepTag) #TODO: fix k + +proc verifyPairingsNaive[C](a1: ECP_ShortW_Jac[Fp[C], G1], a2: ec_p2, b1: ec_p1, b2: ec_p2) : bool = + # first parameter is in extended form to allow inference of C + var + e1, e2: Fp12[C] + a1aff, b1aff {.noInit.}: ec_p1_affine + a2aff, b2aff {.noInit.}: ec_p2_affine + a1aff.affine(a1) + b1aff.affine(b1) + a2aff.affine(a2) + b2aff.affine(b2) + pairing(e1, a1aff, a2aff) + pairing(e2, b1aff, b2aff) + return (e1 == e2).bool() + +proc verifyPairingsNeg[C](a1: ECP_ShortW_Jac[Fp[C], G1], a2: ec_p2, b1: ec_p1, b2: ec_p2) : bool = + # first parameter is in extended form to allow inference of C + when C.getEmbeddingDegree() == 12: + var gt {.noInit.}: Fp12[C] + else: + {.error: "Not implemented: signature on k=" & $C.getEmbeddingDegree() & " for curve " & $$C.} + + var + a1aff, b1aff {.noInit.}: ec_p1_affine + a2aff, negb2aff {.noInit.}: ec_p2_affine + a1aff.affine(a1) + b1aff.affine(b1) + a2aff.affine(a2) + negb2aff.affine(b2) + negb2aff.neg(negb2aff) + gt.pairing([a1aff, b1aff], [a2aff, negb2aff]) + return gt.isOne().bool() + +proc verifyPairings*(a1: ec_p1, a2: ec_p2, b1: ec_p1, b2: ec_p2) : bool = + ## Wrapper to select verify pairings implementation + when C == BLS12_381: + verifyPairingsNeg(a1, a2, b1, b2) + else: + verifyPairingsNaive(a1, a2, b1, b2) + + +func ec_from_bytes*( + dst: var Signature, + raw: array[96, byte] or array[192, byte] + ): bool {.inline.} = + let ok = dst.deserialize_signature_compressed(raw) + ok == cttBLS_Success + +func ec_verify*( + publicKey: PublicKey, + message: openarray[char], + signature: Signature) : bool = + publicKey.verify(message, signature) == cttBLS_Success diff --git a/dagger/por/por.nim b/dagger/por/por.nim index fa021be4..2b71aa69 100644 --- a/dagger/por/por.nim +++ b/dagger/por/por.nim @@ -78,8 +78,13 @@ # The size of the proof is instead # s * 32 + 48 bytes -import blscurve -import blscurve/blst/blst_abi +# Select backend to use +# - blst supports only the BLS12-381 curve +# - constantine is more experimental, supports BLS and BN curves as well +# As of now configuration of backends is in the backend_* file itself +import ./backends/backend_blst +#import ./backends/backend_constantine + import ../rng import endians @@ -90,25 +95,26 @@ const bytespersector = 31 # length in bytes of the unique (random) name const namelen = 512 + type # a single sector ZChar = array[bytespersector, byte] # secret key combining the metadata signing key and the POR generation key SecretKey = object - signkey: blscurve.SecretKey - key: blst_scalar + signkey: ec_SecretKey + key: ec_scalar # public key combining the metadata signing key and the POR validation key PublicKey = object - signkey: blscurve.PublicKey - key: blst_p2 + signkey: ec_PublicKey + key: ec_p2 # POR metadata (called "file tag t_0" in the original paper) TauZero = object name: array[namelen, byte] n: int64 - u: seq[blst_p1] + u: seq[ec_p1] # signed POR metadata (called "signed file tag t" in the original paper) Tau = object @@ -118,61 +124,53 @@ type # PoR query element QElement = object I: int64 - V: blst_scalar + V: ec_scalar -proc fromBytesBE(a: array[32, byte]): blst_scalar = +proc fromBytesBE(a: array[32, byte]): ec_scalar = ## Convert data to blst native form - blst_scalar_from_bendian(result, a) - doAssert(blst_scalar_fr_check(result).bool) + ec_scalar_from_bendian(result, a) + doAssert(ec_scalar_fr_check(result).bool) -proc fromBytesBE(a: openArray[byte]): blst_scalar = +proc fromBytesBE(a: openArray[byte]): ec_scalar = ## Convert data to blst native form var b: array[32, byte] doAssert(a.len <= b.len) let d = b.len - a.len for i in 0 ..< a.len: b[i+d] = a[i] - blst_scalar_from_bendian(result, b) - doAssert(blst_scalar_fr_check(result).bool) + ec_scalar_from_bendian(result, b) + doAssert(ec_scalar_fr_check(result).bool) proc getSector(f: File, blockid: int64, sectorid: int64, spb: int64): ZChar = ## Read file sector at given postion f.setFilePos((blockid * spb + sectorid) * sizeof(result)) let r = f.readBytes(result, 0, sizeof(result)) -proc rndScalar(): blst_scalar = +proc rndScalar(scalar: var ec_scalar): void = ## Generate random scalar within the subroup order r var scal{.noInit.}: array[32, byte] - var scalar{.noInit.}: blst_scalar while true: for val in scal.mitems: val = byte Rng.instance.rand(0xFF) - scalar.blst_scalar_from_bendian(scal) - if blst_scalar_fr_check(scalar).bool: + scalar.ec_scalar_from_bendian(scal) + if ec_scalar_fr_check(scalar).bool: break - return scalar - -proc rndP2(): (blst_p2, blst_scalar) = +proc rndP2(x: var ec_p2, scalar: var ec_scalar): void = ## Generate random point on G2 - var x{.noInit.}: blst_p2 - x.blst_p2_from_affine(BLS12_381_G2) # init from generator - let scalar = rndScalar() - x.blst_p2_mult(x, scalar, 255) - return (x, scalar) + x.ec_p2_from_affine(EC_G2) # init from generator + scalar.rndScalar() + x.ec_p2_mult(x, scalar, 255) -proc rndP1(): (blst_p1, blst_scalar) = +proc rndP1(x: var ec_p1, scalar: var ec_scalar): void = ## Generate random point on G1 - var x{.noInit.}: blst_p1 - x.blst_p1_from_affine(BLS12_381_G1) # init from generator - let scalar = rndScalar() - x.blst_p1_mult(x, scalar, 255) - return (x, scalar) + x.ec_p1_from_affine(EC_G1) # init from generator + scalar.rndScalar() + x.ec_p1_mult(x, scalar, 255) -proc posKeygen(): (blst_p2, blst_scalar) = +let posKeygen = rndP2 ## Generate POS key pair - rndP2() proc keygen*(): (PublicKey, SecretKey) = ## Generate key pair for signing metadata and for POS tags @@ -182,9 +180,9 @@ proc keygen*(): (PublicKey, SecretKey) = for b in ikm.mitems: b = byte Rng.instance.rand(0xFF) - doAssert ikm.keyGen(pk.signkey, sk.signkey) + doAssert ikm.ec_keygen(pk.signkey, sk.signkey) - (pk.key, sk.key) = posKeygen() + posKeygen(pk.key, sk.key) return (pk, sk) proc split(f: File, s: int64): int64 = @@ -198,12 +196,12 @@ proc split(f: File, s: int64): int64 = return n -proc hashToG1[T: byte|char](msg: openArray[T]): blst_p1 = +proc hashToG1(msg: openArray[byte]): ec_p1 = ## Hash to curve with Dagger specific domain separation const dst = "DAGGER-PROOF-OF-CONCEPT" - result.blst_hash_to_g1(msg, dst, aug = "") + result.ec_hash_to_g1(msg, dst, aug = "") -proc hashNameI(name: array[namelen, byte], i: int64): blst_p1 = +proc hashNameI(name: array[namelen, byte], i: int64): ec_p1 = ## Calculate unique filname and block index based hash # # naive implementation, hashing a long string representation @@ -216,20 +214,20 @@ proc hashNameI(name: array[namelen, byte], i: int64): blst_p1 = bigEndian64(addr(namei[sizeof(name)]), unsafeAddr(i)) return hashToG1(namei) -proc generateAuthenticatorNaive(i: int64, s: int64, t: TauZero, f: File, ssk: SecretKey): blst_p1 = +proc generateAuthenticatorNaive(i: int64, s: int64, t: TauZero, f: File, ssk: SecretKey): ec_p1 = ## Naive implementation of authenticator as in the S&W paper. ## With the paper's multiplicative notation: ## \sigmai=\(H(file||i)\cdot\prod{j=0}^{s-1}{uj^{m[i][j]}})^{\alpha} - var sum: blst_p1 + var sum: ec_p1 for j in 0 ..< s: - var prod: blst_p1 - prod.blst_p1_mult(t.u[j], fromBytesBE(getSector(f, i, j, s)), 255) - sum.blst_p1_add_or_double(sum, prod) + var prod: ec_p1 + prod.ec_p1_mult(t.u[j], fromBytesBE(getSector(f, i, j, s)), 255) + sum.ec_p1_add_or_double(sum, prod) - blst_p1_add_or_double(result, hashNameI(t.name, i), sum) - result.blst_p1_mult(result, ssk.key, 255) + ec_p1_add_or_double(result, hashNameI(t.name, i), sum) + result.ec_p1_mult(result, ssk.key, 255) -proc generateAuthenticatorOpt(i: int64, s: int64, t: TauZero, ubase: openArray[blst_scalar], f: File, ssk: SecretKey): blst_p1 = +proc generateAuthenticatorOpt(i: int64, s: int64, t: TauZero, ubase: openArray[ec_scalar], f: File, ssk: SecretKey): ec_p1 = ## Optimized implementation of authenticator generation ## This implementation is reduces the number of scalar multiplications ## from s+1 to 1+1 , using knowledge about the scalars (r_j) @@ -237,31 +235,31 @@ proc generateAuthenticatorOpt(i: int64, s: int64, t: TauZero, ubase: openArray[b ## ## With the paper's multiplicative notation, we use: ## (H(file||i)\cdot g^{\sum{j=0}^{s-1}{r_j \cdot m[i][j]}})^{\alpha} - var sum: blst_fr - var sums: blst_scalar + var sum: ec_fr + var sums: ec_scalar for j in 0 ..< s: - var a, b, x: blst_fr - a.blst_fr_from_scalar(ubase[j]) - b.blst_fr_from_scalar(fromBytesBE(getSector(f, i, j, s))) - x.blst_fr_mul(a, b) - sum.blst_fr_add(sum, x) - sums.blst_scalar_from_fr(sum) + var a, b, x: ec_fr + a.ec_fr_from_scalar(ubase[j]) + b.ec_fr_from_scalar(fromBytesBE(getSector(f, i, j, s))) + x.ec_fr_mul(a, b) + sum.ec_fr_add(sum, x) + sums.ec_scalar_from_fr(sum) - result.blst_p1_from_affine(BLS12_381_G1) - result.blst_p1_mult(result, sums, 255) + result.ec_p1_from_affine(EC_G1) + result.ec_p1_mult(result, sums, 255) - result.blst_p1_add_or_double(result, hashNameI(t.name, i)) - result.blst_p1_mult(result, ssk.key, 255) + result.ec_p1_add_or_double(result, hashNameI(t.name, i)) + result.ec_p1_mult(result, ssk.key, 255) -proc generateAuthenticator(i: int64, s: int64, t: TauZero, ubase: openArray[blst_scalar], f: File, ssk: SecretKey): blst_p1 = +proc generateAuthenticator(i: int64, s: int64, t: TauZero, ubase: openArray[ec_scalar], f: File, ssk: SecretKey): ec_p1 = ## Wrapper to select tag generator implementation # let a = generateAuthenticatorNaive(i, s, t, f, ssk) let b = generateAuthenticatorOpt(i, s, t, ubase, f, ssk) - # doAssert(a.blst_p1_is_equal(b).bool) + # doAssert(a.ec_p1_is_equal(b).bool) return b -proc setup*(ssk: SecretKey, s:int64, filename: string): (Tau, seq[blst_p1]) = +proc setup*(ssk: SecretKey, s:int64, filename: string): (Tau, seq[ec_p1]) = ## Set up the POR scheme by generating tags and metadata let file = open(filename) let n = split(file, s) @@ -272,19 +270,22 @@ proc setup*(ssk: SecretKey, s:int64, filename: string): (Tau, seq[blst_p1]) = t.name[i] = byte Rng.instance.rand(0xFF) # generate the coefficient vector for combining sectors of a block: U - var ubase: seq[blst_scalar] + var ubase: seq[ec_scalar] for i in 0 ..< s : - let (u, ub) = rndP1() + var + u: ec_p1 + ub: ec_scalar + rndP1(u, ub) t.u.add(u) ubase.add(ub) #TODO: a better bytearray conversion of TauZero for the signature might be needed # the current conversion using $t might be architecture dependent and not unique - let signature = sign(ssk.signkey, $t) - let tau = Tau(t: t, signature: signature.exportRaw()) + let signature = ec_sign(ssk.signkey, $t) + let tau = Tau(t: t, signature: signature.ec_export_raw()) #generate sigmas - var sigmas: seq[blst_p1] + var sigmas: seq[ec_p1] for i in 0 ..< n : sigmas.add(generateAuthenticator(i, s, t, ubase, file, ssk)) @@ -298,109 +299,65 @@ proc generateQuery*(tau: Tau, spk: PublicKey, l: int): seq[QElement] = for i in 0 ..< l : var q: QElement q.I = Rng.instance.rand(n-1) #TODO: dedup - q.V = rndScalar() #TODO: fix range + q.V.rndScalar() #TODO: fix range result.add(q) -proc generateProof*(q: openArray[QElement], authenticators: openArray[blst_p1], spk: PublicKey, s: int64, filename: string): (seq[blst_scalar], blst_p1) = +proc generateProof*(q: openArray[QElement], authenticators: openArray[ec_p1], spk: PublicKey, s: int64, filename: string): (seq[ec_scalar], ec_p1) = ## Generata BLS proofs for a given query let file = open(filename) - var mu: seq[blst_scalar] + var mu: seq[ec_scalar] for j in 0 ..< s : - var muj: blst_fr + var muj: ec_fr for qelem in q : - var x, v, sector: blst_fr + var x, v, sector: ec_fr let sect = fromBytesBE(getSector(file, qelem.I, j, s)) - sector.blst_fr_from_scalar(sect) - v.blst_fr_from_scalar(qelem.V) - x.blst_fr_mul(v, sector) - muj.blst_fr_add(muj, x) - var mujs: blst_scalar - mujs.blst_scalar_from_fr(muj) + sector.ec_fr_from_scalar(sect) + v.ec_fr_from_scalar(qelem.V) + x.ec_fr_mul(v, sector) + muj.ec_fr_add(muj, x) + var mujs: ec_scalar + mujs.ec_scalar_from_fr(muj) mu.add(mujs) - var sigma: blst_p1 + var sigma: ec_p1 for qelem in q: - var prod: blst_p1 - prod.blst_p1_mult(authenticators[qelem.I], qelem.V, 255) - sigma.blst_p1_add_or_double(sigma, prod) + var prod: ec_p1 + prod.ec_p1_mult(authenticators[qelem.I], qelem.V, 255) + sigma.ec_p1_add_or_double(sigma, prod) file.close() return (mu, sigma) -proc pairing(a: blst_p1, b: blst_p2): blst_fp12 = - ## Calculate pairing G_1,G_2 -> G_T - var aa: blst_p1_affine - var bb: blst_p2_affine - blst_p1_to_affine(aa, a) - blst_p2_to_affine(bb, b) - var l: blst_fp12 - blst_miller_loop(l, bb, aa) - blst_final_exp(result, l) - -proc verifyPairingsNaive(a1: blst_p1, a2: blst_p2, b1: blst_p1, b2: blst_p2) : bool = - let e1 = pairing(a1, a2) - let e2 = pairing(b1, b2) - return e1 == e2 - -proc verifyPairingsNeg(a1: blst_p1, a2: blst_p2, b1: blst_p1, b2: blst_p2) : bool = - ## Faster pairing verification using 2 miller loops but ony one final exponentiation - ## based on https://github.com/benjaminion/c-kzg/blob/main/src/bls12_381.c - var - loop0, loop1, gt_point: blst_fp12 - aa1, bb1: blst_p1_affine - aa2, bb2: blst_p2_affine - - var a1neg = a1 - blst_p1_cneg(a1neg, 1) - - blst_p1_to_affine(aa1, a1neg) - blst_p1_to_affine(bb1, b1) - blst_p2_to_affine(aa2, a2) - blst_p2_to_affine(bb2, b2) - - blst_miller_loop(loop0, aa2, aa1) - blst_miller_loop(loop1, bb2, bb1) - - blst_fp12_mul(gt_point, loop0, loop1) - blst_final_exp(gt_point, gt_point) - - return blst_fp12_is_one(gt_point).bool - -proc verifyPairings(a1: blst_p1, a2: blst_p2, b1: blst_p1, b2: blst_p2) : bool = - ## Wrapper to select verify pairings implementation - verifyPairingsNaive(a1, a2, b1, b2) - #verifyPairingsNeg(a1, a2, b1, b2) - -proc verifyProof*(tau: Tau, q: openArray[QElement], mus: openArray[blst_scalar], sigma: blst_p1, spk: PublicKey): bool = +proc verifyProof*(tau: Tau, q: openArray[QElement], mus: openArray[ec_scalar], sigma: ec_p1, spk: PublicKey): bool = ## Verify a BLS proof given a query # verify signature on Tau - var signature: Signature - if not signature.fromBytes(tau.signature): + var signature: ec_signature + if not signature.ec_from_bytes(tau.signature): return false - if not verify(spk.signkey, $tau.t, signature): + if not ec_verify(spk.signkey, $tau.t, signature): return false - var first: blst_p1 + var first: ec_p1 for qelem in q : - var prod: blst_p1 - prod.blst_p1_mult(hashNameI(tau.t.name, qelem.I), qelem.V, 255) - first.blst_p1_add_or_double(first, prod) - doAssert(blst_p1_on_curve(first).bool) + var prod: ec_p1 + prod.ec_p1_mult(hashNameI(tau.t.name, qelem.I), qelem.V, 255) + first.ec_p1_add_or_double(first, prod) + doAssert(ec_p1_on_curve(first).bool) let us = tau.t.u - var second: blst_p1 + var second: ec_p1 for j in 0 ..< len(us) : - var prod: blst_p1 - prod.blst_p1_mult(us[j], mus[j], 255) - second.blst_p1_add_or_double(second, prod) - doAssert(blst_p1_on_curve(second).bool) + var prod: ec_p1 + prod.ec_p1_mult(us[j], mus[j], 255) + second.ec_p1_add_or_double(second, prod) + doAssert(ec_p1_on_curve(second).bool) - var sum: blst_p1 - sum.blst_p1_add_or_double(first, second) + var sum: ec_p1 + sum.ec_p1_add_or_double(first, second) - var g{.noInit.}: blst_p2 - g.blst_p2_from_affine(BLS12_381_G2) + var g{.noInit.}: ec_p2 + g.ec_p2_from_affine(EC_G2) return verifyPairings(sum, spk.key, sigma, g) diff --git a/vendor/constantine b/vendor/constantine new file mode 160000 index 00000000..4d3de57b --- /dev/null +++ b/vendor/constantine @@ -0,0 +1 @@ +Subproject commit 4d3de57bbfaf065b7b41d73a9acabc73507bd039