Skip to content

Commit

Permalink
Push
Browse files Browse the repository at this point in the history
  • Loading branch information
SkyYap committed May 24, 2023
1 parent 7ea542a commit 0f28e6a
Show file tree
Hide file tree
Showing 10 changed files with 296 additions and 4 deletions.
Binary file added .yarn/install-state.gz
Binary file not shown.
102 changes: 102 additions & 0 deletions Week19/randomness/contracts/PseudoRandom
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

contract PseudoRandom {
using ECDSA for bytes32;

struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}

Signature savedSig;

function setSignature(
uint8 _v,
bytes32 _r,
bytes32 _s
) public {
savedSig = Signature({v: _v, r: _r, s: _s});
}

function getRandomNumber(string calldata seed)
public
view
returns (uint256 pseudoRandomNumber)
{
address messageSigner = verifyString(
seed,
savedSig.v,
savedSig.r,
savedSig.s
);
require(msg.sender == messageSigner, "Invalid seed");
pseudoRandomNumber = uint256(keccak256(abi.encodePacked(seed)));
}

function getCombinedRandomNumber(string calldata seed)
public
view
returns (uint256 pseudoRandomNumber)
{
address messageSigner = verifyString(
seed,
savedSig.v,
savedSig.r,
savedSig.s
);
require(msg.sender == messageSigner, "Invalid seed");
pseudoRandomNumber = uint256(
keccak256(abi.encodePacked(seed, blockhash(block.number - 1)))
);
}

// Don't worry about this function for now
function verifyString(
string memory message,
uint8 v,
bytes32 r,
bytes32 s
) public pure returns (address signer) {
string memory header = "\x19Ethereum Signed Message:\n000000";
uint256 lengthOffset;
uint256 length;
assembly {
length := mload(message)
lengthOffset := add(header, 57)
}
require(length <= 999999);
uint256 lengthLength = 0;
uint256 divisor = 100000;
while (divisor != 0) {
uint256 digit = length / divisor;
if (digit == 0) {
if (lengthLength == 0) {
divisor /= 10;
continue;
}
}
lengthLength++;
length -= digit * divisor;
divisor /= 10;
digit += 0x30;
lengthOffset++;
assembly {
mstore8(lengthOffset, digit)
}
}
if (lengthLength == 0) {
lengthLength = 1 + 0x19 + 1;
} else {
lengthLength += 1 + 0x19;
}
assembly {
mstore(header, lengthLength)
}
bytes32 check = keccak256(abi.encodePacked(header, message));
return ecrecover(check, v, r, s);
}
}
13 changes: 13 additions & 0 deletions Week19/randomness/contracts/Random.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
contract Random {
function getRandomNumber()
public
view
returns (uint256 randomNumber)
{
// TODO: get randomness from previous block randao reveal
}

function tossCoin() public view returns (bool heads) {
// TODO: make the random number be translated to a boolean
}
}
109 changes: 109 additions & 0 deletions Week19/randomness/scripts/TestPseudoRandom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { ethers } from "ethers";

async function signature() {
const signers = await ethers.getSigners();
const signer = signers[0];
console.log(
`Signing a message with the account of address ${signer.address}`
);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question("Enter a message to be signed:\n", async (answer) => {
const signedMessage = await signer.signMessage(answer);
console.log(`The signed message is:\n${signedMessage}`);
rl.close();
testSignature();
});
}

async function testSignature() {
console.log("Verifying signature\n");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question("Enter message signature:\n", (signature) => {
rl.question("Enter message:\n", (message) => {
const address = ethers.utils.verifyMessage(message, signature);
console.log(`This message signature matches with address ${address}`);
rl.question("Repeat? [Y/N]:\n", (answer) => {
rl.close();
if (answer.toLowerCase() === "y") {
testSignature();
}
});
});
});
}

async function sealedSeed() {
console.log("Deploying contract");
const contractFactory = await ethers.getContractFactory("PseudoRandom");
const contract: PseudoRandom = await contractFactory.deploy();
await contract.deployed();
const signers = await ethers.getSigners();
const signer = signers[0];
console.log(
`Signing a message with the account of address ${signer.address}`
);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question("Enter a random seed to be signed:\n", async (seed) => {
const signedMessage = await signer.signMessage(seed);
rl.close();
console.log(`The signed message is:\n${signedMessage}`);
const sig = ethers.utils.splitSignature(signedMessage);
console.log("Saving signature at contract");
await contract.setSignature(sig.v, sig.r, sig.s);
try {
console.log("Trying to get a number with the original seed");
const randomNumber = await contract.getRandomNumber(seed);
console.log(`Random number result:\n${randomNumber}`);
console.log("Trying to get a number without the original seed");
const fakeSeed = "FAKE_SEED";
const randomNumber2 = await contract.getRandomNumber(fakeSeed);
console.log(`Random number result:\n${randomNumber2}`);
} catch (error) {
console.log("Operation failed");
}
});
}

