1use crate::{
4 baby_jubjub::{BabyJubjubConfig, EdwardsAffine},
5 error::SemaphoreError,
6};
7use ark_ec::{CurveConfig, CurveGroup, twisted_edwards::TECurveConfig};
8use ark_ed_on_bn254::{Fq, Fr};
9use ark_ff::{BigInteger, PrimeField};
10use blake::Blake;
11use light_poseidon::{Poseidon, PoseidonHasher};
12use num_bigint::{BigInt, Sign};
13use std::ops::Mul;
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct Identity {
18 private_key: Vec<u8>,
20 secret_scalar: Fr,
22 public_key: PublicKey,
24 commitment: Fq,
26}
27
28impl Identity {
29 pub fn new(private_key: &[u8]) -> Self {
31 let secret_scalar = Self::gen_secret_scalar(private_key);
33
34 let public_key = PublicKey::from_scalar(&secret_scalar);
36
37 let commitment = public_key.commitment();
39
40 Self {
41 private_key: private_key.to_vec(),
42 secret_scalar,
43 public_key,
44 commitment,
45 }
46 }
47
48 pub fn private_key(&self) -> &[u8] {
50 &self.private_key
51 }
52
53 pub fn secret_scalar(&self) -> &Fr {
55 &self.secret_scalar
56 }
57
58 pub fn public_key(&self) -> &PublicKey {
60 &self.public_key
61 }
62
63 pub fn commitment(&self) -> &Fq {
65 &self.commitment
66 }
67
68 pub fn sign_message(&self, message: &[u8]) -> Result<Signature, SemaphoreError> {
70 if message.len() > 32 {
71 return Err(SemaphoreError::MessageSizeExceeded(message.len()));
72 }
73
74 let mut priv_key_hash = blake_512(&self.private_key);
76 priv_key_hash[0] &= 0xF8;
77 priv_key_hash[31] &= 0x7F;
78 priv_key_hash[31] |= 0x40;
79
80 let mut message_le = message.to_vec();
82 message_le.reverse();
83
84 let mut k_input = [0u8; 64];
86 k_input[..32].copy_from_slice(&priv_key_hash[32..]);
87 k_input[32..32 + message.len()].copy_from_slice(&message_le);
88 let k_fr = Fr::from_le_bytes_mod_order(&blake_512(&k_input));
89
90 let r = BabyJubjubConfig::GENERATOR.mul(k_fr).into_affine();
92
93 let poseidon_inputs = [
95 r.x,
96 r.y,
97 self.public_key.x(),
98 self.public_key.y(),
99 Fq::from_be_bytes_mod_order(message),
100 ];
101 let c_fq = Poseidon::<Fq>::new_circom(5)
102 .unwrap()
103 .hash(&poseidon_inputs)
104 .unwrap();
105 let c_fr = Fr::from_le_bytes_mod_order(&c_fq.into_bigint().to_bytes_le());
106
107 let secret_scalar = Fr::from_le_bytes_mod_order(&priv_key_hash[..32]);
109
110 let s = k_fr + c_fr * secret_scalar;
112
113 Ok(Signature::new(r, s))
114 }
115
116 fn gen_secret_scalar(private_key: &[u8]) -> Fr {
118 let mut hash = blake_512(private_key);
120
121 hash[0] &= 0xF8;
123 hash[31] &= 0x7F;
124 hash[31] |= 0x40;
125
126 let shifted: BigInt = BigInt::from_bytes_le(Sign::Plus, &hash[..32]) >> 3;
128
129 Fr::from_le_bytes_mod_order(&shifted.to_bytes_le().1)
130 }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
135pub struct PublicKey {
136 point: EdwardsAffine,
137}
138
139impl PublicKey {
140 pub fn from_point(point: EdwardsAffine) -> Self {
142 Self { point }
143 }
144
145 pub fn from_scalar(secret_scalar: &Fr) -> Self {
147 let point = BabyJubjubConfig::GENERATOR.mul(secret_scalar).into_affine();
148
149 Self { point }
150 }
151
152 pub fn commitment(&self) -> Fq {
154 Poseidon::<Fq>::new_circom(2)
155 .unwrap()
156 .hash(&[self.point.x, self.point.y])
157 .unwrap()
158 }
159
160 pub fn point(&self) -> EdwardsAffine {
162 self.point
163 }
164
165 pub fn x(&self) -> Fq {
167 self.point.x
168 }
169
170 pub fn y(&self) -> Fq {
172 self.point.y
173 }
174}
175
176#[derive(Debug, Clone, PartialEq, Eq)]
178pub struct Signature {
179 pub r: EdwardsAffine,
181 pub s: Fr,
183}
184
185impl Signature {
186 pub fn new(r: EdwardsAffine, s: Fr) -> Self {
188 Self { r, s }
189 }
190
191 pub fn verify(&self, public_key: &PublicKey, message: &[u8]) -> Result<(), SemaphoreError> {
193 if message.len() > 32 {
194 return Err(SemaphoreError::MessageSizeExceeded(message.len()));
195 }
196
197 if !self.r.is_on_curve() {
198 return Err(SemaphoreError::SignaturePointNotOnCurve);
199 }
200
201 if !public_key.point().is_on_curve() {
202 return Err(SemaphoreError::PublicKeyNotOnCurve);
203 }
204
205 let poseidon_inputs = [
207 self.r.x,
208 self.r.y,
209 public_key.x(),
210 public_key.y(),
211 Fq::from_be_bytes_mod_order(message),
212 ];
213 let c_fq = Poseidon::<Fq>::new_circom(5)
214 .unwrap()
215 .hash(&poseidon_inputs)
216 .unwrap();
217 let mut c_fr = Fr::from_le_bytes_mod_order(&c_fq.into_bigint().to_bytes_le());
218
219 c_fr *= Fr::from_be_bytes_mod_order(&[BabyJubjubConfig::COFACTOR[0] as u8]);
221
222 let left = BabyJubjubConfig::GENERATOR.mul(self.s);
224
225 let right = self.r + public_key.point().mul(c_fr);
227
228 if left != right {
230 return Err(SemaphoreError::SignatureVerificationFailed);
231 }
232
233 Ok(())
234 }
235}
236
237pub fn blake_512(input: &[u8]) -> [u8; 64] {
239 let mut output = [0u8; 64];
240 let mut hasher = Blake::new(512).unwrap();
241
242 hasher.update(input);
243 hasher.finalise(&mut output);
244
245 output
246}