Troubles with Fq::pow
mmaker opened this issue · comments
Hello!
I'm trying to get Fq::pow
to work, but it seems I can't get it right… is this me or is it really a bug?
This is what I can get to do with sage:
sage: def h(x): return hex(int(x))[:-1] # this is only to get a confrontable hex representation
sage: q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787
sage: Fq = GF(q)
sage: h(q)
'0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
sage: a = Fq(945268695322731484897977891916087812827587793626675745004848628347665446205888379878456193299686130571287070888667)
sage: h(a)
'0x6243b9d40ce4d8c1d86a603d9ce33eb76736fc8900b1e8da6de01cbdb27177539b472f83366efa4ed5bf6438391d2db'
sage: a**9
1183374762412757565163659156070127511863449313069977006820839763739586492957873774713939591053070945417445562515423
sage: h(a**9)
'0x7b04438ade27f8f2b916ebad4ad86d3941f87b5bbb022113edcf19384b6892c9e5fa522f8d60ab97d5c4ef522adffdf'
but if I attempt to add the following test case to fq.rs
:
#[test]
fn test_pow_bug() {
let e = Fq(FqRepr([0xd5bf6438391d2db, 0x9b472f83366efa4e, 0x6de01cbdb2717753,
0x6736fc8900b1e8da, 0xd86a603d9ce33eb7, 0x6243b9d40ce4d8c1]));
let expected = Fq(FqRepr([0xd5c4ef522adffdf, 0xe5fa522f8d60ab97, 0xedcf19384b6892c9,
0x41f87b5bbb022113, 0xb916ebad4ad86d39, 0x7b04438ade27f8f2]));
let got = e.pow([0x9, 0x0, 0x0, 0x0, 0x0, 0x0]);
assert_eq!(got, expected)
the test fails:
---- bls12_381::fq::test_pow_bug stdout ----
thread 'bls12_381::fq::test_pow_bug' panicked at 'assertion failed: `(left == right)`
left: `Fq(FqRepr([15168336788228049517, 6104148727050941414, 11744620724444176788, 291052430401786830, 12974234119515072997, 720310162563104718]))`,
right: `Fq(FqRepr([962731235106226143, 16571648143052024727, 17135942836742034121, 4753685040599277843, 13337106476021869881, 8864284230283688178]))`', src/bls12_381/fq.rs:1817:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.
am I doing something wrong here?
There are two methods on Fq
that you need to know about: from_repr
which converts FqRepr
into Fq
elements, and from_str
which converts a string into an Fq
element.
Here's an example of from_str
:
#[test]
fn just_testin() {
assert_eq!(
Fq::from_str(
"1441654611304870083771668378362836059635368675687187728493436807246216518445765908198826216213302212825486491541923"
).unwrap().pow(&[9]),
Fq::from_str(
"2674805500308639681231231679735001911124329544452377898820909721146641766910845335783537874195940953433390291734292"
).unwrap()
);
}
This is a quick-and-dirty python function for converting integers into the correct little-endian order for FqRepr
:
def h(a):
return hex(a % (2**64)) + ", " + hex((a >> 64) % (2**64)) + ", " + hex((a >> 128) % (2**64)) + ", " + hex((a >> 192) % (2**64))
However, it is (deliberately) not possible outside the library to construct Fq
elements like you're doing here:
let e = Fq(FqRepr([0xd5bf6438391d2db, 0x9b472f83366efa4e, 0x6de01cbdb2717753,
0x6736fc8900b1e8da, 0xd86a603d9ce33eb7, 0x6243b9d40ce4d8c1]));
You need to use from_repr
on Fq
to do it, both because it could fail (when the representation is not in the field) and especially because the Fq
element is internally represented in Montgomery form and needs to be converted into this form at runtime.
oh, neat, thanks a lot for the expensive explaination!
To set the record straight, I'm now using
def h(a): return ', '.join(hex((a >> (64*x)) % (2**64)) for x in range(6))
to do the job (obv. multiplying by R
before to have it in Montgomery form, as you pointed out).