diff --git a/CHANGELOG.md b/CHANGELOG.md index 1177a34a..8d193af8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add `uni_random` scalar generation [#125] + ## [0.12.2] - 2023-10-11 ### Fixed @@ -210,24 +214,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rename `S` to `TWO_ADACITY` and export it -[#117]: (https://github.com/dusk-network/bls12_381/issues/117) -[#109]: (https://github.com/dusk-network/bls12_381/issues/109) -[#108]: (https://github.com/dusk-network/bls12_381/issues/108) -[#100]: (https://github.com/dusk-network/bls12_381/issues/100) -[#93]: (https://github.com/dusk-network/bls12_381/issues/93) -[#75]: (https://github.com/dusk-network/bls12_381/issues/75) -[#84]: (https://github.com/dusk-network/bls12_381/issues/84) -[#94]: (https://github.com/dusk-network/bls12_381/issues/94) -[#90]: (https://github.com/dusk-network/bls12_381/issues/90) -[#86]: (https://github.com/dusk-network/bls12_381/issues/86) -[#78]: (https://github.com/dusk-network/bls12_381/issues/78) -[#61]: (https://github.com/dusk-network/bls12_381/issues/61) -[#67]: (https://github.com/dusk-network/bls12_381/issues/67) -[#54]: (https://github.com/dusk-network/bls12_381/issues/54) -[#59]: (https://github.com/dusk-network/bls12_381/issues/59) -[#58]: (https://github.com/dusk-network/bls12_381/issues/58) -[#52]: (https://github.com/dusk-network/bls12_381/issues/52) -[#50]: (https://github.com/dusk-network/bls12_381/issues/50) +[#125]: https://github.com/dusk-network/bls12_381/issues/125 +[#117]: https://github.com/dusk-network/bls12_381/issues/117 +[#109]: https://github.com/dusk-network/bls12_381/issues/109 +[#108]: https://github.com/dusk-network/bls12_381/issues/108 +[#100]: https://github.com/dusk-network/bls12_381/issues/100 +[#93]: https://github.com/dusk-network/bls12_381/issues/93 +[#75]: https://github.com/dusk-network/bls12_381/issues/75 +[#84]: https://github.com/dusk-network/bls12_381/issues/84 +[#94]: https://github.com/dusk-network/bls12_381/issues/94 +[#90]: https://github.com/dusk-network/bls12_381/issues/90 +[#86]: https://github.com/dusk-network/bls12_381/issues/86 +[#78]: https://github.com/dusk-network/bls12_381/issues/78 +[#61]: https://github.com/dusk-network/bls12_381/issues/61 +[#67]: https://github.com/dusk-network/bls12_381/issues/67 +[#54]: https://github.com/dusk-network/bls12_381/issues/54 +[#59]: https://github.com/dusk-network/bls12_381/issues/59 +[#58]: https://github.com/dusk-network/bls12_381/issues/58 +[#52]: https://github.com/dusk-network/bls12_381/issues/52 +[#50]: https://github.com/dusk-network/bls12_381/issues/50 [Unreleased]: https://github.com/dusk-network/bls12_381/compare/v0.12.2...HEAD diff --git a/src/scalar/dusk.rs b/src/scalar/dusk.rs index f8d98623..2ebb9e15 100644 --- a/src/scalar/dusk.rs +++ b/src/scalar/dusk.rs @@ -8,6 +8,7 @@ use core::cmp::{Ord, Ordering, PartialOrd}; use core::convert::TryFrom; use core::ops::{BitAnd, BitXor}; use dusk_bytes::{Error as BytesError, Serializable}; +use rand_core::{CryptoRng, RngCore}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; use super::{Scalar, MODULUS, R2}; @@ -253,6 +254,35 @@ impl Scalar { res } + /// Compute a uniformly distributed random scalar. + /// + /// Because scalars take 255 bits for encoding it is difficult to generate + /// random bit-pattern that ensures to encodes a valid scalar. + /// Wrapping the values that are higher than [`MODULUS`] results in hitting + /// some values more than others, and zeroing out the highest two bits will + /// eliminate some values from the possible results. + /// + /// This function achieves a uniform distribution of scalars by using + /// rejection sampling: random bit-patterns are generated until a valid + /// scalar is found. + /// The function is not constant time but that shouldn't be a concern since + /// no information about the scalar can be gained by knowing the time of + /// its generation. + pub fn uni_random(rng: &mut (impl RngCore + CryptoRng)) -> Self { + let mut buf = [0; 32]; + let mut scalar: Option = None; + + // we loop as long as it takes to generate a valid scalar + while scalar == None { + // Since modulus has 255-bits or less, we can zero the first bit + // to improve our chances of generating a valid scalar + buf[32 - 1] &= 0b0111_1111; + rng.fill_bytes(&mut buf); + scalar = Self::from_bytes(&buf).into(); + } + scalar.unwrap() + } + /// SHR impl #[inline] pub fn divn(&mut self, mut n: u32) {