Assessment reports>Session Token>Medium findings>Incorrect curve mapping
Category: Coding Mistakes

Incorrect curve mapping

Medium Severity
Medium Impact
Low Likelihood

Description

In the original BLS signature paper, the authors construct a hash function called in order to hash a message to an arbitrary point of . This point is later used by the signature algorithms to create the signature. The function construction from the paper ensures that the security proof in the random oracle model holds. It is built such that the hash function is indistinguishable from a random hash function mapping a message to a point.

The function mapToG2 is implementing such algorithm in the code. However, the construction slightly differs from the original paper. Here is an implementation:

// hashes to G2 using the try and increment method
function mapToG2(uint256 h) internal view returns (G2Point memory) {
    // Define the G2Point coordinates
    uint256 x1 = h;
    uint256 x2 = 0;
    uint256 y1 = 0;
    uint256 y2 = 0;

    bool foundValidPoint = false;

    // Iterate until we find a valid G2 point
    while (!foundValidPoint) {
        // Try to get y^2
        (uint256 yx, uint256 yy) = Get_yy_coordinate(x1, x2);

        // Calculate square root
        (uint256 sqrt_x, uint256 sqrt_y) = FQ2Sqrt(yx, yy);

        // Check if this is a point
        if (sqrt_x != 0 && sqrt_y != 0) {
            y1 = sqrt_x;
            y2 = sqrt_y;
            if (IsOnCurve(x1, x2, y1, y2)) {
                foundValidPoint = true;
            } else {
                x1 += 1;
            }
        } else {
            // Increment x coordinate and try again.
            x1 += 1;
        }
    }

    return (G2Point([x2, x1], [y2, y1]));
}

Here, if the point does not exist on the curve, the value of is incremented by 1 until such point exists. It means that the values and will map to the same point on the curve if the function mapToG2 exits after one iteration for .

Here is a proof of concept demonstrating a collision between and :

from bn128_curve import b2
from bn128_field import FQ2, FQ

def mapToG2(h):
    has_root = False
    
    while not has_root:
        x = FQ2([h, 0])
        y = x**3 + b2
        t, has_root = y.sqrt()
        if has_root:
            return (x,t)
        h +=1

if __name__ == "__main__":
    print(mapToG2(3) == mapToG2(4))

This contradicts the initial paper requirements of such function since this is a construction of a collision for the function above.

There is another flaw in the above construction. The imaginary part of the x-coordinate of the resulting point is constant. It means that the function mapToG2 maps to a very small number of points, which is not uniform at all.

This problem is also present in the library mcl in the function tryAndIncMapTo.

Impact

In the library, the function is always applied on an input resulting from the keccak256 function. Thus, the practical exploitability of such behavior is not obvious. However, the BLS-signature security proof does not apply anymore with such construction.

Recommendations

The function mapToG2 should not deviate from the paper construction or be the implementation of a more recent construction as defined in the RFC 9380.

The previous behaviors should be implemented as unitary tests to avoid regression in the future.

Remediation

This issue has been acknowledged by Session team, and fixes were implemented in the following commits:

Zellic © 2024Back to top ↑