1use bls12_381::{pairing, G1Affine, G2Affine, G2Projective, Gt, Scalar};
7use ff::Field;
8use rand::prelude::*;
9use std::iter::zip;
10use std::ops::{Add, Mul};
11
12pub struct Values<const N: usize> {
13 values: [G2Affine; N],
14}
15
16impl<const N: usize> Values<N> {
17 pub fn new(values: [G2Affine; N]) -> Self {
18 Values { values }
19 }
20
21 #[cfg(test)]
22 pub(crate) fn random() -> Self {
23 use group::Group;
24
25 let mut values = Vec::with_capacity(N);
26 for _ in 0..N {
27 values.push(G2Affine::from(G2Projective::random(thread_rng())));
28 }
29 Values {
30 values: values.try_into().unwrap(),
31 }
32 }
33
34 pub fn from_bytes(_bytes: &[u8]) -> Self {
35 todo!("implement converting to and from bytes")
36 }
37
38 pub fn to_bytes(&self) -> Vec<u8> {
39 todo!("implement converting to and from bytes")
40 }
41}
42
43#[allow(clippy::suspicious_arithmetic_impl)]
44impl<const N: usize> Mul for &Values<N> {
45 type Output = Values<N>;
46
47 fn mul(self, rhs: Self) -> Self::Output {
48 let mut values = Vec::with_capacity(N);
49 for i in 0..N {
50 let v = G2Affine::from(self.values[i] + G2Projective::from(rhs.values[i]));
51 values.push(v);
52 }
53 Values {
54 values: values.try_into().unwrap(),
55 }
56 }
57}
58
59pub struct Randomness {
60 r: G2Affine,
61 s: G2Affine,
62}
63
64impl Randomness {
65 pub fn gen(rng: &mut impl RngCore) -> Self {
66 let g = G2Affine::generator();
67 let r = gen_g2_elem(rng, g);
68 let s = gen_g2_elem(rng, g);
69 Randomness { r, s }
70 }
71}
72
73impl Mul for &Randomness {
74 type Output = Randomness;
75
76 fn mul(self, rhs: Self) -> Self::Output {
77 let r = self.r.add(&G2Projective::from(rhs.r)).into();
78 let s = self.s.add(&G2Projective::from(rhs.s)).into();
79 Randomness { r, s }
80 }
81}
82
83#[derive(Debug, PartialEq)]
84pub struct Commitment {
85 c: Gt,
86 d: Gt,
87}
88
89impl Mul for &Commitment {
90 type Output = Commitment;
91
92 fn mul(self, rhs: &Commitment) -> Self::Output {
93 let c = self.c.add(rhs.c);
94 let d = self.d.add(rhs.d);
95 Commitment { c, d }
96 }
97}
98
99pub struct CommitmentKey<const N: usize> {
100 g_arr: [G1Affine; N],
101 h_arr: [G1Affine; N],
102 gr: G1Affine,
103 hr: G1Affine,
104 gs: G1Affine,
105 hs: G1Affine,
106}
107
108impl<const N: usize> CommitmentKey<N> {
109 pub fn generate() -> CommitmentKey<N> {
110 let mut rng = thread_rng();
111 let g = G1Affine::generator();
112
113 let mut g_vec = Vec::with_capacity(N);
114 let mut h_vec = Vec::with_capacity(N);
115 for _ in 0..N {
116 g_vec.push(gen_g1_elem(&mut rng, g));
117 h_vec.push(gen_g1_elem(&mut rng, g));
118 }
119 let g_arr = g_vec.try_into().unwrap();
120 let h_arr = h_vec.try_into().unwrap();
121
122 let gr = gen_g1_elem(&mut rng, g);
123 let hr = gen_g1_elem(&mut rng, g);
124
125 let gs = gen_g1_elem(&mut rng, g);
126 let hs = gen_g1_elem(&mut rng, g);
127
128 CommitmentKey {
129 g_arr,
130 h_arr,
131 gr,
132 hr,
133 gs,
134 hs,
135 }
136 }
137
138 pub fn commit_with_randomness(&self, value: &Values<N>, randomness: &Randomness) -> Commitment {
139 let mut c = pairing(&self.gr, &randomness.r) + pairing(&self.gs, &randomness.s);
140 for (g, v) in zip(&self.g_arr, &value.values) {
141 c += pairing(g, v)
142 }
143
144 let mut d = pairing(&self.hr, &randomness.r) + pairing(&self.hs, &randomness.s);
145 for (h, v) in zip(&self.h_arr, &value.values) {
146 d += pairing(h, v)
147 }
148
149 Commitment { c, d }
150 }
151
152 pub fn commit(&self, value: &Values<N>) -> (Commitment, Randomness) {
153 let randomness = Randomness::gen(&mut thread_rng());
154 let commitment = Self::commit_with_randomness(self, value, &randomness);
155 (commitment, randomness)
156 }
157}
158
159fn gen_g1_elem(rng: &mut impl RngCore, generator: G1Affine) -> G1Affine {
160 let r = Scalar::random(rng);
161 (generator * r).into()
162}
163
164fn gen_g2_elem(rng: &mut impl RngCore, generator: G2Affine) -> G2Affine {
165 let r = Scalar::random(rng);
166 (generator * r).into()
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172
173 #[test]
174 fn it_works() {
175 let ck = CommitmentKey::<10>::generate();
176 let value = Values::random();
177 let (c, r) = ck.commit(&value);
178 let d = ck.commit_with_randomness(&value, &r);
179 assert_eq!(c, d);
180 }
181
182 #[test]
183 fn multiplicatively_homomorphic() {
184 let ck = CommitmentKey::<1>::generate();
185
186 let v1 = Values::random();
187 let (c1, r1) = ck.commit(&v1);
188
189 let v2 = Values::random();
190 let (c2, r2) = ck.commit(&v2);
191
192 let v_mul = &v1 * &v2;
193 let r_mul = &r1 * &r2;
194 let expected = ck.commit_with_randomness(&v_mul, &r_mul);
195
196 let actual = c1.mul(&c2);
197
198 assert_eq!(actual, expected);
199 }
200}