1use sha2::{Digest, Sha256};
2use zeroize::Zeroize;
3
4use crate::field::MODULUS;
5use crate::Field;
6
7#[derive(Clone, PartialEq, Eq, Debug)]
8pub struct Identity {
9 pub trapdoor: Field,
10 pub nullifier: Field,
11}
12
13fn derive_field(seed_hex: &[u8; 64], suffix: &[u8]) -> Field {
17 let mut hasher = Sha256::new();
18 hasher.update(seed_hex);
19 hasher.update(suffix);
20 Field::try_from_be_slice(hasher.finalize().as_ref()).unwrap() % MODULUS
21}
22
23pub fn seed_hex(seed: &[u8]) -> [u8; 64] {
24 let mut hasher = Sha256::new();
25 hasher.update(seed);
26 let bytes: [u8; 32] = hasher.finalize().into();
27 let mut result = [0_u8; 64];
28 hex::encode_to_slice(bytes, &mut result[..]).expect("output buffer is correctly sized");
29 result
30}
31
32impl Identity {
33 #[must_use]
34 #[deprecated(since = "0.2.0", note = "please use `from_secret` instead")]
35 pub fn from_seed(seed: &[u8]) -> Self {
36 let seed_hex = seed_hex(seed);
37 Self {
38 trapdoor: derive_field(&seed_hex, b"identity_trapdoor"),
39 nullifier: derive_field(&seed_hex, b"identity_nullifier"),
40 }
41 }
42
43 #[must_use]
44 pub fn from_secret(secret: &mut [u8], trapdoor_seed: Option<&[u8]>) -> Self {
45 let mut secret_hex = seed_hex(secret);
46 secret.zeroize();
47
48 Self::from_hashed_secret(&mut secret_hex, trapdoor_seed)
49 }
50
51 #[must_use]
52 pub fn from_hashed_secret(secret_hex: &mut [u8; 64], trapdoor_seed: Option<&[u8]>) -> Self {
53 let identity = Self {
54 trapdoor: derive_field(secret_hex, trapdoor_seed.unwrap_or(b"identity_trapdoor")),
55 nullifier: derive_field(secret_hex, b"identity_nullifier"),
56 };
57 secret_hex.zeroize();
58 identity
59 }
60
61 #[must_use]
62 pub fn secret_hash(&self) -> Field {
63 semaphore_rs_poseidon::poseidon::hash2(self.nullifier, self.trapdoor)
64 }
65
66 #[must_use]
67 pub fn commitment(&self) -> Field {
68 semaphore_rs_poseidon::poseidon::hash1(self.secret_hash())
69 }
70}