async function randomSealedSeed() {
console.log("Deploying contract");
const contractFactory = await ethers.getContractFactory("PseudoRandom");
const contract: PseudoRandom = await contractFactory.deploy();
await contract.deployed();
const signers = await ethers.getSigners();
const signer = signers[0];
console.log(
`Signing a message with the account of address ${signer.address}`
);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question("Enter a random seed to be signed:\n", async (seed) => {
const signedMessage = await signer.signMessage(seed);
rl.close();
console.log(`The signed message is:\n${signedMessage}`);
const sig = ethers.utils.splitSignature(signedMessage);
console.log("Saving signature at contract");
await contract.setSignature(sig.v, sig.r, sig.s);
try {
console.log("Trying to get a number with the original seed");
const randomNumber = await contract.getCombinedRandomNumber(seed);
console.log(`Random number result:\n${randomNumber}`);
console.log("Trying to get a number without the original seed");
const fakeSeed = "FAKE_SEED";
const randomNumber2 = await contract.getCombinedRandomNumber(fakeSeed);
console.log(`Random number result:\n${randomNumber2}`);
} catch (error) {
console.log("Operation failed");
}
});
}
8 changes: 4 additions & 4 deletions Week19/randomness/scripts/TestRandom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ async function main() {
tossCoin();
break;
case 3:
// signature();
signature();
break;
case 4:
// sealedSeed();
sealedSeed();
break;
case 5:
// randomSealedSeed();
randomSealedSeed();
break;
case 6:
// randao();
randao();
break;
default:
console.log("Invalid");
Expand Down
36 changes: 36 additions & 0 deletions Week19/randomness/scripts/TestRandomAgain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
async function randao() {
const contractFactory = await ethers.getContractFactory("Random");
contractFactory.deploy().then(async (result) => {
result.deployed().then(async (contract: Random) => {
const currentBlock = await ethers.provider.getBlock("latest");
const randomNumber = await contract.getRandomNumber();
console.log(
`Block number: ${currentBlock.number}\nBlock difficulty: ${currentBlock.difficulty}\nRandom number from this block difficulty: ${randomNumber}`
);
await ethers.provider.send("evm_mine", [currentBlock.timestamp + 1]);
const currentBlock2 = await ethers.provider.getBlock("latest");
const randomNumber2 = await contract.getRandomNumber();
console.log(
`Block number: ${currentBlock2.number}\nBlock difficulty: ${currentBlock2.difficulty}\nRandom number from this block difficulty: ${randomNumber2}`
);
await ethers.provider.send("evm_mine", [currentBlock2.timestamp + 1]);
const currentBlock3 = await ethers.provider.getBlock("latest");
const randomNumber3 = await contract.getRandomNumber();
console.log(
`Block number: ${currentBlock3.number}\nBlock difficulty: ${currentBlock3.difficulty}\nRandom number from this block difficulty: ${randomNumber3}`
);
await ethers.provider.send("evm_mine", [currentBlock3.timestamp + 1]);
const currentBlock4 = await ethers.provider.getBlock("latest");
const randomNumber4 = await contract.getRandomNumber();
console.log(
`Block number: ${currentBlock4.number}\nBlock difficulty: ${currentBlock4.difficulty}\nRandom number from this block difficulty: ${randomNumber4}`
);
await ethers.provider.send("evm_mine", [currentBlock4.timestamp + 1]);
const currentBlock5 = await ethers.provider.getBlock("latest");
const randomNumber5 = await contract.getRandomNumber();
console.log(
`Block number: ${currentBlock5.number}\nBlock difficulty: ${currentBlock5.difficulty}\nRandom number from this block difficulty: ${randomNumber5}`
);
});
});
}
10 changes: 10 additions & 0 deletions node_modules/.yarn-integrity

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions node_modules/.yarn-state.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
11 changes: 11 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!

__metadata:
version: 6

"root-workspace-0b6124@workspace:.":
version: 0.0.0-use.local
resolution: "root-workspace-0b6124@workspace:."
languageName: unknown
linkType: soft

0 comments on commit 0f28e6a

Please sign in to comment.