semaphore_rs/
identity.rs

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
13/// Implements the private key derivation function from zk-kit.
14///
15/// See <https://github.com/appliedzkp/zk-kit/blob/1ea410456fc2b95877efa7c671bc390ffbfb5d36/packages/identity/src/identity.ts#L58>
16fn 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}