Loading...
Loading...
Игрок -> keccak256(значение + секрет) -> Блокчейн
Игрок -> (значение, секрет) -> Блокчейн проверяет хеш
contract AlexSecureRandomness { // Commit-Reveal схема для справедливой случайности struct CommitReveal { bytes32 commitment; // Хеш от (значение + секрет) uint256 revealBlock; // Блок, когда можно раскрыть bool revealed; // Флаг раскрытия uint256 randomValue; // Итоговое случайное число uint256 commitBlock; // Блок коммита (для дополнительной безопасности) }
mapping(address => CommitReveal) public commitments;
event CommitMade(address indexed player, bytes32 commitment, uint256 revealBlock); event ChoiceRevealed(address indexed player, uint256 value, uint256 randomResult);
// Шаг 1: Игрок делает коммит (скрытый выбор) function commitChoice(bytes32 commitment) public { require(commitments[msg.sender].commitment == bytes32(0), "Уже есть активный коммит");
commitments[msg.sender] = CommitReveal({ commitment: commitment, revealBlock: block.number + 1, // Раскрыть можно только в следующем блоке revealed: false, randomValue: 0, commitBlock: block.number });
emit CommitMade(msg.sender, commitment, block.number + 1); }
// Шаг 2: Игрок раскрывает свой выбор function revealChoice(uint256 value, uint256 secret) public { CommitReveal storage commit = commitments[msg.sender];
require(commit.commitment != bytes32(0), "Нет активного коммита"); require(block.number >= commit.revealBlock, "Слишком рано для раскрытия"); require(block.number <= commit.revealBlock + 255, "Слишком поздно для раскрытия"); require(!commit.revealed, "Уже раскрыто");
// Проверяем, что раскрытые данные соответствуют коммиту bytes32 hash = keccak256(abi.encodePacked(value, secret)); require(hash == commit.commitment, "Неверное раскрытие");
// Генерируем случайность, используя будущий блок bytes32 randomHash = keccak256(abi.encodePacked( blockhash(commit.revealBlock), // Хеш блока раскрытия value, // Значение от пользователя secret, // Секрет от пользователя msg.sender, // Адрес игрока commit.commitBlock // Блок коммита для дополнительной энтропии ));
commit.revealed = true; commit.randomValue = uint256(randomHash) % 100; // Случайное число 0-99
emit ChoiceRevealed(msg.sender, value, commit.randomValue); }
// Вспомогательная функция для создания коммита оффлайн function createCommitment(uint256 value, uint256 secret) public pure returns (bytes32) { return keccak256(abi.encodePacked(value, secret)); }
// Получение случайного числа для игрока function getRandomResult(address player) public view returns (uint256) { require(commitments[player].revealed, "Результат не раскрыт"); return commitments[player].randomValue; }
// Очистка старого коммита (если нужно начать заново) function resetCommitment() public { require( commitments[msg.sender].revealed || block.number > commitments[msg.sender].revealBlock + 255, "Коммит все еще активен" ); delete commitments[msg.sender]; }}
blockhash(N+1)
теперь известен// Пример использования Chainlink VRF (концептуальный код)contract AlexChainlinkLottery { struct LotteryRound { uint256 requestId; address[] participants; address winner; bool completed; }
mapping(uint256 => LotteryRound) public lotteries; uint256 public currentLotteryId;
// Запрос случайного числа от Chainlink function startLottery() public { // В реальности здесь вызов Chainlink VRF // uint256 requestId = requestRandomness(keyHash, fee);
currentLotteryId++; lotteries[currentLotteryId] = LotteryRound({ requestId: 0, // Здесь был бы реальный requestId participants: new address[](0), winner: address(0), completed: false }); }
function joinLottery() public payable { require(msg.value >= 0.01 ether, "Минимальная ставка"); require(!lotteries[currentLotteryId].completed, "Лотерея завершена");
lotteries[currentLotteryId].participants.push(msg.sender); }
// Эта функция вызывается Chainlink Oracle с настоящим случайным числом function fulfillRandomness(uint256 requestId, uint256 randomness) internal { LotteryRound storage lottery = lotteries[currentLotteryId]; uint256 winnerIndex = randomness % lottery.participants.length; lottery.winner = lottery.participants[winnerIndex]; lottery.completed = true; }}
contract AlexMerkleWhitelist { bytes32 public merkleRoot; mapping(address => bool) public claimed;
event Claimed(address indexed user, uint256 amount);
constructor(bytes32 _merkleRoot) { merkleRoot = _merkleRoot; }
// Проверка Merkle Proof function verifyMerkleProof( bytes32[] memory proof, bytes32 leaf ) public view returns (bool) { bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) { bytes32 proofElement = proof[i];
if (computedHash <= proofElement) { // Hash(current computed hash + current element of the proof) computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); } else { // Hash(current element of the proof + current computed hash) computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } }
// Проверяем, что вычисленный хеш равен корню return computedHash == merkleRoot; }
// Получение токенов из whitelist function claimTokens( uint256 amount, bytes32[] memory merkleProof ) public { require(!claimed[msg.sender], "Уже получено");
// Создаем лист дерева для текущего пользователя bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount));
// Проверяем принадлежность к whitelist require(verifyMerkleProof(merkleProof, leaf), "Неверное доказательство");
// Отмечаем как полученное claimed[msg.sender] = true;
// Здесь был бы код для перевода токенов // token.transfer(msg.sender, amount);
emit Claimed(msg.sender, amount); }
// Создание хеша листа (для тестирования) function getLeafHash(address user, uint256 amount) public pure returns (bytes32) { return keccak256(abi.encodePacked(user, amount)); }}
contract AlexMerkleAirdrop { bytes32 public immutable merkleRoot; mapping(address => bool) public claimed;
uint256 public constant TOTAL_SUPPLY = 1000000 * 10**18; mapping(address => uint256) public balances;
event AirdropClaimed(address indexed account, uint256 amount);
constructor(bytes32 _merkleRoot) { merkleRoot = _merkleRoot; balances[msg.sender] = TOTAL_SUPPLY; // Все токены у создателя }
function claimAirdrop( uint256 amount, bytes32[] calldata merkleProof ) external { require(!claimed[msg.sender], "Airdrop уже получен");
// Проверяем, что пользователь в whitelist bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount)); require(_verifyMerkleProof(merkleProof, leaf), "Неверное доказательство");
// Отмечаем как полученное claimed[msg.sender] = true;
// Переводим токены require(balances[address(this)] >= amount, "Недостаточно токенов в контракте"); balances[address(this)] -= amount; balances[msg.sender] += amount;
emit AirdropClaimed(msg.sender, amount); }
function _verifyMerkleProof( bytes32[] memory proof, bytes32 leaf ) internal view returns (bool) { bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) { bytes32 proofElement = proof[i];
if (computedHash <= proofElement) { computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); } else { computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } }
return computedHash == merkleRoot; }
// Вспомогательная функция для создания листьев дерева function generateLeaf(address account, uint256 amount) external pure returns (bytes32) { return keccak256(abi.encodePacked(account, amount)); }}
contract AlexSecureVoting { struct Proposal { string title; string description; bytes32 contentHash; // Хеш содержимого для проверки целостности uint256 votesFor; uint256 votesAgainst; uint256 deadline; bool executed; address proposer; }
struct Vote { bool hasVoted; bool vote; // true = за, false = против bytes32 voteHash; // Хеш голоса для коммит-ревил bool revealed; }
mapping(uint256 => Proposal) public proposals; mapping(uint256 => mapping(address => Vote)) public votes;
bytes32 public immutable votersListRoot; // Merkle root списка избирателей uint256 public proposalCount; uint256 public constant VOTING_PERIOD = 7 days; uint256 public constant REVEAL_PERIOD = 1 days;
event ProposalCreated(uint256 indexed proposalId, address indexed proposer, string title); event VoteCommitted(uint256 indexed proposalId, address indexed voter); event VoteRevealed(uint256 indexed proposalId, address indexed voter, bool vote); event ProposalExecuted(uint256 indexed proposalId, bool approved);
constructor(bytes32 _votersListRoot) { votersListRoot = _votersListRoot; }
// Создание предложения function createProposal( string memory title, string memory description, bytes32[] memory merkleProof ) public returns (uint256) { // Проверяем, что создатель в списке избирателей bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); require(_verifyMerkleProof(merkleProof, leaf), "Не в списке избирателей");
bytes32 contentHash = keccak256(abi.encodePacked(title, description)); uint256 proposalId = proposalCount++;
proposals[proposalId] = Proposal({ title: title, description: description, contentHash: contentHash, votesFor: 0, votesAgainst: 0, deadline: block.timestamp + VOTING_PERIOD, executed: false, proposer: msg.sender });
emit ProposalCreated(proposalId, msg.sender, title); return proposalId; }
// Коммит голоса (скрытый) function commitVote( uint256 proposalId, bytes32 voteHash, bytes32[] memory merkleProof ) public { // Проверяем, что пользователь в списке избирателей через Merkle Proof bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); require(_verifyMerkleProof(merkleProof, leaf), "Не в списке избирателей");
Proposal storage proposal = proposals[proposalId]; require(block.timestamp <= proposal.deadline, "Голосование завершено"); require(!votes[proposalId][msg.sender].hasVoted, "Уже проголосовали");
votes[proposalId][msg.sender] = Vote({ hasVoted: true, vote: false, // Будет раскрыто позже voteHash: voteHash, revealed: false });
emit VoteCommitted(proposalId, msg.sender); }
// Раскрытие голоса function revealVote( uint256 proposalId, bool vote, uint256 nonce ) public { Proposal storage proposal = proposals[proposalId]; Vote storage voterData = votes[proposalId][msg.sender];
require(voterData.hasVoted, "Не участвовали в голосовании"); require(!voterData.revealed, "Голос уже раскрыт"); require( block.timestamp > proposal.deadline && block.timestamp <= proposal.deadline + REVEAL_PERIOD, "Не время для раскрытия" );
// Проверяем, что раскрытые данные соответствуют коммиту bytes32 hash = keccak256(abi.encodePacked(vote, nonce, msg.sender)); require(hash == voterData.voteHash, "Неверное раскрытие");
voterData.revealed = true; voterData.vote = vote;
if (vote) { proposal.votesFor++; } else { proposal.votesAgainst++; }
emit VoteRevealed(proposalId, msg.sender, vote); }
// Подсчет голосов и выполнение предложения function executeProposal(uint256 proposalId) public { Proposal storage proposal = proposals[proposalId]; require(!proposal.executed, "Предложение уже выполнено"); require(block.timestamp > proposal.deadline + REVEAL_PERIOD, "Период раскрытия не завершен");
proposal.executed = true; bool approved = proposal.votesFor > proposal.votesAgainst;
emit ProposalExecuted(proposalId, approved);
// Здесь был бы код выполнения предложения, если оно принято if (approved) { // Выполнить предложение } }
// Проверка Merkle Proof для списка избирателей function _verifyMerkleProof( bytes32[] memory proof, bytes32 leaf ) internal view returns (bool) { bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) { bytes32 proofElement = proof[i];
if (computedHash <= proofElement) { computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); } else { computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } }
return computedHash == votersListRoot; }
// Создание хеша голоса для коммита function createVoteHash(bool vote, uint256 nonce) public view returns (bytes32) { return keccak256(abi.encodePacked(vote, nonce, msg.sender)); }
// Проверка целостности предложения function verifyProposalIntegrity( uint256 proposalId, string memory title, string memory description ) public view returns (bool) { bytes32 currentHash = keccak256(abi.encodePacked(title, description)); return currentHash == proposals[proposalId].contentHash; }}
contract TimeLockCrypto { struct LockedData { bytes32 dataHash; uint256 unlockTime; address owner; bool revealed; }
mapping(bytes32 => LockedData) public lockedData;
event DataLocked(bytes32 indexed lockId, address indexed owner, uint256 unlockTime); event DataRevealed(bytes32 indexed lockId, string data);
function lockData( string memory data, uint256 lockDuration, uint256 secret ) public returns (bytes32) { bytes32 dataHash = keccak256(abi.encodePacked(data, secret)); bytes32 lockId = keccak256(abi.encodePacked(dataHash, msg.sender, block.timestamp));
lockedData[lockId] = LockedData({ dataHash: dataHash, unlockTime: block.timestamp + lockDuration, owner: msg.sender, revealed: false });
emit DataLocked(lockId, msg.sender, block.timestamp + lockDuration); return lockId; }
function revealData( bytes32 lockId, string memory data, uint256 secret ) public { LockedData storage locked = lockedData[lockId];
require(locked.owner == msg.sender, "Не владелец"); require(block.timestamp >= locked.unlockTime, "Еще заблокировано"); require(!locked.revealed, "Уже раскрыто");
bytes32 providedHash = keccak256(abi.encodePacked(data, secret)); require(providedHash == locked.dataHash, "Неверные данные");
locked.revealed = true; emit DataRevealed(lockId, data); }}
contract WeightedCryptoVoting { struct WeightedCommit { bytes32 commitment; uint256 weight; bool revealed; bool vote; }
mapping(uint256 => mapping(address => WeightedCommit)) public commits; mapping(uint256 => uint256) public totalWeightFor; mapping(uint256 => uint256) public totalWeightAgainst;
function commitWeightedVote( uint256 proposalId, bytes32 commitment, uint256 weight, bytes32[] memory merkleProof ) public { // Проверяем вес через Merkle Proof bytes32 leaf = keccak256(abi.encodePacked(msg.sender, weight)); require(verifyWeightProof(merkleProof, leaf), "Неверный вес");
commits[proposalId][msg.sender] = WeightedCommit({ commitment: commitment, weight: weight, revealed: false, vote: false }); }
function revealWeightedVote( uint256 proposalId, bool vote, uint256 nonce ) public { WeightedCommit storage commit = commits[proposalId][msg.sender]; require(!commit.revealed, "Уже раскрыто");
bytes32 hash = keccak256(abi.encodePacked(vote, nonce, msg.sender)); require(hash == commit.commitment, "Неверное раскрытие");
commit.revealed = true; commit.vote = vote;
if (vote) { totalWeightFor[proposalId] += commit.weight; } else { totalWeightAgainst[proposalId] += commit.weight; } }
function verifyWeightProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bool) { // Упрощенная проверка Merkle Proof // В реальности здесь была бы полная реализация return true; }}
Термин | Определение | Пример использования |
---|---|---|
Commit-Reveal | Схема скрытого голосования: сначала коммит хеша, потом раскрытие | Справедливые голосования и лотереи |
Merkle Tree | Структура данных для эффективной проверки принадлежности к набору | Airdrop whitelist, проверка транзакций |
Merkle Root | Корневой хеш Merkle Tree, представляющий весь набор данных | Один хеш вместо тысяч адресов в whitelist |
Merkle Proof | Набор хешей для доказательства принадлежности элемента к дереву | Доказательство права на airdrop |
VRF | Verifiable Random Function - проверяемая функция случайности | Chainlink VRF для честной случайности |
Энтропия | Мера непредсказуемости в системе | Источник случайности для генерации чисел |
Oracle | Внешний источник данных для блокчейна | Chainlink для получения случайных чисел |
Временная блокировка | Механизм задержки выполнения операций | Защита от импульсивных решений в DAO |
Whitelist | Список разрешенных адресов или пользователей | Ограничение участников в airdrop или ICO |
Proof | Криптографическое доказательство | Доказательство принадлежности к Merkle Tree |