Skip to content

Instantly share code, notes, and snippets.

@sylvainpelissier
Last active January 24, 2024 14:35
Show Gist options
  • Save sylvainpelissier/ca8420dc1c77417e3090e6f75962641c to your computer and use it in GitHub Desktop.
Save sylvainpelissier/ca8420dc1c77417e3090e6f75962641c to your computer and use it in GitHub Desktop.
puzzle-supervillain solution

Supervillain

BLS Multi-Signatures

The scheme is using a BLS Multi-Signatures With Public-Key Aggregation. It uses $n$ private keys $x_i$ with their corresponding public keys $Q_i = x_i \cdot G$. The scheme signs a single message $m$.

While debugging the code I noticed that the code uses 9 existing public keys.

debug

To solve the puzzle we are requested to create an additional public key with index 9.

The aggregate public key is computed as the sum of all the public keys $Q = Q_0 + \ldots + Q_9$. To sign a message, each participants compute $\sigma_i = x_i\cdot H(m)$. Where $H$ is a hash function mapping a message to a point on the curve. Then the aggregate signature should be computed as the sum of all the signatures: $\sigma = \sum_{i=0} \sigma_i$

To verify the signature the following equality is checked: $$e(Q,-H(m)) + e(G, \sigma) \stackrel{?}{=} 0$$

The signature is considered as valid if the equality holds. A common pitfall of such implementation is that a malicious participant can choose their public key to be $\tilde{Q}{9} = Q_9 - \sum{i=0}^8 Q_i$. This attack is called a rogue public-key attack. Then the attacker can claim that the other participant signed a message $m$ for the signature $\sigma = x_9\cdot H(m)$ even thought it was sign only by the attacker since:

$$ \begin{align*} e(Q,-H(m)) + e(G, \sigma) &=& e(Q_9 - \sum_{i=0}^8 Q_i + \sum_{i=0}^8 Q_i ,-H(m)) + e(G, \sigma) \\ &=& e(Q_9, -H(m)) + e(G, x_9\cdot H(m)) \\ &=& e(x_9 \cdot G, -H(m)) + e(G, x_9\cdot H(m)) \\ &=& 0 \end{align*}$$

The verification pass. One way to prevent such attacks is to use a Proofs-of-Possession. This variant of this mechanism is implemented in the code and prevent applying directly the attack.

Proofs-of-Possession

In the code, for a user $i$ (encoded on a usize variable), the proof of possession (POP) $\Pi_i$ uses a point $R$ on the same curve and is computed such that $\Pi_i = (i+1) \cdot x_i \cdot R$. The main difference here with the previous paper is that in the paper the POP is computed such that:

$\Pi_i = H(<Q_i>) \cdot x_i \cdot R$

The verification of the POP is a standard BLS verification: $e(Q_i, -(i+1) \cdot R) + e(G, \Pi_i) \stackrel{?}{=} 0$

Bypass of the POP

Since the modified POP is linear, it is possible to forge a new POP for $i=10$ from the previous ones. We want to forge a proof $\Pi_{\mathrm{rogue}}$ for the previous rogue public key $\tilde{Q}_{9}$

$$ \begin{align*} \Pi_{\mathrm{rogue}} &=& 10 (x_9 - \sum_{i=0}^8 x_i) \cdot R \\ &=& 10 x_9 \cdot R - 10 x_0 \cdot R- 10 x_1 \cdot R - \ldots \end{align*} $$

Since we already know the values $\Pi_0 = x_0 \cdot R, \Pi_1 = 2x_1 \cdot R, \Pi_2 = 3x_2 \cdot R, \ldots$ from the previous POPs we can compute $\Pi_{\mathrm{rogue}} = 10 x_9 \cdot R - 10\sum (i+1)^{-1} \Pi_i$ and it will pass the POP verification. The public key is not check to be the point to infinity thus we can even simplify the solution by using $x_9 = 0$. In this case $\tilde{Q}{9} = -\sum{i=0}^8 Q_i$ and the signature will be zero for any message. The corresponding Rust code to build the rogue proof is:

/* Rogue proof */
let one: Fr = MontFp!("1");
let mut index: Fr = one;
for n in 0..public_keys.len() {
    let tmp = index.inverse().unwrap();
    new_proof = new_proof.add(public_keys[n].1.mul(tmp));
    index = index + one;
}
let ten: Fr = MontFp!("10");
let new_proof = (new_proof.neg() * ten).into_affine();

Finally we can compute the rogue public key and the signature in Rust:

/* Rogue public key */
for n in 0..public_keys.len() {
    new_key = new_key.add(public_keys[n].0);
}
let new_key = new_key.neg().into_affine();

/* Signature */
let aggregate_signature = G2Affine::zero();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment