supranational / blst

Multilingual BLS12-381 signature library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

blst_scalar_fr_check and bad bytes

belijzajac opened this issue · comments

First of all, thanks for the fantastic library!

I like how blst_p1_in_g1 and blst_p1_on_curve work with the blst_p1 type, so I decided to create method wrappers that check if a point is a valid G1 and Fr point. However, I encountered an issue with Fr points:

use blst::{
    blst_fr, blst_fr_from_scalar, blst_scalar, blst_scalar_fr_check, blst_scalar_from_fr,
    blst_scalar_from_lendian,
};

fn main() {
    let bad_bytes: [u8; 32] = [
        1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216,
        57, 51, 72, 125, 157, 41, 83, 167, 237, 115,
    ];

    let mut fr = blst_fr::default();
    unsafe {
        let mut scalar = blst_scalar::default();
        blst_scalar_from_lendian(&mut scalar, bad_bytes.as_ptr()); // good, `scalar.b` matches the content of `bad_bytes`
        assert_eq!(blst_scalar_fr_check(&scalar), false); // good, bad bytes should fail the validation
        blst_fr_from_scalar(&mut fr, &scalar); // uh oh, `fr.l` became [0, 0, 0, 0] ???
    }

    let retrieved_bytes: [u8; 32] = unsafe {
        let mut scalar = blst_scalar::default();
        blst_scalar_from_fr(&mut scalar, &fr);
        scalar.b
    };

    // fails, but we still want to check if the `retrieved_bytes` is correct using the above routine
    assert_eq!(bad_bytes, retrieved_bytes);
}

I'd like to ask, is there an alternative way to accomplish what I want?

I don't understand what's the issue.

Is it that instead of "undefined behavior", an invalid scalar leads to a zeroed-out output?

Side-note: blst_scalar are secret keys and should not be compared lest you leak it.

Is it that instead of "undefined behavior", an invalid scalar leads to a zeroed-out output?

Yes. I wanted to do validations on Fr points inside methods that take these points as inputs. I thought that maybe a user could potentially overflow this value, resulting in it being zeroed-out, instead of having an invalid value that I could check for its validity.

a user could potentially overflow this value,

If the user treats blst objects as opaque (which is expected) and sticks to the interface (which is expected), no overflows would occur. Well, even if it did, since the objects are not supposed to be looked into, you wouldn't be able to tell the difference since the result would still be modulo correct.

If the question is how come "bad" scalar turned to zero, then the answer is actually above. Conversion to Fr internal representation implies modulo reduction and the suggested value is zero modulo the EC group order. And zero is actually a legitimate element of the Fr field, one can't say that it's "bad." What one doesn't want to see is zero for the secret key or zero appearing in operations with secrets. But this is because it voids security properties, not because zero is an illegitimate element of the Fr field.