1use std::collections::BTreeMap;
7use std::io::Write;
8
9use bls12_381::{G1Affine, G1Projective, G2Affine, G2Projective, Scalar, pairing};
10use fedimint_core::bitcoin::hashes::sha256;
11use fedimint_core::encoding::{Decodable, Encodable};
12use fedimint_core::{BitcoinHash, bls12_381_serde};
13use group::ff::Field;
14use group::{Curve, Group};
15use hex::encode;
16use rand::SeedableRng;
17use rand::rngs::OsRng;
18use rand_chacha::ChaChaRng;
19use serde::{Deserialize, Serialize};
20use sha3::Digest;
21
22const HASH_TAG: &[u8] = b"TBS_BLS12-381_";
23const FINGERPRINT_TAG: &[u8] = b"TBS_KFP24_";
24
25fn hash_bytes_to_g1(data: &[u8]) -> G1Projective {
26 let mut hash_engine = sha3::Sha3_256::new();
27
28 hash_engine.update(HASH_TAG);
29 hash_engine.update(data);
30
31 let mut prng = ChaChaRng::from_seed(hash_engine.finalize().into());
32
33 G1Projective::random(&mut prng)
34}
35
36#[derive(Copy, Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
37pub struct SecretKeyShare(#[serde(with = "bls12_381_serde::scalar")] pub Scalar);
38
39#[derive(Copy, Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
40pub struct PublicKeyShare(#[serde(with = "bls12_381_serde::g2")] pub G2Affine);
41
42#[derive(Copy, Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
43pub struct AggregatePublicKey(#[serde(with = "bls12_381_serde::g2")] pub G2Affine);
44
45#[derive(Copy, Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
46pub struct Message(#[serde(with = "bls12_381_serde::g1")] pub G1Affine);
47
48#[derive(Copy, Clone, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
49pub struct BlindingKey(#[serde(with = "bls12_381_serde::scalar")] pub Scalar);
50
51#[derive(Copy, Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
52pub struct BlindedMessage(#[serde(with = "bls12_381_serde::g1")] pub G1Affine);
53
54#[derive(Copy, Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
55pub struct BlindedSignatureShare(#[serde(with = "bls12_381_serde::g1")] pub G1Affine);
56
57#[derive(Copy, Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
58pub struct BlindedSignature(#[serde(with = "bls12_381_serde::g1")] pub G1Affine);
59
60#[derive(Copy, Clone, Debug, Eq, PartialEq, Encodable, Decodable, Serialize, Deserialize)]
61pub struct Signature(#[serde(with = "bls12_381_serde::g1")] pub G1Affine);
62
63macro_rules! point_hash_impl {
64 ($type:ty) => {
65 impl std::hash::Hash for $type {
66 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
67 self.0.to_compressed().hash(state);
68 }
69 }
70 };
71}
72
73point_hash_impl!(PublicKeyShare);
74point_hash_impl!(AggregatePublicKey);
75point_hash_impl!(Message);
76point_hash_impl!(BlindedMessage);
77point_hash_impl!(BlindedSignatureShare);
78point_hash_impl!(BlindedSignature);
79point_hash_impl!(Signature);
80
81pub fn derive_pk_share(sk: &SecretKeyShare) -> PublicKeyShare {
82 PublicKeyShare((G2Projective::generator() * sk.0).to_affine())
83}
84
85impl std::hash::Hash for BlindingKey {
86 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
87 self.0.to_bytes().hash(state);
88 }
89}
90
91impl BlindingKey {
92 pub fn random() -> BlindingKey {
93 BlindingKey(Scalar::random(OsRng))
95 }
96
97 fn fingerprint(&self) -> [u8; 32] {
98 let mut hash_engine = sha3::Sha3_256::new();
99 hash_engine.update(FINGERPRINT_TAG);
100 hash_engine.update(self.0.to_bytes());
101 let result = hash_engine.finalize();
102 result.into()
103 }
104}
105
106impl ::core::fmt::Debug for BlindingKey {
107 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
108 let fingerprint = self.fingerprint();
109 let fingerprint_hex = encode(&fingerprint[..]);
110 write!(f, "BlindingKey({fingerprint_hex})")
111 }
112}
113
114impl ::core::fmt::Display for BlindingKey {
115 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
116 let fingerprint = self.fingerprint();
117 let fingerprint_hex = encode(&fingerprint[..]);
118 write!(f, "{fingerprint_hex}")
119 }
120}
121
122impl Message {
123 pub fn from_bytes(msg: &[u8]) -> Message {
124 Message(hash_bytes_to_g1(msg).to_affine())
125 }
126
127 pub fn from_bytes_sha256(bytes: &[u8]) -> Message {
131 let mut engine = sha256::HashEngine::default();
132
133 engine
134 .write_all("FEDIMINT_TBS_BLS12_381_MESSAGE".as_bytes())
135 .expect("Writing to a hash engine cannot fail");
136
137 engine
138 .write_all(bytes)
139 .expect("Writing to a hash engine cannot fail");
140
141 let seed = sha256::Hash::from_engine(engine).to_byte_array();
142
143 Message(G1Projective::random(&mut ChaChaRng::from_seed(seed)).to_affine())
144 }
145}
146
147pub fn blind_message(msg: Message, blinding_key: BlindingKey) -> BlindedMessage {
148 let blinded_msg = msg.0 * blinding_key.0;
149
150 BlindedMessage(blinded_msg.to_affine())
151}
152
153pub fn sign_message(msg: BlindedMessage, sks: SecretKeyShare) -> BlindedSignatureShare {
154 let sig = msg.0 * sks.0;
155 BlindedSignatureShare(sig.to_affine())
156}
157
158pub fn verify_signature_share(
159 msg: BlindedMessage,
160 sig: BlindedSignatureShare,
161 pk: PublicKeyShare,
162) -> bool {
163 pairing(&msg.0, &pk.0) == pairing(&sig.0, &G2Affine::generator())
164}
165
166pub fn aggregate_signature_shares(
172 shares: &BTreeMap<u64, BlindedSignatureShare>,
173) -> BlindedSignature {
174 if shares.len() == 1 {
176 return BlindedSignature(
177 shares
178 .values()
179 .next()
180 .expect("We have at least one value")
181 .0,
182 );
183 }
184
185 BlindedSignature(
186 lagrange_multipliers(
187 shares
188 .keys()
189 .cloned()
190 .map(|peer| Scalar::from(peer + 1))
191 .collect(),
192 )
193 .into_iter()
194 .zip(shares.values())
195 .map(|(lagrange_multiplier, share)| lagrange_multiplier * share.0)
196 .reduce(|a, b| a + b)
197 .expect("We have at least one share")
198 .to_affine(),
199 )
200}
201
202pub fn aggregate_public_key_shares(shares: &BTreeMap<u64, PublicKeyShare>) -> AggregatePublicKey {
207 if shares.len() == 1 {
209 return AggregatePublicKey(
210 shares
211 .values()
212 .next()
213 .expect("We have at least one value")
214 .0,
215 );
216 }
217
218 AggregatePublicKey(
219 lagrange_multipliers(
220 shares
221 .keys()
222 .cloned()
223 .map(|peer| Scalar::from(peer + 1))
224 .collect(),
225 )
226 .into_iter()
227 .zip(shares.values())
228 .map(|(lagrange_multiplier, share)| lagrange_multiplier * share.0)
229 .reduce(|a, b| a + b)
230 .expect("We have at least one share")
231 .to_affine(),
232 )
233}
234
235fn lagrange_multipliers(scalars: Vec<Scalar>) -> Vec<Scalar> {
236 scalars
237 .iter()
238 .map(|i| {
239 scalars
240 .iter()
241 .filter(|j| *j != i)
242 .map(|j| j * (j - i).invert().expect("We filtered the case j == i"))
243 .reduce(|a, b| a * b)
244 .expect("We have at least one share")
245 })
246 .collect()
247}
248
249pub fn verify_blinded_signature(
250 msg: BlindedMessage,
251 sig: BlindedSignature,
252 pk: AggregatePublicKey,
253) -> bool {
254 pairing(&msg.0, &pk.0) == pairing(&sig.0, &G2Affine::generator())
255}
256
257pub fn unblind_signature(blinding_key: BlindingKey, blinded_sig: BlindedSignature) -> Signature {
258 let sig = blinded_sig.0 * blinding_key.0.invert().unwrap();
259 Signature(sig.to_affine())
260}
261
262pub fn verify(msg: Message, sig: Signature, pk: AggregatePublicKey) -> bool {
263 pairing(&msg.0, &pk.0) == pairing(&sig.0, &G2Affine::generator())
264}
265
266#[cfg(test)]
267mod tests;