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..f17279aa 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,41 @@ 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`], as done in + /// [`Self::random`], 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 R) -> Self + where + R: RngCore + CryptoRng, + { + let mut buf = [0; 32]; + let mut scalar: Option = None; + + // We loop as long as it takes to generate a valid scalar. + // As long as the random number generator is implemented properly, this + // loop will terminate. + while scalar == None { + rng.fill_bytes(&mut buf); + // Since modulus has at most 255 bits, we can zero the MSB and like + // this improve our chances of hitting a valid scalar to above 50% + buf[32 - 1] &= 0b0111_1111; + scalar = Self::from_bytes(&buf).into(); + } + scalar.unwrap() + } + /// SHR impl #[inline] pub fn divn(&mut self, mut n: u32) {