2021-02-22 17:48:14 +00:00

165 lines
9.3 KiB
Go

package bn256
import (
"testing"
"github.com/stretchr/testify/assert"
)
// Tests that the exponentiation in gfp2 works correctly
// SageMath test vector:
/*
p = 21888242871839275222246405745257275088696311157297823662689037894645226208583
Fp = GF(p)
Fpx.<j> = PolynomialRing(Fp, 'j')
// The modulus is in the form `j^2 - non-residue-in-Fp`
// Fp2.<i> = GF(p^2, modulus=j^2 - 3) // 3 is a quadratic non-residue in Fp
// See: https://github.com/scipr-lab/libff/blob/master/libff/algebra/curves/alt_bn128/alt_bn128_init.cpp#L95
// The quadratic non-residue used in -1, so the modulus is
Fp2.<i> = GF(p^2, modulus=j^2 + 1)
// Quad. Non. Resid. test (Euler's criterion)
eulerExp = (Fp(p-1)/Fp(2))
Fp(-1)^eulerExp + Fp(1) == p // Should return true, then we see that -1 (ie: p-1) is a nqr (non quadratic residue mod p)
// Element taken randomly in the field Fp2
// we denote an element of Fp2 as: e = x*i + y
baseElement = 8192512702373747571754527085437364828369119615795326562285198594140975111129*i + 14719814144181528030533020377409648968040866053797156997322427920899698335369
// baseElementXHex = hex(8192512702373747571754527085437364828369119615795326562285198594140975111129)
baseElementXHex = 121ccc410d6339f7 bbc9a8f5b577c5c5 96c9dfdd6233cbac 34a8ddeafedf9bd9
baseElementXHexLittleEndian = 34a8ddeafedf9bd9 96c9dfdd6233cbac bbc9a8f5b577c5c5 121ccc410d6339f7
// baseElementYHex = hex(14719814144181528030533020377409648968040866053797156997322427920899698335369)
baseElementYHex = 208b1e9b9b11a98c 30a84b2641e87244 9a54780d0e482cfb 146adf9eb7641e89
baseElementYHexLittleEndian = 146adf9eb7641e89 9a54780d0e482cfb 30a84b2641e87244 208b1e9b9b11a98c
// We run in Sage, resExponentiation = baseElement ^ 5, and we get
baseElementTo5 = baseElement ^ 5
baseElementTo5 = 1919494216989370714282264091499504460829540920627494019318177103740489354093*i + 3944397571509712892671395330294281468555185483198747137614153093242854529958
baseElementTo5XHex = 043e652d8f044857 c4cbfe9636928309 44288a2a00432390 7fa7e33a3e5acb6d
baseElementTo5XHexLittleEndian = 7fa7e33a3e5acb6d 44288a2a00432390 c4cbfe9636928309 043e652d8f044857
baseElementTo5YHex = 08b8732d547b1cda b5c82ff0bfaa42c1 54e7b24b65223fc2 88b3e8a6de535ba6
baseElementTo5XHexLittleEndian = 88b3e8a6de535ba6 54e7b24b65223fc2 b5c82ff0bfaa42c1 08b8732d547b1cda
*/
func TestExp(t *testing.T) {
// Case 1: Exponent = 5 (= 0x05)
baseElementX := &gfP{0x34a8ddeafedf9bd9, 0x96c9dfdd6233cbac, 0xbbc9a8f5b577c5c5, 0x121ccc410d6339f7}
baseElementY := &gfP{0x146adf9eb7641e89, 0x9a54780d0e482cfb, 0x30a84b2641e87244, 0x208b1e9b9b11a98c}
// montEncode each Fp element
// Important to do since the field arithmetic uses montgomery encoding in the library
montEncode(baseElementX, baseElementX)
montEncode(baseElementY, baseElementY)
baseElement := &gfP2{*baseElementX, *baseElementY}
// We keep the expected result non encoded
// Will need to decode the obtained result to be able to assert it with this
baseElementTo5X := &gfP{0x7fa7e33a3e5acb6d, 0x44288a2a00432390, 0xc4cbfe9636928309, 0x043e652d8f044857}
baseElementTo5Y := &gfP{0x88b3e8a6de535ba6, 0x54e7b24b65223fc2, 0xb5c82ff0bfaa42c1, 0x08b8732d547b1cda}
baseElementTo5 := &gfP2{*baseElementTo5X, *baseElementTo5Y}
// Manual multiplication, to make sure the results are all coherent with each other
manual := &gfP2{}
manual = manual.Set(baseElement)
manual = manual.Mul(manual, manual) // manual ^ 2
manual = manual.Mul(manual, manual) // manual ^ 4
manual = manual.Mul(manual, baseElement) // manual ^ 5
manualDecoded := gfP2Decode(manual)
// Expected result (obtained with sagemath, after some type conversions)
w := &gfP2{}
w = w.Set(baseElementTo5)
// Result returned by the Exp function
exponent5 := bigFromBase10("5")
h := &gfP2{}
h = h.Set(baseElement)
h = h.Exp(exponent5)
// We decode the result of the exponentiation to be able to compare with the
// non-encoded/sagemath generated expected result
hDecoded := gfP2Decode(h)
assert.Equal(t, *w, *hDecoded, "The result of the exponentiation is not coherent with the Sagemath test vector")
assert.Equal(t, *manualDecoded, *hDecoded, "The result of the exponentiation is not coherent with the manual repeated multiplication")
// Case 2: Exponent = bigExponent = 39028236692093846773374607431768211455 + 2^128 - 2^64 = 379310603613032310218302470789826871295 = 0x11d5c90a20486bd1c40686b493777ffff
// This exponent can be encoded on 3 words/uint64 => 0x1 0x1d5c90a20486bd1c 0x40686b493777ffff if 64bit machine or
// on 5 words/uint32 => 0x1 0x1d5c90a2 0x0486bd1c 0x40686b49 0x3777ffff if 32bit machine
baseElementX = &gfP{0x34a8ddeafedf9bd9, 0x96c9dfdd6233cbac, 0xbbc9a8f5b577c5c5, 0x121ccc410d6339f7}
baseElementY = &gfP{0x146adf9eb7641e89, 0x9a54780d0e482cfb, 0x30a84b2641e87244, 0x208b1e9b9b11a98c}
// montEncode each Fp element
// Important to do since the field arithmetic uses montgomery encoding in the library
montEncode(baseElementX, baseElementX)
montEncode(baseElementY, baseElementY)
baseElement = &gfP2{*baseElementX, *baseElementY}
// We keep the expected result non encoded
// Will need to decode the obtained result to be able to assert it with this
// Sagemath:
// baseElementToBigExp = baseElement ^ bigExponent
// baseElementToBigExp => 7379142427977467878031119988604583496475317621776403696479934226513132928021*i + 17154720713365092794088637301427106756251681045968150072197181728711103784706
// baseElementToBigExpXHex = 10507254ce787236 62cf3f84eb21adee 30ec827a799a519a 1464fc2ec9263c15
// baseElementToBigExpYHex = 25ed3a53d558db9a 07da01cc9d10c5d5 ff7b1e4f41b874d7 debbc13409c8a702
baseElementToBigExpX := &gfP{0x1464fc2ec9263c15, 0x30ec827a799a519a, 0x62cf3f84eb21adee, 0x10507254ce787236}
baseElementToBigExpY := &gfP{0xdebbc13409c8a702, 0xff7b1e4f41b874d7, 0x07da01cc9d10c5d5, 0x25ed3a53d558db9a}
baseElementToBigExp := &gfP2{*baseElementToBigExpX, *baseElementToBigExpY}
// Expected result (obtained with sagemath, after some type conversions)
w = &gfP2{}
w = w.Set(baseElementToBigExp)
// Result returned by the Exp function
bigExp := bigFromBase10("379310603613032310218302470789826871295")
h = &gfP2{}
h = h.Set(baseElement)
h = h.Exp(bigExp)
// We decode the result of the exponentiation to be able to compare with the
// non-encoded/sagemath generated expected result
hDecoded = gfP2Decode(h)
assert.Equal(t, *w, *hDecoded, "The result of the exponentiation is not coherent with the Sagemath test vector")
}
func TestSqrt(t *testing.T) {
// Case 1: Valid QR
// qr = 8192512702373747571754527085437364828369119615795326562285198594140975111129*i + 14719814144181528030533020377409648968040866053797156997322427920899698335369
// This is a QR in Fp2
qrXBig := bigFromBase10("8192512702373747571754527085437364828369119615795326562285198594140975111129")
qrYBig := bigFromBase10("14719814144181528030533020377409648968040866053797156997322427920899698335369")
qr := &gfP2{*newMontEncodedGFpFromBigInt(qrXBig), *newMontEncodedGFpFromBigInt(qrYBig)}
res, err := qr.Sqrt()
assert.NoError(t, err, "An error shouldn't be returned as we try to get the sqrt of a QR")
// We decode the result of the squaring to compare the result with the Sagemath test vector
// To get the sqrt of `r` in Sage, we run: `r.sqrt()`, and we get:
// 838738240039331261565244756819667559640832302782323121523807597830118111128*i + 701115843855913009657260259360827182296091347204618857804078039211229345012
resDecoded := gfP2Decode(res)
expectedXBig := bigFromBase10("838738240039331261565244756819667559640832302782323121523807597830118111128")
expectedYBig := bigFromBase10("701115843855913009657260259360827182296091347204618857804078039211229345012")
expected := &gfP2{*newGFpFromBigInt(expectedXBig), *newGFpFromBigInt(expectedYBig)}
assert.Equal(t, *expected, *resDecoded, "The result of the sqrt is not coherent with the Sagemath test vector")
// Case 2: Valid QR
// qr = -1 = 0 * i + 21888242871839275222246405745257275088696311157297823662689037894645226208582
// The sqrt of qr is: sqrt = 21888242871839275222246405745257275088696311157297823662689037894645226208582 * i + 0
qr = &gfP2{*newGFp(0), *newMontEncodedGFpFromBigInt(bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208582"))}
res, err = qr.Sqrt()
assert.NoError(t, err, "An error shouldn't be returned as we try to get the sqrt of a QR")
resDecoded = gfP2Decode(res)
expected = &gfP2{*newGFpFromBigInt(bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208582")), *newGFp(0)}
assert.Equal(t, *expected, *resDecoded, "The result of the sqrt is not coherent with the Sagemath test vector")
// Case 3: Get the sqrt of a QNR
// qnr = 10142231111593789910248975994434553601587001629804098271704323146176084338608*i + 13558357083504759335548106329923635779485621365040524539176938811542516618464
qnrXBig := bigFromBase10("10142231111593789910248975994434553601587001629804098271704323146176084338608")
qnrYBig := bigFromBase10("13558357083504759335548106329923635779485621365040524539176938811542516618464")
qnr := &gfP2{*newMontEncodedGFpFromBigInt(qnrXBig), *newMontEncodedGFpFromBigInt(qnrYBig)}
res, err = qnr.Sqrt()
assert.Error(t, err, "An error should have been returned as we try to get the sqrt of a QNR")
assert.Nil(t, res, "The result of sqrt should be nil as we try to get the sqrt of a QNR")
}