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

Add ERC: Quantum Supremacy Bounty #731

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
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
550 changes: 550 additions & 0 deletions ERCS/erc-7826.md

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions assets/erc-7826/contracts/bounty-contracts/BountyContract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/utils/Address.sol";
import "./support/CommitRevealManager.sol";
import "./support/LockManager.sol";

abstract contract BountyContract {
bool public solved;

mapping(address => mapping(uint256 => Commit)) private commits;
Locks private locksDefault;

constructor(uint256 numberOfLocksArg) {
locksDefault = LockManager.init(numberOfLocksArg);
}

modifier requireUnsolved() {
require(!solved, 'Already solved');
_;
}

function locks() internal view virtual returns (Locks storage) {
return locksDefault;
}

function _verifySolution(uint256 lockNumber, bytes memory solution) internal view virtual returns (bool);

function getLock(uint256 lockNumber) public view returns (bytes[] memory) {
return LockManager.getLock(locks(), lockNumber);
}

function numberOfLocks() public view returns (uint256) {
return locks().numberOfLocks;
}

function commitSolution(uint256 lockNumber, bytes memory solutionHash) public requireUnsolved {
CommitRevealManager.commitSolution(commits, msg.sender, lockNumber, solutionHash);
}

function getMyCommit(uint256 lockNumber) public view returns (bytes memory, uint256) {
return CommitRevealManager.getMyCommit(commits, msg.sender, lockNumber);
}

function solve(uint256 lockNumber, bytes memory solution) public requireUnsolved {
require(CommitRevealManager.verifyReveal(commits, msg.sender, lockNumber, solution), "Solution hash doesn't match");
require(_verifySolution(lockNumber, solution), 'Invalid solution');

LockManager.setLocksSolvedStatus(locks(), lockNumber, true);
if (LockManager.allLocksSolved(locks())) {
solved = true;
_sendBountyToSolver();
}
}

function _sendBountyToSolver() private {
Address.sendValue(payable(msg.sender), bounty());
}

function bounty() public view returns (uint256) {
return address(this).balance;
}

receive() external payable {
addToBounty();
}

fallback() external payable {
addToBounty();
}

function addToBounty() public payable requireUnsolved {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "../BountyContract.sol";
import "../support/BigNumbers.sol";

abstract contract OrderFindingBounty is BountyContract {
using BigNumbers for *;

constructor(uint256 numberOfLocks) BountyContract(numberOfLocks) {}

function _verifySolution(uint256 lockNumber, bytes memory solution) internal view override returns (bool) {
bytes[] memory lock = getLock(lockNumber);
require(lock.length > 0, 'Lock has not been generated yet.');
bytes memory modulus = lock[0];
bytes memory base = lock[1];

BigNumber memory answer = base.init(false).modexp(solution.init(false), modulus.init(false));
return answer.eq(BigNumbers.one());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/utils/math/Math.sol";
import "solidity-bytes-utils/contracts/BytesLib.sol";
import "../../support/AccumulatorUtils.sol";
import "../../support/BigNumbers.sol";
import "../../support/LockManager.sol";

struct Accumulator {
Locks locks;
bool generationIsDone;
uint8 parametersPerLock;

bytes _currentBytes;
uint256 _currentLockNumber;
uint256 _bytesPerLock;

BigNumber _a;
BigNumber _b;
BigNumber _baseToCheck;
uint256 _gcdIterationsPerCall;
}


library OrderFindingAccumulator {
using BigNumbers for *;

uint8 private constant _BITS_PER_BYTE = 8;

function init(uint256 numberOfLocks, uint256 bytesPerLock, uint256 gcdIterationsPerCall) internal pure returns (Accumulator memory accumulator)
{
accumulator.locks = LockManager.init(numberOfLocks);
accumulator.parametersPerLock = 2;
accumulator._bytesPerLock = bytesPerLock;
accumulator._gcdIterationsPerCall = gcdIterationsPerCall;
return accumulator;
}

function accumulate(Accumulator storage accumulator, bytes memory randomBytes) internal {
if (accumulator.generationIsDone) return;
if (accumulator._baseToCheck.bitlen > 0) {
_isCoprime(accumulator);
return;
}

accumulator._currentBytes = AccumulatorUtils.getRemainingBytes(randomBytes, accumulator._currentBytes, accumulator._bytesPerLock);
if (accumulator._currentBytes.length >= accumulator._bytesPerLock) {
if (accumulator.locks.vals[accumulator._currentLockNumber].length == 0) {
accumulator.locks.vals[accumulator._currentLockNumber] = new bytes[](accumulator.parametersPerLock);
}

if (accumulator.locks.vals[accumulator._currentLockNumber][0].length == 0) {
_setFirstBit(accumulator._currentBytes);
accumulator.locks.vals[accumulator._currentLockNumber][0] = accumulator._currentBytes;
} else {
BigNumber memory modulus = accumulator.locks.vals[accumulator._currentLockNumber][0].init(false);
BigNumber memory base = accumulator._currentBytes.init(false).mod(modulus);
BigNumber memory negativeOne = modulus.sub(BigNumbers.one());

bool hasTrivialOrder = base.eq(BigNumbers.one()) || base.eq(negativeOne);
if (!hasTrivialOrder) {
accumulator._a = modulus;
accumulator._b = accumulator._baseToCheck = base;
return;
}
}
_resetBytes(accumulator);
}
}

function _setFirstBit(bytes storage value) private {
value[0] |= bytes1(uint8(1 << 7));
}

/* Adapted rom https://gist.github.com/3esmit/8c0a63f17f2f2448cc1576eb27fe5910
*/
function _isCoprime(Accumulator storage accumulator) private {
BigNumber memory a = accumulator._a;
BigNumber memory b = accumulator._b;
for (uint256 i = 0; i < accumulator._gcdIterationsPerCall; i++) {
bool checkIsFinished = b.isZero();
if (checkIsFinished) {
bool isCoprime = a.eq(BigNumbers.one());
if (isCoprime) _setBase(accumulator);
_resetBytes(accumulator);
return;
} else {
BigNumber memory temp = b;
b = a.mod(b);
a = temp;
}
}
accumulator._a = a;
accumulator._b = b;
}

function _setBase(Accumulator storage accumulator) private {
accumulator.locks.vals[accumulator._currentLockNumber][1] = _slicePrefix(accumulator);
++accumulator._currentLockNumber;
if (accumulator._currentLockNumber >= accumulator.locks.numberOfLocks) accumulator.generationIsDone = true;
}

function _slicePrefix(Accumulator storage accumulator) private view returns (bytes memory) {
bytes memory value = accumulator._baseToCheck.val;
return BytesLib.slice(value, value.length - accumulator._bytesPerLock, accumulator._bytesPerLock);
}

function _resetBytes(Accumulator storage accumulator) private {
accumulator._currentBytes = '';
accumulator._a = BigNumber('', false, 0);
accumulator._b = BigNumber('', false, 0);
accumulator._baseToCheck = BigNumber('', false, 0);
}

function isCheckingPrime(Accumulator storage accumulator) internal view returns (bool) {
return accumulator._baseToCheck.bitlen > 0;
}

function currentPrimeCheck(Accumulator storage accumulator) internal view returns (bytes memory) {
return accumulator._b.val;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "./OrderFindingAccumulator.sol";

contract OrderFindingAccumulatorTestHelper {
Accumulator public accumulator;

constructor(uint256 numberOfLocks, uint256 bytesPerPrime, uint256 gcdIterationsPerCall) {
accumulator = OrderFindingAccumulator.init(numberOfLocks, bytesPerPrime, gcdIterationsPerCall);
}

function triggerAccumulate(bytes memory randomBytes) public {
OrderFindingAccumulator.accumulate(accumulator, randomBytes);
}

function isCheckingPrime() public view returns (bool) {
return OrderFindingAccumulator.isCheckingPrime(accumulator);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "./OrderFindingAccumulator.sol";
import "../OrderFindingBounty.sol";


contract OrderFindingBountyWithLockGeneration is OrderFindingBounty {
uint256 private iteration;

Accumulator private orderFindingAccumulator;

constructor(uint256 numberOfLocks, uint256 byteSizeOfModulus, uint256 gcdIterationsPerCall)
OrderFindingBounty(numberOfLocks)
{
orderFindingAccumulator = OrderFindingAccumulator.init(numberOfLocks, byteSizeOfModulus, gcdIterationsPerCall);
}

function locks() internal view override returns (Locks storage) {
return orderFindingAccumulator.locks;
}

function isCheckingPrime() public view returns (bool) {
return OrderFindingAccumulator.isCheckingPrime(orderFindingAccumulator);
}

function currentPrimeCheck() public view returns (bytes memory) {
return OrderFindingAccumulator.currentPrimeCheck(orderFindingAccumulator);
}

function triggerLockAccumulation() public {
require(!orderFindingAccumulator.generationIsDone, 'Locks have already been generated');
bytes memory randomNumber = '';
if (!OrderFindingAccumulator.isCheckingPrime(orderFindingAccumulator)) randomNumber = _generateRandomBytes();
OrderFindingAccumulator.accumulate(orderFindingAccumulator, randomNumber);
}

function generationIsDone() public view returns (bool) {
return orderFindingAccumulator.generationIsDone;
}

function _generateRandomBytes() private returns (bytes memory) {
return abi.encodePacked(keccak256(abi.encodePacked(block.difficulty, iteration++)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "../OrderFindingBounty.sol";

contract OrderFindingBountyWithPredeterminedLocks is OrderFindingBounty {
constructor(uint256 numberOfLocks)
OrderFindingBounty(numberOfLocks) {}

function setLock(uint256 lockNumber, bytes[] memory lock) public {
LockManager.setLock(locks(), lockNumber, lock);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;

import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
import "solidity-bytes-utils/contracts/BytesLib.sol";

import "../BountyContract.sol";
import "../support/BigNumbers.sol";
import "./miller-rabin/MillerRabin.sol";

abstract contract PrimeFactoringBounty is BountyContract {
using BigNumbers for *;

constructor(uint256 numberOfLocks) BountyContract(numberOfLocks) {}

function _verifySolution(uint256 lockNumber, bytes memory solution) internal view override returns (bool) {
bytes[] memory primes = abi.decode(solution, (bytes[]));
BigNumber memory product = BigNumbers.one();
for (uint256 i = 0; i < primes.length; i++) {
bytes memory primeFactor = primes[i];
require(MillerRabin.isPrime(primeFactor), 'Given solution is not prime');
product = product.mul(primeFactor.init(false));
}

BigNumber memory lock = getLock(lockNumber)[0].init(false);
return product.eq(lock);
}
}
Loading
Loading