1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
//! Generally useful utilities related to hashing. //! //! In general, things in here are defined against the [`Digest`] trait from the [`RustCrypto`] project. //! //! [`Digest`]: digest::Digest //! [`RustCrypto`]: https://github.com/RustCrypto/hashes use crate::digest::{ generic_array::typenum::{PartialDiv, Unsigned}, BlockInput, Digest, }; /// Extension trait to "tag" a hash as described in [BIP-340]. /// /// [BIP-340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki pub trait Tagged: Default + Clone { /// Returns the _tagged_ (domain separated) SHA256 instance. /// This is meant be used on SHA256 state with an empty buffer. /// # Example /// ``` /// use digest::Digest; /// use secp256kfun::hash::Tagged; /// let mut hash = sha2::Sha256::default().tagged(b"my-domain/my-purpose"); /// hash.update(b"hello world"); /// println!("{:?}", hash.finalize()); /// ``` fn tagged(&self, tag: &[u8]) -> Self; } impl<H: BlockInput + Digest + Default + Clone> Tagged for H where <H as BlockInput>::BlockSize: PartialDiv<H::OutputSize>, <<H as BlockInput>::BlockSize as PartialDiv<H::OutputSize>>::Output: Unsigned, { fn tagged(&self, tag: &[u8]) -> Self { let hashed_tag = { let mut hash = H::default(); hash.update(tag); hash.finalize() }; let mut tagged_hash = self.clone(); let fill_block = <<H::BlockSize as PartialDiv<H::OutputSize>>::Output as Unsigned>::to_usize(); for _ in 0..fill_block { tagged_hash.update(&hashed_tag[..]); } tagged_hash } } /// Anything that can be hashed. /// /// The implementations of this trait decide how the type will be converted into /// bytes so that it can be included in the hash. /// /// # Example /// /// ``` /// use digest::Digest; /// use secp256kfun::hash::{HashAdd, HashInto}; /// struct CryptoData([u8; 42]); /// /// impl HashInto for CryptoData { /// fn hash_into(&self, hash: &mut impl digest::Digest) { /// hash.update(&self.0[..]) /// } /// } /// /// let cryptodata = CryptoData([42u8; 42]); /// let hash = sha2::Sha256::default().add(&cryptodata).finalize(); /// ``` pub trait HashInto { /// Asks the item to convert itself to bytes and add itself to `hash`. fn hash_into(&self, hash: &mut impl digest::Digest); } impl HashInto for [u8] { fn hash_into(&self, hash: &mut impl digest::Digest) { hash.update(self) } } impl HashInto for str { fn hash_into(&self, hash: &mut impl digest::Digest) { hash.update(self.as_bytes()) } } /// Extension trait for [`digest::Digest`] to make adding things to the hash convenient. pub trait HashAdd { /// Converts something that implements [`HashInto`] to bytes and then incorporate the result into the digest (`self`). fn add<HI: HashInto + ?Sized>(self, data: &HI) -> Self; } impl<D: Digest> HashAdd for D { fn add<HI: HashInto + ?Sized>(mut self, data: &HI) -> Self { data.hash_into(&mut self); self } } /// Trait for things that can domain separate themselves. /// /// i.e. given a protocol or application tag can produce a new version that will /// not give the same outputs for a given input if the tags are different. pub trait AddTag { /// Tells the invocant to return a new version of itself modifies with the /// protocol tag. This is to ensure that the `AddTag` does not produce the /// same outputs for tow different protocols even if they have the same /// public inputs. By "protocol" we mean type of cryptographic scheme. For /// example, for the [BIP-340] signature scheme you would use "BIP340" as /// the tag. /// /// [BIP-340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki fn add_protocol_tag(self, tag: &str) -> Self; /// Tells the `AddTag` to further domain separate itself for a particular /// application. This is useful when you are domain separating signatures in /// your application from other signatures. fn add_application_tag(self, tag: &str) -> Self; } /// AddTag is implemented for () so you can use implement things generically for /// `AddTag` even for things that have some field set to () (for example /// `NonceGen` when you're doing verification only). impl AddTag for () { fn add_protocol_tag(self, _tag: &str) -> Self { () } fn add_application_tag(self, _tag: &str) -> Self { () } }