o1_utils/hasher.rs
1//! This module provides the [CryptoDigest] trait,
2//! which provides a generic interface for hashing.
3//!
4//! To use it, simply implement [CryptoDigest] for your type:
5//!
6//! ```
7//! use o1_utils::hasher::CryptoDigest;
8//! use serde::Serialize;
9//!
10//! #[derive(Serialize)]
11//! struct A {
12//! thing: u8,
13//! }
14//!
15//! impl CryptoDigest for A {
16//! const PREFIX: &'static [u8; 15] = b"kimchi-circuit0";
17//! }
18//!
19//! let a = A { thing: 1 };
20//! let expected_result = [164, 8, 215, 27, 25, 36, 6, 167, 42, 86, 200, 203, 99, 74, 178, 134, 66, 168, 85, 7, 224, 189, 73, 63, 117, 23, 18, 193, 168, 176, 123, 80];
21//! assert_eq!(a.digest(), expected_result);
22//!
23//! let b = A { thing: 1 };
24//! assert_eq!(a.digest(), b.digest());
25//! ```
26//!
27//! Warning: make sure not to reuse the same `PREFIX`
28//! for different types. This prefix is here to semantically
29//! distinguish the hash of different types
30//! (and thus different use-case).
31//!
32
33use serde::Serialize;
34use sha2::{Digest, Sha256};
35
36/// This trait can be implemented on any type that implements [serde::Serialize],
37/// in order to provide a `digest()` function that returns a unique hash.
38pub trait CryptoDigest: Serialize {
39 /// The domain separation string to use in the hash.
40 /// This is to distinguish hashes for different use-cases.
41 /// With this approach, a type is linked to a single usecase.
42 ///
43 /// Warning: careful not to use the same separation string with
44 /// two different types.
45 const PREFIX: &'static [u8; 15];
46
47 /// Returns the digest of `self`.
48 /// Note: this is implemented as the SHA-256 of a prefix
49 /// ("kimchi-circuit"), followed by the serialized gates.
50 /// The gates are serialized using [BCS](https://github.com/diem/bcs).
51 fn digest(&self) -> [u8; 32] {
52 // compute the prefixed state lazily
53 let mut hasher = Sha256::new();
54 hasher.update(Self::PREFIX);
55 hasher.update(
56 bcs::to_bytes(self).unwrap_or_else(|e| panic!("couldn't serialize the gate: {e}")),
57 );
58 hasher.finalize().into()
59 }
60}