diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d193af8..3e970653 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `uni_random` scalar generation [#125] +### Changed + +- Change `Hash` derive on `Scalar` to explicit implementation [#106] + ## [0.12.2] - 2023-10-11 ### Fixed @@ -218,6 +222,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#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 +[#106]: https://github.com/dusk-network/bls12_381/issues/106 [#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 diff --git a/src/scalar.rs b/src/scalar.rs index c2f25f73..af274031 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -25,7 +25,7 @@ use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; // The internal representation of this type is four 64-bit unsigned // integers in little-endian order. `Scalar` values are always in // Montgomery form; i.e., Scalar(a) = aR mod q, with R = 2^256. -#[derive(Clone, Copy, Eq, Hash)] +#[derive(Clone, Copy, Eq)] #[cfg_attr( feature = "rkyv-impl", derive(Archive, RkyvSerialize, RkyvDeserialize), diff --git a/src/scalar/dusk.rs b/src/scalar/dusk.rs index f17279aa..e3355a58 100644 --- a/src/scalar/dusk.rs +++ b/src/scalar/dusk.rs @@ -6,6 +6,7 @@ use core::cmp::{Ord, Ordering, PartialOrd}; use core::convert::TryFrom; +use core::hash::{Hash, Hasher}; use core::ops::{BitAnd, BitXor}; use dusk_bytes::{Error as BytesError, Serializable}; use rand_core::{CryptoRng, RngCore}; @@ -205,6 +206,13 @@ impl<'a, 'b> BitAnd<&'b Scalar> for &'a Scalar { } } +impl Hash for Scalar { + #[inline] + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + impl Scalar { /// Checks in ct_time whether a Scalar is equal to zero. pub fn is_zero(&self) -> Choice { @@ -407,3 +415,34 @@ fn pow_of_two_test() { assert_eq!(Scalar::pow_of_2(i as u64), two.pow(&[i as u64, 0, 0, 0])); } } + +#[test] +fn test_scalar_eq_and_hash() { + use sha3::{Digest, Keccak256}; + + let r0 = Scalar::from_raw([ + 0x1fff_3231_233f_fffd, + 0x4884_b7fa_0003_4802, + 0x998c_4fef_ecbc_4ff3, + 0x1824_b159_acc5_0562, + ]); + let r1 = Scalar::from_raw([ + 0x1fff_3231_233f_fffd, + 0x4884_b7fa_0003_4802, + 0x998c_4fef_ecbc_4ff3, + 0x1824_b159_acc5_0562, + ]); + let r2 = Scalar::from(7); + + // Check PartialEq + assert!(r0 == r1); + assert!(r0 != r2); + + let hash_r0 = Keccak256::digest(&r0.to_bytes()); + let hash_r1 = Keccak256::digest(&r1.to_bytes()); + let hash_r2 = Keccak256::digest(&r2.to_bytes()); + + // Check if hash results are consistent with PartialEq results + assert_eq!(hash_r0, hash_r1); + assert_ne!(hash_r0, hash_r2); +}