Import implementations of X25519 and X448 from Catacomb.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 26 Apr 2017 10:53:05 +0000 (11:53 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Wed, 25 Sep 2019 12:46:59 +0000 (13:46 +0100)
Taken from https://git.distorted.org.uk/~mdw/catacomb/, commit-id
9c1437f372e62f0b3b3a7162aabee73bdc96ce4b.

These are just the raw files from upstream.  Don't try to build them,
because they have all sorts of dependencies on the rest of the library.
But at least this way I can record the hacking I did to integrate them
into Secnet.

The test vector files were originally called things like
`math/t/f25519': I've renamed them here because otherwise they'd briefly
introduce directories or have very unhelpful names.  They'll need
radically reformatting anyway, because the test-vector parser didn't
come along for the ride.

Signed-off-by: Mark Wooding <mdw@distorted.org.uk>
14 files changed:
f25519-tests.in [new file with mode: 0644]
f25519.c [new file with mode: 0644]
f25519.h [new file with mode: 0644]
fgoldi-tests.in [new file with mode: 0644]
fgoldi.c [new file with mode: 0644]
fgoldi.h [new file with mode: 0644]
montladder.h [new file with mode: 0644]
qfarith.h [new file with mode: 0644]
x25519-tests.in [new file with mode: 0644]
x25519.c [new file with mode: 0644]
x25519.h [new file with mode: 0644]
x448-tests.in [new file with mode: 0644]
x448.c [new file with mode: 0644]
x448.h [new file with mode: 0644]

diff --git a/f25519-tests.in b/f25519-tests.in
new file mode 100644 (file)
index 0000000..96d4ac7
--- /dev/null
@@ -0,0 +1,1235 @@
+### Test cases for arithmetic mod 2^255 - 19.
+
+add {
+  ## Some load and store tests.
+  0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20
+    0000000000000000000000000000000000000000000000000000000000000000
+    0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20;
+  ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f
+    0000000000000000000000000000000000000000000000000000000000000000
+    ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f;
+  edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f
+    00000000000000000000000000000000000000000000000000000000000000
+    00;
+
+  ## Random tests.
+  bb8cd45b6185ee8ca34c4d7560425fd5c2fc22871113c6427198e8f9439a8523
+    98f16cc5e44b7228b7f3b6ed91930d68bba5071157d19259c48034d2817e30d5
+    667e412146d160b55a400463f2d56c3d7ea22a9868e4589c35191dccc518b678;
+  8ef938a7b07a668c234c2c5bb65115b8e2e22a3703cda51c70e7a56a075d4f34
+    1f3cd4bf4f768058c4de1aa5aeb90e227338e308c7a0a199050ca1c38d1e034c
+    c0350d6700f1e6e4e72a4700650b24da551b0e40ca6d47b675f3462e957b5200;
+  8b2c4678fd4f8b7254eea925e4da8d472db7f97d349d1b2134ced884b747ea7d
+    58dca7954f843b7e4dc56b048903e7728df66ef6824f29932b2f568c995ddf2c
+    f608ee0d4dd4c6f0a1b3152a6dde74babaad6874b7ec44b45ffd2e1151a5c92a;
+  9cd64f0cf439bccd224f7a789396b9f888998d1ba9759c93a5d6a27f45db0e67
+    12f724a127052612081e27e3915db9a540de9b64c566edc313914ad94424464e
+    c1cd74ad1b3fe2df2a6da15b25f4729ec97729806edc8957b967ed588aff5435;
+  82e59fa9703b2557303665fe24e3d46259da974d78155f05c6b8891f92fc808d
+    98a073ec62baf1354b681a3c78d62df1698ed5077dbe2bd68ba4a6e0233e3447
+    2d861396d3f5168d7b9e7f3a9db90254c3686d55f5d38adb515d3000b63ab554;
+  686ceca221d0f4c6d98287e97c506085064e7b172672b88ee555dd0308bfd309
+    60adc3675be5e6c2921a74b5b8b24b0a26341a19567dae713a720786bc72df16
+    c819b00a7db5db896c9dfb9e3503ac8f2c8295307cef660020c8e489c431b320;
+  a50a5b82d2451ed9a5844585712202a6dc0e0230501d57b8c00f4bd4771aed9e
+    98d71b8b140aea02ad47d9b19e47d2a03257adc1d5c47611adc667652b78c87c
+    63e2760de74f08dc52cc1e37106ad4460f66aff125e2cdc96dd6b239a392b51b;
+  1637e3eb4c5d173b8cba29bdb13b930f48ae0599e354819f8ae0cf70f0f7b61b
+    ffeef1767df70de7a4a75864c03935d7934c6cf5228b9c3000813ed0e55447e2
+    2826d562ca542522316282217275c8e6dbfa718e06e01dd08a610e41d64cfe7d;
+  9e8bf571c45bc5f37c9126e70498698978903b94d9c6712baef91894ab924fda
+    480f68f8ee644bfb64e3fa514eaf16aea6368da6813802c4c3e6ce8f6540dfa3
+    0c9b5d6ab3c010efe1742139534780371fc7c83a5bff73ef71e0e72311d32e7e;
+  df9bdbd478bd1ec1ff078cdc76f2a5fcdc52f0198ba412e0b5a10e664b175dad
+    080bc47bd2fb2ba3be6a07a02162f76020479f2cc6469c6766df23acf9517896
+    0da79f504bb94a64be72937c98549d5dfd998f4651ebae471c8132124569d543;
+  b6dd223f5d8a3dc5dd6f7a0679173ff656303017a17f17f4086fd4ecd3a23020
+    560d827aad23c26fddbfd16c3514a9b518a4586d6e3c5739860743662b14f4b4
+    1feba4b90aaeff34bb2f4c73ae2be8ab6fd488840fbc6e2d8f761753ffb62455;
+  1d59691a670c40143ca7f7e693389ab64a911b17a2fe4368fba9097b40864162
+    cb42d3ba12a8b90ef1622ea09241d3157c515043040914356d6d99b95089fa07
+    e89b3cd579b4f9222d0a2687267a6dccc6e26b5aa607589d6817a334910f3c6a;
+  82b48877e9c8c18edb52db3e1417d894e572a8edd84335d93c642158f2a926e0
+    93c6a39c1ef97f318c3b13bf8e77bea653b2eb130bdf43b00a0e0e40a362e819
+    287b2c1408c241c0678eeefda28e963b39259401e422798947722f98950c0f7a;
+  a6137481c5b9b8bcb3c87f3868c5f812da71aeb21c5ce18a508773120ea4f659
+    812eacdc5a8eb2e8fde0c23a19c2e33466d754ab3109d28ff48fb41dab8066e2
+    4d42205e20486ba5b1a942738187dc474049035e4e65b31a45172830b9245d3c;
+  598fb4096a7054e317e66bc9633d56dfcaeabc31a7bbc9da13074b242edeca09
+    929b1bddd55c99b06b99a3ffbac5adc1d28823cb8354adcfea60b7a87fe32039
+    eb2ad0e63fcded93837f0fc91e0304a19d73e0fc2a1077aafe6702cdadc1eb42;
+  c42183d915267e655409326b1b77a042d8918feefd75dd3d18551f398ef426e7
+    e3729a6110686ffa57d1c69284a60fb36173148a89b1810d04614f03c8f90084
+    cd941d3b268eed5facdaf8fd9f1db0f53905a47887275f4b1cb66e3c56ee276b;
+  67b8b7ea7e7f9f52d686f906589c919b293bff6d3127e7ac581dc1630af7bcc1
+    99d18d2190ef0da148b843c014fea3efea59f9adbb28fa38407191fcc24e029c
+    268a450c0f6fadf31e3f3dc76c9a358b1495f81bed4fe1e5988e5260cd45bf5d;
+  bc3422b79e01234fefd3637a19bfb2dd0a83bf2071b27bf5389918a50e579294
+    b665dffe064aceffaabba94697cf27054d016427ebaf68858c5250cc5c1b770f
+    859a01b6a54bf14e9a8f0dc1b08edae2578423485c62e47ac5eb68716b720924;
+  d419cbfd5514d9cffa1765b9f273fd7492000a3d110586ed0b8137760a2e808e
+    bcb52f423917c074464b2078d1c3f883fb793b02411b8b13c08266d17658a499
+    b6cffa3f8f2b994441638531c437f6f88d7a453f52201101cc039e4781862428;
+  2f7eb8051d16a52b797e2618881bd0857eb205bf97e581e09680f86308f7e082
+    9ceda63b29c3bfedbb6f3f0be2f3f2bd285bb9d21620c3edde69629b00b1c3cd
+    f16b5f4146d9641935ee65236a0fc343a70dbf91ae0545ce75ea5aff08a8a450;
+}
+
+sub {
+  dfb53b4ff67c742728c564d50ae20e3e3617804478a95e511d37ff4dcf04fa3f
+    9bc2006bb07dcf7bf0b461e7599e3c3cbfcdf6b6f41fc1db2219767ce9c43bcd
+    1ef33ae445ffa4ab371003eeb043d2017749898d83899d75fa1d89d1e53fbe72;
+  432ec65076c94af41e054a43f64fe4eecb23f50a303fd38e0172e4e846e67394
+    3642c84c5f5fcd5a0f3f2e37114beb8e7b614c39d354f1b32fe7e9cc918da5c8
+    faebfd03176a7d990fc61b0ce504f95f50c2a8d15ceae1dad18afa1bb558ce4b;
+  1725a986c03d9d53346ab2064545ba90ab38191e19ded9ecc2f44d422ab04150
+    11a20caef0239e4ffb5ab2f7d3576633a0d4a08c78a02f35765fafff5398c48b
+    f3829cd8cf19ff03390f000f71ed535d0b647891a03daab74c959e42d6177d44;
+  ec5d5cdfc8183f9aa3d47634d16427c3a399e2166bfa4ddfecbc911e5f33ceba
+    649f8e29c483765c4232c369fd0e50a0026eac306eb4bd6924e7b4d7d3f73e26
+    9bbecdb50495c83d61a2b3cad355d722a12b36e6fc459075c8d5dc468b3b8f14;
+  cc9927c331884612d8fab9a2262ad0db38f55e0cc587e45b972ea8b1f504450d
+    30c5c9f8d5491a350051bbc6bb78e568d98061b43cb1797cd3d7454e8a7aa1bf
+    76d45dca5b3e2cddd7a9fedb6ab1ea725f74fd5788d66adfc35662636b8aa34d;
+  662bc96da214e50f13e07a15b8e0b78f512c744a66975b2170ba28079ca7d03b
+    84b072295dca0abef806ec5c1e594179dc5e9eb172c178af1902a42ea7a3728e
+    cf7a5644454ada511ad98eb89987761675cdd598f3d5e27156b884d8f4035e2d;
+  ed6f947157492eccc5fb1d0542593d58a47e2d87355dc0378e65376163fcf457
+    cb27e06c5ebf42a61caadd4fb222799772aaef31487bf61ac84c15f58af265d3
+    0f48b404f989eb25a95140b58f36c4c031d43d55ede1c91cc618226cd8098f04;
+  33c2fc57d8ffc29e6d670cfc4e25b695320055cf443ade53f49f6c23c452f644
+    3814860ccbb4391894c107961170d3af1594988a7972b97d0fb2169631b216fa
+    d5ad764b0d4b8986d9a504663db5e2e51c6cbc44cbc724d6e4ed558d92a0df4a;
+  d0fd0d5e73be5c534aa37645aecc49b202fadb30733f16d0de719a70bec2c751
+    910c7b4d317397cff70c91e5bf8ec42ba1700b0866adbbfe99b7fbb2c46c7093
+    2cf19210424bc5835296e55fee3d85866189d0280d925ad144ba9ebdf955573e;
+  e0f8130d6b0125e824b254ed57edc59455a8a4704a3f14a4ae8dbf8721595468
+    4e4f69af6f85742068ad70225e8850c85aef3d3fb3ba3b52c2be979db4eb979d
+    7fa9aa5dfb7bb0c7bc04e4caf96475ccfab866319784d851ecce27ea6c6dbc4a;
+  204d5f69ebab4597d2aa9295ecc2959480a2ab0b225674cc8a147cf7c1e59717
+    3abdd29c94819ec7507673bd5cc4fb267fcb17c1509abd5e462b46b012f815a8
+    c08f8ccc562aa7cf81341fd88ffe996d01d7934ad1bbb66d44e93547afed816f;
+  e2d75c74060aee615b6cfc815c8618f826b07c4987e10f20d27ff74eab3ac7d0
+    7a06b32d284b5faedb91dac8e94cb7f76c678bad81ed78ac4e75eb9edd8d11e9
+    55d1a946debe8eb37fda21b972396100ba48f19b05f49673830a0cb0cdacb567;
+  8d50b0573b0bb945bf128e1a9a37c151e991581673cf6295db5a6223d428ac9d
+    47ca477794fdf378f3486355b5348960ee957470b8c74d62199ac48b4478c4ca
+    338668e0a60dc5cccbc92ac5e40238f1fafbe3a5ba071533c2c09d978fb0e752;
+  b66b49190a99456aaac5c33beaec423a3fa79a84df0f00122aed29151185ceef
+    13c06f7941743bfa261845d99772fd0d5f1a8258aeda53b161505ed8bdca1bc8
+    a3abd99fc8240a7083ad7e62527a452ce08c182c3135ac60c89ccb3c53bab227;
+  44ac89bb8d4de1a8756b00401236ea4e316a2fe637f6e5f052576da70c29c4ea
+    05dd39ac32768d899b80ed10279aa10d6316d60ab2d061e877dc5f21ce8e1140
+    52cf4f0f5bd7531fdaea122feb9b4841ce5359db85258408db7a0d863e9ab22a;
+  ef0f6c7f56ff22260c66d583f79c7f581181d3a0f3167c93786bb6c89de4372c
+    be934afeffaf5e6755a92e6606ffd054627dbe1b18ad6ae543363a01da605512
+    317c2181564fc4beb6bca61df19dae03af031585db6911ae34357cc7c383e219;
+  773e0db8f86c5182b5f51d10376f42cde275dac6a646ab1cab065760e045107e
+    3f92ddafdfe67d357b4f9b61807bcb8b0f1f6c2dacba27902f48fc15a31db606
+    38ac2f081986d34c3aa682aeb6f37641d3566e99fa8b838c7bbe5a4a3d285a77;
+  34860a848d0afb20e43f4a36b3c8941f5821864216da9cb3ce1a11f056565a3d
+    9dfed86048acd45ec0009c1ba3b20a1ba645ec141070fd8ae41d25e159bbce9f
+    84873123455e26c2233fae1a10168a04b2db992d066a9f28eafceb0efd9a8b1d;
+  854ba91672ae1b8f6c29395dcfa4f3514ed97dc2c9e1e419f926825619fac55b
+    7a700653ad355caf17f89045ecfb3ee821194b54048e55d8eed41fea2b0a22ab
+    f8daa2c3c478bfdf5431a817e3a8b4692cc0326ec5538f410a52626cedefa330;
+  0c66b3d8c3916940b70d381d232ba8aecfe27e3ae63fa6cbb287216708f224f0
+    477186656245c4083dff93a95c6e5deb707916e52cd74abbd522743c24c53088
+    c5f42c73614ca5377a0ea473c6bc4ac35e696855b9685b10dd64ad2ae42cf467;
+}
+
+neg {
+  0000000000000000000000000000000000000000000000000000000000000000
+    0000000000000000000000000000000000000000000000000000000000000000;
+  23d767107e23d5ce14189cce939c4b5334d6736da3da40a715236b9d8319efc1
+    b72898ef81dc2a31ebe763316c63b4accb298c925c25bf58eadc94627ce6103e;
+  9bb944cfb58b186cc551e0a0eca74528c7618ff47485bf6a723f43d990f69f6e
+    5246bb304a74e7933aae1f5f1358bad7389e700b8b7a40958dc0bc266f096011;
+  bff36d2aa923d5a9af5398e2cfcba4acdf3c3181a8ff00b8a1099cd97a4e8542
+    2e0c92d556dc2a5650ac671d30345b5320c3ce7e5700ff475ef6632685b17a3d;
+  1b65a51746eabb7c0d8d9844dda03bde7128407e94661db2d5fd9c0f3790d120
+    d29a5ae8b9154483f27267bb225fc4218ed7bf816b99e24d2a0263f0c86f2e5f;
+  88f4cf29a610c4465f63a272fde2f19a4874a70a0829885014379b637ab0e82d
+    650b30d659ef3bb9a09c5d8d021d0e65b78b58f5f7d677afebc8649c854f1752;
+  94ca4d567efcf088e6bf1cb3698f6b8bf2164db4f523e28781aebfcbb501ec63
+    5935b2a981030f771940e34c967094740de9b24b0adc1d787e5140344afe131c;
+  3f8d7ae4f1698921524e49ccb2ce4459e4c048f76f04c5e60179f5417d2d52db
+    9b72851b0e9676deadb1b6334d31bba61b3fb70890fb3a19fe860abe82d2ad24;
+  1eaa0c45af0d8f85d865cc66ff3d0dc3355f1ac36821cdd95a6b9232a27f9044
+    cf55f3ba50f2707a279a339900c2f23ccaa0e53c97de3226a5946dcd5d806f3b;
+  33e142c78ee87a7980ade6c796e7ff949cee6d3af0415bf5b6901f84c2db910a
+    ba1ebd38711785867f5219386918006b631192c50fbea40a496fe07b3d246e75;
+  24a0c185c47787caf1a666a62002a503f2a3e591e5f2946e148a47b9b114a884
+    b65f3e7a3b8878350e599959dffd5afc0d5c1a6e1a0d6b91eb75b8464eeb577b;
+  a8bd0c1c3f219a97de87b22e8cb3eb5daea33b5646589b6925ec4ec83ca37455
+    4542f3e3c0de656821784dd1734c14a2515cc4a9b9a76496da13b137c35c8b2a;
+  1a340d2679ca205f6b198cff4bffadcde1afeeed124ef0c574655dbe8732b681
+    c0cbf2d98635dfa094e67300b40052321e501112edb10f3a8b9aa24178cd497e;
+  da43c139a1f92ba1b5fc996befe5218368eac3c46b42e98a9cca8b8f6f1540f5
+    00bc3ec65e06d45e4a036694101ade7c97153c3b94bd16756335747090eabf0a;
+  81aad864a31e5f4afa32c29eb97f22c103dfe5b1323db05fc9b1545312aa6c0d
+    6c55279b5ce1a0b505cd3d614680dd3efc201a4ecdc24fa0364eabaced559372;
+  28231ad38d214f1421df7005eddb4f4c12e522b10d1cbcd10ee26dfcc222a62c
+    c5dce52c72deb0ebde208ffa1224b0b3ed1add4ef2e3432ef11d92033ddd5953;
+  c1facefef35c1ed00db767ed0281ebfad1f3c915c6649f5e1c26a6f3f9478b43
+    2c0531010ca3e12ff2489812fd7e14052e0c36ea399b60a1e3d9590c06b8743c;
+  c2e4046e7200386ca2afea8ecc9c98c105fbf6e31b598e21e482796a69956040
+    2b1bfb918dffc7935d5015713363673efa04091ce4a671de1b7d8695966a9f3f;
+  a42fedea4eac90580a0bbcb0491a7e8cc82de7a99aa74ed35f705c536afa0236
+    49d01215b1536fa7f5f4434fb6e5817337d218566558b12ca08fa3ac9505fd49;
+  d1ab8c50d54279ceac870d0ce4a2af56bf8c03e87482dcb7775183a4908ac739
+    1c5473af2abd86315378f2f31b5d50a94073fc178b7d234888ae7c5b6f753846;
+  1ffd85fa5ead53ff509756fc28051ef65eca040303b65f7b5b7e1d1a8508e030
+    ce027a05a152ac00af68a903d7fae109a135fbfcfc49a084a481e2e57af71f4f;
+}
+
+condneg {
+  5330763b29dff20501a1d6c64025c36279083473721f5cacf89168189ff9810d
+    0x00000000
+    5330763b29dff20501a1d6c64025c36279083473721f5cacf89168189ff9810d;
+  9d9c36e2126d911a503e1cc1a8489ee74949ae2a8408dc7d72ed0d75e4350545
+    0x00000000
+    9d9c36e2126d911a503e1cc1a8489ee74949ae2a8408dc7d72ed0d75e4350545;
+  47da10abec2cb54c5890e5945999deb1d89ffd268bbbe2eafc86f1acc8bf5f7e
+    0x00000000
+    47da10abec2cb54c5890e5945999deb1d89ffd268bbbe2eafc86f1acc8bf5f7e;
+  3e6ec07de86be6ffab2dfa1deb9ed67844645be92bdbb22b7ba91379babcdfed
+    0x00000000
+    516ec07de86be6ffab2dfa1deb9ed67844645be92bdbb22b7ba91379babcdf6d;
+  5f5c0730649586b5c0b60a14d3b669b3649eb6725d71d834e78ff2aa0e5450e5
+    0xffffffff
+    7ba3f8cf9b6a794a3f49f5eb2c49964c9b61498da28e27cb18700d55f1abaf1a;
+  c357befcc6836d89387915e368e5e6162252b433eb58d94eb3cc4b783e98c226
+    0xffffffff
+    2aa84103397c9276c786ea1c971a19e9ddad4bcc14a726b14c33b487c1673d59;
+  713ad0f656a8fcd75fdee2c4ac248ee7ad09a5f357c565daa94ae46d8590d2c8
+    0x00000000
+    843ad0f656a8fcd75fdee2c4ac248ee7ad09a5f357c565daa94ae46d8590d248;
+  909d669185e98b4a88a6531b830193b23035d64665929e34e86d53c4a9eef30a
+    0xffffffff
+    5d62996e7a1674b57759ace47cfe6c4dcfca29b99a6d61cb1792ac3b56110c75;
+  8f23ec139f93258e6d57fa278339f1cb5da193c5d1ad7183fb2b151111262285
+    0x00000000
+    a223ec139f93258e6d57fa278339f1cb5da193c5d1ad7183fb2b151111262205;
+  a9a5480c72157f389be80ae7ad63502434c380ccd1cef813dc9bd2e9a85e2f22
+    0xffffffff
+    445ab7f38dea80c76417f518529cafdbcb3c7f332e3107ec23642d1657a1d05d;
+  316f98b6697e7daa8775d3aa91dee8fbbae4e935a2f62cd2975e2d552f0c9846
+    0xffffffff
+    bc90674996818255788a2c556e211704451b16ca5d09d32d68a1d2aad0f36739;
+  70128d6dd5fb42f287fba3533c71cb5dc2361b6d91c3d9626c58849e27f7d349
+    0xffffffff
+    7ded72922a04bd0d78045cacc38e34a23dc9e4926e3c269d93a77b61d8082c36;
+  66a6f3dc6274e4122dc401ef23529175d71d96b660a52cdcd64556073b5430b2
+    0x00000000
+    79a6f3dc6274e4122dc401ef23529175d71d96b660a52cdcd64556073b543032;
+  3909505812b228e6ca5cc6c0b17824ef765923eded6105e6eb0f176781624c5a
+    0xffffffff
+    b4f6afa7ed4dd71935a3393f4e87db1089a6dc12129efa1914f0e8987e9db325;
+  b7febd7d63efae3bcc60c1c344f2f6166b272eed785a9e541d3ff4f12e82a5f3
+    0xffffffff
+    230142829c1051c4339f3e3cbb0d09e994d8d11287a561abe2c00b0ed17d5a0c;
+  d1cacc1db40de13351224046975319d7546ae9e88e1909c2a8f46792a140d279
+    0xffffffff
+    1c3533e24bf21eccaeddbfb968ace628ab95161771e6f63d570b986d5ebf2d06;
+  4c449a50fc1e145be1463e4c171b3c51c9683c41c45005d8aeca607911c9b3be
+    0xffffffff
+    8ebb65af03e1eba41eb9c1b3e8e4c3ae3697c3be3baffa2751359f86ee364c41;
+  c929c50eedbad6ceacdefb00bd58a32820c874c906741e9d93cd0f668819edcc
+    0x00000000
+    dc29c50eedbad6ceacdefb00bd58a32820c874c906741e9d93cd0f668819ed4c;
+  1c57449dcfc7e8f9fab77d226d4b50d7dee06c29d08d3d4f4ae7c8ad238a0a82
+    0xffffffff
+    bea8bb6230381706054882dd92b4af28211f93d62f72c2b0b5183752dc75f57d;
+  396a2ddc48f158e73c95dc289da3f0d3b2128875e20c401cb50fd6cc7a28dd18
+    0xffffffff
+    b495d223b70ea718c36a23d7625c0f2c4ded778a1df3bfe34af0293385d72267;
+}
+
+pick2 {
+  e6f52222f35081896f3d9ecc0ffb27fa3e75c8ad1c98e161878d2c3cffd72c78
+    a24cd71f7acb653466b7d67bb41efb5a29503d2627d2ce28fe19680ccd939be5
+    0x00000000
+    b54cd71f7acb653466b7d67bb41efb5a29503d2627d2ce28fe19680ccd939b65;
+  4e51fe2dac96a664d0675962116b7af4e605194a1c9fb774c621a3107994c9ed
+    508934be10ce5e11e6940d56e84b148e20f48369e748536846763c80bab9af49
+    0x00000000
+    508934be10ce5e11e6940d56e84b148e20f48369e748536846763c80bab9af49;
+  530175217081c3fb3ecd17702ad334ad48f05affd5ab3754ef10be5b0eb5375d
+    8aebc7e01e2bb2829f21311462175948d85cd3e65d676eec893e3df13f639d07
+    0xffffffff
+    530175217081c3fb3ecd17702ad334ad48f05affd5ab3754ef10be5b0eb5375d;
+  0e53c5141d72c8c81d80b1a1283b0267b278f98e28ce08ccac7b010022e5adae
+    2215cc15e950d6abfffa26113f269628f50f9ac37ad3260ae9189958d75080b6
+    0xffffffff
+    2153c5141d72c8c81d80b1a1283b0267b278f98e28ce08ccac7b010022e5ad2e;
+  3dc16434679d30686d5023fda4cc574563841caf1d588e965fe1ec1c4ba54398
+    4ca50330751d33ebba981277926a3fb801d216474cb183f90947680f5ea383a2
+    0xffffffff
+    50c16434679d30686d5023fda4cc574563841caf1d588e965fe1ec1c4ba54318;
+  09e68cb66b5ae2f3160a71738d1e9a042b9b76335eddc4b9466d0c6b8100eeb6
+    270eb833ae635bed17df9218a53a91b7afeb74f0df3bfffb8334c04773cf716d
+    0xffffffff
+    1ce68cb66b5ae2f3160a71738d1e9a042b9b76335eddc4b9466d0c6b8100ee36;
+  831b8a99e3b44bf21cdd4f3c06da7c16a95e98f3dc42cf2ac282edec67d9b2ca
+    482840e31c7620de6d290d747afc63ca199c60169f8eb62d28ca1142c5336990
+    0xffffffff
+    961b8a99e3b44bf21cdd4f3c06da7c16a95e98f3dc42cf2ac282edec67d9b24a;
+  a022ace6772d82d30832328c7cbfedb622b710d1fe9313a77dc4cc5ca577a7bb
+    39c86c57bf581c16d8c03b4ef0fe813815b5da1281f03bb3f2cdb0ddf19868d0
+    0xffffffff
+    b322ace6772d82d30832328c7cbfedb622b710d1fe9313a77dc4cc5ca577a73b;
+  719d3f13c38b915873bcb14308bfd9bb6f4a6cfd249a745bceb55787ce480caa
+    c72de6e206ed24555d091763644d4405f2ee5dbd846a036d6a21442a6c40e0c6
+    0x00000000
+    da2de6e206ed24555d091763644d4405f2ee5dbd846a036d6a21442a6c40e046;
+  07cdd3cd677a3c1783bcf7855bf1dbb453809b66c66c7bbbb67690cea33ca581
+    c9d889281ac117390875739e4b62df6dc3cca6c65439c46bb907c81d3a961fa3
+    0x00000000
+    dcd889281ac117390875739e4b62df6dc3cca6c65439c46bb907c81d3a961f23;
+  a69a728035cc69d5d3f96dd4a8081864333e53e434820dd569deb9e58393d4b7
+    3f4ef71dfa1eccd817d3192dbe2e08466e4a66b4d836b0892b3636dc523098ed
+    0x00000000
+    524ef71dfa1eccd817d3192dbe2e08466e4a66b4d836b0892b3636dc5230986d;
+  d249414415ac4960e934d29e08c75ff1b18431a6e18f7404e638293d3d8e81d5
+    33cd02e07762f74976834d1b6dd3b8eb7e2ad7a5d04ba90bbe747476071f10cb
+    0x00000000
+    46cd02e07762f74976834d1b6dd3b8eb7e2ad7a5d04ba90bbe747476071f104b;
+  efb782aba4dca351a5c9279b370073840b977b2458c6c84c9c9046dc92cc5507
+    6d9f50eb56b84989aab77c54987f05c715b74185417863f2c275635d2d6f2eeb
+    0x00000000
+    809f50eb56b84989aab77c54987f05c715b74185417863f2c275635d2d6f2e6b;
+  10c4381ed467e27d756ff7a260a6ffd282ad757b10c9956c518a43117699ee91
+    9b9a70c67be3296ef9d65fdd8014c4b263c28fd31f3299f4461c688c469ff704
+    0x00000000
+    9b9a70c67be3296ef9d65fdd8014c4b263c28fd31f3299f4461c688c469ff704;
+  5a30428bee407ee673ec7d2cb4854efd80b9761df5dec906463f888f60be7152
+    fc2e139be53203eb73041e9335253534c420208164682c2e02f31f084f5582f0
+    0xffffffff
+    5a30428bee407ee673ec7d2cb4854efd80b9761df5dec906463f888f60be7152;
+  43c7cd903c7dd7cdab85c6b5585955163e0da7dd0c5b5882ac620246619af342
+    0eb52162c69425ad75b778c39746014789f7929119d4e122d4b98bf64784fcde
+    0xffffffff
+    43c7cd903c7dd7cdab85c6b5585955163e0da7dd0c5b5882ac620246619af342;
+  f37f3707e4609d389096c1fea551b572a6b4644fd6af2e9e7a0fa93a91ae38e5
+    d10dd4d911346a5952e3123d4f156a7e40807d142c4afb4bc314ac6f9346dfa8
+    0xffffffff
+    06803707e4609d389096c1fea551b572a6b4644fd6af2e9e7a0fa93a91ae3865;
+  a4f4c203cb892691a6d6e9dff8a10ac1a8d9470b13ba24e1bddac05d6d7f9c0e
+    b88145fabdeaa9fa108bb04a4d283ac034b4c8d8ffe1b2174de9a80254762c54
+    0xffffffff
+    a4f4c203cb892691a6d6e9dff8a10ac1a8d9470b13ba24e1bddac05d6d7f9c0e;
+  649d8ce64f623228553de99b823c5f5c5ef37f00e2ddf658fc9bc2405afde715
+    0f24ace92223d2db75e2d82e8a5bc8b0e7981478216b999d2bdde9c72732d58f
+    0xffffffff
+    649d8ce64f623228553de99b823c5f5c5ef37f00e2ddf658fc9bc2405afde715;
+  3f466e24ed4169ca3df624d747f054f97422d5eee3fade2fa3c4eba488694a6c
+    37e3171c9aa56d07ffcde4f1fd0fdcc41e2086ecf93c9e53f3f6a4c3e4db587c
+    0xffffffff
+    3f466e24ed4169ca3df624d747f054f97422d5eee3fade2fa3c4eba488694a6c;
+}
+
+pickn {
+  "91aaaaf3ff9e58f299c0f6d0a4a3851d100423e4b7380d5a32a86cde6cb19562
+   e586b4ab140cd20bfc70aa5ae1c389941a8c631ce033f54793d77c91b5e3d50b
+   911122291921aced748e1346261ce8dc0e50704bf59495c3d7c1a9806ae58b5e
+   dac7c42fc0253029c78310ea1508b2464db2c44689fa7d485fb5863b7c136f15"
+    0
+    91aaaaf3ff9e58f299c0f6d0a4a3851d100423e4b7380d5a32a86cde6cb19562;
+  "e8864778a3aecd6f35f8afa097072e94c4e50680baf91a6036f4f24fb0dcf111
+   5dec44933a517f5a8bf6d858920e1200c74e65132baf0d08ca033e36e15a1c46
+   4fca88e6d122c0a460b5dd502281d80616edd30bede891226b4b3c4b3eb9eea0
+   5fbf4e034d45326d89ffe92bf4738a7120c63ea42568c25acacf4dd7915b9e8f
+   343001277d416dd31dc770232fc47c7d02884fef3fc10eaddf6f8b42fbb00b26"
+    1
+    5dec44933a517f5a8bf6d858920e1200c74e65132baf0d08ca033e36e15a1c46;
+  "f0cfc16fe0cb8910c26f6f46e69954dd34277d171044140c2dc448b6f63e053c
+   d54feccab8d55297eb24f622818aaa2ac5b7fcafee5efe872bb600cbdce85a3a
+   5f1cb6c6b4e8eedb566150a99a7c92228e7f737efa1810b9d40f9a4ea020e56d
+   c762a32a3f3a6f8cd956412eacdaa75ee56b347b952a7c18dd19c0ee2e50b8fc
+   b6e76d1d2cdf04692036f26515ca6b92d57b1bba625f07553d2d4adf89de9611
+   874c9e94d425fe9590aa1cde396ec56531342207a0e3b42ef0ae710bc9b68418
+   872ebc0bbd45d07727887aa8116a5743880093c73b3048c3b46920c04e0f64e2
+   9cde037629d20a4481ba7050546eca2dfd293b0953aa708764531bd8d0fba387
+   e9f7cb8ed4af14ac61722de66406e97ee9a87d9362dfa87e489a9c98f8b891b6
+   6c5bb4410d83505ad34d10409d02fc005a47ef802b5d9130f3b5d385ff78957e
+   ff40983b47e7263665a03e4396421fc34209afaf52d7d69012833b4a228e6c40
+   4588ed141f6401c460ff6ad4888172c9d19f15f214d96bedd59f818d7c03b720
+   99ede977304bc4e8f5edc44463b48fc13c001f5c584f2b100c791ae472fdddba
+   8ba76d6aa98a062e1091ca60e05ecf21208657bf287f20c6cacaaeff41a537ff
+   a18760b118187f5b392637dd5c5f97ccce583b5b84b69f8e37d8caf77c616db0
+   7e921cc5caa3b3884358cb0ffd2d9d160ed54256049fa1540d861dbb6dd1631d
+   aa8102188fbba89c45259c52080b3969c234d070411bc4b91870a8b482eedfbf
+   d98da58b248507edf310beb9fb522dd23d88bc0412ef3b5bd7a13b7a15070647
+   0626183221836da09c9bb5a1dd07df570883af17a9a8fed1c4bc7e8770e348fe
+   16b01a5593b3eaf0902d0ade7e00da7b7a57556c2e7169e8b6ba5df5c5fb02a5
+   e40715b07034e109d79a95a8b031eebc6c59dd0bb77de6cb960fe65a6d1be59e"
+    20
+    f70715b07034e109d79a95a8b031eebc6c59dd0bb77de6cb960fe65a6d1be51e;
+  "e30f85631b4ea4aadb9487c76cbec40ab63101a482e5aa2e3ee329fc21071bf4
+   8bc9fdd41fe1ecf5c2cc2075c72e4ceab370b099ddc672ee16bbd7a7de19dbb4
+   ede086a76fedddb463d9f0fb44b39ac7fb64665061eb96015d4ed39eb33cd772
+   a7cd74dc0c94aa8bfa480a88396b7f293f1ac329e4ce79e04507be4edbf4fef1
+   45f5c114a46bf0b2c8be1ecb8fc7c81e7fef668a2e4e9769f2f2dfecf405af92
+   123d101a02348f81088beeb6fafb7f720b49631736829d2f19e95b8d833684a3
+   ba936ae1b5555b05601c2e59bf9585846ac01b5b7f6fe4bbd45e0653e961deaf
+   51c0c307d99e34a617ead92dd37e1a0f36ebe2e45ef5b3690fd114099d483dc6
+   af94cee7979c057995680c3a5adfe26e7dea759e2640b0b09aff383fa355d289
+   6ddb6908532c513f463473e449747f88d47766460ad316734c2cca87963b3060
+   88192953b60710667d47633be71d87214d2dc8be882ceb6928daf311499d2e83
+   37da1b76c2c16025f0644b6451027c8bc9768379c3aa7ab8410d34d8c8222706
+   1a46c0531cc13f546e001a67721931f4f6bf8eeeadaaab667ee651db0b272509"
+    7
+    64c0c307d99e34a617ead92dd37e1a0f36ebe2e45ef5b3690fd114099d483d46;
+  "9929839bce983fe53c4f8f9d07a462f82e8eebabba2c0daee1378abf585bb53d
+   4e47d3997d6562c7b0347acc96925bd1907bf3a9c57d51b099c4a574d7bf8fc7
+   a0de02656ba18dd1cfdb2938fbb864f9f59001110391ee1818f5c1dfee64f61a
+   9c4153154f5b827bb847edfa04ce754e442f2e96ea001fc27f6d94ea8b06fc00
+   7ba90562980966abd857be3a84c1bffeabbb589415e722e51225f8317e829777
+   ac4657b264ccfad4f5ba3f7a470458101d5c6025c45d00191ddd4bf85ca48705
+   8b11cfc6ceb02c5d4b3e19c19f1ae745fd0cdfd9da1a80e9df1be8f7bb99ace3
+   1202bae1f86d05ed8fca09965bb1cfa3fb696a3f2b7089ee10589394639da2bd
+   143f799fc9ebec77aa444eb5ec95f64029cf61b875a2f94e228323844cb8eff9
+   dcf99568b397db79bd2e8ae49778e1e49865e91525f932a1813d1c395420a43c
+   84fdfee8137558f0b9f2441c375fce466e3212c0d0de3179919fb130e61b711a
+   602454ffaf59610f76863a7456146f866539740d6dae63a3628d408e34db8e76
+   86ae4475d41ea312a97c821ac78b815e459dc6bb4d52c236a39e5e53ff17f5fb
+   0fd56e878b74a2daebc2acc30c31c279f3dab146d748e7aa9b17eda7ac039c8f
+   e559e8bbd51113f84ebbe35ab16bfd46cf610a5c61307b986111ddbee3037f7a
+   bac90f3afdf4f4828368090958aef5e49aa83d25fc5dc15d9b8a354a30961e75
+   253eee8f614306e59a31d9fab5423ea269b67babd54c52243b86b8af1372f3ab
+   69828b787af1831f772a3bb9a410dac8bc47909ac6bddc94a5c600a3167ce780
+   1903e9ca239847045875b0bd4e1575a724d9f729e3cbfc377de17ad29839a121
+   57bc65c0fd8495014f31e3be740967f3fd1884bee743b20b947339923530d63d
+   cf7427ebf6088e6f3385275f993b5c06ee14f738b59d49ecc327521ddced2a4a
+   74c2a4122225e97b646d6a38584626a6ed811506ee7cd00b48ba563b7a776380
+   604f163d7d7f4987c8aaf2e7a946cec1597ebeb59aaeaad0dbd0737527b9350a
+   30e7ae69cd5fb42ec00ca840988a59bf5688aa0b810bb2e9ea24fb5b322891a0
+   68caff542deb61b055bf65127a94d8ab107f5d2496764f97351dbbfbf34928e4
+   c0d307ece7f18150d958bd88bf11912dc818fac7cae06ca9ec3fafd15d452af8
+   731b9ae286f29660fd0814568351bd6da114f3ee8b87c217cfe531746faa8c90"
+    8
+    273f799fc9ebec77aa444eb5ec95f64029cf61b875a2f94e228323844cb8ef79;
+  "85b3448d0292edc0b14cfae9225989a16a61ee8441166d5b97faf876b0ab6c7d
+   88b0f7c78f8390b6cc1de0afda111326dbb41e7603b82033902eb56ea542c2dc
+   daf45d38b24294648a7b203758ff0654d42507e958bbd98c72229aae0a9e5757
+   98b44fbbf6e45c81c2473b626307506881a9fa609c546741b3637b731ff62adb
+   c0779c0f0a35658998ee9cb6b0cb6b7e089b7f288ea171c18bd2664ca5c3fc1d
+   8da42494a2c1e2034d2009fd486cc230085fcc8af171e2bc2cf428bbf9b4bc86
+   6dfb99cec539941c9e7d26e5640641e4ef2c3f1a732f9c85759858a95c346ea1
+   471a369f8d1d3341ac707f1c41e5f0655cae51d8a170037ee349b3c14e01be2d
+   c1b75b02941ae0c2e398a2c8871955c8306f6ab88cdc6d751e11b35605d10829
+   ea508e41e33ca0b03b5d93a54ec359e01a5a00a98a80f7e6d998641a6cb7ef58
+   bb009a72b5d5be344a3ba9509b6e8eafbafdab4b0ec9202c8d29983935c6937a
+   fdce2ff0df8548fd7df3b8a087aa30c819af0eff3b8931e5ddedfdb0f4450919
+   eea3990f7f4045a3b6cdae27e4dc8a8062049ac4423ce46108ab464d866b80f3
+   a18000f37c8c4a30195e71864b14f170a3f5c427f4769c736fbdc18b3fe68887
+   ba9aa19e99a69b34f357f92d95a6c409f1bb331d1d27b693164cd0dbb552c771
+   b5863e0215351b2f9b6f661ab94c833016bdef73a34b100b6db79ea8d4b22ec3
+   983eb31be6cd1cd4cb53e489e4535683e21c00e6c52f685e84bd3cfc98f9ab2b
+   c31c18c6c12feb3be4e51a1671fa6001c1dfadc0ebb35349766d9d07d5a70025
+   6f81695294071c711947499c2c3d96969a70948c29ea9506ff675d25052f0950
+   3b42ffd7fb054072e7fb93bfa63d24511e6c93455cdd5b9be3c8382a3cdbfba4
+   6d7463ce0227e29a2706b8ad6be0d6cefa173c261697520b23edb87a189d31eb
+   f6cea0722a490515f48632f42f167a911ba00fd9883604e52d713210f3d9475c
+   6281bf17cc14876c75e9620d8bb9bfd6e4dceae1ad3cb675769f94623ab3a955
+   2c943465a6d4484c71b2c5ae26e1d738059667093450cff54e6b45f12a7588f4
+   3d9ba6aad36754c5c767a0f288b6dbfcd2f1e21bd14094f4ddfb7c4bb79ef882
+   052e95ca0672218808e36c18e1fdee412a945ad735ea883abd527dfe8343a51d
+   3f8ec0ccd82005e01ffd1fd7413a2a1dce1a177cf53474904cc46abdffd22a22
+   2030168387fa230e7a77eae5f051b4e0f1cbc53a78a5df640479c9fc373b9d78
+   3abd6a4fb5a585bb1b4609cebbbd1035392c7565654331a173092c098e1583a2
+   6bceb64086f3874854b4c89d31d20d8772b2f48be6a5fa1fe572be9927345103"
+    2
+    daf45d38b24294648a7b203758ff0654d42507e958bbd98c72229aae0a9e5757;
+  "8a9e76766b2eeda9b4de923344005a825bd2475bc4d529b033de3510cd405b73
+   5206880a0e1c282a10e03253c787e005bc9a18613b6e238f1eb72c604844a2ab
+   acd4fe99d1df199ca20c743238a2bf9562ea4de7b82061d1a6861d77146bdfb8
+   6dccfdff241fd837508913d7e0b1ca3e7a426be578c2e82612f7d2b2491f08f1
+   76aa8f5fb4b3592ff58785ea27d287fa5f250fb84fc9838fad8d6a2cfc223dad
+   71019d81508491afb6a33d8c99aba13d59c63bb88a2ba1182c144f171ed5a815
+   f6ab8f0b95fcaad29def12e05f348a9a35449c7ef5e2859748e69c517f4f3f65
+   237b33cbba9ebcae93f8a4fd863f62a03651be2e936ddb5a62dd3b6a68734b2a
+   4bbe3113be34a9f7fa26dd96258d1776797b8ea454a2f596ae076bdc0f5d0ff0
+   19ae0acbd7ba59869b51caa13e1041bcffed633235a858f39d0d583575a64123
+   cc5e18fdfedf9a416727f81b24a227c0c0771565fff69fc3e19399a254d8c9c5
+   50765357fa421d9153c1f02adcc98f188d2aac6a39fc8d522c5e81fbb775bdbe
+   10e3e53b7605240cadc28c4d3aeb1afe40b7d1d547f4ad60c8d03006b42fb499
+   aec6bfd729a6e2898890c9ee15338aec209c94141dad7b7884f7be481a2f0d6d
+   8f9620a5b985a3a1dc4825f1f4c683457a98f799118691bc57b17ab42713b593
+   92c24c6920edb4f37e73dd795ac9bbfcd8035dba28421fce290109c222bfbc86
+   45bdcd99b590e64aeb5173c7538e77a7cd10a9d786338c43e3a0946b33a9c822
+   e0b86e6b4752ea2cae053b1bd897c6d749c7fa46308be876b8006c3ffa2d6479
+   6cb53b7769f0da52c697c8640c029099d84afb55c20c9ac84b959ff36c339e92
+   a21436f9a4c876375d16c41bd3780f024b867f6fe6394c5c64b4ea5a6f306c7e
+   93b40e751d291e90ec3adf902935285a5746781bfc1c594d520dc5828ba53d3f
+   6dc080d82251557b9804deeaae90bb1a45d9895c5067f3b04dbfcbb5ab0be3e2
+   22783694c9ab9d652dc216306ea4fc09734e90bd08625e688b9bc1b8c73e3366
+   078b0d30cc5fbb248a5e84a416a3d849772ef6eadf20f73eeb82125f68a216e6
+   83dd79bd150e5f7bf7a357236ed41ca06b8c40bcce840e118f6cf457ff151654
+   72169420815aa9a38719072be9c824d68a0cc5d6b4251ff9180938def3dcb0ac
+   63f1febc1579b537b71e1fd12687ec49885dbcf93db68f44660bca4780ca9aa8
+   dc337f8a3699ff549dfa26c1a5ddab43cdac7062d90fc2a779ff528c414035f7"
+    16
+    45bdcd99b590e64aeb5173c7538e77a7cd10a9d786338c43e3a0946b33a9c822;
+  "aa199ae7d7c298e11aa74e5bcff2f206fe6b53962f3bb39767ad6df19c58d93d
+   4b95d1e296609760e06e7e476af7182db41712d73be94a3533b7332a7dbb780d
+   b72f91cbf1117db1982b035f0e76e51bf4cd8e968b932606450bdae0d588906b
+   a1de9fc4d0e579aad319de0280fb45b5fed6c9d38dab5216ff8401376fce0230
+   fc216489a815b0c98969118c9ada3f7152c4eb07217abe54fae4fd4d63e96811
+   b660cb7ac499821dc872c3400fb2590527659ecd72df16c7ec5376075fca7d7e
+   3bbbd9dbbc9263d289de49b1648fd64751d8b0e6d5d506a356fee0ed6452ce89
+   d17efdc8cff826d28ab55b51211209a27054f2d33f108f34ce7bdc5c71b918e1
+   21da90e37be817920404ff5015346dd05ef32e018632e09b7cea35d42eb1de1d
+   66da40ef6fae8df49b5aca9a2400ea4fba527a9513c821e00985625615e71416
+   61e5b60766ca457b36aeca26a62e6f4831691ef79bdc72158c2a2b85fe3b5cb2
+   9a0917795f936a5384c4a504b2ba3d7056906ea4e34474c310b873f88890bd37
+   af65ade7e8f0022420932d50d0a8587c43ac4436bc511248358886e2c7072c1f
+   fadd2a9fa72f438f147964180ffba490beaa55baf6275d8ca347ce5f5f94fd05
+   debd9beec2527f284790a9ca8fbc074ec359f4a89974c2ff49780fcb21c5ea91
+   f6a57794ba1265d9974e52f856acd3dddd0f6a50844172466c82f0d49eef676d
+   97cbe03e723431b6c14bf1681e845d530e083ddaa26f055d3e162615f57c113f
+   b89054ac8b7135c1e6d215e4e5dcf679298fdcf6ef35301002be560389f8cd08
+   8ba6a9d5ee4bf15d87170e7c050699e858c6316bc92d5f4e19eeb3ed82e012b0
+   bf0f272aabf63cd98397f4da2fd3c5742373529c91ab455fdf394fb6d0b8272d
+   7a2a4980dec077abbd6a06f8b90219b818d4990b8f62b9dfc50bc4feec31eaf6
+   f1d55b4e207cf5b7bdff5f59a63b55fbce6704b5ace5c5183f6be8e4770c567c
+   d55b23bebc2f16fc9adddf06ece363add71c4cfd73ab228461cfb926addee0cd
+   76ac92ee62c2bb928bb5ec11673b51c2f1fec44ca27741a647cadfe55733eb41
+   1544a9b6c6cf77fec3e83bb08056bf18f3eb440611249f60cc97b58b5a93d364
+   702a0023d8ff6a108a2eadb777569f54df2c3b85634bb872611ccd8cf74e2807
+   8dc8889dae004e88a94f3c3beb4d39da7c074a038ff8899c5798f7a26fd17ec9"
+    19
+    bf0f272aabf63cd98397f4da2fd3c5742373529c91ab455fdf394fb6d0b8272d;
+  "63eca008f74f57babb34dde1fbaa5264656007f7479d8df3ba5cccadbe83925f
+   001a67bf61d077528bf9b386694a99d7293d6b49f368ad54767a2829643621b0
+   4c124850c332a4e2a6a335e5f5676f803ede7958719b083f648137cfccb82f50
+   39f293fdd5b28c882b824d1cfef38a327334776139bc2d814834a86d6b2d93bf
+   114df0c93aebb6a764740e43a67c6b582b49f6d0c393a23db42611023c044d9a
+   cd9e11bd49d7ee82e52f89d7100fd64c4474695054cd22442ed2bf17991cebe8
+   56931f05328bd38dea431af6537fe4a4f1e419a24c5181974e61b64367a65a5b
+   2bec95a108b7a500937b5a3f3c54ae9b2cc7b11629ac581f7d8663b9c910af96
+   380777fd3ab97d140a142d3d37c7786264ea00b63083219652376d7fd56ea846
+   f0fb2846d9cb0b88751db963f9360ff2bda25052eba9edd2ec561807c1f0fc27
+   34294c58ff5ff91f1472dc3d7b3099c81ef434126c58de3751c788a71f2a78de
+   05c5a1c0bf29c1bef5da9298450b8ce6c5856b3f7e2037133734a03959573927
+   7fd9db5b2418267e94db49ea0534ec8d397f32f90981448c944a4ff3cb6d9c3f
+   7015d096ddd557e669fcedd9b3b2624b910505f756e8ea160c5436bab604669b
+   46858fe7612b43ba805a6c7999a3be02b1e635963792d228f1414fbdf13e175b
+   70422706d36540ece562d1c36bfc5b178d1cf47c1ed87bea38be5a9f95010521
+   250e48d385aefbc10776582e71e4139148c99d6f9ea8c46a8e57194986eb2ef8
+   44accaac045de3183f7a45f89d4bdb5534594c90296ea664061f3f8a142f2d7e"
+    9
+    f0fb2846d9cb0b88751db963f9360ff2bda25052eba9edd2ec561807c1f0fc27;
+  "3fca772e14531611cf82782ecff97358f710763698b73e84479056a97d7d352f"
+    0
+    3fca772e14531611cf82782ecff97358f710763698b73e84479056a97d7d352f;
+  "fd8d6560ef50712fb5f0707c342f618cbbe5697d261d249ad4887dc5ebac4f07
+   89c98bc89a81402e218e377257bd1532d524dd33a3b8c0458b2e5211d4d7b305
+   e48938f9271a8861d46fa6063563b92c0a6fd59634151b075316faad9c87008e
+   332fb871bf280cb18dc5d444a565ab1e505d274e52c231808af7d52cc28990de
+   9073abe824ac2d30ec9562a5a67836af5cf9c038aee85ae1f7d387da64f558d5
+   04c3ffe8e6ed014162fbe6f3b8467114afdb6d5d51ad878c4462d8a926d9966a
+   5864d08abd45dd3d4b6e59762a8feb76cdbcbab01a66e512d40bc070e2754ce9
+   0a780e6ecd9b4ed16cb4fd1b4b060c74d97a4268733855102b036f89cb4d5bac
+   34bddd4d2ac8a920864e6b9cff04ab70f9978a16d0ceb06aee33aaa78e49328e
+   b65e8424be6a9247ad08f01a28e887bca33b3f5c28ef3adebf37798972eb99fc
+   ebd2aa397fc49104dc1c3f82f275bf625984c8c84a6f699e801b736c667a8cb8
+   8a704e508538e1d8a64c4c9052f46a07151c79dcf95e6359a8e5f41370ba40e2"
+    4
+    a373abe824ac2d30ec9562a5a67836af5cf9c038aee85ae1f7d387da64f55855;
+  "fb1b4c61b9b2fbe2faa5c0e3227e3c2fd4c8277aa629fc88fc18a4a29df3d6f0
+   3431d240f65ae76dcca41df165a4eb4c5af155027844d80a0c7f0d07ca4b5761
+   67e879347f3adcd41cac36e8c80a0f4c2ea80eb08ae9ee2b21e528769eb4c7bb
+   ce843b0190451928f2e637449b5ed95580645a0e0440ab017026631c619d2bcb
+   cc85641974b86dfa780e3edeafc0d6730da6f579826ba8f9bb8ab065b1e149b7
+   2f0c812e2c9114bef4810a01d108ff001fe328d575cff750e30133b464e2648b
+   407a5a8964f840ca90aa4cf79a18f5760f7a8ff23bd6bf2d6dfc88c980728aaf
+   26c2b3f4075ede77023b2de230edf8ce5e75a0cb9f1d81a0d154ba5d79de83f6
+   cd98878185983eebc6f188559d9bbf8dc422eca6598a7df35449d0b39106c706
+   42aea74be96565c44c08df95a6aa58603085152d4f7fcf38375283859d17a46c
+   31383c1609e8be3dc7279916eb5bb5d3e95e745a96f55ed3d69f296bfda19a28
+   dc140f380ac16ab63124f9f7a02aa458ceeffbed4a9b8e31f45c67ce6ce1c394
+   81bb67da90b02b5b19ce9863902f12f33a85795994d7d22b914f0e82a44a4f11
+   fd76e39b1d68f07e538353c0ffeb0c1225f5de64166ccd419c10134329f954de
+   e9f40437c324cacfc6974bee082cdb82c432a86d8465a0229a1e05fb19dec82d"
+    0
+    0e1c4c61b9b2fbe2faa5c0e3227e3c2fd4c8277aa629fc88fc18a4a29df3d670;
+  "c2b1fe3853bbed5be05536475b2f1bb818eb5ed0111f3be6c6b3bb8ede2d0beb
+   a692dee2a40878814b9ded7ba7ba47a391585ac93af04a0addec3904ed912ec6
+   015e98f69b98f157f559f8282bfbd20e07cc4a9e2929feab5a8c246011d1098f
+   76761cf13e45886da2b747f0de3a238be8aaf5868eca88c4de6b614ff3902e12
+   b6b06a046fa5f2e43e698fc96818cc7bf888d5c4f4f2f0bda86cc35c1b48679c
+   d7ecabc614122bb6908ebabcf7bcfa9a4fae88bb8450d559297c778dd35279f8
+   cdd96bbd24cc00b4fa5c8b20efa66a3db1d62e76f001dbd87800fc59f4a29a1d
+   9c16ca817b43101672fd1cb3583a6b44bfe2ab5956794280a3a32bd2aa651656
+   4d7ba5f8240527b3c9de386b00dafc163314b3f1311bc30b8434993b50e08d67
+   c4ab9766eee58337a92412440f12083a0205c39ba27e0877613b4288dfce9899
+   71ca275f3f7df242b5770d37c92425bde86184ab23c06c6b6bec799c47651433
+   49da5429ec1ade01eba828ad21d230cced84c8a28f239a69194cc0b5de9a0f20
+   fc17ee1656b6f0de36158fe2db82ad3f63c196c54002728bde4c5e27e6c0d7db
+   ece944bcc82f520e8171aefe728863b99a9772cc48b714d82426224b302b7be2
+   d2ea262ae062bc1167e79a7bd8abc2b6c7cbbdc03622495d1ff3a56e23c03f72
+   9be5176e8e873f9c320cff256e7b8801cdc1cee0b32ddd715d71abeaf909e0bd
+   0e666632a0ea9c9c5cc3fa519a42c34313ed2f64057106e38dddec87d68146b0
+   dc48385d46bcedbdf17f43e7b2de274556b411a0ac4b7e89a2f5f71a1d1ea5ba
+   76919d83ecc757cfcd916e23e5cadbdda21793a322c0fadad4e581819ebc0b18
+   84830e7a1b4b50e6ba90fd5f8b1198aa60b0c8987c962e9eb12adc2cc389ee1d"
+    11
+    49da5429ec1ade01eba828ad21d230cced84c8a28f239a69194cc0b5de9a0f20;
+  "99f065bb53134babd50f3f46adb63c64f7600acb39487718bc0a39fd3a5f4ebd
+   f70702612b9b45f7833232a7267492299c23caeffdc4f8a494653cde777861ab
+   16c9b6b125cb9cbb201cd0a558fd58cc29f2d197b9b160a0cff88ac890b9e429
+   ff87c5e3356c8fb8dbeb739aaedd0df3da2ec3072e5a806569a5847fcbcb4267
+   01d23260fa58bc7c077e05cac9e1359a9f4f2c9f2bc8312e0832376e3c3cc554
+   b7b5071166d68c704410d4e9123a261631822060c336b8cf0f5685a7df6ae6ea
+   621633e25b1ba392baaa31fc2d6a57e8286f6bf6e5edd5a0268a895af91d61c8
+   a29ab1d52fde5e7026124c3cec2be1fa674d37692165f46d1d91bb9f41156a55
+   26d8eb53078f2e515bdee3adc377a16b54ae575343888c27c6d72e07dd7ded04
+   ba5d57dae01659afb41b3b4712f0ccfa3b6b2a0d8a99fa5f1078203925897618
+   8cf51cab05199e2154a5bf655e6a9e9498c20cd08b564936b164b0a7f49a1e30
+   c5b3977228539a7f573c88800633f1da39a3f1bff9e1018af48f94f211a812b3
+   149a93a1ded07e398fe248962a7656f9b0f15ce62c4aa0bba4a3c6f00cc362f7
+   234974b4054622b0672626f111ea5b44afd81dcb15f29974585c9b77476d9290
+   4be4b2338d92909e6a138d4d2e53e72707a4af62acc8cf2a121c8105ec4ebf32
+   1e6192c030263e3847898afaf5003000552b9ccba7caf6361c1f34fa0890b086
+   ba698e634085f7dd38da012c8c97efb97a9b3c08c829d660e72e46d12eba79ea
+   712198efd6734fb564278f1bd0dde082482078548dcf4681e65e6dce39328c1e
+   8cff8caee2ed08e384331fc0509c1ab44b291d840d19ee991c9978bb7642b4c7
+   98a539cf588938c8ee31d80ff0254e13460f50d7907885f2debf7b68be91edf0
+   f0cc67c038324ed37948dfd94ab50dc6fd07ea8b441009ea2c4e185f0d800b85
+   09ae723e872da1687e02c883a254e033e8c67e784ed33e3a28eb8cc92be37d32"
+    6
+    751633e25b1ba392baaa31fc2d6a57e8286f6bf6e5edd5a0268a895af91d6148;
+  "97379391993ac07a0b019c4b6d2d08d4555e5761b4faa7bea8eac269844c6106
+   a2aff4f6141eedf254a8f7122ee37a1403b97fddc2805ce4ad010829aee1575e
+   a54665a1ac19c8ab83dad06bb5ce855b45246a9ad338516c5d67948f86eb1aa7
+   b8fa1fa064f6bd0af94d427686a09472b6a841576754500464ac3310cc147d40
+   dbb4cd734b211f5ad48452a193489fa25b0c82a594105a96ad627c5cd5328596
+   5396b8de36ade038e4424344fb2083226410f771c8ec979e916f37710b56cffe
+   039b59e759c9a380200b129e08d77ef53d703689b60ba5f117111ddd27f1674a
+   b3456d7bfa566b925ef014c6538c89251b7c0fa9fea89fd1806f97bcbfc3cdb7
+   4ab7a386cbc720b5676de0e76d584d6fa538a0015debe30c37e1839165763d5c
+   f7f55c12c67c1ca28b3947fb7bd7c4ed9a5240f962425b9b4810191d448af7c5
+   8dc0a95877c2ea17052b55c9f93440319ec38bbf80b375177e84ad14bab558dd
+   246d97123750b41e5bf2d96f10b3c9e66e92759373999bd94191a65f25a864f3
+   5bfa2905cb0b0aef125fb39deb2cd392b3cfe3f3ec58f8361e8cd5f12bd2db98
+   192413efd53bb958417f65a818d48d6bbf94dcc77210d9623adbca15633bd7ad
+   ee95faf7a7f31c7afd13d393ff2ff4e448799c87c62092e9e646efa4c635d1f4
+   77c00984400bbdcc81aeb42085c44be70137db5a0464f6081aa9c8e646e96e1c
+   743cd93d6f6a48161881d2224b7d7c0ce96d56d54adff0b719955cde417b35a6
+   92b99335dcf6b33de126d05329d8884802cc3afd0f93e9dea7db5f6dbdc6c623
+   584ccd19fe7395f9f2dc53f2a9da292e0cccfabe82bc46aa64c29581fc570deb
+   f9321c751abb9df278fbc2054e3fa368734cc852589891b49580332a52b6bf72
+   debc2bf3cedb7c897924936aac0b485bc05eb89530c886299e8d1ccad277355a
+   472d49f8ccc249b8271fd0630ab575721852e98015ea27732915ed06775b444e
+   7b29b054a2347baeda4dbd1b739072e6d144aae3547adc8287c3af84285057d1
+   d7a79b1f1ca757e17729436fe744ea7d99a64d13bf85737b6a71d41ab13343e4
+   a957b6345193173a231d9db8acb3a6c09bb411d210e0e52c94e75a4d68602aba
+   6277d818cbecae95f1aea85481ee631ff1e7c77c6693e6349d1804db784238f2
+   27e1d5a11dd9025508168d9d11cce0b8f0768b6846105161eca53abfa4aeeff6
+   1823372e2c7cb9fdcdc97ca64ffa06564907b09015472cfa73bf0a45d7c90bec
+   08cfef24b9eb875598779315de4fcfc918931e05f49b374113c25cb5b23a4944
+   3a5d9db56bac2f413a3d33b6d7a2f54053aa3a641d6554d6f008779939f2682f
+   22d0256cb1a53aaefd5d2fde14b63e5adce607ee5a22e8498f29982f88088938"
+    18
+    6b4ccd19fe7395f9f2dc53f2a9da292e0cccfabe82bc46aa64c29581fc570d6b;
+  "91a76b64122a404fbf873d65089a7613bd3d93c4227a4b05817223640ec20ee9
+   ab46f7649122de1d73278608e02d44a1367f4f5a7c01d1c17f2a50fb3148dfcf"
+    0
+    a4a76b64122a404fbf873d65089a7613bd3d93c4227a4b05817223640ec20e69;
+  "1c12d157172079be7ecc31716fac8946f5517a3da6612bf4a0db65707e72764b
+   9d9ec126bd404e82448a16c187152307ab6319fdd5d4280f070275cedf1cced2
+   25be86a2abbf7619f7b92855cc50572af4fcf6ee071078d24baa24d623ebe4e5
+   9b3a13dd1b67a284a9ed869de2663d82035342bc0cad65484da1c7b60b82a55b
+   fb82840bfd348ccaa0d3d362c1123096a5103a09f979e2f4acdf7aa600e55a84
+   c64642a4946ed50924eb1a4c6ab73b53942c5a17cc868f8c6c5ef92ce5986830
+   8e7aaf58bc15be92a31af4f0b092969a250222e7ccbdb638aa846f8253c33d50
+   375bb009118659c831591bd6861e9c9eaec85c0fd9a1facd5f2767ff27e3d36f
+   f5b4b72840ef438fb8f7fd1419aa5248dc38126cfc29099cffe68aa94b215b31
+   3b0cf55a0dc7856788375bfa1390fe4c628c271c99ea76ac78517ad5f36f61ac
+   82cf74084903490f30152c730970f8b622de5414e1a60e1efafc6aa57ff2fba3
+   9d476226e3c4f844f392e7efea7726b02bea64c9aa1e78513efb28a000cf9624"
+    11
+    9d476226e3c4f844f392e7efea7726b02bea64c9aa1e78513efb28a000cf9624;
+  "4f8b3919461d4408a4d4375688f8985332745cb5253671dd7fea3c58b8e33e5b
+   ecd4f6bf71be54fa88e51fd9d98f60c009fa1b4f15ccacdfa7b26a5ba52b1794
+   b0bc276ac01ed6b25fb569ec8c614f4a9299faadcb93bdee4dc637c888381d29
+   2fbc1564ecd906f5d56838c9ceb3ba5b5f13925cadd653008f1ee9f54c18ea37
+   66e9f3ed35f45675f9601181ddcff688229371c6428c1d9dc67699821e3130b6
+   6b08a213ca51403db7e08bf6945b23ccb62465f582248661b901b6e550345516
+   abdb83672459dad5b11c3cf9e4d21235ff92c01ab00b2d44aa6f10bfe9b274d0
+   f609191b4efb288359af7170acd0904c57d45c7c658c0d670e0fb22f9ebc0044
+   e4056ab4b8afad5e6951c8168477f15ee3e11fe3f236a1d19ea201f78b8898a5
+   f3b253fd18515ee3dcfd4a14409838a3d993a5274bd77a1e5a7088d20ba6c592
+   710b8819a202ab80bcf308aa94d3305944dc739e33648df045bba215160f8ee9
+   1b63314e9fbd605ac063546ee4249bf9f37da0b6b78d99848f487c6880f70c3e
+   fb04f3e49a44c4eea104c213446b0e6b81da047a0862604f488e0c6128238d3c
+   43b1624809a253f46b12d97aa08dc3f16b25613022483b8044cb01b6d23cfb28
+   0796291d8916b0b70ebdab0f42b8cc55c14734cf7a398d48f94b48d9871ff0c2
+   c55cc772bb71392f13258339eaa1d8b01c402e8f6c9b6061f0e1c564feb98234
+   882ad3994d999ac7243ebe9955468a52b2242564a295a9740af8980043f9ef0a
+   201f86fc5826d74580c3bd3fe04cda2a823c2a4d1ace3e862a9bf6873ba25055
+   5c39347c213f6e1b5ded1de9f92ed21d99721c4e4216d5abe207321caa426971
+   38ba53a577809f2d2c3cc33016e6141f4a87b6f57b75be70b9cd3d287f07ab00
+   7b9e12c5293fd99ed3fb50a2eac4587bca4aa8bb97c147626dcb9688593ad2e9
+   4852c30283c1ffa109aade1353d11e9712d8c4e6d416926f231a2b89b78fbdbd
+   80d25270ef8002232cd0e35433ecefc135cbcaa06511ba3ac14484b6e41c953a
+   6159366a1aee4692a9986a12234728c685cf766ad3e2c4cc842f1142c0fb856e
+   95d34152d18b9942bb13c6bec8e533c259adfd69dbeb06da63c351997463cee9
+   dd5890be52cd0207fecd0f93dbd3a6819aa2c5a592ca0975a419104e7ff4c284
+   d9c3f02b7644b3580d190f03bfc9accc8abf9546463a2171d9cb19b3783e0c92
+   e59449e7a9d07631450d85d108f3cfec2d67d63ad65a7311b310bb10137fcdbc"
+    27
+    f89449e7a9d07631450d85d108f3cfec2d67d63ad65a7311b310bb10137fcd3c;
+  "e5d98efcc2879f32793efa8f96dda9c87b70834fc9d468dc464b0940a7dc160b
+   04d4bc5cd4690a0c6561feae82c6be57195c7553276f12aa16fb930ac47e315f"
+    0
+    e5d98efcc2879f32793efa8f96dda9c87b70834fc9d468dc464b0940a7dc160b;
+  "bfbed3f0a31b886bd96a817e0b65be1b1e374fddb237514e89fee7ce34a08c45
+   eedd85cd817fc74938e60c366445e6bd5383dedd290db3633d5ed2ff320139a2
+   006b1e62b3aa1830de71c0ae063fbf090e536304d601e6c851800ff1d501d249
+   a4a63dcc680646b69c8e651dd9c3e043bad07eb9bd6b55bc5bc854d82bbc6b00
+   ffa2e97c95ef5efb87b78e89f35e95f89c1c1b2591673fd2166fcc9765abb4b8
+   030984d84d3d9667e436996578a3ae58853d44e111990221cd15795167475426
+   da8350e83ac6d67029c24a8d386c6352a27bd22fd6a207474a952742790e4be9
+   0618b6f82b936b5eca87e9ab8dcd9a2e3744586bae01a75cfabb23b1b64f7aab
+   5a3e077d0d0d28ba3b6d6fefecc6c2f7ca530fa63bf414976ac8b26ed6596a3b
+   381e56750672340b18b60612bd462ade52d3b0d5b487f1af8438140740df484a
+   65275cc865fc4b5d94023fdcb929dd27dcd64870773c79f015d4a5f30751ef2f
+   724f96fe61888b5a885713d0c52e759726b877031b3f4f80ad24bcf417a3dbba
+   17f55299b7cd1d851091052401612078978bf2b09fca8c9e2189474e9d24b81f
+   14b82eebd7325586c1ed8be9353fe5ad9375290a92e76d13947c6405febb2f52
+   eb5a5c7771ccf698a2e803a3a4e6db056ceb0da4d808db5758f2cb28ccc44bee
+   96db7bfd64b7d41430ca6fd0714487926d02dc71571161f8deea0f6a3b52ba80"
+    6
+    ed8350e83ac6d67029c24a8d386c6352a27bd22fd6a207474a952742790e4b69;
+}
+
+condswap {
+  14e55571df646a69a8280bf8dbf8e9afc15bf5558bb8b8236ebcaa19a96053bd
+    8bef5021598a8175565e1f2b522ed1c4306fef4e0e973b50d3a03db1fcf11a43
+    0xffffffff
+    8bef5021598a8175565e1f2b522ed1c4306fef4e0e973b50d3a03db1fcf11a43
+    27e55571df646a69a8280bf8dbf8e9afc15bf5558bb8b8236ebcaa19a960533d;
+  53d8c54864e18f8fc742b2cb996f1d7595122ca9c90de9f49485cf5a5ef05058
+    9aa95be655b6704a3dd482e8424f82d17443ae26ab41092fad95df9cac678787
+    0x00000000
+    53d8c54864e18f8fc742b2cb996f1d7595122ca9c90de9f49485cf5a5ef05058
+    ada95be655b6704a3dd482e8424f82d17443ae26ab41092fad95df9cac678707;
+  8c7b4ffbf50edf7edcf8d69b67796de38b56a5d4e3a9fb2201354cca0b1b7c57
+    856e707988c37e59fc6689d024b98bc01b71034484ba194ec7f45106267cb7f6
+    0xffffffff
+    986e707988c37e59fc6689d024b98bc01b71034484ba194ec7f45106267cb776
+    8c7b4ffbf50edf7edcf8d69b67796de38b56a5d4e3a9fb2201354cca0b1b7c57;
+  c8cb24a636f6d8f2c045c8441b21314884a71d55c73d4ef7ad65620ac0d86616
+    02b47be53df7c8521d57589256e69b8bbeb1e838d84c090287c04a25d5c08e1a
+    0x00000000
+    c8cb24a636f6d8f2c045c8441b21314884a71d55c73d4ef7ad65620ac0d86616
+    02b47be53df7c8521d57589256e69b8bbeb1e838d84c090287c04a25d5c08e1a;
+  7d96f47612fb7135edfa71dd4526d8b4c944d74ddf004e1653d3af52485168b4
+    a4e83162602d20cf71a279c1071038ecf94f38be11ad1191927b3f480d393e1d
+    0x00000000
+    9096f47612fb7135edfa71dd4526d8b4c944d74ddf004e1653d3af5248516834
+    a4e83162602d20cf71a279c1071038ecf94f38be11ad1191927b3f480d393e1d;
+  c3a3d4462091b36bd6fd494e70c3166478be0a65bca7f7361246c52dda402981
+    62d0ae1abbe5cb909328f59e71330269e4f2b1d3c664e7f1f0780e0a4774c262
+    0xffffffff
+    62d0ae1abbe5cb909328f59e71330269e4f2b1d3c664e7f1f0780e0a4774c262
+    d6a3d4462091b36bd6fd494e70c3166478be0a65bca7f7361246c52dda402901;
+  38c9b0d92be50270e29cc3181952e745cbf21c8d145ae0c0a6e59f25394ea59c
+    caf4896a2d3666200741d817ee1dac661652b9a1741ea966d5ed7cbc4c76217a
+    0x00000000
+    4bc9b0d92be50270e29cc3181952e745cbf21c8d145ae0c0a6e59f25394ea51c
+    caf4896a2d3666200741d817ee1dac661652b9a1741ea966d5ed7cbc4c76217a;
+  d637a72affa4112bbccd2878208ce34fae442e97175e1b39f43c00b14d312a2b
+    76209f8b1f152ba7e1e6294f707831021eb2ac03872ed3774ab8fc5e6a0e864f
+    0x00000000
+    d637a72affa4112bbccd2878208ce34fae442e97175e1b39f43c00b14d312a2b
+    76209f8b1f152ba7e1e6294f707831021eb2ac03872ed3774ab8fc5e6a0e864f;
+  12f3bd417fb3860b2a4fd04eb1c51c558a4c5a3dcc1ac457654a45a3cd45b0d4
+    46f802836c7bde099775f3fb4f5f6345364a7e158bae9e16c4c99aee0cfa5e42
+    0xffffffff
+    46f802836c7bde099775f3fb4f5f6345364a7e158bae9e16c4c99aee0cfa5e42
+    25f3bd417fb3860b2a4fd04eb1c51c558a4c5a3dcc1ac457654a45a3cd45b054;
+  bf1809201f83a34cb07aa2e2372516631ba0513e600956e6702903e9084770c4
+    414bbc77d13d7b4e706acc07406e8d624f2485463f9948d81b72268c1e086a14
+    0xffffffff
+    414bbc77d13d7b4e706acc07406e8d624f2485463f9948d81b72268c1e086a14
+    d21809201f83a34cb07aa2e2372516631ba0513e600956e6702903e908477044;
+  bb8703f2ddaaaaa6ad19219684b1bde576b38bbe9065178b24c1bc55563fe525
+    1cb3ca7846a3c584b1bc05b25ee91d4779ab9ac64ecef0fcbaea8d311b55d618
+    0xffffffff
+    1cb3ca7846a3c584b1bc05b25ee91d4779ab9ac64ecef0fcbaea8d311b55d618
+    bb8703f2ddaaaaa6ad19219684b1bde576b38bbe9065178b24c1bc55563fe525;
+  a07c7110c32e362864a42cd2f371ff420bfd442d291cc15ec079d642b5c85bdf
+    497fa7867fcd0617c4cd765aa6f46b89390744b5b57d11ab732153e075fcb607
+    0xffffffff
+    497fa7867fcd0617c4cd765aa6f46b89390744b5b57d11ab732153e075fcb607
+    b37c7110c32e362864a42cd2f371ff420bfd442d291cc15ec079d642b5c85b5f;
+  10fddb7f48015b394512257da026938b67f65dd0a84dace51417d68da003a913
+    ebd6706b7cd2ee2d97848ee1adaa990d8ddbfad48e43f51d7ef843fa7597410c
+    0xffffffff
+    ebd6706b7cd2ee2d97848ee1adaa990d8ddbfad48e43f51d7ef843fa7597410c
+    10fddb7f48015b394512257da026938b67f65dd0a84dace51417d68da003a913;
+  1dd835e2173b936a91da37b3aa11e848e4497964a9a78ea929a19105eb981a24
+    3e6f1ab7d5c460dfb7ad1926c60b64a8dd48ed0115b0655a6d8619666b8c8dde
+    0xffffffff
+    516f1ab7d5c460dfb7ad1926c60b64a8dd48ed0115b0655a6d8619666b8c8d5e
+    1dd835e2173b936a91da37b3aa11e848e4497964a9a78ea929a19105eb981a24;
+  c4541b1380e796a333d88affdccb4d2bc68bc5a1b3890ef2fc1a2c38dbcac725
+    6f6338ad8dc0562bc02e307743b81013ffff6c135fdf8603f9956b7f94eb55fa
+    0xffffffff
+    826338ad8dc0562bc02e307743b81013ffff6c135fdf8603f9956b7f94eb557a
+    c4541b1380e796a333d88affdccb4d2bc68bc5a1b3890ef2fc1a2c38dbcac725;
+  d71f16494f041d1547e5dd9ed539e6b9c1506cebb66f6424e6c7aaf6d0ace080
+    78c1e6cc0b6f64e161def3b2ede7465f21f6afe61299e9a3c52b1a7a080b9b26
+    0x00000000
+    ea1f16494f041d1547e5dd9ed539e6b9c1506cebb66f6424e6c7aaf6d0ace000
+    78c1e6cc0b6f64e161def3b2ede7465f21f6afe61299e9a3c52b1a7a080b9b26;
+  4d90838ab9cc0a79f4e2aa6a860bf8cfbce5f834aab428d4a06f8ef4a2da582a
+    53124b302e7675ea5784e2e7d9fdecb38d9c8be158312dd81c51757bafb79b42
+    0x00000000
+    4d90838ab9cc0a79f4e2aa6a860bf8cfbce5f834aab428d4a06f8ef4a2da582a
+    53124b302e7675ea5784e2e7d9fdecb38d9c8be158312dd81c51757bafb79b42;
+  c8e764092ea695b0dd8f0ecbca5a4e02096c821b0f5cd57de8e3e50d8b2a40db
+    db7fb38dfede5259a584dbcc697f259ce380110636e301acb308bf687449110e
+    0x00000000
+    dbe764092ea695b0dd8f0ecbca5a4e02096c821b0f5cd57de8e3e50d8b2a405b
+    db7fb38dfede5259a584dbcc697f259ce380110636e301acb308bf687449110e;
+  34cf8e55b3d2494362a87a24907fbdab61cb4f452ef5a889a1aa40a22be6d976
+    679c6d6f6dca1b71bb098e3854c63ffb8ddb76f1a1cb246ce956fd71d6477c20
+    0x00000000
+    34cf8e55b3d2494362a87a24907fbdab61cb4f452ef5a889a1aa40a22be6d976
+    679c6d6f6dca1b71bb098e3854c63ffb8ddb76f1a1cb246ce956fd71d6477c20;
+  9638ab322ced065068f98597cc61fc2bd846b5849dc39a881209b8efcbc95eec
+    32922ff2b62e968417225b765f2787387c8a42fcab1dbec3815298f53813a8cd
+    0xffffffff
+    45922ff2b62e968417225b765f2787387c8a42fcab1dbec3815298f53813a84d
+    a938ab322ced065068f98597cc61fc2bd846b5849dc39a881209b8efcbc95e6c;
+}
+
+mulconst {
+  8d517a8804d934ae93388e1d59748c3c22866d7be6cec58a357ec43f6dd029db -319312
+    3f2fea85c9195f2246f4f6fd2e8d5de95c5065edbea45a174bc0d1ef3db4aa54;
+  1b5d6a6c9cdd0dabd126e5f5ee2513f3d27c56dd3aad89c882fe9fd2d38a93b9 499342
+    dd310555966ebe7f409dcce2933f91af8e14c8909f78e4f113606789dd7f504b;
+  9e03b44e93743e0cf5768f65bd3c0f255e001de330d5e1a863d6e4dbb11748a9 -284189
+    6e8c7f8d0f1476cf2603f5702fe8e8bba5c01e86b6e008ac72987fdd6721183c;
+  9cc65e302736aab9bf02dd451c216ac3dd2066af299d7f6bb361eb3b36777f74 -15738
+    8c067e5dccdafaf56301050be17b8895c07e7f13572bbc5ce1af8b5be043d91b;
+  7f36ff91ed165c6ee44aca261dc09e3e124c2ed8167064c20d9b84fa226e2555 423857
+    dc7415db1ab5e5a5658d089ced49bf97718bccc55e2f15b83a28157cbe47e559;
+  e8852c80db69c7e55d476ed00ca7c0735052f7f72f81198a57236feb89a5903c -140934
+    4923ee40bb01314c2fe9f2f87d0743823311b2d9265219eb7a6de5fdfd09a308;
+  505ef65d294b77e260757bc867199c4b0922b5022dfd6a1fe7478ea27ec102c5 -307893
+    b14d72c991a0bfc22b1b95934bbe589b6a4a1f9c76a89d7012f8cb03379a8844;
+  e410c260dc8c1838f3e9658ae586425039b373ee2ab88c750a51853b012af0af 471420
+    42ae337a920ee1b83768cbf0750f524cf1f9e98b99f195e869785f90a2356756;
+  e2d181914b54175190462d11402717f42efa37967b2fe0bc4433fd4c862fd646 492178
+    4c6e1ba6896d2d661fbf99b77f63e3095d3341f04bf258dc3e4f51e39c68f576;
+  9cdda0d7da106ef5cfb34774f48308b64953e92869dab0ba804927080509d8a2 -312149
+    4e75e56793563268480efaf6232ad702bc5aef6246bd44e3499ff437810b523b;
+  9dac4442858b8dcc324464911e6f23ed046e42612e8105dc3aa2b9eccea15dc8 -88818
+    ce52a0897600a05383df0a0b99a451f0d5568146b4323392fc164153715ecb0a;
+  c9f92ceffa7027ffa71e64b714c36b28a6a18c3608f8170d11d51acbee3c62ba -259755
+    89582517069925572219b2eec2a25029e8e1c78772ca8c50bf23220d02740763;
+  8f8bcf28f4920465680c8e15befba4ebd23c1e27b71c224c98461f69caf76eb1 -430350
+    e96b93f0aab6ca70f7d2c1121110efc320aff34e1ec693d7bf17bce1a756d622;
+  6f4d413a27388fe84a2585e809927bd470ba1b0dc749ae6e2dfa100617a5a7db 11486
+    1cf1f5bd0770d949ee36df858e5842805d121722de30d2ef6bc2b82d021fc14b;
+  e1d05a072d1ab70d895969271f44b7c9d1654171836cf234724d2f90434c04e6 8057
+    e32b3c792cd3b6a770eaa2627ff8de8895873d73d734b961646fbce0643a443d;
+  d8564ee3ff02c80f0bf3e9cdfce42cd8ac1012ad8ea74f8c0f5754b5775a8de5 -304373
+    884266ea43a6a9b72d113b437dae63c664ef53884c893212fd864412f4e5e457;
+  bf66769ee0cf873764524e760ee654e8d5090aa774f2e96144d945f8da37af19 -159091
+    d7438999b3bdb99a46e2f3dc8492cbaf52b0a19c651cc382c384940861bccb6b;
+  72b7d02b1fe23adea87696864c0a9f0466db85e39db397f0eb428a50e277aa2a -521654
+    a611bd153336e178a7f3d912adc2fb39b342132458faeedbdb0a35973efae23e;
+  ff5c39d4b7fff86810a7a3b14a58bc01e6ecf062116adaa78dac0d1bd3f6039b -140759
+    eb9e32bf7d027cda198048da50aa79a11bc99f3b37a219a2104c78f4affb584f;
+  a6f1f7f30e3f9e5467f180f92d2c94165fd9427d0c7d383b9077ca9a7e50dac5 -317637
+    56a32847c50bc9609db9796e1650fbe97524aacea746d3cf285f0f2fced01a49;
+}
+
+mul {
+  ## Easy multiplication.
+  0500000c00003800006000004000000009000006000048000090000040000000
+    070000180000200000e00000800200000400000c000030000090000080020000
+    de200094610090df0020fe0180270700650d00dc2a00f84100e0340040570000;
+
+  ## Random tests.
+  adcc6f10734dae2273304a6aa493ee8f96e05f2402341c0d997dce58ea57ff6f
+    df3c8d5bb6380fa278d4ff2994c7865bcc146596d3c3126242f0dc3509b57449
+    5ee2615b75a40367ced4ed4bf1578d13e7afa4d415f38f802b7e7b374365b627;
+  054bc4d5e9b78b068fd20645eeb1f03aef2e89a1f56cb50e5f1170a86529526a
+    f976ffa1d1b4a33d0fd866528897cea3eaffdc75e31aa65450a62ff765fe7985
+    0210280745f6c29a04433f07f880bfd2eddd758d82996e79c65de817c30e7309;
+  e361c6fedbbe081b7cd683d23a2bf0ac889806be7230b56d9398959713a300ec
+    c8121e53d78c2e9ba2ba7f51b7cb15cec970a63b4a642ac470aa1f2145f07bd0
+    b48bb1c7ddd26cd9e5a2cb73bb3885dbe4a47e03886d4dfd59e5729d544d566a;
+  463158a2077f931567d45e19deb4454a2ae77045db70a2c078e160ebdb74fd94
+    3f311e3f8d225016448fbce3fbfbe84002736e3b0d5a90f57d705ede8706008f
+    44cd97e25c20ae2fe2ef4f2630981a1fe54c79ebd904bc40e39d9fa615ffa76c;
+  1c73fca52556e01204d4b957a01d1049f2247c8666d90c1d3703cff16a38c8bf
+    e9afa0cc85577ec7eb1ac66d87260d5f3659936ff88cde8bd1c3fa1d499e8bcb
+    0979a8baf734c86a4f57ae400b7790c4985fba3088cb1b265dfc7a66c794121b;
+  6e2bab74e427b1a44f0cb181f9dedd6fed43cfd395d3708c4ae8fd2137215eb6
+    ef400834f2dad8763a1a5a58a37d1b36a78873860e4dac808d3166f13724942c
+    0d481adbce7bd82ebc5a3e5ed7a492e78a032ebf211a5bd2371c528c77954936;
+  cb3575b41d9521da5c85c6438af14903a8d6d9c3857aa8e101e5295fb277de7b
+    9f76715d2ae3c8ca182406553d3481fc36d67727ca2d51f5db37940aa3208d8d
+    0b2fa619265bd424b9e20d38bf4552ad63de8ab552166080d099edea5fbadf7f;
+  abd66cf3b20dc4c5a866f1a3b965f794a726f96dd00f576d16ead66eea3a1177
+    97f70fc92e0cda0e010f2a9d7608c33db954af18bc18ad55bf66e7d91ae31abd
+    dcbb2cf34274971ef030827865b093a00761de3da90e46f00e18d0fd934a2b7f;
+  3b3c96ff9be8e17e0a0d3979ea5e5623fff5fa18914151abf79fe66639beef06
+    1d29c361677805f1dd2b839e025e56208a10c0b8d9f2a8c490b0a892c0e27080
+    0050873016bc67023d0c479fffa56a5a70512f9864d00b0a3e951f1e85c8b412;
+  b263d4a71b6d963e0a972819e5e5805b9522f142d3c0ff2738c51cce31e9f0d5
+    64f3fbcff2195c297292df3e1cf900aae457e09864c5a6248ea21ef8efd557d9
+    7e6f6f511cbf2743c0fc1c6431243908606cb257d20f8a8a0885e6ecd000e811;
+  0df0497e1e01dbcc4a48d4865127d9cc31a9a0a56e90cc31619e65c1521b2369
+    9277f0c6a5bcd7c7ed8dcf7182795f67a12e856b126d09966689834c43aada47
+    798d270ae34aa2452694b4ff74049a6a5169d71c85bd1a9ac59625e9298cdf1b;
+  1dc64bef2189eb5349f5a8983c1854a40141a5390ea4bf8535a15aa71d0289b7
+    fb59dc9b08f9163881b10020ce040da296ed8c1a9a935c27ca0047a4d7f6342b
+    9fc23104cefd3014a469e6d3a0631338eaf91e24994ecd50bfc0b4547317317e;
+  975b108909e87803af98af9425d2a982865b6cc9c144985b32fe5bb842702e24
+    a69e9130dc40be50e827dc50dac05bf900946cf67ec35f1bb1705001314e4fcb
+    12d042e50d0cff7b43a5ede61ce827a99619bf84995d488fe9eb56a8de769164;
+  39c0db5a4b161c368b0f71c7e8ef97dddc444e4a33181e0743519f2a879ae04f
+    d3cc45ff509ed45998bd5f218408ad51f7457b35e8ad69d5431f174047d7c6e5
+    96b877604f52782ff2a5b1a12d7db642371ca993b648c4971cbf593213503219;
+  f8c6715e4a327cbbdbb08d74121619abc73dc421d7267029e39b50c1510d2045
+    63870a83cad4c1c64195ae7b92f3b19c830f35f1a3186815565d846c787c7ffc
+    286a0b8c6681a7b79a5f85426fb60819b7bd349e93c1e11943c41c8dfd57d00f;
+  49c9bcaf5434b8205a348df290a96da27df084f34047efbf91cf544057a50bde
+    54269f8b23c05b94c9c1cd74eae88d9227af12a6fb337548eb93c2a88a75a8a5
+    1e3dcab5d7361f00e70198b52e8fb6d1fba74abd79d99480527f6711b21b833b;
+  c7212b43ff0d10fc52d3a2a7e15bb9cf53856f7ce33b79df89e1d13f95a94511
+    5213ec20bd054491a5485f665075835da609ad4f3dc005744f061480862ee602
+    e136339fa01067c6c0823a7ebe2f84d917600e244a9883191900bb95a3b59764;
+  a15d62c6308448f1f70602f43be1825696d228eb170bed55322a21d2b1afa915
+    58afe65bc8adbe22807026aa1b0d68af330bca268fdc054406aa41c820960e71
+    996c597e0a024c2ff0ffe289d8c7270e4ea1d38e294d7210eddeb2c0725a1305;
+  ea233ae033ca93034bc8fd8ea3c0625bbb15b00265264fdd61f62cc808b505fe
+    09e12ef9b3426991f7119c2e8349278342ed0072317c4ec7ab24561b61396b39
+    1fd72191fe9f00b0cca6a635d14904bd0c1e0ccd1275e84ad0b7bde134866e2a;
+  fe1fd3da05524af4ccd538f1d2ede09582101fc2a47c2e63758a546bed6cc5ec
+    523346406ef3df6ac9a455d0d2e7f732ad01c88245b07a888cc21c40fce11a76
+    de6cac8fdc878d9c4eda6b78f8b629ecf776980e49fed56bab936fc03924f44e;
+}
+
+sqr {
+  4dc87ad85abe8938634492ce2ea10bf48dc4aa2fa37a6a0fde3e5a01e90dde2b
+    346297c756d77b8ea312ddc455223f4577aea2a2e8d944cb24adb487de143b46;
+  a33aed91165d7fd13a543760d3915c1b5d411a21895cde81b2f3640b87550cc9
+    f923e49da9d5f45e23a782f911fac1a6c2e67cbbc7b03ee4675a0c5fbec03641;
+  a1406e453db6c92ef808295d1919c5bb2491c0ce6d5326d276c57e57943e0acc
+    18425bbd92149991c4545e65495af0e6372289e9a32649c127122243204bdd73;
+  70a56b8484234ed002a68c8d535a4e527a61c360f7d4ee5b4970c8ace1e12de0
+    bed1c435139f151d0650577e03c32428f63cdb7bc1920110b5fdbb27f08cb200;
+  86c3236a6194f1585b4dbeb09d0247fb7d3ae08063ccf9fc4fde70fc23735710
+    9b6509acadd5d31c4c843e91cec78be00aec4fdf7d86132965bd6f62f078f711;
+  0e5e83c51a8c091673425c38785e0aa1d74c7261a035a891bf734cca8c8a3db3
+    4efe5029e99438835a8a45d0180b8de357eac82ba9dd8e127baac0d758dfca1d;
+  31c39a5afc33f8a8d3c570b9dc5389bea6fdaaeeb44cd7524f6c445b9583a34c
+    359b7c8791cc87aa8b3c799c9d4d7e1f4062a4f64436d8c01071597e8c262127;
+  5a06203c15d6c1db6ea0fcf468a1e3f09d68c4a0f64c3d7e30e70290545e708e
+    07f8b435ea322bedf613458b1eb420f1d6bc96741d69695899bd40f7eca6f72a;
+  b1973433646474167b791b326827641260fb33d6a2c96d4e963a6b091f824505
+    52a62396dbbceead62912f8adfed2707fc25edb51aac19b2a274c246f1209f26;
+  96b157d71e107168fac206dd63007f10f4ae1225b0761c470ee18ecdb4fff20b
+    84ba2a84b156437cdcc39ecc8b1ad01bba934d8dfb7d504b9f2442db0ad01167;
+  6167d77675e19785960c28df551b458e41dfd0dfe5e56e785b7367997d5eb0a6
+    79a558436af4310d3eaee93f9a7cab72bd817fdf59d267e2c530ba8d667a005c;
+  fb4b2ab08db932ce10dd62639aabbb266f9ce775fb5a5e0875864f18a3ee506c
+    a6013661f2f0ab875739836039bff6bff4c993aefdda43dccecf4c404b9a612a;
+  ea26bcf0bfc3e15d4df7ddbcac8b5b9e9a7215d74196d77c9e0524e861c6aeb4
+    113e06861e3d338618695f4713464cea536c8019da77ff0dd9946f3b860df062;
+  b67b1ffffec757ef147e86cf60898c5dac515f080f43f4e120017caab4eee5ee
+    7d9748a1ff6ca9cdebeb3dd6668522767afb9ebf1c680fe7fb3f5848f7222036;
+  c122016f17f12e53f9ac031719fe428c826217b2b757ae44f2f33d1b8b1bb553
+    dc068d032b97c98eea6dd6c8bc42e9a0a6250c81a36a8f64615489e191287c72;
+  1266ff0654c08e6183cd6c3cc760cc5c88d1f49b918f2f8f587b3edd4adea513
+    f07f17fadb2e2dbd282d296fe5a15cc5c2baf6b45f5fd5dc4692f252039bc862;
+  4c4dd9c6e46fb2c096388583f2a0c969245452b23f16ea43e15064c45357ccef
+    5127fd4415a84115997b8b3ebe88a590efde9f8b53a43e86b1a4d60782c91025;
+  095d149c2616212e5f770f133e719d285a8bc888414271296684e732feb5473f
+    d8038bee551cac14d1c610bbc0960d943b01526072c589bc913ab51fd47bc848;
+  ad55f9f916d62bb13ceb1461b99e82d76b860c084ca408dd4a18f154b907754a
+    e5c86ee6350c9ab736229f3f53e2ab852641bb8a62fdda609444df377e9ca04a;
+  2e4976f45acc671e38add93aa6a89669cdc9874975879b3134dd37c633c9eb14
+    c6513f1a11346d33b05ad65eca13f11125cf70bdcdd6e666a8a7b9c5b6098429;
+}
+
+inv {
+  344ff33a2bc801f861bd13575797da35352c8164808d27f51ea7ca46931b2b1f
+    07f678dfeef071b038d692bf825cb4e75bc1934bd3a6e3dfea99e78bdaeecf3a;
+  670097e2fbbecf6516e949d98f6d722d3f732c33bfb4e62512f9d28d94546b64
+    b2f5cbcd7d8c996ed33a813b1aa39c36f5826b436867bd89b4ce43a156c1e96b;
+  234f3bd8760cdc8ae7fac9457da418cd082e42906ffe59a13e52185a7845e61c
+    7488ff9231e4819684148e16ebc25440732ffe7d211eb3d3263db1af9f1d0513;
+  22a39a35b1cabc6dfecd1b898593070f0c81bbd04b4b20f43a9c7c14b5dfe967
+    892024fdbc8937b9b3aef794f57b8ed8517510b6de3f6088987b1310c1dc7932;
+  d850c118c69198268826d05650958c6bed55b181090cf1c96493ecc4635a913f
+    7aeae1b0dc5211f374872e78da8f225325f3f33f9c42bfdeff25d425dff7710f;
+  33ccdc0e39f7cd0a61782c87ac089eb7bbcabce4dd222f05088d3d6332efe959
+    668f87e23239e965c80740d4daa9c913609388f291c11f950684f45e689a061d;
+  7c06f93b2f66001c74073b8ba7536049738e89b0a0d859a8a73710de3fadcf79
+    52df0aa24bb4a7474e6ed9852ba542c1f4c5219372a7b5d60988890e2955491e;
+  9a0ce9ff4026bd58abcf8a128dbc55a19c446005834a143634452821d5f9f0ee
+    79eaa93b6287705c0ba564c31bab1854c7f4354845be065c4bf94d38a7a8b421;
+  a13a127490bd3443fdba99baf61d113f3aadd6966c9732cd16348f9fbed32e0e
+    67290b25e6bd7328dd804309a6203c02a75657f593c7e66e48c9192524e5b87b;
+  35f7ac3eaa36c4ed338388fe7eda61cf237eff6ddc0847cb0c95255bbaef8ddc
+    4950601d2cfe75eb9c4524e2f40f404fe82d0014c916dc43d9416cd2e274992d;
+  8a058593035986da3a19e63dacaf40fb3db4cf382205fc4e4802e0ff0c61c8d6
+    6a23b743dc2fa4a4132780cf6edfed4c219760f3b31343b08710ea18d2c0fc43;
+  a10d03234e700ec92270b6105fdb787d8edd3f960fdd78ea2e169f49dc708d45
+    101dad1720604d0b093831baaa97fd0701ce773b9c1be1db0403533ad4376c0a;
+  52d3b9e030a5ed574f7f9489c47e73f78ef88a39b570045f9ef73c9a3e65f425
+    83da3e088dbc9a3cbe06496c5a52edc8d7abcbb8a0f839361762137b119d961a;
+  9928b5f14ec80a036479d7b08c128e601db880daebef36adde6fbd1f50f82629
+    8dcaa9a2439b77cbe44928ac2877e09755c505f58df4d0ffb9b23fc256b12779;
+  5a956523956f8ace6166ea6cb3c7421f8d1142d26084a81d615f00d578e03448
+    658a3ee24ec5b5f1d2d12614e535247c9f2f259131b00f654e09b4517c63ea09;
+  157492cd38a07802351ca0d1a5615d5c5f254692acce930fb6be351e9a52f088
+    32fec1eab85ddf8d27a437876e7f5a07f012b02e7971869811c3c31230204164;
+  2d07c109c332847567621ef4338e149b99c5bc3bf6e50943695da7fed5d8141e
+    a81472d28a8235bff43ad5cc012d52e95ece3dbc5ba2962dc54cf9e7f81bee04;
+  7e172f6c03415e83d4671e0191151d49e5257651ba73848254e68fad0a095c50
+    1a8efdc57ae9d39ffa64afbc5d2dc1f25a29d365ac3dee0d8529977c14aa4415;
+  1934546e37b0bac80319fa7f2f86c18e83de8da830b9d0b5019c26768974eda4
+    ffe55479771f20518d8fc6491055368b5dcce9b4e193d19897f1e116b9cdf946;
+  90324ccfe0e34e9b08db1862be3bc17798a8581ee097be76545e3bf9d586a2e6
+    0f5ccf4920d617c9b4f7fe6e2c9e95e89b5516555d5e3f5f9900485451d7425f;
+}
+
+quosqrt {
+  18798551568191dbfe6bcacf95bf4bf00290de4c773a1d4233d1eae272b3085b
+    2ee52110807ab6e31e0ed7b4de818d6474b514c63c99206e58a6df38e149123f
+    3819accb91d97a3f4dbca732f19723fc772a19b3eb4d307acad706cc7c7e1c1f
+    b5e653346e2685c0b24358cd0e68dc0388d5e64c14b2cf853528f9338381e360;
+  8671a0ecb7344f2e44fc9066aeb42661e848417e8c51b353680573830857d90f
+    9c4cfb1aa650924ceaf3e23b260d02b7d8b7dd4445360cad0bd4270428f55292
+    "" "";
+  bb0d27e1743f444e2f612c2ff575c6c6663f01869eaa8666774b8baa59b2a714
+    2fecb156c393d27d7b9a5e4cc2b57cb5524d5b945e92c5b4bdccdd6d00e684c6
+    "" "";
+  59af963f7245901807a46a59d4e49bab5b1fdf3001f63ef4e600ef8150d0e13a
+    b5ac3372ca5435577c416ba46a57879b0ca1df29057c540cac4edacc507b5e23
+    "" "";
+  a7b8659775a53e1fa315066be6a37a3f645d782cb69ec6b4f27fcf4daed3d82e
+    4550c4697a5d29d1a97b50ea65e98ec839567a3fc556ec3790b016c24b867d89
+    a190875f536f94ae2af8aae90bf0afabed437b36cf640d85529b150155eed53e
+    4c6f78a0ac906b51d5075516f40f505412bc84c9309bf27aad64eafeaa112a41;
+  7163512100699c32d5fadbe3583f2f6f314c347f1e66c434b15ac06a5733f3ed
+    2806d76598a43c24820daaf87afa5a9a4d414e5d8f51993f1b01166bb5479c27
+    01d5d023a6c5f7ec1d5df3179bb240e3003a9e3be8ad4e154c6e8f7cb7af6536
+    ec2a2fdc593a0813e2a20ce8644dbf1cffc561c41752b1eab391708348509a49;
+  e950533666a4a1edc3dae30637d6b005e34b614fe75555be0e1759def06a2aee
+    ac5a603347a585ca19eba141b1dd1b8833855e9807776627e8c9f92001a4b9b0
+    "" "";
+  d3c5ccb02442548901b3ffa2ed5564735b0b041386fd38e6c40844dc9183006e
+    5e6f23ccef94660e569bc42093d2b862ca605b81d64bb3589331d015082b4996
+    d7d578a72f1ea2dcacd0a96be285e9635230dc297fa7f6e1f2b9754e2d29190c
+    162a8758d0e15d23532f56941d7a169cadcf23d68058091e0d468ab1d2d6e673;
+  37cad075017c111f99135be6a0f553535d56153cef8839eee1e70614d65df1c2
+    e5f9944a377be3ab64daccfc9e711f4aa522c68a80efd0a70c72cdd4507014b7
+    "" "";
+  85dedba748f478537d016f20b9871e830e513514fbd27141aa54ca77b2a673be
+    950bc6fb51f6d8c36b7ddc8cb28d9efd498690a46c57888b279de0e549e84c52
+    fb7871031556b171a25dfd0483f0e2ed8d24a8acc2d9fc201f42f0b892fd541a
+    f2868efceaa94e8e5da202fb7c0f1d1272db57533d2603dfe0bd0f476d02ab65;
+  d70f399a983c6ad48acca796d9106c5e7681f34bdf34248f6dc54620282bb327
+    cad23bcd1fb96331bc8139f2a8f21d24492e56a7b80e343a7002acc96a739454
+    ff70c5bffe08911fb5522b21beecfd80fb018f0afef24fe85cfb7e4a5024960a
+    ee8e3a4001f76ee04aadd4de4113027f04fe70f5010db017a30481b5afdb6975;
+  71ee96ced0b50bc560f2477a88ea2447573490f71850f084ae0b318cafd8a75f
+    15c61eefd2c05d72fb07e44a006dfe314d8797f978bab1fe9f9276bcc82b542a
+    "" "";
+  c27a9f169b8096308f313ab5a521886084f03ec6d9e8b30e4773d0a3ab1a7c67
+    a7ca0e7fc5566dfc3790a3de164ef26d6452715db428994d438e79f65034d174
+    129427bd4c2195fac5a0da4c52ff634c697f18c3b02d0e7aad45a64d03b6e922
+    db6bd842b3de6a053a5f25b3ad009cb39680e73c4fd2f18552ba59b2fc49165d;
+  dd73476aeab865af0775723ebd2128ca71621b1d95231813c3d3cb32b805f418
+    dc6621f2ba82deb8272243baa5d2e177a60b1b780daa3ba081040e05b1d1b2f9
+    32ae54f7a7dfa101bad00f723898d29a7307454f86cd1197c44b07d1b997fa1f
+    bb51ab0858205efe452ff08dc7672d658cf8bab07932ee683bb4f82e46680560;
+  3a3ee482bf7075fa38780616603133ecea7b56acab59d96ebf7192e21c49a806
+    b7e6d647792961137dadce55ce69634379338bbda45fbef9d56be52620738d06
+    122b696683c2d1f3feedaf6166037ddbd7281e0c4c875724177f240b54e0dc22
+    dbd496997c3d2e0c0112509e99fc822428d7e1f3b378a8dbe880dbf4ab1f235d;
+  71f31797a8a36123e4a0b173ee4bc5a04d7799d1eba246df51cf943aeba0270c
+    7340069440d6c72b4536018eec373f50a1142c9e79de8a5396f994e53c64ab18
+    "" "";
+  0d2a6a9de4d52289cc724840670abcc5a4ee04f1197bd1d230689431b01afce0
+    21457f6784da81822df90f09b44782bd50a12c4fb378091cd33b177c734e0728
+    2b272304b3cca59e26431d91118a95c965bd542191c7cef760b085673e96a432
+    c2d8dcfb4c335a61d9bce26eee756a369a42abde6e3831089f4f7a98c1695b4d;
+  288b09090258a71747c1a08a51b0894a0c096f5b88ee38ea56a3aaefc1afa0f5
+    a7f6391e06b8972b18e899753bf3853270cae7971774041fa9bf09a55349f950
+    "" "";
+  e912e39e2199c3980c5fe3cac6d8bed394367f28213524f006a9b2c0cce4a6dc
+    e6b4a592e37fb5d3af73c486cc211a57d4077c093a161276dcb6eb44303d3ec6
+    "" "";
+  ec6785be59b890e07176c09195430b7f5daee0b0898ee744e578ac25873012b6
+    b3cd2df2c2531beeca882607d73f38403d8ff384f99be1ce582536bc3d4bfcd1
+    "" "";
+}
+
+sub-mulc-add-sub-mul {
+  ## A very basic smoke-test.
+  03 01 5 01 07 02 37;
+
+  ## Stress the bounds.
+  000000feffff030000f0ffffdfffff7f000000ffffff03000008ffff1f000040 00
+    0xfffff
+    000000feffff030000f0ffffdfffff7f000000ffffff03000008ffff1f000040
+    000000feffff030000f0ffffdfffff7f000000ffffff03000008ffff1f000040 00
+    00000cf2ffdf4400a09a000079fdffea040098edffa73b024072ffbfe0feff65;
+
+  ## Random tests.
+  6f0dc2547ad77f7b3da324876e63c724c1f69cb2bc70ff960f1594f90202e17f
+    23a2d45c26880166516e6831ab5070dd2247992418ad7cc41155a9362744f763
+    4783
+    e145b5f91b683918d1efe6193de27909bf9051b0157acfa458bc3f63e5272de5
+    e694fc475a442bd72cbbf11206474e3169fa74ad453aec3034c1dcc1f1dfbce0
+    f9b4f1ac9369241a302f874305cd2d2fba362b5735d36d3e072c7198d7dd4005
+    08518c9f52236272202869bf7cb549c667f6a27d1c4f18ab58605d63821a6c61;
+  f1b3d663fb9458ba8e4521e8e2c976fafc8936433b62e316c6dcff794b1ac8d0
+    2185dd6948ef2339c9a43518dd02eac6518852d1c35858dbdf5c1acf1d995884
+    -128133
+    d7a628aa59d409b755a1ff0d76f37ae8e4a73d47375940c61351074f3c42ad2a
+    4a353e9e7e9a0700ab2c043cc05f9795cc267e001b64799ca1849f024a42dfd7
+    dbef6513fba5ca19c545b162718eeba960b0930b8ce99c3edac5facf5fddf4f2
+    9dbfe69897a273171ab4a697f88a0d4b420a3ada7a7f9e67d0ba871e2097026d;
+  e8624dbe04a1b19102019d7fd9e06fe502764afb92330d03693279e872e84f81
+    8da8b04024ff708a8b5fa31a6a654fc31d3748f74a897898aa42c2bb65494586
+    -118148
+    83f63df59ce4b3161427b932ecbd7796bd162b553b70bbfef8a990ba6f20c23e
+    9d896d69ec478456fb6cad67774c6e3e0e313aadc0564d759380981fb12dc3b8
+    0e8799aa8de1b1ac4aeae4d1e8cd5936c66b8a0a60c8d17ec23bc9c9f94421ea
+    2221a87687c127b352e077bf7e975c83c667c8ce603e9d9fa5e02b195c7ad873;
+  2527a8ab98898038e9e132a1bc8349a33e2c2f6ec8b6c15b06410177297d30fb
+    71cdbe058a0357295dd5134fb95a630055f39d9bd8fa0c759b1b70fbef6147d0
+    -14780
+    0fe111e19ddf5d11d40b584a31888aea4a388540b86d14b962a1a7135114d5b3
+    a6386eeff2764007a570ba7e82a214667c2949a793fa0a52b7665c09285c6661
+    a7557aaa000c8840e08163b7eec08bf24ba275a35d85bfd7813aaafcc22715c8
+    867491333fc048b229ddb4740b1fe6dca1feebf1d40660814feeb1fce97fca12;
+  fe07ffcd6b14f75efd74ff983e8e5c20f379b0c78907f0e453753b457fb53159
+    617f2f7c1153eaea3ccae7dfb07fbe804b2cb5c8205d657c3106b5a60100cafc
+    -128312
+    a0af624a3f54278e2f7cc77f5d0f10750179bb18e07da059feb0bc98fb1d688f
+    ce432859e6d7e691ba9b44d467e8a5f1a97979facd2d3c7deec46e121193133b
+    d60050fad0f5c4b2e042141e4f7a418d3e8a8a308acc96651728f363ee793628
+    b9e4e8873e006d41104b1cd6a32282fa2b94ade000dd57dee6dd506cceb34c34;
+  b46e84be433f9e4f43ffa2f1f5200013953d820d292e3af978c54401a252111c
+    cb7cec0c48efa4e0e54f05ac18574d5f67bf1a1193d6d58f42183abc9f5bdd49
+    -3288
+    18603c0562c4d893a699fa6258e2de57e1cafd3e8ad756806d09db0c1ac9f86c
+    0854368c6b459ba6fcaa95db92605c9d791bf4dcc57bfda2ef318b48f7521d73
+    0c83d0b2d331ccc62bbcd2d2771b18bc0b909a3bbebcdcb99020952672f050d4
+    d54073b190601f1cc36c25109a5b44f04b6c2240c268bc71cb983d3dfb25cd64;
+  1f490365c3b82416fd3866a42a03f3bd643844e0d0cbebb66af54aa35de3efa4
+    dc805758c7e714a2acbc1e467520ecc3b9d23ce5133fe79e377e6d4520cd5196
+    -129141
+    1a53a3728ef3587085d0b530be8ae95e367927f9ac3b7126445d32b46f3abfad
+    0af6ce5107ca06fdfe732d11161b197830a963ec667065c5293bbdf843e23672
+    5bbfb655a175dcf7a4f4fc886a03e3d99cddbd34524c3cd2fb13b793bb2132be
+    7e5576020e7bac35c7f5b3dc6b60b2c1cca55f6c98141682efb4737963d0307e;
+  09e03f5d67a92cf076740e4261833f244b60da6d02cb42278e2ed9183b6eba3a
+    5a8b665434e91158559cfecf1d43d562c307518a3ce889165b406b1aae38a674
+    -13299
+    16e0d405bc40f2075f5dd901769def19f15759faef9a5fb6356b94c5c48be3e0
+    101da726c0dfd102c8eb2178640054248225a6fcfac1bab28a09b59cf38703d6
+    f268d102402d31a33e52a941a06c64a30a721ed55184edfcfcd85db6fe3db676
+    24fc9112ce6d3d70e8c245f9e2c883290384462065a5a1ab5821b9cf9d61953b;
+  f86ba345a367c676d99450d4893ef4033201c8ddbb631c4658e4ed24ece98749
+    a3c51a17107327742f44cc2e265482522cf39b6bcbff919bcf99fc033d76348f
+    -88039
+    5dcbe0be5f9f80b46d2e651504b10a3e481257a4bfacf40d8ccacea9d73dc2ea
+    2ac88350fbffcbc743d36fe45c80a70a8cbe88be36759943c8e124163e432dec
+    f54685e704df0e499e495b3b77e64aa0ec0c9fc0bb18ed456a412ac6079fe9d2
+    3e7c00ea9ee49825f5fbb9b704dc720b062d8e08ee8dd410f3d34d255602b56b;
+  1cd810875f48ef4c71ecb0997acfa31249ebcc9280e7c2f741038a0529f653d3
+    ba2e564cae8cdc2bea40d64b5598493ac2b11902d91b5aec7a0e4a8649aa7ab2
+    -77488
+    ca4929fb0fed99fd9dca7a21275dbd97185900d4eb362eb09bcb5ce7098aaaa2
+    89b395b440fab27d3b32e0740caac3ce38affbd80b2f8f7b6709294d6770873e
+    d2cd5ac1ea7b0e1f45bd3cc64b651518dcdf9f25078de7cc4970bf54976a0c8d
+    06ea5e15853bb29db5cfccd62db2e64067c90a97eab43039cacf4ee639ffe979;
+  9960c3131e513fba3241b1f9bdf44fdbe06c43d9cda9e05fdb451eda3e8df394
+    4c5f72392dddd1b8e84db5bfc2db04985fe3d1226a470c851a489f98d954e6ec
+    -33449
+    04eacb794c87c19087b793a0e2d187cc7e0b07d265fd6cc46946780d2ab83810
+    414db559bd22f12717b431310c1063534de5e627e983f4967b2fb38f2c5f87b0
+    599bee129778596ba77c27a896020fa55123b8635ff3d9efd56fe406de878146
+    26c7d591e0028dd611d6e84969da716eb740207e49f5ea02f17a3224612def12;
+  2cfc4c9cb8ca259bd4ffcbbd498510f8a65cca584303a28ed475584bd1eed111
+    3223cab1344be86c0af9995a769276cddbf70eaf55caee24dd4ec0d06c2f4309
+    -53728
+    3a48f8bd8a229fa9f5b9d7c4135ef6c3a251b0ce451f482471f017e963839405
+    bec0e71a657e85e024d91c41b3a2f75f478528d8ae1afb70bdc5da255d20de06
+    53dc48614937bd5ea1bce51b166bc9947e248a98cd0fac55f632cded216e9cfd
+    2999f607e716f0c769e9fdeff636568674f3601166d6b7f566a369b5d4e2797a;
+  c37946f39bde051e4a6f91a18fda21ec2bfcc375b703bbb81fdcc7ff15cfedf4
+    f37e2f1bb6b71763263e742cfd1ce8a9e004a5e06faf0afc52cf49ea89ad9244
+    -69223
+    0592777a8c77c1713a72b2ce18fa318fa93e9c6e6b870e54723a43408b502b74
+    cf575224b26f636b4b4f28c90995b87d900f6ca5ec9de6c24e65b747d303d221
+    8ab7d691dd76d7cd63d3456c677987a9e53904a4895f053e3de08786d564c837
+    1d667ed7c9b93f2972de23f4d633bcb5f2e56e446cba103c3cf2cf0931687b13;
+  2afb15ae6438b8eef9d07f2491e43e32a2b9287381c7bf036dce2a1b0a3542e5
+    18c9bb7c91d5e5ed96e6effc6609fe40e72c5634cac2cf6fb55b083c3339f40a
+    -33255
+    c0c870e0ee2116aa1182b2b4ee4bfde446f721fa6f1bba3a2ed4fb703855c673
+    91fd148ae6d53a419983999020d845503cc923e012e6869201615fbb8e460360
+    5d02294b16e04ca4a7fa4fa5dc9f12c7156e2a68c02495ea171a8cf13d35af99
+    f1f90c61c85c137e2e9d5ca7a6b388afd954f6c93548e5fc3b82e02fe875923e;
+  a7a7193315006fd85c97226f44708d61ecddad2e184d69b0db62f9fb2bc678bb
+    87a64ef3c67f464441927c08fd1b57d17bd644a422b96f151aa2d7920989e4ac
+    67151
+    6b31a270025004a878f214f100a764165033e170ea5e4c52832673cf88f9f0b3
+    0c0af67c56e0b2336ba06f447ea4f9cbf052147e35f16216b306ef1211ce4142
+    54fec5270095dfc21f44805ba17565386bc50d45bd1f797ebfa04da5040ad08c
+    92fdbcabd91ab43baa827594672dede4f0c71d8302b4cc8cd79270aa0c96d915;
+  5d72825031c526d9e1efe34fcbbbd81b91460112f9f950e78e12c777a2994a59
+    4334ab5246765e241435c6faac0a00add3a5adcdafe017121d03b9561d0d3516
+    -66199
+    ef3211bb4e1bac43430e48594577d1d271f76b46ea7e44542c23524b3d6236bc
+    1bfb4fb8d8429f0dd7a6cbc23dc2357ce9c1c72be3acf0a49abc331ac751e68a
+    7cf2ea00463d76152e230cb5465ab55d30f09afbd007d2b55393cfe8e348cf9a
+    c0a66f24e5800bec2b9ff65207afd4b29326525b910381d233bd91d51530d046;
+  01a66900161a4ad98f028a8da8f10142b4855712a7eb8ffbd699b13b7cc1a471
+    c6f8a0b42c3f2a1109201c7a97e3307f6cb56a1a27f13e4567456d9eac2a2f4e
+    -71473
+    e2eef0e19682ebb44cfdf84c71cb556311432fd948951a661d4240e16bc68d1c
+    f69b44aaff31db04fa4e8f14f51051d353e50110b1562b27d4493ac5e44a5b07
+    29039f65da48a24be024cf8f1af95ea9b09a08a54eec810e97018add81eec1df
+    a827fcc698403d01f8c2597a582ac8ddd612e5c2a520b0a2428e8dd35c58002d;
+  bc607923665e36ea0f8206b358fb3a327ef9a70ddcadb2edc49660891e932726
+    33e905cd1b262eba320c61428704c1d7c354361043ea7233c69f1f691f7c7175
+    -101999
+    e1b804b366c155d0f1a09fdbede434c669bf7f188daa96b8542dcbc9bbe66b6b
+    413d410937fbf0575bf34c0b70ee6cd5737e17b6058e774f889104b2f6cacc7b
+    0784aeb89be679694477cf399b605473c2c48887b687a980d7d333632e060e6c
+    16edc745e1596492fadffd303c31ce5827c3971c591c68f9e2b4f62c967aaa6f;
+  904e1b99ee3f860409a2db3aa4e539b2b50cebc57359f23fca21b5bb1306dc50
+    133d76a1f768d77a6801d73a570b35f6dbbd98aabfa4258445684143cd30a39f
+    -50858
+    547270fdf41f753a4189d2a9630ab17b4c6034829770a40fd8346e75e92610cf
+    076c4e34375857b9e6289287e03c744fd60d76c377a772f6edef3ad30e4afafb
+    f2e8a830fe203901f5f34ae6e606aa8f6cffb504b166cba4cdd84d011b783b90
+    659233daf8ebd47c77b9d46ac65237e1bfdeebbcc552c7db5cf8dd2d4bd1aa2d;
+  a6f4bce9adbe5a68585c205d20b05c6662748f5f1dd2458defbc126792837a63
+    8f1110929626587241fd403c8332b2ebbc398d4dd7042b993fc24a18b53e3847
+    81985
+    012aaf1e00a521e8e0639ed116e15476f0f8f1c6dff47d860ed60e0bb7c156f7
+    13aaf4f9f20d64110beef21bde5c7262c4bff80a85a08db1e098d45ec3d69457
+    eb3230fdacce04518359bfa7cff0c9d6d015966545e40e1c1da18b760031b2aa
+    607f7b77fc8d3ca15cdf6e2abba71853fa74739f83589a4458854ae2db0a4727;
+}
diff --git a/f25519.c b/f25519.c
new file mode 100644 (file)
index 0000000..6dfc511
--- /dev/null
+++ b/f25519.c
@@ -0,0 +1,1487 @@
+/* -*-c-*-
+ *
+ * Arithmetic modulo 2^255 - 19
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include "ct.h"
+#include "f25519.h"
+
+/*----- Basic setup -------------------------------------------------------*/
+
+#if F25519_IMPL == 26
+/* Elements x of GF(2^255 - 19) are represented by ten signed integers x_i: x
+ * = SUM_{0<=i<10} x_i 2^ceil(51i/2), mostly following Bernstein's original
+ * paper.
+ */
+
+typedef  int32  piece;  typedef  int64  dblpiece;
+typedef uint32 upiece;  typedef uint64 udblpiece;
+#define P p26
+#define PIECEWD(i) ((i)%2 ? 25 : 26)
+#define NPIECE 10
+
+#define M26 0x03ffffffu
+#define M25 0x01ffffffu
+#define B26 0x04000000u
+#define B25 0x02000000u
+#define B24 0x01000000u
+
+#define PIECES(v) v##0, v##1, v##2, v##3, v##4, v##5, v##6, v##7, v##8, v##9
+#define FETCH(v, w) do {                                               \
+  v##0 = (w)->P[0]; v##1 = (w)->P[1];                                  \
+  v##2 = (w)->P[2]; v##3 = (w)->P[3];                                  \
+  v##4 = (w)->P[4]; v##5 = (w)->P[5];                                  \
+  v##6 = (w)->P[6]; v##7 = (w)->P[7];                                  \
+  v##8 = (w)->P[8]; v##9 = (w)->P[9];                                  \
+} while (0)
+#define STASH(w, v) do {                                               \
+  (w)->P[0] = v##0; (w)->P[1] = v##1;                                  \
+  (w)->P[2] = v##2; (w)->P[3] = v##3;                                  \
+  (w)->P[4] = v##4; (w)->P[5] = v##5;                                  \
+  (w)->P[6] = v##6; (w)->P[7] = v##7;                                  \
+  (w)->P[8] = v##8; (w)->P[9] = v##9;                                  \
+} while (0)
+
+#elif F25519_IMPL == 10
+/* Elements x of GF(2^255 - 19) are represented by 26 signed integers x_i: x
+ * = SUM_{0<=i<26} x_i 2^ceil(255i/26); i.e., most pieces are 10 bits wide,
+ * except for pieces 5, 10, 15, 20, and 25 which have 9 bits.
+ */
+
+typedef  int16  piece;  typedef  int32  dblpiece;
+typedef uint16 upiece;  typedef uint32 udblpiece;
+#define P p10
+#define PIECEWD(i)                                                     \
+    ((i) == 5 || (i) == 10 || (i) == 15 || (i) == 20 || (i) == 25 ? 9 : 10)
+#define NPIECE 26
+
+#define B10 0x0400
+#define B9 0x200
+#define B8 0x100
+#define M10 0x3ff
+#define M9 0x1ff
+
+#endif
+
+/*----- Debugging machinery -----------------------------------------------*/
+
+#if defined(F25519_DEBUG) || defined(TEST_RIG)
+
+#include <stdio.h>
+
+#include "mp.h"
+#include "mptext.h"
+
+static mp *get_2p255m91(void)
+{
+  mpw w19 = 19;
+  mp *p = MP_NEW, m19;
+
+  p = mp_setbit(p, MP_ZERO, 255);
+  mp_build(&m19, &w19, &w19 + 1);
+  p = mp_sub(p, p, &m19);
+  return (p);
+}
+
+DEF_FDUMP(fdump, piece, PIECEWD, NPIECE, 32, get_2p255m91())
+
+#endif
+
+/*----- Loading and storing -----------------------------------------------*/
+
+/* --- @f25519_load@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to store the result
+ *             @const octet xv[32]@ = source to read
+ *
+ * Returns:    ---
+ *
+ * Use:                Reads an element of %$\gf{2^{255} - 19}$% in external
+ *             representation from @xv@ and stores it in @z@.
+ *
+ *             External representation is little-endian base-256.  Some
+ *             elements have multiple encodings, which are not produced by
+ *             correct software; use of noncanonical encodings is not an
+ *             error, and toleration of them is considered a performance
+ *             feature.
+ */
+
+void f25519_load(f25519 *z, const octet xv[32])
+{
+#if F25519_IMPL == 26
+
+  uint32 xw0 = LOAD32_L(xv +  0), xw1 = LOAD32_L(xv +  4),
+        xw2 = LOAD32_L(xv +  8), xw3 = LOAD32_L(xv + 12),
+        xw4 = LOAD32_L(xv + 16), xw5 = LOAD32_L(xv + 20),
+        xw6 = LOAD32_L(xv + 24), xw7 = LOAD32_L(xv + 28);
+  piece PIECES(x), b, c;
+
+  /* First, split the 32-bit words into the irregularly-sized pieces we need
+   * for the field representation.  These pieces are all positive.  We'll do
+   * the sign correction afterwards.
+   *
+   * It may be that the top bit of the input is set.  Avoid trouble by
+   * folding that back round into the bottom piece of the representation.
+   *
+   * Here, we briefly have 0 <= x_0 < 2^26 + 19, but will resolve this later.
+   * Otherwise, we have 0 <= x_{2i} < 2^26, and 0 <= x_{2i+1} < 2^25.
+   */
+  x0 = ((xw0 <<  0)&0x03ffffff) + 19*((xw7 >> 31)&0x00000001);
+  x1 = ((xw1 <<  6)&0x01ffffc0) |    ((xw0 >> 26)&0x0000003f);
+  x2 = ((xw2 << 13)&0x03ffe000) |    ((xw1 >> 19)&0x00001fff);
+  x3 = ((xw3 << 19)&0x01f80000) |    ((xw2 >> 13)&0x0007ffff);
+  x4 =                              ((xw3 >>  6)&0x03ffffff);
+  x5 =  (xw4 <<  0)&0x01ffffff;
+  x6 = ((xw5 <<  7)&0x03ffff80) |    ((xw4 >> 25)&0x0000007f);
+  x7 = ((xw6 << 13)&0x01ffe000) |    ((xw5 >> 19)&0x00001fff);
+  x8 = ((xw7 << 20)&0x03f00000) |    ((xw6 >> 12)&0x000fffff);
+  x9 =                              ((xw7 >>  6)&0x01ffffff);
+
+  /* Next, we convert these pieces into a roughly balanced signed
+   * representation.  For each piece, check to see if its top bit is set.  If
+   * it is, then lend a bit to the next piece over.  For x_9, this needs to
+   * be carried around, which is a little fiddly.  In particular, we delay
+   * the carry until after all of the pieces have been balanced.  If we don't
+   * do this, then we have to do a more expensive test for nonzeroness to
+   * decide whether to lend a bit leftwards rather than just testing a single
+   * bit.
+   *
+   * This fixes up the anomalous size of x_0: the loan of a bit becomes an
+   * actual carry if x_0 >= 2^26.  By the end, then, we have:
+   *
+   *            { 2^25         if i even
+   *   |x_i| <= {
+   *            { 2^24         if i odd
+   *
+   * Note that we don't try for a canonical representation here: both upper
+   * and lower bounds are achievable.
+   *
+   * All of the x_i at this point are positive, so we don't need to do
+   * anything wierd when masking them.
+   */
+  b = x9&B24; c   = 19&((b >> 19) - (b >> 24)); x9 -= b << 1;
+  b = x8&B25; x9 +=      b >> 25;              x8 -= b << 1;
+  b = x7&B24; x8 +=     b >> 24;               x7 -= b << 1;
+  b = x6&B25; x7 +=     b >> 25;               x6 -= b << 1;
+  b = x5&B24; x6 +=     b >> 24;               x5 -= b << 1;
+  b = x4&B25; x5 +=     b >> 25;               x4 -= b << 1;
+  b = x3&B24; x4 +=     b >> 24;               x3 -= b << 1;
+  b = x2&B25; x3 +=     b >> 25;               x2 -= b << 1;
+  b = x1&B24; x2 +=     b >> 24;               x1 -= b << 1;
+  b = x0&B25; x1 +=     (b >> 25) + (x0 >> 26); x0 = (x0&M26) - (b << 1);
+             x0 +=      c;
+
+  /* And with that, we're done. */
+  STASH(z, x);
+
+#elif F25519_IMPL == 10
+
+  piece x[NPIECE];
+  unsigned i, j, n, wd;
+  uint32 a;
+  int b, c;
+
+  /* First, just get the content out of the buffer. */
+  for (i = j = a = n = 0, wd = 10; j < NPIECE; i++) {
+    a |= (uint32)xv[i] << n; n += 8;
+    if (n >= wd) {
+      x[j++] = a&MASK(wd);
+      a >>= wd; n -= wd;
+      wd = PIECEWD(j);
+    }
+  }
+
+  /* There's a little bit left over from the top byte.  Carry it into the low
+   * piece.
+   */
+  x[0] += 19*(int)(a&MASK(n));
+
+  /* Next, convert the pieces into a roughly balanced signed representation.
+   * If a piece's top bit is set, lend a bit to the next piece over.  For
+   * x_25, this needs to be carried around, which is a bit fiddly.
+   */
+  b = x[NPIECE - 1]&B8;
+  c = 19&((b >> 3) - (b >> 8));
+  x[NPIECE - 1] -= b << 1;
+  for (i = NPIECE - 2; i > 0; i--) {
+    wd = PIECEWD(i) - 1;
+    b = x[i]&BIT(wd);
+    x[i + 1] += b >> wd;
+    x[i] -= b << 1;
+  }
+  b = x[0]&B9;
+  x[1] += (b >> 9) + (x[0] >> 10);
+  x[0] = (x[0]&M10) - (b << 1) + c;
+
+  /* And we're done. */
+  for (i = 0; i < NPIECE; i++) z->P[i] = x[i];
+
+#endif
+}
+
+/* --- @f25519_store@ --- *
+ *
+ * Arguments:  @octet zv[32]@ = where to write the result
+ *             @const f25519 *x@ = the field element to write
+ *
+ * Returns:    ---
+ *
+ * Use:                Stores a field element in the given octet vector in external
+ *             representation.  A canonical encoding is always stored, so,
+ *             in particular, the top bit of @xv[31]@ is always left clear.
+ */
+
+void f25519_store(octet zv[32], const f25519 *x)
+{
+#if F25519_IMPL == 26
+
+  piece PIECES(x), PIECES(y), c, d;
+  uint32 zw0, zw1, zw2, zw3, zw4, zw5, zw6, zw7;
+  mask32 m;
+
+  FETCH(x, x);
+
+  /* First, propagate the carries throughout the pieces.  By the end of this,
+   * we'll have all of the pieces canonically sized and positive, and maybe
+   * there'll be (signed) carry out.  The carry c is in { -1, 0, +1 }, and
+   * the remaining value will be in the half-open interval [0, 2^255).  The
+   * whole represented value is then x + 2^255 c.
+   *
+   * It's worth paying careful attention to the bounds.  We assume that we
+   * start out with |x_i| <= 2^30.  We start by cutting off and reducing the
+   * carry c_9 from the topmost piece, x_9.  This leaves 0 <= x_9 < 2^25; and
+   * we'll have |c_9| <= 2^5.  We multiply this by 19 and we'll add it onto
+   * x_0 and propagate the carries: but what bounds can we calculate on x
+   * before this?
+   *
+   * Let o_i = floor(51 i/2).  We have X_i = SUM_{0<=j<i} x_j 2^{o_i}, so
+   * x = X_10.  We see, inductively, that |X_i| < 2^{31+o_{i-1}}: X_0 = 0;
+   * |x_i| <= 2^30; and |X_{i+1}| = |X_i + x_i 2^{o_i}| <= |X_i| + 2^{30+o_i}
+   * < 2^{31+o_i}.  Then x = X_9 + 2^230 x_9, and we have better bounds for
+   * x_9, so
+   *
+   *   -2^235 < x + 19 c_9 < 2^255 + 2^235
+   *
+   * Here, the x_i are signed, so we must be cautious about bithacking them.
+   */
+             c = ASR(piece, x9, 25); x9 = (upiece)x9&M25;
+  x0 += 19*c; c = ASR(piece, x0, 26); x0 = (upiece)x0&M26;
+  x1 +=    c; c = ASR(piece, x1, 25); x1 = (upiece)x1&M25;
+  x2 +=    c; c = ASR(piece, x2, 26); x2 = (upiece)x2&M26;
+  x3 +=    c; c = ASR(piece, x3, 25); x3 = (upiece)x3&M25;
+  x4 +=    c; c = ASR(piece, x4, 26); x4 = (upiece)x4&M26;
+  x5 +=    c; c = ASR(piece, x5, 25); x5 = (upiece)x5&M25;
+  x6 +=    c; c = ASR(piece, x6, 26); x6 = (upiece)x6&M26;
+  x7 +=    c; c = ASR(piece, x7, 25); x7 = (upiece)x7&M25;
+  x8 +=    c; c = ASR(piece, x8, 26); x8 = (upiece)x8&M26;
+  x9 +=    c; c = ASR(piece, x9, 25); x9 = (upiece)x9&M25;
+
+  /* Now we have a slightly fiddly job to do.  If c = +1, or if c = 0 and
+   * x >= 2^255 - 19, then we should subtract 2^255 - 19 from the whole
+   * value; if c = -1 then we should add 2^255 - 19; and otherwise we should
+   * do nothing.
+   *
+   * But conditional behaviour is bad, m'kay.  So here's what we do instead.
+   *
+   * The first job is to sort out what we wanted to do.  If c = -1 then we
+   * want to (a) invert the constant addend and (b) feed in a carry-in;
+   * otherwise, we don't.
+   */
+  m = SIGN(c);
+  d = m&1;
+
+  /* Now do the addition/subtraction.  Remember that all of the x_i are
+   * nonnegative, so shifting and masking are safe and easy.
+   */
+  d += x0 + (19 ^ (M26&m)); y0 = d&M26; d >>= 26;
+  d += x1 +      (M25&m);  y1 = d&M25; d >>= 25;
+  d += x2 +      (M26&m);  y2 = d&M26; d >>= 26;
+  d += x3 +      (M25&m);  y3 = d&M25; d >>= 25;
+  d += x4 +      (M26&m);  y4 = d&M26; d >>= 26;
+  d += x5 +      (M25&m);  y5 = d&M25; d >>= 25;
+  d += x6 +      (M26&m);  y6 = d&M26; d >>= 26;
+  d += x7 +      (M25&m);  y7 = d&M25; d >>= 25;
+  d += x8 +      (M26&m);  y8 = d&M26; d >>= 26;
+  d += x9 +      (M25&m);  y9 = d&M25; d >>= 25;
+
+  /* The final carry-out is in d; since we only did addition, and the x_i are
+   * nonnegative, then d is in { 0, 1 }.  We want to keep y, rather than x,
+   * if (a) c /= 0 (in which case we know that the old value was
+   * unsatisfactory), or (b) if d = 1 (in which case, if c = 0, we know that
+   * the subtraction didn't cause a borrow, so we must be in the case where
+   * 2^255 - 19 <= x < 2^255).
+   */
+  m = NONZEROP(c) | ~NONZEROP(d - 1);
+  x0 = (y0&m) | (x0&~m); x1 = (y1&m) | (x1&~m);
+  x2 = (y2&m) | (x2&~m); x3 = (y3&m) | (x3&~m);
+  x4 = (y4&m) | (x4&~m); x5 = (y5&m) | (x5&~m);
+  x6 = (y6&m) | (x6&~m); x7 = (y7&m) | (x7&~m);
+  x8 = (y8&m) | (x8&~m); x9 = (y9&m) | (x9&~m);
+
+  /* Extract 32-bit words from the value. */
+  zw0 = ((x0 >>  0)&0x03ffffff) | (((uint32)x1 << 26)&0xfc000000);
+  zw1 = ((x1 >>  6)&0x0007ffff) | (((uint32)x2 << 19)&0xfff80000);
+  zw2 = ((x2 >> 13)&0x00001fff) | (((uint32)x3 << 13)&0xffffe000);
+  zw3 = ((x3 >> 19)&0x0000003f) | (((uint32)x4 <<  6)&0xffffffc0);
+  zw4 = ((x5 >>  0)&0x01ffffff) | (((uint32)x6 << 25)&0xfe000000);
+  zw5 = ((x6 >>  7)&0x0007ffff) | (((uint32)x7 << 19)&0xfff80000);
+  zw6 = ((x7 >> 13)&0x00000fff) | (((uint32)x8 << 12)&0xfffff000);
+  zw7 = ((x8 >> 20)&0x0000003f) | (((uint32)x9 <<  6)&0x7fffffc0);
+
+  /* Store the result as an octet string. */
+  STORE32_L(zv +  0, zw0); STORE32_L(zv +  4, zw1);
+  STORE32_L(zv +  8, zw2); STORE32_L(zv + 12, zw3);
+  STORE32_L(zv + 16, zw4); STORE32_L(zv + 20, zw5);
+  STORE32_L(zv + 24, zw6); STORE32_L(zv + 28, zw7);
+
+#elif F25519_IMPL == 10
+
+  piece y[NPIECE], yy[NPIECE], c, d;
+  unsigned i, j, n, wd;
+  uint32 m, a;
+
+  /* Before we do anything, copy the input so we can hack on it. */
+  for (i = 0; i < NPIECE; i++) y[i] = x->P[i];
+
+  /* First, propagate the carries throughout the pieces.
+   *
+   * It's worth paying careful attention to the bounds.  We assume that we
+   * start out with |y_i| <= 2^14.  We start by cutting off and reducing the
+   * carry c_25 from the topmost piece, y_25.  This leaves 0 <= y_25 < 2^9;
+   * and we'll have |c_25| <= 2^5.  We multiply this by 19 and we'll ad it
+   * onto y_0 and propagte the carries: but what bounds can we calculate on
+   * y before this?
+   *
+   * Let o_i = floor(255 i/26).  We have Y_i = SUM_{0<=j<i} y_j 2^{o_i}, so
+   * y = Y_26.  We see, inductively, that |Y_i| < 2^{31+o_{i-1}}: Y_0 = 0;
+   * |y_i| <= 2^14; and |Y_{i+1}| = |Y_i + y_i 2^{o_i}| <= |Y_i| + 2^{14+o_i}
+   * < 2^{15+o_i}.  Then x = Y_25 + 2^246 y_25, and we have better bounds for
+   * y_25, so
+   *
+   *   -2^251 < y + 19 c_25 < 2^255 + 2^251
+   *
+   * Here, the y_i are signed, so we must be cautious about bithacking them.
+   *
+   * (Rather closer than the 10-piece case above, but still doable in one
+   * pass.)
+   */
+  c = 19*ASR(piece, y[NPIECE - 1], 9);
+  y[NPIECE - 1] = (upiece)y[NPIECE - 1]&M9;
+  for (i = 0; i < NPIECE; i++) {
+    wd = PIECEWD(i);
+    y[i] += c;
+    c = ASR(piece, y[i], wd);
+    y[i] = (upiece)y[i]&MASK(wd);
+  }
+
+  /* Now the addition or subtraction. */
+  m = SIGN(c);
+  d = m&1;
+
+  d += y[0] + (19 ^ (M10&m));
+  yy[0] = d&M10;
+  d >>= 10;
+  for (i = 1; i < NPIECE; i++) {
+    wd = PIECEWD(i);
+    d += y[i] + (MASK(wd)&m);
+    yy[i] = d&MASK(wd);
+    d >>= wd;
+  }
+
+  /* Choose which value to keep. */
+  m = NONZEROP(c) | ~NONZEROP(d - 1);
+  for (i = 0; i < NPIECE; i++) y[i] = (yy[i]&m) | (y[i]&~m);
+
+  /* Store the result as an octet string. */
+  for (i = j = a = n = 0; i < NPIECE; i++) {
+    a |= (upiece)y[i] << n; n += PIECEWD(i);
+    while (n >= 8) {
+      zv[j++] = a&0xff;
+      a >>= 8; n -= 8;
+    }
+  }
+  zv[j++] = a;
+
+#endif
+}
+
+/* --- @f25519_set@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to write the result
+ *             @int a@ = a small-ish constant
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets @z@ to equal @a@.
+ */
+
+void f25519_set(f25519 *x, int a)
+{
+  unsigned i;
+
+  x->P[0] = a;
+  for (i = 1; i < NPIECE; i++) x->P[i] = 0;
+}
+
+/*----- Basic arithmetic --------------------------------------------------*/
+
+/* --- @f25519_add@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the sum %$x + y$%.
+ */
+
+void f25519_add(f25519 *z, const f25519 *x, const f25519 *y)
+{
+#if F25519_IMPL == 26
+  z->P[0] = x->P[0] + y->P[0]; z->P[1] = x->P[1] + y->P[1];
+  z->P[2] = x->P[2] + y->P[2]; z->P[3] = x->P[3] + y->P[3];
+  z->P[4] = x->P[4] + y->P[4]; z->P[5] = x->P[5] + y->P[5];
+  z->P[6] = x->P[6] + y->P[6]; z->P[7] = x->P[7] + y->P[7];
+  z->P[8] = x->P[8] + y->P[8]; z->P[9] = x->P[9] + y->P[9];
+#elif F25519_IMPL == 10
+  unsigned i;
+  for (i = 0; i < NPIECE; i++) z->P[i] = x->P[i] + y->P[i];
+#endif
+}
+
+/* --- @f25519_sub@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the difference %$x - y$%.
+ */
+
+void f25519_sub(f25519 *z, const f25519 *x, const f25519 *y)
+{
+#if F25519_IMPL == 26
+  z->P[0] = x->P[0] - y->P[0]; z->P[1] = x->P[1] - y->P[1];
+  z->P[2] = x->P[2] - y->P[2]; z->P[3] = x->P[3] - y->P[3];
+  z->P[4] = x->P[4] - y->P[4]; z->P[5] = x->P[5] - y->P[5];
+  z->P[6] = x->P[6] - y->P[6]; z->P[7] = x->P[7] - y->P[7];
+  z->P[8] = x->P[8] - y->P[8]; z->P[9] = x->P[9] - y->P[9];
+#elif F25519_IMPL == 10
+  unsigned i;
+  for (i = 0; i < NPIECE; i++) z->P[i] = x->P[i] - y->P[i];
+#endif
+}
+
+/* --- @f25519_neg@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@)
+ *             @const f25519 *x@ = an operand
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z = -x@.
+ */
+
+void f25519_neg(f25519 *z, const f25519 *x)
+{
+#if F25519_IMPL == 26
+  z->P[0] = -x->P[0]; z->P[1] = -x->P[1];
+  z->P[2] = -x->P[2]; z->P[3] = -x->P[3];
+  z->P[4] = -x->P[4]; z->P[5] = -x->P[5];
+  z->P[6] = -x->P[6]; z->P[7] = -x->P[7];
+  z->P[8] = -x->P[8]; z->P[9] = -x->P[9];
+#elif F25519_IMPL == 10
+  unsigned i;
+  for (i = 0; i < NPIECE; i++) z->P[i] = -x->P[i];
+#endif
+}
+
+/*----- Constant-time utilities -------------------------------------------*/
+
+/* --- @f25519_pick2@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x, *y@ = two operands
+ *             @uint32 m@ = a mask
+ *
+ * Returns:    ---
+ *
+ * Use:                If @m@ is zero, set @z = y@; if @m@ is all-bits-set, then set
+ *             @z = x@.  If @m@ has some other value, then scramble @z@ in
+ *             an unhelpful way.
+ */
+
+void f25519_pick2(f25519 *z, const f25519 *x, const f25519 *y, uint32 m)
+{
+  mask32 mm = FIX_MASK32(m);
+
+#if F25519_IMPL == 26
+  z->P[0] = PICK2(x->P[0], y->P[0], mm);
+  z->P[1] = PICK2(x->P[1], y->P[1], mm);
+  z->P[2] = PICK2(x->P[2], y->P[2], mm);
+  z->P[3] = PICK2(x->P[3], y->P[3], mm);
+  z->P[4] = PICK2(x->P[4], y->P[4], mm);
+  z->P[5] = PICK2(x->P[5], y->P[5], mm);
+  z->P[6] = PICK2(x->P[6], y->P[6], mm);
+  z->P[7] = PICK2(x->P[7], y->P[7], mm);
+  z->P[8] = PICK2(x->P[8], y->P[8], mm);
+  z->P[9] = PICK2(x->P[9], y->P[9], mm);
+#elif F25519_IMPL == 10
+  unsigned i;
+  for (i = 0; i < NPIECE; i++) z->P[i] = PICK2(x->P[i], y->P[i], mm);
+#endif
+}
+
+/* --- @f25519_pickn@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result
+ *             @const f25519 *v@ = a table of entries
+ *             @size_t n@ = the number of entries in @v@
+ *             @size_t i@ = an index
+ *
+ * Returns:    ---
+ *
+ * Use:                If @0 <= i < n < 32@ then set @z = v[i]@.  If @n >= 32@ then
+ *             do something unhelpful; otherwise, if @i >= n@ then set @z@
+ *             to zero.
+ */
+
+void f25519_pickn(f25519 *z, const f25519 *v, size_t n, size_t i)
+{
+  uint32 b = (uint32)1 << (31 - i);
+  mask32 m;
+
+#if F25519_IMPL == 26
+  z->P[0] = z->P[1] = z->P[2] = z->P[3] = z->P[4] =
+    z->P[5] = z->P[6] = z->P[7] = z->P[8] = z->P[9] = 0;
+  while (n--) {
+    m = SIGN(b);
+    CONDPICK(z->P[0], v->P[0], m);
+    CONDPICK(z->P[1], v->P[1], m);
+    CONDPICK(z->P[2], v->P[2], m);
+    CONDPICK(z->P[3], v->P[3], m);
+    CONDPICK(z->P[4], v->P[4], m);
+    CONDPICK(z->P[5], v->P[5], m);
+    CONDPICK(z->P[6], v->P[6], m);
+    CONDPICK(z->P[7], v->P[7], m);
+    CONDPICK(z->P[8], v->P[8], m);
+    CONDPICK(z->P[9], v->P[9], m);
+    v++; b <<= 1;
+  }
+#elif F25519_IMPL == 10
+  unsigned j;
+
+  for (j = 0; j < NPIECE; j++) z->P[j] = 0;
+  while (n--) {
+    m = SIGN(b);
+    for (j = 0; j < NPIECE; j++) CONDPICK(z->P[j], v->P[j], m);
+    v++; b <<= 1;
+  }
+#endif
+}
+
+/* --- @f25519_condswap@ --- *
+ *
+ * Arguments:  @f25519 *x, *y@ = two operands
+ *             @uint32 m@ = a mask
+ *
+ * Returns:    ---
+ *
+ * Use:                If @m@ is zero, do nothing; if @m@ is all-bits-set, then
+ *             exchange @x@ and @y@.  If @m@ has some other value, then
+ *             scramble @x@ and @y@ in an unhelpful way.
+ */
+
+void f25519_condswap(f25519 *x, f25519 *y, uint32 m)
+{
+  mask32 mm = FIX_MASK32(m);
+
+#if F25519_IMPL == 26
+  CONDSWAP(x->P[0], y->P[0], mm);
+  CONDSWAP(x->P[1], y->P[1], mm);
+  CONDSWAP(x->P[2], y->P[2], mm);
+  CONDSWAP(x->P[3], y->P[3], mm);
+  CONDSWAP(x->P[4], y->P[4], mm);
+  CONDSWAP(x->P[5], y->P[5], mm);
+  CONDSWAP(x->P[6], y->P[6], mm);
+  CONDSWAP(x->P[7], y->P[7], mm);
+  CONDSWAP(x->P[8], y->P[8], mm);
+  CONDSWAP(x->P[9], y->P[9], mm);
+#elif F25519_IMPL == 10
+  unsigned i;
+  for (i = 0; i < NPIECE; i++) CONDSWAP(x->P[i], y->P[i], mm);
+#endif
+}
+
+/* --- @f25519_condneg@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@)
+ *             @const f25519 *x@ = an operand
+ *             @uint32 m@ = a mask
+ *
+ * Returns:    ---
+ *
+ * Use:                If @m@ is zero, set @z = x@; if @m@ is all-bits-set, then set
+ *             @z = -x@.  If @m@ has some other value then scramble @z@ in
+ *             an unhelpful way.
+ */
+
+void f25519_condneg(f25519 *z, const f25519 *x, uint32 m)
+{
+#ifdef NEG_TWOC
+  mask32 m_xor = FIX_MASK32(m);
+  piece m_add = m&1;
+# define CONDNEG(x) (((x) ^ m_xor) + m_add)
+#else
+  int s = PICK2(-1, +1, m);
+# define CONDNEG(x) (s*(x))
+#endif
+
+#if F25519_IMPL == 26
+  z->P[0] = CONDNEG(x->P[0]);
+  z->P[1] = CONDNEG(x->P[1]);
+  z->P[2] = CONDNEG(x->P[2]);
+  z->P[3] = CONDNEG(x->P[3]);
+  z->P[4] = CONDNEG(x->P[4]);
+  z->P[5] = CONDNEG(x->P[5]);
+  z->P[6] = CONDNEG(x->P[6]);
+  z->P[7] = CONDNEG(x->P[7]);
+  z->P[8] = CONDNEG(x->P[8]);
+  z->P[9] = CONDNEG(x->P[9]);
+#elif F25519_IMPL == 10
+  unsigned i;
+  for (i = 0; i < NPIECE; i++) z->P[i] = CONDNEG(x->P[i]);
+#endif
+
+#undef CONDNEG
+}
+
+/*----- Multiplication ----------------------------------------------------*/
+
+#if F25519_IMPL == 26
+
+/* Let B = 2^63 - 1 be the largest value such that +B and -B can be
+ * represented in a double-precision piece.  On entry, it must be the case
+ * that |X_i| <= M <= B - 2^25 for some M.  If this is the case, then, on
+ * exit, we will have |Z_i| <= 2^25 + 19 M/2^25.
+ */
+#define CARRYSTEP(z, x, m, b, f, xx, n) do {                           \
+  (z) = (dblpiece)((udblpiece)(x)&(m)) - (b) +                         \
+    (f)*ASR(dblpiece, (xx), (n));                                      \
+} while (0)
+#define CARRY_REDUCE(z, x) do {                                                \
+  dblpiece PIECES(_t);                                                 \
+                                                                       \
+  /* Bias the input pieces.  This keeps the carries and so on centred  \
+   * around zero rather than biased positive.                          \
+   */                                                                  \
+  _t0 = (x##0) + B25; _t1 = (x##1) + B24;                              \
+  _t2 = (x##2) + B25; _t3 = (x##3) + B24;                              \
+  _t4 = (x##4) + B25; _t5 = (x##5) + B24;                              \
+  _t6 = (x##6) + B25; _t7 = (x##7) + B24;                              \
+  _t8 = (x##8) + B25; _t9 = (x##9) + B24;                              \
+                                                                       \
+  /* Calculate the reduced pieces.  Careful with the bithacking. */    \
+  CARRYSTEP(z##0, _t0, M26, B25, 19, _t9, 25);                         \
+  CARRYSTEP(z##1, _t1, M25, B24,  1, _t0, 26);                         \
+  CARRYSTEP(z##2, _t2, M26, B25,  1, _t1, 25);                         \
+  CARRYSTEP(z##3, _t3, M25, B24,  1, _t2, 26);                         \
+  CARRYSTEP(z##4, _t4, M26, B25,  1, _t3, 25);                         \
+  CARRYSTEP(z##5, _t5, M25, B24,  1, _t4, 26);                         \
+  CARRYSTEP(z##6, _t6, M26, B25,  1, _t5, 25);                         \
+  CARRYSTEP(z##7, _t7, M25, B24,  1, _t6, 26);                         \
+  CARRYSTEP(z##8, _t8, M26, B25,  1, _t7, 25);                         \
+  CARRYSTEP(z##9, _t9, M25, B24,  1, _t8, 26);                         \
+} while (0)
+
+#elif F25519_IMPL == 10
+
+/* Perform carry propagation on X. */
+static void carry_reduce(dblpiece x[NPIECE])
+{
+  /* Initial bounds: we assume |x_i| < 2^31 - 2^27. */
+
+  unsigned i, j;
+  dblpiece c;
+
+  /* The result is nearly canonical, because we do sequential carry
+   * propagation, because smaller processors are more likely to prefer the
+   * smaller working set than the instruction-level parallelism.
+   *
+   * Start at x_23; truncate it to 10 bits, and propagate the carry to x_24.
+   * Truncate x_24 to 10 bits, and add the carry onto x_25.  Truncate x_25 to
+   * 9 bits, and add 19 times the carry onto x_0.  And so on.
+   *
+   * Let c_i be the portion of x_i to be carried onto x_{i+1}.  I claim that
+   * |c_i| <= 2^22.  Then the carry /into/ any x_i has magnitude at most
+   * 19*2^22 < 2^27 (allowing for the reduction as we carry from x_25 to
+   * x_0), and x_i after carry is bounded above by 2^31.  Hence, the carry
+   * out is at most 2^22, as claimed.
+   *
+   * Once we reach x_23 for the second time, we start with |x_23| <= 2^9.
+   * The carry into x_23 is at most 2^27 as calculated above; so the carry
+   * out into x_24 has magnitude at most 2^17.  In turn, |x_24| <= 2^9 before
+   * the carry, so is now no more than 2^18 in magnitude, and the carry out
+   * into x_25 is at most 2^8.  This leaves |x_25| < 2^9 after carry
+   * propagation.
+   *
+   * Be careful with the bit hacking because the quantities involved are
+   * signed.
+   */
+
+  /*For each piece, we bias it so that floor division (as done by an
+   * arithmetic right shift) and modulus (as done by bitwise-AND) does the
+   * right thing.
+   */
+#define CARRY(i, wd, b, m) do {                                                \
+  x[i] += (b);                                                         \
+  c = ASR(dblpiece, x[i], (wd));                                       \
+  x[i] = (dblpiece)((udblpiece)x[i]&(m)) - (b);                                \
+} while (0)
+
+                            {                CARRY(23, 10, B9, M10);      }
+                            { x[24] +=    c; CARRY(24, 10, B9, M10);      }
+                            { x[25] +=    c; CARRY(25,  9, B8,  M9);      }
+                            {  x[0] += 19*c; CARRY( 0, 10, B9, M10);      }
+  for (i = 1; i < 21; ) {
+    for (j = i + 4; i < j; ) {  x[i] +=    c; CARRY( i, 10, B9, M10); i++; }
+                            {  x[i] +=    c; CARRY( i,  9, B8,  M9); i++; }
+  }
+  while (i < 25)            {  x[i] +=    c; CARRY( i, 10, B9, M10); i++; }
+  x[25] += c;
+
+#undef CARRY
+}
+
+#endif
+
+/* --- @f25519_mulconst@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@)
+ *             @const f25519 *x@ = an operand
+ *             @long a@ = a small-ish constant; %$|a| < 2^{20}$%.
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the product %$a x$%.
+ */
+
+void f25519_mulconst(f25519 *z, const f25519 *x, long a)
+{
+#if F25519_IMPL == 26
+
+  piece PIECES(x);
+  dblpiece PIECES(z), aa = a;
+
+  FETCH(x, x);
+
+  /* Suppose that |x_i| <= 2^27, and |a| <= 2^23.  Then we'll have
+   * |z_i| <= 2^50.
+   */
+  z0 = aa*x0; z1 = aa*x1; z2 = aa*x2; z3 = aa*x3; z4 = aa*x4;
+  z5 = aa*x5; z6 = aa*x6; z7 = aa*x7; z8 = aa*x8; z9 = aa*x9;
+
+  /* Following `CARRY_REDUCE', we'll have |z_i| <= 2^26. */
+  CARRY_REDUCE(z, z);
+  STASH(z, z);
+
+#elif F25519_IMPL == 10
+
+  dblpiece y[NPIECE];
+  unsigned i;
+
+  for (i = 0; i < NPIECE; i++) y[i] = a*x->P[i];
+  carry_reduce(y);
+  for (i = 0; i < NPIECE; i++) z->P[i] = y[i];
+
+#endif
+}
+
+/* --- @f25519_mul@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the product %$x y$%.
+ */
+
+void f25519_mul(f25519 *z, const f25519 *x, const f25519 *y)
+{
+#if F25519_IMPL == 26
+
+  piece PIECES(x), PIECES(y);
+  dblpiece PIECES(z);
+  unsigned i;
+
+  FETCH(x, x); FETCH(y, y);
+
+  /* Suppose that |x_i|, |y_i| <= 2^27.  Then we'll have
+   *
+   *   |z_0| <= 267*2^54
+   *   |z_1| <= 154*2^54
+   *   |z_2| <= 213*2^54
+   *   |z_3| <= 118*2^54
+   *   |z_4| <= 159*2^54
+   *   |z_5| <=  82*2^54
+   *   |z_6| <= 105*2^54
+   *   |z_7| <=  46*2^54
+   *   |z_8| <=  51*2^54
+   *   |z_9| <=  10*2^54
+   *
+   * all of which are less than 2^63 - 2^25.
+   */
+
+#define M(a, b) ((dblpiece)(a)*(b))
+  z0 =    M(x0, y0) +
+       19*(M(x2, y8) + M(x4, y6) + M(x6, y4) + M(x8, y2)) +
+       38*(M(x1, y9) + M(x3, y7) + M(x5, y5) + M(x7, y3) + M(x9, y1));
+  z1 =    M(x0, y1) + M(x1, y0) +
+       19*(M(x2, y9) + M(x3, y8) + M(x4, y7) + M(x5, y6) +
+          M(x6, y5) + M(x7, y4) + M(x8, y3) + M(x9, y2));
+  z2 =    M(x0, y2) + M(x2, y0) +
+       2* M(x1, y1) +
+       19*(M(x4, y8) + M(x6, y6) + M(x8, y4)) +
+       38*(M(x3, y9) + M(x5, y7) + M(x7, y5) + M(x9, y3));
+  z3 =    M(x0, y3) + M(x1, y2) + M(x2, y1) + M(x3, y0) +
+       19*(M(x4, y9) + M(x5, y8) + M(x6, y7) +
+          M(x7, y6) + M(x8, y5) + M(x9, y4));
+  z4 =    M(x0, y4) + M(x2, y2) + M(x4, y0) +
+       2*(M(x1, y3) + M(x3, y1)) +
+       19*(M(x6, y8) + M(x8, y6)) +
+       38*(M(x5, y9) + M(x7, y7) + M(x9, y5));
+  z5 =    M(x0, y5) + M(x1, y4) + M(x2, y3) +
+          M(x3, y2) + M(x4, y1) + M(x5, y0) +
+       19*(M(x6, y9) + M(x7, y8) + M(x8, y7) + M(x9, y6));
+  z6 =    M(x0, y6) + M(x2, y4) + M(x4, y2) + M(x6, y0) +
+       2*(M(x1, y5) + M(x3, y3) + M(x5, y1)) +
+       19* M(x8, y8) +
+       38*(M(x7, y9) + M(x9, y7));
+  z7 =    M(x0, y7) + M(x1, y6) + M(x2, y5) + M(x3, y4) +
+          M(x4, y3) + M(x5, y2) + M(x6, y1) + M(x7, y0) +
+       19*(M(x8, y9) + M(x9, y8));
+  z8 =    M(x0, y8) + M(x2, y6) + M(x4, y4) + M(x6, y2) + M(x8, y0) +
+       2*(M(x1, y7) + M(x3, y5) + M(x5, y3) + M(x7, y1)) +
+       38* M(x9, y9);
+  z9 =    M(x0, y9) + M(x1, y8) + M(x2, y7) + M(x3, y6) + M(x4, y5) +
+          M(x5, y4) + M(x6, y3) + M(x7, y2) + M(x8, y1) + M(x9, y0);
+#undef M
+
+  /* From above, we have |z_i| <= 2^63 - 2^25.  A pass of `CARRY_REDUCE' will
+   * leave |z_i| <= 2^38 + 2^25; and a second pass will leave |z_i| <= 2^25 +
+   * 2^13, which is comfortable for an addition prior to the next
+   * multiplication.
+   */
+  for (i = 0; i < 2; i++) CARRY_REDUCE(z, z);
+  STASH(z, z);
+
+#elif F25519_IMPL == 10
+
+  dblpiece u[NPIECE], t, tt, p;
+  unsigned i, j, k;
+
+  /* This is unpleasant.  Honestly, this table seems to be the best way of
+   * doing it.
+   */
+  static const unsigned short off[NPIECE] = {
+      0,  10,  20,  30,  40,  50,  59,  69,  79,  89,  99, 108, 118,
+    128, 138, 148, 157, 167, 177, 187, 197, 206, 216, 226, 236, 246
+  };
+
+  /* First pass: things we must multiply by 19 or 38. */
+  for (i = 0; i < NPIECE - 1; i++) {
+    t = tt = 0;
+    for (j = i + 1; j < NPIECE; j++) {
+      k = NPIECE + i - j; p = (dblpiece)x->P[j]*y->P[k];
+      if (off[i] < off[j] + off[k] - 255) tt += p;
+      else t += p;
+    }
+    u[i] = 19*(t + 2*tt);
+  }
+  u[NPIECE - 1] = 0;
+
+  /* Second pass: things we must multiply by 1 or 2. */
+  for (i = 0; i < NPIECE; i++) {
+    t = tt = 0;
+    for (j = 0; j <= i; j++) {
+      k = i - j; p = (dblpiece)x->P[j]*y->P[k];
+      if (off[i] < off[j] + off[k]) tt += p;
+      else t += p;
+    }
+    u[i] += t + 2*tt;
+  }
+
+  /* And we're done. */
+  carry_reduce(u);
+  for (i = 0; i < NPIECE; i++) z->P[i] = u[i];
+
+#endif
+}
+
+/* --- @f25519_sqr@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x@ = an operand
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the square %$x^2$%.
+ */
+
+void f25519_sqr(f25519 *z, const f25519 *x)
+{
+#if F25519_IMPL == 26
+
+  piece PIECES(x);
+  dblpiece PIECES(z);
+  unsigned i;
+
+  FETCH(x, x);
+
+  /* See `f25519_mul' for bounds. */
+
+#define M(a, b) ((dblpiece)(a)*(b))
+  z0 =    M(x0, x0) +
+       38*(M(x2, x8) + M(x4, x6) + M(x5, x5)) +
+       76*(M(x1, x9) + M(x3, x7));
+  z1 =  2* M(x0, x1) +
+       38*(M(x2, x9) + M(x3, x8) + M(x4, x7) + M(x5, x6));
+  z2 = 2*(M(x0, x2) + M(x1, x1)) +
+       19* M(x6, x6) +
+       38* M(x4, x8) +
+       76*(M(x3, x9) + M(x5, x7));
+  z3 =  2*(M(x0, x3) + M(x1, x2)) +
+       38*(M(x4, x9) + M(x5, x8) + M(x6, x7));
+  z4 =    M(x2, x2) +
+       2* M(x0, x4) +
+       4* M(x1, x3) +
+       38*(M(x6, x8) + M(x7, x7)) +
+       76* M(x5, x9);
+  z5 = 2*(M(x0, x5) + M(x1, x4) + M(x2, x3)) +
+       38*(M(x6, x9) + M(x7, x8));
+  z6 = 2*(M(x0, x6) + M(x2, x4) + M(x3, x3)) +
+       4* M(x1, x5) +
+       19* M(x8, x8) +
+       76* M(x7, x9);
+  z7 = 2*(M(x0, x7) + M(x1, x6) + M(x2, x5) + M(x3, x4)) +
+       38* M(x8, x9);
+  z8 =    M(x4, x4) +
+       2*(M(x0, x8) + M(x2, x6)) +
+       4*(M(x1, x7) + M(x3, x5)) +
+       38* M(x9, x9);
+  z9 = 2*(M(x0, x9) + M(x1, x8) + M(x2, x7) + M(x3, x6) + M(x4, x5));
+#undef M
+
+  /* See `f25519_mul' for details. */
+  for (i = 0; i < 2; i++) CARRY_REDUCE(z, z);
+  STASH(z, z);
+
+#elif F25519_IMPL == 10
+  f25519_mul(z, x, x);
+#endif
+}
+
+/*----- More complicated things -------------------------------------------*/
+
+/* --- @f25519_inv@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@)
+ *             @const f25519 *x@ = an operand
+ *
+ * Returns:    ---
+ *
+ * Use:                Stores in @z@ the multiplicative inverse %$x^{-1}$%.  If
+ *             %$x = 0$% then @z@ is set to zero.  This is considered a
+ *             feature.
+ */
+
+void f25519_inv(f25519 *z, const f25519 *x)
+{
+  f25519 t, u, t2, t11, t2p10m1, t2p50m1;
+  unsigned i;
+
+#define SQRN(z, x, n) do {                                             \
+  f25519_sqr((z), (x));                                                        \
+  for (i = 1; i < (n); i++) f25519_sqr((z), (z));                      \
+} while (0)
+
+  /* Calculate x^-1 = x^(p - 2) = x^(2^255 - 21), which also handles x = 0 as
+   * intended.  The addition chain here is from Bernstein's implementation; I
+   * couldn't find a better one.
+   */                                  /* step | value */
+  f25519_sqr(&t2, x);                  /*    1 | 2 */
+  SQRN(&u, &t2, 2);                    /*    3 | 8 */
+  f25519_mul(&t, &u, x);               /*    4 | 9 */
+  f25519_mul(&t11, &t, &t2);           /*    5 | 11 = 2^5 - 21 */
+  f25519_sqr(&u, &t11);                        /*    6 | 22 */
+  f25519_mul(&t, &t, &u);              /*    7 | 31 = 2^5 - 1 */
+  SQRN(&u, &t, 5);                     /*   12 | 2^10 - 2^5 */
+  f25519_mul(&t2p10m1, &t, &u);                /*   13 | 2^10 - 1 */
+  SQRN(&u, &t2p10m1, 10);              /*   23 | 2^20 - 2^10 */
+  f25519_mul(&t, &t2p10m1, &u);                /*   24 | 2^20 - 1 */
+  SQRN(&u, &t, 20);                    /*   44 | 2^40 - 2^20 */
+  f25519_mul(&t, &t, &u);              /*   45 | 2^40 - 1 */
+  SQRN(&u, &t, 10);                    /*   55 | 2^50 - 2^10 */
+  f25519_mul(&t2p50m1, &t2p10m1, &u);  /*   56 | 2^50 - 1 */
+  SQRN(&u, &t2p50m1, 50);              /*  106 | 2^100 - 2^50 */
+  f25519_mul(&t, &t2p50m1, &u);                /*  107 | 2^100 - 1 */
+  SQRN(&u, &t, 100);                   /*  207 | 2^200 - 2^100 */
+  f25519_mul(&t, &t, &u);              /*  208 | 2^200 - 1 */
+  SQRN(&u, &t, 50);                    /*  258 | 2^250 - 2^50 */
+  f25519_mul(&t, &t2p50m1, &u);                /*  259 | 2^250 - 1 */
+  SQRN(&u, &t, 5);                     /*  264 | 2^255 - 2^5 */
+  f25519_mul(z, &u, &t11);             /*  265 | 2^255 - 21 */
+
+#undef SQRN
+}
+
+/* --- @f25519_quosqrt@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x, *y@ = two operands
+ *
+ * Returns:    Zero if successful, @-1@ if %$x/y$% is not a square.
+ *
+ * Use:                Stores in @z@ the one of the square roots %$\pm\sqrt{x/y}$%.
+ *             If %$x = y = 0% then the result is zero; if %$y = 0$% but %$x
+ *             \ne 0$% then the operation fails.  If you wanted a specific
+ *             square root then you'll have to pick it yourself.
+ */
+
+static const piece sqrtm1_pieces[NPIECE] = {
+#if F25519_IMPL == 26
+  -32595792,  -7943725,   9377950,   3500415,  12389472,
+    -272473, -25146209,  -2005654,    326686,  11406482
+#elif F25519_IMPL == 10
+   176,  -88,  161,  157, -485, -196, -231, -220, -416,
+  -169, -255,   50,  189,  -89, -266,  -32,  202, -511,
+   423,  357,  248, -249,   80,  288,   50,  174
+#endif
+};
+#define SQRTM1 ((const f25519 *)sqrtm1_pieces)
+
+int f25519_quosqrt(f25519 *z, const f25519 *x, const f25519 *y)
+{
+  f25519 t, u, w, beta, xy3, t2p50m1;
+  octet xb[32], b0[32], b1[32];
+  int32 rc = -1;
+  mask32 m;
+  unsigned i;
+
+#define SQRN(z, x, n) do {                                             \
+  f25519_sqr((z), (x));                                                        \
+  for (i = 1; i < (n); i++) f25519_sqr((z), (z));                      \
+} while (0)
+
+  /* This is a bit tricky; the algorithm is from Bernstein, Duif, Lange,
+   * Schwabe, and Yang, `High-speed high-security signatures', 2011-09-26,
+   * https://ed25519.cr.yp.to/ed25519-20110926.pdf.
+   *
+   * First of all, a complicated exponentation.  The addition chain here is
+   * mine.  We start with some preliminary values.
+   */                                  /* step | value */
+  SQRN(&u, y, 1);                      /*    1 | 0, 2 */
+  f25519_mul(&t, &u, y);               /*    2 | 0, 3 */
+  f25519_mul(&xy3, &t, x);             /*    3 | 1, 3 */
+  SQRN(&u, &u, 1);                     /*    4 | 0, 4 */
+  f25519_mul(&w, &u, &xy3);            /*    5 | 1, 7 */
+
+  /* And now we calculate w^((p - 5)/8) = w^(252 - 3). */
+  SQRN(&u, &w, 1);                     /*    6 | 2 */
+  f25519_mul(&t, &w, &u);              /*    7 | 3 */
+  SQRN(&u, &t, 1);                     /*    8 | 6 */
+  f25519_mul(&t, &u, &w);              /*    9 | 7 */
+  SQRN(&u, &t, 3);                     /*   12 | 56 */
+  f25519_mul(&t, &t, &u);              /*   13 | 63 = 2^6 - 1 */
+  SQRN(&u, &t, 6);                     /*   19 | 2^12 - 2^6 */
+  f25519_mul(&t, &t, &u);              /*   20 | 2^12 - 1 */
+  SQRN(&u, &t, 12);                    /*   32 | 2^24 - 2^12 */
+  f25519_mul(&t, &t, &u);              /*   33 | 2^24 - 1 */
+  SQRN(&u, &t, 1);                     /*   34 | 2^25 - 2 */
+  f25519_mul(&t, &u, &w);              /*   35 | 2^25 - 1 */
+  SQRN(&u, &t, 25);                    /*   60 | 2^50 - 2^25 */
+  f25519_mul(&t2p50m1, &t, &u);                /*   61 | 2^50 - 1 */
+  SQRN(&u, &t2p50m1, 50);              /*  111 | 2^100 - 2^50 */
+  f25519_mul(&t, &t2p50m1, &u);                /*  112 | 2^100 - 1 */
+  SQRN(&u, &t, 100);                   /*  212 | 2^200 - 2^100 */
+  f25519_mul(&t, &t, &u);              /*  213 | 2^200 - 1 */
+  SQRN(&u, &t, 50);                    /*  263 | 2^250 - 2^50 */
+  f25519_mul(&t, &t2p50m1, &u);                /*  264 | 2^250 - 1 */
+  SQRN(&u, &t, 2);                     /*  266 | 2^252 - 4 */
+  f25519_mul(&t, &u, &w);              /*  267 | 2^252 - 3 */
+
+  /* And finally... */
+  f25519_mul(&beta, &t, &xy3);         /*  268 | ... */
+
+  /* Now we have beta = (x y^3) (x y^7)^((p - 5)/8) = (x/y)^((p + 3)/8), and
+   * we're ready to finish the computation.  Suppose that alpha^2 = u/w.
+   * Then beta^4 = (x/y)^((p + 3)/2) = alpha^(p + 3) = alpha^4 = (x/y)^2, so
+   * we have beta^2 = Â±x/y.  If y beta^2 = x then beta is the one we wanted;
+   * if -y beta^2 = x, then we want beta sqrt(-1), which we already know.  Of
+   * course, it might not match either, in which case we fail.
+   *
+   * The easiest way to compare is to encode.  This isn't as wasteful as it
+   * sounds: the hard part is normalizing the representations, which we have
+   * to do anyway.
+   */
+  f25519_sqr(&t, &beta);
+  f25519_mul(&t, &t, y);
+  f25519_neg(&u, &t);
+  f25519_store(xb, x);
+  f25519_store(b0, &t);
+  f25519_store(b1, &u);
+  f25519_mul(&u, &beta, SQRTM1);
+
+  m = -ct_memeq(b0, xb, 32);
+  rc = PICK2(0, rc, m);
+  f25519_pick2(z, &beta, &u, m);
+  m = -ct_memeq(b1, xb, 32);
+  rc = PICK2(0, rc, m);
+
+  /* And we're done. */
+  return (rc);
+}
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <mLib/report.h>
+#include <mLib/str.h>
+#include <mLib/testrig.h>
+
+static void fixdstr(dstr *d)
+{
+  if (d->len > 32)
+    die(1, "invalid length for f25519");
+  else if (d->len < 32) {
+    dstr_ensure(d, 32);
+    memset(d->buf + d->len, 0, 32 - d->len);
+    d->len = 32;
+  }
+}
+
+static void cvt_f25519(const char *buf, dstr *d)
+{
+  dstr dd = DSTR_INIT;
+
+  type_hex.cvt(buf, &dd); fixdstr(&dd);
+  dstr_ensure(d, sizeof(f25519)); d->len = sizeof(f25519);
+  f25519_load((f25519 *)d->buf, (const octet *)dd.buf);
+  dstr_destroy(&dd);
+}
+
+static void dump_f25519(dstr *d, FILE *fp)
+  { fdump(stderr, "???", (const piece *)d->buf); }
+
+static void cvt_f25519_ref(const char *buf, dstr *d)
+  { type_hex.cvt(buf, d); fixdstr(d); }
+
+static void dump_f25519_ref(dstr *d, FILE *fp)
+{
+  f25519 x;
+
+  f25519_load(&x, (const octet *)d->buf);
+  fdump(stderr, "???", x.P);
+}
+
+static int eq(const f25519 *x, dstr *d)
+  { octet b[32]; f25519_store(b, x); return (memcmp(b, d->buf, 32) == 0); }
+
+static const test_type
+  type_f25519 = { cvt_f25519, dump_f25519 },
+  type_f25519_ref = { cvt_f25519_ref, dump_f25519_ref };
+
+#define TEST_UNOP(op)                                                  \
+  static int vrf_##op(dstr dv[])                                       \
+  {                                                                    \
+    f25519 *x = (f25519 *)dv[0].buf;                                   \
+    f25519 z, zz;                                                      \
+    int ok = 1;                                                                \
+                                                                       \
+    f25519_##op(&z, x);                                                        \
+    if (!eq(&z, &dv[1])) {                                             \
+      ok = 0;                                                          \
+      fprintf(stderr, "failed!\n");                                    \
+      fdump(stderr, "x", x->P);                                                \
+      fdump(stderr, "calc", z.P);                                      \
+      f25519_load(&zz, (const octet *)dv[1].buf);                      \
+      fdump(stderr, "z", zz.P);                                                \
+    }                                                                  \
+                                                                       \
+    return (ok);                                                       \
+  }
+
+TEST_UNOP(neg)
+TEST_UNOP(sqr)
+TEST_UNOP(inv)
+
+#define TEST_BINOP(op)                                                 \
+  static int vrf_##op(dstr dv[])                                       \
+  {                                                                    \
+    f25519 *x = (f25519 *)dv[0].buf, *y = (f25519 *)dv[1].buf;         \
+    f25519 z, zz;                                                      \
+    int ok = 1;                                                                \
+                                                                       \
+    f25519_##op(&z, x, y);                                             \
+    if (!eq(&z, &dv[2])) {                                             \
+      ok = 0;                                                          \
+      fprintf(stderr, "failed!\n");                                    \
+      fdump(stderr, "x", x->P);                                                \
+      fdump(stderr, "y", y->P);                                                \
+      fdump(stderr, "calc", z.P);                                      \
+      f25519_load(&zz, (const octet *)dv[2].buf);                      \
+      fdump(stderr, "z", zz.P);                                                \
+    }                                                                  \
+                                                                       \
+    return (ok);                                                       \
+  }
+
+TEST_BINOP(add)
+TEST_BINOP(sub)
+TEST_BINOP(mul)
+
+static int vrf_mulc(dstr dv[])
+{
+  f25519 *x = (f25519 *)dv[0].buf;
+  long a = *(const long *)dv[1].buf;
+  f25519 z, zz;
+  int ok = 1;
+
+  f25519_mulconst(&z, x, a);
+  if (!eq(&z, &dv[2])) {
+    ok = 0;
+    fprintf(stderr, "failed!\n");
+    fdump(stderr, "x", x->P);
+    fprintf(stderr, "a = %ld\n", a);
+    fdump(stderr, "calc", z.P);
+    f25519_load(&zz, (const octet *)dv[2].buf);
+    fdump(stderr, "z", zz.P);
+  }
+
+  return (ok);
+}
+
+static int vrf_condneg(dstr dv[])
+{
+  f25519 *x = (f25519 *)dv[0].buf;
+  uint32 m = *(uint32 *)dv[1].buf;
+  f25519 z;
+  int ok = 1;
+
+  f25519_condneg(&z, x, m);
+  if (!eq(&z, &dv[2])) {
+    ok = 0;
+    fprintf(stderr, "failed!\n");
+    fdump(stderr, "x", x->P);
+    fprintf(stderr, "m = 0x%08lx\n", (unsigned long)m);
+    fdump(stderr, "calc z", z.P);
+    f25519_load(&z, (const octet *)dv[1].buf);
+    fdump(stderr, "want z", z.P);
+  }
+
+  return (ok);
+}
+
+static int vrf_pick2(dstr dv[])
+{
+  f25519 *x = (f25519 *)dv[0].buf, *y = (f25519 *)dv[1].buf;
+  uint32 m = *(uint32 *)dv[2].buf;
+  f25519 z;
+  int ok = 1;
+
+  f25519_pick2(&z, x, y, m);
+  if (!eq(&z, &dv[3])) {
+    ok = 0;
+    fprintf(stderr, "failed!\n");
+    fdump(stderr, "x", x->P);
+    fdump(stderr, "y", y->P);
+    fprintf(stderr, "m = 0x%08lx\n", (unsigned long)m);
+    fdump(stderr, "calc z", z.P);
+    f25519_load(&z, (const octet *)dv[3].buf);
+    fdump(stderr, "want z", z.P);
+  }
+
+  return (ok);
+}
+
+static int vrf_pickn(dstr dv[])
+{
+  dstr d = DSTR_INIT;
+  f25519 v[32], z;
+  size_t i = *(uint32 *)dv[1].buf, j, n;
+  const char *p;
+  char *q;
+  int ok = 1;
+
+  for (q = dv[0].buf, n = 0; (p = str_qword(&q, 0)) != 0; n++)
+    { cvt_f25519(p, &d); v[n] = *(f25519 *)d.buf; }
+
+  f25519_pickn(&z, v, n, i);
+  if (!eq(&z, &dv[2])) {
+    ok = 0;
+    fprintf(stderr, "failed!\n");
+    for (j = 0; j < n; j++) {
+      fprintf(stderr, "v[%2u]", (unsigned)j);
+      fdump(stderr, "", v[j].P);
+    }
+    fprintf(stderr, "i = %u\n", (unsigned)i);
+    fdump(stderr, "calc z", z.P);
+    f25519_load(&z, (const octet *)dv[2].buf);
+    fdump(stderr, "want z", z.P);
+  }
+
+  dstr_destroy(&d);
+  return (ok);
+}
+
+static int vrf_condswap(dstr dv[])
+{
+  f25519 *x = (f25519 *)dv[0].buf, *y = (f25519 *)dv[1].buf;
+  f25519 xx = *x, yy = *y;
+  uint32 m = *(uint32 *)dv[2].buf;
+  int ok = 1;
+
+  f25519_condswap(&xx, &yy, m);
+  if (!eq(&xx, &dv[3]) || !eq(&yy, &dv[4])) {
+    ok = 0;
+    fprintf(stderr, "failed!\n");
+    fdump(stderr, "x", x->P);
+    fdump(stderr, "y", y->P);
+    fprintf(stderr, "m = 0x%08lx\n", (unsigned long)m);
+    fdump(stderr, "calc xx", xx.P);
+    fdump(stderr, "calc yy", yy.P);
+    f25519_load(&xx, (const octet *)dv[3].buf);
+    f25519_load(&yy, (const octet *)dv[4].buf);
+    fdump(stderr, "want xx", xx.P);
+    fdump(stderr, "want yy", yy.P);
+  }
+
+  return (ok);
+}
+
+static int vrf_quosqrt(dstr dv[])
+{
+  f25519 *x = (f25519 *)dv[0].buf, *y = (f25519 *)dv[1].buf;
+  f25519 z, zz;
+  int rc;
+  int ok = 1;
+
+  if (dv[2].len) { fixdstr(&dv[2]); fixdstr(&dv[3]); }
+  rc = f25519_quosqrt(&z, x, y);
+  if (!dv[2].len ? !rc : (rc || (!eq(&z, &dv[2]) && !eq(&z, &dv[3])))) {
+    ok = 0;
+    fprintf(stderr, "failed!\n");
+    fdump(stderr, "x", x->P);
+    fdump(stderr, "y", y->P);
+    if (rc) fprintf(stderr, "calc: FAIL\n");
+    else fdump(stderr, "calc", z.P);
+    if (!dv[2].len)
+      fprintf(stderr, "exp: FAIL\n");
+    else {
+      f25519_load(&zz, (const octet *)dv[2].buf);
+      fdump(stderr, "z", zz.P);
+      f25519_load(&zz, (const octet *)dv[3].buf);
+      fdump(stderr, "z'", zz.P);
+    }
+  }
+
+  return (ok);
+}
+
+static int vrf_sub_mulc_add_sub_mul(dstr dv[])
+{
+  f25519 *u = (f25519 *)dv[0].buf, *v = (f25519 *)dv[1].buf,
+    *w = (f25519 *)dv[3].buf, *x = (f25519 *)dv[4].buf,
+    *y = (f25519 *)dv[5].buf;
+  long a = *(const long *)dv[2].buf;
+  f25519 umv, aumv, wpaumv, xmy, z, zz;
+  int ok = 1;
+
+  f25519_sub(&umv, u, v);
+  f25519_mulconst(&aumv, &umv, a);
+  f25519_add(&wpaumv, w, &aumv);
+  f25519_sub(&xmy, x, y);
+  f25519_mul(&z, &wpaumv, &xmy);
+
+  if (!eq(&z, &dv[6])) {
+    ok = 0;
+    fprintf(stderr, "failed!\n");
+    fdump(stderr, "u", u->P);
+    fdump(stderr, "v", v->P);
+    fdump(stderr, "u - v", umv.P);
+    fprintf(stderr, "a = %ld\n", a);
+    fdump(stderr, "a (u - v)", aumv.P);
+    fdump(stderr, "w + a (u - v)", wpaumv.P);
+    fdump(stderr, "x", x->P);
+    fdump(stderr, "y", y->P);
+    fdump(stderr, "x - y", xmy.P);
+    fdump(stderr, "(x - y) (w + a (u - v))", z.P);
+    f25519_load(&zz, (const octet *)dv[6].buf); fdump(stderr, "z", zz.P);
+  }
+
+  return (ok);
+}
+
+static test_chunk tests[] = {
+  { "add", vrf_add, { &type_f25519, &type_f25519, &type_f25519_ref } },
+  { "sub", vrf_sub, { &type_f25519, &type_f25519, &type_f25519_ref } },
+  { "neg", vrf_neg, { &type_f25519, &type_f25519_ref } },
+  { "condneg", vrf_condneg,
+    { &type_f25519, &type_uint32, &type_f25519_ref } },
+  { "mul", vrf_mul, { &type_f25519, &type_f25519, &type_f25519_ref } },
+  { "mulconst", vrf_mulc, { &type_f25519, &type_long, &type_f25519_ref } },
+  { "pick2", vrf_pick2,
+    { &type_f25519, &type_f25519, &type_uint32, &type_f25519_ref } },
+  { "pickn", vrf_pickn,
+    { &type_string, &type_uint32, &type_f25519_ref } },
+  { "condswap", vrf_condswap,
+    { &type_f25519, &type_f25519, &type_uint32,
+      &type_f25519_ref, &type_f25519_ref } },
+  { "sqr", vrf_sqr, { &type_f25519, &type_f25519_ref } },
+  { "inv", vrf_inv, { &type_f25519, &type_f25519_ref } },
+  { "quosqrt", vrf_quosqrt,
+    { &type_f25519, &type_f25519, &type_hex, &type_hex } },
+  { "sub-mulc-add-sub-mul", vrf_sub_mulc_add_sub_mul,
+    { &type_f25519, &type_f25519, &type_long, &type_f25519,
+      &type_f25519, &type_f25519, &type_f25519_ref } },
+  { 0, 0, { 0 } }
+};
+
+int main(int argc, char *argv[])
+{
+  test_run(argc, argv, tests, SRCDIR "/t/f25519");
+  return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/f25519.h b/f25519.h
new file mode 100644 (file)
index 0000000..fc75546
--- /dev/null
+++ b/f25519.h
@@ -0,0 +1,285 @@
+/* -*-c-*-
+ *
+ * Arithmetic modulo 2^255 - 19
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_F25519_H
+#define CATACOMB_F25519_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#ifndef CATACOMB_QFARITH_H
+#  include "qfarith.h"
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef union {
+  int32 p26[10];
+  int16 p10[26];
+} f25519;
+
+#if !defined(F25519_IMPL) && defined(HAVE_INT64)
+#  define F25519_IMPL 26
+#endif
+
+#ifndef F25519_IMPL
+#  define F25519_IMPL 10
+#endif
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @f25519_set@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to write the result
+ *             @int a@ = a small-ish constant
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets @z@ to equal @a@.
+ */
+
+extern void f25519_set(f25519 */*x*/, int /*a*/);
+
+/* --- @f25519_load@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to store the result
+ *             @const octet xv[32]@ = source to read
+ *
+ * Returns:    ---
+ *
+ * Use:                Reads an element of %$\gf{2^{255} - 19}$% in external
+ *             representation from @xv@ and stores it in @z@.
+ *
+ *             External representation is little-endian base-256.  Elements
+ *             have multiple encodings, which are not produced by correct
+ *             software; use of noncanonical encodings is not an error, and
+ *             toleration of them is considered a performance feature.
+ *
+ *             Some specifications, e.g., RFC7748, require the topmost bit
+ *             (i.e., bit 7 of @wv[31]@) to be ignored.  Callers
+ *             implementing such specifications should clear the bit
+ *             explicitly.  (It's much easier for a caller who wants the bit
+ *             to be ignored to clear it than for a caller who wants the bit
+ *             to be significant to apply the necessary change by hand.)
+ */
+
+extern void f25519_load(f25519 */*z*/, const octet /*xv*/[32]);
+
+/* --- @f25519_store@ --- *
+ *
+ * Arguments:  @octet zv[32]@ = where to write the result
+ *             @const f25519 *x@ = the field element to write
+ *
+ * Returns:    ---
+ *
+ * Use:                Stores a field element in the given octet vector in external
+ *             representation.  A canonical encoding is always stored, so,
+ *             in particular, the top bit of @xv[31]@ is always left clear.
+ */
+
+extern void f25519_store(octet /*zv*/[32], const f25519 */*x*/);
+
+/* --- @f25519_pick2@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x, *y@ = two operands
+ *             @uint32 m@ = a mask
+ *
+ * Returns:    ---
+ *
+ * Use:                If @m@ is zero, set @z = y@; if @m@ is all-bits-set, then set
+ *             @z = x@.  If @m@ has some other value, then scramble @z@ in
+ *             an unhelpful way.
+ */
+
+extern void f25519_pick2(f25519 */*z*/, const f25519 */*x*/,
+                        const f25519 */*y*/, uint32 /*m*/);
+
+/* --- @f25519_pickn@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result
+ *             @const f25519 *v@ = a table of entries
+ *             @size_t n@ = the number of entries in @v@
+ *             @size_t i@ = an index
+ *
+ * Returns:    ---
+ *
+ * Use:                If @0 <= i < n < 32@ then set @z = v[i]@.  If @n >= 32@ then
+ *             do something unhelpful; otherwise, if @i >= n@ then set @z@
+ *             to zero.
+ */
+
+extern void f25519_pickn(f25519 */*z*/, const f25519 */*v*/, size_t /*n*/,
+                        size_t /*i*/);
+
+/* --- @f25519_condswap@ --- *
+ *
+ * Arguments:  @f25519 *x, *y@ = two operands
+ *             @uint32 m@ = a mask
+ *
+ * Returns:    ---
+ *
+ * Use:                If @m@ is zero, do nothing; if @m@ is all-bits-set, then
+ *             exchange @x@ and @y@.  If @m@ has some other value, then
+ *             scramble @x@ and @y@ in an unhelpful way.
+ */
+
+extern void f25519_condswap(f25519 */*x*/, f25519 */*y*/, uint32 /*m*/);
+
+/* --- @f25519_add@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the sum %$x + y$%.
+ */
+
+extern void f25519_add(f25519 */*z*/,
+                      const f25519 */*x*/, const f25519 */*y*/);
+
+/* --- @f25519_sub@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the difference %$x - y$%.
+ */
+
+extern void f25519_sub(f25519 */*z*/,
+                      const f25519 */*x*/, const f25519 */*y*/);
+
+/* --- @f25519_neg@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@)
+ *             @const f25519 *x@ = an operand
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z = -x@.
+ */
+
+extern void f25519_neg(f25519 */*z*/, const f25519 */*x*/);
+
+/* --- @f25519_condneg@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@)
+ *             @const f25519 *x@ = an operand
+ *             @uint32 m@ = a mask
+ *
+ * Returns:    ---
+ *
+ * Use:                If @m@ is zero, set @z = x@; if @m@ is all-bits-set, then set
+ *             @z = -x@.  If @m@ has some other value then scramble @z@ in
+ *             an unhelpful way.
+ */
+
+extern void f25519_condneg(f25519 */*z*/, const f25519 */*x*/, uint32 /*m*/);
+
+/* --- @f25519_mulconst@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@)
+ *             @const f25519 *x@ = an operand
+ *             @long a@ = a small-ish constant; %$|a| < 2^{20}$%.
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the product %$a x$%.
+ */
+
+extern void f25519_mulconst(f25519 */*z*/, const f25519 */*x*/, long /*a*/);
+
+/* --- @f25519_mul@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the product %$x y$%.
+ */
+
+extern void f25519_mul(f25519 */*z*/,
+                      const f25519 */*x*/, const f25519 */*y*/);
+
+/* --- @f25519_sqr@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x@ = an operand
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the square %$x^2$%.
+ */
+
+extern void f25519_sqr(f25519 */*z*/, const f25519 */*x*/);
+
+/* --- @f25519_inv@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@)
+ *             @const f25519 *x@ = an operand
+ *
+ * Returns:    ---
+ *
+ * Use:                Stores in @z@ the multiplicative inverse %$x^{-1}$%.  If
+ *             %$x = 0$% then @z@ is set to zero.  This is considered a
+ *             feature.
+ */
+
+extern void f25519_inv(f25519 */*z*/, const f25519 */*x*/);
+
+/* --- @f25519_quosqrt@ --- *
+ *
+ * Arguments:  @f25519 *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const f25519 *x, *y@ = two operands
+ *
+ * Returns:    Zero if successful, @-1@ if %$x/y$% is not a square.
+ *
+ * Use:                Stores in @z@ the one of the square roots %$\pm\sqrt{x/y}$%.
+ *             If %$x = y = 0% then the result is zero; if %$y = 0$% but %$x
+ *             \ne 0$% then the operation fails.  If you wanted a specific
+ *             square root then you'll have to pick it yourself.
+ */
+
+extern int f25519_quosqrt(f25519 */*z*/,
+                         const f25519 */*x*/, const f25519 */*y*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/fgoldi-tests.in b/fgoldi-tests.in
new file mode 100644 (file)
index 0000000..1f635c7
--- /dev/null
@@ -0,0 +1,572 @@
+### Test cases for arithmetic mod 2^448 - 2^224 - 1.
+
+add {
+  ## Some easy ones.
+  ffffffffffffff01000030000000ffffff2f00000002000030000000ffffff5f000000fbfffffffffffffcffff4f000000ffffffefffffff
+    00
+    ffffffffffffff01000030000000ffffff2f00000002000030000000ffffff5f000000fbfffffffffffffcffff4f000000ffffffefffffff;
+  fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff
+    0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff;
+  fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff
+    01 00;
+
+  ## Random tests.
+  6b3944398448a0a5f6c4e1be9abfcbb082b8f68f1c831d51ef2244f6e1a4c4baaf0ada769c1261b8e14b4856de381d69961078ea1949d39c
+    62e933c5f93e57e042d66b89d3c72ee85441b1207732d888b3d6bc35f3bcef91a6f4564cb085fd3239191c2fe427dcdb0e81164d30ca8145
+    cd2278fe7d87f785399b4d486e87fa98d7f9a7b093b5f5d9a2f9002cd561b44c56ff30c34c985eeb1a656485c260f944a5918e374a1355e2;
+  34938a406030a285024e9ff0a45987b53accc9d5d59828de8b8e07ba693b64d1dd2c7a190e708253a9ae57572e44fa458c8f8ac87cd96037
+    9d05863131328886c7203fe70924761e56244d40a04d4b5592f1c6a457b9d94fe950fb8a865f9091ba9223479f3e46680fb78ccddc776bf2
+    d298107291622a0cca6eded7ae7dfdd390f0161676e673331e80ce5ec2f43d21c77d75a494cf12e563417b9ecd8240ae9b4617965951cc29;
+  4e9cb6823482233daf59662d00212f2afe42183f8ce949b2e0ca5473e32ab647fe9bc1c472b2288715c0d5b118043fbc9aec782654363cdd
+    6c62329ec8eb576b6866cb6af702b891dd2cd72d21c354ada34221141381acca066fb46a8fbce28df44f0ac8062e38847067b8639be867f8
+    bbfee820fd6d7ba817c03198f723e7bbdb6fef6cadac9e5f840d7687f7ab6212050b762f026f0b150a10e0791f3277400b54318aef1ea4d5;
+  b46d33f24a69c2288bed34eb054d1fcd6244606cffca7d53ff4e68f113174655a9a72898ad2699fe49d069a0a84e077bf48205008dee04aa
+    9abc68911a75a6a376837cc6fc0e18c63cfb81747a59ba1314412f032f8b2a2fc5dde29176d141e71dbc11aeb2ecb9a336c8467882a175ea
+    4f2a9c8365de68cc0171b1b1025c37939f3fe2e079243867139097f443a270846e850b2a24f8dae5678c7b4e5b3bc11e2b4b4c780f907a94;
+  1195eae69f2bad43b7b8330395e41c811bae2f753f0a6727b9decd2e553dce743dbb568b45140c3a464c8646db12b3af18df328a95640706
+    8fc020ba693b4014fbf4e9c64223a8c3234e1361b8e2a745e3897f582537e20417831c159c107451fec49b88c4cde774330d8986430b39e0
+    a0550ba10967ed57b2ad1dcad707c5443ffc42d6f7ec0e6d9c684d877a74b079543e73a0e124808b441122cf9fe09a244cecbb10d96f40e6;
+  4b25a323cba12b5d042369a065a3696c7613898205f7defd3ab15ec351ec9fe1ba453c8b9abf254ff793c92b1f77d5f23f7629c04ec5c70d
+    b12ee8f930b029e2e4b79b808566b88b8087a510e5f80751ffc8f5426709bc2b40608e3e769dbd97d37dfe8a36fd25fbc1efb2cd9eda09f2
+    fc538b1dfc51553fe9da0421eb0922f8f69a2e93eaefe64e3a7a5406b9f55b0dfba5cac9105de3e6ca11c8b65574fbed0166dc8ded9fd1ff;
+  c441e6cebc634bd7de7de356e855528d52f4affae7cdd585352d94218ca171929b17b8f49ea294f5151a277c116519de5ff92ce4e2f6ce0a
+    809617d4e40d53223f01887bfab5a7d2dc1eb4f680ae59981b33e11fe71345b3155f567cc867cd9e48c8b534870c7df49dff883c0900d8cd
+    44d8fda2a1719ef91d7f6bd2e20bfa5f2f1364f1687c2f1e5160754173b5b645b1760e71670a62945ee2dcb0987196d2fdf8b520ecf6a6d8;
+  a92361d9c458605877a6d9229128b1a52f7bab378d0d389568aae10d09d419b0e6436684b438abcaa3e1710efee5ecec1af06cf0c82b339d
+    74bc6cd43025234b1a6e15fe2d4fab520c874af6f896b82ecb096b0ec3cf73ecf04ef1d13ca612ef0981b8aca0a769ae60202eca36410b0e
+    1de0cdadf57d83a39114ef20bf775cf83b02f62d86a4f0c333b44c1ccca38d9cd7925756f1debdb9ad622abb9e8d569b7b109bbaff6c3eab;
+  f0ed25db758767b83b1d5ab6f8bdbe8e263b18341ea296b2a5d27c0d928004d6c48695ac88af863ed12be6629d8a1b58ca83ddb4ff9c778b
+    44998d5a87e29ace239af04334451efca0d8bb88b441140caab3e79da9c73f1354df0c4e2a8148141bb44c33eb63f1c0025ec2b289390e06
+    3487b335fd6902875fb74afa2c03dd8ac713d4bcd2e3aabe4f8664ab3b4844e91866a2fab230cf52ecdf329688ee0c19cde19f6789d68591;
+  64429139cb6dd44a64984ac73cdf306354a32772da0724c647164d89218906de465c0c47f2841564fc69933d140088a02584bbeb7a138e7a
+    391d7bf04dd8082b6b196651c251737ba319720b66075f2e65a06023e1dc9697ee4c540b6fae20bdc333c9a95e69266b5ebeccf0b2aea18d
+    9e5f0c2a1946dd75cfb1b018ff30a4def7bc997d400f83f4acb6adac03669d7535a9605261333621c09d5ce77269ae0b844288dc2dc22f08;
+  0bb7ca441d108e3d7a4c43025798eb1f1036e2d2200e2457aa93a631c068bf9e99805e8c69344d6f5fc063865f2e94bb954c20645f8b7003
+    3f47bc6701604867acc3cf534d62c9847617954d860c34ac2bcacbfb1c24c99a7442a6170ea6539df0c98afaf6fc8f45dcaa77afebcc8290
+    4afe86ac1e70d6a426101356a4fab4a4864d7720a71a5803d65d722ddd8c88390ec304a477daa00c508aee80562b240172f797134b58f393;
+  93205ac6e814337d0d12f8e55f0b62a32ba948cbc6df03293d51e67a7aa7e1457d201991f3392f1cc4a4a9b6b2ed27407ac4e24a5b0e2664
+    c2d648607a99e6dccb9f9940ffed57de39928d9c3fcbabd79876ecf1a5476ff5a637d0052f04d82a2794bf0e31268fd6ff640b4aa1ac921f
+    55f7a22663ae195ad9b191265ff9b981653bd66706abaf00d6c7d26c20ef503b2458e996223e0747eb3869c5e313b7167a29ee94fcbab883;
+  42bb562d81bac7f606d2157697f29f1799b3e5172f003f44785b80006fb56681b832ff6e7875d6a146b09a9a95f9f3cfb210f5b9aa545e0c
+    e7cc109d2ea008a1c938c66e296911c0d7503b1a961f23edce9532c718e53518729dcc6f7e921f831c56d1d8ee7c5b4919f4030ce6703e68
+    298867caaf5ad097d00adce4c05bb1d770042132c51f623147f1b2c7879a9c992ad0cbdef607f62463066c7384764f19cc04f9c590c59c74;
+  4cfc133cf2b3e22f569340c3a59299087f9caf8b36562d418f2e18494769278c16a22641e4de8f675e9540d6fc0f8c210a64dd63c8d01453
+    f33b0a3beaad1fb12ba48d69ef999bb7a5af3bd2b977aaf518bc65a13caaa9d61cacbb7c5ce6173a282d341cf83c86a458c8d2d10a1c1ac2
+    40381e77dc6102e18137ce2c952c35c0244ceb5df0cdd736a8ea7dea8413d162334ee2bd40c5a7a186c274f2f44c12c6622cb035d3ec2e15;
+  fc64ef657d34477c17b0674b697cc5a4bc8e665ba1dee02e5afd0d2f57e0a64abb2bc428215d9e8ece95c5283e4233d483201c286e4997cb
+    ed4af51625762548e95f32e7042f07bb260f734fb9ba43301daddff9a863990d79791d5db1bbbdbad75c09ce313d93638c219c989702c5ed
+    eaafe47ca2aa6cc400109a326eabcc5fe39dd9aa5a99245f77aaed280144405834a5e185d2185c49a6f2cef66f7fc6371042b8c0054c5cb9;
+  2fa4cdcae0b01f3f3aa28d4ff311054c73683c09749eb312cd4ff7cf018fa647a66b44477459cab757b9149623ecf9064dba16d5601eafb7
+    b378045a6652eea3cc9a8530dea6361daa86866f038e579670f2d50e072417342f1887827335a0a041d1411b24a68d8f190edd8a251ac3c7
+    e31cd22447030ee3063d1380d1b83b691defc278772c0ba93d42cdde09b3bd7bd583cbc9e78e6a58998a56b14792879666c8f35f8638727f;
+  5107c636bcd6bc59ec9c7fcf04efbf90fdde936bff7e221be660d542f74fcccb8b49220b93744203bdb7b026f1bb9fd9a64c0187fd3d99a7
+    ee48bc6d5c231bd7be253ed69171d2525157d0d8fe12fdafa6e7a3285f0d966fd4c570928f61850138489fca5cb540444c24b602d9025899
+    405082a418fad730abc2bda5966092e34e366444fe911fcb8c48796b575d623b600f939d22d6c704f5ff4ff14d71e01df370b789d640f140;
+  475e593758fa8506baa94e1b6070aeaff278d905af67f9e5a5273ae0737825d220c02ae7a89f39998f98895c83e51e7bd0cc0c9126273792
+    3f724d7bbb27bf8b2f4e328bd865e412ed6207802703def28b9b64567b15f7648c1f96ca5092400e32427f9880c95fa0a83f7fbdd6b2d2b7
+    87d0a6b213224592e9f780a638d692c2dfdbe085d66ad7d831c39e36f08d1c37addfc0b1f9317aa7c1da08f503af7e1b790c8c4efdd9094a;
+  fb7923d1a8666b372b41792749ae312903e1b1a8198970a5da6d85dc19a4326bcde206ee841a2bf106c95e99b42fa7eb3fa559b4b88d31c2
+    45e467dafaee144bbd614028c0ea4d3a37b4ef99ded5c9e44b7526916218202401233364bffadac9424143bac99b4c2d89ceea71c3fd0ea4
+    415e8baba3558082e8a2b94f09997f633a95a142f85e3a8a26e3ab6d7dbc528fce053a52441506bb490aa2537ecbf318c97344267c8b4066;
+  2212850af1b191227fc4875e981ee15968832cb6898243af481b62d91ae5cb26fdcd72e45a54cbbbd9efc5e1739f8683d8ab318586b51e7c
+    6b7b3294bfd31a11644924c988b0b19cfc1db66d8e674040ee21537b54aed4e1e217f0b3427d7d4d9dc7d9dcbcda8c2c47c5348b9eaa7ddb
+    8e8db79eb085ac33e30dac2721cf92f664a1e22318ea83ef363db5547093a008e0e562989dd1480977b79fbe307a13b01f71661025609c57;
+}
+
+sub {
+  890e734c6f4af5b1c62cf6fdd0facf76af535bdc9781396c59a6cd8c37cc96aac97fa61bef07c60c69dfb633049014868473d28481385ba1
+    0a06a622804bfe9041259a435be8c40aa56d1be10dd3c4261157c16c0d0d99d11b0f5dce0b164a2e6d4c53813242954830a39f2c894fb315
+    7f08cd29effef62085075cba75120b6c0ae63ffb89ae7445484f0c202abffdd8ad70494de3f17bdefb9263b2d14d7f3d54d03258f8e8a78b;
+  17935b9768cf9ecdc3b3a4c3c87ee20f766bca820f620c1852a48d680f445f1a28ee6a9a18fbdcdb9f35846bc6f0bbb1687b227bcadd4c3a
+    9f913b62023a48e577ac9aaa6d06bb5cf46ea3acc2946a80f66fba02859837491a31b6740a5ed1178c8b6faf4198ac836419deb8aa439c0d
+    78012035669556e84b070a195b7827b381fc26d64ccda1975b34d3658aab27d10dbdb4250e9d0bc413aa14bc84580f2e046244c21f9ab02c;
+  b1689e72355c7305d5cab07e2d672e7b92872c115f03f9b45fe7c9d3354ea0d3702f4f915900085ec44e816dcd731086c999c0e97ce52b40
+    a85e9b5cbe9f628049f91b9adcc1db63f19e8f7c37b92e43015d0f76f188c1cfe89c86910afb82c2c6f1f7197562b919380a1b32b2439006
+    090a031677bc10858bd194e450a55217a1e89c94274aca715e8aba5d44c5de038892c8ff4e05859bfd5c89535811576c918fa5b7caa19b39;
+  8f952f2233cdba45ccaafcb8e6d17b38529a44ff49e8ac8dc6378710d5e5af052c460e2758e3ee28f5866e71737c9b6e7731c03d11d21cd6
+    5bc41fd436b58032dd4f50cd0c57bda1127a3033c2183d8133cb9c40760ea41bb42f48f36b6a2f3bcd0dbc60b5bef5e4b712308ca0f2b443
+    34d10f4efc173a13ef5aacebd97abe963f2014cc87cf6f0c936ceacf5ed70bea7716c633ec78bfed2779b210bebda589bf1e90b170df6792;
+  708939d3a13fe996dd90b1128231b7da3593c12d9ab880a4da9febe7f12bfefe72aab1608145911fdfa1e3f1f59b426a06dee253d4d3eeb6
+    008929e61e53becf9bc6dcbf6414f3a71e9f134fcab293cd42e096fef3d87a472a79ed1ce623708aee31e12f5bef9bc6d0aa470ce2a52f80
+    700010ed82ec2ac741cad4521d1dc43217f4addecf05edd697bf54e9fd5283b74831c4439b212195f06f02c29aaca6a335339b47f22dbf36;
+  a7996b0ae1d8ad5856ae5cf3abc8fc61c4b3579d951b632b9af67dce957365759fb5a6f54965a86b1dcccc9439eebdeb04f616c3fb4db382
+    2df8e6cf52e985d0e20f4f5e9bbaf1b8bd7d7b982da05568b7ea82fd2a5c0302d0ce9feec5e135eca886fd30827905eae204a51e498a173d
+    7aa1843a8eef2788739e0d95100e0ba90636dc04687b0dc3e20bfbd06a176273cfe606078483727f7445cf63b774b80122f171a4b2c39b45;
+  74179531aaf2ee4e7a309350982fc9ce501ad18c650f0adacce5da9b520ce27c04ca69dca0e719713d4d10db532401bee26b7ff9819bf532
+    6a3554898f2951ed005bc4ac74dfd0ef124cffbb52301109d8414719473dc17a602a3b530195c383efa22dd6da87414395886e4b9dd5b5f3
+    09e240a81ac99d6179d5cea32350f8de3dced1d012dff8d0f4a393820acf2002a49f2e899f5256ed4daae204799cbf7a4de310aee4c53f3f;
+  e7c145e38ca66fd86991538ab11231abb60af8b0ab7460e047f7b5b69bbe4a3a56c28c14131c35621f4014d541ffabd642c774bc1a5c66c7
+    9ca047c2251cc6012bd734198e4b2c6ca0d50a85db601659b8380510fc6c1d08a27fa5fb8eb3c9e5622185f83fba6ed128d153cc9563e1d6
+    4a21fe20678aa9d63eba1e7123c7043f1635ed2bd0134a878fbeb0a69e512d32b442e71884686b7cbc1e8fdc01453d051af620f084f884f0;
+  8f01ab3bbedf7ac443423793a422910a54dd73f121ce6f52270d7953386bf2b0eb228b2560b7103aa94f3190e80038505f2b21a9f138c414
+    44a6b845b4b3b6d9c55478664fa2134df50e7ff4c5184aa57bcc8d01da42cdbb78da3898fd92287b604b6a369c06d695241c48605b57808f
+    4a5bf2f5092cc4ea7dedbe2c55807dbd5ecef4fc5bb525adab40eb515d2825f57248528d6224e8be4804c7594cfa61ba3a0fd94896e14385;
+  1b6f84c1ad9ec3d008f345a19305aa35e5b55efeb535024b0fc9aee4be1c031bb070655fc5e672ea75b5db98cff0dcfb5427e21e5ffc4fa9
+    ad5d4e308c69186e87ac97551e9ec34f2d1746d5f6712b126c3415346ac2271450aca96fc6b9e82ef7e2f3fad60df4f184e34dff8fb53b02
+    6e1136912135ab628146ae4b7567e6e5b79e1829bfc3d638a39499b0545adb0660c4bbeffe2c8abb7ed2e79df8e2e809d043941fcf4614a7;
+  25ce194230be078d7f35b85d68706d768fec7994654fcd3f63f3d32eaf59f17bc87a617d41f76b7d0c78b63377a203e43194f0b056d26b0b
+    76266bea72a15cdc355867a490e775c909b7b6cfc833107e7c6b7dbaed2c8491c6d000b2d7d2beb72d72937285aa1bceff18aa35d0c52158
+    aea7ae57bd1cabb049dd50b9d788f7ac8535c3c49c1bbdc1e6875674c02c6dea01aa60cb6924adc5de0523c1f1f7e715327b467b860c4ab3;
+  c010bfa3d130f868f2b975318139c2a847c69014b76164192b437fd7e26b892a5a2425670fe3e8fd9efdfa250f57579d1af2d24f8eb6ce92
+    bfe65616e278b6ce46b295600131bf5ea092451a87f6bc3adf1c86f2fe717351b073062ced1394a14051bb33f3874cca569aae8ba97605f9
+    002a688defb7419aab07e0d07f08034aa7334bfa2f6ba7de4b26f9e4e2f915d9a9b01e3b22cf545c5eac3ff21bcf0ad3c35724c4e43fc999;
+  b2f21992b1f2155b7afc3a1d731b52c03cf14208e634b7da123888d652afcd919e9f5f0bea8b9986c71a7ba08fefe58ee0402d9a23b95f2c
+    ae241fa6292c63f3c09301255a866825b39c9645512ea123486f9a873cacab567cd169c463fb1cf0417633a7055d831d23fd1d58dd42e726
+    04cefaeb87c6b267b96839f81895e99a8954acc2940616b7cac8ed4e1603223b22cef54686907c9685a447f989926271bd430f4246767805;
+  b714b60b2614ab6ce63bf8eae621357f2e921f79de94982fcd5f524015db3faa52b15ff042733958fa202786f61bfed0b9fb5d5873619aec
+    0c99e1da4c747ad1a625321cf9359b1d823544d1eacfddc38e4bfd729ed2f9fb37760242340f7986843fb8fa0435bcb5cffdf11453caebcf
+    ab7bd430d99f309b3f16c6ceedeb9961ac5cdba7f3c4ba6b3e1455cd760846ae1a3b5dae0e64c0d175e16e8bf1e6411beafd6b432097ae1c;
+  c5425daf8f7089def2ff910e256d9496fc109d2698cf15dec1ce3f8116231969c5ed327626362b0658c60e74023a3cae5ef128fb5d27cad7
+    bc4e49fbf095f73894c4d623a210475cb7ba78ebbcbee8ab55a851162f789fb21e72de95afe4ddd45b90289f94f6d02b5f5a4b90c603ea31
+    09f413b49eda91a55e3bbbea825c4d3a4556243bdb102d326c26ee6ae7aa79b6a67b54e076514d31fc35e6d46d436b82ff96dd6a9723e0a5;
+  9aa20b4259efd3a701a63347181fa63f56f42a97ef836bf3aab88d30bbf28a91bbf713a0170024e6057e2281ac113f9b58cb13d63e850ea7
+    09e7104367d8c0441d811ecc619af04def9236752c2d47bc508b0de3c3b29c74533d8eb9fee13279aed8d58247e4010206c697d9b72bab43
+    91bbfafef1161363e424157bb684b5f16661f421c35624375a2d804df73fee1c68ba85e6181ef16c57a54cfe642d3d9952057cfc86596363;
+  e8ead9316aeb8f56d43418cd3bb1a71234c9e20b4a6dc1604ffdfdbcaacebe73b71d18c2c167544304d895d67e2daa2538a4ad0708cd9acf
+    ff3603f0960bb7a92f2b7fbfe242b467164e0ca72e89bcab6c467b5391166d05c601b38de40643f04d5b50ff8ec62b18c69e9df74f01babe
+    e9b3d641d3dfd8aca409990d596ef3aa1d7bd6641be404b5e2b6826919b8516ef11b6534dd601153b67c45d7ef667e0d72051010b8cbe010;
+  f37b41d9950036d560f02b8befd6f5c73096b8995850b9fc563291fba59fd994916744fbd4c1dd5d17a9e5ecd4ec4a658dfdae1ba7024bc6
+    eeda58ba400f16a946381fb11f0ac0db895957236bcc629ce9d1ea425eef8412ea73af488b97f1afa950736f26c3cace887417b699cc3410
+    05a1e81e55f11f2c1ab80cdacfcc35eca63c6176ed8356606d60a6b847b05482a7f394b2492aecad6d58727dae298096048997650d3616b6;
+  2bdb71a053047c4173718ce104e5b8671fbd61c59bfe8b20b890ceda15a69d24eec3775f4ce8a9c16d36e50626bc334e0fc1be492d800c06
+    b1ccd0dac33ac46b2709f9626ed70136f98dfbc705ad93ea8f1b325d644daf2c0180cb83bfdbb7398d3f58c0f6600056a174850b9db91ed4
+    790ea1c58fc9b7d54b68937e960db731262f66fd9551f83528759c7db058eef7ec43acdb8c0cf287e0f68c462f5b33f86d4c393e90c6ed31;
+  8f3fd6346c7f2dacf0d7cdb88a5bca3b222a895a07b169d0bcd0af0a9aa634876ae1a939262dd75bd12b5a97127155a015e00acac7d5cbc8
+    0e9c03c5a06accdddd0d8613e41a00f2b586e297e366987e02e7536e0ca1b4c2c75fed619655acddffe8585c7a828432d90575731a4c8519
+    81a3d26fcb1461ce12ca47a5a640ca496ca3a6c2234ad151bae95b9c8d0580c4a281bcd78fd72a7ed142013b98eed06d3cda9556ad8946af;
+}
+
+condswap {
+  db0be3ccfda1e2f8492bffb5d3344f1856ff1896b6a067d2fa064423ac5b05b669db1c9b51899c44a7f470be4173856d9aa3d1cd10cb8c9b
+    3005560f89232a97cebf6808e7493dd0f17e572556b53723b57faee51d8a0a45c7fb51aeb916f59c74ea6041494483b2fdce72189d1bd031
+    0xffffffff
+    3005560f89232a97cebf6808e7493dd0f17e572556b53723b57faee51d8a0a45c7fb51aeb916f59c74ea6041494483b2fdce72189d1bd031
+    db0be3ccfda1e2f8492bffb5d3344f1856ff1896b6a067d2fa064423ac5b05b669db1c9b51899c44a7f470be4173856d9aa3d1cd10cb8c9b;
+  ea009751f6a7045ec7d6d46b16cbe663f5a78fca3835626c79864bec4030443bb9349654d52b2edab92b8f4aa876a97e868aa6267a54e6b1
+    8c6f864ef7f664f4985ed8c1ea0c63bd7ab355b5321c2712791b610a2dadddc90a65ca8d5c25ff199b011193796b08f96420934615103b7b
+    0x00000000
+    ea009751f6a7045ec7d6d46b16cbe663f5a78fca3835626c79864bec4030443bb9349654d52b2edab92b8f4aa876a97e868aa6267a54e6b1
+    8c6f864ef7f664f4985ed8c1ea0c63bd7ab355b5321c2712791b610a2dadddc90a65ca8d5c25ff199b011193796b08f96420934615103b7b;
+  dc3aa7d363058993cbdc54e95f3c972a2cea17cdf9370fccdfedfa1ba939ca35f762c5c6283f84348282fd56d83539804427eabe3bd6170d
+    8c47a0990eccf7300986232dbc8ee26e8996c3bb4b73663ec5525312bea8975221c9f49039840c181d042654a8c1806bb86702ac7d0b80f4
+    0x00000000
+    dc3aa7d363058993cbdc54e95f3c972a2cea17cdf9370fccdfedfa1ba939ca35f762c5c6283f84348282fd56d83539804427eabe3bd6170d
+    8c47a0990eccf7300986232dbc8ee26e8996c3bb4b73663ec5525312bea8975221c9f49039840c181d042654a8c1806bb86702ac7d0b80f4;
+  69b45538513af2148e0a2903539bc5e20fca4da447278bf5967091d2e781121080c14a41989f9ee5218c444d3a42989ba890c7be7faae5d3
+    935eadbde0c571c29deb4d8404dd39a8cca177ced36c359abfa7a6cafe6075422e1d79cba8d81cdbdfa4a5144faf37b19ca22b2b40fe1a0b
+    0x00000000
+    69b45538513af2148e0a2903539bc5e20fca4da447278bf5967091d2e781121080c14a41989f9ee5218c444d3a42989ba890c7be7faae5d3
+    935eadbde0c571c29deb4d8404dd39a8cca177ced36c359abfa7a6cafe6075422e1d79cba8d81cdbdfa4a5144faf37b19ca22b2b40fe1a0b;
+  de30072f175127ad4200a08099f4d0df0edfa40eb02e21a03c5628dcb2f70da8bce9ebbb1ebed2aca391e73a4114c06bcdbf762bf28777cf
+    5eaf3aecf1f7d1fd3b43be8fa450163c79f162b0c6eaa4b1ad39baaf3a4c36564e001c935fdce38e90789151beff0f3cc4fdfc2d86dcb587
+    0x00000000
+    de30072f175127ad4200a08099f4d0df0edfa40eb02e21a03c5628dcb2f70da8bce9ebbb1ebed2aca391e73a4114c06bcdbf762bf28777cf
+    5eaf3aecf1f7d1fd3b43be8fa450163c79f162b0c6eaa4b1ad39baaf3a4c36564e001c935fdce38e90789151beff0f3cc4fdfc2d86dcb587;
+  1bb20a5a05b190737ad6b2bc5bc2b9259fa7e36eac8f3032a7c56ed59c1510baaea32bba898b329b0c64fadbe454095b9f82b366bfae3d8b
+    cf0a87c8befed020caf82f37b4c5f17d2aa9ff8ab75baa156cfe2716ac1eaabf9bc760c2ddcd66a9d02a8384ad1db9e8f857b151d126e0ef
+    0x00000000
+    1bb20a5a05b190737ad6b2bc5bc2b9259fa7e36eac8f3032a7c56ed59c1510baaea32bba898b329b0c64fadbe454095b9f82b366bfae3d8b
+    cf0a87c8befed020caf82f37b4c5f17d2aa9ff8ab75baa156cfe2716ac1eaabf9bc760c2ddcd66a9d02a8384ad1db9e8f857b151d126e0ef;
+  c186531a219344dc485cd5dad6500616ac8e0653693168573cb9be590b02dfb1ddc5d87d27f2d9fa46ffeda955a6285b7ef2b9bf84825d06
+    91f3be7eb2e0be38d92974d81be5126ef40d358f242d23aa4863fb16ba3e8844e02edc87c0206e211587886ed532da0ab148cfcf64e9b58d
+    0x00000000
+    c186531a219344dc485cd5dad6500616ac8e0653693168573cb9be590b02dfb1ddc5d87d27f2d9fa46ffeda955a6285b7ef2b9bf84825d06
+    91f3be7eb2e0be38d92974d81be5126ef40d358f242d23aa4863fb16ba3e8844e02edc87c0206e211587886ed532da0ab148cfcf64e9b58d;
+  9f2476d6db424d19ee0cba4ed091da5b44ca63caf2f711eaeb7edcc75f49e0d0c367c1f2817b6bb39460f897432901064cabed7f6a03b1f0
+    66e7dcd34d76a19e3285685112b7619f9a3557764a918922faf1370bb97c2b2fa845dd34662cfe7299ab702c68fd43b5f6f15a0af6625f2e
+    0xffffffff
+    66e7dcd34d76a19e3285685112b7619f9a3557764a918922faf1370bb97c2b2fa845dd34662cfe7299ab702c68fd43b5f6f15a0af6625f2e
+    9f2476d6db424d19ee0cba4ed091da5b44ca63caf2f711eaeb7edcc75f49e0d0c367c1f2817b6bb39460f897432901064cabed7f6a03b1f0;
+  f124ac31d304a29cdd94bdc0611c61064a7c5f09cf6847bccd52fc7a7b77ede73b42b1ef75f000de4361028e0fb63896f4ef5ad3bc1b9c90
+    6629084a230c793086e469b9a01e052ad7a5680d6955667e0dfb19a250f447d9e238695400dc4ecaeefcebed44d374e57ec4e414f5629e63
+    0x00000000
+    f124ac31d304a29cdd94bdc0611c61064a7c5f09cf6847bccd52fc7a7b77ede73b42b1ef75f000de4361028e0fb63896f4ef5ad3bc1b9c90
+    6629084a230c793086e469b9a01e052ad7a5680d6955667e0dfb19a250f447d9e238695400dc4ecaeefcebed44d374e57ec4e414f5629e63;
+  b64f2952510827bef3d32ef6347251274c7241d9913268a7a6a5c360a4b29e7ed04d09a9ee5aa83235eaf8c0582b076b21d78b7062952773
+    77897028a9a81fd54362a6085aa2c2fd6fdd44589f447c7310b9b3b5a29b54ed15c57e2c9fbff16f20129a4dbd43640a0d1037e277ca5c93
+    0xffffffff
+    77897028a9a81fd54362a6085aa2c2fd6fdd44589f447c7310b9b3b5a29b54ed15c57e2c9fbff16f20129a4dbd43640a0d1037e277ca5c93
+    b64f2952510827bef3d32ef6347251274c7241d9913268a7a6a5c360a4b29e7ed04d09a9ee5aa83235eaf8c0582b076b21d78b7062952773;
+  4d75efd204a66aed323456e6f55cb891ee7a31d739ae89726e0ea84532f9c740d1b647b117094fb85da2c62da04f3b9cb13db6b840046b7c
+    0afd07bb073a150e7b82711e1f42f7b0789af8192ea6b4e1b24a3d48de7f8b802875aca5a02a9d24deca0b58c895992a449d01026495b96c
+    0x00000000
+    4d75efd204a66aed323456e6f55cb891ee7a31d739ae89726e0ea84532f9c740d1b647b117094fb85da2c62da04f3b9cb13db6b840046b7c
+    0afd07bb073a150e7b82711e1f42f7b0789af8192ea6b4e1b24a3d48de7f8b802875aca5a02a9d24deca0b58c895992a449d01026495b96c;
+  1ff4eb5f0280744f0c909cede8be29cccb8ae43e4626018a9a1d352a97d987678863ba34bdeb183bb5e9347e96760665f5881570778a2e19
+    49cd390a9edc7fad6c84c2e44ce09e490161094d2dc6cad30759fbef10aa30e5aa6474bc46571188418f3e4a2b19ecfc379a1f94e3a44e48
+    0x00000000
+    1ff4eb5f0280744f0c909cede8be29cccb8ae43e4626018a9a1d352a97d987678863ba34bdeb183bb5e9347e96760665f5881570778a2e19
+    49cd390a9edc7fad6c84c2e44ce09e490161094d2dc6cad30759fbef10aa30e5aa6474bc46571188418f3e4a2b19ecfc379a1f94e3a44e48;
+  e96c0316baf01c25ef8a41c02e99aa84c82f8eecd3249be268834afb5f7e95f0ad10bfad4160bb335c30ffd6a1090c91c57eb6ac7a7a5e66
+    115e6f115bc4e19af60710f3dd821fb58cb680a32d6973eae9ea3e48f1928dc1d9f684a8c8de80affc59bc0fb342bb040f89d2d46b8ff8fc
+    0x00000000
+    e96c0316baf01c25ef8a41c02e99aa84c82f8eecd3249be268834afb5f7e95f0ad10bfad4160bb335c30ffd6a1090c91c57eb6ac7a7a5e66
+    115e6f115bc4e19af60710f3dd821fb58cb680a32d6973eae9ea3e48f1928dc1d9f684a8c8de80affc59bc0fb342bb040f89d2d46b8ff8fc;
+  71bd8f5036da4c33f6940348ea448c2f9bccb152dab40b410bd695923a9e255b33aaf361055be4bb9a570e201dce784cc1ccb0f89faca85f
+    971b2f6569ddd9099a87ec4086d8218abcfbe81579f25f03634e471170a5088f48a6cfd09ed9e389ca37b780165c00b206304229135b6044
+    0xffffffff
+    971b2f6569ddd9099a87ec4086d8218abcfbe81579f25f03634e471170a5088f48a6cfd09ed9e389ca37b780165c00b206304229135b6044
+    71bd8f5036da4c33f6940348ea448c2f9bccb152dab40b410bd695923a9e255b33aaf361055be4bb9a570e201dce784cc1ccb0f89faca85f;
+  0f1165e19968f3e6159e9f7f843c1b849e5c3917af4e2798869112c6efca9993ed339c8495eec8c54b286820bf7befdc8ae344e4d309c077
+    7ce5a2ae66b9bddd30c98d9aa9fcdd6ef90d244d10115d15cf5d81e9e389f6852b153a42c642447043fcfd278166b92c624508973449b0e8
+    0xffffffff
+    7ce5a2ae66b9bddd30c98d9aa9fcdd6ef90d244d10115d15cf5d81e9e389f6852b153a42c642447043fcfd278166b92c624508973449b0e8
+    0f1165e19968f3e6159e9f7f843c1b849e5c3917af4e2798869112c6efca9993ed339c8495eec8c54b286820bf7befdc8ae344e4d309c077;
+  6dd07b4891d8f45ad1ee64da38383ec50d6f29634767607eca19a547cadc3c157ebe7d86a28d4d2fa2d40f2c5402d8b338cfd8d30aeadb6a
+    63da9a5a0cd51e58168ddb305c0e70a2f898279dae6394e1b3e1ef3a0763847d5d2f15be493114360204d037d7d3c3a9e746d27dcb544ded
+    0xffffffff
+    63da9a5a0cd51e58168ddb305c0e70a2f898279dae6394e1b3e1ef3a0763847d5d2f15be493114360204d037d7d3c3a9e746d27dcb544ded
+    6dd07b4891d8f45ad1ee64da38383ec50d6f29634767607eca19a547cadc3c157ebe7d86a28d4d2fa2d40f2c5402d8b338cfd8d30aeadb6a;
+  d91228b648f75350d775432af35be9aa283e9729fcd3b689f0c7ee02ea67efd33493980ae5eec92ad6ab42ccd253a7aab5a62c26be275278
+    07c5d1b4f9b8db88cd4187b1ae5e175bf703af12b26d066c1d55dd367569d3e23e3d0470f3c47e6761746ce7de39cf563500d026a6791980
+    0xffffffff
+    07c5d1b4f9b8db88cd4187b1ae5e175bf703af12b26d066c1d55dd367569d3e23e3d0470f3c47e6761746ce7de39cf563500d026a6791980
+    d91228b648f75350d775432af35be9aa283e9729fcd3b689f0c7ee02ea67efd33493980ae5eec92ad6ab42ccd253a7aab5a62c26be275278;
+  f9e764e20657319802b53ee29df43b0d83d994d9049b9820fc0c31b631265c49f6613923a042eadce5902fb81753784ff5a9c0de2c4f6b12
+    6ab2f8279e82aa65e8326e5c60bfa067e4967b3ea67d0369853282e5429736529a43eeee3fdf24ebbe5ca85b59647994fc99c90da83c6229
+    0xffffffff
+    6ab2f8279e82aa65e8326e5c60bfa067e4967b3ea67d0369853282e5429736529a43eeee3fdf24ebbe5ca85b59647994fc99c90da83c6229
+    f9e764e20657319802b53ee29df43b0d83d994d9049b9820fc0c31b631265c49f6613923a042eadce5902fb81753784ff5a9c0de2c4f6b12;
+  772289865ac905fac203e4654b258890ddb91cac71c6d2af3826e3acfebfa222c937b40069ce3a757e2ffd960b5821ed1ad54e4ad2e3c6fd
+    58dbf838ab81a754533c7f80fea48cbc981f724e4c150ddbb0afb5c711a8e21079446f77c427f7eb1892c096fa3eae5e2b070413611cd184
+    0xffffffff
+    58dbf838ab81a754533c7f80fea48cbc981f724e4c150ddbb0afb5c711a8e21079446f77c427f7eb1892c096fa3eae5e2b070413611cd184
+    772289865ac905fac203e4654b258890ddb91cac71c6d2af3826e3acfebfa222c937b40069ce3a757e2ffd960b5821ed1ad54e4ad2e3c6fd;
+  0bd6656d68c41bfc5389db274367f69191754919435ba58d2256017b5bc595d102c6f4f745b3ceb0c32bd0a6cdadded3a3dc925ef2b5c73c
+    1d903009c74d3d135a192bd42466cd28303f482626a7d10832f1f6eae72c3b051b0373e62300a71226011475034f0bfc6c9a65601bb83993
+    0xffffffff
+    1d903009c74d3d135a192bd42466cd28303f482626a7d10832f1f6eae72c3b051b0373e62300a71226011475034f0bfc6c9a65601bb83993
+    0bd6656d68c41bfc5389db274367f69191754919435ba58d2256017b5bc595d102c6f4f745b3ceb0c32bd0a6cdadded3a3dc925ef2b5c73c;
+}
+
+mulconst {
+  cb908747a1af81f52715ef8440aed06aaacbcd7903c99cdecef5ec54e7845bedaad6475028b0cbdb0d53b6eeb71843f900fefd398a083d5a -417895
+    e95e64fd1b2e2e79d1bfef5c96942eaf7ca5d40b1af774ed9c4ea2351c8ae81013f896bafd1f0b0e3a3c2ca3347c6cf88f988877af5e009b;
+  46b23d83c0848e79af947191cb76b087483beec6224af749e59c0c5ae27ff8abada31da895f8132aae0457f5ddc30d18a8d52046fbe6ef55 384370
+    31c9bf2f3bdfd3c1dc115db96d7a1c15e2a9ae67dfebccddc9408a0dcd147d9aa62ce4a55a2d6ad54542317756a08d6be3b959bf132624e2;
+  53e19751de62909506bebf74411d359014ec4b6afbb8ce14eeed8a3938013f0fee6897e3cc3adcbc90d7df321c4caa1941d0e5909551335d -49682
+    82fb902a8992ec1032a6837cec56189c45d1c1fdc47748e17dd9ecabc807a52eb537d6411f99f4d3b328e7ca76475924f90506a8adeb908e;
+  7ff3b9b3d8ee248a48d0c8d308d8c3658374acc92303143061a46656ae2b35094ed7b5b27d23366c0e42ee0a9471a4355d81cda0e4390348 131908
+    adbb3dd21e634dfe2c41593c65249f03a048338037d4a107892df36f10e3ff68402d6f48e74bc7a7858f2c3650fd2a10acdfd4213850529e;
+  f532f4f5ab5447b083ee4225246aaa4448696e4fc8bcf5b0ec1b52df88354e5327d7a3cf6e15db9945205968c275755ea3906a27437d29ed 383911
+    1f42b3585a2553ab19b14639c3e3aca636d88053c70fb758962713783bcd824b729fb4d01dd56a344d991bf2d32a2967acf470b39bee88a6;
+  ef0e2a829097e50575eae6b1ad3fa10b8e417b0363654e0cb07a563a905c02e367c6f1ad7be1469b9f5295e3db0726853adffb820715f7d1 -226220
+    a7c5387af1b9f61f09d628feac1a050173021386775c9f534557b8841b812155325e3632eee7a2302ef8af0b4746575d6c2bcf3b29f674b0;
+  3b4655b1c22542ca413f76bc24751a01cdab6b385b50301d67fd62ba31ad132150e38e12a849405112c4742e93b92849bd8b872c29edb2f9 -89924
+    b51c0dfa2407a89435fedbcfd7835b6e0849d8626995fd00974f44c49d794d3c5dc16028e9fdee45bbcd269035e8bdba695a6653028d4d59;
+  48bdc2073bff25ae9bf7fcc368d65602a71e48c343bc7181c361331f108867d56c588f698aa5b91222f5dbbc859bce656f2607b053222fc7 66432
+    e845dfe65d563884074ffeecaa325706df4a129b73b056cab6ad999588216d72525222ce00ce4d2ffb09fcf6f010a6eeb2eb753fefd44b47;
+  98a26f23f83673a480076b2fc7ccfef07fbbe70c4160d5af638c345f7d17b00931efff543fd47b7b8b362a70657a458566ada4aefd1c5eaf 492192
+    0ef483482255b5ca0f8338317f6eaf9c4fbf8bde8b8b04e26d2cdc0632186f1e62a9c3a1be23e8dc444ce50783135aeca614c884bdb77a30;
+  6ebf7c4e06837120cc852a077945656046e64c2d88ce440bdfc8d38736a4d510a722bc8b0d225f11df0e704e4b04c48bf481da68fd1e150e -7098
+    8d4e2cd12323b5744442fe4e4fc21748b344d7f94794398ec187f0f986ee743cd733a7a16bd4495818ab033103f020c794c988c5d2c1628a;
+  94e49f2bb473a7273abed94363c4dc3d13db159e3c3698a62ce5f321252aa03c7f63dd6eff9529c985f43abc7283d11140cb44ff6fd0f3d3 -392951
+    58a606cdc1bf1d5646fc08c7a6b3336fbe532c823c70242ea7536cc6dcdde7c4f492306e39ac0fb88367e41d63a8305d69fab57a52c8c284;
+  cd262298ce3b73294bfb523c30206fc3771144890a0ebcef19e02e5085973a6aeefabdf8cb7186d57be38ee84b114b9a7a22556c0cf88df1 -237681
+    7553420c53b255fb909d6e9008f043e7af25a2a9c29b177b830ff1ae6f6fdcb6aefb8386465f24634fb04c6078322ac691586f91cf7928bd;
+  cc9bd2e72ce15dd50877f95812b65c65cf09b14e2817784a5b296c123e498c532362180a932a455b2ddb75e26335dbcb21eb94a90ebb6940 246794
+    8838e720b6e497d9cde9fbddc2333c13cb5bdbbbe5afe41ffd61f5035c8c4987fddb8036c25b0505765bf1a5aa369c6bf7723c65278584a8;
+  d8ab6b8f3523e98f49140e051c0b744bb0068d20f499c0763aa28ec1d1dd7e86356f357149c317376be96cd520b3ae04a2c4d468d74745e8 -360296
+    4c0bc5f6fc52c6302b74c790d57ccc8fae59f2aeebb59c3393c56e70060f4d170ea41354f5040804a6e8dcb4a7c585ee71a6d90454e701de;
+  6036fbfb9fcc223a1776ec67c9424788aabe553a7d6a0472159edc747ebaf97e99f7263ece635ef0b702a3610aef32e17f59fae503e18d74 -5433
+    f6fa9a49b55077330fcda976a19ba7cfd98e44fa54044840df0ae9e19710193e684703f7fadbcbbc534e7be3adec0cae0d95ea414494f368;
+  a3433dfc89ec4d6d858bb5b018e2d474b7de7604ed4491957fe16453d3793740ef88136814f59b19ed3610252e74cbc3a36571d02e57913b 237641
+    7a01a802b7a5aca44675887d9cf94d04d4893e2dc5d7474090cb32798fa370690255f57d18dce2a57126bb5883672b5a74a1c780f48f7bd8;
+  c17ecc6099e9630a4ec20f4199abe1c10d414f6d734014ada1e6f097090a2bb4e638fb52d9bf56080d77c2b535f52cb091cbaad3c65072e8 517226
+    708adeac4ff99cac4c3eb649d55276f58a7d21a0507af176a53893c567050d352af501a9c242baf53121e8b56f5679b175dc01538350b644;
+  134263fd765e5f1da64900df5643c5241d4fa8a9e96ee59f01667b64f9122e85e995b90d4bf5d5fe9f68825dfa6edd19d8ce009270ae2984 390674
+    2ffbda7ccbeecd8dc4600965679146753c496d35bfa546e13edbbaa259065b024c8aaa3a17a3384f4f14d5ee01371ac55fb50a153b4ac1c0;
+  54326fffef9f0fe1207a07c8ac063d64b3fe81528e005f857319a74da2c3423a552b05f8c465908b028a2dcf15cb7158c99a1d2bdfd890da -255467
+    e554e875e480c68c4fd780425ff8fb50f18bbafd0536a09489bc7cf197fdcb80dd4c7e31447a1a862066b6761ea39ea3b8c3002039c86b40;
+  5c30f73ec3addb2d27e0e79579063f2d30fa9fb47c2b6a3a32553120a047cad83abc901e5a5b4a65f8e51144f7eb0abec9a4d105236b2618 -466309
+    5ec894f6abe2d88971da11b982c3322d1f533a326057816f6273585bfa186a7f569ddf93c27e8e74719ddb515689d5935c56e6b86936f22b;
+}
+
+mul {
+  ## Easy tests.
+  03 02 06;
+  f7ffffdfffffff00000050000000000000a0ffffff03000090fffffffbffffafffffff00000020000000fdffff9ffffffff9ffff7fffffff
+    ffffffffffffff01000030000000ffffff2f00000002000030000000ffffff5f000000fbfffffffffffffcffff4f000000ffffffefffffff
+    bfffff6f02000083ffff5f010000a1ffff9ffcffffc0ffff6ffdffffc4ffffff02000082ffff8f03000089ffff6ffaffff7cffffff000000;
+  f8ff7ffeff5f00001000000800000300000100a0ffffafffff130000fbffff0100000000e0ffffebffffffff7ffffffffeff1f0000080000
+    f7ff7f0200e0ffffefffff070000faff7ffefffffefffffffff7ffff040080ffff1fffff8ffffff7ffff0500800200000000f0fffffbffff
+    0a0100240020f5ff7ffdff4fffff4100003a00201400400300a8feff030180e6fffff9ff8f02003001002c0000f0ff9f0600d0f8ff670200;
+
+  ## Random tests.
+  94aa99eaba90c5eb2efd7101c8efeffc1e44c8fcd84ccb8ef27b9792ae12534c0a250e5400407177bd655e51c343f776a3fd26474da4dc74
+    284a0f7df2d7d7c760cc57b1606625884c1643020230a9eecca7de6098f5338ddf9297daecae8a07e199494cb6db91c2c683566bf79545d2
+    213a31ed7e494f470736ded872f2c4f3675562a7b42bf01ea246be0ecaae2a61ae500690df9f99ea9fa8e5e1b9ccf3614bc34148b7693c91;
+  a434abefb0de3c7f5e33f9230ead871bb3f06888c0d568b9a74fa32b676dc600fed2d54a042e1b97340852c4d6ef796a18561884d760d4ad
+    99d4c85f047d3dd8e530c50ae7d80815a30ec6ba820316f5da922cfa7a51ab45290ac2ab8a53082716a6d7f77ac5a285fac298eca4fd9c52
+    97b2991fcc858d5667d3674484db9435ba71ab0c836c534efb823c123f9e94d0d3445257c55c73e8bd62f1d7acf1d75fea5eea669bfb9912;
+  fe9911abbe57f1ddd61acd062d59637b129a1571af65fb70169db0d8b12b498a66d1eefcf9c8cbea01179f113afef0ae192550828885689c
+    e371e9a11f662e38caff28cf4cf5ca8cdfe4a8b99fa12a33765a22ae25506874fdcd85388ed406a955d293320e01957f119027ec4803c2a9
+    171b49441f9891d927d2f6436eee1dc59e7872730be496638017b42151cdf00e9abb212bafc47c05a4e185bf7cf21ccd97b0c8ea426e4381;
+  1c300df44d28406d070b10c1920e01ea8b9056d9e1d6f9704dbda3f6328c26a28e9e4aa07dc79e03c09c5639cf8b8c783c8b430b9d8c21a8
+    c565b0357a1e8aff3b3a6164ff34c9598a1c15a1551224fb38d25dfa3b0627c9d992dbd215910236aeeed23f4efd99640054b6648946346c
+    f7871e06efb6f737cb4e04f708827092e94e3c70faee57f70096b9d674d0ac5b228824924bb705de49de9f9c0e834462093a9a5551fc7d5d;
+  9014dd22854f1f21fa1475d74eba669101c871c2a21ffd5d10f0792e3cc5d34f15b4735759575dda169e2dd868a5ae64dbeaa2a654cfde5c
+    c6f59ecf6add5ff92813cd6f37de9c6f8d3ae9cd33e4f3236ff43127f463f297c3067493868adf7823bc285a3d609a57d9b0b841a9b628a1
+    cbebe67e30ed82acb0de699a5d874121257b78c2b0642583713b58fdcd089a6277a5c5e571538e4af9025dfc63cd78931be51780055dfb2f;
+  c8fc23a431d744e45e8bcd2dd2ca612db40b26287970aa878a5cf6283c51b2bd4edb76f705f29bc3911a9aee8fb7272009520f3590ac4c4a
+    c1015900ea58d6305b8b558c992bff50a8614843cd3d11274830dff6e1db405f8b268100fbc5e44c477cc2a9e83f825c7840e560fc2b2920
+    6ecf49d92efb60a15a9de38ff37d3b23b339d889ad8b11cb332df260b9c49fd28b287a559fa5a5edf732b3bd1014711fb7d088a37cf6ef72;
+  daaea5c9549776d866be36a032027a65eb8325b1684d3c37cba068e69aad7d4f104ff47c14f669883cdef5dae9a0c7840379631ef97e6bc3
+    f8dc00891a9c55481a224309a8024ea257850b2bc62ab10bb5ea5b836776cd46994900d6656b7f7e0d9092fd824b16d20ea14528a0de7729
+    83d3eb62429c2ece396cd7069dfa2985630da2fb0949b52f1df9231c82f32022543d4a2302241d0146b4db97f44ec5342b6444f463ad056f;
+  786f4ebb20161c96f93ffe3ee2b0cae50fc454d910b3fae4fbd8454b8ab7975c6cab8f6a1b593996b24b22603137a52ee732f9d19f9a6e43
+    d78d3df4f455c8f5d98baaa17200d4c94056e21768c4ca783188bf15c28dc86c581fd9c150f923f905becba19361ca94f7434d8a74744669
+    e857a2020e1877b50151772bcf06763285c1d8b2b5ffdb63e13ef4985ccc3b965fdb053305f16feea4a3ac0edad21423c80ef847181bdff7;
+  6b48bf18ec4557e745cad3e106511bd5a9bbe136c77cf639745f891f54bb16c11e19770eb5112df8bb6755b97cb1e23c9c7efe589693764e
+    95c2a38f889c451f792c3d5d8b3237eed3f99e2b4857bfc48f75d7c0de3f293d2cfa7f97d65d75e0e3df633d84931973ac542ce07ba974b1
+    2fdfb1146b569ac98b0811e600e2d8e578023024ed704f97c7f7d56a2b4a33ac6ec68d14f0789441a904d175fbf8b91603c532ecdffd27e4;
+  1fbba059c333843e3cf0cff19bec99bd0cfc89c3b390200165680b742fe540b32042959022e7393c9e13ef7fa3f1dd5ac46595803210c536
+    c723bb3649b1d95647636abffd325e363931782f02002ad6d75d2082c980a7a2c5e1d51045880b36d4f62c16250faffcb2acb824d8d3d5d4
+    97041eef8892ecaaa97c4effb8c69160b3878fd302bc5f0862bfe4894bf23193738d8dd95c9eee9539e23fff67243372b97f02c3a3934555;
+  26f5bc0c2c49899690fa423478ab1cf7000be27609bf683896a6ce3f619510b061ca04debb6c64540e724d113cd4b8ff3485337851367700
+    b8540188b9ca77a82899c7fd26412dcbd6a3c9b45be595f63bce7426d7c16eb20c3a2dc86afe9064edc19840f75f05de828c276e98451ee5
+    d973580e88abb6c83defc009607082ffbdcae6ce9d577218580459711682f8708a15de9c62e3ca3b50e91a7bf5781deee152ac801a64fe81;
+  6c044d6556abb8efdf5b180695293464a8bc4b9cab201822053c7295973ea0a8866425629cfff1d372a48f51dbc6a7f828691194c32c2c5c
+    da28b84dfd48f206972fe282449991597bc7f0734916b6f7a253897fca2ccd6b80aa477cfd08549b6d25bd18932128e59889e2dcfaf76157
+    a599fabf997468487b9376500b58a51e0e00c86d9eac6f50157aa1017d99ac8b95e7842b36071a192784ef72433c06a1dd042990b71ffe8f;
+  50378c6ac56816962d428ea523a0cf87121fb3c53b37bac6d3a05fcbdfb8a5fb20aa014f1e1b01a3963534d403baeb7c436f72cf3cc5db58
+    78901fa015c6f0d3e1072aa87d865579fa405615691a3f27945f9b1431ee8bce8ac9965a1f9b0f42ff10bc77c43cc93566eee9a9b79866ed
+    00127644003ed4b518f04abbd058a46015fb328883b92070bc5cf0fd98d7307dfabbc65f3e8551c622792efabe55f03953e498e360410790;
+  5db2f6db35af2e1c84ab6832b967bf987cd03adea7113fb8806ce8fb3ffa426dc10997e13afcd39cf5cd65f65f8a09e650fad8e5f6ef2648
+    b063695bc97a18d6ccb0785ee4588951dcbee420ce8e37b25cce325352968015c94f9bb784f3a2bfa34c6a1edf710b63f139fff6d4f7b2f3
+    999284a309482f67ab6460e73ad1ad267052b59fe50cd58a245e22079e2b50b119e312ff60a65037cf9faeaa259d22f689eaedd7924f1093;
+  d5baefaae7fc9000e0d55f287f740dfb1899ba6e9e36338959a16ac5e5f45442a37086b5519a0b439f38b129328aebf468dec4b59c89a249
+    4febc8666dcf2b150faec9902a5f57e97275e7b122724c2b77d9b78655b455d424db93f859b8de6b09c4bad6d5ba68349c65c41caca67f8b
+    19e6ed86dc819e6b4368d196679328710f63bf1fcba6652265508b509ecd0e3e8b8bf17f8f1eeb361af107ef684a729a3635cb55de3f8605;
+  9974be322a0f471cfe0855456104219d8037ca1cb5aacb9ff5da86a047ce159430cfd92f67e764244996668ac44d8d9787dc1b5754d215c1
+    78c00f878fb41fdb0cd22c026881d5022fc470755e6261945b9bfcc3868f591f08288e4d64a65c9f3d0b05d3ab7f27d801aef29e5e98caf8
+    fd51b84f21b06377054dc879b8a176a7799951d5669486b210e4528b9f52bd60f88c2a068f722d85fa12761a4caf2f05bcdeecb7ed62646e;
+  f4048d4a1602eeec43cdf20c3ac9f7b359935bae3648070276faf07a5c58fdf79771ba6c077ddeae47617971e2145f4960587637e7028822
+    32635c7425108f5d19e35e4d91a4bdf3310bc884c9061d0697556ae25e17cd611e090c1179ca9a68225b283c8ab98a7b1e97508592c60c66
+    8d6a91d016aaa7a0da03b06f5876ce8e8a71d1e5e5eb430d6c5ae16e1d6d9b61e77179b4f6fe43ce37cae27689983d41923f3b30e9d9f930;
+  9023c019bf7ef6df45e0e44111903c622220bd3dde046679540302451d001e47a153b0ac7dcfb9831e2d262d8e27002197d9640900e4c1cc
+    1f5e2ca612ec6f14df4b528cc35001e763b9414a81381a1a3c7008c0cc525bdb00aea94ce2348f380dda43b5edf4fec7c8cf5ea2f5fec4b8
+    bf2c241efc180988232b83cda91e12dd0aec0d22ab68353c9841c4ea0547fd1b377fbca125f8cf92c426f8eb859f85a3853516ec104d9b6e;
+  bbdecfafa9284e3067081b7d1bd7ce0e488829859628a8f6a38bc1a3ca6ec3130dbc1345b69abb7224b047fd3f2dadcf9cc11a8ec46a6436
+    49a956ee69cdfecf29440d60fde9db1edd94619af97f625d45dc83c64994fe6c1ac858150cb526ca3c58a9fdc09d409ee3ed0b0cbcdb711c
+    7abfd47fdfcceb278c917afd059e335110bec63fea48dedf7f8275da8922201ea06be39e3d1bccea2d38f5eb7d7aa5ef4e6fe6792a9f0ce0;
+  a9483d4f0c94eac273adc392c3f425be610206683cbb6806dca47be3b54ad142fa2c54a7a473675556bcc8cfd50649af3c58d7a91e84b428
+    b986365aa08f088fe04aaaf2e00468af3fb41cda961b56ece5bedfd83cf9a0fb959ae70c23d9b27cd1eaf8b611d9e578aa0b9d899b81d5f1
+    4af529627637ad3f3f1269319f4fd426d31e276287ee525d0c64974e55fca1cd58694eadf47e44dc3e843e01c36b22f9717067a907840ca1;
+}
+
+sqr {
+  ## Easy tests.
+  03 09;
+  f7ffffdfffffff00000050000000000000a0ffffff03000090fffffffbffffafffffff00000020000000fdffff9ffffffff9ffff7fffffff
+    8c000040010000f3ffffff040000f4000040120000ff0000800a000099000060060000030000000a0000e7010000180000290200800b0000;
+
+  ## Random tests.
+  776cf7ee39df23538f76e6be87ecbb1ed78477b858e3520f24b2b36f09a7dd61daf7bd5990af13c11b1419d8215eb69c30efc3917097797b
+    870001f8ff173e02ce682526a513ff99c6e9688cbec13839ecbf0fbc11d8f84f6cf53041b5bdcbc624f9787db9babe61cd477cb9395590d1;
+  1e5ef8dd68207b3c3d3c670acee7ecb277ee6bc10be9fa3f3d800e1414bf402298ca443de6fd57ca899188c884a93d4b9c9d1b00a7c9ce44
+    4a6d6da8002b6a0f3f5c3a9631254ccc62cf66c93279c4b77dda55d32514c8b388b543002f8055321c7195ce1fd26f51f48732e664cdc62f;
+  e02eba6cd5ec1cc39ab92db439896520e50a5f9e9ed6d31ad37d00ebb2a54cb68f1c0ae537006ec2ffb14aaad2de16ff06194929b702b95a
+    95632fd74045a49782f6f9d0c86d554cf6efd07f9eef57d669828c77537d4c3a69138d755855640064f5e9bc8fbe0eca96fb04053f565431;
+  bad2a1348fc0b54791f9f2875009c8be2d30f14526fbbc22c439c1ae2b865436cd74f428766e4e676b795fe9333312f6334d4e4ec2378e26
+    d87a8f7ca45620b4646fad2c22792538bd16f37879dbc4d87c21cafa60c282f6415fde2fb6293a8b8a6e5b3901f88d75f9243023b68f41d3;
+  d6d221f2bf71eba62e49db570e13ca69f4a8a33543298619cda7c8d2524c9446b11ae7b7d301579f047565b7044b5286c2478896800ad992
+    fdb163312b884bc6d74c4c269011311388ead9c069884f48487f9ac0d62b39aa175e81976fb599716aaa68db4c02985a6f0ffe522b0fb21b;
+  20cc05120202e684981bce1db74af493d218ed8e0f5e76fad46bfeb98c69e504113b0eb91771c602cb422ae09846fbfef7c47afd09689277
+    b07d84ff34dc5f0cbcc60037400ee04ba09f34d1d7a0c6a80672a3f6c1da630681d4207ce1325d301b36f0acaafd7579a108646f5a26b755;
+  72c4c3e4fcfd36389f558e0d4016f3f088145be47b2de85ee7ab963fcd8c7adf449d5b7c37ad8a32cf97ea9bde5c220fc896cf1b91633e19
+    1e8f68736c3b259b661c0c1ec065a642e717f9e4d86003411b8e15ff89537d8e129c116d2f8a9e7e1b46879deedd66fa6ce2b60ab680cfb0;
+  8c524f059e7ebcf3af3072dbd2f76ebc530adba6d26240c8675b5451d5558db648e7a61fefb1369cf2939ba1fadcf8e40385db5d57cacace
+    a19188e6821f5cc2c53b7e59ae6f70e95fb929c0f282627ccfa2c6d9cb59dc871e9dcf3e2a8d6d66b7a6907d4d36c9de03c3d74325d8c1f1;
+  dd47eb6f4f68cd3a9abd6af401bd6f3c795d89474dd41a89025b24c8349a0de417c3676bb6ee36002d7c8ff6b4fb4491e693cfa617e079f8
+    871f46c93dea48a0d937b3f1f724f66615daa9200f0b48cee01c3b20e4a05dd6ce01bd7b2713e096cc2bd1c5ce7ca0c075aed0fc1ef6fa51;
+  577870fdb83454eed0711eb51d7bd91f9843769737566823e41d0668fad45c82fe069347769244af7230e6fbc40f5a71151279ae65e9893a
+    efabd464218df4a490b9870d541c45e9b7ab29bae25d9e976539a553995ded0edc5610916883642a032eae4e96eb9e4e1443f747dec98135;
+  8ba84194db2aad7b46005423b1251555ea931b933e0083fee76b9863fb528927f27a4a0617b8d75de306103b592a0fbd51b72bfbb051ee2d
+    3a29e940174d846df65d51070295f535a03e988fc401ef62f5dd2456cf52668390e61e7b6912186d6d5260f6d6977004003bb106abbdaf02;
+  9f17e0943b4e39051abfd8f4512ef177fd5c368ebdf4b0af49df2e1d89e30c4e68ec474d81203964bfe9c1fecc1279e5e4f598ac97b48cb0
+    d794adb47cff3f7666dd0a934896015e59f278d9b1d6dc7a06328da96d6e6520670598129b7e1b26f9537216364199cf5c0010f23692ec90;
+  a6b51625066e4cccb7d45dff5b182e2a6bf4b1cce7090a187d38dd39f08afad6f868c0277bf70d5fb88b6e67432526e4feb39ae707e34990
+    67315efb85e16a1e97130092cc351759d9c18261845329f63eba1e77d91ad2c7df51ffa50b655de81bc807ea2b3e137214a2b08b400f2b7a;
+  28a0fe53cf73a0419fdb4cb493c6425be8aa812c3693411816c90621097a9d5687feb16ebf874a30ec849297742b7aab5921427d7b474190
+    69300770a5bc2c9c599431e5f879ef3f3ec065e3a2cfe82e3499018add58acada581e9e81d40799fc74674b9721da018a64138519abdb108;
+  fad58259395fd5bbcfca35b095253a3a121b62f1694e14cd9e2f85bd08e8a15d1dff98e3b81eeec678821a1ee9d6192c8351bde45ce0581f
+    bee7e0d6d4de419981ba2aa3964adfc7545e21b72b65c774b2029c22e06f251cebf04cdffd23e2051b57f986cbf7e56f047050714a275e72;
+  91e548171a8136d2d26e6bea02cb16ec9591e9cd5b913184b22b43d1029bdb214ef737f6e45f473f7d95b8fde075645c3b0c2dd2bd224278
+    abe2936ecf2ac3012455dcac906f691f2d96490539c9621658fd7f66790bbfe0d2df07165ea80e0c3282642d45b63b7db476b53e4f94f1c5;
+  a52c855daa9ede16ea8de7c681436d5d31eda6ca5b441f972e5cf5639a1c56f689fcb411965271853de2893f22b81d7d0facafdb49292e39
+    382480e92d44199fe5f7c357ad2e5a7277beab1a3055d48e679516151ca85ee3cb498b172087d588738daac2ec1da9638552d76be97626ad;
+  c65888cdc1a575fc9a06dce8800607f56fe88839948b7e4e2713aae44b0ae6b7c6b68786b11b430d22766e9e4d76af118a972729c67c06b7
+    31311e4ff9600089b533cdac6c05de3ddfe6a450ee7fc90cde1bb297e2deb750336ac3ed2f6fa9b88ece846be6f6aeb392f6753eb6fa475e;
+  a61c81d621df61ece4b7274f63ae4e9f2e2df1d603fc9303ee361962b2d70bd783ff1b5d8f3ed27f17e7773b2b1c85af7fbd70387bdef5d3
+    a014ef20adc291c0238be3759ceb9f9645524b961761c8a991ce67efbddda568359fe36e762980d75a58a7ba10b803c9f883fe4d2239a08b;
+  96ced952366c324c5fccd48ac5d475cc1944e7e455dc093f0d9680d6d6abf1e45c76a286ac46acb4de061b9eb673a2d3124e6c3b921ad71f
+    6debaeff6a7d2bb2c1389cb3338fc87b2a32e651ecb8d43fc012efc9b9c59c79487b742f0b30d0b64ac283af0d3b877102c6a7ff0f606eb9;
+}
+
+inv {
+  d665678f17043846f953fb09c88295d7fd0a53bc70ec7d396aff56e7dfa376f3a338f0da0af9e07b66d3ff7443e3829b541bd667201999d4
+    6839ab730bf666c6ca987d254d83bf32b981b466c147f04b823981da75e12c9ded469a0a462861a987c13f05739f47596401fec25a5eee5c;
+  bb8d567f6163a92603a388405121bd58abfcf05c596bf0624bf65b6a8fe03e6940648382fe01e5ab58e37ce235f4acbfb9e02624001c49da
+    3f60d0fa0036da2db915e232bd841d09f006d4ba018c1d268af86d36990579d669ee63393b95c202645dcb1225fe9e64d14270905e63eb79;
+  d456692d8e00bf9cd86d22a9f4ad9e9879e6298274854ae82729ebbdb0cc46877caeb381506dbb097b10c180d615661189da65d431e3003b
+    6e0f5a173fb60be882a2b570200515dc7ad473e2192470ba89e6dda6cfdd6ff77026a1d76acdded7b5881a54d68605140a4ffceae70906d5;
+  359ab073b7465de1358a5772aef79db09118541c062421cb30a972525a351f16b5545daed5f9ce8e91a283818df6cdbf443831fbe5f3e848
+    2b0ea74e6f4533498eb3f34247a9674f3a2cf2ab0e4fde65ff11b0d1e756430bc5452ca4b85bd3a1f10f6e4e3b1874df8d19f390a9021757;
+  3509fb8b7688f354738d4a8ca4091f66c880db794aacec6115e675090394ca77e1c83b955aaf4d8e75c6e4e9200be1ce5693532a561d970d
+    cafa18317193054cff7884bada249422ba889c19693d66610fb774fb4bdfeac0e67a5ba6f84ace126c125c46b4cfd627ee777e231a6ffc1f;
+  42e2babc095d88b61caa8883e91fd045106db9c4eeb4d945703c1dee3229c58869e21f73909ae2f3c4437d301a2a3724d67f6ad310f63835
+    28c43a594b6471412f504dc10fd79d2c04ec029a7723cfa0a90aef036991f1b56cf156e2cbc7533671086edb54036e9f4ddc9bfe2e3ffcda;
+  9c01d006213bcfda413517ec815e8cebc06707f5649398a9d14a5d64754375c1ded8aaefd838e8eba84746de07a0f9b32caa2325c4c8e540
+    0a3b64374ac2149d602a9f0ee4fcf6d814c476f451531a086b04b0dd598287b1758f77780b7de08573326a9767e816309d871fb1962bb1a4;
+  7bbd8a2de4bd2ffee4e93d0dd2fa9c5d4abcf9ab86c097921fe7d603b7ffdd07006c7d79d1a10267edce9b3069b134bed727c8f0ed1aca13
+    c909ffafbcc09a96723b9afba8ec0d00d5ce0c9d85de3c1e4de24cf44fb934bd0d2397b380885b7419cbbeac339fc85e2161f08c2f3515d7;
+  6a64650ccf103604c3b030415f7114c88c7094fbd0fd2f2b6b907a27fe104ef4e0684c17ff9f26f15eee5e7442e679ecad3e49a0629cb5c3
+    9db77e47433997640b4c0916c5123e8a4d9c7c0bcd12b2dafccbababd6c9dbc3f4ec7991ea68b3ad4ffc6f0be4920764c65d98bdeba8a811;
+  c3823c71f6c0f3679cb9c776e437e718f856c8fde038418942d062423113352aeb60ab84138f2bf73f268386cab0f2a1419660e966c24187
+    558bff4fffa85d6f67ad44938f5b4473d250a87a120af9ff645a7db37a43808abe30c19c90bac94adb190840078214518e189d6c9fc5bef2;
+  44bd920b0eaf47695f93d063cd85c43c58470c23796f4a106b298d5f2b091210d103e9575c369bb0be66b2323d89cc29602a8071697931c6
+    67464f2dab3a95c9ac7c783017105df7d561d7ae499ad89c4698da2c0710a1654c89966a7bd30d2d5c0511ed9f020309cde84cecd66be8d0;
+  a6b12fc35e62532ea7c1fd49dd834bb7957da914ec3daf2e4f446b54916d016054cb59ffd4e3d9eecd4a18b08033ee8d9ff84db072cc4f86
+    cc70960f0bb743da1b23d11eb87530a820484a861abd68d2ed7079b487d88481d915b1b34c29d9938b5fa54d05c75cb1aebf0b722a6770b6;
+  1773dc978cd9f94186b83fd5e10a456b48058acd9e3bbacbecee2cfd0f8303c64721ca64c2913d57764336ea055700c2fcafc60d9f4b817e
+    49e443096eb28c167ee62c63bfe4079418fa8e7f9e58757e13327680890b02ce7c9e5bbbc51366e0b3f5315edc456b6f65a09ea1b1a24438;
+  552158406db36accc32edde2f0ce46e23a1d406f60e54ca6a789386df36a57434c826c9586c4b371df3179f675e5956fe7dc3022f785d9e0
+    e0025a1007d3dff5e44947a0292bee8db5abbd1a0fca1d3ab0a64a37925396cd96c21af54d36656eb0b60c63fd5651622ec5487d53f976e4;
+  6b006d36f60750bb5c59f6eb31e2efe6098ab67de7a7a8a27201652380a295c408ec78351c2a799d62227dffd4731b7605e5c462dce2c1e8
+    21785aae5f73da711f6144894728627824b685fac3d95068a9d0c4e0ee058301a8953322a5ee5be75452164a55477f1a987103a718bf98ca;
+  700cb76911e718ce8829f8d767c53e333dd2f7f20d2c020d1da3cc9ce96b9f6c7aad67450d5aab8f8c60e8ad77d4b5fdb86fae92a0ac30fe
+    257f202b457f19f27ceed047e6778204c2b71646fcc96e19c6f07518780bb5b1c456fd6e93ce2f1cb0aea1a225137511dc71e446c1fe22c3;
+  0c909e0326649d4d375452c5b233a86e90b0fa88b20aa54e02685edd02b70aa022ed8af31e994b70b20101a5cfd8e16ba53c702840b4a16b
+    98c41073ea843b4b5ad6b0589699f48a1576e3d834f8e595b8859069b71bf5e16126aa93b20259ff0a03976ff6d7f78239ec1059f8cf1193;
+  4529761361781e67037eae69c5ca9977b1e21468834eb83cd369471e5092249015cd263563bff9348a0f51e4a8517e27236ed1ecfe30a780
+    e20d5896be18bb273bb0ba84f6c070de45378bac6d793685e654764e5aa847d48403a68560b48dcb12573ac737366ae701072300615b4659;
+  6fae83f7eadeaca22b6781f400b01f9de186b12e31fdf56e0ebe98a8420baacf5069ffdf26d0215c16b64027dd69ff29709a64cfe8f52dcb
+    daa266a02c4500d989670eb63ab78219892d9c1ca2e17f4b5200cf1d920cfece5e80050be77f81a616de840bf19c23835ed17d57aeeea0f5;
+  23ca16e8b4c15f8f2b216441d851368d185a7f8587f398b0cf775875678241094538708da0cb2260c5e056b59c003c30c8f84f5088d0c99c
+    9de1360b4718fc762e6ffab46827c5e4672a77d797aa608b31c132d1ad8138e7a64ba1f4278a07a6088f8cec9a01ea9bc1427c55241433c5;
+}
+
+sub-mulc-add-sub-mul {
+  07ebfe324f64b54e938951a1e437bab4d35c2bbf5f210c5d78ca2b4eb7ef9c3dab61724be4fa7c2e43086b58db7e961f62a44b029f9901d5
+    d44920bba642b8162d1c3e956e060bbe6f15484298c2ec55575ee378556b0e8826f627bebda963b7d4d9f1c768a49cd408957105d3c6008a -41997
+    e3647583d41ee4e813045d4f7a8b53af084c1dfeab8db93472810e8c54d253a2c100a6fc341bd92223341150d363f00f1c2bbb9ff9f8e7ca
+    d61c770618adfc42ef3ac4272dfae86a674f8ae4c273d26ad7b9a29943c4740e0c9535812b9ef0d17fb4bfcc77bf60646aa96a11c29035a3
+    76c496c2c798e23c657eb80c44940229ba88f21bcacb21cb6b4cdc8b93d10832f3c4d31819fbeacb6c5a516c7889f0e639abc29ec4d7b604
+    5a94d8487539381061d764a3806e31e1b2add772d2f9cb9c4fb96336f7b36534a9a0f7caf30b7e086c875670a0d568f895502983b1dec2ef;
+  e1792f9e9c7b70293e041a9059df95bcac07b4112f25d35375ade1794660a0a10c520adf06fd477c79a170ab88108e4b74bc47ede8ddc0a4
+    6cffa5fd3f07f203fcf08c399690b793a152e65aa99c6f9b465d39861c3c46691b635cd02c9e77083ecdee73a54aa1aab5ce6044cb2cb8d8 23228
+    31cd1c1937619b8fe711d22912104fd03fcfa3f14f81f3bc7ec9839c5440836d7c9b92158c818933aa614f9a085f9a1c18d71dd11d09a6db
+    2386136ccd81814300b5f3fa148c4025e6d7a2d9da344e56b42811deaa3d4ecbd5365f91d941d7bab20b305ac6dd0457a4b81cc611bb5f11
+    16bf2b1e10c77597990088a8df91150a6e7b6c3008e6584909b2f7184358abf6b59674e210aeec3219a5202440139aecde4a4b6e0f46dbaa
+    dd373d5908b408e51e3c6f8da1c439f845d40467057a34a96cd53680661b329f073d0bfe6af98543d5d38c3d0476c19d20c54226e7bf8d7c;
+  fe6d00268bafd5878e0a4ddebad8dff25399a1d18e69f94b471029058e9712b98263d88b4dea5d08d8fe70b3a62ba2d136c2c2713ca809ea
+    12be184341bbd7ab5a668f3c3e4b13a60c70cd4e1f229f90901be24a285f3ff0b7391aee82529076c14232f61a11b6a8edffd56af603a25b -252008
+    178e5309ab3a578b8b09149da9539d93309c5214b61e3c045034847354f59d58fee27e31dfcf5d5daa24b5a605686b468a3db727583709d4
+    8da5b2f4c39e442c729a09cf04405136c55cf7b76fbe949ec3b34fb17b2edabcac44f4b4a19afb58c9d86eb87a0c58cff2cf196e6cac7da2
+    3b0be5158a7c13a6c71455025ea5b4466eaa321956fa785f9b74872532e3767d796da94ac47e6d25a368ea1ac79c44fda8d2e13edae5c219
+    7ad75999f1bd89b130fa03274247b36b2c2684163097d46deb852083b5fab0e8755d2150dcd2ee563757f05eb1d132df284ccf818cd56b9c;
+  e4ef0519fc7af554a4a348cfcea95c6c18752f4a35a946b7d2ad1e6aa77d64ec4012eea4faead2d91c66b0d57198b19317a79e136a98caf9
+    008c72ff456f0f941781020ce6387d8065772af7c68955668a7cb05b53f00960f15fc463029a2e2a353a2fd3bc43790a847ea35c75d6cd26 287411
+    5ee722a21955b3bec9ed5f151686af9da9d3f5e6491e3d9a8d82237b1e3dddb58b827264ab5a1aca3eb8c1de7922b59744567e0467a4357f
+    9381ebf793f7b3f523f4621e934217ba463f96279ce2e7d165fc00ea037b20254948132dd2f0481ad9816e1f66da64d081e4d24866094af9
+    62e4648d4716c6e0f99357c8c099c4988cfec4fa21873b7928350f174679f59629a54d78bc8d239800709a585d4890fb2b634f68ec13cd78
+    850e54cf9388bdaf3de63c3e73823c0f39f0b9bf15a9f0262f24c828d2fc8cd7d1ac939193804fac3d92467e26ba5e57d1dc4f8664a270af;
+  5f3811d6b8277fd93a197bf4f3dec4bf4dd5fc6a0ac92ee3d0e64ae48fa9e1373cfd63da945db924bbac41a2b78f6819ccdf2820b1a3c4ff
+    ee669edf4430678ff1190be8e39c06dd00cd9982ab5b625e5a6814ec456f68f9467f1f38519f4bcb392772479ba553060391752ab4fc70aa -254559
+    3d11820f867d39b2b1169030c24a9307eb387f44ee0fc8d53a946e56065e8cf9af6069c9c8099de1565f3d491c33248965ebf941987ade48
+    9582a93732bb52eba39d81c161dd0a996b50dadb13b4eb54085ecb9e86117ed25cb7c78d1a5cc3807a97d740710c2fbf65f97e8de3591163
+    501c2ca79204d22e6c52d32d405310853e7e29da884c0f14782e9029929751821f81a9493c8dd76e582bb48465ce5b40d7c5e398322ceada
+    dcdc428d085f7548c99d963af7b8af997c1503307d75e298efbfc042d425d385a6b7321d86d5af13809ed3ec6bc5d96afcd026d08caeaa30;
+  d17c198598d3b5188e5807c445976b769d458ca952a7b99da4b19ffa3b35b6100bd3605136143912640e402a7cb91675e61527244844409b
+    9cac226e58f5ffbc41bb82b769ed12d061eef4d2d0369eb12724bcd4db6a1ff85f22d6b25003cbea0308a1b7dcce1450283d4e96ac8d4b8c 516083
+    9f92e7a68af5c7737f3f3e959d2b55230ca11e0dd467bd52a20b91816ce61ac7fa7059934c7a952e43058ff4f277170ec5ecc4cab51baef5
+    d4fb3628a45e2290c7fd201ca434ef83911ac2687218605782b3cdca577e692a389756e6b9a0891311727d623fe8ea601fb13efe238adee0
+    ce572b3cdd011749634a577c727aa4516d00c4236cdf3b4664c2be35d3efe7e0b140b5ef2d4a0339a8a29eb26025e60e7d166913251966be
+    790d7ef8990c44fd271d5a41c55a6d552f60fd8980c1c3b91919fdd5e291c75b0a0cbc4224dfd2ce93de2eef53249f3d9d0955f05b4cefaa;
+  396fe89631a66fcf4368600d3a8cbfa6fc903cc8d157f13ac0e4a569436c3230c0a9319a55ebb7e61d428e74b8ce740e973ee5d2b0a99a61
+    f644b35fe8d9bd57a0e6837ef03d889df2248a06a0e52a9cdc80307cf68c496f34aa82f246b8d6e040d166ffa1920b7d921938bb33f8e8a0 -339102
+    716c673c21cd0d92d86f8060beba37c65b7d9eb8b1d4f8aa5665478278ea5c3a2a2c4f606aa179bc8b38f4f37b3e077959ac7c8c81a5fba2
+    6379d7843800b16ad06ff70511c7ff656fc93ff95a05617b4adf7e2b6810cf2cf81dfd6b0c7d478d52f2f4989a13a3ccbc3a4e30f85a3279
+    5b982eda7d33ef68c0d94400610744b91572443614a128bc90011a953bc9422910640047809049a513c413b4390a09395da3de6958c44b64
+    91cf825bde194c05cadbb9dcee5f08f152d2bacabc144b4ee498b82ddf4074846ccc75d366184ee29bd322deaf99d6ae81563cc2e7b2e98d;
+  b8bb334fbe75e81a417ef59e14b52898e34dcc8bca4bb2caa987dc31950a9afa4dd356735dd163eba9073056a2e7f259f1485ef37acf8c24
+    0e872ffa891f664be01868170c452c25cbd41dd0e4df0a66c0ed67dfd3d007c25c50e4b0615450906c69788080546b9a4ad425402c422580 287059
+    52356b0443301992c676f6cfa7eeca79d586324bbb5f8aa71163b89d863ffc7879e55c363ce260fd6ab160e18ef0921d81a4d634799fe816
+    35be6d14d3dc696bb20c90de43c7e08b2427ffc9c63a5c37767ee6756894b6d94c748e9d2c4d8519cbdc2efaa215874bb1923cf7aa5a826c
+    8db5fd04e45f9f93c7a2a2e238c7f001fd7c059d02fce693340c106ebb98d7f6f3029d3e820e2e3e912901c33c3dfce56d68a7c42a2f2e0a
+    29ff4f6533b4292d0e8f2a7abbd1269d1455d8ec34cadca9df875d544ba10395c36d1e750fb66ff0a9d97a92538a63ab48db8583fa6ebd5f;
+  74dfa3166dee585d6d4c5f310259a6f9a407e5c520559f22a3f290733d2f0ba8a276d46820bc73f9231fe25dcc8e9c2e2542eda5024180ed
+    50881f8d2fac3278cadb483b7db6e179306b6e967f8fbdb53f70f443ba9f1b1073921a0a1f46c8833856e6a0ead7ab6f445abf833d2550f7 -430161
+    10b16716f590c13b435ce912fd4adb5dcb4982d8e0302dfccff5f9d388efaae716e8d9e2915de30d365a04468f4bec0f4489d81c0e159bd0
+    b4e67998a7579734cf8f0fc281bb29e1c3dd4dd4d9c1434e830d4d093ea2b908137dad647ab349c5858d1b3ce20f7378546033114dc0fa68
+    76a10a58f6136ec6b73d96ed1d506b758ddf6f54326f7b2a12d28dec9ed880dac2d16f2f57004c7df846ffb4c5c7de814a0245668df0e804
+    33216663bc217e49c81d64e3957f3a16452193b677c68f3df80315c7496995a752c7f42807d22e6a23ad2f5568ada163ba168cd1ff3631c0;
+  c047f2b5077afcb0c246abb9104309be15f2c2da8e703e74459d34281992fbbfb95b1012067415c5b17650d10f5d2d12b84c3c825068b881
+    831adf8c6481178176f11f1d7010fa4b51c6e30ae8a9aec3a748a47bad643ff69cc8e1ba47bf9d33183de1c1220e989c58d6b23e8a602ddd -445266
+    db32546436b5d585cd4fefcdf8affd7c467c31699787dedd133f205641fcf74ee246a5f62dee25eefb54091b5dd0cb4dc7cfad9cc68bb9cb
+    9ea3da4650bbc07d7cefbff97a9bebe5aa932772ce0e47a4bdfaab1be5457f652f9882d8e4ca286b7bce092a4fe93b1c0473a2d5d33d92d3
+    a8eeaf02c9e281f2522def4792beff7382ae509316b80ca3e70b36c080706f9cc8589518dd9b27e61c3f3e28c8608524bc201076d6ae2fcb
+    463c925f11987399440da6a502b87ee798b2dfc37f012951af57dda87651de7bb96c2c30890e6b65771e70ee08bf41e2bde696dfcb177e83;
+  63428356e8b4c5147870a0e653866093d5ca20a691524e3adba1c95af70fc706fdb420391c230dcb70cbad21f028b03e7554efac7bc8bed6
+    e99ca8f8dfe11c545b49031f68a605229adac19568b5cfb9b02b9721416c225179968b5583d0588ead12790c5df7c13bae466f934e997b4e -445574
+    7ace55b2ba3365a01a872ef5882a8d47518fec37bd816d809d4716301a7b6811926eb5aa593fb2c852ae2455fa42e92be1038d96ebf31966
+    db9244d18540fb524ec9455f493b570aba16ee4f4491247fa18efe63a43c70e533ad6660f64e836675bd788113993836c43a3c5868efe068
+    8cc4affd9631c4ff75313f43588d977f24b58a0ef1c3275b7c142e6113f20d72fe974f11c9f7cf3dc176e1799dcb4230d5bb138ddee2eb34
+    179440042f537fcd021678f32a1346547ac1a4aa5dc3e5bed329c543ec35058efa16af2ca066ffb7087a3daf68345aa3a0a21c6133fd3a59;
+  993bb02c2ae6974f6988293ce6eae32f520758329e80ae242801f45937baed48cb9bbc111731aea52883ca30286b7593746e6522fc3ccd54
+    2bbbb81c8e51356355a1e49ebc1c6e160119eca0df8c07d171783665c9d96af7164e6bd7384002ed5c19f531bda705b90e06130bfcb2ad17 -159409
+    6b3eb1b9dac2b8f6d86a0d983bd2b36a98c760ecf5f4aa30e22726e8048cc2e633a7a7bdc862d6bb02fcb0d9e854ac9dce8cb9982645ba44
+    fba6ac4753539d9dea1190d160994937af74be3f73856e56dd7ef4fffd1f6e2d99f1466fff7ec4bacd115f4e1f8708adb8c9afa7b17ee887
+    7f28c3d4526328a9f03cbfb3a0b04fc2aac564effcdbcedfd61a160d0499c83742255e86764c344887a93f7f1851903372e40d7034b16f03
+    2bec5989a2f2fc934dc0e673f07f0ea7ebade4d4bdf7bf472f7e779a716dbc4aa01771bd1dcc634780b0da41389c108a76fc67235e028142;
+  96ab5a1f5b6cffe08fbe3118d7bf2d09e6da8dfdb0ce69cae1c2d3fe71864db59befd7e252410d04a858ef680a754b2d42f7f4ab7cd38e0d
+    673d469ae9193bb79aace5d641041c94b81f6f9a9d12e5a05db86674899ed5650b8d4d30bb00f2b51b0261245dd3a2e18a10f8109cae1535 197264
+    83f7aaef3c944d9d6ef3c329224067a204f738f3625488ba01845e31fa07dda26e08a4e395687b322f594fed860bf1597ab33536c5f24c53
+    9bdc4e2e4e412b65af636a24480a40ab73df53fb209619044317f90df9bba10e5892aa502ee86e1039a8547a4e119caa359e8095ef0f5827
+    659ea4924522edb2aa50430f9bf5ba3112c60af504dd290215a52c8bc275fa8fe0042348811a7cacd0d8bbf95255a547ae9b82db70326b25
+    a28bd6727521f46a3ab3ac32a3452c03b7ceca3c06c4e5f260c1868935269b8cbeb3d303cc6df3faee2595788af6f24a52ef8237763793a1;
+  a0de95d94e3506ed563b974d07454fd347f7b37aa1e9453e0145d23e1867f2aea78434ace37877022343cad84d9100c7683b33c115014903
+    ceeac84a960af7e749645352ddbd4a9f7fd77e96268ed8548e4247b6084e13a193233ba02c49da24c89f2a62ed50029ab38eb6566167aaab -5830
+    8568f4c8837fbef756a3c03ee6a59f7ce0b5ffe370afb5c18545e4fe88eae49c65c642494e1cba91c4eb8b2fa94df6ca22b21d3e7b717f3a
+    70170f374d567a159bd8e354eceee6aacbedfcf9a2be6b530808152a96e93a301518f0042baecaf90170bdc4cc8c2e1003bfe737cd258929
+    cfa4cd159f5793a1833bfdb97261c204d3a80a01e1488ce8c628e68225bbcffa785093267eb3f75702e70b6abef59bc0a223ecfa09aac356
+    7302a30f89bf3163baf814605772b0ca175aec6a030e53a2677c49351d88f1c095a1974e1dabcf5859c206f4bd3e932f7973766e81e0c278;
+  c297bf2bf6e64d4446a2e5d1c6448f5881c5973ccf6e75730dcf2bb74096e603a354461e02e818a94ace1f47053d23710719135cdd366d92
+    8966ea0a08b7f43706340232c68a264c54b4e609ad8c901d0c0768c2aa5660434e5d4ce7510883238b17a8c92f8013d2488730d3a28ca291 -266784
+    c52a9e11dce1938ffb862357a9a696ee72c9fe18f7163d29052c949b4ac0fa151052dffa3546cdefdef598c28ebcc620d064783e8ee20413
+    04f0bdf761a2cfebb822a12bb44b2def0906ae99cf84e7bff6d033e4082c2fed1961942288b0e2beb11a0e96db8a5037fa61631cd89896e4
+    add0f3d532987482db8148a8ef3724e27ad497bdcd804686114acb3a86e4e561001a7af6420bbeef57b77bf8444c4b978e5cd136083d9118
+    efda70e401d9e5beea539fb3ce7a145bfc90422e049387f222db53edae81078046fb1e2db538ebd7ba36ff5509691c83ef9c51f3581edc2e;
+  06768f69843008554828e6665685231b32e60fa878cdc11536819fb04874df4c6f9023b356f1cfb03a1706d04f472f1f1cba2148e161f936
+    61d686b96bd02a99efe67123f3962e318ce9836b1ed0b7a39ae98483f38efa78a89063badbf97325b4743b2342647ed8a44a164e76328781 -301528
+    f8987e1314d3a3fa7ed1784fd04e4b381e9bbee6a785400e51d66402bd95c13de03e4a8213fbcbcec493f0ab8f3aef54794d8baeb9579b57
+    dee30a4b1359ae1459b790e8bedbce16eef2e299082dd2a07e46063c79af11524e438740af78d161afbd5b410888ab9f64eb4129dd1caadf
+    cc52f548a25b964b2556be59c5243b63a323701d696d8d3f866be512554227b8aa3567960aec684ba50701be5528f188a9bcba490517949f
+    bf88a0bbfcf8d048525ba4b7f64988bb8db5ab4abe40c20530b512f130dd54ed8f0bf9c36f51c20735415e25905d4047d896bf6eef7325ec;
+  b2fd5cba9d6d5487c5257954d1d170a99cd27c2e990aa7b20006d8615b929f9024c5b3a0b063dc9c364a668cde34b4a26ec4e374d38d2a32
+    e4796d1ed6d6cd3443a095e6f91e80db3ea043b1f9026e4015a4abff5b2ecde79848dd0b856db0f47a6f29e1759fbaeb2ac82d2d8a939d89 -338517
+    65c169eec5df306b2d17d58f7c1f833bea184fadbbc8924803cc0ff2804d24531e69004059169f29423b5692d54c92fec7936933eac92317
+    ab7c743547424e08a733876339fc4434d1c0ede96dbcfc7a92acbb6ec4e1f6e330d13cee90e4378863022bb49b57b6b4617b37fb5e6f7d0a
+    5fb79ffb10f7c3bc4cc98025f7c7f71bdb4041a5161e7fdee2a701692d16ae77d23680becc76f14e66a7e961d8841adad5485043e13b7694
+    365da4af25fe7f21edf0706495f44475b2d3a9b157b3008dd745cb8e756e3da662108d6c05d573aedfbaa0fd0c8420b6b7ab8d418d273be2;
+  0b1fe73972fe3400b1a9563b759cc65dc7f685031405e14ecbf1ab977c7c9afceafa91f51d1127f09058b637c9cdc39fa665be7c2a4d55d6
+    349cebcab0d98aea0beb0d38dde902e4f6caa23cbb066e68ef8d384613b4ecf6d21780ae1844c4b3eb9598cfd62fc001505d3ce4e66746ae -242599
+    7c7018b38125bf7415723b398f888458a647f4a2f2ff0b7dcbd6eb7ae873c44068429efde0be1f2f28ae1c8e01db9f812442fabaf51ffadb
+    c125c39bcf8ae742747cc2f711e470b8386403e275a14e5651f1dae89231cb3ee186a3d2c1b1a74002ac70e1fc1a5adc89a17734aa231650
+    feb78a43f6e633e7b92ffb2789f6486cc7597ce0ce9ce2486828af900d97c9ee8fcd0f52d43d01e141f9987ad194dfaa8a31b9d649e487ac
+    32318ade75655d7aacba10759063893db2482b2083a924915afefc63891f9951b58bf5525f5b330f16422c65bdf77a5508f1830849c2a941;
+  080f596d6be6f4554477689f6ac45ff60a880924f6e609701bd6d1fe32eb4f1be13edf39399eb170fa5b5b9801e38301e7ed768383cab6cf
+    f14535e25853aa97a8bc8128610eaab77977d07d3a89608a837b16fb2c2878f8edf11a2276f3c42ee21ba275dd4e6059574f887abcf6480f 273443
+    f273139e62664cb2b5f9c268c37abfcddc054c0f30ed8f0fd643017a989512cf115467ca704b3442b1c92496e378f4df6434b27e9c9fbacb
+    8af391a0b26881d67fa19196d5dded3e00cc3dc60247781ec1d000e635b6f39f7186e948bbb5b03894f0a000b27838dbda844836c5c29d99
+    56513a9d50e48e2464df2069404f09c21d4bf112d2223ea316e78cb4ebbca403327ab344af7e15b17b9865ea8d801cc7d4f6f7283687c3bd
+    9c3043751d7889855a337637b51e1fb9c7bb47d75ef529e4e8545822cbb2f535ef1579b9c660813438e2e9f16bb35f4a7843d3e7820e1406;
+  a5d6bc11f9251ec7d03e87c267b2eb05d51fdbeb24970e2c87a7d8923f7adbf4bff904e5ae498f5984072d7a21c703ba6765bc3292e43bfe
+    2be24a92df5b92545f72e710d4a5c71f881d544305e891dc9fcf2b39a24a5e80fe44f856411fc886566f428b5443af8140543e549d092170 -140922
+    629534899a55d04d6e0c879ea02b9eb05675cf6074ce400d8caa25b2adc59eedcd88f203f9440db9fb06c5bfcd65512324d01f871b485650
+    867e9ed2dbef2b0d485a7d5dc71266eae2b6053c2f1e09dfba6192f015419e06868aaaefefdc3b03cb26e50cc4861f38eac76ac69e5ab1fd
+    61d009f31c5be4eaca1f44ab6800f0116dadb7923e427db6e525f03c17b380eaa6d0c8f06440674c80f0040c272b8b956366a82ca28dccbf
+    a7628d76da5a4a8dcabfcd28252b9fb1f780e2d32f72a0f1f8da7ff7d354c6d35a72efb2b75e87c332f93557c1a5e1bd51813e18ee1fe241;
+}
diff --git a/fgoldi.c b/fgoldi.c
new file mode 100644 (file)
index 0000000..5b2889f
--- /dev/null
+++ b/fgoldi.c
@@ -0,0 +1,988 @@
+/* -*-c-*-
+ *
+ * Arithmetic in the Goldilocks field GF(2^448 - 2^224 - 1)
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include "fgoldi.h"
+
+/*----- Basic setup -------------------------------------------------------*
+ *
+ * Let Ï† = 2^224; then p = Ï†^2 - Ï† - 1, and, in GF(p), we have Ï†^2 = Ï† + 1
+ * (hence the name).
+ */
+
+#if FGOLDI_IMPL == 28
+/* We represent an element of GF(p) as 16 28-bit signed integer pieces x_i:
+ * x = SUM_{0<=i<16} x_i 2^(28i).
+ */
+
+typedef  int32  piece; typedef  int64  dblpiece;
+typedef uint32 upiece; typedef uint64 udblpiece;
+#define PIECEWD(i) 28
+#define NPIECE 16
+#define P p28
+
+#define B28 0x10000000u
+#define B27 0x08000000u
+#define M28 0x0fffffffu
+#define M27 0x07ffffffu
+#define M32 0xffffffffu
+
+#elif FGOLDI_IMPL == 12
+/* We represent an element of GF(p) as 40 signed integer pieces x_i: x =
+ * SUM_{0<=i<40} x_i 2^ceil(224i/20).  Pieces i with i == 0 (mod 5) are 12
+ * bits wide; the others are 11 bits wide, so they form eight groups of 56
+ * bits.
+ */
+
+typedef  int16  piece; typedef  int32  dblpiece;
+typedef uint16 upiece; typedef uint32 udblpiece;
+#define PIECEWD(i) ((i)%5 ? 11 : 12)
+#define NPIECE 40
+#define P p12
+
+#define B12 0x1000u
+#define B11 0x0800u
+#define B10 0x0400u
+#define M12 0xfffu
+#define M11 0x7ffu
+#define M10 0x3ffu
+#define M8 0xffu
+
+#endif
+
+/*----- Debugging machinery -----------------------------------------------*/
+
+#if defined(FGOLDI_DEBUG) || defined(TEST_RIG)
+
+#include <stdio.h>
+
+#include "mp.h"
+#include "mptext.h"
+
+static mp *get_pgoldi(void)
+{
+  mp *p = MP_NEW, *t = MP_NEW;
+
+  p = mp_setbit(p, MP_ZERO, 448);
+  t = mp_setbit(t, MP_ZERO, 224);
+  p = mp_sub(p, p, t);
+  p = mp_sub(p, p, MP_ONE);
+  mp_drop(t);
+  return (p);
+}
+
+DEF_FDUMP(fdump, piece, PIECEWD, NPIECE, 56, get_pgoldi())
+
+#endif
+
+/*----- Loading and storing -----------------------------------------------*/
+
+/* --- @fgoldi_load@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to store the result
+ *             @const octet xv[56]@ = source to read
+ *
+ * Returns:    ---
+ *
+ * Use:                Reads an element of %$\gf{2^{448} - 2^{224} - 19}$% in
+ *             external representation from @xv@ and stores it in @z@.
+ *
+ *             External representation is little-endian base-256.  Some
+ *             elements have multiple encodings, which are not produced by
+ *             correct software; use of noncanonical encodings is not an
+ *             error, and toleration of them is considered a performance
+ *             feature.
+ */
+
+void fgoldi_load(fgoldi *z, const octet xv[56])
+{
+#if FGOLDI_IMPL == 28
+
+  unsigned i;
+  uint32 xw[14];
+  piece b, c;
+
+  /* First, read the input value as words. */
+  for (i = 0; i < 14; i++) xw[i] = LOAD32_L(xv + 4*i);
+
+  /* Extract unsigned 28-bit pieces from the words. */
+  z->P[ 0] = (xw[ 0] >> 0)&M28;
+  z->P[ 7] = (xw[ 6] >> 4)&M28;
+  z->P[ 8] = (xw[ 7] >> 0)&M28;
+  z->P[15] = (xw[13] >> 4)&M28;
+  for (i = 1; i < 7; i++) {
+    z->P[i + 0] = ((xw[i + 0] << (4*i)) | (xw[i - 1] >> (32 - 4*i)))&M28;
+    z->P[i + 8] = ((xw[i + 7] << (4*i)) | (xw[i + 6] >> (32 - 4*i)))&M28;
+  }
+
+  /* Convert the nonnegative pieces into a balanced signed representation, so
+   * each piece ends up in the interval |z_i| <= 2^27.  For each piece, if
+   * its top bit is set, lend a bit leftwards; in the case of z_15, reduce
+   * this bit by adding it onto z_0 and z_8, since this is the Ï†^2 bit, and
+   * Ï†^2 = Ï† + 1.  We delay this carry until after all of the pieces have
+   * been balanced.  If we don't do this, then we have to do a more expensive
+   * test for nonzeroness to decide whether to lend a bit leftwards rather
+   * than just testing a single bit.
+   *
+   * Note that we don't try for a canonical representation here: both upper
+   * and lower bounds are achievable.
+   */
+  b = z->P[15]&B27; z->P[15] -= b << 1; c = b >> 27;
+  for (i = NPIECE - 1; i--; )
+    { b = z->P[i]&B27; z->P[i] -= b << 1; z->P[i + 1] += b >> 27; }
+  z->P[0] += c; z->P[8] += c;
+
+#elif FGOLDI_IMPL == 12
+
+  unsigned i, j, n, w, b;
+  uint32 a;
+  int c;
+
+  /* First, convert the bytes into nonnegative pieces. */
+  for (i = j = a = n = 0, w = PIECEWD(0); i < 56; i++) {
+    a |= (uint32)xv[i] << n; n += 8;
+    if (n >= w) {
+      z->P[j++] = a&MASK(w);
+      a >>= w; n -= w; w = PIECEWD(j);
+    }
+  }
+
+  /* Convert the nonnegative pieces into a balanced signed representation, so
+   * each piece ends up in the interval |z_i| <= 2^11 + 1.
+   */
+  b = z->P[39]&B10; z->P[39] -= b << 1; c = b >> 10;
+  for (i = NPIECE - 1; i--; ) {
+    w = PIECEWD(i) - 1;
+    b = z->P[i]&BIT(w);
+    z->P[i] -= b << 1;
+    z->P[i + 1] += b >> w;
+  }
+  z->P[0] += c; z->P[20] += c;
+
+#endif
+}
+
+/* --- @fgoldi_store@ --- *
+ *
+ * Arguments:  @octet zv[56]@ = where to write the result
+ *             @const fgoldi *x@ = the field element to write
+ *
+ * Returns:    ---
+ *
+ * Use:                Stores a field element in the given octet vector in external
+ *             representation.  A canonical encoding is always stored.
+ */
+
+void fgoldi_store(octet zv[56], const fgoldi *x)
+{
+#if FGOLDI_IMPL == 28
+
+  piece y[NPIECE], yy[NPIECE], c, d;
+  uint32 u, v;
+  mask32 m;
+  unsigned i;
+
+  for (i = 0; i < NPIECE; i++) y[i] = x->P[i];
+
+  /* First, propagate the carries.  By the end of this, we'll have all of the
+   * the pieces canonically sized and positive, and maybe there'll be
+   * (signed) carry out.  The carry c is in { -1, 0, +1 }, and the remaining
+   * value will be in the half-open interval [0, Ï†^2).  The whole represented
+   * value is then y + Ï†^2 c.
+   *
+   * Assume that we start out with |y_i| <= 2^30.  We start off by cutting
+   * off and reducing the carry c_15 from the topmost piece, y_15.  This
+   * leaves 0 <= y_15 < 2^28; and we'll have |c_15| <= 4.  We'll add this
+   * onto y_0 and y_8, and propagate the carries.  It's very clear that we'll
+   * end up with |y + (φ + 1) c_15 - Ï†^2/2| << Ï†^2.
+   *
+   * Here, the y_i are signed, so we must be cautious about bithacking them.
+   */
+  c = ASR(piece, y[15], 28); y[15] = (upiece)y[15]&M28; y[8] += c;
+  for (i = 0; i < NPIECE; i++)
+    { y[i] += c; c = ASR(piece, y[i], 28); y[i] = (upiece)y[i]&M28; }
+
+  /* Now we have a slightly fiddly job to do.  If c = +1, or if c = 0 and
+   * y >= p, then we should subtract p from the whole value; if c = -1 then
+   * we should add p; and otherwise we should do nothing.
+   *
+   * But conditional behaviour is bad, m'kay.  So here's what we do instead.
+   *
+   * The first job is to sort out what we wanted to do.  If c = -1 then we
+   * want to (a) invert the constant addend and (b) feed in a carry-in;
+   * otherwise, we don't.
+   */
+  m = SIGN(c)&M28;
+  d = m&1;
+
+  /* Now do the addition/subtraction.  Remember that all of the y_i are
+   * nonnegative, so shifting and masking are safe and easy.
+   */
+      d += y[0] + (1 ^ m); yy[0] = d&M28; d >>= 28;
+  for (i = 1; i < 8; i++)
+    { d += y[i] +      m;  yy[i] = d&M28; d >>= 28; }
+      d += y[8] + (1 ^ m); yy[8] = d&M28; d >>= 28;
+  for (i = 9; i < 16; i++)
+    { d += y[i] +      m;  yy[i] = d&M28; d >>= 28; }
+
+  /* The final carry-out is in d; since we only did addition, and the y_i are
+   * nonnegative, then d is in { 0, 1 }.  We want to keep y', rather than y,
+   * if (a) c /= 0 (in which case we know that the old value was
+   * unsatisfactory), or (b) if d = 1 (in which case, if c = 0, we know that
+   * the subtraction didn't cause a borrow, so we must be in the case where
+   * p <= y < Ï†^2.
+   */
+  m = NONZEROP(c) | ~NONZEROP(d - 1);
+  for (i = 0; i < NPIECE; i++) y[i] = (yy[i]&m) | (y[i]&~m);
+
+  /* Extract 32-bit words from the value. */
+  for (i = 0; i < 7; i++) {
+    u = ((y[i + 0] >> (4*i)) | ((uint32)y[i + 1] << (28 - 4*i)))&M32;
+    v = ((y[i + 8] >> (4*i)) | ((uint32)y[i + 9] << (28 - 4*i)))&M32;
+    STORE32_L(zv + 4*i,             u);
+    STORE32_L(zv + 4*i + 28, v);
+  }
+
+#elif FGOLDI_IMPL == 12
+
+  piece y[NPIECE], yy[NPIECE], c, d;
+  uint32 a;
+  mask32 m, mm;
+  unsigned i, j, n, w;
+
+  for (i = 0; i < NPIECE; i++) y[i] = x->P[i];
+
+  /* First, propagate the carries.  By the end of this, we'll have all of the
+   * the pieces canonically sized and positive, and maybe there'll be
+   * (signed) carry out.  The carry c is in { -1, 0, +1 }, and the remaining
+   * value will be in the half-open interval [0, Ï†^2).  The whole represented
+   * value is then y + Ï†^2 c.
+   *
+   * Assume that we start out with |y_i| <= 2^14.  We start off by cutting
+   * off and reducing the carry c_39 from the topmost piece, y_39.  This
+   * leaves 0 <= y_39 < 2^11; and we'll have |c_39| <= 16.  We'll add this
+   * onto y_0 and y_20, and propagate the carries.  It's very clear that
+   * we'll end up with |y + (φ + 1) c_39 - Ï†^2/2| << Ï†^2.
+   *
+   * Here, the y_i are signed, so we must be cautious about bithacking them.
+   */
+  c = ASR(piece, y[39], 11); y[39] = (piece)y[39]&M11; y[20] += c;
+  for (i = 0; i < NPIECE; i++) {
+    w = PIECEWD(i); m = (1 << w) - 1;
+    y[i] += c; c = ASR(piece, y[i], w); y[i] = (upiece)y[i]&m;
+  }
+
+  /* Now we have a slightly fiddly job to do.  If c = +1, or if c = 0 and
+   * y >= p, then we should subtract p from the whole value; if c = -1 then
+   * we should add p; and otherwise we should do nothing.
+   *
+   * But conditional behaviour is bad, m'kay.  So here's what we do instead.
+   *
+   * The first job is to sort out what we wanted to do.  If c = -1 then we
+   * want to (a) invert the constant addend and (b) feed in a carry-in;
+   * otherwise, we don't.
+   */
+  mm = SIGN(c);
+  d = m&1;
+
+  /* Now do the addition/subtraction.  Remember that all of the y_i are
+   * nonnegative, so shifting and masking are safe and easy.
+   */
+    d += y[ 0] + (1 ^ (mm&M12)); yy[ 0] = d&M12; d >>= 12;
+  for (i = 1; i < 20; i++) {
+    w = PIECEWD(i); m = MASK(w);
+    d += y[ i] +      (mm&m);    yy[ i] = d&m;   d >>= w;
+  }
+    d += y[20] + (1 ^ (mm&M12)); yy[20] = d&M12; d >>= 12;
+  for (i = 21; i < 40; i++) {
+    w = PIECEWD(i); m = MASK(w);
+    d += y[ i] +      (mm&m);    yy[ i] = d&m;   d >>= w;
+  }
+
+  /* The final carry-out is in d; since we only did addition, and the y_i are
+   * nonnegative, then d is in { 0, 1 }.  We want to keep y', rather than y,
+   * if (a) c /= 0 (in which case we know that the old value was
+   * unsatisfactory), or (b) if d = 1 (in which case, if c = 0, we know that
+   * the subtraction didn't cause a borrow, so we must be in the case where
+   * p <= y < Ï†^2.
+   */
+  m = NONZEROP(c) | ~NONZEROP(d - 1);
+  for (i = 0; i < NPIECE; i++) y[i] = (yy[i]&m) | (y[i]&~m);
+
+  /* Convert that back into octets. */
+  for (i = j = a = n = 0; i < NPIECE; i++) {
+    a |= (uint32)y[i] << n; n += PIECEWD(i);
+    while (n >= 8) { zv[j++] = a&M8; a >>= 8; n -= 8; }
+  }
+
+#endif
+}
+
+/* --- @fgoldi_set@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to write the result
+ *             @int a@ = a small-ish constant
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets @z@ to equal @a@.
+ */
+
+void fgoldi_set(fgoldi *x, int a)
+{
+  unsigned i;
+
+  x->P[0] = a;
+  for (i = 1; i < NPIECE; i++) x->P[i] = 0;
+}
+
+/*----- Basic arithmetic --------------------------------------------------*/
+
+/* --- @fgoldi_add@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const fgoldi *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the sum %$x + y$%.
+ */
+
+void fgoldi_add(fgoldi *z, const fgoldi *x, const fgoldi *y)
+{
+  unsigned i;
+  for (i = 0; i < NPIECE; i++) z->P[i] = x->P[i] + y->P[i];
+}
+
+/* --- @fgoldi_sub@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const fgoldi *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the difference %$x - y$%.
+ */
+
+void fgoldi_sub(fgoldi *z, const fgoldi *x, const fgoldi *y)
+{
+  unsigned i;
+  for (i = 0; i < NPIECE; i++) z->P[i] = x->P[i] - y->P[i];
+}
+
+/*----- Constant-time utilities -------------------------------------------*/
+
+/* --- @fgoldi_condswap@ --- *
+ *
+ * Arguments:  @fgoldi *x, *y@ = two operands
+ *             @uint32 m@ = a mask
+ *
+ * Returns:    ---
+ *
+ * Use:                If @m@ is zero, do nothing; if @m@ is all-bits-set, then
+ *             exchange @x@ and @y@.  If @m@ has some other value, then
+ *             scramble @x@ and @y@ in an unhelpful way.
+ */
+
+void fgoldi_condswap(fgoldi *x, fgoldi *y, uint32 m)
+{
+  unsigned i;
+  mask32 mm = FIX_MASK32(m);
+
+  for (i = 0; i < NPIECE; i++) CONDSWAP(x->P[i], y->P[i], mm);
+}
+
+/*----- Multiplication ----------------------------------------------------*/
+
+#if FGOLDI_IMPL == 28
+
+/* Let B = 2^63 - 1 be the largest value such that +B and -B can be
+ * represented in a double-precision piece.  On entry, it must be the case
+ * that |X_i| <= M <= B - 2^27 for some M.  If this is the case, then, on
+ * exit, we will have |Z_i| <= 2^27 + M/2^27.
+ */
+#define CARRY_REDUCE(z, x) do {                                                \
+  dblpiece _t[NPIECE], _c;                                             \
+  unsigned _i;                                                         \
+                                                                       \
+  /* Bias the input pieces.  This keeps the carries and so on centred  \
+   * around zero rather than biased positive.                          \
+   */                                                                  \
+  for (_i = 0; _i < NPIECE; _i++) _t[_i] = (x)[_i] + B27;              \
+                                                                       \
+  /* Calculate the reduced pieces.  Careful with the bithacking. */    \
+  _c = ASR(dblpiece, _t[15], 28);                                      \
+  (z)[0] = (dblpiece)((udblpiece)_t[0]&M28) - B27 + _c;                        \
+  for (_i = 1; _i < NPIECE; _i++) {                                    \
+    (z)[_i] = (dblpiece)((udblpiece)_t[_i]&M28) - B27 +                        \
+      ASR(dblpiece, _t[_i - 1], 28);                                   \
+  }                                                                    \
+  (z)[8] += _c;                                                                \
+} while (0)
+
+#elif FGOLDI_IMPL == 12
+
+static void carry_reduce(dblpiece x[NPIECE])
+{
+  /* Initial bounds: we assume |x_i| < 2^31 - 2^27. */
+
+  unsigned i, j;
+  dblpiece c;
+
+  /* The result is nearly canonical, because we do sequential carry
+   * propagation, because smaller processors are more likely to prefer the
+   * smaller working set than the instruction-level parallelism.
+   *
+   * Start at x_37; truncate it to 10 bits, and propagate the carry to x_38.
+   * Truncate x_38 to 10 bits, and add the carry onto x_39.  Truncate x_39 to
+   * 10 bits, and add the carry onto x_0 and x_20.  And so on.
+   *
+   * Once we reach x_37 for the second time, we start with |x_37| <= 2^10.
+   * The carry into x_37 is at most 2^21; so the carry out into x_38 has
+   * magnitude at most 2^10.  In turn, |x_38| <= 2^10 before the carry, so is
+   * now no more than 2^11 in magnitude, and the carry out into x_39 is at
+   * most 1.  This leaves |x_39| <= 2^10 + 1 after carry propagation.
+   *
+   * Be careful with the bit hacking because the quantities involved are
+   * signed.
+   */
+
+  /* For each piece, we bias it so that floor division (as done by an
+   * arithmetic right shift) and modulus (as done by bitwise-AND) does the
+   * right thing.
+   */
+#define CARRY(i, wd, b, m) do {                                                \
+  x[i] += (b);                                                         \
+  c = ASR(dblpiece, x[i], (wd));                                       \
+  x[i] = (dblpiece)((udblpiece)x[i]&(m)) - (b);                                \
+} while (0)
+
+                            {             CARRY(37, 11, B10, M11);      }
+                            { x[38] += c; CARRY(38, 11, B10, M11);      }
+                            { x[39] += c; CARRY(39, 11, B10, M11);      }
+                              x[20] += c;
+  for (i = 0; i < 35; ) {
+                            {  x[i] += c; CARRY( i, 12, B11, M12); i++; }
+    for (j = i + 4; i < j; ) {  x[i] += c; CARRY( i, 11, B10, M11); i++; }
+  }
+                            {  x[i] += c; CARRY( i, 12, B11, M12); i++; }
+  while (i < 39)            {  x[i] += c; CARRY( i, 11, B10, M11); i++; }
+  x[39] += c;
+}
+
+#endif
+
+/* --- @fgoldi_mulconst@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@)
+ *             @const fgoldi *x@ = an operand
+ *             @long a@ = a small-ish constant; %$|a| < 2^{20}$%.
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the product %$a x$%.
+ */
+
+void fgoldi_mulconst(fgoldi *z, const fgoldi *x, long a)
+{
+  unsigned i;
+  dblpiece zz[NPIECE], aa = a;
+
+  for (i = 0; i < NPIECE; i++) zz[i] = aa*x->P[i];
+#if FGOLDI_IMPL == 28
+  CARRY_REDUCE(z->P, zz);
+#elif FGOLDI_IMPL == 12
+  carry_reduce(zz);
+  for (i = 0; i < NPIECE; i++) z->P[i] = zz[i];
+#endif
+}
+
+/* --- @fgoldi_mul@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const fgoldi *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the product %$x y$%.
+ */
+
+void fgoldi_mul(fgoldi *z, const fgoldi *x, const fgoldi *y)
+{
+  dblpiece zz[NPIECE], u[NPIECE];
+  piece ab[NPIECE/2], cd[NPIECE/2];
+  const piece
+    *a = x->P + NPIECE/2, *b = x->P,
+    *c = y->P + NPIECE/2, *d = y->P;
+  unsigned i, j;
+
+#if FGOLDI_IMPL == 28
+
+#  define M(x,i, y,j) ((dblpiece)(x)[i]*(y)[j])
+
+#elif FGOLDI_IMPL == 12
+
+  static const unsigned short off[39] = {
+      0,  12,  23,  34,  45,  56,  68,  79,  90, 101,
+    112, 124, 135, 146, 157, 168, 180, 191, 202, 213,
+    224, 236, 247, 258, 269, 280, 292, 303, 314, 325,
+    336, 348, 359, 370, 381, 392, 404, 415, 426
+  };
+
+#define M(x,i, y,j)                                                    \
+  (((dblpiece)(x)[i]*(y)[j]) << (off[i] + off[j] - off[(i) + (j)]))
+
+#endif
+
+  /* Behold the magic.
+   *
+   * Write x = a Ï† + b, and y = c Ï† + d.  Then x y = a c Ï†^2 +
+   * (a d + b c) Ï† + b d.  Karatsuba and Ofman observed that a d + b c =
+   * (a + b) (c + d) - a c - b d, saving a multiplication, and Hamburg chose
+   * the prime p so that Ï†^2 = Ï† + 1.  So
+   *
+   *   x y = ((a + b) (c + d) - b d) Ï† + a c + b d
+   */
+
+  for (i = 0; i < NPIECE; i++) zz[i] = 0;
+
+  /* Our first job will be to calculate (1 - Ï†) b d, and write the result
+   * into z.  As we do this, an interesting thing will happen.  Write
+   * b d = u Ï† + v; then (1 - Ï†) b d = u Ï† + v - u Ï†^2 - v Ï† = (1 - Ï†) v - u.
+   * So, what we do is to write the product end-swapped and negated, and then
+   * we'll subtract the (negated, remember) high half from the low half.
+   */
+  for (i = 0; i < NPIECE/2; i++) {
+    for (j = 0; j < NPIECE/2 - i; j++)
+      zz[i + j + NPIECE/2] -= M(b,i, d,j);
+    for (; j < NPIECE/2; j++)
+      zz[i + j - NPIECE/2] -= M(b,i, d,j);
+  }
+  for (i = 0; i < NPIECE/2; i++)
+    zz[i] -= zz[i + NPIECE/2];
+
+  /* Next, we add on a c.  There are no surprises here. */
+  for (i = 0; i < NPIECE/2; i++)
+    for (j = 0; j < NPIECE/2; j++)
+      zz[i + j] += M(a,i, c,j);
+
+  /* Now, calculate a + b and c + d. */
+  for (i = 0; i < NPIECE/2; i++)
+    { ab[i] = a[i] + b[i]; cd[i] = c[i] + d[i]; }
+
+  /* Finally (for the multiplication) we must add on (a + b) (c + d) Ï†.
+   * Write (a + b) (c + d) as u Ï† + v; then we actually want u Ï†^2 + v Ï† =
+   * v Ï† + (1 + Ï†) u.  We'll store u in a temporary place and add it on
+   * twice.
+   */
+  for (i = 0; i < NPIECE; i++) u[i] = 0;
+  for (i = 0; i < NPIECE/2; i++) {
+    for (j = 0; j < NPIECE/2 - i; j++)
+      zz[i + j + NPIECE/2] += M(ab,i, cd,j);
+    for (; j < NPIECE/2; j++)
+      u[i + j - NPIECE/2] += M(ab,i, cd,j);
+  }
+  for (i = 0; i < NPIECE/2; i++)
+    { zz[i] += u[i]; zz[i + NPIECE/2] += u[i]; }
+
+#undef M
+
+#if FGOLDI_IMPL == 28
+  /* That wraps it up for the multiplication.  Let's figure out some bounds.
+   * Fortunately, Karatsuba is a polynomial identity, so all of the pieces
+   * end up the way they'd be if we'd done the thing the easy way, which
+   * simplifies the analysis.  Suppose we started with |x_i|, |y_i| <= 9/5
+   * 2^28.  The overheads in the result are given by the coefficients of
+   *
+   *   ((u^16 - 1)/(u - 1))^2 mod u^16 - u^8 - 1
+   *
+   * the greatest of which is 38.  So |z_i| <= 38*81/25*2^56 < 2^63.
+   *
+   * Anyway, a round of `CARRY_REDUCE' will leave us with |z_i| < 2^27 +
+   * 2^36; and a second round will leave us with |z_i| < 2^27 + 512.
+   */
+  for (i = 0; i < 2; i++) CARRY_REDUCE(zz, zz);
+  for (i = 0; i < NPIECE; i++) z->P[i] = zz[i];
+#elif FGOLDI_IMPL == 12
+  carry_reduce(zz);
+  for (i = 0; i < NPIECE; i++) z->P[i] = zz[i];
+#endif
+}
+
+/* --- @fgoldi_sqr@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const fgoldi *x@ = an operand
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the square %$x^2$%.
+ */
+
+void fgoldi_sqr(fgoldi *z, const fgoldi *x)
+{
+#if FGOLDI_IMPL == 28
+
+  dblpiece zz[NPIECE], u[NPIECE];
+  piece ab[NPIECE];
+  const piece *a = x->P + NPIECE/2, *b = x->P;
+  unsigned i, j;
+
+#  define M(x,i, y,j) ((dblpiece)(x)[i]*(y)[j])
+
+  /* The magic is basically the same as `fgoldi_mul' above.  We write
+   * x = a Ï† + b and use Karatsuba and the special prime shape.  This time,
+   * we have
+   *
+   *   x^2 = ((a + b)^2 - b^2) Ï† + a^2 + b^2
+   */
+
+  for (i = 0; i < NPIECE; i++) zz[i] = 0;
+
+  /* Our first job will be to calculate (1 - Ï†) b^2, and write the result
+   * into z.  Again, this interacts pleasantly with the prime shape.
+   */
+  for (i = 0; i < NPIECE/4; i++) {
+    zz[2*i + NPIECE/2] -= M(b,i, b,i);
+    for (j = i + 1; j < NPIECE/2 - i; j++)
+      zz[i + j + NPIECE/2] -= 2*M(b,i, b,j);
+    for (; j < NPIECE/2; j++)
+      zz[i + j - NPIECE/2] -= 2*M(b,i, b,j);
+  }
+  for (; i < NPIECE/2; i++) {
+    zz[2*i - NPIECE/2] -= M(b,i, b,i);
+    for (j = i + 1; j < NPIECE/2; j++)
+      zz[i + j - NPIECE/2] -= 2*M(b,i, b,j);
+  }
+  for (i = 0; i < NPIECE/2; i++)
+    zz[i] -= zz[i + NPIECE/2];
+
+  /* Next, we add on a^2.  There are no surprises here. */
+  for (i = 0; i < NPIECE/2; i++) {
+    zz[2*i] += M(a,i, a,i);
+    for (j = i + 1; j < NPIECE/2; j++)
+      zz[i + j] += 2*M(a,i, a,j);
+  }
+
+  /* Now, calculate a + b. */
+  for (i = 0; i < NPIECE/2; i++)
+    ab[i] = a[i] + b[i];
+
+  /* Finally (for the multiplication) we must add on (a + b)^2 Ï†.
+   * Write (a + b)^2 as u Ï† + v; then we actually want (u + v) Ï† + u.  We'll
+   * store u in a temporary place and add it on twice.
+   */
+  for (i = 0; i < NPIECE; i++) u[i] = 0;
+  for (i = 0; i < NPIECE/4; i++) {
+    zz[2*i + NPIECE/2] += M(ab,i, ab,i);
+    for (j = i + 1; j < NPIECE/2 - i; j++)
+      zz[i + j + NPIECE/2] += 2*M(ab,i, ab,j);
+    for (; j < NPIECE/2; j++)
+      u[i + j - NPIECE/2] += 2*M(ab,i, ab,j);
+  }
+  for (; i < NPIECE/2; i++) {
+    u[2*i - NPIECE/2] += M(ab,i, ab,i);
+    for (j = i + 1; j < NPIECE/2; j++)
+      u[i + j - NPIECE/2] += 2*M(ab,i, ab,j);
+  }
+  for (i = 0; i < NPIECE/2; i++)
+    { zz[i] += u[i]; zz[i + NPIECE/2] += u[i]; }
+
+#undef M
+
+  /* Finally, carrying. */
+  for (i = 0; i < 2; i++) CARRY_REDUCE(zz, zz);
+  for (i = 0; i < NPIECE; i++) z->P[i] = zz[i];
+
+#elif FGOLDI_IMPL == 12
+  fgoldi_mul(z, x, x);
+#endif
+}
+
+/*----- More advanced operations ------------------------------------------*/
+
+/* --- @fgoldi_inv@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@)
+ *             @const fgoldi *x@ = an operand
+ *
+ * Returns:    ---
+ *
+ * Use:                Stores in @z@ the multiplicative inverse %$x^{-1}$%.  If
+ *             %$x = 0$% then @z@ is set to zero.  This is considered a
+ *             feature.
+ */
+
+void fgoldi_inv(fgoldi *z, const fgoldi *x)
+{
+  fgoldi t, u;
+  unsigned i;
+
+#define SQRN(z, x, n) do {                                             \
+  fgoldi_sqr((z), (x));                                                        \
+  for (i = 1; i < (n); i++) fgoldi_sqr((z), (z));                      \
+} while (0)
+
+  /* Calculate x^-1 = x^(p - 2) = x^(2^448 - 2^224 - 3), which also handles
+   * x = 0 as intended.  The addition chain is home-made.
+   */                                  /* step | value */
+  fgoldi_sqr(&u, x);                   /*    1 | 2 */
+  fgoldi_mul(&t, &u, x);               /*    2 | 3 */
+  SQRN(&u, &t, 2);                     /*    4 | 12 */
+  fgoldi_mul(&t, &u, &t);              /*    5 | 15 */
+  SQRN(&u, &t, 4);                     /*    9 | 240 */
+  fgoldi_mul(&u, &u, &t);              /*   10 | 255 = 2^8 - 1 */
+  SQRN(&u, &u, 4);                     /*   14 | 2^12 - 16 */
+  fgoldi_mul(&t, &u, &t);              /*   15 | 2^12 - 1 */
+  SQRN(&u, &t, 12);                    /*   27 | 2^24 - 2^12 */
+  fgoldi_mul(&u, &u, &t);              /*   28 | 2^24 - 1 */
+  SQRN(&u, &u, 12);                    /*   40 | 2^36 - 2^12 */
+  fgoldi_mul(&t, &u, &t);              /*   41 | 2^36 - 1 */
+  fgoldi_sqr(&t, &t);                  /*   42 | 2^37 - 2 */
+  fgoldi_mul(&t, &t, x);               /*   43 | 2^37 - 1 */
+  SQRN(&u, &t, 37);                    /*   80 | 2^74 - 2^37 */
+  fgoldi_mul(&u, &u, &t);              /*   81 | 2^74 - 1 */
+  SQRN(&u, &u, 37);                    /*  118 | 2^111 - 2^37 */
+  fgoldi_mul(&t, &u, &t);              /*  119 | 2^111 - 1 */
+  SQRN(&u, &t, 111);                   /*  230 | 2^222 - 2^111 */
+  fgoldi_mul(&t, &u, &t);              /*  231 | 2^222 - 1 */
+  fgoldi_sqr(&u, &t);                  /*  232 | 2^223 - 2 */
+  fgoldi_mul(&u, &u, x);               /*  233 | 2^223 - 1 */
+  SQRN(&u, &u, 223);                   /*  456 | 2^446 - 2^223 */
+  fgoldi_mul(&t, &u, &t);              /*  457 | 2^446 - 2^222 - 1 */
+  SQRN(&t, &t, 2);                     /*  459 | 2^448 - 2^224 - 4 */
+  fgoldi_mul(z, &t, x);                        /*  460 | 2^448 - 2^224 - 3 */
+
+#undef SQRN
+}
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <mLib/report.h>
+#include <mLib/str.h>
+#include <mLib/testrig.h>
+
+static void fixdstr(dstr *d)
+{
+  if (d->len > 56)
+    die(1, "invalid length for fgoldi");
+  else if (d->len < 56) {
+    dstr_ensure(d, 56);
+    memset(d->buf + d->len, 0, 56 - d->len);
+    d->len = 56;
+  }
+}
+
+static void cvt_fgoldi(const char *buf, dstr *d)
+{
+  dstr dd = DSTR_INIT;
+
+  type_hex.cvt(buf, &dd); fixdstr(&dd);
+  dstr_ensure(d, sizeof(fgoldi)); d->len = sizeof(fgoldi);
+  fgoldi_load((fgoldi *)d->buf, (const octet *)dd.buf);
+  dstr_destroy(&dd);
+}
+
+static void dump_fgoldi(dstr *d, FILE *fp)
+  { fdump(stderr, "???", (const piece *)d->buf); }
+
+static void cvt_fgoldi_ref(const char *buf, dstr *d)
+  { type_hex.cvt(buf, d); fixdstr(d); }
+
+static void dump_fgoldi_ref(dstr *d, FILE *fp)
+{
+  fgoldi x;
+
+  fgoldi_load(&x, (const octet *)d->buf);
+  fdump(stderr, "???", x.P);
+}
+
+static int eq(const fgoldi *x, dstr *d)
+  { octet b[56]; fgoldi_store(b, x); return (memcmp(b, d->buf, 56) == 0); }
+
+static const test_type
+  type_fgoldi = { cvt_fgoldi, dump_fgoldi },
+  type_fgoldi_ref = { cvt_fgoldi_ref, dump_fgoldi_ref };
+
+#define TEST_UNOP(op)                                                  \
+  static int vrf_##op(dstr dv[])                                       \
+  {                                                                    \
+    fgoldi *x = (fgoldi *)dv[0].buf;                                   \
+    fgoldi z, zz;                                                      \
+    int ok = 1;                                                                \
+                                                                       \
+    fgoldi_##op(&z, x);                                                        \
+    if (!eq(&z, &dv[1])) {                                             \
+      ok = 0;                                                          \
+      fprintf(stderr, "failed!\n");                                    \
+      fdump(stderr, "x", x->P);                                                \
+      fdump(stderr, "calc", z.P);                                      \
+      fgoldi_load(&zz, (const octet *)dv[1].buf);                      \
+      fdump(stderr, "z", zz.P);                                                \
+    }                                                                  \
+                                                                       \
+    return (ok);                                                       \
+  }
+
+TEST_UNOP(sqr)
+TEST_UNOP(inv)
+
+#define TEST_BINOP(op)                                                 \
+  static int vrf_##op(dstr dv[])                                       \
+  {                                                                    \
+    fgoldi *x = (fgoldi *)dv[0].buf, *y = (fgoldi *)dv[1].buf;         \
+    fgoldi z, zz;                                                      \
+    int ok = 1;                                                                \
+                                                                       \
+    fgoldi_##op(&z, x, y);                                             \
+    if (!eq(&z, &dv[2])) {                                             \
+      ok = 0;                                                          \
+      fprintf(stderr, "failed!\n");                                    \
+      fdump(stderr, "x", x->P);                                                \
+      fdump(stderr, "y", y->P);                                                \
+      fdump(stderr, "calc", z.P);                                      \
+      fgoldi_load(&zz, (const octet *)dv[2].buf);                      \
+      fdump(stderr, "z", zz.P);                                                \
+    }                                                                  \
+                                                                       \
+    return (ok);                                                       \
+  }
+
+TEST_BINOP(add)
+TEST_BINOP(sub)
+TEST_BINOP(mul)
+
+static int vrf_mulc(dstr dv[])
+{
+  fgoldi *x = (fgoldi *)dv[0].buf;
+  long a = *(const long *)dv[1].buf;
+  fgoldi z, zz;
+  int ok = 1;
+
+  fgoldi_mulconst(&z, x, a);
+  if (!eq(&z, &dv[2])) {
+    ok = 0;
+    fprintf(stderr, "failed!\n");
+    fdump(stderr, "x", x->P);
+    fprintf(stderr, "a = %ld\n", a);
+    fdump(stderr, "calc", z.P);
+    fgoldi_load(&zz, (const octet *)dv[2].buf);
+    fdump(stderr, "z", zz.P);
+  }
+
+  return (ok);
+}
+
+static int vrf_condswap(dstr dv[])
+{
+  fgoldi *x = (fgoldi *)dv[0].buf, *y = (fgoldi *)dv[1].buf;
+  fgoldi xx = *x, yy = *y;
+  uint32 m = *(uint32 *)dv[2].buf;
+  int ok = 1;
+
+  fgoldi_condswap(&xx, &yy, m);
+  if (!eq(&xx, &dv[3]) || !eq(&yy, &dv[4])) {
+    ok = 0;
+    fprintf(stderr, "failed!\n");
+    fdump(stderr, "x", x->P);
+    fdump(stderr, "y", y->P);
+    fprintf(stderr, "m = 0x%08lx\n", (unsigned long)m);
+    fdump(stderr, "calc xx", xx.P);
+    fdump(stderr, "calc yy", yy.P);
+    fgoldi_load(&xx, (const octet *)dv[3].buf);
+    fgoldi_load(&yy, (const octet *)dv[4].buf);
+    fdump(stderr, "want xx", xx.P);
+    fdump(stderr, "want yy", yy.P);
+  }
+
+  return (ok);
+}
+
+static int vrf_sub_mulc_add_sub_mul(dstr dv[])
+{
+  fgoldi *u = (fgoldi *)dv[0].buf, *v = (fgoldi *)dv[1].buf,
+    *w = (fgoldi *)dv[3].buf, *x = (fgoldi *)dv[4].buf,
+    *y = (fgoldi *)dv[5].buf;
+  long a = *(const long *)dv[2].buf;
+  fgoldi umv, aumv, wpaumv, xmy, z, zz;
+  int ok = 1;
+
+  fgoldi_sub(&umv, u, v);
+  fgoldi_mulconst(&aumv, &umv, a);
+  fgoldi_add(&wpaumv, w, &aumv);
+  fgoldi_sub(&xmy, x, y);
+  fgoldi_mul(&z, &wpaumv, &xmy);
+
+  if (!eq(&z, &dv[6])) {
+    ok = 0;
+    fprintf(stderr, "failed!\n");
+    fdump(stderr, "u", u->P);
+    fdump(stderr, "v", v->P);
+    fdump(stderr, "u - v", umv.P);
+    fprintf(stderr, "a = %ld\n", a);
+    fdump(stderr, "a (u - v)", aumv.P);
+    fdump(stderr, "w + a (u - v)", wpaumv.P);
+    fdump(stderr, "x", x->P);
+    fdump(stderr, "y", y->P);
+    fdump(stderr, "x - y", xmy.P);
+    fdump(stderr, "(x - y) (w + a (u - v))", z.P);
+    fgoldi_load(&zz, (const octet *)dv[6].buf); fdump(stderr, "z", zz.P);
+  }
+
+  return (ok);
+}
+
+static test_chunk tests[] = {
+  { "add", vrf_add, { &type_fgoldi, &type_fgoldi, &type_fgoldi_ref } },
+  { "sub", vrf_sub, { &type_fgoldi, &type_fgoldi, &type_fgoldi_ref } },
+  { "mul", vrf_mul, { &type_fgoldi, &type_fgoldi, &type_fgoldi_ref } },
+  { "mulconst", vrf_mulc, { &type_fgoldi, &type_long, &type_fgoldi_ref } },
+  { "condswap", vrf_condswap,
+    { &type_fgoldi, &type_fgoldi, &type_uint32,
+      &type_fgoldi_ref, &type_fgoldi_ref } },
+  { "sqr", vrf_sqr, { &type_fgoldi, &type_fgoldi_ref } },
+  { "inv", vrf_inv, { &type_fgoldi, &type_fgoldi_ref } },
+  { "sub-mulc-add-sub-mul", vrf_sub_mulc_add_sub_mul,
+    { &type_fgoldi, &type_fgoldi, &type_long, &type_fgoldi,
+      &type_fgoldi, &type_fgoldi, &type_fgoldi_ref } },
+  { 0, 0, { 0 } }
+};
+
+int main(int argc, char *argv[])
+{
+  test_run(argc, argv, tests, SRCDIR "/t/fgoldi");
+  return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/fgoldi.h b/fgoldi.h
new file mode 100644 (file)
index 0000000..b05fd77
--- /dev/null
+++ b/fgoldi.h
@@ -0,0 +1,202 @@
+/* -*-c-*-
+ *
+ * Arithmetic in the Goldilocks field GF(2^448 - 2^224 - 1)
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_FGOLDI_H
+#define CATACOMB_FGOLDI_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#ifndef CATACOMB_QFARITH_H
+#  include "qfarith.h"
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef union {
+  int32 p28[16];
+  int16 p12[40];
+} fgoldi;
+
+#if !defined(FGOLDI_IMPL) && defined(HAVE_INT64)
+#  define FGOLDI_IMPL 28
+#endif
+
+#ifndef FGOLDI_IMPL
+#  define FGOLDI_IMPL 12
+#endif
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @fgoldi_load@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to store the result
+ *             @const octet xv[56]@ = source to read
+ *
+ * Returns:    ---
+ *
+ * Use:                Reads an element of %$\gf{2^{448} - 2^{224} - 19}$% in
+ *             external representation from @xv@ and stores it in @z@.
+ *
+ *             External representation is little-endian base-256.  Some
+ *             elements have multiple encodings, which are not produced by
+ *             correct software; use of noncanonical encodings is not an
+ *             error, and toleration of them is considered a performance
+ *             feature.
+ */
+
+extern void fgoldi_load(fgoldi */*z*/, const octet /*xv*/[56]);
+
+/* --- @fgoldi_store@ --- *
+ *
+ * Arguments:  @octet zv[56]@ = where to write the result
+ *             @const fgoldi *x@ = the field element to write
+ *
+ * Returns:    ---
+ *
+ * Use:                Stores a field element in the given octet vector in external
+ *             representation.  A canonical encoding is always stored.
+ */
+
+extern void fgoldi_store(octet /*zv*/[56], const fgoldi */*x*/);
+
+/* --- @fgoldi_set@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to write the result
+ *             @int a@ = a small-ish constant
+ *
+ * Returns:    ---
+ *
+ * Use:                Sets @z@ to equal @a@.
+ */
+
+extern void fgoldi_set(fgoldi */*x*/, int /*a*/);
+
+/* --- @fgoldi_add@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const fgoldi *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the sum %$x + y$%.
+ */
+
+extern void fgoldi_add(fgoldi */*z*/,
+                      const fgoldi */*x*/, const fgoldi */*y*/);
+
+/* --- @fgoldi_sub@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const fgoldi *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the difference %$x - y$%.
+ */
+
+extern void fgoldi_sub(fgoldi */*z*/,
+                      const fgoldi */*x*/, const fgoldi */*y*/);
+
+/* --- @fgoldi_condswap@ --- *
+ *
+ * Arguments:  @fgoldi *x, *y@ = two operands
+ *             @uint32 m@ = a mask
+ *
+ * Returns:    ---
+ *
+ * Use:                If @m@ is zero, do nothing; if @m@ is all-bits-set, then
+ *             exchange @x@ and @y@.  If @m@ has some other value, then
+ *             scramble @x@ and @y@ in an unhelpful way.
+ */
+
+extern void fgoldi_condswap(fgoldi */*x*/, fgoldi */*y*/, uint32 /*m*/);
+
+/* --- @fgoldi_mulconst@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@)
+ *             @const fgoldi *x@ = an operand
+ *             @long a@ = a small-ish constant; %$|a| < 2^{20}$%.
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the product %$a x$%.
+ */
+
+extern void fgoldi_mulconst(fgoldi */*z*/, const fgoldi */*x*/, long /*a*/);
+
+/* --- @fgoldi_mul@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const fgoldi *x, *y@ = two operands
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the product %$x y$%.
+ */
+
+extern void fgoldi_mul(fgoldi */*z*/,
+                      const fgoldi */*x*/, const fgoldi */*y*/);
+
+/* --- @fgoldi_sqr@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@ or @y@)
+ *             @const fgoldi *x@ = an operand
+ *
+ * Returns:    ---
+ *
+ * Use:                Set @z@ to the square %$x^2$%.
+ */
+
+extern void fgoldi_sqr(fgoldi */*z*/, const fgoldi */*x*/);
+
+/* --- @fgoldi_inv@ --- *
+ *
+ * Arguments:  @fgoldi *z@ = where to put the result (may alias @x@)
+ *             @const fgoldi *x@ = an operand
+ *
+ * Returns:    ---
+ *
+ * Use:                Stores in @z@ the multiplicative inverse %$x^{-1}$%.  If
+ *             %$x = 0$% then @z@ is set to zero.  This is considered a
+ *             feature.
+ */
+
+extern void fgoldi_inv(fgoldi */*z*/, const fgoldi */*x*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/montladder.h b/montladder.h
new file mode 100644 (file)
index 0000000..02d2961
--- /dev/null
@@ -0,0 +1,143 @@
+/* -*-c-*-
+ *
+ * Definitions for Montgomery's ladder
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_MONTLADDER_H
+#define CATACOMB_MONTLADDER_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Notes on the Montgomery ladder ------------------------------------*
+ *
+ * The algorithm here is Montgomery's famous binary ladder for calculating
+ * x-coordinates of scalar products on a particular shape of elliptic curve,
+ * as elucidated by Daniel Bernstein.
+ *
+ * Let Q = (x_1, y_1) be the base point, for some unknown y_1 (which will
+ * turn out to be unimportant).  Define x_n, z_n by x(n Q) = (x_n : z_n).
+ * Given x_n, z_n, x_{n+1}, z_{n+1}, Montgomery's differential addition
+ * formulae calculate x_{2i}, z_{2i}, x_{2i+1}, z_{2i+1}.  Furthermore,
+ * calculating x_{2i}, z_{2i} requires only x_n, z_n, and the calculation of
+ * x_{2i+1}, z_{2i+1} is symmetrical.
+ */
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* F designates a field, both naming the type of its elements and acting as a
+ * prefix for the standard field operations `F_add', `F_sub', `F_mul',
+ * `F_sqr', and `F_inv' (the last of which should return zero its own
+ * inverse); and the constant-time utility `F_condswap'.
+ *
+ * The macro calculates the x-coordinate of the product k Q, where Q is a
+ * point on the elliptic curve B y^2 = x^3 + A x^2 + x or its quadratic
+ * twist, for some irrelevant B.  The x-coordinate of Q is given as X1 (a
+ * pointer to a field element).  The scalar k is given as a vector of NK
+ * unsigned integers KW, each containing NBITS significant bits, with the
+ * least-significant element first.  The result is written to the field
+ * element pointed to by Z.
+ *
+ * The curve coefficient A is given indirectly, as the name of a macro MULA0
+ * such that
+ *
+ *     MULA0(z, x)
+ *
+ * will store in z the value (A - 2)/4 x.
+ */
+#define MONT_LADDER(f, mula0, kw, nk, nbits, z, x1) do {               \
+  f _x, _z, _u, _w;                                                    \
+  f _t0, _t1, _t2, _t3, _t4;                                           \
+  uint32 _m = 0, _mm = 0, _k;                                          \
+  unsigned _i, _j;                                                     \
+                                                                       \
+  /* Initialize the main variables.  We'll have, (x, z) and (u, w)     \
+   * holding (x_n, z_n) and (x_{n+1}, z_{n+1}) in some order, but      \
+   * there's some weirdness: if m = 0 then (x, z) = (x_n, z_n) and     \
+   * (u, v) = (x_{n+1}, z_{n+1}); if m /= 0, then the pairs are                \
+   * swapped over.                                                     \
+   *                                                                   \
+   * Initially, we have (x_0, z_0) = (1, 0), representing the identity \
+   * at projective-infinity, which works fine; and we have z_1 = 1.    \
+   */                                                                  \
+  _u = *(x1); f##_set(&_w, 1); f##_set(&_x, 1); f##_set(&_z, 0);       \
+                                                                       \
+  /* The main ladder loop.  Work through each bit of the clamped key. */ \
+  for (_i = (nk); _i--; ) {                                            \
+    _k = (kw)[_i];                                                     \
+    for (_j = 0; _j < (nbits); _j++) {                                 \
+      /* We're at bit i of the scalar key (represented by 32 (7 - i) + \
+       * (31 - j) in our loop variables -- don't worry about that).    \
+       * Let k = 2^i k_i + k'_i, with 0 <= k'_i < 2^i.  In particular, \
+       * then, k_0 = k.  Write Q(i) = (x_i, z_i).                      \
+       *                                                               \
+       * We currently have, in (x, z) and (u, w), Q(k_i) and Q(k_i +   \
+       * 1), in some order.  The ladder step will double the point in  \
+       * (x, z), and leave the sum of (x : z) and (u : w) in (u, w).   \
+       */                                                              \
+                                                                       \
+      _mm = -((_k >> ((nbits) - 1))&1u); _k <<= 1;                     \
+      f##_condswap(&_x, &_u, _m ^ _mm);                                        \
+      f##_condswap(&_z, &_w, _m ^ _mm);                                        \
+      _m = _mm;                                                                \
+                                                                       \
+      f##_add(&_t0, &_x, &_z);         /* x + z */                     \
+      f##_sub(&_t1, &_x, &_z);         /* x - z */                     \
+      f##_add(&_t2, &_u, &_w);         /* u + w */                     \
+      f##_sub(&_t3, &_u, &_w);         /* u - w */                     \
+      f##_mul(&_t2, &_t2, &_t1);       /* (x - z) (u + w) */           \
+      f##_mul(&_t3, &_t3, &_t0);       /* (x + z) (u - w) */           \
+      f##_sqr(&_t0, &_t0);             /* (x + z)^2 */                 \
+      f##_sqr(&_t1, &_t1);             /* (x - z)^2 */                 \
+      f##_mul(&_x, &_t0, &_t1);                /* (x + z)^2 (x - z)^2 */       \
+      f##_sub(&_t1, &_t0, &_t1);       /* (x + z)^2 - (x - z)^2 */     \
+      mula0(&_t4, &_t1);            /* A_0 ((x + z)^2 - (x - z)^2) */  \
+      f##_add(&_t0, &_t0, &_t4);       /* A_0 ... + (x + z)^2 */       \
+      f##_mul(&_z, &_t0, &_t1);         /* (...^2 - ...^2) (A_0 ... + ...) */  \
+      f##_add(&_t0, &_t2, &_t3); /* (x - z) (u + w) + (x + z) (u - w) */ \
+      f##_sub(&_t1, &_t2, &_t3); /* (x - z) (u + w) - (x + z) (u - w) */ \
+      f##_sqr(&_u, &_t0);              /* (... + ...)^2 */             \
+      f##_sqr(&_t1, &_t1);             /* (... - ...)^2 */             \
+      f##_mul(&_w, &_t1, (x1));                /* x_1 (... - ...)^2 */         \
+    }                                                                  \
+  }                                                                    \
+                                                                       \
+  /* Almost done.  Undo the swap, if any. */                           \
+  f##_condswap(&_x, &_u, _m);                                          \
+  f##_condswap(&_z, &_w, _m);                                          \
+                                                                       \
+  /* And convert to affine. */                                         \
+  f##_inv(&_t0, &_z);                                                  \
+  f##_mul((z), &_x, &_t0);                                             \
+} while (0)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/qfarith.h b/qfarith.h
new file mode 100644 (file)
index 0000000..abcd293
--- /dev/null
+++ b/qfarith.h
@@ -0,0 +1,229 @@
+/* -*-c-*-
+ *
+ * Utilities for quick field arithmetic
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_QFARITH_H
+#define CATACOMB_QFARITH_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <limits.h>
+
+#include <mLib/bits.h>
+
+/*----- Signed integer types ----------------------------------------------*/
+
+/* See if we can find a suitable 64-bit or wider type.  Don't bother if we
+ * don't have a corresponding unsigned type, because we really need both.
+ */
+#ifdef HAVE_UINT64
+#  if INT_MAX >> 31 == 0xffffffff
+#    define HAVE_INT64
+     typedef int int64;
+#  elif LONG_MAX >> 31 == 0xffffffff
+#    define HAVE_INT64
+     typedef long int64;
+#  elif defined(LLONG_MAX)
+#    define HAVE_INT64
+     MLIB_BITS_EXTENSION typedef long long int64;
+#  endif
+#endif
+
+/* Choose suitable 32- and 16-bit types. */
+#if INT_MAX >= 0x7fffffff
+   typedef int int32;
+#else
+   typedef long int32;
+#endif
+
+typedef short int16;
+
+/*----- General bit-hacking utilities -------------------------------------*/
+
+/* Individual bits, and masks for low bits. */
+#define BIT(n) (1ul << (n))
+#define MASK(n) (BIT(n) - 1)
+
+/* Arithmetic right shift.  If X is a value of type TY, and N is a
+ * nonnegative integer, then return the value of X shifted right by N bits;
+ * alternatively, this is floor(X/2^N).
+ *
+ * GCC manages to compile this into a simple shift operation if one is
+ * available, but it's correct for all C targets.
+ */
+#define ASR(ty, x, n) (((x) - (ty)((u##ty)(x)&MASK(n)))/(ty)BIT(n))
+
+/*----- Constant-time utilities -------------------------------------------*/
+
+/* The following have better implementations on a two's complement target. */
+#ifdef NEG_TWOC
+
+  /* If we have two's complement arithmetic then masks are signed; this
+   * avoids a switch to unsigned representation, with the consequent problem
+   * of overflow when we convert back.
+   */
+  typedef int32 mask32;
+
+  /* Convert an unsigned mask M into a `mask32'.  This is a hairy-looking
+   * no-op on many targets, but, given that we have two's complement
+   * integers, it is free of arithmetic overflow.
+   */
+# define FIX_MASK32(m) \
+    ((mask32)((m)&0x7fffffffu) + (-(mask32)0x7fffffff - 1)*(((m) >> 31)&1u))
+
+  /* If Z is zero and M has its low 32 bits set, then copy (at least) the low
+   * 32 bits of X to Z; if M is zero, do nothing.  Otherwise, scramble Z
+   * unhelpfully.
+   */
+# define CONDPICK(z, x, m) do { (z) |= (x)&(m); } while (0)
+
+  /* If M has its low 32 bits set, then return (at least) the low 32 bits of
+   * X in Z; if M is zero, then return (at least) the low 32 bits of Y in Z.
+   * Otherwise, return an unhelful result.
+   */
+# define PICK2(x, y, m) (((x)&(m)) | ((y)&~(m)))
+
+  /* If M has its low 32 bits set then swap (at least) the low 32 bits of X
+   * and Y; if M is zero, then do nothing.  Otherwise, scramble X and Y
+   * unhelpfully.
+   */
+# define CONDSWAP(x, y, m)                                             \
+    do { mask32 t_ = ((x) ^ (y))&(m); (x) ^= t_; (y) ^= t_; } while (0)
+#else
+
+  /* We don't have two's complement arithmetic.  We can't use bithacking at
+   * all: if we try to hack on the bits of signed numbers we'll come unstuck
+   * when we hit the other representation of zero; and if we switch to
+   * unsigned arithmetic then we'll have overflow when we try to convert a
+   * negative number back.  So fall back to simple arithmetic.
+   */
+  typedef uint32 mask32;
+
+  /* Convert an unsigned mask M into a `mask32'.  Our masks are unsigned, so
+   * this does nothing.
+   */
+# define FIX_MASK32(m) ((mask32)(m))
+
+  /* If Z is zero and M has its low 32 bits set, then copy (at least) the low
+   * 32 bits of X to Z; if M is zero, do nothing.  Otherwise, scramble Z
+   * unhelpfully.
+   */
+# define CONDPICK(z, x, m)                                             \
+    do { (z) += (x)*(int)((unsigned)(m)&1u); } while (0)
+
+  /* If M has its low 32 bits set, then return (at least) the low 32 bits of
+   * X in Z; if M is zero, then return (at least) the low 32 bits of Y in Z.
+   * Otherwise, return an unhelful result.
+   */
+# define PICK2(x, y, m)                                                        \
+    ((x)*(int)((unsigned)(m)&1u) + (y)*(int)(1 - ((unsigned)(m)&1u)))
+
+  /* If M has its low 32 bits set then swap (at least) the low 32 bits of X
+   * and Y; if M is zero, then do nothing.  Otherwise, scramble X and Y
+   * unhelpfully.
+   */
+# define CONDSWAP(x, y, m) do {                                                \
+    int32 x_ = PICK2((y), (x), (m)), y_ = PICK2((x), (y), (m));                \
+    (x) = x_; (y) = y_;                                                        \
+  } while (0)
+#endif
+
+/* Return zero if bit 31 of X is clear, or a mask with (at least) the low 32
+ * bits set if bit 31 of X is set.
+ */
+#define SIGN(x) (-(mask32)(((uint32)(x) >> 31)&1))
+
+/* Return zero if X is zero, or a mask with (at least) the low 32 bits set if
+ * X is nonzero.
+ */
+#define NONZEROP(x) SIGN((U32(x) >> 1) - U32(x))
+
+/*----- Debugging utilities -----------------------------------------------*/
+
+/* Define a debugging function DUMPFN, which will dump an integer represented
+ * modulo M.  The integer is represented as a vector of NPIECE pieces of type
+ * PIECETY.  The pieces are assembled at possibly irregular offsets: piece i
+ * logically has width PIECEWD(i), but may overhang the next piece.  The
+ * pieces may be signed.  GETMOD is an expression which calculates and
+ * returns the value of M, as an `mp *'.
+ *
+ * The generated function writes the value of such an integer X to the stream
+ * FP, labelled with the string WHAT.
+ *
+ * The definition assumes that <stdio.h>, <catacomb/mp.h>, and
+ * <catacomb/mptext.h> have been included.
+ */
+#define DEF_FDUMP(dumpfn, piecety, piecewd, npiece, noctet, getmod)    \
+  static void dumpfn(FILE *fp, const char *what, const piecety *x)     \
+  {                                                                    \
+    mpw w;                                                             \
+    mp m, *y = MP_ZERO, *t = MP_NEW, *p;                               \
+    octet b[noctet];                                                   \
+    unsigned i, o;                                                     \
+                                                                       \
+    p = getmod;                                                                \
+    mp_build(&m, &w, &w + 1);                                          \
+    for (i = o = 0; i < npiece; i++) {                                 \
+      if (x[i] >= 0) { w = x[i]; m.f &= ~MP_NEG; }                     \
+      else { w = -x[i]; m.f |= MP_NEG; }                               \
+      t = mp_lsl(t, &m, o);                                            \
+      y = mp_add(y, y, t);                                             \
+      o += piecewd(i);                                                 \
+    }                                                                  \
+                                                                       \
+    fprintf(fp, "%s = <", what);                                       \
+    for (i = 0; i < npiece; i++) {                                     \
+      if (i) fputs(", ", fp);                                          \
+      fprintf(fp, "%ld", (long)x[i]);                                  \
+    }                                                                  \
+    fputs(">\n\t= ", fp);                                              \
+    mp_writefile(y, fp, 10);                                           \
+    fputs("\n\t== ", fp);                                              \
+    mp_div(0, &y, y, p);                                               \
+    mp_writefile(y, fp, 10);                                           \
+    fputs("\n\t= 0x", fp);                                             \
+    mp_writefile(y, fp, 16);                                           \
+    fputs(" (mod 2^255 - 19)\n\t= [", fp);                             \
+    mp_storel(y, b, sizeof(b));                                                \
+    for (i = 0; i < 32; i++) {                                         \
+      if (i && !(i%4)) fputc(':', fp);                                 \
+      fprintf(fp, "%02x", b[i]);                                       \
+    }                                                                  \
+    fputs("]\n", fp);                                                  \
+    mp_drop(y); mp_drop(p); mp_drop(t);                                        \
+  }
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/x25519-tests.in b/x25519-tests.in
new file mode 100644 (file)
index 0000000..b80521d
--- /dev/null
@@ -0,0 +1,51 @@
+### Tests for X25519.
+
+x25519 {
+  ## These are from Daniel J. Bernstein, `Cryptography in NaCl', 2009-03-10,
+  ## https://cr.yp.to/highspeed/naclcrypto-20090310.pdf
+
+  ## Make Alice's public key.
+  77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a
+    0900000000000000000000000000000000000000000000000000000000000000
+    8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a;
+
+  ## Make Bob's public key.
+  5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb
+    0900000000000000000000000000000000000000000000000000000000000000
+    de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f;
+
+  ## Make the shared secret using Alice's private key.
+  77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a
+    de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f
+    4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742;
+
+  ## Make the (same) shared secret using Bob's private key.
+  5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb
+    8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a
+    4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742;
+
+  ## These tests are from RFC7748.  I've clamped the public values because
+  ## RFC7748 wants the top bits ignored.
+  a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4
+    e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c
+    c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552;
+  4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d
+    e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a413
+    95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957;
+}
+
+x25519-mct {
+  ## These tests are from RFC7748.
+
+  0900000000000000000000000000000000000000000000000000000000000000
+    0900000000000000000000000000000000000000000000000000000000000000
+    1 422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079;
+  0900000000000000000000000000000000000000000000000000000000000000
+    0900000000000000000000000000000000000000000000000000000000000000
+    1000 684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51;
+
+  ## This one takes aaaaages.
+  ##0900000000000000000000000000000000000000000000000000000000000000
+  ##  0900000000000000000000000000000000000000000000000000000000000000
+  ##  1000000 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424;
+}
diff --git a/x25519.c b/x25519.c
new file mode 100644 (file)
index 0000000..8e9649e
--- /dev/null
+++ b/x25519.c
@@ -0,0 +1,196 @@
+/* -*-c-*-
+ *
+ * The X25519 key-agreement algorithm
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#include "montladder.h"
+#include "f25519.h"
+#include "x25519.h"
+
+/*----- Important constants -----------------------------------------------*/
+
+const octet x25519_base[32] = { 9, 0, /* ... */ };
+
+#define A0 121665
+
+/*----- Key fetching ------------------------------------------------------*/
+
+const key_fetchdef x25519_pubfetch[] = {
+  { "pub",     offsetof(x25519_pub, pub),      KENC_BINARY,    0 },
+  { 0,         0,                              0,              0 }
+};
+
+static const key_fetchdef priv[] = {
+  { "priv",    offsetof(x25519_priv, priv),    KENC_BINARY,    0 },
+  { 0,         0,                              0,              0 }
+};
+
+const key_fetchdef x25519_privfetch[] = {
+  { "pub",     offsetof(x25519_priv, pub),     KENC_BINARY,    0 },
+  { "private", 0,                              KENC_STRUCT,    priv },
+  { 0,         0,                              0,              0 }
+};
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @x25519@ --- *
+ *
+ * Arguments:  @octet zz[X25519_OUTSZ]@ = where to put the result
+ *             @const octet k[X25519_KEYSZ]@ = pointer to private key
+ *             @const octet qx[X25519_PUBSZ]@ = pointer to public value
+ *
+ * Returns:    ---
+ *
+ * Use:                Calculates X25519 of @k@ and @qx@.
+ *
+ *             Note that there is disagreement over whether the most
+ *             significant bit of @qx@ (i.e., the value @qx[31]&0x80@)
+ *             should be ignored or counted towards the represented value.
+ *             Historically implementations respected the bit; later
+ *             convention seems to be to ignore it.  This implementation
+ *             honours the bit: a caller who wants to ignore the bit can
+ *             easily clear it, while caller who wants to respect it has a
+ *             difficult job if this function ignores it.
+ */
+
+void x25519(octet zz[X25519_OUTSZ],
+           const octet k[X25519_KEYSZ],
+           const octet qx[X25519_PUBSZ])
+{
+  uint32 kw[8];
+  f25519 x1;
+
+  /* Load and clamp the key.  The low bits are cleared to kill the small
+   * subgroups on the curve and its twist, and a high bit is set to guard
+   * against careless implementations, though this isn't one of those.
+   */
+  kw[0] = LOAD32_L(k +  0); kw[1] = LOAD32_L(k +  4);
+  kw[2] = LOAD32_L(k +  8); kw[3] = LOAD32_L(k + 12);
+  kw[4] = LOAD32_L(k + 16); kw[5] = LOAD32_L(k + 20);
+  kw[6] = LOAD32_L(k + 24); kw[7] = LOAD32_L(k + 28);
+  kw[0] &= 0xfffffff8; kw[7] = (kw[7]&0x3fffffff) | 0x40000000;
+
+  /* And run the ladder. */
+  f25519_load(&x1, qx);
+#define MULA0(z, x) do { f25519_mulconst((z), (x), A0); } while (0)
+  MONT_LADDER(f25519, MULA0, kw, 8, 32, &x1, &x1);
+#undef MULA0
+  f25519_store(zz, &x1);
+}
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+#include <string.h>
+
+#include <mLib/report.h>
+#include <mLib/testrig.h>
+
+static int vrf_x25519(dstr dv[])
+{
+  dstr dz = DSTR_INIT;
+  int ok = 1;
+
+  if (dv[0].len != 32) die(1, "bad key length");
+  if (dv[1].len != 32) die(1, "bad public length");
+  if (dv[2].len != 32) die(1, "bad result length");
+
+  dstr_ensure(&dz, 32); dz.len = 32;
+  x25519((octet *)dz.buf,
+        (const octet *)dv[0].buf,
+        (const octet *)dv[1].buf);
+  if (memcmp(dz.buf, dv[2].buf, 32) != 0) {
+    ok = 0;
+    fprintf(stderr, "failed!");
+    fprintf(stderr, "\n\t   k = "); type_hex.dump(&dv[0], stderr);
+    fprintf(stderr, "\n\t   p = "); type_hex.dump(&dv[1], stderr);
+    fprintf(stderr, "\n\twant = "); type_hex.dump(&dv[2], stderr);
+    fprintf(stderr, "\n\tcalc = "); type_hex.dump(&dz, stderr);
+    fprintf(stderr, "\n");
+  }
+
+  dstr_destroy(&dz);
+  return (ok);
+}
+
+static int vrf_mct(dstr dv[])
+{
+  octet b0[32], b1[32], *k = b0, *x = b1, *t;
+  unsigned long i, niter;
+  dstr d = DSTR_INIT;
+  int ok = 1;
+
+  if (dv[0].len != sizeof(b0)) { fprintf(stderr, "k len\n"); exit(2); }
+  if (dv[1].len != sizeof(b1)) { fprintf(stderr, "x len\n"); exit(2); }
+  if (dv[3].len != sizeof(b0)) { fprintf(stderr, "result len\n"); exit(2); }
+  memcpy(b0, dv[0].buf, sizeof(b0));
+  memcpy(b1, dv[1].buf, sizeof(b1));
+  niter = *(unsigned long *)dv[2].buf;
+  dstr_ensure(&d, 32); d.len = 32; t = (octet *)d.buf;
+
+  for (i = 0; i < niter; i++) {
+    x[31] &= 0x7f;
+    x25519(x, k, x);
+    t = x; x = k; k = t;
+  }
+  memcpy(d.buf, k, d.len);
+
+  if (memcmp(d.buf, dv[3].buf, d.len) != 0) {
+    ok = 0;
+    fprintf(stderr, "failed...");
+    fprintf(stderr, "\n\tinitial k = "); type_hex.dump(&dv[0], stderr);
+    fprintf(stderr, "\n\tinitial x = "); type_hex.dump(&dv[1], stderr);
+    fprintf(stderr, "\n\titerations = %lu", niter);
+    fprintf(stderr, "\n\texpected = "); type_hex.dump(&dv[3], stderr);
+    fprintf(stderr, "\n\tcalculated = "); type_hex.dump(&d, stderr);
+    fputc('\n', stderr);
+  }
+
+  dstr_destroy(&d);
+  return (ok);
+}
+
+static test_chunk tests[] = {
+  { "x25519", vrf_x25519, { &type_hex, &type_hex, &type_hex } },
+  { "x25519-mct", vrf_mct,
+    { &type_hex, &type_hex, &type_ulong, &type_hex } },
+  { 0, 0, { 0 } }
+};
+
+int main(int argc, char *argv[])
+{
+  test_run(argc, argv, tests, SRCDIR "/t/x25519");
+  return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/x25519.h b/x25519.h
new file mode 100644 (file)
index 0000000..56008df
--- /dev/null
+++ b/x25519.h
@@ -0,0 +1,103 @@
+/* -*-c-*-
+ *
+ * The X25519 key-agreement algorithm
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_X25519_H
+#define CATACOMB_X25519_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Notes on the X25519 key-agreement algorithm -----------------------*
+ *
+ * This is X25519, as described in Daniel J. Bernstein, `Curve25519: new
+ * Diffie--Hellman speed records', PKC 2006,
+ * https://cr.yp.to/ecdh/curve25519-20060209.pdf
+ *
+ * Since then, the name `Curve25519' has shifted somewhat, to refer to the
+ * specific elliptic curve used, and the x-coordinate Diffie--Hellman
+ * operation is now named `X25519'.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#ifndef CATACOMB_KEY_H
+#  include "key.h"
+#endif
+
+/*----- Important constants -----------------------------------------------*/
+
+#define X25519_KEYSZ 32u
+#define X25519_PUBSZ 32u
+#define X25519_OUTSZ 32u
+
+extern const octet x25519_base[32];
+
+/*----- Key fetching ------------------------------------------------------*/
+
+typedef struct x25519_priv { key_bin priv, pub; } x25519_priv;
+typedef struct x25519_pub { key_bin pub; } x25519_pub;
+
+extern const key_fetchdef x25519_pubfetch[], x25519_privfetch[];
+#define X25519_PUBFETCHSZ 3
+#define X25519_PRIVFETCHSZ 6
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @x25519@ --- *
+ *
+ * Arguments:  @octet zz[X25519_OUTSZ]@ = where to put the result
+ *             @const octet k[X25519_KEYSZ]@ = pointer to private key
+ *             @const octet qx[X25519_PUBSZ]@ = pointer to public value
+ *
+ * Returns:    ---
+ *
+ * Use:                Calculates X25519 of @k@ and @qx@.
+ *
+ *             Note that there is disagreement over whether the most
+ *             significant bit of @qx@ (i.e., the value @qx[31]&0x80@)
+ *             should be ignored or counted towards the represented value.
+ *             Historically implementations respected the bit; later
+ *             convention seems to be to ignore it.  This implementation
+ *             honours the bit: a caller who wants to ignore the bit can
+ *             easily clear it, while caller who wants to respect it has a
+ *             difficult job if this function ignores it.
+ */
+
+extern void x25519(octet /*zz*/[X25519_OUTSZ],
+                  const octet /*k*/[X25519_KEYSZ],
+                  const octet /*qx*/[X25519_PUBSZ]);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/x448-tests.in b/x448-tests.in
new file mode 100644 (file)
index 0000000..0320af3
--- /dev/null
@@ -0,0 +1,41 @@
+### Tests for X448.
+
+x448 {
+  ## These are taken from RFC7748.
+
+  3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3
+    06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086
+    ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f;
+  203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f
+    0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db
+    884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d;
+
+  9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b
+    0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0;
+  1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d
+    0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609;
+  9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b
+    3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609
+    07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d;
+  1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d
+    9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0
+    07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d;
+}
+
+x448-mct {
+  ## These are taken from RFC7748.
+
+  0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    1 3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113;
+  0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    1000 aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38;
+
+  ## This one takes aaaaages.
+  0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+    1000000 077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37;
+}
diff --git a/x448.c b/x448.c
new file mode 100644 (file)
index 0000000..d766e5c
--- /dev/null
+++ b/x448.c
@@ -0,0 +1,182 @@
+/* -*-c-*-
+ *
+ * The X448 key-agreement algorithm
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#include "montladder.h"
+#include "fgoldi.h"
+#include "x448.h"
+
+/*----- Important constants -----------------------------------------------*/
+
+const octet x448_base[56] = { 5, 0, /* ... */ };
+
+#define A0 39081
+
+/*----- Key fetching ------------------------------------------------------*/
+
+const key_fetchdef x448_pubfetch[] = {
+  { "pub",     offsetof(x448_pub, pub),        KENC_BINARY,    0 },
+  { 0,         0,                              0,              0 }
+};
+
+static const key_fetchdef priv[] = {
+  { "priv",    offsetof(x448_priv, priv),      KENC_BINARY,    0 },
+  { 0,         0,                              0,              0 }
+};
+
+const key_fetchdef x448_privfetch[] = {
+  { "pub",     offsetof(x448_priv, pub),       KENC_BINARY,    0 },
+  { "private", 0,                              KENC_STRUCT,    priv },
+  { 0,         0,                              0,              0 }
+};
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @x448@ --- *
+ *
+ * Arguments:  @octet zz[X448_OUTSZ]@ = where to put the result
+ *             @const octet k[X448_KEYSZ]@ = pointer to private key
+ *             @const octet qx[X448_PUBSZ]@ = pointer to public value
+ *
+ * Returns:    ---
+ *
+ * Use:                Calculates X448 of @k@ and @qx@.
+ */
+
+void x448(octet zz[X448_OUTSZ],
+         const octet k[X448_KEYSZ],
+         const octet qx[X448_PUBSZ])
+{
+  uint32 kw[14];
+  fgoldi x1;
+  unsigned i;
+
+  /* Load and clamp the key.  The low bits are cleared to kill the small
+   * subgroups on the curve and its twist, and a high bit is set to guard
+   * against careless implementations, though this isn't one of those.
+   */
+  for (i = 0; i < 14; i++) kw[i] = LOAD32_L(k + 4*i);
+  kw[0] &= 0xfffffffc; kw[13] |= 0x80000000;
+
+  /* And run the ladder. */
+  fgoldi_load(&x1, qx);
+#define MULA0(z, x) do { fgoldi_mulconst((z), (x), A0); } while (0)
+  MONT_LADDER(fgoldi, MULA0, kw, 14, 32, &x1, &x1);
+#undef MULA0
+  fgoldi_store(zz, &x1);
+}
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <mLib/report.h>
+#include <mLib/str.h>
+#include <mLib/testrig.h>
+
+static int vrf_x448(dstr dv[])
+{
+  dstr dz = DSTR_INIT;
+  int ok = 1;
+
+  if (dv[0].len != 56) die(1, "bad key length");
+  if (dv[1].len != 56) die(1, "bad public length");
+  if (dv[2].len != 56) die(1, "bad result length");
+
+  dstr_ensure(&dz, 56); dz.len = 56;
+  x448((octet *)dz.buf,
+       (const octet *)dv[0].buf,
+       (const octet *)dv[1].buf);
+  if (memcmp(dz.buf, dv[2].buf, 56) != 0) {
+    ok = 0;
+    fprintf(stderr, "failed!");
+    fprintf(stderr, "\n\t   k = "); type_hex.dump(&dv[0], stderr);
+    fprintf(stderr, "\n\t   p = "); type_hex.dump(&dv[1], stderr);
+    fprintf(stderr, "\n\twant = "); type_hex.dump(&dv[2], stderr);
+    fprintf(stderr, "\n\tcalc = "); type_hex.dump(&dz, stderr);
+    fprintf(stderr, "\n");
+  }
+
+  dstr_destroy(&dz);
+  return (ok);
+}
+
+static int vrf_mct(dstr dv[])
+{
+  octet b0[56], b1[56], *k = b0, *x = b1, *t;
+  unsigned long i, niter;
+  dstr d = DSTR_INIT;
+  int ok = 1;
+
+  if (dv[0].len != sizeof(b0)) { fprintf(stderr, "k len\n"); exit(2); }
+  if (dv[1].len != sizeof(b1)) { fprintf(stderr, "x len\n"); exit(2); }
+  if (dv[3].len != sizeof(b0)) { fprintf(stderr, "result len\n"); exit(2); }
+  memcpy(b0, dv[0].buf, sizeof(b0));
+  memcpy(b1, dv[1].buf, sizeof(b1));
+  niter = *(unsigned long *)dv[2].buf;
+  dstr_ensure(&d, 56); d.len = 56; t = (octet *)d.buf;
+
+  for (i = 0; i < niter; i++) {
+    x448(x, k, x);
+    t = x; x = k; k = t;
+  }
+  memcpy(d.buf, k, d.len);
+
+  if (memcmp(d.buf, dv[3].buf, d.len) != 0) {
+    ok = 0;
+    fprintf(stderr, "failed...");
+    fprintf(stderr, "\n\tinitial k = "); type_hex.dump(&dv[0], stderr);
+    fprintf(stderr, "\n\tinitial x = "); type_hex.dump(&dv[1], stderr);
+    fprintf(stderr, "\n\titerations = %lu", niter);
+    fprintf(stderr, "\n\texpected = "); type_hex.dump(&dv[3], stderr);
+    fprintf(stderr, "\n\tcalculated = "); type_hex.dump(&d, stderr);
+    fputc('\n', stderr);
+  }
+
+  dstr_destroy(&d);
+  return (ok);
+}
+
+static test_chunk tests[] = {
+  { "x448", vrf_x448, { &type_hex, &type_hex, &type_hex } },
+  { "x448-mct", vrf_mct,
+    { &type_hex, &type_hex, &type_ulong, &type_hex } },
+  { 0, 0, { 0 } }
+};
+
+int main(int argc, char *argv[])
+{
+  test_run(argc, argv, tests, SRCDIR "/t/x448");
+  return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/x448.h b/x448.h
new file mode 100644 (file)
index 0000000..f1b0f2c
--- /dev/null
+++ b/x448.h
@@ -0,0 +1,95 @@
+/* -*-c-*-
+ *
+ * The X448 key-agreement algorithm
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef CATACOMB_X448_H
+#define CATACOMB_X448_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Notes on the X448 key-agreement algorithm -------------------------*
+ *
+ * This is X448, as described in RFC7748, based on the elliptic curve defined
+ * in Mike Hamburg, `Ed448-Goldilocks, a new elliptic curve', EUROCRYPT 2016,
+ * https://eprint.iacr.org/2015/625/.
+ *
+ * The RFC-specified operation is simpler than the Diffie--Hellman function
+ * described in Hamburg's paper, since it doesn't involve the `Decaf'
+ * cofactor elimination procedure.  Indeed, it looks very much like X25519
+ * with Hamburg's curve slotted in in place of Bernstein's.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#ifndef CATACOMB_KEY_H
+#  include "key.h"
+#endif
+
+/*----- Key fetching ------------------------------------------------------*/
+
+typedef struct x448_priv { key_bin priv, pub; } x448_priv;
+typedef struct x448_pub { key_bin pub; } x448_pub;
+
+extern const key_fetchdef x448_pubfetch[], x448_privfetch[];
+#define X448_PUBFETCHSZ 3
+#define X448_PRIVFETCHSZ 6
+
+/*----- Important constants -----------------------------------------------*/
+
+#define X448_KEYSZ 56
+#define X448_PUBSZ 56
+#define X448_OUTSZ 56
+
+extern const octet x448_base[56];
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @x448@ --- *
+ *
+ * Arguments:  @octet zz[X448_OUTSZ]@ = where to put the result
+ *             @const octet k[X448_KEYSZ]@ = pointer to private key
+ *             @const octet qx[X448_PUBSZ]@ = pointer to public value
+ *
+ * Returns:    ---
+ *
+ * Use:                Calculates X448 of @k@ and @qx@.
+ */
+
+extern void x448(octet /*zz*/[X448_OUTSZ],
+                const octet /*k*/[X448_KEYSZ],
+                const octet /*qx*/[X448_PUBSZ]);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif