1use super::*;
17
18impl<E: Environment, const NUM_BITS: u8> CommitUncompressed for Pedersen<E, NUM_BITS> {
19 type Input = Boolean<E>;
20 type Output = Group<E>;
21 type Randomizer = Scalar<E>;
22
23 fn commit_uncompressed(&self, input: &[Self::Input], randomizer: &Self::Randomizer) -> Self::Output {
25 let hash = self.hash_uncompressed(input);
26
27 randomizer
29 .to_bits_le()
30 .iter()
31 .zip_eq(&self.random_base)
32 .map(|(bit, power)| Group::ternary(bit, power, &Group::zero()))
33 .fold(hash, |acc, x| acc + x)
34 }
35}
36
37impl<E: Environment, const NUM_BITS: u8>
38 Metrics<dyn CommitUncompressed<Input = Boolean<E>, Output = Group<E>, Randomizer = Scalar<E>>>
39 for Pedersen<E, NUM_BITS>
40{
41 type Case = (Vec<Mode>, Vec<Mode>);
42
43 fn count(case: &Self::Case) -> Count {
44 let (input_modes, randomizer_modes) = case;
45 let uncompressed_count =
46 count!(Pedersen<E, NUM_BITS>, HashUncompressed<Input = Boolean<E>, Output = Group<E>>, input_modes);
47 let uncompressed_mode =
48 output_mode!(Pedersen<E, NUM_BITS>, HashUncompressed<Input = Boolean<E>, Output = Group<E>>, input_modes);
49
50 let group_initialize_count = randomizer_modes
52 .iter()
53 .map(|mode| {
54 count!(
55 Group<E>,
56 Ternary<Boolean = Boolean<E>, Output = Group<E>>,
57 &(*mode, Mode::Constant, Mode::Constant)
58 )
59 })
60 .fold(Count::zero(), |cumulative, count| cumulative + count);
61
62 let randomizer_to_bits_count =
64 match Mode::combine(randomizer_modes[0], randomizer_modes.iter().copied()).is_constant() {
65 true => Count::is(251, 0, 0, 0),
66 false => Count::is(0, 0, 501, 503),
67 };
68
69 let modes = randomizer_modes.iter().map(|mode| {
71 match mode.is_constant() {
74 true => Mode::Constant,
75 false => Mode::Private,
76 }
77 });
78
79 let (_, summation_count) =
81 modes.fold((uncompressed_mode, Count::zero()), |(prev_mode, cumulative), curr_mode| {
82 let mode = output_mode!(Group<E>, Add<Group<E>, Output = Group<E>>, &(prev_mode, curr_mode));
83 let sum_count = count!(Group<E>, Add<Group<E>, Output = Group<E>>, &(prev_mode, curr_mode));
84 (mode, cumulative + sum_count)
85 });
86
87 uncompressed_count + group_initialize_count + randomizer_to_bits_count + summation_count
89 }
90}
91
92impl<E: Environment, const NUM_BITS: u8>
93 OutputMode<dyn CommitUncompressed<Input = Boolean<E>, Output = Group<E>, Randomizer = Scalar<E>>>
94 for Pedersen<E, NUM_BITS>
95{
96 type Case = (Vec<Mode>, Vec<Mode>);
97
98 fn output_mode(parameters: &Self::Case) -> Mode {
99 let (input_modes, randomizer_modes) = parameters;
100 match input_modes.iter().all(|m| *m == Mode::Constant) && randomizer_modes.iter().all(|m| *m == Mode::Constant)
101 {
102 true => Mode::Constant,
103 false => Mode::Private,
104 }
105 }
106}
107
108#[cfg(all(test, feature = "console"))]
109mod tests {
110 use super::*;
111 use snarkvm_circuit_types::environment::Circuit;
112 use snarkvm_utilities::{TestRng, Uniform};
113
114 const ITERATIONS: u64 = 10;
115 const MESSAGE: &str = "PedersenCircuit0";
116 const NUM_BITS_MULTIPLIER: u8 = 8;
117
118 fn check_commit_uncompressed<const NUM_BITS: u8>(mode: Mode, rng: &mut TestRng) {
119 use console::CommitUncompressed as C;
120
121 let native = console::Pedersen::<<Circuit as Environment>::Network, NUM_BITS>::setup(MESSAGE);
123 let circuit = Pedersen::<Circuit, NUM_BITS>::constant(native.clone());
124
125 for i in 0..ITERATIONS {
126 let input = (0..NUM_BITS).map(|_| bool::rand(rng)).collect::<Vec<bool>>();
128 let randomizer = Uniform::rand(rng);
130 let expected = native.commit_uncompressed(&input, &randomizer).expect("Failed to commit native input");
132 let circuit_input: Vec<Boolean<_>> = Inject::new(mode, input);
134 let circuit_randomizer: Scalar<_> = Inject::new(mode, randomizer);
136
137 Circuit::scope(format!("Pedersen {mode} {i}"), || {
138 let candidate = circuit.commit_uncompressed(&circuit_input, &circuit_randomizer);
140 assert_eq!(expected, candidate.eject_value());
141
142 let input_modes = circuit_input.iter().map(|b| b.eject_mode()).collect::<Vec<_>>();
144 let randomizer_modes =
145 circuit_randomizer.to_bits_le().iter().map(|b| b.eject_mode()).collect::<Vec<_>>();
146 assert_count!(
147 Pedersen<Circuit, NUM_BITS>,
148 CommitUncompressed<Input = Boolean<Circuit>, Output = Group<Circuit>, Randomizer = Scalar<Circuit>>,
149 &(input_modes.clone(), randomizer_modes.clone())
150 );
151 assert_output_mode!(
152 Pedersen<Circuit, NUM_BITS>,
153 CommitUncompressed<Input = Boolean<Circuit>, Output = Group<Circuit>, Randomizer = Scalar<Circuit>>,
154 &(input_modes, randomizer_modes),
155 candidate
156 );
157 });
158 }
159 }
160
161 fn check_homomorphic_addition<C: Display + Eject + Add<Output = C> + ToBits<Boolean = Boolean<Circuit>>>(
162 pedersen: &impl CommitUncompressed<Input = Boolean<Circuit>, Randomizer = Scalar<Circuit>, Output = Group<Circuit>>,
163 first: C,
164 second: C,
165 rng: &mut TestRng,
166 ) {
167 println!("Checking homomorphic addition on {first} + {second}");
168
169 let first_randomizer: Scalar<_> = Inject::new(Mode::Private, Uniform::rand(rng));
171 let second_randomizer: Scalar<_> = Inject::new(Mode::Private, Uniform::rand(rng));
172
173 let a = pedersen.commit_uncompressed(&first.to_bits_le(), &first_randomizer);
175 let b = pedersen.commit_uncompressed(&second.to_bits_le(), &second_randomizer);
176 let expected = a + b;
177
178 let combined_randomizer = first_randomizer + second_randomizer;
179
180 let candidate = pedersen.commit_uncompressed(&(first + second).to_bits_le(), &combined_randomizer);
182 assert_eq!(expected.eject(), candidate.eject());
183 assert!(Circuit::is_satisfied());
184 }
185
186 #[test]
187 fn test_commit_uncompressed_constant() {
188 let mut rng = TestRng::default();
190 check_commit_uncompressed::<NUM_BITS_MULTIPLIER>(Mode::Constant, &mut rng);
191 check_commit_uncompressed::<{ 2 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
192 check_commit_uncompressed::<{ 3 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
193 check_commit_uncompressed::<{ 4 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
194 check_commit_uncompressed::<{ 5 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
195 }
196
197 #[test]
198 fn test_commit_uncompressed_public() {
199 let mut rng = TestRng::default();
201 check_commit_uncompressed::<NUM_BITS_MULTIPLIER>(Mode::Public, &mut rng);
202 check_commit_uncompressed::<{ 2 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
203 check_commit_uncompressed::<{ 3 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
204 check_commit_uncompressed::<{ 4 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
205 check_commit_uncompressed::<{ 5 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
206 }
207
208 #[test]
209 fn test_commit_uncompressed_private() {
210 let mut rng = TestRng::default();
212 check_commit_uncompressed::<NUM_BITS_MULTIPLIER>(Mode::Private, &mut rng);
213 check_commit_uncompressed::<{ 2 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
214 check_commit_uncompressed::<{ 3 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
215 check_commit_uncompressed::<{ 4 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
216 check_commit_uncompressed::<{ 5 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
217 }
218
219 #[test]
220 fn test_pedersen64_homomorphism_private() {
221 let pedersen = Pedersen64::constant(console::Pedersen64::setup("Pedersen64HomomorphismTest"));
223
224 let mut rng = TestRng::default();
225
226 for _ in 0..ITERATIONS {
227 let first = U8::<Circuit>::new(Mode::Private, console::U8::new(u8::rand(&mut rng) >> 1));
229 let second = U8::new(Mode::Private, console::U8::new(u8::rand(&mut rng) >> 1));
230 check_homomorphic_addition(&pedersen, first, second, &mut rng);
231
232 let first = U16::<Circuit>::new(Mode::Private, console::U16::new(u16::rand(&mut rng) >> 1));
234 let second = U16::new(Mode::Private, console::U16::new(u16::rand(&mut rng) >> 1));
235 check_homomorphic_addition(&pedersen, first, second, &mut rng);
236
237 let first = U32::<Circuit>::new(Mode::Private, console::U32::new(u32::rand(&mut rng) >> 1));
239 let second = U32::new(Mode::Private, console::U32::new(u32::rand(&mut rng) >> 1));
240 check_homomorphic_addition(&pedersen, first, second, &mut rng);
241
242 let first = U64::<Circuit>::new(Mode::Private, console::U64::new(u64::rand(&mut rng) >> 1));
244 let second = U64::new(Mode::Private, console::U64::new(u64::rand(&mut rng) >> 1));
245 check_homomorphic_addition(&pedersen, first, second, &mut rng);
246 }
247 }
248
249 #[test]
250 fn test_pedersen_homomorphism_private() {
251 fn check_pedersen_homomorphism(
252 pedersen: &impl CommitUncompressed<
253 Input = Boolean<Circuit>,
254 Randomizer = Scalar<Circuit>,
255 Output = Group<Circuit>,
256 >,
257 ) {
258 let mut rng = TestRng::default();
259
260 for _ in 0..ITERATIONS {
261 let first = U8::<Circuit>::new(Mode::Private, console::U8::new(u8::rand(&mut rng) >> 1));
263 let second = U8::new(Mode::Private, console::U8::new(u8::rand(&mut rng) >> 1));
264 check_homomorphic_addition(pedersen, first, second, &mut rng);
265
266 let first = U16::<Circuit>::new(Mode::Private, console::U16::new(u16::rand(&mut rng) >> 1));
268 let second = U16::new(Mode::Private, console::U16::new(u16::rand(&mut rng) >> 1));
269 check_homomorphic_addition(pedersen, first, second, &mut rng);
270
271 let first = U32::<Circuit>::new(Mode::Private, console::U32::new(u32::rand(&mut rng) >> 1));
273 let second = U32::new(Mode::Private, console::U32::new(u32::rand(&mut rng) >> 1));
274 check_homomorphic_addition(pedersen, first, second, &mut rng);
275
276 let first = U64::<Circuit>::new(Mode::Private, console::U64::new(u64::rand(&mut rng) >> 1));
278 let second = U64::new(Mode::Private, console::U64::new(u64::rand(&mut rng) >> 1));
279 check_homomorphic_addition(pedersen, first, second, &mut rng);
280
281 let first = U128::<Circuit>::new(Mode::Private, console::U128::new(u128::rand(&mut rng) >> 1));
283 let second = U128::new(Mode::Private, console::U128::new(u128::rand(&mut rng) >> 1));
284 check_homomorphic_addition(pedersen, first, second, &mut rng);
285 }
286 }
287
288 let pedersen128 = Pedersen128::constant(console::Pedersen128::setup("Pedersen128HomomorphismTest"));
290 check_pedersen_homomorphism(&pedersen128);
291 }
292}