-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
296 additions
and
4 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
} | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}` | ||
); | ||
}); | ||
}); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |