Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/flyq/puzzle-gamma-ray


https://github.com/flyq/puzzle-gamma-ray

Last synced: 20 days ago
JSON representation

Awesome Lists containing this project

README

        

# puzzle-gamma-ray

**DO NOT FORK THE REPOSITORY, AS IT WILL MAKE YOUR SOLUTION PUBLIC. INSTEAD, CLONE IT AND ADD A NEW REMOTE TO A PRIVATE REPOSITORY, OR SUBMIT A GIST**

Trying it out
=============

Use `cargo run --release` to see it in action

Submitting a solution
=====================

[Submit a solution](https://xng1lsio92y.typeform.com/to/ca4f2sT0)

[Submit a write-up](https://xng1lsio92y.typeform.com/to/zH5sNzep)

Puzzle description
==================

|___ /| | / / | | | | | |
/ / | |/ / | |_| | __ _ ___| | __
/ / | \ | _ |/ _` |/ __| |/ /
./ /___| |\ \ | | | | (_| | (__| <
\_____/\_| \_/ \_| |_/\__,_|\___|_|\_\

Bob was deeply inspired by the Zcash design [1] for private transactions and had some pretty cool ideas on how to adapt it for his requirements. He was also inspired by the Mina design for the lightest blockchain and wanted to combine the two. In order to achieve that, Bob used the MNT6753 cycle of curves to enable efficient infinite recursion, and used elliptic curve public keys to authorize spends. He released a first version of the system to the world and Alice soon announced she was able to double spend by creating two different nullifiers for the same key...

[1] https://zips.z.cash/protocol/protocol.pdf

## writeup

### background

It is assumed that you already know about elliptic curve, such as its point addition, scalar multiplication, ECDLP, Generator, order. These [four articles](https://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle-introduction/) describe them in detail. There is a fact that, in affine space the graph of the elliptic curve $y^2= x^3 + ax +b$ is symmetrical about the $x$-axis. For a certain point $P_0(x_0,y_0)$ above, there must be a point $P_1(x_0,-y_0)$ on the curve. After $\mod q$, the points' $y$ below the $x$-axis will be added to $q$, so that the points of their elliptic curves are symmetrical about $y = \frac{q}{2}$. And in the definition of elliptic curve group, they are inverse elements of each other.

Here we introduce Cycles of curves. As an example, this is the parameter of Secp256k1: $y^2 \equiv x^3 + 7 \mod q$, where `q=0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F`, the generator is point G, the amount of elements is order, and `order=0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141`.
The Fields generated by `mod q` is the base field, related to (x,y), and by `mod order` is the scalar field, which is related to the coefficient of the point, such as $aG$. $a$ is in the scalar field.

In SNARK, the witness prover input is the element in the scalar field, and the proof after instantiation is the point $(x, y)$ related. In the recursive snark, we take the point $(x, y)$ as input and repeat the process, but it can be noted that $q$ is not equal `order`. At this time, we need to prepare two curves, and their `q` and `order` cross-equality. If you need a more detailed description, you can refer to [here](https://blog.icme.io/can-we-avoid-cycles-of-curves/)

When We look at the source code in `main.rs`, you can find that two curves are used: `ark_mnt4_753` and `ark_mnt6_753`. According to the description of [ark-mnt4-753](https://docs.rs/ark-mnt4-753/latest/ark_mnt4_753/):
> The main feature of this curve is that its scalar field and base field respectively equal the base field and scalar field of MNT6_753.

Then I noticed that this is a MerkleTree, which is widely used in existence proof scenarios, such as Tornado Cash. arkworks provides a [merkle-tree-example](https://github.com/arkworks-rs/r1cs-tutorial/tree/main/merkle-tree-example). If you have seen this example before, it will reduce your unfamiliarity.

In `SpendCircuit`, the only things we customize are `secret` and `nullifier`. So we need to pay attention to how they are handled when they are inside the MerkleTree: We look at the implementation of `generate_constraints()` in the `ConstraintSynthesizer` trait.
1. Evaluate the secret with Tree's paramaters. The result need be equal to the input nullifier. We do not need to know what operations are performed in the `evaluate`. If we can get the correct secret, we can get the correct value by printing `nullifier_in_circuit.value()`. If you want to figure out what evaluate does, you can check [code](https://github.com/arkworks-rs/crypto-primitives/blob/main/src/crh/poseidon/constraints.rs#L28-L54), It just hashes the secret.

```rs
let nullifier_in_circuit =
>::evaluate(&leaf_crh_params_var, &[secret])?;

nullifier_in_circuit.enforce_equal(&nullifier)?;
```
2. Get the generator point of `G1Affine` and multiply the secret to get a new point `pk`. Note that `G1Affine` is defined as the mnt6 curve in `ark-mnt6-753`.
```rs
let base = G1Var::new_constant(ark_relations::ns!(cs, "base"), G1Affine::generator())?;
let pk = base.scalar_mul_le(secret_bits.iter())?.to_affine()?;

# https://github.com/arkworks-rs/curves/blob/master/mnt6_753/src/curves/g1.rs#L9
pub type G1Affine = mnt6::G1Affine;
```

3. Check that `pk.x` is indeed on the leaf of the Tree.
```rs
// Allocate Leaf
let leaf_g: Vec<_> = vec![pk.x];

// Allocate Merkle Tree Path
let cw: PathVar =
PathVar::new_witness(ark_relations::ns!(cs, "new_witness"), || Ok(&self.proof))?;

cw.verify_membership(
&leaf_crh_params_var,
&two_to_one_crh_params_var,
&root,
&leaf_g,
)?
.enforce_equal(&Boolean::constant(true))?;
```

4. It is required to use different `nullifier`, and the hidden condition is to use different `secret`.
```rs
assert_ne!(nullifier, nullifier_hack);
```

Therefore, we can find the inverse element of the point corresponding to $secret$ under `mnt6`(because the Generator is `mnt6`), then convert it to `MNT4BigFr`, and then print out `nullifier`, then used it as `nullifier_hack`.
```rs
let zero_mnt6 = MNT6BigFr::from(0);
let leaked_secret_mnt6 = MNT6BigFr::from(leaked_secret.into_bigint());
let secret_hack_mnt6 = zero_mnt6 - leaked_secret_mnt6.clone();

let secret_hack = MNT4BigFr::from(secret_hack_mnt6.into_bigint());
let nullifier_hack = MNT4BigFr::from(BigInt([
3973337740569432013,
13414245347258487558,
2397428639358863969,
9003710485710992633,
7549792233030202438,
12021247171312009477,
10014790687727384398,
10719001394312000749,
12147986067925283906,
7048510174634313048,
13041399962513988848,
81761383246681,
]));
```