miracl / core

MIRACL Core
Apache License 2.0
199 stars 68 forks source link

Rust: incorrect normalization for 1*1 in FP12. #29

Closed blynn closed 3 years ago

blynn commented 3 years ago

Computing 1*1 in FP12 results in something that tests equal to 1, but is incorrectly normalized.

extern crate core;
use core::bls12381::fp12::FP12;

fn main() {
    let mut x = FP12::new();
    x.one();
    println!("x: {}", x.tostring());

    let mut y = FP12::new();
    y.one();
    y.mul(&x);
    println!("y: {}", y.tostring());

    // Returns true, as expected.
    println!("{}", y.equals(&x));

    // Should return true, but returns false.
    println!("{}", y.tostring() == x.tostring());
}

Output:

x: [[[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000],[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]],[[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000],[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]],[[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000],[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]]]
y: [[[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB],[1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB,1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB]],[[1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB,1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB],[1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB,1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB]],[[1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB,1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB],[1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB,1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB]]]
true
false
mcarrickscott commented 3 years ago

Not sure this is a problem. That 1A01111...AAB is the modulus p. The library uses lazy reduction, and field elements need to be fully reduced wrt the modulus before being compared. After reduction the 1A01111...AAB becomes 0 mod p. The fact that it happens in such a simple case is I suspect an artifact that arises from Montgomery reduction, where here we lazily do not perform the "final subtraction".

blynn commented 3 years ago

Thanks! So it's not a normalization problem at all and I should call reduce() before serialization if I want the element in a canonical form (just as equals() does internally).

For the applications I have in mind, I'd prefer if tobytes() and tostring() always called reduce() implicitly, but I suppose there may be some applications where the existing behaviour is better.