Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECPAIRING test vectors #822

Closed
OlivierBBB opened this issue Jul 5, 2024 · 11 comments · Fixed by #909
Closed

ECPAIRING test vectors #822

OlivierBBB opened this issue Jul 5, 2024 · 11 comments · Fixed by #909
Assignees
Labels
documentation Improvements or additions to documentation

Comments

@OlivierBBB
Copy link
Collaborator

OlivierBBB commented Jul 5, 2024

Below is a description of many of the various tests scenarios which we should cover in the arithmetization to test it. We also include some tests (with large n's) that are of use potentially for GNARK + the glue as they will test the circuit's ability to accumulate the results of Miller loops and do a large final exponentiation.

1 point:
========

- ICP fail / success
  - Failure cases: 2 * 2 * 2 - 1 = 7 ways to fail;
    - coordinates out of range for small point
    - small point not on the curve
    - coordinates out of range for large point
  - Success: 1 way to succeed
    - well-formedness of pair of points:
      - Failure: 2 ways to fail ( B not on C2 ? on C2  but not on G2 ?)
      - Success: 4 ways of succeeding:

         | small point A | ≡ ∞ | ≠ ∞ |
         | large point B | ≡ ∞ | ≠ ∞ |

         ( ★  ) case analysis:
          - [B ≡ ∞]: should trigger nothing (CS_ECPAIRING = 0, CS_G2_MEMBERSHIP = 0)
          - [B ≠ ∞] ∧ [A ≡ ∞]: should trigger nothing (CS_ECPAIRING = 0, CS_G2_MEMBERSHIP = 1)
          - [B ≠ ∞] ∧ [A ≠ ∞]: should trigger nothing (CS_ECPAIRING = 1, CS_G2_MEMBERSHIP = 0)

FAILURE_KNOWN_TO_RAM: 7 + 2  test scenarios
RAM_SUCCESS: 3 cases (or 4 is we include the distinction on [A ≡ ∞ ?] in the first case)

n points:
=========

n = number of pairs of points (n = 2, 3, 4 for the extensive tests; and maybe some larger thing to test GNARK's ability to chain the Miller loops)

- ICP failure:
- ICP success:
  - one or more of the B_k are malformed [check with 1 malformed and also with 2 or more]:
    - expect to see: (SUCCESS_BIT = 0, CS_ECPAIRING = 0, CS_G2_MEMBERSHIP = 1 @ first malformed k)
    - we have 2 ways to be malformed but we can be malformed (1) more than once (2) for different reasons
  - all of the B_k are wellformed
    - expect to see: (SUCCESS_BIT = 1)
    - if TRIVIAL_PAIRING = 1 case (all B_k's are infinity) then the arithmetization sets the RESULT to 1 + the arithmetization sets the SUCCESS_BIT = 1)
    - it TRIVIAL_PAIRING = 0
      - k by k we have the same analysis as in the 1 point case ( ★  )


FAILURE_KNOWN_TO_RAM:
- 7 + (2 * n + 4 * n(n-1)/2 + ...) = 7 + (1 + 2)^n test scenarios (the same as before + we have a choice for where it fails, how often, several failure conditions at once etc ...) 2 * n ≡ 2 ways to fail at a position 1 ≤ k ≤ n, 4 * n(n-1)/2 ways to fail at 2 positions etc ...

RAM_SUCCESS test cases we want to test:
- TRIVIAL_PAIRING = 1
  - all the B_k's are ∞, and we can freely select the A_k's to be a mixture of ∞'s and nontrivial points
  - 2 ^ n choices for (which of the A_k are ≡ ∞)
- TRIVIAL_PAIRING = 0
  - all of the pairs of points are ACCEPTABLE_PAIR_OF_POINTS
  - only some are and we require CS_G2_MEMBERSHIP_TEST

@ivokub
Copy link

ivokub commented Jul 9, 2024

@OlivierBBB, @lorenzogentile404 - providing test inputs:

Small points

  • large coordinates
= Ax large and Ay in range (not necessarily satisfying curve equation) =
Ax = 0xb3a1cca4c86cdc017597bb5e39705666199eccabc367f8c6aa5e713921c0886e
Ay = 0x2018c3b9c5993f6e66a53edf1524775bd337cd82931b44760bdb4e0f557fcf55
= Ax in range and Ay large (not necessarily satisfying curve equation) =
Ax = 0x29c5b47fbe82856ac08cfc5e72ee76f9ca909a4360ceafdbb058792b4dea2380
Ay = 0xced846e53d3564f9d059532c94207b64cba68393988bb0bd26711c828f68cd64
= Ax large and Ay large (not necessarily satisfying curve equation) =
Ax = 0x70bf1a09651c7990437f031943fefc89fcf4db43f48c36932e5dce0aad9f747b
Ay = 0x5c9d0608b3bd76f3464fef9402ea1cafdf388d58ee6a9bfea0c996ae6357fe7f
= Ax large and Ay in range (satisfying curve equation) =
Ax = 0x5eaa17cb8e1208585eba5d2b4e836421919b4b79ca16becff6d2e50db4cd0527
Ay = 0x1fc12c00d4cbbe5194c82a03fc221a7f79b9fb9184075b109b2d202705920b22
= Ax in range and Ay large (satisfying curve equation) =
Ax = 0x248ac61b824e9f04836facfaa73b279dca4ba04342af547dcf4d6a3eb45a01b9
Ay = 0x54ef148e63803f2e3bbff2b128bc7ffb61cd0ad4ab211f0b0b6df6558cd6ff00
= Ax large and Ay large (satisfying curve equation) =
Ax = 0x42603eedeb961906414d6570008db85f5b895a83ab2a26f676b943bfcd8bec4e
Ay = 0x3c90ed3461516edfed77ff88f12b03b732dabb51a9a121e9c72d6291f3066252
  • coordinates in range but not satisfying the curve equation
= Ax and Ay in range but not satisfying curve equation =
Ax = 0x1dac6eed25388228c5542dfc2c0b30bd5afbb4fb091791052ad8ca6a8e1c94fb
Ay = 0x0b35150d9fe2b8cff4e81fd7445b6d529f68ca798d16618adf0f1d319e772987
  • just a few points of the C1 curve drawn at random
= random point in G1 =
Ax = 0x26d7d8759964ac70b4d5cdf698ad5f70da246752481ea37da637551a60a2a57f
Ay = 0x13991eda70bd3bd91c43e7c93f8f89c949bd271ba8f9f5a38bce7248f1f6056b
= random point in G1 =
Ax = 0x1760ca14c35b8978c10ba226b4654e4c925218417ec23731c29da60f481c2c0a
Ay = 0x16206149ae732094afbc9921444e04cae6e093a0e73f3212a5e9f93a04f7f07a
= random point in G1 =
Ax = 0x214eb4ed76fa9ea509001fa6d4a1ddc86ac42da639fba6e4956b4045dd74fa26
Ay = 0x0a847e7fee1a9b1c6166724ec7eea284fd71506e31371674164f860ac641b0e4
= random point in G1 =
Ax = 0x1cbcc5ae2ad1e062ffbfe7858b0f962d24656075da7f168779afb5167da8e946
Ay = 0x1504db20d014e62edf9b2105d8fc6c62919351144cfdd8c6e12c3290d9903a79
= random point in G1 =
Ax = 0x117e59d40acc2608b961101994f76516f4cd4204af85de7d499c2b9043e0d771
Ay = 0x2c76b5677261cc2851a41b75f03497ef99522c1c29a4f4d2aba921997cec664a

Large points

  • large coordinates
= BxRe large, BxIm in range, ByRe in range, ByIm in range =
BxIm = 0x268294ac35af168840b758c749a19a7b1ffcb3df81e0047f2a4a3a68549fe8b9
BxRe = 0xfacbb907b18555b9fa34efaa266ab946e1c7eadfe9d8f0cd821e7448e8a8053a
ByIm = 0x2fe08b1ff6a7fbe4cc3f0bfc309ae33bca35e9b29de0b2b3a73a829f3b9393cf
ByRe = 0x1b38210130d62850704dfeeee59e982308d9c976e583ad20a4289145cfcf3b1d
= BxRe in range, BxIm large, ByRe in range, ByIm in range =
BxIm = 0x4dbf7d5e29252a3f871fe6ec7bbb736a82c6a92e1f383988fbf1993fd254535c
BxRe = 0x28747a6a24cce55f56d4847a08e45f2b19a575097915bfb39048be362f605ff8
ByIm = 0x031b86886f00782d83503db96caf1bb0ed6f68a907464fbb5b0de864b80c1ffd
ByRe = 0x302ca42cef622575199921b4f82e95009d09aba8e18c2240b9d084ac8bfd27de
= BxRe in range, BxIm in range, ByRe large, ByIm in range =
BxIm = 0x0fefff1654529948ddff9422011555b212236211766ce7674f9de0867248bec0
BxRe = 0x101dce57329a75b870c3ed82911561dddc38337d9de49c1a201e42097074d358
ByIm = 0x0b9a97e4531fb7c625ba34bf2939bc22a8ad8b2e03d0bd4cc9def5fdf96f30dc
ByRe = 0x5786a896704be805b5301789420715b9e6c4608d6bbf593b8c2bdc27b504eb91
= BxRe in range, BxIm in range, ByRe in range, ByIm large =
BxIm = 0x2ab1c49ae7628ad0ef94a9e181a47f7ebbf697173af1587ee152684b98b3b0d5
BxRe = 0x0efd3c694ab7d704b3f241402397b340a509ba863775d7b8ee1e8c99eddec530
ByIm = 0x5b2a592225a2ce715a205171f503ae70024f4842b4888407d67e0c580d3459d3
ByRe = 0x06433c581782ec0072e2185740924ac1fa2cf74905b40a901d3a7dfc7edb10e0
= point in subgroup, but overflowing =
BxIm = 0x4ff3dc314cf1a04200904cd987949e253a594fc8f63cd345805fd090b0a9109a
BxRe = 0x5707bebe515ba78d92d4c9b46b87c861f8886954bc429b68b0f82e89b1519923
ByIm = 0x4323d04a74d4ebbb7a7223201e31faa21e3bb172d54e177c436a2aaaa2b06fd2
ByRe = 0x4f47d2affd33161882639176e700137e44be4b847c1202c4a6db1f9837ac285a
  • small coordinates but not satisfying the curve equation
= point not on curve =
BxIm = 0x1d3df5be6084324da6333a6ad1367091ca9fbceb70179ec484543a58b8cb5d63
BxRe = 0x119606e6d3ea97cea4eff54433f5c7dbc026b8d0670ddfbe6441e31225028d31
ByIm = 0x49fe60975e8c78b7b31a6ed16a338ac8b28cf6a065cfd2ca47e9402882518ba0
ByRe = 0x1b9a36ea373fe2c5b713557042ce6deb2907d34e12be595f9bbe84c144de86ef
  • small coordinates, satisfying the curve equation but not belonging to the G2 subgroup
= point not in subgroup but on curve =
BxIm = 0x15ce93f1b1c4946dd6cfbb3d287d9c9a1cdedb264bda7aada0844416d8a47a63
BxRe = 0x07192b9fd0e2a32e3e1caa8e59462b757326d48f641924e6a1d00d66478913eb
ByIm = 0x06e1f5e20f68f6dfa8a91a3bea048df66d9eaf56cc7f11215401f7e05027e0c6
ByRe = 0x0fa65a9b48ba018361ed081e3b9e958451de5d9e8ae0bd251833ebb4b2fafc96
  • just a few points on G2 drawn at random
= random point in G2 =
BxIm = 0x13eb8555f322c3885846df8a505693a0012493a30c34196a529f964a684c0cb2
BxRe = 0x18335a998f3db61d3d0b63cd1371789a9a8a5ed4fb1a4adaa20ab9573251a9d0
ByIm = 0x20494259608bfb4cd04716ba62e1350ce90d00d8af00a5170f46f59ae72d060c
ByRe = 0x257a64fbc5a9cf9c3f7be349d09efa099305fe61f364c31c082ef6a81c815c1d
= random point in G2 =
BxIm = 0x2f1e9fe1d767c3ee1f801d43e4238a28cb4f94d3e644b2c43e236a503eade386
BxRe = 0x14675488459758a6e2f0bebcf5cd4c70c0c6d9733575c999a09418ae773ae6b5
ByIm = 0x0ae82edaac30d3ff28ea0c4d8e43e39622b47a19beb334a4216994e3a98a796a
ByRe = 0x237392d458d5e3a479ebb4feac87c4371150ea86ee61f3268f5b65bca02daa4a
= random point in G2 =
BxIm = 0x210c2d4972a76beee46732b60ed998e2e60769847350553f274523a7a9b23d17
BxRe = 0x0dd0cf966d5a0ef6d560e7dc949b48839e14e26bb8e22d08029b17e1f916de8b
ByIm = 0x22a8f09fd8c34454c77a7aeb7d7d6e00e160cdf03700c1e503b7e0cabf9aba3c
ByRe = 0x2090ce9e959dcf086d024dd626111301fd559aab1b4a475bb4c59cd7f598af83
= random point in G2 =
BxIm = 0x15746a21d15b2ffb960a9cb93426fc05f20921467c23f89494966d13e1507e87
BxRe = 0x29670f195cd081b64b28dae6420ad919a7ca8a5c3a0ae5c313420cd4aca339af
ByIm = 0x056e6142247149ea3505c5adbd6f3d1af9f51d50fdd2cdcd637221ee9ef80a3c
ByRe = 0x025f9828f38707d5cb94e8905be933d4ae03e7f084e250a2c65f0c856035a2a4
= random point in G2 =
BxIm = 0x22007e1404f2d2f0a9b676095daef5b4d49be05df224ef98a2cd00da756900d9
BxRe = 0x1d8281748ef6cd4dd40149ce6f2afbcc26f3d2499cb484b0a4c21872f9816171
ByIm = 0x191fc3a7eb19e1f750c5c3dc7a008c8d35dc08feb1de5dd24f293bc2fd84a739
ByRe = 0x16dca8731c250e792423469ab23a2f7d4891d55d43da021f6ce572f268e2cab9

@lorenzogentile404
Copy link
Collaborator

lorenzogentile404 commented Jul 22, 2024

@ivokub could you specify, in the cases described as "not necessarily satisfying curve equation", if they
actually satisfy the equation? So as I know exactly what to expect when I run the tests. Also, was the trace I provided useful? Do you need some specific corner case's trace (so I can give priority to them)? I am now implementing the logic for parametrised testing.

@ivokub
Copy link

ivokub commented Jul 22, 2024

@ivokub could you specify, in the cases described as "not necessarily satisfying curve equation", if they actually satisfy the equation? So as I know exactly what to expect when I run the tests. Also, was the trace I provided useful? Do you need some specific corner case's trace (so I can give priority to them)? I am now implementing the logic for parametrised testing.

In case "not necessarily satisfying curve equation" the coordinates do not satisfy curve equations.

I'm not sure about the trace - here we have IS_ECPAIRING_DATA set to 1 but at the same time CS_ECPAIRING is 0, which imo is a contradiction. And the LIMB values are also unset. See the example.

image

@lorenzogentile404
Copy link
Collaborator

It seems you may be in one of the cases in which CS_G2_MEMBERSHIP = 1 and CS_ECPAIRING = 0 and A is infinity:
Screenshot 2024-07-22 at 14 51 27

@ivokub
Copy link

ivokub commented Jul 22, 2024

It seems you may be in one of the cases in which CS_G2_MEMBERSHIP = 1 and CS_ECPAIRING = 0 and A is infinity: Screenshot 2024-07-22 at 14 51 27

But in the trace neither CS_ECPAIRING nor CS_G2_MEMBERSHIP is set?

@lorenzogentile404
Copy link
Collaborator

lorenzogentile404 commented Jul 22, 2024

I was looking at the wrong row, my bad. It seems you are in the TRIVIAL_PAIRING case, specifically with both points being the points at infinity (even if it is enough only all B points are the points at infinity).

@ivokub
Copy link

ivokub commented Jul 22, 2024

I was looking at the wrong row, my bad. It seems you are in the TRIVIAL_PAIRING case, specifically with both points being the points at infinity (even if it is enough only all B points are the points at infinity).

But neither of the points is at infinity?

func TestIsInfinity(t *testing.T) {
	var p bn254.G1Affine
	p.X.SetString("0x26d7d8759964ac70b4d5cdf698ad5f70da246752481ea37da637551a60a2a57f")
	p.Y.SetString("0x13991eda70bd3bd91c43e7c93f8f89c949bd271ba8f9f5a38bce7248f1f6056b")
	var q bn254.G2Affine
	q.X.A0.SetString("0x13eb8555f322c3885846df8a505693a0012493a30c34196a529f964a684c0cb2")
	q.X.A1.SetString("0x18335a998f3db61d3d0b63cd1371789a9a8a5ed4fb1a4adaa20ab9573251a9d0")
	q.Y.A0.SetString("0x20494259608bfb4cd04716ba62e1350ce90d00d8af00a5170f46f59ae72d060c")
	q.Y.A1.SetString("0x257a64fbc5a9cf9c3f7be349d09efa099305fe61f364c31c082ef6a81c815c1d")
	if p.IsInfinity() {
		t.Fatal("point is infinity")
	}
	if q.IsInfinity() {
		t.Fatal("point is infinity")
	}
}

passes

@lorenzogentile404
Copy link
Collaborator

The issue was that I forgot to MSTORE the input values in the test. Now it should be fine.

@OlivierBBB
Copy link
Collaborator Author

@ivokub Thank you for those points. Could you also provide us with the following:

  • a pair, triple and quadruple of pairs of points whose pairing returns 1 ?

I take it that the examples you provided were more or less random points, here I'm asking for test vectors of 2, 3 or even 4 pairs of points that would be output by a valid snark proof so that we can also test the "standard" case where the result is 1.

@ivokub
Copy link

ivokub commented Jul 31, 2024

Valid pairings

= double successful pairing =
Ax = 0x01395d002b3ca9180fb924650ef0656ead838fd027d487fed681de0d674c30da
Ay = 0x097c3a9a072f9c85edf7a36812f8ee05e2cc73140749dcd7d29ceb34a8412188
BxIm = 0x2bd3295ff81c577fe772543783411c36f463676d9692ca4250588fbad0b44dc7
BxRe = 0x07d8d8329e62324af8091e3a4ffe5a57cb8664d1f5f6838c55261177118e9313
ByIm = 0x230f1851ba0d3d7d36c8603c7118c86bd2b6a7a1610c4af9e907cb702beff1d8
ByRe = 0x12843e703009c1c1a2f1088dcf4d91e9ed43189aa6327cae9a68be22a1aee5cb

Ax = 0x05dcb6449ff95e1a04c3132ce3be82a897811d2087e082e0399985449942a45b
Ay = 0x0cb5122006e9b7ceb5307fa4015b132b3945bb972c83459f598659fc4b5a9d32
BxIm = 0x127a664dd11342beb666506dac296731e404de80a25e05f40b2405c4c00c28fc
BxRe = 0x2bd236cb7a7b0e0543e6b6e0d7308576aeeec4dea2f740654854215d7813826f
ByIm = 0x1b28f411c2931b52b2ad62de524be4eaac555dfed67d59e2d0f6c4607b23526b
ByRe = 0x181c4319cc974dd174c5918ac1892326badb2603a04bc8f565221c06eec8a126


= triple successful pairing =
Ax = 0x01395d002b3ca9180fb924650ef0656ead838fd027d487fed681de0d674c30da
Ay = 0x097c3a9a072f9c85edf7a36812f8ee05e2cc73140749dcd7d29ceb34a8412188
BxIm = 0x2bd3295ff81c577fe772543783411c36f463676d9692ca4250588fbad0b44dc7
BxRe = 0x07d8d8329e62324af8091e3a4ffe5a57cb8664d1f5f6838c55261177118e9313
ByIm = 0x230f1851ba0d3d7d36c8603c7118c86bd2b6a7a1610c4af9e907cb702beff1d8
ByRe = 0x12843e703009c1c1a2f1088dcf4d91e9ed43189aa6327cae9a68be22a1aee5cb

Ax = 0x05dcb6449ff95e1a04c3132ce3be82a897811d2087e082e0399985449942a45b
Ay = 0x0cb5122006e9b7ceb5307fa4015b132b3945bb972c83459f598659fc4b5a9d32
BxIm = 0x12618811f3e9fa06644d43cfe3f69c6c17a738128de60f8f3ebb4266bab29be6
BxRe = 0x00a5a6c2ec01c4d1374078ae1bbea91dea8e938c1275226a1ce51db5e7de53d1
ByIm = 0x2da43ecc11a0095a72454bb08fb4d1116facadcab482a1107ae67a12bb3c19f2
ByRe = 0x1e2f128bf79945a370324b82c36c1e63509b122c023bd8163495526bb030a216

Ax = 0x1296d042f33ccbb814746e187aa20af49bd503356de4846abee08da9e32ae2ac
Ay = 0x0b980019d2af83b353aa8c2efda45f16ce523b99452118be7ae5dd1e92e0e4ec
BxIm = 0x012cd1b1242354b35cd8d2493c487b52411d111c80e8cfb97080e2db1af5f705
BxRe = 0x20ca232ed2582feeca2d56a589eec30c27075a44aced8382d87cd43c011aeeb0
ByIm = 0x2df7d0d9ae47467ca500b528f38ac38433885d6a59db6ecd7d27d37145e75360
ByRe = 0x1e4d8d4d8878cad4de8dbb31ec11d1ecd7b40617c46bb7189ccab201b9bdbaab


= quadruple successful pairing =
Ax = 0x01395d002b3ca9180fb924650ef0656ead838fd027d487fed681de0d674c30da
Ay = 0x097c3a9a072f9c85edf7a36812f8ee05e2cc73140749dcd7d29ceb34a8412188
BxIm = 0x2bd3295ff81c577fe772543783411c36f463676d9692ca4250588fbad0b44dc7
BxRe = 0x07d8d8329e62324af8091e3a4ffe5a57cb8664d1f5f6838c55261177118e9313
ByIm = 0x230f1851ba0d3d7d36c8603c7118c86bd2b6a7a1610c4af9e907cb702beff1d8
ByRe = 0x12843e703009c1c1a2f1088dcf4d91e9ed43189aa6327cae9a68be22a1aee5cb

Ax = 0x05dcb6449ff95e1a04c3132ce3be82a897811d2087e082e0399985449942a45b
Ay = 0x0cb5122006e9b7ceb5307fa4015b132b3945bb972c83459f598659fc4b5a9d32
BxIm = 0x12618811f3e9fa06644d43cfe3f69c6c17a738128de60f8f3ebb4266bab29be6
BxRe = 0x00a5a6c2ec01c4d1374078ae1bbea91dea8e938c1275226a1ce51db5e7de53d1
ByIm = 0x2da43ecc11a0095a72454bb08fb4d1116facadcab482a1107ae67a12bb3c19f2
ByRe = 0x1e2f128bf79945a370324b82c36c1e63509b122c023bd8163495526bb030a216

Ax = 0x1296d042f33ccbb814746e187aa20af49bd503356de4846abee08da9e32ae2ac
Ay = 0x0b980019d2af83b353aa8c2efda45f16ce523b99452118be7ae5dd1e92e0e4ec
BxIm = 0x0cdc14ed1231209df350fbf71c359fa338955c8e4b10678b33237e54473e7b0f
BxRe = 0x2c5be308b741fee6607eea4980779483339372c80494a43189ab6613f2ac6b00
ByIm = 0x0a56a2a107cc154cade228f3da75a714a7de0738b9ebd455f3f73c4c3c43136b
ByRe = 0x1d98bf24e00f830334bdf3334135c5aa55b6fd4e88e87b1aee72fb1550970879

Ax = 0x0baab17525d29e5d7c34a5cdb6558e8427f5c79206e009b4b1e8b91a4c827f1c
Ay = 0x18cb7444434d59d126ccc48244daa9a3709140bfa58bff81751d42b647211a91
BxIm = 0x27f28ec95a4937c625a4fa28551ba8b7010511313699acb72d5eb0a0a208df2b
BxRe = 0x2e04f5f992061adf169ef7423bc2f8748ca8fe437036e44a5a24b32bdbae8754
ByIm = 0x056d39d4c664d7bf3417673a870f94749311be2f4e4c5fdfe6563b1593fcc00e
ByRe = 0x18b849ea2b045d9b94d2e1d8daa843ef2c98577bb7c98d6004eb8982f561fd0f

@lorenzogentile404
Copy link
Collaborator

thanks @ivokub. Note that I inverted the order of imaginary and real parts since this is the way they appear in the trace and it was convenient to keep the same order in the code for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants