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