Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 

420 rader
12 KiB

  1. package p751toolbox
  2. import (
  3. "math/big"
  4. "math/rand"
  5. "reflect"
  6. "testing"
  7. "testing/quick"
  8. )
  9. var quickCheckScaleFactor = uint8(3)
  10. var quickCheckConfig = &quick.Config{MaxCount: (1 << (12 + quickCheckScaleFactor))}
  11. var cln16prime, _ = new(big.Int).SetString("10354717741769305252977768237866805321427389645549071170116189679054678940682478846502882896561066713624553211618840202385203911976522554393044160468771151816976706840078913334358399730952774926980235086850991501872665651576831", 10)
  12. // Convert an Fp751Element to a big.Int for testing. Because this is only
  13. // for testing, no big.Int to Fp751Element conversion is provided.
  14. func radix64ToBigInt(x []uint64) *big.Int {
  15. radix := new(big.Int)
  16. // 2^64
  17. radix.UnmarshalText(([]byte)("18446744073709551616"))
  18. base := new(big.Int).SetUint64(1)
  19. val := new(big.Int).SetUint64(0)
  20. tmp := new(big.Int)
  21. for _, xi := range x {
  22. tmp.SetUint64(xi)
  23. tmp.Mul(tmp, base)
  24. val.Add(val, tmp)
  25. base.Mul(base, radix)
  26. }
  27. return val
  28. }
  29. func VartimeEq(x,y *PrimeFieldElement) bool {
  30. return x.A.vartimeEq(y.A)
  31. }
  32. func (x *Fp751Element) toBigInt() *big.Int {
  33. // Convert from Montgomery form
  34. return x.toBigIntFromMontgomeryForm()
  35. }
  36. func (x *Fp751Element) toBigIntFromMontgomeryForm() *big.Int {
  37. // Convert from Montgomery form
  38. a := Fp751Element{}
  39. aR := fp751X2{}
  40. copy(aR[:], x[:]) // = a*R
  41. fp751MontgomeryReduce(&a, &aR) // = a mod p in [0,2p)
  42. fp751StrongReduce(&a) // = a mod p in [0,p)
  43. return radix64ToBigInt(a[:])
  44. }
  45. func TestPrimeFieldElementToBigInt(t *testing.T) {
  46. // Chosen so that p < xR < 2p
  47. x := PrimeFieldElement{A: Fp751Element{
  48. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 140737488355328,
  49. }}
  50. // Computed using Sage:
  51. // sage: p = 2^372 * 3^239 - 1
  52. // sage: R = 2^768
  53. // sage: from_radix_64 = lambda xs: sum((xi * (2**64)**i for i,xi in enumerate(xs)))
  54. // sage: xR = from_radix_64([1]*11 + [2^47])
  55. // sage: assert(p < xR)
  56. // sage: assert(xR < 2*p)
  57. // sage: (xR / R) % p
  58. xBig, _ := new(big.Int).SetString("4469946751055876387821312289373600189787971305258234719850789711074696941114031433609871105823930699680637820852699269802003300352597419024286385747737509380032982821081644521634652750355306547718505685107272222083450567982240", 10)
  59. if xBig.Cmp(x.A.toBigInt()) != 0 {
  60. t.Error("Expected", xBig, "found", x.A.toBigInt())
  61. }
  62. }
  63. func generateFp751(rand *rand.Rand) Fp751Element {
  64. // Generation strategy: low limbs taken from [0,2^64); high limb
  65. // taken from smaller range
  66. //
  67. // Size hint is ignored since all elements are fixed size.
  68. //
  69. // Field elements taken in range [0,2p). Emulate this by capping
  70. // the high limb by the top digit of 2*p-1:
  71. //
  72. // sage: (2*p-1).digits(2^64)[-1]
  73. // 246065832128056
  74. //
  75. // This still allows generating values >= 2p, but hopefully that
  76. // excess is OK (and if it's not, we'll find out, because it's for
  77. // testing...)
  78. //
  79. highLimb := rand.Uint64() % 246065832128056
  80. return Fp751Element{
  81. rand.Uint64(),
  82. rand.Uint64(),
  83. rand.Uint64(),
  84. rand.Uint64(),
  85. rand.Uint64(),
  86. rand.Uint64(),
  87. rand.Uint64(),
  88. rand.Uint64(),
  89. rand.Uint64(),
  90. rand.Uint64(),
  91. rand.Uint64(),
  92. highLimb,
  93. }
  94. }
  95. func (x PrimeFieldElement) Generate(rand *rand.Rand, size int) reflect.Value {
  96. return reflect.ValueOf(PrimeFieldElement{A: generateFp751(rand)})
  97. }
  98. func (x ExtensionFieldElement) Generate(rand *rand.Rand, size int) reflect.Value {
  99. return reflect.ValueOf(ExtensionFieldElement{A: generateFp751(rand), B: generateFp751(rand)})
  100. }
  101. //------------------------------------------------------------------------------
  102. // Extension Field
  103. //------------------------------------------------------------------------------
  104. func TestOneExtensionFieldToBytes(t *testing.T) {
  105. var x ExtensionFieldElement
  106. var xBytes [188]byte
  107. x.One()
  108. x.ToBytes(xBytes[:])
  109. if xBytes[0] != 1 {
  110. t.Error("Expected 1, got", xBytes[0])
  111. }
  112. for i := 1; i < 188; i++ {
  113. if xBytes[i] != 0 {
  114. t.Error("Expected 0, got", xBytes[0])
  115. }
  116. }
  117. }
  118. func TestExtensionFieldElementToBytesRoundTrip(t *testing.T) {
  119. roundTrips := func(x ExtensionFieldElement) bool {
  120. var xBytes [188]byte
  121. var xPrime ExtensionFieldElement
  122. x.ToBytes(xBytes[:])
  123. xPrime.FromBytes(xBytes[:])
  124. return x.VartimeEq(&xPrime)
  125. }
  126. if err := quick.Check(roundTrips, quickCheckConfig); err != nil {
  127. t.Error(err)
  128. }
  129. }
  130. func TestExtensionFieldElementMulDistributesOverAdd(t *testing.T) {
  131. mulDistributesOverAdd := func(x, y, z ExtensionFieldElement) bool {
  132. // Compute t1 = (x+y)*z
  133. t1 := new(ExtensionFieldElement)
  134. t1.Add(&x, &y)
  135. t1.Mul(t1, &z)
  136. // Compute t2 = x*z + y*z
  137. t2 := new(ExtensionFieldElement)
  138. t3 := new(ExtensionFieldElement)
  139. t2.Mul(&x, &z)
  140. t3.Mul(&y, &z)
  141. t2.Add(t2, t3)
  142. return t1.VartimeEq(t2)
  143. }
  144. if err := quick.Check(mulDistributesOverAdd, quickCheckConfig); err != nil {
  145. t.Error(err)
  146. }
  147. }
  148. func TestExtensionFieldElementMulIsAssociative(t *testing.T) {
  149. isAssociative := func(x, y, z ExtensionFieldElement) bool {
  150. // Compute t1 = (x*y)*z
  151. t1 := new(ExtensionFieldElement)
  152. t1.Mul(&x, &y)
  153. t1.Mul(t1, &z)
  154. // Compute t2 = (y*z)*x
  155. t2 := new(ExtensionFieldElement)
  156. t2.Mul(&y, &z)
  157. t2.Mul(t2, &x)
  158. return t1.VartimeEq(t2)
  159. }
  160. if err := quick.Check(isAssociative, quickCheckConfig); err != nil {
  161. t.Error(err)
  162. }
  163. }
  164. func TestExtensionFieldElementSquareMatchesMul(t *testing.T) {
  165. sqrMatchesMul := func(x ExtensionFieldElement) bool {
  166. // Compute t1 = (x*x)
  167. t1 := new(ExtensionFieldElement)
  168. t1.Mul(&x, &x)
  169. // Compute t2 = x^2
  170. t2 := new(ExtensionFieldElement)
  171. t2.Square(&x)
  172. return t1.VartimeEq(t2)
  173. }
  174. if err := quick.Check(sqrMatchesMul, quickCheckConfig); err != nil {
  175. t.Error(err)
  176. }
  177. }
  178. func TestExtensionFieldElementInv(t *testing.T) {
  179. inverseIsCorrect := func(x ExtensionFieldElement) bool {
  180. z := new(ExtensionFieldElement)
  181. z.Inv(&x)
  182. // Now z = (1/x), so (z * x) * x == x
  183. z.Mul(z, &x)
  184. z.Mul(z, &x)
  185. return z.VartimeEq(&x)
  186. }
  187. // This is more expensive; run fewer tests
  188. var quickCheckConfig = &quick.Config{MaxCount: (1 << (8 + quickCheckScaleFactor))}
  189. if err := quick.Check(inverseIsCorrect, quickCheckConfig); err != nil {
  190. t.Error(err)
  191. }
  192. }
  193. func TestExtensionFieldElementBatch3Inv(t *testing.T) {
  194. batchInverseIsCorrect := func(x1, x2, x3 ExtensionFieldElement) bool {
  195. var x1Inv, x2Inv, x3Inv ExtensionFieldElement
  196. x1Inv.Inv(&x1)
  197. x2Inv.Inv(&x2)
  198. x3Inv.Inv(&x3)
  199. var y1, y2, y3 ExtensionFieldElement
  200. ExtensionFieldBatch3Inv(&x1, &x2, &x3, &y1, &y2, &y3)
  201. return (y1.VartimeEq(&x1Inv) && y2.VartimeEq(&x2Inv) && y3.VartimeEq(&x3Inv))
  202. }
  203. // This is more expensive; run fewer tests
  204. var quickCheckConfig = &quick.Config{MaxCount: (1 << (5 + quickCheckScaleFactor))}
  205. if err := quick.Check(batchInverseIsCorrect, quickCheckConfig); err != nil {
  206. t.Error(err)
  207. }
  208. }
  209. //------------------------------------------------------------------------------
  210. // Prime Field
  211. //------------------------------------------------------------------------------
  212. func TestPrimeFieldElementMulVersusBigInt(t *testing.T) {
  213. mulMatchesBigInt := func(x, y PrimeFieldElement) bool {
  214. z := new(PrimeFieldElement)
  215. z.Mul(&x, &y)
  216. check := new(big.Int)
  217. check.Mul(x.A.toBigInt(), y.A.toBigInt())
  218. check.Mod(check, cln16prime)
  219. return check.Cmp(z.A.toBigInt()) == 0
  220. }
  221. if err := quick.Check(mulMatchesBigInt, quickCheckConfig); err != nil {
  222. t.Error(err)
  223. }
  224. }
  225. func TestPrimeFieldElementP34VersusBigInt(t *testing.T) {
  226. var p34, _ = new(big.Int).SetString("2588679435442326313244442059466701330356847411387267792529047419763669735170619711625720724140266678406138302904710050596300977994130638598261040117192787954244176710019728333589599932738193731745058771712747875468166412894207", 10)
  227. p34MatchesBigInt := func(x PrimeFieldElement) bool {
  228. z := new(PrimeFieldElement)
  229. z.P34(&x)
  230. check := x.A.toBigInt()
  231. check.Exp(check, p34, cln16prime)
  232. return check.Cmp(z.A.toBigInt()) == 0
  233. }
  234. // This is more expensive; run fewer tests
  235. var quickCheckConfig = &quick.Config{MaxCount: (1 << (8 + quickCheckScaleFactor))}
  236. if err := quick.Check(p34MatchesBigInt, quickCheckConfig); err != nil {
  237. t.Error(err)
  238. }
  239. }
  240. // Package-level storage for this field element is intended to deter
  241. // compiler optimizations.
  242. var benchmarkFp751Element Fp751Element
  243. var benchmarkFp751X2 fp751X2
  244. var bench_x = Fp751Element{17026702066521327207, 5108203422050077993, 10225396685796065916, 11153620995215874678, 6531160855165088358, 15302925148404145445, 1248821577836769963, 9789766903037985294, 7493111552032041328, 10838999828319306046, 18103257655515297935, 27403304611634}
  245. var bench_y = Fp751Element{4227467157325093378, 10699492810770426363, 13500940151395637365, 12966403950118934952, 16517692605450415877, 13647111148905630666, 14223628886152717087, 7167843152346903316, 15855377759596736571, 4300673881383687338, 6635288001920617779, 30486099554235}
  246. var bench_z = fp751X2{1595347748594595712, 10854920567160033970, 16877102267020034574, 12435724995376660096, 3757940912203224231, 8251999420280413600, 3648859773438820227, 17622716832674727914, 11029567000887241528, 11216190007549447055, 17606662790980286987, 4720707159513626555, 12887743598335030915, 14954645239176589309, 14178817688915225254, 1191346797768989683, 12629157932334713723, 6348851952904485603, 16444232588597434895, 7809979927681678066, 14642637672942531613, 3092657597757640067, 10160361564485285723, 240071237}
  247. func BenchmarkExtensionFieldElementMul(b *testing.B) {
  248. z := &ExtensionFieldElement{A: bench_x, B: bench_y}
  249. w := new(ExtensionFieldElement)
  250. for n := 0; n < b.N; n++ {
  251. w.Mul(z, z)
  252. }
  253. }
  254. func BenchmarkExtensionFieldElementInv(b *testing.B) {
  255. z := &ExtensionFieldElement{A: bench_x, B: bench_y}
  256. w := new(ExtensionFieldElement)
  257. for n := 0; n < b.N; n++ {
  258. w.Inv(z)
  259. }
  260. }
  261. func BenchmarkExtensionFieldElementSquare(b *testing.B) {
  262. z := &ExtensionFieldElement{A: bench_x, B: bench_y}
  263. w := new(ExtensionFieldElement)
  264. for n := 0; n < b.N; n++ {
  265. w.Square(z)
  266. }
  267. }
  268. func BenchmarkExtensionFieldElementAdd(b *testing.B) {
  269. z := &ExtensionFieldElement{A: bench_x, B: bench_y}
  270. w := new(ExtensionFieldElement)
  271. for n := 0; n < b.N; n++ {
  272. w.Add(z, z)
  273. }
  274. }
  275. func BenchmarkExtensionFieldElementSub(b *testing.B) {
  276. z := &ExtensionFieldElement{A: bench_x, B: bench_y}
  277. w := new(ExtensionFieldElement)
  278. for n := 0; n < b.N; n++ {
  279. w.Sub(z, z)
  280. }
  281. }
  282. func BenchmarkPrimeFieldElementMul(b *testing.B) {
  283. z := &PrimeFieldElement{A: bench_x}
  284. w := new(PrimeFieldElement)
  285. for n := 0; n < b.N; n++ {
  286. w.Mul(z, z)
  287. }
  288. }
  289. // --- field operation functions
  290. func BenchmarkFp751Multiply(b *testing.B) {
  291. for n := 0; n < b.N; n++ {
  292. fp751Mul(&benchmarkFp751X2, &bench_x, &bench_y)
  293. }
  294. }
  295. func BenchmarkFp751MontgomeryReduce(b *testing.B) {
  296. z := bench_z
  297. // This benchmark actually computes garbage, because
  298. // fp751MontgomeryReduce mangles its input, but since it's
  299. // constant-time that shouldn't matter for the benchmarks.
  300. for n := 0; n < b.N; n++ {
  301. fp751MontgomeryReduce(&benchmarkFp751Element, &z)
  302. }
  303. }
  304. func BenchmarkFp751AddReduced(b *testing.B) {
  305. for n := 0; n < b.N; n++ {
  306. fp751AddReduced(&benchmarkFp751Element, &bench_x, &bench_y)
  307. }
  308. }
  309. func BenchmarkFp751SubReduced(b *testing.B) {
  310. for n := 0; n < b.N; n++ {
  311. fp751SubReduced(&benchmarkFp751Element, &bench_x, &bench_y)
  312. }
  313. }
  314. func BenchmarkFp751ConditionalSwap(b *testing.B) {
  315. x, y := bench_x, bench_y
  316. for n := 0; n < b.N; n++ {
  317. fp751ConditionalSwap(&x, &y, 1)
  318. fp751ConditionalSwap(&x, &y, 0)
  319. }
  320. }
  321. func BenchmarkFp751StrongReduce(b *testing.B) {
  322. x := bench_x
  323. for n := 0; n < b.N; n++ {
  324. fp751StrongReduce(&x)
  325. }
  326. }
  327. func BenchmarkFp751AddLazy(b *testing.B) {
  328. var z Fp751Element
  329. x, y := bench_x, bench_y
  330. for n := 0; n < b.N; n++ {
  331. fp751AddLazy(&z, &x, &y)
  332. }
  333. }
  334. func BenchmarkFp751X2AddLazy(b *testing.B) {
  335. x, y, z := bench_z, bench_z, bench_z
  336. for n := 0; n < b.N; n++ {
  337. fp751X2AddLazy(&x, &y, &z)
  338. }
  339. }
  340. func BenchmarkFp751X2SubLazy(b *testing.B) {
  341. x, y, z := bench_z, bench_z, bench_z
  342. for n := 0; n < b.N; n++ {
  343. fp751X2SubLazy(&x, &y, &z)
  344. }
  345. }