blst_scalar_fr_check and bad bytes
belijzajac opened this issue · 3 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.