From c0969815a141b693e23d1ee1d4999a440dee2293 Mon Sep 17 00:00:00 2001 From: Eric Mastro Date: Wed, 8 Jun 2022 15:04:58 +1000 Subject: [PATCH] WIP: type conversions, start moving verifyProof - Add type conversions from BLS12-381 to BN254 - start moving verifyProof over to BN254 in solidity --- contracts/Proofs.sol | 179 ++++++++++++++++++++++++++++++++++++++++++- package.json | 2 + 2 files changed, 179 insertions(+), 2 deletions(-) diff --git a/contracts/Proofs.sol b/contracts/Proofs.sol index 9aa1f70..2b88069 100644 --- a/contracts/Proofs.sol +++ b/contracts/Proofs.sol @@ -1,5 +1,8 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity >=0.6.0 <=0.8.13; + +import "bls-solidity/contracts/BN256G1.sol"; +import "elliptic-curve-solidity/contracts/EllipticCurve.sol"; contract Proofs { uint256 private immutable period; @@ -10,7 +13,7 @@ contract Proofs { uint256 __period, uint256 __timeout, uint8 __downtime - ) { + ) public { require(block.number > 256, "Insufficient block height"); period = __period; timeout = __timeout; @@ -129,6 +132,178 @@ contract Proofs { return _isProofRequired(id, currentPeriod()); } +// proc verifyProof*(tau: Tau, q: openArray[QElement], mus: openArray[blst_scalar], sigma: blst_p1, spk: PublicKey): bool = +// ## Verify a BLS proof given a query + +// # verify signature on Tau +// var signature: Signature +// if not signature.fromBytes(tau.signature): +// return false +// if not verify(spk.signkey, $tau.t, signature): +// return false + +// var first: blst_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) + +// let us = tau.t.u +// var second: blst_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 sum: blst_p1 +// sum.blst_p1_add_or_double(first, second) + +// var g{.noInit.}: blst_p2 +// g.blst_p2_from_affine(BLS12_381_G2) + +// return verifyPairings(sum, spk.key, sigma, g) + struct BnFr { + // in mratsim/constantine, given the following: + // + // func wordsRequired*(bits: int): int {.compileTime.} = + // ## Compute the number of limbs required + // # from the **announced** bit length + // (bits + WordBitWidth - 1) div WordBitWidth + // + // type + // SecretWord* = distinct uint64 + // + // BigInt*[bits: static int] = object + // limbs*: array[bits.wordsRequired, SecretWord] + // + // Fr*[C: static Curve] = object => Fr[C: BN254_Snarks] + // mres*: matchingOrderBigInt(C) => mres*: BigInt[254] + // + // For the BN254_Snarks curve, + // orderBitwidth = 254 + // wordsRequired = 4 (output of the wordsRequired func above) + // + // We can then conclude: + // + // type + // Fr*[C: BN254_Snarks] = object + // mres*: BigInt[254] + // limbs*: array[4, uint64] + // + // This matches FR = distinct BNU256 in nim-bncurve: + // type + // BNU256* = array[4, uint64] + // + // Note: for BLS curves (in nim-blscurve), + // type + // blst_fp = array[0..5, uint64] + uint64[4] ls; + } + struct BnFp { + // see notes from BnFr, the only difference is that we use the + // ordered bit width in BnFr, as opposed to the bit width for Fr. + // Both are 254 bits wide, so the data structure is identical. + uint64[4] ls; + } + + struct BnFp2 { + // In mratsim/constantine, given the following: + // + // type + // + // QuadraticExt*[F] = object + // coords*: array[2, F] + // + // Fp2*[C: static Curve] = + // QuadraticExt[Fp[C]] => QuadraticExt[Fp[BN254_Snarks]] + // + // equates to + // Fp2*[C: static Curve] = + // QuadraticExt[Fp[BN254_Snarks]] + // coords: array[2, Fp[BN254_Snarks]] + BnFp[2] fp; + } + + struct BnP1 { + BnFp x; + BnFp y; + BnFp z; + } + + struct BnScalar { + // Taken from nim-blscurve/bls_abi, cannot find an analogue in + // mratsim/constantine nor nim-bncurve + // + // # blst_scalar + // # = typedesc[array[0..31, byte]] + // array[typeof(256)(typeof(256)(256 / typeof(256)(8))), byte] + bytes32[32] ls; + } + + struct TauZero { + bytes32[512] name; + int64 n; + BnP1[] u; // seq[blst_p1] + } + + struct Tau { + TauZero t; + bytes32[96] signature; + } + + // x', y' affine coordinates, result of EllipticCurve.ecMul + // e.g. https://github.com/witnet/elliptic-curve-solidity/blob/master/examples/Secp256k1.sol + struct PublicKey { + uint256 x; + uint256 y; + } + + struct QElement { + int64 i; + BnScalar v; + } + function isEmpty(bytes32[96] memory array) internal pure returns (bool) { + for(uint i; i< array.length; i++){ + if(i > 0) { + return true; + } + } + return false; + } + function _verifyProof( + Tau memory tau, + QElement[] memory q, + BnFr[10] memory mus, + // Possibly 48 bytes long, csaba? + BnP1 memory sigma, + PublicKey memory spk) internal returns (bool) { + + // is this really needed? + require(!isEmpty(tau.signature), "Signature cannot be empty"); + + // TODO: add verification + // if not verify(spk.signkey, $tau.t, signature): + // return false + + // var first: blst_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) + BnP1 memory bnP1; + for (uint i = 0; i