Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update hash_to_g2 in BLS #1398

Closed
wants to merge 15 commits into from
75 changes: 35 additions & 40 deletions specs/bls_signature.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

**Notice**: This document is a placeholder to facilitate the emergence of cross-client testnets. Substantive changes are postponed until [BLS standardisation](https://github.com/pairingwg/bls_standard) is finalized.

**Warning**: The constructions in this document should not be considered secure. In particular, the `hash_to_G2` function is known to be unsecure.

## Table of contents
<!-- TOC -->

Expand All @@ -14,8 +12,7 @@
- [G1 points](#g1-points)
- [G2 points](#g2-points)
- [Helpers](#helpers)
- [`hash_to_G2`](#hash_to_g2)
- [`modular_squareroot`](#modular_squareroot)
- [`hash_to_G2`](#hash_to_G2)
- [Aggregation operations](#aggregation-operations)
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
- [`bls_aggregate_signatures`](#bls_aggregate_signatures)
Expand All @@ -33,6 +30,18 @@ The BLS12-381 curve parameters are defined [here](https://z.cash/blog/new-snark-

We represent points in the groups G1 and G2 following [zkcrypto/pairing](https://github.com/zkcrypto/pairing/tree/master/src/bls12_381). We denote by `q` the field modulus and by `i` the imaginary unit.

## Ciphersuite
kirk-baird marked this conversation as resolved.
Show resolved Hide resolved

We use the following Ciphersuite `BLS_SIG_BLS12381G2-SHA256-SSWU-RO_POP_`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this ciphersuite only be used for the proof of possession (deposit_data.signature)?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the ciphersuite be BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_ (notice the extra - after RO-)?

Copy link
Contributor

@CarlBeek CarlBeek Nov 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, the IETF spec has a hash_to_point definition for messages of this ciphersuite which is distinct from hash_pubkey_to_point. My understanding is that if you use the PoP defined by the IETF spec, you should use BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_ or BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_NUL_ if their PoP is not used.

Considering that we do not use the exact PoP defined by the IETF spec, I think we should not claim to use the PoP ciphersuite anywhere.

Suggested change
We use the following Ciphersuite `BLS_SIG_BLS12381G2-SHA256-SSWU-RO_POP_`.
We use the following Ciphersuite `BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_NUL_`.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should just use one ciphersuite for both PoP and regular signature validation.
The extra - after RO- is deliberate as that's how the examples were given in the IETF spec.

I agree with Carl, if we don't use the specified PoP we should not use that in our ciphersuite tag. However, I then ask why do we not use that standardized PoP?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extra - after RO- is deliberate as that's how the examples were given in the IETF spec.

Right :) The extra - were missing and added them in.

why do we not use that standardized PoP?

What is the difference between the standardized PoP and the currently specified PoP?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question,
The standardize PoP signs the message:
msg = bytes(public_key)

Where as we sign the message:
msg = signing_root(deposit.data)
Which contains withdrawal_credentials and amount along with the public_key.

Copy link
Contributor

@CarlBeek CarlBeek Nov 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The standardize PoP signs the message:
msg = bytes(public_key)

Note that there is a specific domain separation tag just for signing pubkeys. (A third tag not mentioned here yet.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right sorry, I didn't notice the tag was slightly different between regular signatures and PoP.
PoP: BLS_POP_BLS12381G2-SHA256-SSWU-RO-_POP_
Regular Signature: BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_

With the option of changing the last _POP_ to _NUL_ if required.


Where:
* `POP` refers to proof of possession.
* `G2` refers to signatures on G2.
* `SHA256` is the hash function used.
* `SSWU` refers to the Simplified SWU Map from a finite field element to an elliptic curve point.
* `RO` refers to `hash-to-curve` function rather than `encode-to-curve`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could mention that "RO" stands for "random oracle"

* `BLS12381G2-SHA256-SSWU-RO` refers to the [hash to curve version 5](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-8.9.2) ciphersuite.

### G1 points

A point in G1 is represented as a 384-bit integer `z` decomposed as a 381-bit integer `x` and three 1-bit flags in the top bits:
Expand Down Expand Up @@ -67,46 +76,32 @@ We require:

### `hash_to_G2`

```python
G2_cofactor = 305502333931268344200999753193121504214466019254188142667664032982267604182971884026507427359259977847832272839041616661285803823378372096355777062779109
q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787

def hash_to_G2(message_hash: Bytes32, domain: Bytes8) -> Tuple[uint384, uint384]:
# Initial candidate x coordinate
x_re = int.from_bytes(hash(message_hash + domain + b'\x01'), 'big')
x_im = int.from_bytes(hash(message_hash + domain + b'\x02'), 'big')
x_coordinate = Fq2([x_re, x_im]) # x = x_re + i * x_im

# Test candidate y coordinates until a one is found
while 1:
y_coordinate_squared = x_coordinate ** 3 + Fq2([4, 4]) # The curve is y^2 = x^3 + 4(i + 1)
y_coordinate = modular_squareroot(y_coordinate_squared)
if y_coordinate is not None: # Check if quadratic residue found
return multiply_in_G2((x_coordinate, y_coordinate), G2_cofactor)
x_coordinate += Fq2([1, 0]) # Add 1 and try again
```
`hash_to_g2` is equivaent `hash_to_curve` found in the [BLS standard](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-3) with this interpretation reflecting draft version 5. We use the hash to curve ciphersuite `BLS12381G2-SHA256-SSWU-RO` found in section 8.9.2. It consists of three parts:

### `modular_squareroot`
* `hash_to_base` - Converting a message from bytes to a field point found in [section 5.3](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-5.3). The required constant parameters are:
* Field Degree: `m = 2`
* Length of HKDF: `L = 64`,
* Hash Function: `H = SHA256`,
* Domain Separation Tag: `DST = BLS_SIG_BLS12381G2-SHA256-SSWU-RO_POP_`.
* `map_to_curve` - Converting a field point to a point on the elliptic curve (G2 Point) in two steps:
* First apply a [Simplified SWU Map](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-6.6.3) to the [3-Isogney curve](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-8.9.2) `E'`.
* Second map the `E'` point to G2 using the `iso_map` detailed [here](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#appendix-C.3).
* `clear_cofactor` - Ensure the point is in the correct subfield by multiplying by the curve co-efficient `h_eff` as found [here](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-8.9.2).

`modular_squareroot(x)` returns a solution `y` to `y**2 % q == x`, and `None` if none exists. If there are two solutions, the one with higher imaginary component is favored; if both solutions have equal imaginary component, the one with higher real component is favored (note that this is equivalent to saying that the single solution with either imaginary component > p/2 or imaginary component zero and real component > p/2 is favored).

The following is a sample implementation; implementers are free to implement modular square roots as they wish. Note that `x2 = -x1` is an _additive modular inverse_ so real and imaginary coefficients remain in `[0 .. q-1]`. `coerce_to_int(element: Fq) -> int` is a function that takes Fq element `element` (i.e. integers `mod q`) and converts it to a regular integer.
Details of the `hash_to_curve` function are shown below.

```python
Fq2_order = q ** 2 - 1
eighth_roots_of_unity = [Fq2([1,1]) ** ((Fq2_order * k) // 8) for k in range(8)]

def modular_squareroot(value: Fq2) -> Fq2:
candidate_squareroot = value ** ((Fq2_order + 8) // 16)
check = candidate_squareroot ** 2 / value
if check in eighth_roots_of_unity[::2]:
x1 = candidate_squareroot / eighth_roots_of_unity[eighth_roots_of_unity.index(check) // 2]
x2 = -x1
x1_re, x1_im = coerce_to_int(x1.coeffs[0]), coerce_to_int(x1.coeffs[1])
x2_re, x2_im = coerce_to_int(x2.coeffs[0]), coerce_to_int(x2.coeffs[1])
return x1 if (x1_im > x2_im or (x1_im == x2_im and x1_re > x2_re)) else x2
return None
```
def hash_to_G2(alpha: Bytes) -> Tuple[uint384, uint384]:
u0 = hash_to_base(alpha, 0)
u1 = hash_to_base(alpha, 1)
Q0 = map_to_curve(u0)
Q1 = map_to_curve(u1)
R = Q0 + Q1 # Point Addition
P = clear_cofactor(R)
return P
```

An implementation of `hash_to_curve` can be found [here](https://github.com/kwantam/bls_sigs_ref/blob/93b58f3e9f9ef55085f9ad78c708fa5ad9b894df/python-impl/opt_swu_g2.py#L131).

## Aggregation operations

Expand Down