// SPDX-License-Identifier: UNLICENSED // Proprietary - (c) 2026 Durian (durianfun). All rights reserved. Not open source; for Durianfun + authorized integrations only. See /LICENSE. pragma solidity 0.8.24; /// @title EntropyLib /// @notice Helpers to turn ONE reveal (a single 256-bit number) into many independent values. /// All `internal pure` — they inline into your contract, so there is NO extra external /// call and no per-call gas beyond the keccaks (~36 gas each). One reveal is always /// cheaper and safer than many requests. /// /// @dev Each helper uses a DISTINCT domain tag so that values pulled from the SAME reveal `r` /// by different helpers (or the same helper with the same index) never collide. e.g. /// expand(r, 5)[2], pick(r, 2, max) and digits(r, 6)'s digit #2 are all independent. library EntropyLib { bytes32 private constant D_EXPAND = "DurianEntropy.expand"; bytes32 private constant D_PICK = "DurianEntropy.pick"; bytes32 private constant D_DIGIT = "DurianEntropy.digit"; /// @notice `n` independent, domain-separated values derived from one reveal. /// @dev Bounded to cap gas if `n` ever comes from untrusted input (mirrors digits()'s guard). function expand(uint256 r, uint256 n) internal pure returns (uint256[] memory out) { require(n <= 256, "n too large"); out = new uint256[](n); for (uint256 i = 0; i < n; i++) { out[i] = uint256(keccak256(abi.encode(D_EXPAND, r, i))); } } /// @notice A single value in [0, max). Modulo bias is negligible for max << 2^256 /// (e.g. roulette max=37, dice max=6, NFT tiers). `salt` separates independent draws. function pick(uint256 r, uint256 salt, uint256 max) internal pure returns (uint256) { require(max != 0, "max=0"); return uint256(keccak256(abi.encode(D_PICK, r, salt))) % max; } /// @notice `m` decimal digits (0-9) packed into a number — e.g. a 6-digit lottery: digits(r, 6). /// @dev Bounded to 77 digits: 10**77 < 2**256, so packing never overflows; also caps gas if /// `m` ever comes from untrusted input. function digits(uint256 r, uint256 m) internal pure returns (uint256 number) { require(m <= 77, "too many digits"); for (uint256 i = 0; i < m; i++) { number = number * 10 + (uint256(keccak256(abi.encode(D_DIGIT, r, i))) % 10); } } }