darkfi/blockchain/monero/
keccak.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use std::io::{Cursor, Read, Result, Write};
20
21#[allow(unused_imports)]
22use tiny_keccak::{Hasher, Keccak};
23
24#[repr(C)]
25#[allow(unused)]
26enum Mode {
27    Absorbing,
28    Squeezing,
29}
30
31#[repr(C)]
32// https://docs.rs/tiny-keccak/latest/src/tiny_keccak/lib.rs.html#368
33struct KeccakState {
34    buffer: [u8; 200],
35    offset: usize,
36    rate: usize,
37    delim: u8,
38    mode: Mode,
39}
40
41unsafe fn serialize_keccak<W: Write>(keccak: &Keccak, writer: &mut W) -> Result<()> {
42    let keccak_ptr = keccak as *const Keccak as *const KeccakState;
43    let keccak_state = &*keccak_ptr;
44
45    writer.write_all(&keccak_state.buffer)?;
46    writer.write_all(&(keccak_state.offset as u64).to_le_bytes())?;
47    writer.write_all(&(keccak_state.rate as u64).to_le_bytes())?;
48    writer.write_all(&[keccak_state.delim])?;
49
50    Ok(())
51}
52
53unsafe fn deserialize_keccak<R: Read>(reader: &mut R) -> Result<Keccak> {
54    let mut keccak = Keccak::v256();
55
56    let keccak_ptr = &mut keccak as *mut Keccak as *mut KeccakState;
57    let keccak_state = &mut *keccak_ptr;
58
59    reader.read_exact(&mut keccak_state.buffer)?;
60
61    let mut offset_bytes = [0u8; 8];
62    reader.read_exact(&mut offset_bytes)?;
63    keccak_state.offset = u64::from_le_bytes(offset_bytes) as usize;
64
65    let mut rate_bytes = [0u8; 8];
66    reader.read_exact(&mut rate_bytes)?;
67    keccak_state.rate = u64::from_le_bytes(rate_bytes) as usize;
68
69    let mut delim_byte = [0u8; 1];
70    reader.read_exact(&mut delim_byte)?;
71    keccak_state.delim = delim_byte[0];
72
73    keccak_state.mode = Mode::Absorbing;
74
75    Ok(keccak)
76}
77
78pub fn keccak_to_bytes(keccak: &Keccak) -> Vec<u8> {
79    let mut bytes = vec![];
80    unsafe { serialize_keccak(keccak, &mut bytes).unwrap() }
81    bytes
82}
83
84pub fn keccak_from_bytes(bytes: &[u8]) -> Keccak {
85    let mut cursor = Cursor::new(bytes);
86    unsafe { deserialize_keccak(&mut cursor).unwrap() }
87}
88
89#[test]
90fn test_keccak_serde() {
91    let mut keccak = Keccak::v256();
92    keccak.update(b"foobar");
93
94    let ser = keccak_to_bytes(&keccak);
95
96    let mut digest1 = [0u8; 32];
97    keccak.finalize(&mut digest1);
98
99    let de = keccak_from_bytes(&ser);
100    let mut digest2 = [0u8; 32];
101    de.finalize(&mut digest2);
102
103    println!("{digest1:?}");
104    println!("{digest2:?}");
105
106    assert_eq!(digest1, digest2);
107}