Skip to content

Instantly share code, notes, and snippets.

@obeliskgolem
Last active December 6, 2021 14:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save obeliskgolem/cdc79d50e6d55180b647a4353055e72d to your computer and use it in GitHub Desktop.
Save obeliskgolem/cdc79d50e6d55180b647a4353055e72d to your computer and use it in GitHub Desktop.
Another way to solve `zkhack-soundness-of-music`
Just noticed that in the verifier program, there are no checks against the commited points.
especially the pairing that checks P == H*Z:
```
let d = E::pairing(
(pk + proof.pi_input) + (pk + proof.pi_input) + proof.pi_output.mul(-E::Fr::one()).into(),
E::G2Affine::prime_subgroup_generator(),
) == E::pairing(proof.pi_H, setup.rho_Z);
```
We can make use of this. Let's construct H = 0, in which case P will also be 0.
In order to make P = 0, we just need to make sure the private inputs exactly cancel out the public inputs.
P = 2 * \rho * (IP_1(\tau) * x + IP_2(\tau) * y + IP_3(\tau) * z) - \rho * (OP_1(\tau) * x + OP_2(\tau) * y + OP_3(\tau) * z)
Let the second part equals zero, we get pi_output == pi_output_prime = [0] on G1
then we set pi_input = [- (IP_1(\tau) * x + IP_2(\tau) * y)] on G1, so `pk + pi_input` equals the point at infinity.
(well, actually in order to pass the proof of knowledge check, we can't just set `pi_input` like that. but, we can just fake public inputs, that's even easier.)
That's it!
Here is the prover code which generates a fake proof.
```
pub fn prove_alter<E: PairingEngine>(
public_inputs: &[E::Fr],
private_inputs_len: usize,
setup: &Setup<E>,
) -> Proof<E> {
let mut fake_pub_inputs = vec![];
let mut fake_pri_inputs = vec![];
for i in 0..public_inputs.len() {
fake_pub_inputs.push(public_inputs[i].neg());
}
for _ in 0..private_inputs_len {
fake_pri_inputs.push(E::Fr::zero());
}
let mut private_input_polynomials = E::G1Projective::zero();
let mut private_input_polynomials_prime = E::G1Projective::zero();
for (private_input, private_input_polynomial, private_input_polynomial_prime) in izip!(
fake_pub_inputs.iter().chain(fake_pri_inputs.iter()),
setup.inputs.iter(),
setup.inputs_prime.iter()
) {
private_input_polynomials += private_input_polynomial.mul(*private_input);
private_input_polynomials_prime += private_input_polynomial_prime.mul(*private_input);
}
Proof::<E> {
pi_input: private_input_polynomials.into(),
pi_input_prime: private_input_polynomials_prime.into(),
pi_output: E::G1Affine::zero(),
pi_output_prime: E::G1Affine::zero(),
pi_K: E::G1Affine::zero(),
pi_H: E::G1Affine::zero(),
}
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment