From bd62f6174cdae89f5e3cc1b4ee7daca08e0d5207 Mon Sep 17 00:00:00 2001 From: Giovanni Sanchez <108043524+sisyphusSmiling@users.noreply.github.com> Date: Fri, 27 Sep 2024 19:23:43 -0600 Subject: [PATCH] fix 0 bias in CadenceRandomConsumer._getNumberInRange --- solidity/src/CadenceRandomConsumer.sol | 20 +++++++++++++------- tests/test_helpers.cdc | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/solidity/src/CadenceRandomConsumer.sol b/solidity/src/CadenceRandomConsumer.sol index 9e62ccd..a8d11a8 100644 --- a/solidity/src/CadenceRandomConsumer.sol +++ b/solidity/src/CadenceRandomConsumer.sol @@ -179,12 +179,15 @@ abstract contract CadenceRandomConsumer { function _getNumberInRange(Xorshift128plus.PRG memory prg, uint64 min, uint64 max) private pure returns (uint64) { require(max > min, "Max must be greater than min"); - uint256 value = prg.nextUInt256(); - uint64 range = max - min; uint64 bitsRequired = _mostSignificantBit(range); // Number of bits needed to cover the range uint256 mask = (1 << bitsRequired) - 1; // Create a bitmask to extract relevant bits + + uint256 shiftLimit = 256 / bitsRequired; // Number of shifts needed to cover 256 bits + uint256 shifts = 0; // Initialize shift counter + uint64 candidate = 0; // Initialize candidate + uint256 value = prg.nextUInt256(); // Assign the first 256 bits of randomness while (true) { candidate = uint64(value & mask); // Apply the bitmask to extract bits @@ -194,14 +197,17 @@ abstract contract CadenceRandomConsumer { // Shift by the number of bits covered by the mask value = value >> bitsRequired; - // Get a new value if we've run out of bits - if (value == 0) { + shifts++; + + // Get a new value if we've exhausted the current one + if (shifts == shiftLimit) { value = prg.nextUInt256(); + shifts = 0; } } - uint64 randomResult = candidate + min; // Scale candidate to the range [min, max] - require(randomResult >= min && randomResult <= max, "Random number out of range"); - return randomResult; + + // Scale candidate to the range [min, max] + return min + candidate; } /** diff --git a/tests/test_helpers.cdc b/tests/test_helpers.cdc index d9d442e..3e4009d 100644 --- a/tests/test_helpers.cdc +++ b/tests/test_helpers.cdc @@ -2,7 +2,7 @@ import Test import "EVM" -access(all) let coinTossBytecode = "608060405234801561001057600080fd5b5061126f806100206000396000f3fe6080604052600436106100745760003560e01c80638c0647461161004e5780638c064746146100cb578063cd1a44db14610113578063d59fd63c1461014e578063fcf36b6a1461016e57600080fd5b80631b3ed72214610080578063799ae223146100ac5780638c03fe15146100b657600080fd5b3661007b57005b600080fd5b34801561008c57600080fd5b50610095600281565b60405160ff90911681526020015b60405180910390f35b6100b461019b565b005b3480156100c257600080fd5b506100b46102dc565b3480156100d757600080fd5b506101036100e636600461106e565b6001600160a01b0316600090815260026020526040902054151590565b60405190151581526020016100a3565b34801561011f57600080fd5b5061014061012e36600461109e565b60036020526000908152604090205481565b6040519081526020016100a3565b34801561015a57600080fd5b5061010361016936600461109e565b61044f565b34801561017a57600080fd5b5061014061018936600461106e565b60026020526000908152604090205481565b346101f95760405162461bcd60e51b815260206004820152602360248201527f4d7573742073656e6420464c4f5720746f20706c61636520666c69702061206360448201526237b4b760e91b60648201526084015b60405180910390fd5b33600090815260026020526040902054156102755760405162461bcd60e51b815260206004820152603660248201527f4d75737420636c6f73652070726576696f757320636f696e20666c6970206265604482015275666f726520706c6163696e672061206e6577206f6e6560501b60648201526084016101f0565b600061027f6104cd565b33600081815260026020908152604080832085905584835260038252918290203490819055915191825292935083927faaf5204450758753a474bce0ff33a69922372c674f7f6cde7adc701030fb3c4c910160405180910390a350565b336000908152600260205260409020546103525760405162461bcd60e51b815260206004820152603160248201527f43616c6c657220686173206e6f7420666c6970706564206120636f696e202d206044820152701b9bdd1a1a5b99c81d1bc81c995d99585b607a1b60648201526084016101f0565b336000908152600260205260408120805490829055906103748282600161060e565b600083815260036020526040812080549082905591925060ff83168103610409576103a06002836110cd565b604051909150600090339083156108fc0290849084818181858888f193505050509050806104075760405162461bcd60e51b81526020600482015260146024820152734661696c656420746f2073656e64207072697a6560601b60448201526064016101f0565b505b6040805160ff8516815260208101839052859133917ffa8362afdddf0c36107d3f3ad3c875ecd4c311118133c0e4b2b8e6ac2a0e3105910160405180910390a350505050565b60008061045d6001846110e4565b60005490915081106104725750600092915050565b6000808281548110610486576104866110f7565b9060005260206000209060030201905060006104a06106cc565b600283015490915060ff161580156104c4575081546001600160401b038083169116105b95945050505050565b60018054600091826104de8361110d565b919050555060006001549050600060405180606001604052806104ff6106cc565b6001600160401b0390811682524360208084019190915260006040938401819052805460018101825590805284517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5636003909202918201805467ffffffffffffffff191691909416908117909355848201517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5648201819055858501517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565909201805460ff19169215159290921790915583519283529082015291925083917f7886956edccde10901843c3e51fc26016455e9248e210a29c2a57ead63ad226e910160405180910390a250919050565b60008061061a856107fe565b60405160200161062c91815260200190565b60408051601f198184030181528282526020830188905292506000910160408051601f19818403018152828201909152600080835260208301529150610673818484610943565b6000610680828888610a76565b6040516001600160401b038216815290915088907fe3e452ff947e18cea0f62f23d405e522ac808f69346c5f59ddc4bd722ac10d039060200160405180910390a2979650505050505050565b60408051600481526024810182526020810180516001600160e01b03166329f43eb360e11b17905290516000918291829168010000000000000001916107129190611156565b600060405180830381855afa9150503d806000811461074d576040519150601f19603f3d011682016040523d82523d6000602084013e610752565b606091505b5091509150816107e05760405162461bcd60e51b815260206004820152604d60248201527f556e7375636365737366756c2063616c6c20746f20436164656e63652041726360448201527f68207072652d636f6d70696c65207768656e206665746368696e6720466c6f7760648201526c08189b1bd8dac81a195a59da1d609a1b608482015260a4016101f0565b6000818060200190518101906107f69190611162565b949350505050565b60008061080c6001846110e4565b60005490915081106108915760405162461bcd60e51b815260206004820152604260248201527f496e76616c69642072657175657374204944202d2076616c756520657863656560448201527f647320746865206e756d626572206f66206578697374696e6720726571756573606482015261747360f01b608482015260a4016101f0565b60008082815481106108a5576108a56110f7565b906000526020600020906003020190506108be81610c01565b60028101805460ff1916600117905580546000906108e4906001600160401b0316610ced565b82546001840154604080516001600160401b0390931683526020830191909152810182905290915085907f01f207584638dfbb3f1d85bba3809672fcb07a3d2e291308293ba78b7f1984909060600160405180910390a2949350505050565b6010825110156109c95760405162461bcd60e51b815260206004820152604560248201527f4174206c65617374203136206279746573206f6620656e74726f70792073686f60448201527f756c642062652075736564207768656e20696e697469616c697a696e67207468606482015264652050524760d81b608482015260a4016101f0565b600082826040516020016109de92919061118b565b6040516020818303038152906040529050600081805190602001209050610a2781604051602001610a1191815260200190565b6040516020818303038152906040526000610e29565b6001600160401b031685526040805160208101839052610a5891016040516020818303038152906040526008610e29565b6001600160401b03166020860152610a6f85610ee3565b5050505050565b6000826001600160401b0316826001600160401b031611610ad95760405162461bcd60e51b815260206004820152601c60248201527f4d6178206d7573742062652067726561746572207468616e206d696e0000000060448201526064016101f0565b6000610ae485610f79565b90506000610af285856111a0565b90506000610aff82610fdb565b90506000610b1a60016001600160401b03841681901b6110e4565b905060005b8185169050836001600160401b0316816001600160401b03161115610b6657826001600160401b031685901c945084600003610b6157610b5e89610f79565b94505b610b1f565b6000610b7289836111c7565b9050886001600160401b0316816001600160401b031610158015610ba85750876001600160401b0316816001600160401b031611155b610bf45760405162461bcd60e51b815260206004820152601a60248201527f52616e646f6d206e756d626572206f7574206f662072616e676500000000000060448201526064016101f0565b9998505050505050505050565b600281015460ff1615610c565760405162461bcd60e51b815260206004820152601960248201527f5265717565737420616c72656164792066756c66696c6c65640000000000000060448201526064016101f0565b610c5e6106cc565b81546001600160401b03918216911610610cea5760405162461bcd60e51b815260206004820152604160248201527f43616e6e6f742066756c66696c6c207265717565737420756e74696c2073756260448201527f73657175656e7420466c6f77206e6574776f726b20626c6f636b2068656967686064820152601d60fa1b608482015260a4016101f0565b50565b6040516001600160401b038216602482015260009081908190680100000000000000019060440160408051601f198184030181529181526020820180516001600160e01b0316633c53afdf60e11b17905251610d499190611156565b600060405180830381855afa9150503d8060008114610d84576040519150601f19603f3d011682016040523d82523d6000602084013e610d89565b606091505b509150915081610e135760405162461bcd60e51b815260206004820152604960248201527f556e7375636365737366756c2063616c6c20746f20436164656e63652041726360448201527f68207072652d636f6d70696c65207768656e206665746368696e672072616e646064820152686f6d20736f7572636560b81b608482015260a4016101f0565b6000818060200190518101906104c491906111e7565b6000610e36826008611200565b83511015610e7c5760405162461bcd60e51b8152602060048201526013602482015272092dcecc2d8d2c840c4f2e8ca40d8cadccee8d606b1b60448201526064016101f0565b6000805b6008811015610ed95784610e948286611200565b81518110610ea457610ea46110f7565b602001015160f81c60f81b60f81c60ff166008836001600160401b0316901b1791508080610ed19061110d565b915050610e80565b5090505b92915050565b80516001600160401b0316151580610f07575060208101516001600160401b031615155b610cea5760405162461bcd60e51b815260206004820152603860248201527f50524720696e697469616c2073746174652069732030202d206d75737420626560448201527f20696e697469616c697a6564206173206e6f6e2d7a65726f000000000000000060648201526084016101f0565b600080610f8583611011565b6001600160401b031690506040610f9b84611011565b6001600160401b0316901b176080610fb284611011565b6001600160401b0316901b1760c0610fc984611011565b6001600160401b0316901b1792915050565b6000805b6001600160401b03831615610edd576001836001600160401b0316901c9250808061100990611213565b915050610fdf565b600061101c82610ee3565b5080516020820180516001600160401b03808216909452601783901b6a7fffffffffffffff80000016909218601181901c657fffffffffff1618601a83901c643fffffffff1683181892831690520190565b60006020828403121561108057600080fd5b81356001600160a01b038116811461109757600080fd5b9392505050565b6000602082840312156110b057600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610edd57610edd6110b7565b81810381811115610edd57610edd6110b7565b634e487b7160e01b600052603260045260246000fd5b60006001820161111f5761111f6110b7565b5060010190565b6000815160005b81811015611147576020818501810151868301520161112d565b50600093019283525090919050565b60006110978284611126565b60006020828403121561117457600080fd5b81516001600160401b038116811461109757600080fd5b60006107f661119a8386611126565b84611126565b6001600160401b038281168282160390808211156111c0576111c06110b7565b5092915050565b6001600160401b038181168382160190808211156111c0576111c06110b7565b6000602082840312156111f957600080fd5b5051919050565b80820180821115610edd57610edd6110b7565b60006001600160401b0380831681810361122f5761122f6110b7565b600101939250505056fea2646970667358221220de2b8283cbc9f12dba31db150d1f0e7ee12f17fa96f14636731bcf31cd2d5e5964736f6c63430008130033" +access(all) let coinTossBytecode = "608060405234801561001057600080fd5b50611247806100206000396000f3fe6080604052600436106100745760003560e01c80638c0647461161004e5780638c064746146100cb578063cd1a44db14610113578063d59fd63c1461014e578063fcf36b6a1461016e57600080fd5b80631b3ed72214610080578063799ae223146100ac5780638c03fe15146100b657600080fd5b3661007b57005b600080fd5b34801561008c57600080fd5b50610095600281565b60405160ff90911681526020015b60405180910390f35b6100b461019b565b005b3480156100c257600080fd5b506100b46102dc565b3480156100d757600080fd5b506101036100e6366004611012565b6001600160a01b0316600090815260026020526040902054151590565b60405190151581526020016100a3565b34801561011f57600080fd5b5061014061012e366004611042565b60036020526000908152604090205481565b6040519081526020016100a3565b34801561015a57600080fd5b50610103610169366004611042565b61044f565b34801561017a57600080fd5b50610140610189366004611012565b60026020526000908152604090205481565b346101f95760405162461bcd60e51b815260206004820152602360248201527f4d7573742073656e6420464c4f5720746f20706c61636520666c69702061206360448201526237b4b760e91b60648201526084015b60405180910390fd5b33600090815260026020526040902054156102755760405162461bcd60e51b815260206004820152603660248201527f4d75737420636c6f73652070726576696f757320636f696e20666c6970206265604482015275666f726520706c6163696e672061206e6577206f6e6560501b60648201526084016101f0565b600061027f6104cd565b33600081815260026020908152604080832085905584835260038252918290203490819055915191825292935083927faaf5204450758753a474bce0ff33a69922372c674f7f6cde7adc701030fb3c4c910160405180910390a350565b336000908152600260205260409020546103525760405162461bcd60e51b815260206004820152603160248201527f43616c6c657220686173206e6f7420666c6970706564206120636f696e202d206044820152701b9bdd1a1a5b99c81d1bc81c995d99585b607a1b60648201526084016101f0565b336000908152600260205260408120805490829055906103748282600161060e565b600083815260036020526040812080549082905591925060ff83168103610409576103a0600283611071565b604051909150600090339083156108fc0290849084818181858888f193505050509050806104075760405162461bcd60e51b81526020600482015260146024820152734661696c656420746f2073656e64207072697a6560601b60448201526064016101f0565b505b6040805160ff8516815260208101839052859133917ffa8362afdddf0c36107d3f3ad3c875ecd4c311118133c0e4b2b8e6ac2a0e3105910160405180910390a350505050565b60008061045d600184611088565b60005490915081106104725750600092915050565b60008082815481106104865761048661109b565b9060005260206000209060030201905060006104a06106cc565b600283015490915060ff161580156104c4575081546001600160401b038083169116105b95945050505050565b60018054600091826104de836110b1565b919050555060006001549050600060405180606001604052806104ff6106cc565b6001600160401b0390811682524360208084019190915260006040938401819052805460018101825590805284517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5636003909202918201805467ffffffffffffffff191691909416908117909355848201517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5648201819055858501517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565909201805460ff19169215159290921790915583519283529082015291925083917f7886956edccde10901843c3e51fc26016455e9248e210a29c2a57ead63ad226e910160405180910390a250919050565b60008061061a856107fe565b60405160200161062c91815260200190565b60408051601f198184030181528282526020830188905292506000910160408051601f19818403018152828201909152600080835260208301529150610673818484610943565b6000610680828888610a76565b6040516001600160401b038216815290915088907fe3e452ff947e18cea0f62f23d405e522ac808f69346c5f59ddc4bd722ac10d039060200160405180910390a2979650505050505050565b60408051600481526024810182526020810180516001600160e01b03166329f43eb360e11b179052905160009182918291680100000000000000019161071291906110fa565b600060405180830381855afa9150503d806000811461074d576040519150601f19603f3d011682016040523d82523d6000602084013e610752565b606091505b5091509150816107e05760405162461bcd60e51b815260206004820152604d60248201527f556e7375636365737366756c2063616c6c20746f20436164656e63652041726360448201527f68207072652d636f6d70696c65207768656e206665746368696e6720466c6f7760648201526c08189b1bd8dac81a195a59da1d609a1b608482015260a4016101f0565b6000818060200190518101906107f69190611106565b949350505050565b60008061080c600184611088565b60005490915081106108915760405162461bcd60e51b815260206004820152604260248201527f496e76616c69642072657175657374204944202d2076616c756520657863656560448201527f647320746865206e756d626572206f66206578697374696e6720726571756573606482015261747360f01b608482015260a4016101f0565b60008082815481106108a5576108a561109b565b906000526020600020906003020190506108be81610ba5565b60028101805460ff1916600117905580546000906108e4906001600160401b0316610c91565b82546001840154604080516001600160401b0390931683526020830191909152810182905290915085907f01f207584638dfbb3f1d85bba3809672fcb07a3d2e291308293ba78b7f1984909060600160405180910390a2949350505050565b6010825110156109c95760405162461bcd60e51b815260206004820152604560248201527f4174206c65617374203136206279746573206f6620656e74726f70792073686f60448201527f756c642062652075736564207768656e20696e697469616c697a696e67207468606482015264652050524760d81b608482015260a4016101f0565b600082826040516020016109de92919061112f565b6040516020818303038152906040529050600081805190602001209050610a2781604051602001610a1191815260200190565b6040516020818303038152906040526000610dcd565b6001600160401b031685526040805160208101839052610a5891016040516020818303038152906040526008610dcd565b6001600160401b03166020860152610a6f85610e87565b5050505050565b6000826001600160401b0316826001600160401b031611610ad95760405162461bcd60e51b815260206004820152601c60248201527f4d6178206d7573742062652067726561746572207468616e206d696e0000000060448201526064016101f0565b6000610ae58484611144565b90506000610af282610f1d565b90506000610b0d60016001600160401b03841681901b611088565b90506000610b1d8361010061116b565b6001600160401b031690506000806000610b368b610f53565b90505b8481169150866001600160401b0316826001600160401b03161115610b8c576001600160401b0386161c82610b6d816110b1565b935050838303610b8757610b808b610f53565b9050600092505b610b39565b610b96828b61119f565b9b9a5050505050505050505050565b600281015460ff1615610bfa5760405162461bcd60e51b815260206004820152601960248201527f5265717565737420616c72656164792066756c66696c6c65640000000000000060448201526064016101f0565b610c026106cc565b81546001600160401b03918216911610610c8e5760405162461bcd60e51b815260206004820152604160248201527f43616e6e6f742066756c66696c6c207265717565737420756e74696c2073756260448201527f73657175656e7420466c6f77206e6574776f726b20626c6f636b2068656967686064820152601d60fa1b608482015260a4016101f0565b50565b6040516001600160401b038216602482015260009081908190680100000000000000019060440160408051601f198184030181529181526020820180516001600160e01b0316633c53afdf60e11b17905251610ced91906110fa565b600060405180830381855afa9150503d8060008114610d28576040519150601f19603f3d011682016040523d82523d6000602084013e610d2d565b606091505b509150915081610db75760405162461bcd60e51b815260206004820152604960248201527f556e7375636365737366756c2063616c6c20746f20436164656e63652041726360448201527f68207072652d636f6d70696c65207768656e206665746368696e672072616e646064820152686f6d20736f7572636560b81b608482015260a4016101f0565b6000818060200190518101906104c491906111bf565b6000610dda8260086111d8565b83511015610e205760405162461bcd60e51b8152602060048201526013602482015272092dcecc2d8d2c840c4f2e8ca40d8cadccee8d606b1b60448201526064016101f0565b6000805b6008811015610e7d5784610e3882866111d8565b81518110610e4857610e4861109b565b602001015160f81c60f81b60f81c60ff166008836001600160401b0316901b1791508080610e75906110b1565b915050610e24565b5090505b92915050565b80516001600160401b0316151580610eab575060208101516001600160401b031615155b610c8e5760405162461bcd60e51b815260206004820152603860248201527f50524720696e697469616c2073746174652069732030202d206d75737420626560448201527f20696e697469616c697a6564206173206e6f6e2d7a65726f000000000000000060648201526084016101f0565b6000805b6001600160401b03831615610e81576001836001600160401b0316901c92508080610f4b906111eb565b915050610f21565b600080610f5f83610fb5565b6001600160401b031690506040610f7584610fb5565b6001600160401b0316901b176080610f8c84610fb5565b6001600160401b0316901b1760c0610fa384610fb5565b6001600160401b0316901b1792915050565b6000610fc082610e87565b5080516020820180516001600160401b03808216909452601783901b6a7fffffffffffffff80000016909218601181901c657fffffffffff1618601a83901c643fffffffff1683181892831690520190565b60006020828403121561102457600080fd5b81356001600160a01b038116811461103b57600080fd5b9392505050565b60006020828403121561105457600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610e8157610e8161105b565b81810381811115610e8157610e8161105b565b634e487b7160e01b600052603260045260246000fd5b6000600182016110c3576110c361105b565b5060010190565b6000815160005b818110156110eb57602081850181015186830152016110d1565b50600093019283525090919050565b600061103b82846110ca565b60006020828403121561111857600080fd5b81516001600160401b038116811461103b57600080fd5b60006107f661113e83866110ca565b846110ca565b6001600160401b038281168282160390808211156111645761116461105b565b5092915050565b60006001600160401b038084168061119357634e487b7160e01b600052601260045260246000fd5b92169190910492915050565b6001600160401b038181168382160190808211156111645761116461105b565b6000602082840312156111d157600080fd5b5051919050565b80820180821115610e8157610e8161105b565b60006001600160401b038083168181036112075761120761105b565b600101939250505056fea26469706673582212208cd9a222a39b9105db8805b53551c8a7ab5e6afcc19f207f47d185d99c7c98be64736f6c63430008130033" access(all) fun getCoinTossBytecode(): String {