We found another thread-safety issue with Kilic, described here. In short, it seems that if MulG1 is called concurrently, the two contexts will interact and give an incorrect results.
The following test exposes the problem: 10 threads are running concurrently, each performing a simple EC point multiplication with MulG1, and the result will be sent over a channel. The results are compared with a value calculated in a serial execution context, and they differ (see the failed CI build).
func TestConcurrentMulG1(t *testing.T) {
var fr bls.Fr
bls.AsFr(&fr, 2)
expected := new(bls.G1Point)
bls.MulG1(expected, &bls.GenG1, &fr)
threads := 10
ch := make(chan *bls.G1Point)
builder := func() {
var fr bls.Fr
bls.AsFr(&fr, 2)
dst := new(bls.G1Point)
bls.MulG1(dst, &bls.GenG1, &fr)
ch <- dst
}
for i := 0; i < threads; i++ {
go builder()
}
for i := 0; i < threads; i++ {
res := <-ch
if res.String() != expected.String() {
t.Error("Incorrect fr")
}
}
}
We found another thread-safety issue with Kilic, described here. In short, it seems that if
MulG1is called concurrently, the two contexts will interact and give an incorrect results.The following test exposes the problem: 10 threads are running concurrently, each performing a simple EC point multiplication with
MulG1, and the result will be sent over a channel. The results are compared with a value calculated in a serial execution context, and they differ (see the failed CI build).