ssi_eip712/
hashing.rs

1use keccak_hash::keccak;
2
3use crate::{StructName, TypeDefinition, TypeRef, Types, Value, ValueKind};
4
5#[derive(Debug, thiserror::Error)]
6pub enum TypedDataHashError {
7    #[error("Missing referenced type: {0}")]
8    MissingReferencedType(String),
9    #[error("Missing struct member: {0}")]
10    MissingStructMember(String),
11    #[error("Expected string")]
12    ExpectedString,
13    #[error("Expected bytes")]
14    ExpectedBytes,
15    #[error("Expected boolean")]
16    ExpectedBoolean,
17    #[error("Expected `{0}` array, found {1}")]
18    ExpectedArray(String, ValueKind),
19    #[error("Expected `{0}` struct, found {1}")]
20    ExpectedObject(String, ValueKind),
21    #[error("Expected integer")]
22    ExpectedInteger,
23    #[error("Expected address length 20 but found {0}")]
24    ExpectedAddressLength(usize),
25    #[error("Expected bytes length {0} but found {1}")]
26    ExpectedBytesLength(usize, usize),
27    #[error("Expected array length {0} but found {1}")]
28    ExpectedArrayLength(usize, usize),
29    #[error("Expected integer max length 32 bytes but found {0}")]
30    IntegerTooLong(usize),
31    #[error("Type not byte-aligned: {0} {1}")]
32    TypeNotByteAligned(&'static str, usize),
33    #[error("Expected bytes length between 1 and 32: {0}")]
34    BytesLength(usize),
35    #[error("Expected integer length between 8 and 256: {0}")]
36    IntegerLength(usize),
37    #[error("Expected string to be hex bytes")]
38    ExpectedHex,
39    #[error("Untyped properties: {0:?}")]
40    UntypedProperties(Vec<String>),
41}
42
43impl Value {
44    /// Hash the value.
45    ///
46    /// See: <https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct>
47    #[allow(clippy::ptr_arg)]
48    pub fn hash(
49        &self,
50        struct_name: &StructName,
51        types: &Types,
52    ) -> Result<[u8; 32], TypedDataHashError> {
53        let encoded_data = self
54            .encode(&TypeRef::Struct(struct_name.clone()), types)?
55            .to_vec();
56        Ok(keccak(encoded_data).to_fixed_bytes())
57    }
58}
59
60impl TypeDefinition {
61    /// Encodes and hash this type.
62    #[allow(clippy::ptr_arg)]
63    pub fn hash(
64        &self,
65        struct_name: &StructName,
66        types: &Types,
67    ) -> Result<[u8; 32], TypedDataHashError> {
68        let encoded_type = self.encode(struct_name, types)?.to_vec();
69        let type_hash = keccak(encoded_type).to_fixed_bytes();
70        Ok(type_hash)
71    }
72}